diff --git a/.nvmrc b/.nvmrc index 32cfab6..54c6511 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v22.18.0 +v24 diff --git a/apps/bridge-whatsapp/package.json b/apps/bridge-whatsapp/package.json index 0f591fb..a01cc38 100644 --- a/apps/bridge-whatsapp/package.json +++ b/apps/bridge-whatsapp/package.json @@ -1,33 +1,29 @@ { "name": "@link-stack/bridge-whatsapp", "version": "3.3.2", + "type": "module", "main": "build/main/index.js", "author": "Darren Clarke ", "license": "AGPL-3.0-or-later", "dependencies": { - "@adiwajshing/keyed-db": "0.2.4", "@hapi/hapi": "^21.4.3", "@hapipal/schmervice": "^3.0.0", "@hapipal/toys": "^4.0.0", "@link-stack/bridge-common": "workspace:*", "@link-stack/logger": "workspace:*", - "@whiskeysockets/baileys": "^6.7.21", - "hapi-pino": "^13.0.0", - "link-preview-js": "^3.1.0" + "@whiskeysockets/baileys": "7.0.0-rc.9", + "hapi-pino": "^13.0.0" }, "devDependencies": { "@link-stack/eslint-config": "workspace:*", "@link-stack/jest-config": "workspace:*", "@link-stack/typescript-config": "workspace:*", - "@types/long": "^5", "@types/node": "*", - "dotenv-cli": "^10.0.0", - "tsx": "^4.20.6", "typescript": "^5.9.3" }, "scripts": { "build": "tsc -p tsconfig.json", - "dev": "dotenv -- tsx src/index.ts", + "dev": "node --env-file=.env --experimental-transform-types src/index.ts", "start": "node build/main/index.js" } } diff --git a/apps/bridge-whatsapp/src/index.ts b/apps/bridge-whatsapp/src/index.ts index 5be8763..bd255ff 100644 --- a/apps/bridge-whatsapp/src/index.ts +++ b/apps/bridge-whatsapp/src/index.ts @@ -1,17 +1,17 @@ import * as Hapi from "@hapi/hapi"; import hapiPino from "hapi-pino"; import Schmervice from "@hapipal/schmervice"; -import WhatsappService from "./service.js"; +import WhatsappService from "./service.ts"; import { RegisterBotRoute, UnverifyBotRoute, GetBotRoute, SendMessageRoute, ReceiveMessageRoute, -} from "./routes.js"; +} from "./routes.ts"; import { createLogger } from "@link-stack/logger"; -const logger = createLogger('bridge-whatsapp-index'); +const logger = createLogger("bridge-whatsapp-index"); const server = Hapi.server({ port: 5000 }); diff --git a/apps/bridge-whatsapp/src/routes.ts b/apps/bridge-whatsapp/src/routes.ts index 1d9caf6..7315020 100644 --- a/apps/bridge-whatsapp/src/routes.ts +++ b/apps/bridge-whatsapp/src/routes.ts @@ -1,6 +1,6 @@ import * as Hapi from "@hapi/hapi"; import Toys from "@hapipal/toys"; -import WhatsappService from "./service"; +import WhatsappService from "./service.ts"; const withDefaults = Toys.withRouteDefaults({ options: { @@ -27,15 +27,9 @@ export const SendMessageRoute = withDefaults({ description: "Send a message", async handler(request: Hapi.Request, _h: Hapi.ResponseToolkit) { const { id } = request.params; - const { phoneNumber, message, attachments } = - request.payload as MessageRequest; + const { phoneNumber, message, attachments } = request.payload as MessageRequest; const whatsappService = getService(request); - await whatsappService.send( - id, - phoneNumber, - message as string, - attachments, - ); + await whatsappService.send(id, phoneNumber, message as string, attachments); request.logger.info( { id, diff --git a/apps/bridge-whatsapp/src/service.ts b/apps/bridge-whatsapp/src/service.ts index 352d85b..d3ace51 100644 --- a/apps/bridge-whatsapp/src/service.ts +++ b/apps/bridge-whatsapp/src/service.ts @@ -4,12 +4,13 @@ import makeWASocket, { DisconnectReason, proto, downloadContentFromMessage, - MediaType, fetchLatestBaileysVersion, isJidBroadcast, isJidStatusBroadcast, useMultiFileAuthState, } from "@whiskeysockets/baileys"; + +type MediaType = "audio" | "document" | "image" | "video" | "sticker"; import fs from "fs"; import { createLogger } from "@link-stack/logger"; import { @@ -26,11 +27,7 @@ export default class WhatsappService extends Service { connections: { [key: string]: any } = {}; loginConnections: { [key: string]: any } = {}; - static browserDescription: [string, string, string] = [ - "Bridge", - "Chrome", - "2.0", - ]; + static browserDescription: [string, string, string] = ["Bridge", "Chrome", "2.0"]; constructor(server: Server, options: never) { super(server, options); @@ -47,7 +44,7 @@ export default class WhatsappService extends Service { } // Prevent path traversal by checking for suspicious patterns - if (id.includes('..') || id.includes('/') || id.includes('\\')) { + if (id.includes("..") || id.includes("/") || id.includes("\\")) { throw new Error(`Path traversal detected in bot ID: ${id}`); } @@ -102,20 +99,14 @@ export default class WhatsappService extends Service { auth: state, generateHighQualityLinkPreview: false, msgRetryCounterMap, - shouldIgnoreJid: (jid) => - isJidBroadcast(jid) || isJidStatusBroadcast(jid), + shouldIgnoreJid: (jid) => isJidBroadcast(jid) || isJidStatusBroadcast(jid), }); let pause = 5000; socket.ev.process(async (events) => { if (events["connection.update"]) { const update = events["connection.update"]; - const { - connection: connectionState, - lastDisconnect, - qr, - isNewLogin, - } = update; + const { connection: connectionState, lastDisconnect, qr, isNewLogin } = update; if (qr) { logger.info("got qr code"); const botDirectory = this.getBotDirectory(botID); @@ -130,8 +121,7 @@ export default class WhatsappService extends Service { logger.info("opened connection"); } else if (connectionState === "close") { logger.info({ lastDisconnect }, "connection closed"); - const disconnectStatusCode = (lastDisconnect?.error as any)?.output - ?.statusCode; + const disconnectStatusCode = (lastDisconnect?.error as any)?.output?.statusCode; if (disconnectStatusCode === DisconnectReason.restartRequired) { logger.info("reconnecting after got new login"); await this.createConnection(botID, server, options); @@ -174,10 +164,7 @@ export default class WhatsappService extends Service { const verifiedFile = `${directory}/verified`; if (fs.existsSync(verifiedFile)) { const { version, isLatest } = await fetchLatestBaileysVersion(); - logger.info( - { version: version.join("."), isLatest }, - "using WA version", - ); + logger.info({ version: version.join("."), isLatest }, "using WA version"); await this.createConnection(botID, this.server, { browser: WhatsappService.browserDescription, @@ -188,15 +175,13 @@ export default class WhatsappService extends Service { } } - private async queueMessage( - botID: string, - webMessageInfo: proto.IWebMessageInfo, - ) { - const { - key: { id, fromMe, remoteJid }, - message, - messageTimestamp, - } = webMessageInfo; + private async queueMessage(botID: string, webMessageInfo: proto.IWebMessageInfo) { + const { key, message, messageTimestamp } = webMessageInfo; + if (!key) { + logger.warn("Message missing key, skipping"); + return; + } + const { id, fromMe, remoteJid } = key; logger.info("Message type debug"); for (const key in message) { logger.info( @@ -204,11 +189,9 @@ export default class WhatsappService extends Service { "Message field", ); } - const isValidMessage = - message && remoteJid !== "status@broadcast" && !fromMe; + const isValidMessage = message && remoteJid !== "status@broadcast" && !fromMe; if (isValidMessage) { - const { audioMessage, documentMessage, imageMessage, videoMessage } = - message; + const { audioMessage, documentMessage, imageMessage, videoMessage } = message; const isMediaMessage = audioMessage || documentMessage || imageMessage || videoMessage; @@ -288,10 +271,7 @@ export default class WhatsappService extends Service { } } - private async queueUnreadMessages( - botID: string, - messages: proto.IWebMessageInfo[], - ) { + private async queueUnreadMessages(botID: string, messages: proto.IWebMessageInfo[]) { for await (const message of messages) { await this.queueMessage(botID, message); } @@ -334,10 +314,7 @@ export default class WhatsappService extends Service { } } - async register( - botID: string, - callback?: AuthCompleteCallback, - ): Promise { + async register(botID: string, callback?: AuthCompleteCallback): Promise { const { version } = await fetchLatestBaileysVersion(); await this.createConnection( botID, @@ -368,7 +345,9 @@ export default class WhatsappService extends Service { const MAX_TOTAL_SIZE = getMaxTotalAttachmentSize(); if (attachments.length > MAX_ATTACHMENTS) { - throw new Error(`Too many attachments: ${attachments.length} (max ${MAX_ATTACHMENTS})`); + throw new Error( + `Too many attachments: ${attachments.length} (max ${MAX_ATTACHMENTS})`, + ); } let totalSize = 0; @@ -378,20 +357,26 @@ export default class WhatsappService extends Service { const estimatedSize = (attachment.data.length * 3) / 4; if (estimatedSize > MAX_ATTACHMENT_SIZE) { - logger.warn({ - filename: attachment.filename, - size: estimatedSize, - maxSize: MAX_ATTACHMENT_SIZE - }, 'Attachment exceeds size limit, skipping'); + logger.warn( + { + filename: attachment.filename, + size: estimatedSize, + maxSize: MAX_ATTACHMENT_SIZE, + }, + "Attachment exceeds size limit, skipping", + ); continue; } totalSize += estimatedSize; if (totalSize > MAX_TOTAL_SIZE) { - logger.warn({ - totalSize, - maxTotalSize: MAX_TOTAL_SIZE - }, 'Total attachment size exceeds limit, skipping remaining'); + logger.warn( + { + totalSize, + maxTotalSize: MAX_TOTAL_SIZE, + }, + "Total attachment size exceeds limit, skipping remaining", + ); break; } diff --git a/apps/bridge-whatsapp/src/types.ts b/apps/bridge-whatsapp/src/types.ts index 231a804..dc6d4fb 100644 --- a/apps/bridge-whatsapp/src/types.ts +++ b/apps/bridge-whatsapp/src/types.ts @@ -1,4 +1,4 @@ -import type WhatsappService from "./service.js"; +import type WhatsappService from "./service.ts"; declare module "@hapipal/schmervice" { interface SchmerviceDecorator { diff --git a/apps/bridge-whatsapp/tsconfig.json b/apps/bridge-whatsapp/tsconfig.json index 4b714ce..dce4015 100644 --- a/apps/bridge-whatsapp/tsconfig.json +++ b/apps/bridge-whatsapp/tsconfig.json @@ -1,16 +1,17 @@ { "extends": "@link-stack/typescript-config/tsconfig.node.json", "compilerOptions": { - "module": "commonjs", - "target": "es2018", + "module": "NodeNext", + "target": "es2022", "esModuleInterop": true, - "moduleResolution": "node", + "moduleResolution": "NodeNext", "outDir": "build/main", "rootDir": "src", "skipLibCheck": true, "types": ["node"], - "lib": ["es2020", "DOM"], - "composite": true + "lib": ["es2022", "DOM"], + "composite": true, + "rewriteRelativeImportExtensions": true }, "include": ["src/**/*.ts", "src/**/.*.ts"], "exclude": ["node_modules/**"] diff --git a/package.json b/package.json index 99df06c..9d27920 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "react": "19.2.0", "react-dom": "19.2.0", "ts-node": "^10.9.2", - "turbo": "^2.5.8", + "turbo": "^2.6.0", "typescript": "latest" }, "pnpm": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 58147bd..c415592 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,7 +37,7 @@ importers: specifier: ^10.9.2 version: 10.9.2(@types/node@24.10.0)(typescript@5.9.3) turbo: - specifier: ^2.5.8 + specifier: ^2.6.0 version: 2.6.0 typescript: specifier: latest @@ -146,9 +146,6 @@ importers: apps/bridge-whatsapp: dependencies: - '@adiwajshing/keyed-db': - specifier: 0.2.4 - version: 0.2.4 '@hapi/hapi': specifier: ^21.4.3 version: 21.4.4 @@ -165,14 +162,11 @@ importers: specifier: workspace:* version: link:../../packages/logger '@whiskeysockets/baileys': - specifier: ^6.7.21 - version: 6.7.21(link-preview-js@3.1.0)(sharp@0.34.5) + specifier: 7.0.0-rc.9 + version: 7.0.0-rc.9(link-preview-js@3.1.0)(sharp@0.34.5) hapi-pino: specifier: ^13.0.0 version: 13.0.0 - link-preview-js: - specifier: ^3.1.0 - version: 3.1.0 devDependencies: '@link-stack/eslint-config': specifier: workspace:* @@ -183,18 +177,9 @@ importers: '@link-stack/typescript-config': specifier: workspace:* version: link:../../packages/typescript-config - '@types/long': - specifier: ^5 - version: 5.0.0 '@types/node': specifier: '*' version: 24.10.0 - dotenv-cli: - specifier: ^10.0.0 - version: 10.0.0 - tsx: - specifier: ^4.20.6 - version: 4.20.6 typescript: specifier: ^5.9.3 version: 5.9.3 @@ -589,9 +574,6 @@ importers: packages: - '@adiwajshing/keyed-db@0.2.4': - resolution: {integrity: sha512-yprSnAtj80/VKuDqRcFFLDYltoNV8tChNwFfIgcf6PGD4sjzWIBgs08pRuTqGH5mk5wgL6PBRSsMCZqtZwzFEw==} - '@auth/core@0.41.1': resolution: {integrity: sha512-t9cJ2zNYAdWMacGRMT6+r4xr1uybIdmYa49calBPeTqwgAFPV/88ac9TEvCR85pvATiSPt8VaNf+Gt24JIT/uw==} peerDependencies: @@ -2154,10 +2136,6 @@ packages: '@types/long@4.0.2': resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} - '@types/long@5.0.0': - resolution: {integrity: sha512-eQs9RsucA/LNjnMoJvWG/nXa7Pot/RbBzilF/QRIU/xRl+0ApxrSUFsV5lmf01SvSlqMzJ7Zwxe440wmz2SJGA==} - deprecated: This is a stub types definition. long provides its own type definitions, so you do not need this installed. - '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} @@ -2361,8 +2339,8 @@ packages: cpu: [x64] os: [win32] - '@whiskeysockets/baileys@6.7.21': - resolution: {integrity: sha512-xx9OHd6jlPiu5yZVuUdwEgFNAOXiEG8sULHxC6XfzNwssnwxnA9Lp44pR05H621GQcKyCfsH33TGy+Na6ygX4w==} + '@whiskeysockets/baileys@7.0.0-rc.9': + resolution: {integrity: sha512-YFm5gKXfDP9byCXCW3OPHKXLzrAKzolzgVUlRosHHgwbnf2YOO3XknkMm6J7+F0ns8OA0uuSBhgkRHTDtqkacw==} engines: {node: '>=20.0.0'} peerDependencies: audio-decode: ^2.1.3 @@ -2377,8 +2355,8 @@ packages: link-preview-js: optional: true - '@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/e81ecfc32eb74951d789ab37f7e341ab66d5fff1': - resolution: {tarball: https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/e81ecfc32eb74951d789ab37f7e341ab66d5fff1} + '@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 abstract-logging@2.0.1: @@ -3186,6 +3164,9 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -4306,6 +4287,14 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-queue@9.0.1: + resolution: {integrity: sha512-RhBdVhSwJb7Ocn3e8ULk4NMwBEuOxe+1zcgphUy9c2e5aR/xbEsdVXxHJ3lynw6Qiqu7OINEyHlZkiblEpaq7w==} + 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'} @@ -4849,6 +4838,7 @@ packages: source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} @@ -5340,8 +5330,6 @@ packages: snapshots: - '@adiwajshing/keyed-db@0.2.4': {} - '@auth/core@0.41.1': dependencies: '@panva/hkdf': 1.2.1 @@ -6937,10 +6925,6 @@ snapshots: '@types/long@4.0.2': {} - '@types/long@5.0.0': - dependencies: - long: 5.3.2 - '@types/ms@2.1.0': {} '@types/node@10.17.60': {} @@ -7139,14 +7123,15 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@whiskeysockets/baileys@6.7.21(link-preview-js@3.1.0)(sharp@0.34.5)': + '@whiskeysockets/baileys@7.0.0-rc.9(link-preview-js@3.1.0)(sharp@0.34.5)': dependencies: '@cacheable/node-cache': 1.7.4 '@hapi/boom': 9.1.4 async-mutex: 0.5.0 - axios: 1.13.2 - libsignal: '@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/e81ecfc32eb74951d789ab37f7e341ab66d5fff1' + libsignal: '@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67' + lru-cache: 11.2.2 music-metadata: 11.10.0 + p-queue: 9.0.1 pino: 9.14.0 protobufjs: 7.5.4 sharp: 0.34.5 @@ -7155,11 +7140,10 @@ snapshots: link-preview-js: 3.1.0 transitivePeerDependencies: - bufferutil - - debug - supports-color - utf-8-validate - '@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/e81ecfc32eb74951d789ab37f7e341ab66d5fff1': + '@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67': dependencies: curve25519-js: 0.0.4 protobufjs: 6.8.8 @@ -7380,7 +7364,8 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - boolbase@1.0.0: {} + boolbase@1.0.0: + optional: true brace-expansion@1.1.12: dependencies: @@ -7480,6 +7465,7 @@ snapshots: domelementtype: 2.3.0 domhandler: 5.0.3 domutils: 3.2.2 + optional: true cheerio@1.0.0-rc.11: dependencies: @@ -7491,6 +7477,7 @@ snapshots: parse5: 7.3.0 parse5-htmlparser2-tree-adapter: 7.1.0 tslib: 2.8.1 + optional: true chokidar@4.0.3: dependencies: @@ -7621,8 +7608,10 @@ snapshots: domhandler: 5.0.3 domutils: 3.2.2 nth-check: 2.1.1 + optional: true - css-what@6.2.2: {} + css-what@6.2.2: + optional: true csstype@3.1.3: {} @@ -7716,18 +7705,22 @@ snapshots: domelementtype: 2.3.0 domhandler: 5.0.3 entities: 4.5.0 + optional: true - domelementtype@2.3.0: {} + domelementtype@2.3.0: + optional: true domhandler@5.0.3: dependencies: domelementtype: 2.3.0 + optional: true domutils@3.2.2: dependencies: dom-serializer: 2.0.0 domelementtype: 2.3.0 domhandler: 5.0.3 + optional: true dotenv-cli@10.0.0: dependencies: @@ -7787,9 +7780,11 @@ snapshots: dependencies: once: 1.4.0 - entities@4.5.0: {} + entities@4.5.0: + optional: true - entities@6.0.1: {} + entities@6.0.1: + optional: true error-ex@1.3.4: dependencies: @@ -8104,6 +8099,8 @@ snapshots: esutils@2.0.3: {} + eventemitter3@5.0.1: {} + execa@5.1.1: dependencies: cross-spawn: 7.0.6 @@ -8441,6 +8438,7 @@ snapshots: domhandler: 5.0.3 domutils: 3.2.2 entities: 4.5.0 + optional: true http-proxy-agent@7.0.2: dependencies: @@ -9124,6 +9122,7 @@ snapshots: dependencies: cheerio: 1.0.0-rc.11 url: 0.11.0 + optional: true load-esm@1.0.2: {} @@ -9359,6 +9358,7 @@ snapshots: nth-check@2.1.1: dependencies: boolbase: 1.0.0 + optional: true oauth4webapi@3.8.2: {} @@ -9472,6 +9472,13 @@ snapshots: dependencies: p-limit: 3.1.0 + p-queue@9.0.1: + dependencies: + eventemitter3: 5.0.1 + p-timeout: 7.0.1 + + p-timeout@7.0.1: {} + p-try@2.2.0: {} pac-proxy-agent@7.2.0: @@ -9509,10 +9516,12 @@ snapshots: dependencies: domhandler: 5.0.3 parse5: 7.3.0 + optional: true parse5@7.3.0: dependencies: entities: 6.0.1 + optional: true path-exists@4.0.0: {} @@ -9752,7 +9761,8 @@ snapshots: end-of-stream: 1.4.5 once: 1.4.0 - punycode@1.3.2: {} + punycode@1.3.2: + optional: true punycode@2.3.1: {} @@ -9768,7 +9778,8 @@ snapshots: dependencies: side-channel: 1.1.0 - querystring@0.2.0: {} + querystring@0.2.0: + optional: true queue-microtask@1.2.3: {} @@ -10507,6 +10518,7 @@ snapshots: dependencies: punycode: 1.3.2 querystring: 0.2.0 + optional: true use-sync-external-store@1.6.0(react@19.2.0): dependencies: