개요
Baileys는 WhatsApp Web API와 상호 작용하기 위한 WebSocket 기반 TypeScript 라이브러리입니다. Node.js, Deno 및 Bun을 지원하며, 사용자 정의 WhatsApp 클라이언트와 자동화 도구를 구축하는 데 일반적으로 사용됩니다. 이 프로젝트는 WhatsApp과 관련이 없으며 MIT 라이선스를 따릅니다.
README 미리보기
\n\n\n> [!CAUTION]\n> NOTICE OF BREAKING CHANGE.\n>\n> As of 7.0.0, multiple breaking changes were introduced into the library.\n>\n> Please check out https://whiskey.so/migrate-latest for more information.\n\nBaileys is a WebSockets-based TypeScript library for interacting with the WhatsApp Web API.\n\nJoin the WhiskeySockets community via the link: https://whiskey.so/discord\n\n# Usage & Guide\n\n> [!IMPORTANT]\n> The new guide is a work in progress. Expect missing pages/content. [Report missing or incorrect content.](https://github.com/WhiskeySockets/baileys.wiki-site/issues/new)\n>\n> **You can still access the old guide here:** [README.md](https://github.com/WhiskeySockets/Baileys/tree/master/README.md), or the [NPM homepage](https://npmjs.com/package/baileys).\n\nThe new guide is posted at https://baileys.wiki .\n\n# Get Support\n\nIf you'd like business to enterprise-level support from Rajeh, the current maintainer of Baileys, you can book a video chat. Book a 1 hour time slot by contacting him on Discord or pre-ordering [here](https://purpshell.dev/book). The earlier you pre-order the better, as his time slots usually fill up very quickly. He offers immense value per hour and will answer all your questions before the time runs out.\n\nIf you are a business, we encourage you to contribute back to the high development costs of the project and to feed the maintainers who dump tens of hours a week on this. You can do so by booking meetings or sponsoring below. All support, even in bona fide / contribution hours, is welcome by businesses of all sizes. This is not condoning or endorsing businesses to use the library. See the Disclaimer below.\n\n# Sponsor\n\nIf you'd like to financially support this project, you can do so by supporting the current maintainer [here](https://purpshell.dev/sponsor).\n\n# Disclaimer\n> [!CAUTION]\n> This project is not affiliated, associated, authorized, endorsed by, or in any way officially connected with WhatsApp or any of its subsi
FAQ (5)
문제 해결미디어 다운로드 연결이 끊길 때 Baileys downloadMediaMessage가 무한정 멈추거나 'TypeError: terminated' uncaughtException으로 크래시되는 문제를 해결하는 방법은?
이것은 Baileys의 버그입니다(7.0.0-rc13/rc14 및 master에서 확인됨): src/Utils/messages-media.ts(약 652번째 줄)의 downloadEncryptedContent가 'error' 리스너를 연결하지 않은 채 undici 응답 스트림을 파이프합니다. 본문 전송 도중 연결이 끊기면 undici가 소스 스트림에서 TypeError: terminated를 발생시키는데, .pipe()는 에러를 전달하지 않으므로 이것이 프로세스 수준의 uncaughtException이 되고, 대상 스트림이 종료되지 않아 await downloadMediaMessage(msg, 'buffer')가 resolve되지도 reject되지도 않으며 for await 반복이 영원히 멈춥니다.
**수정 방법(라이브러리 패치):** src/Utils/messages-media.ts에서 다음을:
return fetched.pipe(output, { end: true })다음과 같이 변경하세요:
fetched.on('error', err => output.destroy(err))
return fetched.pipe(output, { end: true })또는 설계상 에러를 전달하고 소스 스트림을 정리해 주는
stream.pipeline(fetched, output, () => {})을 대신 사용하세요.
**적용 방법:** 수정 위치가 npm 패키지 내부이므로, patch-package(또는 pnpm의 pnpm patch)를 사용하여 변경 사항을 유지하세요: node_modules/baileys/lib/Utils/messages-media.js를 동일한 방식으로 편집한 다음 npx patch-package baileys를 실행합니다. 이 패치를 적용하면 반환된 스트림이 소비자 측에서 TypeError: terminated로 reject되므로, 프로세스가 충돌하거나 메시지 핸들러가 조용히 멈추는 대신 downloadMediaMessage를 감싼 기존 try/catch가 실패를 포착하여 재시도할 수 있습니다.
**업스트림에 패치가 적용될 때까지의 방어적 코딩:** 패치되지 않은 스트림은 무한정 멈출 수 있으므로 미디어 다운로드를 자체 타임아웃(예: 타이머와 경쟁하는 Promise.race)으로 감싸고, undici 에러로 인해 프로세스가 종료되는 것을 막기 위한 최후의 수단으로 process.on('uncaughtException') 핸들러를 추가하세요. 이 해결 방법은 Baileys 7.0.0-rc14와 Node 24 환경의 프로덕션에서 검증되었습니다.
문제 해결연결 직후 Baileys로 이미지를 전송할 때 발생하는 'Connection Closed' 오류를 해결하는 방법은?
이 문제는 이미지 업로드가 refreshMediaConn()을 호출하기 때문에 발생합니다. 이 함수는 WebSocket이 아직 CONNECTING 상태(readyState=0)일 수 있는 동안 소켓을 쿼리하므로 sendRawMessage가 Boom('Connection Closed')를 던지게 됩니다. 텍스트 메시지는 한 번의 왕복만 필요하므로 이 문제가 거의 발생하지 않습니다. 해결 방법: 미디어를 보내기 전에 소켓이 완전히 열릴 때까지 기다리세요:
await sock.waitForSocketOpen();
await sock.sendMessage(jid, { image, caption });
waitForSocketOpen()은 소켓이 열리면 resolve되고, 아직 연결 중이면 기다리며, 닫혔거나 닫히는 중이면 예외를 던집니다. @whiskeysockets/baileys 6.7.24에서 확인했으며, 대기를 추가한 후에는 전송이 일관되게 성공합니다.
문제 해결Baileys communityMetadata에서 "Cannot read properties of undefined (reading 'attrs')" 오류가 발생하는 문제를 해결하는 방법은?
이 버그는 @whiskeysockets/baileys@7.0.0-rc.14와 현재 master에 영향을 미칩니다. extractCommunityMetadata()는 <community> 노드를 예상하지만, WhatsApp이 <group> 노드를 반환할 수 있기 때문에 non-null 단언이 실패하고 community.attrs가 예외를 발생시킵니다.
즉시 적용 가능한 해결 방법: 동일한 커뮤니티 JID로 groupMetadata()를 호출하세요. 커뮤니티 JID는 일반적인 @g.us JID이며, 이는 커뮤니티 관련 필드를 포함한 필요한 메타데이터를 반환합니다:
const meta = await sock.groupMetadata(communityJid)
설명 업데이트의 경우 그룹용 대응 메서드를 사용하세요:
await sock.groupUpdateDescription(communityJid, newDescription)
영구적인 수정: 커뮤니티 메타데이터 파서가 두 응답 형태를 모두 받아들이도록 업데이트하고, 둘 다 없는 경우 분류된 오류를 던지도록 하세요:
const community =
getBinaryNodeChild(result, 'community') ??
getBinaryNodeChild(result, 'group')
if (!community) {
throw new Boom('community metadata response carried no <community> or <group> node', {
data: result,
})
}
동일한 잘못된 가정이 communityUpdateDescription() 및 communityGetInviteInfo()에도 영향을 미치며, communityFetchAllParticipating()도 같은 이유로 아무 오류 없이 {}를 반환할 수 있습니다.
문제 해결Baileys에서 로그인 전에 sendMessageAck에서 발생하는 "Cannot read properties of undefined (reading 'id')" 오류를 수정하는 방법은?
Baileys 7.0.0-rc13/rc14에서 sendMessageAck는 로그인 전에 authState.creds.me.id를 읽지만, creds.me는 페어링이 완료된 후에만 채워집니다. src/Socket/messages-recv.ts의 해당 호출을 옵셔널 체이닝을 사용하도록 변경하세요:
- const stanza = buildAckStanza(node, errorCode, authState.creds.me.id);
+ const stanza = buildAckStanza(node, errorCode, authState.creds.me?.id);
buildAckStanza는 이미 falsy한 meId를 처리하며, 로그인 전 notification ACK에는 from 속성이 필요하지 않습니다. 수정 사항이 릴리스될 때까지 패키지를 다시 빌드하거나 patch-package를 사용하세요. 이렇게 하면 숨겨져 있던 TypeError와 오해를 불러일으키는 failed to ack notification { ackErr: {} } 로그가 해결됩니다. 다만 이 변경만으로 QR 페어링이나 처리되지 않은 companion_reg_refresh 알림 문제가 해결되는 것은 아닙니다.
문제 해결매핑된 LID가 있는 전화번호 JID로 일대일 메시지를 보낼 때 발생하는 WhatsApp ERROR 463을 해결하려면 어떻게 해야 하나요?
@s.whatsapp.net PN JID로 1:1 메시지를 보내기 전에, Baileys의 로컬 LID 매핑을 통해 해당 JID를 조회하세요: signalRepository.lidMapping.getLIDForPN(pn)을 호출합니다. LID가 반환되면 PN JID 대신 <lid>@lid로 메시지를 보내고, 원래 PN은 remoteJidAlt 메타데이터로 보존하세요. 예를 들어, 해당 매핑이 존재하는 경우 19178056839@s.whatsapp.net을 148373990592755@lid로 라우팅합니다. 이렇게 하면 messageStubParameters: ["463"]을 포함한 비동기 messages.update 거부를 방지하고 정상적인 SERVER_ACK/DELIVERY_ACK 응답을 얻을 수 있습니다. 로컬 LID 매핑이 없는 경우에는 암묵적인 USync를 강제하지 말고 기존 PN 조회 경로를 유지하세요. 업스트림 수정 사항은 전송/릴레이 경로에서 이 PN-to-LID 조회를 구현합니다.