From af4fae766f0f8b067e25c7acc2a146754c186d29 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Tue, 27 May 2025 23:36:56 -0500 Subject: [PATCH 01/34] Prevent duplicate nodes from being added to a `PublicationTree` Suggestion from https://gitworkshop.dev/silberengel@gitcitadel.com/Alexandria/prs/note1jygtyvjnrd2yz674mqq5emd0pl69ezv2u6nhvr7f0zhcdnshlnqskf94df --- deno.lock | 3 +++ src/lib/data_structures/publication_tree.ts | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/deno.lock b/deno.lock index 9206145..6e9e011 100644 --- a/deno.lock +++ b/deno.lock @@ -3201,8 +3201,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 +3219,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/data_structures/publication_tree.ts b/src/lib/data_structures/publication_tree.ts index d616740..eabaa5b 100644 --- a/src/lib/data_structures/publication_tree.ts +++ b/src/lib/data_structures/publication_tree.ts @@ -464,6 +464,11 @@ export class PublicationTree implements AsyncIterable { } #addNode(address: string, parentNode: PublicationTreeNode) { + if (this.#nodes.has(address)) { + console.debug(`[PublicationTree] Node with address ${address} already exists.`); + return; + } + const lazyNode = new Lazy(() => this.#resolveNode(address, parentNode)); parentNode.children!.push(lazyNode); this.#nodes.set(address, lazyNode); From 4907cc37a79173b42613cc355746f31306718161 Mon Sep 17 00:00:00 2001 From: Silberengel Date: Tue, 8 Jul 2025 20:26:56 +0200 Subject: [PATCH 02/34] 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 03/34] 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 18/34] 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 19/34] 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 20/34] 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 21/34] 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 22/34] 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 23/34] 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 24/34] 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 25/34] 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 28/34] 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 29/34] 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 30/34] 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 31/34] 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 @@ @@ -471,32 +340,70 @@
    - {#if showMentionModal} -
    -
    -

    Mention User

    + +
    +
    { + if (e.key === 'Enter' && mentionSearch.trim() && !isSearching) { + searchMentions(); + } + }} + class="flex-1 rounded-lg border border-gray-300 bg-gray-50 text-gray-900 text-sm focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-primary-500 dark:focus:ring-primary-500 p-2.5" /> - - {#if mentionLoading} -
    Searching...
    - {:else if mentionResults.length > 0} -
      + +
    + + {#if mentionLoading} +
    Searching...
    + {:else if mentionResults.length > 0} +
    +
      {#each mentionResults as profile} - {/each}
    - {:else} -
    No results
    - {/if} -
    -
    -
    + {:else if mentionSearch.trim()} +
    No results found
    + {:else} +
    Enter a search term to find users
    + {/if}
    - {/if} +
    - {#if showWikilinkModal} -
    -
    -

    Insert Wikilink

    - - -
    - - -
    -
    + + + +
    + +
    - {/if} +
    -
    +