diff --git a/container/Dockerfile b/container/Dockerfile index 2622d0619bc..32ca798b9cb 100644 --- a/container/Dockerfile +++ b/container/Dockerfile @@ -23,6 +23,8 @@ ARG CLAUDE_CODE_VERSION=2.1.128 ARG AGENT_BROWSER_VERSION=latest ARG VERCEL_VERSION=52.2.1 ARG BUN_VERSION=1.3.12 +ARG GMAIL_MCP_VERSION=1.1.11 +ARG MCP_REMOTE_VERSION=0.1.29 # ---- System dependencies ----------------------------------------------------- # tini: correct PID 1 / signal forwarding so outbound.db writes finalize on @@ -49,6 +51,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ ca-certificates \ curl \ git \ + poppler-utils \ tini \ unzip \ && if [ "$INSTALL_CJK_FONTS" = "true" ]; then \ @@ -110,6 +113,18 @@ RUN --mount=type=cache,target=/root/.cache/pnpm \ RUN --mount=type=cache,target=/root/.cache/pnpm \ pnpm install -g "@anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}" +RUN --mount=type=cache,target=/root/.cache/pnpm \ + pnpm install -g \ + "@gongrzhe/server-gmail-autoauth-mcp@${GMAIL_MCP_VERSION}" \ + "zod-to-json-schema@3.22.5" + +RUN --mount=type=cache,target=/root/.cache/pnpm \ + pnpm install -g "mcp-remote@${MCP_REMOTE_VERSION}" + +# ---- pdf-reader CLI (fork addition) ------------------------------------------- +COPY skills/pdf-reader/pdf-reader /usr/local/bin/pdf-reader +RUN chmod +x /usr/local/bin/pdf-reader + # ---- ncl CLI wrapper ---------------------------------------------------------- # Actual script lives in the mounted source at /app/src/cli/ncl.ts. RUN printf '#!/bin/sh\nexec bun /app/src/cli/ncl.ts "$@"\n' > /usr/local/bin/ncl && \ diff --git a/container/skills/pdf-reader/SKILL.md b/container/skills/pdf-reader/SKILL.md new file mode 100644 index 00000000000..01fe2ca96e7 --- /dev/null +++ b/container/skills/pdf-reader/SKILL.md @@ -0,0 +1,94 @@ +--- +name: pdf-reader +description: Read and extract text from PDF files — documents, reports, contracts, spreadsheets. Use whenever you need to read PDF content, not just when explicitly asked. Handles local files, URLs, and WhatsApp attachments. +allowed-tools: Bash(pdf-reader:*) +--- + +# PDF Reader + +## Quick start + +```bash +pdf-reader extract report.pdf # Extract all text +pdf-reader extract report.pdf --layout # Preserve tables/columns +pdf-reader fetch https://example.com/doc.pdf # Download and extract +pdf-reader info report.pdf # Show metadata + size +pdf-reader list # List all PDFs in directory tree +``` + +## Commands + +### extract — Extract text from PDF + +```bash +pdf-reader extract # Full text to stdout +pdf-reader extract --layout # Preserve layout (tables, columns) +pdf-reader extract --pages 1-5 # Pages 1 through 5 +pdf-reader extract --pages 3-3 # Single page (page 3) +pdf-reader extract --layout --pages 2-10 # Layout + page range +``` + +Options: +- `--layout` — Maintains spatial positioning. Essential for tables, spreadsheets, multi-column docs. +- `--pages N-M` — Extract only pages N through M (1-based, inclusive). + +### fetch — Download and extract PDF from URL + +```bash +pdf-reader fetch # Download, verify, extract with layout +pdf-reader fetch report.pdf # Also save a local copy +``` + +Downloads the PDF, verifies it has a valid `%PDF` header, then extracts text with layout preservation. Temporary files are cleaned up automatically. + +### info — PDF metadata and file size + +```bash +pdf-reader info +``` + +Shows title, author, page count, page size, PDF version, and file size on disk. + +### list — Find all PDFs in directory tree + +```bash +pdf-reader list +``` + +Recursively lists all `.pdf` files with page count and file size. + +## WhatsApp PDF attachments + +When a user sends a PDF on WhatsApp, it is automatically saved to the `attachments/` directory. The message will include a path hint like: + +> [PDF attached: attachments/document.pdf] + +To read the attached PDF: + +```bash +pdf-reader extract attachments/document.pdf --layout +``` + +## Example workflows + +### Read a contract and summarize key terms + +```bash +pdf-reader info attachments/contract.pdf +pdf-reader extract attachments/contract.pdf --layout +``` + +### Extract specific pages from a long report + +```bash +pdf-reader info report.pdf # Check total pages +pdf-reader extract report.pdf --pages 1-3 # Executive summary +pdf-reader extract report.pdf --pages 15-20 # Financial tables +``` + +### Fetch and analyze a public document + +```bash +pdf-reader fetch https://example.com/annual-report.pdf report.pdf +pdf-reader info report.pdf +``` diff --git a/container/skills/pdf-reader/pdf-reader b/container/skills/pdf-reader/pdf-reader new file mode 100755 index 00000000000..be413c21be1 --- /dev/null +++ b/container/skills/pdf-reader/pdf-reader @@ -0,0 +1,203 @@ +#!/bin/bash +set -euo pipefail + +# pdf-reader — CLI wrapper around poppler-utils (pdftotext, pdfinfo) +# Provides extract, fetch, info, list commands for PDF processing. + +VERSION="1.0.0" + +usage() { + cat <<'USAGE' +pdf-reader — Extract text and metadata from PDF files + +Usage: + pdf-reader extract [--layout] [--pages N-M] + pdf-reader fetch [filename] + pdf-reader info + pdf-reader list + pdf-reader help + +Commands: + extract Extract text from a PDF file to stdout + fetch Download a PDF from a URL and extract text + info Show PDF metadata and file size + list List all PDFs in current directory tree + help Show this help message + +Extract options: + --layout Preserve original layout (tables, columns) + --pages Page range to extract (e.g. 1-5, 3-3 for single page) +USAGE +} + +cmd_extract() { + local file="" + local layout=false + local first_page="" + local last_page="" + + # Parse arguments + while [[ $# -gt 0 ]]; do + case "$1" in + --layout) + layout=true + shift + ;; + --pages) + if [[ -z "${2:-}" ]]; then + echo "Error: --pages requires a range argument (e.g. 1-5)" >&2 + exit 1 + fi + local range="$2" + first_page="${range%-*}" + last_page="${range#*-}" + shift 2 + ;; + -*) + echo "Error: Unknown option: $1" >&2 + exit 1 + ;; + *) + if [[ -z "$file" ]]; then + file="$1" + else + echo "Error: Unexpected argument: $1" >&2 + exit 1 + fi + shift + ;; + esac + done + + if [[ -z "$file" ]]; then + echo "Error: No file specified" >&2 + echo "Usage: pdf-reader extract [--layout] [--pages N-M]" >&2 + exit 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Error: File not found: $file" >&2 + exit 1 + fi + + # Build pdftotext arguments + local args=() + if [[ "$layout" == true ]]; then + args+=(-layout) + fi + if [[ -n "$first_page" ]]; then + args+=(-f "$first_page") + fi + if [[ -n "$last_page" ]]; then + args+=(-l "$last_page") + fi + + pdftotext ${args[@]+"${args[@]}"} "$file" - +} + +cmd_fetch() { + local url="${1:-}" + local filename="${2:-}" + + if [[ -z "$url" ]]; then + echo "Error: No URL specified" >&2 + echo "Usage: pdf-reader fetch [filename]" >&2 + exit 1 + fi + + # Create temporary file + local tmpfile + tmpfile="$(mktemp /tmp/pdf-reader-XXXXXX.pdf)" + trap 'rm -f "$tmpfile"' EXIT + + # Download + echo "Downloading: $url" >&2 + if ! curl -sL -o "$tmpfile" "$url"; then + echo "Error: Failed to download: $url" >&2 + exit 1 + fi + + # Verify PDF header + local header + header="$(head -c 4 "$tmpfile")" + if [[ "$header" != "%PDF" ]]; then + echo "Error: Downloaded file is not a valid PDF (header: $header)" >&2 + exit 1 + fi + + # Save with name if requested + if [[ -n "$filename" ]]; then + cp "$tmpfile" "$filename" + echo "Saved to: $filename" >&2 + fi + + # Extract with layout + pdftotext -layout "$tmpfile" - +} + +cmd_info() { + local file="${1:-}" + + if [[ -z "$file" ]]; then + echo "Error: No file specified" >&2 + echo "Usage: pdf-reader info " >&2 + exit 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Error: File not found: $file" >&2 + exit 1 + fi + + pdfinfo "$file" + echo "" + echo "File size: $(du -h "$file" | cut -f1)" +} + +cmd_list() { + local found=false + + # Use globbing to find PDFs (globstar makes **/ match recursively) + shopt -s nullglob globstar + + # Use associative array to deduplicate (*.pdf overlaps with **/*.pdf) + declare -A seen + for pdf in *.pdf **/*.pdf; do + [[ -v seen["$pdf"] ]] && continue + seen["$pdf"]=1 + found=true + + local pages="?" + local size + size="$(du -h "$pdf" | cut -f1)" + + # Try to get page count from pdfinfo + if page_line="$(pdfinfo "$pdf" 2>/dev/null | grep '^Pages:')"; then + pages="$(echo "$page_line" | awk '{print $2}')" + fi + + printf "%-60s %5s pages %8s\n" "$pdf" "$pages" "$size" + done + + if [[ "$found" == false ]]; then + echo "No PDF files found in current directory tree." >&2 + fi +} + +# Main dispatch +command="${1:-help}" +shift || true + +case "$command" in + extract) cmd_extract "$@" ;; + fetch) cmd_fetch "$@" ;; + info) cmd_info "$@" ;; + list) cmd_list ;; + help|--help|-h) usage ;; + version|--version|-v) echo "pdf-reader $VERSION" ;; + *) + echo "Error: Unknown command: $command" >&2 + echo "Run 'pdf-reader help' for usage." >&2 + exit 1 + ;; +esac diff --git a/package.json b/package.json index 1db2e2a359c..f265d0fffa3 100644 --- a/package.json +++ b/package.json @@ -31,10 +31,15 @@ "@clack/core": "^1.2.0", "@clack/prompts": "^1.2.0", "@onecli-sh/sdk": "^0.5.0", + "@types/qrcode": "1.5.6", + "@whiskeysockets/baileys": "7.0.0-rc.9", "better-sqlite3": "11.10.0", "chat": "^4.24.0", "cron-parser": "5.5.0", - "kleur": "^4.1.5" + "kleur": "^4.1.5", + "openai": "4.104.0", + "pino": "9.6.0", + "qrcode": "1.5.4" }, "devDependencies": { "@eslint/js": "^9.35.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 902b6ae2ba1..b531f8d398d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,25 +10,40 @@ importers: dependencies: '@clack/core': specifier: ^1.2.0 - version: 1.2.0 + version: 1.3.0 '@clack/prompts': specifier: ^1.2.0 - version: 1.2.0 + version: 1.3.0 '@onecli-sh/sdk': specifier: ^0.5.0 version: 0.5.0 + '@types/qrcode': + specifier: 1.5.6 + version: 1.5.6 + '@whiskeysockets/baileys': + specifier: 7.0.0-rc.9 + version: 7.0.0-rc.9(sharp@0.34.5) better-sqlite3: specifier: 11.10.0 version: 11.10.0 chat: specifier: ^4.24.0 - version: 4.26.0 + version: 4.28.1 cron-parser: specifier: 5.5.0 version: 5.5.0 kleur: specifier: ^4.1.5 version: 4.1.5 + openai: + specifier: 4.104.0 + version: 4.104.0(ws@8.20.0) + pino: + specifier: 9.6.0 + version: 9.6.0 + qrcode: + specifier: 1.5.4 + version: 1.5.4 devDependencies: '@eslint/js': specifier: ^9.35.0 @@ -38,7 +53,7 @@ importers: version: 7.6.13 '@types/node': specifier: ^22.10.0 - version: 22.19.17 + version: 22.19.19 eslint: specifier: ^9.35.0 version: 9.39.4 @@ -53,7 +68,7 @@ importers: version: 9.1.7 prettier: specifier: ^3.8.1 - version: 3.8.2 + version: 3.8.3 tsx: specifier: ^4.19.0 version: 4.21.0 @@ -62,24 +77,39 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.35.0 - version: 8.58.2(eslint@9.39.4)(typescript@5.9.3) + version: 8.59.3(eslint@9.39.4)(typescript@5.9.3) vitest: specifier: ^4.0.18 - version: 4.1.4(@types/node@22.19.17)(vite@8.0.8(@types/node@22.19.17)(esbuild@0.27.7)(tsx@4.21.0)) + version: 4.1.6(@types/node@22.19.19)(vite@8.0.12(@types/node@22.19.19)(esbuild@0.27.7)(tsx@4.21.0)) packages: - '@clack/core@1.2.0': - resolution: {integrity: sha512-qfxof/3T3t9DPU/Rj3OmcFyZInceqj/NVtO9rwIuJqCUgh32gwPjpFQQp/ben07qKlhpwq7GzfWpST4qdJ5Drg==} + '@borewit/text-codec@0.2.2': + resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} - '@clack/prompts@1.2.0': - resolution: {integrity: sha512-4jmztR9fMqPMjz6H/UZXj0zEmE43ha1euENwkckKKel4XpSfokExPo5AiVStdHSAlHekz4d0CA/r45Ok1E4D3w==} + '@cacheable/memory@2.0.8': + resolution: {integrity: sha512-FvEb29x5wVwu/Kf93IWwsOOEuhHh6dYCJF3vcKLzXc0KXIW181AOzv6ceT4ZpBHDvAfG60eqb+ekmrnLHIy+jw==} - '@emnapi/core@1.9.2': - resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} + '@cacheable/node-cache@1.7.6': + resolution: {integrity: sha512-6Omk2SgNnjtxB5f/E6bTIWIt5xhdpx39fGNRQgU9lojvRxU68v+qY+SXXLsp3ZGukqoPjsK21wZ6XABFr/Ge3A==} + engines: {node: '>=18'} + + '@cacheable/utils@2.4.1': + resolution: {integrity: sha512-eiFgzCbIneyMlLOmNG4g9xzF7Hv3Mga4LjxjcSC/ues6VYq2+gUbQI8JqNuw/ZM8tJIeIaBGpswAsqV2V7ApgA==} + + '@clack/core@1.3.0': + resolution: {integrity: sha512-xJPHpAmEQUBrXSLx0gF+q5K/IyihXpsHZcha+jB+tyahsKRK3Dxo4D0coZDewHo12NhiuzC3dTtMPbm53GEAAA==} + engines: {node: '>= 20.12.0'} + + '@clack/prompts@1.3.0': + resolution: {integrity: sha512-GgcWwRCs/xPtaqlMy8qRhPnZf9vlWcWZNHAitnVQ3yk7JmSralSiq5q07yaffYE8SogtDm7zFeKccx1QNVARpw==} + engines: {node: '>= 20.12.0'} + + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} - '@emnapi/runtime@1.9.2': - resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} @@ -278,12 +308,22 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + '@hapi/boom@9.1.4': + resolution: {integrity: sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw==} + + '@hapi/hoek@9.3.0': + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} engines: {node: '>=18.18.0'} - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': @@ -294,9 +334,171 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + 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] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@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] + libc: [glibc] + + '@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] + libc: [glibc] + + '@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] + libc: [glibc] + + '@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] + libc: [glibc] + + '@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] + libc: [glibc] + + '@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] + libc: [glibc] + + '@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] + libc: [musl] + + '@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] + libc: [musl] + + '@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/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@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==} + '@napi-rs/wasm-runtime@1.1.4': resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} peerDependencies: @@ -307,112 +509,149 @@ packages: resolution: {integrity: sha512-oe5Yx9o98v6N1PgzcCR7nULHHqcqKWNJIDOHGOSNX+l20mLlZpFUqfKPeFmsojBNRQMoqbvZQKUlFMp6gVuYBA==} engines: {node: '>=20'} - '@oxc-project/types@0.124.0': - resolution: {integrity: sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==} + '@oxc-project/types@0.129.0': + resolution: {integrity: sha512-3oz8m3FGdr2nDXVqmFUw7jolKliC4MoyXYIG2c7gpjBnzUWQpUGIYcXYKxTdTi+N2jusvt610ckTMkxdwHkYEg==} + + '@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.5': + resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} - '@rolldown/binding-android-arm64@1.0.0-rc.15': - resolution: {integrity: sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==} + '@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.1': + resolution: {integrity: sha512-mnzgDV26ueAvk7rsbt9L7bE0SuAoqyuys/sMMrmVcN5x9VsxpcG3rqAUSgDyLp0UZlmNfIbQ4fHfCtreVBk8Ew==} + + '@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.1': + resolution: {integrity: sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==} + + '@rolldown/binding-android-arm64@1.0.0': + resolution: {integrity: sha512-TWMZnRLMe63C2Lhyicviu7ZHaU4kxa6PS3rofvc9GmcvptzNN11BcfQ4Sl7MwTOsisQoa2keB/EBdNCAnUo8vA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-rc.15': - resolution: {integrity: sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==} + '@rolldown/binding-darwin-arm64@1.0.0': + resolution: {integrity: sha512-6XcD+8k0gPVItNagEw78/qqcBDwKcwDYS8V2hRmVsfUSIrd8cWe/CBvRDI5toqFyPfj+FJr6t8U6Xj2P2prEew==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-rc.15': - resolution: {integrity: sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==} + '@rolldown/binding-darwin-x64@1.0.0': + resolution: {integrity: sha512-iN/tWVXRQDWvmZlKdceP1Dwug9GDpEymhb9p4xnEe6zvCg5lFmzVljl+1qR1NVx3yfGpr2Na+CuLmv5IU8uzfQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-rc.15': - resolution: {integrity: sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==} + '@rolldown/binding-freebsd-x64@1.0.0': + resolution: {integrity: sha512-jjQMDvvwSOuhOwMszD/klSOjyWMM3zI64hWTj9KT5x4MxRbZAf+7vLQ6qouRhtsLVFHr3f0ILaJAfgENPiQdAQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': - resolution: {integrity: sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0': + resolution: {integrity: sha512-d//Dtg2x6/m3mbV64yUGNnDGNZaDGRpDLLNGerHQUVObuNaIQaaDp25yUiqGXtHEXX+NP2d0wAlmKgpYgIAJ2A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==} + '@rolldown/binding-linux-arm64-gnu@1.0.0': + resolution: {integrity: sha512-n7Ofp0mx+aB2cC+Sdy5YtMnXtY9lchnHbY+3Yt0uq9JsWQExf4f5Whu0tK0R8Jdc9S6RchTHjIFY7uc92puOVQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': - resolution: {integrity: sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==} + '@rolldown/binding-linux-arm64-musl@1.0.0': + resolution: {integrity: sha512-EIVjy2cgd7uuMMo94FVkBp7F6DhcZAUwNURkSG3RwUmvAXR6s0ISxM81U+IydcZByPG0pZIHsf1b6kTxoFDgJA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==} + '@rolldown/binding-linux-ppc64-gnu@1.0.0': + resolution: {integrity: sha512-JEwwOPcwTLAcpDQlqSmjEmfs63xJnSiUNIGvLcDLUHCWK4XowpS/7c7tUsUH6uT/ct6bMUTdXKfI8967FYj6mg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==} + '@rolldown/binding-linux-s390x-gnu@1.0.0': + resolution: {integrity: sha512-0wjCFhLrihtAubnT9iA0N++0pSV0z5Hg7tNGdNJ4RFaINceHadoF+kiFGyY1qSSNVIAZtLotG8Ju1bgDPkjnFA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==} + '@rolldown/binding-linux-x64-gnu@1.0.0': + resolution: {integrity: sha512-Dfn7iak9BcMMePxcoJfpSbWqnEyrp/dRF63/8qW/eHBdOZov6x5aShLLEYGYdIeSJ6vMLK/XCVB+lGIxm41bQA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': - resolution: {integrity: sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==} + '@rolldown/binding-linux-x64-musl@1.0.0': + resolution: {integrity: sha512-5/utzzDmD/pD/bmuaUcbTf/sZYy0aztwIVlfpoW1fTjCZ0BaPOMVWGZL1zvgxyi7ZIVYWlxKONHmSbHuiOh8Jw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': - resolution: {integrity: sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==} + '@rolldown/binding-openharmony-arm64@1.0.0': + resolution: {integrity: sha512-ouJs8VcUomfLfpbUECqFMRqdV4x6aeAK3MA4m6vTrJJjKyWTV5KnxZx7Jd9G+GlDaQQxubcba00x16OyJ1meig==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-rc.15': - resolution: {integrity: sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==} - engines: {node: '>=14.0.0'} + '@rolldown/binding-wasm32-wasi@1.0.0': + resolution: {integrity: sha512-E+oHKGiDA+lsKMmFtffDDw91EryDT7uJocrIuCHqhm6bCTM6xFK+3gaCkYOHfPwQr0cCNarSM2xaELoQDz9jJg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': - resolution: {integrity: sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==} + '@rolldown/binding-win32-arm64-msvc@1.0.0': + resolution: {integrity: sha512-yYK02n8Rngo+gbm1y6G0+7jk1sJ/2Wt7K0me0Y7k/ErBpyf+LJ2gFpqWVTcRV1rUepBlQRmpgWkTQCiiwrK0Ow==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': - resolution: {integrity: sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==} + '@rolldown/binding-win32-x64-msvc@1.0.0': + resolution: {integrity: sha512-14bpChMahXRRXiTwahSl+zzHPW6qQTXtkMuJBFlbo+pqSAews2d4BdCSHfrJ/MBsCZtpmTafsY+1QhBzitcmdg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-rc.15': - resolution: {integrity: sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==} + '@rolldown/pluginutils@1.0.0': + resolution: {integrity: sha512-aKs/3GSWyV0mrhNmt/96/Z3yczC3yvrzYATCiCXQebBsGyYzjNdUphRVLeJQ67ySKVXRfMxt2lm12pmXvbPFQQ==} '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@tokenizer/inflate@0.4.1': + resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} + engines: {node: '>=18'} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} '@types/better-sqlite3@7.6.13': resolution: {integrity: sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==} @@ -426,88 +665,103 @@ packages: '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/long@4.0.2': + resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} + '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@22.19.17': - resolution: {integrity: sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==} + '@types/node-fetch@2.6.13': + resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} + + '@types/node@10.17.60': + resolution: {integrity: sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==} + + '@types/node@18.19.130': + resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} + + '@types/node@22.19.19': + resolution: {integrity: sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==} + + '@types/qrcode@1.5.6': + resolution: {integrity: sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw==} '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - '@typescript-eslint/eslint-plugin@8.58.2': - resolution: {integrity: sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==} + '@typescript-eslint/eslint-plugin@8.59.3': + resolution: {integrity: sha512-PwFvSKsXGShKGW6n5bZOhGHEcCZXM8HofLK9fNsEwZXzFRjoY+XT1Vsf1zgyXdwTr0ZYz1/2tkZ0DBTT9jZjhw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.58.2 + '@typescript-eslint/parser': ^8.59.3 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.58.2': - resolution: {integrity: sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==} + '@typescript-eslint/parser@8.59.3': + resolution: {integrity: sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.58.2': - resolution: {integrity: sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==} + '@typescript-eslint/project-service@8.59.3': + resolution: {integrity: sha512-ECiUWa/KYRGDFUqTNehaRgzDshnJfkTABJxVemHk4ko22gcr0ukloKjWvyQ64g8YCV/UI47kN1dbmjf/GaQYng==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.58.2': - resolution: {integrity: sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==} + '@typescript-eslint/scope-manager@8.59.3': + resolution: {integrity: sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.58.2': - resolution: {integrity: sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==} + '@typescript-eslint/tsconfig-utils@8.59.3': + resolution: {integrity: sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.58.2': - resolution: {integrity: sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==} + '@typescript-eslint/type-utils@8.59.3': + resolution: {integrity: sha512-g71d8QD8UaiHGvrJwyIS1hCX5r63w6Jll+4VEYhEAHXTDIqX1JgxhTAbEHtKntL9kuc4jRo7/GWw5xfCepSccQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.58.2': - resolution: {integrity: sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==} + '@typescript-eslint/types@8.59.3': + resolution: {integrity: sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.58.2': - resolution: {integrity: sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==} + '@typescript-eslint/typescript-estree@8.59.3': + resolution: {integrity: sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.58.2': - resolution: {integrity: sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==} + '@typescript-eslint/utils@8.59.3': + resolution: {integrity: sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.58.2': - resolution: {integrity: sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==} + '@typescript-eslint/visitor-keys@8.59.3': + resolution: {integrity: sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@vitest/expect@4.1.4': - resolution: {integrity: sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==} + '@vitest/expect@4.1.6': + resolution: {integrity: sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==} - '@vitest/mocker@4.1.4': - resolution: {integrity: sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==} + '@vitest/mocker@4.1.6': + resolution: {integrity: sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -517,24 +771,48 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.4': - resolution: {integrity: sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==} + '@vitest/pretty-format@4.1.6': + resolution: {integrity: sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==} - '@vitest/runner@4.1.4': - resolution: {integrity: sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==} + '@vitest/runner@4.1.6': + resolution: {integrity: sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA==} - '@vitest/snapshot@4.1.4': - resolution: {integrity: sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==} + '@vitest/snapshot@4.1.6': + resolution: {integrity: sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw==} - '@vitest/spy@4.1.4': - resolution: {integrity: sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==} + '@vitest/spy@4.1.6': + resolution: {integrity: sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==} - '@vitest/utils@4.1.4': - resolution: {integrity: sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==} + '@vitest/utils@4.1.6': + resolution: {integrity: sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==} + + '@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 '@workflow/serde@4.1.0-beta.2': resolution: {integrity: sha512-8kkeoQKLDaKXefjV5dbhBj2aErfKp1Mc4pb6tj8144cF+Em5SPbyMbyLCHp+BVrFfFVCBluCtMx+jjvaFVZGww==} + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -545,8 +823,16 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - ajv@6.14.0: - resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} @@ -559,6 +845,16 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + async-mutex@0.5.0: + resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -584,17 +880,28 @@ packages: brace-expansion@1.1.14: resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} - brace-expansion@5.0.5: - resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} engines: {node: 18 || 20 || >=22} buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + cacheable@2.3.5: + resolution: {integrity: sha512-EQfaKe09tl615iNvq/TBRWTFf1AKJNXYQSsMx0Z3EI0nA+pVsVPS8wJhnRlkbdacKPh1d0qVIhwTc2zsQNFEEg==} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -609,12 +916,15 @@ packages: character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} - chat@4.26.0: - resolution: {integrity: sha512-QToDnIEGpyb8yQA6YLMHOSRK30YVk4RtsyFyuWFYyB2c4jQlyIrSWtwVK7qyvmvqzQp9uDwCdJRAhS8GtCHAGQ==} + chat@4.28.1: + resolution: {integrity: sha512-oKBeLQ746rSmHWGoXmPgDOqMVdIe9cWFQBQ1G2pw0l2vV4sAsZgfEJmc1UYqSJR4kYy4PxKgRFy31pe4RJ644Q==} chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -622,9 +932,17 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + 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==} @@ -636,6 +954,9 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + curve25519-js@0.0.4: + resolution: {integrity: sha512-axn2UMEnkhyDUPWOwVKBMVIzSQy2ejH2xRGy1wq81dqRwApXfIzfbE3hIX0ZRFBIihf/KDqK158DLwESu4AK1w==} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -645,6 +966,10 @@ packages: supports-color: optional: true + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + decode-named-character-reference@1.3.0: resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} @@ -659,6 +984,10 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -670,11 +999,37 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + dijkstrajs@1.0.3: + resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - es-module-lexer@2.0.0: - resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@2.1.0: + resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} esbuild@0.27.7: resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} @@ -743,6 +1098,13 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + 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'} @@ -763,14 +1125,18 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-string-truncated-width@1.2.1: - resolution: {integrity: sha512-Q9acT/+Uu3GwGj+5w/zsGuQjh9O1TyywhIwAxHudtWrgF09nHOPrvTLhQevPbttcxjr/SNN7mJmfOw/B1bXgow==} + fast-redact@3.5.0: + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} + engines: {node: '>=6'} - fast-string-width@1.1.0: - resolution: {integrity: sha512-O3fwIVIH5gKB38QNbdg+3760ZmGz0SZMgvwJbA1b2TGXceKE6A2cOlfogh1iw8lr049zPyd7YADHy+B7U4W9bQ==} + fast-string-truncated-width@3.0.3: + resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} - fast-wrap-ansi@0.1.6: - resolution: {integrity: sha512-HlUwET7a5gqjURj70D5jl7aC3Zmy4weA1SHUfM0JFI0Ptq987NH2TwbBFLoERhfwk+E+eaq4EK3jXoT+R3yp3w==} + fast-string-width@3.0.2: + resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} + + fast-wrap-ansi@0.2.0: + resolution: {integrity: sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==} fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} @@ -785,9 +1151,17 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + file-type@21.3.4: + resolution: {integrity: sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==} + engines: {node: '>=20'} + file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -799,6 +1173,17 @@ packages: flatted@3.4.2: resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + form-data-encoder@1.7.2: + resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + formdata-node@4.4.1: + resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} + engines: {node: '>= 12.20'} + fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -807,8 +1192,23 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - get-tsconfig@4.13.7: - resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} github-from-package@0.0.0: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} @@ -825,10 +1225,39 @@ packages: resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} engines: {node: '>=18'} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hashery@1.5.1: + resolution: {integrity: sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==} + engines: {node: '>=20'} + + hasown@2.0.3: + resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} + engines: {node: '>= 0.4'} + + hookified@1.15.1: + resolution: {integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==} + + hookified@2.2.0: + resolution: {integrity: sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==} + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + husky@9.1.7: resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} engines: {node: '>=18'} @@ -863,6 +1292,10 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -890,6 +1323,9 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + keyv@5.6.0: + resolution: {integrity: sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==} + kleur@4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} @@ -972,6 +1408,10 @@ packages: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -979,9 +1419,19 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + long@4.0.0: + resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + lru-cache@11.3.6: + resolution: {integrity: sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==} + engines: {node: 20 || >=22} + luxon@3.7.2: resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} engines: {node: '>=12'} @@ -992,6 +1442,10 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} @@ -1025,6 +1479,10 @@ packages: mdast-util-to-string@4.0.0: resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} @@ -1109,6 +1567,14 @@ packages: micromark@4.0.2: resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + mimic-response@3.1.0: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} @@ -1129,8 +1595,12 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + music-metadata@11.12.3: + resolution: {integrity: sha512-n6hSTZkuD59qWgHh6IP5dtDlDZQXoxk/bcA85Jywg8Z1iFrlNgl2+GTFgjZyn52W5UgQpV42V4XqrQZZAMbZTQ==} + engines: {node: '>=18'} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -1140,28 +1610,78 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - node-abi@3.89.0: - resolution: {integrity: sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==} + node-abi@3.92.0: + resolution: {integrity: sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==} engines: {node: '>=10'} + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + 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 + obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + 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==} + openai@4.104.0: + resolution: {integrity: sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.23.8 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-queue@9.2.0: + resolution: {integrity: sha512-dWgLE8AH0HjQ9fe74pUkKkvzzYT18Inp4zra3lKHnnwqGvcfcUBrvF2EAVX+envufDNBOzpPq/IBUONDbI7+3g==} + engines: {node: '>=20'} + + p-timeout@7.0.1: + resolution: {integrity: sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==} + engines: {node: '>=20'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -1184,8 +1704,22 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} - postcss@8.5.10: - resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} + 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.6.0: + resolution: {integrity: sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg==} + hasBin: true + + pngjs@5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + + postcss@8.5.14: + resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} engines: {node: ^10 || ^12 || >=14} prebuild-install@7.1.3: @@ -1198,11 +1732,22 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.8.2: - resolution: {integrity: sha512-8c3mgTe0ASwWAJK+78dpviD+A8EqhndQPUBpNUIPt6+xWlIigCwfN01lWr9MAede4uqXGTEKeQWTvzb3vjia0Q==} + prettier@3.8.3: + resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} engines: {node: '>=14'} hasBin: true + process-warning@4.0.1: + resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} + + protobufjs@6.8.8: + resolution: {integrity: sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==} + hasBin: true + + protobufjs@7.5.7: + resolution: {integrity: sha512-NGnrxS/nLKUo5nkbVQxlC71sB4hdfImdYIbFeSCidxtwATx0AHRPcANSLd0q5Bb2BkoSWo2iisQhGg5/r+ihbA==} + engines: {node: '>=12.0.0'} + pump@3.0.4: resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} @@ -1210,6 +1755,18 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qified@0.10.1: + resolution: {integrity: sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==} + engines: {node: '>=20'} + + qrcode@1.5.4: + resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} + engines: {node: '>=10.13.0'} + 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 @@ -1218,6 +1775,10 @@ packages: 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'} + remark-gfm@4.0.1: resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} @@ -1230,6 +1791,13 @@ packages: remend@1.3.0: resolution: {integrity: sha512-iIhggPkhW3hFImKtB10w0dz4EZbs28mV/dmbcYVonWEJ6UGHHpP+bFZnTh6GNWJONg5m+U56JrL+8IxZRdgWjw==} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1237,19 +1805,30 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - rolldown@1.0.0-rc.15: - resolution: {integrity: sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==} + rolldown@1.0.0: + resolution: {integrity: sha512-yD986aXDESFGS95spT1LAv0jssywP4npMEjmMHyN2/5+eE8qQJUype2AaKkRiLgBgyD0LFlubwAht7VmY8rGoA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + + semver@7.8.0: + resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} engines: {node: '>=10'} hasBin: true + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -1270,19 +1849,34 @@ packages: sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + sonic-boom@4.2.1: + resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} + 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'} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - std-env@4.0.0: - resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} + std-env@4.1.0: + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + strip-json-comments@2.0.1: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} @@ -1291,6 +1885,10 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + strtok3@10.3.5: + resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} + engines: {node: '>=18'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -1302,11 +1900,14 @@ packages: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} + thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@1.1.1: - resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==} + tinyexec@1.1.2: + resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} engines: {node: '>=18'} tinyglobby@0.2.16: @@ -1317,6 +1918,13 @@ packages: resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.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==} + trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} @@ -1341,8 +1949,8 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - typescript-eslint@8.58.2: - resolution: {integrity: sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==} + typescript-eslint@8.59.3: + resolution: {integrity: sha512-KgusgyDgG4LI8Ih/sWaCtZ06tckLAS5CvT5A4D1Q7bYVoAAyzwiZvE4BmwDHkhRVkvhRBepKeASoFzQetha7Fg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -1353,6 +1961,13 @@ packages: engines: {node: '>=14.17'} hasBin: true + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -1383,13 +1998,13 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - vite@8.0.8: - resolution: {integrity: sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==} + vite@8.0.12: + resolution: {integrity: sha512-w2dDofOWv2QB09ZITZBsvKTVAlYvPR4IAmrY/v0ir9KvLs0xybR7i48wxhM1/oyBWO34wPns+bPGw5ZrZqDpZg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.0 + '@vitejs/devtools': ^0.1.18 esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' less: ^4.0.0 @@ -1426,20 +2041,20 @@ packages: yaml: optional: true - vitest@4.1.4: - resolution: {integrity: sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==} + vitest@4.1.6: + resolution: {integrity: sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.4 - '@vitest/browser-preview': 4.1.4 - '@vitest/browser-webdriverio': 4.1.4 - '@vitest/coverage-istanbul': 4.1.4 - '@vitest/coverage-v8': 4.1.4 - '@vitest/ui': 4.1.4 + '@vitest/browser-playwright': 4.1.6 + '@vitest/browser-preview': 4.1.6 + '@vitest/browser-webdriverio': 4.1.6 + '@vitest/coverage-istanbul': 4.1.6 + '@vitest/coverage-v8': 4.1.6 + '@vitest/ui': 4.1.6 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -1467,6 +2082,19 @@ packages: jsdom: optional: true + web-streams-polyfill@4.0.0-beta.3: + resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} + engines: {node: '>= 14'} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -1477,13 +2105,43 @@ packages: engines: {node: '>=8'} hasBin: true + win-guid@0.2.1: + resolution: {integrity: sha512-gEIQU4mkgl2OPeoNrWflcJFJ3Ae2BPd4eCsHHA/XikslkIVms/nHhvnvzIZV7VLmBvtFlDOzLt9rrZT+n6D67A==} + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@8.20.0: + resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} + 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 + + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -1491,27 +2149,47 @@ packages: zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} -snapshots: +snapshots: + + '@borewit/text-codec@0.2.2': {} + + '@cacheable/memory@2.0.8': + dependencies: + '@cacheable/utils': 2.4.1 + '@keyv/bigmap': 1.3.1(keyv@5.6.0) + hookified: 1.15.1 + keyv: 5.6.0 + + '@cacheable/node-cache@1.7.6': + dependencies: + cacheable: 2.3.5 + hookified: 1.15.1 + keyv: 5.6.0 + + '@cacheable/utils@2.4.1': + dependencies: + hashery: 1.5.1 + keyv: 5.6.0 - '@clack/core@1.2.0': + '@clack/core@1.3.0': dependencies: - fast-wrap-ansi: 0.1.6 + fast-wrap-ansi: 0.2.0 sisteransi: 1.0.5 - '@clack/prompts@1.2.0': + '@clack/prompts@1.3.0': dependencies: - '@clack/core': 1.2.0 - fast-string-width: 1.1.0 - fast-wrap-ansi: 0.1.6 + '@clack/core': 1.3.0 + fast-string-width: 3.0.2 + fast-wrap-ansi: 0.2.0 sisteransi: 1.0.5 - '@emnapi/core@1.9.2': + '@emnapi/core@1.10.0': dependencies: '@emnapi/wasi-threads': 1.2.1 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.9.2': + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 optional: true @@ -1624,7 +2302,7 @@ snapshots: '@eslint/eslintrc@3.3.5': dependencies: - ajv: 6.14.0 + ajv: 6.15.0 debug: 4.4.3 espree: 10.4.0 globals: 14.0.0 @@ -1645,91 +2323,238 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 - '@humanfs/core@0.19.1': {} + '@hapi/boom@9.1.4': + dependencies: + '@hapi/hoek': 9.3.0 + + '@hapi/hoek@9.3.0': {} + + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 - '@humanfs/node@0.16.7': + '@humanfs/node@0.16.8': dependencies: - '@humanfs/core': 0.19.1 + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 '@humanwhocodes/retry': 0.4.3 + '@humanfs/types@0.15.0': {} + '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/retry@0.4.3': {} + '@img/colour@1.1.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.10.0 + 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/sourcemap-codec@1.5.5': {} - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + '@keyv/bigmap@1.3.1(keyv@5.6.0)': dependencies: - '@emnapi/core': 1.9.2 - '@emnapi/runtime': 1.9.2 - '@tybys/wasm-util': 0.10.1 + hashery: 1.5.1 + hookified: 1.15.1 + keyv: 5.6.0 + + '@keyv/serialize@1.1.1': {} + + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 optional: true '@onecli-sh/sdk@0.5.0': {} - '@oxc-project/types@0.124.0': {} + '@oxc-project/types@0.129.0': {} + + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.5': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.0': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.1 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.1': {} + + '@protobufjs/path@1.1.2': {} - '@rolldown/binding-android-arm64@1.0.0-rc.15': + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.1': {} + + '@rolldown/binding-android-arm64@1.0.0': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.15': + '@rolldown/binding-darwin-arm64@1.0.0': optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.15': + '@rolldown/binding-darwin-x64@1.0.0': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.15': + '@rolldown/binding-freebsd-x64@1.0.0': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': + '@rolldown/binding-linux-arm64-gnu@1.0.0': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': + '@rolldown/binding-linux-arm64-musl@1.0.0': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': + '@rolldown/binding-linux-ppc64-gnu@1.0.0': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': + '@rolldown/binding-linux-s390x-gnu@1.0.0': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': + '@rolldown/binding-linux-x64-gnu@1.0.0': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': + '@rolldown/binding-linux-x64-musl@1.0.0': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': + '@rolldown/binding-openharmony-arm64@1.0.0': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.15': + '@rolldown/binding-wasm32-wasi@1.0.0': dependencies: - '@emnapi/core': 1.9.2 - '@emnapi/runtime': 1.9.2 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': + '@rolldown/binding-win32-arm64-msvc@1.0.0': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': + '@rolldown/binding-win32-x64-msvc@1.0.0': optional: true - '@rolldown/pluginutils@1.0.0-rc.15': {} + '@rolldown/pluginutils@1.0.0': {} '@standard-schema/spec@1.1.0': {} - '@tybys/wasm-util@0.10.1': + '@tokenizer/inflate@0.4.1': + dependencies: + debug: 4.4.3 + token-types: 6.1.2 + transitivePeerDependencies: + - supports-color + + '@tokenizer/token@0.3.0': {} + + '@tybys/wasm-util@0.10.2': dependencies: tslib: 2.8.1 optional: true '@types/better-sqlite3@7.6.13': dependencies: - '@types/node': 22.19.17 + '@types/node': 22.19.19 '@types/chai@5.2.3': dependencies: @@ -1742,30 +2567,47 @@ snapshots: '@types/deep-eql@4.0.2': {} - '@types/estree@1.0.8': {} + '@types/estree@1.0.9': {} '@types/json-schema@7.0.15': {} + '@types/long@4.0.2': {} + '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 '@types/ms@2.1.0': {} - '@types/node@22.19.17': + '@types/node-fetch@2.6.13': + dependencies: + '@types/node': 22.19.19 + form-data: 4.0.5 + + '@types/node@10.17.60': {} + + '@types/node@18.19.130': + dependencies: + undici-types: 5.26.5 + + '@types/node@22.19.19': dependencies: undici-types: 6.21.0 + '@types/qrcode@1.5.6': + dependencies: + '@types/node': 22.19.19 + '@types/unist@3.0.3': {} - '@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.59.3(@typescript-eslint/parser@8.59.3(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.58.2(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/type-utils': 8.58.2(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.2(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.58.2 + '@typescript-eslint/parser': 8.59.3(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.59.3 + '@typescript-eslint/type-utils': 8.59.3(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.3(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.3 eslint: 9.39.4 ignore: 7.0.5 natural-compare: 1.4.0 @@ -1774,41 +2616,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.58.2(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/parser@8.59.3(eslint@9.39.4)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.58.2 + '@typescript-eslint/scope-manager': 8.59.3 + '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.3 debug: 4.4.3 eslint: 9.39.4 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.58.2(typescript@5.9.3)': + '@typescript-eslint/project-service@8.59.3(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@5.9.3) - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/tsconfig-utils': 8.59.3(typescript@5.9.3) + '@typescript-eslint/types': 8.59.3 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.58.2': + '@typescript-eslint/scope-manager@8.59.3': dependencies: - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/visitor-keys': 8.58.2 + '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/visitor-keys': 8.59.3 - '@typescript-eslint/tsconfig-utils@8.58.2(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.59.3(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.58.2(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.59.3(eslint@9.39.4)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.2(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.3(eslint@9.39.4)(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.4 ts-api-utils: 2.5.0(typescript@5.9.3) @@ -1816,95 +2658,128 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.58.2': {} + '@typescript-eslint/types@8.59.3': {} - '@typescript-eslint/typescript-estree@8.58.2(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.59.3(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.58.2(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@5.9.3) - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/visitor-keys': 8.58.2 + '@typescript-eslint/project-service': 8.59.3(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.59.3(typescript@5.9.3) + '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/visitor-keys': 8.59.3 debug: 4.4.3 minimatch: 10.2.5 - semver: 7.7.4 + semver: 7.8.0 tinyglobby: 0.2.16 ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.58.2(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/utils@8.59.3(eslint@9.39.4)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.59.3 + '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) eslint: 9.39.4 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.58.2': + '@typescript-eslint/visitor-keys@8.59.3': dependencies: - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/types': 8.59.3 eslint-visitor-keys: 5.0.1 - '@vitest/expect@4.1.4': + '@vitest/expect@4.1.6': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.4 - '@vitest/utils': 4.1.4 + '@vitest/spy': 4.1.6 + '@vitest/utils': 4.1.6 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.4(vite@8.0.8(@types/node@22.19.17)(esbuild@0.27.7)(tsx@4.21.0))': + '@vitest/mocker@4.1.6(vite@8.0.12(@types/node@22.19.19)(esbuild@0.27.7)(tsx@4.21.0))': dependencies: - '@vitest/spy': 4.1.4 + '@vitest/spy': 4.1.6 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.8(@types/node@22.19.17)(esbuild@0.27.7)(tsx@4.21.0) + vite: 8.0.12(@types/node@22.19.19)(esbuild@0.27.7)(tsx@4.21.0) - '@vitest/pretty-format@4.1.4': + '@vitest/pretty-format@4.1.6': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.4': + '@vitest/runner@4.1.6': dependencies: - '@vitest/utils': 4.1.4 + '@vitest/utils': 4.1.6 pathe: 2.0.3 - '@vitest/snapshot@4.1.4': + '@vitest/snapshot@4.1.6': dependencies: - '@vitest/pretty-format': 4.1.4 - '@vitest/utils': 4.1.4 + '@vitest/pretty-format': 4.1.6 + '@vitest/utils': 4.1.6 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.4': {} + '@vitest/spy@4.1.6': {} - '@vitest/utils@4.1.4': + '@vitest/utils@4.1.6': dependencies: - '@vitest/pretty-format': 4.1.4 + '@vitest/pretty-format': 4.1.6 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 + '@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.3.6 + music-metadata: 11.12.3 + p-queue: 9.2.0 + pino: 9.6.0 + protobufjs: 7.5.7 + sharp: 0.34.5 + ws: 8.20.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 + '@workflow/serde@4.1.0-beta.2': {} + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: acorn: 8.16.0 acorn@8.16.0: {} - ajv@6.14.0: + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + + ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ansi-regex@5.0.1: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -1913,6 +2788,14 @@ snapshots: assertion-error@2.0.1: {} + async-mutex@0.5.0: + dependencies: + tslib: 2.8.1 + + asynckit@0.4.0: {} + + atomic-sleep@1.0.0: {} + bail@2.0.2: {} balanced-match@1.0.2: {} @@ -1941,7 +2824,7 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@5.0.5: + brace-expansion@5.0.6: dependencies: balanced-match: 4.0.4 @@ -1950,8 +2833,23 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 + cacheable@2.3.5: + dependencies: + '@cacheable/memory': 2.0.8 + '@cacheable/utils': 2.4.1 + hookified: 1.15.1 + keyv: 5.6.0 + qified: 0.10.1 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + callsites@3.1.0: {} + camelcase@5.3.1: {} + ccount@2.0.1: {} chai@6.2.2: {} @@ -1963,7 +2861,7 @@ snapshots: character-entities@2.0.2: {} - chat@4.26.0: + chat@4.28.1: dependencies: '@workflow/serde': 4.1.0-beta.2 mdast-util-to-string: 4.0.0 @@ -1977,14 +2875,26 @@ snapshots: chownr@1.1.4: {} + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + color-convert@2.0.1: dependencies: color-name: 1.1.4 color-name@1.1.4: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + concat-map@0.0.1: {} + content-type@1.0.5: {} + convert-source-map@2.0.0: {} cron-parser@5.5.0: @@ -1997,10 +2907,14 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + curve25519-js@0.0.4: {} + debug@4.4.3: dependencies: ms: 2.1.3 + decamelize@1.2.0: {} + decode-named-character-reference@1.3.0: dependencies: character-entities: 2.0.2 @@ -2013,6 +2927,8 @@ snapshots: deep-is@0.1.4: {} + delayed-stream@1.0.0: {} + dequal@2.0.3: {} detect-libc@2.1.2: {} @@ -2021,11 +2937,36 @@ snapshots: dependencies: dequal: 2.0.3 + dijkstrajs@1.0.3: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + emoji-regex@8.0.0: {} + end-of-stream@1.4.5: dependencies: once: 1.4.0 - es-module-lexer@2.0.0: {} + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@2.1.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.3 esbuild@0.27.7: optionalDependencies: @@ -2085,11 +3026,11 @@ snapshots: '@eslint/eslintrc': 3.3.5 '@eslint/js': 9.39.4 '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.7 + '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.14.0 + '@types/estree': 1.0.9 + ajv: 6.15.0 chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.3 @@ -2132,10 +3073,14 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esutils@2.0.3: {} + event-target-shim@5.0.1: {} + + eventemitter3@5.0.4: {} + expand-template@2.0.3: {} expect-type@1.3.0: {} @@ -2148,15 +3093,17 @@ snapshots: fast-levenshtein@2.0.6: {} - fast-string-truncated-width@1.2.1: {} + fast-redact@3.5.0: {} - fast-string-width@1.1.0: + fast-string-truncated-width@3.0.3: {} + + fast-string-width@3.0.2: dependencies: - fast-string-truncated-width: 1.2.1 + fast-string-truncated-width: 3.0.3 - fast-wrap-ansi@0.1.6: + fast-wrap-ansi@0.2.0: dependencies: - fast-string-width: 1.1.0 + fast-string-width: 3.0.2 fdir@6.5.0(picomatch@4.0.4): optionalDependencies: @@ -2166,8 +3113,22 @@ snapshots: dependencies: flat-cache: 4.0.1 + file-type@21.3.4: + dependencies: + '@tokenizer/inflate': 0.4.1 + strtok3: 10.3.5 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + transitivePeerDependencies: + - supports-color + file-uri-to-path@1.0.0: {} + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -2180,12 +3141,49 @@ snapshots: flatted@3.4.2: {} + form-data-encoder@1.7.2: {} + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.3 + mime-types: 2.1.35 + + formdata-node@4.4.1: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 4.0.0-beta.3 + fs-constants@1.0.0: {} fsevents@2.3.3: optional: true - get-tsconfig@4.13.7: + function-bind@1.1.2: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.3 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-tsconfig@4.14.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -2199,8 +3197,32 @@ snapshots: globals@15.15.0: {} + gopd@1.2.0: {} + has-flag@4.0.0: {} + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hashery@1.5.1: + dependencies: + hookified: 1.15.1 + + hasown@2.0.3: + dependencies: + function-bind: 1.1.2 + + hookified@1.15.1: {} + + hookified@2.2.0: {} + + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + husky@9.1.7: {} ieee754@1.2.1: {} @@ -2222,6 +3244,8 @@ snapshots: is-extglob@2.1.1: {} + is-fullwidth-code-point@3.0.0: {} + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -2244,6 +3268,10 @@ snapshots: dependencies: json-buffer: 3.0.1 + keyv@5.6.0: + dependencies: + '@keyv/serialize': 1.1.1 + kleur@4.1.5: {} levn@0.4.1: @@ -2300,14 +3328,24 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 lodash.merge@4.6.2: {} + long@4.0.0: {} + + long@5.3.2: {} + longest-streak@3.1.0: {} + lru-cache@11.3.6: {} + luxon@3.7.2: {} magic-string@0.30.21: @@ -2316,6 +3354,8 @@ snapshots: markdown-table@3.0.4: {} + math-intrinsics@1.1.0: {} + mdast-util-find-and-replace@3.0.2: dependencies: '@types/mdast': 4.0.4 @@ -2418,6 +3458,8 @@ snapshots: dependencies: '@types/mdast': 4.0.4 + media-typer@1.1.0: {} + micromark-core-commonmark@2.0.3: dependencies: decode-named-character-reference: 1.3.0 @@ -2609,11 +3651,17 @@ snapshots: transitivePeerDependencies: - supports-color + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + mimic-response@3.1.0: {} minimatch@10.2.5: dependencies: - brace-expansion: 5.0.5 + brace-expansion: 5.0.6 minimatch@3.1.5: dependencies: @@ -2625,22 +3673,59 @@ snapshots: ms@2.1.3: {} - nanoid@3.3.11: {} + music-metadata@11.12.3: + dependencies: + '@borewit/text-codec': 0.2.2 + '@tokenizer/token': 0.3.0 + content-type: 1.0.5 + debug: 4.4.3 + file-type: 21.3.4 + media-typer: 1.1.0 + strtok3: 10.3.5 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + win-guid: 0.2.1 + transitivePeerDependencies: + - supports-color + + nanoid@3.3.12: {} napi-build-utils@2.0.0: {} natural-compare@1.4.0: {} - node-abi@3.89.0: + node-abi@3.92.0: + dependencies: + semver: 7.8.0 + + node-domexception@1.0.0: {} + + node-fetch@2.7.0: dependencies: - semver: 7.7.4 + whatwg-url: 5.0.0 obug@2.1.1: {} + on-exit-leak-free@2.1.2: {} + once@1.4.0: dependencies: wrappy: 1.0.2 + openai@4.104.0(ws@8.20.0): + dependencies: + '@types/node': 18.19.130 + '@types/node-fetch': 2.6.13 + abort-controller: 3.0.0 + agentkeepalive: 4.6.0 + form-data-encoder: 1.7.2 + formdata-node: 4.4.1 + node-fetch: 2.7.0 + optionalDependencies: + ws: 8.20.0 + transitivePeerDependencies: + - encoding + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -2650,14 +3735,31 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + p-locate@5.0.0: dependencies: p-limit: 3.1.0 + p-queue@9.2.0: + dependencies: + eventemitter3: 5.0.4 + p-timeout: 7.0.1 + + p-timeout@7.0.1: {} + + p-try@2.2.0: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -2672,9 +3774,31 @@ snapshots: picomatch@4.0.4: {} - postcss@8.5.10: + pino-abstract-transport@2.0.0: + dependencies: + split2: 4.2.0 + + pino-std-serializers@7.1.0: {} + + pino@9.6.0: + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.5.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.1.0 + process-warning: 4.0.1 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.1 + thread-stream: 3.1.0 + + pngjs@5.0.0: {} + + postcss@8.5.14: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.12 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -2686,7 +3810,7 @@ snapshots: minimist: 1.2.8 mkdirp-classic: 0.5.3 napi-build-utils: 2.0.0 - node-abi: 3.89.0 + node-abi: 3.92.0 pump: 3.0.4 rc: 1.2.8 simple-get: 4.0.1 @@ -2695,7 +3819,40 @@ snapshots: prelude-ls@1.2.1: {} - prettier@3.8.2: {} + prettier@3.8.3: {} + + process-warning@4.0.1: {} + + protobufjs@6.8.8: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.1 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.1 + '@types/long': 4.0.2 + '@types/node': 10.17.60 + long: 4.0.0 + + protobufjs@7.5.7: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.1 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.1 + '@types/node': 22.19.19 + long: 5.3.2 pump@3.0.4: dependencies: @@ -2704,6 +3861,18 @@ snapshots: punycode@2.3.1: {} + qified@0.10.1: + dependencies: + hookified: 2.2.0 + + qrcode@1.5.4: + dependencies: + dijkstrajs: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + + quick-format-unescaped@4.0.4: {} + rc@1.2.8: dependencies: deep-extend: 0.6.0 @@ -2717,6 +3886,8 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 + real-require@0.2.0: {} + remark-gfm@4.0.1: dependencies: '@types/mdast': 4.0.4 @@ -2745,34 +3916,73 @@ snapshots: remend@1.3.0: {} + require-directory@2.1.1: {} + + require-main-filename@2.0.0: {} + resolve-from@4.0.0: {} resolve-pkg-maps@1.0.0: {} - rolldown@1.0.0-rc.15: + rolldown@1.0.0: dependencies: - '@oxc-project/types': 0.124.0 - '@rolldown/pluginutils': 1.0.0-rc.15 + '@oxc-project/types': 0.129.0 + '@rolldown/pluginutils': 1.0.0 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.15 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.15 - '@rolldown/binding-darwin-x64': 1.0.0-rc.15 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.15 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.15 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.15 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.15 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.15 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.15 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.15 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.15 + '@rolldown/binding-android-arm64': 1.0.0 + '@rolldown/binding-darwin-arm64': 1.0.0 + '@rolldown/binding-darwin-x64': 1.0.0 + '@rolldown/binding-freebsd-x64': 1.0.0 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0 + '@rolldown/binding-linux-arm64-gnu': 1.0.0 + '@rolldown/binding-linux-arm64-musl': 1.0.0 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0 + '@rolldown/binding-linux-s390x-gnu': 1.0.0 + '@rolldown/binding-linux-x64-gnu': 1.0.0 + '@rolldown/binding-linux-x64-musl': 1.0.0 + '@rolldown/binding-openharmony-arm64': 1.0.0 + '@rolldown/binding-wasm32-wasi': 1.0.0 + '@rolldown/binding-win32-arm64-msvc': 1.0.0 + '@rolldown/binding-win32-x64-msvc': 1.0.0 safe-buffer@5.2.1: {} - semver@7.7.4: {} + safe-stable-stringify@2.5.0: {} + + semver@7.8.0: {} + + set-blocking@2.0.0: {} + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.0 + 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 shebang-command@2.0.0: dependencies: @@ -2792,20 +4002,40 @@ snapshots: sisteransi@1.0.5: {} + sonic-boom@4.2.1: + dependencies: + atomic-sleep: 1.0.0 + source-map-js@1.2.1: {} + split2@4.2.0: {} + stackback@0.0.2: {} - std-env@4.0.0: {} + std-env@4.1.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + strip-json-comments@2.0.1: {} strip-json-comments@3.1.1: {} + strtok3@10.3.5: + dependencies: + '@tokenizer/token': 0.3.0 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -2825,9 +4055,13 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + thread-stream@3.1.0: + dependencies: + real-require: 0.2.0 + tinybench@2.9.0: {} - tinyexec@1.1.1: {} + tinyexec@1.1.2: {} tinyglobby@0.2.16: dependencies: @@ -2836,19 +4070,26 @@ snapshots: tinyrainbow@3.1.0: {} + token-types@6.1.2: + dependencies: + '@borewit/text-codec': 0.2.2 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + + tr46@0.0.3: {} + trough@2.2.0: {} ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 - tslib@2.8.1: - optional: true + tslib@2.8.1: {} tsx@4.21.0: dependencies: esbuild: 0.27.7 - get-tsconfig: 4.13.7 + get-tsconfig: 4.14.0 optionalDependencies: fsevents: 2.3.3 @@ -2860,12 +4101,12 @@ snapshots: dependencies: prelude-ls: 1.2.1 - typescript-eslint@8.58.2(eslint@9.39.4)(typescript@5.9.3): + typescript-eslint@8.59.3(eslint@9.39.4)(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/parser': 8.58.2(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.58.2(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.2(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.59.3(@typescript-eslint/parser@8.59.3(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/parser': 8.59.3(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.3(eslint@9.39.4)(typescript@5.9.3) eslint: 9.39.4 typescript: 5.9.3 transitivePeerDependencies: @@ -2873,6 +4114,10 @@ snapshots: typescript@5.9.3: {} + uint8array-extras@1.5.0: {} + + undici-types@5.26.5: {} + undici-types@6.21.0: {} unified@11.0.5: @@ -2920,46 +4165,57 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite@8.0.8(@types/node@22.19.17)(esbuild@0.27.7)(tsx@4.21.0): + vite@8.0.12(@types/node@22.19.19)(esbuild@0.27.7)(tsx@4.21.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.10 - rolldown: 1.0.0-rc.15 + postcss: 8.5.14 + rolldown: 1.0.0 tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 22.19.17 + '@types/node': 22.19.19 esbuild: 0.27.7 fsevents: 2.3.3 tsx: 4.21.0 - vitest@4.1.4(@types/node@22.19.17)(vite@8.0.8(@types/node@22.19.17)(esbuild@0.27.7)(tsx@4.21.0)): + vitest@4.1.6(@types/node@22.19.19)(vite@8.0.12(@types/node@22.19.19)(esbuild@0.27.7)(tsx@4.21.0)): dependencies: - '@vitest/expect': 4.1.4 - '@vitest/mocker': 4.1.4(vite@8.0.8(@types/node@22.19.17)(esbuild@0.27.7)(tsx@4.21.0)) - '@vitest/pretty-format': 4.1.4 - '@vitest/runner': 4.1.4 - '@vitest/snapshot': 4.1.4 - '@vitest/spy': 4.1.4 - '@vitest/utils': 4.1.4 - es-module-lexer: 2.0.0 + '@vitest/expect': 4.1.6 + '@vitest/mocker': 4.1.6(vite@8.0.12(@types/node@22.19.19)(esbuild@0.27.7)(tsx@4.21.0)) + '@vitest/pretty-format': 4.1.6 + '@vitest/runner': 4.1.6 + '@vitest/snapshot': 4.1.6 + '@vitest/spy': 4.1.6 + '@vitest/utils': 4.1.6 + es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 pathe: 2.0.3 picomatch: 4.0.4 - std-env: 4.0.0 + std-env: 4.1.0 tinybench: 2.9.0 - tinyexec: 1.1.1 + tinyexec: 1.1.2 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vite: 8.0.8(@types/node@22.19.17)(esbuild@0.27.7)(tsx@4.21.0) + vite: 8.0.12(@types/node@22.19.19)(esbuild@0.27.7)(tsx@4.21.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.19.17 + '@types/node': 22.19.19 transitivePeerDependencies: - msw + web-streams-polyfill@4.0.0-beta.3: {} + + webidl-conversions@3.0.1: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which-module@2.0.1: {} + which@2.0.2: dependencies: isexe: 2.0.0 @@ -2969,10 +4225,41 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 + win-guid@0.2.1: {} + word-wrap@1.2.5: {} + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrappy@1.0.2: {} + ws@8.20.0: {} + + y18n@4.0.3: {} + + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + yocto-queue@0.1.0: {} zwitch@2.0.4: {} diff --git a/setup/groups.ts b/setup/groups.ts new file mode 100644 index 00000000000..4c71e866963 --- /dev/null +++ b/setup/groups.ts @@ -0,0 +1,229 @@ +/** + * Step: groups — Fetch group metadata from messaging platforms, write to DB. + * WhatsApp requires an upfront sync (Baileys groupFetchAllParticipating). + * Other channels discover group names at runtime — this step auto-skips for them. + * Replaces 05-sync-groups.sh + 05b-list-groups.sh + */ +import { execSync } from 'child_process'; +import fs from 'fs'; +import path from 'path'; + +import Database from 'better-sqlite3'; + +import { STORE_DIR } from '../src/config.js'; +import { log } from '../src/log.js'; +import { emitStatus } from './status.js'; + +function parseArgs(args: string[]): { list: boolean; limit: number } { + let list = false; + let limit = 30; + for (let i = 0; i < args.length; i++) { + if (args[i] === '--list') list = true; + if (args[i] === '--limit' && args[i + 1]) { + limit = parseInt(args[i + 1], 10); + i++; + } + } + return { list, limit }; +} + +export async function run(args: string[]): Promise { + const projectRoot = process.cwd(); + const { list, limit } = parseArgs(args); + + if (list) { + await listGroups(limit); + return; + } + + await syncGroups(projectRoot); +} + +async function listGroups(limit: number): Promise { + const dbPath = path.join(STORE_DIR, 'messages.db'); + + if (!fs.existsSync(dbPath)) { + console.error('ERROR: database not found'); + process.exit(1); + } + + const db = new Database(dbPath, { readonly: true }); + const rows = db + .prepare( + `SELECT jid, name FROM chats + WHERE jid LIKE '%@g.us' AND jid <> '__group_sync__' AND name <> jid + ORDER BY last_message_time DESC + LIMIT ?`, + ) + .all(limit) as Array<{ jid: string; name: string }>; + db.close(); + + for (const row of rows) { + console.log(`${row.jid}|${row.name}`); + } +} + +async function syncGroups(projectRoot: string): Promise { + // Only WhatsApp needs an upfront group sync; other channels resolve names at runtime. + // Detect WhatsApp by checking for auth credentials on disk. + const authDir = path.join(projectRoot, 'store', 'auth'); + const hasWhatsAppAuth = + fs.existsSync(authDir) && fs.readdirSync(authDir).length > 0; + + if (!hasWhatsAppAuth) { + log.info('WhatsApp auth not found — skipping group sync'); + emitStatus('SYNC_GROUPS', { + BUILD: 'skipped', + SYNC: 'skipped', + GROUPS_IN_DB: 0, + REASON: 'whatsapp_not_configured', + STATUS: 'success', + LOG: 'logs/setup.log', + }); + return; + } + + // Build TypeScript first + log.info('Building TypeScript'); + let buildOk = false; + try { + execSync('pnpm run build', { + cwd: projectRoot, + stdio: ['ignore', 'pipe', 'pipe'], + }); + buildOk = true; + log.info('Build succeeded'); + } catch { + log.error('Build failed'); + emitStatus('SYNC_GROUPS', { + BUILD: 'failed', + SYNC: 'skipped', + GROUPS_IN_DB: 0, + STATUS: 'failed', + ERROR: 'build_failed', + LOG: 'logs/setup.log', + }); + process.exit(1); + } + + // Run sync script via a temp file to avoid shell escaping issues with node -e + log.info('Fetching group metadata'); + let syncOk = false; + try { + const syncScript = ` +import makeWASocket, { useMultiFileAuthState, makeCacheableSignalKeyStore, Browsers } from '@whiskeysockets/baileys'; +import pino from 'pino'; +import path from 'path'; +import fs from 'fs'; +import Database from 'better-sqlite3'; + +const logger = pino({ level: 'silent' }); +const authDir = path.join('store', 'auth'); +const dbPath = path.join('store', 'messages.db'); + +if (!fs.existsSync(authDir)) { + console.error('NO_AUTH'); + process.exit(1); +} + +const db = new Database(dbPath); +db.pragma('journal_mode = WAL'); +db.exec('CREATE TABLE IF NOT EXISTS chats (jid TEXT PRIMARY KEY, name TEXT, last_message_time TEXT)'); + +const upsert = db.prepare( + 'INSERT INTO chats (jid, name, last_message_time) VALUES (?, ?, ?) ON CONFLICT(jid) DO UPDATE SET name = excluded.name' +); + +const { state, saveCreds } = await useMultiFileAuthState(authDir); + +const sock = makeWASocket({ + auth: { creds: state.creds, keys: makeCacheableSignalKeyStore(state.keys, logger) }, + printQRInTerminal: false, + logger, + browser: Browsers.macOS('Chrome'), +}); + +const timeout = setTimeout(() => { + console.error('TIMEOUT'); + process.exit(1); +}, 30000); + +sock.ev.on('creds.update', saveCreds); + +sock.ev.on('connection.update', async (update) => { + if (update.connection === 'open') { + try { + const groups = await sock.groupFetchAllParticipating(); + const now = new Date().toISOString(); + let count = 0; + for (const [jid, metadata] of Object.entries(groups)) { + if (metadata.subject) { + upsert.run(jid, metadata.subject, now); + count++; + } + } + console.log('SYNCED:' + count); + } catch (err) { + console.error('FETCH_ERROR:' + err.message); + } finally { + clearTimeout(timeout); + sock.end(undefined); + db.close(); + process.exit(0); + } + } else if (update.connection === 'close') { + clearTimeout(timeout); + console.error('CONNECTION_CLOSED'); + process.exit(1); + } +}); +`; + + const tmpScript = path.join(projectRoot, '.tmp-group-sync.mjs'); + fs.writeFileSync(tmpScript, syncScript, 'utf-8'); + try { + const output = execSync(`node ${tmpScript}`, { + cwd: projectRoot, + encoding: 'utf-8', + timeout: 45000, + stdio: ['ignore', 'pipe', 'pipe'], + }); + syncOk = output.includes('SYNCED:'); + log.info('Sync output', { output: output.trim() }); + } finally { + try { fs.unlinkSync(tmpScript); } catch { /* ignore cleanup errors */ } + } + } catch (err) { + log.error('Sync failed', { err }); + } + + // Count groups in DB using better-sqlite3 (no sqlite3 CLI) + let groupsInDb = 0; + const dbPath = path.join(STORE_DIR, 'messages.db'); + if (fs.existsSync(dbPath)) { + try { + const db = new Database(dbPath, { readonly: true }); + const row = db + .prepare( + "SELECT COUNT(*) as count FROM chats WHERE jid LIKE '%@g.us' AND jid <> '__group_sync__'", + ) + .get() as { count: number }; + groupsInDb = row.count; + db.close(); + } catch { + // DB may not exist yet + } + } + + const status = syncOk ? 'success' : 'failed'; + + emitStatus('SYNC_GROUPS', { + BUILD: buildOk ? 'success' : 'failed', + SYNC: syncOk ? 'success' : 'failed', + GROUPS_IN_DB: groupsInDb, + STATUS: status, + LOG: 'logs/setup.log', + }); + + if (status === 'failed') process.exit(1); +} diff --git a/setup/whatsapp-auth.ts b/setup/whatsapp-auth.ts index 47bfc6e9200..e98bcb08cbc 100644 --- a/setup/whatsapp-auth.ts +++ b/setup/whatsapp-auth.ts @@ -1,5 +1,5 @@ /** - * Step: whatsapp-auth — standalone WhatsApp (Baileys) authentication. + * Step: whatsapp-auth — standalone WhatsApp (Baileys v7) authentication. * * Forked from the channels-branch version so setup:auto's driver can render * the terminal UX itself (inside clack) instead of the step dumping a raw QR @@ -27,7 +27,6 @@ */ import fs from 'fs'; import path from 'path'; -import { createRequire } from 'module'; // Named import (not default) — pino's d.ts under NodeNext resolves the // default export to `typeof pino` (namespace), which isn't callable. The // named `pino` export resolves to the callable function. @@ -47,26 +46,23 @@ const AUTH_DIR = path.join(process.cwd(), 'store', 'auth'); const PAIRING_CODE_FILE = path.join(process.cwd(), 'store', 'pairing-code.txt'); const baileysLogger = pino({ level: 'silent' }); -// Baileys v6 bug: getPlatformId sends charCode (49) instead of enum value (1). -// Fixed in Baileys 7.x but not backported. Without this patch pairing codes -// fail with "couldn't link device" because WhatsApp receives an invalid -// platform id. createRequire because proto is not a named ESM export. -const _require = createRequire(import.meta.url); -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const { proto } = _require('@whiskeysockets/baileys') as { proto: any }; -try { - const _generics = _require( - '@whiskeysockets/baileys/lib/Utils/generics', - ) as Record; - _generics.getPlatformId = (browser: string): string => { - const platformType = - proto.DeviceProps.PlatformType[ - browser.toUpperCase() as keyof typeof proto.DeviceProps.PlatformType - ]; - return platformType ? platformType.toString() : '1'; - }; -} catch { - // If CJS require fails, QR auth still works; only pairing code may be affected. +/** Fetch current WA Web version — wppconnect tracker, then Baileys sw.js scrape. */ +async function resolveWaWebVersion(): Promise<[number, number, number]> { + try { + const res = await fetch('https://wppconnect.io/whatsapp-versions/', { + signal: AbortSignal.timeout(5000), + }); + if (res.ok) { + const html = await res.text(); + const match = html.match(/2\.3000\.(\d+)/); + if (match) return [2, 3000, Number(match[1])]; + } + } catch { /* fall through */ } + try { + const { version } = await fetchLatestWaWebVersion({}); + if (version) return version as [number, number, number]; + } catch { /* fall through */ } + throw new Error('Could not fetch current WhatsApp Web version — cannot connect with stale version'); } type AuthMethod = 'qr' | 'pairing-code'; @@ -139,9 +135,7 @@ export async function run(args: string[]): Promise { async function connectSocket(isReconnect = false): Promise { const { state, saveCreds } = await useMultiFileAuthState(AUTH_DIR); - const { version } = await fetchLatestWaWebVersion({}).catch(() => ({ - version: undefined, - })); + const version = await resolveWaWebVersion(); const sock = makeWASocket({ version, diff --git a/src/channels/index.ts b/src/channels/index.ts index e9b3bd1b75a..86a462dc038 100644 --- a/src/channels/index.ts +++ b/src/channels/index.ts @@ -7,3 +7,4 @@ // self-registration import below. import './cli.js'; +import './whatsapp.js'; diff --git a/src/channels/whatsapp.ts b/src/channels/whatsapp.ts new file mode 100644 index 00000000000..37fd7efd9ad --- /dev/null +++ b/src/channels/whatsapp.ts @@ -0,0 +1,868 @@ +/** + * WhatsApp channel adapter (v2) — native Baileys v7 implementation. + * + * Implements ChannelAdapter directly (no Chat SDK bridge) using + * @whiskeysockets/baileys 7.0.0-rc.9 (pinned — last release, unmaintained). + * Ports proven v1 infrastructure: getMessage fallback, outgoing queue, + * group metadata cache, LID mapping, reconnection with backoff. + * + * LID handling: Baileys v7 provides participantAlt / remoteJidAlt on every + * inbound message via extractAddressingContext, plus a real + * signalRepository.lidMapping.getPNForLID API. The adapter always resolves + * to phone JID (@s.whatsapp.net) before emitting to the router. + * + * Auth credentials persist in store/auth/. On first run: + * - If WHATSAPP_PHONE_NUMBER is set → pairing code (printed to log) + * - Otherwise → QR code (printed to log) + * Subsequent restarts reuse the saved session automatically. + */ +import fs from 'fs'; +import path from 'path'; +// Named import (not default) — pino's .d.ts under NodeNext resolution +// exports `{ pino as default, pino }`, but the namespace/function merge at +// `declare namespace pino` + `declare function pino` makes the default +// resolve to `typeof pino` (the namespace type), which isn't callable. +// The named export resolves to the callable function. +import { pino } from 'pino'; + +import { + makeWASocket, + proto, + Browsers, + DisconnectReason, + fetchLatestWaWebVersion, + downloadMediaMessage, + makeCacheableSignalKeyStore, + normalizeMessageContent, + useMultiFileAuthState, +} from '@whiskeysockets/baileys'; +import type { GroupMetadata, WAMessageKey, WAMessage, WASocket } from '@whiskeysockets/baileys'; + +import { isSafeAttachmentName } from '../attachment-safety.js'; +import { ASSISTANT_HAS_OWN_NUMBER, ASSISTANT_NAME, DATA_DIR, GROUPS_DIR, TRIGGER_PATTERN } from '../config.js'; +import { getAgentGroup } from '../db/agent-groups.js'; +import { getMessagingGroupByPlatform, getMessagingGroupAgents } from '../db/messaging-groups.js'; +import { readEnvFile } from '../env.js'; +import { log } from '../log.js'; +import { transcribeAudioFile, TRANSCRIPTION_FALLBACK } from '../transcription.js'; +import { registerChannelAdapter } from './channel-registry.js'; +import { normalizeOptions, type NormalizedOption } from './ask-question.js'; +import type { ChannelAdapter, ChannelSetup, ConversationInfo, InboundMessage, OutboundMessage } from './adapter.js'; + +const baileysLogger = pino({ level: 'silent' }); + +/** + * Fetch the latest WhatsApp Web version. Baileys' built-in + * fetchLatestWaWebVersion scrapes sw.js which is aggressively + * rate-limited (429). When it fails, Baileys falls back to a + * hardcoded version that goes stale within weeks — WhatsApp + * rejects connections with an expired buildHash (405 at Noise + * layer). This fetches from wppconnect's version tracker as a + * more reliable source, with Baileys' own fetch as fallback. + */ +async function resolveWaWebVersion(): Promise<[number, number, number]> { + // 1. Try wppconnect version tracker (HTML scrape — no JSON API) + try { + const res = await fetch('https://wppconnect.io/whatsapp-versions/', { + signal: AbortSignal.timeout(5000), + }); + if (res.ok) { + const html = await res.text(); + const match = html.match(/2\.3000\.(\d+)/); + if (match) { + const version: [number, number, number] = [2, 3000, Number(match[1])]; + log.info('Fetched WA Web version from wppconnect', { version }); + return version; + } + } + } catch { + // Fall through to Baileys' own fetch + } + + // 2. Try Baileys' built-in fetch (scrapes sw.js — often 429'd) + try { + const { version } = await fetchLatestWaWebVersion({}); + if (version) { + log.info('Fetched WA Web version from Baileys', { version }); + return version as [number, number, number]; + } + } catch { + // Fall through + } + + throw new Error( + 'Could not fetch current WhatsApp Web version from any source. ' + + 'Baileys hardcodes a stale version that WhatsApp rejects (405). ' + + 'Check network connectivity to wppconnect.io and web.whatsapp.com.', + ); +} + +const AUTH_DIR = path.join(process.cwd(), 'store', 'auth'); +const GROUP_SYNC_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24h +const GROUP_METADATA_CACHE_TTL_MS = 60_000; // 1 min for outbound sends +const SENT_MESSAGE_CACHE_MAX = 256; +const RECONNECT_DELAY_MS = 5000; +const PENDING_QUESTIONS_MAX = 64; + +/** Normalize an option label to a slash command: "Approve" → "/approve" */ +function optionToCommand(option: string): string { + return '/' + option.toLowerCase().replace(/\s+/g, '-'); +} + +// --- Markdown → WhatsApp formatting --- + +interface TextSegment { + content: string; + isProtected: boolean; +} + +/** Split text into code-block-protected and unprotected regions. */ +function splitProtectedRegions(text: string): TextSegment[] { + const segments: TextSegment[] = []; + const codeBlockRegex = /```[\s\S]*?```|`[^`\n]+`/g; + let lastIndex = 0; + let match: RegExpExecArray | null; + + while ((match = codeBlockRegex.exec(text)) !== null) { + if (match.index > lastIndex) { + segments.push({ content: text.slice(lastIndex, match.index), isProtected: false }); + } + segments.push({ content: match[0], isProtected: true }); + lastIndex = match.index + match[0].length; + } + + if (lastIndex < text.length) { + segments.push({ content: text.slice(lastIndex), isProtected: false }); + } + + return segments; +} + +/** Apply WhatsApp-native formatting to an unprotected text segment. */ +function transformForWhatsApp(text: string): string { + // Order matters: italic before bold to avoid **bold** → *bold* → _bold_ + // 1. Italic: *text* (not **) → _text_ + text = text.replace(/(? (isProtected ? content : transformForWhatsApp(content))).join(''); +} + +/** Map file extension to Baileys media message type. */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function buildMediaMessage(data: Buffer, filename: string, ext: string, caption?: string): any { + const imageExts = ['.jpg', '.jpeg', '.png', '.gif', '.webp']; + const videoExts = ['.mp4', '.mov', '.avi', '.mkv']; + const audioExts = ['.mp3', '.ogg', '.m4a', '.wav', '.aac', '.opus']; + + if (imageExts.includes(ext)) { + return { image: data, caption, mimetype: `image/${ext.slice(1) === 'jpg' ? 'jpeg' : ext.slice(1)}` }; + } + if (videoExts.includes(ext)) { + return { video: data, caption, mimetype: `video/${ext.slice(1)}` }; + } + if (audioExts.includes(ext)) { + return { audio: data, mimetype: `audio/${ext.slice(1) === 'mp3' ? 'mpeg' : ext.slice(1)}` }; + } + // Default: send as document + return { document: data, fileName: filename, caption, mimetype: 'application/octet-stream' }; +} + +registerChannelAdapter('whatsapp', { + factory: () => { + const env = readEnvFile(['WHATSAPP_PHONE_NUMBER', 'WHATSAPP_ENABLED']); + const phoneNumber = env.WHATSAPP_PHONE_NUMBER; + const authDir = AUTH_DIR; + + // Skip if no existing auth, no phone number for pairing, and not explicitly enabled (QR mode) + const hasAuth = fs.existsSync(path.join(authDir, 'creds.json')); + if (!hasAuth && !phoneNumber && !env.WHATSAPP_ENABLED) return null; + + fs.mkdirSync(authDir, { recursive: true }); + + // State + let sock: WASocket; + let connected = false; + let setupConfig: ChannelSetup; + + // LID → phone JID mapping (WhatsApp's new ID system) + const lidToPhoneMap: Record = {}; + let botLidUser: string | undefined; + let botPhoneJid: string | undefined; + + // Outgoing queue for messages sent while disconnected + const outgoingQueue: Array<{ jid: string; text: string }> = []; + let flushing = false; + + // Sent message cache for retry/re-encrypt requests + const sentMessageCache = new Map(); + + // Group metadata cache with TTL + const groupMetadataCache = new Map(); + + // Pending questions: chatJid → { questionId, options } + // User replies with /approve, /reject, etc. to answer + const pendingQuestions = new Map< + string, + { + questionId: string; + options: NormalizedOption[]; + } + >(); + + // Group sync tracking + let lastGroupSync = 0; + let groupSyncTimerStarted = false; + + // First-connect promise + let resolveFirstOpen: (() => void) | undefined; + let rejectFirstOpen: ((err: Error) => void) | undefined; + + // Pairing code file for the setup skill to poll + const pairingCodeFile = path.join(process.cwd(), 'store', 'pairing-code.txt'); + + // --- Helpers --- + + function setLidPhoneMapping(lidUser: string, phoneJid: string): void { + if (lidToPhoneMap[lidUser] === phoneJid) return; + lidToPhoneMap[lidUser] = phoneJid; + // Cached group metadata depends on participant IDs — invalidate + groupMetadataCache.clear(); + } + + async function translateJid(jid: string, altJid?: string): Promise { + if (!jid.endsWith('@lid')) return jid; + const lidUser = jid.split('@')[0].split(':')[0]; + + // 1. Check local cache + const cached = lidToPhoneMap[lidUser]; + if (cached) return cached; + + // 2. Use the alt JID from extractAddressingContext (v7 provides this + // on every inbound message as remoteJidAlt / participantAlt) + if (altJid && !altJid.endsWith('@lid')) { + const phoneJid = altJid.includes('@') ? altJid : `${altJid}@s.whatsapp.net`; + setLidPhoneMapping(lidUser, phoneJid); + log.info('Translated LID via alt JID', { lidJid: jid, phoneJid }); + return phoneJid; + } + + // 3. Query Baileys v7 LID mapping store + try { + const pn = await sock.signalRepository.lidMapping.getPNForLID(jid); + if (pn) { + const phoneJid = `${pn.split('@')[0].split(':')[0]}@s.whatsapp.net`; + setLidPhoneMapping(lidUser, phoneJid); + log.info('Translated LID via signal repository', { lidJid: jid, phoneJid }); + return phoneJid; + } + } catch (err) { + log.debug('Failed to resolve LID via signalRepository', { jid, err }); + } + + return jid; + } + + async function getNormalizedGroupMetadata(jid: string): Promise { + if (!jid.endsWith('@g.us')) return undefined; + + const cached = groupMetadataCache.get(jid); + if (cached && cached.expiresAt > Date.now()) return cached.metadata; + + const metadata = await sock.groupMetadata(jid); + const participants = await Promise.all( + metadata.participants.map(async (p) => ({ + ...p, + id: await translateJid(p.id), + })), + ); + const normalized = { ...metadata, participants }; + groupMetadataCache.set(jid, { + metadata: normalized, + expiresAt: Date.now() + GROUP_METADATA_CACHE_TTL_MS, + }); + return normalized; + } + + async function syncGroupMetadata(force = false): Promise { + if (!force && lastGroupSync && Date.now() - lastGroupSync < GROUP_SYNC_INTERVAL_MS) { + return; + } + try { + log.info('Syncing group metadata from WhatsApp...'); + const groups = await sock.groupFetchAllParticipating(); + let count = 0; + for (const [jid, metadata] of Object.entries(groups)) { + if (metadata.subject) { + setupConfig.onMetadata(jid, metadata.subject, true); + count++; + } + } + lastGroupSync = Date.now(); + log.info('Group metadata synced', { count }); + } catch (err) { + log.error('Failed to sync group metadata', { err }); + } + } + + async function flushOutgoingQueue(): Promise { + if (flushing || outgoingQueue.length === 0) return; + flushing = true; + try { + log.info('Flushing outgoing message queue', { count: outgoingQueue.length }); + while (outgoingQueue.length > 0) { + const item = outgoingQueue.shift()!; + const sent = await sock.sendMessage(item.jid, { text: item.text }); + if (sent?.key?.id && sent.message) { + sentMessageCache.set(sent.key.id, sent.message); + } + } + } finally { + flushing = false; + } + } + + /** + * Resolve the destination group folder for an inbound chat. Picks the + * wired agent group with the highest priority. Returns null when the + * messaging group is missing or has no wirings yet (cold-DM auto-create + * happens later in the router) — callers should skip download in that + * case so attachments don't end up orphaned on disk. + * + * Multi-agent caveat: when one messaging group is wired to several agent + * groups, the file lands in the highest-priority group's folder only. + * For shared/agent-shared modes that need the file visible to all wired + * agents, this needs revisiting (symlink fan-out or a shared mount). + */ + function resolveGroupFolder(chatJid: string): string | null { + const mg = getMessagingGroupByPlatform('whatsapp', chatJid); + if (!mg) return null; + const agents = getMessagingGroupAgents(mg.id); + if (agents.length === 0) return null; + const ag = getAgentGroup(agents[0].agent_group_id); + return ag?.folder ?? null; + } + + /** + * Download media from an inbound message, save into the destination + * agent group's `attachments/` folder so the file lands at + * `/workspace/agent/attachments/` inside the container (the group + * folder is mounted at `/workspace/agent/`). Returns metadata with both + * the container-relative `localPath` and the absolute `hostPath` so + * host-side consumers (e.g. transcription) can read directly. + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + async function downloadInboundMedia( + msg: WAMessage, + normalized: any, + chatJid: string, + ): Promise> { + const folder = resolveGroupFolder(chatJid); + if (!folder) { + log.debug('Skipping media download — messaging group not wired to any agent group', { chatJid }); + return []; + } + + const mediaTypes: Array<{ key: string; type: string; ext: string }> = [ + { key: 'imageMessage', type: 'image', ext: '.jpg' }, + { key: 'videoMessage', type: 'video', ext: '.mp4' }, + { key: 'audioMessage', type: 'audio', ext: '.ogg' }, + { key: 'documentMessage', type: 'document', ext: '' }, + ]; + const results: Array<{ + type: string; + name: string; + localPath: string; + hostPath: string; + }> = []; + for (const { key, type, ext } of mediaTypes) { + if (!normalized[key]) continue; + try { + const buffer = await downloadMediaMessage(msg, 'buffer', {}); + // documentMessage.fileName is attacker-controlled and rides through + // WhatsApp's E2E channel — Meta can't sanitize it server-side. Without + // this guard, a `..`-laden fileName escapes attachDir on path.join. + const rawFilename = normalized[key].fileName; + const fallback = `${type}-${Date.now()}${ext}`; + const filename = isSafeAttachmentName(rawFilename) ? rawFilename : fallback; + if (rawFilename && filename !== rawFilename) { + log.warn('Refused unsafe attachment filename — would escape attachments dir', { + rawFilename, + replacement: filename, + }); + } + const attachDir = path.join(GROUPS_DIR, folder, 'attachments'); + fs.mkdirSync(attachDir, { recursive: true }); + const filePath = path.join(attachDir, filename); + fs.writeFileSync(filePath, buffer); + // localPath is relative to /workspace (set by formatter). Group + // folder is mounted at /workspace/agent/, so prefix with `agent/`. + results.push({ + type, + name: filename, + localPath: `agent/attachments/${filename}`, + hostPath: filePath, + }); + log.info('Media downloaded', { type, filename, folder }); + } catch (err) { + log.warn('Failed to download media', { type, err }); + } + } + return results; + } + + async function sendRawMessage(jid: string, text: string): Promise { + if (!connected) { + outgoingQueue.push({ jid, text }); + log.info('WA disconnected, message queued', { jid, queueSize: outgoingQueue.length }); + return; + } + try { + const sent = await sock.sendMessage(jid, { text }); + if (sent?.key?.id && sent.message) { + sentMessageCache.set(sent.key.id, sent.message); + if (sentMessageCache.size > SENT_MESSAGE_CACHE_MAX) { + const oldest = sentMessageCache.keys().next().value!; + sentMessageCache.delete(oldest); + } + } + return sent?.key?.id ?? undefined; + } catch (err) { + outgoingQueue.push({ jid, text }); + log.warn('Failed to send, message queued', { jid, err, queueSize: outgoingQueue.length }); + return undefined; + } + } + + // --- Socket creation --- + + async function connectSocket(): Promise { + const { state, saveCreds } = await useMultiFileAuthState(authDir); + + const version = await resolveWaWebVersion(); + + sock = makeWASocket({ + version, + auth: { + creds: state.creds, + keys: makeCacheableSignalKeyStore(state.keys, baileysLogger), + }, + printQRInTerminal: false, + logger: baileysLogger, + browser: Browsers.macOS('Chrome'), + cachedGroupMetadata: async (jid: string) => getNormalizedGroupMetadata(jid), + getMessage: async (key: WAMessageKey) => { + // Check in-memory cache first (recently sent messages) + const cached = sentMessageCache.get(key.id || ''); + if (cached) return cached; + // Return empty message to prevent indefinite "waiting for this message" + return proto.Message.create({}); + }, + }); + + // Request pairing code if phone number is set and not yet registered + if (phoneNumber && !state.creds.registered) { + setTimeout(async () => { + try { + const code = await sock.requestPairingCode(phoneNumber); + log.info(`WhatsApp pairing code: ${code}`); + log.info('Enter in WhatsApp > Linked Devices > Link with phone number'); + fs.writeFileSync(pairingCodeFile, code, 'utf-8'); + } catch (err) { + log.error('Failed to request pairing code', { err }); + } + }, 3000); + } + + sock.ev.on('connection.update', (update) => { + const { connection, lastDisconnect, qr } = update; + + if (qr && !phoneNumber) { + // QR code auth — print to terminal + (async () => { + try { + const QRCode = await import('qrcode'); + const qrText = await QRCode.toString(qr, { type: 'terminal' }); + log.info('WhatsApp QR code — scan with WhatsApp > Linked Devices:\n' + qrText); + } catch { + log.info('WhatsApp QR code (raw)', { qr }); + } + })(); + } + + if (connection === 'close') { + connected = false; + const reason = (lastDisconnect?.error as { output?: { statusCode?: number } })?.output?.statusCode; + const shouldReconnect = reason !== DisconnectReason.loggedOut; + + log.info('WhatsApp connection closed', { reason, shouldReconnect }); + + if (shouldReconnect) { + log.info('Reconnecting...'); + connectSocket().catch((err) => { + log.error('Failed to reconnect, retrying in 5s', { err }); + setTimeout(() => { + connectSocket().catch((err2) => { + log.error('Reconnection retry failed', { err: err2 }); + }); + }, RECONNECT_DELAY_MS); + }); + } else { + log.info('WhatsApp logged out'); + if (rejectFirstOpen) { + rejectFirstOpen(new Error('WhatsApp logged out')); + rejectFirstOpen = undefined; + resolveFirstOpen = undefined; + } + } + } else if (connection === 'open') { + connected = true; + log.info('Connected to WhatsApp'); + + // Clean up pairing code file after successful connection + try { + if (fs.existsSync(pairingCodeFile)) fs.unlinkSync(pairingCodeFile); + } catch { + /* ignore */ + } + + // Announce availability for presence updates + sock.sendPresenceUpdate('available').catch((err) => { + log.warn('Failed to send presence update', { err }); + }); + + // Build LID → phone mapping from auth state + if (sock.user) { + const phoneUser = sock.user.id.split(':')[0]; + const lidUser = sock.user.lid?.split(':')[0]; + botPhoneJid = `${phoneUser}@s.whatsapp.net`; + if (lidUser && phoneUser) { + setLidPhoneMapping(lidUser, botPhoneJid); + botLidUser = lidUser; + } + } + + // Flush queued messages + flushOutgoingQueue().catch((err) => log.error('Failed to flush outgoing queue', { err })); + + // Group sync + syncGroupMetadata().catch((err) => log.error('Initial group sync failed', { err })); + if (!groupSyncTimerStarted) { + groupSyncTimerStarted = true; + setInterval(() => { + syncGroupMetadata().catch((err) => log.error('Periodic group sync failed', { err })); + }, GROUP_SYNC_INTERVAL_MS); + } + + // Signal first open + if (resolveFirstOpen) { + resolveFirstOpen(); + resolveFirstOpen = undefined; + rejectFirstOpen = undefined; + } + } + }); + + sock.ev.on('creds.update', saveCreds); + + // LID ↔ phone mapping updates (v7 replaces chats.phoneNumberShare) + sock.ev.on('lid-mapping.update', ({ lid, pn }) => { + const lidUser = lid?.split('@')[0].split(':')[0]; + if (lidUser && pn) { + const phoneJid = pn.includes('@') ? pn : `${pn}@s.whatsapp.net`; + setLidPhoneMapping(lidUser, phoneJid); + } + }); + + // Inbound messages + sock.ev.on('messages.upsert', async ({ messages }) => { + for (const msg of messages) { + try { + if (!msg.message) continue; + const normalized = normalizeMessageContent(msg.message); + if (!normalized) continue; + const rawJid = msg.key.remoteJid; + if (!rawJid || rawJid === 'status@broadcast') continue; + + // Translate LID → phone JID using v7's alt JID from extractAddressingContext + const chatJid = await translateJid(rawJid, msg.key.remoteJidAlt); + + const timestamp = new Date(Number(msg.messageTimestamp) * 1000).toISOString(); + const isGroup = chatJid.endsWith('@g.us'); + + // Notify metadata for group discovery + setupConfig.onMetadata(chatJid, undefined, isGroup); + + let content = + normalized.conversation || + normalized.extendedTextMessage?.text || + normalized.imageMessage?.caption || + normalized.videoMessage?.caption || + ''; + + // Normalize bot LID mention → assistant name for trigger matching + if (botLidUser && content.includes(`@${botLidUser}`)) { + content = content.replace(`@${botLidUser}`, `@${ASSISTANT_NAME}`); + } + + // Strip orphan UTF-16 surrogate pairs (break JSON.stringify downstream) + content = content.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(? a.type === 'audio'); + if (audio) { + const transcript = await transcribeAudioFile(audio.hostPath); + const prefix = transcript ?? TRANSCRIPTION_FALLBACK; + content = content ? `${prefix}\n${content}` : prefix; + } + } + + // Skip empty protocol messages (no text and no attachments) + if (!content && attachments.length === 0) continue; + + // Resolve sender: in groups, participant may be LID — use participantAlt + const rawSender = msg.key.participant || msg.key.remoteJid || ''; + const sender = rawSender.endsWith('@lid') + ? await translateJid(rawSender, msg.key.participantAlt) + : rawSender; + const senderName = msg.pushName || sender.split('@')[0]; + const fromMe = msg.key.fromMe || false; + // Filter bot's own messages to prevent echo loops. + // In self-chat (user messaging their own number), all messages have + // fromMe=true — use sentMessageCache to distinguish bot echoes from + // user-typed messages. + // + // In dedicated-number mode (ASSISTANT_HAS_OWN_NUMBER=true): any fromMe + // message in non-self-chat is the bot's own outbound — skip. + // + // In shared-number mode (ASSISTANT_HAS_OWN_NUMBER=false): the bot + // shares the user's WhatsApp number. The bot prefixes its outbound + // with `${ASSISTANT_NAME}:`. Only filter fromMe messages that: + // (a) hit sentMessageCache (we sent them just now), OR + // (b) start with the assistant prefix (older bot echo) + // Otherwise it's the user typing on the shared phone — process it. + if (fromMe) { + const isSelfChat = botPhoneJid && chatJid === botPhoneJid; + if (sentMessageCache.has(msg.key.id || '')) continue; + if (ASSISTANT_HAS_OWN_NUMBER) { + if (!isSelfChat) continue; + } else { + if (!isSelfChat && content.startsWith(`${ASSISTANT_NAME}:`)) continue; + } + } + + const isBotMessage = ASSISTANT_HAS_OWN_NUMBER ? false : content.startsWith(`${ASSISTANT_NAME}:`); + + // Check if this reply answers a pending question via slash command + const pending = pendingQuestions.get(chatJid); + if (pending && content.startsWith('/')) { + const cmd = content.trim().toLowerCase(); + const matched = pending.options.find((o) => optionToCommand(o.label) === cmd); + if (matched) { + const voterName = msg.pushName || sender.split('@')[0]; + setupConfig.onAction(pending.questionId, matched.value, sender); + pendingQuestions.delete(chatJid); + await sendRawMessage(chatJid, `${matched.selectedLabel} by ${voterName}`); + log.info('Question answered', { + questionId: pending.questionId, + value: matched.value, + voterName, + }); + continue; // Don't forward this reply to the agent + } + } + + const inbound: InboundMessage = { + id: msg.key.id || `wa-${Date.now()}`, + kind: 'chat', + // DMs are addressed to the bot by definition. Mark them as + // platform-confirmed mentions so the router auto-creates an + // approval-required messaging_group when the chat is unknown, + // instead of silently dropping. + isMention: !isGroup ? true : TRIGGER_PATTERN.test(content) ? true : undefined, + isGroup, + content: { + text: content, + sender, + senderName, + // Strip host-only `hostPath` before serializing into messages_in — + // the container only needs the container-relative `localPath`. + ...(attachments.length > 0 && { + attachments: attachments.map(({ hostPath: _hostPath, ...rest }) => rest), + }), + fromMe, + isBotMessage, + isGroup, + chatJid, + }, + timestamp, + }; + + // WhatsApp doesn't use threads — threadId is null + setupConfig.onInbound(chatJid, null, inbound); + } catch (err) { + log.error('Error processing incoming WhatsApp message', { + err, + remoteJid: msg.key?.remoteJid, + }); + } + } + }); + } + + // --- ChannelAdapter implementation --- + + const adapter: ChannelAdapter = { + name: 'whatsapp', + channelType: 'whatsapp', + supportsThreads: false, + + async setup(hostConfig: ChannelSetup) { + setupConfig = hostConfig; + + // Connect and wait for first open + await new Promise((resolve, reject) => { + resolveFirstOpen = resolve; + rejectFirstOpen = reject; + connectSocket().catch(reject); + }); + + log.info('WhatsApp adapter initialized'); + }, + + async deliver( + platformId: string, + _threadId: string | null, + message: OutboundMessage, + ): Promise { + const content = message.content as Record; + + // Ask question → text with slash command replies + if (content.type === 'ask_question' && content.questionId && content.options) { + const questionId = content.questionId as string; + const title = content.title as string; + const question = content.question as string; + if (!title) { + log.error('ask_question missing required title — skipping delivery', { questionId }); + return; + } + const options: NormalizedOption[] = normalizeOptions(content.options as never); + + const optionLines = options.map((o) => ` ${optionToCommand(o.label)}`).join('\n'); + const text = `*${title}*\n\n${question}\n\nReply with:\n${optionLines}`; + const msgId = await sendRawMessage(platformId, text); + if (msgId) { + pendingQuestions.set(platformId, { questionId, options }); + if (pendingQuestions.size > PENDING_QUESTIONS_MAX) { + const oldest = pendingQuestions.keys().next().value!; + pendingQuestions.delete(oldest); + } + } + return msgId; + } + + // Reaction → emoji on a message + if (content.operation === 'reaction' && content.messageId && content.emoji) { + try { + await sock.sendMessage(platformId, { + react: { + text: content.emoji as string, + key: { remoteJid: platformId, id: content.messageId as string, fromMe: false }, + }, + }); + } catch (err) { + log.debug('Failed to send reaction', { platformId, err }); + } + return; + } + + // Normal message (with optional file attachments) + const text = (content.markdown as string) || (content.text as string); + const hasFiles = message.files && message.files.length > 0; + + if (!text && !hasFiles) return; + + // Send file attachments (first file gets the caption, rest are captionless) + if (hasFiles) { + let captionUsed = false; + for (const file of message.files!) { + try { + const ext = path.extname(file.filename).toLowerCase(); + const caption = !captionUsed ? text : undefined; + const mediaMsg = buildMediaMessage(file.data, file.filename, ext, caption); + const sent = await sock.sendMessage(platformId, mediaMsg); + if (sent?.key?.id && sent.message) { + sentMessageCache.set(sent.key.id, sent.message); + } + if (caption) captionUsed = true; + } catch (err) { + log.error('Failed to send file', { platformId, filename: file.filename, err }); + } + } + if (captionUsed) return; // Text was sent as caption + } + + if (text) { + const formatted = formatWhatsApp(text); + const prefixed = ASSISTANT_HAS_OWN_NUMBER ? formatted : `${ASSISTANT_NAME}: ${formatted}`; + return sendRawMessage(platformId, prefixed); + } + }, + + async setTyping(platformId: string) { + try { + await sock.sendPresenceUpdate('composing', platformId); + } catch (err) { + log.debug('Failed to update typing status', { jid: platformId, err }); + } + }, + + async teardown() { + connected = false; + sock?.end(undefined); + log.info('WhatsApp adapter shut down'); + }, + + isConnected() { + return connected; + }, + + async syncConversations(): Promise { + try { + const groups = await sock.groupFetchAllParticipating(); + return Object.entries(groups) + .filter(([, m]) => m.subject) + .map(([jid, m]) => ({ + platformId: jid, + name: m.subject, + isGroup: true, + })); + } catch (err) { + log.error('Failed to sync WhatsApp conversations', { err }); + return []; + } + }, + }; + + return adapter; + }, +}); diff --git a/src/container-runner.ts b/src/container-runner.ts index 7201bfcb513..070bb7710a9 100644 --- a/src/container-runner.ts +++ b/src/container-runner.ts @@ -29,6 +29,7 @@ import { getDb, hasTable } from './db/connection.js'; import { initGroupFilesystem } from './group-init.js'; import { stopTypingRefresh } from './modules/typing/index.js'; import { log } from './log.js'; +import { refreshGoogleTokens } from './google-oauth-refresh.js'; import { validateAdditionalMounts } from './modules/mount-security/index.js'; // Provider host-side config barrel — each provider that needs host-side // container setup self-registers on import. @@ -146,6 +147,10 @@ async function spawnContainer(session: Session): Promise { agentIdentifier, ); + // Refresh Google OAuth tokens (~/.gmail-mcp, ~/.calendar-mcp) if expiring + // within 10 minutes. No-op if the files don't exist. + await refreshGoogleTokens(); + log.info('Spawning container', { sessionId: session.id, agentGroup: agentGroup.name, containerName }); // Clear any orphan heartbeat from a previous container instance — the diff --git a/src/google-oauth-refresh.ts b/src/google-oauth-refresh.ts new file mode 100644 index 00000000000..c5de1b11886 --- /dev/null +++ b/src/google-oauth-refresh.ts @@ -0,0 +1,106 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import os from 'node:os'; + +import { log } from './log.js'; + +const REFRESH_WINDOW_MS = 10 * 60 * 1000; + +interface GoogleCredentials { + access_token?: string; + refresh_token?: string; + expiry_date?: number; + token_type?: string; + scope?: string; +} + +async function refreshOne(credPath: string, clientId: string, clientSecret: string): Promise { + let raw: string; + try { + raw = await fs.readFile(credPath, 'utf8'); + } catch { + return; + } + let creds: GoogleCredentials; + try { + creds = JSON.parse(raw); + } catch (err) { + log.warn('google-oauth-refresh: invalid credentials JSON', { + credPath, + err: String(err), + }); + return; + } + + const now = Date.now(); + if (creds.expiry_date && creds.expiry_date - now > REFRESH_WINDOW_MS) { + return; + } + if (!creds.refresh_token) { + return; + } + + const params = new URLSearchParams({ + client_id: clientId, + client_secret: clientSecret, + refresh_token: creds.refresh_token, + grant_type: 'refresh_token', + }); + + let res: Response; + try { + res = await fetch('https://oauth2.googleapis.com/token', { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: params.toString(), + }); + } catch (err) { + log.warn('google-oauth-refresh: network error', { + credPath, + err: String(err), + }); + return; + } + + if (!res.ok) { + const errText = await res.text().catch(() => ''); + log.warn('google-oauth-refresh: refresh failed', { + credPath, + status: res.status, + errText, + }); + return; + } + + const data = (await res.json()) as { + access_token: string; + expires_in: number; + token_type?: string; + }; + creds.access_token = data.access_token; + creds.expiry_date = Date.now() + data.expires_in * 1000; + if (data.token_type) creds.token_type = data.token_type; + await fs.writeFile(credPath, JSON.stringify(creds, null, 2)); + log.info('google-oauth-refresh: refreshed', { credPath }); +} + +export async function refreshGoogleTokens(): Promise { + const home = os.homedir(); + const gmailKeysPath = path.join(home, '.gmail-mcp', 'gcp-oauth.keys.json'); + let clientId: string | undefined; + let clientSecret: string | undefined; + try { + const keys = JSON.parse(await fs.readFile(gmailKeysPath, 'utf8')); + const inner = keys.installed || keys.web; + clientId = inner?.client_id; + clientSecret = inner?.client_secret; + } catch { + return; + } + if (!clientId || !clientSecret) return; + + await Promise.all([ + refreshOne(path.join(home, '.gmail-mcp', 'credentials.json'), clientId, clientSecret), + refreshOne(path.join(home, '.calendar-mcp', 'credentials.json'), clientId, clientSecret), + ]); +} diff --git a/src/router.ts b/src/router.ts index 9d4765b6b73..973eb5db316 100644 --- a/src/router.ts +++ b/src/router.ts @@ -189,7 +189,7 @@ export async function routeInbound(event: InboundEvent): Promise { platform_id: event.platformId, name: null, is_group: event.message.isGroup ? 1 : 0, - unknown_sender_policy: 'request_approval', + unknown_sender_policy: 'strict', denied_at: null, created_at: new Date().toISOString(), }; diff --git a/src/transcription.ts b/src/transcription.ts new file mode 100644 index 00000000000..33e2c4f38ef --- /dev/null +++ b/src/transcription.ts @@ -0,0 +1,59 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; + +import { DATA_DIR } from './config.js'; +import { readEnvFile } from './env.js'; +import { log } from './log.js'; + +const WHISPER_MODEL = 'whisper-1'; +const FALLBACK = '[Voice Message - transcription unavailable]'; + +export async function transcribeAudioFile(relativeOrAbsolutePath: string): Promise { + const env = readEnvFile(['OPENAI_API_KEY']); + const apiKey = env.OPENAI_API_KEY; + if (!apiKey) { + log.warn('OPENAI_API_KEY not set in .env — skipping transcription'); + return null; + } + + const filePath = path.isAbsolute(relativeOrAbsolutePath) + ? relativeOrAbsolutePath + : path.join(DATA_DIR, relativeOrAbsolutePath); + + let buffer: Buffer; + try { + buffer = await fs.readFile(filePath); + } catch (err) { + log.warn('transcription: failed to read audio file', { + filePath, + err: String(err), + }); + return null; + } + if (buffer.length === 0) return null; + + try { + const openaiModule = await import('openai'); + const OpenAI = openaiModule.default; + const toFile = openaiModule.toFile; + const openai = new OpenAI({ apiKey }); + + const ext = path.extname(filePath).toLowerCase() || '.ogg'; + const mime = ext === '.mp3' ? 'audio/mpeg' : ext === '.m4a' ? 'audio/m4a' : 'audio/ogg'; + + const file = await toFile(buffer, `voice${ext}`, { type: mime }); + const transcription = await openai.audio.transcriptions.create({ + file, + model: WHISPER_MODEL, + response_format: 'text', + }); + + const text = (transcription as unknown as string).trim(); + return text || null; + } catch (err) { + log.warn('transcription: OpenAI Whisper call failed', { err: String(err) }); + return null; + } +} + +export const TRANSCRIPTION_FALLBACK = FALLBACK;