@kyyinfinite/lumina 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -360,6 +360,88 @@ Type-checked features:
360
360
  - Enum-like catalogs (`MessageType`, `HeaderType`, `LayoutKind`, ...) are `Readonly`
361
361
  - `Bot.raw` escape hatch typed as `WASocket`
362
362
 
363
+
364
+ ---
365
+
366
+ ## Baileys Compatibility
367
+
368
+ Lumina is not tied to a specific Baileys version or fork. When `new Bot(sock)` is called, Lumina automatically detects the available Baileys package in your project.
369
+
370
+ ### Auto-Detect (default)
371
+
372
+ No configuration is required. Lumina tries the following packages in order and uses the first one that can be successfully imported:
373
+
374
+ ```
375
+ @kyyinfinite/baileys
376
+ @whiskeysockets/baileys
377
+ baileys
378
+ @adiwajshing/baileys
379
+ @brunocgc/baileys
380
+ @open-wa/baileys
381
+ ```
382
+
383
+ ```js
384
+ // Lumina automatically detects @kyyinfinite/baileys (or any installed fork)
385
+ const bot = new Bot(sock)
386
+ ```
387
+
388
+ ---
389
+
390
+ ### Explicit Package Name
391
+
392
+ If you're using a custom-named fork, specify it with `baileysPackage`:
393
+
394
+ ```js
395
+ const bot = new Bot(sock, {
396
+ baileysPackage: '@namafork/baileys',
397
+ })
398
+ ```
399
+
400
+ ---
401
+
402
+ ### Module Injection
403
+
404
+ The fastest option — zero dynamic imports. Simply inject the module directly:
405
+
406
+ ```js
407
+ import * as baileys from '@kyyinfinite/baileys'
408
+
409
+ const bot = new Bot(sock, {
410
+ baileys,
411
+ })
412
+ ```
413
+
414
+ This is ideal if you've already imported Baileys elsewhere and want to avoid duplicate imports.
415
+
416
+ ---
417
+
418
+ ### Socket Fallback
419
+
420
+ If no Baileys package is found, Lumina falls back to its internal socket-based implementation. Core features (text, buttons, carousel, stickers) continue to work. Media uploads require `sock.waUploadToServer` to be available.
421
+
422
+ ---
423
+
424
+ ### Debug: Check the Active Adapter
425
+
426
+ ```js
427
+ const bot = new Bot(sock)
428
+ console.log(await bot.connection.adapterSource())
429
+ // → '@kyyinfinite/baileys'
430
+ // → '@whiskeysockets/baileys'
431
+ // → 'injected-module'
432
+ // → 'socket-fallback'
433
+ ```
434
+
435
+ ---
436
+
437
+ ### Summary
438
+
439
+ | Option | When to use |
440
+ |---|---|
441
+ | _(not set)_ | Auto-detect. Recommended for most use cases. |
442
+ | `baileysPackage: 'name'` | For custom forks that are not included in the auto-detect list. |
443
+ | `baileys: module` | Manual module injection for the best performance. |
444
+
363
445
  ---
364
446
 
365
447
  ## API Reference
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kyyinfinite/lumina",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Lumina — Modern WhatsApp framework built on top of Baileys. Hide the protocol complexity, expose a fluent API.",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -0,0 +1,140 @@
1
+ import crypto from 'node:crypto'
2
+ import { ConnectionError } from '../errors.js'
3
+
4
+ const KNOWN_PACKAGES = [
5
+ '@kyyinfinite/baileys',
6
+ '@whiskeysockets/baileys',
7
+ 'baileys',
8
+ '@adiwajshing/baileys',
9
+ '@brunocgc/baileys',
10
+ '@open-wa/baileys',
11
+ ]
12
+
13
+ const REQUIRED_FNS = [
14
+ 'prepareWAMessageMedia',
15
+ 'generateWAMessageFromContent',
16
+ 'generatePollMessage',
17
+ 'generateReactionMessage',
18
+ ]
19
+
20
+ function extractFns(mod) {
21
+ const missing = REQUIRED_FNS.filter((fn) => typeof mod[fn] !== 'function')
22
+ if (missing.length > 0) return null
23
+ return {
24
+ prepareWAMessageMedia: mod.prepareWAMessageMedia,
25
+ generateWAMessageFromContent: mod.generateWAMessageFromContent,
26
+ generatePollMessage: mod.generatePollMessage,
27
+ generateReactionMessage: mod.generateReactionMessage,
28
+ }
29
+ }
30
+
31
+ function makeFallbackFns(socket) {
32
+ const generateId = () => crypto.randomBytes(8).toString('hex').toUpperCase()
33
+
34
+ const generateWAMessageFromContent = (jid, content, opts = {}) => ({
35
+ key: {
36
+ remoteJid: jid,
37
+ fromMe: true,
38
+ id: opts.messageId ?? generateId(),
39
+ participant: opts.participant,
40
+ },
41
+ message: content,
42
+ messageTimestamp: Math.floor(Date.now() / 1000),
43
+ status: 1,
44
+ })
45
+
46
+ const generatePollMessage = async (jid, opts) => {
47
+ const msg = await socket.sendMessage(jid, {
48
+ poll: {
49
+ name: opts.name,
50
+ values: opts.values,
51
+ selectableCount: opts.selectableCount ?? 1,
52
+ },
53
+ })
54
+ return msg
55
+ }
56
+
57
+ const generateReactionMessage = (jid, opts) =>
58
+ generateWAMessageFromContent(jid, {
59
+ reactionMessage: { key: opts.key, text: opts.text },
60
+ })
61
+
62
+ const prepareWAMessageMedia = async (media, opts = {}) => {
63
+ if (!socket.waUploadToServer) {
64
+ throw new ConnectionError(
65
+ 'Cannot upload media: no baileys package found and socket.waUploadToServer is unavailable',
66
+ { code: 'LUMINA_ADAPTER_NO_UPLOAD' },
67
+ )
68
+ }
69
+ const [type, source] = Object.entries(media)[0]
70
+ const uploaded = await socket.waUploadToServer(
71
+ Buffer.isBuffer(source) ? source : source,
72
+ { mediaType: type, jid: opts.jid },
73
+ )
74
+ return { [type]: { url: uploaded.url, ...uploaded } }
75
+ }
76
+
77
+ return { generateWAMessageFromContent, generatePollMessage, generateReactionMessage, prepareWAMessageMedia }
78
+ }
79
+
80
+ export class BaileysAdapter {
81
+ #fns = null
82
+ #source = 'unknown'
83
+
84
+ static async resolve(socket, opts = {}) {
85
+ const adapter = new BaileysAdapter()
86
+
87
+ if (opts.baileys && typeof opts.baileys === 'object') {
88
+ const fns = extractFns(opts.baileys)
89
+ if (fns) {
90
+ adapter.#fns = fns
91
+ adapter.#source = 'injected-module'
92
+ return adapter
93
+ }
94
+ }
95
+
96
+ if (typeof opts.baileysPackage === 'string') {
97
+ try {
98
+ const mod = await import(opts.baileysPackage)
99
+ const fns = extractFns(mod)
100
+ if (fns) {
101
+ adapter.#fns = fns
102
+ adapter.#source = opts.baileysPackage
103
+ return adapter
104
+ }
105
+ } catch {
106
+ throw new ConnectionError(
107
+ `baileysPackage "${opts.baileysPackage}" could not be imported or is missing required functions`,
108
+ { code: 'LUMINA_ADAPTER_PACKAGE_NOT_FOUND' },
109
+ )
110
+ }
111
+ }
112
+
113
+ for (const pkg of KNOWN_PACKAGES) {
114
+ try {
115
+ const mod = await import(pkg)
116
+ const fns = extractFns(mod)
117
+ if (fns) {
118
+ adapter.#fns = fns
119
+ adapter.#source = pkg
120
+ return adapter
121
+ }
122
+ } catch {}
123
+ }
124
+
125
+ adapter.#fns = makeFallbackFns(socket)
126
+ adapter.#source = 'socket-fallback'
127
+ return adapter
128
+ }
129
+
130
+ get source() {
131
+ return this.#source
132
+ }
133
+
134
+ get prepareWAMessageMedia() { return this.#fns.prepareWAMessageMedia }
135
+ get generateWAMessageFromContent() { return this.#fns.generateWAMessageFromContent }
136
+ get generatePollMessage() { return this.#fns.generatePollMessage }
137
+ get generateReactionMessage() { return this.#fns.generateReactionMessage }
138
+ }
139
+
140
+ export default BaileysAdapter
@@ -1,11 +1,12 @@
1
1
  import { ConnectionError } from '../errors.js'
2
+ import { BaileysAdapter } from './baileys-adapter.js'
2
3
 
3
4
  export class Connection {
5
+ #socket = null
6
+ #adapter = null
7
+
4
8
  constructor(socket, opts = {}) {
5
9
  if (!socket) throw new ConnectionError('socket is required', { code: 'LUMINA_CONNECTION_NO_SOCKET' })
6
- this.#socket = socket
7
- this.uploadJid = opts.uploadJid
8
- this.logger = opts.logger
9
10
 
10
11
  const required = ['relayMessage', 'ev']
11
12
  for (const m of required) {
@@ -15,34 +16,46 @@ export class Connection {
15
16
  })
16
17
  }
17
18
  }
19
+
20
+ this.#socket = socket
21
+ this.uploadJid = opts.uploadJid
22
+ this.logger = opts.logger
23
+ this.#adapter = BaileysAdapter.resolve(socket, opts)
18
24
  }
19
25
 
20
- #socket = null
26
+ async #fn() {
27
+ if (this.#adapter instanceof Promise) this.#adapter = await this.#adapter
28
+ return this.#adapter
29
+ }
21
30
 
22
31
  async uploadMedia(media, opts = {}) {
23
- const { prepareWAMessageMedia } = await import('@whiskeysockets/baileys')
32
+ const adapter = await this.#fn()
24
33
  const jid = opts.jid ?? this.uploadJid
25
34
  if (!jid) {
26
35
  throw new ConnectionError('uploadJid must be set (via constructor or per-call)', {
27
36
  code: 'LUMINA_CONNECTION_NO_UPLOAD_JID',
28
37
  })
29
38
  }
30
- return prepareWAMessageMedia(media, { upload: this.#socket.waUploadToServer, jid, ...opts })
39
+ return adapter.prepareWAMessageMedia(media, {
40
+ upload: this.#socket.waUploadToServer,
41
+ jid,
42
+ ...opts,
43
+ })
31
44
  }
32
45
 
33
46
  async generateMessage(jid, content, opts = {}) {
34
- const { generateWAMessageFromContent } = await import('@whiskeysockets/baileys')
35
- return generateWAMessageFromContent(jid, content, opts)
47
+ const adapter = await this.#fn()
48
+ return adapter.generateWAMessageFromContent(jid, content, opts)
36
49
  }
37
50
 
38
51
  async generatePoll(jid, opts) {
39
- const { generatePollMessage } = await import('@whiskeysockets/baileys')
40
- return generatePollMessage(jid, opts)
52
+ const adapter = await this.#fn()
53
+ return adapter.generatePollMessage(jid, opts)
41
54
  }
42
55
 
43
56
  async generateReaction(jid, opts) {
44
- const { generateReactionMessage } = await import('@whiskeysockets/baileys')
45
- return generateReactionMessage(jid, opts)
57
+ const adapter = await this.#fn()
58
+ return adapter.generateReactionMessage(jid, opts)
46
59
  }
47
60
 
48
61
  async relayMessage(jid, message, opts = {}) {
@@ -65,8 +78,11 @@ export class Connection {
65
78
  this.#socket.ev.off(event, handler)
66
79
  }
67
80
 
68
- get raw() {
69
- return this.#socket
81
+ get raw() { return this.#socket }
82
+
83
+ async adapterSource() {
84
+ const adapter = await this.#fn()
85
+ return adapter.source
70
86
  }
71
87
  }
72
88