From ff5bd8b09220c4b7cc7faaaad4d19d1022ddedb6 Mon Sep 17 00:00:00 2001 From: Priyanshubhartistm Date: Fri, 17 Apr 2026 23:03:48 +0530 Subject: [PATCH 1/9] feat: improve og invite preview --- Dockerfile | 3 +- README.md | 2 +- package.json | 1 + server.mjs | 379 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 383 insertions(+), 2 deletions(-) create mode 100644 server.mjs diff --git a/Dockerfile b/Dockerfile index 780ce934..013e7632 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,5 +28,6 @@ WORKDIR /app # Copy only the built output - no source, no .env, no dev deps COPY --from=builder /app/build ./build +COPY --from=builder /app/server.mjs ./server.mjs -CMD ["npx", "serve", "-s", "build"] +CMD ["node", "server.mjs"] diff --git a/README.md b/README.md index 6092fd32..8eacb8d9 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ To run your own Flotilla, it's as simple as: ```sh pnpm install pnpm run build -npx serve -s build +pnpm run start ``` Or, if you prefer to use a container: diff --git a/package.json b/package.json index b0dc3763..ae3489ad 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "scripts": { "dev": "vite dev", "build": "./build.sh", + "start": "node server.mjs", "release:android": "./build.sh && cap build android --androidreleasetype APK --signing-type apksigner", "tauri:dev": "tauri dev", "tauri:build": "tauri build", diff --git a/server.mjs b/server.mjs new file mode 100644 index 00000000..0612614f --- /dev/null +++ b/server.mjs @@ -0,0 +1,379 @@ +import http from "node:http" +import path from "node:path" +import {promises as fs} from "node:fs" + +const PORT = Number(process.env.PORT || 3000) +const BUILD_DIR = path.resolve("build") +const INDEX_HTML_PATH = path.join(BUILD_DIR, "index.html") +const DEFAULT_IMAGE_PATH = "/maskable-icon-512x512.png" +const CACHE_SECONDS = 60 + +const MIME_TYPES = { + ".html": "text/html; charset=utf-8", + ".js": "application/javascript; charset=utf-8", + ".css": "text/css; charset=utf-8", + ".json": "application/json; charset=utf-8", + ".svg": "image/svg+xml", + ".png": "image/png", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".webp": "image/webp", + ".gif": "image/gif", + ".ico": "image/x-icon", + ".txt": "text/plain; charset=utf-8", + ".map": "application/json; charset=utf-8", + ".woff": "font/woff", + ".woff2": "font/woff2", +} + +const BOT_UA_REGEX = + /bot|crawler|spider|slackbot|telegrambot|twitterbot|facebookexternalhit|discordbot|linkedinbot|whatsapp|skypeuripreview|applebot|googlebot/i + +const relayMetadataCache = new Map() + +const htmlEscape = value => + String(value) + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll('"', """) + .replaceAll("'", "'") + +const isBotRequest = req => BOT_UA_REGEX.test(String(req.headers["user-agent"] || "")) + +const relayToHttpUrl = relay => { + try { + const url = new URL(relay) + + if (url.protocol === "wss:") { + url.protocol = "https:" + } else if (url.protocol === "ws:") { + url.protocol = "http:" + } + + return url.toString() + } catch { + return null + } +} + +const normalizeRelayParam = relayParam => { + const relay = String(relayParam || "").trim() + + if (!relay) { + return null + } + + try { + const parsed = new URL(relay.includes("://") ? relay : `wss://${relay}`) + + if (!["ws:", "wss:", "http:", "https:"].includes(parsed.protocol)) { + return null + } + + if (parsed.protocol === "http:") { + parsed.protocol = "ws:" + } + + if (parsed.protocol === "https:") { + parsed.protocol = "wss:" + } + + return parsed.toString() + } catch { + return null + } +} + +const fetchJsonWithTimeout = async (url, timeoutMs = 5000) => { + const controller = new AbortController() + const timeout = setTimeout(() => controller.abort(), timeoutMs) + + try { + const response = await fetch(url, { + method: "GET", + headers: {Accept: "application/nostr+json, application/json"}, + signal: controller.signal, + }) + + if (!response.ok) { + return null + } + + return await response.json() + } catch { + return null + } finally { + clearTimeout(timeout) + } +} + +const getRelayMetadata = async relayUrl => { + if (!relayUrl) { + return null + } + + const now = Date.now() + const cached = relayMetadataCache.get(relayUrl) + + if (cached && now - cached.at < CACHE_SECONDS * 1000) { + return cached.value + } + + const httpUrl = relayToHttpUrl(relayUrl) + + if (!httpUrl) { + return null + } + + const profile = await fetchJsonWithTimeout(httpUrl) + + const value = { + name: profile?.name || profile?.title || null, + icon: profile?.icon || profile?.picture || null, + } + + relayMetadataCache.set(relayUrl, {at: now, value}) + + return value +} + +const getAbsoluteUrl = req => { + const host = req.headers["x-forwarded-host"] || req.headers.host || `localhost:${PORT}` + const protocolHeader = req.headers["x-forwarded-proto"] + const protocol = String(protocolHeader || "").split(",")[0] || "http" + + return new URL(req.url || "/", `${protocol}://${host}`) +} + +const getLocalRequestUrl = req => { + const host = req.headers.host || `localhost:${PORT}` + + return new URL(req.url || "/", `http://${host}`) +} + +const toAbsoluteImageUrl = (url, origin) => { + try { + return new URL(url, origin).toString() + } catch { + return new URL(DEFAULT_IMAGE_PATH, origin).toString() + } +} + +const escapeRegex = value => String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + +const replaceOrInsertMeta = (html, keyValue, content, preferredKey = "name") => { + const escapedValue = escapeRegex(keyValue) + const tag = `` + const pattern = new RegExp(`]*(?:name|property)=["']${escapedValue}["'][^>]*>`, "i") + + if (pattern.test(html)) { + return html.replace(pattern, tag) + } + + return html.replace("", ` ${tag}\n`) +} + +const replaceOrInsertTitle = (html, title) => { + const tag = `${htmlEscape(title)}` + + if (/]*>.*<\/title>/i.test(html)) { + return html.replace(/]*>.*<\/title>/i, tag) + } + + return html.replace("", ` ${tag}\n`) +} + +const replaceOrInsertCanonical = (html, href) => { + const tag = `` + const pattern = /]*rel=["']canonical["'][^>]*>/i + + if (pattern.test(html)) { + return html.replace(pattern, tag) + } + + return html.replace("", ` ${tag}\n`) +} + +const injectInviteMetadata = (indexHtml, {title, description, image, ogUrl}) => { + let html = indexHtml + + html = replaceOrInsertTitle(html, title) + html = replaceOrInsertMeta(html, "description", description, "name") + html = replaceOrInsertMeta(html, "og:title", title, "property") + html = replaceOrInsertMeta(html, "og:description", description, "property") + html = replaceOrInsertMeta(html, "og:image", image, "property") + html = replaceOrInsertMeta(html, "og:url", ogUrl, "property") + html = replaceOrInsertMeta(html, "og:type", "website", "property") + html = replaceOrInsertMeta(html, "twitter:card", "summary_large_image", "name") + html = replaceOrInsertMeta(html, "twitter:title", title, "name") + html = replaceOrInsertMeta(html, "twitter:description", description, "name") + html = replaceOrInsertMeta(html, "twitter:image", image, "name") + html = replaceOrInsertCanonical(html, ogUrl) + + return html +} + +const loadIndexTemplate = async () => { + try { + return await fs.readFile(INDEX_HTML_PATH, "utf-8") + } catch { + return [ + "", + '', + "", + ' ', + ' ', + "", + "", + "
", + "", + "", + ].join("\n") + } +} + +const getSpaceMetadata = async (r, c) => { + const relay = String(r || "").trim() + const claim = String(c || "").trim() + + let name = "Space Name" + + if (relay && claim) { + name = `Space (${claim})` + } else if (claim) { + name = `Space (${claim})` + } else if (relay) { + name = `Space (${relay})` + } + + return { + name, + icon: null, + } +} + +const send = (res, statusCode, body, contentType = "text/plain; charset=utf-8") => { + res.writeHead(statusCode, { + "Content-Type": contentType, + "Cache-Control": "no-store", + }) + res.end(body) +} + +const redirect = (res, location, statusCode = 302) => { + res.writeHead(statusCode, { + Location: location, + "Cache-Control": "no-store", + }) + res.end() +} + +const fileExists = async filePath => { + try { + const stat = await fs.stat(filePath) + + return stat.isFile() + } catch { + return false + } +} + +const serveIndexOrFallback = async res => { + if (await fileExists(INDEX_HTML_PATH)) { + await serveFile(res, INDEX_HTML_PATH) + return + } + + const fallbackHtml = await loadIndexTemplate() + send(res, 200, fallbackHtml, "text/html; charset=utf-8") +} + +const serveFile = async (res, filePath) => { + try { + const data = await fs.readFile(filePath) + const ext = path.extname(filePath).toLowerCase() + const contentType = MIME_TYPES[ext] || "application/octet-stream" + + res.writeHead(200, { + "Content-Type": contentType, + "Cache-Control": ext === ".html" ? "no-cache" : "public, max-age=31536000, immutable", + }) + res.end(data) + } catch { + send(res, 404, "Not Found") + } +} + +const sanitizeRequestedPath = pathname => { + const safePath = path.normalize(pathname).replace(/^\.+\//, "") + const candidatePath = path.join(BUILD_DIR, safePath) + + if (!candidatePath.startsWith(BUILD_DIR)) { + return null + } + + return candidatePath +} + +const server = http.createServer(async (req, res) => { + try { + const method = req.method || "GET" + + if (!["GET", "HEAD"].includes(method)) { + send(res, 405, "Method Not Allowed") + return + } + + const requestUrl = getAbsoluteUrl(req) + const pathname = decodeURIComponent(requestUrl.pathname) + + if (pathname.startsWith("/join")) { + const url = getLocalRequestUrl(req) + const r = url.searchParams.get("r") + const c = url.searchParams.get("c") + const space = await getSpaceMetadata(r, c) + const spaceName = space?.name || "Space Name" + const title = `Invitation to ${spaceName} • Flotilla` + const description = `Join ${spaceName} on Flotilla - a Nostr community space` + const image = toAbsoluteImageUrl(space?.icon || DEFAULT_IMAGE_PATH, requestUrl.origin) + const indexHtml = await loadIndexTemplate() + const ogHtml = injectInviteMetadata(indexHtml, { + title, + description, + image, + ogUrl: requestUrl.toString(), + }) + + if (isBotRequest(req)) { + send(res, 200, ogHtml, "text/html; charset=utf-8") + return + } + + await serveIndexOrFallback(res) + return + } + + const directFilePath = sanitizeRequestedPath(pathname) + + if (!directFilePath) { + send(res, 400, "Bad Request") + return + } + + const stat = await fs.stat(directFilePath).catch(() => null) + + if (stat?.isFile()) { + await serveFile(res, directFilePath) + return + } + + await serveIndexOrFallback(res) + } catch { + send(res, 500, "Internal Server Error") + } +}) + +server.listen(PORT, () => { + console.log(`Flotilla server running on port ${PORT}`) +}) From 49476a414b8d261f085022d8a444ee7883bcb1d7 Mon Sep 17 00:00:00 2001 From: Priyanshu Bharti Date: Fri, 17 Apr 2026 17:44:40 +0000 Subject: [PATCH 2/9] Update server.js --- server.js | 426 +++++++++++++++++++++++++++++++++++++++++++++++++++++ server.mjs | 379 ----------------------------------------------- 2 files changed, 426 insertions(+), 379 deletions(-) create mode 100644 server.js delete mode 100644 server.mjs diff --git a/server.js b/server.js new file mode 100644 index 00000000..d0fa51b7 --- /dev/null +++ b/server.js @@ -0,0 +1,426 @@ +import {createServer} from "node:http" +import {createReadStream} from "node:fs" +import {readFile, stat} from "node:fs/promises" +import {dirname, extname, join, normalize} from "node:path" +import {fileURLToPath} from "node:url" + +const __dirname = dirname(fileURLToPath(import.meta.url)) +const buildDir = join(__dirname, "build") +const indexPath = join(buildDir, "index.html") +const indexHtml = await readFile(indexPath, "utf8").catch(error => { + console.error("Unable to start server: build/index.html is missing. Run `pnpm run build` first.") + + throw error +}) + +const defaults = { + title: readMetaContent(indexHtml, "og:title") || "Flotilla", + description: + readMetaContent(indexHtml, "og:description") || + readMetaContent(indexHtml, "description") || + "Flotilla is nostr - for communities.", + url: readMetaContent(indexHtml, "og:url") || "", + image: readMetaContent(indexHtml, "twitter:image") || "/maskable-icon-512x512.png", +} + +const relayInfoCache = new Map() +const RELAY_CACHE_TTL_MS = 5 * 60 * 1000 +const RELAY_TIMEOUT_MS = 1500 + +const MIME_TYPES = { + ".css": "text/css; charset=utf-8", + ".gif": "image/gif", + ".html": "text/html; charset=utf-8", + ".ico": "image/x-icon", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".js": "text/javascript; charset=utf-8", + ".json": "application/json; charset=utf-8", + ".map": "application/json; charset=utf-8", + ".mjs": "text/javascript; charset=utf-8", + ".png": "image/png", + ".svg": "image/svg+xml", + ".txt": "text/plain; charset=utf-8", + ".webmanifest": "application/manifest+json; charset=utf-8", + ".woff": "font/woff", + ".woff2": "font/woff2", +} + +const server = createServer(async (req, res) => { + try { + const method = req.method || "GET" + + if (method !== "GET" && method !== "HEAD") { + res.writeHead(405, {Allow: "GET, HEAD"}) + res.end() + + return + } + + const origin = getRequestOrigin(req) + const requestUrl = new URL(req.url || "/", origin) + const headOnly = method === "HEAD" + + if (requestUrl.pathname === "/healthz") { + sendText(res, "ok", "text/plain; charset=utf-8", headOnly) + + return + } + + if (isJoinInvitePath(requestUrl.pathname)) { + const html = await renderInvitePage(requestUrl, origin) + sendText(res, html, "text/html; charset=utf-8", headOnly) + + return + } + + const filePath = resolveStaticPath(requestUrl.pathname) + + if (filePath) { + try { + const fileInfo = await stat(filePath) + + if (fileInfo.isFile()) { + sendFile(res, filePath, headOnly) + + return + } + } catch { + // Fall through to SPA index fallback. + } + } + + sendText(res, indexHtml, "text/html; charset=utf-8", headOnly) + } catch { + res.writeHead(500, {"Content-Type": "text/plain; charset=utf-8"}) + res.end("Internal Server Error") + } +}) + +const port = Number.parseInt(process.env.PORT || "3000", 10) +const host = process.env.HOST || "0.0.0.0" + +server.listen(port, host, () => { + console.log(`Flotilla server listening on http://${host}:${port}`) +}) + +function resolveStaticPath(pathname) { + const decodedPath = decodeURIComponent(pathname) + + if (decodedPath.includes("\0")) { + return undefined + } + + const relativePath = decodedPath.replace(/^\/+/, "") + const normalizedPath = normalize(relativePath) + + if (normalizedPath.startsWith("..")) { + return undefined + } + + return join(buildDir, normalizedPath) +} + +function sendText(res, body, contentType, headOnly) { + res.writeHead(200, { + "Cache-Control": contentType.includes("text/html") ? "no-cache" : "public, max-age=60", + "Content-Type": contentType, + }) + + if (headOnly) { + res.end() + + return + } + + res.end(body) +} + +function sendFile(res, filePath, headOnly) { + const extension = extname(filePath).toLowerCase() + + res.writeHead(200, { + "Cache-Control": extension === ".html" ? "no-cache" : "public, max-age=31536000, immutable", + "Content-Type": MIME_TYPES[extension] || "application/octet-stream", + }) + + if (headOnly) { + res.end() + + return + } + + const stream = createReadStream(filePath) + + stream.on("error", () => { + if (!res.headersSent) { + res.writeHead(500, {"Content-Type": "text/plain; charset=utf-8"}) + res.end("Internal Server Error") + + return + } + + res.destroy() + }) + + stream.pipe(res) +} + +function isJoinInvitePath(pathname) { + return pathname === "/join" || pathname === "/join/" +} + +async function renderInvitePage(requestUrl, origin) { + const relayUrl = parseInviteRelay(requestUrl) + + if (!relayUrl) { + return indexHtml + } + + const relayInfo = await loadRelayInfo(relayUrl) + const relayDisplay = getRelayDisplay(relayUrl) + const platformName = defaults.title + const image = toAbsoluteHttpUrl(defaults.image, origin) || `${origin}/maskable-icon-512x512.png` + + const title = relayInfo?.name + ? `Invitation to join ${relayInfo.name} on ${platformName}` + : `Invitation to join a ${platformName} space` + + const description = relayInfo?.description || `Join this ${platformName} space on ${relayDisplay}.` + + const meta = { + card: "summary", + description, + image, + site: defaults.url || origin, + title, + type: "website", + url: requestUrl.href, + } + + return setInviteMeta(indexHtml, meta) +} + +function parseInviteRelay(requestUrl) { + const relay = requestUrl.searchParams.get("r") || requestUrl.searchParams.get("relay") + + if (!relay) { + return undefined + } + + return normalizeInviteRelay(relay) +} + +function normalizeInviteRelay(value) { + const trimmed = value.trim() + + if (!trimmed) { + return undefined + } + + const hasProtocol = /^[a-zA-Z][a-zA-Z\d+.-]*:\/\//.test(trimmed) + const normalized = hasProtocol ? trimmed : `wss://${trimmed}` + + try { + const relayUrl = new URL(normalized) + + if (relayUrl.protocol === "http:") { + relayUrl.protocol = "ws:" + } + + if (relayUrl.protocol === "https:") { + relayUrl.protocol = "wss:" + } + + if (!["ws:", "wss:"].includes(relayUrl.protocol)) { + return undefined + } + + relayUrl.hash = "" + relayUrl.search = "" + + return relayUrl.href.replace(/\/$/, "") + } catch { + return undefined + } +} + +async function loadRelayInfo(relayUrl) { + const now = Date.now() + const cached = relayInfoCache.get(relayUrl) + + if (cached && cached.expiresAt > now) { + return cached.value + } + + const relayHttpUrl = toRelayHttpUrl(relayUrl) + + if (!relayHttpUrl) { + return undefined + } + + const controller = new AbortController() + const timeout = setTimeout(() => controller.abort(), RELAY_TIMEOUT_MS) + + let relayInfo + + try { + const response = await fetch(relayHttpUrl, { + headers: {Accept: "application/nostr+json"}, + signal: controller.signal, + }) + + if (response.ok) { + const json = await response.json() + + const name = typeof json.name === "string" ? json.name.trim() : "" + const description = typeof json.description === "string" ? json.description.trim() : "" + const icon = typeof json.icon === "string" ? toAbsoluteHttpUrl(json.icon, relayHttpUrl) : undefined + + relayInfo = { + description: description || undefined, + icon, + name: name || undefined, + } + } + } catch { + relayInfo = undefined + } finally { + clearTimeout(timeout) + } + + relayInfoCache.set(relayUrl, { + expiresAt: now + RELAY_CACHE_TTL_MS, + value: relayInfo, + }) + + return relayInfo +} + +function toRelayHttpUrl(relayUrl) { + if (relayUrl.startsWith("wss://")) { + return `https://${relayUrl.slice(6)}` + } + + if (relayUrl.startsWith("ws://")) { + return `http://${relayUrl.slice(5)}` + } + + return undefined +} + +function getRelayDisplay(relayUrl) { + const relayHttpUrl = toRelayHttpUrl(relayUrl) + + if (!relayHttpUrl) { + return relayUrl + } + + try { + return new URL(relayHttpUrl).host + } catch { + return relayUrl + } +} + +function toAbsoluteHttpUrl(value, baseUrl) { + try { + const parsed = new URL(value, baseUrl) + + if (["http:", "https:"].includes(parsed.protocol)) { + return parsed.href + } + + return undefined + } catch { + return undefined + } +} + +function setInviteMeta(html, meta) { + let result = html + + result = upsertMetaTag(result, "name", "description", meta.description) + result = upsertMetaTag(result, "name", "og:url", meta.url) + result = upsertMetaTag(result, "name", "og:type", meta.type) + result = upsertMetaTag(result, "name", "og:title", meta.title) + result = upsertMetaTag(result, "name", "og:description", meta.description) + result = upsertMetaTag(result, "name", "twitter:card", meta.card) + result = upsertMetaTag(result, "name", "twitter:site", meta.site) + result = upsertMetaTag(result, "name", "twitter:title", meta.title) + result = upsertMetaTag(result, "name", "twitter:description", meta.description) + result = upsertMetaTag(result, "name", "twitter:image", meta.image) + + result = upsertMetaTag(result, "property", "og:url", meta.url) + result = upsertMetaTag(result, "property", "og:type", meta.type) + result = upsertMetaTag(result, "property", "og:title", meta.title) + result = upsertMetaTag(result, "property", "og:description", meta.description) + result = upsertMetaTag(result, "property", "og:image", meta.image) + + return result +} + +function upsertMetaTag(html, attribute, key, value) { + const escapedKey = escapeRegExp(key) + const escapedValue = escapeHtml(value) + const pattern = new RegExp( + `(]*${attribute}=["']${escapedKey}["'][^>]*content=["'])[^"']*(["'][^>]*>)`, + "i", + ) + + if (pattern.test(html)) { + return html.replace(pattern, `$1${escapedValue}$2`) + } + + return html.replace( + "", + ` \n `, + ) +} + +function readMetaContent(html, key) { + const escapedKey = escapeRegExp(key) + const pattern = new RegExp( + `]*(?:name|property)=["']${escapedKey}["'][^>]*content=["']([^"']*)["'][^>]*>`, + "i", + ) + + const match = html.match(pattern) + + return match ? match[1] : undefined +} + +function getRequestOrigin(req) { + const forwardedProto = req.headers["x-forwarded-proto"] + const forwardedHost = req.headers["x-forwarded-host"] + + const protocol = firstHeaderValue(forwardedProto) || "http" + const host = firstHeaderValue(forwardedHost) || req.headers.host || "localhost" + + return `${protocol}://${host}` +} + +function firstHeaderValue(value) { + if (Array.isArray(value)) { + return value[0]?.split(",")[0]?.trim() + } + + if (typeof value === "string") { + return value.split(",")[0].trim() + } + + return undefined +} + +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") +} + +function escapeHtml(value) { + return String(value) + .replaceAll("&", "&") + .replaceAll("\"", """) + .replaceAll("'", "'") + .replaceAll("<", "<") + .replaceAll(">", ">") +} diff --git a/server.mjs b/server.mjs deleted file mode 100644 index 0612614f..00000000 --- a/server.mjs +++ /dev/null @@ -1,379 +0,0 @@ -import http from "node:http" -import path from "node:path" -import {promises as fs} from "node:fs" - -const PORT = Number(process.env.PORT || 3000) -const BUILD_DIR = path.resolve("build") -const INDEX_HTML_PATH = path.join(BUILD_DIR, "index.html") -const DEFAULT_IMAGE_PATH = "/maskable-icon-512x512.png" -const CACHE_SECONDS = 60 - -const MIME_TYPES = { - ".html": "text/html; charset=utf-8", - ".js": "application/javascript; charset=utf-8", - ".css": "text/css; charset=utf-8", - ".json": "application/json; charset=utf-8", - ".svg": "image/svg+xml", - ".png": "image/png", - ".jpg": "image/jpeg", - ".jpeg": "image/jpeg", - ".webp": "image/webp", - ".gif": "image/gif", - ".ico": "image/x-icon", - ".txt": "text/plain; charset=utf-8", - ".map": "application/json; charset=utf-8", - ".woff": "font/woff", - ".woff2": "font/woff2", -} - -const BOT_UA_REGEX = - /bot|crawler|spider|slackbot|telegrambot|twitterbot|facebookexternalhit|discordbot|linkedinbot|whatsapp|skypeuripreview|applebot|googlebot/i - -const relayMetadataCache = new Map() - -const htmlEscape = value => - String(value) - .replaceAll("&", "&") - .replaceAll("<", "<") - .replaceAll(">", ">") - .replaceAll('"', """) - .replaceAll("'", "'") - -const isBotRequest = req => BOT_UA_REGEX.test(String(req.headers["user-agent"] || "")) - -const relayToHttpUrl = relay => { - try { - const url = new URL(relay) - - if (url.protocol === "wss:") { - url.protocol = "https:" - } else if (url.protocol === "ws:") { - url.protocol = "http:" - } - - return url.toString() - } catch { - return null - } -} - -const normalizeRelayParam = relayParam => { - const relay = String(relayParam || "").trim() - - if (!relay) { - return null - } - - try { - const parsed = new URL(relay.includes("://") ? relay : `wss://${relay}`) - - if (!["ws:", "wss:", "http:", "https:"].includes(parsed.protocol)) { - return null - } - - if (parsed.protocol === "http:") { - parsed.protocol = "ws:" - } - - if (parsed.protocol === "https:") { - parsed.protocol = "wss:" - } - - return parsed.toString() - } catch { - return null - } -} - -const fetchJsonWithTimeout = async (url, timeoutMs = 5000) => { - const controller = new AbortController() - const timeout = setTimeout(() => controller.abort(), timeoutMs) - - try { - const response = await fetch(url, { - method: "GET", - headers: {Accept: "application/nostr+json, application/json"}, - signal: controller.signal, - }) - - if (!response.ok) { - return null - } - - return await response.json() - } catch { - return null - } finally { - clearTimeout(timeout) - } -} - -const getRelayMetadata = async relayUrl => { - if (!relayUrl) { - return null - } - - const now = Date.now() - const cached = relayMetadataCache.get(relayUrl) - - if (cached && now - cached.at < CACHE_SECONDS * 1000) { - return cached.value - } - - const httpUrl = relayToHttpUrl(relayUrl) - - if (!httpUrl) { - return null - } - - const profile = await fetchJsonWithTimeout(httpUrl) - - const value = { - name: profile?.name || profile?.title || null, - icon: profile?.icon || profile?.picture || null, - } - - relayMetadataCache.set(relayUrl, {at: now, value}) - - return value -} - -const getAbsoluteUrl = req => { - const host = req.headers["x-forwarded-host"] || req.headers.host || `localhost:${PORT}` - const protocolHeader = req.headers["x-forwarded-proto"] - const protocol = String(protocolHeader || "").split(",")[0] || "http" - - return new URL(req.url || "/", `${protocol}://${host}`) -} - -const getLocalRequestUrl = req => { - const host = req.headers.host || `localhost:${PORT}` - - return new URL(req.url || "/", `http://${host}`) -} - -const toAbsoluteImageUrl = (url, origin) => { - try { - return new URL(url, origin).toString() - } catch { - return new URL(DEFAULT_IMAGE_PATH, origin).toString() - } -} - -const escapeRegex = value => String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&") - -const replaceOrInsertMeta = (html, keyValue, content, preferredKey = "name") => { - const escapedValue = escapeRegex(keyValue) - const tag = `` - const pattern = new RegExp(`]*(?:name|property)=["']${escapedValue}["'][^>]*>`, "i") - - if (pattern.test(html)) { - return html.replace(pattern, tag) - } - - return html.replace("", ` ${tag}\n`) -} - -const replaceOrInsertTitle = (html, title) => { - const tag = `${htmlEscape(title)}` - - if (/]*>.*<\/title>/i.test(html)) { - return html.replace(/]*>.*<\/title>/i, tag) - } - - return html.replace("", ` ${tag}\n`) -} - -const replaceOrInsertCanonical = (html, href) => { - const tag = `` - const pattern = /]*rel=["']canonical["'][^>]*>/i - - if (pattern.test(html)) { - return html.replace(pattern, tag) - } - - return html.replace("", ` ${tag}\n`) -} - -const injectInviteMetadata = (indexHtml, {title, description, image, ogUrl}) => { - let html = indexHtml - - html = replaceOrInsertTitle(html, title) - html = replaceOrInsertMeta(html, "description", description, "name") - html = replaceOrInsertMeta(html, "og:title", title, "property") - html = replaceOrInsertMeta(html, "og:description", description, "property") - html = replaceOrInsertMeta(html, "og:image", image, "property") - html = replaceOrInsertMeta(html, "og:url", ogUrl, "property") - html = replaceOrInsertMeta(html, "og:type", "website", "property") - html = replaceOrInsertMeta(html, "twitter:card", "summary_large_image", "name") - html = replaceOrInsertMeta(html, "twitter:title", title, "name") - html = replaceOrInsertMeta(html, "twitter:description", description, "name") - html = replaceOrInsertMeta(html, "twitter:image", image, "name") - html = replaceOrInsertCanonical(html, ogUrl) - - return html -} - -const loadIndexTemplate = async () => { - try { - return await fs.readFile(INDEX_HTML_PATH, "utf-8") - } catch { - return [ - "", - '', - "", - ' ', - ' ', - "", - "", - "
", - "", - "", - ].join("\n") - } -} - -const getSpaceMetadata = async (r, c) => { - const relay = String(r || "").trim() - const claim = String(c || "").trim() - - let name = "Space Name" - - if (relay && claim) { - name = `Space (${claim})` - } else if (claim) { - name = `Space (${claim})` - } else if (relay) { - name = `Space (${relay})` - } - - return { - name, - icon: null, - } -} - -const send = (res, statusCode, body, contentType = "text/plain; charset=utf-8") => { - res.writeHead(statusCode, { - "Content-Type": contentType, - "Cache-Control": "no-store", - }) - res.end(body) -} - -const redirect = (res, location, statusCode = 302) => { - res.writeHead(statusCode, { - Location: location, - "Cache-Control": "no-store", - }) - res.end() -} - -const fileExists = async filePath => { - try { - const stat = await fs.stat(filePath) - - return stat.isFile() - } catch { - return false - } -} - -const serveIndexOrFallback = async res => { - if (await fileExists(INDEX_HTML_PATH)) { - await serveFile(res, INDEX_HTML_PATH) - return - } - - const fallbackHtml = await loadIndexTemplate() - send(res, 200, fallbackHtml, "text/html; charset=utf-8") -} - -const serveFile = async (res, filePath) => { - try { - const data = await fs.readFile(filePath) - const ext = path.extname(filePath).toLowerCase() - const contentType = MIME_TYPES[ext] || "application/octet-stream" - - res.writeHead(200, { - "Content-Type": contentType, - "Cache-Control": ext === ".html" ? "no-cache" : "public, max-age=31536000, immutable", - }) - res.end(data) - } catch { - send(res, 404, "Not Found") - } -} - -const sanitizeRequestedPath = pathname => { - const safePath = path.normalize(pathname).replace(/^\.+\//, "") - const candidatePath = path.join(BUILD_DIR, safePath) - - if (!candidatePath.startsWith(BUILD_DIR)) { - return null - } - - return candidatePath -} - -const server = http.createServer(async (req, res) => { - try { - const method = req.method || "GET" - - if (!["GET", "HEAD"].includes(method)) { - send(res, 405, "Method Not Allowed") - return - } - - const requestUrl = getAbsoluteUrl(req) - const pathname = decodeURIComponent(requestUrl.pathname) - - if (pathname.startsWith("/join")) { - const url = getLocalRequestUrl(req) - const r = url.searchParams.get("r") - const c = url.searchParams.get("c") - const space = await getSpaceMetadata(r, c) - const spaceName = space?.name || "Space Name" - const title = `Invitation to ${spaceName} • Flotilla` - const description = `Join ${spaceName} on Flotilla - a Nostr community space` - const image = toAbsoluteImageUrl(space?.icon || DEFAULT_IMAGE_PATH, requestUrl.origin) - const indexHtml = await loadIndexTemplate() - const ogHtml = injectInviteMetadata(indexHtml, { - title, - description, - image, - ogUrl: requestUrl.toString(), - }) - - if (isBotRequest(req)) { - send(res, 200, ogHtml, "text/html; charset=utf-8") - return - } - - await serveIndexOrFallback(res) - return - } - - const directFilePath = sanitizeRequestedPath(pathname) - - if (!directFilePath) { - send(res, 400, "Bad Request") - return - } - - const stat = await fs.stat(directFilePath).catch(() => null) - - if (stat?.isFile()) { - await serveFile(res, directFilePath) - return - } - - await serveIndexOrFallback(res) - } catch { - send(res, 500, "Internal Server Error") - } -}) - -server.listen(PORT, () => { - console.log(`Flotilla server running on port ${PORT}`) -}) From aca6973c424b16b3064e5d1163a9b55925eb07ba Mon Sep 17 00:00:00 2001 From: Priyanshu Bharti Date: Fri, 17 Apr 2026 17:45:23 +0000 Subject: [PATCH 3/9] Update Dockerfile --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 013e7632..dab7be50 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,6 +28,6 @@ WORKDIR /app # Copy only the built output - no source, no .env, no dev deps COPY --from=builder /app/build ./build -COPY --from=builder /app/server.mjs ./server.mjs +COPY --from=builder /app/server.js ./server.js -CMD ["node", "server.mjs"] +CMD ["node", "server.js"] From 46364cf4baf63d07f1acc695ed6b94fcfbba9c94 Mon Sep 17 00:00:00 2001 From: Priyanshu Bharti Date: Fri, 17 Apr 2026 17:45:50 +0000 Subject: [PATCH 4/9] Update package.json --- package.json | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index ae3489ad..1aaf908c 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "flotilla", - "version": "1.7.2", + "version": "1.7.4", "private": true, "scripts": { "dev": "vite dev", + "start": "node server.js", "build": "./build.sh", - "start": "node server.mjs", "release:android": "./build.sh && cap build android --androidreleasetype APK --signing-type apksigner", "tauri:dev": "tauri dev", "tauri:build": "tauri build", @@ -23,6 +23,7 @@ "@eslint/js": "^9.39.2", "@sveltejs/kit": "^2.50.1", "@sveltejs/vite-plugin-svelte": "^4.0.4", + "@tailwindcss/postcss": "^4.2.2", "@tauri-apps/cli": "^2.9.6", "@types/eslint": "^9.6.1", "autoprefixer": "^10.4.23", @@ -36,7 +37,7 @@ "prettier-plugin-svelte": "^3.4.1", "svelte": "^5.48.0", "svelte-check": "^4.3.5", - "tailwindcss": "^3.4.19", + "tailwindcss": "^4.2.2", "typescript": "^5.9.3", "typescript-eslint": "^8.53.1", "vite": "^5.4.21" @@ -48,37 +49,40 @@ "@capacitor/android": "^8.0.1", "@capacitor/app": "^8.0.0", "@capacitor/cli": "^8.0.1", + "@capacitor/clipboard": "^8.0.1", "@capacitor/core": "^8.0.1", "@capacitor/filesystem": "^8.1.0", "@capacitor/ios": "^8.0.1", "@capacitor/keyboard": "^8.0.0", "@capacitor/preferences": "^8.0.0", "@capacitor/push-notifications": "^8.0.0", + "@capacitor/share": "^8.0.1", "@capawesome/capacitor-android-dark-mode-support": "^8.0.0", "@capawesome/capacitor-badge": "^8.0.0", "@getalby/lightning-tools": "^6.1.0", "@getalby/sdk": "^5.1.2", "@noble/curves": "^1.9.7", - "@pomade/core": "^0.2.2", + "@pomade/core": "^0.2.3", "@poppanator/sveltekit-svg": "^4.2.1", "@sveltejs/adapter-static": "^3.0.10", "@tiptap/core": "^2.27.2", + "@tiptap/pm": "^2.27.2", "@types/qrcode": "^1.5.6", "@types/throttle-debounce": "^5.0.2", "@vite-pwa/assets-generator": "^0.2.6", "@vite-pwa/sveltekit": "^0.6.8", - "@welshman/app": "^0.8.12", - "@welshman/content": "^0.8.12", - "@welshman/editor": "^0.8.12", - "@welshman/feeds": "^0.8.12", - "@welshman/lib": "^0.8.12", - "@welshman/net": "^0.8.12", - "@welshman/router": "^0.8.12", - "@welshman/signer": "^0.8.12", - "@welshman/store": "^0.8.12", - "@welshman/util": "^0.8.12", + "@welshman/app": "^0.8.13", + "@welshman/content": "^0.8.13", + "@welshman/editor": "^0.8.13", + "@welshman/feeds": "^0.8.13", + "@welshman/lib": "^0.8.13", + "@welshman/net": "^0.8.13", + "@welshman/router": "^0.8.13", + "@welshman/signer": "^0.8.13", + "@welshman/store": "^0.8.13", + "@welshman/util": "^0.8.13", "compressorjs-next": "^1.1.2", - "daisyui": "^4.12.24", + "daisyui": "^5.5.19", "date-picker-svelte": "^2.17.0", "dotenv": "^16.6.1", "emoji-picker-element": "^1.28.1", @@ -88,7 +92,7 @@ "livekit-client": "^2.17.2", "nostr-signer-capacitor-plugin": "github:coracle-social/nostr-signer-capacitor-plugin#main", "nostr-tools": "^2.19.4", - "prettier-plugin-tailwindcss": "^0.6.14", + "prettier-plugin-tailwindcss": "^0.7.2", "qr-scanner": "^1.4.2", "qrcode": "^1.5.4", "throttle-debounce": "^5.0.2", @@ -105,5 +109,6 @@ "overrides": { "sharp": "0.35.0-rc.0" } - } + }, + "packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319" } From b24edde6325dd776a98f5fb709214718b0744be6 Mon Sep 17 00:00:00 2001 From: Priyanshu Bharti Date: Fri, 17 Apr 2026 17:46:19 +0000 Subject: [PATCH 5/9] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8eacb8d9..2c861e7d 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ To run your own Flotilla, it's as simple as: ```sh pnpm install pnpm run build -pnpm run start +node server.js ``` Or, if you prefer to use a container: From 5eff80add25e46fca2d73deab754066a20532cd2 Mon Sep 17 00:00:00 2001 From: Priyanshu Bharti Date: Fri, 17 Apr 2026 19:53:43 +0000 Subject: [PATCH 6/9] Update Dockerfile --- Dockerfile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index dab7be50..c7f45313 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,12 +21,15 @@ ENV VITE_BUILD_HASH=${VITE_BUILD_HASH} ENV NODE_OPTIONS=--max_old_space_size=16384 RUN pnpm run build +RUN pnpm prune --prod -FROM node:20-alpine +FROM node:20-bookworm-slim WORKDIR /app -# Copy only the built output - no source, no .env, no dev deps +# Copy production runtime only +COPY --from=builder /app/package.json ./package.json +COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/build ./build COPY --from=builder /app/server.js ./server.js From 139e86263a4fd0e190f07fb5a2eccaa9622c8401 Mon Sep 17 00:00:00 2001 From: Priyanshu Bharti Date: Fri, 17 Apr 2026 19:54:10 +0000 Subject: [PATCH 7/9] Update server.js --- server.js | 937 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 648 insertions(+), 289 deletions(-) diff --git a/server.js b/server.js index d0fa51b7..427367e8 100644 --- a/server.js +++ b/server.js @@ -1,268 +1,429 @@ -import {createServer} from "node:http" -import {createReadStream} from "node:fs" -import {readFile, stat} from "node:fs/promises" -import {dirname, extname, join, normalize} from "node:path" +// @ts-nocheck +import {readFile} from "node:fs/promises" +import {dirname, extname, join} from "node:path" import {fileURLToPath} from "node:url" +import {load as loadHtml} from "cheerio" +import {serve} from "@hono/node-server" +import {serveStatic} from "@hono/node-server/serve-static" +import {Hono} from "hono" +import {request} from "@welshman/net" +import { + Address, + CLASSIFIED, + EVENT_TIME, + POLL, + ROOM_META, + THREAD, + ZAP_GOAL, + displayPubkey, + getTagValue, + normalizeRelayUrl, + readRoomMeta, +} from "@welshman/util" const __dirname = dirname(fileURLToPath(import.meta.url)) const buildDir = join(__dirname, "build") const indexPath = join(buildDir, "index.html") + +const RELAY_CACHE_TTL_MS = 5 * 60 * 1000 +const NOSTR_CACHE_TTL_MS = 60 * 1000 +const RELAY_TIMEOUT_MS = 1500 +const NOSTR_TIMEOUT_MS = 1800 + +const staticTitles = new Map([ + ["/", "Redirecting"], + ["/home", "Home"], + ["/spaces", "Spaces"], + ["/spaces/create", "Create a Space"], + ["/chat", "Messages"], + ["/join", "Join Space"], + ["/people", "Find People"], + ["/settings/about", "About"], + ["/settings/profile", "Profile Settings"], + ["/settings/content", "Content Settings"], + ["/settings/privacy", "Privacy Settings"], + ["/settings/relays", "Relay Settings"], + ["/settings/alerts", "Alert Settings"], + ["/settings/wallet", "Wallet Settings"], +]) + +const spaceSectionTitles = new Map([ + ["chat", "Space Chat"], + ["recent", "Recent Activity"], + ["threads", "Threads"], + ["classifieds", "Classifieds"], + ["calendar", "Calendar"], + ["goals", "Goals"], + ["polls", "Polls"], +]) + +const eventRouteKinds = new Map([ + ["threads", THREAD], + ["goals", ZAP_GOAL], + ["calendar", EVENT_TIME], + ["classifieds", CLASSIFIED], + ["polls", POLL], +]) + +const reservedSingleSegments = new Set([ + "home", + "spaces", + "space", + "chat", + "join", + "people", + "settings", +]) + +const relayInfoCache = new Map() +const roomInfoCache = new Map() +const eventCache = new Map() + const indexHtml = await readFile(indexPath, "utf8").catch(error => { console.error("Unable to start server: build/index.html is missing. Run `pnpm run build` first.") throw error }) -const defaults = { - title: readMetaContent(indexHtml, "og:title") || "Flotilla", - description: - readMetaContent(indexHtml, "og:description") || - readMetaContent(indexHtml, "description") || - "Flotilla is nostr - for communities.", - url: readMetaContent(indexHtml, "og:url") || "", - image: readMetaContent(indexHtml, "twitter:image") || "/maskable-icon-512x512.png", -} +const defaults = getHtmlDefaults(indexHtml) +const app = new Hono() +const staticFiles = serveStatic({ + root: "./build", + rewriteRequestPath: path => path.replace(/^\/+/, ""), +}) -const relayInfoCache = new Map() -const RELAY_CACHE_TTL_MS = 5 * 60 * 1000 -const RELAY_TIMEOUT_MS = 1500 +app.use("*", staticFiles) -const MIME_TYPES = { - ".css": "text/css; charset=utf-8", - ".gif": "image/gif", - ".html": "text/html; charset=utf-8", - ".ico": "image/x-icon", - ".jpg": "image/jpeg", - ".jpeg": "image/jpeg", - ".js": "text/javascript; charset=utf-8", - ".json": "application/json; charset=utf-8", - ".map": "application/json; charset=utf-8", - ".mjs": "text/javascript; charset=utf-8", - ".png": "image/png", - ".svg": "image/svg+xml", - ".txt": "text/plain; charset=utf-8", - ".webmanifest": "application/manifest+json; charset=utf-8", - ".woff": "font/woff", - ".woff2": "font/woff2", -} +app.get("*", async c => { + const requestUrl = new URL(c.req.url) -const server = createServer(async (req, res) => { - try { - const method = req.method || "GET" - - if (method !== "GET" && method !== "HEAD") { - res.writeHead(405, {Allow: "GET, HEAD"}) - res.end() - - return - } - - const origin = getRequestOrigin(req) - const requestUrl = new URL(req.url || "/", origin) - const headOnly = method === "HEAD" - - if (requestUrl.pathname === "/healthz") { - sendText(res, "ok", "text/plain; charset=utf-8", headOnly) - - return - } - - if (isJoinInvitePath(requestUrl.pathname)) { - const html = await renderInvitePage(requestUrl, origin) - sendText(res, html, "text/html; charset=utf-8", headOnly) - - return - } - - const filePath = resolveStaticPath(requestUrl.pathname) - - if (filePath) { - try { - const fileInfo = await stat(filePath) - - if (fileInfo.isFile()) { - sendFile(res, filePath, headOnly) - - return - } - } catch { - // Fall through to SPA index fallback. - } - } - - sendText(res, indexHtml, "text/html; charset=utf-8", headOnly) - } catch { - res.writeHead(500, {"Content-Type": "text/plain; charset=utf-8"}) - res.end("Internal Server Error") + if (extname(requestUrl.pathname)) { + return c.text("Not Found", 404) } + + const origin = getRequestOrigin(c.req.raw, requestUrl) + const meta = await buildRouteMeta(requestUrl, origin) + const html = renderHtml(indexHtml, meta) + + c.header("Cache-Control", "no-cache") + + return c.html(html) +}) + +app.notFound(c => c.text("Not Found", 404)) + +app.onError((error, c) => { + console.error(error) + + return c.text("Internal Server Error", 500) }) const port = Number.parseInt(process.env.PORT || "3000", 10) const host = process.env.HOST || "0.0.0.0" -server.listen(port, host, () => { - console.log(`Flotilla server listening on http://${host}:${port}`) -}) +serve({fetch: app.fetch, hostname: host, port}) +console.log(`Flotilla server listening on http://${host}:${port}`) -function resolveStaticPath(pathname) { - const decodedPath = decodeURIComponent(pathname) +async function buildRouteMeta(requestUrl, origin) { + const absoluteDefaultImage = toAbsoluteHttpUrl(defaults.image, origin) - if (decodedPath.includes("\0")) { - return undefined + if (!absoluteDefaultImage) { + throw new Error(`Default twitter:image must resolve to an absolute URL. Found: ${defaults.image}`) } - const relativePath = decodedPath.replace(/^\/+/, "") - const normalizedPath = normalize(relativePath) - - if (normalizedPath.startsWith("..")) { - return undefined - } - - return join(buildDir, normalizedPath) -} - -function sendText(res, body, contentType, headOnly) { - res.writeHead(200, { - "Cache-Control": contentType.includes("text/html") ? "no-cache" : "public, max-age=60", - "Content-Type": contentType, - }) - - if (headOnly) { - res.end() - - return - } - - res.end(body) -} - -function sendFile(res, filePath, headOnly) { - const extension = extname(filePath).toLowerCase() - - res.writeHead(200, { - "Cache-Control": extension === ".html" ? "no-cache" : "public, max-age=31536000, immutable", - "Content-Type": MIME_TYPES[extension] || "application/octet-stream", - }) - - if (headOnly) { - res.end() - - return - } - - const stream = createReadStream(filePath) - - stream.on("error", () => { - if (!res.headersSent) { - res.writeHead(500, {"Content-Type": "text/plain; charset=utf-8"}) - res.end("Internal Server Error") - - return - } - - res.destroy() - }) - - stream.pipe(res) -} - -function isJoinInvitePath(pathname) { - return pathname === "/join" || pathname === "/join/" -} - -async function renderInvitePage(requestUrl, origin) { - const relayUrl = parseInviteRelay(requestUrl) - - if (!relayUrl) { - return indexHtml - } - - const relayInfo = await loadRelayInfo(relayUrl) - const relayDisplay = getRelayDisplay(relayUrl) - const platformName = defaults.title - const image = toAbsoluteHttpUrl(defaults.image, origin) || `${origin}/maskable-icon-512x512.png` - - const title = relayInfo?.name - ? `Invitation to join ${relayInfo.name} on ${platformName}` - : `Invitation to join a ${platformName} space` - - const description = relayInfo?.description || `Join this ${platformName} space on ${relayDisplay}.` - const meta = { card: "summary", - description, - image, - site: defaults.url || origin, - title, + description: defaults.description, + image: absoluteDefaultImage, + site: defaults.site, + title: defaults.title, type: "website", url: requestUrl.href, } - return setInviteMeta(indexHtml, meta) + const route = parseRoute(requestUrl.pathname) + + if (route.kind === "join") { + return await buildJoinMeta(meta, requestUrl, origin) + } + + if (route.kind === "static") { + meta.title = route.title + + return meta + } + + if (route.kind === "chat") { + meta.title = getChatTitle(route.chat) + + return meta + } + + if (route.kind === "bech32") { + meta.title = "Opening Link" + + return meta + } + + if (!route.relay) { + return meta + } + + const relayUrl = normalizeRelayParam(route.relay) + const relayInfo = relayUrl ? await loadRelayInfo(relayUrl) : undefined + const relayName = relayInfo?.name || (relayUrl ? getRelayDisplay(relayUrl) : "Space") + const relayHttpUrl = relayUrl ? toRelayHttpUrl(relayUrl) : undefined + + if (relayInfo?.icon) { + meta.image = relayInfo.icon + } + + if (relayInfo?.description) { + meta.description = relayInfo.description + } + + if (route.kind === "space") { + meta.title = relayName + + return meta + } + + if (route.kind === "space-section") { + meta.title = composeSpaceTitle(relayName, route.sectionTitle) + + return meta + } + + if (route.kind === "room") { + const roomInfo = relayUrl ? await loadRoomInfo(relayUrl, route.h) : undefined + const roomName = roomInfo?.name || route.h + + meta.title = composeSpaceTitle(relayName, roomName) + meta.description = roomInfo?.about || meta.description + + const roomImage = roomInfo?.picture + ? toAbsoluteHttpUrl(roomInfo.picture, relayHttpUrl || origin) + : undefined + + if (roomImage) { + meta.image = roomImage + } + + return meta + } + + if (route.kind === "event") { + const event = relayUrl + ? await loadEventForRoute(relayUrl, route.section, route.identifier) + : undefined + const eventTitle = getEventTitle(route.section, event) + + meta.title = composeSpaceTitle(relayName, eventTitle) + meta.description = getEventDescription(route.section, event, meta.description) + + const eventImage = getTagValue("image", event?.tags || []) + const absoluteEventImage = eventImage + ? toAbsoluteHttpUrl(eventImage, relayHttpUrl || origin) + : undefined + + if (absoluteEventImage) { + meta.image = absoluteEventImage + meta.card = "summary_large_image" + } + + return meta + } + + return meta } -function parseInviteRelay(requestUrl) { - const relay = requestUrl.searchParams.get("r") || requestUrl.searchParams.get("relay") +function parseRoute(pathname) { + const normalizedPath = normalizePathname(pathname) - if (!relay) { - return undefined + if (normalizedPath === "/join") { + return {kind: "join"} } - return normalizeInviteRelay(relay) + if (staticTitles.has(normalizedPath)) { + return {kind: "static", title: staticTitles.get(normalizedPath)} + } + + const segments = getPathSegments(normalizedPath) + + if (segments.length === 2 && segments[0] === "chat") { + return {chat: segments[1], kind: "chat"} + } + + if (segments.length === 1 && !reservedSingleSegments.has(segments[0])) { + return {bech32: segments[0], kind: "bech32"} + } + + if ((segments[0] === "spaces" || segments[0] === "space") && segments.length >= 2) { + const relay = segments[1] + + if (segments.length === 2) { + return {kind: "space", relay} + } + + const section = segments[2] + + if (segments.length === 3) { + if (spaceSectionTitles.has(section)) { + return { + kind: "space-section", + relay, + section, + sectionTitle: spaceSectionTitles.get(section), + } + } + + return {h: section, kind: "room", relay} + } + + if (segments.length === 4 && eventRouteKinds.has(section)) { + return { + identifier: segments[3], + kind: "event", + relay, + section, + } + } + } + + return {kind: "unknown"} } -function normalizeInviteRelay(value) { - const trimmed = value.trim() +async function buildJoinMeta(meta, requestUrl, origin) { + const relayUrl = parseInviteRelay(requestUrl) - if (!trimmed) { - return undefined + if (!relayUrl) { + meta.title = staticTitles.get("/join") || "Join Space" + + return meta } - const hasProtocol = /^[a-zA-Z][a-zA-Z\d+.-]*:\/\//.test(trimmed) - const normalized = hasProtocol ? trimmed : `wss://${trimmed}` + const relayInfo = await loadRelayInfo(relayUrl) + const relayDisplay = relayInfo?.name || getRelayDisplay(relayUrl) - try { - const relayUrl = new URL(normalized) + meta.title = `Invitation to join ${relayDisplay}` + meta.description = relayInfo?.description || `Join this Flotilla space on ${relayDisplay}.` + meta.image = relayInfo?.icon || meta.image + meta.url = requestUrl.href + meta.site = defaults.site - if (relayUrl.protocol === "http:") { - relayUrl.protocol = "ws:" - } + return meta +} - if (relayUrl.protocol === "https:") { - relayUrl.protocol = "wss:" - } - - if (!["ws:", "wss:"].includes(relayUrl.protocol)) { - return undefined - } - - relayUrl.hash = "" - relayUrl.search = "" - - return relayUrl.href.replace(/\/$/, "") - } catch { - return undefined +function getChatTitle(chat) { + if (!chat) { + return "Chat" } + + const peers = chat + .split(",") + .map(part => part.trim()) + .filter(Boolean) + + if (peers.length === 1) { + return `Chat with ${displayPubkey(peers[0])}` + } + + if (peers.length > 1) { + return `Group chat (${peers.length})` + } + + return "Chat" +} + +function getEventTitle(section, event) { + if (section === "threads") { + return getTagValue("title", event?.tags || []) || "Thread" + } + + if (section === "calendar") { + return getTagValue("title", event?.tags || []) || "Event" + } + + if (section === "classifieds") { + return getTagValue("title", event?.tags || []) || "Listing" + } + + if (section === "goals") { + return event?.content?.trim() || getTagValue("summary", event?.tags || []) || "Goal" + } + + if (section === "polls") { + return getTagValue("title", event?.tags || []) || "Poll" + } + + return "Event" +} + +function getEventDescription(section, event, fallback) { + const summary = + getTagValue("summary", event?.tags || []) || getTagValue("description", event?.tags || []) + + if (summary) { + return clip(summary, 220) + } + + if (event?.content?.trim()) { + return clip(event.content.trim(), 220) + } + + if (section === "threads") { + return "Read this thread in Flotilla." + } + + if (section === "goals") { + return "Track this goal in Flotilla." + } + + if (section === "calendar") { + return "View this calendar event in Flotilla." + } + + if (section === "classifieds") { + return "Browse this listing in Flotilla." + } + + if (section === "polls") { + return "Take this poll in Flotilla." + } + + return fallback +} + +function composeSpaceTitle(spaceName, leafTitle) { + const cleanedSpace = spaceName?.trim() + const cleanedLeaf = leafTitle?.trim() + + if (cleanedSpace && cleanedLeaf) { + return `${cleanedSpace} / ${cleanedLeaf}` + } + + return cleanedLeaf || cleanedSpace || defaults.title } async function loadRelayInfo(relayUrl) { - const now = Date.now() - const cached = relayInfoCache.get(relayUrl) + const cached = getCachedValue(relayInfoCache, relayUrl) - if (cached && cached.expiresAt > now) { - return cached.value + if (cached) { + return cached } const relayHttpUrl = toRelayHttpUrl(relayUrl) if (!relayHttpUrl) { + setCachedValue(relayInfoCache, relayUrl, undefined, RELAY_CACHE_TTL_MS) + return undefined } const controller = new AbortController() const timeout = setTimeout(() => controller.abort(), RELAY_TIMEOUT_MS) - let relayInfo + let value try { const response = await fetch(relayHttpUrl, { @@ -272,29 +433,237 @@ async function loadRelayInfo(relayUrl) { if (response.ok) { const json = await response.json() - const name = typeof json.name === "string" ? json.name.trim() : "" const description = typeof json.description === "string" ? json.description.trim() : "" const icon = typeof json.icon === "string" ? toAbsoluteHttpUrl(json.icon, relayHttpUrl) : undefined - relayInfo = { + value = { description: description || undefined, icon, name: name || undefined, } } } catch { - relayInfo = undefined + value = undefined } finally { clearTimeout(timeout) } - relayInfoCache.set(relayUrl, { - expiresAt: now + RELAY_CACHE_TTL_MS, - value: relayInfo, - }) + setCachedValue(relayInfoCache, relayUrl, value, RELAY_CACHE_TTL_MS) - return relayInfo + return value +} + +async function loadRoomInfo(relayUrl, h) { + const cacheKey = `${relayUrl}|${h}` + const cached = getCachedValue(roomInfoCache, cacheKey) + + if (cached !== undefined) { + return cached + } + + const events = await requestEvents(relayUrl, [{"#d": [h], kinds: [ROOM_META], limit: 20}]) + const roomMetas = [] + + for (const event of events) { + try { + const roomMeta = readRoomMeta(event) + + if (roomMeta.h === h) { + roomMetas.push(roomMeta) + } + } catch { + // Ignore malformed room metadata. + } + } + + const latest = roomMetas.sort((a, b) => b.event.created_at - a.event.created_at)[0] + const roomInfo = latest + ? { + about: latest.about, + name: latest.name, + picture: latest.picture, + } + : undefined + + setCachedValue(roomInfoCache, cacheKey, roomInfo, NOSTR_CACHE_TTL_MS) + + return roomInfo +} + +async function loadEventForRoute(relayUrl, section, identifier) { + const kind = eventRouteKinds.get(section) + + if (!kind || !identifier) { + return undefined + } + + const cacheKey = `${relayUrl}|${section}|${identifier}` + const cached = getCachedValue(eventCache, cacheKey) + + if (cached !== undefined) { + return cached + } + + const filters = getEventFilters(kind, identifier) + const events = filters.length > 0 ? await requestEvents(relayUrl, filters) : [] + const event = events[0] + + setCachedValue(eventCache, cacheKey, event, NOSTR_CACHE_TTL_MS) + + return event +} + +function getEventFilters(kind, identifier) { + if (kind === EVENT_TIME || kind === CLASSIFIED) { + try { + const address = Address.from(identifier) + + return [ + { + "#d": [address.identifier], + authors: [address.pubkey], + kinds: [address.kind], + limit: 1, + }, + ] + } catch { + return [{ids: [identifier], kinds: [kind], limit: 1}] + } + } + + return [{ids: [identifier], kinds: [kind], limit: 1}] +} + +async function requestEvents(relayUrl, filters) { + const controller = new AbortController() + const timeout = setTimeout(() => controller.abort(), NOSTR_TIMEOUT_MS) + + try { + return await request({ + autoClose: true, + filters, + relays: [relayUrl], + signal: controller.signal, + }) + } catch { + return [] + } finally { + clearTimeout(timeout) + } +} + +function renderHtml(html, meta) { + const $ = loadHtml(html) + + upsertTitle($, meta.title) + upsertMetaTag($, "name", "description", meta.description) + upsertMetaTag($, "name", "og:url", meta.url) + upsertMetaTag($, "name", "og:type", meta.type) + upsertMetaTag($, "name", "og:title", meta.title) + upsertMetaTag($, "name", "og:description", meta.description) + upsertMetaTag($, "name", "twitter:card", meta.card) + upsertMetaTag($, "name", "twitter:site", meta.site) + upsertMetaTag($, "name", "twitter:title", meta.title) + upsertMetaTag($, "name", "twitter:description", meta.description) + upsertMetaTag($, "name", "twitter:image", meta.image) + + upsertMetaTag($, "property", "og:url", meta.url) + upsertMetaTag($, "property", "og:type", meta.type) + upsertMetaTag($, "property", "og:title", meta.title) + upsertMetaTag($, "property", "og:description", meta.description) + upsertMetaTag($, "property", "og:image", meta.image) + + return $.html() +} + +function upsertTitle($, value) { + let titleTag = $("head > title").first() + + if (titleTag.length === 0) { + $("head").prepend("") + titleTag = $("head > title").first() + } + + titleTag.text(value) +} + +function upsertMetaTag($, attribute, key, content) { + const selector = `meta[${attribute}="${key}"]` + let metaTag = $(selector).first() + + if (metaTag.length === 0) { + metaTag = $("").attr(attribute, key) + $("head").append(metaTag) + } + + metaTag.attr("content", content) +} + +function getHtmlDefaults(html) { + const $ = loadHtml(html) + + return { + description: readRequiredMetaContent($, "og:description"), + image: readRequiredMetaContent($, "twitter:image"), + site: readRequiredMetaContent($, "twitter:site"), + title: readRequiredMetaContent($, "og:title"), + } +} + +function readRequiredMetaContent($, key) { + const content = readMetaContent($, key) + + if (!content) { + throw new Error(`Missing required meta tag ${key} in build/index.html. Ensure it exists in src/app.html.`) + } + + return content +} + +function readMetaContent($, key) { + const byName = $(`meta[name="${key}"]`).attr("content") + + if (typeof byName === "string" && byName.trim()) { + return byName.trim() + } + + const byProperty = $(`meta[property="${key}"]`).attr("content") + + return typeof byProperty === "string" && byProperty.trim() ? byProperty.trim() : undefined +} + +function parseInviteRelay(requestUrl) { + const relay = requestUrl.searchParams.get("r") || requestUrl.searchParams.get("relay") + + if (!relay) { + return undefined + } + + return normalizeRelayParam(relay) +} + +function normalizeRelayParam(value) { + const decoded = value.trim() + + if (!decoded) { + return undefined + } + + const hasProtocol = /^[a-zA-Z][a-zA-Z\d+.-]*:\/\//.test(decoded) + const withProtocol = hasProtocol ? decoded : `wss://${decoded}` + + try { + const normalized = normalizeRelayUrl(withProtocol) + + if (normalized.startsWith("ws://") || normalized.startsWith("wss://")) { + return normalized.replace(/\/+$/, "") + } + } catch { + // Ignore malformed relay URLs. + } + + return undefined } function toRelayHttpUrl(relayUrl) { @@ -327,84 +696,28 @@ function toAbsoluteHttpUrl(value, baseUrl) { try { const parsed = new URL(value, baseUrl) - if (["http:", "https:"].includes(parsed.protocol)) { + if (parsed.protocol === "http:" || parsed.protocol === "https:") { return parsed.href } - - return undefined } catch { - return undefined - } -} - -function setInviteMeta(html, meta) { - let result = html - - result = upsertMetaTag(result, "name", "description", meta.description) - result = upsertMetaTag(result, "name", "og:url", meta.url) - result = upsertMetaTag(result, "name", "og:type", meta.type) - result = upsertMetaTag(result, "name", "og:title", meta.title) - result = upsertMetaTag(result, "name", "og:description", meta.description) - result = upsertMetaTag(result, "name", "twitter:card", meta.card) - result = upsertMetaTag(result, "name", "twitter:site", meta.site) - result = upsertMetaTag(result, "name", "twitter:title", meta.title) - result = upsertMetaTag(result, "name", "twitter:description", meta.description) - result = upsertMetaTag(result, "name", "twitter:image", meta.image) - - result = upsertMetaTag(result, "property", "og:url", meta.url) - result = upsertMetaTag(result, "property", "og:type", meta.type) - result = upsertMetaTag(result, "property", "og:title", meta.title) - result = upsertMetaTag(result, "property", "og:description", meta.description) - result = upsertMetaTag(result, "property", "og:image", meta.image) - - return result -} - -function upsertMetaTag(html, attribute, key, value) { - const escapedKey = escapeRegExp(key) - const escapedValue = escapeHtml(value) - const pattern = new RegExp( - `(]*${attribute}=["']${escapedKey}["'][^>]*content=["'])[^"']*(["'][^>]*>)`, - "i", - ) - - if (pattern.test(html)) { - return html.replace(pattern, `$1${escapedValue}$2`) + // Ignore malformed URLs. } - return html.replace( - "", - ` \n `, - ) + return undefined } -function readMetaContent(html, key) { - const escapedKey = escapeRegExp(key) - const pattern = new RegExp( - `]*(?:name|property)=["']${escapedKey}["'][^>]*content=["']([^"']*)["'][^>]*>`, - "i", - ) - - const match = html.match(pattern) - - return match ? match[1] : undefined -} - -function getRequestOrigin(req) { - const forwardedProto = req.headers["x-forwarded-proto"] - const forwardedHost = req.headers["x-forwarded-host"] - - const protocol = firstHeaderValue(forwardedProto) || "http" - const host = firstHeaderValue(forwardedHost) || req.headers.host || "localhost" +function getRequestOrigin(req, requestUrl) { + const protocol = firstHeaderValue(req.headers.get("x-forwarded-proto")) || requestUrl.protocol.slice(0, -1) + const host = + firstHeaderValue(req.headers.get("x-forwarded-host")) || + req.headers.get("host") || + requestUrl.host || + "localhost" return `${protocol}://${host}` } function firstHeaderValue(value) { - if (Array.isArray(value)) { - return value[0]?.split(",")[0]?.trim() - } - if (typeof value === "string") { return value.split(",")[0].trim() } @@ -412,15 +725,61 @@ function firstHeaderValue(value) { return undefined } -function escapeRegExp(value) { - return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") +function normalizePathname(pathname) { + const cleanPath = pathname.replace(/\/+/g, "/") + + if (cleanPath === "/") { + return "/" + } + + return cleanPath.replace(/\/+$/, "") || "/" } -function escapeHtml(value) { - return String(value) - .replaceAll("&", "&") - .replaceAll("\"", """) - .replaceAll("'", "'") - .replaceAll("<", "<") - .replaceAll(">", ">") +function getPathSegments(pathname) { + const normalized = normalizePathname(pathname) + + if (normalized === "/") { + return [] + } + + return normalized + .slice(1) + .split("/") + .map(decodeSegment) +} + +function decodeSegment(value) { + try { + return decodeURIComponent(value) + } catch { + return value + } +} + +function clip(text, maxLength) { + if (text.length <= maxLength) { + return text + } + + return `${text.slice(0, maxLength - 1).trimEnd()}…` +} + +function getCachedValue(cache, key) { + const cached = cache.get(key) + + if (!cached) { + return undefined + } + + if (cached.expiresAt <= Date.now()) { + cache.delete(key) + + return undefined + } + + return cached.value +} + +function setCachedValue(cache, key, value, ttlMs) { + cache.set(key, {expiresAt: Date.now() + ttlMs, value}) } From fe3e1a66e20f93b44f05cd771a8e2d5185cf8a85 Mon Sep 17 00:00:00 2001 From: Priyanshu Bharti Date: Fri, 17 Apr 2026 19:54:59 +0000 Subject: [PATCH 8/9] Update package.json --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index 1aaf908c..bc11daf5 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "@capawesome/capacitor-badge": "^8.0.0", "@getalby/lightning-tools": "^6.1.0", "@getalby/sdk": "^5.1.2", + "@hono/node-server": "^1.19.14", "@noble/curves": "^1.9.7", "@pomade/core": "^0.2.3", "@poppanator/sveltekit-svg": "^4.2.1", @@ -81,12 +82,14 @@ "@welshman/signer": "^0.8.13", "@welshman/store": "^0.8.13", "@welshman/util": "^0.8.13", + "cheerio": "^1.2.0", "compressorjs-next": "^1.1.2", "daisyui": "^5.5.19", "date-picker-svelte": "^2.17.0", "dotenv": "^16.6.1", "emoji-picker-element": "^1.28.1", "fuse.js": "^7.1.0", + "hono": "^4.12.14", "husky": "^9.1.7", "idb": "^8.0.3", "livekit-client": "^2.17.2", From f877c30b80d4a98ff187e79f79198340276e3b01 Mon Sep 17 00:00:00 2001 From: Priyanshu Bharti Date: Fri, 17 Apr 2026 20:01:34 +0000 Subject: [PATCH 9/9] Update pnpm-lock.yaml --- pnpm-lock.yaml | 1153 ++++++++++++++++++++++++++++-------------------- 1 file changed, 670 insertions(+), 483 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9f6bebf7..a3370db8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: '@capacitor/cli': specifier: ^8.0.1 version: 8.0.1 + '@capacitor/clipboard': + specifier: ^8.0.1 + version: 8.0.1(@capacitor/core@8.0.1) '@capacitor/core': specifier: ^8.0.1 version: 8.0.1 @@ -44,6 +47,9 @@ importers: '@capacitor/push-notifications': specifier: ^8.0.0 version: 8.0.0(@capacitor/core@8.0.1) + '@capacitor/share': + specifier: ^8.0.1 + version: 8.0.1(@capacitor/core@8.0.1) '@capawesome/capacitor-android-dark-mode-support': specifier: ^8.0.0 version: 8.0.0(@capacitor/core@8.0.1) @@ -56,21 +62,27 @@ importers: '@getalby/sdk': specifier: ^5.1.2 version: 5.1.2(typescript@5.9.3) + '@hono/node-server': + specifier: ^1.19.14 + version: 1.19.14(hono@4.12.14) '@noble/curves': specifier: ^1.9.7 version: 1.9.7 '@pomade/core': - specifier: ^0.2.2 - version: 0.2.2(@frostr/bifrost@1.0.7(typescript@5.9.3))(@noble/hashes@2.0.1)(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/signer@0.8.12(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-tools@2.20.0(typescript@5.9.3)) + specifier: ^0.2.3 + version: 0.2.3(@frostr/bifrost@1.0.7(typescript@5.9.3))(@noble/hashes@2.0.1)(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/signer@0.8.13(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-tools@2.20.0(typescript@5.9.3)) '@poppanator/sveltekit-svg': specifier: ^4.2.1 - version: 4.2.1(rollup@2.80.0)(svelte@5.48.0)(svgo@3.3.2)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)) + version: 4.2.1(rollup@2.80.0)(svelte@5.48.0)(svgo@3.3.2)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)) '@sveltejs/adapter-static': specifier: ^3.0.10 - version: 3.0.10(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0))) + version: 3.0.10(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0))) '@tiptap/core': specifier: ^2.27.2 version: 2.27.2(@tiptap/pm@2.27.2) + '@tiptap/pm': + specifier: ^2.27.2 + version: 2.27.2 '@types/qrcode': specifier: ^1.5.6 version: 1.5.6 @@ -82,43 +94,46 @@ importers: version: 0.2.6 '@vite-pwa/sveltekit': specifier: ^0.6.8 - version: 0.6.8(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)))(@vite-pwa/assets-generator@0.2.6)(vite-plugin-pwa@0.21.2(@vite-pwa/assets-generator@0.2.6)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0))(workbox-build@7.3.0)(workbox-window@7.3.0)) + version: 0.6.8(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)))(@vite-pwa/assets-generator@0.2.6)(vite-plugin-pwa@0.21.2(@vite-pwa/assets-generator@0.2.6)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0))(workbox-build@7.3.0)(workbox-window@7.3.0)) '@welshman/app': - specifier: ^0.8.12 - version: 0.8.12(3074ef6691f94dc03952d8dbc98013a7) + specifier: ^0.8.13 + version: 0.8.13(ed9ee8a79a580bcb9fa9bb6eb1a69558) '@welshman/content': - specifier: ^0.8.12 - version: 0.8.12(nostr-tools@2.20.0(typescript@5.9.3)) + specifier: ^0.8.13 + version: 0.8.13(nostr-tools@2.20.0(typescript@5.9.3)) '@welshman/editor': - specifier: ^0.8.12 - version: 0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-editor@1.1.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/extension-image@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)))(@tiptap/extension-link@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)(linkifyjs@4.3.2)(nostr-tools@2.20.0(typescript@5.9.3))(prosemirror-markdown@1.13.3)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(tiptap-markdown@0.8.10(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))))(nostr-tools@2.20.0(typescript@5.9.3)) + specifier: ^0.8.13 + version: 0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-editor@1.1.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/extension-image@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)))(@tiptap/extension-link@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)(linkifyjs@4.3.2)(nostr-tools@2.20.0(typescript@5.9.3))(prosemirror-markdown@1.13.3)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(tiptap-markdown@0.8.10(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))))(nostr-tools@2.20.0(typescript@5.9.3)) '@welshman/feeds': - specifier: ^0.8.12 - version: 0.8.12(d5b74f0c83250e052e0b96f7ff5804e8) + specifier: ^0.8.13 + version: 0.8.13(29451a19e278ea4a9cf66616f05d5557) '@welshman/lib': - specifier: ^0.8.12 - version: 0.8.12 + specifier: ^0.8.13 + version: 0.8.13 '@welshman/net': - specifier: ^0.8.12 - version: 0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3) + specifier: ^0.8.13 + version: 0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3) '@welshman/router': - specifier: ^0.8.12 - version: 0.8.12(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3))) + specifier: ^0.8.13 + version: 0.8.13(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3))) '@welshman/signer': - specifier: ^0.8.12 - version: 0.8.12(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)) + specifier: ^0.8.13 + version: 0.8.13(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)) '@welshman/store': - specifier: ^0.8.12 - version: 0.8.12(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(svelte@5.48.0) + specifier: ^0.8.13 + version: 0.8.13(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(svelte@5.48.0) '@welshman/util': - specifier: ^0.8.12 - version: 0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)) + specifier: ^0.8.13 + version: 0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)) + cheerio: + specifier: ^1.2.0 + version: 1.2.0 compressorjs-next: specifier: ^1.1.2 version: 1.1.2 daisyui: - specifier: ^4.12.24 - version: 4.12.24(postcss@8.5.6) + specifier: ^5.5.19 + version: 5.5.19 date-picker-svelte: specifier: ^2.17.0 version: 2.17.0(svelte@5.48.0) @@ -131,6 +146,9 @@ importers: fuse.js: specifier: ^7.1.0 version: 7.1.0 + hono: + specifier: ^4.12.14 + version: 4.12.14 husky: specifier: ^9.1.7 version: 9.1.7 @@ -147,8 +165,8 @@ importers: specifier: ^2.19.4 version: 2.20.0(typescript@5.9.3) prettier-plugin-tailwindcss: - specifier: ^0.6.14 - version: 0.6.14(prettier-plugin-svelte@3.4.1(prettier@3.8.1)(svelte@5.48.0))(prettier@3.8.1) + specifier: ^0.7.2 + version: 0.7.2(prettier-plugin-svelte@3.4.1(prettier@3.8.1)(svelte@5.48.0))(prettier@3.8.1) qr-scanner: specifier: ^1.4.2 version: 1.4.2 @@ -170,10 +188,13 @@ importers: version: 9.39.2 '@sveltejs/kit': specifier: ^2.50.1 - version: 2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)) + version: 2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)) '@sveltejs/vite-plugin-svelte': specifier: ^4.0.4 - version: 4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)) + version: 4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)) + '@tailwindcss/postcss': + specifier: ^4.2.2 + version: 4.2.2 '@tauri-apps/cli': specifier: ^2.9.6 version: 2.10.0 @@ -188,13 +209,13 @@ importers: version: 2.5.1 eslint: specifier: ^9.39.2 - version: 9.39.2(jiti@1.21.7) + version: 9.39.2(jiti@2.6.1) eslint-config-prettier: specifier: ^9.1.2 - version: 9.1.2(eslint@9.39.2(jiti@1.21.7)) + version: 9.1.2(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-svelte: specifier: ^2.46.1 - version: 2.46.1(eslint@9.39.2(jiti@1.21.7))(svelte@5.48.0)(ts-node@10.9.2(@types/node@25.0.10)(typescript@5.9.3)) + version: 2.46.1(eslint@9.39.2(jiti@2.6.1))(svelte@5.48.0)(ts-node@10.9.2(@types/node@25.0.10)(typescript@5.9.3)) globals: specifier: ^15.15.0 version: 15.15.0 @@ -214,17 +235,17 @@ importers: specifier: ^4.3.5 version: 4.3.5(picomatch@4.0.3)(svelte@5.48.0)(typescript@5.9.3) tailwindcss: - specifier: ^3.4.19 - version: 3.4.19(yaml@2.7.1) + specifier: ^4.2.2 + version: 4.2.2 typescript: specifier: ^5.9.3 version: 5.9.3 typescript-eslint: specifier: ^8.53.1 - version: 8.53.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) + version: 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) vite: specifier: ^5.4.21 - version: 5.4.21(@types/node@25.0.10)(terser@5.46.0) + version: 5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0) packages: @@ -788,6 +809,11 @@ packages: engines: {node: '>=22.0.0'} hasBin: true + '@capacitor/clipboard@8.0.1': + resolution: {integrity: sha512-iOlbTi8MojKyLnYE+M27priXid7vHd0PlDwyHohPzkuQ8Rkp6q7ykwZmPEUD+OnU/Ink7Qw/pUOfKgraKmA6Eg==} + peerDependencies: + '@capacitor/core': '>=8.0.0' + '@capacitor/core@8.0.1': resolution: {integrity: sha512-5UqSWxGMp/B8KhYu7rAijqNtYslhcLh+TrbfU48PfdMDsPfaU/VY48sMNzC22xL8BmoFoql/3SKyP+pavTOvOA==} @@ -824,6 +850,11 @@ packages: peerDependencies: '@capacitor/core': '>=8.0.0' + '@capacitor/share@8.0.1': + resolution: {integrity: sha512-3cSBKBCJVon54rKDROP2rqGyeGks4pBh9TbaEk9S375Kbek/ZHe72N50zIa0Vn9Eac/SuhwgehO/mmA4CsUOiw==} + peerDependencies: + '@capacitor/core': '>=8.0.0' + '@capacitor/synapse@1.0.4': resolution: {integrity: sha512-/C1FUo8/OkKuAT4nCIu/34ny9siNHr9qtFezu4kxm6GY1wNFxrCFWjfYx5C1tUhVGz3fxBABegupkpjXvjCHrw==} @@ -1074,6 +1105,12 @@ packages: resolution: {integrity: sha512-yUF9LhuvdIFOwjV1aG0ryzfwDiGBFk/CRLkRvrrM9dsE38SUjKsf1FDga5jxsKMu80nWcPZR9TiGGASWedoYPA==} engines: {node: '>=14'} + '@hono/node-server@1.19.14': + resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -1424,9 +1461,9 @@ packages: '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - '@pomade/core@0.2.2': - resolution: {integrity: sha512-FoilLsO0gVjiKMW3LV63pmXU7x3gh8YVGVulyR6QJr4h47XrsBg8vPkZtKWr4+sH3sW31e2tNIPUb3ptiuhrMA==} - version: 0.2.2 + '@pomade/core@0.2.3': + resolution: {integrity: sha512-36+abWfMH1Mif9FjBO7xICCkGZE4IqQpy7Csxlauyt0bhYQ9GsB07LqK5Qm3GgEHNwF9rFXdSZawkM+E6BeIfg==} + version: 0.2.3 engines: {node: '>=12.0.0'} peerDependencies: '@frostr/bifrost': ^1.0.7 @@ -1708,6 +1745,98 @@ packages: svelte: ^5.0.0-next.96 || ^5.0.0 vite: ^5.0.0 + '@tailwindcss/node@4.2.2': + resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==} + + '@tailwindcss/oxide-android-arm64@4.2.2': + resolution: {integrity: sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.2.2': + resolution: {integrity: sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.2.2': + resolution: {integrity: sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.2.2': + resolution: {integrity: sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': + resolution: {integrity: sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': + resolution: {integrity: sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.2.2': + resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.2.2': + resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.2.2': + resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.2.2': + resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': + resolution: {integrity: sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.2.2': + resolution: {integrity: sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.2.2': + resolution: {integrity: sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==} + engines: {node: '>= 20'} + + '@tailwindcss/postcss@4.2.2': + resolution: {integrity: sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ==} + '@tauri-apps/cli-darwin-arm64@2.10.0': resolution: {integrity: sha512-avqHD4HRjrMamE/7R/kzJPcAJnZs0IIS+1nkDP5b+TNBn3py7N2aIo9LIpy+VQq0AkN8G5dDpZtOOBkmWt/zjA==} engines: {node: '>= 10'} @@ -2036,83 +2165,83 @@ packages: '@vite-pwa/assets-generator': optional: true - '@welshman/app@0.8.12': - resolution: {integrity: sha512-kRp+AVzn4i3FvZmdlyMknFUAb/5SnUz9A/cFKkDqWHsd+N3PbNcL2ZOlV9v5NI77GtsDF2ez6PEQfsZxWvkS/g==} + '@welshman/app@0.8.13': + resolution: {integrity: sha512-+mUMtt5ibotBk/susPFKXnb9jRjqvIQgWMF28poCIzse08V4kfVClJJlzepvgjqRn6Ma/takr6tNkL6eV4rlRQ==} peerDependencies: '@pomade/core': ^0.2.1 - '@welshman/feeds': 0.8.12 - '@welshman/lib': 0.8.12 - '@welshman/net': 0.8.12 - '@welshman/router': 0.8.12 - '@welshman/signer': 0.8.12 - '@welshman/store': 0.8.12 - '@welshman/util': 0.8.12 + '@welshman/feeds': 0.8.13 + '@welshman/lib': 0.8.13 + '@welshman/net': 0.8.13 + '@welshman/router': 0.8.13 + '@welshman/signer': 0.8.13 + '@welshman/store': 0.8.13 + '@welshman/util': 0.8.13 svelte: ^4.0.0 || ^5.0.0 - '@welshman/content@0.8.12': - resolution: {integrity: sha512-hviVTXdyGf04Xq7mGo/82fq6lnbyuUYOGPkf8pJqPkfGh0f3i9nKof6gkzPvjZeEYSczneI2GpLIxkaZ3w1/tw==} + '@welshman/content@0.8.13': + resolution: {integrity: sha512-6ZDKCJ2GKczAULD7P7NZ5DmxFYKw6vfxJ1jpwbQj+0l7alr2IBh8kmaQ8wM1r6n0qOhfcNqeGaaREQxC4VnuHA==} peerDependencies: nostr-tools: ^2.19.4 - '@welshman/editor@0.8.12': - resolution: {integrity: sha512-CEXszH6pfM1kZHU9WnB6Z97YlxEOtgao6R3hhnBL/kRXy2tUTLpmFWyMONg2vu8Uzxtwz665eZhucLsju60U6w==} + '@welshman/editor@0.8.13': + resolution: {integrity: sha512-kr4pSjQ/TZnlyIeGo0UNNAQrTGpp0yMRUFD/LwORVLnC8UGNLwGRmFwOz0WNtCxGxFGquTlX1AkNfViWdkfXHw==} peerDependencies: - '@welshman/lib': 0.8.12 - '@welshman/util': 0.8.12 + '@welshman/lib': 0.8.13 + '@welshman/util': 0.8.13 nostr-editor: ^1.1.1 nostr-tools: ^2.19.4 - '@welshman/feeds@0.8.12': - resolution: {integrity: sha512-Dp/063qdrbe096z6IpIneazsqscfzSwsg09ZNHB6c3OsVb6iLEXLe7mEpATGcRsZ8memuFNLVLIP51eVkBqPcQ==} + '@welshman/feeds@0.8.13': + resolution: {integrity: sha512-zjjKbGG8wQyyuTtm7/7lAGEFbreTp7IO5Y+DZXwBBu/h2/TP/C/v0J0XrshFBqs/wOOURv7vYZlf/bs2En8UIg==} peerDependencies: - '@welshman/lib': 0.8.12 - '@welshman/net': 0.8.12 - '@welshman/router': 0.8.12 - '@welshman/signer': 0.8.12 - '@welshman/util': 0.8.12 + '@welshman/lib': 0.8.13 + '@welshman/net': 0.8.13 + '@welshman/router': 0.8.13 + '@welshman/signer': 0.8.13 + '@welshman/util': 0.8.13 - '@welshman/lib@0.8.12': - resolution: {integrity: sha512-7Y1GjAcABquWF47A1Jni5JdP+k0GH2yRmEbVhIU+0R0TubCwPAKS38J2LTvtuE9CJMX6hPS9IKEZS6qTOAaVuw==} + '@welshman/lib@0.8.13': + resolution: {integrity: sha512-fXVoe7zx+jPnqZdRMXLNOJvW+N6E708HSpNGfyBGlu1/OXg70wkEK3r9E67HsBg7pLxnl22tcOYq7r11GhpeFA==} engines: {node: '>=12.0.0'} - '@welshman/net@0.8.12': - resolution: {integrity: sha512-Ba71jwb8BBwUfPPtWHKYLB0HqeDYK64oqwxfo5bYldtPfGYrlD+a7lHFSZvNyOhvyXygCaIMnaye1QxWAHP8ng==} + '@welshman/net@0.8.13': + resolution: {integrity: sha512-k9BQA2lJI1mnQrf3pR8e3QhCluPtWSSPz2ywTDKq+/pdVXXIjrnsblHA/62d6SjCCSV/n5fONQ08YMivPzgtGA==} peerDependencies: - '@welshman/lib': 0.8.12 - '@welshman/util': 0.8.12 + '@welshman/lib': 0.8.13 + '@welshman/util': 0.8.13 - '@welshman/router@0.8.12': - resolution: {integrity: sha512-Rr7ryBNTvTvjoLsDRMKPuoNJbBv2MgyqN2338p4vVhPMK6MOGM3Nx1og0LpHDGiLlCFuPM8RpParpIWfNnWbKw==} + '@welshman/router@0.8.13': + resolution: {integrity: sha512-MJh8YfHpoSsRUI96OnqxnBDoQwjqIMh8N57US0id9cd6iOlkYlVPEUeicJK8Kcl5oT0zmN13UT/4o3d7nZrqcA==} peerDependencies: - '@welshman/lib': 0.8.12 - '@welshman/net': 0.8.12 - '@welshman/util': 0.8.12 + '@welshman/lib': 0.8.13 + '@welshman/net': 0.8.13 + '@welshman/util': 0.8.13 - '@welshman/signer@0.8.12': - resolution: {integrity: sha512-eO4mw2QOR2d2oCS4zgptkCgjC1s8X+1vNnXfWDbtlEwhk7PD4ySSCkpNVMeElq+uluLOugmKvgDc4gfnIH3p2A==} - version: 0.8.12 + '@welshman/signer@0.8.13': + resolution: {integrity: sha512-VgyKxZhJ/Br0q4H8KPfRWAa8WC0EVUc69dxq/Bt1cl7MTBg1EbzolUJhgOgGDOVO0gAKmWYMCnjNochaQy/Wpg==} + version: 0.8.13 peerDependencies: '@noble/curves': ^1.9.7 '@noble/hashes': ^2.0.1 - '@welshman/lib': 0.8.12 - '@welshman/net': 0.8.12 - '@welshman/util': 0.8.12 + '@welshman/lib': 0.8.13 + '@welshman/net': 0.8.13 + '@welshman/util': 0.8.13 nostr-signer-capacitor-plugin: '*' nostr-tools: ^2.19.4 - '@welshman/store@0.8.12': - resolution: {integrity: sha512-3IUzPRMMVF6Pcw3DaKkfJ4S6bYzVtk6Ze3FnaHs1xJIxkQj9GyBO9VreiovULPW0djsnrP5+1UEN4mKZsG3hXg==} + '@welshman/store@0.8.13': + resolution: {integrity: sha512-tnmbaNa8aqFVbklsMZ5y4h9xlHnbwo7o1l6xxJI0hqZnTuXD3IvN5/V58qhfZveUN/Y5Gz2MWQHFWyRBQ71ANg==} peerDependencies: - '@welshman/lib': 0.8.12 - '@welshman/net': 0.8.12 - '@welshman/util': 0.8.12 + '@welshman/lib': 0.8.13 + '@welshman/net': 0.8.13 + '@welshman/util': 0.8.13 svelte: ^4.0.0 || ^5.0.0 - '@welshman/util@0.8.12': - resolution: {integrity: sha512-lgftFt2moXZdN5fuL0RoAnAARV0n0d2+Q56gt7KrBSevjoCbtJgBVX5idvxL5PCEfh81veovJtty6eHxrhQv5A==} + '@welshman/util@0.8.13': + resolution: {integrity: sha512-3+CNqJjiHGXKzLOniDqAN4Oe038fV1RRjKiVP0++FDVbq8lShtdcliR7FDg/NTjhhmzivhYqdflNvqjAqOxekA==} peerDependencies: '@noble/curves': ^1.9.7 - '@welshman/lib': 0.8.12 + '@welshman/lib': 0.8.13 nostr-tools: ^2.19.4 '@xml-tools/parser@1.0.11': @@ -2175,19 +2304,9 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - arg@5.0.2: - resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -2280,10 +2399,6 @@ packages: resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} engines: {node: '>=0.6'} - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -2339,10 +2454,6 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - camelcase-css@2.0.1: - resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} - engines: {node: '>= 6'} - camelcase-keys@6.2.2: resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} engines: {node: '>=8'} @@ -2369,13 +2480,16 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.2.0: + resolution: {integrity: sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==} + engines: {node: '>=20.18.1'} + chevrotain@7.1.1: resolution: {integrity: sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw==} - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -2428,10 +2542,6 @@ packages: commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - commander@7.2.0: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} engines: {node: '>= 10'} @@ -2556,9 +2666,6 @@ packages: css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} - css-selector-tokenizer@0.8.0: - resolution: {integrity: sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==} - css-tree@2.2.1: resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} @@ -2580,13 +2687,8 @@ packages: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} - culori@3.3.0: - resolution: {integrity: sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - daisyui@4.12.24: - resolution: {integrity: sha512-JYg9fhQHOfXyLadrBrEqCDM6D5dWCSSiM6eTNCRrBRzx/VlOCrLS8eDfIw9RVvs64v2mJdLooKXY8EwQzoszAA==} - engines: {node: '>=16.9.0'} + daisyui@5.5.19: + resolution: {integrity: sha512-pbFAkl1VCEh/MPCeclKL61I/MqRIFFhNU7yiXoDDRapXN4/qNCoMxeCCswyxEEhqL5eiTTfwHvucFtOE71C9sA==} dargs@7.0.0: resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==} @@ -2682,9 +2784,6 @@ packages: dezalgo@1.0.4: resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} - didyoumean@1.2.2: - resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - diff@4.0.4: resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} engines: {node: '>=0.3.1'} @@ -2700,9 +2799,6 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} - dlv@1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - dom-serializer@1.4.1: resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} @@ -2756,6 +2852,13 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + encoding-sniffer@0.2.1: + resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} + + enhanced-resolve@5.20.1: + resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} + engines: {node: '>=10.13.0'} + entities@2.2.0: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} @@ -2763,6 +2866,14 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -2919,9 +3030,6 @@ packages: fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - fastparse@1.1.2: - resolution: {integrity: sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==} - fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -3159,6 +3267,10 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + hono@4.12.14: + resolution: {integrity: sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==} + engines: {node: '>=16.9.0'} + hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -3166,6 +3278,9 @@ packages: resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} engines: {node: '>=10'} + htmlparser2@10.1.0: + resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} + husky@9.1.7: resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} engines: {node: '>=18'} @@ -3174,6 +3289,10 @@ packages: ico-endec@0.1.6: resolution: {integrity: sha512-ZdLU38ZoED3g1j3iEyzcQj+wAkY2xfWNkymszfJPoxucIUhK7NayQ+/C4Kv0nDFMIsbtbEHldv3V8PU494/ueQ==} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + idb@7.1.1: resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} @@ -3237,10 +3356,6 @@ packages: resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} engines: {node: '>= 0.4'} - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - is-boolean-object@1.2.2: resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} engines: {node: '>= 0.4'} @@ -3403,6 +3518,10 @@ packages: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + jose@6.2.1: resolution: {integrity: sha512-jUaKr1yrbfaImV7R2TN/b3IcZzsw38/chqMpo2XJ7i2F8AfM/lA4G1goC3JVEwg0H7UldTmSt3P68nt31W7/mw==} @@ -3493,14 +3612,84 @@ packages: light-bolt11-decoder@3.2.0: resolution: {integrity: sha512-3QEofgiBOP4Ehs9BI+RkZdXZNtSys0nsJ6fyGeSiAGCBsMwHGUDS/JQlY/sTnWs91A2Nh0S9XXfA8Sy9g6QpuQ==} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + lilconfig@2.1.0: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} engines: {node: '>=10'} - lilconfig@3.1.3: - resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} - engines: {node: '>=14'} - lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -3695,9 +3884,6 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -3740,10 +3926,6 @@ packages: resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} engines: {node: '>=10'} - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - nostr-editor@1.1.1: resolution: {integrity: sha512-KwTds1HtEvr/WUjft8ZSpGvFpj5UVgu5S4Uq0XW9HzsuvKHh8G/FoS9TpIrmm4mc6fakG99rgn/gfX/IMGozTw==} engines: {node: '>=18.16.1'} @@ -3796,14 +3978,6 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-hash@3.0.0: - resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} - engines: {node: '>= 6'} - object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} @@ -3885,6 +4059,15 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} @@ -3942,10 +4125,6 @@ packages: resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} engines: {node: '>=4'} - pirates@4.0.7: - resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} - engines: {node: '>= 6'} - plist@3.1.0: resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} engines: {node: '>=10.4.0'} @@ -3958,18 +4137,6 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} - postcss-import@15.1.0: - resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} - engines: {node: '>=14.0.0'} - peerDependencies: - postcss: ^8.0.0 - - postcss-js@4.1.0: - resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} - engines: {node: ^12 || ^14 || >= 16} - peerDependencies: - postcss: ^8.4.21 - postcss-load-config@3.1.4: resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} engines: {node: '>= 10'} @@ -3982,30 +4149,6 @@ packages: ts-node: optional: true - postcss-load-config@6.0.1: - resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} - engines: {node: '>= 18'} - peerDependencies: - jiti: '>=1.21.0' - postcss: '>=8.0.9' - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - jiti: - optional: true - postcss: - optional: true - tsx: - optional: true - yaml: - optional: true - - postcss-nested@6.2.0: - resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} - engines: {node: '>=12.0'} - peerDependencies: - postcss: ^8.2.14 - postcss-safe-parser@6.0.0: resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} engines: {node: '>=12.0'} @@ -4039,9 +4182,9 @@ packages: prettier: ^3.0.0 svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0 - prettier-plugin-tailwindcss@0.6.14: - resolution: {integrity: sha512-pi2e/+ZygeIqntN+vC573BcW5Cve8zUB0SSAGxqpB4f96boZF4M3phPVoOFCeypwkpRYdi7+jQ5YJJUwrkGUAg==} - engines: {node: '>=14.21.3'} + prettier-plugin-tailwindcss@0.7.2: + resolution: {integrity: sha512-LkphyK3Fw+q2HdMOoiEHWf93fNtYJwfamoKPl7UwtjFQdei/iIBoX11G6j706FzN3ymX9mPVi97qIY8328vdnA==} + engines: {node: '>=20.19'} peerDependencies: '@ianvs/prettier-plugin-sort-imports': '*' '@prettier/plugin-hermes': '*' @@ -4053,14 +4196,12 @@ packages: prettier: ^3.0 prettier-plugin-astro: '*' prettier-plugin-css-order: '*' - prettier-plugin-import-sort: '*' prettier-plugin-jsdoc: '*' prettier-plugin-marko: '*' prettier-plugin-multiline-arrays: '*' prettier-plugin-organize-attributes: '*' prettier-plugin-organize-imports: '*' prettier-plugin-sort-imports: '*' - prettier-plugin-style-order: '*' prettier-plugin-svelte: '*' peerDependenciesMeta: '@ianvs/prettier-plugin-sort-imports': @@ -4081,8 +4222,6 @@ packages: optional: true prettier-plugin-css-order: optional: true - prettier-plugin-import-sort: - optional: true prettier-plugin-jsdoc: optional: true prettier-plugin-marko: @@ -4095,8 +4234,6 @@ packages: optional: true prettier-plugin-sort-imports: optional: true - prettier-plugin-style-order: - optional: true prettier-plugin-svelte: optional: true @@ -4224,9 +4361,6 @@ packages: randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - read-pkg-up@3.0.0: resolution: {integrity: sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==} engines: {node: '>=4'} @@ -4250,10 +4384,6 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} @@ -4379,6 +4509,9 @@ packages: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sax@1.1.4: resolution: {integrity: sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg==} @@ -4583,11 +4716,6 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - sucrase@3.35.1: - resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true - supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -4626,10 +4754,12 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - tailwindcss@3.4.19: - resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} - engines: {node: '>=14.0.0'} - hasBin: true + tailwindcss@4.2.2: + resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==} + + tapable@2.3.2: + resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} + engines: {node: '>=6'} tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} @@ -4657,13 +4787,6 @@ packages: resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==} engines: {node: '>=0.10'} - thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} - - thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - throttle-debounce@5.0.2: resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} engines: {node: '>=12.22'} @@ -4728,9 +4851,6 @@ packages: peerDependencies: typescript: '>=4.8.4' - ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - ts-node@10.9.2: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true @@ -4827,6 +4947,10 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici@7.25.0: + resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} + engines: {node: '>=20.18.1'} + unicode-canonical-property-names-ecmascript@2.0.1: resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} engines: {node: '>=4'} @@ -4945,6 +5069,15 @@ packages: resolution: {integrity: sha512-5ZZY1+lGq8LEKuDlg9M2RPJHlH3R7OVwyHqMcUsLKCgd9Wvf+QrFTCItkXXYPmrJn8H6gRLXbSgxLLdexiqHxw==} engines: {node: '>=6.0.0', npm: '>=3.10.0'} + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -5107,11 +5240,6 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} - yaml@2.7.1: - resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==} - engines: {node: '>= 14'} - hasBin: true - yargs-parser@18.1.3: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} engines: {node: '>=6'} @@ -5929,6 +6057,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@capacitor/clipboard@8.0.1(@capacitor/core@8.0.1)': + dependencies: + '@capacitor/core': 8.0.1 + '@capacitor/core@8.0.1': dependencies: tslib: 2.8.1 @@ -5966,6 +6098,10 @@ snapshots: dependencies: '@capacitor/core': 8.0.1 + '@capacitor/share@8.0.1(@capacitor/core@8.0.1)': + dependencies: + '@capacitor/core': 8.0.1 + '@capacitor/synapse@1.0.4': {} '@capawesome/capacitor-android-dark-mode-support@8.0.0(@capacitor/core@8.0.1)': @@ -6093,9 +6229,9 @@ snapshots: '@esbuild/win32-x64@0.21.5': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@1.21.7))': + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': dependencies: - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} @@ -6161,6 +6297,10 @@ snapshots: transitivePeerDependencies: - typescript + '@hono/node-server@1.19.14(hono@4.12.14)': + dependencies: + hono: 4.12.14 + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -6570,26 +6710,26 @@ snapshots: '@polka/url@1.0.0-next.29': {} - '@pomade/core@0.2.2(@frostr/bifrost@1.0.7(typescript@5.9.3))(@noble/hashes@2.0.1)(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/signer@0.8.12(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-tools@2.20.0(typescript@5.9.3))': + '@pomade/core@0.2.3(@frostr/bifrost@1.0.7(typescript@5.9.3))(@noble/hashes@2.0.1)(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/signer@0.8.13(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-tools@2.20.0(typescript@5.9.3))': dependencies: '@frostr/bifrost': 1.0.7(typescript@5.9.3) '@noble/hashes': 2.0.1 '@peculiar/x509': 1.14.3 - '@welshman/lib': 0.8.12 - '@welshman/net': 0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3) - '@welshman/signer': 0.8.12(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)) - '@welshman/util': 0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)) + '@welshman/lib': 0.8.13 + '@welshman/net': 0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3) + '@welshman/signer': 0.8.13(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)) + '@welshman/util': 0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)) cbor-x: 1.6.0 hash-wasm: 4.12.0 nostr-tools: 2.20.0(typescript@5.9.3) zod: 4.3.6 - '@poppanator/sveltekit-svg@4.2.1(rollup@2.80.0)(svelte@5.48.0)(svgo@3.3.2)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0))': + '@poppanator/sveltekit-svg@4.2.1(rollup@2.80.0)(svelte@5.48.0)(svgo@3.3.2)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0))': dependencies: '@rollup/pluginutils': 5.3.0(rollup@2.80.0) svelte: 5.48.0 svgo: 3.3.2 - vite: 5.4.21(@types/node@25.0.10)(terser@5.46.0) + vite: 5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0) transitivePeerDependencies: - rollup @@ -6766,15 +6906,15 @@ snapshots: dependencies: acorn: 8.15.0 - '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)))': + '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)))': dependencies: - '@sveltejs/kit': 2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)) + '@sveltejs/kit': 2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)) - '@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0))': + '@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0))': dependencies: '@standard-schema/spec': 1.1.0 '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0) - '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)) + '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)) '@types/cookie': 0.6.0 acorn: 8.15.0 cookie: 0.6.0 @@ -6787,32 +6927,101 @@ snapshots: set-cookie-parser: 2.7.2 sirv: 3.0.2 svelte: 5.48.0 - vite: 5.4.21(@types/node@25.0.10)(terser@5.46.0) + vite: 5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0) optionalDependencies: typescript: 5.9.3 - '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)))(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0))': + '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)))(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)) + '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)) debug: 4.4.3 svelte: 5.48.0 - vite: 5.4.21(@types/node@25.0.10)(terser@5.46.0) + vite: 5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0))': + '@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)))(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)) + '@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)))(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)) debug: 4.4.3 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.21 svelte: 5.48.0 - vite: 5.4.21(@types/node@25.0.10)(terser@5.46.0) - vitefu: 1.1.1(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)) + vite: 5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0) + vitefu: 1.1.1(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)) transitivePeerDependencies: - supports-color + '@tailwindcss/node@4.2.2': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.20.1 + jiti: 2.6.1 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.2.2 + + '@tailwindcss/oxide-android-arm64@4.2.2': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.2.2': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.2.2': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.2.2': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.2.2': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.2.2': + optional: true + + '@tailwindcss/oxide@4.2.2': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.2.2 + '@tailwindcss/oxide-darwin-arm64': 4.2.2 + '@tailwindcss/oxide-darwin-x64': 4.2.2 + '@tailwindcss/oxide-freebsd-x64': 4.2.2 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.2 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.2 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.2 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.2 + '@tailwindcss/oxide-linux-x64-musl': 4.2.2 + '@tailwindcss/oxide-wasm32-wasi': 4.2.2 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.2 + + '@tailwindcss/postcss@4.2.2': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.2.2 + '@tailwindcss/oxide': 4.2.2 + postcss: 8.5.6 + tailwindcss: 4.2.2 + '@tauri-apps/cli-darwin-arm64@2.10.0': optional: true @@ -7056,15 +7265,15 @@ snapshots: dependencies: '@types/node': 25.0.10 - '@typescript-eslint/eslint-plugin@8.53.1(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.53.1(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.53.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/parser': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.53.1 - '@typescript-eslint/type-utils': 8.53.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.53.1 - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.4.0(typescript@5.9.3) @@ -7072,14 +7281,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.53.1 '@typescript-eslint/types': 8.53.1 '@typescript-eslint/typescript-estree': 8.53.1(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.53.1 debug: 4.4.3 - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -7102,13 +7311,13 @@ snapshots: dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.53.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.53.1 '@typescript-eslint/typescript-estree': 8.53.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@2.6.1) ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: @@ -7131,13 +7340,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.53.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/utils@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) '@typescript-eslint/scope-manager': 8.53.1 '@typescript-eslint/types': 8.53.1 '@typescript-eslint/typescript-estree': 8.53.1(typescript@5.9.3) - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -7158,35 +7367,35 @@ snapshots: sharp-ico: 0.1.5 unconfig: 0.3.13 - '@vite-pwa/sveltekit@0.6.8(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)))(@vite-pwa/assets-generator@0.2.6)(vite-plugin-pwa@0.21.2(@vite-pwa/assets-generator@0.2.6)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0))(workbox-build@7.3.0)(workbox-window@7.3.0))': + '@vite-pwa/sveltekit@0.6.8(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)))(@vite-pwa/assets-generator@0.2.6)(vite-plugin-pwa@0.21.2(@vite-pwa/assets-generator@0.2.6)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0))(workbox-build@7.3.0)(workbox-window@7.3.0))': dependencies: - '@sveltejs/kit': 2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)) + '@sveltejs/kit': 2.50.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.48.0)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)))(svelte@5.48.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)) kolorist: 1.8.0 tinyglobby: 0.2.15 - vite-plugin-pwa: 0.21.2(@vite-pwa/assets-generator@0.2.6)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0))(workbox-build@7.3.0)(workbox-window@7.3.0) + vite-plugin-pwa: 0.21.2(@vite-pwa/assets-generator@0.2.6)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0))(workbox-build@7.3.0)(workbox-window@7.3.0) optionalDependencies: '@vite-pwa/assets-generator': 0.2.6 - '@welshman/app@0.8.12(3074ef6691f94dc03952d8dbc98013a7)': + '@welshman/app@0.8.13(ed9ee8a79a580bcb9fa9bb6eb1a69558)': dependencies: - '@pomade/core': 0.2.2(@frostr/bifrost@1.0.7(typescript@5.9.3))(@noble/hashes@2.0.1)(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/signer@0.8.12(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-tools@2.20.0(typescript@5.9.3)) - '@welshman/feeds': 0.8.12(d5b74f0c83250e052e0b96f7ff5804e8) - '@welshman/lib': 0.8.12 - '@welshman/net': 0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3) - '@welshman/router': 0.8.12(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3))) - '@welshman/signer': 0.8.12(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)) - '@welshman/store': 0.8.12(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(svelte@5.48.0) - '@welshman/util': 0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)) + '@pomade/core': 0.2.3(@frostr/bifrost@1.0.7(typescript@5.9.3))(@noble/hashes@2.0.1)(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/signer@0.8.13(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-tools@2.20.0(typescript@5.9.3)) + '@welshman/feeds': 0.8.13(29451a19e278ea4a9cf66616f05d5557) + '@welshman/lib': 0.8.13 + '@welshman/net': 0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3) + '@welshman/router': 0.8.13(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3))) + '@welshman/signer': 0.8.13(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)) + '@welshman/store': 0.8.13(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(svelte@5.48.0) + '@welshman/util': 0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)) fuse.js: 7.1.0 svelte: 5.48.0 throttle-debounce: 5.0.2 - '@welshman/content@0.8.12(nostr-tools@2.20.0(typescript@5.9.3))': + '@welshman/content@0.8.13(nostr-tools@2.20.0(typescript@5.9.3))': dependencies: '@braintree/sanitize-url': 7.1.1 nostr-tools: 2.20.0(typescript@5.9.3) - '@welshman/editor@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-editor@1.1.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/extension-image@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)))(@tiptap/extension-link@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)(linkifyjs@4.3.2)(nostr-tools@2.20.0(typescript@5.9.3))(prosemirror-markdown@1.13.3)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(tiptap-markdown@0.8.10(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))))(nostr-tools@2.20.0(typescript@5.9.3))': + '@welshman/editor@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-editor@1.1.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/extension-image@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)))(@tiptap/extension-link@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)(linkifyjs@4.3.2)(nostr-tools@2.20.0(typescript@5.9.3))(prosemirror-markdown@1.13.3)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(tiptap-markdown@0.8.10(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))))(nostr-tools@2.20.0(typescript@5.9.3))': dependencies: '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) '@tiptap/extension-code': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) @@ -7201,64 +7410,64 @@ snapshots: '@tiptap/extension-text': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)) '@tiptap/pm': 2.27.2 '@tiptap/suggestion': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2) - '@welshman/lib': 0.8.12 - '@welshman/util': 0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)) + '@welshman/lib': 0.8.13 + '@welshman/util': 0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)) nostr-editor: 1.1.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/extension-image@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)))(@tiptap/extension-link@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)(linkifyjs@4.3.2)(nostr-tools@2.20.0(typescript@5.9.3))(prosemirror-markdown@1.13.3)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(tiptap-markdown@0.8.10(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))) nostr-tools: 2.20.0(typescript@5.9.3) tippy.js: 6.3.7 - '@welshman/feeds@0.8.12(d5b74f0c83250e052e0b96f7ff5804e8)': + '@welshman/feeds@0.8.13(29451a19e278ea4a9cf66616f05d5557)': dependencies: - '@welshman/lib': 0.8.12 - '@welshman/net': 0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3) - '@welshman/router': 0.8.12(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3))) - '@welshman/signer': 0.8.12(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)) - '@welshman/util': 0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)) + '@welshman/lib': 0.8.13 + '@welshman/net': 0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3) + '@welshman/router': 0.8.13(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3))) + '@welshman/signer': 0.8.13(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3)) + '@welshman/util': 0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)) trava: 1.2.1 - '@welshman/lib@0.8.12': + '@welshman/lib@0.8.13': dependencies: '@scure/base': 1.2.6 '@types/events': 3.0.3 events: 3.3.0 - '@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)': + '@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3)': dependencies: - '@welshman/lib': 0.8.12 - '@welshman/util': 0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)) + '@welshman/lib': 0.8.13 + '@welshman/util': 0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)) events: 3.3.0 isomorphic-ws: 5.0.0(ws@8.18.3) transitivePeerDependencies: - ws - '@welshman/router@0.8.12(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))': + '@welshman/router@0.8.13(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))': dependencies: - '@welshman/lib': 0.8.12 - '@welshman/net': 0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3) - '@welshman/util': 0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)) + '@welshman/lib': 0.8.13 + '@welshman/net': 0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3) + '@welshman/util': 0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)) - '@welshman/signer@0.8.12(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3))': + '@welshman/signer@0.8.13(@noble/curves@1.9.7)(@noble/hashes@2.0.1)(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(nostr-signer-capacitor-plugin@https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1))(nostr-tools@2.20.0(typescript@5.9.3))': dependencies: '@noble/curves': 1.9.7 '@noble/hashes': 2.0.1 - '@welshman/lib': 0.8.12 - '@welshman/net': 0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3) - '@welshman/util': 0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)) + '@welshman/lib': 0.8.13 + '@welshman/net': 0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3) + '@welshman/util': 0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)) nostr-signer-capacitor-plugin: https://codeload.github.com/coracle-social/nostr-signer-capacitor-plugin/tar.gz/be4bb90a1a15c8eec0934f2f66ce9e82ecc72d51(@capacitor/core@8.0.1) nostr-tools: 2.20.0(typescript@5.9.3) - '@welshman/store@0.8.12(@welshman/lib@0.8.12)(@welshman/net@0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(svelte@5.48.0)': + '@welshman/store@0.8.13(@welshman/lib@0.8.13)(@welshman/net@0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3))(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(svelte@5.48.0)': dependencies: - '@welshman/lib': 0.8.12 - '@welshman/net': 0.8.12(@welshman/lib@0.8.12)(@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3) - '@welshman/util': 0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3)) + '@welshman/lib': 0.8.13 + '@welshman/net': 0.8.13(@welshman/lib@0.8.13)(@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)))(ws@8.18.3) + '@welshman/util': 0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3)) svelte: 5.48.0 - '@welshman/util@0.8.12(@noble/curves@1.9.7)(@welshman/lib@0.8.12)(nostr-tools@2.20.0(typescript@5.9.3))': + '@welshman/util@0.8.13(@noble/curves@1.9.7)(@welshman/lib@0.8.13)(nostr-tools@2.20.0(typescript@5.9.3))': dependencies: '@noble/curves': 1.9.7 '@types/ws': 8.18.1 - '@welshman/lib': 0.8.12 + '@welshman/lib': 0.8.13 js-base64: 3.7.8 nostr-tools: 2.20.0(typescript@5.9.3) nostr-wasm: 0.1.0 @@ -7319,17 +7528,8 @@ snapshots: dependencies: color-convert: 2.0.1 - any-promise@1.3.0: {} - - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - arg@4.1.3: {} - arg@5.0.2: {} - argparse@2.0.1: {} aria-query@5.3.2: {} @@ -7418,8 +7618,6 @@ snapshots: big-integer@1.6.52: {} - binary-extensions@2.3.0: {} - boolbase@1.0.0: {} bplist-creator@0.1.0: @@ -7480,8 +7678,6 @@ snapshots: callsites@3.1.0: {} - camelcase-css@2.0.1: {} - camelcase-keys@6.2.2: dependencies: camelcase: 5.3.1 @@ -7519,22 +7715,33 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.2.2 + css-what: 6.2.2 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + + cheerio@1.2.0: + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + encoding-sniffer: 0.2.1 + htmlparser2: 10.1.0 + parse5: 7.3.0 + parse5-htmlparser2-tree-adapter: 7.1.0 + parse5-parser-stream: 7.1.2 + undici: 7.25.0 + whatwg-mimetype: 4.0.0 + chevrotain@7.1.1: dependencies: regexp-to-ast: 0.5.0 - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -7583,8 +7790,6 @@ snapshots: commander@2.20.3: {} - commander@4.1.1: {} - commander@7.2.0: {} commander@8.3.0: {} @@ -7741,11 +7946,6 @@ snapshots: domutils: 3.2.2 nth-check: 2.1.1 - css-selector-tokenizer@0.8.0: - dependencies: - cssesc: 3.0.0 - fastparse: 1.1.2 - css-tree@2.2.1: dependencies: mdn-data: 2.0.28 @@ -7764,16 +7964,7 @@ snapshots: dependencies: css-tree: 2.2.1 - culori@3.3.0: {} - - daisyui@4.12.24(postcss@8.5.6): - dependencies: - css-selector-tokenizer: 0.8.0 - culori: 3.3.0 - picocolors: 1.1.1 - postcss-js: 4.1.0(postcss@8.5.6) - transitivePeerDependencies: - - postcss + daisyui@5.5.19: {} dargs@7.0.0: {} @@ -7867,8 +8058,6 @@ snapshots: asap: 2.0.6 wrappy: 1.0.2 - didyoumean@1.2.2: {} - diff@4.0.4: {} diff@5.2.2: {} @@ -7879,8 +8068,6 @@ snapshots: dependencies: path-type: 4.0.0 - dlv@1.1.3: {} - dom-serializer@1.4.1: dependencies: domelementtype: 2.3.0 @@ -7941,10 +8128,24 @@ snapshots: emoji-regex@8.0.0: {} + encoding-sniffer@0.2.1: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + + enhanced-resolve@5.20.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.2 + entities@2.2.0: {} entities@4.5.0: {} + entities@6.0.1: {} + + entities@7.0.1: {} + env-paths@2.2.1: {} env-paths@3.0.0: {} @@ -8063,21 +8264,21 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-compat-utils@0.5.1(eslint@9.39.2(jiti@1.21.7)): + eslint-compat-utils@0.5.1(eslint@9.39.2(jiti@2.6.1)): dependencies: - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@2.6.1) semver: 7.7.3 - eslint-config-prettier@9.1.2(eslint@9.39.2(jiti@1.21.7)): + eslint-config-prettier@9.1.2(eslint@9.39.2(jiti@2.6.1)): dependencies: - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@2.6.1) - eslint-plugin-svelte@2.46.1(eslint@9.39.2(jiti@1.21.7))(svelte@5.48.0)(ts-node@10.9.2(@types/node@25.0.10)(typescript@5.9.3)): + eslint-plugin-svelte@2.46.1(eslint@9.39.2(jiti@2.6.1))(svelte@5.48.0)(ts-node@10.9.2(@types/node@25.0.10)(typescript@5.9.3)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) '@jridgewell/sourcemap-codec': 1.5.5 - eslint: 9.39.2(jiti@1.21.7) - eslint-compat-utils: 0.5.1(eslint@9.39.2(jiti@1.21.7)) + eslint: 9.39.2(jiti@2.6.1) + eslint-compat-utils: 0.5.1(eslint@9.39.2(jiti@2.6.1)) esutils: 2.0.3 known-css-properties: 0.35.0 postcss: 8.5.6 @@ -8105,9 +8306,9 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.39.2(jiti@1.21.7): + eslint@9.39.2(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.2 @@ -8142,7 +8343,7 @@ snapshots: natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: - jiti: 1.21.7 + jiti: 2.6.1 transitivePeerDependencies: - supports-color @@ -8198,8 +8399,6 @@ snapshots: fast-uri@3.1.0: {} - fastparse@1.1.2: {} - fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -8456,16 +8655,29 @@ snapshots: he@1.2.0: {} + hono@4.12.14: {} + hosted-git-info@2.8.9: {} hosted-git-info@4.1.0: dependencies: lru-cache: 6.0.0 + htmlparser2@10.1.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 7.0.1 + husky@9.1.7: {} ico-endec@0.1.6: {} + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + idb@7.1.1: {} idb@8.0.3: {} @@ -8522,10 +8734,6 @@ snapshots: dependencies: has-bigints: 1.1.0 - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - is-boolean-object@1.2.2: dependencies: call-bound: 1.0.4 @@ -8666,6 +8874,8 @@ snapshots: jiti@1.21.7: {} + jiti@2.6.1: {} + jose@6.2.1: {} js-base64@3.7.8: {} @@ -8731,9 +8941,56 @@ snapshots: dependencies: '@scure/base': 1.1.1 - lilconfig@2.1.0: {} + lightningcss-android-arm64@1.32.0: + optional: true - lilconfig@3.1.3: {} + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + lilconfig@2.1.0: {} lines-and-columns@1.2.4: {} @@ -8923,12 +9180,6 @@ snapshots: ms@2.1.3: {} - mz@2.7.0: - dependencies: - any-promise: 1.3.0 - object-assign: 4.1.1 - thenify-all: 1.6.0 - nanoid@3.3.11: {} native-run@2.0.3: @@ -8981,8 +9232,6 @@ snapshots: semver: 7.7.3 validate-npm-package-license: 3.0.4 - normalize-path@3.0.0: {} - nostr-editor@1.1.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/extension-image@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2)))(@tiptap/extension-link@2.27.1(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)(linkifyjs@4.3.2)(nostr-tools@2.20.0(typescript@5.9.3))(prosemirror-markdown@1.13.3)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(tiptap-markdown@0.8.10(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))): dependencies: '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2) @@ -9045,10 +9294,6 @@ snapshots: dependencies: boolbase: 1.0.0 - object-assign@4.1.1: {} - - object-hash@3.0.0: {} - object-inspect@1.13.4: {} object-keys@1.1.1: {} @@ -9139,6 +9384,19 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse5-htmlparser2-tree-adapter@7.1.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.3.0 + + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.3.0 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + path-exists@3.0.0: {} path-exists@4.0.0: {} @@ -9177,8 +9435,6 @@ snapshots: pify@3.0.0: {} - pirates@4.0.7: {} - plist@3.1.0: dependencies: '@xmldom/xmldom': 0.8.11 @@ -9189,18 +9445,6 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-import@15.1.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.11 - - postcss-js@4.1.0(postcss@8.5.6): - dependencies: - camelcase-css: 2.0.1 - postcss: 8.5.6 - postcss-load-config@3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@25.0.10)(typescript@5.9.3)): dependencies: lilconfig: 2.1.0 @@ -9209,19 +9453,6 @@ snapshots: postcss: 8.5.6 ts-node: 10.9.2(@types/node@25.0.10)(typescript@5.9.3) - postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.7.1): - dependencies: - lilconfig: 3.1.3 - optionalDependencies: - jiti: 1.21.7 - postcss: 8.5.6 - yaml: 2.7.1 - - postcss-nested@6.2.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-selector-parser: 6.1.2 - postcss-safe-parser@6.0.0(postcss@8.5.6): dependencies: postcss: 8.5.6 @@ -9250,7 +9481,7 @@ snapshots: prettier: 3.8.1 svelte: 5.48.0 - prettier-plugin-tailwindcss@0.6.14(prettier-plugin-svelte@3.4.1(prettier@3.8.1)(svelte@5.48.0))(prettier@3.8.1): + prettier-plugin-tailwindcss@0.7.2(prettier-plugin-svelte@3.4.1(prettier@3.8.1)(svelte@5.48.0))(prettier@3.8.1): dependencies: prettier: 3.8.1 optionalDependencies: @@ -9404,10 +9635,6 @@ snapshots: dependencies: safe-buffer: 5.2.1 - read-cache@1.0.0: - dependencies: - pify: 2.3.0 - read-pkg-up@3.0.0: dependencies: find-up: 2.1.0 @@ -9448,10 +9675,6 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - readdirp@3.6.0: - dependencies: - picomatch: 2.3.1 - readdirp@4.1.2: {} redent@3.0.0: @@ -9612,6 +9835,8 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 + safer-buffer@2.1.2: {} + sax@1.1.4: {} sax@1.4.4: {} @@ -9872,16 +10097,6 @@ snapshots: strip-json-comments@3.1.1: {} - sucrase@3.35.1: - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - commander: 4.1.1 - lines-and-columns: 1.2.4 - mz: 2.7.0 - pirates: 4.0.7 - tinyglobby: 0.2.15 - ts-interface-checker: 0.1.13 - supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -9942,33 +10157,9 @@ snapshots: csso: 5.0.5 picocolors: 1.1.1 - tailwindcss@3.4.19(yaml@2.7.1): - dependencies: - '@alloc/quick-lru': 5.2.0 - arg: 5.0.2 - chokidar: 3.6.0 - didyoumean: 1.2.2 - dlv: 1.1.3 - fast-glob: 3.3.3 - glob-parent: 6.0.2 - is-glob: 4.0.3 - jiti: 1.21.7 - lilconfig: 3.1.3 - micromatch: 4.0.8 - normalize-path: 3.0.0 - object-hash: 3.0.0 - picocolors: 1.1.1 - postcss: 8.5.6 - postcss-import: 15.1.0(postcss@8.5.6) - postcss-js: 4.1.0(postcss@8.5.6) - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.7.1) - postcss-nested: 6.2.0(postcss@8.5.6) - postcss-selector-parser: 6.1.2 - resolve: 1.22.11 - sucrase: 3.35.1 - transitivePeerDependencies: - - tsx - - yaml + tailwindcss@4.2.2: {} + + tapable@2.3.2: {} tar@6.2.1: dependencies: @@ -10005,14 +10196,6 @@ snapshots: text-extensions@1.9.0: {} - thenify-all@1.6.0: - dependencies: - thenify: 3.3.1 - - thenify@3.3.1: - dependencies: - any-promise: 1.3.0 - throttle-debounce@5.0.2: {} through2@2.0.5: @@ -10069,8 +10252,6 @@ snapshots: dependencies: typescript: 5.9.3 - ts-interface-checker@0.1.13: {} - ts-node@10.9.2(@types/node@25.0.10)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -10148,13 +10329,13 @@ snapshots: optionalDependencies: rxjs: 7.8.2 - typescript-eslint@8.53.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3): + typescript-eslint@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.53.1(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/parser': 8.53.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.53.1(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.53.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - eslint: 9.39.2(jiti@1.21.7) + '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -10181,6 +10362,8 @@ snapshots: undici-types@7.16.0: {} + undici@7.25.0: {} + unicode-canonical-property-names-ecmascript@2.0.1: {} unicode-match-property-ecmascript@2.0.0: @@ -10223,12 +10406,12 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - vite-plugin-pwa@0.21.2(@vite-pwa/assets-generator@0.2.6)(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0))(workbox-build@7.3.0)(workbox-window@7.3.0): + vite-plugin-pwa@0.21.2(@vite-pwa/assets-generator@0.2.6)(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0))(workbox-build@7.3.0)(workbox-window@7.3.0): dependencies: debug: 4.4.3 pretty-bytes: 6.1.1 tinyglobby: 0.2.15 - vite: 5.4.21(@types/node@25.0.10)(terser@5.46.0) + vite: 5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0) workbox-build: 7.3.0 workbox-window: 7.3.0 optionalDependencies: @@ -10236,7 +10419,7 @@ snapshots: transitivePeerDependencies: - supports-color - vite@5.4.21(@types/node@25.0.10)(terser@5.46.0): + vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0): dependencies: esbuild: 0.21.5 postcss: 8.5.6 @@ -10244,11 +10427,12 @@ snapshots: optionalDependencies: '@types/node': 25.0.10 fsevents: 2.3.3 + lightningcss: 1.32.0 terser: 5.46.0 - vitefu@1.1.1(vite@5.4.21(@types/node@25.0.10)(terser@5.46.0)): + vitefu@1.1.1(vite@5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0)): optionalDependencies: - vite: 5.4.21(@types/node@25.0.10)(terser@5.46.0) + vite: 5.4.21(@types/node@25.0.10)(lightningcss@1.32.0)(terser@5.46.0) w3c-keyname@2.2.8: {} @@ -10260,6 +10444,12 @@ snapshots: dependencies: sdp: 3.2.1 + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -10490,9 +10680,6 @@ snapshots: yaml@1.10.2: {} - yaml@2.7.1: - optional: true - yargs-parser@18.1.3: dependencies: camelcase: 5.3.1