diff --git a/README.md b/README.md index 7c3c388f..c86cf844 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,10 @@ It’s a native desktop app that runs **OpenCode** under the hood, but presents The goal: make “agentic work” feel like a product, not a terminal. +## Alternate UIs + +- **Owpenbot (WhatsApp bot)**: a lightweight WhatsApp bridge for a running OpenCode server. See `packages/owpenbot/README.md` for setup and the one-command installer. + ## Quick start Download the dmg here https://github.com/different-ai/openwork/releases (or install from source below) diff --git a/package.json b/package.json index 4af4e516..5d234416 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,10 @@ }, "pnpm": { "onlyBuiltDependencies": [ - "esbuild" + "@whiskeysockets/baileys", + "better-sqlite3", + "esbuild", + "protobufjs" ] }, "packageManager": "pnpm@10.27.0" diff --git a/packages/desktop/src-tauri/Cargo.lock b/packages/desktop/src-tauri/Cargo.lock index c1f765ee..79f19ea9 100644 --- a/packages/desktop/src-tauri/Cargo.lock +++ b/packages/desktop/src-tauri/Cargo.lock @@ -397,9 +397,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.53" +version = "1.2.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932" +checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583" dependencies = [ "find-msvc-tools", "shlex", @@ -2381,7 +2381,7 @@ dependencies = [ [[package]] name = "openwork" -version = "0.3.4" +version = "0.3.5" dependencies = [ "json5", "serde", @@ -2827,9 +2827,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -2900,9 +2900,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -3584,9 +3584,9 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" dependencies = [ "libc", "windows-sys 0.60.2", diff --git a/packages/owpenbot/README.md b/packages/owpenbot/README.md new file mode 100644 index 00000000..97bf9e2a --- /dev/null +++ b/packages/owpenbot/README.md @@ -0,0 +1,96 @@ +# Owpenbot + +Simple WhatsApp bridge for a running OpenCode server. Telegram support exists but is not yet E2E tested. + +## Install + Run (WhatsApp) + +One-command install (recommended): + +```bash +curl -fsSL https://raw.githubusercontent.com/different-ai/openwork/dev/packages/owpenbot/install.sh | bash +``` + +Then follow the printed next steps (edit `.env`, pair WhatsApp, start the bridge). + +1) One-command setup (installs deps, builds, creates `.env` if missing): + +```bash +pnpm -C packages/owpenbot setup +``` + +2) Fill in `packages/owpenbot/.env` (see `.env.example`). + +Required: +- `OPENCODE_URL` +- `OPENCODE_DIRECTORY` +- `WHATSAPP_AUTH_DIR` + +Recommended: +- `OPENCODE_SERVER_USERNAME` +- `OPENCODE_SERVER_PASSWORD` + +3) Pair WhatsApp (first time only): + +```bash +pnpm -C packages/owpenbot whatsapp:login +``` + +4) Launch the bridge: + +```bash +pnpm -C packages/owpenbot start +``` + +5) Pair a user with the bot: + +- Run `pnpm -C packages/owpenbot pairing-code` to get the code. +- Send a WhatsApp message containing the code (e.g. `123456 hello`). +- You should receive an OpenCode response in the same chat. + +## Usage Flows + +### One-person flow (personal testing) + +Use your own WhatsApp account as the bot and test from a second number you control. + +1) Pair WhatsApp using your personal number (`whatsapp:login`). +2) Send the pairing code from a second number (SIM/eSIM or another phone). +3) Chat from that second number to receive OpenCode replies. + +Note: WhatsApp’s “message yourself” thread is not reliable for bot testing. + +### Two-person flow (dedicated bot) + +Use a separate WhatsApp number as the bot account so it stays independent from your personal chat history. + +1) Create a new WhatsApp account for the dedicated number. +2) Pair that account with `whatsapp:login`. +3) Share the pairing code with the person who should use the bot. +4) Optionally pre-allowlist specific numbers with `ALLOW_FROM_WHATSAPP=`. + +## Telegram (Untested) + +Telegram support is wired but not E2E tested yet. To try it: +- Set `TELEGRAM_BOT_TOKEN`. +- Optionally set `TELEGRAM_ENABLED=true`. + +## Commands + +```bash +pnpm -C packages/owpenbot start +pnpm -C packages/owpenbot whatsapp:login +pnpm -C packages/owpenbot pairing-code +``` + +## Defaults + +- SQLite at `~/.owpenbot/owpenbot.db` unless overridden. +- Allowlist is enforced by default; a pairing code is generated if not provided. +- Group chats are disabled unless `GROUPS_ENABLED=true`. + +## Tests + +```bash +pnpm -C packages/owpenbot test:unit +pnpm -C packages/owpenbot test:smoke +``` diff --git a/packages/owpenbot/install.sh b/packages/owpenbot/install.sh new file mode 100644 index 00000000..b81d1aa8 --- /dev/null +++ b/packages/owpenbot/install.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +set -euo pipefail + +OWPENBOT_REF="${OWPENBOT_REF:-dev}" +OWPENBOT_REPO="${OWPENBOT_REPO:-https://github.com/different-ai/openwork.git}" +OWPENBOT_INSTALL_DIR="${OWPENBOT_INSTALL_DIR:-$HOME/.owpenbot/openwork}" + +usage() { + cat <<'EOF' +Owpenbot installer (WhatsApp-first) + +Environment variables: + OWPENBOT_INSTALL_DIR Install directory (default: ~/.owpenbot/openwork) + OWPENBOT_REPO Git repo (default: https://github.com/different-ai/openwork.git) + OWPENBOT_REF Git ref/branch (default: dev) + +Example: + OWPENBOT_INSTALL_DIR=~/owpenbot curl -fsSL https://raw.githubusercontent.com/different-ai/openwork/dev/packages/owpenbot/install.sh | bash +EOF +} + +if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then + usage + exit 0 +fi + +require_bin() { + if ! command -v "$1" >/dev/null 2>&1; then + echo "Missing $1. Please install it and retry." >&2 + exit 1 + fi +} + +require_bin git +require_bin node + +if ! command -v pnpm >/dev/null 2>&1; then + if command -v corepack >/dev/null 2>&1; then + corepack enable >/dev/null 2>&1 || true + corepack prepare pnpm@10.27.0 --activate + else + echo "pnpm is required. Install pnpm or enable corepack, then retry." >&2 + exit 1 + fi +fi + +if [[ -d "$OWPENBOT_INSTALL_DIR/.git" ]]; then + echo "Updating owpenbot source in $OWPENBOT_INSTALL_DIR" + git -C "$OWPENBOT_INSTALL_DIR" fetch origin --prune + git -C "$OWPENBOT_INSTALL_DIR" checkout "$OWPENBOT_REF" + git -C "$OWPENBOT_INSTALL_DIR" pull --ff-only origin "$OWPENBOT_REF" +else + echo "Cloning owpenbot source to $OWPENBOT_INSTALL_DIR" + mkdir -p "$OWPENBOT_INSTALL_DIR" + git clone --branch "$OWPENBOT_REF" --depth 1 "$OWPENBOT_REPO" "$OWPENBOT_INSTALL_DIR" +fi + +echo "Installing dependencies..." +pnpm -C "$OWPENBOT_INSTALL_DIR" install + +echo "Building owpenbot..." +pnpm -C "$OWPENBOT_INSTALL_DIR/packages/owpenbot" build + +ENV_PATH="$OWPENBOT_INSTALL_DIR/packages/owpenbot/.env" +ENV_EXAMPLE="$OWPENBOT_INSTALL_DIR/packages/owpenbot/.env.example" +if [[ ! -f "$ENV_PATH" ]]; then + cp "$ENV_EXAMPLE" "$ENV_PATH" + echo "Created $ENV_PATH" +fi + +cat <; + stop(): Promise; + sendText(peerId: string, text: string): Promise; +}; + +type InboundMessage = { + channel: ChannelName; + peerId: string; + text: string; + raw: unknown; +}; + +type RunState = { + sessionID: string; + channel: ChannelName; + peerId: string; + toolUpdatesEnabled: boolean; + seenToolStates: Map; +}; + +const TOOL_LABELS: Record = { + bash: "bash", + read: "read", + write: "write", + edit: "edit", + patch: "patch", + multiedit: "edit", + grep: "grep", + glob: "glob", + task: "agent", + webfetch: "webfetch", +}; + +export async function startBridge(config: Config, logger: Logger) { + const client = createClient(config); + const store = new BridgeStore(config.dbPath); + store.seedAllowlist("telegram", config.allowlist.telegram); + store.seedAllowlist("whatsapp", config.allowlist.whatsapp); + + const pairingCode = resolvePairingCode(store, config.pairingCode); + logger.info({ pairingCode }, "pairing code ready"); + + const adapters = new Map(); + if (config.telegramEnabled && config.telegramToken) { + adapters.set("telegram", createTelegramAdapter(config, logger, handleInbound)); + } else { + logger.info("telegram adapter disabled"); + } + + if (config.whatsappEnabled) { + adapters.set("whatsapp", createWhatsAppAdapter(config, logger, handleInbound, { printQr: true })); + } else { + logger.info("whatsapp adapter disabled"); + } + + const sessionQueue = new Map>(); + const activeRuns = new Map(); + + let opencodeHealthy = false; + let opencodeVersion: string | undefined; + + async function refreshHealth() { + try { + const health = await client.global.health(); + opencodeHealthy = Boolean((health as { healthy?: boolean }).healthy); + opencodeVersion = (health as { version?: string }).version; + } catch (error) { + logger.warn({ error }, "failed to reach opencode health"); + opencodeHealthy = false; + } + } + + await refreshHealth(); + const healthTimer = setInterval(refreshHealth, 30_000); + + let stopHealthServer: (() => void) | null = null; + if (config.healthPort) { + stopHealthServer = startHealthServer( + config.healthPort, + (): HealthSnapshot => ({ + ok: opencodeHealthy, + opencode: { + url: config.opencodeUrl, + healthy: opencodeHealthy, + version: opencodeVersion, + }, + channels: { + telegram: adapters.has("telegram"), + whatsapp: adapters.has("whatsapp"), + }, + }), + logger, + ); + } + + const eventAbort = new AbortController(); + void (async () => { + const subscription = await client.event.subscribe(undefined, { signal: eventAbort.signal }); + for await (const raw of subscription.stream as AsyncIterable) { + const event = normalizeEvent(raw as any); + if (!event) continue; + + if (event.type === "message.part.updated") { + const part = (event.properties as { part?: any })?.part; + if (!part?.sessionID) continue; + const run = activeRuns.get(part.sessionID); + if (!run || !run.toolUpdatesEnabled) continue; + if (part.type !== "tool") continue; + + const callId = part.callID as string | undefined; + if (!callId) continue; + const state = part.state as { status?: string; input?: Record; output?: string; title?: string }; + const status = state?.status ?? "unknown"; + if (run.seenToolStates.get(callId) === status) continue; + run.seenToolStates.set(callId, status); + + const label = TOOL_LABELS[part.tool] ?? part.tool; + const title = state.title || truncateText(formatInputSummary(state.input ?? {}), 120) || "running"; + let message = `[tool] ${label} ${status}: ${title}`; + + if (status === "completed" && state.output) { + const output = truncateText(state.output.trim(), config.toolOutputLimit); + if (output) message += `\n${output}`; + } + + await sendText(run.channel, run.peerId, message); + } + + if (event.type === "permission.asked") { + const permission = event.properties as { id?: string; sessionID?: string }; + if (!permission?.id || !permission.sessionID) continue; + const response = config.permissionMode === "deny" ? "reject" : "always"; + await client.permission.respond({ + sessionID: permission.sessionID, + permissionID: permission.id, + response, + }); + if (response === "reject") { + const run = activeRuns.get(permission.sessionID); + if (run) { + await sendText(run.channel, run.peerId, "Permission denied. Update configuration to allow tools."); + } + } + } + } + })().catch((error) => { + logger.error({ error }, "event stream closed"); + }); + + async function sendText(channel: ChannelName, peerId: string, text: string) { + const adapter = adapters.get(channel); + if (!adapter) return; + const chunks = chunkText(text, adapter.maxTextLength); + for (const chunk of chunks) { + logger.info({ channel, peerId, length: chunk.length }, "sending message"); + await adapter.sendText(peerId, chunk); + } + } + + async function handleInbound(message: InboundMessage) { + const adapter = adapters.get(message.channel); + if (!adapter) return; + let inbound = message; + logger.info( + { channel: inbound.channel, peerId: inbound.peerId, length: inbound.text.length }, + "received message", + ); + + const allowed = store.isAllowed(inbound.channel, inbound.peerId); + if (!allowed) { + const trimmed = inbound.text.trim(); + if (trimmed.includes(pairingCode)) { + store.allowPeer(inbound.channel, inbound.peerId); + const remaining = trimmed.replace(pairingCode, "").trim(); + if (remaining) { + await sendText(inbound.channel, inbound.peerId, "Paired. Processing your message."); + } else { + await sendText(inbound.channel, inbound.peerId, "Paired. Send your message again."); + return; + } + inbound = { ...inbound, text: remaining }; + } else { + await sendText( + inbound.channel, + inbound.peerId, + `Pairing required. Reply with code: ${pairingCode}`, + ); + return; + } + } + + const session = store.getSession(inbound.channel, inbound.peerId); + const sessionID = session?.session_id ?? (await createSession(inbound)); + + enqueue(sessionID, async () => { + const runState: RunState = { + sessionID, + channel: inbound.channel, + peerId: inbound.peerId, + toolUpdatesEnabled: config.toolUpdatesEnabled, + seenToolStates: new Map(), + }; + activeRuns.set(sessionID, runState); + try { + const response = await client.session.prompt({ + sessionID, + parts: [{ type: "text", text: inbound.text }], + }); + const parts = (response as { parts?: Array<{ type?: string; text?: string; ignored?: boolean }> }).parts ?? []; + const reply = parts + .filter((part) => part.type === "text" && !part.ignored) + .map((part) => part.text ?? "") + .join("\n") + .trim(); + + if (reply) { + await sendText(inbound.channel, inbound.peerId, reply); + } else { + await sendText(inbound.channel, inbound.peerId, "No response generated. Try again."); + } + } catch (error) { + logger.error({ error }, "prompt failed"); + await sendText(inbound.channel, inbound.peerId, "Error: failed to reach OpenCode."); + } finally { + activeRuns.delete(sessionID); + } + }); + } + + async function createSession(message: InboundMessage): Promise { + const title = `owpenbot ${message.channel} ${message.peerId}`; + const session = await client.session.create({ + title, + permission: buildPermissionRules(config.permissionMode), + }); + const sessionID = (session as { id?: string }).id; + if (!sessionID) throw new Error("Failed to create session"); + store.upsertSession(message.channel, message.peerId, sessionID); + logger.info({ sessionID, channel: message.channel, peerId: message.peerId }, "session created"); + return sessionID; + } + + function enqueue(sessionID: string, task: () => Promise) { + const previous = sessionQueue.get(sessionID) ?? Promise.resolve(); + const next = previous + .then(task) + .catch((error) => { + logger.error({ error }, "session task failed"); + }) + .finally(() => { + if (sessionQueue.get(sessionID) === next) { + sessionQueue.delete(sessionID); + } + }); + sessionQueue.set(sessionID, next); + } + + for (const adapter of adapters.values()) { + await adapter.start(); + } + + logger.info({ channels: Array.from(adapters.keys()) }, "bridge started"); + + return { + async stop() { + eventAbort.abort(); + clearInterval(healthTimer); + if (stopHealthServer) stopHealthServer(); + for (const adapter of adapters.values()) { + await adapter.stop(); + } + store.close(); + await delay(50); + }, + }; +} diff --git a/packages/owpenbot/src/cli.ts b/packages/owpenbot/src/cli.ts new file mode 100644 index 00000000..0e5ee08c --- /dev/null +++ b/packages/owpenbot/src/cli.ts @@ -0,0 +1,54 @@ +import { Command } from "commander"; + +import { startBridge } from "./bridge.js"; +import { loadConfig } from "./config.js"; +import { BridgeStore } from "./db.js"; +import { createLogger } from "./logger.js"; +import { resolvePairingCode } from "./pairing.js"; +import { loginWhatsApp } from "./whatsapp.js"; + +const program = new Command(); + +program.name("owpenbot").description("OpenCode WhatsApp + Telegram bridge"); + +program + .command("start") + .description("Start the bridge") + .action(async () => { + const config = loadConfig(); + const logger = createLogger(config.logLevel); + const bridge = await startBridge(config, logger); + + const shutdown = async () => { + logger.info("shutting down"); + await bridge.stop(); + process.exit(0); + }; + + process.on("SIGINT", shutdown); + process.on("SIGTERM", shutdown); + }); + +program + .command("pairing-code") + .description("Print the current pairing code") + .action(() => { + const config = loadConfig(process.env, { requireOpencode: false }); + const store = new BridgeStore(config.dbPath); + const code = resolvePairingCode(store, config.pairingCode); + console.log(code); + store.close(); + }); + +const whatsapp = program.command("whatsapp").description("WhatsApp helpers"); + +whatsapp + .command("login") + .description("Login to WhatsApp via QR code") + .action(async () => { + const config = loadConfig(process.env, { requireOpencode: false }); + const logger = createLogger(config.logLevel); + await loginWhatsApp(config, logger); + }); + +await program.parseAsync(process.argv); diff --git a/packages/owpenbot/src/config.ts b/packages/owpenbot/src/config.ts new file mode 100644 index 00000000..2ab32b0e --- /dev/null +++ b/packages/owpenbot/src/config.ts @@ -0,0 +1,127 @@ +import os from "node:os"; +import path from "node:path"; + +import dotenv from "dotenv"; + +dotenv.config(); + +export type ChannelName = "telegram" | "whatsapp"; + +export type Config = { + opencodeUrl: string; + opencodeDirectory: string; + opencodeUsername?: string; + opencodePassword?: string; + telegramToken?: string; + telegramEnabled: boolean; + whatsappAuthDir: string; + whatsappEnabled: boolean; + dataDir: string; + dbPath: string; + allowlist: Record>; + pairingCode?: string; + toolUpdatesEnabled: boolean; + groupsEnabled: boolean; + permissionMode: "allow" | "deny"; + toolOutputLimit: number; + healthPort?: number; + logLevel: string; +}; + +type EnvLike = NodeJS.ProcessEnv; + +function parseBoolean(value: string | undefined, fallback: boolean): boolean { + if (value === undefined) return fallback; + return ["1", "true", "yes", "on"].includes(value.toLowerCase()); +} + +function parseInteger(value: string | undefined): number | undefined { + if (!value) return undefined; + const parsed = Number.parseInt(value, 10); + return Number.isFinite(parsed) ? parsed : undefined; +} + +function parseList(value: string | undefined): string[] { + if (!value) return []; + return value + .split(",") + .map((item) => item.trim()) + .filter(Boolean); +} + +function expandHome(value: string): string { + if (!value.startsWith("~/")) return value; + return path.join(os.homedir(), value.slice(2)); +} + +function parseAllowlist(env: EnvLike): Record> { + const allowlist: Record> = { + telegram: new Set(), + whatsapp: new Set(), + }; + + const shared = parseList(env.ALLOW_FROM); + for (const entry of shared) { + if (entry.includes(":")) { + const [channel, peer] = entry.split(":"); + const normalized = channel.trim().toLowerCase(); + if (normalized === "telegram" || normalized === "whatsapp") { + if (peer?.trim()) { + allowlist[normalized].add(peer.trim()); + } + } + } else { + allowlist.telegram.add(entry); + allowlist.whatsapp.add(entry); + } + } + + for (const entry of parseList(env.ALLOW_FROM_TELEGRAM)) { + allowlist.telegram.add(entry); + } + for (const entry of parseList(env.ALLOW_FROM_WHATSAPP)) { + allowlist.whatsapp.add(entry); + } + + return allowlist; +} + +export function loadConfig( + env: EnvLike = process.env, + options: { requireOpencode?: boolean } = {}, +): Config { + const requireOpencode = options.requireOpencode ?? true; + const opencodeDirectory = env.OPENCODE_DIRECTORY?.trim(); + if (!opencodeDirectory && requireOpencode) { + throw new Error("OPENCODE_DIRECTORY is required"); + } + const resolvedDirectory = opencodeDirectory || process.cwd(); + + const dataDir = expandHome(env.OWPENBOT_DATA_DIR ?? "~/.owpenbot"); + const dbPath = expandHome(env.OWPENBOT_DB_PATH ?? path.join(dataDir, "owpenbot.db")); + const whatsappAuthDir = expandHome(env.WHATSAPP_AUTH_DIR ?? path.join(dataDir, "whatsapp")); + + const toolOutputLimit = parseInteger(env.TOOL_OUTPUT_LIMIT) ?? 1200; + const permissionMode = env.PERMISSION_MODE?.toLowerCase() === "deny" ? "deny" : "allow"; + + return { + opencodeUrl: env.OPENCODE_URL?.trim() ?? "http://127.0.0.1:4096", + opencodeDirectory: resolvedDirectory, + opencodeUsername: env.OPENCODE_SERVER_USERNAME?.trim() || undefined, + opencodePassword: env.OPENCODE_SERVER_PASSWORD?.trim() || undefined, + telegramToken: env.TELEGRAM_BOT_TOKEN?.trim() || undefined, + telegramEnabled: parseBoolean(env.TELEGRAM_ENABLED, Boolean(env.TELEGRAM_BOT_TOKEN?.trim())), + whatsappAuthDir, + whatsappEnabled: parseBoolean(env.WHATSAPP_ENABLED, true), + dataDir, + dbPath, + allowlist: parseAllowlist(env), + pairingCode: env.PAIRING_CODE?.trim() || undefined, + toolUpdatesEnabled: parseBoolean(env.TOOL_UPDATES_ENABLED, false), + groupsEnabled: parseBoolean(env.GROUPS_ENABLED, false), + permissionMode, + toolOutputLimit, + healthPort: parseInteger(env.OWPENBOT_HEALTH_PORT), + logLevel: env.LOG_LEVEL?.trim() || "info", + }; +} diff --git a/packages/owpenbot/src/db.ts b/packages/owpenbot/src/db.ts new file mode 100644 index 00000000..ddc987df --- /dev/null +++ b/packages/owpenbot/src/db.ts @@ -0,0 +1,122 @@ +import fs from "node:fs"; +import path from "node:path"; + +import Database from "better-sqlite3"; + +import type { ChannelName } from "./config.js"; + +type SessionRow = { + channel: ChannelName; + peer_id: string; + session_id: string; + created_at: number; + updated_at: number; +}; + +type AllowlistRow = { + channel: ChannelName; + peer_id: string; + created_at: number; +}; + +export class BridgeStore { + private db: Database.Database; + + constructor(private readonly dbPath: string) { + this.ensureDir(); + this.db = new Database(dbPath); + this.db.pragma("journal_mode = WAL"); + this.db.exec(` + CREATE TABLE IF NOT EXISTS sessions ( + channel TEXT NOT NULL, + peer_id TEXT NOT NULL, + session_id TEXT NOT NULL, + created_at INTEGER NOT NULL, + updated_at INTEGER NOT NULL, + PRIMARY KEY (channel, peer_id) + ); + CREATE TABLE IF NOT EXISTS allowlist ( + channel TEXT NOT NULL, + peer_id TEXT NOT NULL, + created_at INTEGER NOT NULL, + PRIMARY KEY (channel, peer_id) + ); + CREATE TABLE IF NOT EXISTS settings ( + key TEXT PRIMARY KEY, + value TEXT NOT NULL + ); + `); + } + + private ensureDir() { + const dir = path.dirname(this.dbPath); + fs.mkdirSync(dir, { recursive: true }); + } + + getSession(channel: ChannelName, peerId: string): SessionRow | null { + const stmt = this.db.prepare( + "SELECT channel, peer_id, session_id, created_at, updated_at FROM sessions WHERE channel = ? AND peer_id = ?", + ); + const row = stmt.get(channel, peerId) as SessionRow | undefined; + return row ?? null; + } + + upsertSession(channel: ChannelName, peerId: string, sessionId: string) { + const now = Date.now(); + const stmt = this.db.prepare( + `INSERT INTO sessions (channel, peer_id, session_id, created_at, updated_at) + VALUES (?, ?, ?, ?, ?) + ON CONFLICT(channel, peer_id) DO UPDATE SET session_id = excluded.session_id, updated_at = excluded.updated_at`, + ); + stmt.run(channel, peerId, sessionId, now, now); + } + + isAllowed(channel: ChannelName, peerId: string): boolean { + const stmt = this.db.prepare( + "SELECT channel, peer_id, created_at FROM allowlist WHERE channel = ? AND peer_id = ?", + ); + return Boolean(stmt.get(channel, peerId)); + } + + allowPeer(channel: ChannelName, peerId: string) { + const now = Date.now(); + const stmt = this.db.prepare( + `INSERT INTO allowlist (channel, peer_id, created_at) + VALUES (?, ?, ?) + ON CONFLICT(channel, peer_id) DO UPDATE SET created_at = excluded.created_at`, + ); + stmt.run(channel, peerId, now); + } + + seedAllowlist(channel: ChannelName, peers: Iterable) { + const insert = this.db.prepare( + `INSERT INTO allowlist (channel, peer_id, created_at) + VALUES (?, ?, ?) + ON CONFLICT(channel, peer_id) DO NOTHING`, + ); + const now = Date.now(); + const transaction = this.db.transaction((items: Iterable) => { + for (const peer of items) { + insert.run(channel, peer, now); + } + }); + transaction(peers); + } + + getSetting(key: string): string | null { + const stmt = this.db.prepare("SELECT value FROM settings WHERE key = ?"); + const row = stmt.get(key) as { value?: string } | undefined; + return row?.value ?? null; + } + + setSetting(key: string, value: string) { + const stmt = this.db.prepare( + "INSERT INTO settings (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value", + ); + stmt.run(key, value); + } + + close() { + this.db.close(); + } +} diff --git a/packages/owpenbot/src/events.ts b/packages/owpenbot/src/events.ts new file mode 100644 index 00000000..b7fa374a --- /dev/null +++ b/packages/owpenbot/src/events.ts @@ -0,0 +1,21 @@ +type RawEvent = { + type?: string; + properties?: unknown; + payload?: { type?: string; properties?: unknown }; +}; + +export type NormalizedEvent = { + type: string; + properties?: any; +}; + +export function normalizeEvent(raw: RawEvent | null | undefined): NormalizedEvent | null { + if (!raw) return null; + if (typeof raw.type === "string") { + return { type: raw.type, properties: raw.properties }; + } + if (raw.payload && typeof raw.payload.type === "string") { + return { type: raw.payload.type, properties: raw.payload.properties }; + } + return null; +} diff --git a/packages/owpenbot/src/health.ts b/packages/owpenbot/src/health.ts new file mode 100644 index 00000000..fb6db3a6 --- /dev/null +++ b/packages/owpenbot/src/health.ts @@ -0,0 +1,44 @@ +import http from "node:http"; + +import type { Logger } from "pino"; + +export type HealthSnapshot = { + ok: boolean; + opencode: { + url: string; + healthy: boolean; + version?: string; + }; + channels: { + telegram: boolean; + whatsapp: boolean; + }; +}; + +export function startHealthServer( + port: number, + getStatus: () => HealthSnapshot, + logger: Logger, +) { + const server = http.createServer((req, res) => { + if (!req.url || req.url === "/health") { + const snapshot = getStatus(); + res.writeHead(snapshot.ok ? 200 : 503, { + "Content-Type": "application/json", + }); + res.end(JSON.stringify(snapshot)); + return; + } + + res.writeHead(404, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ ok: false, error: "Not found" })); + }); + + server.listen(port, "0.0.0.0", () => { + logger.info({ port }, "health server listening"); + }); + + return () => { + server.close(); + }; +} diff --git a/packages/owpenbot/src/logger.ts b/packages/owpenbot/src/logger.ts new file mode 100644 index 00000000..eaa78489 --- /dev/null +++ b/packages/owpenbot/src/logger.ts @@ -0,0 +1,8 @@ +import pino from "pino"; + +export function createLogger(level: string) { + return pino({ + level, + base: undefined, + }); +} diff --git a/packages/owpenbot/src/opencode.ts b/packages/owpenbot/src/opencode.ts new file mode 100644 index 00000000..cf17b059 --- /dev/null +++ b/packages/owpenbot/src/opencode.ts @@ -0,0 +1,43 @@ +import { Buffer } from "node:buffer"; + +import { createOpencodeClient } from "@opencode-ai/sdk/v2/client"; + +import type { Config } from "./config.js"; + +type Client = ReturnType; + +export function createClient(config: Config): Client { + const headers: Record = {}; + if (config.opencodeUsername && config.opencodePassword) { + const token = Buffer.from(`${config.opencodeUsername}:${config.opencodePassword}`).toString("base64"); + headers.Authorization = `Basic ${token}`; + } + + return createOpencodeClient({ + baseUrl: config.opencodeUrl, + directory: config.opencodeDirectory, + headers: Object.keys(headers).length ? headers : undefined, + responseStyle: "data", + throwOnError: true, + }); +} + +export function buildPermissionRules(mode: Config["permissionMode"]) { + if (mode === "deny") { + return [ + { + permission: "*", + pattern: "*", + action: "deny" as const, + }, + ]; + } + + return [ + { + permission: "*", + pattern: "*", + action: "allow" as const, + }, + ]; +} diff --git a/packages/owpenbot/src/pairing.ts b/packages/owpenbot/src/pairing.ts new file mode 100644 index 00000000..1123703d --- /dev/null +++ b/packages/owpenbot/src/pairing.ts @@ -0,0 +1,19 @@ +import { randomInt } from "node:crypto"; + +import { BridgeStore } from "./db.js"; + +const SETTING_KEY = "pairing_code"; + +export function resolvePairingCode(store: BridgeStore, override?: string): string { + if (override) { + store.setSetting(SETTING_KEY, override); + return override; + } + + const existing = store.getSetting(SETTING_KEY); + if (existing) return existing; + + const code = String(randomInt(100000, 999999)); + store.setSetting(SETTING_KEY, code); + return code; +} diff --git a/packages/owpenbot/src/telegram.ts b/packages/owpenbot/src/telegram.ts new file mode 100644 index 00000000..1e7229b3 --- /dev/null +++ b/packages/owpenbot/src/telegram.ts @@ -0,0 +1,76 @@ +import { Bot, type BotError, type Context } from "grammy"; +import type { Logger } from "pino"; + +import type { Config } from "./config.js"; + +export type InboundMessage = { + channel: "telegram"; + peerId: string; + text: string; + raw: unknown; +}; + +export type MessageHandler = (message: InboundMessage) => Promise | void; + +export type TelegramAdapter = { + name: "telegram"; + maxTextLength: number; + start(): Promise; + stop(): Promise; + sendText(peerId: string, text: string): Promise; +}; + +const MAX_TEXT_LENGTH = 4096; + +export function createTelegramAdapter( + config: Config, + logger: Logger, + onMessage: MessageHandler, +): TelegramAdapter { + if (!config.telegramToken) { + throw new Error("TELEGRAM_BOT_TOKEN is required for Telegram adapter"); + } + + const bot = new Bot(config.telegramToken); + + bot.catch((err: BotError) => { + logger.error({ error: err.error }, "telegram bot error"); + }); + + bot.on("message", async (ctx: Context) => { + const msg = ctx.message; + if (!msg?.chat) return; + + const chatType = msg.chat.type as string; + const isGroup = chatType === "group" || chatType === "supergroup" || chatType === "channel"; + if (isGroup && !config.groupsEnabled) { + return; + } + + const text = msg.text ?? msg.caption ?? ""; + if (!text.trim()) return; + + await onMessage({ + channel: "telegram", + peerId: String(msg.chat.id), + text, + raw: msg, + }); + }); + + return { + name: "telegram", + maxTextLength: MAX_TEXT_LENGTH, + async start() { + await bot.start(); + logger.info("telegram adapter started"); + }, + async stop() { + bot.stop(); + logger.info("telegram adapter stopped"); + }, + async sendText(peerId: string, text: string) { + await bot.api.sendMessage(Number(peerId), text); + }, + }; +} diff --git a/packages/owpenbot/src/text.ts b/packages/owpenbot/src/text.ts new file mode 100644 index 00000000..bd4b5cc3 --- /dev/null +++ b/packages/owpenbot/src/text.ts @@ -0,0 +1,38 @@ +export function chunkText(input: string, limit: number): string[] { + if (input.length <= limit) return [input]; + const chunks: string[] = []; + let current = ""; + + for (const line of input.split(/\n/)) { + if ((current + line).length + 1 > limit) { + if (current) chunks.push(current.trimEnd()); + current = ""; + } + if (line.length > limit) { + for (let i = 0; i < line.length; i += limit) { + const slice = line.slice(i, i + limit); + if (slice.length) chunks.push(slice); + } + continue; + } + current += current ? `\n${line}` : line; + } + + if (current.trim().length) chunks.push(current.trimEnd()); + return chunks.length ? chunks : [input]; +} + +export function truncateText(text: string, limit: number): string { + if (text.length <= limit) return text; + return `${text.slice(0, Math.max(0, limit - 1))}…`; +} + +export function formatInputSummary(input: Record): string { + const entries = Object.entries(input); + if (!entries.length) return ""; + try { + return JSON.stringify(input); + } catch { + return entries.map(([key, value]) => `${key}=${String(value)}`).join(", "); + } +} diff --git a/packages/owpenbot/src/whatsapp.ts b/packages/owpenbot/src/whatsapp.ts new file mode 100644 index 00000000..6811acb9 --- /dev/null +++ b/packages/owpenbot/src/whatsapp.ts @@ -0,0 +1,204 @@ +import fs from "node:fs"; +import path from "node:path"; + +import { + DisconnectReason, + fetchLatestBaileysVersion, + isJidGroup, + makeCacheableSignalKeyStore, + makeWASocket, + useMultiFileAuthState, + type WAMessage, +} from "@whiskeysockets/baileys"; +import qrcode from "qrcode-terminal"; +import type { Logger } from "pino"; + +import type { Config } from "./config.js"; + +export type InboundMessage = { + channel: "whatsapp"; + peerId: string; + text: string; + raw: unknown; +}; + +export type MessageHandler = (message: InboundMessage) => Promise | void; + +export type WhatsAppAdapter = { + name: "whatsapp"; + maxTextLength: number; + start(): Promise; + stop(): Promise; + sendText(peerId: string, text: string): Promise; +}; + +const MAX_TEXT_LENGTH = 3800; + +function extractText(message: WAMessage): string { + const content = message.message; + if (!content) return ""; + return ( + content.conversation || + content.extendedTextMessage?.text || + content.imageMessage?.caption || + content.videoMessage?.caption || + content.documentMessage?.caption || + "" + ); +} + +function ensureDir(dir: string) { + fs.mkdirSync(dir, { recursive: true }); +} + +export function createWhatsAppAdapter( + config: Config, + logger: Logger, + onMessage: MessageHandler, + opts: { printQr?: boolean } = {}, +): WhatsAppAdapter { + let socket: ReturnType | null = null; + let stopped = false; + + const log = logger.child({ channel: "whatsapp" }); + const authDir = path.resolve(config.whatsappAuthDir); + ensureDir(authDir); + + async function connect() { + const { state, saveCreds } = await useMultiFileAuthState(authDir); + const { version } = await fetchLatestBaileysVersion(); + + const sock = makeWASocket({ + auth: { + creds: state.creds, + keys: makeCacheableSignalKeyStore(state.keys, log), + }, + version, + logger: log, + printQRInTerminal: false, + syncFullHistory: false, + markOnlineOnConnect: false, + browser: ["owpenbot", "cli", "0.1.0"], + }); + + sock.ev.on("creds.update", saveCreds); + sock.ev.on("connection.update", (update: { connection?: string; lastDisconnect?: unknown; qr?: string }) => { + if (update.qr && opts.printQr) { + qrcode.generate(update.qr, { small: true }); + log.info("scan the QR code to connect WhatsApp"); + } + + if (update.connection === "open") { + log.info("whatsapp connected"); + } + + if (update.connection === "close") { + const lastDisconnect = update.lastDisconnect as + | { error?: { output?: { statusCode?: number } } } + | undefined; + const statusCode = lastDisconnect?.error?.output?.statusCode; + const shouldReconnect = statusCode !== DisconnectReason.loggedOut; + if (shouldReconnect && !stopped) { + log.warn("whatsapp connection closed, reconnecting"); + void connect(); + } else if (!shouldReconnect) { + log.warn("whatsapp logged out, run 'owpenbot whatsapp login'"); + } + } + }); + + sock.ev.on("messages.upsert", async ({ messages }: { messages: WAMessage[] }) => { + for (const msg of messages) { + if (!msg.message || msg.key.fromMe) continue; + const peerId = msg.key.remoteJid; + if (!peerId) continue; + if (isJidGroup(peerId) && !config.groupsEnabled) { + continue; + } + const text = extractText(msg); + if (!text.trim()) continue; + + await onMessage({ + channel: "whatsapp", + peerId, + text, + raw: msg, + }); + } + }); + + socket = sock; + } + + return { + name: "whatsapp", + maxTextLength: MAX_TEXT_LENGTH, + async start() { + await connect(); + }, + async stop() { + stopped = true; + if (socket) { + socket.end(undefined); + socket = null; + } + }, + async sendText(peerId: string, text: string) { + if (!socket) throw new Error("WhatsApp socket not initialized"); + await socket.sendMessage(peerId, { text }); + }, + }; +} + +export async function loginWhatsApp(config: Config, logger: Logger) { + const authDir = path.resolve(config.whatsappAuthDir); + ensureDir(authDir); + const log = logger.child({ channel: "whatsapp" }); + const { state, saveCreds } = await useMultiFileAuthState(authDir); + const { version } = await fetchLatestBaileysVersion(); + + await new Promise((resolve) => { + let finished = false; + const sock = makeWASocket({ + auth: { + creds: state.creds, + keys: makeCacheableSignalKeyStore(state.keys, log), + }, + version, + logger: log, + printQRInTerminal: false, + syncFullHistory: false, + markOnlineOnConnect: false, + browser: ["owpenbot", "cli", "0.1.0"], + }); + + const finish = (reason: string) => { + if (finished) return; + finished = true; + log.info({ reason }, "whatsapp login finished"); + sock.end(undefined); + resolve(); + }; + + sock.ev.on("creds.update", async () => { + await saveCreds(); + if (state.creds?.registered) { + finish("creds.registered"); + } + }); + sock.ev.on("connection.update", (update: { connection?: string; qr?: string }) => { + if (update.qr) { + qrcode.generate(update.qr, { small: true }); + log.info("scan the QR code to connect WhatsApp"); + } + + if (update.connection === "open") { + finish("connection.open"); + } + + if (update.connection === "close" && state.creds?.registered) { + finish("connection.close.registered"); + } + }); + }); +} diff --git a/packages/owpenbot/test/db.test.js b/packages/owpenbot/test/db.test.js new file mode 100644 index 00000000..6fb33895 --- /dev/null +++ b/packages/owpenbot/test/db.test.js @@ -0,0 +1,23 @@ +import assert from "node:assert/strict"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import test from "node:test"; + +import { BridgeStore } from "../dist/db.js"; + +test("BridgeStore allowlist and sessions", () => { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "owpenbot-")); + const dbPath = path.join(dir, "owpenbot.db"); + const store = new BridgeStore(dbPath); + + assert.equal(store.isAllowed("telegram", "123"), false); + store.allowPeer("telegram", "123"); + assert.equal(store.isAllowed("telegram", "123"), true); + + store.upsertSession("telegram", "123", "session-1"); + const row = store.getSession("telegram", "123"); + assert.equal(row?.session_id, "session-1"); + + store.close(); +}); diff --git a/packages/owpenbot/tsconfig.json b/packages/owpenbot/tsconfig.json new file mode 100644 index 00000000..508dccf3 --- /dev/null +++ b/packages/owpenbot/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "dist", + "rootDir": "src", + "strict": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "types": ["node"] + }, + "include": ["src"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ed72e1ff..330ed1c2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -52,7 +52,7 @@ importers: devDependencies: '@tailwindcss/vite': specifier: ^4.1.18 - version: 4.1.18(vite@6.4.1(jiti@2.6.1)(lightningcss@1.30.2)) + version: 4.1.18(vite@6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)) tailwindcss: specifier: ^4.1.18 version: 4.1.18 @@ -61,10 +61,10 @@ importers: version: 5.9.3 vite: specifier: ^6.0.1 - version: 6.4.1(jiti@2.6.1)(lightningcss@1.30.2) + version: 6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0) vite-plugin-solid: specifier: ^2.11.0 - version: 2.11.10(solid-js@1.9.10)(vite@6.4.1(jiti@2.6.1)(lightningcss@1.30.2)) + version: 2.11.10(solid-js@1.9.10)(vite@6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)) packages/desktop: devDependencies: @@ -72,6 +72,49 @@ importers: specifier: ^2.0.0 version: 2.9.6 + packages/owpenbot: + dependencies: + '@opencode-ai/sdk': + specifier: ^1.1.19 + version: 1.1.20 + '@whiskeysockets/baileys': + specifier: 7.0.0-rc.9 + version: 7.0.0-rc.9(sharp@0.34.5) + better-sqlite3: + specifier: ^11.7.0 + version: 11.10.0 + commander: + specifier: ^12.1.0 + version: 12.1.0 + dotenv: + specifier: ^16.4.7 + version: 16.6.1 + grammy: + specifier: ^1.39.3 + version: 1.39.3 + pino: + specifier: ^9.6.0 + version: 9.14.0 + qrcode-terminal: + specifier: ^0.12.0 + version: 0.12.0 + devDependencies: + '@types/better-sqlite3': + specifier: ^7.6.12 + version: 7.6.13 + '@types/node': + specifier: ^22.10.2 + version: 22.19.7 + '@types/qrcode-terminal': + specifier: ^0.12.0 + version: 0.12.2 + tsx: + specifier: ^4.19.2 + version: 4.21.0 + typescript: + specifier: ^5.6.3 + version: 5.9.3 + packages: '@babel/code-frame@7.28.6': @@ -155,162 +198,480 @@ packages: resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} engines: {node: '>=6.9.0'} + '@borewit/text-codec@0.2.1': + resolution: {integrity: sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==} + + '@cacheable/memory@2.0.7': + resolution: {integrity: sha512-RbxnxAMf89Tp1dLhXMS7ceft/PGsDl1Ip7T20z5nZ+pwIAsQ1p2izPjVG69oCLv/jfQ7HDPHTWK0c9rcAWXN3A==} + + '@cacheable/node-cache@1.7.6': + resolution: {integrity: sha512-6Omk2SgNnjtxB5f/E6bTIWIt5xhdpx39fGNRQgU9lojvRxU68v+qY+SXXLsp3ZGukqoPjsK21wZ6XABFr/Ge3A==} + engines: {node: '>=18'} + + '@cacheable/utils@2.3.3': + resolution: {integrity: sha512-JsXDL70gQ+1Vc2W/KUFfkAJzgb4puKwwKehNLuB+HrNKWf91O736kGfxn4KujXCCSuh6mRRL4XEB0PkAFjWS0A==} + + '@emnapi/runtime@1.8.1': + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} + '@esbuild/aix-ppc64@0.25.12': resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.27.2': + resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.25.12': resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.27.2': + resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.25.12': resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.27.2': + resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.25.12': resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.27.2': + resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.25.12': resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.27.2': + resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.25.12': resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.27.2': + resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.25.12': resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.27.2': + resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.12': resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.27.2': + resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.25.12': resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.27.2': + resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.25.12': resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.27.2': + resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.25.12': resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.27.2': + resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.25.12': resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.27.2': + resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.25.12': resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.27.2': + resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.25.12': resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.27.2': + resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.25.12': resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.27.2': + resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.25.12': resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.27.2': + resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.25.12': resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.27.2': + resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.12': resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.27.2': + resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.12': resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.27.2': + resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.12': resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.27.2': + resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.12': resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.27.2': + resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.25.12': resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.27.2': + resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.25.12': resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.27.2': + resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.25.12': resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.27.2': + resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.25.12': resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.27.2': + resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.25.12': resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.27.2': + resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@grammyjs/types@3.23.0': + resolution: {integrity: sha512-D3jQ4UWERPsyR3op/YFudMMIPNTU47vy7L51uO9/73tMELmjO/+LX5N36/Y0CG5IQfIsz43MxiHI5rgsK0/k+g==} + + '@hapi/boom@9.1.4': + resolution: {integrity: sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw==} + + '@hapi/hoek@9.3.0': + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -327,9 +688,51 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@keyv/bigmap@1.3.1': + resolution: {integrity: sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==} + engines: {node: '>= 18'} + peerDependencies: + keyv: ^5.6.0 + + '@keyv/serialize@1.1.1': + resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} + '@opencode-ai/sdk@1.1.20': resolution: {integrity: sha512-OYzRFqf13y09TSiaQynsInpvJ2benk63NX+4HM7PbV85vYluGxRIB4j7CLCQUGojFmUz8+gOwiJ8+DDnv1h7lQ==} + '@pinojs/redact@0.4.0': + resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} + + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + '@radix-ui/colors@3.0.0': resolution: {integrity: sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==} @@ -656,6 +1059,13 @@ packages: '@tauri-apps/plugin-updater@2.9.0': resolution: {integrity: sha512-j++sgY8XpeDvzImTrzWA08OqqGqgkNyxczLD7FjNJJx/uXxMZFz5nDcfkyoI/rCjYuj2101Tci/r/HFmOmoxCg==} + '@tokenizer/inflate@0.4.1': + resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} + engines: {node: '>=18'} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -668,9 +1078,55 @@ packages: '@types/babel__traverse@7.28.0': resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/better-sqlite3@7.6.13': + resolution: {integrity: sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/long@4.0.2': + resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} + + '@types/node@10.17.60': + resolution: {integrity: sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==} + + '@types/node@22.19.7': + resolution: {integrity: sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==} + + '@types/qrcode-terminal@0.12.2': + resolution: {integrity: sha512-v+RcIEJ+Uhd6ygSQ0u5YYY7ZM+la7GgPbs0V/7l/kFs2uO4S8BcIUEMoP7za4DNIqNnUD5npf0A/7kBhrCKG5Q==} + + '@whiskeysockets/baileys@7.0.0-rc.9': + resolution: {integrity: sha512-YFm5gKXfDP9byCXCW3OPHKXLzrAKzolzgVUlRosHHgwbnf2YOO3XknkMm6J7+F0ns8OA0uuSBhgkRHTDtqkacw==} + engines: {node: '>=20.0.0'} + peerDependencies: + audio-decode: ^2.1.3 + jimp: ^1.6.0 + link-preview-js: ^3.0.0 + sharp: '*' + peerDependenciesMeta: + audio-decode: + optional: true + jimp: + optional: true + link-preview-js: + optional: true + + '@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67': + resolution: {tarball: https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67} + version: 2.0.1 + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + async-mutex@0.5.0: + resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==} + + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + babel-plugin-jsx-dom-expressions@0.40.3: resolution: {integrity: sha512-5HOwwt0BYiv/zxl7j8Pf2bGL6rDXfV6nUhLs8ygBX+EFJXzBPHM/euj9j/6deMZ6wa52Wb2PBaAV5U/jKwIY1w==} peerDependencies: @@ -685,24 +1141,56 @@ packages: solid-js: optional: true + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + baseline-browser-mapping@2.9.14: resolution: {integrity: sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==} hasBin: true + better-sqlite3@11.10.0: + resolution: {integrity: sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + browserslist@4.28.1: resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + cacheable@2.3.2: + resolution: {integrity: sha512-w+ZuRNmex9c1TR9RcsxbfTKCjSL0rh1WA5SABbrWprIHeNBdmyQLSYonlDy9gpD+63XT8DgZ/wNh1Smvc9WnJA==} + caniuse-lite@1.0.30001764: resolution: {integrity: sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==} + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + curve25519-js@0.0.4: + resolution: {integrity: sha512-axn2UMEnkhyDUPWOwVKBMVIzSQy2ejH2xRGy1wq81dqRwApXfIzfbE3hIX0ZRFBIihf/KDqK158DLwESu4AK1w==} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -712,13 +1200,28 @@ packages: supports-color: optional: true + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + electron-to-chromium@1.5.267: resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + enhanced-resolve@5.18.4: resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} engines: {node: '>=10.13.0'} @@ -732,10 +1235,26 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.27.2: + resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -745,6 +1264,16 @@ packages: picomatch: optional: true + file-type@21.3.0: + resolution: {integrity: sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==} + engines: {node: '>=20'} + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -754,12 +1283,38 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + grammy@1.39.3: + resolution: {integrity: sha512-7arRRoOtOh9UwMwANZ475kJrWV6P3/EGNooeHlY0/SwZv4t3ZZ3Uiz9cAXK8Zg9xSdgmm8T21kx6n7SZaWvOcw==} + engines: {node: ^12.20.0 || >=14.13.1} + + hashery@1.4.0: + resolution: {integrity: sha512-Wn2i1In6XFxl8Az55kkgnFRiAlIAushzh26PTjL2AKtQcEfXrcLa7Hn5QOWGZEf3LU057P9TwwZjFyxfS1VuvQ==} + engines: {node: '>=20'} + + hookified@1.15.0: + resolution: {integrity: sha512-51w+ZZGt7Zw5q7rM3nC4t3aLn/xvKDETsXqMczndvwyVQhAHfUmUuFBRFcos8Iyebtk7OAE9dL26wFNzZVVOkw==} + html-entities@2.3.3: resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + is-what@4.1.16: resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} engines: {node: '>=12.13'} @@ -784,6 +1339,9 @@ packages: jsonc-parser@3.3.1: resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + keyv@5.6.0: + resolution: {integrity: sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==} + lightningcss-android-arm64@1.30.2: resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} engines: {node: '>= 12.0.0'} @@ -854,6 +1412,16 @@ packages: resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} engines: {node: '>= 12.0.0'} + long@4.0.0: + resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + + lru-cache@11.2.4: + resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -870,21 +1438,70 @@ packages: engines: {node: '>= 20'} hasBin: true + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + merge-anything@5.1.7: resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==} engines: {node: '>=12.13'} + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + music-metadata@11.10.6: + resolution: {integrity: sha512-Wb1EigQ3/Z7zrQl0XP16ipxB+rN0J0CHUTbTRtVu9GViALYafb6xT5UGzIfszCG1lscmkutjHO2RYbJ9TFyslA==} + engines: {node: '>=18'} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + + node-abi@3.87.0: + resolution: {integrity: sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==} + engines: {node: '>=10'} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + p-queue@9.1.0: + resolution: {integrity: sha512-O/ZPaXuQV29uSLbxWBGGZO1mCQXV2BLIwUr59JUU9SoH76mnYvtms7aafH/isNSNGwuEfP6W/4xD0/TJXxrizw==} + engines: {node: '>=20'} + + p-timeout@7.0.1: + resolution: {integrity: sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==} + engines: {node: '>=20'} + parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} @@ -895,19 +1512,86 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + + pino-std-serializers@7.1.0: + resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} + + pino@9.14.0: + resolution: {integrity: sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==} + hasBin: true + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + hasBin: true + + process-warning@5.0.0: + resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + + protobufjs@6.8.8: + resolution: {integrity: sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==} + hasBin: true + + protobufjs@7.5.4: + resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==} + engines: {node: '>=12.0.0'} + + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + + qified@0.6.0: + resolution: {integrity: sha512-tsSGN1x3h569ZSU1u6diwhltLyfUWDp3YbFHedapTmpBl0B3P6U3+Qptg7xu+v+1io1EwhdPyyRHYbEw0KN2FA==} + engines: {node: '>=20'} + + qrcode-terminal@0.12.0: + resolution: {integrity: sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==} + hasBin: true + + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + rollup@4.55.1: resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + seroval-plugins@1.3.3: resolution: {integrity: sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==} engines: {node: '>=10'} @@ -918,6 +1602,16 @@ packages: resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==} engines: {node: '>=10'} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + solid-js@1.9.10: resolution: {integrity: sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==} @@ -926,10 +1620,28 @@ packages: peerDependencies: solid-js: ^1.3 + sonic-boom@4.2.0: + resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strtok3@10.3.4: + resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==} + engines: {node: '>=18'} + tailwindcss@4.1.18: resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} @@ -937,21 +1649,59 @@ packages: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} + token-types@6.1.2: + resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} + engines: {node: '>=14.16'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} + hasBin: true + + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + vite-plugin-solid@2.11.10: resolution: {integrity: sha512-Yr1dQybmtDtDAHkii6hXuc1oVH9CPcS/Zb2jN/P36qqcrkNnVPsMTzQ06jyzFPFjj3U1IYKMVt/9ZqcwGCEbjw==} peerDependencies: @@ -1010,6 +1760,30 @@ packages: vite: optional: true + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + win-guid@0.1.3: + resolution: {integrity: sha512-Ah25z4XnblBGFgrcVS5QK7qLkvsFFA35+G+AnHkELUPHXPYWFOSVNMuAxf1zW0B+4X911IBLD+TvB771om0gmg==} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.19.0: + resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -1126,84 +1900,291 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@borewit/text-codec@0.2.1': {} + + '@cacheable/memory@2.0.7': + dependencies: + '@cacheable/utils': 2.3.3 + '@keyv/bigmap': 1.3.1(keyv@5.6.0) + hookified: 1.15.0 + keyv: 5.6.0 + + '@cacheable/node-cache@1.7.6': + dependencies: + cacheable: 2.3.2 + hookified: 1.15.0 + keyv: 5.6.0 + + '@cacheable/utils@2.3.3': + dependencies: + hashery: 1.4.0 + keyv: 5.6.0 + + '@emnapi/runtime@1.8.1': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild/aix-ppc64@0.25.12': optional: true + '@esbuild/aix-ppc64@0.27.2': + optional: true + '@esbuild/android-arm64@0.25.12': optional: true + '@esbuild/android-arm64@0.27.2': + optional: true + '@esbuild/android-arm@0.25.12': optional: true + '@esbuild/android-arm@0.27.2': + optional: true + '@esbuild/android-x64@0.25.12': optional: true + '@esbuild/android-x64@0.27.2': + optional: true + '@esbuild/darwin-arm64@0.25.12': optional: true + '@esbuild/darwin-arm64@0.27.2': + optional: true + '@esbuild/darwin-x64@0.25.12': optional: true + '@esbuild/darwin-x64@0.27.2': + optional: true + '@esbuild/freebsd-arm64@0.25.12': optional: true + '@esbuild/freebsd-arm64@0.27.2': + optional: true + '@esbuild/freebsd-x64@0.25.12': optional: true + '@esbuild/freebsd-x64@0.27.2': + optional: true + '@esbuild/linux-arm64@0.25.12': optional: true + '@esbuild/linux-arm64@0.27.2': + optional: true + '@esbuild/linux-arm@0.25.12': optional: true + '@esbuild/linux-arm@0.27.2': + optional: true + '@esbuild/linux-ia32@0.25.12': optional: true + '@esbuild/linux-ia32@0.27.2': + optional: true + '@esbuild/linux-loong64@0.25.12': optional: true + '@esbuild/linux-loong64@0.27.2': + optional: true + '@esbuild/linux-mips64el@0.25.12': optional: true + '@esbuild/linux-mips64el@0.27.2': + optional: true + '@esbuild/linux-ppc64@0.25.12': optional: true + '@esbuild/linux-ppc64@0.27.2': + optional: true + '@esbuild/linux-riscv64@0.25.12': optional: true + '@esbuild/linux-riscv64@0.27.2': + optional: true + '@esbuild/linux-s390x@0.25.12': optional: true + '@esbuild/linux-s390x@0.27.2': + optional: true + '@esbuild/linux-x64@0.25.12': optional: true + '@esbuild/linux-x64@0.27.2': + optional: true + '@esbuild/netbsd-arm64@0.25.12': optional: true + '@esbuild/netbsd-arm64@0.27.2': + optional: true + '@esbuild/netbsd-x64@0.25.12': optional: true + '@esbuild/netbsd-x64@0.27.2': + optional: true + '@esbuild/openbsd-arm64@0.25.12': optional: true + '@esbuild/openbsd-arm64@0.27.2': + optional: true + '@esbuild/openbsd-x64@0.25.12': optional: true + '@esbuild/openbsd-x64@0.27.2': + optional: true + '@esbuild/openharmony-arm64@0.25.12': optional: true + '@esbuild/openharmony-arm64@0.27.2': + optional: true + '@esbuild/sunos-x64@0.25.12': optional: true + '@esbuild/sunos-x64@0.27.2': + optional: true + '@esbuild/win32-arm64@0.25.12': optional: true + '@esbuild/win32-arm64@0.27.2': + optional: true + '@esbuild/win32-ia32@0.25.12': optional: true + '@esbuild/win32-ia32@0.27.2': + optional: true + '@esbuild/win32-x64@0.25.12': optional: true + '@esbuild/win32-x64@0.27.2': + optional: true + + '@grammyjs/types@3.23.0': {} + + '@hapi/boom@9.1.4': + dependencies: + '@hapi/hoek': 9.3.0 + + '@hapi/hoek@9.3.0': {} + + '@img/colour@1.0.0': {} + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.8.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -1223,8 +2204,41 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@keyv/bigmap@1.3.1(keyv@5.6.0)': + dependencies: + hashery: 1.4.0 + hookified: 1.15.0 + keyv: 5.6.0 + + '@keyv/serialize@1.1.1': {} + '@opencode-ai/sdk@1.1.20': {} + '@pinojs/redact@0.4.0': {} + + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.4': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.0': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.0': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.0': {} + '@radix-ui/colors@3.0.0': {} '@rollup/rollup-android-arm-eabi@4.55.1': @@ -1377,12 +2391,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 - '@tailwindcss/vite@4.1.18(vite@6.4.1(jiti@2.6.1)(lightningcss@1.30.2))': + '@tailwindcss/vite@4.1.18(vite@6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))': dependencies: '@tailwindcss/node': 4.1.18 '@tailwindcss/oxide': 4.1.18 tailwindcss: 4.1.18 - vite: 6.4.1(jiti@2.6.1)(lightningcss@1.30.2) + vite: 6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0) '@tauri-apps/api@2.9.1': {} @@ -1449,6 +2463,15 @@ snapshots: dependencies: '@tauri-apps/api': 2.9.1 + '@tokenizer/inflate@0.4.1': + dependencies: + debug: 4.4.3 + token-types: 6.1.2 + transitivePeerDependencies: + - supports-color + + '@tokenizer/token@0.3.0': {} + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.28.6 @@ -1470,8 +2493,55 @@ snapshots: dependencies: '@babel/types': 7.28.6 + '@types/better-sqlite3@7.6.13': + dependencies: + '@types/node': 22.19.7 + '@types/estree@1.0.8': {} + '@types/long@4.0.2': {} + + '@types/node@10.17.60': {} + + '@types/node@22.19.7': + dependencies: + undici-types: 6.21.0 + + '@types/qrcode-terminal@0.12.2': {} + + '@whiskeysockets/baileys@7.0.0-rc.9(sharp@0.34.5)': + dependencies: + '@cacheable/node-cache': 1.7.6 + '@hapi/boom': 9.1.4 + async-mutex: 0.5.0 + libsignal: '@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67' + lru-cache: 11.2.4 + music-metadata: 11.10.6 + p-queue: 9.1.0 + pino: 9.14.0 + protobufjs: 7.5.4 + sharp: 0.34.5 + ws: 8.19.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67': + dependencies: + curve25519-js: 0.0.4 + protobufjs: 6.8.8 + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + async-mutex@0.5.0: + dependencies: + tslib: 2.8.1 + + atomic-sleep@1.0.0: {} + babel-plugin-jsx-dom-expressions@0.40.3(@babel/core@7.28.6): dependencies: '@babel/core': 7.28.6 @@ -1488,8 +2558,25 @@ snapshots: optionalDependencies: solid-js: 1.9.10 + base64-js@1.5.1: {} + baseline-browser-mapping@2.9.14: {} + better-sqlite3@11.10.0: + dependencies: + bindings: 1.5.0 + prebuild-install: 7.1.3 + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.9.14 @@ -1498,20 +2585,53 @@ snapshots: node-releases: 2.0.27 update-browserslist-db: 1.2.3(browserslist@4.28.1) + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + cacheable@2.3.2: + dependencies: + '@cacheable/memory': 2.0.7 + '@cacheable/utils': 2.3.3 + hookified: 1.15.0 + keyv: 5.6.0 + qified: 0.6.0 + caniuse-lite@1.0.30001764: {} + chownr@1.1.4: {} + + commander@12.1.0: {} + + content-type@1.0.5: {} + convert-source-map@2.0.0: {} csstype@3.2.3: {} + curve25519-js@0.0.4: {} + debug@4.4.3: dependencies: ms: 2.1.3 + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + deep-extend@0.6.0: {} + detect-libc@2.1.2: {} + dotenv@16.6.1: {} + electron-to-chromium@1.5.267: {} + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + enhanced-resolve@5.18.4: dependencies: graceful-fs: 4.2.11 @@ -1548,21 +2668,97 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 + esbuild@0.27.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.2 + '@esbuild/android-arm': 0.27.2 + '@esbuild/android-arm64': 0.27.2 + '@esbuild/android-x64': 0.27.2 + '@esbuild/darwin-arm64': 0.27.2 + '@esbuild/darwin-x64': 0.27.2 + '@esbuild/freebsd-arm64': 0.27.2 + '@esbuild/freebsd-x64': 0.27.2 + '@esbuild/linux-arm': 0.27.2 + '@esbuild/linux-arm64': 0.27.2 + '@esbuild/linux-ia32': 0.27.2 + '@esbuild/linux-loong64': 0.27.2 + '@esbuild/linux-mips64el': 0.27.2 + '@esbuild/linux-ppc64': 0.27.2 + '@esbuild/linux-riscv64': 0.27.2 + '@esbuild/linux-s390x': 0.27.2 + '@esbuild/linux-x64': 0.27.2 + '@esbuild/netbsd-arm64': 0.27.2 + '@esbuild/netbsd-x64': 0.27.2 + '@esbuild/openbsd-arm64': 0.27.2 + '@esbuild/openbsd-x64': 0.27.2 + '@esbuild/openharmony-arm64': 0.27.2 + '@esbuild/sunos-x64': 0.27.2 + '@esbuild/win32-arm64': 0.27.2 + '@esbuild/win32-ia32': 0.27.2 + '@esbuild/win32-x64': 0.27.2 + escalade@3.2.0: {} + event-target-shim@5.0.1: {} + + eventemitter3@5.0.4: {} + + expand-template@2.0.3: {} + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 + file-type@21.3.0: + dependencies: + '@tokenizer/inflate': 0.4.1 + strtok3: 10.3.4 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + transitivePeerDependencies: + - supports-color + + file-uri-to-path@1.0.0: {} + + fs-constants@1.0.0: {} + fsevents@2.3.3: optional: true gensync@1.0.0-beta.2: {} + get-tsconfig@4.13.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + github-from-package@0.0.0: {} + graceful-fs@4.2.11: {} + grammy@1.39.3: + dependencies: + '@grammyjs/types': 3.23.0 + abort-controller: 3.0.0 + debug: 4.4.3 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + - supports-color + + hashery@1.4.0: + dependencies: + hookified: 1.15.0 + + hookified@1.15.0: {} + html-entities@2.3.3: {} + ieee754@1.2.1: {} + + inherits@2.0.4: {} + + ini@1.3.8: {} + is-what@4.1.16: {} jiti@2.6.1: {} @@ -1575,6 +2771,10 @@ snapshots: jsonc-parser@3.3.1: {} + keyv@5.6.0: + dependencies: + '@keyv/serialize': 1.1.1 + lightningcss-android-arm64@1.30.2: optional: true @@ -1624,6 +2824,12 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.2 lightningcss-win32-x64-msvc: 1.30.2 + long@4.0.0: {} + + long@5.3.2: {} + + lru-cache@11.2.4: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -1638,16 +2844,62 @@ snapshots: marked@17.0.1: {} + media-typer@1.1.0: {} + merge-anything@5.1.7: dependencies: is-what: 4.1.16 + mimic-response@3.1.0: {} + + minimist@1.2.8: {} + + mkdirp-classic@0.5.3: {} + ms@2.1.3: {} + music-metadata@11.10.6: + dependencies: + '@borewit/text-codec': 0.2.1 + '@tokenizer/token': 0.3.0 + content-type: 1.0.5 + debug: 4.4.3 + file-type: 21.3.0 + media-typer: 1.1.0 + strtok3: 10.3.4 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + win-guid: 0.1.3 + transitivePeerDependencies: + - supports-color + nanoid@3.3.11: {} + napi-build-utils@2.0.0: {} + + node-abi@3.87.0: + dependencies: + semver: 7.7.3 + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + node-releases@2.0.27: {} + on-exit-leak-free@2.1.2: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + p-queue@9.1.0: + dependencies: + eventemitter3: 5.0.4 + p-timeout: 7.0.1 + + p-timeout@7.0.1: {} + parse5@7.3.0: dependencies: entities: 6.0.1 @@ -1656,12 +2908,110 @@ snapshots: picomatch@4.0.3: {} + pino-abstract-transport@2.0.0: + dependencies: + split2: 4.2.0 + + pino-std-serializers@7.1.0: {} + + pino@9.14.0: + dependencies: + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.0 + thread-stream: 3.1.0 + postcss@8.5.6: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 + prebuild-install@7.1.3: + dependencies: + detect-libc: 2.1.2 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 2.0.0 + node-abi: 3.87.0 + pump: 3.0.3 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.4 + tunnel-agent: 0.6.0 + + process-warning@5.0.0: {} + + protobufjs@6.8.8: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/long': 4.0.2 + '@types/node': 10.17.60 + long: 4.0.0 + + protobufjs@7.5.4: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/node': 22.19.7 + long: 5.3.2 + + pump@3.0.3: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + qified@0.6.0: + dependencies: + hookified: 1.15.0 + + qrcode-terminal@0.12.0: {} + + quick-format-unescaped@4.0.4: {} + + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + real-require@0.2.0: {} + + resolve-pkg-maps@1.0.0: {} + rollup@4.55.1: dependencies: '@types/estree': 1.0.8 @@ -1693,14 +3043,59 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.55.1 fsevents: 2.3.3 + safe-buffer@5.2.1: {} + + safe-stable-stringify@2.5.0: {} + semver@6.3.1: {} + semver@7.7.3: {} + seroval-plugins@1.3.3(seroval@1.3.2): dependencies: seroval: 1.3.2 seroval@1.3.2: {} + sharp@0.34.5: + dependencies: + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + + simple-concat@1.0.1: {} + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + solid-js@1.9.10: dependencies: csstype: 3.2.3 @@ -1716,26 +3111,88 @@ snapshots: transitivePeerDependencies: - supports-color + sonic-boom@4.2.0: + dependencies: + atomic-sleep: 1.0.0 + source-map-js@1.2.1: {} + split2@4.2.0: {} + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-json-comments@2.0.1: {} + + strtok3@10.3.4: + dependencies: + '@tokenizer/token': 0.3.0 + tailwindcss@4.1.18: {} tapable@2.3.0: {} + tar-fs@2.1.4: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.3 + tar-stream: 2.2.0 + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + thread-stream@3.1.0: + dependencies: + real-require: 0.2.0 + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 + token-types@6.1.2: + dependencies: + '@borewit/text-codec': 0.2.1 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + + tr46@0.0.3: {} + + tslib@2.8.1: {} + + tsx@4.21.0: + dependencies: + esbuild: 0.27.2 + get-tsconfig: 4.13.0 + optionalDependencies: + fsevents: 2.3.3 + + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + typescript@5.9.3: {} + uint8array-extras@1.5.0: {} + + undici-types@6.21.0: {} + update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: browserslist: 4.28.1 escalade: 3.2.0 picocolors: 1.1.1 - vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@6.4.1(jiti@2.6.1)(lightningcss@1.30.2)): + util-deprecate@1.0.2: {} + + vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)): dependencies: '@babel/core': 7.28.6 '@types/babel__core': 7.20.5 @@ -1743,12 +3200,12 @@ snapshots: merge-anything: 5.1.7 solid-js: 1.9.10 solid-refresh: 0.6.3(solid-js@1.9.10) - vite: 6.4.1(jiti@2.6.1)(lightningcss@1.30.2) - vitefu: 1.1.1(vite@6.4.1(jiti@2.6.1)(lightningcss@1.30.2)) + vite: 6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0) + vitefu: 1.1.1(vite@6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)) transitivePeerDependencies: - supports-color - vite@6.4.1(jiti@2.6.1)(lightningcss@1.30.2): + vite@6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -1757,12 +3214,27 @@ snapshots: rollup: 4.55.1 tinyglobby: 0.2.15 optionalDependencies: + '@types/node': 22.19.7 fsevents: 2.3.3 jiti: 2.6.1 lightningcss: 1.30.2 + tsx: 4.21.0 - vitefu@1.1.1(vite@6.4.1(jiti@2.6.1)(lightningcss@1.30.2)): + vitefu@1.1.1(vite@6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)): optionalDependencies: - vite: 6.4.1(jiti@2.6.1)(lightningcss@1.30.2) + vite: 6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0) + + webidl-conversions@3.0.1: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + win-guid@0.1.3: {} + + wrappy@1.0.2: {} + + ws@8.19.0: {} yallist@3.1.1: {}