From 830108ac9086e9b20240b2b50a028bf4bcb3f0c2 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Wed, 14 May 2025 23:06:20 -0500 Subject: [PATCH 001/135] Opens #118#137 --- src/lib/components/Publication.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/components/Publication.svelte b/src/lib/components/Publication.svelte index 3ec008d..b80415b 100644 --- a/src/lib/components/Publication.svelte +++ b/src/lib/components/Publication.svelte @@ -167,7 +167,7 @@ {#if showTocButton && !showToc} - + Show Table of Contents {/if} {#if showTocButton && !showToc} From 5be8bedd4238aca916ea86712aac5d0d624e9916 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Wed, 14 May 2025 23:27:30 -0500 Subject: [PATCH 003/135] Remove unused Publication props --- src/lib/components/Publication.svelte | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib/components/Publication.svelte b/src/lib/components/Publication.svelte index f7f4df5..7c7f150 100644 --- a/src/lib/components/Publication.svelte +++ b/src/lib/components/Publication.svelte @@ -17,10 +17,8 @@ import PublicationSection from "./PublicationSection.svelte"; import type { PublicationTree } from "$lib/data_structures/publication_tree"; - let { rootAddress, publicationType, indexEvent } = $props<{ + let { rootAddress } = $props<{ rootAddress: string, - publicationType: string, - indexEvent: NDKEvent }>(); const publicationTree = getContext('publicationTree') as PublicationTree; From 2c045dd2c006382134f3db61176da6736b6ee5dc Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Wed, 14 May 2025 23:29:51 -0500 Subject: [PATCH 004/135] Init ToC interface --- src/lib/data_structures/table_of_contents.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/lib/data_structures/table_of_contents.ts diff --git a/src/lib/data_structures/table_of_contents.ts b/src/lib/data_structures/table_of_contents.ts new file mode 100644 index 0000000..8bf447f --- /dev/null +++ b/src/lib/data_structures/table_of_contents.ts @@ -0,0 +1,6 @@ +export interface TocEntry { + title: string; + href: string; + expanded: boolean; + children: Array | null; +} From 899ee4661575dabca397a381ce449259f57752ed Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Wed, 14 May 2025 23:30:05 -0500 Subject: [PATCH 005/135] Init TableOfContents Svelte component --- src/lib/components/TableOfContents.svelte | 16 +++++++++++++++ src/lib/components/Toc.svelte | 24 ----------------------- 2 files changed, 16 insertions(+), 24 deletions(-) create mode 100644 src/lib/components/TableOfContents.svelte delete mode 100644 src/lib/components/Toc.svelte diff --git a/src/lib/components/TableOfContents.svelte b/src/lib/components/TableOfContents.svelte new file mode 100644 index 0000000..9e606fb --- /dev/null +++ b/src/lib/components/TableOfContents.svelte @@ -0,0 +1,16 @@ + + + diff --git a/src/lib/components/Toc.svelte b/src/lib/components/Toc.svelte deleted file mode 100644 index 9d433b5..0000000 --- a/src/lib/components/Toc.svelte +++ /dev/null @@ -1,24 +0,0 @@ - - -
-

Table of contents

- -
- - From d9c9c5b1ba5e20905041e9a2362374ee2bb3a7ad Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Thu, 15 May 2025 09:13:36 -0500 Subject: [PATCH 006/135] Update Deno lockfile --- deno.lock | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deno.lock b/deno.lock index c97022c..96b2728 100644 --- a/deno.lock +++ b/deno.lock @@ -2902,6 +2902,8 @@ "npm:flowbite-svelte@0", "npm:flowbite@2", "npm:he@1.2", + "npm:highlight.js@^11.11.1", + "npm:node-emoji@^2.2.0", "npm:nostr-tools@2.10", "npm:playwright@^1.50.1", "npm:postcss-load-config@6", From 650aa280d45997ca082f3c5234935ccb24ee50f8 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Thu, 15 May 2025 09:14:00 -0500 Subject: [PATCH 007/135] Add comments with implementation plan --- src/lib/components/TableOfContents.svelte | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/lib/components/TableOfContents.svelte b/src/lib/components/TableOfContents.svelte index 9e606fb..e26cdb9 100644 --- a/src/lib/components/TableOfContents.svelte +++ b/src/lib/components/TableOfContents.svelte @@ -5,12 +5,14 @@ let { rootAddress } = $props<{ rootAddress: string }>(); + // Determine the event kind. + // If index, use the publication tree to build the table of contents. + // If single event, build the table of contents from the rendered HTML. + // Each rendered `` should receive an entry in the ToC. + let toc = $state([]); const publicationTree = getContext('publicationTree') as PublicationTree; - - // TODO: Build the table of contents. - // Base hrefs on d-tags for events within the publication. From 78e4d23f718fe53abb601f555c82cc8514bbcf10 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Fri, 16 May 2025 09:07:24 -0500 Subject: [PATCH 008/135] Add a function to extract ToC entries from HTML --- src/lib/components/TableOfContents.svelte | 30 +++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/lib/components/TableOfContents.svelte b/src/lib/components/TableOfContents.svelte index e26cdb9..71bcdd0 100644 --- a/src/lib/components/TableOfContents.svelte +++ b/src/lib/components/TableOfContents.svelte @@ -1,4 +1,5 @@ From 42cb538be5b7e906e9df7481532c769b6af8cd6e Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Mon, 26 May 2025 08:27:41 -0500 Subject: [PATCH 010/135] Move publication components into their own sub-directory --- deno.lock | 10 ++++++++++ .../components/{ => publications}/Publication.svelte | 0 .../{ => publications}/PublicationFeed.svelte | 0 .../{ => publications}/PublicationHeader.svelte | 2 +- .../{ => publications}/PublicationSection.svelte | 0 src/routes/+page.svelte | 2 +- src/routes/publication/+page.svelte | 2 +- 7 files changed, 13 insertions(+), 3 deletions(-) rename src/lib/components/{ => publications}/Publication.svelte (100%) rename src/lib/components/{ => publications}/PublicationFeed.svelte (100%) rename src/lib/components/{ => publications}/PublicationHeader.svelte (97%) rename src/lib/components/{ => publications}/PublicationSection.svelte (100%) diff --git a/deno.lock b/deno.lock index 9206145..6604928 100644 --- a/deno.lock +++ b/deno.lock @@ -3168,6 +3168,13 @@ "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==" } }, + "redirects": { + "https://esm.sh/bech32": "https://esm.sh/bech32@2.0.0" + }, + "remote": { + "https://esm.sh/bech32@2.0.0": "1b943d1583f3708812c3cfccc8236cf92d8f9b191881984e26e0b9decaed9a16", + "https://esm.sh/bech32@2.0.0/denonext/bech32.mjs": "80859514ec6ba04858364eba363d5ac73ac8d97086754e0baf14fa31d4f1b63a" + }, "workspace": { "dependencies": [ "npm:@nostr-dev-kit/ndk-cache-dexie@2.5", @@ -3201,8 +3208,10 @@ "npm:@types/d3@^7.4.3", "npm:@types/he@1.2", "npm:@types/node@22", + "npm:@types/qrcode@^1.5.5", "npm:asciidoctor@3.0", "npm:autoprefixer@10", + "npm:bech32@2", "npm:d3@^7.9.0", "npm:eslint-plugin-svelte@2", "npm:flowbite-svelte-icons@2.1", @@ -3217,6 +3226,7 @@ "npm:postcss@8", "npm:prettier-plugin-svelte@3", "npm:prettier@3", + "npm:qrcode@^1.5.4", "npm:svelte-check@4", "npm:svelte@5", "npm:tailwind-merge@^3.3.0", diff --git a/src/lib/components/Publication.svelte b/src/lib/components/publications/Publication.svelte similarity index 100% rename from src/lib/components/Publication.svelte rename to src/lib/components/publications/Publication.svelte diff --git a/src/lib/components/PublicationFeed.svelte b/src/lib/components/publications/PublicationFeed.svelte similarity index 100% rename from src/lib/components/PublicationFeed.svelte rename to src/lib/components/publications/PublicationFeed.svelte diff --git a/src/lib/components/PublicationHeader.svelte b/src/lib/components/publications/PublicationHeader.svelte similarity index 97% rename from src/lib/components/PublicationHeader.svelte rename to src/lib/components/publications/PublicationHeader.svelte index 32a674a..25dfdc4 100644 --- a/src/lib/components/PublicationHeader.svelte +++ b/src/lib/components/publications/PublicationHeader.svelte @@ -2,7 +2,7 @@ import { ndkInstance } from '$lib/ndk'; import { naddrEncode } from '$lib/utils'; import type { NDKEvent } from '@nostr-dev-kit/ndk'; - import { standardRelays } from '../consts'; + import { standardRelays } from '../../consts'; import { Card, Img } from "flowbite-svelte"; import CardActions from "$components/util/CardActions.svelte"; import { userBadge } from "$lib/snippets/UserSnippets.svelte"; diff --git a/src/lib/components/PublicationSection.svelte b/src/lib/components/publications/PublicationSection.svelte similarity index 100% rename from src/lib/components/PublicationSection.svelte rename to src/lib/components/publications/PublicationSection.svelte diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index d3cee5c..dd9ba68 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -3,7 +3,7 @@ import { Alert, Button, Dropdown, Radio, Input } from "flowbite-svelte"; import { ChevronDownOutline, HammerSolid } from "flowbite-svelte-icons"; import { inboxRelays, ndkSignedIn } from '$lib/ndk'; - import PublicationFeed from '$lib/components/PublicationFeed.svelte'; + import PublicationFeed from '$lib/components/publications/PublicationFeed.svelte'; import { feedType } from '$lib/stores'; $effect(() => { diff --git a/src/routes/publication/+page.svelte b/src/routes/publication/+page.svelte index 48b156c..9316069 100644 --- a/src/routes/publication/+page.svelte +++ b/src/routes/publication/+page.svelte @@ -1,5 +1,5 @@ + + diff --git a/src/lib/components/TableOfContents.svelte b/src/lib/components/publications/table_of_contents.svelte.ts similarity index 52% rename from src/lib/components/TableOfContents.svelte rename to src/lib/components/publications/table_of_contents.svelte.ts index 78aa83a..548d4f5 100644 --- a/src/lib/components/TableOfContents.svelte +++ b/src/lib/components/publications/table_of_contents.svelte.ts @@ -1,35 +1,38 @@ - - - +} diff --git a/src/lib/data_structures/table_of_contents.ts b/src/lib/data_structures/table_of_contents.ts deleted file mode 100644 index 8bf447f..0000000 --- a/src/lib/data_structures/table_of_contents.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface TocEntry { - title: string; - href: string; - expanded: boolean; - children: Array | null; -} From feab392a4478910af71dd0c6ec689ef37cd161ab Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Mon, 26 May 2025 09:07:26 -0500 Subject: [PATCH 012/135] Refactor `TableOfContents` class for least privilege --- .../publications/TableOfContents.svelte | 9 +--- .../publications/table_of_contents.svelte.ts | 51 ++++++++++++------- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/src/lib/components/publications/TableOfContents.svelte b/src/lib/components/publications/TableOfContents.svelte index 50b383a..15f441e 100644 --- a/src/lib/components/publications/TableOfContents.svelte +++ b/src/lib/components/publications/TableOfContents.svelte @@ -1,15 +1,10 @@ - + + {#each toc as entry} + {entry.title} + {/each} + diff --git a/src/lib/components/publications/table_of_contents.svelte.ts b/src/lib/components/publications/table_of_contents.svelte.ts index 3efddd1..4b6cc7a 100644 --- a/src/lib/components/publications/table_of_contents.svelte.ts +++ b/src/lib/components/publications/table_of_contents.svelte.ts @@ -132,4 +132,25 @@ export class TableOfContents { } }); } + + /** + * Iterates over all ToC entries in depth-first order. + */ + *[Symbol.iterator](): IterableIterator { + function* traverse(entry: TocEntry | null): IterableIterator { + if (!entry) { + return; + } + + yield entry; + + if (entry.children) { + for (const child of entry.children) { + yield* traverse(child); + } + } + } + + yield* traverse(this.#tocRoot); + } } From f9048c468ca5d8a5d12b4775992d60e30293925e Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Wed, 28 May 2025 08:46:52 -0500 Subject: [PATCH 016/135] Add doc comment on ToC constructor --- .../publications/table_of_contents.svelte.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/lib/components/publications/table_of_contents.svelte.ts b/src/lib/components/publications/table_of_contents.svelte.ts index 4b6cc7a..a16f72b 100644 --- a/src/lib/components/publications/table_of_contents.svelte.ts +++ b/src/lib/components/publications/table_of_contents.svelte.ts @@ -7,12 +7,22 @@ export interface TocEntry { children: Array | null; } +// TODO: Include depth in the `TocEntry` interface, and compute it when adding entries to the ToC. + export class TableOfContents { #tocRoot: TocEntry | null = null; #addresses = $state>(new Map()); #publicationTree: PublicationTree; #pagePathname: string; + /** + * Constructor for the `TableOfContents` class. The constructed ToC initially contains only the + * root entry. Additional entries must be inserted programmatically using class methods. + * + * The `TableOfContents` class should be instantiated as a page-scoped singleton so that + * `pagePathname` is correct wherever the instance is used. The singleton should be made + * made available to the entire component tree under that page. + */ constructor(rootAddress: string, publicationTree: PublicationTree, pagePathname: string) { // TODO: Build out the root entry correctly. this.#tocRoot = { From 4afbd04d5e57bb340a3a6151c4021504dd24338e Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Wed, 28 May 2025 08:47:28 -0500 Subject: [PATCH 017/135] Add a TODO --- src/lib/components/publications/TableOfContents.svelte | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/components/publications/TableOfContents.svelte b/src/lib/components/publications/TableOfContents.svelte index a49fd1c..891476a 100644 --- a/src/lib/components/publications/TableOfContents.svelte +++ b/src/lib/components/publications/TableOfContents.svelte @@ -7,6 +7,8 @@ let toc = getContext('toc') as TableOfContents; + // TODO: Check root address against ToC root address for correctness. + // Determine the event kind. // If index, use the publication tree to build the table of contents. // If single event, build the table of contents from the rendered HTML. From 640a1263302e483bf4aca46810b7dcad0aeba7ae Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Wed, 28 May 2025 08:55:48 -0500 Subject: [PATCH 018/135] Compute depth of ToC entries when adding them --- .../publications/table_of_contents.svelte.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/lib/components/publications/table_of_contents.svelte.ts b/src/lib/components/publications/table_of_contents.svelte.ts index a16f72b..77154aa 100644 --- a/src/lib/components/publications/table_of_contents.svelte.ts +++ b/src/lib/components/publications/table_of_contents.svelte.ts @@ -1,14 +1,14 @@ import { PublicationTree } from "../../data_structures/publication_tree.ts"; export interface TocEntry { + address: string; title: string; href: string; + depth: number; expanded: boolean; children: Array | null; } -// TODO: Include depth in the `TocEntry` interface, and compute it when adding entries to the ToC. - export class TableOfContents { #tocRoot: TocEntry | null = null; #addresses = $state>(new Map()); @@ -24,14 +24,6 @@ export class TableOfContents { * made available to the entire component tree under that page. */ constructor(rootAddress: string, publicationTree: PublicationTree, pagePathname: string) { - // TODO: Build out the root entry correctly. - this.#tocRoot = { - title: '', - href: '', - expanded: false, - children: null, - }; - this.#publicationTree = publicationTree; this.#pagePathname = pagePathname; @@ -88,8 +80,10 @@ export class TableOfContents { currentParentTocNode!.children ??= []; const childTocEntry: TocEntry = { + address, title: childEvent.getMatchingTags('title')[0][1], href: `${this.#pagePathname}#${this.#normalizeHashPath(childEvent.getMatchingTags('title')[0][1])}`, + depth: i + 1, expanded: false, children: null, }; @@ -130,8 +124,10 @@ export class TableOfContents { const href = `${this.#pagePathname}#${id}`; const tocEntry: TocEntry = { + address: parentEntry.address, title, href, + depth, expanded: false, children: null, }; From 2c3b9adf58178248f7c19736a7a9028301d6f537 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 31 May 2025 20:34:45 -0500 Subject: [PATCH 019/135] Set workspace tab size to 2 spaces --- .vscode/settings.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index e06c2f4..6953a21 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,5 +10,6 @@ }, "files.associations": { "*.svelte": "svelte" - } + }, + "editor.tabSize": 2 } \ No newline at end of file From d3ec3ad3e204768c96058be550b88339b013424d Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 31 May 2025 20:50:38 -0500 Subject: [PATCH 020/135] Add observability to node resolution --- src/lib/data_structures/publication_tree.ts | 32 ++++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/lib/data_structures/publication_tree.ts b/src/lib/data_structures/publication_tree.ts index d616740..3184b29 100644 --- a/src/lib/data_structures/publication_tree.ts +++ b/src/lib/data_structures/publication_tree.ts @@ -1,7 +1,7 @@ -import type NDK from "@nostr-dev-kit/ndk"; -import type { NDKEvent } from "@nostr-dev-kit/ndk"; -import { Lazy } from "./lazy.ts"; -import { findIndexAsync as _findIndexAsync } from '../utils.ts'; +import type NDK from '@nostr-dev-kit/ndk'; +import type { NDKEvent } from '@nostr-dev-kit/ndk'; +import { Lazy } from './lazy.ts'; +import { SvelteSet } from "svelte/reactivity"; enum PublicationTreeNodeType { Branch, @@ -22,6 +22,14 @@ interface PublicationTreeNode { } export class PublicationTree implements AsyncIterable { + // TODO: Abstract this into a `SveltePublicationTree` wrapper class. + /** + * A reactive set of addresses of the events that have been resolved (loaded) into the tree. + * Svelte components can use this set in reactive code blocks to trigger updates when new nodes + * are added to the tree. + */ + resolvedAddresses: SvelteSet = new SvelteSet(); + /** * The root node of the tree. */ @@ -52,6 +60,8 @@ export class PublicationTree implements AsyncIterable { */ #ndk: NDK; + #onNodeResolvedCallbacks: Array<(address: string) => void> = []; + constructor(rootEvent: NDKEvent, ndk: NDK) { const rootAddress = rootEvent.tagAddress(); this.#root = { @@ -185,6 +195,16 @@ export class PublicationTree implements AsyncIterable { this.#cursor.tryMoveTo(address); } + /** + * Registers an observer function that is invoked whenever a new node is resolved. Nodes are + * added lazily. + * + * @param observer The observer function. + */ + onNodeResolved(observer: (address: string) => void) { + this.#onNodeResolvedCallbacks.push(observer); + } + // #region Iteration Cursor #cursor = new class { @@ -504,6 +524,7 @@ export class PublicationTree implements AsyncIterable { } this.#events.set(address, event); + this.resolvedAddresses.add(address); const childAddresses = event.tags.filter(tag => tag[0] === 'a').map(tag => tag[1]); @@ -519,6 +540,9 @@ export class PublicationTree implements AsyncIterable { this.addEventByAddress(address, event); } + // TODO: We may need to move this to `#addNode`, so the observer is notified more eagerly. + this.#onNodeResolvedCallbacks.forEach(observer => observer(address)); + return node; } From c6effb38397e188f9da37b03d0031a5b77fa8fbe Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Mon, 2 Jun 2025 08:50:15 -0500 Subject: [PATCH 021/135] Create Svelte-specific wrapper that proxies `PublicationTree` The wrapper keeps the core implementation framework-agnostic, but lets us build Svelte's reactivity into the wrapper. --- .../publications/Publication.svelte | 4 +- .../publications/PublicationSection.svelte | 5 +- .../svelte_publication_tree.svelte.ts | 56 +++++++++++++++++++ src/lib/data_structures/publication_tree.ts | 9 --- src/routes/publication/+page.svelte | 5 +- 5 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 src/lib/components/publications/svelte_publication_tree.svelte.ts diff --git a/src/lib/components/publications/Publication.svelte b/src/lib/components/publications/Publication.svelte index f7e026f..7147de4 100644 --- a/src/lib/components/publications/Publication.svelte +++ b/src/lib/components/publications/Publication.svelte @@ -15,13 +15,13 @@ } from "flowbite-svelte-icons"; import type { NDKEvent } from "@nostr-dev-kit/ndk"; import PublicationSection from "./PublicationSection.svelte"; - import type { PublicationTree } from "$lib/data_structures/publication_tree"; import Details from "$components/util/Details.svelte"; import { publicationColumnVisibility } from "$lib/stores"; import BlogHeader from "$components/cards/BlogHeader.svelte"; import Interactions from "$components/util/Interactions.svelte"; import TocToggle from "$components/util/TocToggle.svelte"; import { pharosInstance } from '$lib/parser'; + import type { SveltePublicationTree } from "./svelte_publication_tree.svelte"; let { rootAddress, publicationType, indexEvent } = $props<{ rootAddress: string; @@ -29,7 +29,7 @@ indexEvent: NDKEvent; }>(); - const publicationTree = getContext("publicationTree") as PublicationTree; + const publicationTree = getContext("publicationTree") as SveltePublicationTree; // #region Loading diff --git a/src/lib/components/publications/PublicationSection.svelte b/src/lib/components/publications/PublicationSection.svelte index 6c2586a..7b24fb3 100644 --- a/src/lib/components/publications/PublicationSection.svelte +++ b/src/lib/components/publications/PublicationSection.svelte @@ -6,7 +6,8 @@ import { getContext } from "svelte"; import type { Asciidoctor, Document } from "asciidoctor"; import { getMatchingTags } from '$lib/utils/nostrUtils'; - + import type { SveltePublicationTree } from "./svelte_publication_tree.svelte"; + let { address, rootAddress, @@ -19,7 +20,7 @@ ref: (ref: HTMLElement) => void, } = $props(); - const publicationTree: PublicationTree = getContext('publicationTree'); + const publicationTree: SveltePublicationTree = getContext('publicationTree'); const asciidoctor: Asciidoctor = getContext('asciidoctor'); let leafEvent: Promise = $derived.by(async () => diff --git a/src/lib/components/publications/svelte_publication_tree.svelte.ts b/src/lib/components/publications/svelte_publication_tree.svelte.ts new file mode 100644 index 0000000..cd96118 --- /dev/null +++ b/src/lib/components/publications/svelte_publication_tree.svelte.ts @@ -0,0 +1,56 @@ +import { SvelteSet } from "svelte/reactivity"; +import { PublicationTree } from "../../data_structures/publication_tree.ts"; +import { NDKEvent } from "../../utils/nostrUtils.ts"; +import NDK from "@nostr-dev-kit/ndk"; + +export class SveltePublicationTree { + resolvedAddresses: SvelteSet = new SvelteSet(); + + #publicationTree: PublicationTree; + + constructor(rootEvent: NDKEvent, ndk: NDK) { + this.#publicationTree = new PublicationTree(rootEvent, ndk); + + this.#publicationTree.onNodeResolved(this.#handleNodeResolved); + } + + // #region Proxied Public Methods + + getEvent(address: string): Promise { + return this.#publicationTree.getEvent(address); + } + + getHierarchy(address: string): Promise { + return this.#publicationTree.getHierarchy(address); + } + + setBookmark(address: string) { + this.#publicationTree.setBookmark(address); + } + + // #endregion + + // #region Proxied Async Iterator Methods + + [Symbol.asyncIterator](): AsyncIterator { + return this; + } + + next(): Promise> { + return this.#publicationTree.next(); + } + + previous(): Promise> { + return this.#publicationTree.previous(); + } + + // #endregion + + // #region Private Methods + + #handleNodeResolved(address: string) { + this.resolvedAddresses.add(address); + } + + // #endregion +} \ No newline at end of file diff --git a/src/lib/data_structures/publication_tree.ts b/src/lib/data_structures/publication_tree.ts index 3184b29..7f4c677 100644 --- a/src/lib/data_structures/publication_tree.ts +++ b/src/lib/data_structures/publication_tree.ts @@ -22,14 +22,6 @@ interface PublicationTreeNode { } export class PublicationTree implements AsyncIterable { - // TODO: Abstract this into a `SveltePublicationTree` wrapper class. - /** - * A reactive set of addresses of the events that have been resolved (loaded) into the tree. - * Svelte components can use this set in reactive code blocks to trigger updates when new nodes - * are added to the tree. - */ - resolvedAddresses: SvelteSet = new SvelteSet(); - /** * The root node of the tree. */ @@ -524,7 +516,6 @@ export class PublicationTree implements AsyncIterable { } this.#events.set(address, event); - this.resolvedAddresses.add(address); const childAddresses = event.tags.filter(tag => tag[0] === 'a').map(tag => tag[1]); diff --git a/src/routes/publication/+page.svelte b/src/routes/publication/+page.svelte index 9316069..7defecf 100644 --- a/src/routes/publication/+page.svelte +++ b/src/routes/publication/+page.svelte @@ -3,13 +3,12 @@ import { TextPlaceholder } from "flowbite-svelte"; import type { PageProps } from "./$types"; import { onDestroy, setContext } from "svelte"; - import { PublicationTree } from "$lib/data_structures/publication_tree"; import Processor from "asciidoctor"; import ArticleNav from "$components/util/ArticleNav.svelte"; - + import { SveltePublicationTree } from "$lib/components/publications/svelte_publication_tree.svelte"; let { data }: PageProps = $props(); - const publicationTree = new PublicationTree(data.indexEvent, data.ndk); + const publicationTree = new SveltePublicationTree(data.indexEvent, data.ndk); setContext("publicationTree", publicationTree); setContext("asciidoctor", Processor()); From 34942c50466627811f60214090d5ff6cafafa878 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Mon, 2 Jun 2025 08:51:36 -0500 Subject: [PATCH 022/135] Make adding a node observable --- src/lib/data_structures/publication_tree.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/data_structures/publication_tree.ts b/src/lib/data_structures/publication_tree.ts index 7f4c677..8c57729 100644 --- a/src/lib/data_structures/publication_tree.ts +++ b/src/lib/data_structures/publication_tree.ts @@ -52,6 +52,8 @@ export class PublicationTree implements AsyncIterable { */ #ndk: NDK; + #onNodeAddedCallbacks: Array<(address: string) => void> = []; + #onNodeResolvedCallbacks: Array<(address: string) => void> = []; constructor(rootEvent: NDKEvent, ndk: NDK) { @@ -187,6 +189,10 @@ export class PublicationTree implements AsyncIterable { this.#cursor.tryMoveTo(address); } + onNodeAdded(observer: (address: string) => void) { + this.#onNodeAddedCallbacks.push(observer); + } + /** * Registers an observer function that is invoked whenever a new node is resolved. Nodes are * added lazily. @@ -479,6 +485,8 @@ export class PublicationTree implements AsyncIterable { const lazyNode = new Lazy(() => this.#resolveNode(address, parentNode)); parentNode.children!.push(lazyNode); this.#nodes.set(address, lazyNode); + + this.#onNodeAddedCallbacks.forEach(observer => observer(address)); } /** From 1c47ea226ed55cfb07702b1fe8758d3f0fd1fbc0 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Mon, 2 Jun 2025 08:53:10 -0500 Subject: [PATCH 023/135] Proxy `getChildAddresses` --- .../components/publications/svelte_publication_tree.svelte.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/components/publications/svelte_publication_tree.svelte.ts b/src/lib/components/publications/svelte_publication_tree.svelte.ts index cd96118..b956fd7 100644 --- a/src/lib/components/publications/svelte_publication_tree.svelte.ts +++ b/src/lib/components/publications/svelte_publication_tree.svelte.ts @@ -16,6 +16,10 @@ export class SveltePublicationTree { // #region Proxied Public Methods + getChildAddresses(address: string): Promise> { + return this.#publicationTree.getChildAddresses(address); + } + getEvent(address: string): Promise { return this.#publicationTree.getEvent(address); } From c30484b9bc5bab6add64b921ea5fe7131803fe80 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Mon, 2 Jun 2025 08:53:28 -0500 Subject: [PATCH 024/135] Use `SveltePublicationTree` in ToC class --- src/lib/components/publications/table_of_contents.svelte.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/components/publications/table_of_contents.svelte.ts b/src/lib/components/publications/table_of_contents.svelte.ts index 77154aa..daf190a 100644 --- a/src/lib/components/publications/table_of_contents.svelte.ts +++ b/src/lib/components/publications/table_of_contents.svelte.ts @@ -1,4 +1,4 @@ -import { PublicationTree } from "../../data_structures/publication_tree.ts"; +import { SveltePublicationTree } from "./svelte_publication_tree.svelte.ts"; export interface TocEntry { address: string; @@ -12,7 +12,7 @@ export interface TocEntry { export class TableOfContents { #tocRoot: TocEntry | null = null; #addresses = $state>(new Map()); - #publicationTree: PublicationTree; + #publicationTree: SveltePublicationTree; #pagePathname: string; /** @@ -23,7 +23,7 @@ export class TableOfContents { * `pagePathname` is correct wherever the instance is used. The singleton should be made * made available to the entire component tree under that page. */ - constructor(rootAddress: string, publicationTree: PublicationTree, pagePathname: string) { + constructor(rootAddress: string, publicationTree: SveltePublicationTree, pagePathname: string) { this.#publicationTree = publicationTree; this.#pagePathname = pagePathname; From f438e68726fcee8405f87335a4d7119e8ec6bf10 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Mon, 2 Jun 2025 08:54:19 -0500 Subject: [PATCH 025/135] Remove unused import --- src/lib/data_structures/publication_tree.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/data_structures/publication_tree.ts b/src/lib/data_structures/publication_tree.ts index 8c57729..2682947 100644 --- a/src/lib/data_structures/publication_tree.ts +++ b/src/lib/data_structures/publication_tree.ts @@ -1,7 +1,6 @@ import type NDK from '@nostr-dev-kit/ndk'; import type { NDKEvent } from '@nostr-dev-kit/ndk'; import { Lazy } from './lazy.ts'; -import { SvelteSet } from "svelte/reactivity"; enum PublicationTreeNodeType { Branch, From 1e450dd4b752d3c4ec1e9782e022715bc60eb3d2 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Tue, 3 Jun 2025 08:53:30 -0500 Subject: [PATCH 026/135] Improve abstraction and controllability of tree-walking methods --- src/lib/data_structures/publication_tree.ts | 118 ++++++++++++++------ 1 file changed, 85 insertions(+), 33 deletions(-) diff --git a/src/lib/data_structures/publication_tree.ts b/src/lib/data_structures/publication_tree.ts index 2682947..ea57f05 100644 --- a/src/lib/data_structures/publication_tree.ts +++ b/src/lib/data_structures/publication_tree.ts @@ -12,6 +12,16 @@ enum PublicationTreeNodeStatus { Error, } +export enum TreeTraversalMode { + Leaves, + All, +} + +enum TreeTraversalDirection { + Forward, + Backward, +} + interface PublicationTreeNode { type: PublicationTreeNodeType; status: PublicationTreeNodeStatus; @@ -344,54 +354,80 @@ export class PublicationTree implements AsyncIterable { return this; } - // TODO: Add `previous()` method. - - async next(): Promise> { + /** + * Return the next event in the tree for the given traversal mode. + * + * @param mode The traversal mode. Can be {@link TreeTraversalMode.Leaves} or + * {@link TreeTraversalMode.All}. + * @returns The next event in the tree, or null if the tree is empty. + */ + async next( + mode: TreeTraversalMode = TreeTraversalMode.Leaves + ): Promise> { if (!this.#cursor.target) { if (await this.#cursor.tryMoveTo(this.#bookmark)) { - const event = await this.getEvent(this.#cursor.target!.address); - return { done: false, value: event }; + return this.#yieldEventAtCursor(false); } } - // Based on Raymond Chen's tree traversal algorithm example. - // https://devblogs.microsoft.com/oldnewthing/20200106-00/?p=103300 - do { - if (await this.#cursor.tryMoveToNextSibling()) { - while (await this.#cursor.tryMoveToFirstChild()) { - continue; - } - - if (this.#cursor.target!.status === PublicationTreeNodeStatus.Error) { - return { done: false, value: null }; - } - - const event = await this.getEvent(this.#cursor.target!.address); - return { done: false, value: event }; - } - } while (this.#cursor.tryMoveToParent()); - - if (this.#cursor.target!.status === PublicationTreeNodeStatus.Error) { - return { done: false, value: null }; + if (mode === TreeTraversalMode.Leaves) { + return this.#walkLeaves(TreeTraversalDirection.Forward); } - // If we get to this point, we're at the root node (can't move up any more). - return { done: true, value: null }; + return this.#preorderWalkAll(TreeTraversalDirection.Forward); } - async previous(): Promise> { + /** + * Return the previous event in the tree for the given traversal mode. + * + * @param mode The traversal mode. Can be {@link TreeTraversalMode.Leaves} or + * {@link TreeTraversalMode.All}. + * @returns The previous event in the tree, or null if the tree is empty. + */ + async previous( + mode: TreeTraversalMode = TreeTraversalMode.Leaves + ): Promise> { if (!this.#cursor.target) { if (await this.#cursor.tryMoveTo(this.#bookmark)) { const event = await this.getEvent(this.#cursor.target!.address); return { done: false, value: event }; } } + + if (mode === TreeTraversalMode.Leaves) { + return this.#walkLeaves(TreeTraversalDirection.Backward); + } + + return this.#preorderWalkAll(TreeTraversalDirection.Backward); + } + + async #yieldEventAtCursor(done: boolean): Promise> { + const value = (await this.getEvent(this.#cursor.target!.address)) ?? null; + return { done, value }; + } + + /** + * Walks the tree in the given direction, yielding the event at each leaf. + * + * @param direction The direction to walk the tree. + * @returns The event at the leaf, or null if the tree is empty. + * + * Based on Raymond Chen's tree traversal algorithm example. + * https://devblogs.microsoft.com/oldnewthing/20200106-00/?p=103300 + */ + async #walkLeaves( + direction: TreeTraversalDirection = TreeTraversalDirection.Forward + ): Promise> { + const tryMoveToSibling: () => Promise = direction === TreeTraversalDirection.Forward + ? this.#cursor.tryMoveToNextSibling.bind(this.#cursor) + : this.#cursor.tryMoveToPreviousSibling.bind(this.#cursor); + const tryMoveToChild: () => Promise = direction === TreeTraversalDirection.Forward + ? this.#cursor.tryMoveToFirstChild.bind(this.#cursor) + : this.#cursor.tryMoveToLastChild.bind(this.#cursor); - // Based on Raymond Chen's tree traversal algorithm example. - // https://devblogs.microsoft.com/oldnewthing/20200106-00/?p=103300 do { - if (await this.#cursor.tryMoveToPreviousSibling()) { - while (await this.#cursor.tryMoveToLastChild()) { + if (await tryMoveToSibling()) { + while (await tryMoveToChild()) { continue; } @@ -399,8 +435,7 @@ export class PublicationTree implements AsyncIterable { return { done: false, value: null }; } - const event = await this.getEvent(this.#cursor.target!.address); - return { done: false, value: event }; + return this.#yieldEventAtCursor(false); } } while (this.#cursor.tryMoveToParent()); @@ -408,9 +443,26 @@ export class PublicationTree implements AsyncIterable { return { done: false, value: null }; } + // If we get to this point, we're at the root node (can't move up any more). return { done: true, value: null }; } + /** + * Walks the tree in the given direction, yielding the event at each node. + * + * @param direction The direction to walk the tree. + * @returns The event at the node, or null if the tree is empty. + * + * Based on Raymond Chen's preorder walk algorithm example. + * https://devblogs.microsoft.com/oldnewthing/20200107-00/?p=103304 + */ + async #preorderWalkAll( + direction: TreeTraversalDirection = TreeTraversalDirection.Forward + ): Promise> { + // TODO: Implement this. + return { done: false, value: null }; + } + // #endregion // #region Private Methods From e32354caba3181f875079f44668a3a9df11ee8e3 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Wed, 4 Jun 2025 23:35:36 -0500 Subject: [PATCH 027/135] Add option to walk entire publication tree, not just leaves --- src/lib/data_structures/publication_tree.ts | 39 ++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/lib/data_structures/publication_tree.ts b/src/lib/data_structures/publication_tree.ts index ea57f05..6776626 100644 --- a/src/lib/data_structures/publication_tree.ts +++ b/src/lib/data_structures/publication_tree.ts @@ -370,11 +370,12 @@ export class PublicationTree implements AsyncIterable { } } - if (mode === TreeTraversalMode.Leaves) { + switch (mode) { + case TreeTraversalMode.Leaves: return this.#walkLeaves(TreeTraversalDirection.Forward); + case TreeTraversalMode.All: + return this.#preorderWalkAll(TreeTraversalDirection.Forward); } - - return this.#preorderWalkAll(TreeTraversalDirection.Forward); } /** @@ -394,11 +395,12 @@ export class PublicationTree implements AsyncIterable { } } - if (mode === TreeTraversalMode.Leaves) { + switch (mode) { + case TreeTraversalMode.Leaves: return this.#walkLeaves(TreeTraversalDirection.Backward); + case TreeTraversalMode.All: + return this.#preorderWalkAll(TreeTraversalDirection.Backward); } - - return this.#preorderWalkAll(TreeTraversalDirection.Backward); } async #yieldEventAtCursor(done: boolean): Promise> { @@ -459,8 +461,29 @@ export class PublicationTree implements AsyncIterable { async #preorderWalkAll( direction: TreeTraversalDirection = TreeTraversalDirection.Forward ): Promise> { - // TODO: Implement this. - return { done: false, value: null }; + const tryMoveToSibling: () => Promise = direction === TreeTraversalDirection.Forward + ? this.#cursor.tryMoveToNextSibling.bind(this.#cursor) + : this.#cursor.tryMoveToPreviousSibling.bind(this.#cursor); + const tryMoveToChild: () => Promise = direction === TreeTraversalDirection.Forward + ? this.#cursor.tryMoveToFirstChild.bind(this.#cursor) + : this.#cursor.tryMoveToLastChild.bind(this.#cursor); + + if (await tryMoveToChild()) { + return this.#yieldEventAtCursor(false); + } + + do { + if (await tryMoveToSibling()) { + return this.#yieldEventAtCursor(false); + } + } while (this.#cursor.tryMoveToParent()); + + if (this.#cursor.target!.status === PublicationTreeNodeStatus.Error) { + return { done: false, value: null }; + } + + // If we get to this point, we're at the root node (can't move up any more). + return this.#yieldEventAtCursor(true); } // #endregion From 80c75144898ab38c1a80c8a1306d434f6f71336b Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Wed, 4 Jun 2025 23:46:53 -0500 Subject: [PATCH 028/135] Allow bookmark observers --- src/lib/data_structures/publication_tree.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/lib/data_structures/publication_tree.ts b/src/lib/data_structures/publication_tree.ts index 6776626..1590581 100644 --- a/src/lib/data_structures/publication_tree.ts +++ b/src/lib/data_structures/publication_tree.ts @@ -61,9 +61,11 @@ export class PublicationTree implements AsyncIterable { */ #ndk: NDK; - #onNodeAddedCallbacks: Array<(address: string) => void> = []; + #nodeAddedObservers: Array<(address: string) => void> = []; - #onNodeResolvedCallbacks: Array<(address: string) => void> = []; + #nodeResolvedObservers: Array<(address: string) => void> = []; + + #bookmarkMovedObservers: Array<(address: string) => void> = []; constructor(rootEvent: NDKEvent, ndk: NDK) { const rootAddress = rootEvent.tagAddress(); @@ -195,11 +197,16 @@ export class PublicationTree implements AsyncIterable { */ setBookmark(address: string) { this.#bookmark = address; + this.#bookmarkMovedObservers.forEach(observer => observer(address)); this.#cursor.tryMoveTo(address); } + onBookmarkMoved(observer: (address: string) => void) { + this.#bookmarkMovedObservers.push(observer); + } + onNodeAdded(observer: (address: string) => void) { - this.#onNodeAddedCallbacks.push(observer); + this.#nodeAddedObservers.push(observer); } /** @@ -209,7 +216,7 @@ export class PublicationTree implements AsyncIterable { * @param observer The observer function. */ onNodeResolved(observer: (address: string) => void) { - this.#onNodeResolvedCallbacks.push(observer); + this.#nodeResolvedObservers.push(observer); } // #region Iteration Cursor @@ -560,7 +567,7 @@ export class PublicationTree implements AsyncIterable { parentNode.children!.push(lazyNode); this.#nodes.set(address, lazyNode); - this.#onNodeAddedCallbacks.forEach(observer => observer(address)); + this.#nodeAddedObservers.forEach(observer => observer(address)); } /** @@ -614,7 +621,7 @@ export class PublicationTree implements AsyncIterable { } // TODO: We may need to move this to `#addNode`, so the observer is notified more eagerly. - this.#onNodeResolvedCallbacks.forEach(observer => observer(address)); + this.#nodeResolvedObservers.forEach(observer => observer(address)); return node; } From d3a62c13f6b4716a3a3c971175b5553e2f095b50 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Thu, 5 Jun 2025 08:45:13 -0500 Subject: [PATCH 029/135] Add a `getParent` abstraction to `SveltePublicationTree` --- .../publications/svelte_publication_tree.svelte.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/components/publications/svelte_publication_tree.svelte.ts b/src/lib/components/publications/svelte_publication_tree.svelte.ts index b956fd7..eb8e65f 100644 --- a/src/lib/components/publications/svelte_publication_tree.svelte.ts +++ b/src/lib/components/publications/svelte_publication_tree.svelte.ts @@ -28,6 +28,14 @@ export class SveltePublicationTree { return this.#publicationTree.getHierarchy(address); } + async getParent(address: string): Promise { + const hierarchy = await this.getHierarchy(address); + + // The last element in the hierarchy is the event with the given address, so the parent is the + // second to last element. + return hierarchy.at(-2) ?? null; + } + setBookmark(address: string) { this.#publicationTree.setBookmark(address); } From 7672a103378059ef55ecc3c2d0f5805073cd0802 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Thu, 5 Jun 2025 09:26:30 -0500 Subject: [PATCH 030/135] Allow node resolution subscription on `SveltePublicationTree` --- .../svelte_publication_tree.svelte.ts | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/lib/components/publications/svelte_publication_tree.svelte.ts b/src/lib/components/publications/svelte_publication_tree.svelte.ts index eb8e65f..aac39f2 100644 --- a/src/lib/components/publications/svelte_publication_tree.svelte.ts +++ b/src/lib/components/publications/svelte_publication_tree.svelte.ts @@ -7,6 +7,7 @@ export class SveltePublicationTree { resolvedAddresses: SvelteSet = new SvelteSet(); #publicationTree: PublicationTree; + #nodeResolvedObservers: Array<(address: string) => void> = []; constructor(rootEvent: NDKEvent, ndk: NDK) { this.#publicationTree = new PublicationTree(rootEvent, ndk); @@ -40,6 +41,14 @@ export class SveltePublicationTree { this.#publicationTree.setBookmark(address); } + /** + * Registers an observer function that is invoked whenever a new node is resolved. + * @param observer The observer function. + */ + onNodeResolved(observer: (address: string) => void) { + this.#nodeResolvedObservers.push(observer); + } + // #endregion // #region Proxied Async Iterator Methods @@ -60,8 +69,19 @@ export class SveltePublicationTree { // #region Private Methods - #handleNodeResolved(address: string) { + /** + * Observer function that is invoked whenever a new node is resolved on the publication tree. + * + * @param address The address of the resolved node. + * + * This member is declared as an arrow function to ensure that the correct `this` context is + * used when the function is invoked in this class's constructor. + */ + #handleNodeResolved = (address: string) => { this.resolvedAddresses.add(address); + for (const observer of this.#nodeResolvedObservers) { + observer(address); + } } // #endregion From 534fc23c8cb99d61521261f86aa3454a6e27e702 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Thu, 5 Jun 2025 09:26:49 -0500 Subject: [PATCH 031/135] Update doc comment on `PublicationTree` --- src/lib/data_structures/publication_tree.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/data_structures/publication_tree.ts b/src/lib/data_structures/publication_tree.ts index 1590581..515b866 100644 --- a/src/lib/data_structures/publication_tree.ts +++ b/src/lib/data_structures/publication_tree.ts @@ -154,8 +154,11 @@ export class PublicationTree implements AsyncIterable { /** * Retrieves the addresses of the loaded children, if any, of the node with the given address. + * * @param address The address of the parent node. * @returns An array of addresses of any loaded child nodes. + * + * Note that this method resolves all children of the node. */ async getChildAddresses(address: string): Promise> { const node = await this.#nodes.get(address)?.value(); From ddf8b9006b669a576214cecaf9444137769cd1a7 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Thu, 5 Jun 2025 09:27:41 -0500 Subject: [PATCH 032/135] Update ToC on publication tree node resolution --- .../publications/table_of_contents.svelte.ts | 198 +++++++++++------- 1 file changed, 120 insertions(+), 78 deletions(-) diff --git a/src/lib/components/publications/table_of_contents.svelte.ts b/src/lib/components/publications/table_of_contents.svelte.ts index daf190a..14066e9 100644 --- a/src/lib/components/publications/table_of_contents.svelte.ts +++ b/src/lib/components/publications/table_of_contents.svelte.ts @@ -1,98 +1,52 @@ -import { SveltePublicationTree } from "./svelte_publication_tree.svelte.ts"; +import { SvelteMap } from 'svelte/reactivity'; +import type { SveltePublicationTree } from './svelte_publication_tree.svelte.ts'; +import type { NDKEvent } from '../../utils/nostrUtils.ts'; export interface TocEntry { address: string; title: string; - href: string; + href?: string; + children: TocEntry[]; + parent?: TocEntry; depth: number; - expanded: boolean; - children: Array | null; } export class TableOfContents { - #tocRoot: TocEntry | null = null; - #addresses = $state>(new Map()); + public addressMap: SvelteMap = new SvelteMap(); + + #root: TocEntry | null = null; #publicationTree: SveltePublicationTree; #pagePathname: string; /** - * Constructor for the `TableOfContents` class. The constructed ToC initially contains only the - * root entry. Additional entries must be inserted programmatically using class methods. - * - * The `TableOfContents` class should be instantiated as a page-scoped singleton so that - * `pagePathname` is correct wherever the instance is used. The singleton should be made - * made available to the entire component tree under that page. + * Constructs a `TableOfContents` from a `SveltePublicationTree`. + * + * @param rootAddress The address of the root event. + * @param publicationTree The SveltePublicationTree instance. + * @param pagePathname The current page pathname for href generation. */ constructor(rootAddress: string, publicationTree: SveltePublicationTree, pagePathname: string) { this.#publicationTree = publicationTree; this.#pagePathname = pagePathname; - - this.insertIntoTocFromPublicationTree(rootAddress); + void this.#initRoot(rootAddress); + this.#publicationTree.onNodeResolved((address: string) => { + void this.#handleNodeResolved(address); + }); } - #normalizeHashPath(title: string): string { - // TODO: Confirm this uses good normalization logic to produce unique hrefs within the page. - return title.toLowerCase().replace(/ /g, '-'); - } + // #region Public Methods - get addresses(): Map { - return this.#addresses; + /** + * Returns the root entry of the ToC. + * + * @returns The root entry of the ToC, or `null` if the ToC has not been initialized. + */ + getRootEntry(): TocEntry | null { + return this.#root; } - async insertIntoTocFromPublicationTree(address: string): Promise { - const targetEvent = await this.#publicationTree.getEvent(address); - if (!targetEvent) { - console.warn(`[ToC] Event ${address} not found.`); - // TODO: Determine how to handle this case in the UI. - return; - } - - const hierarchyEvents = await this.#publicationTree.getHierarchy(address); - if (hierarchyEvents.length === 0) { - // This means we are at root. - return; - } - - // Michael J 05 May 2025 - In this loop, we assume that the parent of the current event has - // already been populated into the ToC. As long as the root is set when the component is - // initialized, this code will work fine. - let currentParentTocNode: TocEntry | null = this.#tocRoot; - for (let i = 0; i < hierarchyEvents.length; i++) { - const currentEvent = hierarchyEvents[i]; - const currentAddress = currentEvent.tagAddress(); - - if (this.#addresses.has(currentAddress)) { - continue; - } - - const currentEventChildAddresses = await this.#publicationTree.getChildAddresses(currentAddress); - for (const address of currentEventChildAddresses) { - if (address === null) { - continue; - } - - const childEvent = await this.#publicationTree.getEvent(address); - if (!childEvent) { - console.warn(`[ToC] Event ${address} not found.`); - continue; - } - - currentParentTocNode!.children ??= []; - - const childTocEntry: TocEntry = { - address, - title: childEvent.getMatchingTags('title')[0][1], - href: `${this.#pagePathname}#${this.#normalizeHashPath(childEvent.getMatchingTags('title')[0][1])}`, - depth: i + 1, - expanded: false, - children: null, - }; - currentParentTocNode!.children.push(childTocEntry); - this.#addresses.set(address, childTocEntry); - } - - currentParentTocNode = this.#addresses.get(currentAddress)!; - } + getEntry(address: string): TocEntry | undefined { + return this.addressMap.get(address); } /** @@ -128,10 +82,8 @@ export class TableOfContents { title, href, depth, - expanded: false, - children: null, + children: [], }; - parentEntry.children ??= []; parentEntry.children.push(tocEntry); this.buildTocFromDocument(header, tocEntry, depth + 1); @@ -139,6 +91,10 @@ export class TableOfContents { }); } + // #endregion + + // #region Iterator Methods + /** * Iterates over all ToC entries in depth-first order. */ @@ -157,6 +113,92 @@ export class TableOfContents { } } - yield* traverse(this.#tocRoot); + yield* traverse(this.#root); } + + // #endregion + + // #region Private Methods + + async #initRoot(rootAddress: string) { + const rootEvent = await this.#publicationTree.getEvent(rootAddress); + if (!rootEvent) { + throw new Error(`[ToC] Root event ${rootAddress} not found.`); + } + + this.#root = { + address: rootAddress, + title: this.#getTitle(rootEvent), + children: [], + depth: 0, + }; + + this.addressMap.set(rootAddress, this.#root); + // Handle any other nodes that have already been resolved. + await this.#handleNodeResolved(rootAddress); + } + + async #handleNodeResolved(address: string) { + if (this.addressMap.has(address)) { + return; + } + const event = await this.#publicationTree.getEvent(address); + if (!event) { + return; + } + + const parentEvent = await this.#publicationTree.getParent(address); + const parentAddress = parentEvent?.tagAddress(); + if (!parentAddress) { + // All non-root nodes must have a parent. + if (!this.#root || address !== this.#root.address) { + throw new Error(`[ToC] Parent not found for address ${address}`); + } + return; + } + + const parentEntry = this.addressMap.get(parentAddress); + if (!parentEntry) { + throw new Error(`[ToC] Parent ToC entry not found for address ${address}`); + } + + const entry: TocEntry = { + address, + title: this.#getTitle(event), + children: [], + parent: parentEntry, + depth: parentEntry.depth + 1, + }; + + // Michael J - 05 June 2025 - The `getChildAddresses` method forces node resolution on the + // publication tree. This is acceptable here, because the tree is always resolved top-down. + // Therefore, by the time we handle a node's resolution, its parent and siblings have already + // been resolved. + const childAddresses = await this.#publicationTree.getChildAddresses(parentAddress); + const filteredChildAddresses = childAddresses.filter((a): a is string => !!a); + const insertIndex = filteredChildAddresses.findIndex(a => a === address); + if (insertIndex === -1 || insertIndex > parentEntry.children.length) { + parentEntry.children.push(entry); + } else { + parentEntry.children.splice(insertIndex, 0, entry); + } + + this.addressMap.set(address, entry); + } + + #getTitle(event: NDKEvent | null): string { + if (!event) { + // TODO: What do we want to return in this case? + return '[untitled]'; + } + const titleTag = event.getMatchingTags?.('title')?.[0]?.[1]; + return titleTag || event.tagAddress() || '[untitled]'; + } + + #normalizeHashPath(title: string): string { + // TODO: Confirm this uses good normalization logic to produce unique hrefs within the page. + return title.toLowerCase().replace(/ /g, '-'); + } + + // #endregion } From f635d08982684cbc3b899b29a42116f63a327928 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Thu, 5 Jun 2025 09:32:35 -0500 Subject: [PATCH 033/135] Add doc comment for ToC --- .../components/publications/table_of_contents.svelte.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib/components/publications/table_of_contents.svelte.ts b/src/lib/components/publications/table_of_contents.svelte.ts index 14066e9..c6a26e6 100644 --- a/src/lib/components/publications/table_of_contents.svelte.ts +++ b/src/lib/components/publications/table_of_contents.svelte.ts @@ -11,6 +11,13 @@ export interface TocEntry { depth: number; } +/** + * Maintains a table of contents (ToC) for a `SveltePublicationTree`. Since publication trees are + * conceptually infinite and lazy-loading, the ToC represents only the portion of the tree that has + * been "discovered". The ToC is updated as new nodes are resolved within the publication tree. + * + * @see SveltePublicationTree + */ export class TableOfContents { public addressMap: SvelteMap = new SvelteMap(); From fa6265b346f9eca03f153f4da16f1a51976697f3 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Fri, 6 Jun 2025 09:37:49 -0500 Subject: [PATCH 034/135] Refactor and support tree node resolution via ToC entry closure --- .../publications/table_of_contents.svelte.ts | 128 ++++++++++-------- 1 file changed, 72 insertions(+), 56 deletions(-) diff --git a/src/lib/components/publications/table_of_contents.svelte.ts b/src/lib/components/publications/table_of_contents.svelte.ts index c6a26e6..8665697 100644 --- a/src/lib/components/publications/table_of_contents.svelte.ts +++ b/src/lib/components/publications/table_of_contents.svelte.ts @@ -1,5 +1,5 @@ import { SvelteMap } from 'svelte/reactivity'; -import type { SveltePublicationTree } from './svelte_publication_tree.svelte.ts'; +import { SveltePublicationTree } from './svelte_publication_tree.svelte.ts'; import type { NDKEvent } from '../../utils/nostrUtils.ts'; export interface TocEntry { @@ -9,6 +9,9 @@ export interface TocEntry { children: TocEntry[]; parent?: TocEntry; depth: number; + expanded: boolean; + childrenResolved: boolean; + resolveChildren: () => Promise; } /** @@ -35,10 +38,7 @@ export class TableOfContents { constructor(rootAddress: string, publicationTree: SveltePublicationTree, pagePathname: string) { this.#publicationTree = publicationTree; this.#pagePathname = pagePathname; - void this.#initRoot(rootAddress); - this.#publicationTree.onNodeResolved((address: string) => { - void this.#handleNodeResolved(address); - }); + this.#init(rootAddress); } // #region Public Methods @@ -84,12 +84,16 @@ export class TableOfContents { if (id && title) { const href = `${this.#pagePathname}#${id}`; + // TODO: Check this logic. const tocEntry: TocEntry = { address: parentEntry.address, title, href, depth, children: [], + expanded: false, + childrenResolved: true, + resolveChildren: () => Promise.resolve(), }; parentEntry.children.push(tocEntry); @@ -127,84 +131,96 @@ export class TableOfContents { // #region Private Methods - async #initRoot(rootAddress: string) { + async #init(rootAddress: string) { const rootEvent = await this.#publicationTree.getEvent(rootAddress); if (!rootEvent) { throw new Error(`[ToC] Root event ${rootAddress} not found.`); } - this.#root = { - address: rootAddress, - title: this.#getTitle(rootEvent), - children: [], - depth: 0, - }; + this.#root = await this.#buildTocEntry(rootAddress); this.addressMap.set(rootAddress, this.#root); + + // TODO: Parallelize this. // Handle any other nodes that have already been resolved. - await this.#handleNodeResolved(rootAddress); + this.#publicationTree.resolvedAddresses.forEach(async (address) => { + await this.#buildTocEntryFromResolvedNode(address); + }); + + // Set up an observer to handle progressive resolution of the publication tree. + this.#publicationTree.onNodeResolved(async (address: string) => { + await this.#buildTocEntryFromResolvedNode(address); + }); } - async #handleNodeResolved(address: string) { - if (this.addressMap.has(address)) { - return; - } - const event = await this.#publicationTree.getEvent(address); + #getTitle(event: NDKEvent | null): string { if (!event) { - return; + // TODO: What do we want to return in this case? + return '[untitled]'; } + const titleTag = event.getMatchingTags?.('title')?.[0]?.[1]; + return titleTag || event.tagAddress() || '[untitled]'; + } + + #normalizeHashPath(title: string): string { + // TODO: Confirm this uses good normalization logic to produce unique hrefs within the page. + return title.toLowerCase().replace(/ /g, '-'); + } - const parentEvent = await this.#publicationTree.getParent(address); - const parentAddress = parentEvent?.tagAddress(); - if (!parentAddress) { - // All non-root nodes must have a parent. - if (!this.#root || address !== this.#root.address) { - throw new Error(`[ToC] Parent not found for address ${address}`); + async #buildTocEntry(address: string): Promise { + const resolver = async () => { + if (entry.childrenResolved) { + return; } - return; + + const childAddresses = await this.#publicationTree.getChildAddresses(address); + for (const childAddress of childAddresses) { + if (!childAddress) { + continue; + } + + // Michael J - 05 June 2025 - The `getChildAddresses` method forces node resolution on the + // publication tree. This is acceptable here, because the tree is always resolved + // top-down. Therefore, by the time we handle a node's resolution, its parent and + // siblings have already been resolved. + const childEntry = await this.#buildTocEntry(childAddress); + childEntry.parent = entry; + childEntry.depth = entry.depth + 1; + entry.children.push(childEntry); + this.addressMap.set(childAddress, childEntry); + } + + entry.childrenResolved = true; } - const parentEntry = this.addressMap.get(parentAddress); - if (!parentEntry) { - throw new Error(`[ToC] Parent ToC entry not found for address ${address}`); + const event = await this.#publicationTree.getEvent(address); + if (!event) { + throw new Error(`[ToC] Event ${address} not found.`); } + const depth = (await this.#publicationTree.getHierarchy(address)).length; + const entry: TocEntry = { address, title: this.#getTitle(event), + href: `${this.#pagePathname}#${address}`, children: [], - parent: parentEntry, - depth: parentEntry.depth + 1, + depth, + expanded: false, + childrenResolved: false, + resolveChildren: resolver, }; - - // Michael J - 05 June 2025 - The `getChildAddresses` method forces node resolution on the - // publication tree. This is acceptable here, because the tree is always resolved top-down. - // Therefore, by the time we handle a node's resolution, its parent and siblings have already - // been resolved. - const childAddresses = await this.#publicationTree.getChildAddresses(parentAddress); - const filteredChildAddresses = childAddresses.filter((a): a is string => !!a); - const insertIndex = filteredChildAddresses.findIndex(a => a === address); - if (insertIndex === -1 || insertIndex > parentEntry.children.length) { - parentEntry.children.push(entry); - } else { - parentEntry.children.splice(insertIndex, 0, entry); - } - - this.addressMap.set(address, entry); + + return entry; } - #getTitle(event: NDKEvent | null): string { - if (!event) { - // TODO: What do we want to return in this case? - return '[untitled]'; + async #buildTocEntryFromResolvedNode(address: string) { + if (this.addressMap.has(address)) { + return; } - const titleTag = event.getMatchingTags?.('title')?.[0]?.[1]; - return titleTag || event.tagAddress() || '[untitled]'; - } - #normalizeHashPath(title: string): string { - // TODO: Confirm this uses good normalization logic to produce unique hrefs within the page. - return title.toLowerCase().replace(/ /g, '-'); + const entry = await this.#buildTocEntry(address); + this.addressMap.set(address, entry); } // #endregion From 9a6a494f172c1915e96b9d17b9e7ebb68608a3b7 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Mon, 9 Jun 2025 22:37:11 -0500 Subject: [PATCH 035/135] Fix `NDKEvent` type imports --- src/lib/components/CommentBox.svelte | 3 +-- .../components/publications/svelte_publication_tree.svelte.ts | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib/components/CommentBox.svelte b/src/lib/components/CommentBox.svelte index c46f902..46b2f4b 100644 --- a/src/lib/components/CommentBox.svelte +++ b/src/lib/components/CommentBox.svelte @@ -2,12 +2,11 @@ import { Button, Textarea, Alert } from 'flowbite-svelte'; import { parseBasicmarkup } from '$lib/utils/markup/basicMarkupParser'; import { nip19 } from 'nostr-tools'; - import { getEventHash, signEvent, getUserMetadata, type NostrProfile } from '$lib/utils/nostrUtils'; + import { getEventHash, signEvent, getUserMetadata, type NostrProfile, type NDKEvent } from '$lib/utils/nostrUtils'; import { standardRelays, fallbackRelays } from '$lib/consts'; import { userRelays } from '$lib/stores/relayStore'; import { get } from 'svelte/store'; import { goto } from '$app/navigation'; - import type { NDKEvent } from '$lib/utils/nostrUtils'; import { onMount } from 'svelte'; const props = $props<{ diff --git a/src/lib/components/publications/svelte_publication_tree.svelte.ts b/src/lib/components/publications/svelte_publication_tree.svelte.ts index aac39f2..9969ed7 100644 --- a/src/lib/components/publications/svelte_publication_tree.svelte.ts +++ b/src/lib/components/publications/svelte_publication_tree.svelte.ts @@ -1,7 +1,6 @@ import { SvelteSet } from "svelte/reactivity"; import { PublicationTree } from "../../data_structures/publication_tree.ts"; -import { NDKEvent } from "../../utils/nostrUtils.ts"; -import NDK from "@nostr-dev-kit/ndk"; +import NDK, { NDKEvent } from "@nostr-dev-kit/ndk"; export class SveltePublicationTree { resolvedAddresses: SvelteSet = new SvelteSet(); From 608ce2b8e4392e53aaeca45451282858f0c64fd2 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Mon, 9 Jun 2025 23:20:42 -0500 Subject: [PATCH 036/135] First pass at ToC layout --- .../publications/Publication.svelte | 9 ++- .../publications/TableOfContents.svelte | 65 +++++++++++++++---- src/routes/publication/+page.svelte | 7 ++ 3 files changed, 67 insertions(+), 14 deletions(-) diff --git a/src/lib/components/publications/Publication.svelte b/src/lib/components/publications/Publication.svelte index 7147de4..2511de0 100644 --- a/src/lib/components/publications/Publication.svelte +++ b/src/lib/components/publications/Publication.svelte @@ -19,9 +19,9 @@ import { publicationColumnVisibility } from "$lib/stores"; import BlogHeader from "$components/cards/BlogHeader.svelte"; import Interactions from "$components/util/Interactions.svelte"; - import TocToggle from "$components/util/TocToggle.svelte"; import { pharosInstance } from '$lib/parser'; import type { SveltePublicationTree } from "./svelte_publication_tree.svelte"; + import TableOfContents from "./TableOfContents.svelte"; let { rootAddress, publicationType, indexEvent } = $props<{ rootAddress: string; @@ -160,7 +160,12 @@ {#if publicationType !== "blog" || !isLeaf} - + { + publicationTree.setBookmark(address); + }} + /> {/if} diff --git a/src/lib/components/publications/TableOfContents.svelte b/src/lib/components/publications/TableOfContents.svelte index 891476a..aadfded 100644 --- a/src/lib/components/publications/TableOfContents.svelte +++ b/src/lib/components/publications/TableOfContents.svelte @@ -1,22 +1,63 @@ - - {#each toc as entry} - {entry.title} + + {#each entries as entry} + +

{entry.title}

+ {#if entry.children.length > 0} + + {/if} +
{/each} -
+ diff --git a/src/routes/publication/+page.svelte b/src/routes/publication/+page.svelte index 7defecf..457d896 100644 --- a/src/routes/publication/+page.svelte +++ b/src/routes/publication/+page.svelte @@ -6,11 +6,18 @@ import Processor from "asciidoctor"; import ArticleNav from "$components/util/ArticleNav.svelte"; import { SveltePublicationTree } from "$lib/components/publications/svelte_publication_tree.svelte"; + import { TableOfContents } from "$lib/components/publications/table_of_contents.svelte"; let { data }: PageProps = $props(); const publicationTree = new SveltePublicationTree(data.indexEvent, data.ndk); + const toc = new TableOfContents( + data.indexEvent.tagAddress(), + publicationTree, + data.url?.pathname ?? "", + ); setContext("publicationTree", publicationTree); + setContext("toc", toc); setContext("asciidoctor", Processor()); // Get publication metadata for OpenGraph tags From e3848045224f615f7d7366fc9a53bddf7886f6cb Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Tue, 10 Jun 2025 08:32:46 -0500 Subject: [PATCH 037/135] Add stronger typing to publication layout store --- src/lib/stores.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/lib/stores.ts b/src/lib/stores.ts index e38f0d4..7962e7b 100644 --- a/src/lib/stores.ts +++ b/src/lib/stores.ts @@ -1,5 +1,5 @@ -import { readable, writable } from "svelte/store"; -import { FeedType } from "./consts"; +import { readable, writable } from 'svelte/store'; +import { FeedType } from './consts.ts'; export let idList = writable([]); @@ -7,8 +7,16 @@ export let alexandriaKinds = readable([30040, 30041, 30818]); export let feedType = writable(FeedType.StandardRelays); +export interface PublicationLayoutVisibility { + toc: boolean; + blog: boolean; + main: boolean; + inner: boolean; + discussion: boolean; + editing: boolean; +} -const defaultVisibility = { +const defaultVisibility: PublicationLayoutVisibility = { toc: false, blog: true, main: true, @@ -18,7 +26,8 @@ const defaultVisibility = { }; function createVisibilityStore() { - const { subscribe, set, update } = writable({ ...defaultVisibility }); + const { subscribe, set, update } + = writable({ ...defaultVisibility }); return { subscribe, From d48ddd465a04be3808d239b3b4b30afc23d82b08 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Tue, 10 Jun 2025 08:33:07 -0500 Subject: [PATCH 038/135] Remove unneeded references to Pharos parser --- src/lib/components/publications/Publication.svelte | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/lib/components/publications/Publication.svelte b/src/lib/components/publications/Publication.svelte index 2511de0..5f1a9de 100644 --- a/src/lib/components/publications/Publication.svelte +++ b/src/lib/components/publications/Publication.svelte @@ -19,7 +19,6 @@ import { publicationColumnVisibility } from "$lib/stores"; import BlogHeader from "$components/cards/BlogHeader.svelte"; import Interactions from "$components/util/Interactions.svelte"; - import { pharosInstance } from '$lib/parser'; import type { SveltePublicationTree } from "./svelte_publication_tree.svelte"; import TableOfContents from "./TableOfContents.svelte"; @@ -153,9 +152,6 @@ observer.disconnect(); }; }); - - // Whenever the publication changes, update rootId - let rootId = $derived($pharosInstance.getRootIndexId()); From cd204119f03a6815b3b8d8d8f58115d8bb0cc180 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Tue, 10 Jun 2025 08:52:58 -0500 Subject: [PATCH 039/135] Tidy up code formatting in ArticleNav component --- src/lib/components/util/ArticleNav.svelte | 30 ++++++++++++++++------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/lib/components/util/ArticleNav.svelte b/src/lib/components/util/ArticleNav.svelte index a5b8631..11f804c 100644 --- a/src/lib/components/util/ArticleNav.svelte +++ b/src/lib/components/util/ArticleNav.svelte @@ -113,34 +113,46 @@
{#if shouldShowBack()} {/if} {#if !isLeaf} {#if publicationType === 'blog'} - {:else if !$publicationColumnVisibility.discussion && !$publicationColumnVisibility.toc} - {/if} {/if}
-

{title} by {@render userBadge(pubkey, author)}

+

{title}by {@render userBadge(pubkey, author)}

{#if $publicationColumnVisibility.inner} {/if} {#if publicationType !== 'blog' && !$publicationColumnVisibility.discussion} {/if}
From db4991b229c561e02ef2970d059e5a6a1a9aa909 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Wed, 11 Jun 2025 00:13:49 -0500 Subject: [PATCH 040/135] Update Flowbite Svelte version NB: Upgrading to v1.0.0 or above breaks our current stlying. DO NOT UPGRADE WITHOUT FIXING STYLES. --- deno.lock | 220 ++++++++++++++++++++++++++++++------------------ import_map.json | 2 +- package.json | 2 +- 3 files changed, 140 insertions(+), 84 deletions(-) diff --git a/deno.lock b/deno.lock index 6604928..28f6a0b 100644 --- a/deno.lock +++ b/deno.lock @@ -16,14 +16,15 @@ "npm:@types/d3@^7.4.3": "7.4.3", "npm:@types/he@1.2": "1.2.3", "npm:@types/node@22": "22.13.9", + "npm:@types/qrcode@^1.5.5": "1.5.5", "npm:asciidoctor@3.0": "3.0.4_@asciidoctor+core@3.0.4", "npm:autoprefixer@10": "10.4.20_postcss@8.5.3", + "npm:bech32@2": "2.0.0", "npm:d3@7.9": "7.9.0_d3-selection@3.0.0", "npm:d3@^7.9.0": "7.9.0_d3-selection@3.0.0", "npm:eslint-plugin-svelte@2": "2.46.1_eslint@9.21.0_svelte@5.21.0__acorn@8.14.0_postcss@8.5.3", "npm:flowbite-svelte-icons@2.1": "2.1.1_svelte@5.0.5__acorn@8.14.0_tailwind-merge@3.3.0", - "npm:flowbite-svelte@0": "0.48.4_svelte@5.21.0__acorn@8.14.0", - "npm:flowbite-svelte@0.44": "0.44.24_svelte@4.2.19", + "npm:flowbite-svelte@0.48": "0.48.6_svelte@5.0.5__acorn@8.14.0", "npm:flowbite@2": "2.5.2", "npm:flowbite@2.2": "2.2.1", "npm:he@1.2": "1.2.0", @@ -35,6 +36,7 @@ "npm:postcss@8": "8.5.3", "npm:prettier-plugin-svelte@3": "3.3.3_prettier@3.5.3_svelte@5.21.0__acorn@8.14.0", "npm:prettier@3": "3.5.3", + "npm:qrcode@^1.5.4": "1.5.4", "npm:svelte-check@4": "4.1.4_svelte@5.21.0__acorn@8.14.0_typescript@5.7.3", "npm:svelte@5": "5.21.0_acorn@8.14.0", "npm:svelte@5.0": "5.0.5_acorn@8.14.0", @@ -61,7 +63,7 @@ "integrity": "sha512-x2T9gW42921Zd90juEagtbViPZHNP2MWf0+6rJEkOzW7E9m3TGJtz+Guye9J0gwrpZsTMGCpfYMQy1We3X7osg==", "dependencies": [ "@asciidoctor/core", - "yargs" + "yargs@17.3.1" ] }, "@asciidoctor/core@3.0.4": { @@ -217,14 +219,14 @@ "levn" ] }, - "@floating-ui/core@1.6.9": { - "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", + "@floating-ui/core@1.7.1": { + "integrity": "sha512-azI0DrjMMfIug/ExbBaeDVJXcY0a7EPvPjb2xAJPa4HeimBX+Z18HK8QQR3jb6356SnDDdxx+hinMLcJEDdOjw==", "dependencies": [ "@floating-ui/utils" ] }, - "@floating-ui/dom@1.6.13": { - "integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==", + "@floating-ui/dom@1.7.1": { + "integrity": "sha512-cwsmW/zyw5ltYTUeeYJ60CnQuPqmGwuGVhG9w0PRaRKkAyi38BT5CKrpIbb+jtahSwUl04cWzSx9ZOIxeS6RsQ==", "dependencies": [ "@floating-ui/core", "@floating-ui/utils" @@ -789,12 +791,24 @@ "@types/json-schema@7.0.15": { "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" }, + "@types/node@22.12.0": { + "integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==", + "dependencies": [ + "undici-types" + ] + }, "@types/node@22.13.9": { "integrity": "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==", "dependencies": [ "undici-types" ] }, + "@types/qrcode@1.5.5": { + "integrity": "sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==", + "dependencies": [ + "@types/node@22.12.0" + ] + }, "@types/resolve@1.20.2": { "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==" }, @@ -977,6 +991,9 @@ "balanced-match@1.0.2": { "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "bech32@2.0.0": { + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, "binary-extensions@2.3.0": { "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==" }, @@ -1037,6 +1054,9 @@ "camelcase-css@2.0.1": { "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" }, + "camelcase@5.3.1": { + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, "caniuse-lite@1.0.30001702": { "integrity": "sha512-LoPe/D7zioC0REI5W73PeR1e1MLCipRGq/VkovJnd6Df+QVqT+vT33OXCp8QUd7kA7RZrHWxb1B36OQKI/0gOA==" }, @@ -1088,6 +1108,14 @@ "readdirp@4.1.2" ] }, + "cliui@6.0.0": { + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dependencies": [ + "string-width@4.2.3", + "strip-ansi@6.0.1", + "wrap-ansi@6.2.0" + ] + }, "cliui@7.0.4": { "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dependencies": [ @@ -1099,16 +1127,6 @@ "clsx@2.1.1": { "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" }, - "code-red@1.0.4": { - "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", - "dependencies": [ - "@jridgewell/sourcemap-codec", - "@types/estree", - "acorn@8.14.0", - "estree-walker@3.0.3", - "periscopic" - ] - }, "color-convert@2.0.1": { "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": [ @@ -1151,13 +1169,6 @@ "which" ] }, - "css-tree@2.3.1": { - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dependencies": [ - "mdn-data", - "source-map-js" - ] - }, "cssesc@3.0.0": { "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" }, @@ -1382,6 +1393,9 @@ "ms@2.1.3" ] }, + "decamelize@1.2.0": { + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" + }, "deep-eql@5.0.2": { "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==" }, @@ -1406,6 +1420,9 @@ "didyoumean@1.2.2": { "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, + "dijkstrajs@1.0.3": { + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==" + }, "dlv@1.1.3": { "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, @@ -1586,7 +1603,7 @@ "esutils", "fast-deep-equal", "file-entry-cache", - "find-up", + "find-up@5.0.0", "glob-parent@6.0.2", "ignore", "imurmurhash", @@ -1730,10 +1747,17 @@ "to-regex-range" ] }, + "find-up@4.1.0": { + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": [ + "locate-path@5.0.0", + "path-exists" + ] + }, "find-up@5.0.0": { "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dependencies": [ - "locate-path", + "locate-path@6.0.0", "path-exists" ] }, @@ -1768,24 +1792,14 @@ "tailwind-merge@3.3.0" ] }, - "flowbite-svelte@0.44.24_svelte@4.2.19": { - "integrity": "sha512-kXhJZHGpBVq5RFOoYnzRCEM8eFa81DVp4KjUbBsLJptKhizbSSBJuYApWIQb9pBCS8EBhX4PAX+RsgEDZfEqtA==", - "dependencies": [ - "@floating-ui/dom", - "apexcharts", - "flowbite@2.5.2", - "svelte@4.2.19", - "tailwind-merge@2.5.5" - ] - }, - "flowbite-svelte@0.48.4_svelte@5.21.0__acorn@8.14.0": { - "integrity": "sha512-ivlBxNi2u9+D/nFeHs+vLJU6nYjKq/ooAwdXPP3qIlEnUyIl/hVsH87JtVWwVEgF31NwwQcZeKFkWd8K5DWiGw==", + "flowbite-svelte@0.48.6_svelte@5.0.5__acorn@8.14.0": { + "integrity": "sha512-/PmeR3ipHHvda8vVY9MZlymaRoJsk8VddEeoLzIygfYwJV68ey8gHuQPC1dq9J6NDCTE5+xOPtBiYUtVjCfvZw==", "dependencies": [ "@floating-ui/dom", "apexcharts", "flowbite@3.1.2", - "svelte@5.21.0_acorn@8.14.0", - "tailwind-merge@3.0.2" + "svelte@5.0.5_acorn@8.14.0", + "tailwind-merge@3.3.0" ] }, "flowbite@2.2.1": { @@ -2115,10 +2129,16 @@ "locate-character@3.0.0": { "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==" }, + "locate-path@5.0.0": { + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": [ + "p-locate@4.1.0" + ] + }, "locate-path@6.0.0": { "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dependencies": [ - "p-locate" + "p-locate@5.0.0" ] }, "lodash.castarray@4.4.0": { @@ -2145,9 +2165,6 @@ "math-intrinsics@1.1.0": { "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" }, - "mdn-data@2.0.30": { - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" - }, "merge2@1.4.1": { "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" }, @@ -2285,18 +2302,33 @@ "word-wrap" ] }, + "p-limit@2.3.0": { + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": [ + "p-try" + ] + }, "p-limit@3.1.0": { "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dependencies": [ "yocto-queue" ] }, + "p-locate@4.1.0": { + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": [ + "p-limit@2.3.0" + ] + }, "p-locate@5.0.0": { "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dependencies": [ - "p-limit" + "p-limit@3.1.0" ] }, + "p-try@2.2.0": { + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, "package-json-from-dist@1.0.1": { "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==" }, @@ -2328,14 +2360,6 @@ "pathval@2.0.0": { "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==" }, - "periscopic@3.1.0": { - "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", - "dependencies": [ - "@types/estree", - "estree-walker@3.0.3", - "is-reference@3.0.3" - ] - }, "picocolors@1.1.1": { "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, @@ -2361,6 +2385,9 @@ "playwright-core" ] }, + "pngjs@5.0.0": { + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==" + }, "postcss-import@15.1.0_postcss@8.5.3": { "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", "dependencies": [ @@ -2554,6 +2581,14 @@ "punycode@2.3.1": { "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" }, + "qrcode@1.5.4": { + "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", + "dependencies": [ + "dijkstrajs", + "pngjs", + "yargs@15.4.1" + ] + }, "queue-microtask@1.2.3": { "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, @@ -2575,6 +2610,9 @@ "require-directory@2.1.1": { "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" }, + "require-main-filename@2.0.0": { + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, "resolve-from@4.0.0": { "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" }, @@ -2639,6 +2677,9 @@ "semver@7.7.1": { "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==" }, + "set-blocking@2.0.0": { + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, "set-cookie-parser@2.7.1": { "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==" }, @@ -2758,25 +2799,6 @@ "svelte@5.21.0_acorn@8.14.0" ] }, - "svelte@4.2.19": { - "integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==", - "dependencies": [ - "@ampproject/remapping", - "@jridgewell/sourcemap-codec", - "@jridgewell/trace-mapping", - "@types/estree", - "acorn@8.14.0", - "aria-query", - "axobject-query", - "code-red", - "css-tree", - "estree-walker@3.0.3", - "is-reference@3.0.3", - "locate-character", - "magic-string", - "periscopic" - ] - }, "svelte@5.0.5_acorn@8.14.0": { "integrity": "sha512-f4WBlP5g8W6pEoDfx741lewMlemy+LIGpEqjGPWqnHVP92wqlQXl87U5O5Bi2tkSUrO95OxOoqwU8qlqiHmFKA==", "dependencies": [ @@ -2863,9 +2885,6 @@ "tailwind-merge@2.5.5": { "integrity": "sha512-0LXunzzAZzo0tEPxV3I297ffKZPlKDrjj7NXphC8V5ak9yHC5zRmxnOe2m/Rd/7ivsOMJe3JZ2JVocoDdQTRBA==" }, - "tailwind-merge@3.0.2": { - "integrity": "sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw==" - }, "tailwind-merge@3.3.0": { "integrity": "sha512-fyW/pEfcQSiigd5SNn0nApUOxx0zB/dm6UDU/rEwc2c3sX2smWUNbapHv+QRqLGVp9GWX3THIa7MUGPo+YkDzQ==" }, @@ -3026,7 +3045,7 @@ "vite@5.4.14_@types+node@22.13.9": { "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==", "dependencies": [ - "@types/node", + "@types/node@22.13.9", "esbuild", "fsevents@2.3.3", "postcss", @@ -3042,7 +3061,7 @@ "vitest@3.1.4_@types+node@22.13.9_vite@5.4.14__@types+node@22.13.9": { "integrity": "sha512-Ta56rT7uWxCSJXlBtKgIlApJnT6e6IGmTYxYcmxjJ4ujuZDI59GUQgVDObXXJujOmPDBYXHK1qmaGtneu6TNIQ==", "dependencies": [ - "@types/node", + "@types/node@22.13.9", "@vitest/expect", "@vitest/mocker", "@vitest/pretty-format", @@ -3087,6 +3106,9 @@ "yaeti" ] }, + "which-module@2.0.1": { + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" + }, "which@2.0.2": { "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dependencies": [ @@ -3115,6 +3137,14 @@ "wordwrap@1.0.0": { "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==" }, + "wrap-ansi@6.2.0": { + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dependencies": [ + "ansi-styles@4.3.0", + "string-width@4.2.3", + "strip-ansi@6.0.1" + ] + }, "wrap-ansi@7.0.0": { "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dependencies": [ @@ -3134,6 +3164,9 @@ "wrappy@1.0.2": { "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "y18n@4.0.3": { + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, "y18n@5.0.8": { "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, @@ -3146,19 +3179,42 @@ "yaml@2.7.0": { "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==" }, + "yargs-parser@18.1.3": { + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dependencies": [ + "camelcase", + "decamelize" + ] + }, "yargs-parser@21.1.1": { "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" }, + "yargs@15.4.1": { + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dependencies": [ + "cliui@6.0.0", + "decamelize", + "find-up@4.1.0", + "get-caller-file", + "require-directory", + "require-main-filename", + "set-blocking", + "string-width@4.2.3", + "which-module", + "y18n@4.0.3", + "yargs-parser@18.1.3" + ] + }, "yargs@17.3.1": { "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", "dependencies": [ - "cliui", + "cliui@7.0.4", "escalade", "get-caller-file", "require-directory", "string-width@4.2.3", - "y18n", - "yargs-parser" + "y18n@5.0.8", + "yargs-parser@21.1.1" ] }, "yocto-queue@0.1.0": { @@ -3185,7 +3241,7 @@ "npm:asciidoctor@3.0", "npm:d3@7.9", "npm:flowbite-svelte-icons@2.1", - "npm:flowbite-svelte@0.44", + "npm:flowbite-svelte@0.48", "npm:flowbite@2.2", "npm:he@1.2", "npm:nostr-tools@2.10", @@ -3215,7 +3271,7 @@ "npm:d3@^7.9.0", "npm:eslint-plugin-svelte@2", "npm:flowbite-svelte-icons@2.1", - "npm:flowbite-svelte@0", + "npm:flowbite-svelte@0.48", "npm:flowbite@2", "npm:he@1.2", "npm:highlight.js@^11.11.1", diff --git a/import_map.json b/import_map.json index 4c3af16..af4012c 100644 --- a/import_map.json +++ b/import_map.json @@ -12,7 +12,7 @@ "tailwind-merge": "npm:tailwind-merge@2.5.x", "svelte": "npm:svelte@5.0.x", "flowbite": "npm:flowbite@2.2.x", - "flowbite-svelte": "npm:flowbite-svelte@0.44.x", + "flowbite-svelte": "npm:flowbite-svelte@0.48.x", "flowbite-svelte-icons": "npm:flowbite-svelte-icons@2.1.x", "child_process": "node:child_process" } diff --git a/package.json b/package.json index 787d2e7..3df9454 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "autoprefixer": "10.x", "eslint-plugin-svelte": "2.x", "flowbite": "2.x", - "flowbite-svelte": "0.x", + "flowbite-svelte": "0.48.x", "flowbite-svelte-icons": "2.1.x", "playwright": "^1.50.1", "postcss": "8.x", From 29c06551cf7a51585e0cc68b1dde2d6c6dfd74d7 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Wed, 11 Jun 2025 00:14:34 -0500 Subject: [PATCH 041/135] Remove ToC from page context --- src/routes/publication/+page.svelte | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/routes/publication/+page.svelte b/src/routes/publication/+page.svelte index 457d896..a73d37e 100644 --- a/src/routes/publication/+page.svelte +++ b/src/routes/publication/+page.svelte @@ -10,14 +10,8 @@ let { data }: PageProps = $props(); const publicationTree = new SveltePublicationTree(data.indexEvent, data.ndk); - const toc = new TableOfContents( - data.indexEvent.tagAddress(), - publicationTree, - data.url?.pathname ?? "", - ); setContext("publicationTree", publicationTree); - setContext("toc", toc); setContext("asciidoctor", Processor()); // Get publication metadata for OpenGraph tags From b07914f9635d64e077fee3156f56ecb27d50fc0c Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Wed, 11 Jun 2025 00:16:03 -0500 Subject: [PATCH 042/135] Allow two ToC component variants - A sidebar variant is meant for integration within a sidebar. This is used in the current Publication component. - An accordion variant is intended for standalone use. --- .../publications/Publication.svelte | 30 ++++++--- .../publications/TableOfContents.svelte | 65 ++++++++++++++----- 2 files changed, 69 insertions(+), 26 deletions(-) diff --git a/src/lib/components/publications/Publication.svelte b/src/lib/components/publications/Publication.svelte index 5f1a9de..ec4ec10 100644 --- a/src/lib/components/publications/Publication.svelte +++ b/src/lib/components/publications/Publication.svelte @@ -7,6 +7,7 @@ SidebarGroup, SidebarWrapper, Heading, + CloseButton, } from "flowbite-svelte"; import { getContext, onDestroy, onMount } from "svelte"; import { @@ -90,6 +91,10 @@ return currentBlog !== null && $publicationColumnVisibility.inner; } + function closeToc() { + publicationColumnVisibility.update((v) => ({ ...v, toc: false })); + } + function closeDiscussion() { publicationColumnVisibility.update((v) => ({ ...v, discussion: false })); } @@ -155,13 +160,20 @@ -{#if publicationType !== "blog" || !isLeaf} - { - publicationTree.setBookmark(address); - }} - /> +{#if publicationType !== 'blog' || !isLeaf} + {#if $publicationColumnVisibility.toc} + + + { + publicationTree.setBookmark(address); + }} + /> + + {/if} {/if} @@ -205,9 +217,7 @@ {#if $publicationColumnVisibility.blog}
- import type { TableOfContents, TocEntry } from '$lib/components/publications/table_of_contents.svelte'; + import { TableOfContents, type TocEntry } from '$lib/components/publications/table_of_contents.svelte'; import { getContext } from 'svelte'; - import { Accordion, AccordionItem, Card } from 'flowbite-svelte'; + import { Accordion, AccordionItem, Card, SidebarDropdownWrapper, SidebarGroup, SidebarItem } from 'flowbite-svelte'; import Self from './TableOfContents.svelte'; + import type { SveltePublicationTree } from './svelte_publication_tree.svelte'; + import { page } from '$app/state'; - let { + export type TocDisplayMode = 'accordion' | 'sidebar'; + + let { + displayMode = 'accordion', + rootAddress, depth, onSectionFocused, } = $props<{ + displayMode?: TocDisplayMode; + rootAddress: string; depth: number; onSectionFocused?: (address: string) => void; }>(); - let toc = getContext('toc') as TableOfContents; + let publicationTree = getContext('publicationTree') as SveltePublicationTree; + let toc = new TableOfContents(rootAddress, publicationTree, page.url.pathname ?? ""); - let entries = $derived( - Array + let entries = $derived.by(() => { + console.debug("[ToC] Filtering entries for depth", depth); + const entries = Array .from(toc.addressMap.values()) - .filter((entry) => entry.depth === depth) - ); + .filter((entry) => entry.depth === depth); + console.debug("[ToC] Filtered entries", entries.map((e) => e.title)); + return entries; + }); // Track the currently visible section for highlighting let currentSection = $state(null); @@ -51,13 +63,34 @@ } - - {#each entries as entry} - -

{entry.title}

+{#if displayMode === 'accordion'} + + {#each entries as entry} + + {#snippet header()} + {entry.title} + {/snippet} + {#if entry.children.length > 0} + + {/if} + + {/each} + +{:else} + + {#each entries as entry} {#if entry.children.length > 0} - + + + + {:else} + {/if} -
- {/each} -
+ {/each} + +{/if} \ No newline at end of file From 052392d7f0d09b3da76e9a22f8b3cb7f20f186d4 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Wed, 11 Jun 2025 00:36:17 -0500 Subject: [PATCH 043/135] Add action bindings on ToC component elements --- .../publications/TableOfContents.svelte | 74 +++++++++++-------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/src/lib/components/publications/TableOfContents.svelte b/src/lib/components/publications/TableOfContents.svelte index 8356509..9a1f252 100644 --- a/src/lib/components/publications/TableOfContents.svelte +++ b/src/lib/components/publications/TableOfContents.svelte @@ -23,50 +23,49 @@ let publicationTree = getContext('publicationTree') as SveltePublicationTree; let toc = new TableOfContents(rootAddress, publicationTree, page.url.pathname ?? ""); - let entries = $derived.by(() => { - console.debug("[ToC] Filtering entries for depth", depth); - const entries = Array + let entries = $derived( + Array .from(toc.addressMap.values()) - .filter((entry) => entry.depth === depth); - console.debug("[ToC] Filtered entries", entries.map((e) => e.title)); - return entries; - }); + .filter((entry) => entry.depth === depth) + ); - // Track the currently visible section for highlighting - let currentSection = $state(null); + function getEntryExpanded(address: string) { + return toc.getEntry(address)?.expanded; + } - // Handle section visibility changes from the IntersectionObserver - function handleSectionVisibility(address: string, isVisible: boolean) { - if (isVisible) { - currentSection = address; + function setEntryExpanded(address: string, expanded: boolean = false) { + const entry = toc.getEntry(address); + if (!entry) { + return; } - } - // Toggle expansion of a ToC entry - async function toggleExpansion(entry: TocEntry) { - // Update the current section in the ToC - const tocEntry = toc.getEntry(entry.address); - if (tocEntry) { - // Ensure the parent sections are expanded - let parent = tocEntry.parent; - while (parent) { - parent.expanded = true; - parent = parent.parent; - } + entry.expanded = expanded; + if (entry.childrenResolved) { + return; } - entry.expanded = !entry.expanded; - if (entry.expanded && !entry.childrenResolved) { - onSectionFocused?.(entry.address); - await entry.resolveChildren(); + if (expanded) { + entry.resolveChildren(); } } + + function handleEntryClick(address: string, expanded: boolean = false) { + setEntryExpanded(address, expanded); + onSectionFocused?.(address); + } + {#if displayMode === 'accordion'} {#each entries as entry} - + {@const address = entry.address} + getEntryExpanded(address), + (open) => setEntryExpanded(address, open) + } + > {#snippet header()} {entry.title} {/snippet} @@ -79,8 +78,15 @@ {:else} {#each entries as entry} + {@const address = entry.address} {#if entry.children.length > 0} - + getEntryExpanded(address), + (open) => setEntryExpanded(address, open) + } + > {:else} - + + handleEntryClick(address, !getEntryExpanded(address))} + /> {/if} {/each} From 7219e68ca3bb5b829f3a5b5b48967ed04045be57 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Wed, 11 Jun 2025 07:53:43 -0500 Subject: [PATCH 044/135] Make accordion non-flush --- src/lib/components/publications/TableOfContents.svelte | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/lib/components/publications/TableOfContents.svelte b/src/lib/components/publications/TableOfContents.svelte index 9a1f252..9813d57 100644 --- a/src/lib/components/publications/TableOfContents.svelte +++ b/src/lib/components/publications/TableOfContents.svelte @@ -57,7 +57,7 @@ {#if displayMode === 'accordion'} - + {#each entries as entry} {@const address = entry.address} {entry.title} {/snippet} {#if entry.children.length > 0} - + {/if} {/each} From 2d6d38b3b38e2046d9a11f1e83a2a876edb455a8 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Wed, 11 Jun 2025 23:07:12 -0500 Subject: [PATCH 045/135] Fix data flow between publication tree and ToC --- src/lib/components/publications/TableOfContents.svelte | 8 +------- .../components/publications/table_of_contents.svelte.ts | 4 ++-- src/lib/data_structures/publication_tree.ts | 1 - 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/lib/components/publications/TableOfContents.svelte b/src/lib/components/publications/TableOfContents.svelte index 9813d57..50296d2 100644 --- a/src/lib/components/publications/TableOfContents.svelte +++ b/src/lib/components/publications/TableOfContents.svelte @@ -40,13 +40,7 @@ } entry.expanded = expanded; - if (entry.childrenResolved) { - return; - } - - if (expanded) { - entry.resolveChildren(); - } + entry.resolveChildren(); } function handleEntryClick(address: string, expanded: boolean = false) { diff --git a/src/lib/components/publications/table_of_contents.svelte.ts b/src/lib/components/publications/table_of_contents.svelte.ts index 8665697..63d3b9c 100644 --- a/src/lib/components/publications/table_of_contents.svelte.ts +++ b/src/lib/components/publications/table_of_contents.svelte.ts @@ -148,8 +148,8 @@ export class TableOfContents { }); // Set up an observer to handle progressive resolution of the publication tree. - this.#publicationTree.onNodeResolved(async (address: string) => { - await this.#buildTocEntryFromResolvedNode(address); + this.#publicationTree.onNodeResolved((address: string) => { + this.#buildTocEntryFromResolvedNode(address); }); } diff --git a/src/lib/data_structures/publication_tree.ts b/src/lib/data_structures/publication_tree.ts index 515b866..a7aece6 100644 --- a/src/lib/data_structures/publication_tree.ts +++ b/src/lib/data_structures/publication_tree.ts @@ -623,7 +623,6 @@ export class PublicationTree implements AsyncIterable { this.addEventByAddress(address, event); } - // TODO: We may need to move this to `#addNode`, so the observer is notified more eagerly. this.#nodeResolvedObservers.forEach(observer => observer(address)); return node; From c235646ffeedfddbe75ffb4b4204d420ec6f8399 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 14 Jun 2025 14:10:42 -0500 Subject: [PATCH 046/135] Ensure ToC addresses update correctly Closing and reopening the ToC component shows updates, but it is not responsive to clicks. This will be fixed in a future commit. --- .../publications/TableOfContents.svelte | 32 ++++++++++++------- .../publications/table_of_contents.svelte.ts | 17 +++++++--- src/lib/data_structures/publication_tree.ts | 2 +- src/routes/publication/+page.svelte | 3 ++ 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/lib/components/publications/TableOfContents.svelte b/src/lib/components/publications/TableOfContents.svelte index 50296d2..0f66e4e 100644 --- a/src/lib/components/publications/TableOfContents.svelte +++ b/src/lib/components/publications/TableOfContents.svelte @@ -1,16 +1,13 @@ + {#if displayMode === 'accordion'} {#each entries as entry} @@ -79,7 +75,14 @@ {#each entries as entry} {@const address = entry.address} {@const expanded = toc.expandedMap.get(address) ?? false} - {#if entry.children.length > 0} + {@const isLeaf = toc.leaves.has(address)} + {#if isLeaf} + + onSectionFocused?.(address)} + /> + {:else} {@const childDepth = depth + 1} - {:else} - - handleEntryClick(address, !expanded)} - /> {/if} {/each} diff --git a/src/lib/components/publications/table_of_contents.svelte.ts b/src/lib/components/publications/table_of_contents.svelte.ts index a566f52..95fa0e2 100644 --- a/src/lib/components/publications/table_of_contents.svelte.ts +++ b/src/lib/components/publications/table_of_contents.svelte.ts @@ -1,4 +1,4 @@ -import { SvelteMap } from 'svelte/reactivity'; +import { SvelteMap, SvelteSet } from 'svelte/reactivity'; import { SveltePublicationTree } from './svelte_publication_tree.svelte.ts'; import type { NDKEvent } from '../../utils/nostrUtils.ts'; import { indexKind } from '../../consts.ts'; @@ -24,6 +24,7 @@ export interface TocEntry { export class TableOfContents { public addressMap: SvelteMap = new SvelteMap(); public expandedMap: SvelteMap = new SvelteMap(); + public leaves: SvelteSet = new SvelteSet(); #root: TocEntry | null = null; #publicationTree: SveltePublicationTree; @@ -186,6 +187,13 @@ export class TableOfContents { continue; } + // Michael J - 16 June 2025 - This duplicates logic in the outer function, but is necessary + // here so that we can determine whether to render an entry as a leaf before it is fully + // resolved. + if (childAddress.split(':')[0] !== indexKind.toString()) { + this.leaves.add(childAddress); + } + // Michael J - 05 June 2025 - The `getChildAddresses` method forces node resolution on the // publication tree. This is acceptable here, because the tree is always resolved // top-down. Therefore, by the time we handle a node's resolution, its parent and @@ -217,6 +225,14 @@ export class TableOfContents { resolveChildren: resolver, }; this.expandedMap.set(address, false); + + // Michael J - 16 June 2025 - We determine whether to add a leaf both here and in the inner + // resolver function. The resolver function is called when entries are resolved by expanding + // a ToC entry, and we'll reach the block below when entries are resolved by the publication + // tree. + if (event.kind !== indexKind) { + this.leaves.add(address); + } return entry; } From 7b441dc0a580ac16c703ec8eda14cc699d762006 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Fri, 27 Jun 2025 15:55:32 -0500 Subject: [PATCH 053/135] Adjust some spacing --- src/routes/publication/+page.svelte | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/publication/+page.svelte b/src/routes/publication/+page.svelte index 34ec929..4348871 100644 --- a/src/routes/publication/+page.svelte +++ b/src/routes/publication/+page.svelte @@ -20,8 +20,8 @@ // Get publication metadata for OpenGraph tags let title = $derived( data.indexEvent?.getMatchingTags("title")[0]?.[1] || - data.parser?.getIndexTitle(data.parser?.getRootIndexId()) || - "Alexandria Publication", + data.parser?.getIndexTitle(data.parser?.getRootIndexId()) || + "Alexandria Publication", ); let currentUrl = data.url?.href ?? ""; @@ -33,7 +33,7 @@ ); let summary = $derived( data.indexEvent?.getMatchingTags("summary")[0]?.[1] || - "Alexandria is a digital library, utilizing Nostr events for curated publications and wiki pages.", + "Alexandria is a digital library, utilizing Nostr events for curated publications and wiki pages.", ); onDestroy(() => data.parser.reset()); From 166eb237c172cbc0eb959619a28a4f43249d45c8 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 28 Jun 2025 17:42:11 -0500 Subject: [PATCH 054/135] Update SvelteKit --- deno.lock | 517 ++++++++++++++++++++++++++++++++++++++++----------- package.json | 2 +- 2 files changed, 406 insertions(+), 113 deletions(-) diff --git a/deno.lock b/deno.lock index 28f6a0b..0a222bd 100644 --- a/deno.lock +++ b/deno.lock @@ -1,5 +1,5 @@ { - "version": "4", + "version": "5", "specifiers": { "npm:@nostr-dev-kit/ndk-cache-dexie@2.5": "2.5.13_typescript@5.7.3", "npm:@nostr-dev-kit/ndk@2.11": "2.11.2_typescript@5.7.3", @@ -10,6 +10,7 @@ "npm:@sveltejs/adapter-static@3": "3.0.8_@sveltejs+kit@2.17.3__@sveltejs+vite-plugin-svelte@4.0.4___svelte@5.21.0____acorn@8.14.0___vite@5.4.14____@types+node@22.13.9___@types+node@22.13.9__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", "npm:@sveltejs/kit@2": "2.17.3_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", "npm:@sveltejs/kit@^2.16.0": "2.17.3_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", + "npm:@sveltejs/kit@^2.22.2": "2.22.2_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_acorn@8.15.0_@types+node@22.13.9", "npm:@sveltejs/vite-plugin-svelte@4": "4.0.4_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", "npm:@tailwindcss/forms@0.5": "0.5.10_tailwindcss@3.4.17__postcss@8.5.3", "npm:@tailwindcss/typography@0.5": "0.5.16_tailwindcss@3.4.17__postcss@8.5.3", @@ -22,7 +23,7 @@ "npm:bech32@2": "2.0.0", "npm:d3@7.9": "7.9.0_d3-selection@3.0.0", "npm:d3@^7.9.0": "7.9.0_d3-selection@3.0.0", - "npm:eslint-plugin-svelte@2": "2.46.1_eslint@9.21.0_svelte@5.21.0__acorn@8.14.0_postcss@8.5.3", + "npm:eslint-plugin-svelte@2": "2.46.1_eslint@9.21.0_svelte@5.21.0__acorn@8.14.0_postcss@8.5.3_svelte@5.0.5__acorn@8.14.0", "npm:flowbite-svelte-icons@2.1": "2.1.1_svelte@5.0.5__acorn@8.14.0_tailwind-merge@3.3.0", "npm:flowbite-svelte@0.48": "0.48.6_svelte@5.0.5__acorn@8.14.0", "npm:flowbite@2": "2.5.2", @@ -64,7 +65,8 @@ "dependencies": [ "@asciidoctor/core", "yargs@17.3.1" - ] + ], + "bin": true }, "@asciidoctor/core@3.0.4": { "integrity": "sha512-41SDMi7iRRBViPe0L6VWFTe55bv6HEOJeRqMj5+E5wB1YPdUPuTucL4UAESPZM6OWmn4t/5qM5LusXomFUVwVQ==", @@ -90,7 +92,8 @@ "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==", "dependencies": [ "@babel/types" - ] + ], + "bin": true }, "@babel/types@7.26.9": { "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==", @@ -100,73 +103,119 @@ ] }, "@esbuild/aix-ppc64@0.21.5": { - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==" + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "os": ["aix"], + "cpu": ["ppc64"] }, "@esbuild/android-arm64@0.21.5": { - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==" + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "os": ["android"], + "cpu": ["arm64"] }, "@esbuild/android-arm@0.21.5": { - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==" + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "os": ["android"], + "cpu": ["arm"] }, "@esbuild/android-x64@0.21.5": { - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==" + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "os": ["android"], + "cpu": ["x64"] }, "@esbuild/darwin-arm64@0.21.5": { - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==" + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "os": ["darwin"], + "cpu": ["arm64"] }, "@esbuild/darwin-x64@0.21.5": { - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==" + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "os": ["darwin"], + "cpu": ["x64"] }, "@esbuild/freebsd-arm64@0.21.5": { - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==" + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "os": ["freebsd"], + "cpu": ["arm64"] }, "@esbuild/freebsd-x64@0.21.5": { - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==" + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "os": ["freebsd"], + "cpu": ["x64"] }, "@esbuild/linux-arm64@0.21.5": { - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==" + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "os": ["linux"], + "cpu": ["arm64"] }, "@esbuild/linux-arm@0.21.5": { - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==" + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "os": ["linux"], + "cpu": ["arm"] }, "@esbuild/linux-ia32@0.21.5": { - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==" + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "os": ["linux"], + "cpu": ["ia32"] }, "@esbuild/linux-loong64@0.21.5": { - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==" + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "os": ["linux"], + "cpu": ["loong64"] }, "@esbuild/linux-mips64el@0.21.5": { - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==" + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "os": ["linux"], + "cpu": ["mips64el"] }, "@esbuild/linux-ppc64@0.21.5": { - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==" + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "os": ["linux"], + "cpu": ["ppc64"] }, "@esbuild/linux-riscv64@0.21.5": { - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==" + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "os": ["linux"], + "cpu": ["riscv64"] }, "@esbuild/linux-s390x@0.21.5": { - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==" + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "os": ["linux"], + "cpu": ["s390x"] }, "@esbuild/linux-x64@0.21.5": { - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==" + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "os": ["linux"], + "cpu": ["x64"] }, "@esbuild/netbsd-x64@0.21.5": { - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==" + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "os": ["netbsd"], + "cpu": ["x64"] }, "@esbuild/openbsd-x64@0.21.5": { - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==" + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "os": ["openbsd"], + "cpu": ["x64"] }, "@esbuild/sunos-x64@0.21.5": { - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==" + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "os": ["sunos"], + "cpu": ["x64"] }, "@esbuild/win32-arm64@0.21.5": { - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==" + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "os": ["win32"], + "cpu": ["arm64"] }, "@esbuild/win32-ia32@0.21.5": { - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==" + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "os": ["win32"], + "cpu": ["ia32"] }, "@esbuild/win32-x64@0.21.5": { - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==" + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "os": ["win32"], + "cpu": ["x64"] }, "@eslint-community/eslint-utils@4.4.1_eslint@9.21.0": { "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", @@ -388,7 +437,8 @@ "integrity": "sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==", "dependencies": [ "playwright" - ] + ], + "bin": true }, "@polka/url@1.0.0-next.28": { "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==" @@ -407,6 +457,9 @@ "magic-string", "picomatch@4.0.2", "rollup" + ], + "optionalPeers": [ + "rollup" ] }, "@rollup/plugin-json@6.1.0_rollup@4.34.9": { @@ -414,12 +467,15 @@ "dependencies": [ "@rollup/pluginutils@5.1.4_rollup@4.34.9", "rollup" + ], + "optionalPeers": [ + "rollup" ] }, "@rollup/plugin-node-resolve@15.3.1": { "integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==", "dependencies": [ - "@rollup/pluginutils@5.1.4", + "@rollup/pluginutils@5.1.4_rollup@4.34.9", "@types/resolve", "deepmerge", "is-module", @@ -435,6 +491,9 @@ "is-module", "resolve", "rollup" + ], + "optionalPeers": [ + "rollup" ] }, "@rollup/pluginutils@5.1.4": { @@ -443,6 +502,9 @@ "@types/estree", "estree-walker@2.0.2", "picomatch@4.0.2" + ], + "optionalPeers": [ + "rollup" ] }, "@rollup/pluginutils@5.1.4_rollup@4.34.9": { @@ -452,64 +514,105 @@ "estree-walker@2.0.2", "picomatch@4.0.2", "rollup" + ], + "optionalPeers": [ + "rollup" ] }, "@rollup/rollup-android-arm-eabi@4.34.9": { - "integrity": "sha512-qZdlImWXur0CFakn2BJ2znJOdqYZKiedEPEVNTBrpfPjc/YuTGcaYZcdmNFTkUj3DU0ZM/AElcM8Ybww3xVLzA==" + "integrity": "sha512-qZdlImWXur0CFakn2BJ2znJOdqYZKiedEPEVNTBrpfPjc/YuTGcaYZcdmNFTkUj3DU0ZM/AElcM8Ybww3xVLzA==", + "os": ["android"], + "cpu": ["arm"] }, "@rollup/rollup-android-arm64@4.34.9": { - "integrity": "sha512-4KW7P53h6HtJf5Y608T1ISKvNIYLWRKMvfnG0c44M6In4DQVU58HZFEVhWINDZKp7FZps98G3gxwC1sb0wXUUg==" + "integrity": "sha512-4KW7P53h6HtJf5Y608T1ISKvNIYLWRKMvfnG0c44M6In4DQVU58HZFEVhWINDZKp7FZps98G3gxwC1sb0wXUUg==", + "os": ["android"], + "cpu": ["arm64"] }, "@rollup/rollup-darwin-arm64@4.34.9": { - "integrity": "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==" + "integrity": "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==", + "os": ["darwin"], + "cpu": ["arm64"] }, "@rollup/rollup-darwin-x64@4.34.9": { - "integrity": "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==" + "integrity": "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==", + "os": ["darwin"], + "cpu": ["x64"] }, "@rollup/rollup-freebsd-arm64@4.34.9": { - "integrity": "sha512-2lzjQPJbN5UnHm7bHIUKFMulGTQwdvOkouJDpPysJS+QFBGDJqcfh+CxxtG23Ik/9tEvnebQiylYoazFMAgrYw==" + "integrity": "sha512-2lzjQPJbN5UnHm7bHIUKFMulGTQwdvOkouJDpPysJS+QFBGDJqcfh+CxxtG23Ik/9tEvnebQiylYoazFMAgrYw==", + "os": ["freebsd"], + "cpu": ["arm64"] }, "@rollup/rollup-freebsd-x64@4.34.9": { - "integrity": "sha512-SLl0hi2Ah2H7xQYd6Qaiu01kFPzQ+hqvdYSoOtHYg/zCIFs6t8sV95kaoqjzjFwuYQLtOI0RZre/Ke0nPaQV+g==" + "integrity": "sha512-SLl0hi2Ah2H7xQYd6Qaiu01kFPzQ+hqvdYSoOtHYg/zCIFs6t8sV95kaoqjzjFwuYQLtOI0RZre/Ke0nPaQV+g==", + "os": ["freebsd"], + "cpu": ["x64"] }, "@rollup/rollup-linux-arm-gnueabihf@4.34.9": { - "integrity": "sha512-88I+D3TeKItrw+Y/2ud4Tw0+3CxQ2kLgu3QvrogZ0OfkmX/DEppehus7L3TS2Q4lpB+hYyxhkQiYPJ6Mf5/dPg==" + "integrity": "sha512-88I+D3TeKItrw+Y/2ud4Tw0+3CxQ2kLgu3QvrogZ0OfkmX/DEppehus7L3TS2Q4lpB+hYyxhkQiYPJ6Mf5/dPg==", + "os": ["linux"], + "cpu": ["arm"] }, "@rollup/rollup-linux-arm-musleabihf@4.34.9": { - "integrity": "sha512-3qyfWljSFHi9zH0KgtEPG4cBXHDFhwD8kwg6xLfHQ0IWuH9crp005GfoUUh/6w9/FWGBwEHg3lxK1iHRN1MFlA==" + "integrity": "sha512-3qyfWljSFHi9zH0KgtEPG4cBXHDFhwD8kwg6xLfHQ0IWuH9crp005GfoUUh/6w9/FWGBwEHg3lxK1iHRN1MFlA==", + "os": ["linux"], + "cpu": ["arm"] }, "@rollup/rollup-linux-arm64-gnu@4.34.9": { - "integrity": "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==" + "integrity": "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==", + "os": ["linux"], + "cpu": ["arm64"] }, "@rollup/rollup-linux-arm64-musl@4.34.9": { - "integrity": "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==" + "integrity": "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==", + "os": ["linux"], + "cpu": ["arm64"] }, "@rollup/rollup-linux-loongarch64-gnu@4.34.9": { - "integrity": "sha512-dRAgTfDsn0TE0HI6cmo13hemKpVHOEyeciGtvlBTkpx/F65kTvShtY/EVyZEIfxFkV5JJTuQ9tP5HGBS0hfxIg==" + "integrity": "sha512-dRAgTfDsn0TE0HI6cmo13hemKpVHOEyeciGtvlBTkpx/F65kTvShtY/EVyZEIfxFkV5JJTuQ9tP5HGBS0hfxIg==", + "os": ["linux"], + "cpu": ["loong64"] }, "@rollup/rollup-linux-powerpc64le-gnu@4.34.9": { - "integrity": "sha512-PHcNOAEhkoMSQtMf+rJofwisZqaU8iQ8EaSps58f5HYll9EAY5BSErCZ8qBDMVbq88h4UxaNPlbrKqfWP8RfJA==" + "integrity": "sha512-PHcNOAEhkoMSQtMf+rJofwisZqaU8iQ8EaSps58f5HYll9EAY5BSErCZ8qBDMVbq88h4UxaNPlbrKqfWP8RfJA==", + "os": ["linux"], + "cpu": ["ppc64"] }, "@rollup/rollup-linux-riscv64-gnu@4.34.9": { - "integrity": "sha512-Z2i0Uy5G96KBYKjeQFKbbsB54xFOL5/y1P5wNBsbXB8yE+At3oh0DVMjQVzCJRJSfReiB2tX8T6HUFZ2k8iaKg==" + "integrity": "sha512-Z2i0Uy5G96KBYKjeQFKbbsB54xFOL5/y1P5wNBsbXB8yE+At3oh0DVMjQVzCJRJSfReiB2tX8T6HUFZ2k8iaKg==", + "os": ["linux"], + "cpu": ["riscv64"] }, "@rollup/rollup-linux-s390x-gnu@4.34.9": { - "integrity": "sha512-U+5SwTMoeYXoDzJX5dhDTxRltSrIax8KWwfaaYcynuJw8mT33W7oOgz0a+AaXtGuvhzTr2tVKh5UO8GVANTxyQ==" + "integrity": "sha512-U+5SwTMoeYXoDzJX5dhDTxRltSrIax8KWwfaaYcynuJw8mT33W7oOgz0a+AaXtGuvhzTr2tVKh5UO8GVANTxyQ==", + "os": ["linux"], + "cpu": ["s390x"] }, "@rollup/rollup-linux-x64-gnu@4.34.9": { - "integrity": "sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==" + "integrity": "sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==", + "os": ["linux"], + "cpu": ["x64"] }, "@rollup/rollup-linux-x64-musl@4.34.9": { - "integrity": "sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==" + "integrity": "sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==", + "os": ["linux"], + "cpu": ["x64"] }, "@rollup/rollup-win32-arm64-msvc@4.34.9": { - "integrity": "sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==" + "integrity": "sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==", + "os": ["win32"], + "cpu": ["arm64"] }, "@rollup/rollup-win32-ia32-msvc@4.34.9": { - "integrity": "sha512-KB48mPtaoHy1AwDNkAJfHXvHp24H0ryZog28spEs0V48l3H1fr4i37tiyHsgKZJnCmvxsbATdZGBpbmxTE3a9w==" + "integrity": "sha512-KB48mPtaoHy1AwDNkAJfHXvHp24H0ryZog28spEs0V48l3H1fr4i37tiyHsgKZJnCmvxsbATdZGBpbmxTE3a9w==", + "os": ["win32"], + "cpu": ["ia32"] }, "@rollup/rollup-win32-x64-msvc@4.34.9": { - "integrity": "sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==" + "integrity": "sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==", + "os": ["win32"], + "cpu": ["x64"] }, "@scure/base@1.1.1": { "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==" @@ -535,10 +638,16 @@ "@sindresorhus/is@4.6.0": { "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==" }, + "@sveltejs/acorn-typescript@1.0.5_acorn@8.15.0": { + "integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==", + "dependencies": [ + "acorn@8.15.0" + ] + }, "@sveltejs/adapter-auto@3.3.1_@sveltejs+kit@2.17.3__@sveltejs+vite-plugin-svelte@4.0.4___svelte@5.21.0____acorn@8.14.0___vite@5.4.14____@types+node@22.13.9___@types+node@22.13.9__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9": { "integrity": "sha512-5Sc7WAxYdL6q9j/+D0jJKjGREGlfIevDyHSQ2eNETHcB1TKlQWHcAo8AS8H1QdjNvSXpvOwNjykDUHPEAyGgdQ==", "dependencies": [ - "@sveltejs/kit", + "@sveltejs/kit@2.17.3_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", "import-meta-resolve" ] }, @@ -548,20 +657,20 @@ "@rollup/plugin-commonjs", "@rollup/plugin-json", "@rollup/plugin-node-resolve@16.0.0_rollup@4.34.9", - "@sveltejs/kit", + "@sveltejs/kit@2.17.3_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", "rollup" ] }, "@sveltejs/adapter-static@3.0.8_@sveltejs+kit@2.17.3__@sveltejs+vite-plugin-svelte@4.0.4___svelte@5.21.0____acorn@8.14.0___vite@5.4.14____@types+node@22.13.9___@types+node@22.13.9__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9": { "integrity": "sha512-YaDrquRpZwfcXbnlDsSrBQNCChVOT9MGuSg+dMAyfsAa1SmiAhrA5jUYUiIMC59G92kIbY/AaQOWcBdq+lh+zg==", "dependencies": [ - "@sveltejs/kit" + "@sveltejs/kit@2.17.3_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9" ] }, "@sveltejs/kit@2.17.3_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9": { "integrity": "sha512-GcNaPDr0ti4O/TonPewkML2DG7UVXkSxPN3nPMlpmx0Rs4b2kVP4gymz98WEHlfzPXdd4uOOT1Js26DtieTNBQ==", "dependencies": [ - "@sveltejs/vite-plugin-svelte", + "@sveltejs/vite-plugin-svelte@4.0.4_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", "@types/cookie", "cookie", "devalue", @@ -575,21 +684,53 @@ "sirv", "svelte@5.21.0_acorn@8.14.0", "vite" - ] + ], + "bin": true + }, + "@sveltejs/kit@2.22.2_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_acorn@8.15.0_@types+node@22.13.9": { + "integrity": "sha512-2MvEpSYabUrsJAoq5qCOBGAlkICjfjunrnLcx3YAk2XV7TvAIhomlKsAgR4H/4uns5rAfYmj7Wet5KRtc8dPIg==", + "dependencies": [ + "@sveltejs/acorn-typescript", + "@sveltejs/vite-plugin-svelte@4.0.4_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0", + "@types/cookie", + "acorn@8.15.0", + "cookie", + "devalue", + "esm-env", + "kleur", + "magic-string", + "mrmime", + "sade", + "set-cookie-parser", + "sirv", + "svelte@5.0.5_acorn@8.14.0", + "vite", + "vitefu" + ], + "bin": true }, "@sveltejs/vite-plugin-svelte-inspector@3.0.1_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9": { "integrity": "sha512-2CKypmj1sM4GE7HjllT7UKmo4Q6L5xFRd7VMGEWhYnZ+wc6AUVU01IBd7yUi6WnFndEwWoMNOd6e8UjoN0nbvQ==", "dependencies": [ - "@sveltejs/vite-plugin-svelte", + "@sveltejs/vite-plugin-svelte@4.0.4_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0", "debug@4.4.0", "svelte@5.21.0_acorn@8.14.0", "vite" ] }, + "@sveltejs/vite-plugin-svelte-inspector@3.0.1_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0": { + "integrity": "sha512-2CKypmj1sM4GE7HjllT7UKmo4Q6L5xFRd7VMGEWhYnZ+wc6AUVU01IBd7yUi6WnFndEwWoMNOd6e8UjoN0nbvQ==", + "dependencies": [ + "@sveltejs/vite-plugin-svelte@4.0.4_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0", + "debug@4.4.0", + "svelte@5.0.5_acorn@8.14.0", + "vite" + ] + }, "@sveltejs/vite-plugin-svelte@4.0.4_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9": { "integrity": "sha512-0ba1RQ/PHen5FGpdSrW7Y3fAMQjrXantECALeOiOdBdzR5+5vPP6HVZRLmZaQL+W8m++o+haIAKq5qT+MiZ7VA==", "dependencies": [ - "@sveltejs/vite-plugin-svelte-inspector", + "@sveltejs/vite-plugin-svelte-inspector@3.0.1_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", "debug@4.4.0", "deepmerge", "kleur", @@ -599,6 +740,19 @@ "vitefu" ] }, + "@sveltejs/vite-plugin-svelte@4.0.4_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0": { + "integrity": "sha512-0ba1RQ/PHen5FGpdSrW7Y3fAMQjrXantECALeOiOdBdzR5+5vPP6HVZRLmZaQL+W8m++o+haIAKq5qT+MiZ7VA==", + "dependencies": [ + "@sveltejs/vite-plugin-svelte-inspector@3.0.1_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0", + "debug@4.4.0", + "deepmerge", + "kleur", + "magic-string", + "svelte@5.0.5_acorn@8.14.0", + "vite", + "vitefu" + ] + }, "@tailwindcss/forms@0.5.10_tailwindcss@3.4.17__postcss@8.5.3": { "integrity": "sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==", "dependencies": [ @@ -828,6 +982,9 @@ "estree-walker@3.0.3", "magic-string", "vite" + ], + "optionalPeers": [ + "vite" ] }, "@vitest/pretty-format@3.1.4": { @@ -884,10 +1041,16 @@ ] }, "acorn@7.4.1": { - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "bin": true }, "acorn@8.14.0": { - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==" + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "bin": true + }, + "acorn@8.15.0": { + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "bin": true }, "ajv@6.12.6": { "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", @@ -956,7 +1119,8 @@ "handlebars", "nunjucks", "pug" - ] + ], + "bin": true }, "assert-never@1.4.0": { "integrity": "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==" @@ -977,7 +1141,8 @@ "picocolors", "postcss", "postcss-value-parser" - ] + ], + "bin": true }, "axobject-query@4.1.0": { "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==" @@ -1023,13 +1188,15 @@ "electron-to-chromium", "node-releases", "update-browserslist-db" - ] + ], + "bin": true }, "bufferutil@4.0.9": { "integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==", "dependencies": [ "node-gyp-build" - ] + ], + "scripts": true }, "cac@6.7.14": { "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==" @@ -1094,12 +1261,14 @@ "dependencies": [ "anymatch", "braces", - "fsevents@2.3.3", "glob-parent@5.1.2", "is-binary-path", "is-glob", "normalize-path", "readdirp@3.6.0" + ], + "optionalDependencies": [ + "fsevents@2.3.3" ] }, "chokidar@4.0.3": { @@ -1170,7 +1339,8 @@ ] }, "cssesc@3.0.0": { - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": true }, "d3-array@3.2.4": { "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", @@ -1228,7 +1398,8 @@ "commander@7.2.0", "iconv-lite", "rw" - ] + ], + "bin": true }, "d3-ease@3.0.1": { "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==" @@ -1444,7 +1615,8 @@ "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dependencies": [ "jake" - ] + ], + "bin": true }, "electron-to-chromium@1.5.111": { "integrity": "sha512-vJyJlO95wQRAw6K2ZGF/8nol7AcbCOnp8S6H91mwOOBbXoS9seDBYxCTPYAFsvXLxl3lc0jLXXe9GLxC4nXVog==" @@ -1480,7 +1652,8 @@ "es6-symbol", "esniff", "next-tick" - ] + ], + "scripts": true }, "es6-iterator@2.0.3": { "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", @@ -1499,7 +1672,7 @@ }, "esbuild@0.21.5": { "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dependencies": [ + "optionalDependencies": [ "@esbuild/aix-ppc64", "@esbuild/android-arm", "@esbuild/android-arm64", @@ -1523,7 +1696,9 @@ "@esbuild/win32-arm64", "@esbuild/win32-ia32", "@esbuild/win32-x64" - ] + ], + "scripts": true, + "bin": true }, "escalade@3.2.0": { "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==" @@ -1553,7 +1728,31 @@ "postcss-selector-parser@6.1.2", "semver", "svelte@5.21.0_acorn@8.14.0", - "svelte-eslint-parser" + "svelte-eslint-parser@0.43.0_svelte@5.21.0__acorn@8.14.0_postcss@8.5.3" + ], + "optionalPeers": [ + "svelte@^3.37.0 || ^4.0.0 || ^5.0.0" + ] + }, + "eslint-plugin-svelte@2.46.1_eslint@9.21.0_svelte@5.21.0__acorn@8.14.0_postcss@8.5.3_svelte@5.0.5__acorn@8.14.0": { + "integrity": "sha512-7xYr2o4NID/f9OEYMqxsEQsCsj4KaMy4q5sANaKkAb6/QeCjYFxRmDm2S3YC3A3pl1kyPZ/syOx/i7LcWYSbIw==", + "dependencies": [ + "@eslint-community/eslint-utils", + "@jridgewell/sourcemap-codec", + "eslint", + "eslint-compat-utils", + "esutils", + "known-css-properties", + "postcss", + "postcss-load-config@3.1.4_postcss@8.5.3", + "postcss-safe-parser", + "postcss-selector-parser@6.1.2", + "semver", + "svelte@5.0.5_acorn@8.14.0", + "svelte-eslint-parser@0.43.0_svelte@5.21.0__acorn@8.14.0_postcss@8.5.3_svelte@5.0.5__acorn@8.14.0" + ], + "optionalPeers": [ + "svelte@5.0.5_acorn@8.14.0" ] }, "eslint-scope@7.2.2": { @@ -1613,7 +1812,8 @@ "minimatch@3.1.2", "natural-compare", "optionator" - ] + ], + "bin": true }, "esm-env@1.2.2": { "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==" @@ -1721,12 +1921,18 @@ "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", "dependencies": [ "picomatch@4.0.2" + ], + "optionalPeers": [ + "picomatch@4.0.2" ] }, "fdir@6.4.4_picomatch@4.0.2": { "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", "dependencies": [ "picomatch@4.0.2" + ], + "optionalPeers": [ + "picomatch@4.0.2" ] }, "file-entry-cache@8.0.0": { @@ -1840,10 +2046,14 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "fsevents@2.3.2": { - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==" + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "os": ["darwin"], + "scripts": true }, "fsevents@2.3.3": { - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==" + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "os": ["darwin"], + "scripts": true }, "function-bind@1.1.2": { "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" @@ -1894,7 +2104,8 @@ "minipass", "package-json-from-dist", "path-scurry" - ] + ], + "bin": true }, "glob@8.1.0": { "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", @@ -1904,7 +2115,8 @@ "inherits", "minimatch@5.1.6", "once" - ] + ], + "deprecated": true }, "globals@14.0.0": { "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==" @@ -1918,9 +2130,12 @@ "minimist", "neo-async", "source-map", - "uglify-js", "wordwrap" - ] + ], + "optionalDependencies": [ + "uglify-js" + ], + "bin": true }, "has-flag@4.0.0": { "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" @@ -1941,7 +2156,8 @@ ] }, "he@1.2.0": { - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": true }, "highlight.js@11.11.1": { "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==" @@ -1973,7 +2189,8 @@ "dependencies": [ "once", "wrappy" - ] + ], + "deprecated": true }, "inherits@2.0.4": { "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" @@ -2051,7 +2268,9 @@ "jackspeak@3.4.3": { "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dependencies": [ - "@isaacs/cliui", + "@isaacs/cliui" + ], + "optionalDependencies": [ "@pkgjs/parseargs" ] }, @@ -2062,10 +2281,12 @@ "chalk", "filelist", "minimatch@3.1.2" - ] + ], + "bin": true }, "jiti@1.21.7": { - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==" + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "bin": true }, "js-stringify@1.0.2": { "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==" @@ -2074,7 +2295,8 @@ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dependencies": [ "argparse" - ] + ], + "bin": true }, "json-buffer@3.0.1": { "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" @@ -2176,7 +2398,8 @@ ] }, "mini-svg-data-uri@1.4.4": { - "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==" + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", + "bin": true }, "minimatch@3.1.2": { "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", @@ -2223,7 +2446,8 @@ ] }, "nanoid@3.3.8": { - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==" + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "bin": true }, "natural-compare@1.4.0": { "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" @@ -2244,7 +2468,8 @@ ] }, "node-gyp-build@4.8.4": { - "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==" + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "bin": true }, "node-releases@2.0.19": { "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==" @@ -2264,7 +2489,12 @@ "@scure/base@1.1.1", "@scure/bip32", "@scure/bip39", - "nostr-wasm", + "typescript" + ], + "optionalDependencies": [ + "nostr-wasm" + ], + "optionalPeers": [ "typescript" ] }, @@ -2277,7 +2507,8 @@ "a-sync-waterfall", "asap", "commander@5.1.0" - ] + ], + "bin": true }, "object-assign@4.1.1": { "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" @@ -2376,14 +2607,18 @@ "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==" }, "playwright-core@1.50.1": { - "integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==" + "integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==", + "bin": true }, "playwright@1.50.1": { "integrity": "sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==", "dependencies": [ - "fsevents@2.3.2", "playwright-core" - ] + ], + "optionalDependencies": [ + "fsevents@2.3.2" + ], + "bin": true }, "pngjs@5.0.0": { "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==" @@ -2410,6 +2645,9 @@ "lilconfig@2.1.0", "postcss", "yaml@1.10.2" + ], + "optionalPeers": [ + "postcss" ] }, "postcss-load-config@4.0.2_postcss@8.5.3": { @@ -2418,6 +2656,9 @@ "lilconfig@3.1.3", "postcss", "yaml@2.7.0" + ], + "optionalPeers": [ + "postcss" ] }, "postcss-load-config@6.0.1_postcss@8.5.3": { @@ -2425,6 +2666,9 @@ "dependencies": [ "lilconfig@3.1.3", "postcss" + ], + "optionalPeers": [ + "postcss" ] }, "postcss-nested@6.2.0_postcss@8.5.3": { @@ -2482,7 +2726,8 @@ ] }, "prettier@3.5.3": { - "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==" + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "bin": true }, "promise@7.3.1": { "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", @@ -2587,7 +2832,8 @@ "dijkstrajs", "pngjs", "yargs@15.4.1" - ] + ], + "bin": true }, "queue-microtask@1.2.3": { "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" @@ -2622,7 +2868,8 @@ "is-core-module", "path-parse", "supports-preserve-symlinks-flag" - ] + ], + "bin": true }, "reusify@1.1.0": { "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==" @@ -2633,6 +2880,9 @@ "rollup@4.34.9": { "integrity": "sha512-nF5XYqWWp9hx/LrpC8sZvvvmq0TeTjQgaZHYmAgwysT9nh8sWnZhBnM8ZyVbbJFIQBLwHDNoMqsBZBbUo4U8sQ==", "dependencies": [ + "@types/estree" + ], + "optionalDependencies": [ "@rollup/rollup-android-arm-eabi", "@rollup/rollup-android-arm64", "@rollup/rollup-darwin-arm64", @@ -2652,9 +2902,9 @@ "@rollup/rollup-win32-arm64-msvc", "@rollup/rollup-win32-ia32-msvc", "@rollup/rollup-win32-x64-msvc", - "@types/estree", "fsevents@2.3.3" - ] + ], + "bin": true }, "run-parallel@1.2.0": { "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", @@ -2675,7 +2925,8 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver@7.7.1": { - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==" + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "bin": true }, "set-blocking@2.0.0": { "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" @@ -2765,7 +3016,8 @@ "mz", "pirates", "ts-interface-checker" - ] + ], + "bin": true }, "supports-color@7.2.0": { "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", @@ -2786,7 +3038,8 @@ "sade", "svelte@5.21.0_acorn@8.14.0", "typescript" - ] + ], + "bin": true }, "svelte-eslint-parser@0.43.0_svelte@5.21.0__acorn@8.14.0_postcss@8.5.3": { "integrity": "sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA==", @@ -2797,6 +3050,23 @@ "postcss", "postcss-scss", "svelte@5.21.0_acorn@8.14.0" + ], + "optionalPeers": [ + "svelte@^3.37.0 || ^4.0.0 || ^5.0.0" + ] + }, + "svelte-eslint-parser@0.43.0_svelte@5.21.0__acorn@8.14.0_postcss@8.5.3_svelte@5.0.5__acorn@8.14.0": { + "integrity": "sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA==", + "dependencies": [ + "eslint-scope@7.2.2", + "eslint-visitor-keys@3.4.3", + "espree@9.6.1_acorn@8.14.0", + "postcss", + "postcss-scss", + "svelte@5.0.5_acorn@8.14.0" + ], + "optionalPeers": [ + "svelte@5.0.5_acorn@8.14.0" ] }, "svelte@5.0.5_acorn@8.14.0": { @@ -2913,7 +3183,8 @@ "postcss-selector-parser@6.1.2", "resolve", "sucrase" - ] + ], + "bin": true }, "thenify-all@1.6.0": { "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", @@ -2992,10 +3263,12 @@ "integrity": "sha512-Jp57Qyy8wXeMkdNuZiglE6v2Cypg13eDA1chHwDG6kq51X7gk4K7P7HaDdzZKCxkegXkVHNcPD0n5aW6OZH3aA==" }, "typescript@5.7.3": { - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==" + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "bin": true }, "uglify-js@3.19.3": { - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==" + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "bin": true }, "undici-types@6.20.0": { "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" @@ -3012,7 +3285,8 @@ "browserslist", "escalade", "picocolors" - ] + ], + "bin": true }, "uri-js@4.4.1": { "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", @@ -3024,7 +3298,8 @@ "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", "dependencies": [ "node-gyp-build" - ] + ], + "scripts": true }, "utf8-buffer@1.0.0": { "integrity": "sha512-ueuhzvWnp5JU5CiGSY4WdKbiN/PO2AZ/lpeLiz2l38qwdLy/cW40XobgyuIWucNyum0B33bVB0owjFCeGBSLqg==" @@ -3040,22 +3315,32 @@ "es-module-lexer", "pathe", "vite" - ] + ], + "bin": true }, "vite@5.4.14_@types+node@22.13.9": { "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==", "dependencies": [ "@types/node@22.13.9", "esbuild", - "fsevents@2.3.3", "postcss", "rollup" - ] + ], + "optionalDependencies": [ + "fsevents@2.3.3" + ], + "optionalPeers": [ + "@types/node@22.13.9" + ], + "bin": true }, "vitefu@1.0.6_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9": { "integrity": "sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==", "dependencies": [ "vite" + ], + "optionalPeers": [ + "vite" ] }, "vitest@3.1.4_@types+node@22.13.9_vite@5.4.14__@types+node@22.13.9": { @@ -3083,7 +3368,11 @@ "vite", "vite-node", "why-is-node-running" - ] + ], + "optionalPeers": [ + "@types/node@22.13.9" + ], + "bin": true }, "void-elements@3.1.0": { "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==" @@ -3113,14 +3402,16 @@ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dependencies": [ "isexe" - ] + ], + "bin": true }, "why-is-node-running@2.3.0": { "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dependencies": [ "siginfo", "stackback" - ] + ], + "bin": true }, "with@7.0.2": { "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", @@ -3171,13 +3462,15 @@ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, "yaeti@0.0.6": { - "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==" + "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", + "deprecated": true }, "yaml@1.10.2": { "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" }, "yaml@2.7.0": { - "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==" + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "bin": true }, "yargs-parser@18.1.3": { "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", @@ -3257,7 +3550,7 @@ "npm:@sveltejs/adapter-auto@3", "npm:@sveltejs/adapter-node@^5.2.12", "npm:@sveltejs/adapter-static@3", - "npm:@sveltejs/kit@^2.16.0", + "npm:@sveltejs/kit@^2.22.2", "npm:@sveltejs/vite-plugin-svelte@4", "npm:@tailwindcss/forms@0.5", "npm:@tailwindcss/typography@0.5", diff --git a/package.json b/package.json index 3df9454..a200816 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@sveltejs/adapter-auto": "3.x", "@sveltejs/adapter-node": "^5.2.12", "@sveltejs/adapter-static": "3.x", - "@sveltejs/kit": "^2.16.0", + "@sveltejs/kit": "^2.22.2", "@sveltejs/vite-plugin-svelte": "4.x", "@types/d3": "^7.4.3", "@types/he": "1.2.x", From d299017b9eabedee6c5165cb1e5169d1382bdab3 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 28 Jun 2025 17:42:47 -0500 Subject: [PATCH 055/135] Jump to element via ToC --- .../components/publications/Publication.svelte | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/lib/components/publications/Publication.svelte b/src/lib/components/publications/Publication.svelte index a32bdb9..c5efd96 100644 --- a/src/lib/components/publications/Publication.svelte +++ b/src/lib/components/publications/Publication.svelte @@ -22,6 +22,7 @@ import Interactions from "$components/util/Interactions.svelte"; import type { SveltePublicationTree } from "./svelte_publication_tree.svelte"; import TableOfContents from "./TableOfContents.svelte"; + import { goto } from "$app/navigation"; let { rootAddress, publicationType, indexEvent } = $props<{ rootAddress: string; @@ -33,8 +34,6 @@ // #region Loading - // TODO: Test load handling. - let leaves = $state>([]); let isLoading = $state(false); let isDone = $state(false); @@ -82,7 +81,8 @@ // #endregion - // region Columns visibility + // #region Columns visibility + let currentBlog: null | string = $state(null); let currentBlogEvent: null | NDKEvent = $state(null); const isLeaf = $derived(indexEvent.kind === 30041); @@ -123,6 +123,10 @@ return currentBlog && currentBlogEvent && window.innerWidth < 1140; } + // #endregion + + // #region Lifecycle hooks + onDestroy(() => { // reset visibility publicationColumnVisibility.reset(); @@ -157,6 +161,8 @@ observer.disconnect(); }; }); + + // #endregion @@ -170,6 +176,9 @@ depth={2} onSectionFocused={(address: string) => { publicationTree.setBookmark(address); + goto(`#${address}`, { + replaceState: true, + }); }} /> From 5fb32e35b23906aa531fa54118a5c7f73b402a26 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 28 Jun 2025 17:44:08 -0500 Subject: [PATCH 056/135] Formatting and SvelteKit 2/Svelte 5 upgrades --- src/lib/components/publications/TableOfContents.svelte | 7 +++++-- src/routes/+layout.svelte | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lib/components/publications/TableOfContents.svelte b/src/lib/components/publications/TableOfContents.svelte index 9079cd6..09280b8 100644 --- a/src/lib/components/publications/TableOfContents.svelte +++ b/src/lib/components/publications/TableOfContents.svelte @@ -1,5 +1,8 @@ From 1af98ec9d607a64f8c8e3a5f26b2b0efccdc77c5 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 28 Jun 2025 18:44:54 -0500 Subject: [PATCH 059/135] Remove unused component --- src/lib/components/util/TocToggle.svelte | 143 ----------------------- 1 file changed, 143 deletions(-) delete mode 100644 src/lib/components/util/TocToggle.svelte diff --git a/src/lib/components/util/TocToggle.svelte b/src/lib/components/util/TocToggle.svelte deleted file mode 100644 index 8fe9626..0000000 --- a/src/lib/components/util/TocToggle.svelte +++ /dev/null @@ -1,143 +0,0 @@ - - - -{#if $publicationColumnVisibility.toc} - - - - Table of contents -

(This ToC is only for demo purposes, and is not fully-functional.)

- {#each tocItems as item} - - {/each} -
-
-
-{/if} \ No newline at end of file From 9afcd37aafae4374495410825632e6f585edd08a Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 28 Jun 2025 18:45:16 -0500 Subject: [PATCH 060/135] Remove unneeded load actions for publication page --- src/routes/publication/+page.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/routes/publication/+page.ts b/src/routes/publication/+page.ts index b100f70..d154cd8 100644 --- a/src/routes/publication/+page.ts +++ b/src/routes/publication/+page.ts @@ -83,10 +83,11 @@ async function fetchEventByDTag(ndk: any, dTag: string): Promise { } } +// TODO: Use path params instead of query params. export const load: Load = async ({ url, parent }: { url: URL; parent: () => Promise }) => { const id = url.searchParams.get('id'); const dTag = url.searchParams.get('d'); - const { ndk, parser } = await parent(); + const { ndk } = await parent(); if (!id && !dTag) { throw error(400, 'No publication root event ID or d tag provided.'); @@ -98,12 +99,9 @@ export const load: Load = async ({ url, parent }: { url: URL; parent: () => Prom : await fetchEventByDTag(ndk, dTag!); const publicationType = getMatchingTags(indexEvent, 'type')[0]?.[1]; - const fetchPromise = parser.fetch(indexEvent); return { - waitable: fetchPromise, publicationType, indexEvent, - url, }; }; From 8b2ac0e48f30b5e57a73d1c7e5443ae30a5e11c8 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 28 Jun 2025 18:45:41 -0500 Subject: [PATCH 061/135] Simplify `getMatchingTags` invocation --- src/lib/components/util/ArticleNav.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/util/ArticleNav.svelte b/src/lib/components/util/ArticleNav.svelte index 11f804c..916a298 100644 --- a/src/lib/components/util/ArticleNav.svelte +++ b/src/lib/components/util/ArticleNav.svelte @@ -16,7 +16,7 @@ }>(); let title: string = $derived(indexEvent.getMatchingTags('title')[0]?.[1]); - let author: string = $derived(indexEvent.getMatchingTags(event, 'author')[0]?.[1] ?? 'unknown'); + let author: string = $derived(indexEvent.getMatchingTags('author')[0]?.[1] ?? 'unknown'); let pubkey: string = $derived(indexEvent.getMatchingTags('p')[0]?.[1] ?? null); let isLeaf: boolean = $derived(indexEvent.kind === 30041); From 700dec88752c2772eca383ea5f60373f4f62eaac Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 28 Jun 2025 18:46:03 -0500 Subject: [PATCH 062/135] Proxy bookmark observers through `SveltePublicationTree` --- .../svelte_publication_tree.svelte.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/lib/components/publications/svelte_publication_tree.svelte.ts b/src/lib/components/publications/svelte_publication_tree.svelte.ts index 9969ed7..0c1eefc 100644 --- a/src/lib/components/publications/svelte_publication_tree.svelte.ts +++ b/src/lib/components/publications/svelte_publication_tree.svelte.ts @@ -7,11 +7,13 @@ export class SveltePublicationTree { #publicationTree: PublicationTree; #nodeResolvedObservers: Array<(address: string) => void> = []; + #bookmarkMovedObservers: Array<(address: string) => void> = []; constructor(rootEvent: NDKEvent, ndk: NDK) { this.#publicationTree = new PublicationTree(rootEvent, ndk); this.#publicationTree.onNodeResolved(this.#handleNodeResolved); + this.#publicationTree.onBookmarkMoved(this.#handleBookmarkMoved); } // #region Proxied Public Methods @@ -48,6 +50,14 @@ export class SveltePublicationTree { this.#nodeResolvedObservers.push(observer); } + /** + * Registers an observer function that is invoked whenever the bookmark is moved. + * @param observer The observer function. + */ + onBookmarkMoved(observer: (address: string) => void) { + this.#bookmarkMovedObservers.push(observer); + } + // #endregion // #region Proxied Async Iterator Methods @@ -83,5 +93,19 @@ export class SveltePublicationTree { } } + /** + * Observer function that is invoked whenever the bookmark is moved on the publication tree. + * + * @param address The address of the new bookmark. + * + * This member is declared as an arrow function to ensure that the correct `this` context is + * used when the function is invoked in this class's constructor. + */ + #handleBookmarkMoved = (address: string) => { + for (const observer of this.#bookmarkMovedObservers) { + observer(address); + } + } + // #endregion } \ No newline at end of file From b8b9deb727afbb802323bf63ef4590c913ebc121 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 28 Jun 2025 18:46:34 -0500 Subject: [PATCH 063/135] Don't invoke `goto` in `onSectionFocused` --- src/lib/components/publications/Publication.svelte | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/lib/components/publications/Publication.svelte b/src/lib/components/publications/Publication.svelte index c5efd96..a9daf52 100644 --- a/src/lib/components/publications/Publication.svelte +++ b/src/lib/components/publications/Publication.svelte @@ -22,7 +22,6 @@ import Interactions from "$components/util/Interactions.svelte"; import type { SveltePublicationTree } from "./svelte_publication_tree.svelte"; import TableOfContents from "./TableOfContents.svelte"; - import { goto } from "$app/navigation"; let { rootAddress, publicationType, indexEvent } = $props<{ rootAddress: string; @@ -174,12 +173,7 @@ displayMode='sidebar' rootAddress={rootAddress} depth={2} - onSectionFocused={(address: string) => { - publicationTree.setBookmark(address); - goto(`#${address}`, { - replaceState: true, - }); - }} + onSectionFocused={(address: string) => publicationTree.setBookmark(address)} /> {/if} From ddb56d07ecc893c97f8622edc6455e69eb648042 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 28 Jun 2025 18:46:57 -0500 Subject: [PATCH 064/135] Clean up key and await in publication page --- src/routes/publication/+page.svelte | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/routes/publication/+page.svelte b/src/routes/publication/+page.svelte index 4348871..077e866 100644 --- a/src/routes/publication/+page.svelte +++ b/src/routes/publication/+page.svelte @@ -59,22 +59,16 @@
-{#key data} - + +
+ -{/key} - -
- {#await data.waitable} - - {:then} - - {/await}
From 458004bd9f744b9bedff1ec3e39497e67350ce93 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 28 Jun 2025 18:48:18 -0500 Subject: [PATCH 065/135] First pass at use of IndexedDB for publication bookmarks Scrolling to the bookmark doesn't yet work, so the IndexedDB usage is moot until that is fixed. IndexedDB access should be moved into a service layer before merging. --- src/routes/publication/+page.svelte | 54 +++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/routes/publication/+page.svelte b/src/routes/publication/+page.svelte index 077e866..5e92cbd 100644 --- a/src/routes/publication/+page.svelte +++ b/src/routes/publication/+page.svelte @@ -2,12 +2,14 @@ import Publication from "$lib/components/publications/Publication.svelte"; import { TextPlaceholder } from "flowbite-svelte"; import type { PageProps } from "./$types"; - import { onDestroy, setContext } from "svelte"; + import { onDestroy, onMount, setContext } from "svelte"; import Processor from "asciidoctor"; import ArticleNav from "$components/util/ArticleNav.svelte"; import { SveltePublicationTree } from "$lib/components/publications/svelte_publication_tree.svelte"; import { TableOfContents } from "$lib/components/publications/table_of_contents.svelte"; import { page } from "$app/state"; + import { goto } from "$app/navigation"; + let { data }: PageProps = $props(); const publicationTree = new SveltePublicationTree(data.indexEvent, data.ndk); @@ -23,7 +25,7 @@ data.parser?.getIndexTitle(data.parser?.getRootIndexId()) || "Alexandria Publication", ); - let currentUrl = data.url?.href ?? ""; + let currentUrl = $derived(`${page.url.origin}${page.url.pathname}${page.url.search}`); // Get image and summary from the event tags if available // If image unavailable, use the Alexandria default pic. @@ -36,6 +38,54 @@ "Alexandria is a digital library, utilizing Nostr events for curated publications and wiki pages.", ); + publicationTree.onBookmarkMoved(address => { + goto(`#${address}`, { + replaceState: true, + }); + + // TODO: Extract IndexedDB interaction to a service layer. + // Store bookmark in IndexedDB + const db = indexedDB.open('alexandria', 1); + db.onupgradeneeded = () => { + const objectStore = db.result.createObjectStore('bookmarks', { keyPath: 'key' }); + }; + + db.onsuccess = () => { + const transaction = db.result.transaction(['bookmarks'], 'readwrite'); + const store = transaction.objectStore('bookmarks'); + const bookmarkKey = `${data.indexEvent.tagAddress()}`; + store.put({ key: bookmarkKey, address }); + }; + }); + + onMount(() => { + // TODO: Extract IndexedDB interaction to a service layer. + // Read bookmark from IndexedDB + const db = indexedDB.open('alexandria', 1); + db.onupgradeneeded = () => { + const objectStore = db.result.createObjectStore('bookmarks', { keyPath: 'key' }); + }; + + db.onsuccess = () => { + const transaction = db.result.transaction(['bookmarks'], 'readonly'); + const store = transaction.objectStore('bookmarks'); + const bookmarkKey = `${data.indexEvent.tagAddress()}`; + const request = store.get(bookmarkKey); + + request.onsuccess = () => { + if (request.result?.address) { + // Set the bookmark in the publication tree + publicationTree.setBookmark(request.result.address); + + // Jump to the bookmarked element + goto(`#${request.result.address}`, { + replaceState: true, + }); + } + }; + }; + }); + onDestroy(() => data.parser.reset()); From 0fc90e5cebd0759219d294a096b4ff2287711b1e Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Mon, 30 Jun 2025 09:23:39 -0500 Subject: [PATCH 066/135] Use ToC hrefs for proper navigation --- src/lib/components/publications/Publication.svelte | 5 +++-- src/lib/components/publications/TableOfContents.svelte | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/components/publications/Publication.svelte b/src/lib/components/publications/Publication.svelte index a9daf52..f183806 100644 --- a/src/lib/components/publications/Publication.svelte +++ b/src/lib/components/publications/Publication.svelte @@ -167,8 +167,9 @@ {#if publicationType !== 'blog' || !isLeaf} {#if $publicationColumnVisibility.toc} - - + - {#if displayMode === 'accordion'} @@ -80,9 +79,9 @@ {@const expanded = toc.expandedMap.get(address) ?? false} {@const isLeaf = toc.leaves.has(address)} {#if isLeaf} - onSectionFocused?.(address)} /> {:else} From b492a33cc7b92608a66c6457350c096dd6e0db71 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Mon, 30 Jun 2025 09:23:49 -0500 Subject: [PATCH 067/135] Fit ToC styling to theme --- src/app.css | 14 -------------- src/lib/components/publications/Publication.svelte | 5 +++++ .../components/publications/TableOfContents.svelte | 4 ++++ src/lib/components/util/ArticleNav.svelte | 9 +++++++-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/app.css b/src/app.css index 21e1a48..572628b 100644 --- a/src/app.css +++ b/src/app.css @@ -154,20 +154,6 @@ @apply text-gray-800 hover:text-primary-400 dark:text-gray-300 dark:hover:text-primary-500; } - /* Sidebar */ - aside.sidebar-leather { - @apply fixed md:sticky top-[130px] sm:top-[146px] h-[calc(100vh-130px)] sm:h-[calc(100vh-146px)] z-10; - @apply bg-primary-0 dark:bg-primary-1000 px-5 w-full sm:w-auto sm:max-w-xl; - } - - aside.sidebar-leather > div { - @apply bg-primary-50 dark:bg-gray-800 h-full px-5 py-0; - } - - a.sidebar-item-leather { - @apply hover:bg-primary-100 dark:hover:bg-gray-800; - } - div.skeleton-leather div { @apply bg-primary-100 dark:bg-primary-800; } diff --git a/src/lib/components/publications/Publication.svelte b/src/lib/components/publications/Publication.svelte index f183806..eff97b0 100644 --- a/src/lib/components/publications/Publication.svelte +++ b/src/lib/components/publications/Publication.svelte @@ -37,6 +37,7 @@ let isLoading = $state(false); let isDone = $state(false); let lastElementRef = $state(null); + let activeAddress = $state(null); let observer: IntersectionObserver; @@ -169,7 +170,11 @@ {#if $publicationColumnVisibility.toc} + {:else} + + {#each entries as entry} {@const address = entry.address} @@ -82,12 +84,14 @@ onSectionFocused?.(address)} /> {:else} {@const childDepth = depth + 1} expanded, (open) => setEntryExpanded(address, open) diff --git a/src/lib/components/util/ArticleNav.svelte b/src/lib/components/util/ArticleNav.svelte index 916a298..24d2137 100644 --- a/src/lib/components/util/ArticleNav.svelte +++ b/src/lib/components/util/ArticleNav.svelte @@ -139,8 +139,13 @@ {/if} {/if}
-
-

{title}by {@render userBadge(pubkey, author)}

+
+

+ {title} +

+

+ by {@render userBadge(pubkey, author)} +

{#if $publicationColumnVisibility.inner} From 6a0a35f091f2e1618b80f9a10d8d10a7b09ca309 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Tue, 1 Jul 2025 08:06:29 -0500 Subject: [PATCH 068/135] Add border styling to ToC sidebar --- src/lib/components/publications/Publication.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/publications/Publication.svelte b/src/lib/components/publications/Publication.svelte index eff97b0..3bfdace 100644 --- a/src/lib/components/publications/Publication.svelte +++ b/src/lib/components/publications/Publication.svelte @@ -170,7 +170,7 @@ {#if $publicationColumnVisibility.toc} From eae495fa7776bd74a8f5b221078fcd34dbe65f73 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Tue, 1 Jul 2025 08:41:27 -0500 Subject: [PATCH 069/135] Ensure correct sorting of children of tree nodes --- .../publications/table_of_contents.svelte.ts | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/lib/components/publications/table_of_contents.svelte.ts b/src/lib/components/publications/table_of_contents.svelte.ts index 95fa0e2..afe8920 100644 --- a/src/lib/components/publications/table_of_contents.svelte.ts +++ b/src/lib/components/publications/table_of_contents.svelte.ts @@ -181,7 +181,7 @@ export class TableOfContents { return; } - const childAddresses = await this.#publicationTree.getChildAddresses(address); + const childAddresses = await this.#publicationTree.getChildAddresses(entry.address); for (const childAddress of childAddresses) { if (!childAddress) { continue; @@ -205,6 +205,8 @@ export class TableOfContents { this.addressMap.set(childAddress, childEntry); } + await this.#matchChildrenToTagOrder(entry); + entry.childrenResolved = true; } @@ -237,6 +239,31 @@ export class TableOfContents { return entry; } + /** + * Reorders the children of a ToC entry to match the order of 'a' tags in the corresponding + * Nostr index event. + * + * @param entry The ToC entry to reorder. + */ + async #matchChildrenToTagOrder(entry: TocEntry) { + const parentEvent = await this.#publicationTree.getEvent(entry.address); + if (parentEvent?.kind === indexKind) { + const tagOrder = parentEvent.getMatchingTags('a').map(tag => tag[1]); + const addressToOrdinal = new Map(); + + // Build map of addresses to their ordinals from tag order + tagOrder.forEach((address, index) => { + addressToOrdinal.set(address, index); + }); + + entry.children.sort((a, b) => { + const aOrdinal = addressToOrdinal.get(a.address) ?? Number.MAX_SAFE_INTEGER; + const bOrdinal = addressToOrdinal.get(b.address) ?? Number.MAX_SAFE_INTEGER; + return aOrdinal - bOrdinal; + }); + } + } + #buildTocEntryFromResolvedNode(address: string) { if (this.addressMap.has(address)) { return; From f0d35e0f29184c1c1b7f9e6f4d76a5e7367b558c Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Mon, 7 Jul 2025 09:04:16 -0500 Subject: [PATCH 070/135] Add time complexity notes on child sort function --- src/lib/components/publications/table_of_contents.svelte.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/components/publications/table_of_contents.svelte.ts b/src/lib/components/publications/table_of_contents.svelte.ts index afe8920..118a4ec 100644 --- a/src/lib/components/publications/table_of_contents.svelte.ts +++ b/src/lib/components/publications/table_of_contents.svelte.ts @@ -244,6 +244,9 @@ export class TableOfContents { * Nostr index event. * * @param entry The ToC entry to reorder. + * + * This function has a time complexity of `O(n log n)`, where `n` is the number of children the + * parent event has. Average size of `n` is small enough to be negligible. */ async #matchChildrenToTagOrder(entry: TocEntry) { const parentEvent = await this.#publicationTree.getEvent(entry.address); From ff8cfd39add1186bcc6d657952b6fda36af981bd Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Mon, 7 Jul 2025 09:18:39 -0500 Subject: [PATCH 071/135] Remove unused function --- src/lib/components/publications/table_of_contents.svelte.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/lib/components/publications/table_of_contents.svelte.ts b/src/lib/components/publications/table_of_contents.svelte.ts index 118a4ec..532c0a7 100644 --- a/src/lib/components/publications/table_of_contents.svelte.ts +++ b/src/lib/components/publications/table_of_contents.svelte.ts @@ -164,11 +164,6 @@ export class TableOfContents { return titleTag || event.tagAddress() || '[untitled]'; } - #normalizeHashPath(title: string): string { - // TODO: Confirm this uses good normalization logic to produce unique hrefs within the page. - return title.toLowerCase().replace(/ /g, '-'); - } - async #buildTocEntry(address: string): Promise { const resolver = async () => { if (entry.childrenResolved) { From d62e2fef5fb86cdb4fc41ec26077dd603ff153fe Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Mon, 7 Jul 2025 09:39:00 -0500 Subject: [PATCH 072/135] Add contextual and todo comments --- .../publications/table_of_contents.svelte.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/lib/components/publications/table_of_contents.svelte.ts b/src/lib/components/publications/table_of_contents.svelte.ts index 532c0a7..aaf3ac3 100644 --- a/src/lib/components/publications/table_of_contents.svelte.ts +++ b/src/lib/components/publications/table_of_contents.svelte.ts @@ -133,6 +133,18 @@ export class TableOfContents { // #region Private Methods + /** + * Initializes the ToC from the associated publication tree. + * + * @param rootAddress The address of the publication's root event. + * + * Michael J - 07 July 2025 - NOTE: Since the publication tree is conceptually infinite and + * lazy-loading, the ToC is not guaranteed to contain all the nodes at any layer until the + * publication has been fully resolved. + * + * Michael J - 07 July 2025 - TODO: If the relay provides event metadata, use the metadata to + * initialize the ToC with all of its first-level children. + */ async #init(rootAddress: string) { const rootEvent = await this.#publicationTree.getEvent(rootAddress); if (!rootEvent) { @@ -165,6 +177,9 @@ export class TableOfContents { } async #buildTocEntry(address: string): Promise { + // Michael J - 07 July 2025 - NOTE: This arrow function is nested so as to use its containing + // scope in its operation. Do not move it to the top level without ensuring it still has access + // to the necessary variables. const resolver = async () => { if (entry.childrenResolved) { return; From 70e7674a774a9384935c6da5e38d04e4221faee9 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Tue, 8 Jul 2025 09:18:11 -0500 Subject: [PATCH 073/135] Parallelize ToC initialization step --- .../publications/table_of_contents.svelte.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/lib/components/publications/table_of_contents.svelte.ts b/src/lib/components/publications/table_of_contents.svelte.ts index aaf3ac3..6c07f66 100644 --- a/src/lib/components/publications/table_of_contents.svelte.ts +++ b/src/lib/components/publications/table_of_contents.svelte.ts @@ -155,11 +155,12 @@ export class TableOfContents { this.addressMap.set(rootAddress, this.#root); - // TODO: Parallelize this. - // Handle any other nodes that have already been resolved. - this.#publicationTree.resolvedAddresses.forEach((address) => { - this.#buildTocEntryFromResolvedNode(address); - }); + // Handle any other nodes that have already been resolved in parallel. + await Promise.all( + Array.from(this.#publicationTree.resolvedAddresses).map((address) => + this.#buildTocEntryFromResolvedNode(address) + ) + ); // Set up an observer to handle progressive resolution of the publication tree. this.#publicationTree.onNodeResolved((address: string) => { From 43d77d0f0477af975438120f3f84778d49cc8490 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Tue, 8 Jul 2025 09:18:32 -0500 Subject: [PATCH 074/135] Remove accordion display mode from ToC component --- .../publications/TableOfContents.svelte | 93 ++++++------------- 1 file changed, 30 insertions(+), 63 deletions(-) diff --git a/src/lib/components/publications/TableOfContents.svelte b/src/lib/components/publications/TableOfContents.svelte index 3c0b8f1..08097ed 100644 --- a/src/lib/components/publications/TableOfContents.svelte +++ b/src/lib/components/publications/TableOfContents.svelte @@ -4,17 +4,13 @@ type TocEntry } from '$lib/components/publications/table_of_contents.svelte'; import { getContext } from 'svelte'; - import { Accordion, AccordionItem, SidebarDropdownWrapper, SidebarGroup, SidebarItem } from 'flowbite-svelte'; + import { SidebarDropdownWrapper, SidebarGroup, SidebarItem } from 'flowbite-svelte'; import Self from './TableOfContents.svelte'; - export type TocDisplayMode = 'accordion' | 'sidebar'; - let { - displayMode = 'accordion', depth, onSectionFocused, - } = $props<{ - displayMode?: TocDisplayMode; + } = $props<{ rootAddress: string; depth: number; onSectionFocused?: (address: string) => void; @@ -46,65 +42,36 @@ } - -{#if displayMode === 'accordion'} - - {#each entries as entry} - {@const address = entry.address} - {@const expanded = toc.expandedMap.get(address) ?? false} - + + + {#each entries as entry} + {@const address = entry.address} + {@const expanded = toc.expandedMap.get(address) ?? false} + {@const isLeaf = toc.leaves.has(address)} + {#if isLeaf} + onSectionFocused?.(address)} + /> + {:else} + {@const childDepth = depth + 1} + expanded, (open) => setEntryExpanded(address, open) } > - {#snippet header()} - {entry.title} - {/snippet} - {#if entry.children.length > 0} - - {/if} - - {/each} - -{:else} - - - - {#each entries as entry} - {@const address = entry.address} - {@const expanded = toc.expandedMap.get(address) ?? false} - {@const isLeaf = toc.leaves.has(address)} - {#if isLeaf} - onSectionFocused?.(address)} + - {:else} - {@const childDepth = depth + 1} - expanded, - (open) => setEntryExpanded(address, open) - } - > - - - {/if} - {/each} - -{/if} + + {/if} + {/each} + From e714ac26317cbd6c5d597b33ddf8ff8ab228bcb1 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Tue, 8 Jul 2025 09:23:05 -0500 Subject: [PATCH 075/135] Pass publication section DOM into ToC class --- .../publications/Publication.svelte | 30 +++++++++++++++++-- .../publications/table_of_contents.svelte.ts | 8 ++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/lib/components/publications/Publication.svelte b/src/lib/components/publications/Publication.svelte index 3bfdace..9a0dd70 100644 --- a/src/lib/components/publications/Publication.svelte +++ b/src/lib/components/publications/Publication.svelte @@ -22,6 +22,7 @@ import Interactions from "$components/util/Interactions.svelte"; import type { SveltePublicationTree } from "./svelte_publication_tree.svelte"; import TableOfContents from "./TableOfContents.svelte"; + import type { TableOfContents as TocType } from "./table_of_contents.svelte"; let { rootAddress, publicationType, indexEvent } = $props<{ rootAddress: string; @@ -30,6 +31,7 @@ }>(); const publicationTree = getContext("publicationTree") as SveltePublicationTree; + const toc = getContext("toc") as TocType; // #region Loading @@ -125,6 +127,29 @@ // #endregion + /** + * Performs actions on the DOM element for a publication tree leaf when it is mounted. + * + * @param el The DOM element that was mounted. + * @param address The address of the event that was mounted. + */ + function onPublicationSectionMounted(el: HTMLElement, address: string) { + // Update last element ref for the intersection observer. + setLastElementRef(el, leaves.length); + + // Michael J - 08 July 2025 - NOTE: Updating the ToC from here somewhat breaks separation of + // concerns, since the TableOfContents component is primarily responsible for working with the + // ToC data structure. However, the Publication component has direct access to the needed DOM + // element already, and I want to avoid complicated callbacks between the two components. + // Update the ToC from the contents of the leaf section. + const entry = toc.getEntry(address); + if (!entry) { + console.warn(`[Publication] No parent found for ${address}`); + return; + } + toc.buildTocFromDocument(el, entry); + } + // #region Lifecycle hooks onDestroy(() => { @@ -201,11 +226,12 @@ Error loading content. One or more events could not be loaded. {:else} + {@const address = leaf.tagAddress()} setLastElementRef(el, i)} + {address} + ref={(el) => onPublicationSectionMounted(el, address)} /> {/if} {/each} diff --git a/src/lib/components/publications/table_of_contents.svelte.ts b/src/lib/components/publications/table_of_contents.svelte.ts index 6c07f66..0e4e310 100644 --- a/src/lib/components/publications/table_of_contents.svelte.ts +++ b/src/lib/components/publications/table_of_contents.svelte.ts @@ -74,11 +74,11 @@ export class TableOfContents { buildTocFromDocument( parentElement: HTMLElement, parentEntry: TocEntry, - depth: number = 1 ) { parentElement - .querySelectorAll(`h${depth}`) + .querySelectorAll(`h${parentEntry.depth}`) .forEach((header) => { + // TODO: Correctly update ToC state from DOM. const title = header.textContent?.trim(); const id = header.id; @@ -91,7 +91,7 @@ export class TableOfContents { address: parentEntry.address, title, href, - depth, + depth: parentEntry.depth + 1, children: [], childrenResolved: true, resolveChildren: () => Promise.resolve(), @@ -99,7 +99,7 @@ export class TableOfContents { parentEntry.children.push(tocEntry); this.expandedMap.set(tocEntry.address, false); - this.buildTocFromDocument(header, tocEntry, depth + 1); + this.buildTocFromDocument(header, tocEntry); } }); } From 4907cc37a79173b42613cc355746f31306718161 Mon Sep 17 00:00:00 2001 From: Silberengel Date: Tue, 8 Jul 2025 20:26:56 +0200 Subject: [PATCH 076/135] got rid of old docker updated packages --- Dockerfile | 13 - package-lock.json | 2239 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 1986 insertions(+), 266 deletions(-) delete mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index f11d306..0000000 --- a/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM node:23-alpine AS build - -WORKDIR /app - -COPY . ./ -COPY package.json ./ -COPY package-lock.json ./ -RUN npm install -RUN npm run build - -EXPOSE 80 -FROM nginx:1.27.4 -COPY --from=build /app/build /usr/share/nginx/html \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b631ab9..10ea381 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,6 +55,8 @@ }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", "license": "MIT", "engines": { "node": ">=10" @@ -65,6 +67,8 @@ }, "node_modules/@ampproject/remapping": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -77,6 +81,8 @@ }, "node_modules/@asciidoctor/cli": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@asciidoctor/cli/-/cli-4.0.0.tgz", + "integrity": "sha512-x2T9gW42921Zd90juEagtbViPZHNP2MWf0+6rJEkOzW7E9m3TGJtz+Guye9J0gwrpZsTMGCpfYMQy1We3X7osg==", "license": "MIT", "dependencies": { "yargs": "17.3.1" @@ -95,6 +101,8 @@ }, "node_modules/@asciidoctor/core": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@asciidoctor/core/-/core-3.0.4.tgz", + "integrity": "sha512-41SDMi7iRRBViPe0L6VWFTe55bv6HEOJeRqMj5+E5wB1YPdUPuTucL4UAESPZM6OWmn4t/5qM5LusXomFUVwVQ==", "license": "MIT", "dependencies": { "@asciidoctor/opal-runtime": "3.0.1", @@ -107,6 +115,8 @@ }, "node_modules/@asciidoctor/opal-runtime": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@asciidoctor/opal-runtime/-/opal-runtime-3.0.1.tgz", + "integrity": "sha512-iW7ACahOG0zZft4A/4CqDcc7JX+fWRNjV5tFAVkNCzwZD+EnFolPaUOPYt8jzadc0+Bgd80cQTtRMQnaaV1kkg==", "license": "MIT", "dependencies": { "glob": "8.1.0", @@ -118,6 +128,8 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -125,16 +137,20 @@ }, "node_modules/@babel/helper-validator-identifier": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.27.2", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", "license": "MIT", "dependencies": { - "@babel/types": "^7.27.1" + "@babel/types": "^7.28.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -144,7 +160,9 @@ } }, "node_modules/@babel/types": { - "version": "7.27.1", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.0.tgz", + "integrity": "sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -154,8 +172,282 @@ "node": ">=6.9.0" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/linux-x64": { "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -169,8 +461,112 @@ "node": ">=12" } }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dev": true, "license": "MIT", "dependencies": { @@ -188,6 +584,8 @@ }, "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "license": "Apache-2.0", "engines": { @@ -199,6 +597,8 @@ }, "node_modules/@eslint-community/regexpp": { "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, "license": "MIT", "peer": true, @@ -207,7 +607,9 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.20.0", + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -221,7 +623,9 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.2.2", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", + "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -231,6 +635,8 @@ }, "node_modules/@eslint/core": { "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -243,6 +649,8 @@ }, "node_modules/@eslint/eslintrc": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, "license": "MIT", "peer": true, @@ -265,7 +673,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.27.0", + "version": "9.30.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.1.tgz", + "integrity": "sha512-zXhuECFlyep42KZUhWjfvsmXGX39W8K8LFb8AWXM9gSV9dQB+MrJGLKvW6Zw0Ggnbpw0VHTtrhFXYe3Gym18jg==", "dev": true, "license": "MIT", "peer": true, @@ -278,6 +688,8 @@ }, "node_modules/@eslint/object-schema": { "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -286,42 +698,66 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.3.1", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.3.tgz", + "integrity": "sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==", "dev": true, "license": "Apache-2.0", "peer": true, "dependencies": { - "@eslint/core": "^0.14.0", + "@eslint/core": "^0.15.1", "levn": "^0.4.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@floating-ui/core": { - "version": "1.7.0", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.2.tgz", + "integrity": "sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==", "dev": true, "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.9" + "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/dom": { - "version": "1.7.0", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.2.tgz", + "integrity": "sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA==", "dev": true, "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.0", - "@floating-ui/utils": "^0.2.9" + "@floating-ui/core": "^1.7.2", + "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/utils": { - "version": "0.2.9", + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", "dev": true, "license": "MIT" }, "node_modules/@humanfs/core": { "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -331,6 +767,8 @@ }, "node_modules/@humanfs/node": { "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -344,6 +782,8 @@ }, "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -357,6 +797,8 @@ }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -370,6 +812,8 @@ }, "node_modules/@humanwhocodes/retry": { "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -383,6 +827,8 @@ }, "node_modules/@isaacs/cliui": { "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -398,6 +844,8 @@ }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "license": "MIT", "engines": { "node": ">=12" @@ -408,6 +856,8 @@ }, "node_modules/@isaacs/cliui/node_modules/ansi-styles": { "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "license": "MIT", "engines": { "node": ">=12" @@ -418,10 +868,14 @@ }, "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -437,6 +891,8 @@ }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -450,6 +906,8 @@ }, "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -464,37 +922,34 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -503,13 +958,17 @@ }, "node_modules/@noble/ciphers": { "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.5.3.tgz", + "integrity": "sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w==", "license": "MIT", "funding": { "url": "https://paulmillr.com/funding/" } }, "node_modules/@noble/curves": { - "version": "1.9.1", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.2.tgz", + "integrity": "sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==", "license": "MIT", "dependencies": { "@noble/hashes": "1.8.0" @@ -523,6 +982,8 @@ }, "node_modules/@noble/hashes": { "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "license": "MIT", "engines": { "node": "^14.21.3 || >=16" @@ -532,7 +993,9 @@ } }, "node_modules/@noble/secp256k1": { - "version": "2.2.3", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-2.3.0.tgz", + "integrity": "sha512-0TQed2gcBbIrh7Ccyw+y/uZQvbJwm7Ao4scBUxqpBCcsOlZG0O4KGfjtNAy/li4W8n1xt3dxrwJ0beZ2h2G6Kw==", "license": "MIT", "funding": { "url": "https://paulmillr.com/funding/" @@ -540,6 +1003,8 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -551,6 +1016,8 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "license": "MIT", "engines": { "node": ">= 8" @@ -558,6 +1025,8 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -569,6 +1038,8 @@ }, "node_modules/@nostr-dev-kit/ndk": { "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@nostr-dev-kit/ndk/-/ndk-2.11.2.tgz", + "integrity": "sha512-DNrodIBC0j2MqEUQ5Mqaa671iZiRiKluu0c/wLkX7PCva07KSPyvcuyGp5fhk+/EZBurwZccMaML0syH0Qu8kQ==", "license": "MIT", "dependencies": { "@noble/curves": "^1.6.0", @@ -589,6 +1060,8 @@ }, "node_modules/@nostr-dev-kit/ndk-cache-dexie": { "version": "2.5.15", + "resolved": "https://registry.npmjs.org/@nostr-dev-kit/ndk-cache-dexie/-/ndk-cache-dexie-2.5.15.tgz", + "integrity": "sha512-6icRT+tqob0tWqGjQqoaeNDimfO+0gaooG9kch5OQcqlkQh2u1/ySUa47SC/m2E8q3MQVQbU66r8ZjssN2BVmw==", "license": "MIT", "dependencies": { "@nostr-dev-kit/ndk": "2.12.2", @@ -600,6 +1073,8 @@ }, "node_modules/@nostr-dev-kit/ndk-cache-dexie/node_modules/@nostr-dev-kit/ndk": { "version": "2.12.2", + "resolved": "https://registry.npmjs.org/@nostr-dev-kit/ndk/-/ndk-2.12.2.tgz", + "integrity": "sha512-uvautgwbpk3AgddoFpew67/FiaV/zpKwwvSnjCvbE/tAdJBpUUS+VjWR5WfUnJvxTy/ZZpPW+X2TkwVFHhUdvA==", "license": "MIT", "dependencies": { "@noble/curves": "^1.6.0", @@ -620,6 +1095,8 @@ }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "license": "MIT", "optional": true, "engines": { @@ -627,11 +1104,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.52.0", + "version": "1.53.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.53.2.tgz", + "integrity": "sha512-tEB2U5z74ebBeyfGNZ3Jfg29AnW+5HlWhvHtb/Mqco9pFdZU1ZLNdVb2UtB5CvmiilNr2ZfVH/qMmAROG/XTzw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.52.0" + "playwright": "1.53.2" }, "bin": { "playwright": "cli.js" @@ -642,11 +1121,15 @@ }, "node_modules/@polka/url": { "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", "dev": true, "license": "MIT" }, "node_modules/@popperjs/core": { "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", "license": "MIT", "funding": { "type": "opencollective", @@ -654,7 +1137,9 @@ } }, "node_modules/@rollup/plugin-commonjs": { - "version": "28.0.3", + "version": "28.0.6", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.6.tgz", + "integrity": "sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw==", "dev": true, "license": "MIT", "dependencies": { @@ -680,6 +1165,8 @@ }, "node_modules/@rollup/plugin-json": { "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", "dev": true, "license": "MIT", "dependencies": { @@ -699,6 +1186,8 @@ }, "node_modules/@rollup/plugin-node-resolve": { "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz", + "integrity": "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==", "dev": true, "license": "MIT", "dependencies": { @@ -721,7 +1210,9 @@ } }, "node_modules/@rollup/pluginutils": { - "version": "5.1.4", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz", + "integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==", "dev": true, "license": "MIT", "dependencies": { @@ -741,8 +1232,234 @@ } } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.2.tgz", + "integrity": "sha512-g0dF8P1e2QYPOj1gu7s/3LVP6kze9A7m6x0BZ9iTdXK8N5c2V7cpBKHV3/9A4Zd8xxavdhK0t4PnqjkqVmUc9Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.2.tgz", + "integrity": "sha512-Yt5MKrOosSbSaAK5Y4J+vSiID57sOvpBNBR6K7xAaQvk3MkcNVV0f9fE20T+41WYN8hDn6SGFlFrKudtx4EoxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.2.tgz", + "integrity": "sha512-EsnFot9ZieM35YNA26nhbLTJBHD0jTwWpPwmRVDzjylQT6gkar+zenfb8mHxWpRrbn+WytRRjE0WKsfaxBkVUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.2.tgz", + "integrity": "sha512-dv/t1t1RkCvJdWWxQ2lWOO+b7cMsVw5YFaS04oHpZRWehI1h0fV1gF4wgGCTyQHHjJDfbNpwOi6PXEafRBBezw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.2.tgz", + "integrity": "sha512-W4tt4BLorKND4qeHElxDoim0+BsprFTwb+vriVQnFFtT/P6v/xO5I99xvYnVzKWrK6j7Hb0yp3x7V5LUbaeOMg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.2.tgz", + "integrity": "sha512-tdT1PHopokkuBVyHjvYehnIe20fxibxFCEhQP/96MDSOcyjM/shlTkZZLOufV3qO6/FQOSiJTBebhVc12JyPTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.2.tgz", + "integrity": "sha512-+xmiDGGaSfIIOXMzkhJ++Oa0Gwvl9oXUeIiwarsdRXSe27HUIvjbSIpPxvnNsRebsNdUo7uAiQVgBD1hVriwSQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.2.tgz", + "integrity": "sha512-bDHvhzOfORk3wt8yxIra8N4k/N0MnKInCW5OGZaeDYa/hMrdPaJzo7CSkjKZqX4JFUWjUGm88lI6QJLCM7lDrA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.2.tgz", + "integrity": "sha512-NMsDEsDiYghTbeZWEGnNi4F0hSbGnsuOG+VnNvxkKg0IGDvFh7UVpM/14mnMwxRxUf9AdAVJgHPvKXf6FpMB7A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.2.tgz", + "integrity": "sha512-lb5bxXnxXglVq+7imxykIp5xMq+idehfl+wOgiiix0191av84OqbjUED+PRC5OA8eFJYj5xAGcpAZ0pF2MnW+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.2.tgz", + "integrity": "sha512-Yl5Rdpf9pIc4GW1PmkUGHdMtbx0fBLE1//SxDmuf3X0dUC57+zMepow2LK0V21661cjXdTn8hO2tXDdAWAqE5g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.2.tgz", + "integrity": "sha512-03vUDH+w55s680YYryyr78jsO1RWU9ocRMaeV2vMniJJW/6HhoTBwyyiiTPVHNWLnhsnwcQ0oH3S9JSBEKuyqw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.2.tgz", + "integrity": "sha512-iYtAqBg5eEMG4dEfVlkqo05xMOk6y/JXIToRca2bAWuqjrJYJlx/I7+Z+4hSrsWU8GdJDFPL4ktV3dy4yBSrzg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.2.tgz", + "integrity": "sha512-e6vEbgaaqz2yEHqtkPXa28fFuBGmUJ0N2dOJK8YUfijejInt9gfCSA7YDdJ4nYlv67JfP3+PSWFX4IVw/xRIPg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.2.tgz", + "integrity": "sha512-evFOtkmVdY3udE+0QKrV5wBx7bKI0iHz5yEVx5WqDJkxp9YQefy4Mpx3RajIVcM6o7jxTvVd/qpC1IXUhGc1Mw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.40.2", + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.2.tgz", + "integrity": "sha512-/bXb0bEsWMyEkIsUL2Yt5nFB5naLAwyOWMEviQfQY1x3l5WsLKgvZf66TM7UTfED6erckUVUJQ/jJ1FSpm3pRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.2.tgz", + "integrity": "sha512-3D3OB1vSSBXmkGEZR27uiMRNiwN08/RVAcBKwhUYPaiZ8bcvdeEwWPvbnXvvXHY+A/7xluzcN+kaiOFNiOZwWg==", "cpu": [ "x64" ], @@ -753,8 +1470,52 @@ "linux" ] }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.2.tgz", + "integrity": "sha512-VfU0fsMK+rwdK8mwODqYeM2hDrF2WiHaSmCBrS7gColkQft95/8tphyzv2EupVxn3iE0FI78wzffoULH1G+dkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.2.tgz", + "integrity": "sha512-+qMUrkbUurpE6DVRjiJCNGZBGo9xM4Y0FXU5cjgudWqIBWbcLkjE3XprJUsOFgC6xjBClwVa9k6O3A7K3vxb5Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.2.tgz", + "integrity": "sha512-3+QZROYfJ25PDcxFF66UEk8jGWigHJeecZILvkPkyQN7oc5BvFo4YEXFkOs154j3FTMp9mn9Ky8RCOwastduEA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@scure/base": { - "version": "1.2.5", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", "license": "MIT", "funding": { "url": "https://paulmillr.com/funding/" @@ -762,6 +1523,8 @@ }, "node_modules/@scure/bip32": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", + "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", "license": "MIT", "dependencies": { "@noble/curves": "~1.1.0", @@ -774,6 +1537,8 @@ }, "node_modules/@scure/bip32/node_modules/@noble/curves": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", + "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", "license": "MIT", "dependencies": { "@noble/hashes": "1.3.1" @@ -784,6 +1549,8 @@ }, "node_modules/@scure/bip32/node_modules/@noble/curves/node_modules/@noble/hashes": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", + "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", "license": "MIT", "engines": { "node": ">= 16" @@ -794,6 +1561,8 @@ }, "node_modules/@scure/bip32/node_modules/@noble/hashes": { "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", "license": "MIT", "engines": { "node": ">= 16" @@ -804,6 +1573,8 @@ }, "node_modules/@scure/bip32/node_modules/@scure/base": { "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", "license": "MIT", "funding": { "url": "https://paulmillr.com/funding/" @@ -811,6 +1582,8 @@ }, "node_modules/@scure/bip39": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", + "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", "license": "MIT", "dependencies": { "@noble/hashes": "~1.3.0", @@ -822,6 +1595,8 @@ }, "node_modules/@scure/bip39/node_modules/@noble/hashes": { "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", "license": "MIT", "engines": { "node": ">= 16" @@ -832,6 +1607,8 @@ }, "node_modules/@scure/bip39/node_modules/@scure/base": { "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", "license": "MIT", "funding": { "url": "https://paulmillr.com/funding/" @@ -839,6 +1616,8 @@ }, "node_modules/@sindresorhus/is": { "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", "license": "MIT", "engines": { "node": ">=10" @@ -849,6 +1628,8 @@ }, "node_modules/@sveltejs/acorn-typescript": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz", + "integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -857,6 +1638,8 @@ }, "node_modules/@sveltejs/adapter-auto": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-3.3.1.tgz", + "integrity": "sha512-5Sc7WAxYdL6q9j/+D0jJKjGREGlfIevDyHSQ2eNETHcB1TKlQWHcAo8AS8H1QdjNvSXpvOwNjykDUHPEAyGgdQ==", "dev": true, "license": "MIT", "dependencies": { @@ -868,6 +1651,8 @@ }, "node_modules/@sveltejs/adapter-node": { "version": "5.2.12", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.2.12.tgz", + "integrity": "sha512-0bp4Yb3jKIEcZWVcJC/L1xXp9zzJS4hDwfb4VITAkfT4OVdkspSHsx7YhqJDbb2hgLl6R9Vs7VQR+fqIVOxPUQ==", "dev": true, "license": "MIT", "dependencies": { @@ -882,6 +1667,8 @@ }, "node_modules/@sveltejs/adapter-static": { "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.8.tgz", + "integrity": "sha512-YaDrquRpZwfcXbnlDsSrBQNCChVOT9MGuSg+dMAyfsAa1SmiAhrA5jUYUiIMC59G92kIbY/AaQOWcBdq+lh+zg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -889,7 +1676,9 @@ } }, "node_modules/@sveltejs/kit": { - "version": "2.21.0", + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.22.2.tgz", + "integrity": "sha512-2MvEpSYabUrsJAoq5qCOBGAlkICjfjunrnLcx3YAk2XV7TvAIhomlKsAgR4H/4uns5rAfYmj7Wet5KRtc8dPIg==", "dev": true, "license": "MIT", "dependencies": { @@ -904,7 +1693,8 @@ "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", - "sirv": "^3.0.0" + "sirv": "^3.0.0", + "vitefu": "^1.0.6" }, "bin": { "svelte-kit": "svelte-kit.js" @@ -913,13 +1703,15 @@ "node": ">=18.13" }, "peerDependencies": { - "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0", "svelte": "^4.0.0 || ^5.0.0-next.0", - "vite": "^5.0.3 || ^6.0.0" + "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0" } }, "node_modules/@sveltejs/vite-plugin-svelte": { "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-4.0.4.tgz", + "integrity": "sha512-0ba1RQ/PHen5FGpdSrW7Y3fAMQjrXantECALeOiOdBdzR5+5vPP6HVZRLmZaQL+W8m++o+haIAKq5qT+MiZ7VA==", "dev": true, "license": "MIT", "dependencies": { @@ -940,6 +1732,8 @@ }, "node_modules/@sveltejs/vite-plugin-svelte-inspector": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-3.0.1.tgz", + "integrity": "sha512-2CKypmj1sM4GE7HjllT7UKmo4Q6L5xFRd7VMGEWhYnZ+wc6AUVU01IBd7yUi6WnFndEwWoMNOd6e8UjoN0nbvQ==", "dev": true, "license": "MIT", "dependencies": { @@ -956,6 +1750,8 @@ }, "node_modules/@tailwindcss/forms": { "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.10.tgz", + "integrity": "sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==", "license": "MIT", "dependencies": { "mini-svg-data-uri": "^1.2.3" @@ -966,6 +1762,8 @@ }, "node_modules/@tailwindcss/typography": { "version": "0.5.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.16.tgz", + "integrity": "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==", "license": "MIT", "dependencies": { "lodash.castarray": "^4.4.0", @@ -977,13 +1775,27 @@ "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, + "node_modules/@types/chai": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz", + "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*" + } + }, "node_modules/@types/cookie": { "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", "dev": true, "license": "MIT" }, "node_modules/@types/d3": { "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", "dev": true, "license": "MIT", "dependencies": { @@ -1021,11 +1833,15 @@ }, "node_modules/@types/d3-array": { "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-axis": { "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", "dev": true, "license": "MIT", "dependencies": { @@ -1034,6 +1850,8 @@ }, "node_modules/@types/d3-brush": { "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", "dev": true, "license": "MIT", "dependencies": { @@ -1042,16 +1860,22 @@ }, "node_modules/@types/d3-chord": { "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-color": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-contour": { "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", "dev": true, "license": "MIT", "dependencies": { @@ -1061,16 +1885,22 @@ }, "node_modules/@types/d3-delaunay": { "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-dispatch": { "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz", + "integrity": "sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-drag": { "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1079,16 +1909,22 @@ }, "node_modules/@types/d3-dsv": { "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-ease": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-fetch": { "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", "dev": true, "license": "MIT", "dependencies": { @@ -1097,16 +1933,22 @@ }, "node_modules/@types/d3-force": { "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-format": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-geo": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1115,11 +1957,15 @@ }, "node_modules/@types/d3-hierarchy": { "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-interpolate": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", "dev": true, "license": "MIT", "dependencies": { @@ -1128,26 +1974,36 @@ }, "node_modules/@types/d3-path": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-polygon": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-quadtree": { "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-random": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-scale": { "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", "dev": true, "license": "MIT", "dependencies": { @@ -1156,16 +2012,22 @@ }, "node_modules/@types/d3-scale-chromatic": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-selection": { "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-shape": { "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", "dev": true, "license": "MIT", "dependencies": { @@ -1174,21 +2036,29 @@ }, "node_modules/@types/d3-time": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-time-format": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-timer": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", "dev": true, "license": "MIT" }, "node_modules/@types/d3-transition": { "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", "dev": true, "license": "MIT", "dependencies": { @@ -1197,6 +2067,8 @@ }, "node_modules/@types/d3-zoom": { "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", "dev": true, "license": "MIT", "dependencies": { @@ -1204,29 +2076,46 @@ "@types/d3-selection": "*" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { - "version": "1.0.7", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, "node_modules/@types/geojson": { "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", "dev": true, "license": "MIT" }, "node_modules/@types/he": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/he/-/he-1.2.3.tgz", + "integrity": "sha512-q67/qwlxblDzEDvzHhVkwc1gzVWxaNxeyHUBF4xElrvjL11O+Ytze+1fGpBHlr/H9myiBUaUXNnNPmBHxxfAcA==", "dev": true, "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, "license": "MIT", "peer": true }, "node_modules/@types/node": { - "version": "22.15.18", + "version": "22.16.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.16.1.tgz", + "integrity": "sha512-oaNE4MzsA6uO7HcsjUvqzz19lYIRsV6I1Dc6iOvgwYYDiOeF7/9b2E/PE0UW2ccwpgWPVUedjltYXQXVKFd4EA==", "dev": true, "license": "MIT", "dependencies": { @@ -1245,16 +2134,21 @@ }, "node_modules/@types/resolve": { "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", "dev": true, "license": "MIT" }, "node_modules/@vitest/expect": { - "version": "3.1.3", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.1.3", - "@vitest/utils": "3.1.3", + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" }, @@ -1263,11 +2157,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "3.1.3", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.1.3", + "@vitest/spy": "3.2.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, @@ -1276,7 +2172,7 @@ }, "peerDependencies": { "msw": "^2.4.9", - "vite": "^5.0.0 || ^6.0.0" + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "peerDependenciesMeta": { "msw": { @@ -1289,6 +2185,8 @@ }, "node_modules/@vitest/mocker/node_modules/estree-walker": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, "license": "MIT", "dependencies": { @@ -1296,7 +2194,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "3.1.3", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", "dev": true, "license": "MIT", "dependencies": { @@ -1307,23 +2207,28 @@ } }, "node_modules/@vitest/runner": { - "version": "3.1.3", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "3.1.3", - "pathe": "^2.0.3" + "@vitest/utils": "3.2.4", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/snapshot": { - "version": "3.1.3", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.1.3", + "@vitest/pretty-format": "3.2.4", "magic-string": "^0.30.17", "pathe": "^2.0.3" }, @@ -1332,23 +2237,27 @@ } }, "node_modules/@vitest/spy": { - "version": "3.1.3", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", "dev": true, "license": "MIT", "dependencies": { - "tinyspy": "^3.0.2" + "tinyspy": "^4.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/utils": { - "version": "3.1.3", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.1.3", - "loupe": "^3.1.3", + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" }, "funding": { @@ -1357,15 +2266,21 @@ }, "node_modules/@yr/monotone-cubic-spline": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz", + "integrity": "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==", "dev": true, "license": "MIT" }, "node_modules/a-sync-waterfall": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz", + "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==", "license": "MIT" }, "node_modules/acorn": { - "version": "8.14.1", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", "bin": { @@ -1377,6 +2292,8 @@ }, "node_modules/acorn-jsx": { "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -1385,6 +2302,8 @@ }, "node_modules/ajv": { "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", "peer": true, @@ -1401,6 +2320,8 @@ }, "node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", "engines": { "node": ">=8" @@ -1408,6 +2329,8 @@ }, "node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -1421,10 +2344,14 @@ }, "node_modules/any-promise": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", "license": "MIT" }, "node_modules/anymatch": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -1436,6 +2363,8 @@ }, "node_modules/anymatch/node_modules/picomatch": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -1446,6 +2375,8 @@ }, "node_modules/apexcharts": { "version": "3.54.1", + "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.54.1.tgz", + "integrity": "sha512-E4et0h/J1U3r3EwS/WlqJCQIbepKbp6wGUmaAwJOMjHUP4Ci0gxanLa7FR3okx6p9coi4st6J853/Cb1NP0vpA==", "dev": true, "license": "MIT", "dependencies": { @@ -1460,16 +2391,22 @@ }, "node_modules/arg": { "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, "license": "Python-2.0", "peer": true }, "node_modules/aria-query": { "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1478,10 +2415,14 @@ }, "node_modules/asap": { "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "license": "MIT" }, "node_modules/asciidoctor": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/asciidoctor/-/asciidoctor-3.0.4.tgz", + "integrity": "sha512-hIc0Bx73wePxtic+vWBHOIgMfKSNiCmRz7BBfkyykXATrw20YGd5a3CozCHvqEPH+Wxp5qKD4aBsgtokez8nEA==", "license": "MIT", "dependencies": { "@asciidoctor/cli": "4.0.0", @@ -1502,10 +2443,14 @@ }, "node_modules/assert-never": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.4.0.tgz", + "integrity": "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==", "license": "MIT" }, "node_modules/assertion-error": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "license": "MIT", "engines": { @@ -1514,10 +2459,14 @@ }, "node_modules/async": { "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "license": "MIT" }, "node_modules/autoprefixer": { "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", "dev": true, "funding": [ { @@ -1554,6 +2503,8 @@ }, "node_modules/axobject-query": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1562,6 +2513,8 @@ }, "node_modules/babel-walk": { "version": "3.0.0-canary-5", + "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", + "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", "license": "MIT", "dependencies": { "@babel/types": "^7.9.6" @@ -1572,6 +2525,8 @@ }, "node_modules/balanced-match": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, "node_modules/bech32": { @@ -1582,6 +2537,8 @@ }, "node_modules/binary-extensions": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "license": "MIT", "engines": { "node": ">=8" @@ -1591,7 +2548,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -1600,6 +2559,8 @@ }, "node_modules/braces": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -1609,7 +2570,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.5", + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", "dev": true, "funding": [ { @@ -1627,8 +2590,8 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001716", - "electron-to-chromium": "^1.5.149", + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, @@ -1641,6 +2604,8 @@ }, "node_modules/bufferutil": { "version": "4.0.9", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz", + "integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -1652,6 +2617,8 @@ }, "node_modules/cac": { "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, "license": "MIT", "engines": { @@ -1660,6 +2627,8 @@ }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -1671,6 +2640,8 @@ }, "node_modules/call-bound": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -1685,6 +2656,8 @@ }, "node_modules/callsites": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, "license": "MIT", "peer": true, @@ -1703,13 +2676,17 @@ }, "node_modules/camelcase-css": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001718", + "version": "1.0.30001727", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", + "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==", "dev": true, "funding": [ { @@ -1728,7 +2705,9 @@ "license": "CC-BY-4.0" }, "node_modules/chai": { - "version": "5.2.0", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.1.tgz", + "integrity": "sha512-5nFxhUrX0PqtyogoYOA8IPswy5sZFTOsBFl/9bNsmDLgsxYTzSZQJDPppDnZPTQbzSEm0hqGjWPzRemQCYbD6A==", "dev": true, "license": "MIT", "dependencies": { @@ -1739,11 +2718,13 @@ "pathval": "^2.0.0" }, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -1758,6 +2739,8 @@ }, "node_modules/char-regex": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "license": "MIT", "engines": { "node": ">=10" @@ -1765,6 +2748,8 @@ }, "node_modules/character-parser": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", "license": "MIT", "dependencies": { "is-regex": "^1.0.3" @@ -1772,6 +2757,8 @@ }, "node_modules/check-error": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, "license": "MIT", "engines": { @@ -1779,43 +2766,25 @@ } }, "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "devOptional": true, "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, "funding": { "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" } }, "node_modules/cliui": { "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -1825,6 +2794,8 @@ }, "node_modules/clsx": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "dev": true, "license": "MIT", "engines": { @@ -1833,6 +2804,8 @@ }, "node_modules/color-convert": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -1843,10 +2816,14 @@ }, "node_modules/color-name": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, "node_modules/commander": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "license": "MIT", "engines": { "node": ">= 10" @@ -1854,15 +2831,21 @@ }, "node_modules/commondir": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true, "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, "node_modules/constantinople": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", + "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", "license": "MIT", "dependencies": { "@babel/parser": "^7.6.0", @@ -1871,6 +2854,8 @@ }, "node_modules/cookie": { "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, "license": "MIT", "engines": { @@ -1879,6 +2864,8 @@ }, "node_modules/cross-spawn": { "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -1891,6 +2878,8 @@ }, "node_modules/cssesc": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "license": "MIT", "bin": { "cssesc": "bin/cssesc" @@ -1901,6 +2890,8 @@ }, "node_modules/d": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", "license": "ISC", "dependencies": { "es5-ext": "^0.10.64", @@ -1912,6 +2903,8 @@ }, "node_modules/d3": { "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", "license": "ISC", "dependencies": { "d3-array": "3", @@ -1951,6 +2944,8 @@ }, "node_modules/d3-array": { "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", "license": "ISC", "dependencies": { "internmap": "1 - 2" @@ -1961,6 +2956,8 @@ }, "node_modules/d3-axis": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", "license": "ISC", "engines": { "node": ">=12" @@ -1968,6 +2965,8 @@ }, "node_modules/d3-brush": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", @@ -1982,6 +2981,8 @@ }, "node_modules/d3-chord": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", "license": "ISC", "dependencies": { "d3-path": "1 - 3" @@ -1992,6 +2993,8 @@ }, "node_modules/d3-color": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", "license": "ISC", "engines": { "node": ">=12" @@ -1999,6 +3002,8 @@ }, "node_modules/d3-contour": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", "license": "ISC", "dependencies": { "d3-array": "^3.2.0" @@ -2009,6 +3014,8 @@ }, "node_modules/d3-delaunay": { "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", "license": "ISC", "dependencies": { "delaunator": "5" @@ -2019,6 +3026,8 @@ }, "node_modules/d3-dispatch": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", "license": "ISC", "engines": { "node": ">=12" @@ -2026,6 +3035,8 @@ }, "node_modules/d3-drag": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", @@ -2037,6 +3048,8 @@ }, "node_modules/d3-dsv": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", "license": "ISC", "dependencies": { "commander": "7", @@ -2060,6 +3073,8 @@ }, "node_modules/d3-ease": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", "license": "BSD-3-Clause", "engines": { "node": ">=12" @@ -2067,6 +3082,8 @@ }, "node_modules/d3-fetch": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", "license": "ISC", "dependencies": { "d3-dsv": "1 - 3" @@ -2077,6 +3094,8 @@ }, "node_modules/d3-force": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", @@ -2089,6 +3108,8 @@ }, "node_modules/d3-format": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", "license": "ISC", "engines": { "node": ">=12" @@ -2096,6 +3117,8 @@ }, "node_modules/d3-geo": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", "license": "ISC", "dependencies": { "d3-array": "2.5.0 - 3" @@ -2106,6 +3129,8 @@ }, "node_modules/d3-hierarchy": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", "license": "ISC", "engines": { "node": ">=12" @@ -2113,6 +3138,8 @@ }, "node_modules/d3-interpolate": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", "license": "ISC", "dependencies": { "d3-color": "1 - 3" @@ -2123,6 +3150,8 @@ }, "node_modules/d3-path": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", "license": "ISC", "engines": { "node": ">=12" @@ -2130,6 +3159,8 @@ }, "node_modules/d3-polygon": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", "license": "ISC", "engines": { "node": ">=12" @@ -2137,6 +3168,8 @@ }, "node_modules/d3-quadtree": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", "license": "ISC", "engines": { "node": ">=12" @@ -2144,6 +3177,8 @@ }, "node_modules/d3-random": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", "license": "ISC", "engines": { "node": ">=12" @@ -2151,6 +3186,8 @@ }, "node_modules/d3-scale": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", "license": "ISC", "dependencies": { "d3-array": "2.10.0 - 3", @@ -2165,6 +3202,8 @@ }, "node_modules/d3-scale-chromatic": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", "license": "ISC", "dependencies": { "d3-color": "1 - 3", @@ -2176,6 +3215,8 @@ }, "node_modules/d3-selection": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", "engines": { "node": ">=12" @@ -2183,6 +3224,8 @@ }, "node_modules/d3-shape": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", "license": "ISC", "dependencies": { "d3-path": "^3.1.0" @@ -2193,6 +3236,8 @@ }, "node_modules/d3-time": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", "license": "ISC", "dependencies": { "d3-array": "2 - 3" @@ -2203,6 +3248,8 @@ }, "node_modules/d3-time-format": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", "license": "ISC", "dependencies": { "d3-time": "1 - 3" @@ -2213,6 +3260,8 @@ }, "node_modules/d3-timer": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", "license": "ISC", "engines": { "node": ">=12" @@ -2220,6 +3269,8 @@ }, "node_modules/d3-transition": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", "license": "ISC", "dependencies": { "d3-color": "1 - 3", @@ -2237,6 +3288,8 @@ }, "node_modules/d3-zoom": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", @@ -2251,6 +3304,8 @@ }, "node_modules/debug": { "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -2275,6 +3330,8 @@ }, "node_modules/deep-eql": { "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", "dev": true, "license": "MIT", "engines": { @@ -2283,12 +3340,16 @@ }, "node_modules/deep-is": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, "license": "MIT", "peer": true }, "node_modules/deepmerge": { "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, "license": "MIT", "engines": { @@ -2297,6 +3358,8 @@ }, "node_modules/delaunator": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", "license": "ISC", "dependencies": { "robust-predicates": "^3.0.2" @@ -2304,15 +3367,21 @@ }, "node_modules/devalue": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz", + "integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==", "dev": true, "license": "MIT" }, "node_modules/dexie": { "version": "4.0.11", + "resolved": "https://registry.npmjs.org/dexie/-/dexie-4.0.11.tgz", + "integrity": "sha512-SOKO002EqlvBYYKQSew3iymBoN2EQ4BDw/3yprjh7kAfFzjBYkaMNa/pZvcA7HSWlcKSQb9XhPe3wKyQ0x4A8A==", "license": "Apache-2.0" }, "node_modules/didyoumean": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", "license": "Apache-2.0" }, "node_modules/dijkstrajs": { @@ -2323,14 +3392,20 @@ }, "node_modules/dlv": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "license": "MIT" }, "node_modules/doctypes": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", "license": "MIT" }, "node_modules/dunder-proto": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -2343,10 +3418,14 @@ }, "node_modules/eastasianwidth": { "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "license": "MIT" }, "node_modules/ejs": { "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "license": "Apache-2.0", "dependencies": { "jake": "^10.8.5" @@ -2359,20 +3438,28 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.155", + "version": "1.5.180", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.180.tgz", + "integrity": "sha512-ED+GEyEh3kYMwt2faNmgMB0b8O5qtATGgR4RmRsIp4T6p7B8vdMbIedYndnvZfsaXvSzegtpfqRMDNCjjiSduA==", "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, "node_modules/emojilib": { "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", "license": "MIT" }, "node_modules/es-define-property": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -2380,6 +3467,8 @@ }, "node_modules/es-errors": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -2387,11 +3476,15 @@ }, "node_modules/es-module-lexer": { "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", "dev": true, "license": "MIT" }, "node_modules/es-object-atoms": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -2402,6 +3495,8 @@ }, "node_modules/es5-ext": { "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", "hasInstallScript": true, "license": "ISC", "dependencies": { @@ -2416,6 +3511,8 @@ }, "node_modules/es6-iterator": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", "license": "MIT", "dependencies": { "d": "1", @@ -2425,6 +3522,8 @@ }, "node_modules/es6-symbol": { "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", "license": "ISC", "dependencies": { "d": "^1.0.2", @@ -2436,6 +3535,8 @@ }, "node_modules/esbuild": { "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2473,6 +3574,8 @@ }, "node_modules/escalade": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "license": "MIT", "engines": { "node": ">=6" @@ -2480,6 +3583,8 @@ }, "node_modules/escape-string-regexp": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", "peer": true, @@ -2491,18 +3596,20 @@ } }, "node_modules/eslint": { - "version": "9.27.0", + "version": "9.30.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.30.1.tgz", + "integrity": "sha512-zmxXPNMOXmwm9E0yQLi5uqXHs7uq2UIiqEKo3Gq+3fwo1XrJ+hijAZImyF7hclW3E6oHz43Yk3RP8at6OTKflQ==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.20.0", - "@eslint/config-helpers": "^0.2.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.0", "@eslint/core": "^0.14.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.27.0", + "@eslint/js": "9.30.1", "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -2514,9 +3621,9 @@ "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.3.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -2552,6 +3659,8 @@ }, "node_modules/eslint-compat-utils": { "version": "0.5.1", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", + "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", "dev": true, "license": "MIT", "dependencies": { @@ -2566,6 +3675,8 @@ }, "node_modules/eslint-plugin-svelte": { "version": "2.46.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.46.1.tgz", + "integrity": "sha512-7xYr2o4NID/f9OEYMqxsEQsCsj4KaMy4q5sANaKkAb6/QeCjYFxRmDm2S3YC3A3pl1kyPZ/syOx/i7LcWYSbIw==", "dev": true, "license": "MIT", "dependencies": { @@ -2599,6 +3710,8 @@ }, "node_modules/eslint-plugin-svelte/node_modules/lilconfig": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", "dev": true, "license": "MIT", "engines": { @@ -2607,6 +3720,8 @@ }, "node_modules/eslint-plugin-svelte/node_modules/postcss-load-config": { "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", "dev": true, "license": "MIT", "dependencies": { @@ -2635,6 +3750,8 @@ }, "node_modules/eslint-plugin-svelte/node_modules/postcss-selector-parser": { "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, "license": "MIT", "dependencies": { @@ -2645,18 +3762,10 @@ "node": ">=4" } }, - "node_modules/eslint-plugin-svelte/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 6" - } - }, "node_modules/eslint-scope": { - "version": "8.3.0", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, "license": "BSD-2-Clause", "peer": true, @@ -2672,7 +3781,9 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "4.2.0", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -2685,11 +3796,15 @@ }, "node_modules/esm-env": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", "dev": true, "license": "MIT" }, "node_modules/esniff": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", "license": "ISC", "dependencies": { "d": "^1.0.1", @@ -2702,14 +3817,16 @@ } }, "node_modules/espree": { - "version": "10.3.0", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "peer": true, "dependencies": { - "acorn": "^8.14.0", + "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" + "eslint-visitor-keys": "^4.2.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2720,6 +3837,8 @@ }, "node_modules/esquery": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "license": "BSD-3-Clause", "peer": true, @@ -2731,7 +3850,9 @@ } }, "node_modules/esrap": { - "version": "1.4.6", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.1.0.tgz", + "integrity": "sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==", "dev": true, "license": "MIT", "dependencies": { @@ -2740,6 +3861,8 @@ }, "node_modules/esrecurse": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -2751,6 +3874,8 @@ }, "node_modules/estraverse": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -2759,11 +3884,15 @@ }, "node_modules/estree-walker": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true, "license": "MIT" }, "node_modules/esutils": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -2772,6 +3901,8 @@ }, "node_modules/event-emitter": { "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", "license": "MIT", "dependencies": { "d": "1", @@ -2779,7 +3910,9 @@ } }, "node_modules/expect-type": { - "version": "1.2.1", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", + "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -2788,6 +3921,8 @@ }, "node_modules/ext": { "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", "license": "ISC", "dependencies": { "type": "^2.7.2" @@ -2795,12 +3930,16 @@ }, "node_modules/fast-deep-equal": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true, "license": "MIT", "peer": true }, "node_modules/fast-glob": { "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -2815,6 +3954,8 @@ }, "node_modules/fast-glob/node_modules/glob-parent": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -2825,25 +3966,33 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true, "license": "MIT", "peer": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, "license": "MIT", "peer": true }, "node_modules/fastq": { "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, "node_modules/fdir": { - "version": "6.4.4", + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", "dev": true, "license": "MIT", "peerDependencies": { @@ -2857,6 +4006,8 @@ }, "node_modules/file-entry-cache": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "peer": true, @@ -2869,13 +4020,17 @@ }, "node_modules/filelist": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", "license": "Apache-2.0", "dependencies": { "minimatch": "^5.0.1" } }, "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -2883,6 +4038,8 @@ }, "node_modules/filelist/node_modules/minimatch": { "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -2893,6 +4050,8 @@ }, "node_modules/fill-range": { "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -2903,6 +4062,8 @@ }, "node_modules/find-up": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "peer": true, @@ -2919,6 +4080,8 @@ }, "node_modules/flat-cache": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "peer": true, @@ -2932,12 +4095,16 @@ }, "node_modules/flatted": { "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, "license": "ISC", "peer": true }, "node_modules/flowbite": { "version": "2.5.2", + "resolved": "https://registry.npmjs.org/flowbite/-/flowbite-2.5.2.tgz", + "integrity": "sha512-kwFD3n8/YW4EG8GlY3Od9IoKND97kitO+/ejISHSqpn3vw2i5K/+ZI8Jm2V+KC4fGdnfi0XZ+TzYqQb4Q1LshA==", "dev": true, "license": "MIT", "dependencies": { @@ -2948,6 +4115,8 @@ }, "node_modules/flowbite-datepicker": { "version": "1.3.2", + "resolved": "https://registry.npmjs.org/flowbite-datepicker/-/flowbite-datepicker-1.3.2.tgz", + "integrity": "sha512-6Nfm0MCVX3mpaR7YSCjmEO2GO8CDt6CX8ZpQnGdeu03WUCWtEPQ/uy0PUiNtIJjJZWnX0Cm3H55MOhbD1g+E/g==", "dev": true, "license": "MIT", "dependencies": { @@ -2957,6 +4126,8 @@ }, "node_modules/flowbite-datepicker/node_modules/@rollup/plugin-node-resolve": { "version": "15.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz", + "integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==", "dev": true, "license": "MIT", "dependencies": { @@ -2980,6 +4151,8 @@ }, "node_modules/flowbite-svelte": { "version": "0.48.6", + "resolved": "https://registry.npmjs.org/flowbite-svelte/-/flowbite-svelte-0.48.6.tgz", + "integrity": "sha512-/PmeR3ipHHvda8vVY9MZlymaRoJsk8VddEeoLzIygfYwJV68ey8gHuQPC1dq9J6NDCTE5+xOPtBiYUtVjCfvZw==", "dev": true, "license": "MIT", "dependencies": { @@ -2994,6 +4167,8 @@ }, "node_modules/flowbite-svelte-icons": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/flowbite-svelte-icons/-/flowbite-svelte-icons-2.1.1.tgz", + "integrity": "sha512-VNNMcekjbM1bQEGgbdGsdYR9mRdTj/L0A5ba0P1tiFv5QB9GvbvJMABJoiD80eqpZUkfR2QVOmiZfgCwHicT/Q==", "dev": true, "license": "MIT", "peerDependencies": { @@ -3003,6 +4178,8 @@ }, "node_modules/flowbite-svelte/node_modules/flowbite": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/flowbite/-/flowbite-3.1.2.tgz", + "integrity": "sha512-MkwSgbbybCYgMC+go6Da5idEKUFfMqc/AmSjm/2ZbdmvoKf5frLPq/eIhXc9P+rC8t9boZtUXzHDgt5whZ6A/Q==", "dev": true, "license": "MIT", "dependencies": { @@ -3014,6 +4191,8 @@ }, "node_modules/foreground-child": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", @@ -3028,6 +4207,8 @@ }, "node_modules/fraction.js": { "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "dev": true, "license": "MIT", "engines": { @@ -3040,12 +4221,14 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "license": "ISC" }, "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "hasInstallScript": true, "license": "MIT", "optional": true, @@ -3058,6 +4241,8 @@ }, "node_modules/function-bind": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3065,6 +4250,8 @@ }, "node_modules/get-caller-file": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" @@ -3072,6 +4259,8 @@ }, "node_modules/get-intrinsic": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -3094,6 +4283,8 @@ }, "node_modules/get-proto": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -3105,6 +4296,9 @@ }, "node_modules/glob": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -3122,6 +4316,8 @@ }, "node_modules/glob-parent": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -3131,7 +4327,9 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -3139,6 +4337,8 @@ }, "node_modules/glob/node_modules/minimatch": { "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -3149,6 +4349,8 @@ }, "node_modules/globals": { "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", "peer": true, @@ -3161,6 +4363,8 @@ }, "node_modules/gopd": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -3171,6 +4375,8 @@ }, "node_modules/handlebars": { "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "license": "MIT", "dependencies": { "minimist": "^1.2.5", @@ -3190,6 +4396,8 @@ }, "node_modules/has-flag": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", "engines": { "node": ">=8" @@ -3197,6 +4405,8 @@ }, "node_modules/has-symbols": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -3207,6 +4417,8 @@ }, "node_modules/has-tostringtag": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -3220,6 +4432,8 @@ }, "node_modules/hasown": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -3230,6 +4444,8 @@ }, "node_modules/he": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "license": "MIT", "bin": { "he": "bin/he" @@ -3237,6 +4453,8 @@ }, "node_modules/highlight.js": { "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", "license": "BSD-3-Clause", "engines": { "node": ">=12.0.0" @@ -3244,6 +4462,8 @@ }, "node_modules/iconv-lite": { "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -3254,6 +4474,8 @@ }, "node_modules/ignore": { "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "peer": true, @@ -3263,6 +4485,8 @@ }, "node_modules/import-fresh": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, "license": "MIT", "peer": true, @@ -3279,6 +4503,8 @@ }, "node_modules/import-meta-resolve": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", "dev": true, "license": "MIT", "funding": { @@ -3288,6 +4514,8 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "license": "MIT", "peer": true, @@ -3297,6 +4525,9 @@ }, "node_modules/inflight": { "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -3305,10 +4536,14 @@ }, "node_modules/inherits": { "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, "node_modules/internmap": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", "license": "ISC", "engines": { "node": ">=12" @@ -3316,6 +4551,8 @@ }, "node_modules/is-binary-path": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -3326,6 +4563,8 @@ }, "node_modules/is-core-module": { "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -3339,6 +4578,8 @@ }, "node_modules/is-expression": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", + "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", "license": "MIT", "dependencies": { "acorn": "^7.1.1", @@ -3347,6 +4588,8 @@ }, "node_modules/is-expression/node_modules/acorn": { "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3357,6 +4600,8 @@ }, "node_modules/is-extglob": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3364,6 +4609,8 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "license": "MIT", "engines": { "node": ">=8" @@ -3371,6 +4618,8 @@ }, "node_modules/is-glob": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -3381,11 +4630,15 @@ }, "node_modules/is-module": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", "dev": true, "license": "MIT" }, "node_modules/is-number": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "license": "MIT", "engines": { "node": ">=0.12.0" @@ -3393,10 +4646,14 @@ }, "node_modules/is-promise": { "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", "license": "MIT" }, "node_modules/is-reference": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3405,6 +4662,8 @@ }, "node_modules/is-regex": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -3421,14 +4680,20 @@ }, "node_modules/is-typedarray": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, "node_modules/jackspeak": { "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -3442,6 +4707,8 @@ }, "node_modules/jake": { "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", "license": "Apache-2.0", "dependencies": { "async": "^3.2.3", @@ -3458,6 +4725,8 @@ }, "node_modules/jiti": { "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "license": "MIT", "bin": { "jiti": "bin/jiti.js" @@ -3465,10 +4734,21 @@ }, "node_modules/js-stringify": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "license": "MIT", "peer": true, @@ -3481,24 +4761,32 @@ }, "node_modules/json-buffer": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, "license": "MIT", "peer": true }, "node_modules/json-schema-traverse": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, "license": "MIT", "peer": true }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, "license": "MIT", "peer": true }, "node_modules/jstransformer": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", "license": "MIT", "dependencies": { "is-promise": "^2.0.0", @@ -3507,6 +4795,8 @@ }, "node_modules/keyv": { "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", "peer": true, @@ -3516,6 +4806,8 @@ }, "node_modules/kleur": { "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "dev": true, "license": "MIT", "engines": { @@ -3524,11 +4816,15 @@ }, "node_modules/known-css-properties": { "version": "0.35.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz", + "integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==", "dev": true, "license": "MIT" }, "node_modules/levn": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", "peer": true, @@ -3542,6 +4838,8 @@ }, "node_modules/light-bolt11-decoder": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/light-bolt11-decoder/-/light-bolt11-decoder-3.2.0.tgz", + "integrity": "sha512-3QEofgiBOP4Ehs9BI+RkZdXZNtSys0nsJ6fyGeSiAGCBsMwHGUDS/JQlY/sTnWs91A2Nh0S9XXfA8Sy9g6QpuQ==", "license": "MIT", "dependencies": { "@scure/base": "1.1.1" @@ -3549,6 +4847,8 @@ }, "node_modules/light-bolt11-decoder/node_modules/@scure/base": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", "funding": [ { "type": "individual", @@ -3559,6 +4859,8 @@ }, "node_modules/lilconfig": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "license": "MIT", "engines": { "node": ">=14" @@ -3569,15 +4871,21 @@ }, "node_modules/lines-and-columns": { "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "license": "MIT" }, "node_modules/locate-character": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", "dev": true, "license": "MIT" }, "node_modules/locate-path": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", "peer": true, @@ -3593,27 +4901,39 @@ }, "node_modules/lodash.castarray": { "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", "license": "MIT" }, "node_modules/lodash.isplainobject": { "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "license": "MIT" }, "node_modules/loupe": { - "version": "3.1.3", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.4.tgz", + "integrity": "sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==", "dev": true, "license": "MIT" }, "node_modules/lru-cache": { "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "license": "ISC" }, "node_modules/magic-string": { "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "dev": true, "license": "MIT", "dependencies": { @@ -3622,6 +4942,8 @@ }, "node_modules/math-intrinsics": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -3629,6 +4951,8 @@ }, "node_modules/merge2": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "license": "MIT", "engines": { "node": ">= 8" @@ -3636,6 +4960,8 @@ }, "node_modules/micromatch": { "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -3647,6 +4973,8 @@ }, "node_modules/micromatch/node_modules/picomatch": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -3657,6 +4985,8 @@ }, "node_modules/mini-svg-data-uri": { "version": "1.4.4", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", "license": "MIT", "bin": { "mini-svg-data-uri": "cli.js" @@ -3664,6 +4994,8 @@ }, "node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -3674,6 +5006,8 @@ }, "node_modules/minimist": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3681,6 +5015,8 @@ }, "node_modules/minipass": { "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -3688,6 +5024,8 @@ }, "node_modules/mri": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", "dev": true, "license": "MIT", "engines": { @@ -3696,6 +5034,8 @@ }, "node_modules/mrmime": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "dev": true, "license": "MIT", "engines": { @@ -3704,10 +5044,14 @@ }, "node_modules/ms": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/mz": { "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", "license": "MIT", "dependencies": { "any-promise": "^1.0.0", @@ -3717,6 +5061,8 @@ }, "node_modules/nanoid": { "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "funding": [ { "type": "github", @@ -3733,20 +5079,28 @@ }, "node_modules/natural-compare": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, "license": "MIT", "peer": true }, "node_modules/neo-async": { "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "license": "MIT" }, "node_modules/next-tick": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", "license": "ISC" }, "node_modules/node-emoji": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", + "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", "license": "MIT", "dependencies": { "@sindresorhus/is": "^4.6.0", @@ -3760,6 +5114,8 @@ }, "node_modules/node-gyp-build": { "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", "license": "MIT", "bin": { "node-gyp-build": "bin.js", @@ -3769,11 +5125,15 @@ }, "node_modules/node-releases": { "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "dev": true, "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3781,6 +5141,8 @@ }, "node_modules/normalize-range": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "dev": true, "license": "MIT", "engines": { @@ -3789,6 +5151,8 @@ }, "node_modules/nostr-tools": { "version": "2.10.4", + "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-2.10.4.tgz", + "integrity": "sha512-biU7sk+jxHgVASfobg2T5ttxOGGSt69wEVBC51sHHOEaKAAdzHBLV/I2l9Rf61UzClhliZwNouYhqIso4a3HYg==", "license": "Unlicense", "dependencies": { "@noble/ciphers": "^0.5.1", @@ -3812,6 +5176,8 @@ }, "node_modules/nostr-tools/node_modules/@noble/curves": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", "license": "MIT", "dependencies": { "@noble/hashes": "1.3.2" @@ -3822,6 +5188,8 @@ }, "node_modules/nostr-tools/node_modules/@noble/curves/node_modules/@noble/hashes": { "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", "license": "MIT", "engines": { "node": ">= 16" @@ -3832,6 +5200,8 @@ }, "node_modules/nostr-tools/node_modules/@noble/hashes": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", + "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", "license": "MIT", "engines": { "node": ">= 16" @@ -3842,6 +5212,8 @@ }, "node_modules/nostr-tools/node_modules/@scure/base": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", "funding": [ { "type": "individual", @@ -3852,11 +5224,15 @@ }, "node_modules/nostr-wasm": { "version": "0.1.0", + "resolved": "https://registry.npmjs.org/nostr-wasm/-/nostr-wasm-0.1.0.tgz", + "integrity": "sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA==", "license": "MIT", "optional": true }, "node_modules/nunjucks": { "version": "3.2.4", + "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz", + "integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==", "license": "BSD-2-Clause", "dependencies": { "a-sync-waterfall": "^1.0.0", @@ -3880,6 +5256,8 @@ }, "node_modules/nunjucks/node_modules/commander": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", "license": "MIT", "engines": { "node": ">= 6" @@ -3887,6 +5265,8 @@ }, "node_modules/object-assign": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3894,6 +5274,8 @@ }, "node_modules/object-hash": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", "license": "MIT", "engines": { "node": ">= 6" @@ -3901,6 +5283,8 @@ }, "node_modules/once": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "license": "ISC", "dependencies": { "wrappy": "1" @@ -3908,6 +5292,8 @@ }, "node_modules/optionator": { "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", "peer": true, @@ -3925,6 +5311,8 @@ }, "node_modules/p-limit": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", "peer": true, @@ -3940,6 +5328,8 @@ }, "node_modules/p-locate": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", "peer": true, @@ -3964,10 +5354,14 @@ }, "node_modules/package-json-from-dist": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "license": "BlueOak-1.0.0" }, "node_modules/parent-module": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", "peer": true, @@ -3980,6 +5374,8 @@ }, "node_modules/path-exists": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "license": "MIT", "engines": { "node": ">=8" @@ -3987,6 +5383,8 @@ }, "node_modules/path-key": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", "engines": { "node": ">=8" @@ -3994,10 +5392,14 @@ }, "node_modules/path-parse": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, "node_modules/path-scurry": { "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -4012,11 +5414,15 @@ }, "node_modules/pathe": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, "license": "MIT" }, "node_modules/pathval": { - "version": "2.0.0", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", "dev": true, "license": "MIT", "engines": { @@ -4025,10 +5431,14 @@ }, "node_modules/picocolors": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, "license": "MIT", "engines": { @@ -4040,6 +5450,8 @@ }, "node_modules/pify": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -4047,17 +5459,21 @@ }, "node_modules/pirates": { "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/playwright": { - "version": "1.52.0", + "version": "1.53.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.53.2.tgz", + "integrity": "sha512-6K/qQxVFuVQhRQhFsVZ9fGeatxirtrpPgxzBYWyZLEXJzqYwuL4fuNmfOfD5et1tJE4GScKyPNeLhZeRwuTU3A==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.52.0" + "playwright-core": "1.53.2" }, "bin": { "playwright": "cli.js" @@ -4070,7 +5486,9 @@ } }, "node_modules/playwright-core": { - "version": "1.52.0", + "version": "1.53.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.53.2.tgz", + "integrity": "sha512-ox/OytMy+2w1jcYEYlOo1Hhp8hZkLCximMTUTMBXjGUA1KoFfiSZ+DU+3a739jsPY0yoKH2TFy9S2fsJas8yAw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4080,21 +5498,6 @@ "node": ">=18" } }, - "node_modules/playwright/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/pngjs": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", @@ -4105,7 +5508,9 @@ } }, "node_modules/postcss": { - "version": "8.5.3", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "funding": [ { "type": "opencollective", @@ -4122,7 +5527,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.8", + "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -4132,6 +5537,8 @@ }, "node_modules/postcss-import": { "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", @@ -4147,6 +5554,8 @@ }, "node_modules/postcss-js": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", "license": "MIT", "dependencies": { "camelcase-css": "^2.0.1" @@ -4164,6 +5573,8 @@ }, "node_modules/postcss-load-config": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", "dev": true, "funding": [ { @@ -4205,6 +5616,8 @@ }, "node_modules/postcss-nested": { "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", "funding": [ { "type": "opencollective", @@ -4228,6 +5641,8 @@ }, "node_modules/postcss-nested/node_modules/postcss-selector-parser": { "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -4239,6 +5654,8 @@ }, "node_modules/postcss-safe-parser": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", + "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", "dev": true, "license": "MIT", "engines": { @@ -4254,6 +5671,8 @@ }, "node_modules/postcss-scss": { "version": "4.0.9", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", + "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", "dev": true, "funding": [ { @@ -4279,6 +5698,8 @@ }, "node_modules/postcss-selector-parser": { "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -4290,10 +5711,14 @@ }, "node_modules/postcss-value-parser": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "license": "MIT" }, "node_modules/prelude-ls": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", "peer": true, @@ -4302,7 +5727,9 @@ } }, "node_modules/prettier": { - "version": "3.5.3", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", "bin": { @@ -4317,6 +5744,8 @@ }, "node_modules/prettier-plugin-svelte": { "version": "3.4.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.4.0.tgz", + "integrity": "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -4326,6 +5755,8 @@ }, "node_modules/promise": { "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "license": "MIT", "dependencies": { "asap": "~2.0.3" @@ -4333,6 +5764,8 @@ }, "node_modules/pug": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.3.tgz", + "integrity": "sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==", "license": "MIT", "dependencies": { "pug-code-gen": "^3.0.3", @@ -4347,6 +5780,8 @@ }, "node_modules/pug-attrs": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", + "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", "license": "MIT", "dependencies": { "constantinople": "^4.0.1", @@ -4356,6 +5791,8 @@ }, "node_modules/pug-code-gen": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.3.tgz", + "integrity": "sha512-cYQg0JW0w32Ux+XTeZnBEeuWrAY7/HNE6TWnhiHGnnRYlCgyAUPoyh9KzCMa9WhcJlJ1AtQqpEYHc+vbCzA+Aw==", "license": "MIT", "dependencies": { "constantinople": "^4.0.1", @@ -4370,10 +5807,14 @@ }, "node_modules/pug-error": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz", + "integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==", "license": "MIT" }, "node_modules/pug-filters": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", + "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", "license": "MIT", "dependencies": { "constantinople": "^4.0.1", @@ -4385,6 +5826,8 @@ }, "node_modules/pug-lexer": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", + "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", "license": "MIT", "dependencies": { "character-parser": "^2.2.0", @@ -4394,6 +5837,8 @@ }, "node_modules/pug-linker": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", + "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", "license": "MIT", "dependencies": { "pug-error": "^2.0.0", @@ -4402,6 +5847,8 @@ }, "node_modules/pug-load": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", + "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", "license": "MIT", "dependencies": { "object-assign": "^4.1.1", @@ -4410,6 +5857,8 @@ }, "node_modules/pug-parser": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", + "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", "license": "MIT", "dependencies": { "pug-error": "^2.0.0", @@ -4418,10 +5867,14 @@ }, "node_modules/pug-runtime": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", + "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", "license": "MIT" }, "node_modules/pug-strip-comments": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", + "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", "license": "MIT", "dependencies": { "pug-error": "^2.0.0" @@ -4429,10 +5882,14 @@ }, "node_modules/pug-walk": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", "license": "MIT" }, "node_modules/punycode": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", "peer": true, @@ -4577,6 +6034,8 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "funding": [ { "type": "github", @@ -4595,37 +6054,31 @@ }, "node_modules/read-cache": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", "license": "MIT", "dependencies": { "pify": "^2.3.0" } }, "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "devOptional": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">= 14.18.0" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/require-directory": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -4639,6 +6092,8 @@ }, "node_modules/resolve": { "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "license": "MIT", "dependencies": { "is-core-module": "^2.16.0", @@ -4657,6 +6112,8 @@ }, "node_modules/resolve-from": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", "peer": true, @@ -4666,6 +6123,8 @@ }, "node_modules/reusify": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -4674,14 +6133,18 @@ }, "node_modules/robust-predicates": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", "license": "Unlicense" }, "node_modules/rollup": { - "version": "4.40.2", + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.2.tgz", + "integrity": "sha512-PVoapzTwSEcelaWGth3uR66u7ZRo6qhPHc0f2uRO9fX6XDVNrIiGYS0Pj9+R8yIIYSD/mCx2b16Ws9itljKSPg==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.7" + "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" @@ -4691,31 +6154,33 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.40.2", - "@rollup/rollup-android-arm64": "4.40.2", - "@rollup/rollup-darwin-arm64": "4.40.2", - "@rollup/rollup-darwin-x64": "4.40.2", - "@rollup/rollup-freebsd-arm64": "4.40.2", - "@rollup/rollup-freebsd-x64": "4.40.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.40.2", - "@rollup/rollup-linux-arm-musleabihf": "4.40.2", - "@rollup/rollup-linux-arm64-gnu": "4.40.2", - "@rollup/rollup-linux-arm64-musl": "4.40.2", - "@rollup/rollup-linux-loongarch64-gnu": "4.40.2", - "@rollup/rollup-linux-powerpc64le-gnu": "4.40.2", - "@rollup/rollup-linux-riscv64-gnu": "4.40.2", - "@rollup/rollup-linux-riscv64-musl": "4.40.2", - "@rollup/rollup-linux-s390x-gnu": "4.40.2", - "@rollup/rollup-linux-x64-gnu": "4.40.2", - "@rollup/rollup-linux-x64-musl": "4.40.2", - "@rollup/rollup-win32-arm64-msvc": "4.40.2", - "@rollup/rollup-win32-ia32-msvc": "4.40.2", - "@rollup/rollup-win32-x64-msvc": "4.40.2", + "@rollup/rollup-android-arm-eabi": "4.44.2", + "@rollup/rollup-android-arm64": "4.44.2", + "@rollup/rollup-darwin-arm64": "4.44.2", + "@rollup/rollup-darwin-x64": "4.44.2", + "@rollup/rollup-freebsd-arm64": "4.44.2", + "@rollup/rollup-freebsd-x64": "4.44.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.44.2", + "@rollup/rollup-linux-arm-musleabihf": "4.44.2", + "@rollup/rollup-linux-arm64-gnu": "4.44.2", + "@rollup/rollup-linux-arm64-musl": "4.44.2", + "@rollup/rollup-linux-loongarch64-gnu": "4.44.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.44.2", + "@rollup/rollup-linux-riscv64-gnu": "4.44.2", + "@rollup/rollup-linux-riscv64-musl": "4.44.2", + "@rollup/rollup-linux-s390x-gnu": "4.44.2", + "@rollup/rollup-linux-x64-gnu": "4.44.2", + "@rollup/rollup-linux-x64-musl": "4.44.2", + "@rollup/rollup-win32-arm64-msvc": "4.44.2", + "@rollup/rollup-win32-ia32-msvc": "4.44.2", + "@rollup/rollup-win32-x64-msvc": "4.44.2", "fsevents": "~2.3.2" } }, "node_modules/run-parallel": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "funding": [ { "type": "github", @@ -4737,10 +6202,14 @@ }, "node_modules/rw": { "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", "license": "BSD-3-Clause" }, "node_modules/sade": { "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", "dev": true, "license": "MIT", "dependencies": { @@ -4752,10 +6221,14 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, "node_modules/semver": { "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, "license": "ISC", "bin": { @@ -4773,11 +6246,15 @@ }, "node_modules/set-cookie-parser": { "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", "dev": true, "license": "MIT" }, "node_modules/shebang-command": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -4788,6 +6265,8 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "license": "MIT", "engines": { "node": ">=8" @@ -4795,11 +6274,15 @@ }, "node_modules/siginfo": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true, "license": "ISC" }, "node_modules/signal-exit": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "license": "ISC", "engines": { "node": ">=14" @@ -4810,6 +6293,8 @@ }, "node_modules/sirv": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", + "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", "dev": true, "license": "MIT", "dependencies": { @@ -4823,6 +6308,8 @@ }, "node_modules/skin-tone": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", "license": "MIT", "dependencies": { "unicode-emoji-modifier-base": "^1.0.0" @@ -4833,6 +6320,8 @@ }, "node_modules/source-map": { "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -4840,6 +6329,8 @@ }, "node_modules/source-map-js": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -4847,16 +6338,22 @@ }, "node_modules/stackback": { "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true, "license": "MIT" }, "node_modules/std-env": { "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", "dev": true, "license": "MIT" }, "node_modules/string-width": { "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -4870,6 +6367,8 @@ "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -4882,6 +6381,8 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -4893,6 +6394,8 @@ "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -4903,6 +6406,8 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "license": "MIT", "peer": true, @@ -4913,8 +6418,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-literal": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz", + "integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/sucrase": { "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", @@ -4934,7 +6454,9 @@ } }, "node_modules/sucrase/node_modules/brace-expansion": { - "version": "2.0.1", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -4942,6 +6464,8 @@ }, "node_modules/sucrase/node_modules/commander": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "license": "MIT", "engines": { "node": ">= 6" @@ -4949,6 +6473,8 @@ }, "node_modules/sucrase/node_modules/glob": { "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -4967,6 +6493,8 @@ }, "node_modules/sucrase/node_modules/minimatch": { "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -4980,6 +6508,8 @@ }, "node_modules/supports-color": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -4990,6 +6520,8 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -4999,7 +6531,9 @@ } }, "node_modules/svelte": { - "version": "5.30.1", + "version": "5.35.4", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.35.4.tgz", + "integrity": "sha512-NUUD+GcV/uvLBANoFwPNtnlkJM77PEkYYH6TChRZnGI1a5UHc9k2Glq7jxGtClfVz2ZhEvpg+c4yS577qM1c6g==", "dev": true, "license": "MIT", "dependencies": { @@ -5012,7 +6546,7 @@ "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", - "esrap": "^1.4.6", + "esrap": "^2.1.0", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", @@ -5023,7 +6557,9 @@ } }, "node_modules/svelte-check": { - "version": "4.2.1", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.2.2.tgz", + "integrity": "sha512-1+31EOYZ7NKN0YDMKusav2hhEoA51GD9Ws6o//0SphMT0ve9mBTsTUEX7OmDMadUP3KjNHsSKtJrqdSaD8CrGQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5044,38 +6580,10 @@ "typescript": ">=5.0.0" } }, - "node_modules/svelte-check/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/svelte-check/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/svelte-eslint-parser": { "version": "0.43.0", + "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.43.0.tgz", + "integrity": "sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA==", "dev": true, "license": "MIT", "dependencies": { @@ -5102,6 +6610,8 @@ }, "node_modules/svelte-eslint-parser/node_modules/eslint-scope": { "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -5117,6 +6627,8 @@ }, "node_modules/svelte-eslint-parser/node_modules/eslint-visitor-keys": { "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "license": "Apache-2.0", "engines": { @@ -5128,6 +6640,8 @@ }, "node_modules/svelte-eslint-parser/node_modules/espree": { "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -5144,6 +6658,8 @@ }, "node_modules/svelte/node_modules/is-reference": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", "dev": true, "license": "MIT", "dependencies": { @@ -5152,6 +6668,8 @@ }, "node_modules/svg.draggable.js": { "version": "2.2.2", + "resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz", + "integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==", "dev": true, "license": "MIT", "dependencies": { @@ -5163,6 +6681,8 @@ }, "node_modules/svg.easing.js": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz", + "integrity": "sha512-//ctPdJMGy22YoYGV+3HEfHbm6/69LJUTAqI2/5qBvaNHZ9uUFVC82B0Pl299HzgH13rKrBgi4+XyXXyVWWthA==", "dev": true, "license": "MIT", "dependencies": { @@ -5174,6 +6694,8 @@ }, "node_modules/svg.filter.js": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz", + "integrity": "sha512-xkGBwU+dKBzqg5PtilaTb0EYPqPfJ9Q6saVldX+5vCRy31P6TlRCP3U9NxH3HEufkKkpNgdTLBJnmhDHeTqAkw==", "dev": true, "license": "MIT", "dependencies": { @@ -5185,11 +6707,15 @@ }, "node_modules/svg.js": { "version": "2.7.1", + "resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz", + "integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA==", "dev": true, "license": "MIT" }, "node_modules/svg.pathmorphing.js": { "version": "0.1.3", + "resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz", + "integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==", "dev": true, "license": "MIT", "dependencies": { @@ -5201,6 +6727,8 @@ }, "node_modules/svg.resize.js": { "version": "1.4.3", + "resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz", + "integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==", "dev": true, "license": "MIT", "dependencies": { @@ -5213,6 +6741,8 @@ }, "node_modules/svg.resize.js/node_modules/svg.select.js": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz", + "integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5224,6 +6754,8 @@ }, "node_modules/svg.select.js": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz", + "integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==", "dev": true, "license": "MIT", "dependencies": { @@ -5234,7 +6766,9 @@ } }, "node_modules/tailwind-merge": { - "version": "3.3.0", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz", + "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==", "dev": true, "license": "MIT", "funding": { @@ -5244,6 +6778,8 @@ }, "node_modules/tailwindcss": { "version": "3.4.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", + "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", @@ -5277,8 +6813,58 @@ "node": ">=14.0.0" } }, + "node_modules/tailwindcss/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/tailwindcss/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tailwindcss/node_modules/postcss-load-config": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", "funding": [ { "type": "opencollective", @@ -5312,6 +6898,8 @@ }, "node_modules/tailwindcss/node_modules/postcss-selector-parser": { "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -5321,8 +6909,34 @@ "node": ">=4" } }, + "node_modules/tailwindcss/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/tailwindcss/node_modules/yaml": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, "node_modules/thenify": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", "license": "MIT", "dependencies": { "any-promise": "^1.0.0" @@ -5330,6 +6944,8 @@ }, "node_modules/thenify-all": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" @@ -5340,16 +6956,22 @@ }, "node_modules/tinybench": { "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", "dev": true, "license": "MIT" }, "node_modules/tinyexec": { "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", "dev": true, "license": "MIT" }, "node_modules/tinyglobby": { - "version": "0.2.13", + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5364,7 +6986,9 @@ } }, "node_modules/tinypool": { - "version": "1.0.2", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", "dev": true, "license": "MIT", "engines": { @@ -5373,6 +6997,8 @@ }, "node_modules/tinyrainbow": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", "dev": true, "license": "MIT", "engines": { @@ -5380,7 +7006,9 @@ } }, "node_modules/tinyspy": { - "version": "3.0.2", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz", + "integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==", "dev": true, "license": "MIT", "engines": { @@ -5389,6 +7017,8 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -5399,10 +7029,14 @@ }, "node_modules/token-stream": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", + "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", "license": "MIT" }, "node_modules/totalist": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", "dev": true, "license": "MIT", "engines": { @@ -5411,27 +7045,39 @@ }, "node_modules/ts-interface-checker": { "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "license": "Apache-2.0" }, "node_modules/tseep": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tseep/-/tseep-1.3.1.tgz", + "integrity": "sha512-ZPtfk1tQnZVyr7BPtbJ93qaAh2lZuIOpTMjhrYa4XctT8xe7t4SAW9LIxrySDuYMsfNNayE51E/WNGrNVgVicQ==", "license": "MIT" }, "node_modules/tslib": { "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, "node_modules/tstl": { "version": "2.5.16", + "resolved": "https://registry.npmjs.org/tstl/-/tstl-2.5.16.tgz", + "integrity": "sha512-+O2ybLVLKcBwKm4HymCEwZIT0PpwS3gCYnxfSDEjJEKADvIFruaQjd3m7CAKNU1c7N3X3WjVz87re7TA2A5FUw==", "license": "MIT" }, "node_modules/type": { "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", "license": "ISC" }, "node_modules/type-check": { "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", "peer": true, @@ -5444,6 +7090,8 @@ }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "license": "MIT", "dependencies": { "is-typedarray": "^1.0.0" @@ -5451,6 +7099,8 @@ }, "node_modules/typescript": { "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "devOptional": true, "license": "Apache-2.0", "bin": { @@ -5463,10 +7113,14 @@ }, "node_modules/typescript-lru-cache": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/typescript-lru-cache/-/typescript-lru-cache-2.0.0.tgz", + "integrity": "sha512-Jp57Qyy8wXeMkdNuZiglE6v2Cypg13eDA1chHwDG6kq51X7gk4K7P7HaDdzZKCxkegXkVHNcPD0n5aW6OZH3aA==", "license": "MIT" }, "node_modules/uglify-js": { "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "license": "BSD-2-Clause", "optional": true, "bin": { @@ -5478,11 +7132,15 @@ }, "node_modules/undici-types": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, "license": "MIT" }, "node_modules/unicode-emoji-modifier-base": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", "license": "MIT", "engines": { "node": ">=4" @@ -5490,6 +7148,8 @@ }, "node_modules/unxhr": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unxhr/-/unxhr-1.2.0.tgz", + "integrity": "sha512-6cGpm8NFXPD9QbSNx0cD2giy7teZ6xOkCUH3U89WKVkL9N9rBrWjlCwhR94Re18ZlAop4MOc3WU1M3Hv/bgpIw==", "license": "MIT", "engines": { "node": ">=8.11" @@ -5497,6 +7157,8 @@ }, "node_modules/update-browserslist-db": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dev": true, "funding": [ { @@ -5526,6 +7188,8 @@ }, "node_modules/uri-js": { "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "license": "BSD-2-Clause", "peer": true, @@ -5535,6 +7199,8 @@ }, "node_modules/utf-8-validate": { "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -5546,6 +7212,8 @@ }, "node_modules/utf8-buffer": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/utf8-buffer/-/utf8-buffer-1.0.0.tgz", + "integrity": "sha512-ueuhzvWnp5JU5CiGSY4WdKbiN/PO2AZ/lpeLiz2l38qwdLy/cW40XobgyuIWucNyum0B33bVB0owjFCeGBSLqg==", "license": "MIT", "engines": { "node": ">=8" @@ -5553,10 +7221,14 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, "node_modules/vite": { "version": "5.4.19", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", + "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==", "dev": true, "license": "MIT", "dependencies": { @@ -5614,15 +7286,17 @@ } }, "node_modules/vite-node": { - "version": "3.1.3", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", "dev": true, "license": "MIT", "dependencies": { "cac": "^6.7.14", - "debug": "^4.4.0", + "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", - "vite": "^5.0.0 || ^6.0.0" + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" @@ -5634,16 +7308,34 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/vite/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/vitefu": { - "version": "1.0.6", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz", + "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==", "dev": true, "license": "MIT", "workspaces": [ "tests/deps/*", - "tests/projects/*" + "tests/projects/*", + "tests/projects/workspace/packages/*" ], "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "peerDependenciesMeta": { "vite": { @@ -5652,30 +7344,34 @@ } }, "node_modules/vitest": { - "version": "3.1.3", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "3.1.3", - "@vitest/mocker": "3.1.3", - "@vitest/pretty-format": "^3.1.3", - "@vitest/runner": "3.1.3", - "@vitest/snapshot": "3.1.3", - "@vitest/spy": "3.1.3", - "@vitest/utils": "3.1.3", + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", "chai": "^5.2.0", - "debug": "^4.4.0", + "debug": "^4.4.1", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", + "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", - "tinyglobby": "^0.2.13", - "tinypool": "^1.0.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", - "vite": "^5.0.0 || ^6.0.0", - "vite-node": "3.1.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "bin": { @@ -5691,8 +7387,8 @@ "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.1.3", - "@vitest/ui": "3.1.3", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", "happy-dom": "*", "jsdom": "*" }, @@ -5722,6 +7418,8 @@ }, "node_modules/void-elements": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5729,6 +7427,8 @@ }, "node_modules/websocket": { "version": "1.0.35", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.35.tgz", + "integrity": "sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q==", "license": "Apache-2.0", "dependencies": { "bufferutil": "^4.0.1", @@ -5744,6 +7444,8 @@ }, "node_modules/websocket-polyfill": { "version": "0.0.3", + "resolved": "https://registry.npmjs.org/websocket-polyfill/-/websocket-polyfill-0.0.3.tgz", + "integrity": "sha512-pF3kR8Uaoau78MpUmFfzbIRxXj9PeQrCuPepGE6JIsfsJ/o/iXr07Q2iQNzKSSblQJ0FiGWlS64N4pVSm+O3Dg==", "dependencies": { "tstl": "^2.0.7", "websocket": "^1.0.28" @@ -5751,6 +7453,8 @@ }, "node_modules/websocket/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -5758,10 +7462,14 @@ }, "node_modules/websocket/node_modules/ms": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, "node_modules/which": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -5781,6 +7489,8 @@ }, "node_modules/why-is-node-running": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "license": "MIT", "dependencies": { @@ -5796,6 +7506,8 @@ }, "node_modules/with": { "version": "7.0.2", + "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", + "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", "license": "MIT", "dependencies": { "@babel/parser": "^7.9.6", @@ -5809,6 +7521,8 @@ }, "node_modules/word-wrap": { "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", "peer": true, @@ -5818,10 +7532,14 @@ }, "node_modules/wordwrap": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", "license": "MIT" }, "node_modules/wrap-ansi": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -5838,6 +7556,8 @@ "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -5853,10 +7573,14 @@ }, "node_modules/wrappy": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, "node_modules/y18n": { "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "license": "ISC", "engines": { "node": ">=10" @@ -5864,25 +7588,28 @@ }, "node_modules/yaeti": { "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "license": "MIT", "engines": { "node": ">=0.10.32" } }, "node_modules/yaml": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", - "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, "engines": { - "node": ">= 14.6" + "node": ">= 6" } }, "node_modules/yargs": { "version": "17.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", + "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", "license": "MIT", "dependencies": { "cliui": "^7.0.2", @@ -5899,6 +7626,8 @@ }, "node_modules/yargs-parser": { "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "license": "ISC", "engines": { "node": ">=12" @@ -5906,6 +7635,8 @@ }, "node_modules/yocto-queue": { "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "license": "MIT", "peer": true, @@ -5918,6 +7649,8 @@ }, "node_modules/zimmerframe": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", + "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", "dev": true, "license": "MIT" } From 3af81d34233a0c4a2287083230e268d343c64cf2 Mon Sep 17 00:00:00 2001 From: Silberengel Date: Tue, 8 Jul 2025 20:37:11 +0200 Subject: [PATCH 077/135] Improved contrast on all text, to meet accessibility guidelines --- src/app.css | 40 +++++++++---------- src/lib/components/CommentBox.svelte | 2 +- src/lib/components/EventDetails.svelte | 22 +++++----- src/lib/components/EventLimitControl.svelte | 2 +- .../components/EventRenderLevelLimit.svelte | 2 +- src/lib/components/EventSearch.svelte | 2 +- src/lib/components/LoginModal.svelte | 6 +-- src/lib/components/Publication.svelte | 4 +- src/lib/components/PublicationFeed.svelte | 4 +- src/lib/components/PublicationHeader.svelte | 2 +- src/lib/components/RelayActions.svelte | 4 +- src/lib/components/RelayDisplay.svelte | 2 +- src/lib/components/cards/BlogHeader.svelte | 2 +- src/lib/components/util/CardActions.svelte | 2 +- src/lib/components/util/Details.svelte | 2 +- src/lib/components/util/Interactions.svelte | 2 +- src/routes/+page.svelte | 2 +- src/routes/about/+page.svelte | 2 +- src/routes/contact/+page.svelte | 8 ++-- src/routes/events/+page.svelte | 2 +- src/routes/visualize/+page.svelte | 2 +- src/styles/publications.css | 2 +- 22 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/app.css b/src/app.css index 21e1a48..5db7fde 100644 --- a/src/app.css +++ b/src/app.css @@ -7,7 +7,7 @@ /* Custom styles */ @layer base { .leather { - @apply bg-primary-0 dark:bg-primary-1000 text-gray-800 dark:text-gray-200; + @apply bg-primary-0 dark:bg-primary-1000 text-gray-900 dark:text-gray-100; } .btn-leather.text-xs { @@ -27,7 +27,7 @@ } div[role='tooltip'] button.btn-leather { - @apply hover:text-primary-400 dark:hover:text-primary-500 hover:border-primary-400 dark:hover:border-primary-500 hover:bg-gray-200 dark:hover:bg-gray-700; + @apply hover:text-primary-600 dark:hover:text-primary-400 hover:border-primary-600 dark:hover:border-primary-400 hover:bg-gray-200 dark:hover:bg-gray-700; } .image-border { @@ -45,11 +45,11 @@ div.card-leather h4, div.card-leather h5, div.card-leather h6 { - @apply text-gray-800 hover:text-primary-400 dark:text-gray-300 dark:hover:text-primary-500; + @apply text-gray-900 hover:text-primary-600 dark:text-gray-100 dark:hover:text-primary-400; } div.card-leather .font-thin { - @apply text-gray-900 hover:text-primary-600 dark:text-gray-200 dark:hover:text-primary-200; + @apply text-gray-900 hover:text-primary-700 dark:text-gray-100 dark:hover:text-primary-300; } main { @@ -67,13 +67,13 @@ main.main-leather, article.article-leather { - @apply bg-primary-0 dark:bg-primary-1000 text-gray-800 dark:text-gray-300; + @apply bg-primary-0 dark:bg-primary-1000 text-gray-900 dark:text-gray-100; } div.note-leather, p.note-leather, section.note-leather { - @apply bg-primary-0 dark:bg-primary-1000 text-gray-800 dark:text-gray-300 p-2 rounded; + @apply bg-primary-0 dark:bg-primary-1000 text-gray-900 dark:text-gray-100 p-2 rounded; } .edit div.note-leather:hover:not(:has(.note-leather:hover)), @@ -88,7 +88,7 @@ h4.h-leather, h5.h-leather, h6.h-leather { - @apply text-gray-800 dark:text-gray-300; + @apply text-gray-900 dark:text-gray-100; } h1.h-leather { @@ -125,11 +125,11 @@ div.modal-leather>div>h4, div.modal-leather>div>h5, div.modal-leather>div>h6 { - @apply text-gray-800 hover:text-gray-800 dark:text-gray-300 dark:hover:text-gray-300; + @apply text-gray-900 hover:text-gray-900 dark:text-gray-100 dark:hover:text-gray-100; } div.modal-leather button { - @apply bg-primary-0 hover:bg-primary-0 dark:bg-primary-950 dark:hover:bg-primary-950 text-gray-800 hover:text-primary-400 dark:text-gray-300 dark:hover:text-primary-500; + @apply bg-primary-0 hover:bg-primary-0 dark:bg-primary-950 dark:hover:bg-primary-950 text-gray-900 hover:text-primary-600 dark:text-gray-100 dark:hover:text-primary-400; } /* Navbar */ @@ -142,7 +142,7 @@ } nav.navbar-leather svg { - @apply fill-gray-800 hover:fill-primary-400 dark:fill-gray-300 dark:hover:fill-primary-500; + @apply fill-gray-900 hover:fill-primary-600 dark:fill-gray-100 dark:hover:fill-primary-400; } nav.navbar-leather h1, @@ -151,7 +151,7 @@ nav.navbar-leather h4, nav.navbar-leather h5, nav.navbar-leather h6 { - @apply text-gray-800 hover:text-primary-400 dark:text-gray-300 dark:hover:text-primary-500; + @apply text-gray-900 hover:text-primary-600 dark:text-gray-100 dark:hover:text-primary-400; } /* Sidebar */ @@ -187,11 +187,11 @@ div.textarea-leather, div.textarea-leather textarea { - @apply text-gray-800 dark:text-gray-300; + @apply text-gray-900 dark:text-gray-100; } div.tooltip-leather { - @apply text-gray-800 dark:text-gray-300; + @apply text-gray-900 dark:text-gray-100; } div[role='tooltip'] button.btn-leather .tooltip-leather { @@ -215,7 +215,7 @@ /* Utilities can be applied via the @apply directive. */ @layer utilities { .h-leather { - @apply text-gray-800 dark:text-gray-300 pt-4; + @apply text-gray-900 dark:text-gray-100 pt-4; } .h1-leather { @@ -245,11 +245,11 @@ /* Lists */ .ol-leather li a, .ul-leather li a { - @apply text-gray-800 hover:text-primary-400 dark:text-gray-300 dark:hover:text-primary-500; + @apply text-gray-900 hover:text-primary-600 dark:text-gray-100 dark:hover:text-primary-400; } .link { - @apply underline cursor-pointer hover:text-primary-400 dark:hover:text-primary-500; + @apply underline cursor-pointer hover:text-primary-600 dark:hover:text-primary-400; } /* Card with transition */ @@ -286,7 +286,7 @@ /* Tooltip */ .tooltip-leather { - @apply fixed p-4 rounded shadow-lg bg-primary-0 dark:bg-primary-1000 text-gray-800 dark:text-gray-300 border border-gray-200 dark:border-gray-700 transition-colors duration-200; + @apply fixed p-4 rounded shadow-lg bg-primary-0 dark:bg-primary-1000 text-gray-900 dark:text-gray-100 border border-gray-200 dark:border-gray-700 transition-colors duration-200; max-width: 400px; z-index: 1000; } @@ -377,7 +377,7 @@ } .stemblock { - @apply bg-gray-100 dark:bg-gray-900 p-4 rounded-lg; + @apply bg-gray-200 dark:bg-gray-800 p-4 rounded-lg; } .literalblock { @@ -494,7 +494,7 @@ input[type="tel"], input[type="url"], textarea { - @apply bg-primary-0 dark:bg-primary-1000 text-gray-800 dark:text-gray-300 border-s-4 border-primary-200 rounded shadow-none px-4 py-2; - @apply focus:border-primary-400 dark:focus:border-primary-500; + @apply bg-primary-0 dark:bg-primary-1000 text-gray-900 dark:text-gray-100 border-s-4 border-primary-200 rounded shadow-none px-4 py-2; + @apply focus:border-primary-600 dark:focus:border-primary-400; } } \ No newline at end of file diff --git a/src/lib/components/CommentBox.svelte b/src/lib/components/CommentBox.svelte index c46f902..5f279bb 100644 --- a/src/lib/components/CommentBox.svelte +++ b/src/lib/components/CommentBox.svelte @@ -281,7 +281,7 @@ }} /> {/if} - + {userProfile.displayName || userProfile.name || nip19.npubEncode(props.userPubkey).slice(0, 8) + '...'}
diff --git a/src/lib/components/EventDetails.svelte b/src/lib/components/EventDetails.svelte index 17c3d0c..d054cfe 100644 --- a/src/lib/components/EventDetails.svelte +++ b/src/lib/components/EventDetails.svelte @@ -109,31 +109,31 @@
{#if toNpub(event.pubkey)} - Author: {@render userBadge(toNpub(event.pubkey) as string, profile?.display_name || event.pubkey)} + Author: {@render userBadge(toNpub(event.pubkey) as string, profile?.display_name || event.pubkey)} {:else} - Author: {profile?.display_name || event.pubkey} + Author: {profile?.display_name || event.pubkey} {/if}
- Kind: + Kind: {event.kind} - ({getEventTypeDisplay(event)}) + ({getEventTypeDisplay(event)})
{#if getEventSummary(event)}
- Summary: -

{getEventSummary(event)}

+ Summary: +

{getEventSummary(event)}

{/if} {#if getEventHashtags(event).length}
- Tags: + Tags:
{#each getEventHashtags(event) as tag} - #{tag} + #{tag} {/each}
@@ -142,11 +142,11 @@
{#if event.kind !== 0} - Content: + Content:
{@html showFullContent ? parsedContent : contentPreview} {#if !showFullContent && parsedContent.length > 250} - + {/if}
{/if} @@ -160,7 +160,7 @@ {#if event.tags && event.tags.length}
- Event Tags: + Event Tags:
{#each event.tags as tag} {@html renderTag(tag)} diff --git a/src/lib/components/EventLimitControl.svelte b/src/lib/components/EventLimitControl.svelte index d8c28be..a6e3ae8 100644 --- a/src/lib/components/EventLimitControl.svelte +++ b/src/lib/components/EventLimitControl.svelte @@ -45,7 +45,7 @@ /> diff --git a/src/lib/components/EventRenderLevelLimit.svelte b/src/lib/components/EventRenderLevelLimit.svelte index 3a7d8a8..b6addc5 100644 --- a/src/lib/components/EventRenderLevelLimit.svelte +++ b/src/lib/components/EventRenderLevelLimit.svelte @@ -45,7 +45,7 @@ /> diff --git a/src/lib/components/EventSearch.svelte b/src/lib/components/EventSearch.svelte index 36cbdf3..36f67e3 100644 --- a/src/lib/components/EventSearch.svelte +++ b/src/lib/components/EventSearch.svelte @@ -195,7 +195,7 @@ {/each}
{#if !foundEvent && Object.values(relayStatuses).some(s => s === 'pending')} -
Searching relays...
+
Searching relays...
{/if} {#if !foundEvent && !searching && Object.values(relayStatuses).every(s => s !== 'pending')}
Event not found on any relay.
diff --git a/src/lib/components/LoginModal.svelte b/src/lib/components/LoginModal.svelte index 14ffdcb..65d9a35 100644 --- a/src/lib/components/LoginModal.svelte +++ b/src/lib/components/LoginModal.svelte @@ -43,16 +43,16 @@

Login Required

-

+

You need to be logged in to submit an issue. Your form data will be preserved.

diff --git a/src/lib/components/Publication.svelte b/src/lib/components/Publication.svelte index f7e026f..d7fe6d4 100644 --- a/src/lib/components/Publication.svelte +++ b/src/lib/components/Publication.svelte @@ -193,7 +193,7 @@ {:else if !isDone} {:else} -

+

You've reached the end of the publication.

{/if} @@ -287,7 +287,7 @@
Unknown - 1.1.1970 + 1.1.1970
This is a very intelligent comment placeholder that applies to diff --git a/src/lib/components/PublicationFeed.svelte b/src/lib/components/PublicationFeed.svelte index 8f13028..9ea5096 100644 --- a/src/lib/components/PublicationFeed.svelte +++ b/src/lib/components/PublicationFeed.svelte @@ -242,13 +242,13 @@ {:else if loadingMore}
{:else}
-

You've reached the end of the feed.

+

You've reached the end of the feed.

{/if}
diff --git a/src/lib/components/PublicationHeader.svelte b/src/lib/components/PublicationHeader.svelte index 32a674a..d31eae3 100644 --- a/src/lib/components/PublicationHeader.svelte +++ b/src/lib/components/PublicationHeader.svelte @@ -52,7 +52,7 @@ {/if} {#if version != '1'} -

version: {version}

+

version: {version}

{/if}
diff --git a/src/lib/components/RelayActions.svelte b/src/lib/components/RelayActions.svelte index 9645f8c..dc572a9 100644 --- a/src/lib/components/RelayActions.svelte +++ b/src/lib/components/RelayActions.svelte @@ -162,7 +162,7 @@ {#if showRelayModal}
- +

Relay Search Results

{#each Object.entries({ @@ -172,7 +172,7 @@ }) as [groupName, groupRelays]} {#if groupRelays.length > 0}
-

+

{groupName}

{#each groupRelays as relay} diff --git a/src/lib/components/RelayDisplay.svelte b/src/lib/components/RelayDisplay.svelte index 1161f7c..ffaa963 100644 --- a/src/lib/components/RelayDisplay.svelte +++ b/src/lib/components/RelayDisplay.svelte @@ -46,7 +46,7 @@ {relay} {#if showStatus && status} {#if status === 'pending'} - + diff --git a/src/lib/components/cards/BlogHeader.svelte b/src/lib/components/cards/BlogHeader.svelte index a91d0a4..49cd6cd 100644 --- a/src/lib/components/cards/BlogHeader.svelte +++ b/src/lib/components/cards/BlogHeader.svelte @@ -39,7 +39,7 @@
{@render userBadge(authorPubkey, author)} - {publishedAt()} + {publishedAt()}
diff --git a/src/lib/components/util/CardActions.svelte b/src/lib/components/util/CardActions.svelte index 6397d17..8949a0d 100644 --- a/src/lib/components/util/CardActions.svelte +++ b/src/lib/components/util/CardActions.svelte @@ -171,7 +171,7 @@ {/if} {#if version} -

Version: {version}

+

Version: {version}

{/if}
diff --git a/src/lib/components/util/Details.svelte b/src/lib/components/util/Details.svelte index e776e9d..5fe1f06 100644 --- a/src/lib/components/util/Details.svelte +++ b/src/lib/components/util/Details.svelte @@ -53,7 +53,7 @@ {/if} {#if version !== '1' } -

Version: {version}

+

Version: {version}

{/if}
diff --git a/src/lib/components/util/Interactions.svelte b/src/lib/components/util/Interactions.svelte index 52e9bab..b5e48ff 100644 --- a/src/lib/components/util/Interactions.svelte +++ b/src/lib/components/util/Interactions.svelte @@ -80,7 +80,7 @@ } -
+
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index d3cee5c..cd6dc39 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -24,7 +24,7 @@ let searchQuery = $state(''); - + Pardon our dust! The publication view is currently using an experimental loader, and may be unstable. diff --git a/src/routes/about/+page.svelte b/src/routes/about/+page.svelte index a6badf3..5e31c26 100644 --- a/src/routes/about/+page.svelte +++ b/src/routes/about/+page.svelte @@ -15,7 +15,7 @@ > {#if isVersionKnown} Version: {appVersion} {/if} diff --git a/src/routes/contact/+page.svelte b/src/routes/contact/+page.svelte index 4f034f3..d17357b 100644 --- a/src/routes/contact/+page.svelte +++ b/src/routes/contact/+page.svelte @@ -330,7 +330,7 @@
{:else} -
- - - + + + + - - + + {#if rootIndexId} - + {/if} {/if} diff --git a/src/routes/publication/+error.svelte b/src/routes/publication/+error.svelte index 2cbb819..9d0d347 100644 --- a/src/routes/publication/+error.svelte +++ b/src/routes/publication/+error.svelte @@ -1,29 +1,37 @@ -
-
- - - Failed to load publication. - +
+ + Failed to load publication.
-

- Alexandria failed to find one or more of the events comprising this publication. +

+ Alexandria failed to find one or more of the events comprising this + publication.

-

+

{page.error?.message}

-
- -
diff --git a/src/routes/publication/+page.ts b/src/routes/publication/+page.ts index b100f70..b3d0885 100644 --- a/src/routes/publication/+page.ts +++ b/src/routes/publication/+page.ts @@ -1,28 +1,28 @@ -import { error } from '@sveltejs/kit'; -import type { Load } from '@sveltejs/kit'; -import type { NDKEvent } from '@nostr-dev-kit/ndk'; -import { nip19 } from 'nostr-tools'; -import { getActiveRelays } from '$lib/ndk'; -import { getMatchingTags } from '$lib/utils/nostrUtils'; +import { error } from "@sveltejs/kit"; +import type { Load } from "@sveltejs/kit"; +import type { NDKEvent } from "@nostr-dev-kit/ndk"; +import { nip19 } from "nostr-tools"; +import { getActiveRelays } from "$lib/ndk"; +import { getMatchingTags } from "$lib/utils/nostrUtils"; /** * Decodes an naddr identifier and returns a filter object */ function decodeNaddr(id: string) { try { - if (!id.startsWith('naddr')) return {}; - + if (!id.startsWith("naddr")) return {}; + const decoded = nip19.decode(id); - if (decoded.type !== 'naddr') return {}; - + if (decoded.type !== "naddr") return {}; + const data = decoded.data; return { kinds: [data.kind], authors: [data.pubkey], - '#d': [data.identifier] + "#d": [data.identifier], }; } catch (e) { - console.error('Failed to decode naddr:', e); + console.error("Failed to decode naddr:", e); return null; } } @@ -32,7 +32,7 @@ function decodeNaddr(id: string) { */ async function fetchEventById(ndk: any, id: string): Promise { const filter = decodeNaddr(id); - + // Handle the case where filter is null (decoding error) if (filter === null) { // If we can't decode the naddr, try using the raw ID @@ -46,14 +46,14 @@ async function fetchEventById(ndk: any, id: string): Promise { throw error(404, `Failed to fetch publication root event.\n${err}`); } } - + const hasFilter = Object.keys(filter).length > 0; - + try { - const event = await (hasFilter ? - ndk.fetchEvent(filter) : - ndk.fetchEvent(id)); - + const event = await (hasFilter + ? ndk.fetchEvent(filter) + : ndk.fetchEvent(id)); + if (!event) { throw new Error(`Event not found for ID: ${id}`); } @@ -69,11 +69,11 @@ async function fetchEventById(ndk: any, id: string): Promise { async function fetchEventByDTag(ndk: any, dTag: string): Promise { try { const event = await ndk.fetchEvent( - { '#d': [dTag] }, - { closeOnEose: false }, - getActiveRelays(ndk) + { "#d": [dTag] }, + { closeOnEose: false }, + getActiveRelays(ndk), ); - + if (!event) { throw new Error(`Event not found for d tag: ${dTag}`); } @@ -83,21 +83,27 @@ async function fetchEventByDTag(ndk: any, dTag: string): Promise { } } -export const load: Load = async ({ url, parent }: { url: URL; parent: () => Promise }) => { - const id = url.searchParams.get('id'); - const dTag = url.searchParams.get('d'); +export const load: Load = async ({ + url, + parent, +}: { + url: URL; + parent: () => Promise; +}) => { + const id = url.searchParams.get("id"); + const dTag = url.searchParams.get("d"); const { ndk, parser } = await parent(); - + if (!id && !dTag) { - throw error(400, 'No publication root event ID or d tag provided.'); + throw error(400, "No publication root event ID or d tag provided."); } - + // Fetch the event based on available parameters - const indexEvent = id + const indexEvent = id ? await fetchEventById(ndk, id) : await fetchEventByDTag(ndk, dTag!); - - const publicationType = getMatchingTags(indexEvent, 'type')[0]?.[1]; + + const publicationType = getMatchingTags(indexEvent, "type")[0]?.[1]; const fetchPromise = parser.fetch(indexEvent); return { diff --git a/src/routes/start/+page.svelte b/src/routes/start/+page.svelte index 05d0776..fbc77f3 100644 --- a/src/routes/start/+page.svelte +++ b/src/routes/start/+page.svelte @@ -54,10 +54,9 @@ Each content section (30041 or 30818) is also a level in the table of contents, which can be accessed from the floating icon top-left in the reading view. This allows for navigation within the publication. - Publications of type "blog" have a ToC which emphasizes that each entry - is a blog post. - - (This functionality has been temporarily disabled, but the TOC is visible.) + Publications of type "blog" have a ToC which emphasizes that each entry is + a blog post. (This functionality has been temporarily disabled, but the + TOC is visible.)

diff --git a/src/routes/visualize/+page.svelte b/src/routes/visualize/+page.svelte index 21dc2b1..ba2901f 100644 --- a/src/routes/visualize/+page.svelte +++ b/src/routes/visualize/+page.svelte @@ -11,12 +11,12 @@ import type { NDKEvent } from "@nostr-dev-kit/ndk"; import { filterValidIndexEvents } from "$lib/utils"; import { networkFetchLimit } from "$lib/state"; - + // Configuration const DEBUG = false; // Set to true to enable debug logging const INDEX_EVENT_KIND = 30040; const CONTENT_EVENT_KINDS = [30041, 30818]; - + /** * Debug logging function that only logs when DEBUG is true */ @@ -34,7 +34,7 @@ /** * Fetches events from the Nostr network - * + * * This function fetches index events and their referenced content events, * filters them according to NIP-62, and combines them for visualization. */ @@ -47,9 +47,9 @@ // Step 1: Fetch index events debug(`Fetching index events (kind ${INDEX_EVENT_KIND})`); const indexEvents = await $ndkInstance.fetchEvents( - { - kinds: [INDEX_EVENT_KIND], - limit: $networkFetchLimit + { + kinds: [INDEX_EVENT_KIND], + limit: $networkFetchLimit, }, { groupable: true, @@ -68,7 +68,7 @@ validIndexEvents.forEach((event) => { const aTags = event.getMatchingTags("a"); debug(`Event ${event.id} has ${aTags.length} a-tags`); - + aTags.forEach((tag) => { const eventId = tag[3]; if (eventId) { @@ -79,7 +79,9 @@ debug("Content event IDs to fetch:", contentEventIds.size); // Step 4: Fetch the referenced content events - debug(`Fetching content events (kinds ${CONTENT_EVENT_KINDS.join(', ')})`); + debug( + `Fetching content events (kinds ${CONTENT_EVENT_KINDS.join(", ")})`, + ); const contentEvents = await $ndkInstance.fetchEvents( { kinds: CONTENT_EVENT_KINDS, @@ -104,7 +106,6 @@ } } - // Fetch events when component mounts onMount(() => { debug("Component mounted"); @@ -140,7 +141,7 @@ Loading...
- + {:else if error}
- + {:else} diff --git a/src/styles/base.css b/src/styles/base.css index e655206..943b334 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -3,7 +3,7 @@ @tailwind utilities; @layer components { - body { - @apply bg-primary-0 dark:bg-primary-1000; - } -} \ No newline at end of file + body { + @apply bg-primary-0 dark:bg-primary-1000; + } +} diff --git a/src/styles/events.css b/src/styles/events.css index 9e8c202..3c61536 100644 --- a/src/styles/events.css +++ b/src/styles/events.css @@ -1,5 +1,5 @@ @layer components { - canvas.qr-code { - @apply block mx-auto my-4; - } -} \ No newline at end of file + canvas.qr-code { + @apply block mx-auto my-4; + } +} diff --git a/src/styles/publications.css b/src/styles/publications.css index f09a1cf..71b70b6 100644 --- a/src/styles/publications.css +++ b/src/styles/publications.css @@ -1,288 +1,288 @@ @layer components { - /* AsciiDoc content */ - .publication-leather p a { - @apply underline hover:text-primary-600 dark:hover:text-primary-400; - } - - .publication-leather section p { - @apply w-full; - } - - .publication-leather section p table { - @apply w-full table-fixed space-x-2 space-y-2; - } - - .publication-leather section p table td { - @apply p-2; - } - - .publication-leather section p table td .content:has(> .imageblock) { - @apply flex flex-col items-center; - } - - .publication-leather .imageblock { - @apply flex flex-col space-y-2; - } - - .publication-leather .imageblock .content { - @apply flex justify-center; - } - .publication-leather .imageblock .title { - @apply text-center; - } - - .publication-leather .imageblock.left .content { - @apply justify-start; - } - .publication-leather .imageblock.left .title { - @apply text-left; - } - - .publication-leather .imageblock.right .content { - @apply justify-end; - } - .publication-leather .imageblock.right .title { - @apply text-right; - } - - .publication-leather section p table td .literalblock { - @apply my-2 p-2 border rounded border-gray-400 dark:border-gray-600; - } - - .publication-leather .literalblock pre { - @apply p-3 text-wrap break-words; - } - - .publication-leather .listingblock pre { - @apply overflow-x-auto; - } - - /* lists */ - .publication-leather .ulist ul { - @apply space-y-1 list-disc list-inside; - } - - .publication-leather .olist ol { - @apply space-y-1 list-inside; - } - - .publication-leather ol.arabic { - @apply list-decimal; - } - - .publication-leather ol.loweralpha { - @apply list-lower-alpha; - } - - .publication-leather ol.upperalpha { - @apply list-upper-alpha; - } - - .publication-leather li ol, - .publication-leather li ul { - @apply ps-5 my-2; - } - - .audioblock .title, - .imageblock .title, - .literalblock .title, - .tableblock .title, - .videoblock .title, - .olist .title, - .ulist .title { - @apply my-2 font-thin text-lg; - } - - .publication-leather li p { - @apply inline; - } - - /* blockquote; prose and poetry quotes */ - .publication-leather .quoteblock, - .publication-leather .verseblock { - @apply p-4 my-4 border-s-4 rounded border-primary-300 bg-primary-50 dark:border-primary-500 dark:bg-primary-700; - } - - .publication-leather .verseblock pre.content { - @apply text-base font-sans overflow-x-scroll py-1; - } - - .publication-leather .attribution { - @apply mt-3 italic clear-both; - } - - .publication-leather cite { - @apply text-sm; - } - - .leading-normal.first-letter\:text-7xl .quoteblock { - min-height: 108px; - } - - /* admonition */ - .publication-leather .admonitionblock .title { - @apply font-semibold; - } - - .publication-leather .admonitionblock table { - @apply w-full border-collapse; - } - - .publication-leather .admonitionblock tr { - @apply flex flex-col border-none; - } - - .publication-leather .admonitionblock td { - @apply border-none; - } - - .publication-leather .admonitionblock p:has(code) { - @apply my-3; - } - - .publication-leather .admonitionblock { - @apply rounded overflow-hidden border; - } - - .publication-leather .admonitionblock .icon, - .publication-leather .admonitionblock .content { - @apply p-4; - } - - .publication-leather .admonitionblock .content { - @apply pt-0; - } - - .publication-leather .admonitionblock.tip { - @apply rounded overflow-hidden border border-success-100 dark:border-success-800; - } - - .publication-leather .admonitionblock.tip .icon, - .publication-leather .admonitionblock.tip .content { - @apply bg-success-100 dark:bg-success-800; - } - - .publication-leather .admonitionblock.note { - @apply rounded overflow-hidden border border-info-100 dark:border-info-700; - } - - .publication-leather .admonitionblock.note .icon, - .publication-leather .admonitionblock.note .content { - @apply bg-info-100 dark:bg-info-800; - } - - .publication-leather .admonitionblock.important { - @apply rounded overflow-hidden border border-primary-200 dark:border-primary-700; - } - - .publication-leather .admonitionblock.important .icon, - .publication-leather .admonitionblock.important .content { - @apply bg-primary-200 dark:bg-primary-700; - } - - .publication-leather .admonitionblock.caution { - @apply rounded overflow-hidden border border-warning-200 dark:border-warning-700; - } - - .publication-leather .admonitionblock.caution .icon, - .publication-leather .admonitionblock.caution .content { - @apply bg-warning-200 dark:bg-warning-700; - } - - .publication-leather .admonitionblock.warning { - @apply rounded overflow-hidden border border-danger-200 dark:border-danger-800; - } - - .publication-leather .admonitionblock.warning .icon, - .publication-leather .admonitionblock.warning .content { - @apply bg-danger-200 dark:bg-danger-800; - } - - /* listingblock, literalblock */ - .publication-leather .listingblock, - .publication-leather .literalblock { - @apply p-4 rounded bg-highlight dark:bg-primary-700; - } - - .publication-leather .sidebarblock .title, - .publication-leather .listingblock .title, - .publication-leather .literalblock .title { - @apply font-semibold mb-1; - } - - /* sidebar */ - .publication-leather .sidebarblock { - @apply p-4 rounded bg-info-100 dark:bg-info-800; - } - - /* video */ - .videoblock .content { - @apply w-full aspect-video; - } - - .videoblock .content iframe, - .videoblock .content video { - @apply w-full h-full; - } - - /* audio */ - .audioblock .content { - @apply my-3; - } - - .audioblock .content audio { - @apply w-full; - } - - .coverImage { - @apply max-h-[230px] overflow-hidden; - } - - .coverImage.depth-0 { - @apply max-h-[460px] overflow-hidden; - } - - .coverImage img { - @apply object-contain w-full; - } - - .coverImage.depth-0 img { - @apply m-auto w-auto; - } - - /** blog */ - @screen lg { - @media (hover: hover) { - .blog .discreet .card-leather:not(:hover) { - @apply bg-primary-50 dark:bg-primary-1000 opacity-75 transition duration-500 ease-in-out ; - } - .blog .discreet .group { - @apply bg-transparent; - } - } - } - - /* Discrete headers */ - h3.discrete, - h4.discrete, - h5.discrete, - h6.discrete { - @apply text-gray-800 dark:text-gray-300; - } - - h3.discrete { - @apply text-2xl font-bold; - } - - h4.discrete { - @apply text-xl font-bold; - } - - h5.discrete { - @apply text-lg font-semibold; - } - - h6.discrete { - @apply text-base font-semibold; - } -} \ No newline at end of file + /* AsciiDoc content */ + .publication-leather p a { + @apply underline hover:text-primary-600 dark:hover:text-primary-400; + } + + .publication-leather section p { + @apply w-full; + } + + .publication-leather section p table { + @apply w-full table-fixed space-x-2 space-y-2; + } + + .publication-leather section p table td { + @apply p-2; + } + + .publication-leather section p table td .content:has(> .imageblock) { + @apply flex flex-col items-center; + } + + .publication-leather .imageblock { + @apply flex flex-col space-y-2; + } + + .publication-leather .imageblock .content { + @apply flex justify-center; + } + .publication-leather .imageblock .title { + @apply text-center; + } + + .publication-leather .imageblock.left .content { + @apply justify-start; + } + .publication-leather .imageblock.left .title { + @apply text-left; + } + + .publication-leather .imageblock.right .content { + @apply justify-end; + } + .publication-leather .imageblock.right .title { + @apply text-right; + } + + .publication-leather section p table td .literalblock { + @apply my-2 p-2 border rounded border-gray-400 dark:border-gray-600; + } + + .publication-leather .literalblock pre { + @apply p-3 text-wrap break-words; + } + + .publication-leather .listingblock pre { + @apply overflow-x-auto; + } + + /* lists */ + .publication-leather .ulist ul { + @apply space-y-1 list-disc list-inside; + } + + .publication-leather .olist ol { + @apply space-y-1 list-inside; + } + + .publication-leather ol.arabic { + @apply list-decimal; + } + + .publication-leather ol.loweralpha { + @apply list-lower-alpha; + } + + .publication-leather ol.upperalpha { + @apply list-upper-alpha; + } + + .publication-leather li ol, + .publication-leather li ul { + @apply ps-5 my-2; + } + + .audioblock .title, + .imageblock .title, + .literalblock .title, + .tableblock .title, + .videoblock .title, + .olist .title, + .ulist .title { + @apply my-2 font-thin text-lg; + } + + .publication-leather li p { + @apply inline; + } + + /* blockquote; prose and poetry quotes */ + .publication-leather .quoteblock, + .publication-leather .verseblock { + @apply p-4 my-4 border-s-4 rounded border-primary-300 bg-primary-50 dark:border-primary-500 dark:bg-primary-700; + } + + .publication-leather .verseblock pre.content { + @apply text-base font-sans overflow-x-scroll py-1; + } + + .publication-leather .attribution { + @apply mt-3 italic clear-both; + } + + .publication-leather cite { + @apply text-sm; + } + + .leading-normal.first-letter\:text-7xl .quoteblock { + min-height: 108px; + } + + /* admonition */ + .publication-leather .admonitionblock .title { + @apply font-semibold; + } + + .publication-leather .admonitionblock table { + @apply w-full border-collapse; + } + + .publication-leather .admonitionblock tr { + @apply flex flex-col border-none; + } + + .publication-leather .admonitionblock td { + @apply border-none; + } + + .publication-leather .admonitionblock p:has(code) { + @apply my-3; + } + + .publication-leather .admonitionblock { + @apply rounded overflow-hidden border; + } + + .publication-leather .admonitionblock .icon, + .publication-leather .admonitionblock .content { + @apply p-4; + } + + .publication-leather .admonitionblock .content { + @apply pt-0; + } + + .publication-leather .admonitionblock.tip { + @apply rounded overflow-hidden border border-success-100 dark:border-success-800; + } + + .publication-leather .admonitionblock.tip .icon, + .publication-leather .admonitionblock.tip .content { + @apply bg-success-100 dark:bg-success-800; + } + + .publication-leather .admonitionblock.note { + @apply rounded overflow-hidden border border-info-100 dark:border-info-700; + } + + .publication-leather .admonitionblock.note .icon, + .publication-leather .admonitionblock.note .content { + @apply bg-info-100 dark:bg-info-800; + } + + .publication-leather .admonitionblock.important { + @apply rounded overflow-hidden border border-primary-200 dark:border-primary-700; + } + + .publication-leather .admonitionblock.important .icon, + .publication-leather .admonitionblock.important .content { + @apply bg-primary-200 dark:bg-primary-700; + } + + .publication-leather .admonitionblock.caution { + @apply rounded overflow-hidden border border-warning-200 dark:border-warning-700; + } + + .publication-leather .admonitionblock.caution .icon, + .publication-leather .admonitionblock.caution .content { + @apply bg-warning-200 dark:bg-warning-700; + } + + .publication-leather .admonitionblock.warning { + @apply rounded overflow-hidden border border-danger-200 dark:border-danger-800; + } + + .publication-leather .admonitionblock.warning .icon, + .publication-leather .admonitionblock.warning .content { + @apply bg-danger-200 dark:bg-danger-800; + } + + /* listingblock, literalblock */ + .publication-leather .listingblock, + .publication-leather .literalblock { + @apply p-4 rounded bg-highlight dark:bg-primary-700; + } + + .publication-leather .sidebarblock .title, + .publication-leather .listingblock .title, + .publication-leather .literalblock .title { + @apply font-semibold mb-1; + } + + /* sidebar */ + .publication-leather .sidebarblock { + @apply p-4 rounded bg-info-100 dark:bg-info-800; + } + + /* video */ + .videoblock .content { + @apply w-full aspect-video; + } + + .videoblock .content iframe, + .videoblock .content video { + @apply w-full h-full; + } + + /* audio */ + .audioblock .content { + @apply my-3; + } + + .audioblock .content audio { + @apply w-full; + } + + .coverImage { + @apply max-h-[230px] overflow-hidden; + } + + .coverImage.depth-0 { + @apply max-h-[460px] overflow-hidden; + } + + .coverImage img { + @apply object-contain w-full; + } + + .coverImage.depth-0 img { + @apply m-auto w-auto; + } + + /** blog */ + @screen lg { + @media (hover: hover) { + .blog .discreet .card-leather:not(:hover) { + @apply bg-primary-50 dark:bg-primary-1000 opacity-75 transition duration-500 ease-in-out; + } + .blog .discreet .group { + @apply bg-transparent; + } + } + } + + /* Discrete headers */ + h3.discrete, + h4.discrete, + h5.discrete, + h6.discrete { + @apply text-gray-800 dark:text-gray-300; + } + + h3.discrete { + @apply text-2xl font-bold; + } + + h4.discrete { + @apply text-xl font-bold; + } + + h5.discrete { + @apply text-lg font-semibold; + } + + h6.discrete { + @apply text-base font-semibold; + } +} diff --git a/src/styles/scrollbar.css b/src/styles/scrollbar.css index 8d2735d..4691a9b 100644 --- a/src/styles/scrollbar.css +++ b/src/styles/scrollbar.css @@ -1,20 +1,20 @@ @layer components { - /* Global scrollbar styles */ - * { - scrollbar-color: rgba(87, 66, 41, 0.8) transparent; /* Transparent track, default scrollbar thumb */ - } + /* Global scrollbar styles */ + * { + scrollbar-color: rgba(87, 66, 41, 0.8) transparent; /* Transparent track, default scrollbar thumb */ + } - /* Webkit Browsers (Chrome, Safari, Edge) */ - *::-webkit-scrollbar { - width: 12px; /* Thin scrollbar */ - } + /* Webkit Browsers (Chrome, Safari, Edge) */ + *::-webkit-scrollbar { + width: 12px; /* Thin scrollbar */ + } - *::-webkit-scrollbar-track { - background: transparent; /* Fully transparent track */ - } + *::-webkit-scrollbar-track { + background: transparent; /* Fully transparent track */ + } - *::-webkit-scrollbar-thumb { - @apply bg-primary-500 dark:bg-primary-600 hover:bg-primary-600 dark:hover:bg-primary-800;; - border-radius: 6px; /* Rounded scrollbar */ - } -} \ No newline at end of file + *::-webkit-scrollbar-thumb { + @apply bg-primary-500 dark:bg-primary-600 hover:bg-primary-600 dark:hover:bg-primary-800; + border-radius: 6px; /* Rounded scrollbar */ + } +} diff --git a/src/styles/visualize.css b/src/styles/visualize.css index 1ff732d..a2f8374 100644 --- a/src/styles/visualize.css +++ b/src/styles/visualize.css @@ -1,112 +1,112 @@ @layer components { - /* Legend styles - specific to visualization */ - .legend-list { - @apply list-disc mt-2 space-y-2 text-gray-800 dark:text-gray-300; - } - - .legend-item { - @apply flex items-center; - } - - .legend-icon { - @apply relative w-6 h-6 mr-2; - } - - .legend-circle { - @apply absolute inset-0 rounded-full border-2 border-black; - } - - .legend-circle.content { - @apply bg-gray-700 dark:bg-gray-300; - background-color: #d6c1a8; - } - - .legend-circle.content { - background-color: var(--content-color, #d6c1a8); - } - - :global(.dark) .legend-circle.content { - background-color: var(--content-color-dark, #FFFFFF); - } - - .legend-letter { - @apply absolute inset-0 flex items-center justify-center text-black text-xs font-bold; - } - - .legend-text { - @apply text-sm; - } - - /* Network visualization styles - specific to visualization */ - .network-container { - @apply flex flex-col w-full h-[calc(100vh-138px)] min-h-[400px] max-h-[900px]; - } - - .network-svg-container { - @apply relative sm:h-[100%]; - } - - .network-svg { - @apply w-full sm:h-[100%] border; - @apply border border-primary-200 has-[:hover]:border-primary-700 dark:bg-primary-1000 dark:border-primary-800 dark:has-[:hover]:bg-primary-950 dark:has-[:hover]:border-primary-500 rounded; - } - - .network-error { - @apply w-full p-4 bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200 rounded-lg mb-4; - } - - .network-error-title { - @apply font-bold text-lg; - } - - .network-error-retry { - @apply mt-2 px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700; - } - - .network-debug { - @apply mt-4 text-sm text-gray-500; - } - - /* Zoom controls */ - .network-controls { - @apply absolute bottom-4 right-4 flex flex-col gap-2 z-10; - } - - .network-control-button { - @apply bg-white; - } - - /* Tooltip styles - specific to visualization tooltips */ - .tooltip-close-btn { - @apply absolute top-2 right-2 bg-gray-200 hover:bg-gray-300 dark:bg-gray-700 dark:hover:bg-gray-600 + /* Legend styles - specific to visualization */ + .legend-list { + @apply list-disc mt-2 space-y-2 text-gray-800 dark:text-gray-300; + } + + .legend-item { + @apply flex items-center; + } + + .legend-icon { + @apply relative w-6 h-6 mr-2; + } + + .legend-circle { + @apply absolute inset-0 rounded-full border-2 border-black; + } + + .legend-circle.content { + @apply bg-gray-700 dark:bg-gray-300; + background-color: #d6c1a8; + } + + .legend-circle.content { + background-color: var(--content-color, #d6c1a8); + } + + :global(.dark) .legend-circle.content { + background-color: var(--content-color-dark, #ffffff); + } + + .legend-letter { + @apply absolute inset-0 flex items-center justify-center text-black text-xs font-bold; + } + + .legend-text { + @apply text-sm; + } + + /* Network visualization styles - specific to visualization */ + .network-container { + @apply flex flex-col w-full h-[calc(100vh-138px)] min-h-[400px] max-h-[900px]; + } + + .network-svg-container { + @apply relative sm:h-[100%]; + } + + .network-svg { + @apply w-full sm:h-[100%] border; + @apply border border-primary-200 has-[:hover]:border-primary-700 dark:bg-primary-1000 dark:border-primary-800 dark:has-[:hover]:bg-primary-950 dark:has-[:hover]:border-primary-500 rounded; + } + + .network-error { + @apply w-full p-4 bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200 rounded-lg mb-4; + } + + .network-error-title { + @apply font-bold text-lg; + } + + .network-error-retry { + @apply mt-2 px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700; + } + + .network-debug { + @apply mt-4 text-sm text-gray-500; + } + + /* Zoom controls */ + .network-controls { + @apply absolute bottom-4 right-4 flex flex-col gap-2 z-10; + } + + .network-control-button { + @apply bg-white; + } + + /* Tooltip styles - specific to visualization tooltips */ + .tooltip-close-btn { + @apply absolute top-2 right-2 bg-gray-200 hover:bg-gray-300 dark:bg-gray-700 dark:hover:bg-gray-600 rounded-full p-1 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200; - } + } - .tooltip-content { - @apply space-y-2 pr-6; - } + .tooltip-content { + @apply space-y-2 pr-6; + } - .tooltip-title { - @apply font-bold text-base; - } + .tooltip-title { + @apply font-bold text-base; + } - .tooltip-title-link { - @apply text-gray-800 hover:text-blue-600 dark:text-gray-200 dark:hover:text-blue-400; - } + .tooltip-title-link { + @apply text-gray-800 hover:text-blue-600 dark:text-gray-200 dark:hover:text-blue-400; + } - .tooltip-metadata { - @apply text-gray-600 dark:text-gray-400 text-sm; - } + .tooltip-metadata { + @apply text-gray-600 dark:text-gray-400 text-sm; + } - .tooltip-summary { - @apply mt-2 text-xs bg-gray-100 dark:bg-gray-900 p-2 rounded overflow-auto max-h-40; - } + .tooltip-summary { + @apply mt-2 text-xs bg-gray-100 dark:bg-gray-900 p-2 rounded overflow-auto max-h-40; + } - .tooltip-content-preview { - @apply mt-2 text-xs bg-gray-100 dark:bg-gray-900 p-2 rounded overflow-auto max-h-40; - } + .tooltip-content-preview { + @apply mt-2 text-xs bg-gray-100 dark:bg-gray-900 p-2 rounded overflow-auto max-h-40; + } - .tooltip-help-text { - @apply mt-2 text-xs text-gray-500 dark:text-gray-400 italic; - } + .tooltip-help-text { + @apply mt-2 text-xs text-gray-500 dark:text-gray-400 italic; + } } diff --git a/src/types/d3.d.ts b/src/types/d3.d.ts index 3d230f5..2b12771 100644 --- a/src/types/d3.d.ts +++ b/src/types/d3.d.ts @@ -1,19 +1,19 @@ /** * Type declarations for D3.js and related modules - * + * * These declarations allow TypeScript to recognize D3 imports without requiring * detailed type definitions. For a project requiring more type safety, consider * using the @types/d3 package and its related sub-packages. */ // Core D3 library -declare module 'd3'; +declare module "d3"; // Force simulation module for graph layouts -declare module 'd3-force'; +declare module "d3-force"; // DOM selection and manipulation module -declare module 'd3-selection'; +declare module "d3-selection"; // Drag behavior module -declare module 'd3-drag'; +declare module "d3-drag"; diff --git a/src/types/global.d.ts b/src/types/global.d.ts index a1ade26..4e2e76a 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -2,4 +2,4 @@ interface Window { hljs?: { highlightAll: () => void; }; -} \ No newline at end of file +} diff --git a/src/types/plantuml-encoder.d.ts b/src/types/plantuml-encoder.d.ts index 8149f62..0e6c137 100644 --- a/src/types/plantuml-encoder.d.ts +++ b/src/types/plantuml-encoder.d.ts @@ -1,5 +1,5 @@ -declare module 'plantuml-encoder' { +declare module "plantuml-encoder" { export function encode(text: string): string; const _default: { encode: typeof encode }; export default _default; -} \ No newline at end of file +} diff --git a/tailwind.config.cjs b/tailwind.config.cjs index e28c2eb..5bd3b5f 100644 --- a/tailwind.config.cjs +++ b/tailwind.config.cjs @@ -12,110 +12,110 @@ const config = { theme: { extend: { colors: { - highlight: '#f9f6f1', + highlight: "#f9f6f1", primary: { - 0: '#efe6dc', - 50: '#decdb9', - 100: '#d6c1a8', - 200: '#c6a885', - 300: '#b58f62', - 400: '#ad8351', - 500: '#c6a885', - 600: '#795c39', - 700: '#564a3e', - 800: '#3c352c', - 900: '#2a241c', - 950: '#1d1812', - 1000: '#15110d', + 0: "#efe6dc", + 50: "#decdb9", + 100: "#d6c1a8", + 200: "#c6a885", + 300: "#b58f62", + 400: "#ad8351", + 500: "#c6a885", + 600: "#795c39", + 700: "#564a3e", + 800: "#3c352c", + 900: "#2a241c", + 950: "#1d1812", + 1000: "#15110d", }, success: { - 50: '#e3f2e7', - 100: '#c7e6cf', - 200: '#a2d4ae', - 300: '#7dbf8e', - 400: '#5ea571', - 500: '#4e8e5f', - 600: '#3e744c', - 700: '#305b3b', - 800: '#22412a', - 900: '#15281b', + 50: "#e3f2e7", + 100: "#c7e6cf", + 200: "#a2d4ae", + 300: "#7dbf8e", + 400: "#5ea571", + 500: "#4e8e5f", + 600: "#3e744c", + 700: "#305b3b", + 800: "#22412a", + 900: "#15281b", }, info: { - 50: '#e7eff6', - 100: '#c5d9ea', - 200: '#9fbfdb', - 300: '#7aa5cc', - 400: '#5e90be', - 500: '#4779a5', - 600: '#365d80', - 700: '#27445d', - 800: '#192b3a', - 900: '#0d161f', + 50: "#e7eff6", + 100: "#c5d9ea", + 200: "#9fbfdb", + 300: "#7aa5cc", + 400: "#5e90be", + 500: "#4779a5", + 600: "#365d80", + 700: "#27445d", + 800: "#192b3a", + 900: "#0d161f", }, warning: { - 50: '#fef4e6', - 100: '#fde4bf', - 200: '#fcd18e', - 300: '#fbbc5c', - 400: '#f9aa33', - 500: '#f7971b', - 600: '#c97a14', - 700: '#9a5c0e', - 800: '#6c3e08', - 900: '#3e2404', + 50: "#fef4e6", + 100: "#fde4bf", + 200: "#fcd18e", + 300: "#fbbc5c", + 400: "#f9aa33", + 500: "#f7971b", + 600: "#c97a14", + 700: "#9a5c0e", + 800: "#6c3e08", + 900: "#3e2404", }, danger: { - 50: '#fbeaea', - 100: '#f5cccc', - 200: '#eba5a5', - 300: '#e17e7e', - 400: '#d96060', - 500: '#c94848', - 600: '#a53939', - 700: '#7c2b2b', - 800: '#521c1c', - 900: '#2b0e0e', + 50: "#fbeaea", + 100: "#f5cccc", + 200: "#eba5a5", + 300: "#e17e7e", + 400: "#d96060", + 500: "#c94848", + 600: "#a53939", + 700: "#7c2b2b", + 800: "#521c1c", + 900: "#2b0e0e", }, }, listStyleType: { - 'upper-alpha': 'upper-alpha', // Uppercase letters - 'lower-alpha': 'lower-alpha', // Lowercase letters + "upper-alpha": "upper-alpha", // Uppercase letters + "lower-alpha": "lower-alpha", // Lowercase letters }, flexGrow: { - '1': '1', - '2': '2', - '3': '3', + 1: "1", + 2: "2", + 3: "3", }, hueRotate: { - 20: '20deg', - } + 20: "20deg", + }, }, }, plugins: [ flowbite(), - plugin(function({ addUtilities, matchUtilities }) { + plugin(function ({ addUtilities, matchUtilities }) { addUtilities({ - '.content-visibility-auto': { - 'content-visibility': 'auto', + ".content-visibility-auto": { + "content-visibility": "auto", }, - '.contain-size': { - contain: 'size', + ".contain-size": { + contain: "size", }, }); matchUtilities({ - 'contain-intrinsic-w-*': value => ({ + "contain-intrinsic-w-*": (value) => ({ width: value, }), - 'contain-intrinsic-h-*': value => ({ + "contain-intrinsic-h-*": (value) => ({ height: value, - }) + }), }); - }) + }), ], - darkMode: 'class', + darkMode: "class", }; module.exports = config; diff --git a/test_data/latex_markdown.md b/test_data/latex_markdown.md new file mode 100644 index 0000000..0317f22 --- /dev/null +++ b/test_data/latex_markdown.md @@ -0,0 +1,50 @@ +{ +"created*at": 1752035710, +"content": "## 1 Introduction\n\nThe P versus NP problem asks whether every problem verifiable in polynomial time (NP) can be solved in polynomial time (P) [1]. The NP-complete Boolean Satisfiability (SAT) problem, determining if a conjunctive normal form formula has a satisfying assignment, is central to this question [2]. Proving that 3-SAT requires super-polynomial time would imply $P \\neq NP$, impacting computer science, cryptography, and optimization [3].\n\nWe prove $P \\neq NP$ by reformulating 3-SAT as an optimization problem using categorical and graph-theoretic frameworks. A 2-category models SAT’s logical constraints, while a clause graph captures satisfiability combinatorially [4]. A constraint measure and topological invariant establish that determining satisfiability requires exponential time [5,6]. Unlike combinatorial or algebraic methods [3], our approach leverages category theory and graph theory for a novel perspective.\n\nThe paper is organized as follows: Section 2 defines a 2-category for SAT; Section 3 presents an optimization problem; Section 4 introduces a constraint measure; Section 5 proves exponential time complexity; and Section 6 provides a graph-theoretic reformulation.\n\n## 2 Categorical Reformulation of SAT\n\nTo prove $P \\neq NP$, we reformulate the Boolean Satisfiability (SAT) problem as an optimization problem using a 2-category framework. Variables and clauses of a SAT instance are encoded as vectors and linear transformations in a complex vector space, with their logical structure modeled by a strict 2-category [4,7]. This allows satisfiability to be tested via compositions of transformations, setting up the constraint measure defined in Section 4.\n\n### 2.1 Construction of the 2-Category\n\nFor a SAT instance $\\phi = C_1 \\wedge \\cdots \\wedge C_m$, where each clause $C_j = l*{j1} \\vee \\cdots \\vee l*{jk}$ is a disjunction of $k \\leq n$ literals (with $l*{ji} = x*i$ or $\\neg x_i$ for variables $x_1, \\ldots, x_n$), we define a strict 2-category $\\mathcal{C}$ to encode $\\phi$’s logical structure.\n\n**Definition 2.1 (2-Category $\\mathcal{C}$)** \nThe 2-category $\\mathcal{C}$ consists of:\n- *Objects*: Vectors in the complex vector space $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes n}$, dimension $2^n$, representing variable assignments. For each variable $x_i$, define basis vectors:\n - $\\mathbf{v}_i = (1, 0) \\in \\mathbb{C}^2$, for $x_i = \\text{True}$.\n - $\\mathbf{w}_i = (0, 1) \\in \\mathbb{C}^2$, for $\\neg x_i = \\text{False}$.\n \n A configuration, e.g., $\\mathbf{v}_1 \\otimes \\mathbf{w}_2 \\otimes \\mathbf{v}_3 \\in \\mathcal{V}$, represents $x_1 = \\text{True}, x_2 = \\text{False}, x_3 = \\text{True}$.\n\n- *1-Morphisms*: Linear maps $f: \\mathcal{V} \\to \\mathcal{V}$, including:\n - *Clause projections* $P_j: \\mathcal{V} \\to \\mathcal{V}$, for clause $C_j$ with variables indexed by $I_j \\subseteq \\{1, \\ldots, n\\}$, defined as:\n $$\n P_j = \\bigotimes*{i=1}^n Q*i, \\quad Q_i = \\begin{cases} \n I - |\\mathbf{l}*{ji}\\rangle\\langle \\mathbf{l}_{ji}| & \\text{if } i \\in I_j, \\\\\n I & \\text{otherwise},\n \\end{cases}\n $$\n where $\\mathbf{l}_{ji} = \\mathbf{v}_i$ if $l_{ji} = x*i$, or $\\mathbf{l}*{ji} = \\mathbf{w}_i$ if $l_{ji} = \\neg x*i$, and $I$ is the identity on $\\mathbb{C}^2$. Thus, $P_j v = v$ if $v$ satisfies $C_j$; otherwise, $P_j v$ lies in the orthogonal complement.\n - *Identity maps* $\\text{id}_A: A \\to A$, for subspaces $A \\subseteq \\mathcal{V}$.\n - *Negation maps* $N_i: \\mathcal{V} \\to \\mathcal{V}$, swapping $\\mathbf{v}_i \\leftrightarrow \\mathbf{w}_i$ on the $i$-th tensor factor:\n $$\n N_i = I \\otimes \\cdots \\otimes \\begin{pmatrix} 0 & 1 \\\\ 1 & 0 \\end{pmatrix} \\otimes \\cdots \\otimes I.\n $$\n\n- *2-Morphisms*: Natural transformations $\\alpha: f \\Rightarrow g$ between 1-morphisms $f, g: A \\to B$, where $A, B \\subseteq \\mathcal{V}$. A 2-morphism $\\alpha$ is a linear map ensuring that if $f$ and $g$ represent assignments, $f$ satisfies all clauses satisfied by $g$, preserving the logical structure of $\\phi$ [4].\n\n- *Compositions*: Horizontal composition $\\beta \\circ \\alpha: g \\circ f \\Rightarrow g' \\circ f'$ for 2-morphisms $\\alpha: f \\Rightarrow f'$, $\\beta: g \\Rightarrow g'$, and vertical composition $\\beta \\cdot \\alpha: f \\Rightarrow h$ for $\\alpha: f \\Rightarrow g$, $\\beta: g \\Rightarrow h$, defined via linear map composition. Associativity and identity laws ensure $\\mathcal{C}$ is a strict 2-category [4].\n\nThe 2-category $\\mathcal{C}$ encodes SAT as follows: vectors in $\\mathcal{V}$ represent assignments, projections $P_j$ enforce clause constraints, negation maps $N_i$ handle negated literals, and 2-morphisms preserve logical consistency across transformations [7].\n\n### 2.2 Satisfiability via Projection Composition\n\nSatisfiability of $\\phi$ is tested by composing the clause projections:\n$$\nP = P_m \\circ \\cdots \\circ P_1: \\mathcal{V} \\to \\mathcal{V}.\n$$\nFor a normalized vector $v \\in \\mathcal{V}, \\|v\\|=1$, $\\phi$ is satisfiable if there exists $v$ such that $P v = v$, meaning $P_j v = v$ for all $j = 1, \\ldots, m$, corresponding to a satisfying assignment. If $\\phi$ is unsatisfiable, the intersection of projection images $\\bigcap*{j=1}^m \\text{im}(P*j) = \\emptyset$, so $P v \\neq v$ for all $v$. This composition reformulates SAT as finding a fixed point of $P$, which we analyze as an optimization problem in Section 3 using a distance metric.\n\n### 2.3 Example: 3-SAT Instance\n\nConsider a 3-SAT instance with $n=3$ variables, $\\phi = (x_1 \\vee \\neg x_2 \\vee x_3) \\wedge (\\neg x_1 \\vee x_2 \\vee \\neg x_3)$, encoded in $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes 3}$. Assign $\\mathbf{v}_i = (1, 0)$, $\\mathbf{w}_i = (0, 1)$ for $x_i = \\text{True}$, $\\neg x_i = \\text{False}$. For clause $C_1 = x_1 \\vee \\neg x_2 \\vee x_3$, the projection is:\n$$\nP_1 = I - (I - |\\mathbf{v}_1\\rangle\\langle \\mathbf{v}_1|) \\otimes (I - |\\mathbf{w}_2\\rangle\\langle \\mathbf{w}_2|) \\otimes (I - |\\mathbf{v}_3\\rangle\\langle \\mathbf{v}_3|).\n$$\nFor $C_2 = \\neg x_1 \\vee x_2 \\vee \\neg x_3$:\n$$\nP_2 = I - (I - |\\mathbf{w}_1\\rangle\\langle \\mathbf{w}_1|) \\otimes (I - |\\mathbf{v}_2\\rangle\\langle \\mathbf{v}_2|) \\otimes (I - |\\mathbf{w}_3\\rangle\\langle \\mathbf{w}_3|).\n$$\nThe assignment $x_1 = x_2 = x_3 = \\text{True}$, represented by $v = \\mathbf{v}_1 \\otimes \\mathbf{v}_2 \\otimes \\mathbf{v}_3$, satisfies $C_1$ ($x_1 = \\text{True}$) and $C_2$ ($x_2 = \\text{True}$). Thus, $P_1 v = v$, $P_2 v = v$, and $P v = P_2 \\circ P_1 v = v$, confirming satisfiability.\n\n## 3 Optimization Problem for SAT\n\nWe reformulate the Boolean Satisfiability (SAT) problem as an optimization problem, where satisfiability is determined by minimizing a distance metric between configurations under the projection composition defined in Section 2.2. Building on the 2-category $\\mathcal{C}$ (Section 2), this approach quantifies deviations from satisfiability, with satisfiable instances achieving zero deviation and unsatisfiable ones exhibiting a positive gap [8].\n\n### 3.1 Configuration Space and Distance Metric\n\n**Definition 3.1 (Configuration Space)** \nThe configuration space $\\mathcal{D}(\\mathcal{V})$ consists of positive semi-definite operators $\\rho$ on $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes n}$, dimension $2^n$, with trace $\\text{Tr}(\\rho) = 1$. Pure configurations, such as $\\rho_v = |v\\rangle\\langle v|$ for a normalized vector $v \\in \\mathcal{V}$, correspond to classical assignments (e.g., $v = \\mathbf{v}_1 \\otimes \\mathbf{v}_2 \\otimes \\mathbf{v}_3$ for $x_1 = x_2 = x_3 = \\text{True}$, where $\\mathbf{v}_i = (1, 0)$).\n\nThe space $\\mathcal{D}(\\mathcal{V})$ is convex and compact, equipped with a metric to measure distances between configurations [8]. We use the Bures distance due to its compatibility with the transformations in $\\mathcal{C}$.\n\n**Definition 3.2 (Bures Distance)** \nFor $\\rho, \\sigma \\in \\mathcal{D}(\\mathcal{V})$, the Bures distance is:\n$$\nd_B(\\rho, \\sigma) = \\sqrt{2 \\left( 1 - \\sqrt{F(\\rho, \\sigma)} \\right)},\n$$\nwhere the fidelity is $F(\\rho, \\sigma) = \\left( \\text{Tr} \\sqrt{\\sqrt{\\rho} \\sigma \\sqrt{\\rho}} \\right)^2$. For pure configurations $\\rho = |u\\rangle\\langle u|$, $\\sigma = |v\\rangle\\langle v|$ with $u, v \\in \\mathcal{V}, \\|u\\| = \\|v\\| = 1$, it simplifies to:\n$$\nd_B(\\rho, \\sigma) = \\sqrt{2 (1 - |\\langle u | v \\rangle|)},\n$$\nsince $|\\langle u | v \\rangle|$ is real and non-negative for normalized vectors [8].\n\nThe Bures distance is a metric on $\\mathcal{D}(\\mathcal{V})$, satisfying positivity, symmetry, and the triangle inequality [8]. It is suitable for measuring deviations induced by clause projections $P_j: \\mathcal{V} \\to \\mathcal{V}$ (Section 2.1), as it aligns with the 2-category’s structure [9,10].\n\n### 3.2 Optimization Problem\n\nFor the projection composition $P = P_m \\circ \\cdots \\circ P_1: \\mathcal{V} \\to \\mathcal{V}$ (Section 2.2), we define a deviation measure to reformulate SAT as an optimization problem.\n\n**Definition 3.3 (Deviation Measure)** \nThe deviation measure for a configuration $\\rho \\in \\mathcal{D}(\\mathcal{V})$ is:\n$$\nd_B(\\rho, P(\\rho)),\n$$\nwhere:\n$$\nP(\\rho) = \\frac{P \\rho P^\\dagger}{\\text{Tr}(P \\rho P^\\dagger)},\n$$\nif $\\text{Tr}(P \\rho P^\\dagger) \\neq 0$, and $P(\\rho) = 0$ otherwise. The SAT problem is equivalent to minimizing:\n$$\nS[\\rho] = d_B(\\rho, P(\\rho))^2,\n$$\nover $\\rho \\in \\mathcal{D}(\\mathcal{V})$.\n\nThe deviation measure quantifies how far $\\rho$ is from being invariant under $P$. For a pure configuration $\\rho_v = |v\\rangle\\langle v|$, $v \\in \\mathcal{V}, \\|v\\|=1$:\n- If $\\phi$ is satisfiable, there exists $\\rho_v$ such that $P_j \\rho_v = \\rho_v$ for all $j$, so $P(\\rho_v) = \\rho_v$ and $d_B(\\rho_v, P(\\rho_v)) = 0$.\n- If $\\phi$ is unsatisfiable, $\\bigcap*{j=1}^m \\text{im}(P*j) = \\emptyset$, so $P(\\rho) = 0$ for all $\\rho \\in \\mathcal{D}(\\mathcal{V})$, and $d_B(\\rho, P(\\rho)) = \\sqrt{2}$ [8].\n\nThus, the infimum satisfies:\n$$\n\\inf*{\\rho \\in \\mathcal{D}(\\mathcal{V})} S[\\rho] = \\begin{cases} \n0 & \\text{if } \\phi \\text{ is satisfiable}, \\\\\n2 & \\text{if } \\phi \\text{ is unsatisfiable}.\n\\end{cases}\n$$\nWe focus on pure configurations $\\rho_v$, as they correspond to classical assignments and suffice to determine satisfiability, aligning with the constraint measure $\\lambda(v) = \\sum_{j=1}^m M_j(v)$ in Section 4 [8].\n\n### 3.3 Example: 3-SAT Instance\n\nConsider the 3-SAT instance $\\phi = (x_1 \\vee \\neg x_2 \\vee x_3) \\wedge (\\neg x_1 \\vee x_2 \\vee \\neg x_3)$ with $n=3$, as in Section 2.3, using $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes 3}$. For the assignment $x_1 = x_2 = x_3 = \\text{True}$, the pure configuration is $\\rho = |\\mathbf{v}_1 \\otimes \\mathbf{v}_2 \\otimes \\mathbf{v}_3\\rangle\\langle \\mathbf{v}_1 \\otimes \\mathbf{v}_2 \\otimes \\mathbf{v}_3|$, where $\\mathbf{v}_i = (1, 0)$. The clause projections are as in Section 2.3. Since $\\mathbf{v}_1 \\otimes \\mathbf{v}_2 \\otimes \\mathbf{v}_3$ satisfies $C_1$ ($x_1 = \\text{True}$) and $C_2$ ($x_2 = \\text{True}$), we have $P_1 \\rho = \\rho$, $P_2 \\rho = \\rho$, so $P(\\rho) = P_2 (P_1 \\rho) = \\rho$, and:\n$$\nd*B(\\rho, P(\\rho)) = 0.\n$$\nFor an unsatisfiable 3-SAT instance, consider $\\phi = (x_1 \\vee x_2) \\wedge (\\neg x_1 \\vee \\neg x_2) \\wedge (x_1 \\vee \\neg x_2) \\wedge (\\neg x_1 \\vee x_2)$. For any $\\rho \\in \\mathcal{D}(\\mathcal{V})$, the projections conflict, so $P(\\rho) = 0$, yielding:\n$$\nd_B(\\rho, P(\\rho)) = \\sqrt{2}.\n$$\nThis gap ($0$ vs. $\\sqrt{2}$) distinguishes satisfiable from unsatisfiable instances, aligning with the constraint measure in Section 4.\n\n## 4 Constraint Measure for SAT\n\nWe define a constraint measure $\\lambda(v)$ for a SAT instance, quantifying clause violations in the 2-category $\\mathcal{C}$ (Section 2). This measure distinguishes satisfiable from unsatisfiable instances via a positive gap, aligning with the optimization problem in Section 3 and enabling the complexity analysis in Section 5 [2].\n\n### 4.1 Constraint Measure and Satisfiability Gap\n\n**Definition 4.1 (Constraint Measure)** \nFor a SAT instance $\\phi = C_1 \\wedge \\cdots \\wedge C_m$ with $n$ variables, represented in $\\mathcal{C}$, the constraint measure $\\lambda: \\mathcal{V} \\to \\mathbb{R}*{\\geq 0}$ on the configuration space $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes n}$ is:\n$$\n\\lambda(v) = \\sum_{j=1}^m M_j(v),\n$$\nwhere $v \\in \\mathcal{V}, \\|v\\|=1$, and the clause mapping $M_j: \\mathcal{V} \\to \\mathbb{R}_{\\geq 0}$ for clause $C_j$ is:\n$$\nM_j(v) = \\text{Tr}((I - P_j) \\rho_v),\n$$\nwith $\\rho_v = |v\\rangle\\langle v|$ and $P_j: \\mathcal{V} \\to \\mathcal{V}$ the clause projection (Definition 2.1). The minimum penalty is:\n$$\n\\lambda_{\\min} = \\inf_{v \\in \\mathcal{V}, \\|v\\|=1} \\lambda(v).\n$$\n\nThe mapping $M_j(v) = 0$ if $v$ satisfies $C_j$ (i.e., $P_j v = v$), and $M_j(v) \\geq \\delta > 0$ otherwise, where $\\delta$ is a constant reflecting the orthogonal distance to the satisfying subspace, determined by the clause structure (e.g., up to three literals in 3-SAT) [8]. The measure $\\lambda(v)$ sums clause violations, with $\\lambda_{\\min} = 0$ indicating satisfiability. This aligns with the optimization problem in Section 3.2, where $\\lambda(v) = 0$ corresponds to $d_B(\\rho_v, P(\\rho_v)) = 0$ for a pure configuration $\\rho_v = |v\\rangle\\langle v|$ [2].\n\n**Theorem 4.1 (Satisfiability Gap)** \nFor a SAT instance $\\phi$, the minimum penalty satisfies:\n$$\n\\lambda_{\\min} = \\begin{cases} \n0 & \\text{if } \\phi \\text{ is satisfiable}, \\\\\nc & \\text{if } \\phi \\text{ is unsatisfiable},\n\\end{cases}\n$$\nwhere $c \\geq \\delta > 0$ is a constant independent of $n$ or $m$.\n\n**Proof.** \nConsider $\\phi = C_1 \\wedge \\cdots \\wedge C_m$ with configurations in $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes n}$. Each clause $C_j$ has a projection $P_j$ (Section 2.1), where $P_j v = v$ if $v$ satisfies $C_j$, and $P_j v$ lies in the orthogonal complement otherwise.\n\n**Case 1: Satisfiable.** If $\\phi$ is satisfiable, there exists an assignment $a = (a_1, \\ldots, a_n) \\in \\{0,1\\}^n$ satisfying all clauses. Construct $v_a \\in \\mathcal{V}$ as the tensor product of $\\mathbf{v}_i = (1, 0)$ for $a_i = 1$ or $\\mathbf{w}_i = (0, 1)$ for $a_i = 0$, with $\\|v_a\\|=1$. Since $a$ satisfies each $C_j$, we have $P_j v_a = v_a$, so:\n$$\nM_j(v_a) = \\text{Tr}((I - P_j) \\rho_{v_a}) = \\langle v_a | (I - P_j) v_a \\rangle = 0.\n$$\nThus, $\\lambda(v_a) = \\sum_{j=1}^m M_j(v_a) = 0$, and since $\\lambda(v) \\geq 0$, we have $\\lambda_{\\min} = 0$.\n\n**Case 2: Unsatisfiable.** If $\\phi$ is unsatisfiable, no $v \\in \\mathcal{V}, \\|v\\|=1$ satisfies all clauses. For any $v$, at least one clause $C_j$ is violated, so $P_j v \\neq v$, and:\n$$\nM_j(v) = \\langle v | (I - P_j) v \\rangle \\geq \\delta > 0,\n$$\nwhere $\\delta > 0$ is a constant determined by the clause structure [8]. Thus, $\\lambda(v) \\geq \\delta$, and:\n$$\n\\lambda_{\\min} = \\inf_{v \\in \\mathcal{V}, \\|v\\|=1} \\lambda(v) \\geq \\delta.\n$$\nSet $c = \\delta$, independent of $n$ or $m$. The projection composition $P = P_m \\circ \\cdots \\circ P_1$ (Section 2.2) yields $P(\\rho_v) = 0$ for unsatisfiable instances, confirming the gap: $\\lambda_{\\min} \\geq c > 0$. $\\square$\n\nThe gap ($\\lambda_{\\min} = 0$ vs. $c > 0$) mirrors the optimization gap in Section 3.2 ($S[\\rho] = 0$ vs. $2$), linking $\\lambda(v)$ to the complexity analysis in Section 5.\n\n### 4.2 Example: 3-SAT Instance\n\nFor the satisfiable 3-SAT instance $\\phi = (x_1 \\vee \\neg x_2 \\vee x_3) \\wedge (\\neg x_1 \\vee x_2 \\vee \\neg x_3)$ with $n=3$, using $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes 3}$ (Section 2.3), consider the assignment $x_1 = x_2 = x_3 = \\text{True}$, with $v_a = \\mathbf{v}_1 \\otimes \\mathbf{v}_2 \\otimes \\mathbf{v}_3$, $\\mathbf{v}_i = (1, 0)$, $\\|v_a\\|=1$. The projections $P_1, P_2$ are defined as in Section 2.3. Since $v_a$ satisfies $C_1$ ($x_1 = \\text{True}$) and $C_2$ ($x_2 = \\text{True}$), we have $P_1 v_a = v_a$, $P_2 v_a = v_a$, so:\n$$\nM_1(v_a) = \\text{Tr}((I - P_1) \\rho_{v_a}) = 0, \\quad M_2(v_a) = \\text{Tr}((I - P_2) \\rho_{v_a}) = 0.\n$$\nThus, $\\lambda(v_a) = 0$, so $\\lambda_{\\min} = 0$.\n\nFor an unsatisfiable 3-SAT instance, consider $\\phi = (x_1 \\vee x_2) \\wedge (\\neg x_1 \\vee \\neg x_2) \\wedge (x_1 \\vee \\neg x_2) \\wedge (\\neg x_1 \\vee x_2)$. For any $v \\in \\mathcal{V}, \\|v\\|=1$, at least one clause is violated. For $v = \\mathbf{v}_1 \\otimes \\mathbf{v}_2$, satisfying the first clause, the second clause $\\neg x_1 \\vee \\neg x_2$ is violated, so:\n$$\nP_2 v \\neq v, \\quad M_2(v) = \\text{Tr}((I - P_2) \\rho_v) \\geq \\delta > 0.\n$$\nThus, $\\lambda(v) \\geq \\delta$, and $\\lambda_{\\min} \\geq c = \\delta > 0$. This gap illustrates the theorem’s distinction between satisfiable and unsatisfiable instances.\n\n## 5 Exponential Time Complexity of 3-SAT\n\nWe prove that computing the satisfiability of a 3-SAT instance, an NP-complete problem, requires exponential time in the number of variables $n$, establishing $P \\neq NP$. This builds on the 2-category $\\mathcal{C}$ (Section 2), optimization problem (Section 3), and constraint measure $\\lambda(v)$ (Section 4), showing that computing the minimum penalty $\\lambda_{\\min}$ demands exponential time [1,2].\n\n### 5.1 Hardness of Computing the Minimum Penalty\n\nFor a 3-SAT instance $\\phi = C_1 \\wedge \\cdots \\wedge C_m$ with $n$ variables and $m = O(n)$ clauses, each with up to three literals, satisfiability is equivalent to determining whether $\\lambda_{\\min} = \\inf_{v \\in \\mathcal{V}, \\|v\\|=1} \\lambda(v) = 0$, where $\\lambda(v) = \\sum_{j=1}^m M_j(v)$ is the constraint measure on $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes n}$, with $M_j(v) = \\text{Tr}((I - P_j) \\rho_v)$, $\\rho_v = |v\\rangle\\langle v|$, and $P_j$ the clause projection (Section 4.1). For example, the satisfiable 3-SAT instance from Section 2.3 has $\\lambda_{\\min} = 0$, while the unsatisfiable instance from Section 4.2 has $\\lambda_{\\min} \\geq c$.\n\n**Theorem 5.1 (Exponential Time for $\\lambda_{\\min}$)** \nComputing $\\lambda_{\\min}$ for worst-case 3-SAT instances requires $\\Omega(2^{kn})$ time for some constant $k > 0$, unless $P = NP$.\n\n**Proof.** \nBy the Satisfiability Gap Theorem (Theorem 4.1), $\\lambda_{\\min} = 0$ if $\\phi$ is satisfiable (there exists $v \\in \\mathcal{V}, \\|v\\|=1$ such that $P_j v = v$ for all $j$), and $\\lambda_{\\min} \\geq c = \\delta > 0$ otherwise, where $\\delta$ is a constant. Exact computation of $\\lambda_{\\min}$ over $\\mathcal{V}$, dimension $2^n$, requires evaluating $\\lambda(v)$ for $O(2^n)$ basis configurations, taking $O(2^{3n})$ time due to matrix operations [11]. We show that even approximating $\\lambda_{\\min}$ to decide satisfiability is NP-hard.\n\n**Lemma 5.1 (Hardness of Approximation)** \nApproximating $\\lambda_{\\min}$ to within additive error $\\epsilon < c/m$ requires $\\Omega(2^{kn})$ time for some $k > 0$, unless $P = NP$.\n\n**Proof.** \nFor a satisfiable $\\phi$, there exists $v$ such that $\\lambda(v) = 0$, so $\\lambda_{\\min} = 0$. For an unsatisfiable $\\phi$, every $v$ violates at least one clause, so $\\lambda(v) \\geq \\delta$, and $\\lambda_{\\min} \\geq c = \\delta$. An algorithm outputting a value $< c/m$ for satisfiable instances ($\\lambda_{\\min} = 0$) and $\\geq c/2$ for unsatisfiable instances ($\\lambda_{\\min} \\geq c$) distinguishes $\\lambda_{\\min} = 0$ from $\\lambda_{\\min} \\geq c$, as $c/m < c/2$ for $m \\geq 2$, solving 3-SAT.\n\nSince 3-SAT is NP-complete [1], and MAX-3-SAT inapproximability [6] shows that distinguishing fully satisfiable instances from those with at most a $1 - 1/8$ fraction satisfiable is NP-hard, approximating $\\lambda_{\\min}$ within $\\epsilon < c/m$ (with $m = O(n)$) is equivalent to solving 3-SAT. The projections $P_j$ encode 3-SAT’s combinatorial structure (Section 2.1), requiring $\\Omega(2^{kn})$ evaluations of $\\lambda(v)$ to find a satisfying configuration [5,6]. A polynomial-time approximation algorithm would imply $P = NP$. $\\square$\n\nThus, computing $\\lambda_{\\min}$ requires $\\Omega(2^{kn})$ time unless $P = NP$. $\\square$\n\n### 5.2 Implications and Complexity Barriers\n\nThe exponential time requirement for computing $\\lambda_{\\min}$ for 3-SAT implies that no polynomial-time algorithm exists for 3-SAT unless $P = NP$. Since 3-SAT is reducible to any NP problem [1], this extends to all NP problems, yielding:\n$$\n\\boxed{P \\neq NP}\n$$\n\nOur categorical approach avoids known complexity barriers [12,13]. The _relativization barrier_ [12] is sidestepped because the proof relies on the categorical structure of $\\mathcal{C}$ and the linear algebraic properties of $\\mathcal{V}$, which encode 3-SAT’s constraints non-relativizingly, unlike diagonalization techniques [2,4]. The _natural proofs barrier_ [13] is avoided as the proof is non-constructive (no efficient algorithm is provided) and problem-specific to 3-SAT’s clause structure, not broadly applicable to Boolean functions. These properties ensure the proof’s robustness, relying on standard NP-hardness assumptions [1,5,6].\n\n## 6 Graph-Theoretic Reformulation of 3-SAT\n\nTo reinforce the proof that $P \\neq NP$, we reformulate the 3-SAT problem as a graph-theoretic problem on a clause graph, preserving the constraint measure $\\lambda(v)$ (Section 4) as a combinatorial invariant. By showing that computing this invariant requires exponential time, we provide an alternative confirmation of the exponential complexity of 3-SAT, supporting the result of Section 5 [1,2].\n\n### 6.1 Clause Graph and Connectivity Index\n\nFor a 3-SAT instance $\\phi = C_1 \\wedge \\cdots \\wedge C_m$ with $n$ variables and $m = O(n)$ clauses, we define a clause graph to encode satisfiability combinatorially.\n\n**Definition 6.1 (Clause Graph)** \nThe clause graph $G_\\phi = (V, E)$ is defined as:\n- _Vertices_ $V$: Configurations in $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes n}$, representing variable assignments (Section 2.1).\n- _Edges_ $E$: Pairs $(v, v')$ where $v, v' \\in \\mathcal{V}, \\|v\\| = \\|v'\\| = 1$, differ in at most one variable, and satisfy the same clauses $C_j$, i.e., $P_j v = v$ and $P_j v' = v'$ for some $j$, with $P_j$ the clause projection (Definition 2.1).\n\nThe graph $G_\\phi$ connects configurations with similar clause satisfaction profiles. For a satisfiable $\\phi$, there exists a configuration $v$ such that $P_j v = v$ for all $j$, forming a connected component in $G_\\phi$ where all vertices satisfy $\\phi$. For an unsatisfiable $\\phi$, no such component exists, as every $v$ violates at least one clause (Section 4.1). For the satisfiable instance $\\phi = (x_1 \\vee \\neg x_2 \\vee x_3) \\wedge (\\neg x_1 \\vee x_2 \\vee \\neg x_3)$ (Section 2.3) with $n=3$, the clause graph $G_\\phi$ has $2^3 = 8$ vertices, and includes a connected component containing $v = \\mathbf{v}_1 \\otimes \\mathbf{v}_2 \\otimes \\mathbf{v}_3$, with $\\kappa_\\phi = 1$. For the unsatisfiable instance $\\phi = (x_1 \\vee x_2) \\wedge (\\neg x_1 \\vee \\neg x_2) \\wedge (x_1 \\vee \\neg x_2) \\wedge (\\neg x_1 \\vee x_2)$ (Section 4.2) with $n=2$, the graph has $2^2 = 4$ vertices, and no such component exists, so $\\kappa_\\phi = 0$.\n\n**Definition 6.2 (Connectivity Index)** \nThe connectivity index $\\kappa_\\phi$ is 1 if there exists a connected component in $G_\\phi$ where all vertices satisfy $\\phi$ (i.e., $P_j v = v$ for all $j$), and 0 otherwise.\n\nThe index $\\kappa_\\phi$ mirrors the constraint measure’s minimum penalty $\\lambda_{\\min}$ (Section 4.1). If $\\lambda_{\\min} = 0$, there exists $v$ with $\\lambda(v) = 0$, corresponding to $\\kappa_\\phi = 1$. If $\\lambda_{\\min} \\geq c > 0$, no configuration satisfies all clauses, so $\\kappa_\\phi = 0$. This invariant captures satisfiability combinatorially [2].\n\n### 6.2 Exponential Time Complexity\n\n**Theorem 6.1** \nComputing the connectivity index $\\kappa_\\phi$ for worst-case 3-SAT instances requires $\\Omega(2^{kn})$ time for some constant $k > 0$, unless $P = NP$.\n\n**Proof.** \nComputing $\\kappa_\\phi$ requires identifying a connected component in $G_\\phi$ where all vertices satisfy $\\phi$. Each vertex $v \\in \\mathcal{V}$, dimension $2^n$, represents a variable assignment, and edges connect $v$ to $O(n)$ neighbors differing in one variable. For satisfiable $\\phi$, there exists a component where all vertices have $\\lambda(v) = 0$ (Section 4.1), so $\\kappa_\\phi = 1$. For unsatisfiable $\\phi$, every vertex violates at least one clause, so $\\kappa_\\phi = 0$. Since 3-SAT’s combinatorial structure ensures that any satisfying configuration $v$ (where $P_j v = v$ for all $j$) implies a non-empty component, checking one such $v$ is equivalent to solving 3-SAT.\n\nDetermining whether $\\kappa_\\phi = 1$ is equivalent to finding a configuration $v$ such that $P_j v = v$ for all $j$, i.e., solving 3-SAT. Since $\\mathcal{V}$ has $2^n$ vertices, evaluating clause satisfaction (via projections $P_j$) for each vertex and checking connectivity requires $\\Omega(2^n)$ operations. The NP-completeness of 3-SAT [1] and MAX-3-SAT inapproximability [6] imply that distinguishing $\\kappa_\\phi = 1$ from $\\kappa_\\phi = 0$ is NP-hard, requiring $\\Omega(2^{kn})$ time for some $k > 0$ due to the combinatorial structure of clause interactions [5]. A polynomial-time algorithm for computing $\\kappa_\\phi$ would solve 3-SAT, implying $P = NP$. $\\square$\n\nThis graph-theoretic reformulation reinforces the exponential time complexity of 3-SAT (Section 5), as computing $\\kappa_\\phi$ mirrors the hardness of computing $\\lambda_{\\min}$, confirming $P \\neq NP$.\n\n## 7 Conclusion\n\nWe prove that $P \\neq NP$ by reformulating the NP-complete 3-SAT problem in categorical and graph-theoretic frameworks. A 2-category and a clause graph model 3-SAT, enabling an optimization problem and connectivity analysis that confirm $P \\neq NP$ (Sections 2, 6). By defining a constraint measure and a topological invariant, we show that determining satisfiability requires exponential time (Sections 4, 5, 6) [1,5,6]. Unlike combinatorial or algebraic approaches [3], our methods leverage category theory and graph theory, offering novel insights into computational complexity. The proof avoids relativization and natural proofs barriers by being non-relativizing and specific to 3-SAT, ensuring robustness [12,13]. This result confirms that NP-complete problems require super-polynomial time unless $P = NP$. Future work could extend these frameworks to other NP-complete problems [2,4].\n\n$$\n\\boxed{P \\neq NP}\n$$\n\n---\n\n## References\n\n1. Cook, Stephen A. \"The complexity of theorem-proving procedures.\" _Proceedings of the Third Annual ACM Symposium on Theory of Computing (STOC '71)_, 151–158, ACM, New York, NY, USA, 1971. DOI: 10.1145/800157.805047.\n2. Arora, Sanjeev and Barak, Boaz. _Computational Complexity: A Modern Approach_. Cambridge University Press, Cambridge, UK, 2009.\n3. Fortnow, Lance. \"The status of the P versus NP problem.\" _Communications of the ACM_ 56(9): 78–86, 2013. DOI: 10.1145/2500468.2500487.\n4. Leinster, Tom. _Basic Category Theory_. Cambridge University Press, Cambridge, UK, 2014.\n5. Dinur, Irit and Safra, Shmuel. \"On the hardness of approximating minimum vertex cover.\" _Annals of Mathematics_ 162(1): 439–485, 2007. DOI: 10.4007/annals.2007.162.439.\n6. Håstad, Johan. \"Some optimal inapproximability results.\" _Journal of the ACM_ 48(4): 798–859, 2001. DOI: 10.1145/502090.502098.\n7. Mac Lane, Saunders. _Categories for the Working Mathematician_, 2nd ed. Springer, New York, NY, USA, 1998.\n8. Bengtsson, Ingemar and Życzkowski, Karol. _Geometry of Quantum States: An Introduction to Quantum Entanglement_. Cambridge University Press, Cambridge, UK, 2006.\n9. Petz, Dénes. \"Monotone metrics on matrix spaces.\" _Linear Algebra and its Applications_ 244: 81–96, 1996. DOI: 10.1016/0024-3795(94)00211-8.\n10. Petz, Dénes and Sudár, Csaba. \"Geometries of quantum states.\" _Journal of Mathematical Physics_ 37(6): 2662–2673, 1996. DOI: 10.1063/1.531551.\n11. Golub, Gene H. and Van Loan, Charles F. _Matrix Computations_, 3rd ed. Johns Hopkins University Press, Baltimore, MD, USA, 1996.\n12. Baker, Theodore P. and Gill, John and Solovay, Robert. \"Relativizations of the P =? NP question.\" _SIAM Journal on Computing_ 4(4): 431–442, 1975. DOI: 10.1137/0204037.\n13. Razborov, Alexander A. and Rudich, Steven. \"Natural proofs.\" _Journal of Computer and System Sciences_ 55(1): 24–35, 1997. DOI: 10.1006/jcss.1997.1494.", +"tags": [ +[ +"d", +"1752035287698" +], +[ +"title", +"Proving P ≠ NP via Categorical and Graph-Theoretic 3-SAT" +], +[ +"summary", +"We prove that $P \\neq NP$ by reformulating the NP-complete 3-SAT problem as an optimization problem using categorical and graph-theoretic frameworks. A 2-category encodes 3-SAT’s variables and clauses as vectors and transformations in a complex vector space, while a clause graph captures satisfiability as a connectivity property, with a constraint measure and invariant distinguishing satisfiable and unsatisfiable cases. Computing either requires exponential time, establishing $P \\neq NP$. This dual approach, leveraging category theory and graph theory, offers a novel perspective on computational complexity." +], +[ +"t", +"math" +], +[ +"t", +"p vs np" +], +[ +"t", +"complexity theory" +], +[ +"t", +"category theory" +], +[ +"t", +"graph theory" +], +[ +"published_at", +"1752035704" +], +[ +"alt", +"This is a long form article, you can read it in https://habla.news/a/naddr1qvzqqqr4gupzqwe6gtf5eu9pgqk334fke8f2ct43ccqe4y2nhetssnypvhge9ce9qqxnzde4xgcrxdfj8qmnvwfc69lg5m" +] +], +"kind": 30023, +"pubkey": "3b3a42d34cf0a1402d18d536c9d2ac2eb1c6019a9153be57084c8165d192e325", +"id": "4afdd068904f12c370913ca3c8744b71fae258e59457fad6f3c28ddffb8f0f41", +"sig": "6be4cf6472b98c80c659e472d8db3bc8c144a1c551c821d1cfd925dade26b395690f71b38631e49d180d7ec79fbbbbcb148df27a40955ef22479e7bec36bd6ad" +} diff --git a/tests/e2e/example.pw.spec.ts b/tests/e2e/example.pw.spec.ts index 54a906a..b60fe7c 100644 --- a/tests/e2e/example.pw.spec.ts +++ b/tests/e2e/example.pw.spec.ts @@ -1,18 +1,20 @@ -import { test, expect } from '@playwright/test'; +import { test, expect } from "@playwright/test"; -test('has title', async ({ page }) => { - await page.goto('https://playwright.dev/'); +test("has title", async ({ page }) => { + await page.goto("https://playwright.dev/"); // Expect a title "to contain" a substring. await expect(page).toHaveTitle(/Playwright/); }); -test('get started link', async ({ page }) => { - await page.goto('https://playwright.dev/'); +test("get started link", async ({ page }) => { + await page.goto("https://playwright.dev/"); // Click the get started link. - await page.getByRole('link', { name: 'Get started' }).click(); + await page.getByRole("link", { name: "Get started" }).click(); // Expects page to have a heading with the name of Installation. - await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible(); + await expect( + page.getByRole("heading", { name: "Installation" }), + ).toBeVisible(); }); diff --git a/tests/integration/markupIntegration.test.ts b/tests/integration/markupIntegration.test.ts index b4de512..a834593 100644 --- a/tests/integration/markupIntegration.test.ts +++ b/tests/integration/markupIntegration.test.ts @@ -1,42 +1,50 @@ -import { describe, it, expect } from 'vitest'; -import { parseBasicmarkup } from '../../src/lib/utils/markup/basicMarkupParser'; -import { parseAdvancedmarkup } from '../../src/lib/utils/markup/advancedMarkupParser'; -import { readFileSync } from 'fs'; -import { join } from 'path'; +import { describe, it, expect } from "vitest"; +import { parseBasicmarkup } from "../../src/lib/utils/markup/basicMarkupParser"; +import { parseAdvancedmarkup } from "../../src/lib/utils/markup/advancedMarkupParser"; +import { readFileSync } from "fs"; +import { join } from "path"; -const testFilePath = join(__dirname, './markupTestfile.md'); -const md = readFileSync(testFilePath, 'utf-8'); +const testFilePath = join(__dirname, "./markupTestfile.md"); +const md = readFileSync(testFilePath, "utf-8"); -describe('Markup Integration Test', () => { - it('parses markupTestfile.md with the basic parser', async () => { +describe("Markup Integration Test", () => { + it("parses markupTestfile.md with the basic parser", async () => { const output = await parseBasicmarkup(md); - // Headers (should be present as text, not

tags) - expect(output).toContain('This is a test'); - expect(output).toContain('============'); - expect(output).toContain('### Disclaimer'); + // Headers (should be present as raw text, not HTML tags) + expect(output).toContain("This is a test"); + expect(output).toContain("# This is a test"); + expect(output).toContain("### Disclaimer"); // Unordered list - expect(output).toContain(']*>.*]*>/s); // Blockquotes - expect(output).toContain(''); + expect(output).toContain( + '
', + ); // Images - expect(output).toMatch(/]+src="https:\/\/upload\.wikimedia\.org\/wikipedia\/commons\/f\/f1\/Heart_coraz%C3%B3n\.svg"/); + expect(output).toMatch( + /]+src="https:\/\/upload\.wikimedia\.org\/wikipedia\/commons\/f\/f1\/Heart_coraz%C3%B3n\.svg"/, + ); // Links - expect(output).toMatch(/]+href="https:\/\/github.com\/nostrability\/nostrability\/issues\/146"/); + expect(output).toMatch( + /]+href="https:\/\/github.com\/nostrability\/nostrability\/issues\/146"/, + ); // Hashtags - expect(output).toContain('text-primary-600'); + expect(output).toContain("text-primary-600"); // Nostr identifiers (should be Alexandria links) - expect(output).toContain('./events?id=npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z'); + expect(output).toContain( + "./events?id=npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z", + ); // Wikilinks - expect(output).toContain('wikilink'); + expect(output).toContain("wikilink"); // YouTube iframe expect(output).toMatch(/]+youtube/); // Tracking token removal: should not contain utm_, fbclid, or gclid in any link @@ -44,42 +52,50 @@ describe('Markup Integration Test', () => { expect(output).not.toMatch(/fbclid/); expect(output).not.toMatch(/gclid/); // Horizontal rule (should be present as --- in basic) - expect(output).toContain('---'); + expect(output).toContain("---"); // Footnote references (should be present as [^1] in basic) - expect(output).toContain('[^1]'); + expect(output).toContain("[^1]"); // Table (should be present as | Syntax | Description | in basic) - expect(output).toContain('| Syntax | Description |'); + expect(output).toContain("| Syntax | Description |"); }); - it('parses markupTestfile.md with the advanced parser', async () => { + it("parses markupTestfile.md with the advanced parser", async () => { const output = await parseAdvancedmarkup(md); // Headers - expect(output).toContain(']*>.*]*>/s); // Blockquotes - expect(output).toContain(']*>.*leather min-h-full w-full flex flex-col items-center.*<\/code>/s); + expect(output).toMatch( + /]*>.*leather min-h-full w-full flex flex-col items-center.*<\/code>/s, + ); // Images - expect(output).toMatch(/]+src="https:\/\/upload\.wikimedia\.org\/wikipedia\/commons\/f\/f1\/Heart_coraz%C3%B3n\.svg"/); + expect(output).toMatch( + /]+src="https:\/\/upload\.wikimedia\.org\/wikipedia\/commons\/f\/f1\/Heart_coraz%C3%B3n\.svg"/, + ); // Links - expect(output).toMatch(/]+href="https:\/\/github.com\/nostrability\/nostrability\/issues\/146"/); + expect(output).toMatch( + /]+href="https:\/\/github.com\/nostrability\/nostrability\/issues\/146"/, + ); // Hashtags - expect(output).toContain('text-primary-600'); + expect(output).toContain("text-primary-600"); // Nostr identifiers (should be Alexandria links) - expect(output).toContain('./events?id=npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z'); + expect(output).toContain( + "./events?id=npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z", + ); // Wikilinks - expect(output).toContain('wikilink'); + expect(output).toContain("wikilink"); // YouTube iframe expect(output).toMatch(/]+youtube/); // Tracking token removal: should not contain utm_, fbclid, or gclid in any link @@ -87,13 +103,13 @@ describe('Markup Integration Test', () => { expect(output).not.toMatch(/fbclid/); expect(output).not.toMatch(/gclid/); // Horizontal rule - expect(output).toContain('/); // Table - expect(output).toContain(' lines of > important information > with a second[^2] footnote. -[^2]: This is a "Test" of a longer footnote-reference, placed inline, including some punctuation. 1984. +> [^2]: This is a "Test" of a longer footnote-reference, placed inline, including some punctuation. 1984. -This is a youtube link +This is a youtube link https://www.youtube.com/watch?v=9aqVxNCpx9s And here is a link with tracking tokens: https://arstechnica.com/science/2019/07/new-data-may-extend-norse-occupancy-in-north-america/?fbclid=IwAR1LOW3BebaMLinfkWFtFpzkLFi48jKNF7P6DV2Ux2r3lnT6Lqj6eiiOZNU This is an unordered list: -* but -* not -* really + +- but +- not +- really This is an unordered list with nesting: -* but - * not - * really -* but - * yes, - * really - + +- but + - not + - really +- but + - yes, + - really + ## More testing An ordered list: + 1. first 2. second 3. third Let's nest that: -1. first - 2. second indented -3. third - 4. fourth indented - 5. fifth indented even more - 6. sixth under the fourth - 7. seventh under the sixth -8. eighth under the third + +1. first 2. second indented +2. third 4. fourth indented 5. fifth indented even more 6. sixth under the fourth 7. seventh under the sixth +3. eighth under the third This is ordered and unordered mixed: -1. first - 2. second indented -3. third - * make this a bullet point - 4. fourth indented even more - * second bullet point + +1. first 2. second indented +2. third + - make this a bullet point 4. fourth indented even more + - second bullet point Here is a horizontal rule: @@ -130,13 +132,31 @@ in a code block You can even use a multi-line code block, with a json tag. -```json +````json { -"created_at":1745038670,"content":"# This is a test\n\nIt is _only_ a test. I just wanted to see if the *markup* renders correctly on the page, even if I use **two asterisks** for bold text.[^1]\n\nnpub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z wrote this. That's the same person as nostr:npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z. That is a different person from npub1s3ht77dq4zqnya8vjun5jp3p44pr794ru36d0ltxu65chljw8xjqd975wz.\n\n> This is important information\n\n> This is multiple\n> lines of\n> important information\n> with a second[^2] footnote.\n\n* but\n* not\n* really\n\n## More testing\n\n1. first\n2. second\n3. third\n\nHere is a horizontal rule:\n\n---\n\nThis is an implementation of [Nostr-flavored markup](github.com/nostrability/nostrability/issues/146 ) for #gitstuff issue notes.\n\nYou can even include `code inline` or\n\n```\nin a code block\n```\n\nYou can even use a \n\n```json\nmultiline of json block\n```\n\n\n![Nostr logo](https://user-images.githubusercontent.com/99301796/219900773-d6d02038-e2a0-4334-9f28-c14d40ab6fe7.png)\n\n[^1]: this is a footnote\n[^2]: so is this","tags":[["subject","test"],["alt","git repository issue: test"],["a","30617:fd208ee8c8f283780a9552896e4823cc9dc6bfd442063889577106940fd927c1:Alexandria","","root"],["p","fd208ee8c8f283780a9552896e4823cc9dc6bfd442063889577106940fd927c1"],["t","gitstuff"]],"kind":1621,"pubkey":"dd664d5e4016433a8cd69f005ae1480804351789b59de5af06276de65633d319","id":"e78a689369511fdb3c36b990380c2d8db2b5e62f13f6b836e93ef5a09611afe8","sig":"7a2b3a6f6f61b6ea04de1fe873e46d40f2a220f02cdae004342430aa1df67647a9589459382f22576c651b3d09811546bbd79564cf472deaff032f137e94a865" + "created_at": 1745038670, + "content": "# This is a test\n\nIt is _only_ a test. I just wanted to see if the *markup* renders correctly on the page, even if I use **two asterisks** for bold text.[^1]\n\nnpub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z wrote this. That's the same person as nostr:npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z. That is a different person from npub1s3ht77dq4zqnya8vjun5jp3p44pr794ru36d0ltxu65chljw8xjqd975wz.\n\n> This is important information\n\n> This is multiple\n> lines of\n> important information\n> with a second[^2] footnote.\n\n* but\n* not\n* really\n\n## More testing\n\n1. first\n2. second\n3. third\n\nHere is a horizontal rule:\n\n---\n\nThis is an implementation of [Nostr-flavored markup](github.com/nostrability/nostrability/issues/146 ) for #gitstuff issue notes.\n\nYou can even include `code inline` or\n\n```\nin a code block\n```\n\nYou can even use a \n\n```json\nmultiline of json block\n```\n\n\n![Nostr logo](https://user-images.githubusercontent.com/99301796/219900773-d6d02038-e2a0-4334-9f28-c14d40ab6fe7.png)\n\n[^1]: this is a footnote\n[^2]: so is this", + "tags": [ + ["subject", "test"], + ["alt", "git repository issue: test"], + [ + "a", + "30617:fd208ee8c8f283780a9552896e4823cc9dc6bfd442063889577106940fd927c1:Alexandria", + "", + "root" + ], + ["p", "fd208ee8c8f283780a9552896e4823cc9dc6bfd442063889577106940fd927c1"], + ["t", "gitstuff"] + ], + "kind": 1621, + "pubkey": "dd664d5e4016433a8cd69f005ae1480804351789b59de5af06276de65633d319", + "id": "e78a689369511fdb3c36b990380c2d8db2b5e62f13f6b836e93ef5a09611afe8", + "sig": "7a2b3a6f6f61b6ea04de1fe873e46d40f2a220f02cdae004342430aa1df67647a9589459382f22576c651b3d09811546bbd79564cf472deaff032f137e94a865" } -``` +```` C or C++: + ```cpp bool getBit(int num, int i) { return ((num & (1< { - it('parses headers (ATX and Setext)', async () => { - const input = '# H1\nText\n\nH2\n====\n'; +describe("Advanced Markup Parser", () => { + it("parses headers (ATX and Setext)", async () => { + const input = "# H1\nText\n\nH2\n====\n"; const output = await parseAdvancedmarkup(input); - expect(stripWS(output)).toContain('H1'); - expect(stripWS(output)).toContain('H2'); + expect(stripWS(output)).toContain("H1"); + expect(stripWS(output)).toContain("H2"); }); - it('parses bold, italic, and strikethrough', async () => { - const input = '*bold* **bold** _italic_ __italic__ ~strikethrough~ ~~strikethrough~~'; + it("parses bold, italic, and strikethrough", async () => { + const input = + "*bold* **bold** _italic_ __italic__ ~strikethrough~ ~~strikethrough~~"; const output = await parseAdvancedmarkup(input); - expect(output).toContain('bold'); - expect(output).toContain('italic'); + expect(output).toContain("bold"); + expect(output).toContain("italic"); expect(output).toContain('strikethrough'); }); - it('parses blockquotes', async () => { - const input = '> quote'; + it("parses blockquotes", async () => { + const input = "> quote"; const output = await parseAdvancedmarkup(input); - expect(output).toContain(' { - const input = '> quote\n> quote'; + it("parses multi-line blockquotes", async () => { + const input = "> quote\n> quote"; const output = await parseAdvancedmarkup(input); - expect(output).toContain(' { - const input = '* a\n* b'; + it("parses unordered lists", async () => { + const input = "* a\n* b"; const output = await parseAdvancedmarkup(input); - expect(output).toContain(' { - const input = '1. one\n2. two'; + it("parses ordered lists", async () => { + const input = "1. one\n2. two"; const output = await parseAdvancedmarkup(input); - expect(output).toContain(' { - const input = '[link](https://example.com) ![alt](https://img.com/x.png)'; + it("parses links and images", async () => { + const input = "[link](https://example.com) ![alt](https://img.com/x.png)"; const output = await parseAdvancedmarkup(input); - expect(output).toContain(' { - const input = '#hashtag'; + it("parses hashtags", async () => { + const input = "#hashtag"; const output = await parseAdvancedmarkup(input); - expect(output).toContain('text-primary-600'); - expect(output).toContain('#hashtag'); + expect(output).toContain("text-primary-600"); + expect(output).toContain("#hashtag"); }); - it('parses nostr identifiers', async () => { - const input = 'npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'; + it("parses nostr identifiers", async () => { + const input = + "npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"; const output = await parseAdvancedmarkup(input); - expect(output).toContain('./events?id=npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'); + expect(output).toContain( + "./events?id=npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + ); }); - it('parses emoji shortcodes', async () => { - const input = 'hello :smile:'; + it("parses emoji shortcodes", async () => { + const input = "hello :smile:"; const output = await parseAdvancedmarkup(input); expect(output).toMatch(/😄|:smile:/); }); - it('parses wikilinks', async () => { - const input = '[[Test Page|display]]'; + it("parses wikilinks", async () => { + const input = "[[Test Page|display]]"; const output = await parseAdvancedmarkup(input); - expect(output).toContain('wikilink'); - expect(output).toContain('display'); + expect(output).toContain("wikilink"); + expect(output).toContain("display"); }); - it('parses tables (with and without headers)', async () => { + it("parses tables (with and without headers)", async () => { const input = `| Syntax | Description |\n|--------|-------------|\n| Header | Title |\n| Paragraph | Text |\n\n| a | b |\n| c | d |`; const output = await parseAdvancedmarkup(input); - expect(output).toContain(' { - const input = '```js\nconsole.log(1);\n```\n```\nno lang\n```'; + it("parses code blocks (with and without language)", async () => { + const input = "```js\nconsole.log(1);\n```\n```\nno lang\n```"; const output = await parseAdvancedmarkup(input); - const textOnly = output.replace(/<[^>]+>/g, ''); - expect(output).toContain(']+>/g, ""); + expect(output).toContain(" { - const input = '---'; + it("parses horizontal rules", async () => { + const input = "---"; const output = await parseAdvancedmarkup(input); - expect(output).toContain(' { - const input = 'Here is a footnote[^1].\n\n[^1]: This is the footnote.'; + it("parses footnotes (references and section)", async () => { + const input = "Here is a footnote[^1].\n\n[^1]: This is the footnote."; const output = await parseAdvancedmarkup(input); - expect(output).toContain('Footnotes'); - expect(output).toContain('This is the footnote'); - expect(output).toContain('fn-1'); + expect(output).toContain("Footnotes"); + expect(output).toContain("This is the footnote"); + expect(output).toContain("fn-1"); }); -}); \ No newline at end of file + + it("parses unordered lists with '-' as bullet", async () => { + const input = "- item one\n- item two\n - nested item\n- item three"; + const output = await parseAdvancedmarkup(input); + expect(output).toContain(" { - it('parses ATX and Setext headers', async () => { - const input = '# H1\nText\n\nH2\n====\n'; +describe("Basic Markup Parser", () => { + it("parses ATX and Setext headers", async () => { + const input = "# H1\nText\n\nH2\n====\n"; const output = await parseBasicmarkup(input); - expect(stripWS(output)).toContain('H1'); - expect(stripWS(output)).toContain('H2'); + expect(stripWS(output)).toContain("H1"); + expect(stripWS(output)).toContain("H2"); }); - it('parses bold, italic, and strikethrough', async () => { - const input = '*bold* **bold** _italic_ __italic__ ~strikethrough~ ~~strikethrough~~'; + it("parses bold, italic, and strikethrough", async () => { + const input = + "*bold* **bold** _italic_ __italic__ ~strikethrough~ ~~strikethrough~~"; const output = await parseBasicmarkup(input); - expect(output).toContain('bold'); - expect(output).toContain('italic'); + expect(output).toContain("bold"); + expect(output).toContain("italic"); expect(output).toContain('strikethrough'); }); - it('parses blockquotes', async () => { - const input = '> quote'; + it("parses blockquotes", async () => { + const input = "> quote"; const output = await parseBasicmarkup(input); - expect(output).toContain(' { - const input = '> quote\n> quote'; + it("parses multi-line blockquotes", async () => { + const input = "> quote\n> quote"; const output = await parseBasicmarkup(input); - expect(output).toContain(' { - const input = '* a\n* b'; + it("parses unordered lists", async () => { + const input = "* a\n* b"; const output = await parseBasicmarkup(input); - expect(output).toContain(' { - const input = '1. one\n2. two'; + it("parses ordered lists", async () => { + const input = "1. one\n2. two"; const output = await parseBasicmarkup(input); - expect(output).toContain(' { - const input = '[link](https://example.com) ![alt](https://img.com/x.png)'; + it("parses links and images", async () => { + const input = "[link](https://example.com) ![alt](https://img.com/x.png)"; const output = await parseBasicmarkup(input); - expect(output).toContain(' { - const input = '#hashtag'; + it("parses hashtags", async () => { + const input = "#hashtag"; const output = await parseBasicmarkup(input); - expect(output).toContain('text-primary-600'); - expect(output).toContain('#hashtag'); + expect(output).toContain("text-primary-600"); + expect(output).toContain("#hashtag"); }); - it('parses nostr identifiers', async () => { - const input = 'npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'; + it("parses nostr identifiers", async () => { + const input = + "npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"; const output = await parseBasicmarkup(input); - expect(output).toContain('./events?id=npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'); + expect(output).toContain( + "./events?id=npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + ); }); - it('parses emoji shortcodes', async () => { - const input = 'hello :smile:'; + it("parses emoji shortcodes", async () => { + const input = "hello :smile:"; const output = await parseBasicmarkup(input); expect(output).toMatch(/😄|:smile:/); }); - it('parses wikilinks', async () => { - const input = '[[Test Page|display]]'; + it("parses wikilinks", async () => { + const input = "[[Test Page|display]]"; const output = await parseBasicmarkup(input); - expect(output).toContain('wikilink'); - expect(output).toContain('display'); + expect(output).toContain("wikilink"); + expect(output).toContain("display"); }); -}); \ No newline at end of file +}); diff --git a/tests/unit/latexRendering.test.ts b/tests/unit/latexRendering.test.ts new file mode 100644 index 0000000..7096a8a --- /dev/null +++ b/tests/unit/latexRendering.test.ts @@ -0,0 +1,101 @@ +import { describe, it, expect } from "vitest"; +import { parseAdvancedmarkup } from "../../src/lib/utils/markup/advancedMarkupParser"; +import { readFileSync } from "fs"; +import { join } from "path"; + +describe("LaTeX Math Rendering", () => { + const mdPath = join(__dirname, "../../test_data/latex_markdown.md"); + const raw = readFileSync(mdPath, "utf-8"); + // Extract the markdown content field from the JSON + const content = JSON.parse(raw).content; + + it('renders inline math as ', async () => { + const html = await parseAdvancedmarkup(content); + expect(html).toMatch(/\$P \\neq NP\$<\/span>/); + expect(html).toMatch( + /\$x_1 = \\text\{True\}\$<\/span>/, + ); + }); + + it('renders display math as
\$\$\s*P_j = \\bigotimes/, + ); + expect(html).toMatch( + /
\$\$[\s\S]*?\\begin\{pmatrix\}/, + ); + expect(html).toMatch( + /
\$\$\\boxed\{P \\neq NP\}\$\$<\/div>/, + ); + }); + + it("does not wrap display math in

or

", async () => { + const html = await parseAdvancedmarkup(content); + // No

or

directly wrapping math-block + expect(html).not.toMatch(/]*>\s*
{ + const html = await parseAdvancedmarkup(content); + // Check that pmatrix is properly rendered within a display math block + expect(html).toMatch( + /
\$\$[\s\S]*?\\begin\{pmatrix\}[\s\S]*?\\end\{pmatrix\}[\s\S]*?\$\$<\/div>/, + ); + }); + + it('renders all math as math (no unwrapped $...$, $$...$$, \\(...\\), \\[...\\], or environments left)', async () => { + const html = await parseAdvancedmarkup(content); + // No unwrapped $...$ outside math-inline or math-block + // Remove all math-inline and math-block tags and check for stray $...$ + const htmlNoMath = html + .replace(/\$[^$]+\$<\/span>/g, '') + .replace(/
\$\$[\s\S]*?\$\$<\/div>/g, '') + .replace(/
[\s\S]*?<\/div>/g, ''); + expect(htmlNoMath).not.toMatch(/\$[^\$\n]+\$/); // inline math + expect(htmlNoMath).not.toMatch(/\$\$[\s\S]*?\$\$/); // display math + expect(htmlNoMath).not.toMatch(/\\\([^)]+\\\)/); // \(...\) + expect(htmlNoMath).not.toMatch(/\\\[[^\]]+\\\]/); // \[...\] + expect(htmlNoMath).not.toMatch(/\\begin\{[a-zA-Z*]+\}[\s\S]*?\\end\{[a-zA-Z*]+\}/); // environments + // No math inside code or pre + expect(html).not.toMatch(//); + expect(html).not.toMatch(//); + }); + + it('renders every line of the document: all math is wrapped', async () => { + const lines = content.split(/\r?\n/); + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (!line.trim()) continue; + const html = await parseAdvancedmarkup(line); + // If the line contains $...$, $$...$$, \(...\), \[...\], or bare LaTeX commands, it should be wrapped + const hasMath = /\$[^$]+\$|\$\$[\s\S]*?\$\$|\\\([^)]+\\\)|\\\[[^\]]+\\\]|\\[a-zA-Z]+(\{[^}]*\})*/.test(line); + if (hasMath) { + const wrapped = /math-inline|math-block/.test(html); + if (!wrapped) { + // eslint-disable-next-line no-console + console.error(`Line ${i + 1} failed:`, line); + // eslint-disable-next-line no-console + console.error('Rendered HTML:', html); + } + expect(wrapped).toBe(true); + } + // Should not have any unwrapped $...$, $$...$$, \(...\), \[...\], or bare LaTeX commands + const stray = /(^|[^>])\$[^$\n]+\$|\$\$[\s\S]*?\$\$|\\\([^)]+\\\)|\\\[[^\]]+\\\]|\\[a-zA-Z]+(\{[^}]*\})*/.test(html); + expect(stray).toBe(false); + } + }); + + it('renders standalone math lines as display math blocks', async () => { + const mdPath = require('path').join(__dirname, '../../test_data/latex_markdown.md'); + const raw = require('fs').readFileSync(mdPath, 'utf-8'); + const content = JSON.parse(raw).content || raw; + const html = await parseAdvancedmarkup(content); + // Example: Bures distance line + expect(html).toMatch(/
\$\$d_B\([^$]+\) = [^$]+\$\$<\/div>/); + // Example: P(\rho) = ... + expect(html).toMatch(/
\$\$P\([^$]+\) = [^$]+\$\$<\/div>/); + }); +}); diff --git a/vite.config.ts b/vite.config.ts index 61e619b..dfbd6e3 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -5,16 +5,20 @@ import { execSync } from "child_process"; // Function to get the latest git tag function getAppVersionString() { // if running in ci context, we can assume the package has been properly versioned - if (process.env.ALEXANDIRA_IS_CI_BUILD && process.env.npm_package_version && process.env.npm_package_version.trim() !== '') { + if ( + process.env.ALEXANDIRA_IS_CI_BUILD && + process.env.npm_package_version && + process.env.npm_package_version.trim() !== "" + ) { return process.env.npm_package_version; } - + try { // Get the latest git tag, assuming git is installed and tagged branch is available - const tag = execSync('git describe --tags --abbrev=0').toString().trim(); + const tag = execSync("git describe --tags --abbrev=0").toString().trim(); return tag; } catch (error) { - return 'development'; + return "development"; } } @@ -22,20 +26,20 @@ export default defineConfig({ plugins: [sveltekit()], resolve: { alias: { - $lib: './src/lib', - $components: './src/components' - } + $lib: "./src/lib", + $components: "./src/components", + }, }, build: { rollupOptions: { - external: ['bech32'] - } + external: ["bech32"], + }, }, test: { - include: ['./tests/unit/**/*.test.ts', './tests/integration/**/*.test.ts'] + include: ["./tests/unit/**/*.test.ts", "./tests/integration/**/*.test.ts"], }, define: { // Expose the app version as a global variable - 'import.meta.env.APP_VERSION': JSON.stringify(getAppVersionString()) - } + "import.meta.env.APP_VERSION": JSON.stringify(getAppVersionString()), + }, }); From 5c4a866a9f3854b40c3ed01375a41d732d4db437 Mon Sep 17 00:00:00 2001 From: Silberengel Date: Wed, 9 Jul 2025 23:23:35 +0200 Subject: [PATCH 092/135] fix missing copy icon --- src/lib/components/util/CardActions.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/util/CardActions.svelte b/src/lib/components/util/CardActions.svelte index ca8ae10..af030e3 100644 --- a/src/lib/components/util/CardActions.svelte +++ b/src/lib/components/util/CardActions.svelte @@ -174,7 +174,7 @@
  • From 766818b2c60adda315f0c89e7e058ed3634720ea Mon Sep 17 00:00:00 2001 From: Silberengel Date: Thu, 10 Jul 2025 01:13:48 +0200 Subject: [PATCH 093/135] Rudimentary comment box and event input box implemented --- src/lib/components/CommentBox.svelte | 167 ++++++++---- src/lib/components/EventDetails.svelte | 31 ++- src/lib/components/EventInput.svelte | 363 +++++++++++++++++++++++++ src/lib/components/RelayActions.svelte | 68 ----- src/lib/components/RelayStatus.svelte | 2 + src/lib/consts.ts | 2 +- src/lib/ndk.ts | 37 ++- src/lib/stores/authStore.ts | 11 + src/lib/utils/event_input_utils.ts | 219 +++++++++++++++ src/lib/utils/relayDiagnostics.ts | 140 ++++++++++ src/routes/events/+page.svelte | 25 +- 11 files changed, 938 insertions(+), 127 deletions(-) create mode 100644 src/lib/components/EventInput.svelte create mode 100644 src/lib/stores/authStore.ts create mode 100644 src/lib/utils/event_input_utils.ts create mode 100644 src/lib/utils/relayDiagnostics.ts diff --git a/src/lib/components/CommentBox.svelte b/src/lib/components/CommentBox.svelte index 9c6dd9f..15fab77 100644 --- a/src/lib/components/CommentBox.svelte +++ b/src/lib/components/CommentBox.svelte @@ -11,13 +11,13 @@ import { standardRelays, fallbackRelays } from "$lib/consts"; import { userRelays } from "$lib/stores/relayStore"; import { get } from "svelte/store"; + import { activePubkey } from '$lib/ndk'; import { goto } from "$app/navigation"; import type { NDKEvent } from "$lib/utils/nostrUtils"; import { onMount } from "svelte"; const props = $props<{ event: NDKEvent; - userPubkey: string; userRelayPreference: boolean; }>(); @@ -29,12 +29,26 @@ let showOtherRelays = $state(false); let showFallbackRelays = $state(false); let userProfile = $state(null); + let pubkey = $state(null); + $effect(() => { + pubkey = get(activePubkey); + }); // Fetch user profile on mount - onMount(async () => { - if (props.userPubkey) { - const npub = nip19.npubEncode(props.userPubkey); - userProfile = await getUserMetadata(npub); + onMount(() => { + const trimmedPubkey = pubkey?.trim(); + if (trimmedPubkey && /^[a-fA-F0-9]{64}$/.test(trimmedPubkey)) { + (async () => { + const npub = nip19.npubEncode(trimmedPubkey); + userProfile = await getUserMetadata(npub); + error = null; + })(); + } else if (trimmedPubkey) { + userProfile = null; + error = 'Invalid public key: must be a 64-character hex string.'; + } else { + userProfile = null; + error = null; } }); @@ -102,6 +116,22 @@ updatePreview(); } + // Helper functions to ensure relay and pubkey are always strings + function getRelayString(relay: any): string { + if (!relay) return ''; + if (typeof relay === 'string') return relay; + if (typeof relay.url === 'string') return relay.url; + return ''; + } + + function getPubkeyString(pubkey: any): string { + if (!pubkey) return ''; + if (typeof pubkey === 'string') return pubkey; + if (typeof pubkey.hex === 'function') return pubkey.hex(); + if (typeof pubkey.pubkey === 'string') return pubkey.pubkey; + return ''; + } + async function handleSubmit( useOtherRelays = false, useFallbackRelays = false, @@ -111,53 +141,91 @@ success = null; try { - if (!props.event.kind) { - throw new Error("Invalid event: missing kind"); + if (!pubkey || !/^[a-fA-F0-9]{64}$/.test(pubkey)) { + throw new Error('Invalid public key: must be a 64-character hex string.'); + } + if (props.event.kind === undefined || props.event.kind === null) { + throw new Error('Invalid event: missing kind'); } - const kind = props.event.kind === 1 ? 1 : 1111; - const tags: string[][] = []; - - if (kind === 1) { - // NIP-10 reply - tags.push(["e", props.event.id, "", "reply"]); - tags.push(["p", props.event.pubkey]); - if (props.event.tags) { - const rootTag = props.event.tags.find( - (t: string[]) => t[0] === "e" && t[3] === "root", - ); - if (rootTag) { - tags.push(["e", rootTag[1], "", "root"]); - } - // Add all p tags from the parent event - props.event.tags - .filter((t: string[]) => t[0] === "p") - .forEach((t: string[]) => { - if (!tags.some((pt: string[]) => pt[1] === t[1])) { - tags.push(["p", t[1]]); - } - }); + // Always use kind 1111 for comments + const kind = 1111; + const parent = props.event; + // Try to extract root info from parent tags (NIP-22 threading) + let rootKind = parent.kind; + let rootPubkey = getPubkeyString(parent.pubkey); + let rootRelay = getRelayString(parent.relay); + let rootId = parent.id; + let rootAddress = ''; + let parentRelay = getRelayString(parent.relay); + let parentAddress = ''; + let parentKind = parent.kind; + let parentPubkey = getPubkeyString(parent.pubkey); + // Try to find root event info from tags (E/A/I) + let isRootA = false; + let isRootI = false; + if (parent.tags) { + const rootE = parent.tags.find((t: string[]) => t[0] === 'E'); + const rootA = parent.tags.find((t: string[]) => t[0] === 'A'); + const rootI = parent.tags.find((t: string[]) => t[0] === 'I'); + isRootA = !!rootA; + isRootI = !!rootI; + if (rootE) { + rootId = rootE[1]; + rootRelay = getRelayString(rootE[2]); + rootPubkey = getPubkeyString(rootE[3] || rootPubkey); + rootKind = parent.tags.find((t: string[]) => t[0] === 'K')?.[1] || rootKind; + } else if (rootA) { + rootAddress = rootA[1]; + rootRelay = getRelayString(rootA[2]); + rootPubkey = getPubkeyString(parent.tags.find((t: string[]) => t[0] === 'P')?.[1] || rootPubkey); + rootKind = parent.tags.find((t: string[]) => t[0] === 'K')?.[1] || rootKind; + } else if (rootI) { + rootAddress = rootI[1]; + rootKind = parent.tags.find((t: string[]) => t[0] === 'K')?.[1] || rootKind; } + } + // Compose tags according to NIP-22 + const tags: string[][] = []; + // Root scope (uppercase) + if (rootAddress) { + tags.push([isRootA ? 'A' : isRootI ? 'I' : 'E', rootAddress || rootId, rootRelay, rootPubkey]); + } else { + tags.push(['E', rootId, rootRelay, rootPubkey]); + } + tags.push(['K', String(rootKind), '', '']); + tags.push(['P', rootPubkey, rootRelay, '']); + // Parent (lowercase) + if (parentAddress) { + tags.push([isRootA ? 'a' : isRootI ? 'i' : 'e', parentAddress || parent.id, parentRelay, parentPubkey]); } else { - // NIP-22 comment - tags.push(["E", props.event.id, "", props.event.pubkey]); - tags.push(["K", props.event.kind.toString()]); - tags.push(["P", props.event.pubkey]); - tags.push(["e", props.event.id, "", props.event.pubkey]); - tags.push(["k", props.event.kind.toString()]); - tags.push(["p", props.event.pubkey]); + tags.push(['e', parent.id, parentRelay, parentPubkey]); } + tags.push(['k', String(parentKind), '', '']); + tags.push(['p', parentPubkey, parentRelay, '']); + // Create a completely plain object to avoid proxy cloning issues const eventToSign = { - kind, - created_at: Math.floor(Date.now() / 1000), - tags, - content, - pubkey: props.userPubkey, + kind: Number(kind), + created_at: Number(Math.floor(Date.now() / 1000)), + tags: tags.map(tag => [String(tag[0]), String(tag[1]), String(tag[2] || ''), String(tag[3] || '')]), + content: String(content), + pubkey: String(pubkey), }; - const id = getEventHash(eventToSign); - const sig = await signEvent(eventToSign); + let sig, id; + if (typeof window !== 'undefined' && window.nostr && window.nostr.signEvent) { + const signed = await window.nostr.signEvent(eventToSign); + sig = signed.sig as string; + if ('id' in signed) { + id = signed.id as string; + } else { + id = getEventHash(eventToSign); + } + } else { + id = getEventHash(eventToSign); + sig = await signEvent(eventToSign); + } const signedEvent = { ...eventToSign, @@ -288,10 +356,11 @@ {#if success} - Comment published successfully to {success.relay}! + Comment published successfully to {success.relay}!
    + Event ID: {success.eventId} View your comment @@ -315,16 +384,16 @@ {userProfile.displayName || userProfile.name || - nip19.npubEncode(props.userPubkey).slice(0, 8) + "..."} + nip19.npubEncode(pubkey || '').slice(0, 8) + "..."}
  • {/if}
    - {#if !props.userPubkey} + {#if !pubkey} Please sign in to post comments. Your comments will be signed with your current account. diff --git a/src/lib/components/EventDetails.svelte b/src/lib/components/EventDetails.svelte index a20ef15..d12a61a 100644 --- a/src/lib/components/EventDetails.svelte +++ b/src/lib/components/EventDetails.svelte @@ -37,7 +37,36 @@ let authorDisplayName = $state(undefined); function getEventTitle(event: NDKEvent): string { - return getMatchingTags(event, "title")[0]?.[1] || "Untitled"; + // First try to get title from title tag + const titleTag = getMatchingTags(event, "title")[0]?.[1]; + if (titleTag) { + return titleTag; + } + + // For kind 30023 events, extract title from markdown content if no title tag + if (event.kind === 30023 && event.content) { + const match = event.content.match(/^#\s+(.+)$/m); + if (match) { + return match[1].trim(); + } + } + + // For kind 30040, 30041, and 30818 events, extract title from AsciiDoc content if no title tag + if ((event.kind === 30040 || event.kind === 30041 || event.kind === 30818) && event.content) { + // First try to find a document header (= ) + const docMatch = event.content.match(/^=\s+(.+)$/m); + if (docMatch) { + return docMatch[1].trim(); + } + + // If no document header, try to find the first section header (== ) + const sectionMatch = event.content.match(/^==\s+(.+)$/m); + if (sectionMatch) { + return sectionMatch[1].trim(); + } + } + + return "Untitled"; } function getEventSummary(event: NDKEvent): string { diff --git a/src/lib/components/EventInput.svelte b/src/lib/components/EventInput.svelte new file mode 100644 index 0000000..c7f49d5 --- /dev/null +++ b/src/lib/components/EventInput.svelte @@ -0,0 +1,363 @@ + + +{#if pubkey} +
    +

    Publish Nostr Event

    +
    +
    + + + {#if !isValidKind(kind)} +
    + Kind must be an integer between 0 and 65535 (NIP-01). +
    + {/if} +
    +
    + +
    + {#each tags as [key, value], i} +
    + updateTag(i, (e.target as HTMLInputElement).value, tags[i][1])} /> + updateTag(i, tags[i][0], (e.target as HTMLInputElement).value)} /> + +
    + {/each} + +
    +
    +
    + + +
    +
    + + +
    +
    + + + {#if dTagError} +
    {dTagError}
    + {/if} +
    + + {#if loading} + Publishing... + {/if} + {#if error} +
    {error}
    + {/if} + {#if success} +
    {success}
    +
    Relays: {publishedRelays.join(', ')}
    + {#if lastPublishedEventId} +
    + Event ID: {lastPublishedEventId} + + View your event + +
    + {/if} + {/if} +
    +
    +{/if} \ No newline at end of file diff --git a/src/lib/components/RelayActions.svelte b/src/lib/components/RelayActions.svelte index 0f21891..b854d77 100644 --- a/src/lib/components/RelayActions.svelte +++ b/src/lib/components/RelayActions.svelte @@ -19,9 +19,6 @@ let searchingRelays = $state(false); let foundRelays = $state([]); - let broadcasting = $state(false); - let broadcastSuccess = $state(false); - let broadcastError = $state(null); let showRelayModal = $state(false); let relaySearchResults = $state< Record @@ -33,43 +30,6 @@ `; - // Broadcast icon SVG - const broadcastIcon = ``; - - async function broadcastEvent() { - if (!event || !$ndkInstance?.activeUser) return; - broadcasting = true; - broadcastSuccess = false; - broadcastError = null; - - try { - const connectedRelays = getConnectedRelays(); - if (connectedRelays.length === 0) { - throw new Error("No connected relays available"); - } - - // Create a new event with the same content - const newEvent = createNDKEvent($ndkInstance, { - ...event.rawEvent(), - pubkey: $ndkInstance.activeUser.pubkey, - created_at: Math.floor(Date.now() / 1000), - sig: "", - }); - - // Publish to all relays - await newEvent.publish(); - broadcastSuccess = true; - } catch (err) { - console.error("Error broadcasting event:", err); - broadcastError = - err instanceof Error ? err.message : "Failed to broadcast event"; - } finally { - broadcasting = false; - } - } - function openRelayModal() { showRelayModal = true; relaySearchResults = {}; @@ -117,17 +77,6 @@ {@html searchIcon} Where can I find this event? - - {#if $ndkInstance?.activeUser} - - {/if}
    {#if foundRelays.length > 0} @@ -141,23 +90,6 @@
    {/if} -{#if broadcastSuccess} -
    - Event broadcast successfully to: -
    - {#each getConnectedRelays() as relay} - - {/each} -
    -
    -{/if} - -{#if broadcastError} -
    - {broadcastError} -
    -{/if} -
    Found on:
    diff --git a/src/lib/components/RelayStatus.svelte b/src/lib/components/RelayStatus.svelte index 92c5028..fa9f51c 100644 --- a/src/lib/components/RelayStatus.svelte +++ b/src/lib/components/RelayStatus.svelte @@ -99,6 +99,8 @@ onMount(() => { checkWebSocketSupport(); checkEnvironmentForWebSocketDowngrade(); + // Run initial relay tests + void runRelayTests(); }); function getStatusColor(status: RelayStatus): string { diff --git a/src/lib/consts.ts b/src/lib/consts.ts index c661399..ac908fd 100644 --- a/src/lib/consts.ts +++ b/src/lib/consts.ts @@ -6,7 +6,7 @@ export const standardRelays = [ "wss://thecitadel.nostr1.com", "wss://theforest.nostr1.com", "wss://profiles.nostr1.com", - "wss://gitcitadel.nostr1.com", + // Removed gitcitadel.nostr1.com as it's causing connection issues //'wss://thecitadel.gitcitadel.eu', //'wss://theforest.gitcitadel.eu', ]; diff --git a/src/lib/ndk.ts b/src/lib/ndk.ts index cbdf546..196ee03 100644 --- a/src/lib/ndk.ts +++ b/src/lib/ndk.ts @@ -397,21 +397,40 @@ function createRelayWithAuth(url: string, ndk: NDK): NDKRelay { // Ensure the URL is using wss:// protocol const secureUrl = ensureSecureWebSocket(url); + // Add connection timeout and error handling const relay = new NDKRelay( secureUrl, NDKRelayAuthPolicies.signIn({ ndk }), ndk, ); + // Set up connection timeout + const connectionTimeout = setTimeout(() => { + console.warn(`[NDK.ts] Connection timeout for ${secureUrl}`); + relay.disconnect(); + }, 10000); // 10 second timeout + // Set up custom authentication handling only if user is signed in if (ndk.signer && ndk.activeUser) { const authPolicy = new CustomRelayAuthPolicy(ndk); relay.on("connect", () => { console.debug(`[NDK.ts] Relay connected: ${secureUrl}`); + clearTimeout(connectionTimeout); authPolicy.authenticate(relay); }); + } else { + relay.on("connect", () => { + console.debug(`[NDK.ts] Relay connected: ${secureUrl}`); + clearTimeout(connectionTimeout); + }); } + // Add error handling + relay.on("disconnect", () => { + console.debug(`[NDK.ts] Relay disconnected: ${secureUrl}`); + clearTimeout(connectionTimeout); + }); + return relay; } @@ -462,7 +481,23 @@ export function initNdk(): NDK { // Set up custom authentication policy ndk.relayAuthDefaultPolicy = NDKRelayAuthPolicies.signIn({ ndk }); - ndk.connect().then(() => console.debug("[NDK.ts] NDK connected")); + + // Connect with better error handling + ndk.connect() + .then(() => { + console.debug("[NDK.ts] NDK connected successfully"); + }) + .catch((error) => { + console.error("[NDK.ts] Failed to connect NDK:", error); + // Try to reconnect after a delay + setTimeout(() => { + console.debug("[NDK.ts] Attempting to reconnect..."); + ndk.connect().catch((retryError) => { + console.error("[NDK.ts] Reconnection failed:", retryError); + }); + }, 5000); + }); + return ndk; } diff --git a/src/lib/stores/authStore.ts b/src/lib/stores/authStore.ts new file mode 100644 index 0000000..9337100 --- /dev/null +++ b/src/lib/stores/authStore.ts @@ -0,0 +1,11 @@ +import { writable, derived } from 'svelte/store'; + +/** + * Stores the user's public key if logged in, or null otherwise. + */ +export const userPubkey = writable(null); + +/** + * Derived store indicating if the user is logged in. + */ +export const isLoggedIn = derived(userPubkey, ($userPubkey) => !!$userPubkey); \ No newline at end of file diff --git a/src/lib/utils/event_input_utils.ts b/src/lib/utils/event_input_utils.ts new file mode 100644 index 0000000..4a35c5e --- /dev/null +++ b/src/lib/utils/event_input_utils.ts @@ -0,0 +1,219 @@ +import type { NDKEvent } from './nostrUtils'; +import { get } from 'svelte/store'; +import { ndkInstance } from '$lib/ndk'; +import { NDKEvent as NDKEventClass } from '@nostr-dev-kit/ndk'; + +// ========================= +// Validation +// ========================= + +/** + * Returns true if the event kind requires a d-tag (kinds 30000-39999). + */ +export function requiresDTag(kind: number): boolean { + return kind >= 30000 && kind <= 39999; +} + +/** + * Returns true if the tags array contains at least one d-tag with a non-empty value. + */ +export function hasDTag(tags: [string, string][]): boolean { + return tags.some(([k, v]) => k === 'd' && v && v.trim() !== ''); +} + +/** + * Returns true if the content contains AsciiDoc headers (lines starting with '=' or '=='). + */ +function containsAsciiDocHeaders(content: string): boolean { + return /^={1,}\s+/m.test(content); +} + +/** + * Validates that content does NOT contain AsciiDoc headers (for kind 30023). + * Returns { valid, reason }. + */ +export function validateNotAsciidoc(content: string): { valid: boolean; reason?: string } { + if (containsAsciiDocHeaders(content)) { + return { + valid: false, + reason: 'Kind 30023 must not contain AsciiDoc headers (lines starting with = or ==).', + }; + } + return { valid: true }; +} + +/** + * Validates AsciiDoc content. Must start with '=' and contain at least one '==' section header. + * Returns { valid, reason }. + */ +export function validateAsciiDoc(content: string): { valid: boolean; reason?: string } { + if (!content.trim().startsWith('=')) { + return { valid: false, reason: 'AsciiDoc must start with a document title ("=").' }; + } + if (!/^==\s+/m.test(content)) { + return { valid: false, reason: 'AsciiDoc must contain at least one section header ("==").' }; + } + return { valid: true }; +} + +// ========================= +// Extraction & Normalization +// ========================= + +/** + * Normalize a string for use as a d-tag: lowercase, hyphens, alphanumeric only. + */ +function normalizeDTagValue(header: string): string { + return header + .toLowerCase() + .replace(/[^\p{L}\p{N}]+/gu, '-') + .replace(/^-+|-+$/g, ''); +} + +/** + * Converts a title string to a valid d-tag (lowercase, hyphens, no punctuation). + */ +export function titleToDTag(title: string): string { + return title + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') // Replace non-alphanumeric with hyphens + .replace(/^-+|-+$/g, ''); // Trim leading/trailing hyphens +} + +/** + * Extracts the first AsciiDoc document header (line starting with '= '). + */ +function extractAsciiDocDocumentHeader(content: string): string | null { + const match = content.match(/^=\s+(.+)$/m); + return match ? match[1].trim() : null; +} + +/** + * Extracts all section headers (lines starting with '== '). + */ +function extractAsciiDocSectionHeaders(content: string): string[] { + return Array.from(content.matchAll(/^==\s+(.+)$/gm)).map(m => m[1].trim()); +} + +/** + * Extracts the topmost Markdown # header (line starting with '# '). + */ +function extractMarkdownTopHeader(content: string): string | null { + const match = content.match(/^#\s+(.+)$/m); + return match ? match[1].trim() : null; +} + +/** + * Splits AsciiDoc content into sections at each '==' header. Returns array of section strings. + */ +function splitAsciiDocSections(content: string): string[] { + const lines = content.split(/\r?\n/); + const sections: string[] = []; + let current: string[] = []; + for (const line of lines) { + if (/^==\s+/.test(line) && current.length > 0) { + sections.push(current.join('\n').trim()); + current = []; + } + current.push(line); + } + if (current.length > 0) { + sections.push(current.join('\n').trim()); + } + return sections; +} + +// ========================= +// Event Construction +// ========================= + +/** + * Returns the current NDK instance from the store. + */ +function getNdk() { + return get(ndkInstance); +} + +/** + * Builds a set of events for a 30040 publication: one 30040 index event and one 30041 event per section. + * Each 30041 gets a d-tag (normalized section header) and a title tag (raw section header). + * The 30040 index event references all 30041s by their d-tag. + */ +export function build30040EventSet( + content: string, + tags: [string, string][], + baseEvent: Partial & { pubkey: string; created_at: number } +): { indexEvent: NDKEvent; sectionEvents: NDKEvent[] } { + const ndk = getNdk(); + const sections = splitAsciiDocSections(content); + const sectionHeaders = extractAsciiDocSectionHeaders(content); + const dTags = sectionHeaders.length === sections.length + ? sectionHeaders.map(normalizeDTagValue) + : sections.map((_, i) => `section${i}`); + const sectionEvents: NDKEvent[] = sections.map((section, i) => { + const header = sectionHeaders[i] || `Section ${i + 1}`; + const dTag = dTags[i]; + return new NDKEventClass(ndk, { + kind: 30041, + content: section, + tags: [ + ...tags, + ['d', dTag], + ['title', header], + ], + pubkey: baseEvent.pubkey, + created_at: baseEvent.created_at, + }); + }); + const indexTags = [ + ...tags, + ...dTags.map(d => ['a', d] as [string, string]), + ]; + const indexEvent: NDKEvent = new NDKEventClass(ndk, { + kind: 30040, + content: '', + tags: indexTags, + pubkey: baseEvent.pubkey, + created_at: baseEvent.created_at, + }); + return { indexEvent, sectionEvents }; +} + +/** + * Returns the appropriate title tag for a given event kind and content. + * - 30041, 30818: AsciiDoc document header (first '= ' line) + * - 30023: Markdown topmost '# ' header + */ +export function getTitleTagForEvent(kind: number, content: string): string | null { + if (kind === 30041 || kind === 30818) { + return extractAsciiDocDocumentHeader(content); + } + if (kind === 30023) { + return extractMarkdownTopHeader(content); + } + return null; +} + +/** + * Returns the appropriate d-tag value for a given event kind and content. + * - 30023: Normalized markdown header + * - 30041, 30818: Normalized AsciiDoc document header + * - 30040: Uses existing d-tag or generates from content + */ +export function getDTagForEvent(kind: number, content: string, existingDTag?: string): string | null { + if (existingDTag && existingDTag.trim() !== '') { + return existingDTag.trim(); + } + + if (kind === 30023) { + const title = extractMarkdownTopHeader(content); + return title ? normalizeDTagValue(title) : null; + } + + if (kind === 30041 || kind === 30818) { + const title = extractAsciiDocDocumentHeader(content); + return title ? normalizeDTagValue(title) : null; + } + + return null; +} \ No newline at end of file diff --git a/src/lib/utils/relayDiagnostics.ts b/src/lib/utils/relayDiagnostics.ts new file mode 100644 index 0000000..71a5d99 --- /dev/null +++ b/src/lib/utils/relayDiagnostics.ts @@ -0,0 +1,140 @@ +import { standardRelays, anonymousRelays, fallbackRelays } from '$lib/consts'; +import NDK from '@nostr-dev-kit/ndk'; + +export interface RelayDiagnostic { + url: string; + connected: boolean; + requiresAuth: boolean; + error?: string; + responseTime?: number; +} + +/** + * Tests connection to a single relay + */ +export async function testRelay(url: string): Promise { + const startTime = Date.now(); + + return new Promise((resolve) => { + const ws = new WebSocket(url); + let resolved = false; + + const timeout = setTimeout(() => { + if (!resolved) { + resolved = true; + ws.close(); + resolve({ + url, + connected: false, + requiresAuth: false, + error: 'Connection timeout', + responseTime: Date.now() - startTime, + }); + } + }, 5000); + + ws.onopen = () => { + if (!resolved) { + resolved = true; + clearTimeout(timeout); + ws.close(); + resolve({ + url, + connected: true, + requiresAuth: false, + responseTime: Date.now() - startTime, + }); + } + }; + + ws.onerror = () => { + if (!resolved) { + resolved = true; + clearTimeout(timeout); + resolve({ + url, + connected: false, + requiresAuth: false, + error: 'WebSocket error', + responseTime: Date.now() - startTime, + }); + } + }; + + ws.onmessage = (event) => { + const data = JSON.parse(event.data); + if (data[0] === 'NOTICE' && data[1]?.includes('auth-required')) { + if (!resolved) { + resolved = true; + clearTimeout(timeout); + ws.close(); + resolve({ + url, + connected: true, + requiresAuth: true, + responseTime: Date.now() - startTime, + }); + } + } + }; + }); +} + +/** + * Tests all relays and returns diagnostic information + */ +export async function testAllRelays(): Promise { + const allRelays = [...new Set([...standardRelays, ...anonymousRelays, ...fallbackRelays])]; + + console.log('[RelayDiagnostics] Testing', allRelays.length, 'relays...'); + + const results = await Promise.allSettled( + allRelays.map(url => testRelay(url)) + ); + + return results.map((result, index) => { + if (result.status === 'fulfilled') { + return result.value; + } else { + return { + url: allRelays[index], + connected: false, + requiresAuth: false, + error: 'Test failed', + }; + } + }); +} + +/** + * Gets working relays from diagnostic results + */ +export function getWorkingRelays(diagnostics: RelayDiagnostic[]): string[] { + return diagnostics + .filter(d => d.connected) + .map(d => d.url); +} + +/** + * Logs relay diagnostic results to console + */ +export function logRelayDiagnostics(diagnostics: RelayDiagnostic[]): void { + console.group('[RelayDiagnostics] Results'); + + const working = diagnostics.filter(d => d.connected); + const failed = diagnostics.filter(d => !d.connected); + + console.log(`✅ Working relays (${working.length}):`); + working.forEach(d => { + console.log(` - ${d.url}${d.requiresAuth ? ' (requires auth)' : ''}${d.responseTime ? ` (${d.responseTime}ms)` : ''}`); + }); + + if (failed.length > 0) { + console.log(`❌ Failed relays (${failed.length}):`); + failed.forEach(d => { + console.log(` - ${d.url}: ${d.error || 'Unknown error'}`); + }); + } + + console.groupEnd(); +} \ No newline at end of file diff --git a/src/routes/events/+page.svelte b/src/routes/events/+page.svelte index 7e426e5..fd1236b 100644 --- a/src/routes/events/+page.svelte +++ b/src/routes/events/+page.svelte @@ -9,6 +9,10 @@ import CommentBox from "$lib/components/CommentBox.svelte"; import { userBadge } from "$lib/snippets/UserSnippets.svelte"; import { getMatchingTags, toNpub } from "$lib/utils/nostrUtils"; + import EventInput from '$lib/components/EventInput.svelte'; + import { userPubkey, isLoggedIn } from '$lib/stores/authStore'; + import RelayStatus from '$lib/components/RelayStatus.svelte'; + import { testAllRelays, logRelayDiagnostics } from '$lib/utils/relayDiagnostics'; let loading = $state(false); let error = $state(null); @@ -26,7 +30,6 @@ lud16?: string; nip05?: string; } | null>(null); - let userPubkey = $state(null); let userRelayPreference = $state(false); function handleEventFound(newEvent: NDKEvent) { @@ -74,10 +77,14 @@ } }); - onMount(async () => { - // Get user's pubkey and relay preference from localStorage - userPubkey = localStorage.getItem("userPubkey"); - userRelayPreference = localStorage.getItem("useUserRelays") === "true"; + onMount(() => { + // Initialize userPubkey from localStorage if available + const pubkey = localStorage.getItem('userPubkey'); + userPubkey.set(pubkey); + userRelayPreference = localStorage.getItem('useUserRelays') === 'true'; + + // Run relay diagnostics to help identify connection issues + testAllRelays().then(logRelayDiagnostics).catch(console.error); }); @@ -103,13 +110,17 @@ onSearchResults={handleSearchResults} /> + {#if $isLoggedIn && !event && searchResults.length === 0} + + {/if} + {#if event} - {#if userPubkey} + {#if $isLoggedIn && $userPubkey}
    Add Comment - +
    {:else}
    From 3fca7c06995a27182ce6549d83db1f8cd5c3091c Mon Sep 17 00:00:00 2001 From: Silberengel Date: Thu, 10 Jul 2025 08:31:23 +0200 Subject: [PATCH 094/135] Publication writer done. --- src/lib/components/CommentBox.svelte | 185 +++++++++++++++++++----- src/lib/components/EventInput.svelte | 114 ++++++++++++--- src/lib/components/EventSearch.svelte | 77 +++++++++- src/lib/utils/event_input_utils.ts | 198 ++++++++++++++++++++++++-- src/lib/utils/nostrUtils.ts | 76 ++++++++++ src/routes/events/+page.svelte | 18 +++ 6 files changed, 601 insertions(+), 67 deletions(-) diff --git a/src/lib/components/CommentBox.svelte b/src/lib/components/CommentBox.svelte index 15fab77..fb91e11 100644 --- a/src/lib/components/CommentBox.svelte +++ b/src/lib/components/CommentBox.svelte @@ -6,6 +6,7 @@ getEventHash, signEvent, getUserMetadata, + prefixNostrAddresses, type NostrProfile, } from "$lib/utils/nostrUtils"; import { standardRelays, fallbackRelays } from "$lib/consts"; @@ -29,17 +30,22 @@ let showOtherRelays = $state(false); let showFallbackRelays = $state(false); let userProfile = $state(null); - let pubkey = $state(null); + let pubkey = $derived(() => get(activePubkey)); + $effect(() => { - pubkey = get(activePubkey); + if (!pubkey()) { + userProfile = null; + error = null; + } }); - // Fetch user profile on mount - onMount(() => { - const trimmedPubkey = pubkey?.trim(); + // Remove the onMount block that sets pubkey and userProfile only once. Instead, fetch userProfile reactively when pubkey changes. + $effect(() => { + const trimmedPubkey = pubkey()?.trim(); if (trimmedPubkey && /^[a-fA-F0-9]{64}$/.test(trimmedPubkey)) { + const npub = nip19.npubEncode(trimmedPubkey); + // Call an async function, but don't make the effect itself async (async () => { - const npub = nip19.npubEncode(trimmedPubkey); userProfile = await getUserMetadata(npub); error = null; })(); @@ -52,6 +58,13 @@ } }); + $effect(() => { + if (success) { + content = ''; + preview = ''; + } + }); + // Markup buttons const markupButtons = [ { label: "Bold", action: () => insertMarkup("**", "**") }, @@ -141,16 +154,17 @@ success = null; try { - if (!pubkey || !/^[a-fA-F0-9]{64}$/.test(pubkey)) { + const pk = pubkey() || ''; + if (!pk || !/^[a-fA-F0-9]{64}$/.test(pk)) { throw new Error('Invalid public key: must be a 64-character hex string.'); } if (props.event.kind === undefined || props.event.kind === null) { throw new Error('Invalid event: missing kind'); } - // Always use kind 1111 for comments - const kind = 1111; const parent = props.event; + // Use the same kind as parent for replies, or 1111 for generic replies + const kind = parent.kind === 1 ? 1 : 1111; // Try to extract root info from parent tags (NIP-22 threading) let rootKind = parent.kind; let rootPubkey = getPubkeyString(parent.pubkey); @@ -161,9 +175,18 @@ let parentAddress = ''; let parentKind = parent.kind; let parentPubkey = getPubkeyString(parent.pubkey); - // Try to find root event info from tags (E/A/I) + + // Check if parent is a replaceable event (3xxxxx kinds) + const isParentReplaceable = parentKind >= 30000 && parentKind < 40000; + + // Check if parent is a comment (kind 1111) - if so, we need to find the original root + const isParentComment = parentKind === 1111; + + // Try to find root event info from parent tags (E/A/I) let isRootA = false; let isRootI = false; + let rootIValue = ''; + let rootIRelay = ''; if (parent.tags) { const rootE = parent.tags.find((t: string[]) => t[0] === 'E'); const rootA = parent.tags.find((t: string[]) => t[0] === 'A'); @@ -181,36 +204,134 @@ rootPubkey = getPubkeyString(parent.tags.find((t: string[]) => t[0] === 'P')?.[1] || rootPubkey); rootKind = parent.tags.find((t: string[]) => t[0] === 'K')?.[1] || rootKind; } else if (rootI) { - rootAddress = rootI[1]; + rootIValue = rootI[1]; + rootIRelay = getRelayString(rootI[2]); rootKind = parent.tags.find((t: string[]) => t[0] === 'K')?.[1] || rootKind; } } - // Compose tags according to NIP-22 + + // Compose tags according to event kind const tags: string[][] = []; - // Root scope (uppercase) - if (rootAddress) { - tags.push([isRootA ? 'A' : isRootI ? 'I' : 'E', rootAddress || rootId, rootRelay, rootPubkey]); - } else { - tags.push(['E', rootId, rootRelay, rootPubkey]); - } - tags.push(['K', String(rootKind), '', '']); - tags.push(['P', rootPubkey, rootRelay, '']); - // Parent (lowercase) - if (parentAddress) { - tags.push([isRootA ? 'a' : isRootI ? 'i' : 'e', parentAddress || parent.id, parentRelay, parentPubkey]); + + if (kind === 1) { + // Kind 1 replies use simple e/p tags, not NIP-22 threading + tags.push(['e', parent.id, parentRelay, 'root']); + tags.push(['p', parentPubkey]); + + // If parent is replaceable, also add the address + if (isParentReplaceable) { + const dTag = parent.tags?.find((t: string[]) => t[0] === 'd')?.[1] || ''; + if (dTag) { + const parentAddress = `${parentKind}:${parentPubkey}:${dTag}`; + tags.push(['a', parentAddress, '', 'root']); + } + } } else { - tags.push(['e', parent.id, parentRelay, parentPubkey]); + // Kind 1111 uses NIP-22 threading format + // For replaceable events, use A/a tags; for regular events, use E/e tags + if (isParentReplaceable) { + // For replaceable events, construct the address: kind:pubkey:d-tag + const dTag = parent.tags?.find((t: string[]) => t[0] === 'd')?.[1] || ''; + if (dTag) { + const parentAddress = `${parentKind}:${parentPubkey}:${dTag}`; + + // If we're replying to a comment, use the root from the comment's tags + if (isParentComment && rootId !== parent.id) { + // Root scope (uppercase) - use the original article + tags.push(['A', parentAddress, parentRelay]); + tags.push(['K', String(rootKind)]); + tags.push(['P', rootPubkey, rootRelay]); + // Parent scope (lowercase) - the comment we're replying to + tags.push(['e', parent.id, parentRelay]); + tags.push(['k', String(parentKind)]); + tags.push(['p', parentPubkey, parentRelay]); + } else { + // Top-level comment - root and parent are the same + tags.push(['A', parentAddress, parentRelay]); + tags.push(['K', String(rootKind)]); + tags.push(['P', rootPubkey, rootRelay]); + tags.push(['a', parentAddress, parentRelay]); + tags.push(['e', parent.id, parentRelay]); + tags.push(['k', String(parentKind)]); + tags.push(['p', parentPubkey, parentRelay]); + } + } else { + // Fallback to E/e tags if no d-tag found + if (isParentComment && rootId !== parent.id) { + tags.push(['E', rootId, rootRelay]); + tags.push(['K', String(rootKind)]); + tags.push(['P', rootPubkey, rootRelay]); + tags.push(['e', parent.id, parentRelay]); + tags.push(['k', String(parentKind)]); + tags.push(['p', parentPubkey, parentRelay]); + } else { + tags.push(['E', parent.id, parentRelay]); + tags.push(['K', String(rootKind)]); + tags.push(['P', rootPubkey, rootRelay]); + tags.push(['e', parent.id, parentRelay]); + tags.push(['k', String(parentKind)]); + tags.push(['p', parentPubkey, parentRelay]); + } + } + } else { + // For regular events, use E/e tags + if (isParentComment && rootId !== parent.id) { + // Reply to a comment - distinguish root from parent + if (rootAddress) { + tags.push([isRootA ? 'A' : isRootI ? 'I' : 'E', rootAddress || rootId, rootRelay]); + } else if (rootIValue) { + tags.push(['I', rootIValue, rootIRelay]); + } else { + tags.push(['E', rootId, rootRelay]); + } + tags.push(['K', String(rootKind)]); + if (rootPubkey && !rootIValue) { + tags.push(['P', rootPubkey, rootRelay]); + } + tags.push(['e', parent.id, parentRelay]); + tags.push(['k', String(parentKind)]); + tags.push(['p', parentPubkey, parentRelay]); + } else { + // Top-level comment or regular event + if (rootAddress) { + tags.push([isRootA ? 'A' : isRootI ? 'I' : 'E', rootAddress || rootId, rootRelay]); + tags.push(['K', String(rootKind)]); + if (rootPubkey) { + tags.push(['P', rootPubkey, rootRelay]); + } + tags.push([isRootA ? 'a' : isRootI ? 'i' : 'e', parentAddress || parent.id, parentRelay]); + tags.push(['e', parent.id, parentRelay]); + tags.push(['k', String(parentKind)]); + tags.push(['p', parentPubkey, parentRelay]); + } else if (rootIValue) { + tags.push(['I', rootIValue, rootIRelay]); + tags.push(['K', String(rootKind)]); + tags.push(['i', rootIValue, rootIRelay]); + tags.push(['k', String(parentKind)]); + } else { + tags.push(['E', rootId, rootRelay]); + tags.push(['K', String(rootKind)]); + if (rootPubkey) { + tags.push(['P', rootPubkey, rootRelay]); + } + tags.push(['e', parent.id, parentRelay]); + tags.push(['k', String(parentKind)]); + tags.push(['p', parentPubkey, parentRelay]); + } + } + } } - tags.push(['k', String(parentKind), '', '']); - tags.push(['p', parentPubkey, parentRelay, '']); + // Prefix Nostr addresses before publishing + const prefixedContent = prefixNostrAddresses(content); + // Create a completely plain object to avoid proxy cloning issues const eventToSign = { kind: Number(kind), created_at: Number(Math.floor(Date.now() / 1000)), tags: tags.map(tag => [String(tag[0]), String(tag[1]), String(tag[2] || ''), String(tag[3] || '')]), - content: String(content), - pubkey: String(pubkey), + content: String(prefixedContent), + pubkey: pk, }; let sig, id; @@ -384,16 +505,16 @@ {userProfile.displayName || userProfile.name || - nip19.npubEncode(pubkey || '').slice(0, 8) + "..."} + nip19.npubEncode(pubkey() || '').slice(0, 8) + "..."}
    {/if}
    - {#if !pubkey} + {#if !pubkey()} Please sign in to post comments. Your comments will be signed with your current account. diff --git a/src/lib/components/EventInput.svelte b/src/lib/components/EventInput.svelte index c7f49d5..70d2707 100644 --- a/src/lib/components/EventInput.svelte +++ b/src/lib/components/EventInput.svelte @@ -1,9 +1,10 @@ {#if pubkey} @@ -285,6 +356,11 @@ Kind must be an integer between 0 and 65535 (NIP-01).
    {/if} + {#if kind === 30040} +
    + 30040 - Publication Index: {get30040EventDescription()} +
    + {/if}
    @@ -330,7 +406,7 @@ oninput={handleDTagInput} placeholder='d-tag (auto-generated from title)' class='input input-bordered w-full' - required + required={requiresDTag(kind)} /> {#if dTagError}
    {dTagError}
    diff --git a/src/lib/components/EventSearch.svelte b/src/lib/components/EventSearch.svelte index d731169..68b5358 100644 --- a/src/lib/components/EventSearch.svelte +++ b/src/lib/components/EventSearch.svelte @@ -1,5 +1,6 @@
    -
    +
    e.key === "Enter" && searchEvent(true)} + onkeydown={(e: KeyboardEvent) => e.key === "Enter" && searchEvent(true)} /> - +
    diff --git a/src/lib/utils/event_input_utils.ts b/src/lib/utils/event_input_utils.ts index 4a35c5e..a22fef0 100644 --- a/src/lib/utils/event_input_utils.ts +++ b/src/lib/utils/event_input_utils.ts @@ -56,6 +56,38 @@ export function validateAsciiDoc(content: string): { valid: boolean; reason?: st return { valid: true }; } +/** + * Validates that a 30040 event set will be created correctly. + * Returns { valid, reason }. + */ +export function validate30040EventSet(content: string): { valid: boolean; reason?: string } { + // First validate as AsciiDoc + const asciiDocValidation = validateAsciiDoc(content); + if (!asciiDocValidation.valid) { + return asciiDocValidation; + } + + // Check that we have at least one section + const sectionsResult = splitAsciiDocSections(content); + if (sectionsResult.sections.length === 0) { + return { valid: false, reason: '30040 events must contain at least one section.' }; + } + + // Check that we have a document title + const documentTitle = extractAsciiDocDocumentHeader(content); + if (!documentTitle) { + return { valid: false, reason: '30040 events must have a document title (line starting with "=").' }; + } + + // Check that the content will result in an empty 30040 event + // The 30040 event should have empty content, with all content split into 30041 events + if (!content.trim().startsWith('=')) { + return { valid: false, reason: '30040 events must start with a document title ("=").' }; + } + + return { valid: true }; +} + // ========================= // Extraction & Normalization // ========================= @@ -105,22 +137,63 @@ function extractMarkdownTopHeader(content: string): string | null { /** * Splits AsciiDoc content into sections at each '==' header. Returns array of section strings. + * Document title (= header) is excluded from sections and only used for the index event title. + * Section headers (==) are discarded from content. + * Text between document header and first section becomes a "Preamble" section. */ -function splitAsciiDocSections(content: string): string[] { +function splitAsciiDocSections(content: string): { sections: string[]; sectionHeaders: string[]; hasPreamble: boolean } { const lines = content.split(/\r?\n/); const sections: string[] = []; + const sectionHeaders: string[] = []; let current: string[] = []; + let foundFirstSection = false; + let hasPreamble = false; + let preambleContent: string[] = []; + for (const line of lines) { - if (/^==\s+/.test(line) && current.length > 0) { - sections.push(current.join('\n').trim()); - current = []; + // Skip document title lines (= header) + if (/^=\s+/.test(line)) { + continue; + } + + // If we encounter a section header (==) and we have content, start a new section + if (/^==\s+/.test(line)) { + if (current.length > 0) { + sections.push(current.join('\n').trim()); + current = []; + } + + // Extract section header for title tag + const headerMatch = line.match(/^==\s+(.+)$/); + if (headerMatch) { + sectionHeaders.push(headerMatch[1].trim()); + } + + foundFirstSection = true; + } else if (foundFirstSection) { + // Only add lines to current section if we've found the first section + current.push(line); + } else { + // Text before first section becomes preamble + if (line.trim() !== '') { + preambleContent.push(line); + } } - current.push(line); } + + // Add the last section if (current.length > 0) { sections.push(current.join('\n').trim()); } - return sections; + + // Add preamble as first section if it exists + if (preambleContent.length > 0) { + sections.unshift(preambleContent.join('\n').trim()); + sectionHeaders.unshift('Preamble'); + hasPreamble = true; + } + + return { sections, sectionHeaders, hasPreamble }; } // ========================= @@ -144,15 +217,29 @@ export function build30040EventSet( tags: [string, string][], baseEvent: Partial & { pubkey: string; created_at: number } ): { indexEvent: NDKEvent; sectionEvents: NDKEvent[] } { + console.log('=== build30040EventSet called ==='); + console.log('Input content:', content); + console.log('Input tags:', tags); + console.log('Input baseEvent:', baseEvent); + const ndk = getNdk(); - const sections = splitAsciiDocSections(content); - const sectionHeaders = extractAsciiDocSectionHeaders(content); + console.log('NDK instance:', ndk); + + const sectionsResult = splitAsciiDocSections(content); + const sections = sectionsResult.sections; + const sectionHeaders = sectionsResult.sectionHeaders; + console.log('Sections:', sections); + console.log('Section headers:', sectionHeaders); + const dTags = sectionHeaders.length === sections.length ? sectionHeaders.map(normalizeDTagValue) : sections.map((_, i) => `section${i}`); + console.log('D tags:', dTags); + const sectionEvents: NDKEvent[] = sections.map((section, i) => { const header = sectionHeaders[i] || `Section ${i + 1}`; const dTag = dTags[i]; + console.log(`Creating section ${i}:`, { header, dTag, content: section }); return new NDKEventClass(ndk, { kind: 30041, content: section, @@ -165,10 +252,23 @@ export function build30040EventSet( created_at: baseEvent.created_at, }); }); + + // Create proper a tags with format: kind:pubkey:d-tag + const aTags = dTags.map(dTag => ['a', `30041:${baseEvent.pubkey}:${dTag}`] as [string, string]); + console.log('A tags:', aTags); + + // Extract document title for the index event + const documentTitle = extractAsciiDocDocumentHeader(content); + const indexDTag = documentTitle ? normalizeDTagValue(documentTitle) : 'index'; + console.log('Index event:', { documentTitle, indexDTag }); + const indexTags = [ ...tags, - ...dTags.map(d => ['a', d] as [string, string]), + ['d', indexDTag], + ['title', documentTitle || 'Untitled'], + ...aTags, ]; + const indexEvent: NDKEvent = new NDKEventClass(ndk, { kind: 30040, content: '', @@ -176,6 +276,8 @@ export function build30040EventSet( pubkey: baseEvent.pubkey, created_at: baseEvent.created_at, }); + console.log('Final index event:', indexEvent); + console.log('=== build30040EventSet completed ==='); return { indexEvent, sectionEvents }; } @@ -216,4 +318,82 @@ export function getDTagForEvent(kind: number, content: string, existingDTag?: st } return null; +} + +/** + * Returns a description of what a 30040 event structure should be. + */ +export function get30040EventDescription(): string { + return `30040 events are publication indexes that contain: +- Empty content (metadata only) +- A d-tag for the publication identifier +- A title tag for the publication title +- A tags referencing 30041 content events (one per section) + +The content is split into sections, each published as a separate 30041 event.`; +} + +/** + * Analyzes a 30040 event to determine if it was created correctly. + * Returns { valid, issues } where issues is an array of problems found. + */ +export function analyze30040Event(event: { content: string; tags: [string, string][]; kind: number }): { valid: boolean; issues: string[] } { + const issues: string[] = []; + + // Check if it's actually a 30040 event + if (event.kind !== 30040) { + issues.push('Event is not kind 30040'); + return { valid: false, issues }; + } + + // Check if content is empty (30040 should be metadata only) + if (event.content && event.content.trim() !== '') { + issues.push('30040 events should have empty content (metadata only)'); + issues.push('Content should be split into separate 30041 events'); + } + + // Check for required tags + const hasTitle = event.tags.some(([k, v]) => k === 'title' && v); + const hasDTag = event.tags.some(([k, v]) => k === 'd' && v); + const hasATags = event.tags.some(([k, v]) => k === 'a' && v); + + if (!hasTitle) { + issues.push('Missing title tag'); + } + if (!hasDTag) { + issues.push('Missing d tag'); + } + if (!hasATags) { + issues.push('Missing a tags (should reference 30041 content events)'); + } + + // Check if a tags have the correct format (kind:pubkey:d-tag) + const aTags = event.tags.filter(([k, v]) => k === 'a' && v); + for (const [, value] of aTags) { + if (!value.includes(':')) { + issues.push(`Invalid a tag format: ${value} (should be "kind:pubkey:d-tag")`); + } + } + + return { valid: issues.length === 0, issues }; +} + +/** + * Returns guidance on how to fix incorrect 30040 events. + */ +export function get30040FixGuidance(): string { + return `To fix a 30040 event: + +1. **Content Issue**: 30040 events should have empty content. All content should be split into separate 30041 events. + +2. **Structure**: A proper 30040 event should contain: + - Empty content + - d tag: publication identifier + - title tag: publication title + - a tags: references to 30041 content events (format: "30041:pubkey:d-tag") + +3. **Process**: When creating a 30040 event: + - Write your content with document title (= Title) and sections (== Section) + - The system will automatically split it into one 30040 index event and multiple 30041 content events + - The 30040 will have empty content and reference the 30041s via a tags`; } \ No newline at end of file diff --git a/src/lib/utils/nostrUtils.ts b/src/lib/utils/nostrUtils.ts index 739c8f5..b30d46b 100644 --- a/src/lib/utils/nostrUtils.ts +++ b/src/lib/utils/nostrUtils.ts @@ -507,3 +507,79 @@ export async function signEvent(event: { const sig = await schnorr.sign(id, event.pubkey); return bytesToHex(sig); } + +/** + * Prefixes Nostr addresses (npub, nprofile, nevent, naddr, note, etc.) with "nostr:" + * if they are not already prefixed and are not part of a hyperlink + */ +export function prefixNostrAddresses(content: string): string { + // Regex to match Nostr addresses that are not already prefixed with "nostr:" + // and are not part of a markdown link or HTML link + // Must be followed by at least 20 alphanumeric characters to be considered an address + const nostrAddressPattern = /\b(npub|nprofile|nevent|naddr|note)[a-zA-Z0-9]{20,}\b/g; + + return content.replace(nostrAddressPattern, (match, offset) => { + // Check if this match is part of a markdown link [text](url) + const beforeMatch = content.substring(0, offset); + const afterMatch = content.substring(offset + match.length); + + // Check if it's part of a markdown link + const beforeBrackets = beforeMatch.lastIndexOf('['); + const afterParens = afterMatch.indexOf(')'); + + if (beforeBrackets !== -1 && afterParens !== -1) { + const textBeforeBrackets = beforeMatch.substring(0, beforeBrackets); + const lastOpenBracket = textBeforeBrackets.lastIndexOf('['); + const lastCloseBracket = textBeforeBrackets.lastIndexOf(']'); + + // If we have [text] before this, it might be a markdown link + if (lastOpenBracket !== -1 && lastCloseBracket > lastOpenBracket) { + return match; // Don't prefix if it's part of a markdown link + } + } + + // Check if it's part of an HTML link + const beforeHref = beforeMatch.lastIndexOf('href='); + if (beforeHref !== -1) { + const afterHref = afterMatch.indexOf('"'); + if (afterHref !== -1) { + return match; // Don't prefix if it's part of an HTML link + } + } + + // Check if it's already prefixed with "nostr:" + const beforeNostr = beforeMatch.lastIndexOf('nostr:'); + if (beforeNostr !== -1) { + const textAfterNostr = beforeMatch.substring(beforeNostr + 6); + if (!textAfterNostr.includes(' ')) { + return match; // Already prefixed + } + } + + // Additional check: ensure it's actually a valid Nostr address format + // The part after the prefix should be a valid bech32 string + const addressPart = match.substring(4); // Remove npub, nprofile, etc. + if (addressPart.length < 20) { + return match; // Too short to be a valid address + } + + // Check if it looks like a valid bech32 string (alphanumeric, no special chars) + if (!/^[a-zA-Z0-9]+$/.test(addressPart)) { + return match; // Not a valid bech32 format + } + + // Additional check: ensure the word before is not a common word that would indicate + // this is just a general reference, not an actual address + const wordBefore = beforeMatch.match(/\b(\w+)\s*$/); + if (wordBefore) { + const beforeWord = wordBefore[1].toLowerCase(); + const commonWords = ['the', 'a', 'an', 'this', 'that', 'my', 'your', 'his', 'her', 'their', 'our']; + if (commonWords.includes(beforeWord)) { + return match; // Likely just a general reference, not an actual address + } + } + + // Prefix with "nostr:" + return `nostr:${match}`; + }); +} diff --git a/src/routes/events/+page.svelte b/src/routes/events/+page.svelte index fd1236b..3ed8137 100644 --- a/src/routes/events/+page.svelte +++ b/src/routes/events/+page.svelte @@ -2,6 +2,7 @@ import { Heading, P } from "flowbite-svelte"; import { onMount } from "svelte"; import { page } from "$app/stores"; + import { goto } from "$app/navigation"; import type { NDKEvent } from "$lib/utils/nostrUtils"; import EventSearch from "$lib/components/EventSearch.svelte"; import EventDetails from "$lib/components/EventDetails.svelte"; @@ -52,6 +53,10 @@ profile = null; } + function handleClear() { + goto('/events', { replaceState: true }); + } + function getSummary(event: NDKEvent): string | undefined { return getMatchingTags(event, "summary")[0]?.[1]; } @@ -61,6 +66,10 @@ return getMatchingTags(event, "deferrel")[0]?.[1]; } + function onLoadingChange(val: boolean) { + loading = val; + } + $effect(() => { const id = $page.url.searchParams.get("id"); const dTag = $page.url.searchParams.get("d"); @@ -75,6 +84,13 @@ dTagValue = dTag ? dTag.toLowerCase() : null; searchValue = null; } + + // Reset state if both id and dTag are absent + if (!id && !dTag) { + event = null; + searchResults = []; + profile = null; + } }); onMount(() => { @@ -108,6 +124,8 @@ {event} onEventFound={handleEventFound} onSearchResults={handleSearchResults} + onClear={handleClear} + onLoadingChange={onLoadingChange} /> {#if $isLoggedIn && !event && searchResults.length === 0} From 5d6d24dfbcdcb831436fa411948abdadb1831b36 Mon Sep 17 00:00:00 2001 From: Silberengel Date: Thu, 10 Jul 2025 09:08:09 +0200 Subject: [PATCH 095/135] Made the buttons more prominent --- src/lib/components/EventInput.svelte | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/lib/components/EventInput.svelte b/src/lib/components/EventInput.svelte index 70d2707..9def128 100644 --- a/src/lib/components/EventInput.svelte +++ b/src/lib/components/EventInput.svelte @@ -372,7 +372,9 @@
    {/each} - +
    + +
    @@ -412,7 +414,9 @@
    {dTagError}
    {/if}
    - +
    + +
    {#if loading} Publishing... {/if} From 1fff18b26729ebf49e658a10f3e4d939dbfd73af Mon Sep 17 00:00:00 2001 From: Silberengel Date: Thu, 10 Jul 2025 15:34:08 +0200 Subject: [PATCH 096/135] latex/Asciidoc rendering improvement for NostrMarkup --- .../advancedAsciidoctorPostProcessor.ts | 121 ++++-- src/lib/utils/markup/advancedMarkupParser.ts | 409 +++++++++++++----- src/lib/utils/markup/basicMarkupParser.ts | 4 +- test_data/LaTeXtestfile.json | 34 ++ test_data/LaTeXtestfile.md | 135 ++++++ test_data/latex_markdown.md | 50 --- tests/unit/latexRendering.test.ts | 112 ++--- 7 files changed, 593 insertions(+), 272 deletions(-) create mode 100644 test_data/LaTeXtestfile.json create mode 100644 test_data/LaTeXtestfile.md delete mode 100644 test_data/latex_markdown.md diff --git a/src/lib/utils/markup/advancedAsciidoctorPostProcessor.ts b/src/lib/utils/markup/advancedAsciidoctorPostProcessor.ts index 0700496..ab417d7 100644 --- a/src/lib/utils/markup/advancedAsciidoctorPostProcessor.ts +++ b/src/lib/utils/markup/advancedAsciidoctorPostProcessor.ts @@ -45,54 +45,103 @@ export async function postProcessAdvancedAsciidoctorHtml( /** * Fixes all math blocks for MathJax rendering. - * Handles stem blocks, inline math, and normalizes delimiters. + * Now only processes LaTeX within inline code blocks. */ function fixAllMathBlocks(html: string): string { // Unescape \$ to $ for math delimiters html = html.replace(/\\\$/g, "$"); - // Block math:
    ...
    + // Process inline code blocks that contain LaTeX html = html.replace( - /
    \s*
    ([\s\S]*?)<\/div>\s*<\/div>/g, - (_match, mathContent) => { - let cleanMath = mathContent - .replace(/\$<\/span>/g, "") - .replace(/\$\$<\/span>/g, "") - // Remove $ or $$ on their own line, or surrounded by whitespace/newlines - .replace(/(^|[\n\r\s])\$([\n\r\s]|$)/g, "$1$2") - .replace(/(^|[\n\r\s])\$\$([\n\r\s]|$)/g, "$1$2") - // Remove all leading and trailing whitespace and $ - .replace(/^[\s$]+/, "") - .replace(/[\s$]+$/, "") - .trim(); // Final trim to remove any stray whitespace or $ - // Always wrap in $$...$$ - return `
    $$${cleanMath}$$
    `; - }, - ); - // Inline math: $ ... $ (allow whitespace/newlines) - html = html.replace( - /\$<\/span>\s*([\s\S]+?)\s*\$<\/span>/g, - (_match, mathContent) => - `$${mathContent.trim()}$`, - ); - // Inline math: stem:[...] or latexmath:[...] - html = html.replace( - /stem:\[([^\]]+?)\]/g, - (_match, content) => `$${content.trim()}$`, - ); - html = html.replace( - /latexmath:\[([^\]]+?)\]/g, - (_match, content) => - `\\(${content.trim().replace(/\\\\/g, "\\")}\\)`, + /]*class="[^"]*language-[^"]*"[^>]*>([\s\S]*?)<\/code>/g, + (match, codeContent) => { + const trimmedCode = codeContent.trim(); + if (isLaTeXContent(trimmedCode)) { + return `$${trimmedCode}$`; + } + return match; // Return original if not LaTeX + } ); + + // Also process code blocks without language class html = html.replace( - /asciimath:\[([^\]]+?)\]/g, - (_match, content) => - `\`${content.trim()}\``, + /]*>([\s\S]*?)<\/code>/g, + (match, codeContent) => { + const trimmedCode = codeContent.trim(); + if (isLaTeXContent(trimmedCode)) { + return `$${trimmedCode}$`; + } + return match; // Return original if not LaTeX + } ); + return html; } +/** + * Checks if content contains LaTeX syntax + */ +function isLaTeXContent(content: string): boolean { + const trimmed = content.trim(); + + // Check for common LaTeX patterns + const latexPatterns = [ + /\\[a-zA-Z]+/, // LaTeX commands like \frac, \sum, etc. + /\\[\(\)\[\]]/, // LaTeX delimiters like \(, \), \[, \] + /\\begin\{/, // LaTeX environments + /\\end\{/, // LaTeX environments + /\$\$/, // Display math delimiters + /\$[^$]+\$/, // Inline math delimiters + /\\text\{/, // LaTeX text command + /\\mathrm\{/, // LaTeX mathrm command + /\\mathbf\{/, // LaTeX bold command + /\\mathit\{/, // LaTeX italic command + /\\sqrt/, // Square root + /\\frac/, // Fraction + /\\sum/, // Sum + /\\int/, // Integral + /\\lim/, // Limit + /\\infty/, // Infinity + /\\alpha/, // Greek letters + /\\beta/, + /\\gamma/, + /\\delta/, + /\\theta/, + /\\lambda/, + /\\mu/, + /\\pi/, + /\\sigma/, + /\\phi/, + /\\omega/, + /\\partial/, // Partial derivative + /\\nabla/, // Nabla + /\\cdot/, // Dot product + /\\times/, // Times + /\\div/, // Division + /\\pm/, // Plus-minus + /\\mp/, // Minus-plus + /\\leq/, // Less than or equal + /\\geq/, // Greater than or equal + /\\neq/, // Not equal + /\\approx/, // Approximately equal + /\\equiv/, // Equivalent + /\\propto/, // Proportional + /\\in/, // Element of + /\\notin/, // Not element of + /\\subset/, // Subset + /\\supset/, // Superset + /\\cup/, // Union + /\\cap/, // Intersection + /\\emptyset/, // Empty set + /\\mathbb\{/, // Blackboard bold + /\\mathcal\{/, // Calligraphic + /\\mathfrak\{/, // Fraktur + /\\mathscr\{/, // Script + ]; + + return latexPatterns.some(pattern => pattern.test(trimmed)); +} + /** * Processes PlantUML blocks in HTML content */ diff --git a/src/lib/utils/markup/advancedMarkupParser.ts b/src/lib/utils/markup/advancedMarkupParser.ts index 34785ba..2e4721f 100644 --- a/src/lib/utils/markup/advancedMarkupParser.ts +++ b/src/lib/utils/markup/advancedMarkupParser.ts @@ -8,6 +8,22 @@ hljs.configure({ ignoreUnescapedHTML: true, }); +// Escapes HTML characters for safe display +function escapeHtml(text: string): string { + const div = typeof document !== 'undefined' ? document.createElement('div') : null; + if (div) { + div.textContent = text; + return div.innerHTML; + } + // Fallback for non-browser environments + return text + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); +} + // Regular expressions for advanced markup elements const HEADING_REGEX = /^(#{1,6})\s+(.+)$/gm; const ALTERNATE_HEADING_REGEX = /^([^\n]+)\n(=+|-+)\n/gm; @@ -380,111 +396,296 @@ function restoreCodeBlocks(text: string, blocks: Map): string { } /** - * Process LaTeX math expressions using a token-based approach to avoid nested processing + * Process $...$ and $$...$$ math blocks: render as LaTeX if recognized, otherwise as AsciiMath + * This must run BEFORE any paragraph or inline code formatting. + */ +function processDollarMath(content: string): string { + // Display math: $$...$$ (multi-line, not empty) + content = content.replace(/\$\$([\s\S]*?\S[\s\S]*?)\$\$/g, (match, expr) => { + if (isLaTeXContent(expr)) { + return `
    $$${expr}$$
    `; + } else { + // Strip all $ or $$ from AsciiMath + const clean = expr.replace(/\$+/g, '').trim(); + return `
    ${clean}
    `; + } + }); + // Inline math: $...$ (not empty, not just whitespace) + content = content.replace(/\$([^\s$][^$\n]*?)\$/g, (match, expr) => { + if (isLaTeXContent(expr)) { + return `$${expr}$`; + } else { + const clean = expr.replace(/\$+/g, '').trim(); + return `${clean}`; + } + }); + return content; +} + +/** + * Process LaTeX math expressions only within inline code blocks */ function processMathExpressions(content: string): string { - // Tokenize the content to avoid nested processing - const tokens: Array<{type: 'text' | 'math', content: string}> = []; - let currentText = ''; - let i = 0; - - while (i < content.length) { - // Check for LaTeX environments first (most specific) - const envMatch = content.slice(i).match(/^\\begin\{([^}]+)\}([\s\S]*?)\\end\{\1\}/); - if (envMatch) { - if (currentText) { - tokens.push({type: 'text', content: currentText}); - currentText = ''; - } - tokens.push({type: 'math', content: `\\begin{${envMatch[1]}}${envMatch[2]}\\end{${envMatch[1]}}`}); - i += envMatch[0].length; - continue; + // Only process LaTeX within inline code blocks (backticks) + return content.replace(INLINE_CODE_REGEX, (match, code) => { + const trimmedCode = code.trim(); + + // Check for unsupported LaTeX environments (like tabular) first + if (/\\begin\{tabular\}|\\\\begin\{tabular\}/.test(trimmedCode)) { + return `
    +

    + Unrendered, as it is LaTeX typesetting, not a formula: +

    +
    +          ${escapeHtml(trimmedCode)}
    +        
    +
    `; } - - // Check for display math blocks ($$...$$) - const displayMatch = content.slice(i).match(/^\$\$([\s\S]*?)\$\$/); - if (displayMatch) { - if (currentText) { - tokens.push({type: 'text', content: currentText}); - currentText = ''; + + // Check if the code contains LaTeX syntax + if (isLaTeXContent(trimmedCode)) { + // Detect LaTeX display math (\\[...\\]) + if (/^\\\[[\s\S]*\\\]$/.test(trimmedCode)) { + // Remove the delimiters for rendering + const inner = trimmedCode.replace(/^\\\[|\\\]$/g, ''); + return `
    $$${inner}$$
    `; } - tokens.push({type: 'math', content: displayMatch[1]}); - i += displayMatch[0].length; - continue; - } - - // Check for LaTeX display math (\[...\]) - const latexDisplayMatch = content.slice(i).match(/^\\\[([^\]]+)\\\]/); - if (latexDisplayMatch) { - if (currentText) { - tokens.push({type: 'text', content: currentText}); - currentText = ''; + // Detect display math ($$...$$) + if (/^\$\$[\s\S]*\$\$$/.test(trimmedCode)) { + // Remove the delimiters for rendering + const inner = trimmedCode.replace(/^\$\$|\$\$$/g, ''); + return `
    $$${inner}$$
    `; } - tokens.push({type: 'math', content: latexDisplayMatch[1]}); - i += latexDisplayMatch[0].length; - continue; - } - - // Check for inline math ($...$) - const inlineMatch = content.slice(i).match(/^\$([^$\n]+)\$/); - if (inlineMatch) { - if (currentText) { - tokens.push({type: 'text', content: currentText}); - currentText = ''; + // Detect inline math ($...$) + if (/^\$[\s\S]*\$$/.test(trimmedCode)) { + // Remove the delimiters for rendering + const inner = trimmedCode.replace(/^\$|\$$/g, ''); + return `$${inner}$`; } - tokens.push({type: 'math', content: inlineMatch[1]}); - i += inlineMatch[0].length; - continue; - } - - // Check for LaTeX inline math (\(...\)) - const latexInlineMatch = content.slice(i).match(/^\\\(([^)]+)\\\)/); - if (latexInlineMatch) { - if (currentText) { - tokens.push({type: 'text', content: currentText}); - currentText = ''; + // Default to inline math for any other LaTeX content + return `$${trimmedCode}$`; + } else { + // Check for edge cases that should remain as code, not math + // These patterns indicate code that contains dollar signs but is not math + const codePatterns = [ + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*=/, // Variable assignment like "const price =" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*\(/, // Function call like "echo(" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*\{/, // Object literal like "const obj = {" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*\[/, // Array literal like "const arr = [" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*!&|^~]/, // Operator like "const x = 1 +" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[a-zA-Z_$][a-zA-Z0-9_$]*/, // Two identifiers like "const price = amount" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[0-9]/, // Number like "const x = 1" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*[+\-*/%=<>!&|^~]/, // Complex expression like "const price = amount +" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[a-zA-Z0-9_$]*\s*[a-zA-Z_$][a-zA-Z0-9_$]*/, // Three identifiers like "const price = amount + tax" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*[0-9]/, // Two identifiers and number like "const price = amount + 1" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[0-9]\s*[+\-*/%=<>!&|^~]/, // Identifier, number, operator like "const x = 1 +" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[0-9]\s*[a-zA-Z_$][a-zA-Z0-9_$]*/, // Identifier, number, identifier like "const x = 1 + y" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[0-9]\s*[0-9]/, // Identifier, number, number like "const x = 1 + 2" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[0-9]\s*[+\-*/%=<>!&|^~]\s*[a-zA-Z_$][a-zA-Z0-9_$]*/, // Complex like "const x = 1 + y" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[0-9]\s*[+\-*/%=<>!&|^~]\s*[0-9]/, // Complex like "const x = 1 + 2" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[0-9]\s*[+\-*/%=<>!&|^~]\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*[+\-*/%=<>!&|^~]/, // Very complex like "const x = 1 + y +" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[0-9]\s*[+\-*/%=<>!&|^~]\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*[+\-*/%=<>!&|^~]\s*[a-zA-Z_$][a-zA-Z0-9_$]*/, // Very complex like "const x = 1 + y + z" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[0-9]\s*[+\-*/%=<>!&|^~]\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*[+\-*/%=<>!&|^~]\s*[0-9]/, // Very complex like "const x = 1 + y + 2" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[0-9]\s*[+\-*/%=<>!&|^~]\s*[0-9]\s*[+\-*/%=<>!&|^~]/, // Very complex like "const x = 1 + 2 +" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[0-9]\s*[+\-*/%=<>!&|^~]\s*[0-9]\s*[+\-*/%=<>!&|^~]\s*[a-zA-Z_$][a-zA-Z0-9_$]*/, // Very complex like "const x = 1 + 2 + y" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[0-9]\s*[+\-*/%=<>!&|^~]\s*[0-9]\s*[+\-*/%=<>!&|^~]\s*[0-9]/, // Very complex like "const x = 1 + 2 + 3" + // Additional patterns for JavaScript template literals and other code + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*=\s*`/, // Template literal assignment like "const str = `" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*=\s*'/, // String assignment like "const str = '" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*=\s*"/, // String assignment like "const str = \"" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*=\s*[0-9]/, // Number assignment like "const x = 1" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*=\s*[a-zA-Z_$][a-zA-Z0-9_$]*/, // Variable assignment like "const x = y" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*=\s*[+\-*/%=<>!&|^~]/, // Assignment with operator like "const x = +" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*=\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*[+\-*/%=<>!&|^~]/, // Assignment with variable and operator like "const x = y +" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*=\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*[+\-*/%=<>!&|^~]\s*[a-zA-Z_$][a-zA-Z0-9_$]*/, // Assignment with two variables and operator like "const x = y + z" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*=\s*[0-9]\s*[+\-*/%=<>!&|^~]/, // Assignment with number and operator like "const x = 1 +" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*=\s*[0-9]\s*[+\-*/%=<>!&|^~]\s*[a-zA-Z_$][a-zA-Z0-9_$]*/, // Assignment with number, operator, variable like "const x = 1 + y" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*=\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*[+\-*/%=<>!&|^~]\s*[0-9]/, // Assignment with variable, operator, number like "const x = y + 1" + /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*=\s*[0-9]\s*[+\-*/%=<>!&|^~]\s*[0-9]/, // Assignment with number, operator, number like "const x = 1 + 2" + ]; + + // If it matches code patterns, treat as regular code + if (codePatterns.some(pattern => pattern.test(trimmedCode))) { + const escapedCode = trimmedCode + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); + return `${escapedCode}`; } - tokens.push({type: 'math', content: latexInlineMatch[1]}); - i += latexInlineMatch[0].length; - continue; + + // Return as regular inline code + const escapedCode = trimmedCode + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); + return `${escapedCode}`; } - - // If no math pattern matches, add to current text - currentText += content[i]; - i++; + }); +} + +/** + * Checks if content contains LaTeX syntax + */ +function isLaTeXContent(content: string): boolean { + const trimmed = content.trim(); + + // Check for simple math expressions first (like AsciiMath) + if (/^\$[^$]+\$$/.test(trimmed)) { + return true; } - // Add any remaining text - if (currentText) { - tokens.push({type: 'text', content: currentText}); + // Check for display math + if (/^\$\$[\s\S]*\$\$$/.test(trimmed)) { + return true; } - // Now process the tokens to create the final HTML - let result = ''; - for (const token of tokens) { - if (token.type === 'text') { - result += token.content; - } else { - // Determine if this should be display or inline math - const isDisplay = token.content.includes('\\begin{') || - token.content.includes('\\end{') || - token.content.includes('\\[') || - token.content.includes('\\]') || - token.content.length > 50 || // Heuristic for display math - token.content.includes('=') && token.content.length > 20 || // Equations with equals - token.content.includes('\\begin{') || // Any LaTeX environment - token.content.includes('\\boxed{') || // Boxed expressions - token.content.includes('\\text{') && token.content.length > 30; // Text blocks - - if (isDisplay) { - result += `
    $$${token.content}$$
    `; - } else { - result += `$${token.content}$`; - } - } + // Check for LaTeX display math + if (/^\\\[[\s\S]*\\\]$/.test(trimmed)) { + return true; } - return result; + // Check for LaTeX environments with double backslashes (like tabular) + if (/\\\\begin\{[^}]+\}/.test(trimmed) || /\\\\end\{[^}]+\}/.test(trimmed)) { + return true; + } + + // Check for common LaTeX patterns + const latexPatterns = [ + /\\[a-zA-Z]+/, // LaTeX commands like \frac, \sum, etc. + /\\\\[a-zA-Z]+/, // LaTeX commands with double backslashes like \\frac, \\sum, etc. + /\\[\(\)\[\]]/, // LaTeX delimiters like \(, \), \[, \] + /\\\\[\(\)\[\]]/, // LaTeX delimiters with double backslashes like \\(, \\), \\[, \\] + /\\\[[\s\S]*?\\\]/, // LaTeX display math \[ ... \] + /\\\\\[[\s\S]*?\\\\\]/, // LaTeX display math with double backslashes \\[ ... \\] + /\\begin\{/, // LaTeX environments + /\\\\begin\{/, // LaTeX environments with double backslashes + /\\end\{/, // LaTeX environments + /\\\\end\{/, // LaTeX environments with double backslashes + /\\begin\{array\}/, // LaTeX array environment + /\\\\begin\{array\}/, // LaTeX array environment with double backslashes + /\\end\{array\}/, + /\\\\end\{array\}/, + /\\begin\{matrix\}/, // LaTeX matrix environment + /\\\\begin\{matrix\}/, // LaTeX matrix environment with double backslashes + /\\end\{matrix\}/, + /\\\\end\{matrix\}/, + /\\begin\{bmatrix\}/, // LaTeX bmatrix environment + /\\\\begin\{bmatrix\}/, // LaTeX bmatrix environment with double backslashes + /\\end\{bmatrix\}/, + /\\\\end\{bmatrix\}/, + /\\begin\{pmatrix\}/, // LaTeX pmatrix environment + /\\\\begin\{pmatrix\}/, // LaTeX pmatrix environment with double backslashes + /\\end\{pmatrix\}/, + /\\\\end\{pmatrix\}/, + /\\begin\{tabular\}/, // LaTeX tabular environment + /\\\\begin\{tabular\}/, // LaTeX tabular environment with double backslashes + /\\end\{tabular\}/, + /\\\\end\{tabular\}/, + /\$\$/, // Display math delimiters + /\$[^$]+\$/, // Inline math delimiters + /\\text\{/, // LaTeX text command + /\\\\text\{/, // LaTeX text command with double backslashes + /\\mathrm\{/, // LaTeX mathrm command + /\\\\mathrm\{/, // LaTeX mathrm command with double backslashes + /\\mathbf\{/, // LaTeX bold command + /\\\\mathbf\{/, // LaTeX bold command with double backslashes + /\\mathit\{/, // LaTeX italic command + /\\\\mathit\{/, // LaTeX italic command with double backslashes + /\\sqrt/, // Square root + /\\\\sqrt/, // Square root with double backslashes + /\\frac/, // Fraction + /\\\\frac/, // Fraction with double backslashes + /\\sum/, // Sum + /\\\\sum/, // Sum with double backslashes + /\\int/, // Integral + /\\\\int/, // Integral with double backslashes + /\\lim/, // Limit + /\\\\lim/, // Limit with double backslashes + /\\infty/, // Infinity + /\\\\infty/, // Infinity with double backslashes + /\\alpha/, // Greek letters + /\\\\alpha/, // Greek letters with double backslashes + /\\beta/, + /\\\\beta/, + /\\gamma/, + /\\\\gamma/, + /\\delta/, + /\\\\delta/, + /\\theta/, + /\\\\theta/, + /\\lambda/, + /\\\\lambda/, + /\\mu/, + /\\\\mu/, + /\\pi/, + /\\\\pi/, + /\\sigma/, + /\\\\sigma/, + /\\phi/, + /\\\\phi/, + /\\omega/, + /\\\\omega/, + /\\partial/, // Partial derivative + /\\\\partial/, // Partial derivative with double backslashes + /\\nabla/, // Nabla + /\\\\nabla/, // Nabla with double backslashes + /\\cdot/, // Dot product + /\\\\cdot/, // Dot product with double backslashes + /\\times/, // Times + /\\\\times/, // Times with double backslashes + /\\div/, // Division + /\\\\div/, // Division with double backslashes + /\\pm/, // Plus-minus + /\\\\pm/, // Plus-minus with double backslashes + /\\mp/, // Minus-plus + /\\\\mp/, // Minus-plus with double backslashes + /\\leq/, // Less than or equal + /\\\\leq/, // Less than or equal with double backslashes + /\\geq/, // Greater than or equal + /\\\\geq/, // Greater than or equal with double backslashes + /\\neq/, // Not equal + /\\\\neq/, // Not equal with double backslashes + /\\approx/, // Approximately equal + /\\\\approx/, // Approximately equal with double backslashes + /\\equiv/, // Equivalent + /\\\\equiv/, // Equivalent with double backslashes + /\\propto/, // Proportional + /\\\\propto/, // Proportional with double backslashes + /\\in/, // Element of + /\\\\in/, // Element of with double backslashes + /\\notin/, // Not element of + /\\\\notin/, // Not element of with double backslashes + /\\subset/, // Subset + /\\\\subset/, // Subset with double backslashes + /\\supset/, // Superset + /\\\\supset/, // Superset with double backslashes + /\\cup/, // Union + /\\\\cup/, // Union with double backslashes + /\\cap/, // Intersection + /\\\\cap/, // Intersection with double backslashes + /\\emptyset/, // Empty set + /\\\\emptyset/, // Empty set with double backslashes + /\\mathbb\{/, // Blackboard bold + /\\\\mathbb\{/, // Blackboard bold with double backslashes + /\\mathcal\{/, // Calligraphic + /\\\\mathcal\{/, // Calligraphic with double backslashes + /\\mathfrak\{/, // Fraktur + /\\\\mathfrak\{/, // Fraktur with double backslashes + /\\mathscr\{/, // Script + /\\\\mathscr\{/, // Script with double backslashes + ]; + + return latexPatterns.some(pattern => pattern.test(trimmed)); } /** @@ -498,34 +699,26 @@ export async function parseAdvancedmarkup(text: string): Promise { const { text: withoutCode, blocks } = processCodeBlocks(text); let processedText = withoutCode; - // Step 2: Process LaTeX math expressions FIRST to avoid wrapping in

    or

    + // Step 2: Process $...$ and $$...$$ math blocks (LaTeX or AsciiMath) + processedText = processDollarMath(processedText); + + // Step 3: Process LaTeX math expressions ONLY within inline code blocks (legacy support) processedText = processMathExpressions(processedText); - // Step 3: Process block-level elements + // Step 4: Process block-level elements (tables, blockquotes, headings, horizontal rules) processedText = processTables(processedText); processedText = processBlockquotes(processedText); processedText = processHeadings(processedText); processedText = processHorizontalRules(processedText); - // Process inline elements - processedText = processedText.replace(INLINE_CODE_REGEX, (_, code) => { - const escapedCode = code - .trim() - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """) - .replace(/'/g, "'"); - return `${escapedCode}`; - }); - - // Process footnotes (only references, not definitions) + // Step 5: Process footnotes (only references, not definitions) processedText = processFootnotes(processedText); - // Process basic markup (which will also handle Nostr identifiers) + // Step 6: Process basic markup (which will also handle Nostr identifiers) + // This includes paragraphs, inline code, links, lists, etc. processedText = await parseBasicmarkup(processedText); - // Step 4: Restore code blocks + // Step 7: Restore code blocks processedText = restoreCodeBlocks(processedText, blocks); return processedText; diff --git a/src/lib/utils/markup/basicMarkupParser.ts b/src/lib/utils/markup/basicMarkupParser.ts index f829462..e7a1d74 100644 --- a/src/lib/utils/markup/basicMarkupParser.ts +++ b/src/lib/utils/markup/basicMarkupParser.ts @@ -411,8 +411,8 @@ export async function parseBasicmarkup(text: string): Promise { .map((para) => para.trim()) .filter((para) => para.length > 0) .map((para) => { - // Skip wrapping if para already contains block-level elements - if (/<(div|h[1-6]|blockquote|table|pre|ul|ol|hr)/i.test(para)) { + // Skip wrapping if para already contains block-level elements or math blocks + if (/(]*class=["'][^"']*math-block[^"']*["'])|<(div|h[1-6]|blockquote|table|pre|ul|ol|hr)/i.test(para)) { return para; } return `

    ${para}

    `; diff --git a/test_data/LaTeXtestfile.json b/test_data/LaTeXtestfile.json new file mode 100644 index 0000000..079226d --- /dev/null +++ b/test_data/LaTeXtestfile.json @@ -0,0 +1,34 @@ +{ + "created_at": 1752150799, + "content": "# This is a test file for writing mathematical formulas in #NostrMarkup\n\nThis document covers the rendering of formulas in TeX/LaTeX and AsciiMath notation, or some combination of those within the same page. It is meant to be rendered by clients utilizing MathJax.\n\nIf you want the entire document to be rendered as mathematics, place the entire thing in a back-tick code-block, but know that this makes the document slower to load, it is harder to format the prose, and the result is less legible. It also doesn't increase portability, as it's easy to export markup as LaTeX files, or as PDFs, with the formulas rendered.\n\nThe general idea, is that anything placed within `single back-ticks` is inline code, and inline-code will all be scanned for typical mathematics statements and rendered with best-effort. (For more precise rendering, use AsciiDoc.) We will not render text that is not marked as inline code, as mathematical formulas, as that is prose.\n\nIf you want the TeX to be blended into the surrounding text, wrap the text within single `$`. Otherwise, use double `$$` symbols, for display math, and it will appear on its own line.\n\n## TeX Examples\n\nInline equation: `$\\sqrt{x}$`\n\nSame equation, in the display mode: `$$\\sqrt{x}$$`\n\nSomething more complex, inline: `$\\mathbb{N} = \\{ a \\in \\mathbb{Z} : a > 0 \\}$`\n\nSomething complex, in display mode: `$$P \\left( A=2 \\, \\middle| \\, \\dfrac{A^2}{B}>4 \\right)$$`\n\nAnother example of `$$\\prod_{i=1}^{n} x_i - 1$$` inline formulas.\n\nFunction example: \n`$$\nf(x)=\n\\begin{cases}\n1/d_{ij} & \\quad \\text{when $d_{ij} \\leq 160$}\\\\ \n0 & \\quad \\text{otherwise}\n\\end{cases}\n$$`\n\nAnd a matrix:\n`$$\nM = \n\\begin{bmatrix}\n\\frac{5}{6} & \\frac{1}{6} & 0 \\\\[0.3em]\n\\frac{5}{6} & 0 & \\frac{1}{6} \\\\[0.3em]\n0 & \\frac{5}{6} & \\frac{1}{6}\n\\end{bmatrix}\n$$`\n\nLaTeX ypesetting won't be rendered. Use NostrMarkup delimeter tables for this sort of thing.\n\n`\\\\begin{tabular}{|c|c|c|l|r|}\n\\\\hline\n\\\\multicolumn{3}{|l|}{test} & A & B \\\\\\\\\n\\\\hline\n1 & 2 & 3 & 4 & 5 \\\\\\\\\n\\\\hline\n\\\\end{tabular}`\n\nWe also recognize common LaTeX statements:\n\n`\\[\n\\begin{array}{ccccc}\n1 & 2 & 3 & 4 & 5 \\\\\n\\end{array}\n\\]`\n\n`\\[ x^n + y^n = z^n \\]`\n\n`\\sqrt{x^2+1}`\n\nGreek letters are a snap: `$\\Psi$`, `$\\psi$`, `$\\Phi$`, `$\\phi$`. \n\nEquations within text are easy--- A well known Maxwell thermodynamic relation is `$\\left.{\\partial T \\over \\partial P}\\right|_{s} = \\left.{\\partial v \\over \\partial s}\\right|_{P}$`.\n\nYou can also set aside equations like so: `\\begin{eqnarray} du &=& T\\ ds -P\\ dv, \\qquad \\mbox{first law.}\\label{fl}\\\\ ds &\\ge& {\\delta q \\over T}.\\qquad \\qquad \\mbox{second law.} \\label{sl} \\end {eqnarray}`\n\n## And some good ole Asciimath\n\nAsciimath doesn't use `$` or `$$` delimiters, but we are using it to make mathy stuff easier to find. If you want it inline, include it inline. If you want it on a separate line, put a hard-return before and after.\n\nInline text example here `$E=mc^2$` and another `$1/(x+1)$`; very simple.\n\nDisplaying on a separate line:\n\n`$$sum_(k=1)^n k = 1+2+ cdots +n=(n(n+1))/2$$`\n\n`$$int_0^1 x^2 dx$$`\n\n`$$x = (-6 +- sqrt((-6)^2 - 4 (1)(4)))/(2 xx 1)$$`\n\n`$$|x|= {(x , if x ge 0 text(,)),(-x , if x <0.):}$$`\n\nDisplaying with wider spacing:\n\n`$a=3, \\ \\ \\ b=-3,\\ \\ $` and `$ \\ \\ c=2$`.\n\nThus `$(a+b)(c+b)=0$`.\n\nDisplaying with indentations:\n\nUsing the quadratic formula, the roots of `$x^2-6x+4=0$` are\n\n`$$x = (-6 +- sqrt((-6)^2 - 4 (1)(4)))/(2 xx 1)$$`\n\n`$$ \\ \\ = (-6 +- sqrt(36 - 16))/2$$`\n\n`$$ \\ \\ =(-6 +- sqrt(20))/2$$`\n\n`$$ \\ \\ = -0.8 or 2.2 \\ \\ \\ $$` to 1 decimal place.\n\nAdvanced alignment and matrices looks like this:\n\nA `$3xx3$` matrix, `$$((1,2,3),(4,5,6),(7,8,9))$$` and a `$2xx1$` matrix, or vector, `$$((1),(0))$$`.\n\nThe outer brackets determine the delimiters e.g. `$|(a,b),(c,d)|=ad-bc$`.\n\nA general `$m xx n$` matrix `$$((a_(11), cdots , a_(1n)),(vdots, ddots, vdots),(a_(m1), cdots , a_(mn)))$$`\n\n## Mixed Examples\n\nHere are some examples mixing LaTeX and AsciiMath:\n\n- LaTeX inline: `$\\frac{1}{2}$` vs AsciiMath inline: `$1/2$`\n- LaTeX display: `$$\\sum_{i=1}^n x_i$$` vs AsciiMath display: `$$sum_(i=1)^n x_i$$`\n- LaTeX matrix: `$$\\begin{pmatrix} a & b \\\\ c & d \\end{pmatrix}$$` vs AsciiMath matrix: `$$((a,b),(c,d))$$`\n\n## Edge Cases\n\n- Empty math: `$$`\n- Just delimiters: `$ $`\n- Dollar signs in text: The price is $10.50\n- Currency: `$19.99`\n- Shell command: `echo \"Price: $100\"`\n- JavaScript template: `const price = \\`$${amount}\\``\n- CSS with dollar signs: `color: $primary-color`\n\nThis document should demonstrate that:\n1. LaTeX is processed within inline code blocks with proper delimiters\n2. AsciiMath is processed within inline code blocks with proper delimiters\n3. Regular code blocks remain unchanged\n4. Mixed content is handled correctly\n5. Edge cases are handled gracefully", + "tags": [ + [ + "t", + "test" + ], + [ + "t", + "Asciimath" + ], + [ + "t", + "TeX" + ], + [ + "t", + "LaTeX" + ], + [ + "d", + "this-is-a-test-file-for-writing-mathematical-formulas-in-nostrmarkup" + ], + [ + "title", + "This is a test file for writing mathematical formulas in #NostrMarkup" + ] + ], + "kind": 30023, + "pubkey": "fd208ee8c8f283780a9552896e4823cc9dc6bfd442063889577106940fd927c1", + "id": "91be487e67cb68cfe3c7e965a654642b7bcedecb68340523a8c1b865b21fa5dc", + "sig": "59b7f87fe2c2d318152cf5b4796580f79a26936d515a816ddcb89b89ba337992eaa3d50896d3bde345d25be99c9caa3a237d476abeb8537589256cbcceeb2e75" +} \ No newline at end of file diff --git a/test_data/LaTeXtestfile.md b/test_data/LaTeXtestfile.md new file mode 100644 index 0000000..3c2e7e8 --- /dev/null +++ b/test_data/LaTeXtestfile.md @@ -0,0 +1,135 @@ +# This is a testfile for writing mathematic formulas in NostrMarkup + +This document covers the rendering of formulas in TeX/LaTeX and AsciiMath notation, or some combination of those within the same page. It is meant to be rendered by clients utilizing MathJax. + +If you want the entire document to be rendered as mathematics, place the entire thing in a backtick-codeblock, but know that this makes the document slower to load, it is harder to format the prose, and the result is less legible. It also doesn't increase portability, as it's easy to export markup as LaTeX files, or as PDFs, with the formulas rendered. + +The general idea, is that anything placed within `single backticks` is inline code, and inline-code will all be scanned for typical mathematics statements and rendered with best-effort. (For more precise rendering, use Asciidoc.) We will not render text that is not marked as inline code, as mathematical formulas, as that is prose. + +If you want the TeX to be blended into the surrounding text, wrap the text within single `$`. Otherwise, use double `$$` symbols, for display math, and it will appear on its own line. + +## TeX Examples + +Inline equation: `$\sqrt{x}$` + +Same equation, in the display mode: `$$\sqrt{x}$$` + +Something more complex, inline: `$\mathbb{N} = \{ a \in \mathbb{Z} : a > 0 \}$` + +Something complex, in display mode: `$$P \left( A=2 \, \middle| \, \dfrac{A^2}{B}>4 \right)$$` + +Another example of `$$\prod_{i=1}^{n} x_i - 1$$` inline formulas. + +Function example: +`$$ +f(x)= +\begin{cases} +1/d_{ij} & \quad \text{when $d_{ij} \leq 160$}\\ +0 & \quad \text{otherwise} +\end{cases} +$$` + +And a matrix: +`$$ +M = +\begin{bmatrix} +\frac{5}{6} & \frac{1}{6} & 0 \\[0.3em] +\frac{5}{6} & 0 & \frac{1}{6} \\[0.3em] +0 & \frac{5}{6} & \frac{1}{6} +\end{bmatrix} +$$` + +LaTeX ypesetting won't be rendered. Use NostrMarkup delimeter tables for this sort of thing. + +`\\begin{tabular}{|c|c|c|l|r|} +\\hline +\\multicolumn{3}{|l|}{test} & A & B \\\\ +\\hline +1 & 2 & 3 & 4 & 5 \\\\ +\\hline +\\end{tabular}` + +We also recognize common LaTeX statements: + +`\[ +\begin{array}{ccccc} +1 & 2 & 3 & 4 & 5 \\ +\end{array} +\]` + +`\[ x^n + y^n = z^n \]` + +`\sqrt{x^2+1}` + +Greek letters are a snap: `$\Psi$`, `$\psi$`, `$\Phi$`, `$\phi$`. + +Equations within text are easy--- A well known Maxwell thermodynamic relation is `$\left.{\partial T \over \partial P}\right|_{s} = \left.{\partial v \over \partial s}\right|_{P}$`. + +You can also set aside equations like so: `\begin{eqnarray} du &=& T\ ds -P\ dv, \qquad \mbox{first law.}\label{fl}\\ ds &\ge& {\delta q \over T}.\qquad \qquad \mbox{second law.} \label{sl} \end {eqnarray}` + +## And some good ole Asciimath + +Asciimath doesn't use `$` or `$$` delimiters, but we are using it to make mathy stuff easier to find. If you want it inline, include it inline. If you want it on a separate line, put a hard-return before and after. + +Inline text example here `$E=mc^2$` and another `$1/(x+1)$`; very simple. + +Displaying on a separate line: + +`$$sum_(k=1)^n k = 1+2+ cdots +n=(n(n+1))/2$$` + +`$$int_0^1 x^2 dx$$` + +`$$x = (-6 +- sqrt((-6)^2 - 4 (1)(4)))/(2 xx 1)$$` + +`$$|x|= {(x , if x ge 0 text(,)),(-x , if x <0.):}$$` + +Displaying with wider spacing: + +`$a=3, \ \ \ b=-3,\ \ $` and `$ \ \ c=2$`. + +Thus `$(a+b)(c+b)=0$`. + +Displaying with indentations: + +Using the quadratic formula, the roots of `$x^2-6x+4=0$` are + +`$$x = (-6 +- sqrt((-6)^2 - 4 (1)(4)))/(2 xx 1)$$` + +`$$ \ \ = (-6 +- sqrt(36 - 16))/2$$` + +`$$ \ \ =(-6 +- sqrt(20))/2$$` + +`$$ \ \ = -0.8 or 2.2 \ \ \ $$` to 1 decimal place. + +Advanced alignment and matrices looks like this: + +A `$3xx3$` matrix, `$$((1,2,3),(4,5,6),(7,8,9))$$` and a `$2xx1$` matrix, or vector, `$$((1),(0))$$`. + +The outer brackets determine the delimiters e.g. `$|(a,b),(c,d)|=ad-bc$`. + +A general `$m xx n$` matrix `$$((a_(11), cdots , a_(1n)),(vdots, ddots, vdots),(a_(m1), cdots , a_(mn)))$$` + +## Mixed Examples + +Here are some examples mixing LaTeX and AsciiMath: + +- LaTeX inline: `$\frac{1}{2}$` vs AsciiMath inline: `$1/2$` +- LaTeX display: `$$\sum_{i=1}^n x_i$$` vs AsciiMath display: `$$sum_(i=1)^n x_i$$` +- LaTeX matrix: `$$\begin{pmatrix} a & b \\ c & d \end{pmatrix}$$` vs AsciiMath matrix: `$$((a,b),(c,d))$$` + +## Edge Cases + +- Empty math: `$$` +- Just delimiters: `$ $` +- Dollar signs in text: The price is $10.50 +- Currency: `$19.99` +- Shell command: `echo "Price: $100"` +- JavaScript template: `const price = \`$${amount}\`` +- CSS with dollar signs: `color: $primary-color` + +This document should demonstrate that: +1. LaTeX is processed within inline code blocks with proper delimiters +2. AsciiMath is processed within inline code blocks with proper delimiters +3. Regular code blocks remain unchanged +4. Mixed content is handled correctly +5. Edge cases are handled gracefully diff --git a/test_data/latex_markdown.md b/test_data/latex_markdown.md deleted file mode 100644 index 0317f22..0000000 --- a/test_data/latex_markdown.md +++ /dev/null @@ -1,50 +0,0 @@ -{ -"created*at": 1752035710, -"content": "## 1 Introduction\n\nThe P versus NP problem asks whether every problem verifiable in polynomial time (NP) can be solved in polynomial time (P) [1]. The NP-complete Boolean Satisfiability (SAT) problem, determining if a conjunctive normal form formula has a satisfying assignment, is central to this question [2]. Proving that 3-SAT requires super-polynomial time would imply $P \\neq NP$, impacting computer science, cryptography, and optimization [3].\n\nWe prove $P \\neq NP$ by reformulating 3-SAT as an optimization problem using categorical and graph-theoretic frameworks. A 2-category models SAT’s logical constraints, while a clause graph captures satisfiability combinatorially [4]. A constraint measure and topological invariant establish that determining satisfiability requires exponential time [5,6]. Unlike combinatorial or algebraic methods [3], our approach leverages category theory and graph theory for a novel perspective.\n\nThe paper is organized as follows: Section 2 defines a 2-category for SAT; Section 3 presents an optimization problem; Section 4 introduces a constraint measure; Section 5 proves exponential time complexity; and Section 6 provides a graph-theoretic reformulation.\n\n## 2 Categorical Reformulation of SAT\n\nTo prove $P \\neq NP$, we reformulate the Boolean Satisfiability (SAT) problem as an optimization problem using a 2-category framework. Variables and clauses of a SAT instance are encoded as vectors and linear transformations in a complex vector space, with their logical structure modeled by a strict 2-category [4,7]. This allows satisfiability to be tested via compositions of transformations, setting up the constraint measure defined in Section 4.\n\n### 2.1 Construction of the 2-Category\n\nFor a SAT instance $\\phi = C_1 \\wedge \\cdots \\wedge C_m$, where each clause $C_j = l*{j1} \\vee \\cdots \\vee l*{jk}$ is a disjunction of $k \\leq n$ literals (with $l*{ji} = x*i$ or $\\neg x_i$ for variables $x_1, \\ldots, x_n$), we define a strict 2-category $\\mathcal{C}$ to encode $\\phi$’s logical structure.\n\n**Definition 2.1 (2-Category $\\mathcal{C}$)** \nThe 2-category $\\mathcal{C}$ consists of:\n- *Objects*: Vectors in the complex vector space $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes n}$, dimension $2^n$, representing variable assignments. For each variable $x_i$, define basis vectors:\n - $\\mathbf{v}_i = (1, 0) \\in \\mathbb{C}^2$, for $x_i = \\text{True}$.\n - $\\mathbf{w}_i = (0, 1) \\in \\mathbb{C}^2$, for $\\neg x_i = \\text{False}$.\n \n A configuration, e.g., $\\mathbf{v}_1 \\otimes \\mathbf{w}_2 \\otimes \\mathbf{v}_3 \\in \\mathcal{V}$, represents $x_1 = \\text{True}, x_2 = \\text{False}, x_3 = \\text{True}$.\n\n- *1-Morphisms*: Linear maps $f: \\mathcal{V} \\to \\mathcal{V}$, including:\n - *Clause projections* $P_j: \\mathcal{V} \\to \\mathcal{V}$, for clause $C_j$ with variables indexed by $I_j \\subseteq \\{1, \\ldots, n\\}$, defined as:\n $$\n P_j = \\bigotimes*{i=1}^n Q*i, \\quad Q_i = \\begin{cases} \n I - |\\mathbf{l}*{ji}\\rangle\\langle \\mathbf{l}_{ji}| & \\text{if } i \\in I_j, \\\\\n I & \\text{otherwise},\n \\end{cases}\n $$\n where $\\mathbf{l}_{ji} = \\mathbf{v}_i$ if $l_{ji} = x*i$, or $\\mathbf{l}*{ji} = \\mathbf{w}_i$ if $l_{ji} = \\neg x*i$, and $I$ is the identity on $\\mathbb{C}^2$. Thus, $P_j v = v$ if $v$ satisfies $C_j$; otherwise, $P_j v$ lies in the orthogonal complement.\n - *Identity maps* $\\text{id}_A: A \\to A$, for subspaces $A \\subseteq \\mathcal{V}$.\n - *Negation maps* $N_i: \\mathcal{V} \\to \\mathcal{V}$, swapping $\\mathbf{v}_i \\leftrightarrow \\mathbf{w}_i$ on the $i$-th tensor factor:\n $$\n N_i = I \\otimes \\cdots \\otimes \\begin{pmatrix} 0 & 1 \\\\ 1 & 0 \\end{pmatrix} \\otimes \\cdots \\otimes I.\n $$\n\n- *2-Morphisms*: Natural transformations $\\alpha: f \\Rightarrow g$ between 1-morphisms $f, g: A \\to B$, where $A, B \\subseteq \\mathcal{V}$. A 2-morphism $\\alpha$ is a linear map ensuring that if $f$ and $g$ represent assignments, $f$ satisfies all clauses satisfied by $g$, preserving the logical structure of $\\phi$ [4].\n\n- *Compositions*: Horizontal composition $\\beta \\circ \\alpha: g \\circ f \\Rightarrow g' \\circ f'$ for 2-morphisms $\\alpha: f \\Rightarrow f'$, $\\beta: g \\Rightarrow g'$, and vertical composition $\\beta \\cdot \\alpha: f \\Rightarrow h$ for $\\alpha: f \\Rightarrow g$, $\\beta: g \\Rightarrow h$, defined via linear map composition. Associativity and identity laws ensure $\\mathcal{C}$ is a strict 2-category [4].\n\nThe 2-category $\\mathcal{C}$ encodes SAT as follows: vectors in $\\mathcal{V}$ represent assignments, projections $P_j$ enforce clause constraints, negation maps $N_i$ handle negated literals, and 2-morphisms preserve logical consistency across transformations [7].\n\n### 2.2 Satisfiability via Projection Composition\n\nSatisfiability of $\\phi$ is tested by composing the clause projections:\n$$\nP = P_m \\circ \\cdots \\circ P_1: \\mathcal{V} \\to \\mathcal{V}.\n$$\nFor a normalized vector $v \\in \\mathcal{V}, \\|v\\|=1$, $\\phi$ is satisfiable if there exists $v$ such that $P v = v$, meaning $P_j v = v$ for all $j = 1, \\ldots, m$, corresponding to a satisfying assignment. If $\\phi$ is unsatisfiable, the intersection of projection images $\\bigcap*{j=1}^m \\text{im}(P*j) = \\emptyset$, so $P v \\neq v$ for all $v$. This composition reformulates SAT as finding a fixed point of $P$, which we analyze as an optimization problem in Section 3 using a distance metric.\n\n### 2.3 Example: 3-SAT Instance\n\nConsider a 3-SAT instance with $n=3$ variables, $\\phi = (x_1 \\vee \\neg x_2 \\vee x_3) \\wedge (\\neg x_1 \\vee x_2 \\vee \\neg x_3)$, encoded in $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes 3}$. Assign $\\mathbf{v}_i = (1, 0)$, $\\mathbf{w}_i = (0, 1)$ for $x_i = \\text{True}$, $\\neg x_i = \\text{False}$. For clause $C_1 = x_1 \\vee \\neg x_2 \\vee x_3$, the projection is:\n$$\nP_1 = I - (I - |\\mathbf{v}_1\\rangle\\langle \\mathbf{v}_1|) \\otimes (I - |\\mathbf{w}_2\\rangle\\langle \\mathbf{w}_2|) \\otimes (I - |\\mathbf{v}_3\\rangle\\langle \\mathbf{v}_3|).\n$$\nFor $C_2 = \\neg x_1 \\vee x_2 \\vee \\neg x_3$:\n$$\nP_2 = I - (I - |\\mathbf{w}_1\\rangle\\langle \\mathbf{w}_1|) \\otimes (I - |\\mathbf{v}_2\\rangle\\langle \\mathbf{v}_2|) \\otimes (I - |\\mathbf{w}_3\\rangle\\langle \\mathbf{w}_3|).\n$$\nThe assignment $x_1 = x_2 = x_3 = \\text{True}$, represented by $v = \\mathbf{v}_1 \\otimes \\mathbf{v}_2 \\otimes \\mathbf{v}_3$, satisfies $C_1$ ($x_1 = \\text{True}$) and $C_2$ ($x_2 = \\text{True}$). Thus, $P_1 v = v$, $P_2 v = v$, and $P v = P_2 \\circ P_1 v = v$, confirming satisfiability.\n\n## 3 Optimization Problem for SAT\n\nWe reformulate the Boolean Satisfiability (SAT) problem as an optimization problem, where satisfiability is determined by minimizing a distance metric between configurations under the projection composition defined in Section 2.2. Building on the 2-category $\\mathcal{C}$ (Section 2), this approach quantifies deviations from satisfiability, with satisfiable instances achieving zero deviation and unsatisfiable ones exhibiting a positive gap [8].\n\n### 3.1 Configuration Space and Distance Metric\n\n**Definition 3.1 (Configuration Space)** \nThe configuration space $\\mathcal{D}(\\mathcal{V})$ consists of positive semi-definite operators $\\rho$ on $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes n}$, dimension $2^n$, with trace $\\text{Tr}(\\rho) = 1$. Pure configurations, such as $\\rho_v = |v\\rangle\\langle v|$ for a normalized vector $v \\in \\mathcal{V}$, correspond to classical assignments (e.g., $v = \\mathbf{v}_1 \\otimes \\mathbf{v}_2 \\otimes \\mathbf{v}_3$ for $x_1 = x_2 = x_3 = \\text{True}$, where $\\mathbf{v}_i = (1, 0)$).\n\nThe space $\\mathcal{D}(\\mathcal{V})$ is convex and compact, equipped with a metric to measure distances between configurations [8]. We use the Bures distance due to its compatibility with the transformations in $\\mathcal{C}$.\n\n**Definition 3.2 (Bures Distance)** \nFor $\\rho, \\sigma \\in \\mathcal{D}(\\mathcal{V})$, the Bures distance is:\n$$\nd_B(\\rho, \\sigma) = \\sqrt{2 \\left( 1 - \\sqrt{F(\\rho, \\sigma)} \\right)},\n$$\nwhere the fidelity is $F(\\rho, \\sigma) = \\left( \\text{Tr} \\sqrt{\\sqrt{\\rho} \\sigma \\sqrt{\\rho}} \\right)^2$. For pure configurations $\\rho = |u\\rangle\\langle u|$, $\\sigma = |v\\rangle\\langle v|$ with $u, v \\in \\mathcal{V}, \\|u\\| = \\|v\\| = 1$, it simplifies to:\n$$\nd_B(\\rho, \\sigma) = \\sqrt{2 (1 - |\\langle u | v \\rangle|)},\n$$\nsince $|\\langle u | v \\rangle|$ is real and non-negative for normalized vectors [8].\n\nThe Bures distance is a metric on $\\mathcal{D}(\\mathcal{V})$, satisfying positivity, symmetry, and the triangle inequality [8]. It is suitable for measuring deviations induced by clause projections $P_j: \\mathcal{V} \\to \\mathcal{V}$ (Section 2.1), as it aligns with the 2-category’s structure [9,10].\n\n### 3.2 Optimization Problem\n\nFor the projection composition $P = P_m \\circ \\cdots \\circ P_1: \\mathcal{V} \\to \\mathcal{V}$ (Section 2.2), we define a deviation measure to reformulate SAT as an optimization problem.\n\n**Definition 3.3 (Deviation Measure)** \nThe deviation measure for a configuration $\\rho \\in \\mathcal{D}(\\mathcal{V})$ is:\n$$\nd_B(\\rho, P(\\rho)),\n$$\nwhere:\n$$\nP(\\rho) = \\frac{P \\rho P^\\dagger}{\\text{Tr}(P \\rho P^\\dagger)},\n$$\nif $\\text{Tr}(P \\rho P^\\dagger) \\neq 0$, and $P(\\rho) = 0$ otherwise. The SAT problem is equivalent to minimizing:\n$$\nS[\\rho] = d_B(\\rho, P(\\rho))^2,\n$$\nover $\\rho \\in \\mathcal{D}(\\mathcal{V})$.\n\nThe deviation measure quantifies how far $\\rho$ is from being invariant under $P$. For a pure configuration $\\rho_v = |v\\rangle\\langle v|$, $v \\in \\mathcal{V}, \\|v\\|=1$:\n- If $\\phi$ is satisfiable, there exists $\\rho_v$ such that $P_j \\rho_v = \\rho_v$ for all $j$, so $P(\\rho_v) = \\rho_v$ and $d_B(\\rho_v, P(\\rho_v)) = 0$.\n- If $\\phi$ is unsatisfiable, $\\bigcap*{j=1}^m \\text{im}(P*j) = \\emptyset$, so $P(\\rho) = 0$ for all $\\rho \\in \\mathcal{D}(\\mathcal{V})$, and $d_B(\\rho, P(\\rho)) = \\sqrt{2}$ [8].\n\nThus, the infimum satisfies:\n$$\n\\inf*{\\rho \\in \\mathcal{D}(\\mathcal{V})} S[\\rho] = \\begin{cases} \n0 & \\text{if } \\phi \\text{ is satisfiable}, \\\\\n2 & \\text{if } \\phi \\text{ is unsatisfiable}.\n\\end{cases}\n$$\nWe focus on pure configurations $\\rho_v$, as they correspond to classical assignments and suffice to determine satisfiability, aligning with the constraint measure $\\lambda(v) = \\sum_{j=1}^m M_j(v)$ in Section 4 [8].\n\n### 3.3 Example: 3-SAT Instance\n\nConsider the 3-SAT instance $\\phi = (x_1 \\vee \\neg x_2 \\vee x_3) \\wedge (\\neg x_1 \\vee x_2 \\vee \\neg x_3)$ with $n=3$, as in Section 2.3, using $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes 3}$. For the assignment $x_1 = x_2 = x_3 = \\text{True}$, the pure configuration is $\\rho = |\\mathbf{v}_1 \\otimes \\mathbf{v}_2 \\otimes \\mathbf{v}_3\\rangle\\langle \\mathbf{v}_1 \\otimes \\mathbf{v}_2 \\otimes \\mathbf{v}_3|$, where $\\mathbf{v}_i = (1, 0)$. The clause projections are as in Section 2.3. Since $\\mathbf{v}_1 \\otimes \\mathbf{v}_2 \\otimes \\mathbf{v}_3$ satisfies $C_1$ ($x_1 = \\text{True}$) and $C_2$ ($x_2 = \\text{True}$), we have $P_1 \\rho = \\rho$, $P_2 \\rho = \\rho$, so $P(\\rho) = P_2 (P_1 \\rho) = \\rho$, and:\n$$\nd*B(\\rho, P(\\rho)) = 0.\n$$\nFor an unsatisfiable 3-SAT instance, consider $\\phi = (x_1 \\vee x_2) \\wedge (\\neg x_1 \\vee \\neg x_2) \\wedge (x_1 \\vee \\neg x_2) \\wedge (\\neg x_1 \\vee x_2)$. For any $\\rho \\in \\mathcal{D}(\\mathcal{V})$, the projections conflict, so $P(\\rho) = 0$, yielding:\n$$\nd_B(\\rho, P(\\rho)) = \\sqrt{2}.\n$$\nThis gap ($0$ vs. $\\sqrt{2}$) distinguishes satisfiable from unsatisfiable instances, aligning with the constraint measure in Section 4.\n\n## 4 Constraint Measure for SAT\n\nWe define a constraint measure $\\lambda(v)$ for a SAT instance, quantifying clause violations in the 2-category $\\mathcal{C}$ (Section 2). This measure distinguishes satisfiable from unsatisfiable instances via a positive gap, aligning with the optimization problem in Section 3 and enabling the complexity analysis in Section 5 [2].\n\n### 4.1 Constraint Measure and Satisfiability Gap\n\n**Definition 4.1 (Constraint Measure)** \nFor a SAT instance $\\phi = C_1 \\wedge \\cdots \\wedge C_m$ with $n$ variables, represented in $\\mathcal{C}$, the constraint measure $\\lambda: \\mathcal{V} \\to \\mathbb{R}*{\\geq 0}$ on the configuration space $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes n}$ is:\n$$\n\\lambda(v) = \\sum_{j=1}^m M_j(v),\n$$\nwhere $v \\in \\mathcal{V}, \\|v\\|=1$, and the clause mapping $M_j: \\mathcal{V} \\to \\mathbb{R}_{\\geq 0}$ for clause $C_j$ is:\n$$\nM_j(v) = \\text{Tr}((I - P_j) \\rho_v),\n$$\nwith $\\rho_v = |v\\rangle\\langle v|$ and $P_j: \\mathcal{V} \\to \\mathcal{V}$ the clause projection (Definition 2.1). The minimum penalty is:\n$$\n\\lambda_{\\min} = \\inf_{v \\in \\mathcal{V}, \\|v\\|=1} \\lambda(v).\n$$\n\nThe mapping $M_j(v) = 0$ if $v$ satisfies $C_j$ (i.e., $P_j v = v$), and $M_j(v) \\geq \\delta > 0$ otherwise, where $\\delta$ is a constant reflecting the orthogonal distance to the satisfying subspace, determined by the clause structure (e.g., up to three literals in 3-SAT) [8]. The measure $\\lambda(v)$ sums clause violations, with $\\lambda_{\\min} = 0$ indicating satisfiability. This aligns with the optimization problem in Section 3.2, where $\\lambda(v) = 0$ corresponds to $d_B(\\rho_v, P(\\rho_v)) = 0$ for a pure configuration $\\rho_v = |v\\rangle\\langle v|$ [2].\n\n**Theorem 4.1 (Satisfiability Gap)** \nFor a SAT instance $\\phi$, the minimum penalty satisfies:\n$$\n\\lambda_{\\min} = \\begin{cases} \n0 & \\text{if } \\phi \\text{ is satisfiable}, \\\\\nc & \\text{if } \\phi \\text{ is unsatisfiable},\n\\end{cases}\n$$\nwhere $c \\geq \\delta > 0$ is a constant independent of $n$ or $m$.\n\n**Proof.** \nConsider $\\phi = C_1 \\wedge \\cdots \\wedge C_m$ with configurations in $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes n}$. Each clause $C_j$ has a projection $P_j$ (Section 2.1), where $P_j v = v$ if $v$ satisfies $C_j$, and $P_j v$ lies in the orthogonal complement otherwise.\n\n**Case 1: Satisfiable.** If $\\phi$ is satisfiable, there exists an assignment $a = (a_1, \\ldots, a_n) \\in \\{0,1\\}^n$ satisfying all clauses. Construct $v_a \\in \\mathcal{V}$ as the tensor product of $\\mathbf{v}_i = (1, 0)$ for $a_i = 1$ or $\\mathbf{w}_i = (0, 1)$ for $a_i = 0$, with $\\|v_a\\|=1$. Since $a$ satisfies each $C_j$, we have $P_j v_a = v_a$, so:\n$$\nM_j(v_a) = \\text{Tr}((I - P_j) \\rho_{v_a}) = \\langle v_a | (I - P_j) v_a \\rangle = 0.\n$$\nThus, $\\lambda(v_a) = \\sum_{j=1}^m M_j(v_a) = 0$, and since $\\lambda(v) \\geq 0$, we have $\\lambda_{\\min} = 0$.\n\n**Case 2: Unsatisfiable.** If $\\phi$ is unsatisfiable, no $v \\in \\mathcal{V}, \\|v\\|=1$ satisfies all clauses. For any $v$, at least one clause $C_j$ is violated, so $P_j v \\neq v$, and:\n$$\nM_j(v) = \\langle v | (I - P_j) v \\rangle \\geq \\delta > 0,\n$$\nwhere $\\delta > 0$ is a constant determined by the clause structure [8]. Thus, $\\lambda(v) \\geq \\delta$, and:\n$$\n\\lambda_{\\min} = \\inf_{v \\in \\mathcal{V}, \\|v\\|=1} \\lambda(v) \\geq \\delta.\n$$\nSet $c = \\delta$, independent of $n$ or $m$. The projection composition $P = P_m \\circ \\cdots \\circ P_1$ (Section 2.2) yields $P(\\rho_v) = 0$ for unsatisfiable instances, confirming the gap: $\\lambda_{\\min} \\geq c > 0$. $\\square$\n\nThe gap ($\\lambda_{\\min} = 0$ vs. $c > 0$) mirrors the optimization gap in Section 3.2 ($S[\\rho] = 0$ vs. $2$), linking $\\lambda(v)$ to the complexity analysis in Section 5.\n\n### 4.2 Example: 3-SAT Instance\n\nFor the satisfiable 3-SAT instance $\\phi = (x_1 \\vee \\neg x_2 \\vee x_3) \\wedge (\\neg x_1 \\vee x_2 \\vee \\neg x_3)$ with $n=3$, using $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes 3}$ (Section 2.3), consider the assignment $x_1 = x_2 = x_3 = \\text{True}$, with $v_a = \\mathbf{v}_1 \\otimes \\mathbf{v}_2 \\otimes \\mathbf{v}_3$, $\\mathbf{v}_i = (1, 0)$, $\\|v_a\\|=1$. The projections $P_1, P_2$ are defined as in Section 2.3. Since $v_a$ satisfies $C_1$ ($x_1 = \\text{True}$) and $C_2$ ($x_2 = \\text{True}$), we have $P_1 v_a = v_a$, $P_2 v_a = v_a$, so:\n$$\nM_1(v_a) = \\text{Tr}((I - P_1) \\rho_{v_a}) = 0, \\quad M_2(v_a) = \\text{Tr}((I - P_2) \\rho_{v_a}) = 0.\n$$\nThus, $\\lambda(v_a) = 0$, so $\\lambda_{\\min} = 0$.\n\nFor an unsatisfiable 3-SAT instance, consider $\\phi = (x_1 \\vee x_2) \\wedge (\\neg x_1 \\vee \\neg x_2) \\wedge (x_1 \\vee \\neg x_2) \\wedge (\\neg x_1 \\vee x_2)$. For any $v \\in \\mathcal{V}, \\|v\\|=1$, at least one clause is violated. For $v = \\mathbf{v}_1 \\otimes \\mathbf{v}_2$, satisfying the first clause, the second clause $\\neg x_1 \\vee \\neg x_2$ is violated, so:\n$$\nP_2 v \\neq v, \\quad M_2(v) = \\text{Tr}((I - P_2) \\rho_v) \\geq \\delta > 0.\n$$\nThus, $\\lambda(v) \\geq \\delta$, and $\\lambda_{\\min} \\geq c = \\delta > 0$. This gap illustrates the theorem’s distinction between satisfiable and unsatisfiable instances.\n\n## 5 Exponential Time Complexity of 3-SAT\n\nWe prove that computing the satisfiability of a 3-SAT instance, an NP-complete problem, requires exponential time in the number of variables $n$, establishing $P \\neq NP$. This builds on the 2-category $\\mathcal{C}$ (Section 2), optimization problem (Section 3), and constraint measure $\\lambda(v)$ (Section 4), showing that computing the minimum penalty $\\lambda_{\\min}$ demands exponential time [1,2].\n\n### 5.1 Hardness of Computing the Minimum Penalty\n\nFor a 3-SAT instance $\\phi = C_1 \\wedge \\cdots \\wedge C_m$ with $n$ variables and $m = O(n)$ clauses, each with up to three literals, satisfiability is equivalent to determining whether $\\lambda_{\\min} = \\inf_{v \\in \\mathcal{V}, \\|v\\|=1} \\lambda(v) = 0$, where $\\lambda(v) = \\sum_{j=1}^m M_j(v)$ is the constraint measure on $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes n}$, with $M_j(v) = \\text{Tr}((I - P_j) \\rho_v)$, $\\rho_v = |v\\rangle\\langle v|$, and $P_j$ the clause projection (Section 4.1). For example, the satisfiable 3-SAT instance from Section 2.3 has $\\lambda_{\\min} = 0$, while the unsatisfiable instance from Section 4.2 has $\\lambda_{\\min} \\geq c$.\n\n**Theorem 5.1 (Exponential Time for $\\lambda_{\\min}$)** \nComputing $\\lambda_{\\min}$ for worst-case 3-SAT instances requires $\\Omega(2^{kn})$ time for some constant $k > 0$, unless $P = NP$.\n\n**Proof.** \nBy the Satisfiability Gap Theorem (Theorem 4.1), $\\lambda_{\\min} = 0$ if $\\phi$ is satisfiable (there exists $v \\in \\mathcal{V}, \\|v\\|=1$ such that $P_j v = v$ for all $j$), and $\\lambda_{\\min} \\geq c = \\delta > 0$ otherwise, where $\\delta$ is a constant. Exact computation of $\\lambda_{\\min}$ over $\\mathcal{V}$, dimension $2^n$, requires evaluating $\\lambda(v)$ for $O(2^n)$ basis configurations, taking $O(2^{3n})$ time due to matrix operations [11]. We show that even approximating $\\lambda_{\\min}$ to decide satisfiability is NP-hard.\n\n**Lemma 5.1 (Hardness of Approximation)** \nApproximating $\\lambda_{\\min}$ to within additive error $\\epsilon < c/m$ requires $\\Omega(2^{kn})$ time for some $k > 0$, unless $P = NP$.\n\n**Proof.** \nFor a satisfiable $\\phi$, there exists $v$ such that $\\lambda(v) = 0$, so $\\lambda_{\\min} = 0$. For an unsatisfiable $\\phi$, every $v$ violates at least one clause, so $\\lambda(v) \\geq \\delta$, and $\\lambda_{\\min} \\geq c = \\delta$. An algorithm outputting a value $< c/m$ for satisfiable instances ($\\lambda_{\\min} = 0$) and $\\geq c/2$ for unsatisfiable instances ($\\lambda_{\\min} \\geq c$) distinguishes $\\lambda_{\\min} = 0$ from $\\lambda_{\\min} \\geq c$, as $c/m < c/2$ for $m \\geq 2$, solving 3-SAT.\n\nSince 3-SAT is NP-complete [1], and MAX-3-SAT inapproximability [6] shows that distinguishing fully satisfiable instances from those with at most a $1 - 1/8$ fraction satisfiable is NP-hard, approximating $\\lambda_{\\min}$ within $\\epsilon < c/m$ (with $m = O(n)$) is equivalent to solving 3-SAT. The projections $P_j$ encode 3-SAT’s combinatorial structure (Section 2.1), requiring $\\Omega(2^{kn})$ evaluations of $\\lambda(v)$ to find a satisfying configuration [5,6]. A polynomial-time approximation algorithm would imply $P = NP$. $\\square$\n\nThus, computing $\\lambda_{\\min}$ requires $\\Omega(2^{kn})$ time unless $P = NP$. $\\square$\n\n### 5.2 Implications and Complexity Barriers\n\nThe exponential time requirement for computing $\\lambda_{\\min}$ for 3-SAT implies that no polynomial-time algorithm exists for 3-SAT unless $P = NP$. Since 3-SAT is reducible to any NP problem [1], this extends to all NP problems, yielding:\n$$\n\\boxed{P \\neq NP}\n$$\n\nOur categorical approach avoids known complexity barriers [12,13]. The _relativization barrier_ [12] is sidestepped because the proof relies on the categorical structure of $\\mathcal{C}$ and the linear algebraic properties of $\\mathcal{V}$, which encode 3-SAT’s constraints non-relativizingly, unlike diagonalization techniques [2,4]. The _natural proofs barrier_ [13] is avoided as the proof is non-constructive (no efficient algorithm is provided) and problem-specific to 3-SAT’s clause structure, not broadly applicable to Boolean functions. These properties ensure the proof’s robustness, relying on standard NP-hardness assumptions [1,5,6].\n\n## 6 Graph-Theoretic Reformulation of 3-SAT\n\nTo reinforce the proof that $P \\neq NP$, we reformulate the 3-SAT problem as a graph-theoretic problem on a clause graph, preserving the constraint measure $\\lambda(v)$ (Section 4) as a combinatorial invariant. By showing that computing this invariant requires exponential time, we provide an alternative confirmation of the exponential complexity of 3-SAT, supporting the result of Section 5 [1,2].\n\n### 6.1 Clause Graph and Connectivity Index\n\nFor a 3-SAT instance $\\phi = C_1 \\wedge \\cdots \\wedge C_m$ with $n$ variables and $m = O(n)$ clauses, we define a clause graph to encode satisfiability combinatorially.\n\n**Definition 6.1 (Clause Graph)** \nThe clause graph $G_\\phi = (V, E)$ is defined as:\n- _Vertices_ $V$: Configurations in $\\mathcal{V} = (\\mathbb{C}^2)^{\\otimes n}$, representing variable assignments (Section 2.1).\n- _Edges_ $E$: Pairs $(v, v')$ where $v, v' \\in \\mathcal{V}, \\|v\\| = \\|v'\\| = 1$, differ in at most one variable, and satisfy the same clauses $C_j$, i.e., $P_j v = v$ and $P_j v' = v'$ for some $j$, with $P_j$ the clause projection (Definition 2.1).\n\nThe graph $G_\\phi$ connects configurations with similar clause satisfaction profiles. For a satisfiable $\\phi$, there exists a configuration $v$ such that $P_j v = v$ for all $j$, forming a connected component in $G_\\phi$ where all vertices satisfy $\\phi$. For an unsatisfiable $\\phi$, no such component exists, as every $v$ violates at least one clause (Section 4.1). For the satisfiable instance $\\phi = (x_1 \\vee \\neg x_2 \\vee x_3) \\wedge (\\neg x_1 \\vee x_2 \\vee \\neg x_3)$ (Section 2.3) with $n=3$, the clause graph $G_\\phi$ has $2^3 = 8$ vertices, and includes a connected component containing $v = \\mathbf{v}_1 \\otimes \\mathbf{v}_2 \\otimes \\mathbf{v}_3$, with $\\kappa_\\phi = 1$. For the unsatisfiable instance $\\phi = (x_1 \\vee x_2) \\wedge (\\neg x_1 \\vee \\neg x_2) \\wedge (x_1 \\vee \\neg x_2) \\wedge (\\neg x_1 \\vee x_2)$ (Section 4.2) with $n=2$, the graph has $2^2 = 4$ vertices, and no such component exists, so $\\kappa_\\phi = 0$.\n\n**Definition 6.2 (Connectivity Index)** \nThe connectivity index $\\kappa_\\phi$ is 1 if there exists a connected component in $G_\\phi$ where all vertices satisfy $\\phi$ (i.e., $P_j v = v$ for all $j$), and 0 otherwise.\n\nThe index $\\kappa_\\phi$ mirrors the constraint measure’s minimum penalty $\\lambda_{\\min}$ (Section 4.1). If $\\lambda_{\\min} = 0$, there exists $v$ with $\\lambda(v) = 0$, corresponding to $\\kappa_\\phi = 1$. If $\\lambda_{\\min} \\geq c > 0$, no configuration satisfies all clauses, so $\\kappa_\\phi = 0$. This invariant captures satisfiability combinatorially [2].\n\n### 6.2 Exponential Time Complexity\n\n**Theorem 6.1** \nComputing the connectivity index $\\kappa_\\phi$ for worst-case 3-SAT instances requires $\\Omega(2^{kn})$ time for some constant $k > 0$, unless $P = NP$.\n\n**Proof.** \nComputing $\\kappa_\\phi$ requires identifying a connected component in $G_\\phi$ where all vertices satisfy $\\phi$. Each vertex $v \\in \\mathcal{V}$, dimension $2^n$, represents a variable assignment, and edges connect $v$ to $O(n)$ neighbors differing in one variable. For satisfiable $\\phi$, there exists a component where all vertices have $\\lambda(v) = 0$ (Section 4.1), so $\\kappa_\\phi = 1$. For unsatisfiable $\\phi$, every vertex violates at least one clause, so $\\kappa_\\phi = 0$. Since 3-SAT’s combinatorial structure ensures that any satisfying configuration $v$ (where $P_j v = v$ for all $j$) implies a non-empty component, checking one such $v$ is equivalent to solving 3-SAT.\n\nDetermining whether $\\kappa_\\phi = 1$ is equivalent to finding a configuration $v$ such that $P_j v = v$ for all $j$, i.e., solving 3-SAT. Since $\\mathcal{V}$ has $2^n$ vertices, evaluating clause satisfaction (via projections $P_j$) for each vertex and checking connectivity requires $\\Omega(2^n)$ operations. The NP-completeness of 3-SAT [1] and MAX-3-SAT inapproximability [6] imply that distinguishing $\\kappa_\\phi = 1$ from $\\kappa_\\phi = 0$ is NP-hard, requiring $\\Omega(2^{kn})$ time for some $k > 0$ due to the combinatorial structure of clause interactions [5]. A polynomial-time algorithm for computing $\\kappa_\\phi$ would solve 3-SAT, implying $P = NP$. $\\square$\n\nThis graph-theoretic reformulation reinforces the exponential time complexity of 3-SAT (Section 5), as computing $\\kappa_\\phi$ mirrors the hardness of computing $\\lambda_{\\min}$, confirming $P \\neq NP$.\n\n## 7 Conclusion\n\nWe prove that $P \\neq NP$ by reformulating the NP-complete 3-SAT problem in categorical and graph-theoretic frameworks. A 2-category and a clause graph model 3-SAT, enabling an optimization problem and connectivity analysis that confirm $P \\neq NP$ (Sections 2, 6). By defining a constraint measure and a topological invariant, we show that determining satisfiability requires exponential time (Sections 4, 5, 6) [1,5,6]. Unlike combinatorial or algebraic approaches [3], our methods leverage category theory and graph theory, offering novel insights into computational complexity. The proof avoids relativization and natural proofs barriers by being non-relativizing and specific to 3-SAT, ensuring robustness [12,13]. This result confirms that NP-complete problems require super-polynomial time unless $P = NP$. Future work could extend these frameworks to other NP-complete problems [2,4].\n\n$$\n\\boxed{P \\neq NP}\n$$\n\n---\n\n## References\n\n1. Cook, Stephen A. \"The complexity of theorem-proving procedures.\" _Proceedings of the Third Annual ACM Symposium on Theory of Computing (STOC '71)_, 151–158, ACM, New York, NY, USA, 1971. DOI: 10.1145/800157.805047.\n2. Arora, Sanjeev and Barak, Boaz. _Computational Complexity: A Modern Approach_. Cambridge University Press, Cambridge, UK, 2009.\n3. Fortnow, Lance. \"The status of the P versus NP problem.\" _Communications of the ACM_ 56(9): 78–86, 2013. DOI: 10.1145/2500468.2500487.\n4. Leinster, Tom. _Basic Category Theory_. Cambridge University Press, Cambridge, UK, 2014.\n5. Dinur, Irit and Safra, Shmuel. \"On the hardness of approximating minimum vertex cover.\" _Annals of Mathematics_ 162(1): 439–485, 2007. DOI: 10.4007/annals.2007.162.439.\n6. Håstad, Johan. \"Some optimal inapproximability results.\" _Journal of the ACM_ 48(4): 798–859, 2001. DOI: 10.1145/502090.502098.\n7. Mac Lane, Saunders. _Categories for the Working Mathematician_, 2nd ed. Springer, New York, NY, USA, 1998.\n8. Bengtsson, Ingemar and Życzkowski, Karol. _Geometry of Quantum States: An Introduction to Quantum Entanglement_. Cambridge University Press, Cambridge, UK, 2006.\n9. Petz, Dénes. \"Monotone metrics on matrix spaces.\" _Linear Algebra and its Applications_ 244: 81–96, 1996. DOI: 10.1016/0024-3795(94)00211-8.\n10. Petz, Dénes and Sudár, Csaba. \"Geometries of quantum states.\" _Journal of Mathematical Physics_ 37(6): 2662–2673, 1996. DOI: 10.1063/1.531551.\n11. Golub, Gene H. and Van Loan, Charles F. _Matrix Computations_, 3rd ed. Johns Hopkins University Press, Baltimore, MD, USA, 1996.\n12. Baker, Theodore P. and Gill, John and Solovay, Robert. \"Relativizations of the P =? NP question.\" _SIAM Journal on Computing_ 4(4): 431–442, 1975. DOI: 10.1137/0204037.\n13. Razborov, Alexander A. and Rudich, Steven. \"Natural proofs.\" _Journal of Computer and System Sciences_ 55(1): 24–35, 1997. DOI: 10.1006/jcss.1997.1494.", -"tags": [ -[ -"d", -"1752035287698" -], -[ -"title", -"Proving P ≠ NP via Categorical and Graph-Theoretic 3-SAT" -], -[ -"summary", -"We prove that $P \\neq NP$ by reformulating the NP-complete 3-SAT problem as an optimization problem using categorical and graph-theoretic frameworks. A 2-category encodes 3-SAT’s variables and clauses as vectors and transformations in a complex vector space, while a clause graph captures satisfiability as a connectivity property, with a constraint measure and invariant distinguishing satisfiable and unsatisfiable cases. Computing either requires exponential time, establishing $P \\neq NP$. This dual approach, leveraging category theory and graph theory, offers a novel perspective on computational complexity." -], -[ -"t", -"math" -], -[ -"t", -"p vs np" -], -[ -"t", -"complexity theory" -], -[ -"t", -"category theory" -], -[ -"t", -"graph theory" -], -[ -"published_at", -"1752035704" -], -[ -"alt", -"This is a long form article, you can read it in https://habla.news/a/naddr1qvzqqqr4gupzqwe6gtf5eu9pgqk334fke8f2ct43ccqe4y2nhetssnypvhge9ce9qqxnzde4xgcrxdfj8qmnvwfc69lg5m" -] -], -"kind": 30023, -"pubkey": "3b3a42d34cf0a1402d18d536c9d2ac2eb1c6019a9153be57084c8165d192e325", -"id": "4afdd068904f12c370913ca3c8744b71fae258e59457fad6f3c28ddffb8f0f41", -"sig": "6be4cf6472b98c80c659e472d8db3bc8c144a1c551c821d1cfd925dade26b395690f71b38631e49d180d7ec79fbbbbcb148df27a40955ef22479e7bec36bd6ad" -} diff --git a/tests/unit/latexRendering.test.ts b/tests/unit/latexRendering.test.ts index 7096a8a..667cd0d 100644 --- a/tests/unit/latexRendering.test.ts +++ b/tests/unit/latexRendering.test.ts @@ -3,99 +3,59 @@ import { parseAdvancedmarkup } from "../../src/lib/utils/markup/advancedMarkupPa import { readFileSync } from "fs"; import { join } from "path"; -describe("LaTeX Math Rendering", () => { - const mdPath = join(__dirname, "../../test_data/latex_markdown.md"); - const raw = readFileSync(mdPath, "utf-8"); - // Extract the markdown content field from the JSON +describe("LaTeX and AsciiMath Rendering in Inline Code Blocks", () => { + const jsonPath = join(__dirname, "../../test_data/LaTeXtestfile.json"); + const raw = readFileSync(jsonPath, "utf-8"); + // Extract the markdown content field from the JSON event const content = JSON.parse(raw).content; - it('renders inline math as ', async () => { + it('renders LaTeX inline and display math correctly', async () => { const html = await parseAdvancedmarkup(content); - expect(html).toMatch(/\$P \\neq NP\$<\/span>/); - expect(html).toMatch( - /\$x_1 = \\text\{True\}\$<\/span>/, - ); + // Test basic LaTeX examples from the test document + expect(html).toMatch(/\$\\sqrt\{x\}\$<\/span>/); + expect(html).toMatch(/
    \$\$\\sqrt\{x\}\$\$<\/div>/); + expect(html).toMatch(/\$\\mathbb\{N\} = \\{ a \\in \\mathbb\{Z\} : a > 0 \\}\$<\/span>/); + expect(html).toMatch(/
    \$\$P \\left\( A=2 \\, \\middle\| \\, \\dfrac\{A\^2\}\{B\}>4 \\right\)\$\$<\/div>/); }); - it('renders display math as
    \$\$\s*P_j = \\bigotimes/, - ); - expect(html).toMatch( - /
    \$\$[\s\S]*?\\begin\{pmatrix\}/, - ); - expect(html).toMatch( - /
    \$\$\\boxed\{P \\neq NP\}\$\$<\/div>/, - ); + // Test AsciiMath examples + expect(html).toMatch(/\$E=mc\^2\$<\/span>/); + expect(html).toMatch(/
    \$\$sum_\(k=1\)\^n k = 1\+2\+ cdots \+n=\(n\(n\+1\)\)\/2\$\$<\/div>/); + expect(html).toMatch(/
    \$\$int_0\^1 x\^2 dx\$\$<\/div>/); }); - it("does not wrap display math in

    or

    ", async () => { + it('renders LaTeX array and matrix environments as math', async () => { const html = await parseAdvancedmarkup(content); - // No

    or

    directly wrapping math-block - expect(html).not.toMatch(/]*>\s*
    \$\$[\s\S]*\\begin\{array\}\{ccccc\}[\s\S]*\\end\{array\}[\s\S]*\$\$<\/div>/); + expect(html).toMatch(/
    \$\$[\s\S]*\\begin\{bmatrix\}[\s\S]*\\end\{bmatrix\}[\s\S]*\$\$<\/div>/); }); - it("renders LaTeX environments (pmatrix) within display math blocks", async () => { + it('handles unsupported LaTeX environments gracefully', async () => { const html = await parseAdvancedmarkup(content); - // Check that pmatrix is properly rendered within a display math block - expect(html).toMatch( - /
    \$\$[\s\S]*?\\begin\{pmatrix\}[\s\S]*?\\end\{pmatrix\}[\s\S]*?\$\$<\/div>/, - ); + // Should show a message and plaintext for tabular + expect(html).toMatch(/
    /); + expect(html).toMatch(/Unrendered, as it is LaTeX typesetting, not a formula:/); + expect(html).toMatch(/\\\\begin\{tabular\}/); }); - it('renders all math as math (no unwrapped $...$, $$...$$, \\(...\\), \\[...\\], or environments left)', async () => { + it('renders mixed LaTeX and AsciiMath correctly', async () => { const html = await parseAdvancedmarkup(content); - // No unwrapped $...$ outside math-inline or math-block - // Remove all math-inline and math-block tags and check for stray $...$ - const htmlNoMath = html - .replace(/\$[^$]+\$<\/span>/g, '') - .replace(/
    \$\$[\s\S]*?\$\$<\/div>/g, '') - .replace(/
    [\s\S]*?<\/div>/g, ''); - expect(htmlNoMath).not.toMatch(/\$[^\$\n]+\$/); // inline math - expect(htmlNoMath).not.toMatch(/\$\$[\s\S]*?\$\$/); // display math - expect(htmlNoMath).not.toMatch(/\\\([^)]+\\\)/); // \(...\) - expect(htmlNoMath).not.toMatch(/\\\[[^\]]+\\\]/); // \[...\] - expect(htmlNoMath).not.toMatch(/\\begin\{[a-zA-Z*]+\}[\s\S]*?\\end\{[a-zA-Z*]+\}/); // environments - // No math inside code or pre - expect(html).not.toMatch(//); - expect(html).not.toMatch(//); + // Test mixed content + expect(html).toMatch(/\$\\frac\{1\}\{2\}\$<\/span>/); + expect(html).toMatch(/\$1\/2\$<\/span>/); + expect(html).toMatch(/
    \$\$\\sum_\{i=1\}\^n x_i\$\$<\/div>/); + expect(html).toMatch(/
    \$\$sum_\(i=1\)\^n x_i\$\$<\/div>/); }); - it('renders every line of the document: all math is wrapped', async () => { - const lines = content.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - if (!line.trim()) continue; - const html = await parseAdvancedmarkup(line); - // If the line contains $...$, $$...$$, \(...\), \[...\], or bare LaTeX commands, it should be wrapped - const hasMath = /\$[^$]+\$|\$\$[\s\S]*?\$\$|\\\([^)]+\\\)|\\\[[^\]]+\\\]|\\[a-zA-Z]+(\{[^}]*\})*/.test(line); - if (hasMath) { - const wrapped = /math-inline|math-block/.test(html); - if (!wrapped) { - // eslint-disable-next-line no-console - console.error(`Line ${i + 1} failed:`, line); - // eslint-disable-next-line no-console - console.error('Rendered HTML:', html); - } - expect(wrapped).toBe(true); - } - // Should not have any unwrapped $...$, $$...$$, \(...\), \[...\], or bare LaTeX commands - const stray = /(^|[^>])\$[^$\n]+\$|\$\$[\s\S]*?\$\$|\\\([^)]+\\\)|\\\[[^\]]+\\\]|\\[a-zA-Z]+(\{[^}]*\})*/.test(html); - expect(stray).toBe(false); - } - }); - - it('renders standalone math lines as display math blocks', async () => { - const mdPath = require('path').join(__dirname, '../../test_data/latex_markdown.md'); - const raw = require('fs').readFileSync(mdPath, 'utf-8'); - const content = JSON.parse(raw).content || raw; + it('handles edge cases and regular code blocks', async () => { const html = await parseAdvancedmarkup(content); - // Example: Bures distance line - expect(html).toMatch(/
    \$\$d_B\([^$]+\) = [^$]+\$\$<\/div>/); - // Example: P(\rho) = ... - expect(html).toMatch(/
    \$\$P\([^$]+\) = [^$]+\$\$<\/div>/); + // Test regular code blocks (should remain as code, not math) + expect(html).toMatch(/]*>\$19\.99<\/code>/); + expect(html).toMatch(/]*>echo "Price: \$100"<\/code>/); + expect(html).toMatch(/]*>const price = \\`\$\$\{amount\}\\`<\/code>/); + expect(html).toMatch(/]*>color: \$primary-color<\/code>/); }); }); From 1ef9db64cd3c2c257475c7cb7547d4c140967efe Mon Sep 17 00:00:00 2001 From: Silberengel Date: Thu, 10 Jul 2025 15:58:52 +0200 Subject: [PATCH 097/135] Fixed deferrel to deferral Added nostr address copy to event searc results --- src/routes/events/+page.svelte | 59 ++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/src/routes/events/+page.svelte b/src/routes/events/+page.svelte index 3ed8137..8c87db1 100644 --- a/src/routes/events/+page.svelte +++ b/src/routes/events/+page.svelte @@ -14,6 +14,10 @@ import { userPubkey, isLoggedIn } from '$lib/stores/authStore'; import RelayStatus from '$lib/components/RelayStatus.svelte'; import { testAllRelays, logRelayDiagnostics } from '$lib/utils/relayDiagnostics'; + import CopyToClipboard from '$lib/components/util/CopyToClipboard.svelte'; + import { neventEncode, naddrEncode } from '$lib/utils'; + import { standardRelays } from '$lib/consts'; + import { getEventType } from '$lib/utils/mime'; let loading = $state(false); let error = $state(null); @@ -61,9 +65,33 @@ return getMatchingTags(event, "summary")[0]?.[1]; } - function getDeferrelNaddr(event: NDKEvent): string | undefined { - // Look for a 'deferrel' tag, e.g. ['deferrel', 'naddr1...'] - return getMatchingTags(event, "deferrel")[0]?.[1]; + function getDeferralNaddr(event: NDKEvent): string | undefined { + // Look for a 'deferral' tag, e.g. ['deferral', 'naddr1...'] + return getMatchingTags(event, "deferral")[0]?.[1]; + } + + function getNeventAddress(event: NDKEvent): string { + return neventEncode(event, standardRelays); + } + + function isAddressableEvent(event: NDKEvent): boolean { + return getEventType(event.kind || 0) === "addressable"; + } + + function getNaddrAddress(event: NDKEvent): string | null { + if (!isAddressableEvent(event)) { + return null; + } + try { + return naddrEncode(event, standardRelays); + } catch { + return null; + } + } + + function shortenAddress(addr: string, head = 10, tail = 10): string { + if (!addr || addr.length <= head + tail + 3) return addr; + return addr.slice(0, head) + '…' + addr.slice(-tail); } function onLoadingChange(val: boolean) { @@ -128,11 +156,24 @@ onLoadingChange={onLoadingChange} /> - {#if $isLoggedIn && !event && searchResults.length === 0} - - {/if} - {#if event} + {#if event.kind !== 0} +
    + + {#if isAddressableEvent(event)} + {@const naddrAddress = getNaddrAddress(event)} + {#if naddrAddress} + + {/if} + {/if} +
    + {/if} {#if $isLoggedIn && $userPubkey} @@ -188,7 +229,7 @@ {getSummary(result)}
    {/if} - {#if getDeferrelNaddr(result)} + {#if getDeferralNaddr(result)}
    @@ -200,7 +241,7 @@ onclick={(e) => e.stopPropagation()} tabindex="0" > - {getDeferrelNaddr(result)} + {getDeferralNaddr(result)}
    {/if} From c8891f31091843de8643fbda5a942ee6212ca19e Mon Sep 17 00:00:00 2001 From: silberengel Date: Sun, 13 Jul 2025 00:37:14 +0200 Subject: [PATCH 098/135] Amber and npub-only login implemented --- package-lock.json | 17 +- package.json | 2 +- src/lib/components/Login.svelte | 338 ++++++++++++++--- src/lib/components/LoginMenu.svelte | 480 +++++++++++++++++++++++++ src/lib/components/Navigation.svelte | 4 +- src/lib/components/util/Profile.svelte | 8 - src/lib/utils/nostrUtils.ts | 2 +- 7 files changed, 772 insertions(+), 79 deletions(-) create mode 100644 src/lib/components/LoginMenu.svelte diff --git a/package-lock.json b/package-lock.json index b631ab9..095e9ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "alexandria", "version": "0.0.6", "dependencies": { - "@nostr-dev-kit/ndk": "2.11.x", + "@nostr-dev-kit/ndk": "^2.14.32", "@nostr-dev-kit/ndk-cache-dexie": "2.5.x", "@popperjs/core": "2.11.x", "@tailwindcss/forms": "0.5.x", @@ -568,8 +568,9 @@ } }, "node_modules/@nostr-dev-kit/ndk": { - "version": "2.11.2", - "license": "MIT", + "version": "2.14.32", + "resolved": "https://registry.npmjs.org/@nostr-dev-kit/ndk/-/ndk-2.14.32.tgz", + "integrity": "sha512-LUBO35RCB9/emBYsXNDece7m/WO2rGYR8j4SD0Crb3z8GcKTJq6P8OjpZ6+Kr+sLNo8N0uL07XxtAvEBnp2OqQ==", "dependencies": { "@noble/curves": "^1.6.0", "@noble/hashes": "^1.5.0", @@ -577,14 +578,14 @@ "@scure/base": "^1.1.9", "debug": "^4.3.6", "light-bolt11-decoder": "^3.2.0", - "nostr-tools": "^2.7.1", - "tseep": "^1.2.2", - "typescript-lru-cache": "^2.0.0", - "utf8-buffer": "^1.0.0", - "websocket-polyfill": "^0.0.3" + "tseep": "^1.3.1", + "typescript-lru-cache": "^2" }, "engines": { "node": ">=16" + }, + "peerDependencies": { + "nostr-tools": "^2" } }, "node_modules/@nostr-dev-kit/ndk-cache-dexie": { diff --git a/package.json b/package.json index 787d2e7..cb2a5d9 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "test": "vitest" }, "dependencies": { - "@nostr-dev-kit/ndk": "2.11.x", + "@nostr-dev-kit/ndk": "^2.14.32", "@nostr-dev-kit/ndk-cache-dexie": "2.5.x", "@popperjs/core": "2.11.x", "@tailwindcss/forms": "0.5.x", diff --git a/src/lib/components/Login.svelte b/src/lib/components/Login.svelte index e0d1171..8ea7dda 100644 --- a/src/lib/components/Login.svelte +++ b/src/lib/components/Login.svelte @@ -1,76 +1,296 @@ -
    - {#if $ndkSignedIn} - - {:else} - - -
    - - {#if signInFailed} -
    - {errorMessage} + {#if isLoading} + 🔄 Generating QR code... + {:else} + 🔗 Connect with Amber + {/if} + + +
    +

    Click to generate a QR code for your mobile Amber app

    +
    + {:else} +
    +
    +

    Scan with Amber

    +

    Open Amber on your phone and scan this QR code

    +
    + + + {#if qrCodeDataUrl} +
    + Nostr Connect QR Code +
    + {/if} + + +
    + +
    + + +
    +
    + +
    +

    1. Open Amber on your phone

    +

    2. Scan the QR code above

    +

    3. Approve the connection in Amber

    - {/if} - + ✍️ Test Sign Event + + + +
    + {/if} + + {#if result} +
    + {result}
    - - {/if} + {/if} +
    diff --git a/src/lib/components/LoginMenu.svelte b/src/lib/components/LoginMenu.svelte new file mode 100644 index 0000000..b7b8c74 --- /dev/null +++ b/src/lib/components/LoginMenu.svelte @@ -0,0 +1,480 @@ + + +
    + {#if !npub} + +
    + + +
    +

    Login with...

    + + + +
    +
    + {#if result} +
    + {result} + +
    + {/if} +
    + {:else} + +
    + + +
    +
    +

    {profileHandle || shortenNpub(npub)}

    +
      +
    • + +
    • +
    • + +
    • +
    +
    +
    +
    +
    + {/if} +
    + +{#if showQrCode && qrCodeDataUrl} + +
    +
    +
    +

    Scan with Amber

    +

    Open Amber on your phone and scan this QR code

    + +
    + Nostr Connect QR Code +
    + +
    + +
    + + +
    +
    + +
    +

    1. Open Amber on your phone

    +

    2. Scan the QR code above

    +

    3. Approve the connection in Amber

    +
    + + +
    +
    +
    +{/if} \ No newline at end of file diff --git a/src/lib/components/Navigation.svelte b/src/lib/components/Navigation.svelte index 4fefd1a..e634c55 100644 --- a/src/lib/components/Navigation.svelte +++ b/src/lib/components/Navigation.svelte @@ -7,7 +7,7 @@ NavHamburger, NavBrand, } from "flowbite-svelte"; - import Login from "./Login.svelte"; + import LoginMenu from "./LoginMenu.svelte"; let { class: className = "" } = $props(); @@ -19,7 +19,7 @@
    - +
    diff --git a/src/lib/components/util/Profile.svelte b/src/lib/components/util/Profile.svelte index 9d75bd5..402eb3b 100644 --- a/src/lib/components/util/Profile.svelte +++ b/src/lib/components/util/Profile.svelte @@ -80,14 +80,6 @@ function shortenNpub(long: string|undefined) { Sign out - {:else} - {/if}
    diff --git a/src/lib/utils/nostrUtils.ts b/src/lib/utils/nostrUtils.ts index 9d80b1c..b85dbb9 100644 --- a/src/lib/utils/nostrUtils.ts +++ b/src/lib/utils/nostrUtils.ts @@ -87,7 +87,7 @@ export async function getUserMetadata(identifier: string): Promise name: profile?.name || fallback.name, displayName: profile?.displayName, nip05: profile?.nip05, - picture: profile?.image, + picture: profile?.picture || profile?.image, about: profile?.about, banner: profile?.banner, website: profile?.website, From 97036fe9302f5fc5e677e5ff6d353f42f8b631f7 Mon Sep 17 00:00:00 2001 From: silberengel Date: Sun, 13 Jul 2025 01:52:22 +0200 Subject: [PATCH 099/135] fixed all logins/logouts universal user store --- src/lib/components/CommentBox.svelte | 32 ++- src/lib/components/Login.svelte | 296 ------------------- src/lib/components/LoginMenu.svelte | 271 +++--------------- src/lib/components/LoginModal.svelte | 12 +- src/lib/components/PublicationHeader.svelte | 2 - src/lib/components/cards/BlogHeader.svelte | 1 + src/lib/components/util/CardActions.svelte | 12 +- src/lib/components/util/Profile.svelte | 15 +- src/lib/ndk.ts | 73 +---- src/lib/stores/relayStore.ts | 4 - src/lib/stores/userStore.ts | 298 ++++++++++++++++++++ src/routes/+layout.ts | 35 ++- src/routes/+page.svelte | 8 +- src/routes/contact/+page.svelte | 11 +- src/routes/events/+page.svelte | 13 +- 15 files changed, 430 insertions(+), 653 deletions(-) delete mode 100644 src/lib/components/Login.svelte delete mode 100644 src/lib/stores/relayStore.ts create mode 100644 src/lib/stores/userStore.ts diff --git a/src/lib/components/CommentBox.svelte b/src/lib/components/CommentBox.svelte index c46f902..552ad5f 100644 --- a/src/lib/components/CommentBox.svelte +++ b/src/lib/components/CommentBox.svelte @@ -4,16 +4,13 @@ import { nip19 } from 'nostr-tools'; import { getEventHash, signEvent, getUserMetadata, type NostrProfile } from '$lib/utils/nostrUtils'; import { standardRelays, fallbackRelays } from '$lib/consts'; - import { userRelays } from '$lib/stores/relayStore'; - import { get } from 'svelte/store'; + import { userStore } from '$lib/stores/userStore'; import { goto } from '$app/navigation'; import type { NDKEvent } from '$lib/utils/nostrUtils'; import { onMount } from 'svelte'; const props = $props<{ event: NDKEvent; - userPubkey: string; - userRelayPreference: boolean; }>(); let content = $state(''); @@ -24,11 +21,13 @@ let showOtherRelays = $state(false); let showFallbackRelays = $state(false); let userProfile = $state(null); + let user = $state($userStore); + userStore.subscribe(val => user = val); // Fetch user profile on mount onMount(async () => { - if (props.userPubkey) { - const npub = nip19.npubEncode(props.userPubkey); + if (user.signedIn && user.pubkey) { + const npub = nip19.npubEncode(user.pubkey); userProfile = await getUserMetadata(npub); } }); @@ -92,6 +91,11 @@ } async function handleSubmit(useOtherRelays = false, useFallbackRelays = false) { + if (!user.signedIn || !user.pubkey) { + error = 'You must be signed in to comment'; + return; + } + isSubmitting = true; error = null; success = null; @@ -135,7 +139,7 @@ created_at: Math.floor(Date.now() / 1000), tags, content, - pubkey: props.userPubkey + pubkey: user.pubkey }; const id = getEventHash(eventToSign); @@ -147,10 +151,10 @@ sig }; - // Determine which relays to use - let relays = props.userRelayPreference ? get(userRelays) : standardRelays; + // Determine which relays to use based on user's relay preference + let relays = user.relays.inbox.length > 0 ? user.relays.inbox : standardRelays; if (useOtherRelays) { - relays = props.userRelayPreference ? standardRelays : get(userRelays); + relays = user.relays.inbox.length > 0 ? standardRelays : user.relays.inbox; } if (useFallbackRelays) { relays = fallbackRelays; @@ -282,16 +286,16 @@ /> {/if} - {userProfile.displayName || userProfile.name || nip19.npubEncode(props.userPubkey).slice(0, 8) + '...'} + {userProfile.displayName || userProfile.name || (user.pubkey ? nip19.npubEncode(user.pubkey).slice(0, 8) + '...' : 'Unknown')}
    {/if}
    - {#if !props.userPubkey} + {#if !user.signedIn} Please sign in to post comments. Your comments will be signed with your current account. diff --git a/src/lib/components/Login.svelte b/src/lib/components/Login.svelte deleted file mode 100644 index 8ea7dda..0000000 --- a/src/lib/components/Login.svelte +++ /dev/null @@ -1,296 +0,0 @@ - - -
    -
    - {#if !npub} -
    -

    Welcome to Alexandria

    -

    Connect with Amber to start reading and publishing

    -
    - - {#if !showQrCode} - - -
    -

    Click to generate a QR code for your mobile Amber app

    -
    - {:else} -
    -
    -

    Scan with Amber

    -

    Open Amber on your phone and scan this QR code

    -
    - - - {#if qrCodeDataUrl} -
    - Nostr Connect QR Code -
    - {/if} - - -
    - -
    - - -
    -
    - -
    -

    1. Open Amber on your phone

    -

    2. Scan the QR code above

    -

    3. Approve the connection in Amber

    -
    -
    - {/if} - {:else} -
    -
    ✅ Connected to Amber
    -
    {npub}
    -
    - -
    - - - -
    - {/if} - - {#if result} -
    - {result} -
    - {/if} -
    -
    diff --git a/src/lib/components/LoginMenu.svelte b/src/lib/components/LoginMenu.svelte index b7b8c74..36c7e68 100644 --- a/src/lib/components/LoginMenu.svelte +++ b/src/lib/components/LoginMenu.svelte @@ -1,55 +1,24 @@
    - {#if !npub} + {#if !user.signedIn}
    -

    {profileHandle || shortenNpub(npub)}

    +

    {user.profile?.displayName || user.profile?.name || (user.npub ? shortenNpub(user.npub) : 'Unknown')}

    • @@ -431,24 +244,22 @@

      Scan with Amber

      Open Amber on your phone and scan this QR code

      -
      Nostr Connect QR Code
      -
      -

      1. Open Amber on your phone

      2. Scan the QR code above

      3. Approve the connection in Amber

      -
      - {#if !pubkey()} + {#if !$activePubkey} Please sign in to post comments. Your comments will be signed with your current account. diff --git a/src/lib/components/EventDetails.svelte b/src/lib/components/EventDetails.svelte index d12a61a..e0ccaef 100644 --- a/src/lib/components/EventDetails.svelte +++ b/src/lib/components/EventDetails.svelte @@ -128,7 +128,10 @@ }); $effect(() => { - if (event?.pubkey) { + if(!event?.pubkey) { + authorDisplayName = undefined; + return; + } getUserMetadata(toNpub(event.pubkey) as string).then((profile) => { authorDisplayName = profile.displayName || @@ -136,9 +139,6 @@ profile.name || event.pubkey; }); - } else { - authorDisplayName = undefined; - } }); // --- Identifier helpers --- diff --git a/src/lib/components/EventRenderLevelLimit.svelte b/src/lib/components/EventRenderLevelLimit.svelte index 9bce52c..9cc08bf 100644 --- a/src/lib/components/EventRenderLevelLimit.svelte +++ b/src/lib/components/EventRenderLevelLimit.svelte @@ -34,8 +34,8 @@ class="leather bg-transparent text-sm font-medium" >Levels to render: -
    {/if} + + {#if secondOrderResults.length > 0} +
    + + Second-Order Events (References, Replies, Quotes) ({secondOrderResults.length} + events) + +

    + Events that reference, reply to, highlight, or quote the original events. +

    +
    + {#each secondOrderResults as result, index} + + {/each} +
    +
    + {/if} + + {#if tTagResults.length > 0} +
    + + Search Results for t-tag: "{dTagValue?.toLowerCase()}" ({tTagResults.length} + events) + +

    + Events that are tagged with the t-tag. +

    +
    + {#each tTagResults as result, index} + + {/each} +
    +
    + {/if}

    From f3fa56556c4bf41fccadd37a540193cee6f1f0a1 Mon Sep 17 00:00:00 2001 From: silberengel Date: Sun, 13 Jul 2025 09:41:06 +0200 Subject: [PATCH 102/135] make columns more responsive --- src/lib/components/PublicationFeed.svelte | 4 +--- src/lib/components/PublicationHeader.svelte | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib/components/PublicationFeed.svelte b/src/lib/components/PublicationFeed.svelte index a490c0e..62d4fc3 100644 --- a/src/lib/components/PublicationFeed.svelte +++ b/src/lib/components/PublicationFeed.svelte @@ -202,8 +202,7 @@ }); -
    -
    +
    {#if loading && eventsInView.length === 0} {#each getSkeletonIds() as id} @@ -244,4 +243,3 @@ >
    {/if} -
    diff --git a/src/lib/components/PublicationHeader.svelte b/src/lib/components/PublicationHeader.svelte index 685449e..b4e9a4d 100644 --- a/src/lib/components/PublicationHeader.svelte +++ b/src/lib/components/PublicationHeader.svelte @@ -57,7 +57,7 @@ {#if title != null && href != null} {#if image}
    Date: Sun, 13 Jul 2025 14:15:34 +0200 Subject: [PATCH 103/135] updated and expanded comment box. corrected eventinput displa and updated search. Fixed reactivity problem. --- src/lib/components/CommentBox.svelte | 346 ++++++++++++++++++++- src/lib/components/EventInput.svelte | 187 ++++++------ src/lib/components/EventSearch.svelte | 417 +++++++++++++++++++------- src/lib/consts.ts | 2 +- src/lib/ndk.ts | 23 +- src/routes/events/+page.svelte | 12 +- 6 files changed, 759 insertions(+), 228 deletions(-) diff --git a/src/lib/components/CommentBox.svelte b/src/lib/components/CommentBox.svelte index ef8bb61..f4b9a86 100644 --- a/src/lib/components/CommentBox.svelte +++ b/src/lib/components/CommentBox.svelte @@ -5,8 +5,20 @@ import { getUserMetadata, toNpub, - type NostrProfile, } from "$lib/utils/nostrUtils"; + + // Extend NostrProfile locally to include pubkey for mention search results + type NostrProfile = { + name?: string; + displayName?: string; + nip05?: string; + picture?: string; + about?: string; + banner?: string; + website?: string; + lud16?: string; + pubkey?: string; + }; import { activePubkey } from '$lib/ndk'; import type { NDKEvent } from "$lib/utils/nostrUtils"; import { @@ -17,6 +29,12 @@ publishEvent, navigateToEvent, } from "$lib/utils/nostrEventService"; + import { get } from 'svelte/store'; + import { ndkInstance } from '$lib/ndk'; + import type NDK from '@nostr-dev-kit/ndk'; + import { NDKRelaySet } from '@nostr-dev-kit/ndk'; + import { NDKRelay } from '@nostr-dev-kit/ndk'; + import { communityRelay } from '$lib/consts'; const props = $props<{ event: NDKEvent; @@ -32,6 +50,75 @@ let showFallbackRelays = $state(false); let userProfile = $state(null); + // Add state for modals and search + let showMentionModal = $state(false); + let showWikilinkModal = $state(false); + let mentionSearch = $state(''); + let mentionResults = $state([]); + let mentionLoading = $state(false); + let wikilinkTarget = $state(''); + let wikilinkLabel = $state(''); + let mentionSearchTimeout: ReturnType | null = null; + let nip05Search = $state(''); + let nip05Results = $state([]); + let nip05Loading = $state(false); + + // Add a cache for pubkeys with kind 1 events on communityRelay + const forestCache: Record = {}; + + async function checkForest(pubkey: string): Promise { + if (forestCache[pubkey] !== undefined) { + return forestCache[pubkey]; + } + // Query the communityRelay for kind 1 events by this pubkey + try { + const relayUrl = communityRelay[0]; + const ws = new WebSocket(relayUrl); + return await new Promise((resolve) => { + ws.onopen = () => { + // NIP-01 filter for kind 1 events by pubkey + ws.send(JSON.stringify([ + 'REQ', 'alexandria-forest', { kinds: [1], authors: [pubkey], limit: 1 } + ])); + }; + ws.onmessage = (event) => { + const data = JSON.parse(event.data); + if (data[0] === 'EVENT' && data[2]?.kind === 1) { + forestCache[pubkey] = true; + ws.close(); + resolve(true); + } else if (data[0] === 'EOSE') { + forestCache[pubkey] = false; + ws.close(); + resolve(false); + } + }; + ws.onerror = () => { + forestCache[pubkey] = false; + ws.close(); + resolve(false); + }; + }); + } catch { + forestCache[pubkey] = false; + return false; + } + } + + // Track which pubkeys have forest status loaded + let forestStatus: Record = $state({}); + + $effect(() => { + // When mentionResults change, check forest status for each + for (const profile of mentionResults) { + if (profile.pubkey && forestStatus[profile.pubkey] === undefined) { + checkForest(profile.pubkey).then((hasForest) => { + forestStatus = { ...forestStatus, [profile.pubkey!]: hasForest }; + }); + } + } + }); + $effect(() => { if (!activePubkey) { userProfile = null; @@ -72,9 +159,11 @@ { label: "Link", action: () => insertMarkup("[", "](url)") }, { label: "Image", action: () => insertMarkup("![", "](url)") }, { label: "Quote", action: () => insertMarkup("> ", "") }, - { label: "List", action: () => insertMarkup("- ", "") }, + { label: "List", action: () => insertMarkup("* ", "") }, { label: "Numbered List", action: () => insertMarkup("1. ", "") }, { label: "Hashtag", action: () => insertMarkup("#", "") }, + { label: '@', action: () => { mentionSearch = ''; mentionResults = []; showMentionModal = true; } }, + { label: 'Wikilink', action: () => { showWikilinkModal = true; } }, ]; function insertMarkup(prefix: string, suffix: string) { @@ -191,6 +280,183 @@ isSubmitting = false; } } + + // Insert at cursor helper + function insertAtCursor(text: string) { + const textarea = document.querySelector('textarea'); + if (!textarea) return; + const start = textarea.selectionStart; + const end = textarea.selectionEnd; + content = content.substring(0, start) + text + content.substring(end); + updatePreview(); + setTimeout(() => { + textarea.focus(); + textarea.selectionStart = textarea.selectionEnd = start + text.length; + }, 0); + } + + // Real Nostr profile search logic + async function searchMentions() { + mentionLoading = true; + mentionResults = []; + const searchTerm = mentionSearch.trim(); + if (!searchTerm) { + mentionLoading = false; + return; + } + // NIP-05 pattern: user@domain + if (/^[a-z0-9._-]+@[a-z0-9.-]+$/i.test(searchTerm)) { + try { + const [name, domain] = searchTerm.split('@'); + const res = await fetch(`https://${domain}/.well-known/nostr.json?name=${name}`); + const data = await res.json(); + const pubkey = data.names?.[name]; + if (pubkey) { + // Fetch kind:0 event for pubkey from theforest first + const ndk: NDK = get(ndkInstance); + if (!ndk) { + mentionLoading = false; + return; + } + // Try theforest relay first + const { communityRelay } = await import('$lib/consts'); + const forestRelays = communityRelay.map(url => ndk.pool.relays.get(url) ?? ndk.pool.getRelay(url)); + let events = await ndk.fetchEvents({ kinds: [0], authors: [pubkey] }, { closeOnEose: true }, new NDKRelaySet(new Set(forestRelays), ndk)); + let eventArr = Array.from(events); + if (eventArr.length === 0) { + // Fallback to all relays + const relaySet = new NDKRelaySet(new Set(Array.from(ndk.pool.relays.values())), ndk); + events = await ndk.fetchEvents({ kinds: [0], authors: [pubkey] }, { closeOnEose: true }, relaySet); + eventArr = Array.from(events); + } + if (eventArr.length > 0) { + try { + const event = eventArr[0]; + const profileData = JSON.parse(event.content); + mentionResults = [{ ...profileData, pubkey }]; + } catch { + mentionResults = []; + } + } else { + mentionResults = []; + } + } else { + mentionResults = []; + } + } catch { + mentionResults = []; + } + mentionLoading = false; + return; + } + // Fallback: search by display name or name + const ndk: NDK = get(ndkInstance); + if (!ndk) { + mentionLoading = false; + return; + } + // Try theforest relay first + const { communityRelay } = await import('$lib/consts'); + const forestRelays = communityRelay.map(url => ndk.pool.relays.get(url) ?? ndk.pool.getRelay(url)); + let foundProfiles: Record = {}; + let relaySet = new NDKRelaySet(new Set(forestRelays), ndk); + let filter = { kinds: [0] }; + let sub = ndk.subscribe(filter, { closeOnEose: true }, relaySet); + sub.on('event', (event: any) => { + try { + if (!event.content) return; + const profileData = JSON.parse(event.content); + const displayName = profileData.display_name || profileData.displayName || ''; + const name = profileData.name || ''; + const searchLower = searchTerm.toLowerCase(); + if ( + displayName.toLowerCase().includes(searchLower) || + name.toLowerCase().includes(searchLower) + ) { + // Deduplicate by pubkey, keep only newest + const pubkey = event.pubkey; + const created_at = event.created_at || 0; + if (!foundProfiles[pubkey] || foundProfiles[pubkey].created_at < created_at) { + foundProfiles[pubkey] = { + profile: { ...profileData, pubkey }, + created_at, + }; + } + } + } catch {} + }); + sub.on('eose', async () => { + const forestResults = Object.values(foundProfiles).map(x => x.profile); + if (forestResults.length > 0) { + mentionResults = forestResults; + mentionLoading = false; + return; + } + // Fallback to all relays + foundProfiles = {}; + const allRelays: NDKRelay[] = Array.from(ndk.pool.relays.values()); + relaySet = new NDKRelaySet(new Set(allRelays), ndk); + sub = ndk.subscribe(filter, { closeOnEose: true }, relaySet); + sub.on('event', (event: any) => { + try { + if (!event.content) return; + const profileData = JSON.parse(event.content); + const displayName = profileData.display_name || profileData.displayName || ''; + const name = profileData.name || ''; + const searchLower = searchTerm.toLowerCase(); + if ( + displayName.toLowerCase().includes(searchLower) || + name.toLowerCase().includes(searchLower) + ) { + // Deduplicate by pubkey, keep only newest + const pubkey = event.pubkey; + const created_at = event.created_at || 0; + if (!foundProfiles[pubkey] || foundProfiles[pubkey].created_at < created_at) { + foundProfiles[pubkey] = { + profile: { ...profileData, pubkey }, + created_at, + }; + } + } + } catch {} + }); + sub.on('eose', () => { + mentionResults = Object.values(foundProfiles).map(x => x.profile); + mentionLoading = false; + }); + }); + } + + function selectMention(profile: NostrProfile) { + // Always insert nostr:npub... for the selected profile + const npub = toNpub(profile.pubkey); + if (profile && npub) { + insertAtCursor(`nostr:${npub}`); + } + showMentionModal = false; + mentionSearch = ''; + mentionResults = []; + } + + function insertWikilink() { + if (!wikilinkTarget.trim()) return; + let markup = ''; + if (wikilinkLabel.trim()) { + markup = `[[${wikilinkTarget}|${wikilinkLabel}]]`; + } else { + markup = `[[${wikilinkTarget}]]`; + } + insertAtCursor(markup); + showWikilinkModal = false; + wikilinkTarget = ''; + wikilinkLabel = ''; + } + + // Add a helper to shorten npub + function shortenNpub(npub: string | undefined) { + if (!npub) return ''; + return npub.slice(0, 8) + '…' + npub.slice(-4); + }
    @@ -204,6 +470,80 @@
    + + {#if showMentionModal} +
    +
    +

    Mention User

    + + + {#if mentionLoading} +
    Searching...
    + {:else if mentionResults.length > 0} +
      + {#each mentionResults as profile} + + {/each} +
    + {:else} +
    No results
    + {/if} +
    + +
    +
    +
    + {/if} + + + {#if showWikilinkModal} +
    +
    +

    Insert Wikilink

    + + +
    + + +
    +
    +
    + {/if} +
    -
    -
    - - -
    -
    - - - {#if dTagError} -
    {dTagError}
    - {/if} -
    -
    - -
    - {#if loading} - Publishing... {/if} - {#if error} -
    {error}
    + {#if kind === 30040} +
    + 30040 - Publication Index: {get30040EventDescription()} +
    {/if} - {#if success} -
    {success}
    -
    Relays: {publishedRelays.join(', ')}
    - {#if lastPublishedEventId} -
    - Event ID: {lastPublishedEventId} - - View your event - +
    +
    + +
    + {#each tags as [key, value], i} +
    + updateTag(i, (e.target as HTMLInputElement).value, tags[i][1])} /> + updateTag(i, tags[i][0], (e.target as HTMLInputElement).value)} /> +
    - {/if} + {/each} +
    + +
    +
    +
    +
    + + +
    +
    + + +
    +
    + + + {#if dTagError} +
    {dTagError}
    + {/if} +
    +
    + +
    + {#if loading} + Publishing... + {/if} + {#if error} +
    {error}
    + {/if} + {#if success} +
    {success}
    +
    Relays: {publishedRelays.join(', ')}
    + {#if lastPublishedEventId} +
    + Event ID: {lastPublishedEventId} + + View your event + +
    {/if} - -
    -{/if} \ No newline at end of file + {/if} + +
    \ No newline at end of file diff --git a/src/lib/components/EventSearch.svelte b/src/lib/components/EventSearch.svelte index 3ad6e96..d83c6eb 100644 --- a/src/lib/components/EventSearch.svelte +++ b/src/lib/components/EventSearch.svelte @@ -7,7 +7,7 @@ import { goto } from "$app/navigation"; import type { NDKEvent } from "$lib/utils/nostrUtils"; import RelayDisplay from "./RelayDisplay.svelte"; - import { getActiveRelays } from "$lib/ndk"; + import { NDKRelaySet } from "@nostr-dev-kit/ndk"; const { loading, @@ -38,6 +38,8 @@ ); let foundEvent = $state(null); let searching = $state(false); + let activeSub: any = null; + let foundProfiles: NDKEvent[] = []; $effect(() => { if (searchValue) { @@ -47,7 +49,7 @@ $effect(() => { if (dTagValue) { - searchByDTag(dTagValue); + searchBySubscription('d', dTagValue); } }); @@ -55,66 +57,231 @@ foundEvent = event; }); - async function searchByDTag(dTag: string) { + async function searchBySubscription(searchType: 'd' | 't' | 'n', searchTerm: string) { localError = null; searching = true; if (onLoadingChange) { onLoadingChange(true); } - // Convert d-tag to lowercase for consistent searching - const normalizedDTag = dTag.toLowerCase(); + const normalizedSearchTerm = searchTerm.toLowerCase(); + const ndk = $ndkInstance; + if (!ndk) { + localError = 'NDK not initialized'; + searching = false; + if (onLoadingChange) { onLoadingChange(false); } + return; + } - try { - console.log("[Events] Searching for events with d-tag:", normalizedDTag); - const ndk = $ndkInstance; - if (!ndk) { - localError = "NDK not initialized"; - searching = false; - if (onLoadingChange) { onLoadingChange(false); } - return; + // Use all relays from the NDK pool + const relaySet = new NDKRelaySet(new Set(Array.from(ndk.pool.relays.values())), ndk); + let timeoutId: ReturnType | null = null; + let firstOrderEvents: NDKEvent[] = []; + let secondOrderEvents: NDKEvent[] = []; + let tTagEvents: NDKEvent[] = []; + let eventIds = new Set(); + let eventAddresses = new Set(); + let foundProfiles: NDKEvent[] = []; + + // Helper function to clean up subscription and timeout + const cleanup = () => { + if (timeoutId) { + clearTimeout(timeoutId); + timeoutId = null; + } + if (activeSub) { + activeSub.stop(); + activeSub = null; } + searching = false; + if (onLoadingChange) { onLoadingChange(false); } + }; + + // Helper function to check if a profile field matches the search term + const fieldMatches = (field: string) => { + if (!field) return false; + const fieldLower = field.toLowerCase(); + const searchLower = normalizedSearchTerm.toLowerCase(); + if (fieldLower === searchLower) return true; + if (fieldLower.includes(searchLower)) return true; + const words = fieldLower.split(/\s+/); + return words.some(word => word.includes(searchLower)); + }; + + // Set a timeout to force completion after 15 seconds + timeoutId = setTimeout(() => { + console.log(`[Events] ${searchType.toUpperCase()}-tag search timeout reached`); + if (searchType === 'n' && foundProfiles.length === 0) { + localError = `No profiles found matching: ${searchTerm} (search timed out)`; + onSearchResults([], [], [], new Set(), new Set()); + } else if (searchType === 'd' && firstOrderEvents.length === 0) { + localError = `No events found with d-tag: ${searchTerm} (search timed out)`; + onSearchResults([], [], [], new Set(), new Set()); + } else if (searchType === 't' && tTagEvents.length === 0) { + localError = `No events found with t-tag: ${searchTerm} (search timed out)`; + onSearchResults([], [], [], new Set(), new Set()); + } + cleanup(); + }, 15000); + + let filter: any; + let subscriptionType: string; + + switch (searchType) { + case 'd': + filter = { "#d": [normalizedSearchTerm] }; + subscriptionType = 'd-tag'; + break; + case 't': + filter = { "#t": [normalizedSearchTerm] }; + subscriptionType = 't-tag'; + break; + case 'n': + filter = { kinds: [0] }; + subscriptionType = 'profile'; + break; + } - const filter = { "#d": [normalizedDTag] }; - const relaySet = getActiveRelays(ndk); + console.log(`[Events] Starting ${subscriptionType} search for:`, normalizedSearchTerm); - // Fetch multiple events with the same d-tag - const events = await ndk.fetchEvents( - filter, - { closeOnEose: true }, - relaySet, - ); - const eventArray = Array.from(events); + // Subscribe to events + const sub = ndk.subscribe( + filter, + { closeOnEose: true }, + relaySet + ); - if (eventArray.length === 0) { - localError = `No events found with d-tag: ${normalizedDTag}`; - onSearchResults([], [], [], new Set(), new Set()); - searching = false; - if (onLoadingChange) { onLoadingChange(false); } - return; + sub.on('event', (event) => { + try { + if (searchType === 'n') { + // Profile search logic + if (!event.content) return; + const profileData = JSON.parse(event.content); + const displayName = profileData.display_name || profileData.displayName || ''; + const name = profileData.name || ''; + const nip05 = profileData.nip05 || ''; + + if (fieldMatches(displayName) || fieldMatches(name) || fieldMatches(nip05.split('@')[0])) { + foundProfiles = [...foundProfiles, event]; + onSearchResults(foundProfiles, [], [], new Set(foundProfiles.map(p => p.id)), new Set()); + } + } else { + // d-tag and t-tag search logic + if (event.kind === 7) return; // Skip emoji reactions + + if (searchType === 'd') { + firstOrderEvents = [...firstOrderEvents, event]; + + // Collect event IDs and addresses for second-order search + if (event.id) { + eventIds.add(event.id); + } + const aTags = getMatchingTags(event, "a"); + aTags.forEach((tag: string[]) => { + if (tag[1]) { + eventAddresses.add(tag[1]); + } + }); + } else if (searchType === 't') { + tTagEvents = [...tTagEvents, event]; + } + } + } catch (e) { + // Invalid JSON or other error, skip } + }); - // Collect all event IDs and addresses for second-order search - const eventIds = new Set(); - const eventAddresses = new Set(); + sub.on('eose', () => { + console.log(`[Events] ${subscriptionType} search EOSE received`); - eventArray.forEach(event => { - if (event.id) { - eventIds.add(event.id); + if (searchType === 'n') { + if (foundProfiles.length === 0) { + localError = `No profiles found matching: ${searchTerm}`; + onSearchResults([], [], [], new Set(), new Set()); + } else { + // Deduplicate by pubkey, keep only newest + const deduped: Record = {}; + for (const event of foundProfiles) { + const pubkey = event.pubkey; + const created_at = event.created_at || 0; + if (!deduped[pubkey] || deduped[pubkey].created_at < created_at) { + deduped[pubkey] = { event, created_at }; + } + } + const dedupedProfiles = Object.values(deduped).map(x => x.event); + onSearchResults(dedupedProfiles, [], [], new Set(dedupedProfiles.map(p => p.id)), new Set()); } - // Add a-tag addresses (kind:pubkey:d) - const aTags = getMatchingTags(event, "a"); - aTags.forEach((tag: string[]) => { - if (tag[1]) { - eventAddresses.add(tag[1]); + } else if (searchType === 'd') { + if (firstOrderEvents.length === 0) { + localError = `No events found with d-tag: ${searchTerm}`; + onSearchResults([], [], [], new Set(), new Set()); + } else { + // Deduplicate by kind, pubkey, and d-tag, keep only newest event for each combination + const deduped: Record = {}; + for (const event of firstOrderEvents) { + const dTag = getMatchingTags(event, 'd')[0]?.[1] || ''; + const key = `${event.kind}:${event.pubkey}:${dTag}`; + const created_at = event.created_at || 0; + if (!deduped[key] || deduped[key].created_at < created_at) { + deduped[key] = { event, created_at }; + } } - }); - }); + const dedupedEvents = Object.values(deduped).map(x => x.event); + onSearchResults(dedupedEvents, [], [], eventIds, eventAddresses); + localError = `Found ${dedupedEvents.length} unique d-tag events. Searching for second-order results...`; + // Perform second-order search in background + firstOrderEvents = dedupedEvents; + performSecondOrderSearch(); + } + } else if (searchType === 't') { + if (tTagEvents.length === 0) { + localError = `No events found with t-tag: ${searchTerm}`; + onSearchResults([], [], [], new Set(), new Set()); + } else { + console.log("[Events] T-tag search completed, found", tTagEvents.length, "events"); + onSearchResults([], [], tTagEvents, new Set(), new Set()); + } + } + + cleanup(); + }); + + // Helper function to perform second-order search for d-tag searches + async function performSecondOrderSearch() { + if (eventIds.size === 0 && eventAddresses.size === 0) { + // No references to search for, just search for t-tag events + console.log("[Events] No references found, searching for t-tag events only"); + try { + const tTagFilter = { '#t': [normalizedSearchTerm] }; + const tTagEventsSet = await ndk.fetchEvents( + tTagFilter, + { closeOnEose: true }, + relaySet, + ); + + const tTagEvents = Array.from(tTagEventsSet).filter(e => + e.kind !== 7 && + !firstOrderEvents.some(fe => fe.id === e.id) + ); - // Search for second-order events that reference the original events - const secondOrderEvents = new Set(); + console.log("[Events] T-tag search completed:", { + firstOrder: firstOrderEvents.length, + tTag: tTagEvents.length + }); + + // Clear the "searching" message + localError = null; + + onSearchResults(firstOrderEvents, [], tTagEvents, eventIds, eventAddresses); + } catch (err) { + console.error("[Events] Error in t-tag search:", err); + localError = null; + onSearchResults(firstOrderEvents, [], [], eventIds, eventAddresses); + } + return; + } + + console.log("[Events] Starting second-order search..."); - if (eventIds.size > 0 || eventAddresses.size > 0) { - console.log("[Events] Searching for second-order events..."); - + try { // Search for events with e tags referencing the original events if (eventIds.size > 0) { const eTagFilter = { "#e": Array.from(eventIds) }; @@ -123,7 +290,11 @@ { closeOnEose: true }, relaySet, ); - eTagEvents.forEach(event => secondOrderEvents.add(event)); + eTagEvents.forEach(event => { + if (event.kind !== 7) { // Skip emoji reactions + secondOrderEvents.push(event); + } + }); } // Search for events with a tags referencing the original events @@ -134,35 +305,36 @@ { closeOnEose: true }, relaySet, ); - aTagEvents.forEach(event => secondOrderEvents.add(event)); + aTagEvents.forEach(event => { + if (event.kind !== 7) { // Skip emoji reactions + secondOrderEvents.push(event); + } + }); } // Search for events with content containing nevent/naddr/note references - // This is a more complex search that requires fetching recent events and checking content // Limit the search to recent events to avoid performance issues const recentEvents = await ndk.fetchEvents( { - limit: 500, // Reduced limit for better performance - since: Math.floor(Date.now() / 1000) - (7 * 24 * 60 * 60) // Last 7 days + limit: 10000, + since: Math.floor(Date.now() / 1000) - (30 * 24 * 60 * 60) // Last 30 days }, { closeOnEose: true }, relaySet, ); recentEvents.forEach(event => { - if (event.content) { - // Check for nevent references with more precise matching + if (event.content && event.kind !== 7) { + // Check for nevent references eventIds.forEach(id => { - // Look for complete nevent references const neventPattern = new RegExp(`nevent1[a-z0-9]{50,}`, 'i'); const matches = event.content.match(neventPattern); if (matches) { - // Verify the nevent contains the event ID matches.forEach(match => { try { const decoded = nip19.decode(match); if (decoded && decoded.type === 'nevent' && decoded.data.id === id) { - secondOrderEvents.add(event); + secondOrderEvents.push(event); } } catch (e) { // Invalid nevent, skip @@ -171,19 +343,18 @@ } }); - // Check for naddr references with more precise matching + // Check for naddr references eventAddresses.forEach(address => { const naddrPattern = new RegExp(`naddr1[a-z0-9]{50,}`, 'i'); const matches = event.content.match(naddrPattern); if (matches) { - // Verify the naddr contains the address matches.forEach(match => { try { const decoded = nip19.decode(match); if (decoded && decoded.type === 'naddr') { const decodedAddress = `${decoded.data.kind}:${decoded.data.pubkey}:${decoded.data.identifier}`; if (decodedAddress === address) { - secondOrderEvents.add(event); + secondOrderEvents.push(event); } } } catch (e) { @@ -193,17 +364,16 @@ } }); - // Check for note references (event IDs) with more precise matching + // Check for note references eventIds.forEach(id => { const notePattern = new RegExp(`note1[a-z0-9]{50,}`, 'i'); const matches = event.content.match(notePattern); if (matches) { - // Verify the note contains the event ID matches.forEach(match => { try { const decoded = nip19.decode(match); if (decoded && decoded.type === 'note' && decoded.data === id) { - secondOrderEvents.add(event); + secondOrderEvents.push(event); } } catch (e) { // Invalid note, skip @@ -213,58 +383,64 @@ }); } }); - } - // Combine first-order and second-order events - const allEvents = [...eventArray, ...Array.from(secondOrderEvents)]; - - // Remove duplicates based on event ID - const uniqueEvents = new Map(); - allEvents.forEach(event => { - if (event.id) { - uniqueEvents.set(event.id, event); - } - }); - - const finalEvents = Array.from(uniqueEvents.values()); - - // Separate first-order and second-order events - const firstOrderSet = new Set(eventArray.map(e => e.id)); - const firstOrder = finalEvents.filter(e => firstOrderSet.has(e.id)); - const secondOrder = finalEvents.filter(e => !firstOrderSet.has(e.id)); - - // Remove kind 7 (emoji reactions) from both first-order and second-order results - const filteredFirstOrder = firstOrder.filter(e => e.kind !== 7); - const filteredSecondOrder = secondOrder.filter(e => e.kind !== 7); - - // --- t: search --- - // Search for events with a matching t-tag (topic/tag) - const tTagFilter = { '#t': [normalizedDTag] }; - const tTagEventsSet = await ndk.fetchEvents( - tTagFilter, - { closeOnEose: true }, - relaySet, - ); - // Remove any events already in first or second order - const tTagEvents = Array.from(tTagEventsSet).filter(e => - e.kind !== 7 && - !firstOrderSet.has(e.id) && - !filteredSecondOrder.some(se => se.id === e.id) - ); + // Remove duplicates from second-order events + const uniqueSecondOrder = new Map(); + secondOrderEvents.forEach(event => { + if (event.id) { + uniqueSecondOrder.set(event.id, event); + } + }); + let deduplicatedSecondOrder = Array.from(uniqueSecondOrder.values()); - onSearchResults(filteredFirstOrder, filteredSecondOrder, tTagEvents, eventIds, eventAddresses); - searching = false; - if (onLoadingChange) { onLoadingChange(false); } - return; - } catch (err) { - console.error("[Events] Error searching by d-tag:", err); - onSearchResults([], [], [], new Set(), new Set()); - searching = false; - if (onLoadingChange) { onLoadingChange(false); } - return; + // Remove any events already in firstOrderEvents (d-tag section) + const firstOrderIds = new Set(firstOrderEvents.map(e => e.id)); + deduplicatedSecondOrder = deduplicatedSecondOrder.filter(e => !firstOrderIds.has(e.id)); + + // Search for t-tag events + const tTagFilter = { '#t': [normalizedSearchTerm] }; + const tTagEventsSet = await ndk.fetchEvents( + tTagFilter, + { closeOnEose: true }, + relaySet, + ); + + // Remove any events already in first or second order + const firstOrderSet = new Set(firstOrderEvents.map(e => e.id)); + const secondOrderSet = new Set(deduplicatedSecondOrder.map(e => e.id)); + + const tTagEvents = Array.from(tTagEventsSet).filter(e => + e.kind !== 7 && + !firstOrderSet.has(e.id) && + !secondOrderSet.has(e.id) + ); + + console.log("[Events] Second-order search completed:", { + firstOrder: firstOrderEvents.length, + secondOrder: deduplicatedSecondOrder.length, + tTag: tTagEvents.length + }); + + // Clear the "searching" message + localError = null; + + // Update results with second-order and t-tag events + onSearchResults(firstOrderEvents, deduplicatedSecondOrder, tTagEvents, eventIds, eventAddresses); + } catch (err) { + console.error("[Events] Error in second-order search:", err); + // Clear the "searching" message + localError = null; + // Return first-order results even if second-order search fails + onSearchResults(firstOrderEvents, [], [], eventIds, eventAddresses); + } } + + if (activeSub) { activeSub.stop(); } + activeSub = sub; } + + async function searchEvent( clearInput: boolean = true, queryOverride?: string, @@ -297,6 +473,24 @@ } } + // Check if this is a t-tag search + if (query.toLowerCase().startsWith("t:")) { + const searchTerm = query.slice(2).trim(); + if (searchTerm) { + await searchBySubscription('t', searchTerm); + return; + } + } + + // Check if this is an npub search + if (query.toLowerCase().startsWith("n:")) { + const searchTerm = query.slice(2).trim(); + if (searchTerm) { + await searchBySubscription('n', searchTerm); + return; + } + } + // Only update the URL if this is a manual search if (clearInput) { const encoded = encodeURIComponent(query); @@ -471,6 +665,9 @@ localError = null; foundEvent = null; relayStatuses = {}; + if (activeSub) { activeSub.stop(); activeSub = null; } + foundProfiles = []; + onSearchResults([], [], [], new Set(), new Set()); if (onClear) { onClear(); } @@ -481,7 +678,7 @@
    e.key === "Enter" && searchEvent(true)} /> diff --git a/src/lib/consts.ts b/src/lib/consts.ts index ac908fd..86bb122 100644 --- a/src/lib/consts.ts +++ b/src/lib/consts.ts @@ -23,8 +23,8 @@ export const fallbackRelays = [ "wss://indexer.coracle.social", "wss://relay.noswhere.com", "wss://aggr.nostr.land", - "wss://nostr.wine", "wss://nostr.land", + "wss://nostr.wine", "wss://nostr.sovbit.host", "wss://freelay.sovbit.host", "wss://nostr21.com", diff --git a/src/lib/ndk.ts b/src/lib/ndk.ts index 196ee03..ff130dd 100644 --- a/src/lib/ndk.ts +++ b/src/lib/ndk.ts @@ -15,6 +15,7 @@ import { anonymousRelays, } from "./consts"; import { feedType } from "./stores"; +import { userPubkey } from '$lib/stores/authStore'; export const ndkInstance: Writable = writable(); @@ -435,21 +436,11 @@ function createRelayWithAuth(url: string, ndk: NDK): NDKRelay { } export function getActiveRelays(ndk: NDK): NDKRelaySet { - // Use anonymous relays if user is not signed in - const isSignedIn = ndk.signer && ndk.activeUser; - const relays = isSignedIn ? standardRelays : anonymousRelays; - - return get(feedType) === FeedType.UserRelays - ? new NDKRelaySet( - new Set( - get(inboxRelays).map((relay) => createRelayWithAuth(relay, ndk)), - ), - ndk, - ) - : new NDKRelaySet( - new Set(relays.map((relay) => createRelayWithAuth(relay, ndk))), - ndk, - ); + // Use all relays currently in the NDK pool + return new NDKRelaySet( + new Set(Array.from(ndk.pool.relays.values())), + ndk, + ); } /** @@ -522,6 +513,7 @@ export async function loginWithExtension( } activePubkey.set(signerUser.pubkey); + userPubkey.set(signerUser.pubkey); const [persistedInboxes, persistedOutboxes] = getPersistedRelays(signerUser); @@ -561,6 +553,7 @@ export function logout(user: NDKUser): void { clearLogin(); clearPersistedRelays(user); activePubkey.set(null); + userPubkey.set(null); ndkSignedIn.set(false); ndkInstance.set(initNdk()); // Re-initialize with anonymous instance } diff --git a/src/routes/events/+page.svelte b/src/routes/events/+page.svelte index 2a1c12a..410b02d 100644 --- a/src/routes/events/+page.svelte +++ b/src/routes/events/+page.svelte @@ -12,7 +12,6 @@ import { getMatchingTags, toNpub } from "$lib/utils/nostrUtils"; import EventInput from '$lib/components/EventInput.svelte'; import { userPubkey, isLoggedIn } from '$lib/stores/authStore'; - import RelayStatus from '$lib/components/RelayStatus.svelte'; import { testAllRelays, logRelayDiagnostics } from '$lib/utils/relayDiagnostics'; import CopyToClipboard from '$lib/components/util/CopyToClipboard.svelte'; import { neventEncode, naddrEncode } from '$lib/utils'; @@ -172,9 +171,6 @@ }); onMount(() => { - // Initialize userPubkey from localStorage if available - const pubkey = localStorage.getItem('userPubkey'); - userPubkey.set(pubkey); userRelayPreference = localStorage.getItem('useUserRelays') === 'true'; // Run relay diagnostics to help identify connection issues @@ -183,7 +179,7 @@
    -
    +
    Events
    @@ -465,5 +461,11 @@
    {/if} + + {#if !event && searchResults.length === 0 && secondOrderResults.length === 0 && tTagResults.length === 0 && !searchValue && !dTagValue} +
    + +
    + {/if}
    From 7cd1a522f222ece76f1955d4a858d618d8409d4a Mon Sep 17 00:00:00 2001 From: silberengel Date: Mon, 14 Jul 2025 18:48:03 +0200 Subject: [PATCH 104/135] Made Amber session persistent. --- src/lib/components/LoginMenu.svelte | 42 +++++++++++++++++++++++++++++ src/routes/+layout.ts | 31 ++++++++++++++++++--- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/src/lib/components/LoginMenu.svelte b/src/lib/components/LoginMenu.svelte index 36c7e68..921d5f6 100644 --- a/src/lib/components/LoginMenu.svelte +++ b/src/lib/components/LoginMenu.svelte @@ -4,6 +4,7 @@ import { userStore, loginWithExtension, loginWithAmber, loginWithNpub, logoutUser } from '$lib/stores/userStore'; import { get } from 'svelte/store'; import NDK, { NDKNip46Signer, NDKPrivateKeySigner } from '@nostr-dev-kit/ndk'; + import { onMount } from 'svelte'; // UI state let isLoadingExtension: boolean = $state(false); @@ -15,6 +16,13 @@ let loginButtonRef: HTMLElement | undefined = $state(); let resultTimeout: ReturnType | null = null; let profileAvatarId = 'profile-avatar-btn'; + let showAmberReconnect = $state(false); + + onMount(() => { + if (localStorage.getItem('alexandria/amber/reconnect') === '1') { + showAmberReconnect = true; + } + }); // Subscribe to userStore let user = $state(get(userStore)); @@ -112,9 +120,17 @@ }; const handleLogout = () => { + localStorage.removeItem('amber/nsec'); + localStorage.removeItem('alexandria/amber/reconnect'); logoutUser(); }; + function handleAmberReconnect() { + showAmberReconnect = false; + localStorage.removeItem('alexandria/amber/reconnect'); + handleAmberLogin(); + } + function shortenNpub(long: string | undefined) { if (!long) return ''; return long.slice(0, 8) + '…' + long.slice(-4); @@ -286,4 +302,30 @@
    +{/if} + +{#if showAmberReconnect} +
    +
    +
    +

    Reconnect Amber Wallet

    +

    + Your Amber wallet session could not be restored automatically.
    + Please reconnect your Amber wallet to continue. +

    + + +
    +
    +
    {/if} \ No newline at end of file diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts index b45c6e8..4744b85 100644 --- a/src/routes/+layout.ts +++ b/src/routes/+layout.ts @@ -6,6 +6,7 @@ import { loginMethodStorageKey } from '$lib/stores/userStore'; import Pharos, { pharosInstance } from '$lib/parser'; import { feedType } from '$lib/stores'; import type { LayoutLoad } from './$types'; +import { get } from 'svelte/store'; export const ssr = false; @@ -31,9 +32,33 @@ export const load: LayoutLoad = () => { console.log('Restoring extension login...'); loginWithExtension(); } else if (loginMethod === 'amber') { - // Amber login restoration would require more context (e.g., session, signer), so skip for now - alert('Amber login cannot be restored automatically. Please reconnect your Amber wallet.'); - console.warn('Amber login cannot be restored automatically. Please reconnect your Amber wallet.'); + // Attempt to restore Amber (NIP-46) session from localStorage + const relay = 'wss://relay.nsec.app'; + const localNsec = localStorage.getItem('amber/nsec'); + if (localNsec) { + import('@nostr-dev-kit/ndk').then(async ({ NDKNip46Signer, default: NDK }) => { + const ndk = get(ndkInstance); + try { + const amberSigner = NDKNip46Signer.nostrconnect(ndk, relay, localNsec, { + name: 'Alexandria', + perms: 'sign_event:1;sign_event:4', + }); + // Try to reconnect (blockUntilReady will resolve if Amber is running and session is valid) + await amberSigner.blockUntilReady(); + const user = await amberSigner.user(); + await loginWithAmber(amberSigner, user); + console.log('Amber session restored.'); + } catch (err) { + // If reconnection fails, show a non-blocking prompt (handled in LoginMenu UI) + console.warn('Amber session could not be restored. Prompting user to reconnect.'); + // Optionally, set a flag in localStorage or a Svelte store to show a reconnect banner/modal + localStorage.setItem('alexandria/amber/reconnect', '1'); + } + }); + } else { + // No session data, prompt user to reconnect (handled in LoginMenu UI) + localStorage.setItem('alexandria/amber/reconnect', '1'); + } } else if (loginMethod === 'npub') { console.log('Restoring npub login...'); loginWithNpub(pubkey); From c30bd1d5199a386b1f8a580d8884989fd85d625e Mon Sep 17 00:00:00 2001 From: silberengel Date: Mon, 14 Jul 2025 21:30:38 +0200 Subject: [PATCH 105/135] Fix the page redirection to sustain the Amber sessions --- src/lib/components/CommentBox.svelte | 10 ++-- src/lib/components/EventDetails.svelte | 45 +++++++++++++--- src/lib/components/LoginMenu.svelte | 3 +- src/lib/components/Preview.svelte | 1 + src/lib/components/PublicationHeader.svelte | 32 +++++++++--- src/lib/components/util/Details.svelte | 25 ++++++--- src/lib/snippets/UserSnippets.svelte | 58 +++++++++++++++++---- src/lib/stores/userStore.ts | 2 +- src/lib/utils/nostrUtils.ts | 11 ++-- src/routes/about/+page.svelte | 5 +- src/routes/events/+page.svelte | 9 ++-- src/routes/start/+page.svelte | 21 ++++---- 12 files changed, 164 insertions(+), 58 deletions(-) diff --git a/src/lib/components/CommentBox.svelte b/src/lib/components/CommentBox.svelte index 552ad5f..ab37d19 100644 --- a/src/lib/components/CommentBox.svelte +++ b/src/lib/components/CommentBox.svelte @@ -263,11 +263,15 @@ {/if} {#if success} + {@const s = success} - Comment published successfully to {success.relay}! - + Comment published successfully to {s.relay}! + {/if} diff --git a/src/lib/components/EventDetails.svelte b/src/lib/components/EventDetails.svelte index 17c3d0c..1672820 100644 --- a/src/lib/components/EventDetails.svelte +++ b/src/lib/components/EventDetails.svelte @@ -8,6 +8,8 @@ import type { NDKEvent } from '$lib/utils/nostrUtils'; import { getMatchingTags } from '$lib/utils/nostrUtils'; import ProfileHeader from "$components/cards/ProfileHeader.svelte"; + import { goto } from '$app/navigation'; + import { onMount } from 'svelte'; const { event, profile = null, searchValue = null } = $props<{ event: NDKEvent; @@ -27,6 +29,12 @@ let showFullContent = $state(false); let parsedContent = $state(''); let contentPreview = $state(''); + let authorTag: string = $derived(getMatchingTags(event, 'author')[0]?.[1] ?? ''); + let pTag: string = $derived(getMatchingTags(event, 'p')[0]?.[1] ?? ''); + + function isValidNostrPubkey(str: string): boolean { + return /^[a-f0-9]{64}$/i.test(str) || (str.startsWith('npub1') && str.length >= 59 && str.length <= 63); + } function getEventTitle(event: NDKEvent): string { return getMatchingTags(event, 'title')[0]?.[1] || 'Untitled'; @@ -48,9 +56,9 @@ function renderTag(tag: string[]): string { if (tag[0] === 'a' && tag.length > 1) { const [kind, pubkey, d] = tag[1].split(':'); - return `a:${tag[1]}`; + return ``; } else if (tag[0] === 'e' && tag.length > 1) { - return `e:${tag[1]}`; + return ``; } else { return `${tag[0]}:${tag[1]}`; } @@ -100,6 +108,21 @@ const norm = (s: string) => s.replace(/^nostr:/, '').toLowerCase(); return norm(value) === norm(searchValue); } + + onMount(() => { + function handleInternalLinkClick(event: MouseEvent) { + const target = event.target as HTMLElement; + if (target.tagName === 'A') { + const href = (target as HTMLAnchorElement).getAttribute('href'); + if (href && href.startsWith('/')) { + event.preventDefault(); + goto(href); + } + } + } + document.addEventListener('click', handleInternalLinkClick); + return () => document.removeEventListener('click', handleInternalLinkClick); + });
    @@ -108,11 +131,19 @@ {/if}
    - {#if toNpub(event.pubkey)} - Author: {@render userBadge(toNpub(event.pubkey) as string, profile?.display_name || event.pubkey)} - {:else} - Author: {profile?.display_name || event.pubkey} - {/if} + Author: + {#if authorTag && pTag && isValidNostrPubkey(pTag)} + {authorTag} {@render userBadge(pTag, '')} + {:else if authorTag} + {authorTag} + {:else if pTag && isValidNostrPubkey(pTag)} + {@render userBadge(pTag, '')} + {:else if authorTag} + {authorTag} + {:else} + unknown + {/if} +
    diff --git a/src/lib/components/LoginMenu.svelte b/src/lib/components/LoginMenu.svelte index 921d5f6..c5a037a 100644 --- a/src/lib/components/LoginMenu.svelte +++ b/src/lib/components/LoginMenu.svelte @@ -5,6 +5,7 @@ import { get } from 'svelte/store'; import NDK, { NDKNip46Signer, NDKPrivateKeySigner } from '@nostr-dev-kit/ndk'; import { onMount } from 'svelte'; + import { goto } from '$app/navigation'; // UI state let isLoadingExtension: boolean = $state(false); @@ -230,7 +231,7 @@
  • diff --git a/src/lib/components/util/Details.svelte b/src/lib/components/util/Details.svelte index e776e9d..f2fe837 100644 --- a/src/lib/components/util/Details.svelte +++ b/src/lib/components/util/Details.svelte @@ -11,10 +11,8 @@ let { event, isModal = false } = $props(); let title: string = $derived(getMatchingTags(event, 'title')[0]?.[1]); - let author: string = $derived(getMatchingTags(event, 'author')[0]?.[1] ?? 'unknown'); let version: string = $derived(getMatchingTags(event, 'version')[0]?.[1] ?? '1'); let image: string = $derived(getMatchingTags(event, 'image')[0]?.[1] ?? null); - let originalAuthor: string = $derived(getMatchingTags(event, 'p')[0]?.[1] ?? null); let summary: string = $derived(getMatchingTags(event, 'summary')[0]?.[1] ?? null); let type: string = $derived(getMatchingTags(event, 'type')[0]?.[1] ?? null); let language: string = $derived(getMatchingTags(event, 'l')[0]?.[1] ?? null); @@ -25,6 +23,12 @@ let rootId: string = $derived(getMatchingTags(event, 'd')[0]?.[1] ?? null); let kind = $derived(event.kind); + let authorTag: string = $derived(getMatchingTags(event, 'author')[0]?.[1] ?? ''); + let pTag: string = $derived(getMatchingTags(event, 'p')[0]?.[1] ?? ''); + + function isValidNostrPubkey(str: string): boolean { + return /^[a-f0-9]{64}$/i.test(str) || (str.startsWith('npub1') && str.length >= 59 && str.length <= 63); + } @@ -32,7 +36,8 @@
    {#if !isModal}
    -

    {@render userBadge(event.pubkey, author)}

    + +

    {@render userBadge(event.pubkey, '')}

    {/if} @@ -46,10 +51,16 @@

    {title}

    by - {#if originalAuthor !== null} - {@render userBadge(originalAuthor, author)} + {#if authorTag && pTag && isValidNostrPubkey(pTag)} + {authorTag} {@render userBadge(pTag, '')} + {:else if authorTag} + {authorTag} + {:else if pTag && isValidNostrPubkey(pTag)} + {@render userBadge(pTag, '')} + {:else if authorTag} + {authorTag} {:else} - {author} + unknown {/if}

    {#if version !== '1' } @@ -81,7 +92,7 @@ {:else} Author: {/if} - {@render userBadge(event.pubkey, author)} + {@render userBadge(event.pubkey, '')}
    diff --git a/src/lib/snippets/UserSnippets.svelte b/src/lib/snippets/UserSnippets.svelte index d8c960e..7fc5632 100644 --- a/src/lib/snippets/UserSnippets.svelte +++ b/src/lib/snippets/UserSnippets.svelte @@ -1,18 +1,58 @@ {#snippet userBadge(identifier: string, displayText: string | undefined)} - {#if toNpub(identifier)} - {#await createProfileLinkWithVerification(toNpub(identifier) as string, displayText)} - {@html createProfileLink(toNpub(identifier) as string, displayText)} - {:then html} - {@html html} - {:catch} - {@html createProfileLink(toNpub(identifier) as string, displayText)} - {/await} + {@const npub = toNpub(identifier)} + {#if npub} + {#if !displayText || displayText.trim().toLowerCase() === 'unknown'} + {#await getUserMetadata(npub) then profile} + {@const p = profile as NostrProfileWithLegacy} + + + + {:catch} + + + + {/await} + {:else} + {#await createProfileLinkWithVerification(npub as string, displayText)} + + + + {:then html} + + + {@html html.replace(/([\s\S]*<\/a>)/, '').trim()} + + {:catch} + + + + {/await} + {/if} {:else} {displayText ?? ''} {/if} diff --git a/src/lib/stores/userStore.ts b/src/lib/stores/userStore.ts index 5c95ff8..3e3d77f 100644 --- a/src/lib/stores/userStore.ts +++ b/src/lib/stores/userStore.ts @@ -168,7 +168,7 @@ export async function loginWithAmber(amberSigner: NDKSigner, user: NDKUser) { if (!ndk) throw new Error('NDK not initialized'); // Only clear previous login state after successful login const npub = user.npub; - const profile = await getUserMetadata(npub); + const profile = await getUserMetadata(npub, true); // Force fresh fetch const [persistedInboxes, persistedOutboxes] = getPersistedRelays(user); for (const relay of persistedInboxes) { ndk.addExplicitRelay(relay); diff --git a/src/lib/utils/nostrUtils.ts b/src/lib/utils/nostrUtils.ts index b85dbb9..faa001b 100644 --- a/src/lib/utils/nostrUtils.ts +++ b/src/lib/utils/nostrUtils.ts @@ -46,11 +46,11 @@ function escapeHtml(text: string): string { /** * Get user metadata for a nostr identifier (npub or nprofile) */ -export async function getUserMetadata(identifier: string): Promise { +export async function getUserMetadata(identifier: string, force = false): Promise { // Remove nostr: prefix if present const cleanId = identifier.replace(/^nostr:/, ''); - if (npubCache.has(cleanId)) { + if (!force && npubCache.has(cleanId)) { return npubCache.get(cleanId)!; } @@ -111,7 +111,8 @@ export function createProfileLink(identifier: string, displayText: string | unde const defaultText = `${cleanId.slice(0, 8)}...${cleanId.slice(-4)}`; const escapedText = escapeHtml(displayText || defaultText); - return `@${escapedText}`; + // Remove target="_blank" for internal navigation + return `@${escapedText}`; } /** @@ -167,9 +168,9 @@ export async function createProfileLinkWithVerification(identifier: string, disp const type = nip05.endsWith('edu') ? 'edu' : 'standard'; switch (type) { case 'edu': - return `@${displayIdentifier}${graduationCapSvg}`; + return `@${displayIdentifier}${graduationCapSvg}`; case 'standard': - return `@${displayIdentifier}${badgeCheckSvg}`; + return `@${displayIdentifier}${badgeCheckSvg}`; } } /** diff --git a/src/routes/about/+page.svelte b/src/routes/about/+page.svelte index a6badf3..b5b7c09 100644 --- a/src/routes/about/+page.svelte +++ b/src/routes/about/+page.svelte @@ -1,6 +1,7 @@ diff --git a/src/routes/start/+page.svelte b/src/routes/start/+page.svelte index 05d0776..04177de 100644 --- a/src/routes/start/+page.svelte +++ b/src/routes/start/+page.svelte @@ -1,5 +1,6 @@ + +
    +
    + +
    + +
    + +
    +
    +
    - +
    - + {#if dTagError} -
    {dTagError}
    +
    {dTagError}
    {/if}
    -
    - +
    +
    {#if loading} - Publishing... + Publishing... {/if} {#if error} -
    {error}
    +
    {error}
    {/if} {#if success} -
    {success}
    -
    Relays: {publishedRelays.join(', ')}
    +
    {success}
    +
    + Relays: {publishedRelays.join(", ")} +
    {#if lastPublishedEventId} -
    - Event ID: {lastPublishedEventId} -
    {/if} {/if} -
    \ No newline at end of file +
    diff --git a/src/lib/components/EventSearch.svelte b/src/lib/components/EventSearch.svelte index e9dfed2..c32f72b 100644 --- a/src/lib/components/EventSearch.svelte +++ b/src/lib/components/EventSearch.svelte @@ -4,7 +4,11 @@ import { goto } from "$app/navigation"; import type { NDKEvent } from "$lib/utils/nostrUtils"; import RelayDisplay from "./RelayDisplay.svelte"; - import { searchEvent, searchBySubscription, searchNip05 } from "$lib/utils/search_utility"; + import { + searchEvent, + searchBySubscription, + searchNip05, + } from "$lib/utils/search_utility"; import { neventEncode, naddrEncode, nprofileEncode } from "$lib/utils"; import { standardRelays } from "$lib/consts"; import { getMatchingTags, toNpub } from "$lib/utils/nostrUtils"; @@ -33,7 +37,7 @@ eventIds: Set, addresses: Set, searchType?: string, - searchTerm?: string + searchTerm?: string, ) => void; event: NDKEvent | null; onClear?: () => void; @@ -43,7 +47,9 @@ // Component state let searchQuery = $state(""); let localError = $state(null); - let relayStatuses = $state>({}); + let relayStatuses = $state>( + {}, + ); let foundEvent = $state(null); let searching = $state(false); let searchCompleted = $state(false); @@ -56,7 +62,11 @@ let currentAbortController: AbortController | null = null; // Derived values - let hasActiveSearch = $derived(searching || (Object.values(relayStatuses).some(s => s === "pending") && !foundEvent)); + let hasActiveSearch = $derived( + searching || + (Object.values(relayStatuses).some((s) => s === "pending") && + !foundEvent), + ); let showError = $derived(localError || error); let showSuccess = $derived(searchCompleted && searchResultCount !== null); @@ -75,18 +85,39 @@ const foundEvent = await searchNip05(query); if (foundEvent) { handleFoundEvent(foundEvent); - updateSearchState(false, true, 1, 'nip05'); + updateSearchState(false, true, 1, "nip05"); } else { relayStatuses = {}; - if (activeSub) { try { activeSub.stop(); } catch (e) { console.warn('Error stopping subscription:', e); } activeSub = null; } - if (currentAbortController) { currentAbortController.abort(); currentAbortController = null; } - updateSearchState(false, true, 0, 'nip05'); + if (activeSub) { + try { + activeSub.stop(); + } catch (e) { + console.warn("Error stopping subscription:", e); + } + activeSub = null; + } + if (currentAbortController) { + currentAbortController.abort(); + currentAbortController = null; + } + updateSearchState(false, true, 0, "nip05"); } } catch (error) { - localError = error instanceof Error ? error.message : 'NIP-05 lookup failed'; + localError = + error instanceof Error ? error.message : "NIP-05 lookup failed"; relayStatuses = {}; - if (activeSub) { try { activeSub.stop(); } catch (e) { console.warn('Error stopping subscription:', e); } activeSub = null; } - if (currentAbortController) { currentAbortController.abort(); currentAbortController = null; } + if (activeSub) { + try { + activeSub.stop(); + } catch (e) { + console.warn("Error stopping subscription:", e); + } + activeSub = null; + } + if (currentAbortController) { + currentAbortController.abort(); + currentAbortController = null; + } updateSearchState(false, false, null, null); isProcessingSearch = false; currentProcessingSearchValue = null; @@ -102,26 +133,49 @@ console.warn("[Events] Event not found for query:", query); localError = "Event not found"; relayStatuses = {}; - if (activeSub) { try { activeSub.stop(); } catch (e) { console.warn('Error stopping subscription:', e); } activeSub = null; } - if (currentAbortController) { currentAbortController.abort(); currentAbortController = null; } + if (activeSub) { + try { + activeSub.stop(); + } catch (e) { + console.warn("Error stopping subscription:", e); + } + activeSub = null; + } + if (currentAbortController) { + currentAbortController.abort(); + currentAbortController = null; + } updateSearchState(false, false, null, null); } else { console.log("[Events] Event found:", foundEvent); handleFoundEvent(foundEvent); - updateSearchState(false, true, 1, 'event'); + updateSearchState(false, true, 1, "event"); } } catch (err) { console.error("[Events] Error fetching event:", err, "Query:", query); localError = "Error fetching event. Please check the ID and try again."; relayStatuses = {}; - if (activeSub) { try { activeSub.stop(); } catch (e) { console.warn('Error stopping subscription:', e); } activeSub = null; } - if (currentAbortController) { currentAbortController.abort(); currentAbortController = null; } + if (activeSub) { + try { + activeSub.stop(); + } catch (e) { + console.warn("Error stopping subscription:", e); + } + activeSub = null; + } + if (currentAbortController) { + currentAbortController.abort(); + currentAbortController = null; + } updateSearchState(false, false, null, null); isProcessingSearch = false; } } - async function handleSearchEvent(clearInput: boolean = true, queryOverride?: string) { + async function handleSearchEvent( + clearInput: boolean = true, + queryOverride?: string, + ) { if (searching) { console.log("EventSearch: Already searching, skipping"); return; @@ -131,7 +185,9 @@ updateSearchState(true); isResetting = false; isUserEditing = false; // Reset user editing flag when search starts - const query = (queryOverride !== undefined ? queryOverride : searchQuery).trim(); + const query = ( + queryOverride !== undefined ? queryOverride : searchQuery + ).trim(); if (!query) { updateSearchState(false, false, null, null); return; @@ -140,7 +196,7 @@ const dTag = query.slice(2).trim().toLowerCase(); if (dTag) { console.log("EventSearch: Processing d-tag search:", dTag); - navigateToSearch(dTag, 'd'); + navigateToSearch(dTag, "d"); updateSearchState(false, false, null, null); return; } @@ -148,23 +204,23 @@ if (query.toLowerCase().startsWith("t:")) { const searchTerm = query.slice(2).trim(); if (searchTerm) { - await handleSearchBySubscription('t', searchTerm); + await handleSearchBySubscription("t", searchTerm); return; } } if (query.toLowerCase().startsWith("n:")) { const searchTerm = query.slice(2).trim(); if (searchTerm) { - await handleSearchBySubscription('n', searchTerm); + await handleSearchBySubscription("n", searchTerm); return; } } - if (query.includes('@')) { + if (query.includes("@")) { await handleNip05Search(query); return; } if (clearInput) { - navigateToSearch(query, 'id'); + navigateToSearch(query, "id"); // Don't clear searchQuery here - let the effect handle it } await handleEventSearch(query); @@ -176,7 +232,7 @@ if (searching || isResetting || isUserEditing) { return; } - + if (dTagValue) { // If dTagValue is set, show it as "d:tag" in the search bar searchQuery = `d:${dTagValue}`; @@ -191,7 +247,13 @@ // Debounced effect to handle searchValue changes $effect(() => { - if (!searchValue || searching || isResetting || isProcessingSearch || isWaitingForSearchResult) { + if ( + !searchValue || + searching || + isResetting || + isProcessingSearch || + isWaitingForSearchResult + ) { return; } @@ -205,7 +267,7 @@ currentNevent = neventEncode(foundEvent, standardRelays); } catch {} try { - currentNaddr = getMatchingTags(foundEvent, 'd')[0]?.[1] + currentNaddr = getMatchingTags(foundEvent, "d")[0]?.[1] ? naddrEncode(foundEvent, standardRelays) : null; } catch {} @@ -214,11 +276,30 @@ } catch {} // Debug log for comparison - console.log('[EventSearch effect] searchValue:', searchValue, 'foundEvent.id:', currentEventId, 'foundEvent.pubkey:', foundEvent.pubkey, 'toNpub(pubkey):', currentNpub, 'foundEvent.kind:', foundEvent.kind, 'currentNaddr:', currentNaddr, 'currentNevent:', currentNevent); + console.log( + "[EventSearch effect] searchValue:", + searchValue, + "foundEvent.id:", + currentEventId, + "foundEvent.pubkey:", + foundEvent.pubkey, + "toNpub(pubkey):", + currentNpub, + "foundEvent.kind:", + foundEvent.kind, + "currentNaddr:", + currentNaddr, + "currentNevent:", + currentNevent, + ); // Also check if searchValue is an nprofile and matches the current event's pubkey let currentNprofile = null; - if (searchValue && searchValue.startsWith('nprofile1') && foundEvent.kind === 0) { + if ( + searchValue && + searchValue.startsWith("nprofile1") && + foundEvent.kind === 0 + ) { try { currentNprofile = nprofileEncode(foundEvent.pubkey, standardRelays); } catch {} @@ -261,10 +342,15 @@ // Simple effect to handle dTagValue changes $effect(() => { - if (dTagValue && !searching && !isResetting && dTagValue !== lastProcessedDTagValue) { + if ( + dTagValue && + !searching && + !isResetting && + dTagValue !== lastProcessedDTagValue + ) { console.log("EventSearch: Processing dTagValue:", dTagValue); lastProcessedDTagValue = dTagValue; - handleSearchBySubscription('d', dTagValue); + handleSearchBySubscription("d", dTagValue); } }); @@ -276,7 +362,12 @@ }); // Search utility functions - function updateSearchState(isSearching: boolean, completed: boolean = false, count: number | null = null, type: string | null = null) { + function updateSearchState( + isSearching: boolean, + completed: boolean = false, + count: number | null = null, + type: string | null = null, + ) { searching = isSearching; searchCompleted = completed; searchResultCount = count; @@ -297,32 +388,32 @@ currentProcessingSearchValue = null; lastSearchValue = null; updateSearchState(false, false, null, null); - + // Cancel ongoing search if (currentAbortController) { currentAbortController.abort(); currentAbortController = null; } - + // Clean up subscription if (activeSub) { try { activeSub.stop(); } catch (e) { - console.warn('Error stopping subscription:', e); + console.warn("Error stopping subscription:", e); } activeSub = null; } - + // Clear search results onSearchResults([], [], [], new Set(), new Set()); - + // Clear any pending timeout if (searchTimeout) { clearTimeout(searchTimeout); searchTimeout = null; } - + // Reset the flag after a short delay to allow effects to settle setTimeout(() => { isResetting = false; @@ -332,40 +423,40 @@ function handleFoundEvent(event: NDKEvent) { foundEvent = event; relayStatuses = {}; // Clear relay statuses when event is found - + // Stop any ongoing subscription if (activeSub) { try { activeSub.stop(); } catch (e) { - console.warn('Error stopping subscription:', e); + console.warn("Error stopping subscription:", e); } activeSub = null; } - + // Abort any ongoing fetch if (currentAbortController) { currentAbortController.abort(); currentAbortController = null; } - + // Clear search state searching = false; searchCompleted = true; searchResultCount = 1; - searchResultType = 'event'; - + searchResultType = "event"; + // Update last processed search value to prevent re-processing if (searchValue) { lastProcessedSearchValue = searchValue; lastSearchValue = searchValue; } - + // Reset processing flag isProcessingSearch = false; currentProcessingSearchValue = null; isWaitingForSearchResult = false; - + onEventFound(event); } @@ -379,8 +470,14 @@ } // Search handlers - async function handleSearchBySubscription(searchType: 'd' | 't' | 'n', searchTerm: string) { - console.log("EventSearch: Starting subscription search:", { searchType, searchTerm }); + async function handleSearchBySubscription( + searchType: "d" | "t" | "n", + searchTerm: string, + ) { + console.log("EventSearch: Starting subscription search:", { + searchType, + searchTerm, + }); isResetting = false; // Allow effects to run for new searches localError = null; updateSearchState(true); @@ -403,7 +500,7 @@ updatedResult.eventIds, updatedResult.addresses, updatedResult.searchType, - updatedResult.searchTerm + updatedResult.searchTerm, ); }, onSubscriptionCreated: (sub) => { @@ -412,9 +509,9 @@ activeSub.stop(); } activeSub = sub; - } + }, }, - currentAbortController.signal + currentAbortController.signal, ); console.log("EventSearch: Search completed:", result); onSearchResults( @@ -424,16 +521,19 @@ result.eventIds, result.addresses, result.searchType, - result.searchTerm + result.searchTerm, ); - const totalCount = result.events.length + result.secondOrder.length + result.tTagEvents.length; + const totalCount = + result.events.length + + result.secondOrder.length + + result.tTagEvents.length; relayStatuses = {}; // Clear relay statuses when search completes // Stop any ongoing subscription if (activeSub) { try { activeSub.stop(); } catch (e) { - console.warn('Error stopping subscription:', e); + console.warn("Error stopping subscription:", e); } activeSub = null; } @@ -447,20 +547,25 @@ currentProcessingSearchValue = null; isWaitingForSearchResult = false; } catch (error) { - if (error instanceof Error && error.message === 'Search cancelled') { + if (error instanceof Error && error.message === "Search cancelled") { isProcessingSearch = false; currentProcessingSearchValue = null; isWaitingForSearchResult = false; return; } console.error("EventSearch: Search failed:", error); - localError = error instanceof Error ? error.message : 'Search failed'; + localError = error instanceof Error ? error.message : "Search failed"; // Provide more specific error messages for different failure types if (error instanceof Error) { - if (error.message.includes('timeout') || error.message.includes('connection')) { - localError = 'Search timed out. The relays may be temporarily unavailable. Please try again.'; - } else if (error.message.includes('NDK not initialized')) { - localError = 'Nostr client not initialized. Please refresh the page and try again.'; + if ( + error.message.includes("timeout") || + error.message.includes("connection") + ) { + localError = + "Search timed out. The relays may be temporarily unavailable. Please try again."; + } else if (error.message.includes("NDK not initialized")) { + localError = + "Nostr client not initialized. Please refresh the page and try again."; } else { localError = `Search failed: ${error.message}`; } @@ -471,35 +576,35 @@ try { activeSub.stop(); } catch (e) { - console.warn('Error stopping subscription:', e); + console.warn("Error stopping subscription:", e); + } + activeSub = null; } - activeSub = null; - } - // Abort any ongoing fetch - if (currentAbortController) { - currentAbortController.abort(); - currentAbortController = null; + // Abort any ongoing fetch + if (currentAbortController) { + currentAbortController.abort(); + currentAbortController = null; + } + updateSearchState(false, false, null, null); + isProcessingSearch = false; + currentProcessingSearchValue = null; + isWaitingForSearchResult = false; } - updateSearchState(false, false, null, null); - isProcessingSearch = false; - currentProcessingSearchValue = null; - isWaitingForSearchResult = false; - } } function handleClear() { isResetting = true; - searchQuery = ''; + searchQuery = ""; isUserEditing = false; // Reset user editing flag resetSearchState(); - + // Clear URL parameters to reset the page - goto('', { + goto("", { replaceState: true, keepFocus: true, noScroll: true, }); - + // Ensure all search state is cleared searching = false; searchCompleted = false; @@ -512,17 +617,17 @@ currentProcessingSearchValue = null; lastSearchValue = null; isWaitingForSearchResult = false; - + // Clear any pending timeout if (searchTimeout) { clearTimeout(searchTimeout); searchTimeout = null; } - + if (onClear) { onClear(); } - + // Reset the flag after a short delay to allow effects to settle setTimeout(() => { isResetting = false; @@ -533,12 +638,16 @@ if (searchResultCount === 0) { return "Search completed. No results found."; } - - const typeLabel = searchResultType === 'n' ? 'profile' : - searchResultType === 'nip05' ? 'NIP-05 address' : 'event'; - const countLabel = searchResultType === 'n' ? 'profiles' : 'events'; - - return searchResultCount === 1 + + const typeLabel = + searchResultType === "n" + ? "profile" + : searchResultType === "nip05" + ? "NIP-05 address" + : "event"; + const countLabel = searchResultType === "n" ? "profiles" : "events"; + + return searchResultCount === 1 ? `Search completed. Found 1 ${typeLabel}.` : `Search completed. Found ${searchResultCount} ${countLabel}.`; } @@ -551,9 +660,10 @@ bind:value={searchQuery} placeholder="Enter event ID, nevent, naddr, d:tag-name, t:topic, or n:username..." class="flex-grow" - onkeydown={(e: KeyboardEvent) => e.key === "Enter" && handleSearchEvent(true)} - oninput={() => isUserEditing = true} - onblur={() => isUserEditing = false} + onkeydown={(e: KeyboardEvent) => + e.key === "Enter" && handleSearchEvent(true)} + oninput={() => (isUserEditing = true)} + onblur={() => (isUserEditing = false)} /> -
    {/if} -
    \ No newline at end of file +
    diff --git a/src/lib/components/publications/PublicationHeader.svelte b/src/lib/components/publications/PublicationHeader.svelte index 25dfdc4..36e76eb 100644 --- a/src/lib/components/publications/PublicationHeader.svelte +++ b/src/lib/components/publications/PublicationHeader.svelte @@ -1,8 +1,8 @@ {#if title != null && href != null} - + {#if image} -
    - -
    +
    + +
    {/if} -
    + diff --git a/src/lib/components/publications/PublicationSection.svelte b/src/lib/components/publications/PublicationSection.svelte index 7b24fb3..d5b5ecb 100644 --- a/src/lib/components/publications/PublicationSection.svelte +++ b/src/lib/components/publications/PublicationSection.svelte @@ -1,45 +1,54 @@ - -
    - {#await Promise.all([leafTitle, leafContent, leafHierarchy, publicationType, divergingBranches])} - +
    + {#await Promise.all( [leafTitle, leafContent, leafHierarchy, publicationType, divergingBranches], )} + {:then [leafTitle, leafContent, leafHierarchy, publicationType, divergingBranches]} {#each divergingBranches as [branch, depth]} - {@render sectionHeading(getMatchingTags(branch, 'title')[0]?.[1] ?? '', depth)} + {@render sectionHeading( + getMatchingTags(branch, "title")[0]?.[1] ?? "", + depth, + )} {/each} {#if leafTitle} {@const leafDepth = leafHierarchy.length - 1} {@render sectionHeading(leafTitle, leafDepth)} {/if} - {@render contentParagraph(leafContent.toString(), publicationType ?? 'article', false)} + {@render contentParagraph( + leafContent.toString(), + publicationType ?? "article", + false, + )} {/await}
    diff --git a/src/lib/components/publications/TableOfContents.svelte b/src/lib/components/publications/TableOfContents.svelte index 08097ed..e50bce0 100644 --- a/src/lib/components/publications/TableOfContents.svelte +++ b/src/lib/components/publications/TableOfContents.svelte @@ -1,22 +1,23 @@ - - diff --git a/src/lib/components/util/CardActions.svelte b/src/lib/components/util/CardActions.svelte index ef6b45e..28cab68 100644 --- a/src/lib/components/util/CardActions.svelte +++ b/src/lib/components/util/CardActions.svelte @@ -20,20 +20,42 @@ // Subscribe to userStore let user = $state($userStore); - userStore.subscribe(val => user = val); + userStore.subscribe((val) => (user = val)); // Derive metadata from event - let title = $derived(event.tags.find((t: string[]) => t[0] === 'title')?.[1] ?? ''); - let summary = $derived(event.tags.find((t: string[]) => t[0] === 'summary')?.[1] ?? ''); - let image = $derived(event.tags.find((t: string[]) => t[0] === 'image')?.[1] ?? null); - let author = $derived(event.tags.find((t: string[]) => t[0] === 'author')?.[1] ?? ''); - let originalAuthor = $derived(event.tags.find((t: string[]) => t[0] === 'original_author')?.[1] ?? null); - let version = $derived(event.tags.find((t: string[]) => t[0] === 'version')?.[1] ?? ''); - let source = $derived(event.tags.find((t: string[]) => t[0] === 'source')?.[1] ?? null); - let type = $derived(event.tags.find((t: string[]) => t[0] === 'type')?.[1] ?? null); - let language = $derived(event.tags.find((t: string[]) => t[0] === 'language')?.[1] ?? null); - let publisher = $derived(event.tags.find((t: string[]) => t[0] === 'publisher')?.[1] ?? null); - let identifier = $derived(event.tags.find((t: string[]) => t[0] === 'identifier')?.[1] ?? null); + let title = $derived( + event.tags.find((t: string[]) => t[0] === "title")?.[1] ?? "", + ); + let summary = $derived( + event.tags.find((t: string[]) => t[0] === "summary")?.[1] ?? "", + ); + let image = $derived( + event.tags.find((t: string[]) => t[0] === "image")?.[1] ?? null, + ); + let author = $derived( + event.tags.find((t: string[]) => t[0] === "author")?.[1] ?? "", + ); + let originalAuthor = $derived( + event.tags.find((t: string[]) => t[0] === "original_author")?.[1] ?? null, + ); + let version = $derived( + event.tags.find((t: string[]) => t[0] === "version")?.[1] ?? "", + ); + let source = $derived( + event.tags.find((t: string[]) => t[0] === "source")?.[1] ?? null, + ); + let type = $derived( + event.tags.find((t: string[]) => t[0] === "type")?.[1] ?? null, + ); + let language = $derived( + event.tags.find((t: string[]) => t[0] === "language")?.[1] ?? null, + ); + let publisher = $derived( + event.tags.find((t: string[]) => t[0] === "publisher")?.[1] ?? null, + ); + let identifier = $derived( + event.tags.find((t: string[]) => t[0] === "identifier")?.[1] ?? null, + ); // UI state let detailsModalOpen: boolean = $state(false); @@ -48,7 +70,7 @@ (() => { const isUserFeed = user.signedIn && $feedType === FeedType.UserRelays; const relays = isUserFeed ? user.relays.inbox : standardRelays; - + console.debug("[CardActions] Selected relays:", { eventId: event.id, isSignedIn: user.signedIn, @@ -100,7 +122,7 @@ * Navigates to the event details page */ function viewEventDetails() { - const nevent = getIdentifier('nevent'); + const nevent = getIdentifier("nevent"); goto(`/events?id=${encodeURIComponent(nevent)}`); } diff --git a/src/lib/components/util/ContainingIndexes.svelte b/src/lib/components/util/ContainingIndexes.svelte index 1c7da12..992115d 100644 --- a/src/lib/components/util/ContainingIndexes.svelte +++ b/src/lib/components/util/ContainingIndexes.svelte @@ -17,13 +17,19 @@ let lastEventId = $state(null); async function loadContainingIndexes() { - console.log("[ContainingIndexes] Loading containing indexes for event:", event.id); + console.log( + "[ContainingIndexes] Loading containing indexes for event:", + event.id, + ); loading = true; error = null; try { containingIndexes = await findContainingIndexEvents(event); - console.log("[ContainingIndexes] Found containing indexes:", containingIndexes.length); + console.log( + "[ContainingIndexes] Found containing indexes:", + containingIndexes.length, + ); } catch (err) { error = err instanceof Error diff --git a/src/lib/components/util/Details.svelte b/src/lib/components/util/Details.svelte index 9c6d312..ff9643a 100644 --- a/src/lib/components/util/Details.svelte +++ b/src/lib/components/util/Details.svelte @@ -4,37 +4,54 @@ import Interactions from "$components/util/Interactions.svelte"; import { P } from "flowbite-svelte"; import { getMatchingTags } from "$lib/utils/nostrUtils"; - import { goto } from '$app/navigation'; + import { goto } from "$app/navigation"; // isModal // - don't show interactions in modal view // - don't show all the details when _not_ in modal view let { event, isModal = false } = $props(); - let title: string = $derived(getMatchingTags(event, 'title')[0]?.[1]); + let title: string = $derived(getMatchingTags(event, "title")[0]?.[1]); let author: string = $derived( getMatchingTags(event, "author")[0]?.[1] ?? "unknown", ); - let version: string = $derived(getMatchingTags(event, 'version')[0]?.[1] ?? '1'); - let image: string = $derived(getMatchingTags(event, 'image')[0]?.[1] ?? null); - let summary: string = $derived(getMatchingTags(event, 'summary')[0]?.[1] ?? null); - let type: string = $derived(getMatchingTags(event, 'type')[0]?.[1] ?? null); - let language: string = $derived(getMatchingTags(event, 'l')[0]?.[1] ?? null); - let source: string = $derived(getMatchingTags(event, 'source')[0]?.[1] ?? null); - let publisher: string = $derived(getMatchingTags(event, 'published_by')[0]?.[1] ?? null); - let identifier: string = $derived(getMatchingTags(event, 'i')[0]?.[1] ?? null); - let hashtags: string[] = $derived(getMatchingTags(event, 't').map(tag => tag[1])); - let rootId: string = $derived(getMatchingTags(event, 'd')[0]?.[1] ?? null); + let version: string = $derived( + getMatchingTags(event, "version")[0]?.[1] ?? "1", + ); + let image: string = $derived(getMatchingTags(event, "image")[0]?.[1] ?? null); + let summary: string = $derived( + getMatchingTags(event, "summary")[0]?.[1] ?? null, + ); + let type: string = $derived(getMatchingTags(event, "type")[0]?.[1] ?? null); + let language: string = $derived(getMatchingTags(event, "l")[0]?.[1] ?? null); + let source: string = $derived( + getMatchingTags(event, "source")[0]?.[1] ?? null, + ); + let publisher: string = $derived( + getMatchingTags(event, "published_by")[0]?.[1] ?? null, + ); + let identifier: string = $derived( + getMatchingTags(event, "i")[0]?.[1] ?? null, + ); + let hashtags: string[] = $derived( + getMatchingTags(event, "t").map((tag) => tag[1]), + ); + let rootId: string = $derived(getMatchingTags(event, "d")[0]?.[1] ?? null); let kind = $derived(event.kind); - let authorTag: string = $derived(getMatchingTags(event, 'author')[0]?.[1] ?? ''); - let pTag: string = $derived(getMatchingTags(event, 'p')[0]?.[1] ?? ''); + let authorTag: string = $derived( + getMatchingTags(event, "author")[0]?.[1] ?? "", + ); + let pTag: string = $derived(getMatchingTags(event, "p")[0]?.[1] ?? ""); let originalAuthor: string = $derived( getMatchingTags(event, "p")[0]?.[1] ?? null, ); function isValidNostrPubkey(str: string): boolean { - return /^[a-f0-9]{64}$/i.test(str) || (str.startsWith('npub1') && str.length >= 59 && str.length <= 63); + return ( + /^[a-f0-9]{64}$/i.test(str) || + (str.startsWith("npub1") && str.length >= 59 && str.length <= 63) + ); } @@ -42,7 +59,9 @@ {#if !isModal}
    -

    {@render userBadge(event.pubkey, author)}

    +

    {@render userBadge(event.pubkey, author)}

    {/if} @@ -63,11 +82,11 @@

    by {#if authorTag && pTag && isValidNostrPubkey(pTag)} - {authorTag} {@render userBadge(pTag, '')} + {authorTag} {@render userBadge(pTag, "")} {:else if authorTag} {authorTag} {:else if pTag && isValidNostrPubkey(pTag)} - {@render userBadge(pTag, '')} + {@render userBadge(pTag, "")} {:else if originalAuthor !== null} {@render userBadge(originalAuthor, author)} {:else} @@ -111,7 +130,7 @@ {:else} Author: {/if} - {@render userBadge(event.pubkey, '')} + {@render userBadge(event.pubkey, "")}

    diff --git a/src/lib/components/util/Profile.svelte b/src/lib/components/util/Profile.svelte index 88ebe4c..7ba8f81 100644 --- a/src/lib/components/util/Profile.svelte +++ b/src/lib/components/util/Profile.svelte @@ -1,11 +1,15 @@ -
    -
    +
    +
    - +
    diff --git a/src/routes/about/+page.svelte b/src/routes/about/+page.svelte index caabdcb..72b4697 100644 --- a/src/routes/about/+page.svelte +++ b/src/routes/about/+page.svelte @@ -1,7 +1,7 @@
    @@ -700,18 +750,4 @@ {getResultMessage()}
    {/if} - - -
    -
    - {#each Object.entries(relayStatuses) as [relay, status]} - - {/each} -
    - {#if !foundEvent && hasActiveSearch} -
    - Searching relays... -
    - {/if} -
    diff --git a/src/lib/components/Login.svelte b/src/lib/components/Login.svelte deleted file mode 100644 index e24490d..0000000 --- a/src/lib/components/Login.svelte +++ /dev/null @@ -1,78 +0,0 @@ - - -
    - {#if $ndkSignedIn} - - {:else} - - -
    - - {#if signInFailed} -
    - {errorMessage} -
    - {/if} - -
    -
    - {/if} -
    diff --git a/src/lib/components/LoginMenu.svelte b/src/lib/components/LoginMenu.svelte index 8814333..4ac4222 100644 --- a/src/lib/components/LoginMenu.svelte +++ b/src/lib/components/LoginMenu.svelte @@ -11,10 +11,11 @@ loginWithNpub, logoutUser, } from "$lib/stores/userStore"; - import { get } from "svelte/store"; + import NDK, { NDKNip46Signer, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk"; import { onMount } from "svelte"; import { goto } from "$app/navigation"; + import NetworkStatus from "./NetworkStatus.svelte"; // UI state let isLoadingExtension: boolean = $state(false); @@ -36,13 +37,16 @@ } }); - // Subscribe to userStore - let user = $state(get(userStore)); - userStore.subscribe((val) => { - user = val; + // Use reactive user state from store + let user = $derived($userStore); + + // Handle user state changes with effects + $effect(() => { + const currentUser = user; + // Check for fallback flag when user state changes to signed in if ( - val.signedIn && + currentUser.signedIn && localStorage.getItem("alexandria/amber/fallback") === "1" && !showAmberFallback ) { @@ -53,7 +57,7 @@ } // Set up periodic check when user is signed in - if (val.signedIn && !fallbackCheckInterval) { + if (currentUser.signedIn && !fallbackCheckInterval) { fallbackCheckInterval = setInterval(() => { if ( localStorage.getItem("alexandria/amber/fallback") === "1" && @@ -65,7 +69,7 @@ showAmberFallback = true; } }, 500); // Check every 500ms - } else if (!val.signedIn && fallbackCheckInterval) { + } else if (!currentUser.signedIn && fallbackCheckInterval) { clearInterval(fallbackCheckInterval); fallbackCheckInterval = null; } @@ -249,6 +253,10 @@ > 📖 npub (read only) +
    +
    Network Status:
    + +
    {#if result} @@ -313,6 +321,10 @@ Unknown login method {/if} +
  • +
    Network Status:
    + +
  • -
  • - {#if isNav} -
  • - -
  • - {:else} - - {/if} - -
    -
    - - {/key} -
    - {/if} + + +
    +
    + {#if username} +

    {username}

    + {#if isNav}

    @{tag}

    {/if} + {:else} +

    Loading...

    + {/if} +
      +
    • + +
    • +
    • + +
    • +
    • + +
    • + {#if isNav} +
    • + +
    • + {:else} + + {/if} +
    +
    +
    +
    +
    diff --git a/src/lib/components/util/ViewPublicationLink.svelte b/src/lib/components/util/ViewPublicationLink.svelte index fbbc550..fd7538d 100644 --- a/src/lib/components/util/ViewPublicationLink.svelte +++ b/src/lib/components/util/ViewPublicationLink.svelte @@ -3,7 +3,8 @@ import { getMatchingTags } from "$lib/utils/nostrUtils"; import { naddrEncode } from "$lib/utils"; import { getEventType } from "$lib/utils/mime"; - import { standardRelays } from "$lib/consts"; + import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; + import { communityRelays } from "$lib/consts"; import { goto } from "$app/navigation"; let { event, className = "" } = $props<{ @@ -25,7 +26,7 @@ return null; } try { - return naddrEncode(event, standardRelays); + return naddrEncode(event, $activeInboxRelays); } catch { return null; } diff --git a/src/lib/consts.ts b/src/lib/consts.ts index 19955c5..4241d1d 100644 --- a/src/lib/consts.ts +++ b/src/lib/consts.ts @@ -1,45 +1,48 @@ export const wikiKind = 30818; export const indexKind = 30040; export const zettelKinds = [30041, 30818]; -export const communityRelay = "wss://theforest.nostr1.com"; -export const profileRelays = [ + +export const communityRelays = [ + "wss://theforest.nostr1.com", + //"wss://theforest.gitcitadel.eu" +]; + +export const searchRelays = [ "wss://profiles.nostr1.com", "wss://aggr.nostr.land", "wss://relay.noswhere.com", -]; -export const standardRelays = [ - "wss://thecitadel.nostr1.com", - "wss://theforest.nostr1.com", - "wss://profiles.nostr1.com", - // Removed gitcitadel.nostr1.com as it's causing connection issues - //'wss://thecitadel.gitcitadel.eu', - //'wss://theforest.gitcitadel.eu', + "wss://nostr.wine", ]; -// Non-auth relays for anonymous users -export const anonymousRelays = [ - "wss://thecitadel.nostr1.com", +export const secondaryRelays = [ "wss://theforest.nostr1.com", - "wss://profiles.nostr1.com", - "wss://freelay.sovbit.host", -]; -export const fallbackRelays = [ - "wss://purplepag.es", - "wss://indexer.coracle.social", - "wss://relay.noswhere.com", - "wss://aggr.nostr.land", + //"wss://theforest.gitcitadel.eu" + "wss://thecitadel.nostr1.com", + //"wss://thecitadel.gitcitadel.eu", "wss://nostr.land", "wss://nostr.wine", "wss://nostr.sovbit.host", - "wss://freelay.sovbit.host", "wss://nostr21.com", - "wss://greensoul.space", - "wss://relay.damus.io", - "wss://relay.nostr.band", +]; + +export const anonymousRelays = [ + "wss://freelay.sovbit.host", + "wss://thecitadel.nostr1.com" +]; + +export const lowbandwidthRelays = [ + "wss://theforest.nostr1.com", + "wss://thecitadel.nostr1.com", + "wss://aggr.nostr.land" +]; + +export const localRelays = [ + "wss://localhost:8080", + "wss://localhost:4869" ]; export enum FeedType { - StandardRelays = "standard", + CommunityRelays = "standard", UserRelays = "user", } diff --git a/src/lib/navigator/EventNetwork/utils/networkBuilder.ts b/src/lib/navigator/EventNetwork/utils/networkBuilder.ts index 83537c3..d62f189 100644 --- a/src/lib/navigator/EventNetwork/utils/networkBuilder.ts +++ b/src/lib/navigator/EventNetwork/utils/networkBuilder.ts @@ -8,8 +8,9 @@ import type { NDKEvent } from "@nostr-dev-kit/ndk"; import type { NetworkNode, NetworkLink, GraphData, GraphState } from "../types"; import { nip19 } from "nostr-tools"; -import { standardRelays } from "$lib/consts"; +import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; import { getMatchingTags } from "$lib/utils/nostrUtils"; +import { get } from "svelte/store"; // Configuration const DEBUG = false; // Set to true to enable debug logging @@ -71,13 +72,13 @@ export function createNetworkNode( pubkey: event.pubkey, identifier: dTag, kind: event.kind, - relays: standardRelays, + relays: [...get(activeInboxRelays), ...get(activeOutboxRelays)], }); // Create nevent (NIP-19 event reference) for the event node.nevent = nip19.neventEncode({ id: event.id, - relays: standardRelays, + relays: [...get(activeInboxRelays), ...get(activeOutboxRelays)], kind: event.kind, }); } catch (error) { diff --git a/src/lib/ndk.ts b/src/lib/ndk.ts index 4e319b8..cd13df2 100644 --- a/src/lib/ndk.ts +++ b/src/lib/ndk.ts @@ -8,15 +8,29 @@ import NDK, { } from "@nostr-dev-kit/ndk"; import { get, writable, type Writable } from "svelte/store"; import { - fallbackRelays, + secondaryRelays, FeedType, loginStorageKey, - standardRelays, + communityRelays, anonymousRelays, + searchRelays, } from "./consts"; -import { feedType } from "./stores"; +import { + buildCompleteRelaySet, + testRelayConnection, + discoverLocalRelays, + getUserLocalRelays, + getUserBlockedRelays, + getUserOutboxRelays, + deduplicateRelayUrls, +} from "./utils/relay_management"; + +// Re-export testRelayConnection for components that need it +export { testRelayConnection }; +import { startNetworkMonitoring, NetworkCondition } from "./utils/network_detection"; import { userStore } from "./stores/userStore"; import { userPubkey } from "$lib/stores/authStore.Svelte"; +import { startNetworkStatusMonitoring, stopNetworkStatusMonitoring } from "./stores/networkStore"; export const ndkInstance: Writable = writable(); export const ndkSignedIn = writable(false); @@ -24,6 +38,10 @@ export const activePubkey = writable(null); export const inboxRelays = writable([]); export const outboxRelays = writable([]); +// New relay management stores +export const activeInboxRelays = writable([]); +export const activeOutboxRelays = writable([]); + /** * Custom authentication policy that handles NIP-42 authentication manually * when the default NDK authentication fails @@ -207,83 +225,7 @@ export function checkWebSocketSupport(): void { } } -/** - * Tests connection to a relay and returns connection status - * @param relayUrl The relay URL to test - * @param ndk The NDK instance - * @returns Promise that resolves to connection status - */ -export async function testRelayConnection( - relayUrl: string, - ndk: NDK, -): Promise<{ - connected: boolean; - requiresAuth: boolean; - error?: string; - actualUrl?: string; -}> { - return new Promise((resolve) => { - console.debug(`[NDK.ts] Testing connection to: ${relayUrl}`); - - // Ensure the URL is using wss:// protocol - const secureUrl = ensureSecureWebSocket(relayUrl); - - const relay = new NDKRelay(secureUrl, undefined, new NDK()); - let authRequired = false; - let connected = false; - let error: string | undefined; - let actualUrl: string | undefined; - - const timeout = setTimeout(() => { - relay.disconnect(); - resolve({ - connected: false, - requiresAuth: authRequired, - error: "Connection timeout", - actualUrl, - }); - }, 5000); - relay.on("connect", () => { - console.debug(`[NDK.ts] Connected to ${secureUrl}`); - connected = true; - actualUrl = secureUrl; - clearTimeout(timeout); - relay.disconnect(); - resolve({ - connected: true, - requiresAuth: authRequired, - error, - actualUrl, - }); - }); - - relay.on("notice", (message: string) => { - if (message.includes("auth-required")) { - authRequired = true; - console.debug(`[NDK.ts] ${secureUrl} requires authentication`); - } - }); - - relay.on("disconnect", () => { - if (!connected) { - error = "Connection failed"; - console.error(`[NDK.ts] Failed to connect to ${secureUrl}`); - clearTimeout(timeout); - resolve({ - connected: false, - requiresAuth: authRequired, - error, - actualUrl, - }); - } - }); - - // Log the actual WebSocket URL being used - console.debug(`[NDK.ts] Attempting connection to: ${secureUrl}`); - relay.connect(); - }); -} /** * Gets the user's pubkey from local storage, if it exists. @@ -433,98 +375,180 @@ function createRelayWithAuth(url: string, ndk: NDK): NDKRelay { return relay; } -export function getActiveRelays(ndk: NDK): NDKRelaySet { + + + + +/** + * Gets the active relay set for the current user + * @param ndk NDK instance + * @returns Promise that resolves to object with inbox and outbox relay arrays + */ +export async function getActiveRelaySet(ndk: NDK): Promise<{ inboxRelays: string[]; outboxRelays: string[] }> { const user = get(userStore); + + if (user.signedIn && user.ndkUser) { + return await buildCompleteRelaySet(ndk, user.ndkUser); + } else { + return await buildCompleteRelaySet(ndk, null); + } +} - // Filter out problematic relays that are known to cause connection issues - const filterProblematicRelays = (relays: string[]) => { - return relays.filter((relay) => { - // Filter out gitcitadel.nostr1.com which is causing connection issues - if (relay.includes("gitcitadel.nostr1.com")) { - console.warn(`[NDK.ts] Filtering out problematic relay: ${relay}`); - return false; +/** + * Updates the active relay stores and NDK pool with new relay URLs + * @param ndk NDK instance + */ +export async function updateActiveRelayStores(ndk: NDK): Promise { + try { + // Get the active relay set from the relay management system + const relaySet = await getActiveRelaySet(ndk); + + // Update the stores with the new relay configuration + activeInboxRelays.set(relaySet.inboxRelays); + activeOutboxRelays.set(relaySet.outboxRelays); + + // Add relays to NDK pool (deduplicated) + const allRelayUrls = deduplicateRelayUrls([...relaySet.inboxRelays, ...relaySet.outboxRelays]); + for (const url of allRelayUrls) { + try { + const relay = createRelayWithAuth(url, ndk); + ndk.pool?.addRelay(relay); + } catch (error) { + // Silently ignore relay addition failures } - return true; - }); - }; + } + } catch (error) { + // Silently ignore relay store update errors + } +} - return get(feedType) === FeedType.UserRelays && user.signedIn - ? new NDKRelaySet( - new Set( - filterProblematicRelays(user.relays.inbox).map( - (relay) => - new NDKRelay(relay, NDKRelayAuthPolicies.signIn({ ndk }), ndk), - ), - ), - ndk, - ) - : new NDKRelaySet( - new Set( - filterProblematicRelays(standardRelays).map( - (relay) => - new NDKRelay(relay, NDKRelayAuthPolicies.signIn({ ndk }), ndk), - ), - ), - ndk, - ); +/** + * Logs the current relay configuration to console + */ +export function logCurrentRelayConfiguration(): void { + const inboxRelays = get(activeInboxRelays); + const outboxRelays = get(activeOutboxRelays); + + console.log('🔌 Current Relay Configuration:'); + console.log('📥 Inbox Relays:', inboxRelays); + console.log('📤 Outbox Relays:', outboxRelays); + console.log(`📊 Total: ${inboxRelays.length} inbox, ${outboxRelays.length} outbox`); } /** - * Initializes an instance of NDK, and connects it to the logged-in user's preferred relay set - * (if available), or to Alexandria's standard relay set. - * @returns The initialized NDK instance. + * Updates relay stores when user state changes + * @param ndk NDK instance */ -export function initNdk(): NDK { - const startingPubkey = getPersistedLogin(); - const [startingInboxes, _] = - startingPubkey != null - ? getPersistedRelays(new NDKUser({ pubkey: startingPubkey })) - : [null, null]; +export async function refreshRelayStores(ndk: NDK): Promise { + console.debug('[NDK.ts] Refreshing relay stores due to user state change'); + await updateActiveRelayStores(ndk); +} + +/** + * Updates relay stores when network condition changes + * @param ndk NDK instance + */ +export async function refreshRelayStoresOnNetworkChange(ndk: NDK): Promise { + console.debug('[NDK.ts] Refreshing relay stores due to network condition change'); + await updateActiveRelayStores(ndk); +} + +/** + * Starts network monitoring for relay optimization + * @param ndk NDK instance + */ +export function startNetworkMonitoringForRelays(ndk: NDK): void { + // Use centralized network monitoring instead of separate monitoring + startNetworkStatusMonitoring(); +} - // Ensure all relay URLs use secure WebSocket protocol - const secureRelayUrls = ( - startingInboxes != null - ? Array.from(startingInboxes.values()) - : anonymousRelays - ).map(ensureSecureWebSocket); +/** + * Creates NDKRelaySet from relay URLs with proper authentication + * @param relayUrls Array of relay URLs + * @param ndk NDK instance + * @returns NDKRelaySet + */ +function createRelaySetFromUrls(relayUrls: string[], ndk: NDK): NDKRelaySet { + const relays = relayUrls.map(url => + new NDKRelay(url, NDKRelayAuthPolicies.signIn({ ndk }), ndk) + ); + + return new NDKRelaySet(new Set(relays), ndk); +} - console.debug("[NDK.ts] Initializing NDK with relay URLs:", secureRelayUrls); +/** + * Gets the active relay set as NDKRelaySet for use in queries + * @param ndk NDK instance + * @param useInbox Whether to use inbox relays (true) or outbox relays (false) + * @returns Promise that resolves to NDKRelaySet + */ +export async function getActiveRelaySetAsNDKRelaySet( + ndk: NDK, + useInbox: boolean = true +): Promise { + const relaySet = await getActiveRelaySet(ndk); + const urls = useInbox ? relaySet.inboxRelays : relaySet.outboxRelays; + + return createRelaySetFromUrls(urls, ndk); +} + +/** + * Initializes an instance of NDK with the new relay management system + * @returns The initialized NDK instance + */ +export function initNdk(): NDK { + console.debug("[NDK.ts] Initializing NDK with new relay management system"); const ndk = new NDK({ - autoConnectUserRelays: true, + autoConnectUserRelays: false, // We'll manage relays manually enableOutboxModel: true, - explicitRelayUrls: secureRelayUrls, }); // Set up custom authentication policy ndk.relayAuthDefaultPolicy = NDKRelayAuthPolicies.signIn({ ndk }); - // Connect with better error handling - ndk - .connect() - .then(() => { + // Connect with better error handling and reduced retry attempts + let retryCount = 0; + const maxRetries = 2; + + const attemptConnection = async () => { + try { + await ndk.connect(); console.debug("[NDK.ts] NDK connected successfully"); - }) - .catch((error) => { - console.error("[NDK.ts] Failed to connect NDK:", error); - // Try to reconnect after a delay - setTimeout(() => { - console.debug("[NDK.ts] Attempting to reconnect..."); - ndk.connect().catch((retryError) => { - console.error("[NDK.ts] Reconnection failed:", retryError); - }); - }, 5000); - }); + // Update relay stores after connection + await updateActiveRelayStores(ndk); + // Start network monitoring for relay optimization + startNetworkMonitoringForRelays(ndk); + } catch (error) { + console.warn("[NDK.ts] Failed to connect NDK:", error); + + // Only retry a limited number of times + if (retryCount < maxRetries) { + retryCount++; + console.debug(`[NDK.ts] Attempting to reconnect (${retryCount}/${maxRetries})...`); + setTimeout(attemptConnection, 3000); + } else { + console.warn("[NDK.ts] Max retries reached, continuing with limited functionality"); + // Still try to update relay stores even if connection failed + try { + await updateActiveRelayStores(ndk); + startNetworkMonitoringForRelays(ndk); + } catch (storeError) { + console.warn("[NDK.ts] Failed to update relay stores:", storeError); + } + } + } + }; + + attemptConnection(); return ndk; } /** - * Signs in with a NIP-07 browser extension, and determines the user's preferred inbox and outbox - * relays. - * @returns The user's profile, if it is available. - * @throws If sign-in fails. This may because there is no accessible NIP-07 extension, or because - * NDK is unable to fetch the user's profile or relay lists. + * Signs in with a NIP-07 browser extension using the new relay management system + * @returns The user's profile, if it is available + * @throws If sign-in fails */ export async function loginWithExtension( pubkey?: string, @@ -542,23 +566,10 @@ export async function loginWithExtension( activePubkey.set(signerUser.pubkey); userPubkey.set(signerUser.pubkey); - const [persistedInboxes, persistedOutboxes] = - getPersistedRelays(signerUser); - for (const relay of persistedInboxes) { - ndk.addExplicitRelay(relay); - } - const user = ndk.getUser({ pubkey: signerUser.pubkey }); - const [inboxes, outboxes] = await getUserPreferredRelays(ndk, user); - - inboxRelays.set( - Array.from(inboxes ?? persistedInboxes).map((relay) => relay.url), - ); - outboxRelays.set( - Array.from(outboxes ?? persistedOutboxes).map((relay) => relay.url), - ); - - persistRelays(signerUser, inboxes, outboxes); + + // Update relay stores with the new system + await updateActiveRelayStores(ndk); ndk.signer = signer; ndk.activeUser = user; @@ -582,73 +593,17 @@ export function logout(user: NDKUser): void { activePubkey.set(null); userPubkey.set(null); ndkSignedIn.set(false); - ndkInstance.set(initNdk()); // Re-initialize with anonymous instance + + // Clear relay stores + activeInboxRelays.set([]); + activeOutboxRelays.set([]); + + // Stop network monitoring + stopNetworkStatusMonitoring(); + + // Re-initialize with anonymous instance + const newNdk = initNdk(); + ndkInstance.set(newNdk); } -/** - * Fetches the user's NIP-65 relay list, if one can be found, and returns the inbox and outbox - * relay sets. - * @returns A tuple of relay sets of the form `[inboxRelays, outboxRelays]`. - */ -export async function getUserPreferredRelays( - ndk: NDK, - user: NDKUser, - fallbacks: readonly string[] = fallbackRelays, -): Promise<[Set, Set]> { - const relayList = await ndk.fetchEvent( - { - kinds: [10002], - authors: [user.pubkey], - }, - { - groupable: false, - skipVerification: false, - skipValidation: false, - }, - NDKRelaySet.fromRelayUrls(fallbacks, ndk), - ); - - const inboxRelays = new Set(); - const outboxRelays = new Set(); - // Filter out problematic relays - const filterProblematicRelay = (url: string): boolean => { - if (url.includes("gitcitadel.nostr1.com")) { - console.warn( - `[NDK.ts] Filtering out problematic relay from user preferences: ${url}`, - ); - return false; - } - return true; - }; - - if (relayList == null) { - const relayMap = await window.nostr?.getRelays?.(); - Object.entries(relayMap ?? {}).forEach(([url, relayType]) => { - if (filterProblematicRelay(url)) { - const relay = createRelayWithAuth(url, ndk); - if (relayType.read) inboxRelays.add(relay); - if (relayType.write) outboxRelays.add(relay); - } - }); - } else { - relayList.tags.forEach((tag) => { - if (filterProblematicRelay(tag[1])) { - switch (tag[0]) { - case "r": - inboxRelays.add(createRelayWithAuth(tag[1], ndk)); - break; - case "w": - outboxRelays.add(createRelayWithAuth(tag[1], ndk)); - break; - default: - inboxRelays.add(createRelayWithAuth(tag[1], ndk)); - outboxRelays.add(createRelayWithAuth(tag[1], ndk)); - break; - } - } - }); - } - - return [inboxRelays, outboxRelays]; -} diff --git a/src/lib/stores.ts b/src/lib/stores.ts index ae38008..3315022 100644 --- a/src/lib/stores.ts +++ b/src/lib/stores.ts @@ -1,11 +1,11 @@ -import { readable, writable } from "svelte/store"; -import { FeedType } from "./consts.ts"; +import { writable } from "svelte/store"; -export let idList = writable([]); +// The old feedType store is no longer needed since we use the new relay management system +// All relay selection is now handled by the activeInboxRelays and activeOutboxRelays stores in ndk.ts -export let alexandriaKinds = readable([30040, 30041, 30818]); +export let idList = writable([]); -export let feedType = writable(FeedType.StandardRelays); +export let alexandriaKinds = writable([30040, 30041, 30818]); export interface PublicationLayoutVisibility { toc: boolean; diff --git a/src/lib/stores/networkStore.ts b/src/lib/stores/networkStore.ts new file mode 100644 index 0000000..981b0c9 --- /dev/null +++ b/src/lib/stores/networkStore.ts @@ -0,0 +1,55 @@ +import { writable, type Writable } from 'svelte/store'; +import { detectNetworkCondition, NetworkCondition, startNetworkMonitoring } from '$lib/utils/network_detection'; + +// Network status store +export const networkCondition = writable(NetworkCondition.ONLINE); +export const isNetworkChecking = writable(false); + +// Network monitoring state +let stopNetworkMonitoring: (() => void) | null = null; + +/** + * Starts network monitoring if not already running + */ +export function startNetworkStatusMonitoring(): void { + if (stopNetworkMonitoring) { + return; // Already monitoring + } + + console.debug('[networkStore.ts] Starting network status monitoring'); + + stopNetworkMonitoring = startNetworkMonitoring( + (condition: NetworkCondition) => { + console.debug(`[networkStore.ts] Network condition changed to: ${condition}`); + networkCondition.set(condition); + }, + 60000 // Check every 60 seconds to reduce spam + ); +} + +/** + * Stops network monitoring + */ +export function stopNetworkStatusMonitoring(): void { + if (stopNetworkMonitoring) { + console.debug('[networkStore.ts] Stopping network status monitoring'); + stopNetworkMonitoring(); + stopNetworkMonitoring = null; + } +} + +/** + * Manually check network status (for immediate updates) + */ +export async function checkNetworkStatus(): Promise { + try { + isNetworkChecking.set(true); + const condition = await detectNetworkCondition(); + networkCondition.set(condition); + } catch (error) { + console.warn('[networkStore.ts] Failed to check network status:', error); + networkCondition.set(NetworkCondition.OFFLINE); + } finally { + isNetworkChecking.set(false); + } +} \ No newline at end of file diff --git a/src/lib/stores/relayStore.ts b/src/lib/stores/relayStore.ts deleted file mode 100644 index 2c038c7..0000000 --- a/src/lib/stores/relayStore.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { writable } from "svelte/store"; - -// Initialize with empty array, will be populated from user preferences -export const userRelays = writable([]); diff --git a/src/lib/stores/userStore.ts b/src/lib/stores/userStore.ts index e5dbe8b..3275e23 100644 --- a/src/lib/stores/userStore.ts +++ b/src/lib/stores/userStore.ts @@ -8,8 +8,8 @@ import { NDKRelay, } from "@nostr-dev-kit/ndk"; import { getUserMetadata } from "$lib/utils/nostrUtils"; -import { ndkInstance } from "$lib/ndk"; -import { loginStorageKey, fallbackRelays } from "$lib/consts"; +import { ndkInstance, activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; +import { loginStorageKey } from "$lib/consts"; import { nip19 } from "nostr-tools"; export interface UserState { @@ -70,7 +70,7 @@ function getPersistedRelays(user: NDKUser): [Set, Set] { async function getUserPreferredRelays( ndk: any, user: NDKUser, - fallbacks: readonly string[] = fallbackRelays, + fallbacks: readonly string[] = [...get(activeInboxRelays), ...get(activeOutboxRelays)], ): Promise<[Set, Set]> { const relayList = await ndk.fetchEvent( { diff --git a/src/lib/utils/ZettelParser.ts b/src/lib/utils/ZettelParser.ts index 24b0891..42d1b77 100644 --- a/src/lib/utils/ZettelParser.ts +++ b/src/lib/utils/ZettelParser.ts @@ -1,7 +1,7 @@ import { ndkInstance } from "$lib/ndk"; import { signEvent, getEventHash } from "$lib/utils/nostrUtils"; import { getMimeTags } from "$lib/utils/mime"; -import { standardRelays } from "$lib/consts"; +import { communityRelays } from "$lib/consts"; import { nip19 } from "nostr-tools"; export interface ZettelSection { diff --git a/src/lib/utils/community_checker.ts b/src/lib/utils/community_checker.ts index 56c9030..7e6ea11 100644 --- a/src/lib/utils/community_checker.ts +++ b/src/lib/utils/community_checker.ts @@ -1,4 +1,4 @@ -import { communityRelay } from "$lib/consts"; +import { communityRelays } from "$lib/consts"; import { RELAY_CONSTANTS, SEARCH_LIMITS } from "./search_constants"; // Cache for pubkeys with kind 1 events on communityRelay @@ -13,40 +13,54 @@ export async function checkCommunity(pubkey: string): Promise { } try { - const relayUrl = communityRelay; - const ws = new WebSocket(relayUrl); - return await new Promise((resolve) => { - ws.onopen = () => { - ws.send( - JSON.stringify([ - "REQ", - RELAY_CONSTANTS.COMMUNITY_REQUEST_ID, - { - kinds: RELAY_CONSTANTS.COMMUNITY_REQUEST_KINDS, - authors: [pubkey], - limit: SEARCH_LIMITS.COMMUNITY_CHECK, - }, - ]), - ); - }; - ws.onmessage = (event) => { - const data = JSON.parse(event.data); - if (data[0] === "EVENT" && data[2]?.kind === 1) { - communityCache.set(pubkey, true); - ws.close(); - resolve(true); - } else if (data[0] === "EOSE") { - communityCache.set(pubkey, false); - ws.close(); - resolve(false); + // Try each community relay until we find one that works + for (const relayUrl of communityRelays) { + try { + const ws = new WebSocket(relayUrl); + const result = await new Promise((resolve) => { + ws.onopen = () => { + ws.send( + JSON.stringify([ + "REQ", + RELAY_CONSTANTS.COMMUNITY_REQUEST_ID, + { + kinds: RELAY_CONSTANTS.COMMUNITY_REQUEST_KINDS, + authors: [pubkey], + limit: SEARCH_LIMITS.COMMUNITY_CHECK, + }, + ]), + ); + }; + ws.onmessage = (event) => { + const data = JSON.parse(event.data); + if (data[0] === "EVENT" && data[2]?.kind === 1) { + communityCache.set(pubkey, true); + ws.close(); + resolve(true); + } else if (data[0] === "EOSE") { + communityCache.set(pubkey, false); + ws.close(); + resolve(false); + } + }; + ws.onerror = () => { + ws.close(); + resolve(false); + }; + }); + + if (result) { + return true; } - }; - ws.onerror = () => { - communityCache.set(pubkey, false); - ws.close(); - resolve(false); - }; - }); + } catch { + // Continue to next relay if this one fails + continue; + } + } + + // If we get here, no relay found the user + communityCache.set(pubkey, false); + return false; } catch { communityCache.set(pubkey, false); return false; diff --git a/src/lib/utils/network_detection.ts b/src/lib/utils/network_detection.ts new file mode 100644 index 0000000..1e812db --- /dev/null +++ b/src/lib/utils/network_detection.ts @@ -0,0 +1,189 @@ +import { deduplicateRelayUrls } from './relay_management'; + +/** + * Network conditions for relay selection + */ +export enum NetworkCondition { + ONLINE = 'online', + SLOW = 'slow', + OFFLINE = 'offline' +} + +/** + * Network connectivity test endpoints + */ +const NETWORK_ENDPOINTS = [ + 'https://www.google.com/favicon.ico', + 'https://httpbin.org/status/200', + 'https://api.github.com/zen' +]; + +/** + * Detects if the network is online using more reliable endpoints + * @returns Promise that resolves to true if online, false otherwise + */ +export async function isNetworkOnline(): Promise { + for (const endpoint of NETWORK_ENDPOINTS) { + try { + // Use a simple fetch without HEAD method to avoid CORS issues + const response = await fetch(endpoint, { + method: 'GET', + cache: 'no-cache', + signal: AbortSignal.timeout(3000), + mode: 'no-cors' // Use no-cors mode to avoid CORS issues + }); + // With no-cors mode, we can't check response.ok, so we assume success if no error + return true; + } catch (error) { + console.debug(`[network_detection.ts] Failed to reach ${endpoint}:`, error); + continue; + } + } + + console.debug('[network_detection.ts] All network endpoints failed'); + return false; +} + +/** + * Tests network speed by measuring response time + * @returns Promise that resolves to network speed in milliseconds + */ +export async function testNetworkSpeed(): Promise { + const startTime = performance.now(); + + for (const endpoint of NETWORK_ENDPOINTS) { + try { + await fetch(endpoint, { + method: 'GET', + cache: 'no-cache', + signal: AbortSignal.timeout(5000), + mode: 'no-cors' // Use no-cors mode to avoid CORS issues + }); + + const endTime = performance.now(); + return endTime - startTime; + } catch (error) { + console.debug(`[network_detection.ts] Speed test failed for ${endpoint}:`, error); + continue; + } + } + + console.debug('[network_detection.ts] Network speed test failed for all endpoints'); + return Infinity; // Very slow if it fails +} + +/** + * Determines network condition based on connectivity and speed + * @returns Promise that resolves to NetworkCondition + */ +export async function detectNetworkCondition(): Promise { + const isOnline = await isNetworkOnline(); + + if (!isOnline) { + console.debug('[network_detection.ts] Network condition: OFFLINE'); + return NetworkCondition.OFFLINE; + } + + const speed = await testNetworkSpeed(); + + // Consider network slow if response time > 2000ms + if (speed > 2000) { + console.debug(`[network_detection.ts] Network condition: SLOW (${speed.toFixed(0)}ms)`); + return NetworkCondition.SLOW; + } + + console.debug(`[network_detection.ts] Network condition: ONLINE (${speed.toFixed(0)}ms)`); + return NetworkCondition.ONLINE; +} + +/** + * Gets the appropriate relay sets based on network condition + * @param networkCondition The detected network condition + * @param discoveredLocalRelays Array of discovered local relay URLs + * @param lowbandwidthRelays Array of low bandwidth relay URLs + * @param fullRelaySet The complete relay set for normal conditions + * @returns Object with inbox and outbox relay arrays + */ +export function getRelaySetForNetworkCondition( + networkCondition: NetworkCondition, + discoveredLocalRelays: string[], + lowbandwidthRelays: string[], + fullRelaySet: { inboxRelays: string[]; outboxRelays: string[] } +): { inboxRelays: string[]; outboxRelays: string[] } { + switch (networkCondition) { + case NetworkCondition.OFFLINE: + // When offline, use local relays if available, otherwise rely on cache + // This will be improved when IndexedDB local relay is implemented + if (discoveredLocalRelays.length > 0) { + console.debug('[network_detection.ts] Using local relays (offline)'); + return { + inboxRelays: discoveredLocalRelays, + outboxRelays: discoveredLocalRelays + }; + } else { + console.debug('[network_detection.ts] No local relays available, will rely on cache (offline)'); + return { + inboxRelays: [], + outboxRelays: [] + }; + } + + case NetworkCondition.SLOW: + // Local relays + low bandwidth relays when slow (deduplicated) + console.debug('[network_detection.ts] Using local + low bandwidth relays (slow network)'); + const slowInboxRelays = deduplicateRelayUrls([...discoveredLocalRelays, ...lowbandwidthRelays]); + const slowOutboxRelays = deduplicateRelayUrls([...discoveredLocalRelays, ...lowbandwidthRelays]); + return { + inboxRelays: slowInboxRelays, + outboxRelays: slowOutboxRelays + }; + + case NetworkCondition.ONLINE: + default: + // Full relay set when online + console.debug('[network_detection.ts] Using full relay set (online)'); + return fullRelaySet; + } +} + +/** + * Starts periodic network monitoring with reduced frequency to avoid spam + * @param onNetworkChange Callback function called when network condition changes + * @param checkInterval Interval in milliseconds between network checks (default: 60 seconds) + * @returns Function to stop the monitoring + */ +export function startNetworkMonitoring( + onNetworkChange: (condition: NetworkCondition) => void, + checkInterval: number = 60000 // Increased to 60 seconds to reduce spam +): () => void { + let lastCondition: NetworkCondition | null = null; + let intervalId: number | null = null; + + const checkNetwork = async () => { + try { + const currentCondition = await detectNetworkCondition(); + + if (currentCondition !== lastCondition) { + console.debug(`[network_detection.ts] Network condition changed: ${lastCondition} -> ${currentCondition}`); + lastCondition = currentCondition; + onNetworkChange(currentCondition); + } + } catch (error) { + console.warn('[network_detection.ts] Network monitoring error:', error); + } + }; + + // Initial check + checkNetwork(); + + // Set up periodic monitoring + intervalId = window.setInterval(checkNetwork, checkInterval); + + // Return function to stop monitoring + return () => { + if (intervalId !== null) { + clearInterval(intervalId); + intervalId = null; + } + }; +} \ No newline at end of file diff --git a/src/lib/utils/nostrEventService.ts b/src/lib/utils/nostrEventService.ts index 5efb37b..e7d437f 100644 --- a/src/lib/utils/nostrEventService.ts +++ b/src/lib/utils/nostrEventService.ts @@ -1,11 +1,13 @@ import { nip19 } from "nostr-tools"; import { getEventHash, signEvent, prefixNostrAddresses } from "./nostrUtils"; -import { standardRelays, fallbackRelays } from "$lib/consts"; -import { userRelays } from "$lib/stores/relayStore"; +import { communityRelays, secondaryRelays } from "$lib/consts"; import { get } from "svelte/store"; import { goto } from "$app/navigation"; import type { NDKEvent } from "./nostrUtils"; import { EVENT_KINDS, TIME_CONSTANTS, TIMEOUTS } from "./search_constants"; +import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; +import { ndkInstance } from "$lib/ndk"; +import { NDKRelaySet } from "@nostr-dev-kit/ndk"; export interface RootEventInfo { rootId: string; @@ -358,82 +360,44 @@ export async function createSignedEvent( } /** - * Publish event to a single relay - */ -async function publishToRelay( - relayUrl: string, - signedEvent: any, -): Promise { - const ws = new WebSocket(relayUrl); - - return new Promise((resolve, reject) => { - const timeout = setTimeout(() => { - ws.close(); - reject(new Error("Timeout")); - }, TIMEOUTS.GENERAL); - - ws.onopen = () => { - ws.send(JSON.stringify(["EVENT", signedEvent])); - }; - - ws.onmessage = (e) => { - const [type, id, ok, message] = JSON.parse(e.data); - if (type === "OK" && id === signedEvent.id) { - clearTimeout(timeout); - if (ok) { - ws.close(); - resolve(); - } else { - ws.close(); - reject(new Error(message)); - } - } - }; - - ws.onerror = () => { - clearTimeout(timeout); - ws.close(); - reject(new Error("WebSocket error")); - }; - }); -} - -/** - * Publish event to relays + * Publishes an event to relays using the new relay management system + * @param event The event to publish + * @param relayUrls Array of relay URLs to publish to + * @returns Promise that resolves to array of successful relay URLs */ export async function publishEvent( - signedEvent: any, - useOtherRelays = false, - useFallbackRelays = false, - userRelayPreference = false, -): Promise { - // Determine which relays to use - let relays = userRelayPreference ? get(userRelays) : standardRelays; - if (useOtherRelays) { - relays = userRelayPreference ? standardRelays : get(userRelays); - } - if (useFallbackRelays) { - relays = fallbackRelays; + event: NDKEvent, + relayUrls: string[], +): Promise { + const successfulRelays: string[] = []; + const ndk = get(ndkInstance); + + if (!ndk) { + throw new Error("NDK instance not available"); } - // Try to publish to relays - for (const relayUrl of relays) { - try { - await publishToRelay(relayUrl, signedEvent); - return { - success: true, - relay: relayUrl, - eventId: signedEvent.id, - }; - } catch (e) { - console.error(`Failed to publish to ${relayUrl}:`, e); - } + // Create relay set from URLs + const relaySet = NDKRelaySet.fromRelayUrls(relayUrls, ndk); + + try { + // Publish with timeout + await event.publish(relaySet).withTimeout(10000); + + // For now, assume all relays were successful + // In a more sophisticated implementation, you'd track individual relay responses + successfulRelays.push(...relayUrls); + + console.debug("[nostrEventService] Published event successfully:", { + eventId: event.id, + relayCount: relayUrls.length, + successfulRelays + }); + } catch (error) { + console.error("[nostrEventService] Failed to publish event:", error); + throw new Error(`Failed to publish event: ${error}`); } - return { - success: false, - error: "Failed to publish to any relays", - }; + return successfulRelays; } /** diff --git a/src/lib/utils/nostrUtils.ts b/src/lib/utils/nostrUtils.ts index 23ed7b9..a7aef5e 100644 --- a/src/lib/utils/nostrUtils.ts +++ b/src/lib/utils/nostrUtils.ts @@ -4,7 +4,8 @@ import { ndkInstance } from "$lib/ndk"; import { npubCache } from "./npubCache"; import NDK, { NDKEvent, NDKRelaySet, NDKUser } from "@nostr-dev-kit/ndk"; import type { NDKFilter, NDKKind } from "@nostr-dev-kit/ndk"; -import { standardRelays, fallbackRelays, anonymousRelays } from "$lib/consts"; +import { communityRelays, secondaryRelays, anonymousRelays } from "$lib/consts"; +import { activeInboxRelays } from "$lib/ndk"; import { NDKRelaySet as NDKRelaySetFromNDK } from "@nostr-dev-kit/ndk"; import { sha256 } from "@noble/hashes/sha256"; import { schnorr } from "@noble/curves/secp256k1"; @@ -174,9 +175,9 @@ export async function createProfileLinkWithVerification( }; const allRelays = [ - ...standardRelays, + ...communityRelays, ...userRelays, - ...fallbackRelays, + ...secondaryRelays, ].filter((url, idx, arr) => arr.indexOf(url) === idx); const filteredRelays = filterProblematicRelays(allRelays); @@ -422,91 +423,43 @@ export async function fetchEventWithFallback( filterOrId: string | NDKFilter, timeoutMs: number = 3000, ): Promise { - // Get user relays if logged in - const userRelays = ndk.activeUser - ? Array.from(ndk.pool?.relays.values() || []) - .filter((r) => r.status === 1) // Only use connected relays - .map((r) => r.url) - .filter((url) => !url.includes("gitcitadel.nostr1.com")) // Filter out problematic relay - : []; - - // Determine which relays to use based on user authentication status - const isSignedIn = ndk.signer && ndk.activeUser; - const primaryRelays = isSignedIn ? standardRelays : anonymousRelays; - - // Create three relay sets in priority order - const relaySets = [ - NDKRelaySetFromNDK.fromRelayUrls(primaryRelays, ndk), // 1. Primary relays (auth or anonymous) - NDKRelaySetFromNDK.fromRelayUrls(userRelays, ndk), // 2. User relays (if logged in) - NDKRelaySetFromNDK.fromRelayUrls(fallbackRelays, ndk), // 3. fallback relays (last resort) - ]; + // Use the active inbox relays from the relay management system + const inboxRelays = get(activeInboxRelays); + + // Create relay set from active inbox relays + const relaySet = NDKRelaySetFromNDK.fromRelayUrls(inboxRelays, ndk); try { - let found: NDKEvent | null = null; - const triedRelaySets: string[] = []; - - // Helper function to try fetching from a relay set - async function tryFetchFromRelaySet( - relaySet: NDKRelaySetFromNDK, - setName: string, - ): Promise { - if (relaySet.relays.size === 0) return null; - triedRelaySets.push(setName); - - if ( - typeof filterOrId === "string" && - new RegExp(`^[0-9a-f]{${VALIDATION.HEX_LENGTH}}$`, "i").test(filterOrId) - ) { - return await ndk - .fetchEvent({ ids: [filterOrId] }, undefined, relaySet) - .withTimeout(timeoutMs); - } else { - const filter = - typeof filterOrId === "string" ? { ids: [filterOrId] } : filterOrId; - const results = await ndk - .fetchEvents(filter, undefined, relaySet) - .withTimeout(timeoutMs); - return results instanceof Set - ? (Array.from(results)[0] as NDKEvent) - : null; - } + if (relaySet.relays.size === 0) { + console.warn("No inbox relays available for event fetch"); + return null; } - // Try each relay set in order - for (const [index, relaySet] of relaySets.entries()) { - const setName = - index === 0 - ? isSignedIn - ? "standard relays" - : "anonymous relays" - : index === 1 - ? "user relays" - : "fallback relays"; - - found = await tryFetchFromRelaySet(relaySet, setName); - if (found) break; + let found: NDKEvent | null = null; + + if ( + typeof filterOrId === "string" && + new RegExp(`^[0-9a-f]{${VALIDATION.HEX_LENGTH}}$`, "i").test(filterOrId) + ) { + found = await ndk + .fetchEvent({ ids: [filterOrId] }, undefined, relaySet) + .withTimeout(timeoutMs); + } else { + const filter = + typeof filterOrId === "string" ? { ids: [filterOrId] } : filterOrId; + const results = await ndk + .fetchEvents(filter, undefined, relaySet) + .withTimeout(timeoutMs); + found = results instanceof Set + ? (Array.from(results)[0] as NDKEvent) + : null; } if (!found) { const timeoutSeconds = timeoutMs / 1000; - const relayUrls = relaySets - .map((set, i) => { - const setName = - i === 0 - ? isSignedIn - ? "standard relays" - : "anonymous relays" - : i === 1 - ? "user relays" - : "fallback relays"; - const urls = Array.from(set.relays).map((r) => r.url); - return urls.length > 0 ? `${setName} (${urls.join(", ")})` : null; - }) - .filter(Boolean) - .join(", then "); - + const relayUrls = Array.from(relaySet.relays).map((r: any) => r.url).join(", "); console.warn( - `Event not found after ${timeoutSeconds}s timeout. Tried ${relayUrls}. Some relays may be offline or slow.`, + `Event not found after ${timeoutSeconds}s timeout. Tried inbox relays: ${relayUrls}. Some relays may be offline or slow.`, ); return null; } diff --git a/src/lib/utils/profile_search.ts b/src/lib/utils/profile_search.ts index 20b3db0..1fde323 100644 --- a/src/lib/utils/profile_search.ts +++ b/src/lib/utils/profile_search.ts @@ -2,7 +2,7 @@ import { ndkInstance } from "$lib/ndk"; import { getUserMetadata, getNpubFromNip05 } from "$lib/utils/nostrUtils"; import { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk"; import { searchCache } from "$lib/utils/searchCache"; -import { standardRelays, fallbackRelays } from "$lib/consts"; +import { communityRelays, secondaryRelays } from "$lib/consts"; import { get } from "svelte/store"; import type { NostrProfile, ProfileSearchResult } from "./search_types"; import { @@ -270,7 +270,7 @@ async function quickRelaySearch( console.log("Normalized search term for relay search:", normalizedSearchTerm); // Use all profile relays for better coverage - const quickRelayUrls = [...standardRelays, ...fallbackRelays]; // Use all available relays + const quickRelayUrls = [...communityRelays, ...secondaryRelays]; // Use all available relays console.log("Using all relays for search:", quickRelayUrls); // Create relay sets for parallel search diff --git a/src/lib/utils/relayDiagnostics.ts b/src/lib/utils/relayDiagnostics.ts index dee9bc4..9a0db7c 100644 --- a/src/lib/utils/relayDiagnostics.ts +++ b/src/lib/utils/relayDiagnostics.ts @@ -1,6 +1,7 @@ -import { standardRelays, anonymousRelays, fallbackRelays } from "$lib/consts"; +import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; import NDK from "@nostr-dev-kit/ndk"; import { TIMEOUTS } from "./search_constants"; +import { get } from "svelte/store"; export interface RelayDiagnostic { url: string; @@ -85,9 +86,8 @@ export async function testRelay(url: string): Promise { * Tests all relays and returns diagnostic information */ export async function testAllRelays(): Promise { - const allRelays = [ - ...new Set([...standardRelays, ...anonymousRelays, ...fallbackRelays]), - ]; + // Use the new relay management system + const allRelays = [...get(activeInboxRelays), ...get(activeOutboxRelays)]; console.log("[RelayDiagnostics] Testing", allRelays.length, "relays..."); diff --git a/src/lib/utils/relay_management.ts b/src/lib/utils/relay_management.ts new file mode 100644 index 0000000..dbaa08a --- /dev/null +++ b/src/lib/utils/relay_management.ts @@ -0,0 +1,424 @@ +import NDK, { NDKRelay, NDKUser } from "@nostr-dev-kit/ndk"; +import { communityRelays, searchRelays, secondaryRelays, anonymousRelays, lowbandwidthRelays, localRelays } from "../consts"; +import { getRelaySetForNetworkCondition, NetworkCondition } from "./network_detection"; +import { networkCondition } from "../stores/networkStore"; +import { get } from "svelte/store"; + +/** + * Normalizes a relay URL to a standard format + * @param url The relay URL to normalize + * @returns The normalized relay URL + */ +export function normalizeRelayUrl(url: string): string { + let normalized = url.toLowerCase().trim(); + + // Ensure protocol is present + if (!normalized.startsWith('ws://') && !normalized.startsWith('wss://')) { + normalized = 'wss://' + normalized; + } + + // Remove trailing slash + normalized = normalized.replace(/\/$/, ''); + + return normalized; +} + +/** + * Normalizes an array of relay URLs + * @param urls Array of relay URLs to normalize + * @returns Array of normalized relay URLs + */ +export function normalizeRelayUrls(urls: string[]): string[] { + return urls.map(normalizeRelayUrl); +} + +/** + * Removes duplicates from an array of relay URLs + * @param urls Array of relay URLs + * @returns Array of unique relay URLs + */ +export function deduplicateRelayUrls(urls: string[]): string[] { + const normalized = normalizeRelayUrls(urls); + return [...new Set(normalized)]; +} + +/** + * Tests connection to a relay and returns connection status + * @param relayUrl The relay URL to test + * @param ndk The NDK instance + * @returns Promise that resolves to connection status + */ +export async function testRelayConnection( + relayUrl: string, + ndk: NDK, +): Promise<{ + connected: boolean; + requiresAuth: boolean; + error?: string; + actualUrl?: string; +}> { + return new Promise((resolve) => { + // Ensure the URL is using wss:// protocol + const secureUrl = ensureSecureWebSocket(relayUrl); + + // Use the existing NDK instance instead of creating a new one + const relay = new NDKRelay(secureUrl, undefined, ndk); + let authRequired = false; + let connected = false; + let error: string | undefined; + let actualUrl: string | undefined; + + const timeout = setTimeout(() => { + relay.disconnect(); + resolve({ + connected: false, + requiresAuth: authRequired, + error: "Connection timeout", + actualUrl, + }); + }, 3000); // Increased timeout to 3 seconds to give relays more time + + relay.on("connect", () => { + connected = true; + actualUrl = secureUrl; + clearTimeout(timeout); + relay.disconnect(); + resolve({ + connected: true, + requiresAuth: authRequired, + error, + actualUrl, + }); + }); + + relay.on("notice", (message: string) => { + if (message.includes("auth-required")) { + authRequired = true; + } + }); + + relay.on("disconnect", () => { + if (!connected) { + error = "Connection failed"; + clearTimeout(timeout); + resolve({ + connected: false, + requiresAuth: authRequired, + error, + actualUrl, + }); + } + }); + + relay.connect(); + }); +} + +/** + * Ensures a relay URL uses secure WebSocket protocol for remote relays + * @param url The relay URL to secure + * @returns The URL with wss:// protocol (except for localhost) + */ +function ensureSecureWebSocket(url: string): string { + // For localhost, always use ws:// (never wss://) + if (url.includes('localhost') || url.includes('127.0.0.1')) { + // Convert any wss://localhost to ws://localhost + return url.replace(/^wss:\/\//, "ws://"); + } + + // Replace ws:// with wss:// for remote relays + const secureUrl = url.replace(/^ws:\/\//, "wss://"); + + if (secureUrl !== url) { + console.warn( + `[relay_management.ts] Protocol upgrade for rem ote relay: ${url} -> ${secureUrl}`, + ); + } + + return secureUrl; +} + +/** + * Tests connection to local relays + * @param localRelayUrls Array of local relay URLs to test + * @param ndk NDK instance + * @returns Promise that resolves to array of working local relay URLs + */ +async function testLocalRelays(localRelayUrls: string[], ndk: NDK): Promise { + const workingRelays: string[] = []; + + await Promise.all( + localRelayUrls.map(async (url) => { + try { + const result = await testRelayConnection(url, ndk); + if (result.connected) { + workingRelays.push(url); + } + } catch (error) { + // Silently ignore local relay failures + } + }) + ); + + return workingRelays; +} + +/** + * Discovers local relays by testing common localhost URLs + * @param ndk NDK instance + * @returns Promise that resolves to array of working local relay URLs + */ +export async function discoverLocalRelays(ndk: NDK): Promise { + try { + // Convert wss:// URLs from consts to ws:// for local testing + const localRelayUrls = localRelays.map(url => + url.replace(/^wss:\/\//, 'ws://') + ); + + const workingRelays = await testLocalRelays(localRelayUrls, ndk); + + // If no local relays are working, return empty array + // The network detection logic will provide fallback relays + return workingRelays; + } catch (error) { + // Silently fail and return empty array + return []; + } +} + +/** + * Fetches user's local relays from kind 10432 event + * @param ndk NDK instance + * @param user User to fetch local relays for + * @returns Promise that resolves to array of local relay URLs + */ +export async function getUserLocalRelays(ndk: NDK, user: NDKUser): Promise { + try { + const localRelayEvent = await ndk.fetchEvent( + { + kinds: [10432 as any], + authors: [user.pubkey], + }, + { + groupable: false, + skipVerification: false, + skipValidation: false, + } + ); + + if (!localRelayEvent) { + return []; + } + + const localRelays: string[] = []; + localRelayEvent.tags.forEach((tag) => { + if (tag[0] === 'r' && tag[1]) { + localRelays.push(tag[1]); + } + }); + + return localRelays; + } catch (error) { + console.info('[relay_management.ts] Error fetching user local relays:', error); + return []; + } +} + +/** + * Fetches user's blocked relays from kind 10006 event + * @param ndk NDK instance + * @param user User to fetch blocked relays for + * @returns Promise that resolves to array of blocked relay URLs + */ +export async function getUserBlockedRelays(ndk: NDK, user: NDKUser): Promise { + try { + const blockedRelayEvent = await ndk.fetchEvent( + { + kinds: [10006], + authors: [user.pubkey], + }, + { + groupable: false, + skipVerification: false, + skipValidation: false, + } + ); + + if (!blockedRelayEvent) { + return []; + } + + const blockedRelays: string[] = []; + blockedRelayEvent.tags.forEach((tag) => { + if (tag[0] === 'r' && tag[1]) { + blockedRelays.push(tag[1]); + } + }); + + return blockedRelays; + } catch (error) { + console.info('[relay_management.ts] Error fetching user blocked relays:', error); + return []; + } +} + +/** + * Fetches user's outbox relays from NIP-65 relay list + * @param ndk NDK instance + * @param user User to fetch outbox relays for + * @returns Promise that resolves to array of outbox relay URLs + */ +export async function getUserOutboxRelays(ndk: NDK, user: NDKUser): Promise { + try { + const relayList = await ndk.fetchEvent( + { + kinds: [10002], + authors: [user.pubkey], + }, + { + groupable: false, + skipVerification: false, + skipValidation: false, + } + ); + + if (!relayList) { + return []; + } + + const outboxRelays: string[] = []; + relayList.tags.forEach((tag) => { + if (tag[0] === 'w' && tag[1]) { + outboxRelays.push(tag[1]); + } + }); + + return outboxRelays; + } catch (error) { + console.info('[relay_management.ts] Error fetching user outbox relays:', error); + return []; + } +} + +/** + * Tests a set of relays in batches to avoid overwhelming them + * @param relayUrls Array of relay URLs to test + * @param ndk NDK instance + * @returns Promise that resolves to array of working relay URLs + */ +async function testRelaySet(relayUrls: string[], ndk: NDK): Promise { + const workingRelays: string[] = []; + const maxConcurrent = 3; // Test 3 relays at a time to avoid overwhelming them + + for (let i = 0; i < relayUrls.length; i += maxConcurrent) { + const batch = relayUrls.slice(i, i + maxConcurrent); + + const batchPromises = batch.map(async (url) => { + try { + const result = await testRelayConnection(url, ndk); + return result.connected ? url : null; + } catch (error) { + return null; + } + }); + + const batchResults = await Promise.all(batchPromises); + const batchWorkingRelays = batchResults.filter((url): url is string => url !== null); + workingRelays.push(...batchWorkingRelays); + } + + return workingRelays; +} + +/** + * Builds a complete relay set for a user, including local, user-specific, and fallback relays + * @param ndk NDK instance + * @param user NDKUser or null for anonymous access + * @returns Promise that resolves to inbox and outbox relay arrays + */ +export async function buildCompleteRelaySet( + ndk: NDK, + user: NDKUser | null +): Promise<{ inboxRelays: string[]; outboxRelays: string[] }> { + // Discover local relays first + const discoveredLocalRelays = await discoverLocalRelays(ndk); + + // Get user-specific relays if available + let userOutboxRelays: string[] = []; + let userLocalRelays: string[] = []; + let blockedRelays: string[] = []; + + if (user) { + try { + userOutboxRelays = await getUserOutboxRelays(ndk, user); + } catch (error) { + // Silently ignore user relay fetch errors + } + + try { + userLocalRelays = await getUserLocalRelays(ndk, user); + } catch (error) { + // Silently ignore user local relay fetch errors + } + + try { + blockedRelays = await getUserBlockedRelays(ndk, user); + } catch (error) { + // Silently ignore blocked relay fetch errors + } + } + + // Build initial relay sets and deduplicate + const finalInboxRelays = deduplicateRelayUrls([...discoveredLocalRelays, ...userLocalRelays]); + const finalOutboxRelays = deduplicateRelayUrls([...discoveredLocalRelays, ...userOutboxRelays]); + + // Test relays and filter out non-working ones + let testedInboxRelays: string[] = []; + let testedOutboxRelays: string[] = []; + + if (finalInboxRelays.length > 0) { + testedInboxRelays = await testRelaySet(finalInboxRelays, ndk); + } + + if (finalOutboxRelays.length > 0) { + testedOutboxRelays = await testRelaySet(finalOutboxRelays, ndk); + } + + // If no relays passed testing, use remote relays without testing + if (testedInboxRelays.length === 0 && testedOutboxRelays.length === 0) { + const remoteRelays = deduplicateRelayUrls([...secondaryRelays, ...searchRelays]); + return { + inboxRelays: remoteRelays, + outboxRelays: remoteRelays + }; + } + + // Use tested relays and deduplicate + const inboxRelays = testedInboxRelays.length > 0 ? deduplicateRelayUrls(testedInboxRelays) : deduplicateRelayUrls(secondaryRelays); + const outboxRelays = testedOutboxRelays.length > 0 ? deduplicateRelayUrls(testedOutboxRelays) : deduplicateRelayUrls(secondaryRelays); + + // Apply network condition optimization + const currentNetworkCondition = get(networkCondition); + const networkOptimizedRelaySet = getRelaySetForNetworkCondition( + currentNetworkCondition, + discoveredLocalRelays, + lowbandwidthRelays, + { inboxRelays, outboxRelays } + ); + + // Filter out blocked relays and deduplicate final sets + const finalRelaySet = { + inboxRelays: deduplicateRelayUrls(networkOptimizedRelaySet.inboxRelays.filter(r => !blockedRelays.includes(r))), + outboxRelays: deduplicateRelayUrls(networkOptimizedRelaySet.outboxRelays.filter(r => !blockedRelays.includes(r))) + }; + + // If no relays are working, use anonymous relays as fallback + if (finalRelaySet.inboxRelays.length === 0 && finalRelaySet.outboxRelays.length === 0) { + return { + inboxRelays: deduplicateRelayUrls(anonymousRelays), + outboxRelays: deduplicateRelayUrls(anonymousRelays) + }; + } + + return finalRelaySet; +} \ No newline at end of file diff --git a/src/lib/utils/subscription_search.ts b/src/lib/utils/subscription_search.ts index 97ef19d..22cefb4 100644 --- a/src/lib/utils/subscription_search.ts +++ b/src/lib/utils/subscription_search.ts @@ -3,7 +3,7 @@ import { getMatchingTags, getNpubFromNip05 } from "$lib/utils/nostrUtils"; import { nip19 } from "$lib/utils/nostrUtils"; import { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk"; import { searchCache } from "$lib/utils/searchCache"; -import { communityRelay, profileRelays } from "$lib/consts"; +import { communityRelays, searchRelays } from "$lib/consts"; import { get } from "svelte/store"; import type { SearchResult, @@ -20,6 +20,12 @@ import { isEmojiReaction, } from "./search_utils"; import { TIMEOUTS, SEARCH_LIMITS } from "./search_constants"; +import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; + +// Helper function to normalize URLs for comparison +const normalizeUrl = (url: string): string => { + return url.replace(/\/$/, ''); // Remove trailing slash +}; /** * Search for events by subscription type (d, t, n) @@ -292,23 +298,40 @@ function createPrimaryRelaySet( searchType: SearchSubscriptionType, ndk: any, ): NDKRelaySet { + // Use the new relay management system + const searchRelays = [...get(activeInboxRelays), ...get(activeOutboxRelays)]; + console.debug('subscription_search: Active relay stores:', { + inboxRelays: get(activeInboxRelays), + outboxRelays: get(activeOutboxRelays), + searchRelays + }); + + // Debug: Log all relays in NDK pool + const poolRelays = Array.from(ndk.pool.relays.values()); + console.debug('subscription_search: NDK pool relays:', poolRelays.map((r: any) => r.url)); + if (searchType === "n") { - // For profile searches, use profile relays first - const profileRelaySet = Array.from(ndk.pool.relays.values()).filter( + // For profile searches, use search relays first + const profileRelaySet = poolRelays.filter( (relay: any) => - profileRelays.some( - (profileRelay) => - relay.url === profileRelay || relay.url === profileRelay + "/", + searchRelays.some( + (searchRelay: string) => + normalizeUrl(relay.url) === normalizeUrl(searchRelay), ), ); + console.debug('subscription_search: Profile relay set:', profileRelaySet.map((r: any) => r.url)); return new NDKRelaySet(new Set(profileRelaySet) as any, ndk); } else { - // For other searches, use community relay first - const communityRelaySet = Array.from(ndk.pool.relays.values()).filter( + // For other searches, use active relays first + const activeRelaySet = poolRelays.filter( (relay: any) => - relay.url === communityRelay || relay.url === communityRelay + "/", + searchRelays.some( + (searchRelay: string) => + normalizeUrl(relay.url) === normalizeUrl(searchRelay), + ), ); - return new NDKRelaySet(new Set(communityRelaySet) as any, ndk); + console.debug('subscription_search: Active relay set:', activeRelaySet.map((r: any) => r.url)); + return new NDKRelaySet(new Set(activeRelaySet) as any, ndk); } } @@ -511,15 +534,16 @@ async function searchOtherRelaysInBackground( new Set( Array.from(ndk.pool.relays.values()).filter((relay: any) => { if (searchType === "n") { - // For profile searches, exclude profile relays from fallback search - return !profileRelays.some( - (profileRelay) => - relay.url === profileRelay || relay.url === profileRelay + "/", + // For profile searches, exclude search relays from fallback search + return !searchRelays.some( + (searchRelay: string) => + normalizeUrl(relay.url) === normalizeUrl(searchRelay), ); } else { - // For other searches, exclude community relay from fallback search - return ( - relay.url !== communityRelay && relay.url !== communityRelay + "/" + // For other searches, exclude community relays from fallback search + return !communityRelays.some( + (communityRelay: string) => + normalizeUrl(relay.url) === normalizeUrl(communityRelay), ); } }), diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 9cb3197..47be24c 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -5,6 +5,7 @@ import { page } from "$app/stores"; import { Alert } from "flowbite-svelte"; import { HammerSolid } from "flowbite-svelte-icons"; + import { logCurrentRelayConfiguration } from "$lib/ndk"; // Get standard metadata for OpenGraph tags let title = "Library of Alexandria"; @@ -18,6 +19,9 @@ onMount(() => { const rect = document.body.getBoundingClientRect(); // document.body.style.height = `${rect.height}px`; + + // Log relay configuration when layout mounts + logCurrentRelayConfiguration(); }); diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts index eb40d1c..dd255ca 100644 --- a/src/routes/+layout.ts +++ b/src/routes/+layout.ts @@ -1,5 +1,3 @@ -import { feedTypeStorageKey } from "$lib/consts"; -import { FeedType } from "$lib/consts"; import { getPersistedLogin, initNdk, ndkInstance } from "$lib/ndk"; import { loginWithExtension, @@ -8,18 +6,13 @@ import { } from "$lib/stores/userStore"; import { loginMethodStorageKey } from "$lib/stores/userStore"; import Pharos, { pharosInstance } from "$lib/parser"; -import { feedType } from "$lib/stores"; import type { LayoutLoad } from "./$types"; import { get } from "svelte/store"; export const ssr = false; export const load: LayoutLoad = () => { - const initialFeedType = - (localStorage.getItem(feedTypeStorageKey) as FeedType) ?? - FeedType.StandardRelays; - feedType.set(initialFeedType); - + // Initialize NDK with new relay management system const ndk = initNdk(); ndkInstance.set(ndk); diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 594d3cc..8461bd4 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,14 +1,17 @@ + + {#if eventCount.total > 0} +
    + Showing {eventCount.displayed} of {eventCount.total} events. +
    + {/if} + diff --git a/src/routes/contact/+page.svelte b/src/routes/contact/+page.svelte index fbe29c0..4137220 100644 --- a/src/routes/contact/+page.svelte +++ b/src/routes/contact/+page.svelte @@ -9,9 +9,9 @@ Input, Modal, } from "flowbite-svelte"; - import { ndkInstance, ndkSignedIn } from "$lib/ndk"; + import { ndkInstance, ndkSignedIn, activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; import { userStore } from "$lib/stores/userStore"; - import { standardRelays } from "$lib/consts"; + import { communityRelays } from "$lib/consts"; import type NDK from "@nostr-dev-kit/ndk"; import { NDKEvent, NDKRelaySet } from "@nostr-dev-kit/ndk"; // @ts-ignore - Workaround for Svelte component import issue @@ -62,12 +62,13 @@ const repoAddress = "naddr1qvzqqqrhnypzplfq3m5v3u5r0q9f255fdeyz8nyac6lagssx8zy4wugxjs8ajf7pqy88wumn8ghj7mn0wvhxcmmv9uqq5stvv4uxzmnywf5kz2elajr"; - // Hard-coded relays to ensure we have working relays + // Use the new relay management system instead of hardcoded relays const allRelays = [ "wss://relay.damus.io", "wss://relay.nostr.band", "wss://nos.lol", - ...standardRelays, + ...$activeInboxRelays, + ...$activeOutboxRelays, ]; // Hard-coded repository owner pubkey and ID from the task @@ -451,7 +452,7 @@ Also renders nostr identifiers: npubs, nprofiles, nevents, notes, and naddrs. Wi size="xs" class="absolute bottom-2 right-2 z-10 opacity-60 hover:opacity-100" color="light" - on:click={toggleSize} + onclick={toggleSize} > {isExpanded ? "⌃" : "⌄"} @@ -459,7 +460,7 @@ Also renders nostr identifiers: npubs, nprofiles, nevents, notes, and naddrs. Wi
    - - + +
    diff --git a/src/routes/events/+page.svelte b/src/routes/events/+page.svelte index c0932b5..0b8c20d 100644 --- a/src/routes/events/+page.svelte +++ b/src/routes/events/+page.svelte @@ -13,13 +13,9 @@ import { getMatchingTags, toNpub } from "$lib/utils/nostrUtils"; import EventInput from "$lib/components/EventInput.svelte"; import { userPubkey, isLoggedIn } from "$lib/stores/authStore.Svelte"; - import { - testAllRelays, - logRelayDiagnostics, - } from "$lib/utils/relayDiagnostics"; import CopyToClipboard from "$lib/components/util/CopyToClipboard.svelte"; import { neventEncode, naddrEncode } from "$lib/utils"; - import { standardRelays } from "$lib/consts"; + import { activeInboxRelays, activeOutboxRelays, logCurrentRelayConfiguration } from "$lib/ndk"; import { getEventType } from "$lib/utils/mime"; import ViewPublicationLink from "$lib/components/util/ViewPublicationLink.svelte"; import { checkCommunity } from "$lib/utils/search_utility"; @@ -246,8 +242,15 @@ return "Reference"; } - function getNeventAddress(event: NDKEvent): string { - return neventEncode(event, standardRelays); + function getNeventUrl(event: NDKEvent): string { + if (event.kind === 0) { + return neventEncode(event, $activeInboxRelays); + } + return neventEncode(event, $activeInboxRelays); + } + + function getNaddrUrl(event: NDKEvent): string { + return naddrEncode(event, $activeInboxRelays); } function isAddressableEvent(event: NDKEvent): boolean { @@ -259,7 +262,7 @@ return null; } try { - return naddrEncode(event, standardRelays); + return naddrEncode(event, $activeInboxRelays); } catch { return null; } @@ -498,12 +501,11 @@ handleUrlChange(); }); + // Log relay configuration when page mounts onMount(() => { - userRelayPreference = localStorage.getItem("useUserRelays") === "true"; - - // Run relay diagnostics to help identify connection issues - testAllRelays().then(logRelayDiagnostics).catch(console.error); + logCurrentRelayConfiguration(); }); +
    @@ -942,8 +944,8 @@ {#if event.kind !== 0}
    {#if isAddressableEvent(event)} {@const naddrAddress = getViewPublicationNaddr(event)} diff --git a/src/routes/publication/+page.ts b/src/routes/publication/+page.ts index b870262..6a06156 100644 --- a/src/routes/publication/+page.ts +++ b/src/routes/publication/+page.ts @@ -2,7 +2,7 @@ import { error } from "@sveltejs/kit"; import type { Load } from "@sveltejs/kit"; import type { NDKEvent } from "@nostr-dev-kit/ndk"; import { nip19 } from "nostr-tools"; -import { getActiveRelays } from "$lib/ndk"; +import { getActiveRelaySetAsNDKRelaySet } from "$lib/ndk"; import { getMatchingTags } from "$lib/utils/nostrUtils"; /** @@ -68,10 +68,11 @@ async function fetchEventById(ndk: any, id: string): Promise { */ async function fetchEventByDTag(ndk: any, dTag: string): Promise { try { + const relaySet = await getActiveRelaySetAsNDKRelaySet(ndk, true); // true for inbox relays const event = await ndk.fetchEvent( { "#d": [dTag] }, { closeOnEose: false }, - getActiveRelays(ndk), + relaySet, ); if (!event) { From 17c49a092bae5328aa4ddb26d88bd9154b8ba4a4 Mon Sep 17 00:00:00 2001 From: vnugent Date: Fri, 18 Jul 2025 11:14:57 -0400 Subject: [PATCH 115/135] refactor(container): updated dockerfiles for deployments - Removed the next/prod docker files as they don't get used in our deployment scheme - Renamed the local dockerfile to Dockerfile so it's easily buidable for all deployments --- Dockerfile.local => Dockerfile | 0 Dockerfile.next | 15 --------------- Dockerfile.prod | 15 --------------- 3 files changed, 30 deletions(-) rename Dockerfile.local => Dockerfile (100%) delete mode 100644 Dockerfile.next delete mode 100644 Dockerfile.prod diff --git a/Dockerfile.local b/Dockerfile similarity index 100% rename from Dockerfile.local rename to Dockerfile diff --git a/Dockerfile.next b/Dockerfile.next deleted file mode 100644 index e3924ba..0000000 --- a/Dockerfile.next +++ /dev/null @@ -1,15 +0,0 @@ -FROM denoland/deno:alpine AS build -WORKDIR /app/src -COPY . . -RUN deno install -RUN deno task build - -FROM denoland/deno:alpine AS release -WORKDIR /app -COPY --from=build /app/src/build/ ./build/ -COPY --from=build /app/src/import_map.json . - -ENV ORIGIN=https://$HOST - -EXPOSE 3000 -CMD [ "deno", "run", "--allow-env", "--allow-read", "--allow-net", "--import-map=import_map.json", "./build/index.js" ] diff --git a/Dockerfile.prod b/Dockerfile.prod deleted file mode 100644 index e3924ba..0000000 --- a/Dockerfile.prod +++ /dev/null @@ -1,15 +0,0 @@ -FROM denoland/deno:alpine AS build -WORKDIR /app/src -COPY . . -RUN deno install -RUN deno task build - -FROM denoland/deno:alpine AS release -WORKDIR /app -COPY --from=build /app/src/build/ ./build/ -COPY --from=build /app/src/import_map.json . - -ENV ORIGIN=https://$HOST - -EXPOSE 3000 -CMD [ "deno", "run", "--allow-env", "--allow-read", "--allow-net", "--import-map=import_map.json", "./build/index.js" ] From efcf3d7195a5b64d97bafcc83e25404e0ce6504b Mon Sep 17 00:00:00 2001 From: vnugent Date: Fri, 18 Jul 2025 11:16:21 -0400 Subject: [PATCH 116/135] fix(compose): update the docker compose file to build correctly - fixed the compose file so it builds the current deno application - fixed the port numbers to match the deno server --- docker-compose.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index ad37163..b6633a6 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,9 +1,9 @@ version: "3" services: - wikinostr: + alexandria: build: context: . dockerfile: Dockerfile ports: - - 3023:4173 + - 3000:3000 From fd73b0afad03ae75e4ee46c04047bb0b72f4cf0b Mon Sep 17 00:00:00 2001 From: vnugent Date: Fri, 18 Jul 2025 11:43:46 -0400 Subject: [PATCH 117/135] chore: removed old bun.lock file as we no longer use bun --- bun.lock | 1078 ------------------------------------------------------ 1 file changed, 1078 deletions(-) delete mode 100644 bun.lock diff --git a/bun.lock b/bun.lock deleted file mode 100644 index c2e3679..0000000 --- a/bun.lock +++ /dev/null @@ -1,1078 +0,0 @@ -{ - "lockfileVersion": 1, - "workspaces": { - "": { - "name": "alexandria", - "dependencies": { - "@nostr-dev-kit/ndk": "2.11.x", - "@nostr-dev-kit/ndk-cache-dexie": "2.5.x", - "@popperjs/core": "2.11.x", - "@tailwindcss/forms": "0.5.x", - "@tailwindcss/typography": "0.5.x", - "asciidoctor": "3.0.x", - "d3": "^7.9.0", - "he": "1.2.x", - "nostr-tools": "2.10.x", - "playwright": "^1.50.1", - "svelte-adapter-bun": "0.5.x", - }, - "devDependencies": { - "@playwright/test": "^1.50.1", - "@sveltejs/adapter-auto": "3.x", - "@sveltejs/adapter-static": "3.x", - "@sveltejs/kit": "2.x", - "@sveltejs/vite-plugin-svelte": "4.x", - "@types/he": "1.2.x", - "@types/node": "22.x", - "autoprefixer": "10.x", - "eslint-plugin-svelte": "2.x", - "flowbite": "2.x", - "flowbite-svelte": "0.x", - "flowbite-svelte-icons": "2.x", - "postcss": "8.x", - "postcss-load-config": "6.x", - "prettier": "3.x", - "prettier-plugin-svelte": "3.x", - "svelte": "5.x", - "svelte-check": "4.x", - "tailwind-merge": "^2.5.5", - "tailwindcss": "3.x", - "tslib": "2.8.x", - "typescript": "5.7.x", - "vite": "5.x", - "vitest": "^3.0.5", - }, - }, - }, - "packages": { - "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], - - "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], - - "@asciidoctor/cli": ["@asciidoctor/cli@4.0.0", "", { "dependencies": { "yargs": "17.3.1" }, "peerDependencies": { "@asciidoctor/core": ">=2 <4" }, "bin": { "asciidoctor": "bin/asciidoctor", "asciidoctorjs": "bin/asciidoctor" } }, "sha512-x2T9gW42921Zd90juEagtbViPZHNP2MWf0+6rJEkOzW7E9m3TGJtz+Guye9J0gwrpZsTMGCpfYMQy1We3X7osg=="], - - "@asciidoctor/core": ["@asciidoctor/core@3.0.4", "", { "dependencies": { "@asciidoctor/opal-runtime": "3.0.1", "unxhr": "1.2.0" } }, "sha512-41SDMi7iRRBViPe0L6VWFTe55bv6HEOJeRqMj5+E5wB1YPdUPuTucL4UAESPZM6OWmn4t/5qM5LusXomFUVwVQ=="], - - "@asciidoctor/opal-runtime": ["@asciidoctor/opal-runtime@3.0.1", "", { "dependencies": { "glob": "8.1.0", "unxhr": "1.2.0" } }, "sha512-iW7ACahOG0zZft4A/4CqDcc7JX+fWRNjV5tFAVkNCzwZD+EnFolPaUOPYt8jzadc0+Bgd80cQTtRMQnaaV1kkg=="], - - "@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="], - - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="], - - "@babel/parser": ["@babel/parser@7.26.3", "", { "dependencies": { "@babel/types": "^7.26.3" }, "bin": { "parser": "bin/babel-parser.js" } }, "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA=="], - - "@babel/types": ["@babel/types@7.26.3", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA=="], - - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], - - "@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="], - - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="], - - "@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="], - - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="], - - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="], - - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="], - - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="], - - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="], - - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="], - - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="], - - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="], - - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="], - - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="], - - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="], - - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="], - - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="], - - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="], - - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="], - - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="], - - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="], - - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="], - - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="], - - "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.4.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA=="], - - "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], - - "@eslint/config-array": ["@eslint/config-array@0.19.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.5", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA=="], - - "@eslint/core": ["@eslint/core@0.9.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q=="], - - "@eslint/eslintrc": ["@eslint/eslintrc@3.2.0", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w=="], - - "@eslint/js": ["@eslint/js@9.17.0", "", {}, "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w=="], - - "@eslint/object-schema": ["@eslint/object-schema@2.1.5", "", {}, "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ=="], - - "@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.4", "", { "dependencies": { "levn": "^0.4.1" } }, "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg=="], - - "@floating-ui/core": ["@floating-ui/core@1.6.8", "", { "dependencies": { "@floating-ui/utils": "^0.2.8" } }, "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA=="], - - "@floating-ui/dom": ["@floating-ui/dom@1.6.12", "", { "dependencies": { "@floating-ui/core": "^1.6.0", "@floating-ui/utils": "^0.2.8" } }, "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w=="], - - "@floating-ui/utils": ["@floating-ui/utils@0.2.8", "", {}, "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig=="], - - "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], - - "@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="], - - "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], - - "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.1", "", {}, "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA=="], - - "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], - - "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="], - - "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], - - "@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="], - - "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], - - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], - - "@noble/ciphers": ["@noble/ciphers@0.5.3", "", {}, "sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w=="], - - "@noble/curves": ["@noble/curves@1.7.0", "", { "dependencies": { "@noble/hashes": "1.6.0" } }, "sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw=="], - - "@noble/hashes": ["@noble/hashes@1.6.1", "", {}, "sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w=="], - - "@noble/secp256k1": ["@noble/secp256k1@2.1.0", "", {}, "sha512-XLEQQNdablO0XZOIniFQimiXsZDNwaYgL96dZwC54Q30imSbAOFf3NKtepc+cXyuZf5Q1HCgbqgZ2UFFuHVcEw=="], - - "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], - - "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], - - "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], - - "@nostr-dev-kit/ndk": ["@nostr-dev-kit/ndk@2.11.0", "", { "dependencies": { "@noble/curves": "^1.6.0", "@noble/hashes": "^1.5.0", "@noble/secp256k1": "^2.1.0", "@scure/base": "^1.1.9", "debug": "^4.3.6", "light-bolt11-decoder": "^3.2.0", "nostr-tools": "^2.7.1", "tseep": "^1.2.2", "typescript-lru-cache": "^2.0.0", "utf8-buffer": "^1.0.0", "websocket-polyfill": "^0.0.3" } }, "sha512-FKIMtcVsVcquzrC+yir9lOXHCIHmQ3IKEVCMohqEB7N96HjP2qrI9s5utbjI3lkavFNF5tXg1Gp9ODEo7XCfLA=="], - - "@nostr-dev-kit/ndk-cache-dexie": ["@nostr-dev-kit/ndk-cache-dexie@2.5.8", "", { "dependencies": { "@nostr-dev-kit/ndk": "2.10.7", "debug": "^4.3.7", "dexie": "^4.0.8", "nostr-tools": "^2.4.0", "typescript-lru-cache": "^2.0.0" } }, "sha512-8a6BK5Fdy1CW3uyB92u56t5wIDz6dYm/MIAGQzJA96gC8CR1RgVM/5eV0TEm4o86Lf4atnVOXTWwi1Hle+FEYA=="], - - "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], - - "@playwright/test": ["@playwright/test@1.50.1", "", { "dependencies": { "playwright": "1.50.1" }, "bin": { "playwright": "cli.js" } }, "sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ=="], - - "@polka/url": ["@polka/url@1.0.0-next.28", "", {}, "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw=="], - - "@popperjs/core": ["@popperjs/core@2.11.8", "", {}, "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="], - - "@rollup/plugin-node-resolve": ["@rollup/plugin-node-resolve@15.3.1", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "@types/resolve": "1.20.2", "deepmerge": "^4.2.2", "is-module": "^1.0.0", "resolve": "^1.22.1" }, "peerDependencies": { "rollup": "^2.78.0||^3.0.0||^4.0.0" } }, "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA=="], - - "@rollup/pluginutils": ["@rollup/pluginutils@5.1.4", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" } }, "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ=="], - - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.28.1", "", { "os": "linux", "cpu": "x64" }, "sha512-fzgeABz7rrAlKYB0y2kSEiURrI0691CSL0+KXwKwhxvj92VULEDQLpBYLHpF49MSiPG4sq5CK3qHMnb9tlCjBw=="], - - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.28.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xQTDVzSGiMlSshpJCtudbWyRfLaNiVPXt1WgdWTwWz9n0U12cI2ZVtWe/Jgwyv/6wjL7b66uu61Vg0POWVfz4g=="], - - "@scure/base": ["@scure/base@1.2.1", "", {}, "sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ=="], - - "@scure/bip32": ["@scure/bip32@1.3.1", "", { "dependencies": { "@noble/curves": "~1.1.0", "@noble/hashes": "~1.3.1", "@scure/base": "~1.1.0" } }, "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A=="], - - "@scure/bip39": ["@scure/bip39@1.2.1", "", { "dependencies": { "@noble/hashes": "~1.3.0", "@scure/base": "~1.1.0" } }, "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg=="], - - "@sveltejs/adapter-auto": ["@sveltejs/adapter-auto@3.3.1", "", { "dependencies": { "import-meta-resolve": "^4.1.0" }, "peerDependencies": { "@sveltejs/kit": "^2.0.0" } }, "sha512-5Sc7WAxYdL6q9j/+D0jJKjGREGlfIevDyHSQ2eNETHcB1TKlQWHcAo8AS8H1QdjNvSXpvOwNjykDUHPEAyGgdQ=="], - - "@sveltejs/adapter-static": ["@sveltejs/adapter-static@3.0.8", "", { "peerDependencies": { "@sveltejs/kit": "^2.0.0" } }, "sha512-YaDrquRpZwfcXbnlDsSrBQNCChVOT9MGuSg+dMAyfsAa1SmiAhrA5jUYUiIMC59G92kIbY/AaQOWcBdq+lh+zg=="], - - "@sveltejs/kit": ["@sveltejs/kit@2.17.2", "", { "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^0.6.0", "devalue": "^5.1.0", "esm-env": "^1.2.2", "import-meta-resolve": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", "sirv": "^3.0.0" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "vite": "^5.0.3 || ^6.0.0" }, "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-Vypk02baf7qd3SOB1uUwUC/3Oka+srPo2J0a8YN3EfJypRshDkNx9HzNKjSmhOnGWwT+SSO06+N0mAb8iVTmTQ=="], - - "@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@4.0.4", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^3.0.0-next.0||^3.0.0", "debug": "^4.3.7", "deepmerge": "^4.3.1", "kleur": "^4.1.5", "magic-string": "^0.30.12", "vitefu": "^1.0.3" }, "peerDependencies": { "svelte": "^5.0.0-next.96 || ^5.0.0", "vite": "^5.0.0" } }, "sha512-0ba1RQ/PHen5FGpdSrW7Y3fAMQjrXantECALeOiOdBdzR5+5vPP6HVZRLmZaQL+W8m++o+haIAKq5qT+MiZ7VA=="], - - "@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@3.0.1", "", { "dependencies": { "debug": "^4.3.7" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^4.0.0-next.0||^4.0.0", "svelte": "^5.0.0-next.96 || ^5.0.0", "vite": "^5.0.0" } }, "sha512-2CKypmj1sM4GE7HjllT7UKmo4Q6L5xFRd7VMGEWhYnZ+wc6AUVU01IBd7yUi6WnFndEwWoMNOd6e8UjoN0nbvQ=="], - - "@tailwindcss/forms": ["@tailwindcss/forms@0.5.9", "", { "dependencies": { "mini-svg-data-uri": "^1.2.3" }, "peerDependencies": { "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20" } }, "sha512-tM4XVr2+UVTxXJzey9Twx48c1gcxFStqn1pQz0tRsX8o3DvxhN5oY5pvyAbUx7VTaZxpej4Zzvc6h+1RJBzpIg=="], - - "@tailwindcss/typography": ["@tailwindcss/typography@0.5.15", "", { "dependencies": { "lodash.castarray": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.merge": "^4.6.2", "postcss-selector-parser": "6.0.10" }, "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20" } }, "sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA=="], - - "@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="], - - "@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="], - - "@types/he": ["@types/he@1.2.3", "", {}, "sha512-q67/qwlxblDzEDvzHhVkwc1gzVWxaNxeyHUBF4xElrvjL11O+Ytze+1fGpBHlr/H9myiBUaUXNnNPmBHxxfAcA=="], - - "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], - - "@types/node": ["@types/node@22.10.2", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ=="], - - "@types/resolve": ["@types/resolve@1.20.2", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="], - - "@vitest/expect": ["@vitest/expect@3.0.6", "", { "dependencies": { "@vitest/spy": "3.0.6", "@vitest/utils": "3.0.6", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-zBduHf/ja7/QRX4HdP1DSq5XrPgdN+jzLOwaTq/0qZjYfgETNFCKf9nOAp2j3hmom3oTbczuUzrzg9Hafh7hNg=="], - - "@vitest/mocker": ["@vitest/mocker@3.0.6", "", { "dependencies": { "@vitest/spy": "3.0.6", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0 || ^6.0.0" }, "optionalPeers": ["msw"] }, "sha512-KPztr4/tn7qDGZfqlSPQoF2VgJcKxnDNhmfR3VgZ6Fy1bO8T9Fc1stUiTXtqz0yG24VpD00pZP5f8EOFknjNuQ=="], - - "@vitest/pretty-format": ["@vitest/pretty-format@3.0.6", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-Zyctv3dbNL+67qtHfRnUE/k8qxduOamRfAL1BurEIQSyOEFffoMvx2pnDSSbKAAVxY0Ej2J/GH2dQKI0W2JyVg=="], - - "@vitest/runner": ["@vitest/runner@3.0.6", "", { "dependencies": { "@vitest/utils": "3.0.6", "pathe": "^2.0.3" } }, "sha512-JopP4m/jGoaG1+CBqubV/5VMbi7L+NQCJTu1J1Pf6YaUbk7bZtaq5CX7p+8sY64Sjn1UQ1XJparHfcvTTdu9cA=="], - - "@vitest/snapshot": ["@vitest/snapshot@3.0.6", "", { "dependencies": { "@vitest/pretty-format": "3.0.6", "magic-string": "^0.30.17", "pathe": "^2.0.3" } }, "sha512-qKSmxNQwT60kNwwJHMVwavvZsMGXWmngD023OHSgn873pV0lylK7dwBTfYP7e4URy5NiBCHHiQGA9DHkYkqRqg=="], - - "@vitest/spy": ["@vitest/spy@3.0.6", "", { "dependencies": { "tinyspy": "^3.0.2" } }, "sha512-HfOGx/bXtjy24fDlTOpgiAEJbRfFxoX3zIGagCqACkFKKZ/TTOE6gYMKXlqecvxEndKFuNHcHqP081ggZ2yM0Q=="], - - "@vitest/utils": ["@vitest/utils@3.0.6", "", { "dependencies": { "@vitest/pretty-format": "3.0.6", "loupe": "^3.1.3", "tinyrainbow": "^2.0.0" } }, "sha512-18ktZpf4GQFTbf9jK543uspU03Q2qya7ZGya5yiZ0Gx0nnnalBvd5ZBislbl2EhLjM8A8rt4OilqKG7QwcGkvQ=="], - - "@yr/monotone-cubic-spline": ["@yr/monotone-cubic-spline@1.0.3", "", {}, "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA=="], - - "a-sync-waterfall": ["a-sync-waterfall@1.0.1", "", {}, "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA=="], - - "acorn": ["acorn@8.14.0", "", { "bin": "bin/acorn" }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], - - "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], - - "acorn-typescript": ["acorn-typescript@1.4.13", "", { "peerDependencies": { "acorn": ">=8.9.0" } }, "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q=="], - - "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], - - "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - - "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - - "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], - - "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], - - "apexcharts": ["apexcharts@3.54.1", "", { "dependencies": { "@yr/monotone-cubic-spline": "^1.0.3", "svg.draggable.js": "^2.2.2", "svg.easing.js": "^2.0.0", "svg.filter.js": "^2.0.2", "svg.pathmorphing.js": "^0.1.3", "svg.resize.js": "^1.4.3", "svg.select.js": "^3.0.1" } }, "sha512-E4et0h/J1U3r3EwS/WlqJCQIbepKbp6wGUmaAwJOMjHUP4Ci0gxanLa7FR3okx6p9coi4st6J853/Cb1NP0vpA=="], - - "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], - - "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], - - "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], - - "asap": ["asap@2.0.6", "", {}, "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="], - - "asciidoctor": ["asciidoctor@3.0.4", "", { "dependencies": { "@asciidoctor/cli": "4.0.0", "@asciidoctor/core": "3.0.4", "ejs": "^3.1.2", "handlebars": "^4.7.6", "nunjucks": "^3.2.1", "pug": "^3.0.0" }, "bin": { "asciidoctor": "bin/asciidoctor", "asciidoctorjs": "bin/asciidoctor" } }, "sha512-hIc0Bx73wePxtic+vWBHOIgMfKSNiCmRz7BBfkyykXATrw20YGd5a3CozCHvqEPH+Wxp5qKD4aBsgtokez8nEA=="], - - "assert-never": ["assert-never@1.4.0", "", {}, "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA=="], - - "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], - - "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], - - "autoprefixer": ["autoprefixer@10.4.20", "", { "dependencies": { "browserslist": "^4.23.3", "caniuse-lite": "^1.0.30001646", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.0.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": "bin/autoprefixer" }, "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g=="], - - "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], - - "babel-walk": ["babel-walk@3.0.0-canary-5", "", { "dependencies": { "@babel/types": "^7.9.6" } }, "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw=="], - - "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - - "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], - - "brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="], - - "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - - "browserslist": ["browserslist@4.24.3", "", { "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": "cli.js" }, "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA=="], - - "bufferutil": ["bufferutil@4.0.8", "", { "dependencies": { "node-gyp-build": "^4.3.0" } }, "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw=="], - - "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], - - "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.1", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g=="], - - "call-bound": ["call-bound@1.0.3", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "get-intrinsic": "^1.2.6" } }, "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA=="], - - "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], - - "camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="], - - "caniuse-lite": ["caniuse-lite@1.0.30001690", "", {}, "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w=="], - - "chai": ["chai@5.2.0", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw=="], - - "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - - "character-parser": ["character-parser@2.2.0", "", { "dependencies": { "is-regex": "^1.0.3" } }, "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw=="], - - "check-error": ["check-error@2.1.1", "", {}, "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw=="], - - "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], - - "cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="], - - "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - - "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - - "commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], - - "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], - - "constantinople": ["constantinople@4.0.1", "", { "dependencies": { "@babel/parser": "^7.6.0", "@babel/types": "^7.6.1" } }, "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw=="], - - "cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="], - - "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], - - "cssesc": ["cssesc@3.0.0", "", { "bin": "bin/cssesc" }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], - - "d": ["d@1.0.2", "", { "dependencies": { "es5-ext": "^0.10.64", "type": "^2.7.2" } }, "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw=="], - - "d3": ["d3@7.9.0", "", { "dependencies": { "d3-array": "3", "d3-axis": "3", "d3-brush": "3", "d3-chord": "3", "d3-color": "3", "d3-contour": "4", "d3-delaunay": "6", "d3-dispatch": "3", "d3-drag": "3", "d3-dsv": "3", "d3-ease": "3", "d3-fetch": "3", "d3-force": "3", "d3-format": "3", "d3-geo": "3", "d3-hierarchy": "3", "d3-interpolate": "3", "d3-path": "3", "d3-polygon": "3", "d3-quadtree": "3", "d3-random": "3", "d3-scale": "4", "d3-scale-chromatic": "3", "d3-selection": "3", "d3-shape": "3", "d3-time": "3", "d3-time-format": "4", "d3-timer": "3", "d3-transition": "3", "d3-zoom": "3" } }, "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA=="], - - "d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="], - - "d3-axis": ["d3-axis@3.0.0", "", {}, "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw=="], - - "d3-brush": ["d3-brush@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", "d3-interpolate": "1 - 3", "d3-selection": "3", "d3-transition": "3" } }, "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ=="], - - "d3-chord": ["d3-chord@3.0.1", "", { "dependencies": { "d3-path": "1 - 3" } }, "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g=="], - - "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="], - - "d3-contour": ["d3-contour@4.0.2", "", { "dependencies": { "d3-array": "^3.2.0" } }, "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA=="], - - "d3-delaunay": ["d3-delaunay@6.0.4", "", { "dependencies": { "delaunator": "5" } }, "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A=="], - - "d3-dispatch": ["d3-dispatch@3.0.1", "", {}, "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg=="], - - "d3-drag": ["d3-drag@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-selection": "3" } }, "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg=="], - - "d3-dsv": ["d3-dsv@3.0.1", "", { "dependencies": { "commander": "7", "iconv-lite": "0.6", "rw": "1" }, "bin": { "csv2json": "bin/dsv2json.js", "csv2tsv": "bin/dsv2dsv.js", "dsv2dsv": "bin/dsv2dsv.js", "dsv2json": "bin/dsv2json.js", "json2csv": "bin/json2dsv.js", "json2dsv": "bin/json2dsv.js", "json2tsv": "bin/json2dsv.js", "tsv2csv": "bin/dsv2dsv.js", "tsv2json": "bin/dsv2json.js" } }, "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q=="], - - "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="], - - "d3-fetch": ["d3-fetch@3.0.1", "", { "dependencies": { "d3-dsv": "1 - 3" } }, "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw=="], - - "d3-force": ["d3-force@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-quadtree": "1 - 3", "d3-timer": "1 - 3" } }, "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg=="], - - "d3-format": ["d3-format@3.1.0", "", {}, "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA=="], - - "d3-geo": ["d3-geo@3.1.1", "", { "dependencies": { "d3-array": "2.5.0 - 3" } }, "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q=="], - - "d3-hierarchy": ["d3-hierarchy@3.1.2", "", {}, "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA=="], - - "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="], - - "d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="], - - "d3-polygon": ["d3-polygon@3.0.1", "", {}, "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg=="], - - "d3-quadtree": ["d3-quadtree@3.0.1", "", {}, "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw=="], - - "d3-random": ["d3-random@3.0.1", "", {}, "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ=="], - - "d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="], - - "d3-scale-chromatic": ["d3-scale-chromatic@3.1.0", "", { "dependencies": { "d3-color": "1 - 3", "d3-interpolate": "1 - 3" } }, "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ=="], - - "d3-selection": ["d3-selection@3.0.0", "", {}, "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="], - - "d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "^3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="], - - "d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "2 - 3" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="], - - "d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="], - - "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="], - - "d3-transition": ["d3-transition@3.0.1", "", { "dependencies": { "d3-color": "1 - 3", "d3-dispatch": "1 - 3", "d3-ease": "1 - 3", "d3-interpolate": "1 - 3", "d3-timer": "1 - 3" }, "peerDependencies": { "d3-selection": "2 - 3" } }, "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w=="], - - "d3-zoom": ["d3-zoom@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", "d3-interpolate": "1 - 3", "d3-selection": "2 - 3", "d3-transition": "2 - 3" } }, "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw=="], - - "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], - - "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], - - "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], - - "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], - - "delaunator": ["delaunator@5.0.1", "", { "dependencies": { "robust-predicates": "^3.0.2" } }, "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw=="], - - "devalue": ["devalue@5.1.1", "", {}, "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw=="], - - "dexie": ["dexie@4.0.10", "", {}, "sha512-eM2RzuR3i+M046r2Q0Optl3pS31qTWf8aFuA7H9wnsHTwl8EPvroVLwvQene/6paAs39Tbk6fWZcn2aZaHkc/w=="], - - "didyoumean": ["didyoumean@1.2.2", "", {}, "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="], - - "dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="], - - "doctypes": ["doctypes@1.1.0", "", {}, "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ=="], - - "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], - - "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], - - "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": "bin/cli.js" }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], - - "electron-to-chromium": ["electron-to-chromium@1.5.74", "", {}, "sha512-ck3//9RC+6oss/1Bh9tiAVFy5vfSKbRHAFh7Z3/eTRkEqJeWgymloShB17Vg3Z4nmDNp35vAd1BZ6CMW4Wt6Iw=="], - - "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - - "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], - - "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], - - "es-module-lexer": ["es-module-lexer@1.6.0", "", {}, "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ=="], - - "es-object-atoms": ["es-object-atoms@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw=="], - - "es5-ext": ["es5-ext@0.10.64", "", { "dependencies": { "es6-iterator": "^2.0.3", "es6-symbol": "^3.1.3", "esniff": "^2.0.1", "next-tick": "^1.1.0" } }, "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg=="], - - "es6-iterator": ["es6-iterator@2.0.3", "", { "dependencies": { "d": "1", "es5-ext": "^0.10.35", "es6-symbol": "^3.1.1" } }, "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g=="], - - "es6-symbol": ["es6-symbol@3.1.4", "", { "dependencies": { "d": "^1.0.2", "ext": "^1.7.0" } }, "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg=="], - - "esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": "bin/esbuild" }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="], - - "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], - - "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], - - "eslint": ["eslint@9.17.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.9.0", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "9.17.0", "@eslint/plugin-kit": "^0.2.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "bin": "bin/eslint.js" }, "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA=="], - - "eslint-compat-utils": ["eslint-compat-utils@0.5.1", "", { "dependencies": { "semver": "^7.5.4" }, "peerDependencies": { "eslint": ">=6.0.0" } }, "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q=="], - - "eslint-plugin-svelte": ["eslint-plugin-svelte@2.46.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@jridgewell/sourcemap-codec": "^1.4.15", "eslint-compat-utils": "^0.5.1", "esutils": "^2.0.3", "known-css-properties": "^0.35.0", "postcss": "^8.4.38", "postcss-load-config": "^3.1.4", "postcss-safe-parser": "^6.0.0", "postcss-selector-parser": "^6.1.0", "semver": "^7.6.2", "svelte-eslint-parser": "^0.43.0" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0-0 || ^9.0.0-0", "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" } }, "sha512-7xYr2o4NID/f9OEYMqxsEQsCsj4KaMy4q5sANaKkAb6/QeCjYFxRmDm2S3YC3A3pl1kyPZ/syOx/i7LcWYSbIw=="], - - "eslint-scope": ["eslint-scope@8.2.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A=="], - - "eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="], - - "esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="], - - "esniff": ["esniff@2.0.1", "", { "dependencies": { "d": "^1.0.1", "es5-ext": "^0.10.62", "event-emitter": "^0.3.5", "type": "^2.7.2" } }, "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg=="], - - "espree": ["espree@10.3.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.0" } }, "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg=="], - - "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], - - "esrap": ["esrap@1.3.2", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-C4PXusxYhFT98GjLSmb20k9PREuUdporer50dhzGuJu9IJXktbMddVCMLAERl5dAHyAi73GWWCE4FVHGP1794g=="], - - "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], - - "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], - - "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], - - "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], - - "event-emitter": ["event-emitter@0.3.5", "", { "dependencies": { "d": "1", "es5-ext": "~0.10.14" } }, "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA=="], - - "expect-type": ["expect-type@1.1.0", "", {}, "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA=="], - - "ext": ["ext@1.7.0", "", { "dependencies": { "type": "^2.7.2" } }, "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw=="], - - "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], - - "fast-glob": ["fast-glob@3.3.2", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow=="], - - "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], - - "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], - - "fastq": ["fastq@1.17.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w=="], - - "fdir": ["fdir@6.4.2", "", { "peerDependencies": { "picomatch": "^3 || ^4" } }, "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ=="], - - "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], - - "filelist": ["filelist@1.0.4", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q=="], - - "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], - - "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], - - "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], - - "flatted": ["flatted@3.3.2", "", {}, "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA=="], - - "flowbite": ["flowbite@2.5.2", "", { "dependencies": { "@popperjs/core": "^2.9.3", "flowbite-datepicker": "^1.3.0", "mini-svg-data-uri": "^1.4.3" } }, "sha512-kwFD3n8/YW4EG8GlY3Od9IoKND97kitO+/ejISHSqpn3vw2i5K/+ZI8Jm2V+KC4fGdnfi0XZ+TzYqQb4Q1LshA=="], - - "flowbite-datepicker": ["flowbite-datepicker@1.3.1", "", { "dependencies": { "@rollup/plugin-node-resolve": "^15.2.3", "flowbite": "^2.0.0" } }, "sha512-FM8EZE0Vc/nhEr+FcvJQldkIeS3hGhDQY5hoTWvqSrnlAqNd1JJhSj9bNiq6xpIXLqewWiTONiRVMUcUcSSiQA=="], - - "flowbite-svelte": ["flowbite-svelte@0.47.4", "", { "dependencies": { "@floating-ui/dom": "^1.6.11", "apexcharts": "^3.54.1", "flowbite": "^2.5.2", "tailwind-merge": "^2.5.4" }, "peerDependencies": { "svelte": "^3.55.1 || ^4.0.0 || ^5.0.0" } }, "sha512-8oiY/oeWA7fgkDF91MZKEBo5VmjL8El3wuqTDWAFO1j7p45BHIL6G1VGnnidgCEYlbADDQN9BIGCvyPq4J3g+w=="], - - "flowbite-svelte-icons": ["flowbite-svelte-icons@2.0.2", "", { "dependencies": { "tailwind-merge": "^2.5.4", "tailwindcss": "^3.4.14" }, "peerDependencies": { "svelte": "^5.0.0", "tailwind-merge": "^2.3.0", "tailwindcss": "^3.4.3" } }, "sha512-Vkmduy2867Rk8R7TziPirsWkixJnToFBEXRaN4ouJabOx62NQjiBbHFe+HTaMOQmdp4FNMI2Nhtk2I2CQ8r3RQ=="], - - "foreground-child": ["foreground-child@3.3.0", "", { "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" } }, "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg=="], - - "fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="], - - "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], - - "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - - "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], - - "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], - - "get-intrinsic": ["get-intrinsic@1.2.6", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "dunder-proto": "^1.0.0", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.0.0" } }, "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA=="], - - "glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], - - "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], - - "globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], - - "globalyzer": ["globalyzer@0.1.0", "", {}, "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q=="], - - "globrex": ["globrex@0.1.2", "", {}, "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg=="], - - "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], - - "handlebars": ["handlebars@4.7.8", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": "bin/handlebars" }, "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ=="], - - "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], - - "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], - - "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], - - "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], - - "he": ["he@1.2.0", "", { "bin": "bin/he" }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="], - - "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], - - "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], - - "import-fresh": ["import-fresh@3.3.0", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw=="], - - "import-meta-resolve": ["import-meta-resolve@4.1.0", "", {}, "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw=="], - - "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], - - "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], - - "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], - - "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], - - "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], - - "is-core-module": ["is-core-module@2.16.0", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-urTSINYfAYgcbLb0yDQ6egFm6h3Mo1DcF9EkyXSRjjzdHbsulg01qhwWuXdOoUBuTkbQ80KDboXa0vFJ+BDH+g=="], - - "is-expression": ["is-expression@4.0.0", "", { "dependencies": { "acorn": "^7.1.1", "object-assign": "^4.1.1" } }, "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A=="], - - "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], - - "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], - - "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], - - "is-module": ["is-module@1.0.0", "", {}, "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g=="], - - "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], - - "is-promise": ["is-promise@2.2.2", "", {}, "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="], - - "is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="], - - "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], - - "is-typedarray": ["is-typedarray@1.0.0", "", {}, "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="], - - "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - - "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], - - "jake": ["jake@10.9.2", "", { "dependencies": { "async": "^3.2.3", "chalk": "^4.0.2", "filelist": "^1.0.4", "minimatch": "^3.1.2" }, "bin": "bin/cli.js" }, "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA=="], - - "jiti": ["jiti@1.21.7", "", { "bin": "bin/jiti.js" }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="], - - "js-stringify": ["js-stringify@1.0.2", "", {}, "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g=="], - - "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": "bin/js-yaml.js" }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], - - "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], - - "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], - - "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], - - "jstransformer": ["jstransformer@1.0.0", "", { "dependencies": { "is-promise": "^2.0.0", "promise": "^7.0.1" } }, "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A=="], - - "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], - - "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], - - "known-css-properties": ["known-css-properties@0.35.0", "", {}, "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A=="], - - "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], - - "light-bolt11-decoder": ["light-bolt11-decoder@3.2.0", "", { "dependencies": { "@scure/base": "1.1.1" } }, "sha512-3QEofgiBOP4Ehs9BI+RkZdXZNtSys0nsJ6fyGeSiAGCBsMwHGUDS/JQlY/sTnWs91A2Nh0S9XXfA8Sy9g6QpuQ=="], - - "lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], - - "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], - - "locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="], - - "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], - - "lodash.castarray": ["lodash.castarray@4.4.0", "", {}, "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q=="], - - "lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="], - - "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], - - "loupe": ["loupe@3.1.3", "", {}, "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug=="], - - "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - - "magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="], - - "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], - - "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], - - "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], - - "mini-svg-data-uri": ["mini-svg-data-uri@1.4.4", "", { "bin": "cli.js" }, "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg=="], - - "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], - - "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], - - "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], - - "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], - - "mrmime": ["mrmime@2.0.0", "", {}, "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw=="], - - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - - "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], - - "nanoid": ["nanoid@3.3.8", "", { "bin": "bin/nanoid.cjs" }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="], - - "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], - - "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], - - "next-tick": ["next-tick@1.1.0", "", {}, "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="], - - "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], - - "node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="], - - "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], - - "normalize-range": ["normalize-range@0.1.2", "", {}, "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA=="], - - "nostr-tools": ["nostr-tools@2.10.4", "", { "dependencies": { "@noble/ciphers": "^0.5.1", "@noble/curves": "1.2.0", "@noble/hashes": "1.3.1", "@scure/base": "1.1.1", "@scure/bip32": "1.3.1", "@scure/bip39": "1.2.1" }, "optionalDependencies": { "nostr-wasm": "0.1.0" }, "peerDependencies": { "typescript": ">=5.0.0" } }, "sha512-biU7sk+jxHgVASfobg2T5ttxOGGSt69wEVBC51sHHOEaKAAdzHBLV/I2l9Rf61UzClhliZwNouYhqIso4a3HYg=="], - - "nostr-wasm": ["nostr-wasm@0.1.0", "", {}, "sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA=="], - - "nunjucks": ["nunjucks@3.2.4", "", { "dependencies": { "a-sync-waterfall": "^1.0.0", "asap": "^2.0.3", "commander": "^5.1.0" }, "peerDependencies": { "chokidar": "^3.3.0" }, "bin": { "nunjucks-precompile": "bin/precompile" } }, "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ=="], - - "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], - - "object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="], - - "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], - - "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], - - "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], - - "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], - - "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], - - "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], - - "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], - - "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], - - "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], - - "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - - "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - - "pathval": ["pathval@2.0.0", "", {}, "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA=="], - - "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - - "picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], - - "pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="], - - "pirates": ["pirates@4.0.6", "", {}, "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg=="], - - "playwright": ["playwright@1.50.1", "", { "dependencies": { "playwright-core": "1.50.1" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": "cli.js" }, "sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw=="], - - "playwright-core": ["playwright-core@1.50.1", "", { "bin": "cli.js" }, "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ=="], - - "postcss": ["postcss@8.4.49", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA=="], - - "postcss-import": ["postcss-import@15.1.0", "", { "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", "resolve": "^1.1.7" }, "peerDependencies": { "postcss": "^8.0.0" } }, "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew=="], - - "postcss-js": ["postcss-js@4.0.1", "", { "dependencies": { "camelcase-css": "^2.0.1" }, "peerDependencies": { "postcss": "^8.4.21" } }, "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw=="], - - "postcss-load-config": ["postcss-load-config@6.0.1", "", { "dependencies": { "lilconfig": "^3.1.1" }, "peerDependencies": { "jiti": ">=1.21.0", "postcss": ">=8.0.9", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["tsx"] }, "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g=="], - - "postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="], - - "postcss-safe-parser": ["postcss-safe-parser@6.0.0", "", { "peerDependencies": { "postcss": "^8.3.3" } }, "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ=="], - - "postcss-scss": ["postcss-scss@4.0.9", "", { "peerDependencies": { "postcss": "^8.4.29" } }, "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A=="], - - "postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], - - "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], - - "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], - - "prettier": ["prettier@3.4.2", "", { "bin": "bin/prettier.cjs" }, "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ=="], - - "prettier-plugin-svelte": ["prettier-plugin-svelte@3.3.2", "", { "peerDependencies": { "prettier": "^3.0.0", "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" } }, "sha512-kRPjH8wSj2iu+dO+XaUv4vD8qr5mdDmlak3IT/7AOgGIMRG86z/EHOLauFcClKEnOUf4A4nOA7sre5KrJD4Raw=="], - - "promise": ["promise@7.3.1", "", { "dependencies": { "asap": "~2.0.3" } }, "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg=="], - - "pug": ["pug@3.0.3", "", { "dependencies": { "pug-code-gen": "^3.0.3", "pug-filters": "^4.0.0", "pug-lexer": "^5.0.1", "pug-linker": "^4.0.0", "pug-load": "^3.0.0", "pug-parser": "^6.0.0", "pug-runtime": "^3.0.1", "pug-strip-comments": "^2.0.0" } }, "sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g=="], - - "pug-attrs": ["pug-attrs@3.0.0", "", { "dependencies": { "constantinople": "^4.0.1", "js-stringify": "^1.0.2", "pug-runtime": "^3.0.0" } }, "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA=="], - - "pug-code-gen": ["pug-code-gen@3.0.3", "", { "dependencies": { "constantinople": "^4.0.1", "doctypes": "^1.1.0", "js-stringify": "^1.0.2", "pug-attrs": "^3.0.0", "pug-error": "^2.1.0", "pug-runtime": "^3.0.1", "void-elements": "^3.1.0", "with": "^7.0.0" } }, "sha512-cYQg0JW0w32Ux+XTeZnBEeuWrAY7/HNE6TWnhiHGnnRYlCgyAUPoyh9KzCMa9WhcJlJ1AtQqpEYHc+vbCzA+Aw=="], - - "pug-error": ["pug-error@2.1.0", "", {}, "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg=="], - - "pug-filters": ["pug-filters@4.0.0", "", { "dependencies": { "constantinople": "^4.0.1", "jstransformer": "1.0.0", "pug-error": "^2.0.0", "pug-walk": "^2.0.0", "resolve": "^1.15.1" } }, "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A=="], - - "pug-lexer": ["pug-lexer@5.0.1", "", { "dependencies": { "character-parser": "^2.2.0", "is-expression": "^4.0.0", "pug-error": "^2.0.0" } }, "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w=="], - - "pug-linker": ["pug-linker@4.0.0", "", { "dependencies": { "pug-error": "^2.0.0", "pug-walk": "^2.0.0" } }, "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw=="], - - "pug-load": ["pug-load@3.0.0", "", { "dependencies": { "object-assign": "^4.1.1", "pug-walk": "^2.0.0" } }, "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ=="], - - "pug-parser": ["pug-parser@6.0.0", "", { "dependencies": { "pug-error": "^2.0.0", "token-stream": "1.0.0" } }, "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw=="], - - "pug-runtime": ["pug-runtime@3.0.1", "", {}, "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg=="], - - "pug-strip-comments": ["pug-strip-comments@2.0.0", "", { "dependencies": { "pug-error": "^2.0.0" } }, "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ=="], - - "pug-walk": ["pug-walk@2.0.0", "", {}, "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ=="], - - "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], - - "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], - - "read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="], - - "readdirp": ["readdirp@4.0.2", "", {}, "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA=="], - - "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], - - "resolve": ["resolve@1.22.9", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-QxrmX1DzraFIi9PxdG5VkRfRwIgjwyud+z/iBwfRRrVmHc+P9Q7u2lSSpQ6bjr2gy5lrqIiU9vb6iAeGf2400A=="], - - "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], - - "reusify": ["reusify@1.0.4", "", {}, "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="], - - "robust-predicates": ["robust-predicates@3.0.2", "", {}, "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="], - - "rollup": ["rollup@4.28.1", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-linux-x64-gnu": "4.28.1", "@rollup/rollup-linux-x64-musl": "4.28.1", "fsevents": "~2.3.2" }, "bin": "dist/bin/rollup" }, "sha512-61fXYl/qNVinKmGSTHAZ6Yy8I3YIJC/r2m9feHo6SwVAVcLT5MPwOUFe7EuURA/4m0NR8lXG4BBXuo/IZEsjMg=="], - - "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], - - "rw": ["rw@1.3.3", "", {}, "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="], - - "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], - - "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], - - "semver": ["semver@7.6.3", "", { "bin": "bin/semver.js" }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="], - - "set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="], - - "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], - - "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], - - "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="], - - "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - - "sirv": ["sirv@3.0.0", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg=="], - - "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], - - "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], - - "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], - - "std-env": ["std-env@3.8.0", "", {}, "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w=="], - - "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - - "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - - "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - - "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - - "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], - - "sucrase": ["sucrase@3.35.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA=="], - - "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - - "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - - "svelte": ["svelte@5.14.4", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "@jridgewell/sourcemap-codec": "^1.5.0", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "acorn-typescript": "^1.4.13", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "esm-env": "^1.2.1", "esrap": "^1.3.1", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-2iR/UHHA2Dsldo4JdXDcdqT+spueuh+uNYw1FoTKBbpnFEECVISeqSo0uubPS4AfBE0xI6u7DGHxcdq3DTDmoQ=="], - - "svelte-adapter-bun": ["svelte-adapter-bun@0.5.2", "", { "dependencies": { "tiny-glob": "^0.2.9" } }, "sha512-xEtFgaal6UgrCwwkSIcapO9kopoFNUYCYqyKCikdqxX9bz2TDYnrWQZ7qBnkunMxi1HOIERUCvTcebYGiarZLA=="], - - "svelte-check": ["svelte-check@4.1.1", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": "bin/svelte-check" }, "sha512-NfaX+6Qtc8W/CyVGS/F7/XdiSSyXz+WGYA9ZWV3z8tso14V2vzjfXviKaTFEzB7g8TqfgO2FOzP6XT4ApSTUTw=="], - - "svelte-eslint-parser": ["svelte-eslint-parser@0.43.0", "", { "dependencies": { "eslint-scope": "^7.2.2", "eslint-visitor-keys": "^3.4.3", "espree": "^9.6.1", "postcss": "^8.4.39", "postcss-scss": "^4.0.9" }, "peerDependencies": { "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" } }, "sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA=="], - - "svg.draggable.js": ["svg.draggable.js@2.2.2", "", { "dependencies": { "svg.js": "^2.0.1" } }, "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw=="], - - "svg.easing.js": ["svg.easing.js@2.0.0", "", { "dependencies": { "svg.js": ">=2.3.x" } }, "sha512-//ctPdJMGy22YoYGV+3HEfHbm6/69LJUTAqI2/5qBvaNHZ9uUFVC82B0Pl299HzgH13rKrBgi4+XyXXyVWWthA=="], - - "svg.filter.js": ["svg.filter.js@2.0.2", "", { "dependencies": { "svg.js": "^2.2.5" } }, "sha512-xkGBwU+dKBzqg5PtilaTb0EYPqPfJ9Q6saVldX+5vCRy31P6TlRCP3U9NxH3HEufkKkpNgdTLBJnmhDHeTqAkw=="], - - "svg.js": ["svg.js@2.7.1", "", {}, "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA=="], - - "svg.pathmorphing.js": ["svg.pathmorphing.js@0.1.3", "", { "dependencies": { "svg.js": "^2.4.0" } }, "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww=="], - - "svg.resize.js": ["svg.resize.js@1.4.3", "", { "dependencies": { "svg.js": "^2.6.5", "svg.select.js": "^2.1.2" } }, "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw=="], - - "svg.select.js": ["svg.select.js@3.0.1", "", { "dependencies": { "svg.js": "^2.6.5" } }, "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw=="], - - "tailwind-merge": ["tailwind-merge@2.5.5", "", {}, "sha512-0LXunzzAZzo0tEPxV3I297ffKZPlKDrjj7NXphC8V5ak9yHC5zRmxnOe2m/Rd/7ivsOMJe3JZ2JVocoDdQTRBA=="], - - "tailwindcss": ["tailwindcss@3.4.17", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.6", "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.2", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og=="], - - "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], - - "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], - - "tiny-glob": ["tiny-glob@0.2.9", "", { "dependencies": { "globalyzer": "0.1.0", "globrex": "^0.1.2" } }, "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg=="], - - "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], - - "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], - - "tinypool": ["tinypool@1.0.2", "", {}, "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA=="], - - "tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="], - - "tinyspy": ["tinyspy@3.0.2", "", {}, "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q=="], - - "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], - - "token-stream": ["token-stream@1.0.0", "", {}, "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg=="], - - "totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="], - - "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], - - "tseep": ["tseep@1.3.1", "", {}, "sha512-ZPtfk1tQnZVyr7BPtbJ93qaAh2lZuIOpTMjhrYa4XctT8xe7t4SAW9LIxrySDuYMsfNNayE51E/WNGrNVgVicQ=="], - - "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - - "tstl": ["tstl@2.5.16", "", {}, "sha512-+O2ybLVLKcBwKm4HymCEwZIT0PpwS3gCYnxfSDEjJEKADvIFruaQjd3m7CAKNU1c7N3X3WjVz87re7TA2A5FUw=="], - - "type": ["type@2.7.3", "", {}, "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ=="], - - "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], - - "typedarray-to-buffer": ["typedarray-to-buffer@3.1.5", "", { "dependencies": { "is-typedarray": "^1.0.0" } }, "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q=="], - - "typescript": ["typescript@5.7.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg=="], - - "typescript-lru-cache": ["typescript-lru-cache@2.0.0", "", {}, "sha512-Jp57Qyy8wXeMkdNuZiglE6v2Cypg13eDA1chHwDG6kq51X7gk4K7P7HaDdzZKCxkegXkVHNcPD0n5aW6OZH3aA=="], - - "uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="], - - "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], - - "unxhr": ["unxhr@1.2.0", "", {}, "sha512-6cGpm8NFXPD9QbSNx0cD2giy7teZ6xOkCUH3U89WKVkL9N9rBrWjlCwhR94Re18ZlAop4MOc3WU1M3Hv/bgpIw=="], - - "update-browserslist-db": ["update-browserslist-db@1.1.1", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.0" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A=="], - - "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], - - "utf-8-validate": ["utf-8-validate@5.0.10", "", { "dependencies": { "node-gyp-build": "^4.3.0" } }, "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ=="], - - "utf8-buffer": ["utf8-buffer@1.0.0", "", {}, "sha512-ueuhzvWnp5JU5CiGSY4WdKbiN/PO2AZ/lpeLiz2l38qwdLy/cW40XobgyuIWucNyum0B33bVB0owjFCeGBSLqg=="], - - "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], - - "vite": ["vite@5.4.14", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": "bin/vite.js" }, "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA=="], - - "vite-node": ["vite-node@3.0.6", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.0", "es-module-lexer": "^1.6.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0" }, "bin": "vite-node.mjs" }, "sha512-s51RzrTkXKJrhNbUzQRsarjmAae7VmMPAsRT7lppVpIg6mK3zGthP9Hgz0YQQKuNcF+Ii7DfYk3Fxz40jRmePw=="], - - "vitefu": ["vitefu@1.0.5", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" } }, "sha512-h4Vflt9gxODPFNGPwp4zAMZRpZR7eslzwH2c5hn5kNZ5rhnKyRJ50U+yGCdc2IRaBs8O4haIgLNGrV5CrpMsCA=="], - - "vitest": ["vitest@3.0.6", "", { "dependencies": { "@vitest/expect": "3.0.6", "@vitest/mocker": "3.0.6", "@vitest/pretty-format": "^3.0.6", "@vitest/runner": "3.0.6", "@vitest/snapshot": "3.0.6", "@vitest/spy": "3.0.6", "@vitest/utils": "3.0.6", "chai": "^5.2.0", "debug": "^4.4.0", "expect-type": "^1.1.0", "magic-string": "^0.30.17", "pathe": "^2.0.3", "std-env": "^3.8.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinypool": "^1.0.2", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0", "vite-node": "3.0.6", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.0.6", "@vitest/ui": "3.0.6", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": "vitest.mjs" }, "sha512-/iL1Sc5VeDZKPDe58oGK4HUFLhw6b5XdY1MYawjuSaDA4sEfYlY9HnS6aCEG26fX+MgUi7MwlduTBHHAI/OvMA=="], - - "void-elements": ["void-elements@3.1.0", "", {}, "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="], - - "websocket": ["websocket@1.0.35", "", { "dependencies": { "bufferutil": "^4.0.1", "debug": "^2.2.0", "es5-ext": "^0.10.63", "typedarray-to-buffer": "^3.1.5", "utf-8-validate": "^5.0.2", "yaeti": "^0.0.6" } }, "sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q=="], - - "websocket-polyfill": ["websocket-polyfill@0.0.3", "", { "dependencies": { "tstl": "^2.0.7", "websocket": "^1.0.28" } }, "sha512-pF3kR8Uaoau78MpUmFfzbIRxXj9PeQrCuPepGE6JIsfsJ/o/iXr07Q2iQNzKSSblQJ0FiGWlS64N4pVSm+O3Dg=="], - - "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], - - "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": "cli.js" }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="], - - "with": ["with@7.0.2", "", { "dependencies": { "@babel/parser": "^7.9.6", "@babel/types": "^7.9.6", "assert-never": "^1.2.1", "babel-walk": "3.0.0-canary-5" } }, "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w=="], - - "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], - - "wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="], - - "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - - "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - - "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], - - "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], - - "yaeti": ["yaeti@0.0.6", "", {}, "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug=="], - - "yaml": ["yaml@2.6.1", "", { "bin": "bin.mjs" }, "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg=="], - - "yargs": ["yargs@17.3.1", "", { "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.0.0" } }, "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA=="], - - "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], - - "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - - "zimmerframe": ["zimmerframe@1.1.2", "", {}, "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w=="], - - "@asciidoctor/opal-runtime/glob": ["glob@8.1.0", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^5.0.1", "once": "^1.3.0" } }, "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ=="], - - "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], - - "@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], - - "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], - - "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], - - "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], - - "@noble/curves/@noble/hashes": ["@noble/hashes@1.6.0", "", {}, "sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ=="], - - "@nostr-dev-kit/ndk-cache-dexie/@nostr-dev-kit/ndk": ["@nostr-dev-kit/ndk@2.10.7", "", { "dependencies": { "@noble/curves": "^1.6.0", "@noble/hashes": "^1.5.0", "@noble/secp256k1": "^2.1.0", "@scure/base": "^1.1.9", "debug": "^4.3.6", "light-bolt11-decoder": "^3.2.0", "nostr-tools": "^2.7.1", "tseep": "^1.2.2", "typescript-lru-cache": "^2.0.0", "utf8-buffer": "^1.0.0", "websocket-polyfill": "^0.0.3" } }, "sha512-cylva8jsaAGMijxAI32CnJWlzvwD4sWyl86/+RMS6xpZn4MIgeVUfBFc/pYkcfZzDP3v1Z9mIPsuiICRyvu9yQ=="], - - "@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], - - "@scure/bip32/@noble/curves": ["@noble/curves@1.1.0", "", { "dependencies": { "@noble/hashes": "1.3.1" } }, "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA=="], - - "@scure/bip32/@noble/hashes": ["@noble/hashes@1.3.3", "", {}, "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA=="], - - "@scure/bip32/@scure/base": ["@scure/base@1.1.9", "", {}, "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg=="], - - "@scure/bip39/@noble/hashes": ["@noble/hashes@1.3.3", "", {}, "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA=="], - - "@scure/bip39/@scure/base": ["@scure/base@1.1.9", "", {}, "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg=="], - - "@tailwindcss/typography/postcss-selector-parser": ["postcss-selector-parser@6.0.10", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w=="], - - "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - - "d3-dsv/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], - - "eslint-plugin-svelte/postcss-load-config": ["postcss-load-config@3.1.4", "", { "dependencies": { "lilconfig": "^2.0.5", "yaml": "^1.10.2" }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" }, "optionalPeers": ["ts-node"] }, "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg=="], - - "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - - "filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], - - "glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "is-expression/acorn": ["acorn@7.4.1", "", { "bin": "bin/acorn" }, "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="], - - "light-bolt11-decoder/@scure/base": ["@scure/base@1.1.1", "", {}, "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA=="], - - "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - - "nostr-tools/@noble/curves": ["@noble/curves@1.2.0", "", { "dependencies": { "@noble/hashes": "1.3.2" } }, "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw=="], - - "nostr-tools/@noble/hashes": ["@noble/hashes@1.3.1", "", {}, "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA=="], - - "nostr-tools/@scure/base": ["@scure/base@1.1.1", "", {}, "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA=="], - - "nunjucks/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], - - "nunjucks/commander": ["commander@5.1.0", "", {}, "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="], - - "playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], - - "postcss-nested/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], - - "svelte-eslint-parser/eslint-scope": ["eslint-scope@7.2.2", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg=="], - - "svelte-eslint-parser/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], - - "svelte-eslint-parser/espree": ["espree@9.6.1", "", { "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" } }, "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ=="], - - "svg.resize.js/svg.select.js": ["svg.select.js@2.1.2", "", { "dependencies": { "svg.js": "^2.2.5" } }, "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ=="], - - "tailwindcss/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], - - "tailwindcss/postcss-load-config": ["postcss-load-config@4.0.2", "", { "dependencies": { "lilconfig": "^3.0.0", "yaml": "^2.3.4" }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" }, "optionalPeers": ["ts-node"] }, "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ=="], - - "tailwindcss/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], - - "websocket/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - - "@asciidoctor/opal-runtime/glob/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], - - "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], - - "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], - - "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], - - "@scure/bip32/@noble/curves/@noble/hashes": ["@noble/hashes@1.3.1", "", {}, "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA=="], - - "eslint-plugin-svelte/postcss-load-config/lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="], - - "eslint-plugin-svelte/postcss-load-config/yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="], - - "filelist/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], - - "glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], - - "nostr-tools/@noble/curves/@noble/hashes": ["@noble/hashes@1.3.2", "", {}, "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ=="], - - "nunjucks/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - - "nunjucks/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], - - "tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - - "tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], - - "websocket/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - - "@asciidoctor/opal-runtime/glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], - - "nunjucks/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - - "tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - } -} From 3036214ca78c7f85defe669158e7bd94982bdc2c Mon Sep 17 00:00:00 2001 From: vnugent Date: Fri, 18 Jul 2025 11:50:20 -0400 Subject: [PATCH 118/135] chore(readme): correct the readme for container builds - Removed the plain docker build since we didn't have a docker file, those instructions didnt work - Corrected the deno container build instructions --- README.md | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/README.md b/README.md index 5615dac..274657e 100644 --- a/README.md +++ b/README.md @@ -69,37 +69,6 @@ or with Deno: deno task preview ``` -## Docker - -This docker container performs the build. - -To build the container: - -```bash -docker build . -t gc-alexandria -``` - -To run the container, in detached mode (-d): - -```bash -docker run -d --rm --name=gc-alexandria -p 4174:80 gc-alexandria -``` - -The container is then viewable on your [local machine](http://localhost:4173). - -If you want to see the container process (assuming it's the last process to start), enter: - -```bash -docker ps -l -``` - -which should return something like: - -```bash -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -1d83d736322f gc-alexandria "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:4174->80/tcp, [::]:4174->80/tcp gc-alexandria -``` - ## Docker + Deno This application is configured to use the Deno runtime. A Docker container is provided to handle builds and deployments. @@ -107,7 +76,7 @@ This application is configured to use the Deno runtime. A Docker container is pr To build the app for local development: ```bash -docker build -t local-alexandria -f Dockerfile.local . +docker build -t local-alexandria -f Dockerfile . ``` To run the local development build: From ba1f0164ba8131090419dfb33ad423661056bd3c Mon Sep 17 00:00:00 2001 From: silberengel Date: Fri, 18 Jul 2025 20:02:14 +0200 Subject: [PATCH 119/135] fixed feed display --- src/app.css | 6 +- src/lib/components/LoginMenu.svelte | 440 --------------- src/lib/components/Navigation.svelte | 7 +- src/lib/components/RelayActions.svelte | 2 +- src/lib/components/cards/BlogHeader.svelte | 20 +- .../publications/PublicationFeed.svelte | 64 ++- .../publications/PublicationHeader.svelte | 49 +- src/lib/components/util/CardActions.svelte | 3 +- src/lib/components/util/Profile.svelte | 523 +++++++++++++++--- src/lib/utils/nostrEventService.ts | 3 +- src/routes/+page.svelte | 12 - 11 files changed, 544 insertions(+), 585 deletions(-) delete mode 100644 src/lib/components/LoginMenu.svelte diff --git a/src/app.css b/src/app.css index 1f07464..fbaca62 100644 --- a/src/app.css +++ b/src/app.css @@ -159,6 +159,10 @@ @apply bg-primary-100 dark:bg-primary-800; } + div.skeleton-leather { + @apply h-48; + } + div.textarea-leather { @apply bg-primary-0 dark:bg-primary-1000; } @@ -246,7 +250,7 @@ } .ArticleBox.grid.active .ArticleBoxImage { - @apply max-h-72; + @apply max-h-40; } .tags span { diff --git a/src/lib/components/LoginMenu.svelte b/src/lib/components/LoginMenu.svelte deleted file mode 100644 index 4ac4222..0000000 --- a/src/lib/components/LoginMenu.svelte +++ /dev/null @@ -1,440 +0,0 @@ - - -
    - {#if !user.signedIn} - -
    - - -
    -

    Login with...

    - - - -
    -
    Network Status:
    - -
    -
    -
    - {#if result} -
    - {result} - -
    - {/if} -
    - {:else} - -
    - - -
    -
    -

    - {user.profile?.displayName || - user.profile?.name || - (user.npub ? shortenNpub(user.npub) : "Unknown")} -

    -
      -
    • - -
    • -
    • - {#if user.loginMethod === "extension"} - Logged in with extension - {:else if user.loginMethod === "amber"} - Logged in with Amber - {:else if user.loginMethod === "npub"} - Logged in with npub - {:else} - Unknown login method - {/if} -
    • -
    • -
      Network Status:
      - -
    • -
    • - -
    • -
    -
    -
    -
    -
    - {/if} -
    - -{#if showQrCode && qrCodeDataUrl} - -
    -
    -
    -

    - Scan with Amber -

    -

    - Open Amber on your phone and scan this QR code -

    -
    - Nostr Connect QR Code -
    -
    - -
    - - -
    -
    -
    -

    1. Open Amber on your phone

    -

    2. Scan the QR code above

    -

    3. Approve the connection in Amber

    -
    - -
    -
    -
    -{/if} - -{#if showAmberFallback} -
    -
    -
    -

    - Amber Session Restored -

    -

    - Your Amber wallet session could not be restored automatically, so - you've been switched to read-only mode.
    - You can still browse and read content, but you'll need to reconnect Amber - to publish or comment. -

    - - -
    -
    -
    -{/if} diff --git a/src/lib/components/Navigation.svelte b/src/lib/components/Navigation.svelte index aa6b7e2..fdcfe32 100644 --- a/src/lib/components/Navigation.svelte +++ b/src/lib/components/Navigation.svelte @@ -7,9 +7,12 @@ NavHamburger, NavBrand, } from "flowbite-svelte"; - import LoginMenu from "./LoginMenu.svelte"; + import Profile from "./util/Profile.svelte"; + import { userStore } from "$lib/stores/userStore"; let { class: className = "" } = $props(); + + let userState = $derived($userStore); @@ -19,7 +22,7 @@
    - +
    diff --git a/src/lib/components/RelayActions.svelte b/src/lib/components/RelayActions.svelte index 041f4a4..e7f289c 100644 --- a/src/lib/components/RelayActions.svelte +++ b/src/lib/components/RelayActions.svelte @@ -55,7 +55,7 @@ const relaySet = createRelaySetFromUrls([relay], ndk); const found = await ndk .fetchEvent({ ids: [event?.id || ""] }, undefined, relaySet) - .withTimeout(3000); + .withTimeout(2000); relaySearchResults = { ...relaySearchResults, [relay]: found ? "found" : "notfound", diff --git a/src/lib/components/cards/BlogHeader.svelte b/src/lib/components/cards/BlogHeader.svelte index adaa6bf..0696d89 100644 --- a/src/lib/components/cards/BlogHeader.svelte +++ b/src/lib/components/cards/BlogHeader.svelte @@ -54,24 +54,28 @@ ? 'active' : ''}" > -
    +
    {@render userBadge(authorPubkey, author)} {publishedAt()}
    -
    {#if image && active}
    - + {title
    {/if} -
    + +
    @@ -83,9 +87,15 @@
    {/if}
    + {#if active} {/if} + + +
    + +
    {/if} diff --git a/src/lib/components/publications/PublicationFeed.svelte b/src/lib/components/publications/PublicationFeed.svelte index 14bd331..2236dce 100644 --- a/src/lib/components/publications/PublicationFeed.svelte +++ b/src/lib/components/publications/PublicationFeed.svelte @@ -137,9 +137,10 @@ allRelays.map((r: string) => [r, "pending"]), ); let allEvents: NDKEvent[] = []; + const eventMap = new Map(); // Helper to fetch from a single relay with timeout - async function fetchFromRelay(relay: string): Promise { + async function fetchFromRelay(relay: string): Promise { try { console.debug(`[PublicationFeed] Fetching from relay: ${relay}`); const relaySet = NDKRelaySetFromNDK.fromRelayUrls([relay], ndk); @@ -156,57 +157,60 @@ }, relaySet, ) - .withTimeout(10000); // Increased timeout to 10 seconds + .withTimeout(5000); // Reduced timeout to 5 seconds for faster response console.debug(`[PublicationFeed] Raw events from ${relay}:`, eventSet.size); eventSet = filterValidIndexEvents(eventSet); console.debug(`[PublicationFeed] Valid events from ${relay}:`, eventSet.size); relayStatuses = { ...relayStatuses, [relay]: "found" }; - return Array.from(eventSet); + + // Add new events to the map and update the view immediately + const newEvents: NDKEvent[] = []; + for (const event of eventSet) { + const tagAddress = event.tagAddress(); + if (!eventMap.has(tagAddress)) { + eventMap.set(tagAddress, event); + newEvents.push(event); + } + } + + if (newEvents.length > 0) { + // Update allIndexEvents with new events + allIndexEvents = Array.from(eventMap.values()); + // Sort by created_at descending + allIndexEvents.sort((a, b) => b.created_at! - a.created_at!); + + // Update the view immediately with new events + eventsInView = allIndexEvents.slice(0, 30); + endOfFeed = allIndexEvents.length <= 30; + + console.debug(`[PublicationFeed] Updated view with ${newEvents.length} new events from ${relay}, total: ${allIndexEvents.length}`); + } } catch (err) { console.error(`[PublicationFeed] Error fetching from relay ${relay}:`, err); relayStatuses = { ...relayStatuses, [relay]: "notfound" }; - return []; } } - // Fetch from all relays in parallel, do not block on any single relay + // Fetch from all relays in parallel, return events as they arrive console.debug(`[PublicationFeed] Starting fetch from ${allRelays.length} relays`); - const results = await Promise.allSettled(allRelays.map(fetchFromRelay)); - for (const result of results) { - if (result.status === "fulfilled") { - allEvents = allEvents.concat(result.value); - } - } + // Start all relay fetches in parallel + const fetchPromises = allRelays.map(fetchFromRelay); - console.debug(`[PublicationFeed] Total events fetched:`, allEvents.length); + // Wait for all to complete (but events are shown as they arrive) + await Promise.allSettled(fetchPromises); - // Deduplicate by tagAddress - const eventMap = new Map( - allEvents.map((event) => [event.tagAddress(), event]), - ); - allIndexEvents = Array.from(eventMap.values()); - console.debug(`[PublicationFeed] Events after deduplication:`, allIndexEvents.length); + console.debug(`[PublicationFeed] All relays completed, final event count:`, allIndexEvents.length); - // Sort by created_at descending - allIndexEvents.sort((a, b) => b.created_at! - a.created_at!); - // Cache the fetched events indexEventCache.set(allRelays, allIndexEvents); - // Initially show first page + // Final update to ensure we have the latest view eventsInView = allIndexEvents.slice(0, 30); endOfFeed = allIndexEvents.length <= 30; loading = false; - - console.debug(`[PublicationFeed] Final state:`, { - totalEvents: allIndexEvents.length, - eventsInView: eventsInView.length, - endOfFeed, - loading - }); } // Function to filter events based on search query @@ -332,7 +336,7 @@ } function getSkeletonIds(): string[] { - const skeletonHeight = 124; // The height of the skeleton component in pixels. + const skeletonHeight = 192; // The height of the card component in pixels (h-48 = 12rem = 192px). const skeletonCount = Math.floor(window.innerHeight / skeletonHeight) - 2; const skeletonIds = []; for (let i = 0; i < skeletonCount; i++) { diff --git a/src/lib/components/publications/PublicationHeader.svelte b/src/lib/components/publications/PublicationHeader.svelte index 465c423..2a0ea56 100644 --- a/src/lib/components/publications/PublicationHeader.svelte +++ b/src/lib/components/publications/PublicationHeader.svelte @@ -1,9 +1,7 @@ {#if title != null && href != null} - + {#if image}
    - + {title
    {/if} -
    + + + + +
    +
    {/if} diff --git a/src/lib/components/util/CardActions.svelte b/src/lib/components/util/CardActions.svelte index 2083d4e..d5d49c5 100644 --- a/src/lib/components/util/CardActions.svelte +++ b/src/lib/components/util/CardActions.svelte @@ -8,8 +8,7 @@ import CopyToClipboard from "$components/util/CopyToClipboard.svelte"; import { userBadge } from "$lib/snippets/UserSnippets.svelte"; import { neventEncode, naddrEncode } from "$lib/utils"; - import { communityRelays, secondaryRelays, FeedType } from "$lib/consts"; - import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; + import { activeInboxRelays } from "$lib/ndk"; import { userStore } from "$lib/stores/userStore"; import { goto } from "$app/navigation"; import type { NDKEvent } from "$lib/utils/nostrUtils"; diff --git a/src/lib/components/util/Profile.svelte b/src/lib/components/util/Profile.svelte index 19fb0bb..399539a 100644 --- a/src/lib/components/util/Profile.svelte +++ b/src/lib/components/util/Profile.svelte @@ -1,7 +1,13 @@
    -
    - - -
    -
    - {#if username} -

    {username}

    - {#if isNav}

    @{tag}

    {/if} - {:else} -

    Loading...

    - {/if} -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • - {#if isNav} + {#if !userState.signedIn} + +
      + + +
      +

      Login with...

      + + + +
      +
      Network Status:
      + +
      +
      +
      + {#if result} +
      + {result} + +
      + {/if} +
      + {:else} + +
      + + +
      +
      + {#if username} +

      {username}

      + {#if isNav}

      @{tag}

      {/if} + {:else if isProfileLoading} +

      Loading profile...

      + {:else} +

      Loading...

      + {/if} +
        +
      • + +
      • - {:else} - - {/if} -
      +
    • + {#if userState.loginMethod === "extension"} + Logged in with extension + {:else if userState.loginMethod === "amber"} + Logged in with Amber + {:else if userState.loginMethod === "npub"} + Logged in with npub + {:else} + Unknown login method + {/if} +
    • +
    • + +
    • + {#if isNav} +
    • + +
    • + {:else} + + {/if} +
    +
    +
    +
    +
    + {/if} +
    + +{#if showQrCode && qrCodeDataUrl} + +
    +
    +
    +

    + Scan with Amber +

    +

    + Open Amber on your phone and scan this QR code +

    +
    + Nostr Connect QR Code +
    +
    + +
    + + +
    +
    +

    1. Open Amber on your phone

    +

    2. Scan the QR code above

    +

    3. Approve the connection in Amber

    +
    +
    - +
    -
    +{/if} + +{#if showAmberFallback} +
    +
    +
    +

    + Amber Session Restored +

    +

    + Your Amber wallet session could not be restored automatically, so + you've been switched to read-only mode.
    + You can still browse and read content, but you'll need to reconnect Amber + to publish or comment. +

    + + +
    +
    +
    +{/if} diff --git a/src/lib/utils/nostrEventService.ts b/src/lib/utils/nostrEventService.ts index e7d437f..1a233a8 100644 --- a/src/lib/utils/nostrEventService.ts +++ b/src/lib/utils/nostrEventService.ts @@ -1,6 +1,5 @@ import { nip19 } from "nostr-tools"; import { getEventHash, signEvent, prefixNostrAddresses } from "./nostrUtils"; -import { communityRelays, secondaryRelays } from "$lib/consts"; import { get } from "svelte/store"; import { goto } from "$app/navigation"; import type { NDKEvent } from "./nostrUtils"; @@ -381,7 +380,7 @@ export async function publishEvent( try { // Publish with timeout - await event.publish(relaySet).withTimeout(10000); + await event.publish(relaySet).withTimeout(5000); // For now, assume all relays were successful // In a more sophisticated implementation, you'd track individual relay responses diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 8461bd4..03a9c14 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -14,18 +14,6 @@ } - - - - Pardon our dust! The publication view is currently using an experimental - loader, and may be unstable. - - -
    Date: Fri, 18 Jul 2025 20:19:01 +0200 Subject: [PATCH 120/135] added pastel placeholders --- src/lib/components/cards/BlogHeader.svelte | 29 +++--- src/lib/components/cards/ProfileHeader.svelte | 26 +++--- .../publications/PublicationHeader.svelte | 27 ++++-- src/lib/components/util/Details.svelte | 23 +++-- src/lib/components/util/LazyImage.svelte | 90 +++++++++++++++++++ src/lib/consts.ts | 6 +- src/lib/stores/userStore.ts | 15 +++- src/lib/utils/image_utils.ts | 31 +++++++ src/lib/utils/nostrUtils.ts | 18 +++- src/lib/utils/relay_management.ts | 19 +++- 10 files changed, 241 insertions(+), 43 deletions(-) create mode 100644 src/lib/components/util/LazyImage.svelte create mode 100644 src/lib/utils/image_utils.ts diff --git a/src/lib/components/cards/BlogHeader.svelte b/src/lib/components/cards/BlogHeader.svelte index 0696d89..0c3a2bc 100644 --- a/src/lib/components/cards/BlogHeader.svelte +++ b/src/lib/components/cards/BlogHeader.svelte @@ -1,12 +1,14 @@ + +
    + +
    +
    + + + { + setTimeout(() => { + imageLoaded = true; + }, 100); + }} + onerror={() => { + imageError = true; + }} + /> + + + {#if imageError} +
    +
    + Failed to load +
    +
    + {/if} +
    \ No newline at end of file diff --git a/src/lib/consts.ts b/src/lib/consts.ts index 4241d1d..b6df380 100644 --- a/src/lib/consts.ts +++ b/src/lib/consts.ts @@ -36,9 +36,9 @@ export const lowbandwidthRelays = [ "wss://aggr.nostr.land" ]; -export const localRelays = [ - "wss://localhost:8080", - "wss://localhost:4869" +export const localRelays: string[] = [ + // "wss://localhost:8080", + // "wss://localhost:4869" ]; export enum FeedType { diff --git a/src/lib/stores/userStore.ts b/src/lib/stores/userStore.ts index 3275e23..6e8ef07 100644 --- a/src/lib/stores/userStore.ts +++ b/src/lib/stores/userStore.ts @@ -162,7 +162,20 @@ export async function loginWithExtension() { const signer = new NDKNip07Signer(); const user = await signer.user(); const npub = user.npub; - const profile = await getUserMetadata(npub); + + // Try to fetch user metadata, but don't fail if it times out + let profile: NostrProfile | null = null; + try { + profile = await getUserMetadata(npub); + } catch (error) { + console.warn("Failed to fetch user metadata during login:", error); + // Continue with login even if metadata fetch fails + profile = { + name: npub.slice(0, 8) + "..." + npub.slice(-4), + displayName: npub.slice(0, 8) + "..." + npub.slice(-4), + }; + } + // Fetch user's preferred relays const [persistedInboxes, persistedOutboxes] = getPersistedRelays(user); for (const relay of persistedInboxes) { diff --git a/src/lib/utils/image_utils.ts b/src/lib/utils/image_utils.ts new file mode 100644 index 0000000..4922995 --- /dev/null +++ b/src/lib/utils/image_utils.ts @@ -0,0 +1,31 @@ +/** + * Generate a dark-pastel color based on a string (like an event ID) + * @param seed - The string to generate a color from + * @returns A dark-pastel hex color + */ +export function generateDarkPastelColor(seed: string): string { + // Create a simple hash from the seed string + let hash = 0; + for (let i = 0; i < seed.length; i++) { + const char = seed.charCodeAt(i); + hash = ((hash << 5) - hash) + char; + hash = hash & hash; // Convert to 32-bit integer + } + + // Use the hash to generate lighter pastel colors + // Keep values in the 120-200 range for better pastel effect + const r = Math.abs(hash) % 80 + 120; // 120-200 range + const g = Math.abs(hash >> 8) % 80 + 120; // 120-200 range + const b = Math.abs(hash >> 16) % 80 + 120; // 120-200 range + + return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`; +} + +/** + * Test function to verify color generation + * @param eventId - The event ID to test + * @returns The generated color + */ +export function testColorGeneration(eventId: string): string { + return generateDarkPastelColor(eventId); +} \ No newline at end of file diff --git a/src/lib/utils/nostrUtils.ts b/src/lib/utils/nostrUtils.ts index a7aef5e..85e9e8d 100644 --- a/src/lib/utils/nostrUtils.ts +++ b/src/lib/utils/nostrUtils.ts @@ -426,12 +426,18 @@ export async function fetchEventWithFallback( // Use the active inbox relays from the relay management system const inboxRelays = get(activeInboxRelays); + // Check if we have any relays available + if (inboxRelays.length === 0) { + console.warn("No inbox relays available for event fetch"); + return null; + } + // Create relay set from active inbox relays const relaySet = NDKRelaySetFromNDK.fromRelayUrls(inboxRelays, ndk); try { if (relaySet.relays.size === 0) { - console.warn("No inbox relays available for event fetch"); + console.warn("No relays in relay set for event fetch"); return null; } @@ -467,7 +473,15 @@ export async function fetchEventWithFallback( // Always wrap as NDKEvent return found instanceof NDKEvent ? found : new NDKEvent(ndk, found); } catch (err) { - console.error("Error in fetchEventWithFallback:", err); + if (err instanceof Error && err.message === 'Timeout') { + const timeoutSeconds = timeoutMs / 1000; + const relayUrls = Array.from(relaySet.relays).map((r: any) => r.url).join(", "); + console.warn( + `Event fetch timed out after ${timeoutSeconds}s. Tried inbox relays: ${relayUrls}. Some relays may be offline or slow.`, + ); + } else { + console.error("Error in fetchEventWithFallback:", err); + } return null; } } diff --git a/src/lib/utils/relay_management.ts b/src/lib/utils/relay_management.ts index dbaa08a..e02c7f8 100644 --- a/src/lib/utils/relay_management.ts +++ b/src/lib/utils/relay_management.ts @@ -147,19 +147,30 @@ function ensureSecureWebSocket(url: string): string { async function testLocalRelays(localRelayUrls: string[], ndk: NDK): Promise { const workingRelays: string[] = []; + if (localRelayUrls.length === 0) { + return workingRelays; + } + + console.debug(`[relay_management.ts] Testing ${localRelayUrls.length} local relays...`); + await Promise.all( localRelayUrls.map(async (url) => { try { const result = await testRelayConnection(url, ndk); if (result.connected) { workingRelays.push(url); + console.debug(`[relay_management.ts] Local relay connected: ${url}`); + } else { + console.debug(`[relay_management.ts] Local relay failed: ${url} - ${result.error}`); } } catch (error) { - // Silently ignore local relay failures + // Silently ignore local relay failures - they're optional + console.debug(`[relay_management.ts] Local relay error (ignored): ${url}`); } }) ); + console.debug(`[relay_management.ts] Found ${workingRelays.length} working local relays`); return workingRelays; } @@ -170,6 +181,12 @@ async function testLocalRelays(localRelayUrls: string[], ndk: NDK): Promise { try { + // If no local relays are configured, return empty array + if (localRelays.length === 0) { + console.debug('[relay_management.ts] No local relays configured'); + return []; + } + // Convert wss:// URLs from consts to ws:// for local testing const localRelayUrls = localRelays.map(url => url.replace(/^wss:\/\//, 'ws://') From 97d54e64ac51945db5d0216eb7e2a7663cc0c4fa Mon Sep 17 00:00:00 2001 From: silberengel Date: Fri, 18 Jul 2025 20:51:30 +0200 Subject: [PATCH 121/135] highlight current section and pad header --- src/app.css | 27 +++++ .../publications/TableOfContents.svelte | 105 +++++++++++++++++- src/lib/consts.ts | 2 + src/lib/data_structures/publication_tree.ts | 3 +- src/lib/ndk.ts | 6 +- src/lib/utils/relay_management.ts | 14 ++- 6 files changed, 146 insertions(+), 11 deletions(-) diff --git a/src/app.css b/src/app.css index fbaca62..da20412 100644 --- a/src/app.css +++ b/src/app.css @@ -288,6 +288,8 @@ /* Rendered publication content */ .publication-leather { @apply flex flex-col space-y-4; + scroll-margin-top: 150px; + scroll-behavior: smooth; h1, h2, @@ -441,6 +443,21 @@ scrollbar-color: rgba(156, 163, 175, 0.5) transparent !important; } + /* Section scroll behavior */ + section[id] { + scroll-margin-top: 150px; + } + + /* Ensure section headers maintain their padding */ + section[id] h1, + section[id] h2, + section[id] h3, + section[id] h4, + section[id] h5, + section[id] h6 { + @apply pt-4; + } + .description-textarea { min-height: 100% !important; } @@ -486,4 +503,14 @@ @apply bg-primary-0 dark:bg-primary-1000 text-gray-900 dark:text-gray-100 border-s-4 border-primary-200 rounded shadow-none px-4 py-2; @apply focus:border-primary-600 dark:focus:border-primary-400; } + + /* Table of Contents highlighting */ + .toc-highlight { + @apply bg-primary-100 dark:bg-primary-800 border-l-4 border-primary-600 dark:border-primary-400; + transition: all 0.2s ease-in-out; + } + + .toc-highlight:hover { + @apply bg-primary-200 dark:bg-primary-700; + } } diff --git a/src/lib/components/publications/TableOfContents.svelte b/src/lib/components/publications/TableOfContents.svelte index e50bce0..0a16108 100644 --- a/src/lib/components/publications/TableOfContents.svelte +++ b/src/lib/components/publications/TableOfContents.svelte @@ -10,6 +10,7 @@ SidebarItem, } from "flowbite-svelte"; import Self from "./TableOfContents.svelte"; + import { onMount, onDestroy } from "svelte"; let { depth, onSectionFocused } = $props<{ rootAddress: string; @@ -32,6 +33,10 @@ return newEntries; }); + // Track the currently visible section + let currentVisibleSection = $state(null); + let observer: IntersectionObserver; + function setEntryExpanded(address: string, expanded: boolean = false) { const entry = toc.getEntry(address); if (!entry) { @@ -41,6 +46,100 @@ toc.expandedMap.set(address, expanded); entry.resolveChildren(); } + + function handleSectionClick(address: string) { + // Smooth scroll to the section + const element = document.getElementById(address); + if (element) { + element.scrollIntoView({ + behavior: 'smooth', + block: 'start', + }); + } + + onSectionFocused?.(address); + } + + // Check if an entry is currently visible + function isEntryVisible(address: string): boolean { + return currentVisibleSection === address; + } + + // Set up intersection observer to track visible sections + onMount(() => { + observer = new IntersectionObserver( + (entries) => { + // Find the section that is most visible in the viewport + let maxIntersectionRatio = 0; + let mostVisibleSection: string | null = null; + + entries.forEach((entry) => { + if (entry.isIntersecting && entry.intersectionRatio > maxIntersectionRatio) { + maxIntersectionRatio = entry.intersectionRatio; + mostVisibleSection = entry.target.id; + } + }); + + if (mostVisibleSection && mostVisibleSection !== currentVisibleSection) { + currentVisibleSection = mostVisibleSection; + } + }, + { + threshold: [0, 0.25, 0.5, 0.75, 1], + rootMargin: "-20% 0px -20% 0px", // Consider section visible when it's in the middle 60% of the viewport + } + ); + + // Function to observe all section elements + function observeSections() { + const sections = document.querySelectorAll('section[id]'); + sections.forEach((section) => { + observer.observe(section); + }); + } + + // Initial observation + observeSections(); + + // Set up a mutation observer to watch for new sections being added + const mutationObserver = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + mutation.addedNodes.forEach((node) => { + if (node.nodeType === Node.ELEMENT_NODE) { + const element = node as Element; + // Check if the added node is a section with an id + if (element.tagName === 'SECTION' && element.id) { + observer.observe(element); + } + // Check if the added node contains sections + const sections = element.querySelectorAll?.('section[id]'); + if (sections) { + sections.forEach((section) => { + observer.observe(section); + }); + } + } + }); + }); + }); + + // Start observing the document body for changes + mutationObserver.observe(document.body, { + childList: true, + subtree: true, + }); + + return () => { + observer.disconnect(); + mutationObserver.disconnect(); + }; + }); + + onDestroy(() => { + if (observer) { + observer.disconnect(); + } + }); @@ -50,18 +149,20 @@ {@const address = entry.address} {@const expanded = toc.expandedMap.get(address) ?? false} {@const isLeaf = toc.leaves.has(address)} + {@const isVisible = isEntryVisible(address)} {#if isLeaf} onSectionFocused?.(address)} + class={isVisible ? "toc-highlight" : ""} + onclick={() => handleSectionClick(address)} /> {:else} {@const childDepth = depth + 1} expanded, (open) => setEntryExpanded(address, open)} > diff --git a/src/lib/consts.ts b/src/lib/consts.ts index b6df380..998cbec 100644 --- a/src/lib/consts.ts +++ b/src/lib/consts.ts @@ -1,3 +1,5 @@ +// AI SHOULD NEVER CHANGE THIS FILE + export const wikiKind = 30818; export const indexKind = 30040; export const zettelKinds = [30041, 30818]; diff --git a/src/lib/data_structures/publication_tree.ts b/src/lib/data_structures/publication_tree.ts index dbb20cb..2fefad7 100644 --- a/src/lib/data_structures/publication_tree.ts +++ b/src/lib/data_structures/publication_tree.ts @@ -558,9 +558,10 @@ export class PublicationTree implements AsyncIterable { currentEvent = this.#events.get(currentAddress!); if (!currentEvent) { - throw new Error( + console.warn( `[PublicationTree] Event with address ${currentAddress} not found.`, ); + return null; } // Stop immediately if the target of the search is found. diff --git a/src/lib/ndk.ts b/src/lib/ndk.ts index cd13df2..6e1120e 100644 --- a/src/lib/ndk.ts +++ b/src/lib/ndk.ts @@ -349,7 +349,7 @@ function createRelayWithAuth(url: string, ndk: NDK): NDKRelay { const connectionTimeout = setTimeout(() => { console.warn(`[NDK.ts] Connection timeout for ${secureUrl}`); relay.disconnect(); - }, 10000); // 10 second timeout + }, 5000); // 5 second timeout // Set up custom authentication handling only if user is signed in if (ndk.signer && ndk.activeUser) { @@ -509,7 +509,7 @@ export function initNdk(): NDK { // Connect with better error handling and reduced retry attempts let retryCount = 0; - const maxRetries = 2; + const maxRetries = 1; // Reduce to 1 retry const attemptConnection = async () => { try { @@ -526,7 +526,7 @@ export function initNdk(): NDK { if (retryCount < maxRetries) { retryCount++; console.debug(`[NDK.ts] Attempting to reconnect (${retryCount}/${maxRetries})...`); - setTimeout(attemptConnection, 3000); + setTimeout(attemptConnection, 2000); // Reduce timeout to 2 seconds } else { console.warn("[NDK.ts] Max retries reached, continuing with limited functionality"); // Still try to update relay stores even if connection failed diff --git a/src/lib/utils/relay_management.ts b/src/lib/utils/relay_management.ts index e02c7f8..09aa5ac 100644 --- a/src/lib/utils/relay_management.ts +++ b/src/lib/utils/relay_management.ts @@ -325,7 +325,7 @@ export async function getUserOutboxRelays(ndk: NDK, user: NDKUser): Promise { const workingRelays: string[] = []; - const maxConcurrent = 3; // Test 3 relays at a time to avoid overwhelming them + const maxConcurrent = 2; // Reduce to 2 relays at a time to avoid overwhelming them for (let i = 0; i < relayUrls.length; i += maxConcurrent) { const batch = relayUrls.slice(i, i + maxConcurrent); @@ -335,12 +335,16 @@ async function testRelaySet(relayUrls: string[], ndk: NDK): Promise { const result = await testRelayConnection(url, ndk); return result.connected ? url : null; } catch (error) { + console.debug(`[relay_management.ts] Failed to test relay ${url}:`, error); return null; } }); - const batchResults = await Promise.all(batchPromises); - const batchWorkingRelays = batchResults.filter((url): url is string => url !== null); + const batchResults = await Promise.allSettled(batchPromises); + const batchWorkingRelays = batchResults + .filter((result): result is PromiseFulfilledResult => result.status === 'fulfilled') + .map(result => result.value) + .filter((url): url is string => url !== null); workingRelays.push(...batchWorkingRelays); } @@ -369,13 +373,13 @@ export async function buildCompleteRelaySet( try { userOutboxRelays = await getUserOutboxRelays(ndk, user); } catch (error) { - // Silently ignore user relay fetch errors + console.debug('[relay_management.ts] Error fetching user outbox relays:', error); } try { userLocalRelays = await getUserLocalRelays(ndk, user); } catch (error) { - // Silently ignore user local relay fetch errors + console.debug('[relay_management.ts] Error fetching user local relays:', error); } try { From c7ce63621021322a2013c1f5b92f9c5182d365f2 Mon Sep 17 00:00:00 2001 From: silberengel Date: Fri, 18 Jul 2025 21:39:51 +0200 Subject: [PATCH 122/135] ToC corrections --- src/app.css | 4 ++-- src/lib/data_structures/publication_tree.ts | 19 ++++++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/app.css b/src/app.css index da20412..7a55d9d 100644 --- a/src/app.css +++ b/src/app.css @@ -506,11 +506,11 @@ /* Table of Contents highlighting */ .toc-highlight { - @apply bg-primary-100 dark:bg-primary-800 border-l-4 border-primary-600 dark:border-primary-400; + @apply bg-primary-200 dark:bg-primary-700 border-l-4 border-primary-600 dark:border-primary-400 font-medium; transition: all 0.2s ease-in-out; } .toc-highlight:hover { - @apply bg-primary-200 dark:bg-primary-700; + @apply bg-primary-300 dark:bg-primary-600; } } diff --git a/src/lib/data_structures/publication_tree.ts b/src/lib/data_structures/publication_tree.ts index 2fefad7..f87b1c3 100644 --- a/src/lib/data_structures/publication_tree.ts +++ b/src/lib/data_structures/publication_tree.ts @@ -246,8 +246,11 @@ export class PublicationTree implements AsyncIterable { async tryMoveTo(address?: string) { if (!address) { const startEvent = await this.#tree.#depthFirstRetrieve(); + if (!startEvent) { + return false; + } this.target = await this.#tree.#nodes - .get(startEvent!.tagAddress()) + .get(startEvent.tagAddress()) ?.value(); } else { this.target = await this.#tree.#nodes.get(address)?.value(); @@ -424,8 +427,7 @@ export class PublicationTree implements AsyncIterable { ): Promise> { if (!this.#cursor.target) { if (await this.#cursor.tryMoveTo(this.#bookmark)) { - const event = await this.getEvent(this.#cursor.target!.address); - return { done: false, value: event }; + return this.#yieldEventAtCursor(false); } } @@ -440,7 +442,10 @@ export class PublicationTree implements AsyncIterable { async #yieldEventAtCursor( done: boolean, ): Promise> { - const value = (await this.getEvent(this.#cursor.target!.address)) ?? null; + if (!this.#cursor.target) { + return { done, value: null }; + } + const value = (await this.getEvent(this.#cursor.target.address)) ?? null; return { done, value }; } @@ -471,7 +476,7 @@ export class PublicationTree implements AsyncIterable { continue; } - if (this.#cursor.target!.status === PublicationTreeNodeStatus.Error) { + if (this.#cursor.target && this.#cursor.target.status === PublicationTreeNodeStatus.Error) { return { done: false, value: null }; } @@ -479,7 +484,7 @@ export class PublicationTree implements AsyncIterable { } } while (this.#cursor.tryMoveToParent()); - if (this.#cursor.target!.status === PublicationTreeNodeStatus.Error) { + if (this.#cursor.target && this.#cursor.target.status === PublicationTreeNodeStatus.Error) { return { done: false, value: null }; } @@ -518,7 +523,7 @@ export class PublicationTree implements AsyncIterable { } } while (this.#cursor.tryMoveToParent()); - if (this.#cursor.target!.status === PublicationTreeNodeStatus.Error) { + if (this.#cursor.target && this.#cursor.target.status === PublicationTreeNodeStatus.Error) { return { done: false, value: null }; } From bd6d96ed6274840913f508abd757a13f585d3ff7 Mon Sep 17 00:00:00 2001 From: silberengel Date: Fri, 18 Jul 2025 21:51:28 +0200 Subject: [PATCH 123/135] Made ToC auto-expanding --- .../publications/Publication.svelte | 7 ++- .../publications/TableOfContents.svelte | 20 ++++++-- src/lib/data_structures/publication_tree.ts | 47 ++++++++++++------- 3 files changed, 52 insertions(+), 22 deletions(-) diff --git a/src/lib/components/publications/Publication.svelte b/src/lib/components/publications/Publication.svelte index c751f5d..52489e5 100644 --- a/src/lib/components/publications/Publication.svelte +++ b/src/lib/components/publications/Publication.svelte @@ -182,7 +182,7 @@ }, { threshold: 0.5 }, ); - loadMore(8); + loadMore(12); return () => { observer.disconnect(); @@ -210,6 +210,11 @@ depth={2} onSectionFocused={(address: string) => publicationTree.setBookmark(address)} + onLoadMore={() => { + if (!isLoading && !isDone) { + loadMore(4); + } + }} /> {/if} diff --git a/src/lib/components/publications/TableOfContents.svelte b/src/lib/components/publications/TableOfContents.svelte index 0a16108..a2fc748 100644 --- a/src/lib/components/publications/TableOfContents.svelte +++ b/src/lib/components/publications/TableOfContents.svelte @@ -12,10 +12,11 @@ import Self from "./TableOfContents.svelte"; import { onMount, onDestroy } from "svelte"; - let { depth, onSectionFocused } = $props<{ + let { depth, onSectionFocused, onLoadMore } = $props<{ rootAddress: string; depth: number; onSectionFocused?: (address: string) => void; + onLoadMore?: () => void; }>(); let toc = getContext("toc") as TableOfContents; @@ -58,6 +59,14 @@ } onSectionFocused?.(address); + + // Check if this is the last entry and trigger loading more events + const currentEntries = entries; + const lastEntry = currentEntries[currentEntries.length - 1]; + if (lastEntry && lastEntry.address === address) { + console.debug('[TableOfContents] Last entry clicked, triggering load more'); + onLoadMore?.(); + } } // Check if an entry is currently visible @@ -145,27 +154,28 @@ - {#each entries as entry} + {#each entries as entry, index} {@const address = entry.address} {@const expanded = toc.expandedMap.get(address) ?? false} {@const isLeaf = toc.leaves.has(address)} {@const isVisible = isEntryVisible(address)} + {@const isLastEntry = index === entries.length - 1} {#if isLeaf} handleSectionClick(address)} /> {:else} {@const childDepth = depth + 1} expanded, (open) => setEntryExpanded(address, open)} > - + {/if} {/each} diff --git a/src/lib/data_structures/publication_tree.ts b/src/lib/data_structures/publication_tree.ts index f87b1c3..8b3a8f3 100644 --- a/src/lib/data_structures/publication_tree.ts +++ b/src/lib/data_structures/publication_tree.ts @@ -45,6 +45,11 @@ export class PublicationTree implements AsyncIterable { * A map of addresses in the tree to their corresponding events. */ #events: Map; + + /** + * Simple cache for fetched events to avoid re-fetching. + */ + #eventCache: Map = new Map(); /** * An ordered list of the addresses of the leaves of the tree. @@ -589,13 +594,11 @@ export class PublicationTree implements AsyncIterable { } // Augment the tree with the children of the current event. - for (const childAddress of currentChildAddresses) { - if (this.#nodes.has(childAddress)) { - continue; - } - - await this.#addNode(childAddress, currentNode!); - } + const childPromises = currentChildAddresses + .filter(childAddress => !this.#nodes.has(childAddress)) + .map(childAddress => this.#addNode(childAddress, currentNode!)); + + await Promise.all(childPromises); // Push the popped address's children onto the stack for the next iteration. while (currentChildAddresses.length > 0) { @@ -630,12 +633,23 @@ export class PublicationTree implements AsyncIterable { address: string, parentNode: PublicationTreeNode, ): Promise { - const [kind, pubkey, dTag] = address.split(":"); - const event = await this.#ndk.fetchEvent({ - kinds: [parseInt(kind)], - authors: [pubkey], - "#d": [dTag], - }); + // Check cache first + let event = this.#eventCache.get(address); + + if (!event) { + const [kind, pubkey, dTag] = address.split(":"); + const fetchedEvent = await this.#ndk.fetchEvent({ + kinds: [parseInt(kind)], + authors: [pubkey], + "#d": [dTag], + }); + + // Cache the event if found + if (fetchedEvent) { + this.#eventCache.set(address, fetchedEvent); + event = fetchedEvent; + } + } if (!event) { console.debug( @@ -665,9 +679,10 @@ export class PublicationTree implements AsyncIterable { children: [], }; - for (const address of childAddresses) { - this.addEventByAddress(address, event); - } + const childPromises = childAddresses.map(address => + this.addEventByAddress(address, event) + ); + await Promise.all(childPromises); this.#nodeResolvedObservers.forEach((observer) => observer(address)); From 3f511dfcb1cfdd96e07c195ebdf8c5cb204dc909 Mon Sep 17 00:00:00 2001 From: silberengel Date: Fri, 18 Jul 2025 22:02:14 +0200 Subject: [PATCH 124/135] fixed event search --- src/lib/components/EventSearch.svelte | 17 ++ src/routes/events/+page.svelte | 219 ++++---------------------- 2 files changed, 49 insertions(+), 187 deletions(-) diff --git a/src/lib/components/EventSearch.svelte b/src/lib/components/EventSearch.svelte index 6e4a49f..cb71ade 100644 --- a/src/lib/components/EventSearch.svelte +++ b/src/lib/components/EventSearch.svelte @@ -251,6 +251,11 @@ return; } + // Check if we've already processed this searchValue + if (searchValue === lastProcessedSearchValue) { + return; + } + // If we already have the event for this searchValue, do nothing if (foundEvent) { const currentEventId = foundEvent.id; @@ -307,6 +312,7 @@ (currentNprofile && searchValue === currentNprofile) ) { // Already displaying the event for this searchValue + lastProcessedSearchValue = searchValue; return; } } @@ -318,6 +324,7 @@ searchTimeout = setTimeout(() => { isProcessingSearch = true; isWaitingForSearchResult = true; + lastProcessedSearchValue = searchValue; if (searchValue) { handleSearchEvent(false, searchValue); } @@ -585,6 +592,11 @@ isProcessingSearch = false; currentProcessingSearchValue = null; isWaitingForSearchResult = false; + + // Update last processed search value to prevent re-processing + if (searchValue) { + lastProcessedSearchValue = searchValue; + } } catch (error) { if (error instanceof Error && error.message === "Search cancelled") { isProcessingSearch = false; @@ -628,6 +640,11 @@ isProcessingSearch = false; currentProcessingSearchValue = null; isWaitingForSearchResult = false; + + // Update last processed search value to prevent re-processing even on error + if (searchValue) { + lastProcessedSearchValue = searchValue; + } } } diff --git a/src/routes/events/+page.svelte b/src/routes/events/+page.svelte index 0b8c20d..ae93f34 100644 --- a/src/routes/events/+page.svelte +++ b/src/routes/events/+page.svelte @@ -79,7 +79,19 @@ // Use Svelte 5 idiomatic effect to update searchValue when $page.url.searchParams.get('id') changes $effect(() => { const url = $page.url.searchParams; - searchValue = url.get("id") ?? url.get("d"); + const idParam = url.get("id"); + const dParam = url.get("d"); + + if (idParam) { + searchValue = idParam; + dTagValue = null; + } else if (dParam) { + searchValue = null; + dTagValue = dParam.toLowerCase(); + } else { + searchValue = null; + dTagValue = null; + } }); // Add support for t and n parameters @@ -92,12 +104,28 @@ // Decode the t parameter and set it as searchValue with t: prefix const decodedT = decodeURIComponent(tParam); searchValue = `t:${decodedT}`; - } - - if (nParam) { + dTagValue = null; + } else if (nParam) { // Decode the n parameter and set it as searchValue with n: prefix const decodedN = decodeURIComponent(nParam); searchValue = `n:${decodedN}`; + dTagValue = null; + } + }); + + // Handle side panel visibility based on search type + $effect(() => { + const url = $page.url.searchParams; + const hasIdParam = url.get("id"); + const hasDParam = url.get("d"); + const hasTParam = url.get("t"); + const hasNParam = url.get("n"); + + // Close side panel for searches that return multiple results + if (hasDParam || hasTParam || hasNParam) { + showSidePanel = false; + event = null; + profile = null; } }); @@ -316,190 +344,7 @@ communityStatus = { ...communityStatus, ...newCommunityStatus }; } - function updateSearchFromURL() { - const id = $page.url.searchParams.get("id"); - const dTag = $page.url.searchParams.get("d"); - const tParam = $page.url.searchParams.get("t"); - const nParam = $page.url.searchParams.get("n"); - - console.log("Events page URL update:", { - id, - dTag, - tParam, - nParam, - searchValue, - }); - - if (id !== searchValue) { - console.log("ID changed, updating searchValue:", { - old: searchValue, - new: id, - }); - searchValue = id; - dTagValue = null; - // Only close side panel if we're clearing the search - if (!id) { - showSidePanel = false; - event = null; - profile = null; - } - } - - if (dTag !== dTagValue) { - console.log("DTag changed, updating dTagValue:", { - old: dTagValue, - new: dTag, - }); - // Normalize d-tag to lowercase for consistent searching - dTagValue = dTag ? dTag.toLowerCase() : null; - searchValue = null; - // For d-tag searches (which return multiple results), close side panel - showSidePanel = false; - event = null; - profile = null; - } - - // Handle t parameter - if (tParam) { - const decodedT = decodeURIComponent(tParam); - const tSearchValue = `t:${decodedT}`; - if (tSearchValue !== searchValue) { - console.log("T parameter changed, updating searchValue:", { - old: searchValue, - new: tSearchValue, - }); - searchValue = tSearchValue; - dTagValue = null; - // For t-tag searches (which return multiple results), close side panel - showSidePanel = false; - event = null; - profile = null; - } - } - - // Handle n parameter - if (nParam) { - const decodedN = decodeURIComponent(nParam); - const nSearchValue = `n:${decodedN}`; - if (nSearchValue !== searchValue) { - console.log("N parameter changed, updating searchValue:", { - old: searchValue, - new: nSearchValue, - }); - searchValue = nSearchValue; - dTagValue = null; - // For n-tag searches (which return multiple results), close side panel - showSidePanel = false; - event = null; - profile = null; - } - } - - // Reset state if all parameters are absent - if (!id && !dTag && !tParam && !nParam) { - event = null; - searchResults = []; - profile = null; - searchType = null; - searchTerm = null; - showSidePanel = false; - searchInProgress = false; - secondOrderSearchMessage = null; - } - } - - // Force search when URL changes - function handleUrlChange() { - const id = $page.url.searchParams.get("id"); - const dTag = $page.url.searchParams.get("d"); - const tParam = $page.url.searchParams.get("t"); - const nParam = $page.url.searchParams.get("n"); - - console.log("Events page URL change:", { - id, - dTag, - tParam, - nParam, - currentSearchValue: searchValue, - currentDTagValue: dTagValue, - }); - - // Handle ID parameter changes - if (id !== searchValue) { - console.log("ID parameter changed:", { old: searchValue, new: id }); - searchValue = id; - dTagValue = null; - if (!id) { - showSidePanel = false; - event = null; - profile = null; - } - } - - // Handle d-tag parameter changes - if (dTag !== dTagValue) { - console.log("d-tag parameter changed:", { old: dTagValue, new: dTag }); - dTagValue = dTag ? dTag.toLowerCase() : null; - searchValue = null; - showSidePanel = false; - event = null; - profile = null; - } - - // Handle t parameter changes - if (tParam) { - const decodedT = decodeURIComponent(tParam); - const tSearchValue = `t:${decodedT}`; - if (tSearchValue !== searchValue) { - console.log("t parameter changed:", { - old: searchValue, - new: tSearchValue, - }); - searchValue = tSearchValue; - dTagValue = null; - showSidePanel = false; - event = null; - profile = null; - } - } - - // Handle n parameter changes - if (nParam) { - const decodedN = decodeURIComponent(nParam); - const nSearchValue = `n:${decodedN}`; - if (nSearchValue !== searchValue) { - console.log("n parameter changed:", { - old: searchValue, - new: nSearchValue, - }); - searchValue = nSearchValue; - dTagValue = null; - showSidePanel = false; - event = null; - profile = null; - } - } - - // Reset state if all parameters are absent - if (!id && !dTag && !tParam && !nParam) { - console.log("All parameters absent, resetting state"); - event = null; - searchResults = []; - profile = null; - searchType = null; - searchTerm = null; - showSidePanel = false; - searchInProgress = false; - secondOrderSearchMessage = null; - searchValue = null; - dTagValue = null; - } - } - // Listen for URL changes - $effect(() => { - handleUrlChange(); - }); // Log relay configuration when page mounts onMount(() => { From fd3b26741da7404e14912f58b8da40ec809b3c5c Mon Sep 17 00:00:00 2001 From: silberengel Date: Fri, 18 Jul 2025 22:21:19 +0200 Subject: [PATCH 125/135] login working --- src/lib/components/util/Profile.svelte | 172 +++++++++++++++++++------ src/lib/stores/userStore.ts | 73 +++++++++-- src/lib/utils/nostrUtils.ts | 35 ++++- 3 files changed, 224 insertions(+), 56 deletions(-) diff --git a/src/lib/components/util/Profile.svelte b/src/lib/components/util/Profile.svelte index 399539a..ad52084 100644 --- a/src/lib/components/util/Profile.svelte +++ b/src/lib/components/util/Profile.svelte @@ -20,6 +20,8 @@ import { goto } from "$app/navigation"; import NDK, { NDKNip46Signer, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk"; import { onMount } from "svelte"; + import { getUserMetadata } from "$lib/utils/nostrUtils"; + import { activeInboxRelays } from "$lib/ndk"; let { pubkey, isNav = false } = $props<{ pubkey?: string, isNav?: boolean }>(); @@ -35,7 +37,7 @@ let profileAvatarId = "profile-avatar-btn"; let showAmberFallback = $state(false); let fallbackCheckInterval: ReturnType | null = null; - let isProfileLoading = $state(false); + let isRefreshingProfile = $state(false); onMount(() => { if (localStorage.getItem("alexandria/amber/fallback") === "1") { @@ -44,7 +46,7 @@ } }); - // Use profile data from userStore instead of fetching separately + // Use profile data from userStore let userState = $derived($userStore); let profile = $derived(userState.profile); let pfp = $derived(profile?.picture); @@ -52,6 +54,14 @@ let tag = $derived(profile?.name); let npub = $derived(userState.npub); + // Debug logging + $effect(() => { + console.log("Profile component - userState:", userState); + console.log("Profile component - profile:", profile); + console.log("Profile component - pfp:", pfp); + console.log("Profile component - username:", username); + }); + // Handle user state changes with effects $effect(() => { const currentUser = userState; @@ -87,51 +97,131 @@ } }); - // Fetch profile when user signs in or when pubkey changes + // Auto-refresh profile when user signs in $effect(() => { const currentUser = userState; - // If user is signed in but profile is not available, fetch it - if (currentUser.signedIn && !profile && currentUser.npub) { - const ndk = get(ndkInstance); - if (!ndk) return; + // If user is signed in and we have an npub but no profile data, refresh it + if (currentUser.signedIn && currentUser.npub && !profile?.name && !isRefreshingProfile) { + console.log("Profile: User signed in but no profile data, refreshing..."); + refreshProfile(); + } + }); - isProfileLoading = true; + // Debug activeInboxRelays + $effect(() => { + const inboxRelays = get(activeInboxRelays); + console.log("Profile component - activeInboxRelays:", inboxRelays); + }); + + // Manual trigger to refresh profile when user signs in + $effect(() => { + const currentUser = userState; + + if (currentUser.signedIn && currentUser.npub && !isRefreshingProfile) { + console.log("Profile: User signed in, triggering profile refresh..."); + // Add a small delay to ensure relays are ready + setTimeout(() => { + refreshProfile(); + }, 1000); + } + }); + + // Refresh profile when login method changes (e.g., Amber to read-only) + $effect(() => { + const currentUser = userState; + + if (currentUser.signedIn && currentUser.npub && currentUser.loginMethod) { + console.log("Profile: Login method detected:", currentUser.loginMethod); - // Use the current user's npub to fetch profile - const user = ndk.getUser({ npub: currentUser.npub }); + // If switching to read-only mode (npub), refresh profile + if (currentUser.loginMethod === "npub" && !isRefreshingProfile) { + console.log("Profile: Switching to read-only mode, refreshing profile..."); + setTimeout(() => { + refreshProfile(); + }, 500); + } + } + }); + + // Track login method changes and refresh profile when switching from Amber to npub + let previousLoginMethod = $state(null); + + $effect(() => { + const currentUser = userState; + + if (currentUser.signedIn && currentUser.loginMethod !== previousLoginMethod) { + console.log("Profile: Login method changed from", previousLoginMethod, "to", currentUser.loginMethod); - user.fetchProfile().then((userProfile: NDKUserProfile | null) => { - if (userProfile && !profile) { - // Only update if we don't already have profile data - profile = userProfile; - } - isProfileLoading = false; - }).catch(() => { - isProfileLoading = false; - }); + // If switching from Amber to npub (read-only), refresh profile + if (previousLoginMethod === "amber" && currentUser.loginMethod === "npub") { + console.log("Profile: Switching from Amber to read-only mode, refreshing profile..."); + setTimeout(() => { + refreshProfile(); + }, 1000); + } + + previousLoginMethod = currentUser.loginMethod; } + }); + + // Function to refresh profile data + async function refreshProfile() { + if (!userState.signedIn || !userState.npub) return; - // Fallback to fetching profile if not available in userStore and pubkey prop is provided - if (!profile && pubkey) { + isRefreshingProfile = true; + try { + console.log("Refreshing profile for npub:", userState.npub); + + // Try using NDK's built-in profile fetching first const ndk = get(ndkInstance); - if (!ndk) return; - - isProfileLoading = true; + if (ndk && userState.ndkUser) { + console.log("Using NDK's built-in profile fetching"); + const userProfile = await userState.ndkUser.fetchProfile(); + console.log("NDK profile fetch result:", userProfile); + + if (userProfile) { + const profileData = { + name: userProfile.name, + displayName: userProfile.displayName, + nip05: userProfile.nip05, + picture: userProfile.image, + about: userProfile.bio, + banner: userProfile.banner, + website: userProfile.website, + lud16: userProfile.lud16, + }; + + console.log("Converted profile data:", profileData); + + // Update the userStore with fresh profile data + userStore.update(currentState => ({ + ...currentState, + profile: profileData + })); + + return; + } + } - const user = ndk.getUser({ pubkey: pubkey ?? undefined }); + // Fallback to getUserMetadata + console.log("Falling back to getUserMetadata"); + const freshProfile = await getUserMetadata(userState.npub, true); // Force fresh fetch + console.log("Fresh profile data from getUserMetadata:", freshProfile); - user.fetchProfile().then((userProfile: NDKUserProfile | null) => { - if (userProfile && !profile) { - // Only update if we don't already have profile data - profile = userProfile; - } - isProfileLoading = false; - }).catch(() => { - isProfileLoading = false; - }); + // Update the userStore with fresh profile data + userStore.update(currentState => ({ + ...currentState, + profile: freshProfile + })); + } catch (error) { + console.error("Failed to refresh profile:", error); + } finally { + isRefreshingProfile = false; } - }); + } + + // Generate QR code const generateQrCode = async (text: string): Promise => { @@ -237,7 +327,6 @@ localStorage.removeItem("amber/nsec"); localStorage.removeItem("alexandria/amber/fallback"); logoutUser(); - profile = null; } function handleViewProfile() { @@ -255,6 +344,12 @@ function handleAmberFallbackDismiss() { showAmberFallback = false; localStorage.removeItem("alexandria/amber/fallback"); + + // Refresh profile when switching to read-only mode + setTimeout(() => { + console.log("Profile: Amber fallback dismissed, refreshing profile for read-only mode..."); + refreshProfile(); + }, 500); } function shortenNpub(long: string | null | undefined) { @@ -337,7 +432,7 @@ type="button" aria-label="Open profile menu" > - {#if isProfileLoading && !pfp} + {#if !pfp}
    {:else} {username} {#if isNav}

    @{tag}

    {/if} - {:else if isProfileLoading} + {:else if !pfp}

    Loading profile...

    {:else}

    Loading...

    @@ -381,6 +476,7 @@ />View profile +
  • {#if userState.loginMethod === "extension"} Logged in with extension diff --git a/src/lib/stores/userStore.ts b/src/lib/stores/userStore.ts index 6e8ef07..4e2b067 100644 --- a/src/lib/stores/userStore.ts +++ b/src/lib/stores/userStore.ts @@ -163,10 +163,14 @@ export async function loginWithExtension() { const user = await signer.user(); const npub = user.npub; + console.log("Login with extension - fetching profile for npub:", npub); + // Try to fetch user metadata, but don't fail if it times out let profile: NostrProfile | null = null; try { - profile = await getUserMetadata(npub); + console.log("Login with extension - attempting to fetch profile..."); + profile = await getUserMetadata(npub, true); // Force fresh fetch + console.log("Login with extension - fetched profile:", profile); } catch (error) { console.warn("Failed to fetch user metadata during login:", error); // Continue with login even if metadata fetch fails @@ -174,6 +178,7 @@ export async function loginWithExtension() { name: npub.slice(0, 8) + "..." + npub.slice(-4), displayName: npub.slice(0, 8) + "..." + npub.slice(-4), }; + console.log("Login with extension - using fallback profile:", profile); } // Fetch user's preferred relays @@ -185,7 +190,8 @@ export async function loginWithExtension() { persistRelays(user, inboxes, outboxes); ndk.signer = signer; ndk.activeUser = user; - userStore.set({ + + const userState = { pubkey: user.pubkey, npub, profile, @@ -195,11 +201,14 @@ export async function loginWithExtension() { (relay) => relay.url, ), }, - loginMethod: "extension", + loginMethod: "extension" as const, ndkUser: user, signer, signedIn: true, - }); + }; + + console.log("Login with extension - setting userStore with:", userState); + userStore.set(userState); clearLogin(); localStorage.removeItem("alexandria/logout/flag"); persistLogin(user, "extension"); @@ -213,7 +222,23 @@ export async function loginWithAmber(amberSigner: NDKSigner, user: NDKUser) { if (!ndk) throw new Error("NDK not initialized"); // Only clear previous login state after successful login const npub = user.npub; - const profile = await getUserMetadata(npub, true); // Force fresh fetch + + console.log("Login with Amber - fetching profile for npub:", npub); + + let profile: NostrProfile | null = null; + try { + profile = await getUserMetadata(npub, true); // Force fresh fetch + console.log("Login with Amber - fetched profile:", profile); + } catch (error) { + console.warn("Failed to fetch user metadata during Amber login:", error); + // Continue with login even if metadata fetch fails + profile = { + name: npub.slice(0, 8) + "..." + npub.slice(-4), + displayName: npub.slice(0, 8) + "..." + npub.slice(-4), + }; + console.log("Login with Amber - using fallback profile:", profile); + } + const [persistedInboxes, persistedOutboxes] = getPersistedRelays(user); for (const relay of persistedInboxes) { ndk.addExplicitRelay(relay); @@ -222,7 +247,8 @@ export async function loginWithAmber(amberSigner: NDKSigner, user: NDKUser) { persistRelays(user, inboxes, outboxes); ndk.signer = amberSigner; ndk.activeUser = user; - userStore.set({ + + const userState = { pubkey: user.pubkey, npub, profile, @@ -232,11 +258,14 @@ export async function loginWithAmber(amberSigner: NDKSigner, user: NDKUser) { (relay) => relay.url, ), }, - loginMethod: "amber", + loginMethod: "amber" as const, ndkUser: user, signer: amberSigner, signedIn: true, - }); + }; + + console.log("Login with Amber - setting userStore with:", userState); + userStore.set(userState); clearLogin(); localStorage.removeItem("alexandria/logout/flag"); persistLogin(user, "amber"); @@ -267,20 +296,40 @@ export async function loginWithNpub(pubkeyOrNpub: string) { console.error("Failed to encode npub from hex pubkey:", hexPubkey, e); throw e; } + + console.log("Login with npub - fetching profile for npub:", npub); + const user = ndk.getUser({ npub }); - const profile = await getUserMetadata(npub); + let profile: NostrProfile | null = null; + try { + profile = await getUserMetadata(npub, true); // Force fresh fetch + console.log("Login with npub - fetched profile:", profile); + } catch (error) { + console.warn("Failed to fetch user metadata during npub login:", error); + // Continue with login even if metadata fetch fails + profile = { + name: npub.slice(0, 8) + "..." + npub.slice(-4), + displayName: npub.slice(0, 8) + "..." + npub.slice(-4), + }; + console.log("Login with npub - using fallback profile:", profile); + } + ndk.signer = undefined; ndk.activeUser = user; - userStore.set({ + + const userState = { pubkey: user.pubkey, npub, profile, relays: { inbox: [], outbox: [] }, - loginMethod: "npub", + loginMethod: "npub" as const, ndkUser: user, signer: null, signedIn: true, - }); + }; + + console.log("Login with npub - setting userStore with:", userState); + userStore.set(userState); clearLogin(); localStorage.removeItem("alexandria/logout/flag"); persistLogin(user, "npub"); diff --git a/src/lib/utils/nostrUtils.ts b/src/lib/utils/nostrUtils.ts index 85e9e8d..f70d139 100644 --- a/src/lib/utils/nostrUtils.ts +++ b/src/lib/utils/nostrUtils.ts @@ -60,8 +60,12 @@ export async function getUserMetadata( // Remove nostr: prefix if present const cleanId = identifier.replace(/^nostr:/, ""); + console.log("getUserMetadata called with identifier:", identifier, "force:", force); + if (!force && npubCache.has(cleanId)) { - return npubCache.get(cleanId)!; + const cached = npubCache.get(cleanId)!; + console.log("getUserMetadata returning cached profile:", cached); + return cached; } const fallback = { name: `${cleanId.slice(0, 8)}...${cleanId.slice(-4)}` }; @@ -69,12 +73,14 @@ export async function getUserMetadata( try { const ndk = get(ndkInstance); if (!ndk) { + console.warn("getUserMetadata: No NDK instance available"); npubCache.set(cleanId, fallback); return fallback; } const decoded = nip19.decode(cleanId); if (!decoded) { + console.warn("getUserMetadata: Failed to decode identifier:", cleanId); npubCache.set(cleanId, fallback); return fallback; } @@ -86,19 +92,27 @@ export async function getUserMetadata( } else if (decoded.type === "nprofile") { pubkey = decoded.data.pubkey; } else { + console.warn("getUserMetadata: Unsupported identifier type:", decoded.type); npubCache.set(cleanId, fallback); return fallback; } + console.log("getUserMetadata: Fetching profile for pubkey:", pubkey); + const profileEvent = await fetchEventWithFallback(ndk, { kinds: [0], authors: [pubkey], }); + + console.log("getUserMetadata: Profile event found:", profileEvent); + const profile = profileEvent && profileEvent.content ? JSON.parse(profileEvent.content) : null; + console.log("getUserMetadata: Parsed profile:", profile); + const metadata: NostrProfile = { name: profile?.name || fallback.name, displayName: profile?.displayName || profile?.display_name, @@ -110,9 +124,11 @@ export async function getUserMetadata( lud16: profile?.lud16, }; + console.log("getUserMetadata: Final metadata:", metadata); npubCache.set(cleanId, metadata); return metadata; } catch (e) { + console.error("getUserMetadata: Error fetching profile:", e); npubCache.set(cleanId, fallback); return fallback; } @@ -426,9 +442,11 @@ export async function fetchEventWithFallback( // Use the active inbox relays from the relay management system const inboxRelays = get(activeInboxRelays); + console.log("fetchEventWithFallback: Using inbox relays:", inboxRelays); + // Check if we have any relays available if (inboxRelays.length === 0) { - console.warn("No inbox relays available for event fetch"); + console.warn("fetchEventWithFallback: No inbox relays available for event fetch"); return null; } @@ -437,10 +455,14 @@ export async function fetchEventWithFallback( try { if (relaySet.relays.size === 0) { - console.warn("No relays in relay set for event fetch"); + console.warn("fetchEventWithFallback: No relays in relay set for event fetch"); return null; } + console.log("fetchEventWithFallback: Relay set size:", relaySet.relays.size); + console.log("fetchEventWithFallback: Filter:", filterOrId); + console.log("fetchEventWithFallback: Relay URLs:", Array.from(relaySet.relays).map((r: any) => r.url)); + let found: NDKEvent | null = null; if ( @@ -465,11 +487,12 @@ export async function fetchEventWithFallback( const timeoutSeconds = timeoutMs / 1000; const relayUrls = Array.from(relaySet.relays).map((r: any) => r.url).join(", "); console.warn( - `Event not found after ${timeoutSeconds}s timeout. Tried inbox relays: ${relayUrls}. Some relays may be offline or slow.`, + `fetchEventWithFallback: Event not found after ${timeoutSeconds}s timeout. Tried inbox relays: ${relayUrls}. Some relays may be offline or slow.`, ); return null; } + console.log("fetchEventWithFallback: Found event:", found.id); // Always wrap as NDKEvent return found instanceof NDKEvent ? found : new NDKEvent(ndk, found); } catch (err) { @@ -477,10 +500,10 @@ export async function fetchEventWithFallback( const timeoutSeconds = timeoutMs / 1000; const relayUrls = Array.from(relaySet.relays).map((r: any) => r.url).join(", "); console.warn( - `Event fetch timed out after ${timeoutSeconds}s. Tried inbox relays: ${relayUrls}. Some relays may be offline or slow.`, + `fetchEventWithFallback: Event fetch timed out after ${timeoutSeconds}s. Tried inbox relays: ${relayUrls}. Some relays may be offline or slow.`, ); } else { - console.error("Error in fetchEventWithFallback:", err); + console.error("fetchEventWithFallback: Error in fetchEventWithFallback:", err); } return null; } From fab4a00992e568d0bfeaf888e824d4f6a05678b8 Mon Sep 17 00:00:00 2001 From: silberengel Date: Fri, 18 Jul 2025 23:06:49 +0200 Subject: [PATCH 126/135] publishing from events works --- src/lib/components/EventInput.svelte | 25 +++++--- src/lib/components/EventSearch.svelte | 17 ++++- src/lib/components/util/Profile.svelte | 26 ++++++-- src/lib/ndk.ts | 15 ++++- src/lib/stores/userStore.ts | 33 +++++++++- src/lib/utils/nostrUtils.ts | 15 +++-- src/lib/utils/relay_management.ts | 88 +++++++++++++++++++++++++- 7 files changed, 194 insertions(+), 25 deletions(-) diff --git a/src/lib/components/EventInput.svelte b/src/lib/components/EventInput.svelte index 1b9cb6b..cc2e2a3 100644 --- a/src/lib/components/EventInput.svelte +++ b/src/lib/components/EventInput.svelte @@ -16,6 +16,7 @@ import { get } from "svelte/store"; import { ndkInstance } from "$lib/ndk"; import { userPubkey } from "$lib/stores/authStore.Svelte"; + import { userStore } from "$lib/stores/userStore"; import { NDKEvent as NDKEventClass } from "@nostr-dev-kit/ndk"; import type { NDKEvent } from "$lib/utils/nostrUtils"; import { prefixNostrAddresses } from "$lib/utils/nostrUtils"; @@ -99,8 +100,12 @@ function validate(): { valid: boolean; reason?: string } { const currentUserPubkey = get(userPubkey as any); - if (!currentUserPubkey) return { valid: false, reason: "Not logged in." }; - const pubkey = String(currentUserPubkey); + const userState = get(userStore); + + // Try userPubkey first, then fallback to userStore + const pubkey = currentUserPubkey || userState.pubkey; + if (!pubkey) return { valid: false, reason: "Not logged in." }; + if (!content.trim()) return { valid: false, reason: "Content required." }; if (kind === 30023) { const v = validateNotAsciidoc(content); @@ -137,14 +142,18 @@ try { const ndk = get(ndkInstance); const currentUserPubkey = get(userPubkey as any); - if (!ndk || !currentUserPubkey) { + const userState = get(userStore); + + // Try userPubkey first, then fallback to userStore + const pubkey = currentUserPubkey || userState.pubkey; + if (!ndk || !pubkey) { error = "NDK or pubkey missing."; loading = false; return; } - const pubkey = String(currentUserPubkey); + const pubkeyString = String(pubkey); - if (!/^[a-fA-F0-9]{64}$/.test(pubkey)) { + if (!/^[a-fA-F0-9]{64}$/.test(pubkeyString)) { error = "Invalid public key: must be a 64-character hex string."; loading = false; return; @@ -158,7 +167,7 @@ return; } - const baseEvent = { pubkey, created_at: createdAt }; + const baseEvent = { pubkey: pubkeyString, created_at: createdAt }; let events: NDKEvent[] = []; console.log("Publishing event with kind:", kind); @@ -235,7 +244,7 @@ kind, content: prefixedContent, tags: eventTags, - pubkey, + pubkey: pubkeyString, created_at: createdAt, }; @@ -520,7 +529,7 @@ Event ID: {lastPublishedEventId} diff --git a/src/lib/components/EventSearch.svelte b/src/lib/components/EventSearch.svelte index cb71ade..10f888b 100644 --- a/src/lib/components/EventSearch.svelte +++ b/src/lib/components/EventSearch.svelte @@ -13,6 +13,8 @@ import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; import { getMatchingTags, toNpub } from "$lib/utils/nostrUtils"; import type { SearchResult } from '$lib/utils/search_types'; + import { userStore } from "$lib/stores/userStore"; + import { get } from "svelte/store"; // Props definition let { @@ -492,7 +494,7 @@ // Wait for relays to be available (with timeout) let retryCount = 0; - const maxRetries = 10; // Wait up to 5 seconds (10 * 500ms) + const maxRetries = 20; // Wait up to 10 seconds (20 * 500ms) for user login to complete while ($activeInboxRelays.length === 0 && $activeOutboxRelays.length === 0 && retryCount < maxRetries) { console.debug(`EventSearch: Waiting for relays... (attempt ${retryCount + 1}/${maxRetries})`); @@ -500,6 +502,19 @@ retryCount++; } + // Additional wait for user-specific relays if user is logged in + const currentUser = get(userStore); + if (currentUser.signedIn && currentUser.pubkey) { + console.debug(`EventSearch: User is logged in (${currentUser.pubkey}), waiting for user-specific relays...`); + retryCount = 0; + while ($activeOutboxRelays.length <= 9 && retryCount < maxRetries) { + // If we still have the default relay count (9), wait for user-specific relays + console.debug(`EventSearch: Waiting for user-specific relays... (attempt ${retryCount + 1}/${maxRetries})`); + await new Promise(resolve => setTimeout(resolve, 500)); + retryCount++; + } + } + // Check if we have any relays available if ($activeInboxRelays.length === 0 && $activeOutboxRelays.length === 0) { console.warn("EventSearch: No relays available after waiting, failing search"); diff --git a/src/lib/components/util/Profile.svelte b/src/lib/components/util/Profile.svelte index ad52084..cc5ff4a 100644 --- a/src/lib/components/util/Profile.svelte +++ b/src/lib/components/util/Profile.svelte @@ -114,12 +114,24 @@ console.log("Profile component - activeInboxRelays:", inboxRelays); }); - // Manual trigger to refresh profile when user signs in + // Track if we've already refreshed the profile for this session + let hasRefreshedProfile = $state(false); + + // Reset the refresh flag when user logs out + $effect(() => { + const currentUser = userState; + if (!currentUser.signedIn) { + hasRefreshedProfile = false; + } + }); + + // Manual trigger to refresh profile when user signs in (only once) $effect(() => { const currentUser = userState; - if (currentUser.signedIn && currentUser.npub && !isRefreshingProfile) { + if (currentUser.signedIn && currentUser.npub && !isRefreshingProfile && !hasRefreshedProfile) { console.log("Profile: User signed in, triggering profile refresh..."); + hasRefreshedProfile = true; // Add a small delay to ensure relays are ready setTimeout(() => { refreshProfile(); @@ -131,12 +143,13 @@ $effect(() => { const currentUser = userState; - if (currentUser.signedIn && currentUser.npub && currentUser.loginMethod) { + if (currentUser.signedIn && currentUser.npub && currentUser.loginMethod && !isRefreshingProfile) { console.log("Profile: Login method detected:", currentUser.loginMethod); // If switching to read-only mode (npub), refresh profile - if (currentUser.loginMethod === "npub" && !isRefreshingProfile) { + if (currentUser.loginMethod === "npub" && !hasRefreshedProfile) { console.log("Profile: Switching to read-only mode, refreshing profile..."); + hasRefreshedProfile = true; setTimeout(() => { refreshProfile(); }, 500); @@ -150,12 +163,13 @@ $effect(() => { const currentUser = userState; - if (currentUser.signedIn && currentUser.loginMethod !== previousLoginMethod) { + if (currentUser.signedIn && currentUser.loginMethod !== previousLoginMethod && !isRefreshingProfile) { console.log("Profile: Login method changed from", previousLoginMethod, "to", currentUser.loginMethod); // If switching from Amber to npub (read-only), refresh profile - if (previousLoginMethod === "amber" && currentUser.loginMethod === "npub") { + if (previousLoginMethod === "amber" && currentUser.loginMethod === "npub" && !hasRefreshedProfile) { console.log("Profile: Switching from Amber to read-only mode, refreshing profile..."); + hasRefreshedProfile = true; setTimeout(() => { refreshProfile(); }, 1000); diff --git a/src/lib/ndk.ts b/src/lib/ndk.ts index 6e1120e..7b9745e 100644 --- a/src/lib/ndk.ts +++ b/src/lib/ndk.ts @@ -386,10 +386,13 @@ function createRelayWithAuth(url: string, ndk: NDK): NDKRelay { */ export async function getActiveRelaySet(ndk: NDK): Promise<{ inboxRelays: string[]; outboxRelays: string[] }> { const user = get(userStore); + console.debug('[NDK.ts] getActiveRelaySet: User state:', { signedIn: user.signedIn, hasNdkUser: !!user.ndkUser, pubkey: user.pubkey }); if (user.signedIn && user.ndkUser) { + console.debug('[NDK.ts] getActiveRelaySet: Building relay set for authenticated user:', user.ndkUser.pubkey); return await buildCompleteRelaySet(ndk, user.ndkUser); } else { + console.debug('[NDK.ts] getActiveRelaySet: Building relay set for anonymous user'); return await buildCompleteRelaySet(ndk, null); } } @@ -400,25 +403,33 @@ export async function getActiveRelaySet(ndk: NDK): Promise<{ inboxRelays: string */ export async function updateActiveRelayStores(ndk: NDK): Promise { try { + console.debug('[NDK.ts] updateActiveRelayStores: Starting relay store update'); + // Get the active relay set from the relay management system const relaySet = await getActiveRelaySet(ndk); + console.debug('[NDK.ts] updateActiveRelayStores: Got relay set:', relaySet); // Update the stores with the new relay configuration activeInboxRelays.set(relaySet.inboxRelays); activeOutboxRelays.set(relaySet.outboxRelays); + console.debug('[NDK.ts] updateActiveRelayStores: Updated stores with inbox:', relaySet.inboxRelays.length, 'outbox:', relaySet.outboxRelays.length); // Add relays to NDK pool (deduplicated) const allRelayUrls = deduplicateRelayUrls([...relaySet.inboxRelays, ...relaySet.outboxRelays]); + console.debug('[NDK.ts] updateActiveRelayStores: Adding', allRelayUrls.length, 'relays to NDK pool'); + for (const url of allRelayUrls) { try { const relay = createRelayWithAuth(url, ndk); ndk.pool?.addRelay(relay); } catch (error) { - // Silently ignore relay addition failures + console.debug('[NDK.ts] updateActiveRelayStores: Failed to add relay', url, ':', error); } } + + console.debug('[NDK.ts] updateActiveRelayStores: Relay store update completed'); } catch (error) { - // Silently ignore relay store update errors + console.warn('[NDK.ts] updateActiveRelayStores: Error updating relay stores:', error); } } diff --git a/src/lib/stores/userStore.ts b/src/lib/stores/userStore.ts index 4e2b067..376367c 100644 --- a/src/lib/stores/userStore.ts +++ b/src/lib/stores/userStore.ts @@ -8,9 +8,10 @@ import { NDKRelay, } from "@nostr-dev-kit/ndk"; import { getUserMetadata } from "$lib/utils/nostrUtils"; -import { ndkInstance, activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; +import { ndkInstance, activeInboxRelays, activeOutboxRelays, updateActiveRelayStores } from "$lib/ndk"; import { loginStorageKey } from "$lib/consts"; import { nip19 } from "nostr-tools"; +import { userPubkey } from "$lib/stores/authStore.Svelte"; export interface UserState { pubkey: string | null; @@ -209,6 +210,15 @@ export async function loginWithExtension() { console.log("Login with extension - setting userStore with:", userState); userStore.set(userState); + + // Update relay stores with the new user's relays + try { + console.debug('[userStore.ts] loginWithExtension: Updating relay stores for authenticated user'); + await updateActiveRelayStores(ndk); + } catch (error) { + console.warn('[userStore.ts] loginWithExtension: Failed to update relay stores:', error); + } + clearLogin(); localStorage.removeItem("alexandria/logout/flag"); persistLogin(user, "extension"); @@ -266,6 +276,16 @@ export async function loginWithAmber(amberSigner: NDKSigner, user: NDKUser) { console.log("Login with Amber - setting userStore with:", userState); userStore.set(userState); + userPubkey.set(user.pubkey); + + // Update relay stores with the new user's relays + try { + console.debug('[userStore.ts] loginWithAmber: Updating relay stores for authenticated user'); + await updateActiveRelayStores(ndk); + } catch (error) { + console.warn('[userStore.ts] loginWithAmber: Failed to update relay stores:', error); + } + clearLogin(); localStorage.removeItem("alexandria/logout/flag"); persistLogin(user, "amber"); @@ -330,6 +350,16 @@ export async function loginWithNpub(pubkeyOrNpub: string) { console.log("Login with npub - setting userStore with:", userState); userStore.set(userState); + userPubkey.set(user.pubkey); + + // Update relay stores with the new user's relays + try { + console.debug('[userStore.ts] loginWithNpub: Updating relay stores for authenticated user'); + await updateActiveRelayStores(ndk); + } catch (error) { + console.warn('[userStore.ts] loginWithNpub: Failed to update relay stores:', error); + } + clearLogin(); localStorage.removeItem("alexandria/logout/flag"); persistLogin(user, "npub"); @@ -393,6 +423,7 @@ export function logoutUser() { signer: null, signedIn: false, }); + userPubkey.set(null); const ndk = get(ndkInstance); if (ndk) { diff --git a/src/lib/utils/nostrUtils.ts b/src/lib/utils/nostrUtils.ts index f70d139..da8bb1b 100644 --- a/src/lib/utils/nostrUtils.ts +++ b/src/lib/utils/nostrUtils.ts @@ -5,7 +5,7 @@ import { npubCache } from "./npubCache"; import NDK, { NDKEvent, NDKRelaySet, NDKUser } from "@nostr-dev-kit/ndk"; import type { NDKFilter, NDKKind } from "@nostr-dev-kit/ndk"; import { communityRelays, secondaryRelays, anonymousRelays } from "$lib/consts"; -import { activeInboxRelays } from "$lib/ndk"; +import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; import { NDKRelaySet as NDKRelaySetFromNDK } from "@nostr-dev-kit/ndk"; import { sha256 } from "@noble/hashes/sha256"; import { schnorr } from "@noble/curves/secp256k1"; @@ -439,19 +439,22 @@ export async function fetchEventWithFallback( filterOrId: string | NDKFilter, timeoutMs: number = 3000, ): Promise { - // Use the active inbox relays from the relay management system + // Use both inbox and outbox relays for better event discovery const inboxRelays = get(activeInboxRelays); + const outboxRelays = get(activeOutboxRelays); + const allRelays = [...(inboxRelays || []), ...(outboxRelays || [])]; console.log("fetchEventWithFallback: Using inbox relays:", inboxRelays); + console.log("fetchEventWithFallback: Using outbox relays:", outboxRelays); // Check if we have any relays available - if (inboxRelays.length === 0) { - console.warn("fetchEventWithFallback: No inbox relays available for event fetch"); + if (allRelays.length === 0) { + console.warn("fetchEventWithFallback: No relays available for event fetch"); return null; } - // Create relay set from active inbox relays - const relaySet = NDKRelaySetFromNDK.fromRelayUrls(inboxRelays, ndk); + // Create relay set from all available relays + const relaySet = NDKRelaySetFromNDK.fromRelayUrls(allRelays, ndk); try { if (relaySet.relays.size === 0) { diff --git a/src/lib/utils/relay_management.ts b/src/lib/utils/relay_management.ts index 09aa5ac..2787938 100644 --- a/src/lib/utils/relay_management.ts +++ b/src/lib/utils/relay_management.ts @@ -287,6 +287,7 @@ export async function getUserBlockedRelays(ndk: NDK, user: NDKUser): Promise { try { + console.debug('[relay_management.ts] Fetching outbox relays for user:', user.pubkey); const relayList = await ndk.fetchEvent( { kinds: [10002], @@ -300,16 +301,29 @@ export async function getUserOutboxRelays(ndk: NDK, user: NDKUser): Promise { + console.debug('[relay_management.ts] Processing tag:', tag); if (tag[0] === 'w' && tag[1]) { outboxRelays.push(tag[1]); + console.debug('[relay_management.ts] Added outbox relay:', tag[1]); + } else if (tag[0] === 'r' && tag[1]) { + // Some relay lists use 'r' for both inbox and outbox + outboxRelays.push(tag[1]); + console.debug('[relay_management.ts] Added relay (r tag):', tag[1]); + } else { + console.debug('[relay_management.ts] Skipping tag:', tag[0], 'value:', tag[1]); } }); + console.debug('[relay_management.ts] Final outbox relays:', outboxRelays); return outboxRelays; } catch (error) { console.info('[relay_management.ts] Error fetching user outbox relays:', error); @@ -317,6 +331,56 @@ export async function getUserOutboxRelays(ndk: NDK, user: NDKUser): Promise { + try { + // Check if we're in a browser environment with extension support + if (typeof window === 'undefined' || !window.nostr) { + console.debug('[relay_management.ts] No window.nostr available'); + return []; + } + + console.debug('[relay_management.ts] Extension available, checking for getRelays()'); + const extensionRelays: string[] = []; + + // Try to get relays from the extension's API + // Different extensions may expose their relay config differently + if (window.nostr.getRelays) { + console.debug('[relay_management.ts] getRelays() method found, calling it...'); + try { + const relays = await window.nostr.getRelays(); + console.debug('[relay_management.ts] getRelays() returned:', relays); + if (relays && typeof relays === 'object') { + // Convert relay object to array of URLs + const relayUrls = Object.keys(relays); + extensionRelays.push(...relayUrls); + console.debug('[relay_management.ts] Got relays from extension:', relayUrls); + } + } catch (error) { + console.debug('[relay_management.ts] Extension getRelays() failed:', error); + } + } else { + console.debug('[relay_management.ts] getRelays() method not found on window.nostr'); + } + + // If getRelays() didn't work, try alternative methods + if (extensionRelays.length === 0) { + // Some extensions might expose relays through other methods + // This is a fallback for extensions that don't expose getRelays() + console.debug('[relay_management.ts] Extension does not expose relay configuration'); + } + + console.debug('[relay_management.ts] Final extension relays:', extensionRelays); + return extensionRelays; + } catch (error) { + console.debug('[relay_management.ts] Error getting extension relays:', error); + return []; + } +} + /** * Tests a set of relays in batches to avoid overwhelming them * @param relayUrls Array of relay URLs to test @@ -361,37 +425,55 @@ export async function buildCompleteRelaySet( ndk: NDK, user: NDKUser | null ): Promise<{ inboxRelays: string[]; outboxRelays: string[] }> { + console.debug('[relay_management.ts] buildCompleteRelaySet: Starting with user:', user?.pubkey || 'null'); + // Discover local relays first const discoveredLocalRelays = await discoverLocalRelays(ndk); + console.debug('[relay_management.ts] buildCompleteRelaySet: Discovered local relays:', discoveredLocalRelays); // Get user-specific relays if available let userOutboxRelays: string[] = []; let userLocalRelays: string[] = []; let blockedRelays: string[] = []; + let extensionRelays: string[] = []; if (user) { + console.debug('[relay_management.ts] buildCompleteRelaySet: Fetching user-specific relays for:', user.pubkey); + try { userOutboxRelays = await getUserOutboxRelays(ndk, user); + console.debug('[relay_management.ts] buildCompleteRelaySet: User outbox relays:', userOutboxRelays); } catch (error) { console.debug('[relay_management.ts] Error fetching user outbox relays:', error); } try { userLocalRelays = await getUserLocalRelays(ndk, user); + console.debug('[relay_management.ts] buildCompleteRelaySet: User local relays:', userLocalRelays); } catch (error) { console.debug('[relay_management.ts] Error fetching user local relays:', error); } try { blockedRelays = await getUserBlockedRelays(ndk, user); + console.debug('[relay_management.ts] buildCompleteRelaySet: User blocked relays:', blockedRelays); } catch (error) { // Silently ignore blocked relay fetch errors } + + try { + extensionRelays = await getExtensionRelays(); + console.debug('[relay_management.ts] Extension relays gathered:', extensionRelays); + } catch (error) { + console.debug('[relay_management.ts] Error fetching extension relays:', error); + } + } else { + console.debug('[relay_management.ts] buildCompleteRelaySet: No user provided, skipping user-specific relays'); } // Build initial relay sets and deduplicate const finalInboxRelays = deduplicateRelayUrls([...discoveredLocalRelays, ...userLocalRelays]); - const finalOutboxRelays = deduplicateRelayUrls([...discoveredLocalRelays, ...userOutboxRelays]); + const finalOutboxRelays = deduplicateRelayUrls([...discoveredLocalRelays, ...userOutboxRelays, ...extensionRelays]); // Test relays and filter out non-working ones let testedInboxRelays: string[] = []; @@ -441,5 +523,9 @@ export async function buildCompleteRelaySet( }; } + console.debug('[relay_management.ts] buildCompleteRelaySet: Final relay sets - inbox:', finalRelaySet.inboxRelays.length, 'outbox:', finalRelaySet.outboxRelays.length); + console.debug('[relay_management.ts] buildCompleteRelaySet: Final inbox relays:', finalRelaySet.inboxRelays); + console.debug('[relay_management.ts] buildCompleteRelaySet: Final outbox relays:', finalRelaySet.outboxRelays); + return finalRelaySet; } \ No newline at end of file From c1d60069a886749d3ae46742ac77cb734659abb0 Mon Sep 17 00:00:00 2001 From: silberengel Date: Fri, 18 Jul 2025 23:12:17 +0200 Subject: [PATCH 127/135] commenting works --- src/lib/stores/userStore.ts | 1 + src/lib/utils/nostrEventService.ts | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/lib/stores/userStore.ts b/src/lib/stores/userStore.ts index 376367c..4fdcf48 100644 --- a/src/lib/stores/userStore.ts +++ b/src/lib/stores/userStore.ts @@ -210,6 +210,7 @@ export async function loginWithExtension() { console.log("Login with extension - setting userStore with:", userState); userStore.set(userState); + userPubkey.set(user.pubkey); // Update relay stores with the new user's relays try { diff --git a/src/lib/utils/nostrEventService.ts b/src/lib/utils/nostrEventService.ts index 1a233a8..4ad05f8 100644 --- a/src/lib/utils/nostrEventService.ts +++ b/src/lib/utils/nostrEventService.ts @@ -2,11 +2,10 @@ import { nip19 } from "nostr-tools"; import { getEventHash, signEvent, prefixNostrAddresses } from "./nostrUtils"; import { get } from "svelte/store"; import { goto } from "$app/navigation"; -import type { NDKEvent } from "./nostrUtils"; import { EVENT_KINDS, TIME_CONSTANTS, TIMEOUTS } from "./search_constants"; import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; import { ndkInstance } from "$lib/ndk"; -import { NDKRelaySet } from "@nostr-dev-kit/ndk"; +import { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk"; export interface RootEventInfo { rootId: string; @@ -360,12 +359,12 @@ export async function createSignedEvent( /** * Publishes an event to relays using the new relay management system - * @param event The event to publish + * @param event The event to publish (can be NDKEvent or plain event object) * @param relayUrls Array of relay URLs to publish to * @returns Promise that resolves to array of successful relay URLs */ export async function publishEvent( - event: NDKEvent, + event: NDKEvent | any, relayUrls: string[], ): Promise { const successfulRelays: string[] = []; @@ -379,15 +378,25 @@ export async function publishEvent( const relaySet = NDKRelaySet.fromRelayUrls(relayUrls, ndk); try { + // If event is a plain object, create an NDKEvent from it + let ndkEvent: NDKEvent; + if (event.publish && typeof event.publish === 'function') { + // It's already an NDKEvent + ndkEvent = event; + } else { + // It's a plain event object, create NDKEvent + ndkEvent = new NDKEvent(ndk, event); + } + // Publish with timeout - await event.publish(relaySet).withTimeout(5000); + await ndkEvent.publish(relaySet).withTimeout(5000); // For now, assume all relays were successful // In a more sophisticated implementation, you'd track individual relay responses successfulRelays.push(...relayUrls); console.debug("[nostrEventService] Published event successfully:", { - eventId: event.id, + eventId: ndkEvent.id, relayCount: relayUrls.length, successfulRelays }); From 5822c087a632b193f17d4aebf6753fdce44d2a6a Mon Sep 17 00:00:00 2001 From: silberengel Date: Fri, 18 Jul 2025 23:30:13 +0200 Subject: [PATCH 128/135] blog updated --- src/lib/components/cards/BlogHeader.svelte | 2 +- src/lib/parser.ts | 37 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/lib/components/cards/BlogHeader.svelte b/src/lib/components/cards/BlogHeader.svelte index 0c3a2bc..f6f10f5 100644 --- a/src/lib/components/cards/BlogHeader.svelte +++ b/src/lib/components/cards/BlogHeader.svelte @@ -68,7 +68,7 @@ class="ArticleBoxImage flex justify-center items-center p-2 h-40 -mt-2" in:scale={{ start: 0.8, duration: 500, delay: 100, easing: quintOut }} > - {#if image && active} + {#if image} Date: Fri, 18 Jul 2025 23:32:36 +0200 Subject: [PATCH 129/135] turned on local relays --- src/lib/consts.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/consts.ts b/src/lib/consts.ts index 998cbec..ef41e0d 100644 --- a/src/lib/consts.ts +++ b/src/lib/consts.ts @@ -39,8 +39,8 @@ export const lowbandwidthRelays = [ ]; export const localRelays: string[] = [ - // "wss://localhost:8080", - // "wss://localhost:4869" + "wss://localhost:8080", + "wss://localhost:4869" ]; export enum FeedType { From 0eb8509e2fa26dc3bb7bcb09abb5003860c2d913 Mon Sep 17 00:00:00 2001 From: silberengel Date: Fri, 18 Jul 2025 23:43:50 +0200 Subject: [PATCH 130/135] v0.0.2 packages --- package-lock.json | 182 +++++++++++++++++++++++----------------------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0d82dc9..f256933 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1577,9 +1577,9 @@ } }, "node_modules/@sveltejs/kit": { - "version": "2.25.0", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.25.0.tgz", - "integrity": "sha512-Yc/WUMqYjYIZp2JsFUajw+cx7hIIqL1Z4uuhVl/yess65bGITbmG1aRIVOrlHg4oxmZqMluUJaVTLMLZZ9sNlg==", + "version": "2.25.1", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.25.1.tgz", + "integrity": "sha512-8H+fxDEp7Xq6tLFdrGdS5fLu6ONDQQ9DgyjboXpChubuFdfH9QoFX09ypssBpyNkJNZFt9eW3yLmXIc9CesPCA==", "dev": true, "dependencies": { "@sveltejs/acorn-typescript": "^1.0.5", @@ -2559,37 +2559,18 @@ } }, "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "devOptional": true, "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, "funding": { "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" } }, "node_modules/cliui": { @@ -3450,15 +3431,6 @@ "node": ">=4" } }, - "node_modules/eslint-plugin-svelte/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -5516,25 +5488,16 @@ } }, "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "devOptional": true, "engines": { - "node": ">=8.6" + "node": ">= 14.18.0" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/require-directory": { @@ -5956,9 +5919,9 @@ } }, "node_modules/svelte": { - "version": "5.36.7", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.36.7.tgz", - "integrity": "sha512-QsaFAxL1PZvo9hwaN+x7Sq2U8oJARmsEuM8TEZVy98nx5D5IKzRi8FKkPvmOx9NXScSYnItDGLErBBn/ieIn2A==", + "version": "5.36.8", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.36.8.tgz", + "integrity": "sha512-8JbZWQu96hMjH/oYQPxXW6taeC6Awl6muGHeZzJTxQx7NGRQ/J9wN1hkzRKLOlSDlbS2igiFg7p5xyTp5uXG3A==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.3.0", @@ -6003,34 +5966,6 @@ "typescript": ">=5.0.0" } }, - "node_modules/svelte-check/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/svelte-check/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/svelte-eslint-parser": { "version": "0.43.0", "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.43.0.tgz", @@ -6249,6 +6184,51 @@ "node": ">=14.0.0" } }, + "node_modules/tailwindcss/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/tailwindcss/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tailwindcss/node_modules/postcss-load-config": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", @@ -6295,6 +6275,28 @@ "node": ">=4" } }, + "node_modules/tailwindcss/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/tailwindcss/node_modules/yaml": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -6835,14 +6837,12 @@ } }, "node_modules/yaml": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", - "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", - "bin": { - "yaml": "bin.mjs" - }, + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, "engines": { - "node": ">= 14.6" + "node": ">= 6" } }, "node_modules/yargs": { From 491b87401c399c77ac8a132ea0a3a1f3b1b95b98 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Fri, 18 Jul 2025 18:17:54 -0500 Subject: [PATCH 131/135] Update Deno lockfile --- deno.lock | 562 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 360 insertions(+), 202 deletions(-) diff --git a/deno.lock b/deno.lock index 0a222bd..b94e4ee 100644 --- a/deno.lock +++ b/deno.lock @@ -1,17 +1,17 @@ { "version": "5", "specifiers": { - "npm:@nostr-dev-kit/ndk-cache-dexie@2.5": "2.5.13_typescript@5.7.3", - "npm:@nostr-dev-kit/ndk@2.11": "2.11.2_typescript@5.7.3", + "npm:@nostr-dev-kit/ndk-cache-dexie@2.5": "2.5.15_typescript@5.8.3", + "npm:@nostr-dev-kit/ndk-cache-dexie@2.6": "2.6.33_nostr-tools@2.15.1__typescript@5.8.3_typescript@5.8.3", + "npm:@nostr-dev-kit/ndk@2.11": "2.11.2_typescript@5.8.3", + "npm:@nostr-dev-kit/ndk@^2.14.32": "2.14.32_nostr-tools@2.15.1__typescript@5.8.3_typescript@5.8.3", "npm:@playwright/test@^1.50.1": "1.50.1", "npm:@popperjs/core@2.11": "2.11.8", - "npm:@sveltejs/adapter-auto@3": "3.3.1_@sveltejs+kit@2.17.3__@sveltejs+vite-plugin-svelte@4.0.4___svelte@5.21.0____acorn@8.14.0___vite@5.4.14____@types+node@22.13.9___@types+node@22.13.9__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", - "npm:@sveltejs/adapter-node@^5.2.12": "5.2.12_@sveltejs+kit@2.17.3__@sveltejs+vite-plugin-svelte@4.0.4___svelte@5.21.0____acorn@8.14.0___vite@5.4.14____@types+node@22.13.9___@types+node@22.13.9__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_rollup@4.34.9_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", - "npm:@sveltejs/adapter-static@3": "3.0.8_@sveltejs+kit@2.17.3__@sveltejs+vite-plugin-svelte@4.0.4___svelte@5.21.0____acorn@8.14.0___vite@5.4.14____@types+node@22.13.9___@types+node@22.13.9__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", - "npm:@sveltejs/kit@2": "2.17.3_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", - "npm:@sveltejs/kit@^2.16.0": "2.17.3_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", - "npm:@sveltejs/kit@^2.22.2": "2.22.2_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_acorn@8.15.0_@types+node@22.13.9", - "npm:@sveltejs/vite-plugin-svelte@4": "4.0.4_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", + "npm:@sveltejs/adapter-auto@3": "3.3.1_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@5.1.1___svelte@5.0.5____acorn@8.14.0___vite@6.3.5____@types+node@22.13.9____picomatch@4.0.2___@types+node@22.13.9__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__acorn@8.15.0__@types+node@22.13.9_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9", + "npm:@sveltejs/adapter-node@^5.2.13": "5.2.13_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@5.1.1___svelte@5.0.5____acorn@8.14.0___vite@6.3.5____@types+node@22.13.9____picomatch@4.0.2___@types+node@22.13.9__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__acorn@8.15.0__@types+node@22.13.9_rollup@4.34.9_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9", + "npm:@sveltejs/adapter-static@3": "3.0.8_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@5.1.1___svelte@5.0.5____acorn@8.14.0___vite@6.3.5____@types+node@22.13.9____picomatch@4.0.2___@types+node@22.13.9__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__acorn@8.15.0__@types+node@22.13.9_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9", + "npm:@sveltejs/kit@^2.25.0": "2.25.1_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_acorn@8.15.0_@types+node@22.13.9", + "npm:@sveltejs/vite-plugin-svelte@5": "5.1.1_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9", "npm:@tailwindcss/forms@0.5": "0.5.10_tailwindcss@3.4.17__postcss@8.5.3", "npm:@tailwindcss/typography@0.5": "0.5.16_tailwindcss@3.4.17__postcss@8.5.3", "npm:@types/d3@^7.4.3": "7.4.3", @@ -31,23 +31,25 @@ "npm:he@1.2": "1.2.0", "npm:highlight.js@^11.11.1": "11.11.1", "npm:node-emoji@^2.2.0": "2.2.0", - "npm:nostr-tools@2.10": "2.10.4_typescript@5.7.3", + "npm:nostr-tools@2.10": "2.10.4_typescript@5.8.3", + "npm:nostr-tools@2.15": "2.15.1_typescript@5.8.3", + "npm:plantuml-encoder@^1.4.0": "1.4.0", "npm:playwright@^1.50.1": "1.50.1", "npm:postcss-load-config@6": "6.0.1_postcss@8.5.3", "npm:postcss@8": "8.5.3", "npm:prettier-plugin-svelte@3": "3.3.3_prettier@3.5.3_svelte@5.21.0__acorn@8.14.0", "npm:prettier@3": "3.5.3", "npm:qrcode@^1.5.4": "1.5.4", - "npm:svelte-check@4": "4.1.4_svelte@5.21.0__acorn@8.14.0_typescript@5.7.3", + "npm:svelte-check@4": "4.3.0_svelte@5.0.5__acorn@8.14.0_typescript@5.8.3", "npm:svelte@5": "5.21.0_acorn@8.14.0", "npm:svelte@5.0": "5.0.5_acorn@8.14.0", "npm:tailwind-merge@2.5": "2.5.5", "npm:tailwind-merge@^3.3.0": "3.3.0", "npm:tailwindcss@3": "3.4.17_postcss@8.5.3", "npm:tslib@2.8": "2.8.1", - "npm:typescript@5.7": "5.7.3", - "npm:vite@5": "5.4.14_@types+node@22.13.9", - "npm:vitest@^3.1.3": "3.1.4_@types+node@22.13.9_vite@5.4.14__@types+node@22.13.9" + "npm:typescript@5.8": "5.8.3", + "npm:vite@6": "6.3.5_@types+node@22.13.9_picomatch@4.0.2", + "npm:vitest@^3.1.3": "3.2.4_@types+node@22.13.9_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2" }, "npm": { "@alloc/quick-lru@5.2.0": { @@ -107,116 +109,246 @@ "os": ["aix"], "cpu": ["ppc64"] }, + "@esbuild/aix-ppc64@0.25.7": { + "integrity": "sha512-uD0kKFHh6ETr8TqEtaAcV+dn/2qnYbH/+8wGEdY70Qf7l1l/jmBUbrmQqwiPKAQE6cOQ7dTj6Xr0HzQDGHyceQ==", + "os": ["aix"], + "cpu": ["ppc64"] + }, "@esbuild/android-arm64@0.21.5": { "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "os": ["android"], "cpu": ["arm64"] }, + "@esbuild/android-arm64@0.25.7": { + "integrity": "sha512-p0ohDnwyIbAtztHTNUTzN5EGD/HJLs1bwysrOPgSdlIA6NDnReoVfoCyxG6W1d85jr2X80Uq5KHftyYgaK9LPQ==", + "os": ["android"], + "cpu": ["arm64"] + }, "@esbuild/android-arm@0.21.5": { "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "os": ["android"], "cpu": ["arm"] }, + "@esbuild/android-arm@0.25.7": { + "integrity": "sha512-Jhuet0g1k9rAJHrXGIh7sFknFuT4sfytYZpZpuZl7YKDhnPByVAm5oy2LEBmMbuYf3ejWVYCc2seX81Mk+madA==", + "os": ["android"], + "cpu": ["arm"] + }, "@esbuild/android-x64@0.21.5": { "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "os": ["android"], "cpu": ["x64"] }, + "@esbuild/android-x64@0.25.7": { + "integrity": "sha512-mMxIJFlSgVK23HSsII3ZX9T2xKrBCDGyk0qiZnIW10LLFFtZLkFD6imZHu7gUo2wkNZwS9Yj3mOtZD3ZPcjCcw==", + "os": ["android"], + "cpu": ["x64"] + }, "@esbuild/darwin-arm64@0.21.5": { "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "os": ["darwin"], "cpu": ["arm64"] }, + "@esbuild/darwin-arm64@0.25.7": { + "integrity": "sha512-jyOFLGP2WwRwxM8F1VpP6gcdIJc8jq2CUrURbbTouJoRO7XCkU8GdnTDFIHdcifVBT45cJlOYsZ1kSlfbKjYUQ==", + "os": ["darwin"], + "cpu": ["arm64"] + }, "@esbuild/darwin-x64@0.21.5": { "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "os": ["darwin"], "cpu": ["x64"] }, + "@esbuild/darwin-x64@0.25.7": { + "integrity": "sha512-m9bVWqZCwQ1BthruifvG64hG03zzz9gE2r/vYAhztBna1/+qXiHyP9WgnyZqHgGeXoimJPhAmxfbeU+nMng6ZA==", + "os": ["darwin"], + "cpu": ["x64"] + }, "@esbuild/freebsd-arm64@0.21.5": { "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "os": ["freebsd"], "cpu": ["arm64"] }, + "@esbuild/freebsd-arm64@0.25.7": { + "integrity": "sha512-Bss7P4r6uhr3kDzRjPNEnTm/oIBdTPRNQuwaEFWT/uvt6A1YzK/yn5kcx5ZxZ9swOga7LqeYlu7bDIpDoS01bA==", + "os": ["freebsd"], + "cpu": ["arm64"] + }, "@esbuild/freebsd-x64@0.21.5": { "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "os": ["freebsd"], "cpu": ["x64"] }, + "@esbuild/freebsd-x64@0.25.7": { + "integrity": "sha512-S3BFyjW81LXG7Vqmr37ddbThrm3A84yE7ey/ERBlK9dIiaWgrjRlre3pbG7txh1Uaxz8N7wGGQXmC9zV+LIpBQ==", + "os": ["freebsd"], + "cpu": ["x64"] + }, "@esbuild/linux-arm64@0.21.5": { "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "os": ["linux"], "cpu": ["arm64"] }, + "@esbuild/linux-arm64@0.25.7": { + "integrity": "sha512-HfQZQqrNOfS1Okn7PcsGUqHymL1cWGBslf78dGvtrj8q7cN3FkapFgNA4l/a5lXDwr7BqP2BSO6mz9UremNPbg==", + "os": ["linux"], + "cpu": ["arm64"] + }, "@esbuild/linux-arm@0.21.5": { "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "os": ["linux"], "cpu": ["arm"] }, + "@esbuild/linux-arm@0.25.7": { + "integrity": "sha512-JZMIci/1m5vfQuhKoFXogCKVYVfYQmoZJg8vSIMR4TUXbF+0aNlfXH3DGFEFMElT8hOTUF5hisdZhnrZO/bkDw==", + "os": ["linux"], + "cpu": ["arm"] + }, "@esbuild/linux-ia32@0.21.5": { "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "os": ["linux"], "cpu": ["ia32"] }, + "@esbuild/linux-ia32@0.25.7": { + "integrity": "sha512-9Jex4uVpdeofiDxnwHRgen+j6398JlX4/6SCbbEFEXN7oMO2p0ueLN+e+9DdsdPLUdqns607HmzEFnxwr7+5wQ==", + "os": ["linux"], + "cpu": ["ia32"] + }, "@esbuild/linux-loong64@0.21.5": { "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "os": ["linux"], "cpu": ["loong64"] }, + "@esbuild/linux-loong64@0.25.7": { + "integrity": "sha512-TG1KJqjBlN9IHQjKVUYDB0/mUGgokfhhatlay8aZ/MSORMubEvj/J1CL8YGY4EBcln4z7rKFbsH+HeAv0d471w==", + "os": ["linux"], + "cpu": ["loong64"] + }, "@esbuild/linux-mips64el@0.21.5": { "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "os": ["linux"], "cpu": ["mips64el"] }, + "@esbuild/linux-mips64el@0.25.7": { + "integrity": "sha512-Ty9Hj/lx7ikTnhOfaP7ipEm/ICcBv94i/6/WDg0OZ3BPBHhChsUbQancoWYSO0WNkEiSW5Do4febTTy4x1qYQQ==", + "os": ["linux"], + "cpu": ["mips64el"] + }, "@esbuild/linux-ppc64@0.21.5": { "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "os": ["linux"], "cpu": ["ppc64"] }, + "@esbuild/linux-ppc64@0.25.7": { + "integrity": "sha512-MrOjirGQWGReJl3BNQ58BLhUBPpWABnKrnq8Q/vZWWwAB1wuLXOIxS2JQ1LT3+5T+3jfPh0tyf5CpbyQHqnWIQ==", + "os": ["linux"], + "cpu": ["ppc64"] + }, "@esbuild/linux-riscv64@0.21.5": { "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "os": ["linux"], "cpu": ["riscv64"] }, + "@esbuild/linux-riscv64@0.25.7": { + "integrity": "sha512-9pr23/pqzyqIZEZmQXnFyqp3vpa+KBk5TotfkzGMqpw089PGm0AIowkUppHB9derQzqniGn3wVXgck19+oqiOw==", + "os": ["linux"], + "cpu": ["riscv64"] + }, "@esbuild/linux-s390x@0.21.5": { "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "os": ["linux"], "cpu": ["s390x"] }, + "@esbuild/linux-s390x@0.25.7": { + "integrity": "sha512-4dP11UVGh9O6Y47m8YvW8eoA3r8qL2toVZUbBKyGta8j6zdw1cn9F/Rt59/Mhv0OgY68pHIMjGXWOUaykCnx+w==", + "os": ["linux"], + "cpu": ["s390x"] + }, "@esbuild/linux-x64@0.21.5": { "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "os": ["linux"], "cpu": ["x64"] }, + "@esbuild/linux-x64@0.25.7": { + "integrity": "sha512-ghJMAJTdw/0uhz7e7YnpdX1xVn7VqA0GrWrAO2qKMuqbvgHT2VZiBv1BQ//VcHsPir4wsL3P2oPggfKPzTKoCA==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@esbuild/netbsd-arm64@0.25.7": { + "integrity": "sha512-bwXGEU4ua45+u5Ci/a55B85KWaDSRS8NPOHtxy2e3etDjbz23wlry37Ffzapz69JAGGc4089TBo+dGzydQmydg==", + "os": ["netbsd"], + "cpu": ["arm64"] + }, "@esbuild/netbsd-x64@0.21.5": { "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "os": ["netbsd"], "cpu": ["x64"] }, + "@esbuild/netbsd-x64@0.25.7": { + "integrity": "sha512-tUZRvLtgLE5OyN46sPSYlgmHoBS5bx2URSrgZdW1L1teWPYVmXh+QN/sKDqkzBo/IHGcKcHLKDhBeVVkO7teEA==", + "os": ["netbsd"], + "cpu": ["x64"] + }, + "@esbuild/openbsd-arm64@0.25.7": { + "integrity": "sha512-bTJ50aoC+WDlDGBReWYiObpYvQfMjBNlKztqoNUL0iUkYtwLkBQQeEsTq/I1KyjsKA5tyov6VZaPb8UdD6ci6Q==", + "os": ["openbsd"], + "cpu": ["arm64"] + }, "@esbuild/openbsd-x64@0.21.5": { "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "os": ["openbsd"], "cpu": ["x64"] }, + "@esbuild/openbsd-x64@0.25.7": { + "integrity": "sha512-TA9XfJrgzAipFUU895jd9j2SyDh9bbNkK2I0gHcvqb/o84UeQkBpi/XmYX3cO1q/9hZokdcDqQxIi6uLVrikxg==", + "os": ["openbsd"], + "cpu": ["x64"] + }, + "@esbuild/openharmony-arm64@0.25.7": { + "integrity": "sha512-5VTtExUrWwHHEUZ/N+rPlHDwVFQ5aME7vRJES8+iQ0xC/bMYckfJ0l2n3yGIfRoXcK/wq4oXSItZAz5wslTKGw==", + "os": ["openharmony"], + "cpu": ["arm64"] + }, "@esbuild/sunos-x64@0.21.5": { "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "os": ["sunos"], "cpu": ["x64"] }, + "@esbuild/sunos-x64@0.25.7": { + "integrity": "sha512-umkbn7KTxsexhv2vuuJmj9kggd4AEtL32KodkJgfhNOHMPtQ55RexsaSrMb+0+jp9XL4I4o2y91PZauVN4cH3A==", + "os": ["sunos"], + "cpu": ["x64"] + }, "@esbuild/win32-arm64@0.21.5": { "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "os": ["win32"], "cpu": ["arm64"] }, + "@esbuild/win32-arm64@0.25.7": { + "integrity": "sha512-j20JQGP/gz8QDgzl5No5Gr4F6hurAZvtkFxAKhiv2X49yi/ih8ECK4Y35YnjlMogSKJk931iNMcd35BtZ4ghfw==", + "os": ["win32"], + "cpu": ["arm64"] + }, "@esbuild/win32-ia32@0.21.5": { "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "os": ["win32"], "cpu": ["ia32"] }, + "@esbuild/win32-ia32@0.25.7": { + "integrity": "sha512-4qZ6NUfoiiKZfLAXRsvFkA0hoWVM+1y2bSHXHkpdLAs/+r0LgwqYohmfZCi985c6JWHhiXP30mgZawn/XrqAkQ==", + "os": ["win32"], + "cpu": ["ia32"] + }, "@esbuild/win32-x64@0.21.5": { "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "os": ["win32"], "cpu": ["x64"] }, + "@esbuild/win32-x64@0.25.7": { + "integrity": "sha512-FaPsAHTwm+1Gfvn37Eg3E5HIpfR3i6x1AIcla/MkqAIupD4BW3MrSeUqfoTzwwJhk3WE2/KqUn4/eenEJC76VA==", + "os": ["win32"], + "cpu": ["x64"] + }, "@eslint-community/eslint-utils@4.4.1_eslint@9.21.0": { "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dependencies": [ @@ -353,10 +485,10 @@ "@noble/hashes@1.3.2" ] }, - "@noble/curves@1.8.1": { - "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", + "@noble/curves@1.9.4": { + "integrity": "sha512-2bKONnuM53lINoDrSmK8qP8W271ms7pygDhZt4SiLOoLwBtoHqeCFi6RG42V8zd3mLHuJFhU/Bmaqo4nX0/kBw==", "dependencies": [ - "@noble/hashes@1.7.1" + "@noble/hashes@1.8.0" ] }, "@noble/hashes@1.3.1": { @@ -365,11 +497,11 @@ "@noble/hashes@1.3.2": { "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==" }, - "@noble/hashes@1.7.1": { - "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==" + "@noble/hashes@1.8.0": { + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==" }, - "@noble/secp256k1@2.2.3": { - "integrity": "sha512-l7r5oEQym9Us7EAigzg30/PQAvynhMt2uoYtT3t26eGDVm9Yii5mZ5jWSWmZ/oSIR2Et0xfc6DXrG0bZ787V3w==" + "@noble/secp256k1@2.3.0": { + "integrity": "sha512-0TQed2gcBbIrh7Ccyw+y/uZQvbJwm7Ao4scBUxqpBCcsOlZG0O4KGfjtNAy/li4W8n1xt3dxrwJ0beZ2h2G6Kw==" }, "@nodelib/fs.scandir@2.1.5": { "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", @@ -388,48 +520,72 @@ "fastq" ] }, - "@nostr-dev-kit/ndk-cache-dexie@2.5.13_typescript@5.7.3": { - "integrity": "sha512-Suv/ChvtLzmIa0yKnAjggT9SnoWAmxBrsWGGbVZea4lMCrZErlej+RVjza1SRphZhSDTB+ZtH6Q+O5TKUZpWPA==", + "@nostr-dev-kit/ndk-cache-dexie@2.5.15_typescript@5.8.3": { + "integrity": "sha512-6icRT+tqob0tWqGjQqoaeNDimfO+0gaooG9kch5OQcqlkQh2u1/ySUa47SC/m2E8q3MQVQbU66r8ZjssN2BVmw==", + "dependencies": [ + "@nostr-dev-kit/ndk@2.12.2_typescript@5.8.3", + "debug@4.4.1", + "dexie", + "nostr-tools@2.15.1_typescript@5.8.3", + "typescript-lru-cache" + ] + }, + "@nostr-dev-kit/ndk-cache-dexie@2.6.33_nostr-tools@2.15.1__typescript@5.8.3_typescript@5.8.3": { + "integrity": "sha512-JzUD5cuJbGQDUXYuW1530vy347Kk3AhdtvPO8tL6kFpV3KzGt/QPZ0SHxcjMhJdf7r6cAIpCEWj9oUlStr0gsg==", "dependencies": [ - "@nostr-dev-kit/ndk@2.12.0_typescript@5.7.3", + "@nostr-dev-kit/ndk@2.14.32_nostr-tools@2.15.1__typescript@5.8.3_typescript@5.8.3", "debug@4.4.0", "dexie", - "nostr-tools", + "nostr-tools@2.15.1_typescript@5.8.3", "typescript-lru-cache" ] }, - "@nostr-dev-kit/ndk@2.11.2_typescript@5.7.3": { + "@nostr-dev-kit/ndk@2.11.2_typescript@5.8.3": { "integrity": "sha512-DNrodIBC0j2MqEUQ5Mqaa671iZiRiKluu0c/wLkX7PCva07KSPyvcuyGp5fhk+/EZBurwZccMaML0syH0Qu8kQ==", "dependencies": [ - "@noble/curves@1.8.1", - "@noble/hashes@1.7.1", + "@noble/curves@1.9.4", + "@noble/hashes@1.8.0", "@noble/secp256k1", - "@scure/base@1.2.4", - "debug@4.4.0", + "@scure/base@1.2.6", + "debug@4.4.1", "light-bolt11-decoder", - "nostr-tools", + "nostr-tools@2.15.1_typescript@5.8.3", "tseep", "typescript-lru-cache", "utf8-buffer", "websocket-polyfill" ] }, - "@nostr-dev-kit/ndk@2.12.0_typescript@5.7.3": { - "integrity": "sha512-B9NKdgn9CKNn0WHIFzj7SxeZhr+daT5im/ozj9Ey791MkaZiTB5XUCy5j9O15FDHTyFy0/gpCyq7LvJKIxCOoA==", + "@nostr-dev-kit/ndk@2.12.2_typescript@5.8.3": { + "integrity": "sha512-uvautgwbpk3AgddoFpew67/FiaV/zpKwwvSnjCvbE/tAdJBpUUS+VjWR5WfUnJvxTy/ZZpPW+X2TkwVFHhUdvA==", "dependencies": [ - "@noble/curves@1.8.1", - "@noble/hashes@1.7.1", + "@noble/curves@1.9.4", + "@noble/hashes@1.8.0", "@noble/secp256k1", - "@scure/base@1.2.4", - "debug@4.4.0", + "@scure/base@1.2.6", + "debug@4.4.1", "light-bolt11-decoder", - "nostr-tools", + "nostr-tools@2.15.1_typescript@5.8.3", "tseep", "typescript-lru-cache", "utf8-buffer", "websocket-polyfill" ] }, + "@nostr-dev-kit/ndk@2.14.32_nostr-tools@2.15.1__typescript@5.8.3_typescript@5.8.3": { + "integrity": "sha512-LUBO35RCB9/emBYsXNDece7m/WO2rGYR8j4SD0Crb3z8GcKTJq6P8OjpZ6+Kr+sLNo8N0uL07XxtAvEBnp2OqQ==", + "dependencies": [ + "@noble/curves@1.9.4", + "@noble/hashes@1.8.0", + "@noble/secp256k1", + "@scure/base@1.2.6", + "debug@4.4.0", + "light-bolt11-decoder", + "nostr-tools@2.15.1_typescript@5.8.3", + "tseep", + "typescript-lru-cache" + ] + }, "@pkgjs/parseargs@0.11.0": { "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==" }, @@ -440,19 +596,19 @@ ], "bin": true }, - "@polka/url@1.0.0-next.28": { - "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==" + "@polka/url@1.0.0-next.29": { + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==" }, "@popperjs/core@2.11.8": { "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" }, - "@rollup/plugin-commonjs@28.0.2_rollup@4.34.9_picomatch@4.0.2": { - "integrity": "sha512-BEFI2EDqzl+vA1rl97IDRZ61AIwGH093d9nz8+dThxJNH8oSoB7MjWvPCX3dkaK1/RCJ/1v/R1XB15FuSs0fQw==", + "@rollup/plugin-commonjs@28.0.6_rollup@4.34.9_picomatch@4.0.2": { + "integrity": "sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw==", "dependencies": [ "@rollup/pluginutils@5.1.4_rollup@4.34.9", "commondir", "estree-walker@2.0.2", - "fdir@6.4.3_picomatch@4.0.2", + "fdir", "is-reference@1.2.1", "magic-string", "picomatch@4.0.2", @@ -482,8 +638,8 @@ "resolve" ] }, - "@rollup/plugin-node-resolve@16.0.0_rollup@4.34.9": { - "integrity": "sha512-0FPvAeVUT/zdWoO0jnb/V5BlBsUSNfkIOtFHzMO4H9MOklrmQFY6FduVHKucNb/aTFxvnGhj4MNj/T1oNdDfNg==", + "@rollup/plugin-node-resolve@16.0.1_rollup@4.34.9": { + "integrity": "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==", "dependencies": [ "@rollup/pluginutils@5.1.4_rollup@4.34.9", "@types/resolve", @@ -617,8 +773,8 @@ "@scure/base@1.1.1": { "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==" }, - "@scure/base@1.2.4": { - "integrity": "sha512-5Yy9czTO47mqz+/J8GM6GIId4umdCk1wc1q8rKERQulIoc8VP9pzDcghv10Tl2E7R96ZUx/PhND3ESYUQX8NuQ==" + "@scure/base@1.2.6": { + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==" }, "@scure/bip32@1.3.1": { "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", @@ -644,54 +800,34 @@ "acorn@8.15.0" ] }, - "@sveltejs/adapter-auto@3.3.1_@sveltejs+kit@2.17.3__@sveltejs+vite-plugin-svelte@4.0.4___svelte@5.21.0____acorn@8.14.0___vite@5.4.14____@types+node@22.13.9___@types+node@22.13.9__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9": { + "@sveltejs/adapter-auto@3.3.1_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@5.1.1___svelte@5.0.5____acorn@8.14.0___vite@6.3.5____@types+node@22.13.9____picomatch@4.0.2___@types+node@22.13.9__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__acorn@8.15.0__@types+node@22.13.9_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9": { "integrity": "sha512-5Sc7WAxYdL6q9j/+D0jJKjGREGlfIevDyHSQ2eNETHcB1TKlQWHcAo8AS8H1QdjNvSXpvOwNjykDUHPEAyGgdQ==", "dependencies": [ - "@sveltejs/kit@2.17.3_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", + "@sveltejs/kit", "import-meta-resolve" ] }, - "@sveltejs/adapter-node@5.2.12_@sveltejs+kit@2.17.3__@sveltejs+vite-plugin-svelte@4.0.4___svelte@5.21.0____acorn@8.14.0___vite@5.4.14____@types+node@22.13.9___@types+node@22.13.9__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_rollup@4.34.9_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9": { - "integrity": "sha512-0bp4Yb3jKIEcZWVcJC/L1xXp9zzJS4hDwfb4VITAkfT4OVdkspSHsx7YhqJDbb2hgLl6R9Vs7VQR+fqIVOxPUQ==", + "@sveltejs/adapter-node@5.2.13_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@5.1.1___svelte@5.0.5____acorn@8.14.0___vite@6.3.5____@types+node@22.13.9____picomatch@4.0.2___@types+node@22.13.9__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__acorn@8.15.0__@types+node@22.13.9_rollup@4.34.9_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9": { + "integrity": "sha512-yS2TVFmIrxjGhYaV5/iIUrJ3mJl6zjaYn0lBD70vTLnYvJeqf3cjvLXeXCUCuYinhSBoyF4DpfGla49BnIy7sQ==", "dependencies": [ "@rollup/plugin-commonjs", "@rollup/plugin-json", - "@rollup/plugin-node-resolve@16.0.0_rollup@4.34.9", - "@sveltejs/kit@2.17.3_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", + "@rollup/plugin-node-resolve@16.0.1_rollup@4.34.9", + "@sveltejs/kit", "rollup" ] }, - "@sveltejs/adapter-static@3.0.8_@sveltejs+kit@2.17.3__@sveltejs+vite-plugin-svelte@4.0.4___svelte@5.21.0____acorn@8.14.0___vite@5.4.14____@types+node@22.13.9___@types+node@22.13.9__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9": { + "@sveltejs/adapter-static@3.0.8_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@5.1.1___svelte@5.0.5____acorn@8.14.0___vite@6.3.5____@types+node@22.13.9____picomatch@4.0.2___@types+node@22.13.9__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__acorn@8.15.0__@types+node@22.13.9_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9": { "integrity": "sha512-YaDrquRpZwfcXbnlDsSrBQNCChVOT9MGuSg+dMAyfsAa1SmiAhrA5jUYUiIMC59G92kIbY/AaQOWcBdq+lh+zg==", "dependencies": [ - "@sveltejs/kit@2.17.3_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9" + "@sveltejs/kit" ] }, - "@sveltejs/kit@2.17.3_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9": { - "integrity": "sha512-GcNaPDr0ti4O/TonPewkML2DG7UVXkSxPN3nPMlpmx0Rs4b2kVP4gymz98WEHlfzPXdd4uOOT1Js26DtieTNBQ==", - "dependencies": [ - "@sveltejs/vite-plugin-svelte@4.0.4_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", - "@types/cookie", - "cookie", - "devalue", - "esm-env", - "import-meta-resolve", - "kleur", - "magic-string", - "mrmime", - "sade", - "set-cookie-parser", - "sirv", - "svelte@5.21.0_acorn@8.14.0", - "vite" - ], - "bin": true - }, - "@sveltejs/kit@2.22.2_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_acorn@8.15.0_@types+node@22.13.9": { - "integrity": "sha512-2MvEpSYabUrsJAoq5qCOBGAlkICjfjunrnLcx3YAk2XV7TvAIhomlKsAgR4H/4uns5rAfYmj7Wet5KRtc8dPIg==", + "@sveltejs/kit@2.25.1_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_acorn@8.15.0_@types+node@22.13.9": { + "integrity": "sha512-8H+fxDEp7Xq6tLFdrGdS5fLu6ONDQQ9DgyjboXpChubuFdfH9QoFX09ypssBpyNkJNZFt9eW3yLmXIc9CesPCA==", "dependencies": [ "@sveltejs/acorn-typescript", - "@sveltejs/vite-plugin-svelte@4.0.4_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0", + "@sveltejs/vite-plugin-svelte", "@types/cookie", "acorn@8.15.0", "cookie", @@ -704,47 +840,24 @@ "set-cookie-parser", "sirv", "svelte@5.0.5_acorn@8.14.0", - "vite", - "vitefu" + "vite" ], "bin": true }, - "@sveltejs/vite-plugin-svelte-inspector@3.0.1_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9": { - "integrity": "sha512-2CKypmj1sM4GE7HjllT7UKmo4Q6L5xFRd7VMGEWhYnZ+wc6AUVU01IBd7yUi6WnFndEwWoMNOd6e8UjoN0nbvQ==", + "@sveltejs/vite-plugin-svelte-inspector@4.0.1_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9": { + "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==", "dependencies": [ - "@sveltejs/vite-plugin-svelte@4.0.4_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0", - "debug@4.4.0", - "svelte@5.21.0_acorn@8.14.0", - "vite" - ] - }, - "@sveltejs/vite-plugin-svelte-inspector@3.0.1_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0": { - "integrity": "sha512-2CKypmj1sM4GE7HjllT7UKmo4Q6L5xFRd7VMGEWhYnZ+wc6AUVU01IBd7yUi6WnFndEwWoMNOd6e8UjoN0nbvQ==", - "dependencies": [ - "@sveltejs/vite-plugin-svelte@4.0.4_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0", - "debug@4.4.0", + "@sveltejs/vite-plugin-svelte", + "debug@4.4.1", "svelte@5.0.5_acorn@8.14.0", "vite" ] }, - "@sveltejs/vite-plugin-svelte@4.0.4_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9": { - "integrity": "sha512-0ba1RQ/PHen5FGpdSrW7Y3fAMQjrXantECALeOiOdBdzR5+5vPP6HVZRLmZaQL+W8m++o+haIAKq5qT+MiZ7VA==", + "@sveltejs/vite-plugin-svelte@5.1.1_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9": { + "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==", "dependencies": [ - "@sveltejs/vite-plugin-svelte-inspector@3.0.1_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9", - "debug@4.4.0", - "deepmerge", - "kleur", - "magic-string", - "svelte@5.21.0_acorn@8.14.0", - "vite", - "vitefu" - ] - }, - "@sveltejs/vite-plugin-svelte@4.0.4_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0": { - "integrity": "sha512-0ba1RQ/PHen5FGpdSrW7Y3fAMQjrXantECALeOiOdBdzR5+5vPP6HVZRLmZaQL+W8m++o+haIAKq5qT+MiZ7VA==", - "dependencies": [ - "@sveltejs/vite-plugin-svelte-inspector@3.0.1_@sveltejs+vite-plugin-svelte@4.0.4__svelte@5.21.0___acorn@8.14.0__vite@5.4.14___@types+node@22.13.9__@types+node@22.13.9_svelte@5.21.0__acorn@8.14.0_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0", - "debug@4.4.0", + "@sveltejs/vite-plugin-svelte-inspector", + "debug@4.4.1", "deepmerge", "kleur", "magic-string", @@ -770,6 +883,12 @@ "tailwindcss" ] }, + "@types/chai@5.2.2": { + "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==", + "dependencies": [ + "@types/deep-eql" + ] + }, "@types/cookie@0.6.0": { "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==" }, @@ -933,6 +1052,9 @@ "@types/d3-zoom" ] }, + "@types/deep-eql@4.0.2": { + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==" + }, "@types/estree@1.0.6": { "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" }, @@ -966,17 +1088,18 @@ "@types/resolve@1.20.2": { "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==" }, - "@vitest/expect@3.1.4": { - "integrity": "sha512-xkD/ljeliyaClDYqHPNCiJ0plY5YIcM0OlRiZizLhlPmpXWpxnGMyTZXOHFhFeG7w9P5PBeL4IdtJ/HeQwTbQA==", + "@vitest/expect@3.2.4": { + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", "dependencies": [ + "@types/chai", "@vitest/spy", "@vitest/utils", "chai", "tinyrainbow" ] }, - "@vitest/mocker@3.1.4_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9": { - "integrity": "sha512-8IJ3CvwtSw/EFXqWFL8aCMu+YyYXG2WUSrQbViOZkWTKTVicVwZ/YiEZDSqD00kX+v/+W+OnxhNWoeVKorHygA==", + "@vitest/mocker@3.2.4_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9": { + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", "dependencies": [ "@vitest/spy", "estree-walker@3.0.3", @@ -987,35 +1110,36 @@ "vite" ] }, - "@vitest/pretty-format@3.1.4": { - "integrity": "sha512-cqv9H9GvAEoTaoq+cYqUTCGscUjKqlJZC7PRwY5FMySVj5J+xOm1KQcCiYHJOEzOKRUhLH4R2pTwvFlWCEScsg==", + "@vitest/pretty-format@3.2.4": { + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", "dependencies": [ "tinyrainbow" ] }, - "@vitest/runner@3.1.4": { - "integrity": "sha512-djTeF1/vt985I/wpKVFBMWUlk/I7mb5hmD5oP8K9ACRmVXgKTae3TUOtXAEBfslNKPzUQvnKhNd34nnRSYgLNQ==", + "@vitest/runner@3.2.4": { + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", "dependencies": [ "@vitest/utils", - "pathe" + "pathe", + "strip-literal" ] }, - "@vitest/snapshot@3.1.4": { - "integrity": "sha512-JPHf68DvuO7vilmvwdPr9TS0SuuIzHvxeaCkxYcCD4jTk67XwL45ZhEHFKIuCm8CYstgI6LZ4XbwD6ANrwMpFg==", + "@vitest/snapshot@3.2.4": { + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", "dependencies": [ "@vitest/pretty-format", "magic-string", "pathe" ] }, - "@vitest/spy@3.1.4": { - "integrity": "sha512-Xg1bXhu+vtPXIodYN369M86K8shGLouNjoVI78g8iAq2rFoHFdajNvJJ5A/9bPMFcfQqdaCpOgWKEoMQg/s0Yg==", + "@vitest/spy@3.2.4": { + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", "dependencies": [ "tinyspy" ] }, - "@vitest/utils@3.1.4": { - "integrity": "sha512-yriMuO1cfFhmiGc8ataN51+9ooHRuURdfAZfwFd3usWynjzpLslZdYnRegTv32qdgtJTsj15FoeZe2g15fY1gg==", + "@vitest/utils@3.2.4": { + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", "dependencies": [ "@vitest/pretty-format", "loupe", @@ -1227,8 +1351,8 @@ "caniuse-lite@1.0.30001702": { "integrity": "sha512-LoPe/D7zioC0REI5W73PeR1e1MLCipRGq/VkovJnd6Df+QVqT+vT33OXCp8QUd7kA7RZrHWxb1B36OQKI/0gOA==" }, - "chai@5.2.0": { - "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", + "chai@5.2.1": { + "integrity": "sha512-5nFxhUrX0PqtyogoYOA8IPswy5sZFTOsBFl/9bNsmDLgsxYTzSZQJDPppDnZPTQbzSEm0hqGjWPzRemQCYbD6A==", "dependencies": [ "assertion-error", "check-error", @@ -1564,6 +1688,12 @@ "ms@2.1.3" ] }, + "debug@4.4.1": { + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dependencies": [ + "ms@2.1.3" + ] + }, "decamelize@1.2.0": { "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" }, @@ -1670,32 +1800,35 @@ "ext" ] }, - "esbuild@0.21.5": { - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "esbuild@0.25.7": { + "integrity": "sha512-daJB0q2dmTzo90L9NjRaohhRWrCzYxWNFTjEi72/h+p5DcY3yn4MacWfDakHmaBaDzDiuLJsCh0+6LK/iX+c+Q==", "optionalDependencies": [ - "@esbuild/aix-ppc64", - "@esbuild/android-arm", - "@esbuild/android-arm64", - "@esbuild/android-x64", - "@esbuild/darwin-arm64", - "@esbuild/darwin-x64", - "@esbuild/freebsd-arm64", - "@esbuild/freebsd-x64", - "@esbuild/linux-arm", - "@esbuild/linux-arm64", - "@esbuild/linux-ia32", - "@esbuild/linux-loong64", - "@esbuild/linux-mips64el", - "@esbuild/linux-ppc64", - "@esbuild/linux-riscv64", - "@esbuild/linux-s390x", - "@esbuild/linux-x64", - "@esbuild/netbsd-x64", - "@esbuild/openbsd-x64", - "@esbuild/sunos-x64", - "@esbuild/win32-arm64", - "@esbuild/win32-ia32", - "@esbuild/win32-x64" + "@esbuild/aix-ppc64@0.25.7", + "@esbuild/android-arm@0.25.7", + "@esbuild/android-arm64@0.25.7", + "@esbuild/android-x64@0.25.7", + "@esbuild/darwin-arm64@0.25.7", + "@esbuild/darwin-x64@0.25.7", + "@esbuild/freebsd-arm64@0.25.7", + "@esbuild/freebsd-x64@0.25.7", + "@esbuild/linux-arm@0.25.7", + "@esbuild/linux-arm64@0.25.7", + "@esbuild/linux-ia32@0.25.7", + "@esbuild/linux-loong64@0.25.7", + "@esbuild/linux-mips64el@0.25.7", + "@esbuild/linux-ppc64@0.25.7", + "@esbuild/linux-riscv64@0.25.7", + "@esbuild/linux-s390x@0.25.7", + "@esbuild/linux-x64@0.25.7", + "@esbuild/netbsd-arm64", + "@esbuild/netbsd-x64@0.25.7", + "@esbuild/openbsd-arm64", + "@esbuild/openbsd-x64@0.25.7", + "@esbuild/openharmony-arm64", + "@esbuild/sunos-x64@0.25.7", + "@esbuild/win32-arm64@0.25.7", + "@esbuild/win32-ia32@0.25.7", + "@esbuild/win32-x64@0.25.7" ], "scripts": true, "bin": true @@ -1883,8 +2016,8 @@ "es5-ext" ] }, - "expect-type@1.2.1": { - "integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==" + "expect-type@1.2.2": { + "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==" }, "ext@1.7.0": { "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", @@ -1917,17 +2050,8 @@ "reusify" ] }, - "fdir@6.4.3_picomatch@4.0.2": { - "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", - "dependencies": [ - "picomatch@4.0.2" - ], - "optionalPeers": [ - "picomatch@4.0.2" - ] - }, - "fdir@6.4.4_picomatch@4.0.2": { - "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "fdir@6.4.6_picomatch@4.0.2": { + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", "dependencies": [ "picomatch@4.0.2" ], @@ -2291,6 +2415,9 @@ "js-stringify@1.0.2": { "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==" }, + "js-tokens@9.0.1": { + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==" + }, "js-yaml@4.1.0": { "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dependencies": [ @@ -2372,8 +2499,8 @@ "lodash.merge@4.6.2": { "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "loupe@3.1.3": { - "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==" + "loupe@3.1.4": { + "integrity": "sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==" }, "lru-cache@10.4.3": { "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" @@ -2480,7 +2607,7 @@ "normalize-range@0.1.2": { "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==" }, - "nostr-tools@2.10.4_typescript@5.7.3": { + "nostr-tools@2.10.4_typescript@5.8.3": { "integrity": "sha512-biU7sk+jxHgVASfobg2T5ttxOGGSt69wEVBC51sHHOEaKAAdzHBLV/I2l9Rf61UzClhliZwNouYhqIso4a3HYg==", "dependencies": [ "@noble/ciphers", @@ -2498,6 +2625,22 @@ "typescript" ] }, + "nostr-tools@2.15.1_typescript@5.8.3": { + "integrity": "sha512-LpetHDR9ltnkpJDkva/SONgyKBbsoV+5yLB8DWc0/U3lCWGtoWJw6Nbc2vR2Ai67RIQYrBQeZLyMlhwVZRK/9A==", + "dependencies": [ + "@noble/ciphers", + "@noble/curves@1.2.0", + "@noble/hashes@1.3.1", + "@scure/base@1.1.1", + "@scure/bip32", + "@scure/bip39", + "nostr-wasm", + "typescript" + ], + "optionalPeers": [ + "typescript" + ] + }, "nostr-wasm@0.1.0": { "integrity": "sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA==" }, @@ -2588,8 +2731,8 @@ "pathe@2.0.3": { "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==" }, - "pathval@2.0.0": { - "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==" + "pathval@2.0.1": { + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==" }, "picocolors@1.1.1": { "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" @@ -2606,6 +2749,9 @@ "pirates@4.0.6": { "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==" }, + "plantuml-encoder@1.4.0": { + "integrity": "sha512-sxMwpDw/ySY1WB2CE3+IdMuEcWibJ72DDOsXLkSmEaSzwEUaYBT6DWgOfBiHGCux4q433X6+OEFWjlVqp7gL6g==" + }, "playwright-core@1.50.1": { "integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==", "bin": true @@ -3006,6 +3152,12 @@ "strip-json-comments@3.1.1": { "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" }, + "strip-literal@3.0.0": { + "integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==", + "dependencies": [ + "js-tokens" + ] + }, "sucrase@3.35.0": { "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", "dependencies": [ @@ -3028,15 +3180,15 @@ "supports-preserve-symlinks-flag@1.0.0": { "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, - "svelte-check@4.1.4_svelte@5.21.0__acorn@8.14.0_typescript@5.7.3": { - "integrity": "sha512-v0j7yLbT29MezzaQJPEDwksybTE2Ups9rUxEXy92T06TiA0cbqcO8wAOwNUVkFW6B0hsYHA+oAX3BS8b/2oHtw==", + "svelte-check@4.3.0_svelte@5.0.5__acorn@8.14.0_typescript@5.8.3": { + "integrity": "sha512-Iz8dFXzBNAM7XlEIsUjUGQhbEE+Pvv9odb9+0+ITTgFWZBGeJRRYqHUUglwe2EkLD5LIsQaAc4IUJyvtKuOO5w==", "dependencies": [ "@jridgewell/trace-mapping", "chokidar@4.0.3", - "fdir@6.4.3_picomatch@4.0.2", + "fdir", "picocolors", "sade", - "svelte@5.21.0_acorn@8.14.0", + "svelte@5.0.5_acorn@8.14.0", "typescript" ], "bin": true @@ -3204,21 +3356,21 @@ "tinyexec@0.3.2": { "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==" }, - "tinyglobby@0.2.13_picomatch@4.0.2": { - "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "tinyglobby@0.2.14_picomatch@4.0.2": { + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "dependencies": [ - "fdir@6.4.4_picomatch@4.0.2", + "fdir", "picomatch@4.0.2" ] }, - "tinypool@1.0.2": { - "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==" + "tinypool@1.1.1": { + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==" }, "tinyrainbow@2.0.0": { "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==" }, - "tinyspy@3.0.2": { - "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==" + "tinyspy@4.0.3": { + "integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==" }, "to-regex-range@5.0.1": { "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", @@ -3262,8 +3414,8 @@ "typescript-lru-cache@2.0.0": { "integrity": "sha512-Jp57Qyy8wXeMkdNuZiglE6v2Cypg13eDA1chHwDG6kq51X7gk4K7P7HaDdzZKCxkegXkVHNcPD0n5aW6OZH3aA==" }, - "typescript@5.7.3": { - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "typescript@5.8.3": { + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "bin": true }, "uglify-js@3.19.3": { @@ -3307,24 +3459,27 @@ "util-deprecate@1.0.2": { "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, - "vite-node@3.1.4_@types+node@22.13.9": { - "integrity": "sha512-6enNwYnpyDo4hEgytbmc6mYWHXDHYEn0D1/rw4Q+tnHUGtKTJsn8T1YkX6Q18wI5LCrS8CTYlBaiCqxOy2kvUA==", + "vite-node@3.2.4_@types+node@22.13.9": { + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", "dependencies": [ "cac", - "debug@4.4.0", + "debug@4.4.1", "es-module-lexer", "pathe", "vite" ], "bin": true }, - "vite@5.4.14_@types+node@22.13.9": { - "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==", + "vite@6.3.5_@types+node@22.13.9_picomatch@4.0.2": { + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "dependencies": [ "@types/node@22.13.9", "esbuild", + "fdir", + "picomatch@4.0.2", "postcss", - "rollup" + "rollup", + "tinyglobby" ], "optionalDependencies": [ "fsevents@2.3.3" @@ -3334,8 +3489,8 @@ ], "bin": true }, - "vitefu@1.0.6_vite@5.4.14__@types+node@22.13.9_@types+node@22.13.9": { - "integrity": "sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==", + "vitefu@1.1.1_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9": { + "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==", "dependencies": [ "vite" ], @@ -3343,9 +3498,10 @@ "vite" ] }, - "vitest@3.1.4_@types+node@22.13.9_vite@5.4.14__@types+node@22.13.9": { - "integrity": "sha512-Ta56rT7uWxCSJXlBtKgIlApJnT6e6IGmTYxYcmxjJ4ujuZDI59GUQgVDObXXJujOmPDBYXHK1qmaGtneu6TNIQ==", + "vitest@3.2.4_@types+node@22.13.9_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2": { + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dependencies": [ + "@types/chai", "@types/node@22.13.9", "@vitest/expect", "@vitest/mocker", @@ -3355,10 +3511,11 @@ "@vitest/spy", "@vitest/utils", "chai", - "debug@4.4.0", + "debug@4.4.1", "expect-type", "magic-string", "pathe", + "picomatch@4.0.2", "std-env", "tinybench", "tinyexec", @@ -3543,15 +3700,15 @@ ], "packageJson": { "dependencies": [ - "npm:@nostr-dev-kit/ndk-cache-dexie@2.5", - "npm:@nostr-dev-kit/ndk@2.11", + "npm:@nostr-dev-kit/ndk-cache-dexie@2.6", + "npm:@nostr-dev-kit/ndk@^2.14.32", "npm:@playwright/test@^1.50.1", "npm:@popperjs/core@2.11", "npm:@sveltejs/adapter-auto@3", - "npm:@sveltejs/adapter-node@^5.2.12", + "npm:@sveltejs/adapter-node@^5.2.13", "npm:@sveltejs/adapter-static@3", - "npm:@sveltejs/kit@^2.22.2", - "npm:@sveltejs/vite-plugin-svelte@4", + "npm:@sveltejs/kit@^2.25.0", + "npm:@sveltejs/vite-plugin-svelte@5", "npm:@tailwindcss/forms@0.5", "npm:@tailwindcss/typography@0.5", "npm:@types/d3@^7.4.3", @@ -3569,7 +3726,8 @@ "npm:he@1.2", "npm:highlight.js@^11.11.1", "npm:node-emoji@^2.2.0", - "npm:nostr-tools@2.10", + "npm:nostr-tools@2.15", + "npm:plantuml-encoder@^1.4.0", "npm:playwright@^1.50.1", "npm:postcss-load-config@6", "npm:postcss@8", @@ -3581,8 +3739,8 @@ "npm:tailwind-merge@^3.3.0", "npm:tailwindcss@3", "npm:tslib@2.8", - "npm:typescript@5.7", - "npm:vite@5", + "npm:typescript@5.8", + "npm:vite@6", "npm:vitest@^3.1.3" ] } From e26c6a9fdd227f82374c08344f64aa6003082b16 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Fri, 18 Jul 2025 18:18:09 -0500 Subject: [PATCH 132/135] Set package version to agree with tag --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a41e1f7..e5c9a9c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "alexandria", - "version": "0.0.6", + "version": "0.0.2", "private": true, "type": "module", "scripts": { From 163236db2a4c327577ebe12f19ed9888df061b65 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 19 Jul 2025 01:11:16 -0500 Subject: [PATCH 133/135] Update deps and include @noble packages --- deno.json | 1 - deno.lock | 1160 +++++++++++++++++------------------------------ import_map.json | 16 +- package.json | 31 +- 4 files changed, 446 insertions(+), 762 deletions(-) diff --git a/deno.json b/deno.json index 8b474cb..9e2ecc6 100644 --- a/deno.json +++ b/deno.json @@ -1,7 +1,6 @@ { "importMap": "./import_map.json", "compilerOptions": { - "allowJs": true, "lib": ["dom", "dom.iterable", "dom.asynciterable", "deno.ns"] } } diff --git a/deno.lock b/deno.lock index b94e4ee..098f9db 100644 --- a/deno.lock +++ b/deno.lock @@ -1,55 +1,59 @@ { "version": "5", "specifiers": { - "npm:@nostr-dev-kit/ndk-cache-dexie@2.5": "2.5.15_typescript@5.8.3", + "npm:@noble/curves@^1.9.4": "1.9.4", + "npm:@noble/hashes@^1.8.0": "1.8.0", + "npm:@noble/secp256k1@^2.3.0": "2.3.0", "npm:@nostr-dev-kit/ndk-cache-dexie@2.6": "2.6.33_nostr-tools@2.15.1__typescript@5.8.3_typescript@5.8.3", - "npm:@nostr-dev-kit/ndk@2.11": "2.11.2_typescript@5.8.3", + "npm:@nostr-dev-kit/ndk-cache-dexie@^2.6.33": "2.6.33_nostr-tools@2.15.1__typescript@5.8.3_typescript@5.8.3", "npm:@nostr-dev-kit/ndk@^2.14.32": "2.14.32_nostr-tools@2.15.1__typescript@5.8.3_typescript@5.8.3", - "npm:@playwright/test@^1.50.1": "1.50.1", + "npm:@playwright/test@^1.54.1": "1.54.1", "npm:@popperjs/core@2.11": "2.11.8", - "npm:@sveltejs/adapter-auto@3": "3.3.1_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@5.1.1___svelte@5.0.5____acorn@8.14.0___vite@6.3.5____@types+node@22.13.9____picomatch@4.0.2___@types+node@22.13.9__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__acorn@8.15.0__@types+node@22.13.9_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9", - "npm:@sveltejs/adapter-node@^5.2.13": "5.2.13_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@5.1.1___svelte@5.0.5____acorn@8.14.0___vite@6.3.5____@types+node@22.13.9____picomatch@4.0.2___@types+node@22.13.9__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__acorn@8.15.0__@types+node@22.13.9_rollup@4.34.9_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9", - "npm:@sveltejs/adapter-static@3": "3.0.8_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@5.1.1___svelte@5.0.5____acorn@8.14.0___vite@6.3.5____@types+node@22.13.9____picomatch@4.0.2___@types+node@22.13.9__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__acorn@8.15.0__@types+node@22.13.9_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9", - "npm:@sveltejs/kit@^2.25.0": "2.25.1_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_acorn@8.15.0_@types+node@22.13.9", - "npm:@sveltejs/vite-plugin-svelte@5": "5.1.1_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9", - "npm:@tailwindcss/forms@0.5": "0.5.10_tailwindcss@3.4.17__postcss@8.5.3", - "npm:@tailwindcss/typography@0.5": "0.5.16_tailwindcss@3.4.17__postcss@8.5.3", + "npm:@sveltejs/adapter-auto@^6.0.1": "6.0.1_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@6.1.0___svelte@5.36.8____acorn@8.15.0___vite@7.0.5____@types+node@24.0.15____picomatch@4.0.3___@types+node@24.0.15__svelte@5.36.8___acorn@8.15.0__vite@7.0.5___@types+node@24.0.15___picomatch@4.0.3__acorn@8.15.0__@types+node@24.0.15_@sveltejs+vite-plugin-svelte@6.1.0__svelte@5.36.8___acorn@8.15.0__vite@7.0.5___@types+node@24.0.15___picomatch@4.0.3__@types+node@24.0.15_svelte@5.36.8__acorn@8.15.0_vite@7.0.5__@types+node@24.0.15__picomatch@4.0.3_@types+node@24.0.15", + "npm:@sveltejs/adapter-node@^5.2.13": "5.2.13_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@6.1.0___svelte@5.36.8____acorn@8.15.0___vite@7.0.5____@types+node@24.0.15____picomatch@4.0.3___@types+node@24.0.15__svelte@5.36.8___acorn@8.15.0__vite@7.0.5___@types+node@24.0.15___picomatch@4.0.3__acorn@8.15.0__@types+node@24.0.15_rollup@4.45.1_@sveltejs+vite-plugin-svelte@6.1.0__svelte@5.36.8___acorn@8.15.0__vite@7.0.5___@types+node@24.0.15___picomatch@4.0.3__@types+node@24.0.15_svelte@5.36.8__acorn@8.15.0_vite@7.0.5__@types+node@24.0.15__picomatch@4.0.3_@types+node@24.0.15", + "npm:@sveltejs/adapter-static@3": "3.0.8_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@6.1.0___svelte@5.36.8____acorn@8.15.0___vite@7.0.5____@types+node@24.0.15____picomatch@4.0.3___@types+node@24.0.15__svelte@5.36.8___acorn@8.15.0__vite@7.0.5___@types+node@24.0.15___picomatch@4.0.3__acorn@8.15.0__@types+node@24.0.15_@sveltejs+vite-plugin-svelte@6.1.0__svelte@5.36.8___acorn@8.15.0__vite@7.0.5___@types+node@24.0.15___picomatch@4.0.3__@types+node@24.0.15_svelte@5.36.8__acorn@8.15.0_vite@7.0.5__@types+node@24.0.15__picomatch@4.0.3_@types+node@24.0.15", + "npm:@sveltejs/kit@^2.25.0": "2.25.1_@sveltejs+vite-plugin-svelte@6.1.0__svelte@5.36.8___acorn@8.15.0__vite@7.0.5___@types+node@24.0.15___picomatch@4.0.3__@types+node@24.0.15_svelte@5.36.8__acorn@8.15.0_vite@7.0.5__@types+node@24.0.15__picomatch@4.0.3_acorn@8.15.0_@types+node@24.0.15", + "npm:@sveltejs/vite-plugin-svelte@^6.1.0": "6.1.0_svelte@5.36.8__acorn@8.15.0_vite@7.0.5__@types+node@24.0.15__picomatch@4.0.3_@types+node@24.0.15", + "npm:@tailwindcss/forms@0.5": "0.5.10_tailwindcss@3.4.17__postcss@8.5.6", + "npm:@tailwindcss/typography@0.5": "0.5.16_tailwindcss@3.4.17__postcss@8.5.6", "npm:@types/d3@^7.4.3": "7.4.3", "npm:@types/he@1.2": "1.2.3", - "npm:@types/node@22": "22.13.9", + "npm:@types/mathjax@^0.0.40": "0.0.40", + "npm:@types/node@^24.0.15": "24.0.15", "npm:@types/qrcode@^1.5.5": "1.5.5", "npm:asciidoctor@3.0": "3.0.4_@asciidoctor+core@3.0.4", - "npm:autoprefixer@10": "10.4.20_postcss@8.5.3", + "npm:autoprefixer@^10.4.21": "10.4.21_postcss@8.5.6", "npm:bech32@2": "2.0.0", "npm:d3@7.9": "7.9.0_d3-selection@3.0.0", "npm:d3@^7.9.0": "7.9.0_d3-selection@3.0.0", - "npm:eslint-plugin-svelte@2": "2.46.1_eslint@9.21.0_svelte@5.21.0__acorn@8.14.0_postcss@8.5.3_svelte@5.0.5__acorn@8.14.0", - "npm:flowbite-svelte-icons@2.1": "2.1.1_svelte@5.0.5__acorn@8.14.0_tailwind-merge@3.3.0", - "npm:flowbite-svelte@0.48": "0.48.6_svelte@5.0.5__acorn@8.14.0", + "npm:eslint-plugin-svelte@^3.11.0": "3.11.0_eslint@9.31.0_svelte@5.36.8__acorn@8.15.0_postcss@8.5.6", + "npm:flowbite-svelte-icons@2.1": "2.1.1_svelte@5.36.8__acorn@8.15.0_tailwind-merge@3.3.1", + "npm:flowbite-svelte-icons@^2.2.1": "2.2.1_svelte@5.36.8__acorn@8.15.0", + "npm:flowbite-svelte@0.48": "0.48.6_svelte@5.36.8__acorn@8.15.0", + "npm:flowbite-svelte@^1.10.10": "1.10.10_svelte@5.36.8__acorn@8.15.0_tailwindcss@3.4.17__postcss@8.5.6", "npm:flowbite@2": "2.5.2", - "npm:flowbite@2.2": "2.2.1", + "npm:flowbite@^3.1.2": "3.1.2", "npm:he@1.2": "1.2.0", "npm:highlight.js@^11.11.1": "11.11.1", "npm:node-emoji@^2.2.0": "2.2.0", - "npm:nostr-tools@2.10": "2.10.4_typescript@5.8.3", "npm:nostr-tools@2.15": "2.15.1_typescript@5.8.3", + "npm:nostr-tools@^2.15.1": "2.15.1_typescript@5.8.3", "npm:plantuml-encoder@^1.4.0": "1.4.0", - "npm:playwright@^1.50.1": "1.50.1", - "npm:postcss-load-config@6": "6.0.1_postcss@8.5.3", - "npm:postcss@8": "8.5.3", - "npm:prettier-plugin-svelte@3": "3.3.3_prettier@3.5.3_svelte@5.21.0__acorn@8.14.0", - "npm:prettier@3": "3.5.3", + "npm:playwright@^1.50.1": "1.54.1", + "npm:playwright@^1.54.1": "1.54.1", + "npm:postcss-load-config@6": "6.0.1_postcss@8.5.6", + "npm:postcss@^8.5.6": "8.5.6", + "npm:prettier-plugin-svelte@^3.4.0": "3.4.0_prettier@3.6.2_svelte@5.36.8__acorn@8.15.0", + "npm:prettier@^3.6.2": "3.6.2", "npm:qrcode@^1.5.4": "1.5.4", - "npm:svelte-check@4": "4.3.0_svelte@5.0.5__acorn@8.14.0_typescript@5.8.3", - "npm:svelte@5": "5.21.0_acorn@8.14.0", - "npm:svelte@5.0": "5.0.5_acorn@8.14.0", - "npm:tailwind-merge@2.5": "2.5.5", - "npm:tailwind-merge@^3.3.0": "3.3.0", - "npm:tailwindcss@3": "3.4.17_postcss@8.5.3", + "npm:svelte-check@4": "4.3.0_svelte@5.36.8__acorn@8.15.0_typescript@5.8.3", + "npm:svelte@^5.36.8": "5.36.8_acorn@8.15.0", + "npm:tailwind-merge@^3.3.1": "3.3.1", + "npm:tailwindcss@^3.4.17": "3.4.17_postcss@8.5.6", "npm:tslib@2.8": "2.8.1", - "npm:typescript@5.8": "5.8.3", - "npm:vite@6": "6.3.5_@types+node@22.13.9_picomatch@4.0.2", - "npm:vitest@^3.1.3": "3.2.4_@types+node@22.13.9_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2" + "npm:typescript@^5.8.3": "5.8.3", + "npm:vite@^7.0.5": "7.0.5_@types+node@24.0.15_picomatch@4.0.3", + "npm:vitest@^3.1.3": "3.2.4_@types+node@24.0.15_vite@7.0.5__@types+node@24.0.15__picomatch@4.0.3" }, "npm": { "@alloc/quick-lru@5.2.0": { @@ -84,191 +88,106 @@ "unxhr" ] }, - "@babel/helper-string-parser@7.25.9": { - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==" + "@babel/helper-string-parser@7.27.1": { + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==" }, - "@babel/helper-validator-identifier@7.25.9": { - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==" + "@babel/helper-validator-identifier@7.27.1": { + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==" }, - "@babel/parser@7.26.9": { - "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==", + "@babel/parser@7.28.0": { + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", "dependencies": [ "@babel/types" ], "bin": true }, - "@babel/types@7.26.9": { - "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==", + "@babel/types@7.28.1": { + "integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==", "dependencies": [ "@babel/helper-string-parser", "@babel/helper-validator-identifier" ] }, - "@esbuild/aix-ppc64@0.21.5": { - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "os": ["aix"], - "cpu": ["ppc64"] - }, "@esbuild/aix-ppc64@0.25.7": { "integrity": "sha512-uD0kKFHh6ETr8TqEtaAcV+dn/2qnYbH/+8wGEdY70Qf7l1l/jmBUbrmQqwiPKAQE6cOQ7dTj6Xr0HzQDGHyceQ==", "os": ["aix"], "cpu": ["ppc64"] }, - "@esbuild/android-arm64@0.21.5": { - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "os": ["android"], - "cpu": ["arm64"] - }, "@esbuild/android-arm64@0.25.7": { "integrity": "sha512-p0ohDnwyIbAtztHTNUTzN5EGD/HJLs1bwysrOPgSdlIA6NDnReoVfoCyxG6W1d85jr2X80Uq5KHftyYgaK9LPQ==", "os": ["android"], "cpu": ["arm64"] }, - "@esbuild/android-arm@0.21.5": { - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "os": ["android"], - "cpu": ["arm"] - }, "@esbuild/android-arm@0.25.7": { "integrity": "sha512-Jhuet0g1k9rAJHrXGIh7sFknFuT4sfytYZpZpuZl7YKDhnPByVAm5oy2LEBmMbuYf3ejWVYCc2seX81Mk+madA==", "os": ["android"], "cpu": ["arm"] }, - "@esbuild/android-x64@0.21.5": { - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "os": ["android"], - "cpu": ["x64"] - }, "@esbuild/android-x64@0.25.7": { "integrity": "sha512-mMxIJFlSgVK23HSsII3ZX9T2xKrBCDGyk0qiZnIW10LLFFtZLkFD6imZHu7gUo2wkNZwS9Yj3mOtZD3ZPcjCcw==", "os": ["android"], "cpu": ["x64"] }, - "@esbuild/darwin-arm64@0.21.5": { - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "os": ["darwin"], - "cpu": ["arm64"] - }, "@esbuild/darwin-arm64@0.25.7": { "integrity": "sha512-jyOFLGP2WwRwxM8F1VpP6gcdIJc8jq2CUrURbbTouJoRO7XCkU8GdnTDFIHdcifVBT45cJlOYsZ1kSlfbKjYUQ==", "os": ["darwin"], "cpu": ["arm64"] }, - "@esbuild/darwin-x64@0.21.5": { - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "os": ["darwin"], - "cpu": ["x64"] - }, "@esbuild/darwin-x64@0.25.7": { "integrity": "sha512-m9bVWqZCwQ1BthruifvG64hG03zzz9gE2r/vYAhztBna1/+qXiHyP9WgnyZqHgGeXoimJPhAmxfbeU+nMng6ZA==", "os": ["darwin"], "cpu": ["x64"] }, - "@esbuild/freebsd-arm64@0.21.5": { - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "os": ["freebsd"], - "cpu": ["arm64"] - }, "@esbuild/freebsd-arm64@0.25.7": { "integrity": "sha512-Bss7P4r6uhr3kDzRjPNEnTm/oIBdTPRNQuwaEFWT/uvt6A1YzK/yn5kcx5ZxZ9swOga7LqeYlu7bDIpDoS01bA==", "os": ["freebsd"], "cpu": ["arm64"] }, - "@esbuild/freebsd-x64@0.21.5": { - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "os": ["freebsd"], - "cpu": ["x64"] - }, "@esbuild/freebsd-x64@0.25.7": { "integrity": "sha512-S3BFyjW81LXG7Vqmr37ddbThrm3A84yE7ey/ERBlK9dIiaWgrjRlre3pbG7txh1Uaxz8N7wGGQXmC9zV+LIpBQ==", "os": ["freebsd"], "cpu": ["x64"] }, - "@esbuild/linux-arm64@0.21.5": { - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "os": ["linux"], - "cpu": ["arm64"] - }, "@esbuild/linux-arm64@0.25.7": { "integrity": "sha512-HfQZQqrNOfS1Okn7PcsGUqHymL1cWGBslf78dGvtrj8q7cN3FkapFgNA4l/a5lXDwr7BqP2BSO6mz9UremNPbg==", "os": ["linux"], "cpu": ["arm64"] }, - "@esbuild/linux-arm@0.21.5": { - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "os": ["linux"], - "cpu": ["arm"] - }, "@esbuild/linux-arm@0.25.7": { "integrity": "sha512-JZMIci/1m5vfQuhKoFXogCKVYVfYQmoZJg8vSIMR4TUXbF+0aNlfXH3DGFEFMElT8hOTUF5hisdZhnrZO/bkDw==", "os": ["linux"], "cpu": ["arm"] }, - "@esbuild/linux-ia32@0.21.5": { - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "os": ["linux"], - "cpu": ["ia32"] - }, "@esbuild/linux-ia32@0.25.7": { "integrity": "sha512-9Jex4uVpdeofiDxnwHRgen+j6398JlX4/6SCbbEFEXN7oMO2p0ueLN+e+9DdsdPLUdqns607HmzEFnxwr7+5wQ==", "os": ["linux"], "cpu": ["ia32"] }, - "@esbuild/linux-loong64@0.21.5": { - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "os": ["linux"], - "cpu": ["loong64"] - }, "@esbuild/linux-loong64@0.25.7": { "integrity": "sha512-TG1KJqjBlN9IHQjKVUYDB0/mUGgokfhhatlay8aZ/MSORMubEvj/J1CL8YGY4EBcln4z7rKFbsH+HeAv0d471w==", "os": ["linux"], "cpu": ["loong64"] }, - "@esbuild/linux-mips64el@0.21.5": { - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "os": ["linux"], - "cpu": ["mips64el"] - }, "@esbuild/linux-mips64el@0.25.7": { "integrity": "sha512-Ty9Hj/lx7ikTnhOfaP7ipEm/ICcBv94i/6/WDg0OZ3BPBHhChsUbQancoWYSO0WNkEiSW5Do4febTTy4x1qYQQ==", "os": ["linux"], "cpu": ["mips64el"] }, - "@esbuild/linux-ppc64@0.21.5": { - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "os": ["linux"], - "cpu": ["ppc64"] - }, "@esbuild/linux-ppc64@0.25.7": { "integrity": "sha512-MrOjirGQWGReJl3BNQ58BLhUBPpWABnKrnq8Q/vZWWwAB1wuLXOIxS2JQ1LT3+5T+3jfPh0tyf5CpbyQHqnWIQ==", "os": ["linux"], "cpu": ["ppc64"] }, - "@esbuild/linux-riscv64@0.21.5": { - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "os": ["linux"], - "cpu": ["riscv64"] - }, "@esbuild/linux-riscv64@0.25.7": { "integrity": "sha512-9pr23/pqzyqIZEZmQXnFyqp3vpa+KBk5TotfkzGMqpw089PGm0AIowkUppHB9derQzqniGn3wVXgck19+oqiOw==", "os": ["linux"], "cpu": ["riscv64"] }, - "@esbuild/linux-s390x@0.21.5": { - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "os": ["linux"], - "cpu": ["s390x"] - }, "@esbuild/linux-s390x@0.25.7": { "integrity": "sha512-4dP11UVGh9O6Y47m8YvW8eoA3r8qL2toVZUbBKyGta8j6zdw1cn9F/Rt59/Mhv0OgY68pHIMjGXWOUaykCnx+w==", "os": ["linux"], "cpu": ["s390x"] }, - "@esbuild/linux-x64@0.21.5": { - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "os": ["linux"], - "cpu": ["x64"] - }, "@esbuild/linux-x64@0.25.7": { "integrity": "sha512-ghJMAJTdw/0uhz7e7YnpdX1xVn7VqA0GrWrAO2qKMuqbvgHT2VZiBv1BQ//VcHsPir4wsL3P2oPggfKPzTKoCA==", "os": ["linux"], @@ -279,11 +198,6 @@ "os": ["netbsd"], "cpu": ["arm64"] }, - "@esbuild/netbsd-x64@0.21.5": { - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "os": ["netbsd"], - "cpu": ["x64"] - }, "@esbuild/netbsd-x64@0.25.7": { "integrity": "sha512-tUZRvLtgLE5OyN46sPSYlgmHoBS5bx2URSrgZdW1L1teWPYVmXh+QN/sKDqkzBo/IHGcKcHLKDhBeVVkO7teEA==", "os": ["netbsd"], @@ -294,11 +208,6 @@ "os": ["openbsd"], "cpu": ["arm64"] }, - "@esbuild/openbsd-x64@0.21.5": { - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "os": ["openbsd"], - "cpu": ["x64"] - }, "@esbuild/openbsd-x64@0.25.7": { "integrity": "sha512-TA9XfJrgzAipFUU895jd9j2SyDh9bbNkK2I0gHcvqb/o84UeQkBpi/XmYX3cO1q/9hZokdcDqQxIi6uLVrikxg==", "os": ["openbsd"], @@ -309,48 +218,28 @@ "os": ["openharmony"], "cpu": ["arm64"] }, - "@esbuild/sunos-x64@0.21.5": { - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "os": ["sunos"], - "cpu": ["x64"] - }, "@esbuild/sunos-x64@0.25.7": { "integrity": "sha512-umkbn7KTxsexhv2vuuJmj9kggd4AEtL32KodkJgfhNOHMPtQ55RexsaSrMb+0+jp9XL4I4o2y91PZauVN4cH3A==", "os": ["sunos"], "cpu": ["x64"] }, - "@esbuild/win32-arm64@0.21.5": { - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "os": ["win32"], - "cpu": ["arm64"] - }, "@esbuild/win32-arm64@0.25.7": { "integrity": "sha512-j20JQGP/gz8QDgzl5No5Gr4F6hurAZvtkFxAKhiv2X49yi/ih8ECK4Y35YnjlMogSKJk931iNMcd35BtZ4ghfw==", "os": ["win32"], "cpu": ["arm64"] }, - "@esbuild/win32-ia32@0.21.5": { - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "os": ["win32"], - "cpu": ["ia32"] - }, "@esbuild/win32-ia32@0.25.7": { "integrity": "sha512-4qZ6NUfoiiKZfLAXRsvFkA0hoWVM+1y2bSHXHkpdLAs/+r0LgwqYohmfZCi985c6JWHhiXP30mgZawn/XrqAkQ==", "os": ["win32"], "cpu": ["ia32"] }, - "@esbuild/win32-x64@0.21.5": { - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "os": ["win32"], - "cpu": ["x64"] - }, "@esbuild/win32-x64@0.25.7": { "integrity": "sha512-FaPsAHTwm+1Gfvn37Eg3E5HIpfR3i6x1AIcla/MkqAIupD4BW3MrSeUqfoTzwwJhk3WE2/KqUn4/eenEJC76VA==", "os": ["win32"], "cpu": ["x64"] }, - "@eslint-community/eslint-utils@4.4.1_eslint@9.21.0": { - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "@eslint-community/eslint-utils@4.7.0_eslint@9.31.0": { + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dependencies": [ "eslint", "eslint-visitor-keys@3.4.3" @@ -359,27 +248,30 @@ "@eslint-community/regexpp@4.12.1": { "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==" }, - "@eslint/config-array@0.19.2": { - "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", + "@eslint/config-array@0.21.0": { + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", "dependencies": [ "@eslint/object-schema", - "debug@4.4.0", + "debug", "minimatch@3.1.2" ] }, - "@eslint/core@0.12.0": { - "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", + "@eslint/config-helpers@0.3.0": { + "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==" + }, + "@eslint/core@0.15.1": { + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", "dependencies": [ "@types/json-schema" ] }, - "@eslint/eslintrc@3.3.0": { - "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==", + "@eslint/eslintrc@3.3.1": { + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dependencies": [ "ajv", - "debug@4.4.0", - "espree@10.3.0_acorn@8.14.0", - "globals", + "debug", + "espree", + "globals@14.0.0", "ignore", "import-fresh", "js-yaml", @@ -387,34 +279,34 @@ "strip-json-comments" ] }, - "@eslint/js@9.21.0": { - "integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==" + "@eslint/js@9.31.0": { + "integrity": "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==" }, "@eslint/object-schema@2.1.6": { "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==" }, - "@eslint/plugin-kit@0.2.7": { - "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==", + "@eslint/plugin-kit@0.3.3": { + "integrity": "sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==", "dependencies": [ "@eslint/core", "levn" ] }, - "@floating-ui/core@1.7.1": { - "integrity": "sha512-azI0DrjMMfIug/ExbBaeDVJXcY0a7EPvPjb2xAJPa4HeimBX+Z18HK8QQR3jb6356SnDDdxx+hinMLcJEDdOjw==", + "@floating-ui/core@1.7.2": { + "integrity": "sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==", "dependencies": [ "@floating-ui/utils" ] }, - "@floating-ui/dom@1.7.1": { - "integrity": "sha512-cwsmW/zyw5ltYTUeeYJ60CnQuPqmGwuGVhG9w0PRaRKkAyi38BT5CKrpIbb+jtahSwUl04cWzSx9ZOIxeS6RsQ==", + "@floating-ui/dom@1.7.2": { + "integrity": "sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA==", "dependencies": [ "@floating-ui/core", "@floating-ui/utils" ] }, - "@floating-ui/utils@0.2.9": { - "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==" + "@floating-ui/utils@0.2.10": { + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==" }, "@humanfs/core@0.19.1": { "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==" @@ -432,8 +324,8 @@ "@humanwhocodes/retry@0.3.1": { "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==" }, - "@humanwhocodes/retry@0.4.2": { - "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==" + "@humanwhocodes/retry@0.4.3": { + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==" }, "@isaacs/cliui@8.0.2": { "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", @@ -446,10 +338,9 @@ "wrap-ansi-cjs@npm:wrap-ansi@7.0.0" ] }, - "@jridgewell/gen-mapping@0.3.8": { - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "@jridgewell/gen-mapping@0.3.12": { + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", "dependencies": [ - "@jridgewell/set-array", "@jridgewell/sourcemap-codec", "@jridgewell/trace-mapping" ] @@ -457,14 +348,11 @@ "@jridgewell/resolve-uri@3.1.2": { "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==" }, - "@jridgewell/set-array@1.2.1": { - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" - }, - "@jridgewell/sourcemap-codec@1.5.0": { - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + "@jridgewell/sourcemap-codec@1.5.4": { + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==" }, - "@jridgewell/trace-mapping@0.3.25": { - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "@jridgewell/trace-mapping@0.3.29": { + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", "dependencies": [ "@jridgewell/resolve-uri", "@jridgewell/sourcemap-codec" @@ -520,58 +408,16 @@ "fastq" ] }, - "@nostr-dev-kit/ndk-cache-dexie@2.5.15_typescript@5.8.3": { - "integrity": "sha512-6icRT+tqob0tWqGjQqoaeNDimfO+0gaooG9kch5OQcqlkQh2u1/ySUa47SC/m2E8q3MQVQbU66r8ZjssN2BVmw==", - "dependencies": [ - "@nostr-dev-kit/ndk@2.12.2_typescript@5.8.3", - "debug@4.4.1", - "dexie", - "nostr-tools@2.15.1_typescript@5.8.3", - "typescript-lru-cache" - ] - }, "@nostr-dev-kit/ndk-cache-dexie@2.6.33_nostr-tools@2.15.1__typescript@5.8.3_typescript@5.8.3": { "integrity": "sha512-JzUD5cuJbGQDUXYuW1530vy347Kk3AhdtvPO8tL6kFpV3KzGt/QPZ0SHxcjMhJdf7r6cAIpCEWj9oUlStr0gsg==", "dependencies": [ - "@nostr-dev-kit/ndk@2.14.32_nostr-tools@2.15.1__typescript@5.8.3_typescript@5.8.3", - "debug@4.4.0", + "@nostr-dev-kit/ndk", + "debug", "dexie", - "nostr-tools@2.15.1_typescript@5.8.3", + "nostr-tools", "typescript-lru-cache" ] }, - "@nostr-dev-kit/ndk@2.11.2_typescript@5.8.3": { - "integrity": "sha512-DNrodIBC0j2MqEUQ5Mqaa671iZiRiKluu0c/wLkX7PCva07KSPyvcuyGp5fhk+/EZBurwZccMaML0syH0Qu8kQ==", - "dependencies": [ - "@noble/curves@1.9.4", - "@noble/hashes@1.8.0", - "@noble/secp256k1", - "@scure/base@1.2.6", - "debug@4.4.1", - "light-bolt11-decoder", - "nostr-tools@2.15.1_typescript@5.8.3", - "tseep", - "typescript-lru-cache", - "utf8-buffer", - "websocket-polyfill" - ] - }, - "@nostr-dev-kit/ndk@2.12.2_typescript@5.8.3": { - "integrity": "sha512-uvautgwbpk3AgddoFpew67/FiaV/zpKwwvSnjCvbE/tAdJBpUUS+VjWR5WfUnJvxTy/ZZpPW+X2TkwVFHhUdvA==", - "dependencies": [ - "@noble/curves@1.9.4", - "@noble/hashes@1.8.0", - "@noble/secp256k1", - "@scure/base@1.2.6", - "debug@4.4.1", - "light-bolt11-decoder", - "nostr-tools@2.15.1_typescript@5.8.3", - "tseep", - "typescript-lru-cache", - "utf8-buffer", - "websocket-polyfill" - ] - }, "@nostr-dev-kit/ndk@2.14.32_nostr-tools@2.15.1__typescript@5.8.3_typescript@5.8.3": { "integrity": "sha512-LUBO35RCB9/emBYsXNDece7m/WO2rGYR8j4SD0Crb3z8GcKTJq6P8OjpZ6+Kr+sLNo8N0uL07XxtAvEBnp2OqQ==", "dependencies": [ @@ -579,9 +425,9 @@ "@noble/hashes@1.8.0", "@noble/secp256k1", "@scure/base@1.2.6", - "debug@4.4.0", + "debug", "light-bolt11-decoder", - "nostr-tools@2.15.1_typescript@5.8.3", + "nostr-tools", "tseep", "typescript-lru-cache" ] @@ -589,8 +435,8 @@ "@pkgjs/parseargs@0.11.0": { "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==" }, - "@playwright/test@1.50.1": { - "integrity": "sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==", + "@playwright/test@1.54.1": { + "integrity": "sha512-FS8hQ12acieG2dYSksmLOF7BNxnVf2afRJdCuM1eMSxj6QTSE6G4InGF7oApGgDb65MX7AwMVlIkpru0yZA4Xw==", "dependencies": [ "playwright" ], @@ -602,26 +448,26 @@ "@popperjs/core@2.11.8": { "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" }, - "@rollup/plugin-commonjs@28.0.6_rollup@4.34.9_picomatch@4.0.2": { + "@rollup/plugin-commonjs@28.0.6_rollup@4.45.1_picomatch@4.0.3": { "integrity": "sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw==", "dependencies": [ - "@rollup/pluginutils@5.1.4_rollup@4.34.9", + "@rollup/pluginutils", "commondir", "estree-walker@2.0.2", "fdir", "is-reference@1.2.1", "magic-string", - "picomatch@4.0.2", + "picomatch@4.0.3", "rollup" ], "optionalPeers": [ "rollup" ] }, - "@rollup/plugin-json@6.1.0_rollup@4.34.9": { + "@rollup/plugin-json@6.1.0_rollup@4.45.1": { "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", "dependencies": [ - "@rollup/pluginutils@5.1.4_rollup@4.34.9", + "@rollup/pluginutils", "rollup" ], "optionalPeers": [ @@ -631,17 +477,17 @@ "@rollup/plugin-node-resolve@15.3.1": { "integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==", "dependencies": [ - "@rollup/pluginutils@5.1.4_rollup@4.34.9", + "@rollup/pluginutils", "@types/resolve", "deepmerge", "is-module", "resolve" ] }, - "@rollup/plugin-node-resolve@16.0.1_rollup@4.34.9": { + "@rollup/plugin-node-resolve@16.0.1_rollup@4.45.1": { "integrity": "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==", "dependencies": [ - "@rollup/pluginutils@5.1.4_rollup@4.34.9", + "@rollup/pluginutils", "@types/resolve", "deepmerge", "is-module", @@ -652,121 +498,115 @@ "rollup" ] }, - "@rollup/pluginutils@5.1.4": { - "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", - "dependencies": [ - "@types/estree", - "estree-walker@2.0.2", - "picomatch@4.0.2" - ], - "optionalPeers": [ - "rollup" - ] - }, - "@rollup/pluginutils@5.1.4_rollup@4.34.9": { - "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", + "@rollup/pluginutils@5.2.0_rollup@4.45.1": { + "integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==", "dependencies": [ "@types/estree", "estree-walker@2.0.2", - "picomatch@4.0.2", + "picomatch@4.0.3", "rollup" ], "optionalPeers": [ "rollup" ] }, - "@rollup/rollup-android-arm-eabi@4.34.9": { - "integrity": "sha512-qZdlImWXur0CFakn2BJ2znJOdqYZKiedEPEVNTBrpfPjc/YuTGcaYZcdmNFTkUj3DU0ZM/AElcM8Ybww3xVLzA==", + "@rollup/rollup-android-arm-eabi@4.45.1": { + "integrity": "sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==", "os": ["android"], "cpu": ["arm"] }, - "@rollup/rollup-android-arm64@4.34.9": { - "integrity": "sha512-4KW7P53h6HtJf5Y608T1ISKvNIYLWRKMvfnG0c44M6In4DQVU58HZFEVhWINDZKp7FZps98G3gxwC1sb0wXUUg==", + "@rollup/rollup-android-arm64@4.45.1": { + "integrity": "sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==", "os": ["android"], "cpu": ["arm64"] }, - "@rollup/rollup-darwin-arm64@4.34.9": { - "integrity": "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==", + "@rollup/rollup-darwin-arm64@4.45.1": { + "integrity": "sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==", "os": ["darwin"], "cpu": ["arm64"] }, - "@rollup/rollup-darwin-x64@4.34.9": { - "integrity": "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==", + "@rollup/rollup-darwin-x64@4.45.1": { + "integrity": "sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==", "os": ["darwin"], "cpu": ["x64"] }, - "@rollup/rollup-freebsd-arm64@4.34.9": { - "integrity": "sha512-2lzjQPJbN5UnHm7bHIUKFMulGTQwdvOkouJDpPysJS+QFBGDJqcfh+CxxtG23Ik/9tEvnebQiylYoazFMAgrYw==", + "@rollup/rollup-freebsd-arm64@4.45.1": { + "integrity": "sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==", "os": ["freebsd"], "cpu": ["arm64"] }, - "@rollup/rollup-freebsd-x64@4.34.9": { - "integrity": "sha512-SLl0hi2Ah2H7xQYd6Qaiu01kFPzQ+hqvdYSoOtHYg/zCIFs6t8sV95kaoqjzjFwuYQLtOI0RZre/Ke0nPaQV+g==", + "@rollup/rollup-freebsd-x64@4.45.1": { + "integrity": "sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==", "os": ["freebsd"], "cpu": ["x64"] }, - "@rollup/rollup-linux-arm-gnueabihf@4.34.9": { - "integrity": "sha512-88I+D3TeKItrw+Y/2ud4Tw0+3CxQ2kLgu3QvrogZ0OfkmX/DEppehus7L3TS2Q4lpB+hYyxhkQiYPJ6Mf5/dPg==", + "@rollup/rollup-linux-arm-gnueabihf@4.45.1": { + "integrity": "sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==", "os": ["linux"], "cpu": ["arm"] }, - "@rollup/rollup-linux-arm-musleabihf@4.34.9": { - "integrity": "sha512-3qyfWljSFHi9zH0KgtEPG4cBXHDFhwD8kwg6xLfHQ0IWuH9crp005GfoUUh/6w9/FWGBwEHg3lxK1iHRN1MFlA==", + "@rollup/rollup-linux-arm-musleabihf@4.45.1": { + "integrity": "sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==", "os": ["linux"], "cpu": ["arm"] }, - "@rollup/rollup-linux-arm64-gnu@4.34.9": { - "integrity": "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==", + "@rollup/rollup-linux-arm64-gnu@4.45.1": { + "integrity": "sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==", "os": ["linux"], "cpu": ["arm64"] }, - "@rollup/rollup-linux-arm64-musl@4.34.9": { - "integrity": "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==", + "@rollup/rollup-linux-arm64-musl@4.45.1": { + "integrity": "sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==", "os": ["linux"], "cpu": ["arm64"] }, - "@rollup/rollup-linux-loongarch64-gnu@4.34.9": { - "integrity": "sha512-dRAgTfDsn0TE0HI6cmo13hemKpVHOEyeciGtvlBTkpx/F65kTvShtY/EVyZEIfxFkV5JJTuQ9tP5HGBS0hfxIg==", + "@rollup/rollup-linux-loongarch64-gnu@4.45.1": { + "integrity": "sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==", "os": ["linux"], "cpu": ["loong64"] }, - "@rollup/rollup-linux-powerpc64le-gnu@4.34.9": { - "integrity": "sha512-PHcNOAEhkoMSQtMf+rJofwisZqaU8iQ8EaSps58f5HYll9EAY5BSErCZ8qBDMVbq88h4UxaNPlbrKqfWP8RfJA==", + "@rollup/rollup-linux-powerpc64le-gnu@4.45.1": { + "integrity": "sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==", "os": ["linux"], "cpu": ["ppc64"] }, - "@rollup/rollup-linux-riscv64-gnu@4.34.9": { - "integrity": "sha512-Z2i0Uy5G96KBYKjeQFKbbsB54xFOL5/y1P5wNBsbXB8yE+At3oh0DVMjQVzCJRJSfReiB2tX8T6HUFZ2k8iaKg==", + "@rollup/rollup-linux-riscv64-gnu@4.45.1": { + "integrity": "sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==", "os": ["linux"], "cpu": ["riscv64"] }, - "@rollup/rollup-linux-s390x-gnu@4.34.9": { - "integrity": "sha512-U+5SwTMoeYXoDzJX5dhDTxRltSrIax8KWwfaaYcynuJw8mT33W7oOgz0a+AaXtGuvhzTr2tVKh5UO8GVANTxyQ==", + "@rollup/rollup-linux-riscv64-musl@4.45.1": { + "integrity": "sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==", + "os": ["linux"], + "cpu": ["riscv64"] + }, + "@rollup/rollup-linux-s390x-gnu@4.45.1": { + "integrity": "sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==", "os": ["linux"], "cpu": ["s390x"] }, - "@rollup/rollup-linux-x64-gnu@4.34.9": { - "integrity": "sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==", + "@rollup/rollup-linux-x64-gnu@4.45.1": { + "integrity": "sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==", "os": ["linux"], "cpu": ["x64"] }, - "@rollup/rollup-linux-x64-musl@4.34.9": { - "integrity": "sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==", + "@rollup/rollup-linux-x64-musl@4.45.1": { + "integrity": "sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==", "os": ["linux"], "cpu": ["x64"] }, - "@rollup/rollup-win32-arm64-msvc@4.34.9": { - "integrity": "sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==", + "@rollup/rollup-win32-arm64-msvc@4.45.1": { + "integrity": "sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==", "os": ["win32"], "cpu": ["arm64"] }, - "@rollup/rollup-win32-ia32-msvc@4.34.9": { - "integrity": "sha512-KB48mPtaoHy1AwDNkAJfHXvHp24H0ryZog28spEs0V48l3H1fr4i37tiyHsgKZJnCmvxsbATdZGBpbmxTE3a9w==", + "@rollup/rollup-win32-ia32-msvc@4.45.1": { + "integrity": "sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==", "os": ["win32"], "cpu": ["ia32"] }, - "@rollup/rollup-win32-x64-msvc@4.34.9": { - "integrity": "sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==", + "@rollup/rollup-win32-x64-msvc@4.45.1": { + "integrity": "sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==", "os": ["win32"], "cpu": ["x64"] }, @@ -800,30 +640,29 @@ "acorn@8.15.0" ] }, - "@sveltejs/adapter-auto@3.3.1_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@5.1.1___svelte@5.0.5____acorn@8.14.0___vite@6.3.5____@types+node@22.13.9____picomatch@4.0.2___@types+node@22.13.9__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__acorn@8.15.0__@types+node@22.13.9_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9": { - "integrity": "sha512-5Sc7WAxYdL6q9j/+D0jJKjGREGlfIevDyHSQ2eNETHcB1TKlQWHcAo8AS8H1QdjNvSXpvOwNjykDUHPEAyGgdQ==", + "@sveltejs/adapter-auto@6.0.1_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@6.1.0___svelte@5.36.8____acorn@8.15.0___vite@7.0.5____@types+node@24.0.15____picomatch@4.0.3___@types+node@24.0.15__svelte@5.36.8___acorn@8.15.0__vite@7.0.5___@types+node@24.0.15___picomatch@4.0.3__acorn@8.15.0__@types+node@24.0.15_@sveltejs+vite-plugin-svelte@6.1.0__svelte@5.36.8___acorn@8.15.0__vite@7.0.5___@types+node@24.0.15___picomatch@4.0.3__@types+node@24.0.15_svelte@5.36.8__acorn@8.15.0_vite@7.0.5__@types+node@24.0.15__picomatch@4.0.3_@types+node@24.0.15": { + "integrity": "sha512-mcWud3pYGPWM2Pphdj8G9Qiq24nZ8L4LB7coCUckUEy5Y7wOWGJ/enaZ4AtJTcSm5dNK1rIkBRoqt+ae4zlxcQ==", "dependencies": [ - "@sveltejs/kit", - "import-meta-resolve" + "@sveltejs/kit" ] }, - "@sveltejs/adapter-node@5.2.13_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@5.1.1___svelte@5.0.5____acorn@8.14.0___vite@6.3.5____@types+node@22.13.9____picomatch@4.0.2___@types+node@22.13.9__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__acorn@8.15.0__@types+node@22.13.9_rollup@4.34.9_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9": { + "@sveltejs/adapter-node@5.2.13_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@6.1.0___svelte@5.36.8____acorn@8.15.0___vite@7.0.5____@types+node@24.0.15____picomatch@4.0.3___@types+node@24.0.15__svelte@5.36.8___acorn@8.15.0__vite@7.0.5___@types+node@24.0.15___picomatch@4.0.3__acorn@8.15.0__@types+node@24.0.15_rollup@4.45.1_@sveltejs+vite-plugin-svelte@6.1.0__svelte@5.36.8___acorn@8.15.0__vite@7.0.5___@types+node@24.0.15___picomatch@4.0.3__@types+node@24.0.15_svelte@5.36.8__acorn@8.15.0_vite@7.0.5__@types+node@24.0.15__picomatch@4.0.3_@types+node@24.0.15": { "integrity": "sha512-yS2TVFmIrxjGhYaV5/iIUrJ3mJl6zjaYn0lBD70vTLnYvJeqf3cjvLXeXCUCuYinhSBoyF4DpfGla49BnIy7sQ==", "dependencies": [ "@rollup/plugin-commonjs", "@rollup/plugin-json", - "@rollup/plugin-node-resolve@16.0.1_rollup@4.34.9", + "@rollup/plugin-node-resolve@16.0.1_rollup@4.45.1", "@sveltejs/kit", "rollup" ] }, - "@sveltejs/adapter-static@3.0.8_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@5.1.1___svelte@5.0.5____acorn@8.14.0___vite@6.3.5____@types+node@22.13.9____picomatch@4.0.2___@types+node@22.13.9__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__acorn@8.15.0__@types+node@22.13.9_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9": { + "@sveltejs/adapter-static@3.0.8_@sveltejs+kit@2.25.1__@sveltejs+vite-plugin-svelte@6.1.0___svelte@5.36.8____acorn@8.15.0___vite@7.0.5____@types+node@24.0.15____picomatch@4.0.3___@types+node@24.0.15__svelte@5.36.8___acorn@8.15.0__vite@7.0.5___@types+node@24.0.15___picomatch@4.0.3__acorn@8.15.0__@types+node@24.0.15_@sveltejs+vite-plugin-svelte@6.1.0__svelte@5.36.8___acorn@8.15.0__vite@7.0.5___@types+node@24.0.15___picomatch@4.0.3__@types+node@24.0.15_svelte@5.36.8__acorn@8.15.0_vite@7.0.5__@types+node@24.0.15__picomatch@4.0.3_@types+node@24.0.15": { "integrity": "sha512-YaDrquRpZwfcXbnlDsSrBQNCChVOT9MGuSg+dMAyfsAa1SmiAhrA5jUYUiIMC59G92kIbY/AaQOWcBdq+lh+zg==", "dependencies": [ "@sveltejs/kit" ] }, - "@sveltejs/kit@2.25.1_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_acorn@8.15.0_@types+node@22.13.9": { + "@sveltejs/kit@2.25.1_@sveltejs+vite-plugin-svelte@6.1.0__svelte@5.36.8___acorn@8.15.0__vite@7.0.5___@types+node@24.0.15___picomatch@4.0.3__@types+node@24.0.15_svelte@5.36.8__acorn@8.15.0_vite@7.0.5__@types+node@24.0.15__picomatch@4.0.3_acorn@8.15.0_@types+node@24.0.15": { "integrity": "sha512-8H+fxDEp7Xq6tLFdrGdS5fLu6ONDQQ9DgyjboXpChubuFdfH9QoFX09ypssBpyNkJNZFt9eW3yLmXIc9CesPCA==", "dependencies": [ "@sveltejs/acorn-typescript", @@ -839,41 +678,69 @@ "sade", "set-cookie-parser", "sirv", - "svelte@5.0.5_acorn@8.14.0", + "svelte", "vite" ], "bin": true }, - "@sveltejs/vite-plugin-svelte-inspector@4.0.1_@sveltejs+vite-plugin-svelte@5.1.1__svelte@5.0.5___acorn@8.14.0__vite@6.3.5___@types+node@22.13.9___picomatch@4.0.2__@types+node@22.13.9_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9": { - "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==", + "@sveltejs/vite-plugin-svelte-inspector@5.0.0_@sveltejs+vite-plugin-svelte@6.1.0__svelte@5.36.8___acorn@8.15.0__vite@7.0.5___@types+node@24.0.15___picomatch@4.0.3__@types+node@24.0.15_svelte@5.36.8__acorn@8.15.0_vite@7.0.5__@types+node@24.0.15__picomatch@4.0.3_@types+node@24.0.15": { + "integrity": "sha512-iwQ8Z4ET6ZFSt/gC+tVfcsSBHwsqc6RumSaiLUkAurW3BCpJam65cmHw0oOlDMTO0u+PZi9hilBRYN+LZNHTUQ==", "dependencies": [ "@sveltejs/vite-plugin-svelte", - "debug@4.4.1", - "svelte@5.0.5_acorn@8.14.0", + "debug", + "svelte", "vite" ] }, - "@sveltejs/vite-plugin-svelte@5.1.1_svelte@5.0.5__acorn@8.14.0_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9": { - "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==", + "@sveltejs/vite-plugin-svelte@6.1.0_svelte@5.36.8__acorn@8.15.0_vite@7.0.5__@types+node@24.0.15__picomatch@4.0.3_@types+node@24.0.15": { + "integrity": "sha512-+U6lz1wvGEG/BvQyL4z/flyNdQ9xDNv5vrh+vWBWTHaebqT0c9RNggpZTo/XSPoHsSCWBlYaTlRX8pZ9GATXCw==", "dependencies": [ "@sveltejs/vite-plugin-svelte-inspector", - "debug@4.4.1", + "debug", "deepmerge", "kleur", "magic-string", - "svelte@5.0.5_acorn@8.14.0", + "svelte", "vite", "vitefu" ] }, - "@tailwindcss/forms@0.5.10_tailwindcss@3.4.17__postcss@8.5.3": { + "@svgdotjs/svg.draggable.js@3.0.6_@svgdotjs+svg.js@3.2.4": { + "integrity": "sha512-7iJFm9lL3C40HQcqzEfezK2l+dW2CpoVY3b77KQGqc8GXWa6LhhmX5Ckv7alQfUXBuZbjpICZ+Dvq1czlGx7gA==", + "dependencies": [ + "@svgdotjs/svg.js" + ] + }, + "@svgdotjs/svg.filter.js@3.0.9": { + "integrity": "sha512-/69XMRCDoam2HgC4ldHIaDgeQf1ViHIsa0Ld4uWgiXtZ+E24DWHe/9Ib6kbNiZ7WRIdlVokUDR1Fg0kjIpkfbw==", + "dependencies": [ + "@svgdotjs/svg.js" + ] + }, + "@svgdotjs/svg.js@3.2.4": { + "integrity": "sha512-BjJ/7vWNowlX3Z8O4ywT58DqbNRyYlkk6Yz/D13aB7hGmfQTvGX4Tkgtm/ApYlu9M7lCQi15xUEidqMUmdMYwg==" + }, + "@svgdotjs/svg.resize.js@2.0.5_@svgdotjs+svg.js@3.2.4_@svgdotjs+svg.select.js@4.0.3__@svgdotjs+svg.js@3.2.4": { + "integrity": "sha512-4heRW4B1QrJeENfi7326lUPYBCevj78FJs8kfeDxn5st0IYPIRXoTtOSYvTzFWgaWWXd3YCDE6ao4fmv91RthA==", + "dependencies": [ + "@svgdotjs/svg.js", + "@svgdotjs/svg.select.js" + ] + }, + "@svgdotjs/svg.select.js@4.0.3_@svgdotjs+svg.js@3.2.4": { + "integrity": "sha512-qkMgso1sd2hXKd1FZ1weO7ANq12sNmQJeGDjs46QwDVsxSRcHmvWKL2NDF7Yimpwf3sl5esOLkPqtV2bQ3v/Jg==", + "dependencies": [ + "@svgdotjs/svg.js" + ] + }, + "@tailwindcss/forms@0.5.10_tailwindcss@3.4.17__postcss@8.5.6": { "integrity": "sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==", "dependencies": [ "mini-svg-data-uri", "tailwindcss" ] }, - "@tailwindcss/typography@0.5.16_tailwindcss@3.4.17__postcss@8.5.3": { + "@tailwindcss/typography@0.5.16_tailwindcss@3.4.17__postcss@8.5.6": { "integrity": "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==", "dependencies": [ "lodash.castarray", @@ -1055,8 +922,8 @@ "@types/deep-eql@4.0.2": { "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==" }, - "@types/estree@1.0.6": { - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" + "@types/estree@1.0.8": { + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==" }, "@types/geojson@7946.0.16": { "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==" @@ -1067,22 +934,25 @@ "@types/json-schema@7.0.15": { "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" }, - "@types/node@22.12.0": { - "integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==", + "@types/mathjax@0.0.40": { + "integrity": "sha512-rHusx08LCg92WJxrsM3SPjvLTSvK5C+gealtSuhKbEOcUZfWlwigaFoPLf6Dfxhg4oryN5qP9Sj7zOQ4HYXINw==" + }, + "@types/node@22.15.15": { + "integrity": "sha512-R5muMcZob3/Jjchn5LcO8jdKwSCbzqmPB6ruBxMcf9kbxtniZHP327s6C37iOfuw8mbKK3cAQa7sEl7afLrQ8A==", "dependencies": [ - "undici-types" + "undici-types@6.21.0" ] }, - "@types/node@22.13.9": { - "integrity": "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==", + "@types/node@24.0.15": { + "integrity": "sha512-oaeTSbCef7U/z7rDeJA138xpG3NuKc64/rZ2qmUFkFJmnMsAPaluIifqyWd8hSSMxyP9oie3dLAqYPblag9KgA==", "dependencies": [ - "undici-types" + "undici-types@7.8.0" ] }, "@types/qrcode@1.5.5": { "integrity": "sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==", "dependencies": [ - "@types/node@22.12.0" + "@types/node@22.15.15" ] }, "@types/resolve@1.20.2": { @@ -1098,7 +968,7 @@ "tinyrainbow" ] }, - "@vitest/mocker@3.2.4_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9": { + "@vitest/mocker@3.2.4_vite@7.0.5__@types+node@24.0.15__picomatch@4.0.3_@types+node@24.0.15": { "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", "dependencies": [ "@vitest/spy", @@ -1152,26 +1022,16 @@ "a-sync-waterfall@1.0.1": { "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==" }, - "acorn-jsx@5.3.2_acorn@8.14.0": { + "acorn-jsx@5.3.2_acorn@8.15.0": { "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dependencies": [ - "acorn@8.14.0" - ] - }, - "acorn-typescript@1.4.13_acorn@8.14.0": { - "integrity": "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==", - "dependencies": [ - "acorn@8.14.0" + "acorn@8.15.0" ] }, "acorn@7.4.1": { "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "bin": true }, - "acorn@8.14.0": { - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "bin": true - }, "acorn@8.15.0": { "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "bin": true @@ -1222,6 +1082,17 @@ "svg.select.js@3.0.1" ] }, + "apexcharts@4.7.0_@svgdotjs+svg.js@3.2.4_@svgdotjs+svg.select.js@4.0.3__@svgdotjs+svg.js@3.2.4": { + "integrity": "sha512-iZSrrBGvVlL+nt2B1NpqfDuBZ9jX61X9I2+XV0hlYXHtTwhwLTHDKGXjNXAgFBDLuvSYCB/rq2nPWVPRv2DrGA==", + "dependencies": [ + "@svgdotjs/svg.draggable.js", + "@svgdotjs/svg.filter.js", + "@svgdotjs/svg.js", + "@svgdotjs/svg.resize.js", + "@svgdotjs/svg.select.js", + "@yr/monotone-cubic-spline" + ] + }, "arg@5.0.2": { "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" }, @@ -1255,8 +1126,8 @@ "async@3.2.6": { "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" }, - "autoprefixer@10.4.20_postcss@8.5.3": { - "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "autoprefixer@10.4.21_postcss@8.5.6": { + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", "dependencies": [ "browserslist", "caniuse-lite", @@ -1286,15 +1157,15 @@ "binary-extensions@2.3.0": { "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==" }, - "brace-expansion@1.1.11": { - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "brace-expansion@1.1.12": { + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dependencies": [ "balanced-match", "concat-map" ] }, - "brace-expansion@2.0.1": { - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "brace-expansion@2.0.2": { + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dependencies": [ "balanced-match" ] @@ -1305,8 +1176,8 @@ "fill-range" ] }, - "browserslist@4.24.4": { - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "browserslist@4.25.1": { + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", "dependencies": [ "caniuse-lite", "electron-to-chromium", @@ -1315,13 +1186,6 @@ ], "bin": true }, - "bufferutil@4.0.9": { - "integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==", - "dependencies": [ - "node-gyp-build" - ], - "scripts": true - }, "cac@6.7.14": { "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==" }, @@ -1348,8 +1212,8 @@ "camelcase@5.3.1": { "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" }, - "caniuse-lite@1.0.30001702": { - "integrity": "sha512-LoPe/D7zioC0REI5W73PeR1e1MLCipRGq/VkovJnd6Df+QVqT+vT33OXCp8QUd7kA7RZrHWxb1B36OQKI/0gOA==" + "caniuse-lite@1.0.30001727": { + "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==" }, "chai@5.2.1": { "integrity": "sha512-5nFxhUrX0PqtyogoYOA8IPswy5sZFTOsBFl/9bNsmDLgsxYTzSZQJDPppDnZPTQbzSEm0hqGjWPzRemQCYbD6A==", @@ -1669,29 +1533,13 @@ "d3-zoom" ] }, - "d@1.0.2": { - "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", - "dependencies": [ - "es5-ext", - "type" - ] - }, - "debug@2.6.9": { - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": [ - "ms@2.0.0" - ] - }, - "debug@4.4.0": { - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dependencies": [ - "ms@2.1.3" - ] + "date-fns@4.1.0": { + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==" }, "debug@4.4.1": { "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dependencies": [ - "ms@2.1.3" + "ms" ] }, "decamelize@1.2.0": { @@ -1748,8 +1596,8 @@ ], "bin": true }, - "electron-to-chromium@1.5.111": { - "integrity": "sha512-vJyJlO95wQRAw6K2ZGF/8nol7AcbCOnp8S6H91mwOOBbXoS9seDBYxCTPYAFsvXLxl3lc0jLXXe9GLxC4nXVog==" + "electron-to-chromium@1.5.187": { + "integrity": "sha512-cl5Jc9I0KGUoOoSbxvTywTa40uspGJt/BDBoDLoxJRSBpWh4FFXBsjNRHfQrONsV/OoEjDfHUmZQa2d6Ze4YgA==" }, "emoji-regex@8.0.0": { "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" @@ -1775,60 +1623,35 @@ "es-errors" ] }, - "es5-ext@0.10.64": { - "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", - "dependencies": [ - "es6-iterator", - "es6-symbol", - "esniff", - "next-tick" - ], - "scripts": true - }, - "es6-iterator@2.0.3": { - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dependencies": [ - "d", - "es5-ext", - "es6-symbol" - ] - }, - "es6-symbol@3.1.4": { - "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", - "dependencies": [ - "d", - "ext" - ] - }, "esbuild@0.25.7": { "integrity": "sha512-daJB0q2dmTzo90L9NjRaohhRWrCzYxWNFTjEi72/h+p5DcY3yn4MacWfDakHmaBaDzDiuLJsCh0+6LK/iX+c+Q==", "optionalDependencies": [ - "@esbuild/aix-ppc64@0.25.7", - "@esbuild/android-arm@0.25.7", - "@esbuild/android-arm64@0.25.7", - "@esbuild/android-x64@0.25.7", - "@esbuild/darwin-arm64@0.25.7", - "@esbuild/darwin-x64@0.25.7", - "@esbuild/freebsd-arm64@0.25.7", - "@esbuild/freebsd-x64@0.25.7", - "@esbuild/linux-arm@0.25.7", - "@esbuild/linux-arm64@0.25.7", - "@esbuild/linux-ia32@0.25.7", - "@esbuild/linux-loong64@0.25.7", - "@esbuild/linux-mips64el@0.25.7", - "@esbuild/linux-ppc64@0.25.7", - "@esbuild/linux-riscv64@0.25.7", - "@esbuild/linux-s390x@0.25.7", - "@esbuild/linux-x64@0.25.7", + "@esbuild/aix-ppc64", + "@esbuild/android-arm", + "@esbuild/android-arm64", + "@esbuild/android-x64", + "@esbuild/darwin-arm64", + "@esbuild/darwin-x64", + "@esbuild/freebsd-arm64", + "@esbuild/freebsd-x64", + "@esbuild/linux-arm", + "@esbuild/linux-arm64", + "@esbuild/linux-ia32", + "@esbuild/linux-loong64", + "@esbuild/linux-mips64el", + "@esbuild/linux-ppc64", + "@esbuild/linux-riscv64", + "@esbuild/linux-s390x", + "@esbuild/linux-x64", "@esbuild/netbsd-arm64", - "@esbuild/netbsd-x64@0.25.7", + "@esbuild/netbsd-x64", "@esbuild/openbsd-arm64", - "@esbuild/openbsd-x64@0.25.7", + "@esbuild/openbsd-x64", "@esbuild/openharmony-arm64", - "@esbuild/sunos-x64@0.25.7", - "@esbuild/win32-arm64@0.25.7", - "@esbuild/win32-ia32@0.25.7", - "@esbuild/win32-x64@0.25.7" + "@esbuild/sunos-x64", + "@esbuild/win32-arm64", + "@esbuild/win32-ia32", + "@esbuild/win32-x64" ], "scripts": true, "bin": true @@ -1839,64 +1662,28 @@ "escape-string-regexp@4.0.0": { "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, - "eslint-compat-utils@0.5.1_eslint@9.21.0": { - "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", - "dependencies": [ - "eslint", - "semver" - ] - }, - "eslint-plugin-svelte@2.46.1_eslint@9.21.0_svelte@5.21.0__acorn@8.14.0_postcss@8.5.3": { - "integrity": "sha512-7xYr2o4NID/f9OEYMqxsEQsCsj4KaMy4q5sANaKkAb6/QeCjYFxRmDm2S3YC3A3pl1kyPZ/syOx/i7LcWYSbIw==", - "dependencies": [ - "@eslint-community/eslint-utils", - "@jridgewell/sourcemap-codec", - "eslint", - "eslint-compat-utils", - "esutils", - "known-css-properties", - "postcss", - "postcss-load-config@3.1.4_postcss@8.5.3", - "postcss-safe-parser", - "postcss-selector-parser@6.1.2", - "semver", - "svelte@5.21.0_acorn@8.14.0", - "svelte-eslint-parser@0.43.0_svelte@5.21.0__acorn@8.14.0_postcss@8.5.3" - ], - "optionalPeers": [ - "svelte@^3.37.0 || ^4.0.0 || ^5.0.0" - ] - }, - "eslint-plugin-svelte@2.46.1_eslint@9.21.0_svelte@5.21.0__acorn@8.14.0_postcss@8.5.3_svelte@5.0.5__acorn@8.14.0": { - "integrity": "sha512-7xYr2o4NID/f9OEYMqxsEQsCsj4KaMy4q5sANaKkAb6/QeCjYFxRmDm2S3YC3A3pl1kyPZ/syOx/i7LcWYSbIw==", + "eslint-plugin-svelte@3.11.0_eslint@9.31.0_svelte@5.36.8__acorn@8.15.0_postcss@8.5.6": { + "integrity": "sha512-KliWlkieHyEa65aQIkRwUFfHzT5Cn4u3BQQsu3KlkJOs7c1u7ryn84EWaOjEzilbKgttT4OfBURA8Uc4JBSQIw==", "dependencies": [ "@eslint-community/eslint-utils", "@jridgewell/sourcemap-codec", "eslint", - "eslint-compat-utils", "esutils", + "globals@16.3.0", "known-css-properties", "postcss", - "postcss-load-config@3.1.4_postcss@8.5.3", + "postcss-load-config@3.1.4_postcss@8.5.6", "postcss-safe-parser", - "postcss-selector-parser@6.1.2", "semver", - "svelte@5.0.5_acorn@8.14.0", - "svelte-eslint-parser@0.43.0_svelte@5.21.0__acorn@8.14.0_postcss@8.5.3_svelte@5.0.5__acorn@8.14.0" + "svelte", + "svelte-eslint-parser" ], "optionalPeers": [ - "svelte@5.0.5_acorn@8.14.0" + "svelte" ] }, - "eslint-scope@7.2.2": { - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dependencies": [ - "esrecurse", - "estraverse" - ] - }, - "eslint-scope@8.2.0": { - "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "eslint-scope@8.4.0": { + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dependencies": [ "esrecurse", "estraverse" @@ -1905,32 +1692,33 @@ "eslint-visitor-keys@3.4.3": { "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==" }, - "eslint-visitor-keys@4.2.0": { - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==" + "eslint-visitor-keys@4.2.1": { + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==" }, - "eslint@9.21.0": { - "integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==", + "eslint@9.31.0": { + "integrity": "sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ==", "dependencies": [ "@eslint-community/eslint-utils", "@eslint-community/regexpp", "@eslint/config-array", + "@eslint/config-helpers", "@eslint/core", "@eslint/eslintrc", "@eslint/js", "@eslint/plugin-kit", "@humanfs/node", "@humanwhocodes/module-importer", - "@humanwhocodes/retry@0.4.2", + "@humanwhocodes/retry@0.4.3", "@types/estree", "@types/json-schema", "ajv", "chalk", "cross-spawn", - "debug@4.4.0", + "debug", "escape-string-regexp", - "eslint-scope@8.2.0", - "eslint-visitor-keys@4.2.0", - "espree@10.3.0_acorn@8.14.0", + "eslint-scope", + "eslint-visitor-keys@4.2.1", + "espree", "esquery", "esutils", "fast-deep-equal", @@ -1951,29 +1739,12 @@ "esm-env@1.2.2": { "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==" }, - "esniff@2.0.1": { - "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", - "dependencies": [ - "d", - "es5-ext", - "event-emitter", - "type" - ] - }, - "espree@10.3.0_acorn@8.14.0": { - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "espree@10.4.0_acorn@8.15.0": { + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dependencies": [ - "acorn@8.14.0", - "acorn-jsx", - "eslint-visitor-keys@4.2.0" - ] - }, - "espree@9.6.1_acorn@8.14.0": { - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dependencies": [ - "acorn@8.14.0", + "acorn@8.15.0", "acorn-jsx", - "eslint-visitor-keys@3.4.3" + "eslint-visitor-keys@4.2.1" ] }, "esquery@1.6.0": { @@ -1982,8 +1753,8 @@ "estraverse" ] }, - "esrap@1.4.5": { - "integrity": "sha512-CjNMjkBWWZeHn+VX+gS8YvFwJ5+NDhg8aWZBSFJPR8qQduDNjbJodA2WcwCm7uQa5Rjqj+nZvVmceg1RbHFB9g==", + "esrap@2.1.0": { + "integrity": "sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==", "dependencies": [ "@jridgewell/sourcemap-codec" ] @@ -2009,22 +1780,9 @@ "esutils@2.0.3": { "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, - "event-emitter@0.3.5": { - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "dependencies": [ - "d", - "es5-ext" - ] - }, "expect-type@1.2.2": { "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==" }, - "ext@1.7.0": { - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "dependencies": [ - "type" - ] - }, "fast-deep-equal@3.1.3": { "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, @@ -2050,13 +1808,13 @@ "reusify" ] }, - "fdir@6.4.6_picomatch@4.0.2": { + "fdir@6.4.6_picomatch@4.0.3": { "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", "dependencies": [ - "picomatch@4.0.2" + "picomatch@4.0.3" ], "optionalPeers": [ - "picomatch@4.0.2" + "picomatch@4.0.3" ] }, "file-entry-cache@8.0.0": { @@ -2108,35 +1866,44 @@ "flowbite@2.5.2" ] }, - "flowbite-svelte-icons@2.1.1_svelte@5.0.5__acorn@8.14.0_tailwind-merge@3.3.0": { + "flowbite-svelte-icons@2.1.1_svelte@5.36.8__acorn@8.15.0_tailwind-merge@3.3.1": { "integrity": "sha512-VNNMcekjbM1bQEGgbdGsdYR9mRdTj/L0A5ba0P1tiFv5QB9GvbvJMABJoiD80eqpZUkfR2QVOmiZfgCwHicT/Q==", "dependencies": [ - "svelte@5.0.5_acorn@8.14.0", - "tailwind-merge@3.3.0" + "svelte", + "tailwind-merge@3.3.1" ] }, - "flowbite-svelte-icons@2.1.1_svelte@5.21.0__acorn@8.14.0_tailwind-merge@3.3.0": { - "integrity": "sha512-VNNMcekjbM1bQEGgbdGsdYR9mRdTj/L0A5ba0P1tiFv5QB9GvbvJMABJoiD80eqpZUkfR2QVOmiZfgCwHicT/Q==", + "flowbite-svelte-icons@2.2.1_svelte@5.36.8__acorn@8.15.0": { + "integrity": "sha512-SH59319zN4TFpmvFMD7+0ETyDxez4Wyw3mgz7hkjhvrx8HawNAS3Fp7au84pZEs1gniX4hvXIg54U+4YybV2rA==", "dependencies": [ - "svelte@5.21.0_acorn@8.14.0", - "tailwind-merge@3.3.0" + "clsx", + "svelte", + "tailwind-merge@3.3.1" ] }, - "flowbite-svelte@0.48.6_svelte@5.0.5__acorn@8.14.0": { + "flowbite-svelte@0.48.6_svelte@5.36.8__acorn@8.15.0": { "integrity": "sha512-/PmeR3ipHHvda8vVY9MZlymaRoJsk8VddEeoLzIygfYwJV68ey8gHuQPC1dq9J6NDCTE5+xOPtBiYUtVjCfvZw==", "dependencies": [ "@floating-ui/dom", - "apexcharts", + "apexcharts@3.54.1", "flowbite@3.1.2", - "svelte@5.0.5_acorn@8.14.0", - "tailwind-merge@3.3.0" + "svelte", + "tailwind-merge@3.3.1" ] }, - "flowbite@2.2.1": { - "integrity": "sha512-iiZyBTtriEDRHrqXZgpKHaxl4B2J8HZUP8Yn1RXozUDKszWHDVj4GxQqMMB9AJHRWOgXV/4E/LJZ/zqQgBUhWA==", + "flowbite-svelte@1.10.10_svelte@5.36.8__acorn@8.15.0_tailwindcss@3.4.17__postcss@8.5.6": { + "integrity": "sha512-9YCB3EqQKlu7in9pxE46eeA+zt98vhUK1nb0eR2o5wpRfsWj60u9v43lMtfhpxSTsh2Jebh+wVLNYyyrYa0UGA==", "dependencies": [ - "@popperjs/core", - "mini-svg-data-uri" + "@floating-ui/dom", + "@floating-ui/utils", + "apexcharts@4.7.0_@svgdotjs+svg.js@3.2.4_@svgdotjs+svg.select.js@4.0.3__@svgdotjs+svg.js@3.2.4", + "clsx", + "date-fns", + "flowbite@3.1.2", + "svelte", + "tailwind-merge@3.3.1", + "tailwind-variants", + "tailwindcss" ] }, "flowbite@2.5.2": { @@ -2245,6 +2012,9 @@ "globals@14.0.0": { "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==" }, + "globals@16.3.0": { + "integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==" + }, "gopd@1.2.0": { "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" }, @@ -2302,9 +2072,6 @@ "resolve-from" ] }, - "import-meta-resolve@4.1.0": { - "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==" - }, "imurmurhash@0.1.4": { "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" }, @@ -2383,9 +2150,6 @@ "hasown" ] }, - "is-typedarray@1.0.0": { - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, "isexe@2.0.0": { "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, @@ -2450,8 +2214,8 @@ "kleur@4.1.5": { "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==" }, - "known-css-properties@0.35.0": { - "integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==" + "known-css-properties@0.37.0": { + "integrity": "sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==" }, "levn@0.4.1": { "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", @@ -2531,19 +2295,19 @@ "minimatch@3.1.2": { "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": [ - "brace-expansion@1.1.11" + "brace-expansion@1.1.12" ] }, "minimatch@5.1.6": { "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dependencies": [ - "brace-expansion@2.0.1" + "brace-expansion@2.0.2" ] }, "minimatch@9.0.5": { "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dependencies": [ - "brace-expansion@2.0.1" + "brace-expansion@2.0.2" ] }, "minimist@1.2.8": { @@ -2558,9 +2322,6 @@ "mrmime@2.0.1": { "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==" }, - "ms@2.0.0": { - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "ms@2.1.3": { "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, @@ -2572,8 +2333,8 @@ "thenify-all" ] }, - "nanoid@3.3.8": { - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "nanoid@3.3.11": { + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "bin": true }, "natural-compare@1.4.0": { @@ -2582,9 +2343,6 @@ "neo-async@2.6.2": { "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, - "next-tick@1.1.0": { - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" - }, "node-emoji@2.2.0": { "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", "dependencies": [ @@ -2594,10 +2352,6 @@ "skin-tone" ] }, - "node-gyp-build@4.8.4": { - "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", - "bin": true - }, "node-releases@2.0.19": { "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==" }, @@ -2607,24 +2361,6 @@ "normalize-range@0.1.2": { "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==" }, - "nostr-tools@2.10.4_typescript@5.8.3": { - "integrity": "sha512-biU7sk+jxHgVASfobg2T5ttxOGGSt69wEVBC51sHHOEaKAAdzHBLV/I2l9Rf61UzClhliZwNouYhqIso4a3HYg==", - "dependencies": [ - "@noble/ciphers", - "@noble/curves@1.2.0", - "@noble/hashes@1.3.1", - "@scure/base@1.1.1", - "@scure/bip32", - "@scure/bip39", - "typescript" - ], - "optionalDependencies": [ - "nostr-wasm" - ], - "optionalPeers": [ - "typescript" - ] - }, "nostr-tools@2.15.1_typescript@5.8.3": { "integrity": "sha512-LpetHDR9ltnkpJDkva/SONgyKBbsoV+5yLB8DWc0/U3lCWGtoWJw6Nbc2vR2Ai67RIQYrBQeZLyMlhwVZRK/9A==", "dependencies": [ @@ -2740,24 +2476,24 @@ "picomatch@2.3.1": { "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, - "picomatch@4.0.2": { - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==" + "picomatch@4.0.3": { + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==" }, "pify@2.3.0": { "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" }, - "pirates@4.0.6": { - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==" + "pirates@4.0.7": { + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==" }, "plantuml-encoder@1.4.0": { "integrity": "sha512-sxMwpDw/ySY1WB2CE3+IdMuEcWibJ72DDOsXLkSmEaSzwEUaYBT6DWgOfBiHGCux4q433X6+OEFWjlVqp7gL6g==" }, - "playwright-core@1.50.1": { - "integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==", + "playwright-core@1.54.1": { + "integrity": "sha512-Nbjs2zjj0htNhzgiy5wu+3w09YetDx5pkrpI/kZotDlDUaYk0HVA5xrBVPdow4SAUIlhgKcJeJg4GRKW6xHusA==", "bin": true }, - "playwright@1.50.1": { - "integrity": "sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==", + "playwright@1.54.1": { + "integrity": "sha512-peWpSwIBmSLi6aW2auvrUtf2DqY16YYcCMO8rTVx486jKmDTJg7UAhyrraP98GB8BoPURZP8+nxO7TSd4cPr5g==", "dependencies": [ "playwright-core" ], @@ -2769,7 +2505,7 @@ "pngjs@5.0.0": { "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==" }, - "postcss-import@15.1.0_postcss@8.5.3": { + "postcss-import@15.1.0_postcss@8.5.6": { "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", "dependencies": [ "postcss", @@ -2778,14 +2514,14 @@ "resolve" ] }, - "postcss-js@4.0.1_postcss@8.5.3": { + "postcss-js@4.0.1_postcss@8.5.6": { "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", "dependencies": [ "camelcase-css", "postcss" ] }, - "postcss-load-config@3.1.4_postcss@8.5.3": { + "postcss-load-config@3.1.4_postcss@8.5.6": { "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", "dependencies": [ "lilconfig@2.1.0", @@ -2796,18 +2532,18 @@ "postcss" ] }, - "postcss-load-config@4.0.2_postcss@8.5.3": { + "postcss-load-config@4.0.2_postcss@8.5.6": { "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", "dependencies": [ "lilconfig@3.1.3", "postcss", - "yaml@2.7.0" + "yaml@2.8.0" ], "optionalPeers": [ "postcss" ] }, - "postcss-load-config@6.0.1_postcss@8.5.3": { + "postcss-load-config@6.0.1_postcss@8.5.6": { "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", "dependencies": [ "lilconfig@3.1.3", @@ -2817,20 +2553,20 @@ "postcss" ] }, - "postcss-nested@6.2.0_postcss@8.5.3": { + "postcss-nested@6.2.0_postcss@8.5.6": { "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", "dependencies": [ "postcss", "postcss-selector-parser@6.1.2" ] }, - "postcss-safe-parser@6.0.0_postcss@8.5.3": { - "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", + "postcss-safe-parser@7.0.1_postcss@8.5.6": { + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", "dependencies": [ "postcss" ] }, - "postcss-scss@4.0.9_postcss@8.5.3": { + "postcss-scss@4.0.9_postcss@8.5.6": { "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", "dependencies": [ "postcss" @@ -2850,11 +2586,18 @@ "util-deprecate" ] }, + "postcss-selector-parser@7.1.0": { + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dependencies": [ + "cssesc", + "util-deprecate" + ] + }, "postcss-value-parser@4.2.0": { "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, - "postcss@8.5.3": { - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "postcss@8.5.6": { + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dependencies": [ "nanoid", "picocolors", @@ -2864,15 +2607,15 @@ "prelude-ls@1.2.1": { "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" }, - "prettier-plugin-svelte@3.3.3_prettier@3.5.3_svelte@5.21.0__acorn@8.14.0": { - "integrity": "sha512-yViK9zqQ+H2qZD1w/bH7W8i+bVfKrD8GIFjkFe4Thl6kCT9SlAsXVNmt3jCvQOCsnOhcvYgsoVlRV/Eu6x5nNw==", + "prettier-plugin-svelte@3.4.0_prettier@3.6.2_svelte@5.36.8__acorn@8.15.0": { + "integrity": "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==", "dependencies": [ "prettier", - "svelte@5.21.0_acorn@8.14.0" + "svelte" ] }, - "prettier@3.5.3": { - "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "prettier@3.6.2": { + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "bin": true }, "promise@7.3.1": { @@ -3023,8 +2766,8 @@ "robust-predicates@3.0.2": { "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" }, - "rollup@4.34.9": { - "integrity": "sha512-nF5XYqWWp9hx/LrpC8sZvvvmq0TeTjQgaZHYmAgwysT9nh8sWnZhBnM8ZyVbbJFIQBLwHDNoMqsBZBbUo4U8sQ==", + "rollup@4.45.1": { + "integrity": "sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==", "dependencies": [ "@types/estree" ], @@ -3042,6 +2785,7 @@ "@rollup/rollup-linux-loongarch64-gnu", "@rollup/rollup-linux-powerpc64le-gnu", "@rollup/rollup-linux-riscv64-gnu", + "@rollup/rollup-linux-riscv64-musl", "@rollup/rollup-linux-s390x-gnu", "@rollup/rollup-linux-x64-gnu", "@rollup/rollup-linux-x64-musl", @@ -3070,8 +2814,8 @@ "safer-buffer@2.1.2": { "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "semver@7.7.1": { - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "semver@7.7.2": { + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "bin": true }, "set-blocking@2.0.0": { @@ -3180,7 +2924,7 @@ "supports-preserve-symlinks-flag@1.0.0": { "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, - "svelte-check@4.3.0_svelte@5.0.5__acorn@8.14.0_typescript@5.8.3": { + "svelte-check@4.3.0_svelte@5.36.8__acorn@8.15.0_typescript@5.8.3": { "integrity": "sha512-Iz8dFXzBNAM7XlEIsUjUGQhbEE+Pvv9odb9+0+ITTgFWZBGeJRRYqHUUglwe2EkLD5LIsQaAc4IUJyvtKuOO5w==", "dependencies": [ "@jridgewell/trace-mapping", @@ -3188,65 +2932,34 @@ "fdir", "picocolors", "sade", - "svelte@5.0.5_acorn@8.14.0", + "svelte", "typescript" ], "bin": true }, - "svelte-eslint-parser@0.43.0_svelte@5.21.0__acorn@8.14.0_postcss@8.5.3": { - "integrity": "sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA==", + "svelte-eslint-parser@1.3.0_svelte@5.36.8__acorn@8.15.0_postcss@8.5.6": { + "integrity": "sha512-VCgMHKV7UtOGcGLGNFSbmdm6kEKjtzo5nnpGU/mnx4OsFY6bZ7QwRF5DUx+Hokw5Lvdyo8dpk8B1m8mliomrNg==", "dependencies": [ - "eslint-scope@7.2.2", - "eslint-visitor-keys@3.4.3", - "espree@9.6.1_acorn@8.14.0", + "eslint-scope", + "eslint-visitor-keys@4.2.1", + "espree", "postcss", "postcss-scss", - "svelte@5.21.0_acorn@8.14.0" + "postcss-selector-parser@7.1.0", + "svelte" ], "optionalPeers": [ - "svelte@^3.37.0 || ^4.0.0 || ^5.0.0" - ] - }, - "svelte-eslint-parser@0.43.0_svelte@5.21.0__acorn@8.14.0_postcss@8.5.3_svelte@5.0.5__acorn@8.14.0": { - "integrity": "sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA==", - "dependencies": [ - "eslint-scope@7.2.2", - "eslint-visitor-keys@3.4.3", - "espree@9.6.1_acorn@8.14.0", - "postcss", - "postcss-scss", - "svelte@5.0.5_acorn@8.14.0" - ], - "optionalPeers": [ - "svelte@5.0.5_acorn@8.14.0" - ] - }, - "svelte@5.0.5_acorn@8.14.0": { - "integrity": "sha512-f4WBlP5g8W6pEoDfx741lewMlemy+LIGpEqjGPWqnHVP92wqlQXl87U5O5Bi2tkSUrO95OxOoqwU8qlqiHmFKA==", - "dependencies": [ - "@ampproject/remapping", - "@jridgewell/sourcemap-codec", - "@types/estree", - "acorn@8.14.0", - "acorn-typescript", - "aria-query", - "axobject-query", - "esm-env", - "esrap", - "is-reference@3.0.3", - "locate-character", - "magic-string", - "zimmerframe" + "svelte" ] }, - "svelte@5.21.0_acorn@8.14.0": { - "integrity": "sha512-+pUFl4d0cu2KoxTtwjzByneCXbUzsNlGc4zMDDT/r2usp3VowYEGu1mFvbjcxmWTkwoy3tyhOg7fsz5aJo0wHw==", + "svelte@5.36.8_acorn@8.15.0": { + "integrity": "sha512-8JbZWQu96hMjH/oYQPxXW6taeC6Awl6muGHeZzJTxQx7NGRQ/J9wN1hkzRKLOlSDlbS2igiFg7p5xyTp5uXG3A==", "dependencies": [ "@ampproject/remapping", "@jridgewell/sourcemap-codec", + "@sveltejs/acorn-typescript", "@types/estree", - "acorn@8.14.0", - "acorn-typescript", + "acorn@8.15.0", "aria-query", "axobject-query", "clsx", @@ -3304,13 +3017,20 @@ "svg.js" ] }, - "tailwind-merge@2.5.5": { - "integrity": "sha512-0LXunzzAZzo0tEPxV3I297ffKZPlKDrjj7NXphC8V5ak9yHC5zRmxnOe2m/Rd/7ivsOMJe3JZ2JVocoDdQTRBA==" + "tailwind-merge@3.0.2": { + "integrity": "sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw==" }, - "tailwind-merge@3.3.0": { - "integrity": "sha512-fyW/pEfcQSiigd5SNn0nApUOxx0zB/dm6UDU/rEwc2c3sX2smWUNbapHv+QRqLGVp9GWX3THIa7MUGPo+YkDzQ==" + "tailwind-merge@3.3.1": { + "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==" + }, + "tailwind-variants@1.0.0_tailwindcss@3.4.17__postcss@8.5.6": { + "integrity": "sha512-2WSbv4ulEEyuBKomOunut65D8UZwxrHoRfYnxGcQNnHqlSCp2+B7Yz2W+yrNDrxRodOXtGD/1oCcKGNBnUqMqA==", + "dependencies": [ + "tailwind-merge@3.0.2", + "tailwindcss" + ] }, - "tailwindcss@3.4.17_postcss@8.5.3": { + "tailwindcss@3.4.17_postcss@8.5.6": { "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "dependencies": [ "@alloc/quick-lru", @@ -3330,7 +3050,7 @@ "postcss", "postcss-import", "postcss-js", - "postcss-load-config@4.0.2_postcss@8.5.3", + "postcss-load-config@4.0.2_postcss@8.5.6", "postcss-nested", "postcss-selector-parser@6.1.2", "resolve", @@ -3356,11 +3076,11 @@ "tinyexec@0.3.2": { "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==" }, - "tinyglobby@0.2.14_picomatch@4.0.2": { + "tinyglobby@0.2.14_picomatch@4.0.3": { "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "dependencies": [ "fdir", - "picomatch@4.0.2" + "picomatch@4.0.3" ] }, "tinypool@1.1.1": { @@ -3393,24 +3113,12 @@ "tslib@2.8.1": { "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, - "tstl@2.5.16": { - "integrity": "sha512-+O2ybLVLKcBwKm4HymCEwZIT0PpwS3gCYnxfSDEjJEKADvIFruaQjd3m7CAKNU1c7N3X3WjVz87re7TA2A5FUw==" - }, "type-check@0.4.0": { "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dependencies": [ "prelude-ls" ] }, - "type@2.7.3": { - "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==" - }, - "typedarray-to-buffer@3.1.5": { - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dependencies": [ - "is-typedarray" - ] - }, "typescript-lru-cache@2.0.0": { "integrity": "sha512-Jp57Qyy8wXeMkdNuZiglE6v2Cypg13eDA1chHwDG6kq51X7gk4K7P7HaDdzZKCxkegXkVHNcPD0n5aW6OZH3aA==" }, @@ -3422,8 +3130,11 @@ "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "bin": true }, - "undici-types@6.20.0": { - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" + "undici-types@6.21.0": { + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" + }, + "undici-types@7.8.0": { + "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==" }, "unicode-emoji-modifier-base@1.0.0": { "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==" @@ -3431,7 +3142,7 @@ "unxhr@1.2.0": { "integrity": "sha512-6cGpm8NFXPD9QbSNx0cD2giy7teZ6xOkCUH3U89WKVkL9N9rBrWjlCwhR94Re18ZlAop4MOc3WU1M3Hv/bgpIw==" }, - "update-browserslist-db@1.1.3_browserslist@4.24.4": { + "update-browserslist-db@1.1.3_browserslist@4.25.1": { "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dependencies": [ "browserslist", @@ -3446,37 +3157,27 @@ "punycode" ] }, - "utf-8-validate@5.0.10": { - "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", - "dependencies": [ - "node-gyp-build" - ], - "scripts": true - }, - "utf8-buffer@1.0.0": { - "integrity": "sha512-ueuhzvWnp5JU5CiGSY4WdKbiN/PO2AZ/lpeLiz2l38qwdLy/cW40XobgyuIWucNyum0B33bVB0owjFCeGBSLqg==" - }, "util-deprecate@1.0.2": { "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, - "vite-node@3.2.4_@types+node@22.13.9": { + "vite-node@3.2.4_@types+node@24.0.15": { "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", "dependencies": [ "cac", - "debug@4.4.1", + "debug", "es-module-lexer", "pathe", "vite" ], "bin": true }, - "vite@6.3.5_@types+node@22.13.9_picomatch@4.0.2": { - "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", + "vite@7.0.5_@types+node@24.0.15_picomatch@4.0.3": { + "integrity": "sha512-1mncVwJxy2C9ThLwz0+2GKZyEXuC3MyWtAAlNftlZZXZDP3AJt5FmwcMit/IGGaNZ8ZOB2BNO/HFUB+CpN0NQw==", "dependencies": [ - "@types/node@22.13.9", + "@types/node@24.0.15", "esbuild", "fdir", - "picomatch@4.0.2", + "picomatch@4.0.3", "postcss", "rollup", "tinyglobby" @@ -3485,11 +3186,11 @@ "fsevents@2.3.3" ], "optionalPeers": [ - "@types/node@22.13.9" + "@types/node@24.0.15" ], "bin": true }, - "vitefu@1.1.1_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2_@types+node@22.13.9": { + "vitefu@1.1.1_vite@7.0.5__@types+node@24.0.15__picomatch@4.0.3_@types+node@24.0.15": { "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==", "dependencies": [ "vite" @@ -3498,11 +3199,11 @@ "vite" ] }, - "vitest@3.2.4_@types+node@22.13.9_vite@6.3.5__@types+node@22.13.9__picomatch@4.0.2": { + "vitest@3.2.4_@types+node@24.0.15_vite@7.0.5__@types+node@24.0.15__picomatch@4.0.3": { "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dependencies": [ "@types/chai", - "@types/node@22.13.9", + "@types/node@24.0.15", "@vitest/expect", "@vitest/mocker", "@vitest/pretty-format", @@ -3511,11 +3212,11 @@ "@vitest/spy", "@vitest/utils", "chai", - "debug@4.4.1", + "debug", "expect-type", "magic-string", "pathe", - "picomatch@4.0.2", + "picomatch@4.0.3", "std-env", "tinybench", "tinyexec", @@ -3527,31 +3228,13 @@ "why-is-node-running" ], "optionalPeers": [ - "@types/node@22.13.9" + "@types/node@24.0.15" ], "bin": true }, "void-elements@3.1.0": { "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==" }, - "websocket-polyfill@0.0.3": { - "integrity": "sha512-pF3kR8Uaoau78MpUmFfzbIRxXj9PeQrCuPepGE6JIsfsJ/o/iXr07Q2iQNzKSSblQJ0FiGWlS64N4pVSm+O3Dg==", - "dependencies": [ - "tstl", - "websocket" - ] - }, - "websocket@1.0.35": { - "integrity": "sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q==", - "dependencies": [ - "bufferutil", - "debug@2.6.9", - "es5-ext", - "typedarray-to-buffer", - "utf-8-validate", - "yaeti" - ] - }, "which-module@2.0.1": { "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" }, @@ -3618,15 +3301,11 @@ "y18n@5.0.8": { "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, - "yaeti@0.0.6": { - "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", - "deprecated": true - }, "yaml@1.10.2": { "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" }, - "yaml@2.7.0": { - "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "yaml@2.8.0": { + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", "bin": true }, "yargs-parser@18.1.3": { @@ -3683,43 +3362,46 @@ }, "workspace": { "dependencies": [ - "npm:@nostr-dev-kit/ndk-cache-dexie@2.5", - "npm:@nostr-dev-kit/ndk@2.11", + "npm:@nostr-dev-kit/ndk-cache-dexie@^2.6.33", + "npm:@nostr-dev-kit/ndk@^2.14.32", "npm:@popperjs/core@2.11", "npm:@tailwindcss/forms@0.5", "npm:@tailwindcss/typography@0.5", "npm:asciidoctor@3.0", "npm:d3@7.9", - "npm:flowbite-svelte-icons@2.1", - "npm:flowbite-svelte@0.48", - "npm:flowbite@2.2", + "npm:flowbite-svelte-icons@^2.2.1", + "npm:flowbite-svelte@^1.10.10", + "npm:flowbite@^3.1.2", "npm:he@1.2", - "npm:nostr-tools@2.10", - "npm:svelte@5.0", - "npm:tailwind-merge@2.5" + "npm:nostr-tools@^2.15.1", + "npm:svelte@^5.36.8", + "npm:tailwind-merge@^3.3.1" ], "packageJson": { "dependencies": [ + "npm:@noble/curves@^1.9.4", + "npm:@noble/hashes@^1.8.0", "npm:@nostr-dev-kit/ndk-cache-dexie@2.6", "npm:@nostr-dev-kit/ndk@^2.14.32", - "npm:@playwright/test@^1.50.1", + "npm:@playwright/test@^1.54.1", "npm:@popperjs/core@2.11", - "npm:@sveltejs/adapter-auto@3", + "npm:@sveltejs/adapter-auto@^6.0.1", "npm:@sveltejs/adapter-node@^5.2.13", "npm:@sveltejs/adapter-static@3", "npm:@sveltejs/kit@^2.25.0", - "npm:@sveltejs/vite-plugin-svelte@5", + "npm:@sveltejs/vite-plugin-svelte@^6.1.0", "npm:@tailwindcss/forms@0.5", "npm:@tailwindcss/typography@0.5", "npm:@types/d3@^7.4.3", "npm:@types/he@1.2", - "npm:@types/node@22", + "npm:@types/mathjax@^0.0.40", + "npm:@types/node@^24.0.15", "npm:@types/qrcode@^1.5.5", "npm:asciidoctor@3.0", - "npm:autoprefixer@10", + "npm:autoprefixer@^10.4.21", "npm:bech32@2", "npm:d3@^7.9.0", - "npm:eslint-plugin-svelte@2", + "npm:eslint-plugin-svelte@^3.11.0", "npm:flowbite-svelte-icons@2.1", "npm:flowbite-svelte@0.48", "npm:flowbite@2", @@ -3730,17 +3412,17 @@ "npm:plantuml-encoder@^1.4.0", "npm:playwright@^1.50.1", "npm:postcss-load-config@6", - "npm:postcss@8", - "npm:prettier-plugin-svelte@3", - "npm:prettier@3", + "npm:postcss@^8.5.6", + "npm:prettier-plugin-svelte@^3.4.0", + "npm:prettier@^3.6.2", "npm:qrcode@^1.5.4", "npm:svelte-check@4", - "npm:svelte@5", - "npm:tailwind-merge@^3.3.0", - "npm:tailwindcss@3", + "npm:svelte@^5.36.8", + "npm:tailwind-merge@^3.3.1", + "npm:tailwindcss@^3.4.17", "npm:tslib@2.8", - "npm:typescript@5.8", - "npm:vite@6", + "npm:typescript@^5.8.3", + "npm:vite@^7.0.5", "npm:vitest@^3.1.3" ] } diff --git a/import_map.json b/import_map.json index 0d971b8..b5aa95c 100644 --- a/import_map.json +++ b/import_map.json @@ -1,19 +1,19 @@ { "imports": { "he": "npm:he@1.2.x", - "@nostr-dev-kit/ndk": "npm:@nostr-dev-kit/ndk@2.11.x", - "@nostr-dev-kit/ndk-cache-dexie": "npm:@nostr-dev-kit/ndk-cache-dexie@2.5.x", + "@nostr-dev-kit/ndk": "npm:@nostr-dev-kit/ndk@^2.14.32", + "@nostr-dev-kit/ndk-cache-dexie": "npm:@nostr-dev-kit/ndk-cache-dexie@^2.6.33", "@popperjs/core": "npm:@popperjs/core@2.11.x", "@tailwindcss/forms": "npm:@tailwindcss/forms@0.5.x", "@tailwindcss/typography": "npm:@tailwindcss/typography@0.5.x", "asciidoctor": "npm:asciidoctor@3.0.x", "d3": "npm:d3@7.9.x", - "nostr-tools": "npm:nostr-tools@2.10.x", - "tailwind-merge": "npm:tailwind-merge@2.5.x", - "svelte": "npm:svelte@5.0.x", - "flowbite": "npm:flowbite@2.2.x", - "flowbite-svelte": "npm:flowbite-svelte@0.48.x", - "flowbite-svelte-icons": "npm:flowbite-svelte-icons@2.1.x", + "nostr-tools": "npm:nostr-tools@^2.15.1", + "tailwind-merge": "npm:tailwind-merge@^3.3.1", + "svelte": "npm:svelte@^5.36.8", + "flowbite": "npm:flowbite@^3.1.2", + "flowbite-svelte": "npm:flowbite-svelte@^1.10.10", + "flowbite-svelte-icons": "npm:flowbite-svelte-icons@^2.2.1", "child_process": "node:child_process" } } diff --git a/package.json b/package.json index e5c9a9c..647d2c6 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,8 @@ "test": "vitest" }, "dependencies": { + "@noble/hashes": "^1.8.0", + "@noble/curves": "^1.9.4", "@nostr-dev-kit/ndk": "^2.14.32", "@nostr-dev-kit/ndk-cache-dexie": "2.6.x", "@popperjs/core": "2.11.x", @@ -30,33 +32,34 @@ "qrcode": "^1.5.4" }, "devDependencies": { - "@playwright/test": "^1.50.1", - "@sveltejs/adapter-auto": "3.x", + "@playwright/test": "^1.54.1", + "@sveltejs/adapter-auto": "^6.0.1", "@sveltejs/adapter-node": "^5.2.13", "@sveltejs/adapter-static": "3.x", "@sveltejs/kit": "^2.25.0", - "@sveltejs/vite-plugin-svelte": "5.x", + "@sveltejs/vite-plugin-svelte": "^6.1.0", "@types/d3": "^7.4.3", "@types/he": "1.2.x", - "@types/node": "22.x", + "@types/mathjax": "^0.0.40", + "@types/node": "^24.0.15", "@types/qrcode": "^1.5.5", - "autoprefixer": "10.x", - "eslint-plugin-svelte": "2.x", + "autoprefixer": "^10.4.21", + "eslint-plugin-svelte": "^3.11.0", "flowbite": "2.x", "flowbite-svelte": "0.48.x", "flowbite-svelte-icons": "2.1.x", "playwright": "^1.50.1", - "postcss": "8.x", + "postcss": "^8.5.6", "postcss-load-config": "6.x", - "prettier": "3.x", - "prettier-plugin-svelte": "3.x", - "svelte": "5.x", + "prettier": "^3.6.2", + "prettier-plugin-svelte": "^3.4.0", + "svelte": "^5.36.8", "svelte-check": "4.x", - "tailwind-merge": "^3.3.0", - "tailwindcss": "3.x", + "tailwind-merge": "^3.3.1", + "tailwindcss": "^3.4.17", "tslib": "2.8.x", - "typescript": "5.8.x", - "vite": "6.x", + "typescript": "^5.8.3", + "vite": "^7.0.5", "vitest": "^3.1.3" } } From 3b7ffb913f7ce1b8c127ab0637afa5b61f27098f Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 19 Jul 2025 01:11:27 -0500 Subject: [PATCH 134/135] Fix warnings and errors thrown be Deno's linter --- playwright.config.ts | 1 + src/app.d.ts | 17 +++- .../publications/PublicationFeed.svelte | 6 -- src/lib/components/util/CardActions.svelte | 2 +- .../EventNetwork/utils/forceSimulation.ts | 3 +- .../EventNetwork/utils/networkBuilder.ts | 8 +- src/lib/ndk.ts | 93 ++++--------------- src/lib/parser.ts | 16 ++-- src/lib/services/publisher.ts | 10 +- src/lib/state.ts | 2 +- src/lib/stores.ts | 4 +- src/lib/stores/networkStore.ts | 4 +- src/lib/stores/userStore.ts | 27 ++---- src/lib/types.ts | 2 +- src/lib/utils.ts | 8 +- src/lib/utils/ZettelParser.ts | 8 +- src/lib/utils/event_input_utils.ts | 13 +-- src/lib/utils/event_search.ts | 18 ++-- src/lib/utils/indexEventCache.ts | 5 +- .../advancedAsciidoctorPostProcessor.ts | 14 +-- src/lib/utils/markup/advancedMarkupParser.ts | 24 ++--- src/lib/utils/markup/asciidoctorExtensions.ts | 25 ++--- src/lib/utils/markup/basicMarkupParser.ts | 8 +- src/lib/utils/network_detection.ts | 11 +-- src/lib/utils/nostrEventService.ts | 21 +++-- src/lib/utils/nostrUtils.ts | 26 +++--- src/lib/utils/profile_search.ts | 30 +++--- src/lib/utils/relayDiagnostics.ts | 7 +- src/lib/utils/relay_management.ts | 34 +++---- src/lib/utils/searchCache.ts | 5 +- src/lib/utils/search_types.ts | 6 +- src/lib/utils/search_utils.ts | 7 +- src/lib/utils/subscription_search.ts | 46 ++++----- src/routes/+layout.ts | 15 +-- src/routes/+page.svelte | 6 +- src/routes/publication/+page.ts | 15 +-- vite.config.ts | 3 +- 37 files changed, 231 insertions(+), 319 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index cee1e49..4ef00bd 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,4 +1,5 @@ import { defineConfig, devices } from "@playwright/test"; +import process from "node:process"; /** * Read environment variables from file. diff --git a/src/app.d.ts b/src/app.d.ts index 1b260cf..25c13d3 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -1,7 +1,7 @@ // See https://kit.svelte.dev/docs/types#app -import NDK, { NDKEvent } from "@nostr-dev-kit/ndk"; -import Pharos from "./lib/parser.ts"; +import { NDKEvent, NDKNip07Signer } from "@nostr-dev-kit/ndk"; +import { HLJSApi } from "highlight.js"; // for information about these interfaces declare global { @@ -9,13 +9,24 @@ declare global { // interface Error {} // interface Locals {} interface PageData { - waitable?: Promise; + waitable?: Promise; publicationType?: string; indexEvent?: NDKEvent; url?: URL; } // interface Platform {} } + + var hljs: HLJSApi; + + // deno-lint-ignore no-explicit-any + var MathJax: any; + + var nostr: NDKNip07Signer & { + getRelays: () => Promise>>; + // deno-lint-ignore no-explicit-any + signEvent: (event: any) => Promise; + }; } export {}; diff --git a/src/lib/components/publications/PublicationFeed.svelte b/src/lib/components/publications/PublicationFeed.svelte index 2236dce..674eb5a 100644 --- a/src/lib/components/publications/PublicationFeed.svelte +++ b/src/lib/components/publications/PublicationFeed.svelte @@ -35,10 +35,6 @@ // Event management let allIndexEvents: NDKEvent[] = $state([]); - let cutoffTimestamp: number = $derived( - eventsInView?.at(eventsInView.length - 1)?.created_at ?? - new Date().getTime(), - ); // Initialize relays and fetch events async function initializeAndFetch() { @@ -371,8 +367,6 @@
    - -
    diff --git a/src/lib/components/util/CardActions.svelte b/src/lib/components/util/CardActions.svelte index d5d49c5..dddbb8a 100644 --- a/src/lib/components/util/CardActions.svelte +++ b/src/lib/components/util/CardActions.svelte @@ -9,7 +9,7 @@ import { userBadge } from "$lib/snippets/UserSnippets.svelte"; import { neventEncode, naddrEncode } from "$lib/utils"; import { activeInboxRelays } from "$lib/ndk"; -import { userStore } from "$lib/stores/userStore"; + import { userStore } from "$lib/stores/userStore"; import { goto } from "$app/navigation"; import type { NDKEvent } from "$lib/utils/nostrUtils"; diff --git a/src/lib/navigator/EventNetwork/utils/forceSimulation.ts b/src/lib/navigator/EventNetwork/utils/forceSimulation.ts index dbcb1e0..6eb0dd3 100644 --- a/src/lib/navigator/EventNetwork/utils/forceSimulation.ts +++ b/src/lib/navigator/EventNetwork/utils/forceSimulation.ts @@ -1,3 +1,4 @@ +// deno-lint-ignore-file no-explicit-any /** * D3 Force Simulation Utilities * @@ -5,7 +6,7 @@ * graph simulations for the event network visualization. */ -import type { NetworkNode, NetworkLink } from "../types"; +import type { NetworkNode, NetworkLink } from "../types.ts"; import * as d3 from "d3"; // Configuration diff --git a/src/lib/navigator/EventNetwork/utils/networkBuilder.ts b/src/lib/navigator/EventNetwork/utils/networkBuilder.ts index d62f189..aa234b2 100644 --- a/src/lib/navigator/EventNetwork/utils/networkBuilder.ts +++ b/src/lib/navigator/EventNetwork/utils/networkBuilder.ts @@ -6,10 +6,10 @@ */ import type { NDKEvent } from "@nostr-dev-kit/ndk"; -import type { NetworkNode, NetworkLink, GraphData, GraphState } from "../types"; +import type { NetworkNode, GraphData, GraphState } from "../types.ts"; import { nip19 } from "nostr-tools"; -import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; -import { getMatchingTags } from "$lib/utils/nostrUtils"; +import { activeInboxRelays, activeOutboxRelays } from "../../../ndk.ts"; +import { getMatchingTags } from "../../../utils/nostrUtils.ts"; import { get } from "svelte/store"; // Configuration @@ -20,7 +20,7 @@ const CONTENT_EVENT_KIND = 30041; /** * Debug logging function that only logs when DEBUG is true */ -function debug(...args: any[]) { +function debug(...args: unknown[]) { if (DEBUG) { console.log("[NetworkBuilder]", ...args); } diff --git a/src/lib/ndk.ts b/src/lib/ndk.ts index 7b9745e..af039c4 100644 --- a/src/lib/ndk.ts +++ b/src/lib/ndk.ts @@ -8,29 +8,19 @@ import NDK, { } from "@nostr-dev-kit/ndk"; import { get, writable, type Writable } from "svelte/store"; import { - secondaryRelays, - FeedType, loginStorageKey, - communityRelays, - anonymousRelays, - searchRelays, -} from "./consts"; +} from "./consts.ts"; import { buildCompleteRelaySet, testRelayConnection, - discoverLocalRelays, - getUserLocalRelays, - getUserBlockedRelays, - getUserOutboxRelays, deduplicateRelayUrls, -} from "./utils/relay_management"; +} from "./utils/relay_management.ts"; // Re-export testRelayConnection for components that need it export { testRelayConnection }; -import { startNetworkMonitoring, NetworkCondition } from "./utils/network_detection"; -import { userStore } from "./stores/userStore"; -import { userPubkey } from "$lib/stores/authStore.Svelte"; -import { startNetworkStatusMonitoring, stopNetworkStatusMonitoring } from "./stores/networkStore"; +import { userStore } from "./stores/userStore.ts"; +import { userPubkey } from "./stores/authStore.Svelte.ts"; +import { startNetworkStatusMonitoring, stopNetworkStatusMonitoring } from "./stores/networkStore.ts"; export const ndkInstance: Writable = writable(); export const ndkSignedIn = writable(false); @@ -59,7 +49,7 @@ class CustomRelayAuthPolicy { * @param relay The relay to authenticate with * @returns Promise that resolves when authentication is complete */ - async authenticate(relay: NDKRelay): Promise { + authenticate(relay: NDKRelay): void { if (!this.ndk.signer || !this.ndk.activeUser) { console.warn( "[NDK.ts] No signer or active user available for relay authentication", @@ -84,7 +74,7 @@ class CustomRelayAuthPolicy { relay.on("notice", (message: string) => { if (message.includes("auth-required")) { console.debug(`[NDK.ts] Auth required from ${relay.url}:`, message); - this.handleAuthRequired(relay, message); + this.handleAuthRequired(relay); } }); @@ -94,7 +84,7 @@ class CustomRelayAuthPolicy { }); // Listen for authentication failures - relay.on("auth:failed", (error: any) => { + relay.on("auth:failed", (error) => { console.error( `[NDK.ts] Authentication failed for ${relay.url}:`, error, @@ -151,10 +141,7 @@ class CustomRelayAuthPolicy { /** * Handles auth-required error from relay */ - private async handleAuthRequired( - relay: NDKRelay, - message: string, - ): Promise { + private async handleAuthRequired(relay: NDKRelay): Promise { const challenge = this.challenges.get(relay.url); if (challenge) { await this.handleAuthChallenge(relay, challenge); @@ -173,13 +160,13 @@ export function checkEnvironmentForWebSocketDowngrade(): void { console.debug("[NDK.ts] Environment Check for WebSocket Protocol:"); const isLocalhost = - window.location.hostname === "localhost" || - window.location.hostname === "127.0.0.1"; - const isHttp = window.location.protocol === "http:"; - const isHttps = window.location.protocol === "https:"; + globalThis.location.hostname === "localhost" || + globalThis.location.hostname === "127.0.0.1"; + const isHttp = globalThis.location.protocol === "http:"; + const isHttps = globalThis.location.protocol === "https:"; console.debug("[NDK.ts] - Is localhost:", isLocalhost); - console.debug("[NDK.ts] - Protocol:", window.location.protocol); + console.debug("[NDK.ts] - Protocol:", globalThis.location.protocol); console.debug("[NDK.ts] - Is HTTP:", isHttp); console.debug("[NDK.ts] - Is HTTPS:", isHttps); @@ -205,9 +192,9 @@ export function checkEnvironmentForWebSocketDowngrade(): void { */ export function checkWebSocketSupport(): void { console.debug("[NDK.ts] WebSocket Support Diagnostics:"); - console.debug("[NDK.ts] - Protocol:", window.location.protocol); - console.debug("[NDK.ts] - Hostname:", window.location.hostname); - console.debug("[NDK.ts] - Port:", window.location.port); + console.debug("[NDK.ts] - Protocol:", globalThis.location.protocol); + console.debug("[NDK.ts] - Hostname:", globalThis.location.hostname); + console.debug("[NDK.ts] - Port:", globalThis.location.port); console.debug("[NDK.ts] - User Agent:", navigator.userAgent); // Test if secure WebSocket is supported @@ -266,46 +253,6 @@ function getRelayStorageKey(user: NDKUser, type: "inbox" | "outbox"): string { return `${loginStorageKey}/${user.pubkey}/${type}`; } -/** - * Stores the user's relay lists in local storage. - * @param user The user for whom to store the relay lists. - * @param inboxes The user's inbox relays. - * @param outboxes The user's outbox relays. - */ -function persistRelays( - user: NDKUser, - inboxes: Set, - outboxes: Set, -): void { - localStorage.setItem( - getRelayStorageKey(user, "inbox"), - JSON.stringify(Array.from(inboxes).map((relay) => relay.url)), - ); - localStorage.setItem( - getRelayStorageKey(user, "outbox"), - JSON.stringify(Array.from(outboxes).map((relay) => relay.url)), - ); -} - -/** - * Retrieves the user's relay lists from local storage. - * @param user The user for whom to retrieve the relay lists. - * @returns A tuple of relay sets of the form `[inboxRelays, outboxRelays]`. Either set may be - * empty if no relay lists were stored for the user. - */ -function getPersistedRelays(user: NDKUser): [Set, Set] { - const inboxes = new Set( - JSON.parse(localStorage.getItem(getRelayStorageKey(user, "inbox")) ?? "[]"), - ); - const outboxes = new Set( - JSON.parse( - localStorage.getItem(getRelayStorageKey(user, "outbox")) ?? "[]", - ), - ); - - return [inboxes, outboxes]; -} - export function clearPersistedRelays(user: NDKUser): void { localStorage.removeItem(getRelayStorageKey(user, "inbox")); localStorage.removeItem(getRelayStorageKey(user, "outbox")); @@ -468,7 +415,7 @@ export async function refreshRelayStoresOnNetworkChange(ndk: NDK): Promise * Starts network monitoring for relay optimization * @param ndk NDK instance */ -export function startNetworkMonitoringForRelays(ndk: NDK): void { +export function startNetworkMonitoringForRelays(): void { // Use centralized network monitoring instead of separate monitoring startNetworkStatusMonitoring(); } @@ -529,7 +476,7 @@ export function initNdk(): NDK { // Update relay stores after connection await updateActiveRelayStores(ndk); // Start network monitoring for relay optimization - startNetworkMonitoringForRelays(ndk); + startNetworkMonitoringForRelays(); } catch (error) { console.warn("[NDK.ts] Failed to connect NDK:", error); @@ -543,7 +490,7 @@ export function initNdk(): NDK { // Still try to update relay stores even if connection failed try { await updateActiveRelayStores(ndk); - startNetworkMonitoringForRelays(ndk); + startNetworkMonitoringForRelays(); } catch (storeError) { console.warn("[NDK.ts] Failed to update relay stores:", storeError); } diff --git a/src/lib/parser.ts b/src/lib/parser.ts index 1a36881..38c7b36 100644 --- a/src/lib/parser.ts +++ b/src/lib/parser.ts @@ -1,9 +1,9 @@ +// deno-lint-ignore-file no-this-alias import NDK, { NDKEvent } from "@nostr-dev-kit/ndk"; -import asciidoctor from "asciidoctor"; +import Processor from "asciidoctor"; import type { AbstractBlock, AbstractNode, - Asciidoctor, Block, Document, Extensions, @@ -13,7 +13,7 @@ import type { import he from "he"; import { writable, type Writable } from "svelte/store"; import { zettelKinds } from "./consts.ts"; -import { getMatchingTags } from "$lib/utils/nostrUtils"; +import { getMatchingTags } from "./utils/nostrUtils.ts"; interface IndexMetadata { authors?: string[]; @@ -65,7 +65,7 @@ export default class Pharos { * hierarchically to form the Abstract Syntax Tree (AST) representation of the document. */ - private asciidoctor: Asciidoctor; + private asciidoctor; private pharosExtensions: Extensions.Registry; @@ -140,7 +140,7 @@ export default class Pharos { // #region Public API constructor(ndk: NDK) { - this.asciidoctor = asciidoctor(); + this.asciidoctor = Processor(); this.pharosExtensions = this.asciidoctor.Extensions.create(); this.ndk = ndk; @@ -164,9 +164,9 @@ export default class Pharos { private async loadAdvancedExtensions(): Promise { try { const { createAdvancedExtensions } = await import( - "./utils/markup/asciidoctorExtensions" + "./utils/markup/asciidoctorExtensions.ts" ); - const advancedExtensions = createAdvancedExtensions(); + createAdvancedExtensions(); // Note: Extensions merging might not be available in this version // We'll handle this in the parse method instead } catch (error) { @@ -549,7 +549,7 @@ export default class Pharos { * - Each ID of a node containing children is mapped to the set of IDs of its children. */ private treeProcessor( - treeProcessor: Extensions.TreeProcessor, + _: Extensions.TreeProcessor, document: Document, ) { this.rootNodeId = this.generateNodeId(document); diff --git a/src/lib/services/publisher.ts b/src/lib/services/publisher.ts index 137b979..4bfc033 100644 --- a/src/lib/services/publisher.ts +++ b/src/lib/services/publisher.ts @@ -1,12 +1,8 @@ import { get } from "svelte/store"; -import { ndkInstance } from "$lib/ndk"; -import { getMimeTags } from "$lib/utils/mime"; -import { - parseAsciiDocSections, - type ZettelSection, -} from "$lib/utils/ZettelParser"; +import { ndkInstance } from "../ndk.ts"; +import { getMimeTags } from "../utils/mime.ts"; +import { parseAsciiDocSections } from "../utils/ZettelParser.ts"; import { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk"; -import { nip19 } from "nostr-tools"; export interface PublishResult { success: boolean; diff --git a/src/lib/state.ts b/src/lib/state.ts index 27a1562..280fb48 100644 --- a/src/lib/state.ts +++ b/src/lib/state.ts @@ -1,6 +1,6 @@ import { browser } from "$app/environment"; import { writable, type Writable } from "svelte/store"; -import type { Tab } from "./types"; +import type { Tab } from "./types.ts"; export const pathLoaded: Writable = writable(false); diff --git a/src/lib/stores.ts b/src/lib/stores.ts index 3315022..3cefe7c 100644 --- a/src/lib/stores.ts +++ b/src/lib/stores.ts @@ -3,9 +3,9 @@ import { writable } from "svelte/store"; // The old feedType store is no longer needed since we use the new relay management system // All relay selection is now handled by the activeInboxRelays and activeOutboxRelays stores in ndk.ts -export let idList = writable([]); +export const idList = writable([]); -export let alexandriaKinds = writable([30040, 30041, 30818]); +export const alexandriaKinds = writable([30040, 30041, 30818]); export interface PublicationLayoutVisibility { toc: boolean; diff --git a/src/lib/stores/networkStore.ts b/src/lib/stores/networkStore.ts index 981b0c9..1c81a08 100644 --- a/src/lib/stores/networkStore.ts +++ b/src/lib/stores/networkStore.ts @@ -1,5 +1,5 @@ -import { writable, type Writable } from 'svelte/store'; -import { detectNetworkCondition, NetworkCondition, startNetworkMonitoring } from '$lib/utils/network_detection'; +import { writable } from "svelte/store"; +import { detectNetworkCondition, NetworkCondition, startNetworkMonitoring } from '../utils/network_detection.ts'; // Network status store export const networkCondition = writable(NetworkCondition.ONLINE); diff --git a/src/lib/stores/userStore.ts b/src/lib/stores/userStore.ts index 4fdcf48..df73ab7 100644 --- a/src/lib/stores/userStore.ts +++ b/src/lib/stores/userStore.ts @@ -1,17 +1,17 @@ import { writable, get } from "svelte/store"; -import type { NostrProfile } from "$lib/utils/nostrUtils"; +import type { NostrProfile } from "../utils/nostrUtils.ts"; import type { NDKUser, NDKSigner } from "@nostr-dev-kit/ndk"; -import { +import NDK, { NDKNip07Signer, NDKRelayAuthPolicies, NDKRelaySet, NDKRelay, } from "@nostr-dev-kit/ndk"; -import { getUserMetadata } from "$lib/utils/nostrUtils"; -import { ndkInstance, activeInboxRelays, activeOutboxRelays, updateActiveRelayStores } from "$lib/ndk"; -import { loginStorageKey } from "$lib/consts"; +import { getUserMetadata } from "../utils/nostrUtils.ts"; +import { ndkInstance, activeInboxRelays, activeOutboxRelays, updateActiveRelayStores } from "../ndk.ts"; +import { loginStorageKey } from "../consts.ts"; import { nip19 } from "nostr-tools"; -import { userPubkey } from "$lib/stores/authStore.Svelte"; +import { userPubkey } from "../stores/authStore.Svelte.ts"; export interface UserState { pubkey: string | null; @@ -69,7 +69,7 @@ function getPersistedRelays(user: NDKUser): [Set, Set] { } async function getUserPreferredRelays( - ndk: any, + ndk: NDK, user: NDKUser, fallbacks: readonly string[] = [...get(activeInboxRelays), ...get(activeOutboxRelays)], ): Promise<[Set, Set]> { @@ -90,9 +90,9 @@ async function getUserPreferredRelays( const outboxRelays = new Set(); if (relayList == null) { - const relayMap = await window.nostr?.getRelays?.(); + const relayMap = await globalThis.nostr?.getRelays?.(); Object.entries(relayMap ?? {}).forEach( - ([url, relayType]: [string, any]) => { + ([url, relayType]: [string, Record]) => { const relay = new NDKRelay( url, NDKRelayAuthPolicies.signIn({ ndk }), @@ -139,15 +139,6 @@ function persistLogin(user: NDKUser, method: "extension" | "amber" | "npub") { localStorage.setItem(loginMethodStorageKey, method); } -function getPersistedLoginMethod(): "extension" | "amber" | "npub" | null { - return ( - (localStorage.getItem(loginMethodStorageKey) as - | "extension" - | "amber" - | "npub") ?? null - ); -} - function clearLogin() { localStorage.removeItem(loginStorageKey); localStorage.removeItem(loginMethodStorageKey); diff --git a/src/lib/types.ts b/src/lib/types.ts index e47b037..06e130c 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -3,7 +3,7 @@ export type Tab = { type: TabType; parent?: number; previous?: Tab; - data?: any; + data?: unknown; }; export type TabType = diff --git a/src/lib/utils.ts b/src/lib/utils.ts index b5be33c..ca992d0 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,6 +1,6 @@ import type { NDKEvent } from "@nostr-dev-kit/ndk"; import { nip19 } from "nostr-tools"; -import { getMatchingTags } from "./utils/nostrUtils"; +import { getMatchingTags } from "./utils/nostrUtils.ts"; export function neventEncode(event: NDKEvent, relays: string[]) { return nip19.neventEncode({ @@ -97,8 +97,8 @@ export function isElementInViewport(el: string | HTMLElement) { rect.top >= 0 && rect.left >= 0 && rect.bottom <= - (window.innerHeight || document.documentElement.clientHeight) && - rect.right <= (window.innerWidth || document.documentElement.clientWidth) + (globalThis.innerHeight || document.documentElement.clientHeight) && + rect.right <= (globalThis.innerWidth || document.documentElement.clientWidth) ); } @@ -169,7 +169,7 @@ Array.prototype.findIndexAsync = function ( * @param wait The number of milliseconds to delay * @returns A debounced version of the function */ -export function debounce any>( +export function debounce unknown>( func: T, wait: number, ): (...args: Parameters) => void { diff --git a/src/lib/utils/ZettelParser.ts b/src/lib/utils/ZettelParser.ts index 42d1b77..fea2e08 100644 --- a/src/lib/utils/ZettelParser.ts +++ b/src/lib/utils/ZettelParser.ts @@ -1,9 +1,3 @@ -import { ndkInstance } from "$lib/ndk"; -import { signEvent, getEventHash } from "$lib/utils/nostrUtils"; -import { getMimeTags } from "$lib/utils/mime"; -import { communityRelays } from "$lib/consts"; -import { nip19 } from "nostr-tools"; - export interface ZettelSection { title: string; content: string; @@ -37,7 +31,7 @@ export function splitAsciiDocByHeadingLevel( export function parseZettelSection(section: string): ZettelSection { const lines = section.split("\n"); let title = "Untitled"; - let contentLines: string[] = []; + const contentLines: string[] = []; let inHeader = true; let tags: string[][] = []; tags = extractTags(section); diff --git a/src/lib/utils/event_input_utils.ts b/src/lib/utils/event_input_utils.ts index c6634f3..d2f33a2 100644 --- a/src/lib/utils/event_input_utils.ts +++ b/src/lib/utils/event_input_utils.ts @@ -1,6 +1,6 @@ -import type { NDKEvent } from "./nostrUtils"; +import type { NDKEvent } from "./nostrUtils.ts"; import { get } from "svelte/store"; -import { ndkInstance } from "$lib/ndk"; +import { ndkInstance } from "../ndk.ts"; import { NDKEvent as NDKEventClass } from "@nostr-dev-kit/ndk"; import { EVENT_KINDS } from "./search_constants"; @@ -149,13 +149,6 @@ function extractAsciiDocDocumentHeader(content: string): string | null { return match ? match[1].trim() : null; } -/** - * Extracts all section headers (lines starting with '== '). - */ -function extractAsciiDocSectionHeaders(content: string): string[] { - return Array.from(content.matchAll(/^==\s+(.+)$/gm)).map((m) => m[1].trim()); -} - /** * Extracts the topmost Markdown # header (line starting with '# '). */ @@ -181,7 +174,7 @@ function splitAsciiDocSections(content: string): { let current: string[] = []; let foundFirstSection = false; let hasPreamble = false; - let preambleContent: string[] = []; + const preambleContent: string[] = []; for (const line of lines) { // Skip document title lines (= header) diff --git a/src/lib/utils/event_search.ts b/src/lib/utils/event_search.ts index 95605b4..25319c0 100644 --- a/src/lib/utils/event_search.ts +++ b/src/lib/utils/event_search.ts @@ -1,18 +1,18 @@ -import { ndkInstance } from "$lib/ndk"; -import { fetchEventWithFallback } from "$lib/utils/nostrUtils"; -import { nip19 } from "$lib/utils/nostrUtils"; -import { NDKEvent } from "@nostr-dev-kit/ndk"; +import { ndkInstance } from "../ndk.ts"; +import { fetchEventWithFallback } from "./nostrUtils.ts"; +import { nip19 } from "nostr-tools"; +import { NDKEvent, NDKFilter } from "@nostr-dev-kit/ndk"; import { get } from "svelte/store"; -import { wellKnownUrl, isValidNip05Address } from "./search_utils"; -import { TIMEOUTS, VALIDATION } from "./search_constants"; +import { wellKnownUrl, isValidNip05Address } from "./search_utils.ts"; +import { TIMEOUTS, VALIDATION } from "./search_constants.ts"; /** * Search for a single event by ID or filter */ export async function searchEvent(query: string): Promise { // Clean the query and normalize to lowercase - let cleanedQuery = query.replace(/^nostr:/, "").toLowerCase(); - let filterOrId: any = cleanedQuery; + const cleanedQuery = query.replace(/^nostr:/, "").toLowerCase(); + let filterOrId: NDKFilter | string = cleanedQuery; // If it's a valid hex string, try as event id first, then as pubkey (profile) if ( @@ -164,7 +164,7 @@ export async function findContainingIndexEvents( ): Promise { // Support all content event kinds that can be contained in indexes const contentEventKinds = [30041, 30818, 30040, 30023]; - if (!contentEventKinds.includes(contentEvent.kind)) { + if (!contentEventKinds.includes(contentEvent.kind!)) { return []; } diff --git a/src/lib/utils/indexEventCache.ts b/src/lib/utils/indexEventCache.ts index 5a8c2c2..0badc14 100644 --- a/src/lib/utils/indexEventCache.ts +++ b/src/lib/utils/indexEventCache.ts @@ -1,5 +1,5 @@ -import type { NDKEvent } from "./nostrUtils"; -import { CACHE_DURATIONS, TIMEOUTS } from "./search_constants"; +import type { NDKEvent } from "@nostr-dev-kit/ndk"; +import { CACHE_DURATIONS, TIMEOUTS } from "./search_constants.ts"; export interface IndexEventCacheEntry { events: NDKEvent[]; @@ -84,7 +84,6 @@ class IndexEventCache { * Clear expired entries from cache */ cleanup(): void { - const now = Date.now(); for (const [key, entry] of this.cache.entries()) { if (this.isExpired(entry)) { this.cache.delete(key); diff --git a/src/lib/utils/markup/advancedAsciidoctorPostProcessor.ts b/src/lib/utils/markup/advancedAsciidoctorPostProcessor.ts index f9dcc60..10ec1a7 100644 --- a/src/lib/utils/markup/advancedAsciidoctorPostProcessor.ts +++ b/src/lib/utils/markup/advancedAsciidoctorPostProcessor.ts @@ -1,4 +1,4 @@ -import { postProcessAsciidoctorHtml } from "./asciidoctorPostProcessor"; +import { postProcessAsciidoctorHtml } from "./asciidoctorPostProcessor.ts"; import plantumlEncoder from "plantuml-encoder"; /** @@ -25,16 +25,16 @@ export async function postProcessAdvancedAsciidoctorHtml( processedHtml = processTikZBlocks(processedHtml); // After all processing, apply highlight.js if available if ( - typeof window !== "undefined" && - typeof window.hljs?.highlightAll === "function" + typeof globalThis !== "undefined" && + typeof globalThis.hljs?.highlightAll === "function" ) { - setTimeout(() => window.hljs!.highlightAll(), 0); + setTimeout(() => globalThis.hljs!.highlightAll(), 0); } if ( - typeof window !== "undefined" && - typeof (window as any).MathJax?.typesetPromise === "function" + typeof globalThis !== "undefined" && + typeof globalThis.MathJax?.typesetPromise === "function" ) { - setTimeout(() => (window as any).MathJax.typesetPromise(), 0); + setTimeout(() => globalThis.MathJax.typesetPromise(), 0); } return processedHtml; } catch (error) { diff --git a/src/lib/utils/markup/advancedMarkupParser.ts b/src/lib/utils/markup/advancedMarkupParser.ts index 344f0e3..8777390 100644 --- a/src/lib/utils/markup/advancedMarkupParser.ts +++ b/src/lib/utils/markup/advancedMarkupParser.ts @@ -1,4 +1,4 @@ -import { parseBasicmarkup } from "./basicMarkupParser"; +import { parseBasicmarkup } from "./basicMarkupParser.ts"; import hljs from "highlight.js"; import "highlight.js/lib/common"; // Import common languages import "highlight.js/styles/github-dark.css"; // Dark theme only @@ -35,14 +35,14 @@ const FOOTNOTE_DEFINITION_REGEX = /^\[\^([^\]]+)\]:\s*(.+)$/gm; const CODE_BLOCK_REGEX = /^```(\w*)$/; // LaTeX math regex patterns -const INLINE_MATH_REGEX = /\$([^$\n]+?)\$/g; -const DISPLAY_MATH_REGEX = /\$\$([\s\S]*?)\$\$/g; -const LATEX_BLOCK_REGEX = /\\\[([\s\S]*?)\\\]/g; -const LATEX_INLINE_REGEX = /\\\(([^)]+?)\\\)/g; +// const INLINE_MATH_REGEX = /\$([^$\n]+?)\$/g; +// const DISPLAY_MATH_REGEX = /\$\$([\s\S]*?)\$\$/g; +// const LATEX_BLOCK_REGEX = /\\\[([\s\S]*?)\\\]/g; +// const LATEX_INLINE_REGEX = /\\\(([^)]+?)\\\)/g; // Add regex for LaTeX display math environments (e.g., \begin{pmatrix}...\end{pmatrix}) // Improved regex: match optional whitespace/linebreaks before and after, and allow for indented environments -const LATEX_ENV_BLOCK_REGEX = - /(?:^|\n)\s*\\begin\{([a-zA-Z*]+)\}([\s\S]*?)\\end\{\1\}\s*(?=\n|$)/gm; +// const LATEX_ENV_BLOCK_REGEX = +// /(?:^|\n)\s*\\begin\{([a-zA-Z*]+)\}([\s\S]*?)\\end\{\1\}\s*(?=\n|$)/gm; /** * Process headings (both styles) @@ -290,7 +290,7 @@ function processCodeBlocks(text: string): { if (currentLanguage.toLowerCase() === "json") { try { formattedCode = JSON.stringify(JSON.parse(code), null, 2); - } catch (e: unknown) { + } catch { formattedCode = code; } } @@ -333,7 +333,7 @@ function processCodeBlocks(text: string): { if (currentLanguage.toLowerCase() === "json") { try { formattedCode = JSON.stringify(JSON.parse(code), null, 2); - } catch (e: unknown) { + } catch { formattedCode = code; } } @@ -402,7 +402,7 @@ function restoreCodeBlocks(text: string, blocks: Map): string { */ function processDollarMath(content: string): string { // Display math: $$...$$ (multi-line, not empty) - content = content.replace(/\$\$([\s\S]*?\S[\s\S]*?)\$\$/g, (match, expr) => { + content = content.replace(/\$\$([\s\S]*?\S[\s\S]*?)\$\$/g, (_match, expr) => { if (isLaTeXContent(expr)) { return `
    $$${expr}$$
    `; } else { @@ -412,7 +412,7 @@ function processDollarMath(content: string): string { } }); // Inline math: $...$ (not empty, not just whitespace) - content = content.replace(/\$([^\s$][^$\n]*?)\$/g, (match, expr) => { + content = content.replace(/\$([^\s$][^$\n]*?)\$/g, (_match, expr) => { if (isLaTeXContent(expr)) { return `$${expr}$`; } else { @@ -428,7 +428,7 @@ function processDollarMath(content: string): string { */ function processMathExpressions(content: string): string { // Only process LaTeX within inline code blocks (backticks) - return content.replace(INLINE_CODE_REGEX, (match, code) => { + return content.replace(INLINE_CODE_REGEX, (_match, code) => { const trimmedCode = code.trim(); // Check for unsupported LaTeX environments (like tabular) first diff --git a/src/lib/utils/markup/asciidoctorExtensions.ts b/src/lib/utils/markup/asciidoctorExtensions.ts index 5e7be35..0a7b646 100644 --- a/src/lib/utils/markup/asciidoctorExtensions.ts +++ b/src/lib/utils/markup/asciidoctorExtensions.ts @@ -1,17 +1,6 @@ -import { renderTikZ } from "./tikzRenderer"; -import asciidoctor from "asciidoctor"; - -// Simple math rendering using MathJax CDN -function renderMath(content: string): string { - return `
    -
    ${content}
    - -
    `; -} +// deno-lint-ignore-file no-this-alias no-explicit-any +import Processor from "asciidoctor"; +import { renderTikZ } from "./tikzRenderer.ts"; // Simple PlantUML rendering using PlantUML server function renderPlantUML(content: string): string { @@ -27,7 +16,7 @@ function renderPlantUML(content: string): string { * including Asciimath/Latex, PlantUML, BPMN, and TikZ */ export function createAdvancedExtensions(): any { - const Asciidoctor = asciidoctor(); + const Asciidoctor = Processor(); const extensions = Asciidoctor.Extensions.create(); // Math rendering extension (Asciimath/Latex) @@ -95,7 +84,7 @@ export function createAdvancedExtensions(): any { /** * Processes math blocks (stem blocks) and converts them to rendered HTML */ -function processMathBlocks(treeProcessor: any, document: any): void { +function processMathBlocks(_: any, document: any): void { const blocks = document.getBlocks(); for (const block of blocks) { if (block.getContext() === "stem") { @@ -131,7 +120,7 @@ function processMathBlocks(treeProcessor: any, document: any): void { /** * Processes PlantUML blocks and converts them to rendered SVG */ -function processPlantUMLBlocks(treeProcessor: any, document: any): void { +function processPlantUMLBlocks(_: any, document: any): void { const blocks = document.getBlocks(); for (const block of blocks) { @@ -156,7 +145,7 @@ function processPlantUMLBlocks(treeProcessor: any, document: any): void { /** * Processes TikZ blocks and converts them to rendered SVG */ -function processTikZBlocks(treeProcessor: any, document: any): void { +function processTikZBlocks(_: any, document: any): void { const blocks = document.getBlocks(); for (const block of blocks) { diff --git a/src/lib/utils/markup/basicMarkupParser.ts b/src/lib/utils/markup/basicMarkupParser.ts index d29ba5a..953fba5 100644 --- a/src/lib/utils/markup/basicMarkupParser.ts +++ b/src/lib/utils/markup/basicMarkupParser.ts @@ -1,4 +1,4 @@ -import { processNostrIdentifiers } from "../nostrUtils"; +import { processNostrIdentifiers } from "../nostrUtils.ts"; import * as emoji from "node-emoji"; import { nip19 } from "nostr-tools"; @@ -236,7 +236,7 @@ function processBasicFormatting(content: string): string { processedText = replaceAlexandriaNostrLinks(processedText); // Process markup images first - processedText = processedText.replace(MARKUP_IMAGE, (match, alt, url) => { + processedText = processedText.replace(MARKUP_IMAGE, (_match, alt, url) => { url = stripTrackingParams(url); if (YOUTUBE_URL_REGEX.test(url)) { const videoId = extractYouTubeVideoId(url); @@ -261,7 +261,7 @@ function processBasicFormatting(content: string): string { // Process markup links processedText = processedText.replace( MARKUP_LINK, - (match, text, url) => + (_match, text, url) => `${text}`, ); @@ -303,7 +303,7 @@ function processBasicFormatting(content: string): string { }); processedText = processedText.replace( STRIKETHROUGH_REGEX, - (match, doubleText, singleText) => { + (_match, doubleText, singleText) => { const text = doubleText || singleText; return `${text}`; }, diff --git a/src/lib/utils/network_detection.ts b/src/lib/utils/network_detection.ts index 1e812db..40bb568 100644 --- a/src/lib/utils/network_detection.ts +++ b/src/lib/utils/network_detection.ts @@ -1,4 +1,4 @@ -import { deduplicateRelayUrls } from './relay_management'; +import { deduplicateRelayUrls } from "./relay_management.ts"; /** * Network conditions for relay selection @@ -26,7 +26,7 @@ export async function isNetworkOnline(): Promise { for (const endpoint of NETWORK_ENDPOINTS) { try { // Use a simple fetch without HEAD method to avoid CORS issues - const response = await fetch(endpoint, { + await fetch(endpoint, { method: 'GET', cache: 'no-cache', signal: AbortSignal.timeout(3000), @@ -127,8 +127,7 @@ export function getRelaySetForNetworkCondition( outboxRelays: [] }; } - - case NetworkCondition.SLOW: + case NetworkCondition.SLOW: { // Local relays + low bandwidth relays when slow (deduplicated) console.debug('[network_detection.ts] Using local + low bandwidth relays (slow network)'); const slowInboxRelays = deduplicateRelayUrls([...discoveredLocalRelays, ...lowbandwidthRelays]); @@ -137,7 +136,7 @@ export function getRelaySetForNetworkCondition( inboxRelays: slowInboxRelays, outboxRelays: slowOutboxRelays }; - + } case NetworkCondition.ONLINE: default: // Full relay set when online @@ -177,7 +176,7 @@ export function startNetworkMonitoring( checkNetwork(); // Set up periodic monitoring - intervalId = window.setInterval(checkNetwork, checkInterval); + intervalId = globalThis.setInterval(checkNetwork, checkInterval); // Return function to stop monitoring return () => { diff --git a/src/lib/utils/nostrEventService.ts b/src/lib/utils/nostrEventService.ts index 4ad05f8..cdea5e1 100644 --- a/src/lib/utils/nostrEventService.ts +++ b/src/lib/utils/nostrEventService.ts @@ -1,10 +1,9 @@ import { nip19 } from "nostr-tools"; -import { getEventHash, signEvent, prefixNostrAddresses } from "./nostrUtils"; +import { getEventHash, signEvent, prefixNostrAddresses } from "./nostrUtils.ts"; import { get } from "svelte/store"; import { goto } from "$app/navigation"; -import { EVENT_KINDS, TIME_CONSTANTS, TIMEOUTS } from "./search_constants"; -import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; -import { ndkInstance } from "$lib/ndk"; +import { EVENT_KINDS, TIME_CONSTANTS } from "./search_constants.ts"; +import { ndkInstance } from "../ndk.ts"; import { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk"; export interface RootEventInfo { @@ -139,7 +138,6 @@ export function extractParentEventInfo(parent: NDKEvent): ParentEventInfo { */ function buildRootScopeTags( rootInfo: RootEventInfo, - parentInfo: ParentEventInfo, ): string[][] { const tags: string[][] = []; @@ -292,7 +290,7 @@ export function buildReplyTags( // For regular events, use E/e tags if (isReplyToComment) { // Reply to a comment - distinguish root from parent - addTags(tags, ...buildRootScopeTags(rootInfo, parentInfo)); + addTags(tags, ...buildRootScopeTags(rootInfo)); addTags( tags, createTag("e", parent.id, parentInfo.parentRelay), @@ -301,7 +299,7 @@ export function buildReplyTags( ); } else { // Top-level comment or regular event - addTags(tags, ...buildRootScopeTags(rootInfo, parentInfo)); + addTags(tags, ...buildRootScopeTags(rootInfo)); addTags(tags, ...buildParentScopeTags(parent, parentInfo, rootInfo)); } } @@ -318,6 +316,7 @@ export async function createSignedEvent( pubkey: string, kind: number, tags: string[][], +// deno-lint-ignore no-explicit-any ): Promise<{ id: string; sig: string; event: any }> { const prefixedContent = prefixNostrAddresses(content); @@ -337,8 +336,8 @@ export async function createSignedEvent( }; let sig, id; - if (typeof window !== "undefined" && window.nostr && window.nostr.signEvent) { - const signed = await window.nostr.signEvent(eventToSign); + if (typeof window !== "undefined" && globalThis.nostr && globalThis.nostr.signEvent) { + const signed = await globalThis.nostr.signEvent(eventToSign); sig = signed.sig as string; id = "id" in signed ? (signed.id as string) : getEventHash(eventToSign); } else { @@ -364,7 +363,7 @@ export async function createSignedEvent( * @returns Promise that resolves to array of successful relay URLs */ export async function publishEvent( - event: NDKEvent | any, + event: NDKEvent, relayUrls: string[], ): Promise { const successfulRelays: string[] = []; @@ -427,6 +426,7 @@ export function navigateToEvent(eventId: string): void { } // Helper functions to ensure relay and pubkey are always strings +// deno-lint-ignore no-explicit-any function getRelayString(relay: any): string { if (!relay) return ""; if (typeof relay === "string") return relay; @@ -434,6 +434,7 @@ function getRelayString(relay: any): string { return ""; } +// deno-lint-ignore no-explicit-any function getPubkeyString(pubkey: any): string { if (!pubkey) return ""; if (typeof pubkey === "string") return pubkey; diff --git a/src/lib/utils/nostrUtils.ts b/src/lib/utils/nostrUtils.ts index da8bb1b..91d3309 100644 --- a/src/lib/utils/nostrUtils.ts +++ b/src/lib/utils/nostrUtils.ts @@ -1,17 +1,17 @@ import { get } from "svelte/store"; import { nip19 } from "nostr-tools"; -import { ndkInstance } from "$lib/ndk"; -import { npubCache } from "./npubCache"; +import { ndkInstance } from "../ndk.ts"; +import { npubCache } from "./npubCache.ts"; import NDK, { NDKEvent, NDKRelaySet, NDKUser } from "@nostr-dev-kit/ndk"; -import type { NDKFilter, NDKKind } from "@nostr-dev-kit/ndk"; -import { communityRelays, secondaryRelays, anonymousRelays } from "$lib/consts"; -import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; +import type { NDKFilter, NDKKind, NostrEvent } from "@nostr-dev-kit/ndk"; +import { communityRelays, secondaryRelays } from "../consts.ts"; +import { activeInboxRelays, activeOutboxRelays } from "../ndk.ts"; import { NDKRelaySet as NDKRelaySetFromNDK } from "@nostr-dev-kit/ndk"; -import { sha256 } from "@noble/hashes/sha256"; +import { sha256 } from "@noble/hashes/sha2.js"; import { schnorr } from "@noble/curves/secp256k1"; import { bytesToHex } from "@noble/hashes/utils"; -import { wellKnownUrl } from "./search_utility"; -import { TIMEOUTS, VALIDATION } from "./search_constants"; +import { wellKnownUrl } from "./search_utility.ts"; +import { VALIDATION } from "./search_constants.ts"; const badgeCheckSvg = ''; @@ -442,7 +442,7 @@ export async function fetchEventWithFallback( // Use both inbox and outbox relays for better event discovery const inboxRelays = get(activeInboxRelays); const outboxRelays = get(activeOutboxRelays); - const allRelays = [...(inboxRelays || []), ...(outboxRelays || [])]; + const allRelays = [...inboxRelays, ...outboxRelays]; console.log("fetchEventWithFallback: Using inbox relays:", inboxRelays); console.log("fetchEventWithFallback: Using outbox relays:", outboxRelays); @@ -464,7 +464,7 @@ export async function fetchEventWithFallback( console.log("fetchEventWithFallback: Relay set size:", relaySet.relays.size); console.log("fetchEventWithFallback: Filter:", filterOrId); - console.log("fetchEventWithFallback: Relay URLs:", Array.from(relaySet.relays).map((r: any) => r.url)); + console.log("fetchEventWithFallback: Relay URLs:", Array.from(relaySet.relays).map((r) => r.url)); let found: NDKEvent | null = null; @@ -488,7 +488,7 @@ export async function fetchEventWithFallback( if (!found) { const timeoutSeconds = timeoutMs / 1000; - const relayUrls = Array.from(relaySet.relays).map((r: any) => r.url).join(", "); + const relayUrls = Array.from(relaySet.relays).map((r) => r.url).join(", "); console.warn( `fetchEventWithFallback: Event not found after ${timeoutSeconds}s timeout. Tried inbox relays: ${relayUrls}. Some relays may be offline or slow.`, ); @@ -501,7 +501,7 @@ export async function fetchEventWithFallback( } catch (err) { if (err instanceof Error && err.message === 'Timeout') { const timeoutSeconds = timeoutMs / 1000; - const relayUrls = Array.from(relaySet.relays).map((r: any) => r.url).join(", "); + const relayUrls = Array.from(relaySet.relays).map((r) => r.url).join(", "); console.warn( `fetchEventWithFallback: Event fetch timed out after ${timeoutSeconds}s. Tried inbox relays: ${relayUrls}. Some relays may be offline or slow.`, ); @@ -536,7 +536,7 @@ export function createRelaySetFromUrls(relayUrls: string[], ndk: NDK) { return NDKRelaySetFromNDK.fromRelayUrls(relayUrls, ndk); } -export function createNDKEvent(ndk: NDK, rawEvent: any) { +export function createNDKEvent(ndk: NDK, rawEvent: NDKEvent | NostrEvent | undefined) { return new NDKEvent(ndk, rawEvent); } diff --git a/src/lib/utils/profile_search.ts b/src/lib/utils/profile_search.ts index 1fde323..eeac332 100644 --- a/src/lib/utils/profile_search.ts +++ b/src/lib/utils/profile_search.ts @@ -1,19 +1,16 @@ -import { ndkInstance } from "$lib/ndk"; -import { getUserMetadata, getNpubFromNip05 } from "$lib/utils/nostrUtils"; -import { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk"; -import { searchCache } from "$lib/utils/searchCache"; -import { communityRelays, secondaryRelays } from "$lib/consts"; +import { ndkInstance } from "../ndk.ts"; +import { getUserMetadata, getNpubFromNip05 } from "./nostrUtils.ts"; +import NDK, { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk"; +import { searchCache } from "./searchCache.ts"; +import { communityRelays, secondaryRelays } from "../consts.ts"; import { get } from "svelte/store"; -import type { NostrProfile, ProfileSearchResult } from "./search_types"; +import type { NostrProfile, ProfileSearchResult } from "./search_types.ts"; import { fieldMatches, nip05Matches, normalizeSearchTerm, - COMMON_DOMAINS, createProfileFromEvent, -} from "./search_utils"; -import { checkCommunityStatus } from "./community_checker"; -import { TIMEOUTS } from "./search_constants"; +} from "./search_utils.ts"; /** * Search for profiles by various criteria (display name, name, NIP-05, npub) @@ -92,7 +89,7 @@ export async function searchProfiles( } else { // Try NIP-05 search first (faster than relay search) console.log("Starting NIP-05 search for:", normalizedSearchTerm); - foundProfiles = await searchNip05Domains(normalizedSearchTerm, ndk); + foundProfiles = await searchNip05Domains(normalizedSearchTerm); console.log( "NIP-05 search completed, found:", foundProfiles.length, @@ -145,7 +142,6 @@ export async function searchProfiles( */ async function searchNip05Domains( searchTerm: string, - ndk: any, ): Promise { const foundProfiles: NostrProfile[] = []; @@ -260,10 +256,9 @@ async function searchNip05Domains( */ async function quickRelaySearch( searchTerm: string, - ndk: any, + ndk: NDK, ): Promise { console.log("quickRelaySearch called with:", searchTerm); - const foundProfiles: NostrProfile[] = []; // Normalize the search term for relay search const normalizedSearchTerm = normalizeSearchTerm(searchTerm); @@ -286,7 +281,7 @@ async function quickRelaySearch( .filter(Boolean); // Search all relays in parallel with short timeout - const searchPromises = relaySets.map(async (relaySet, index) => { + const searchPromises = relaySets.map((relaySet, index) => { if (!relaySet) return []; return new Promise((resolve) => { @@ -299,7 +294,8 @@ async function quickRelaySearch( const sub = ndk.subscribe( { kinds: [0] }, - { closeOnEose: true, relaySet }, + { closeOnEose: true }, + relaySet, ); sub.on("event", (event: NDKEvent) => { @@ -351,7 +347,7 @@ async function quickRelaySearch( foundInRelay.push(profile); } } - } catch (e) { + } catch { // Invalid JSON or other error, skip } }); diff --git a/src/lib/utils/relayDiagnostics.ts b/src/lib/utils/relayDiagnostics.ts index 9a0db7c..df61930 100644 --- a/src/lib/utils/relayDiagnostics.ts +++ b/src/lib/utils/relayDiagnostics.ts @@ -1,6 +1,5 @@ -import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; -import NDK from "@nostr-dev-kit/ndk"; -import { TIMEOUTS } from "./search_constants"; +import { activeInboxRelays, activeOutboxRelays } from "../ndk.ts"; +import { TIMEOUTS } from "./search_constants.ts"; import { get } from "svelte/store"; export interface RelayDiagnostic { @@ -14,7 +13,7 @@ export interface RelayDiagnostic { /** * Tests connection to a single relay */ -export async function testRelay(url: string): Promise { +export function testRelay(url: string): Promise { const startTime = Date.now(); return new Promise((resolve) => { diff --git a/src/lib/utils/relay_management.ts b/src/lib/utils/relay_management.ts index 2787938..a4f41fa 100644 --- a/src/lib/utils/relay_management.ts +++ b/src/lib/utils/relay_management.ts @@ -1,7 +1,7 @@ -import NDK, { NDKRelay, NDKUser } from "@nostr-dev-kit/ndk"; -import { communityRelays, searchRelays, secondaryRelays, anonymousRelays, lowbandwidthRelays, localRelays } from "../consts"; -import { getRelaySetForNetworkCondition, NetworkCondition } from "./network_detection"; -import { networkCondition } from "../stores/networkStore"; +import NDK, { NDKKind, NDKRelay, NDKUser } from "@nostr-dev-kit/ndk"; +import { searchRelays, secondaryRelays, anonymousRelays, lowbandwidthRelays, localRelays } from "../consts.ts"; +import { getRelaySetForNetworkCondition } from "./network_detection.ts"; +import { networkCondition } from "../stores/networkStore.ts"; import { get } from "svelte/store"; /** @@ -48,7 +48,7 @@ export function deduplicateRelayUrls(urls: string[]): string[] { * @param ndk The NDK instance * @returns Promise that resolves to connection status */ -export async function testRelayConnection( +export function testRelayConnection( relayUrl: string, ndk: NDK, ): Promise<{ @@ -163,7 +163,7 @@ async function testLocalRelays(localRelayUrls: string[], ndk: NDK): Promise { } // Convert wss:// URLs from consts to ws:// for local testing - const localRelayUrls = localRelays.map(url => + const localRelayUrls = localRelays.map((url: string) => url.replace(/^wss:\/\//, 'ws://') ); @@ -197,7 +197,7 @@ export async function discoverLocalRelays(ndk: NDK): Promise { // If no local relays are working, return empty array // The network detection logic will provide fallback relays return workingRelays; - } catch (error) { + } catch { // Silently fail and return empty array return []; } @@ -213,7 +213,7 @@ export async function getUserLocalRelays(ndk: NDK, user: NDKUser): Promise { try { // Check if we're in a browser environment with extension support - if (typeof window === 'undefined' || !window.nostr) { - console.debug('[relay_management.ts] No window.nostr available'); + if (typeof window === 'undefined' || !globalThis.nostr) { + console.debug('[relay_management.ts] No globalThis.nostr available'); return []; } @@ -348,10 +348,10 @@ export async function getExtensionRelays(): Promise { // Try to get relays from the extension's API // Different extensions may expose their relay config differently - if (window.nostr.getRelays) { + if (globalThis.nostr.getRelays) { console.debug('[relay_management.ts] getRelays() method found, calling it...'); try { - const relays = await window.nostr.getRelays(); + const relays = await globalThis.nostr.getRelays(); console.debug('[relay_management.ts] getRelays() returned:', relays); if (relays && typeof relays === 'object') { // Convert relay object to array of URLs @@ -363,7 +363,7 @@ export async function getExtensionRelays(): Promise { console.debug('[relay_management.ts] Extension getRelays() failed:', error); } } else { - console.debug('[relay_management.ts] getRelays() method not found on window.nostr'); + console.debug('[relay_management.ts] getRelays() method not found on globalThis.nostr'); } // If getRelays() didn't work, try alternative methods @@ -457,7 +457,7 @@ export async function buildCompleteRelaySet( try { blockedRelays = await getUserBlockedRelays(ndk, user); console.debug('[relay_management.ts] buildCompleteRelaySet: User blocked relays:', blockedRelays); - } catch (error) { + } catch { // Silently ignore blocked relay fetch errors } @@ -511,8 +511,8 @@ export async function buildCompleteRelaySet( // Filter out blocked relays and deduplicate final sets const finalRelaySet = { - inboxRelays: deduplicateRelayUrls(networkOptimizedRelaySet.inboxRelays.filter(r => !blockedRelays.includes(r))), - outboxRelays: deduplicateRelayUrls(networkOptimizedRelaySet.outboxRelays.filter(r => !blockedRelays.includes(r))) + inboxRelays: deduplicateRelayUrls(networkOptimizedRelaySet.inboxRelays.filter((r: string) => !blockedRelays.includes(r))), + outboxRelays: deduplicateRelayUrls(networkOptimizedRelaySet.outboxRelays.filter((r: string) => !blockedRelays.includes(r))) }; // If no relays are working, use anonymous relays as fallback diff --git a/src/lib/utils/searchCache.ts b/src/lib/utils/searchCache.ts index 336641c..76eb3c0 100644 --- a/src/lib/utils/searchCache.ts +++ b/src/lib/utils/searchCache.ts @@ -1,5 +1,5 @@ -import type { NDKEvent } from "./nostrUtils"; -import { CACHE_DURATIONS, TIMEOUTS } from "./search_constants"; +import type { NDKEvent } from "@nostr-dev-kit/ndk"; +import { CACHE_DURATIONS, TIMEOUTS } from "./search_constants.ts"; export interface SearchResult { events: NDKEvent[]; @@ -78,7 +78,6 @@ class SearchCache { * Clear expired entries from cache */ cleanup(): void { - const now = Date.now(); for (const [key, result] of this.cache.entries()) { if (this.isExpired(result)) { this.cache.delete(key); diff --git a/src/lib/utils/search_types.ts b/src/lib/utils/search_types.ts index 49a4f79..134ceff 100644 --- a/src/lib/utils/search_types.ts +++ b/src/lib/utils/search_types.ts @@ -1,4 +1,4 @@ -import { NDKEvent } from "@nostr-dev-kit/ndk"; +import { NDKEvent, NDKFilter, NDKSubscription } from "@nostr-dev-kit/ndk"; /** * Extended NostrProfile interface for search results @@ -45,7 +45,7 @@ export type SearchSubscriptionType = "d" | "t" | "n"; * Search filter configuration */ export interface SearchFilter { - filter: any; + filter: NDKFilter; subscriptionType: string; } @@ -65,5 +65,5 @@ export interface SecondOrderSearchParams { */ export interface SearchCallbacks { onSecondOrderUpdate?: (result: SearchResult) => void; - onSubscriptionCreated?: (sub: any) => void; + onSubscriptionCreated?: (sub: NDKSubscription) => void; } diff --git a/src/lib/utils/search_utils.ts b/src/lib/utils/search_utils.ts index 02e3c94..055004e 100644 --- a/src/lib/utils/search_utils.ts +++ b/src/lib/utils/search_utils.ts @@ -1,3 +1,5 @@ +import { NDKEvent } from "@nostr-dev-kit/ndk"; + /** * Generate well-known NIP-05 URL */ @@ -85,14 +87,15 @@ export const COMMON_DOMAINS = [ /** * Check if an event is an emoji reaction (kind 7) */ -export function isEmojiReaction(event: any): boolean { +export function isEmojiReaction(event: NDKEvent): boolean { return event.kind === 7; } /** * Create a profile object from event data */ -export function createProfileFromEvent(event: any, profileData: any): any { +// deno-lint-ignore no-explicit-any +export function createProfileFromEvent(event: NDKEvent, profileData: any): any { return { name: profileData.name, displayName: profileData.displayName || profileData.display_name, diff --git a/src/lib/utils/subscription_search.ts b/src/lib/utils/subscription_search.ts index 22cefb4..17fa093 100644 --- a/src/lib/utils/subscription_search.ts +++ b/src/lib/utils/subscription_search.ts @@ -1,26 +1,25 @@ -import { ndkInstance } from "$lib/ndk"; -import { getMatchingTags, getNpubFromNip05 } from "$lib/utils/nostrUtils"; -import { nip19 } from "$lib/utils/nostrUtils"; +// deno-lint-ignore-file no-explicit-any +import { ndkInstance } from "../ndk.ts"; +import { getMatchingTags, getNpubFromNip05 } from "./nostrUtils.ts"; +import { nip19 } from "./nostrUtils.ts"; import { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk"; -import { searchCache } from "$lib/utils/searchCache"; -import { communityRelays, searchRelays } from "$lib/consts"; +import { searchCache } from "./searchCache.ts"; +import { communityRelays, searchRelays } from "../consts.ts"; import { get } from "svelte/store"; import type { SearchResult, SearchSubscriptionType, SearchFilter, SearchCallbacks, - SecondOrderSearchParams, -} from "./search_types"; +} from "./search_types.ts"; import { fieldMatches, nip05Matches, - normalizeSearchTerm, COMMON_DOMAINS, isEmojiReaction, -} from "./search_utils"; -import { TIMEOUTS, SEARCH_LIMITS } from "./search_constants"; -import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; +} from "./search_utils.ts"; +import { TIMEOUTS, SEARCH_LIMITS } from "./search_constants.ts"; +import { activeInboxRelays, activeOutboxRelays } from "../ndk.ts"; // Helper function to normalize URLs for comparison const normalizeUrl = (url: string): string => { @@ -132,7 +131,6 @@ export async function searchBySubscription( searchFilter, searchState, callbacks, - abortSignal, cleanup, ); @@ -160,7 +158,6 @@ export async function searchBySubscription( searchFilter, searchState, callbacks, - abortSignal, cleanup, ); } @@ -215,26 +212,30 @@ async function createSearchFilter( }); switch (searchType) { - case "d": + case "d": { const dFilter = { filter: { "#d": [normalizedSearchTerm] }, subscriptionType: "d-tag", }; console.log("subscription_search: Created d-tag filter:", dFilter); return dFilter; - case "t": + } + case "t": { const tFilter = { filter: { "#t": [normalizedSearchTerm] }, subscriptionType: "t-tag", }; console.log("subscription_search: Created t-tag filter:", tFilter); return tFilter; - case "n": + } + case "n": { const nFilter = await createProfileSearchFilter(normalizedSearchTerm); console.log("subscription_search: Created profile filter:", nFilter); return nFilter; - default: + } + default: { throw new Error(`Unknown search type: ${searchType}`); + } } } @@ -257,7 +258,7 @@ async function createProfileSearchFilter( subscriptionType: "npub-specific", }; } - } catch (e) { + } catch { // Not a valid npub, continue with other strategies } @@ -277,11 +278,11 @@ async function createProfileSearchFilter( subscriptionType: "nip05-found", }; } - } catch (e) { + } catch { // Continue to next domain } } - } catch (e) { + } catch { // Fallback to reasonable profile search } @@ -520,12 +521,11 @@ function createSearchResult( /** * Search other relays in background */ -async function searchOtherRelaysInBackground( +function searchOtherRelaysInBackground( searchType: SearchSubscriptionType, searchFilter: SearchFilter, searchState: any, callbacks?: SearchCallbacks, - abortSignal?: AbortSignal, cleanup?: () => void, ): Promise { const ndk = get(ndkInstance); @@ -578,7 +578,7 @@ async function searchOtherRelaysInBackground( } else { processContentEvent(event, searchType, searchState); } - } catch (e) { + } catch { // Invalid JSON or other error, skip } }); diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts index dd255ca..80555ad 100644 --- a/src/routes/+layout.ts +++ b/src/routes/+layout.ts @@ -1,11 +1,11 @@ -import { getPersistedLogin, initNdk, ndkInstance } from "$lib/ndk"; +import { getPersistedLogin, initNdk, ndkInstance } from "../lib/ndk.ts"; import { loginWithExtension, loginWithAmber, loginWithNpub, -} from "$lib/stores/userStore"; -import { loginMethodStorageKey } from "$lib/stores/userStore"; -import Pharos, { pharosInstance } from "$lib/parser"; +} from "../lib/stores/userStore.ts"; +import { loginMethodStorageKey } from "../lib/stores/userStore.ts"; +import Pharos, { pharosInstance } from "../lib/parser.ts"; import type { LayoutLoad } from "./$types"; import { get } from "svelte/store"; @@ -35,10 +35,11 @@ export const load: LayoutLoad = () => { const localNsec = localStorage.getItem("amber/nsec"); if (localNsec) { import("@nostr-dev-kit/ndk").then( - async ({ NDKNip46Signer, default: NDK }) => { + async ({ NDKNip46Signer }) => { const ndk = get(ndkInstance); try { - const amberSigner = NDKNip46Signer.nostrconnect( + // deno-lint-ignore no-explicit-any + const amberSigner = (NDKNip46Signer as any).nostrconnect( ndk, relay, localNsec, @@ -52,7 +53,7 @@ export const load: LayoutLoad = () => { const user = await amberSigner.user(); await loginWithAmber(amberSigner, user); console.log("Amber session restored."); - } catch (err) { + } catch { // If reconnection fails, automatically fallback to npub-only mode console.warn( "Amber session could not be restored. Falling back to npub-only mode.", diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 03a9c14..1439a42 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,12 +1,8 @@