feat(engine): Baileys engine — minimal slice (link + text send/receive)#299
Merged
Conversation
…; test pairing-code guard
…nce, inbound fan-out
…ardening from final review
…-method disable pattern)
This was referenced Jun 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a second, browser-free WhatsApp engine to OpenWA:
@whiskeysockets/baileys(WebSocket/Noise protocol, no Chromium). This is slice 1 of a decomposed effort — a minimal working engine that links a session and sends/receives text through the unchanged engine-neutral pipeline. Everything outside that minimal set is honestly capability-gated to HTTP 501.Selectable via
ENGINE_TYPE=baileys. The whatsapp-web.js engine and the defaultENGINE_TYPEare untouched (backward compatible), and the work builds directly on the opaque per-engine-config foundation (#296): the factory passes only neutral fields + an opaquecontext.configblob each engine reads its own namespace from.In scope (the minimal working engine)
initialize/disconnect/logout/destroyuseMultiFileAuthState(per-session dir underBAILEYS_AUTH_DIR), QR viaconnection.update.qr,requestPairingCode, creds persisted on everycreds.updateqr→onQRCode/QR_READY,open→onReady+phone/pushName/READY,close→ terminal onloggedOut(no reconnect) vs. auto-reconnect on recoverable closes (Baileys emitsrestartRequiredright after pairing — reconnect is required for linking to complete), guarded against reconnecting after an intentional closesendTextMessage→sock.sendMessage(jid, { text })checkNumberExists/getNumberIdviasock.onWhatsApp(powers send-to-number + the dashboard MessageTester)sendChatState→sock.sendPresenceUpdate(so the default-on anti-ban typing path works)messages.upsert→onMessage(incoming) /onMessageCreate(fromMe),messages.update→onMessageAck, all mapped to the neutralIncomingMessage/DeliveryStatusby a newbaileys-message-mapper(the sole Baileys-scheme→neutral boundary)Out of scope → gated to HTTP 501
Media/location/contact/sticker sends, reply/forward/react/delete, contacts/groups/chats/history/seen, labels/catalog/channels/status — every one throws the new typed
EngineNotSupportedError(→ 501). No self-maintained store in this slice (that's the largest piece of net-new infra; it unlocks most of the above in later slices).getFeatures()advertises only['text-messages', 'typing-indicator'].@whiskeysockets/baileysis ESM-only ("type": "module"). OpenWA is CommonJS, so itrequire()s the lib at startup, and because the engine factory statically imports the Baileys plugin, the lib loads on every boot — even with the default whatsapp-web.js engine.require()-of-ESM needs Node ≥ 20.19 (and 22.12+); on older Node the app would fail to boot withERR_REQUIRE_ESM. This PR declaresengines.node >= 20.19.0and documents it (CI + Docker already run Node 22). Operators on EOL Node 18 must upgrade. → targets v0.3.0 per the SemVer policy.Notes
@whiskeysockets/baileys@6.7.23(stable 6.x), not npm'slatest(7.0.0-rc13, a pre-release). Core APIs are unchanged across 6→7; the adapter +baileys.types.tsboundary isolates a future bump.proxyUrlis logged-and-ignored and documented in.env.example.@s.whatsapp.net/@g.us/@lid/status@broadcast) and proto types stay strictly inside the adapter + mapper + types files — nothing leaks into the neutral pipeline, webhooks, or dashboard.Testing
baileys-message-mapper(neutral shaping,@lid/group/fromMe/status), the adapter (QR/open/close + reconnect-vs-terminal, gating, text send, recipient resolution, presence, inbound fan-out, pairing-code guard), the plugin (opaque-config read + fallback + minimal feature set), and a factory-registration test.test/baileys-engine.e2e-spec.ts): boots the fullAppModulewithENGINE_TYPE=baileysand asserts the engine is selected + the plugin enabled — without connecting a socket. (This is also the gate that catches DI module-load cycles.)require()of the ESM lib was verified directly on Node 22 (all symbols resolve); the jest stub for Baileys is a test-environment workaround only (ts-jest can't loadtype: module), not a masked runtime break.Next slices