@shoru/kitten 0.0.5 → 0.1.0

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.
@@ -1,144 +1,189 @@
1
- import {
2
- isJidGroup,
3
- areJidsSameUser,
4
- getDevice,
5
- downloadMediaMessage,
6
- getContentType,
7
- isLidUser,
8
- jidNormalizedUser
9
- } from 'baileys';
10
-
11
- import {
12
- getTimeString,
13
- isString,
14
- toNumber,
15
- toBase64,
16
- getPN
17
- } from '#utils.js';
18
-
19
- const extractMessage = (message) => {
20
- let type = getContentType(message);
21
- let data = message?.[type];
22
-
23
- // cases like viewonce or document messages etc
24
- if (data?.message) {
25
- const innerType = getContentType(data.message);
26
- if (innerType) {
27
- type = innerType;
28
- data = data.message[type];
29
- }
30
- }
31
- return [type, data];
32
- };
33
-
34
- const extractContent = (message = {}) => ({
35
- body: message.text ?? message.caption ??
36
- (isString(message) ? message : undefined),
37
- mentions: message.contextInfo?.mentionedJid,
38
- groupMentions: message.contextInfo?.groupMentions,
39
- mimetype: message.mimetype,
40
- fileName: message.fileName,
41
- pageCount: message.pageCount,
42
- fileLength: toNumber(message.fileLength),
43
- hash: toBase64(message.fileSha256),
44
- isViewOnce: message.viewOnce,
45
- url: message.matchedText,
46
- description: message.description,
47
- thumbnail: message.jpegThumbnail,
48
- });
49
-
50
- const load = async (x) => downloadMediaMessage(x, 'buffer', {});
51
-
52
- export const formatMessage = (sock, raw) => {
53
- const myId = jidNormalizedUser(sock.user.lid);
54
- const [type, messageData] = extractMessage(raw.message);
55
-
56
- const {
57
- pushName: name,
58
- messageTimestamp,
59
- participant: p1,
60
- broadcast,
61
- key,
62
- key: {
63
- remoteJid: roomId,
64
- id, fromMe,
65
- participant: p2,
66
- }
67
- } = raw;
68
-
69
- const jid = fromMe ? myId : p2 || p1 || roomId;
70
-
71
- const {
72
- quotedMessage,
73
- participant: quotedSender,
74
- stanzaId: quotedId,
75
- isForwarded,
76
- forwardingScore,
77
- } = messageData?.contextInfo || {};
78
- const [quotedType, quotedData] = extractMessage(quotedMessage);
79
-
80
- const quotedKey = {
81
- id: quotedId,
82
- participant: quotedSender,
83
- remoteJid: roomId,
84
- fromMe: areJidsSameUser(quotedSender, myId)
85
- };
86
-
87
- return {
88
- type,
89
- name,
90
- id,
91
- broadcast,
92
- isForwarded,
93
- forwardingScore,
94
- fromMe,
95
- jid,
96
- roomId,
97
- timestamp: toNumber(messageTimestamp),
98
- isLid: isLidUser(jid),
99
- device: getDevice(id),
100
- isGroup: isJidGroup(roomId),
101
- timeString: getTimeString(messageTimestamp),
102
- ...extractContent(messageData),
103
- key, raw,
104
- contextInfo: {
105
- stanzaId: id,
106
- participant: jid,
107
- remoteJid: roomId
108
- },
109
- load() {
110
- return load(this.raw)
111
- },
112
- senderIs(id) {
113
- return areJidsSameUser(this.jid, id)
114
- },
115
- pn() {
116
- return getPN(sock, this.jid)
117
- },
118
- quoted: quotedData ? {
119
- type: quotedType,
120
- jid: quotedSender,
121
- id: quotedId,
122
- ...extractContent(quotedData),
123
- key: quotedKey,
124
- contextInfo: {
125
- stanzaId: quotedId,
126
- participant: quotedSender,
127
- remoteJid: roomId
128
- },
129
- raw: {
130
- key: quotedKey,
131
- message: quotedMessage
132
- },
133
- load() {
134
- return load(this.raw)
135
- },
136
- senderIs(id) {
137
- return areJidsSameUser(this.jid, id)
138
- },
139
- pn() {
140
- return getPN(sock, this.jid)
141
- }
142
- }: undefined,
143
- }
144
- }
1
+ import {
2
+ isJidGroup,
3
+ areJidsSameUser,
4
+ getDevice,
5
+ downloadMediaMessage,
6
+ getContentType,
7
+ isLidUser,
8
+ jidNormalizedUser,
9
+ } from 'baileys';
10
+
11
+ import {
12
+ getTimeString,
13
+ isString,
14
+ toNumber,
15
+ toBase64,
16
+ getPN,
17
+ } from '#utils.js';
18
+
19
+ const extractMessage = (message) => {
20
+ if (!message) return [undefined, undefined];
21
+ let type = getContentType(message);
22
+ let data = message?.[type];
23
+
24
+ // cases like viewonce or document messages etc
25
+ if (data?.message) {
26
+ const innerType = getContentType(data.message);
27
+ if (innerType) {
28
+ type = innerType;
29
+ data = data.message[type];
30
+ }
31
+ }
32
+ return [type, data];
33
+ };
34
+
35
+ const extractContent = (message = {}) => ({
36
+ body:
37
+ message.text ??
38
+ message.caption ??
39
+ (isString(message) ? message : undefined),
40
+ mentions: message.contextInfo?.mentionedJid,
41
+ groupMentions: message.contextInfo?.groupMentions,
42
+ mimetype: message.mimetype,
43
+ fileName: message.fileName,
44
+ pageCount: message.pageCount,
45
+ fileLength: toNumber(message.fileLength),
46
+ hash: toBase64(message.fileSha256),
47
+ isViewOnce: message.viewOnce,
48
+ url: message.matchedText,
49
+ description: message.description,
50
+ thumbnail: message.jpegThumbnail,
51
+ });
52
+
53
+ const load = async (x) => downloadMediaMessage(x, 'buffer', {});
54
+
55
+ export const formatMessage = (sock, raw) => {
56
+ const userJid = sock.user?.lid || sock.user?.id || '';
57
+ const myId = userJid ? jidNormalizedUser(userJid) : '';
58
+ const [type, messageData] = extractMessage(raw.message);
59
+
60
+ const {
61
+ pushName: name,
62
+ messageTimestamp,
63
+ participant: p1,
64
+ broadcast,
65
+ key,
66
+ key: {
67
+ remoteJid: roomId,
68
+ id,
69
+ fromMe,
70
+ participant: p2,
71
+ } = {},
72
+ } = raw;
73
+
74
+ const jid = fromMe ? myId : p2 || p1 || roomId;
75
+
76
+ const {
77
+ quotedMessage,
78
+ participant: quotedSender,
79
+ stanzaId: quotedId,
80
+ isForwarded,
81
+ forwardingScore,
82
+ } = messageData?.contextInfo || {};
83
+ const [quotedType, quotedData] = quotedMessage ? extractMessage(quotedMessage) : [undefined, undefined];
84
+
85
+ const quotedKey = quotedData
86
+ ? {
87
+ id: quotedId,
88
+ participant: quotedSender,
89
+ remoteJid: roomId,
90
+ fromMe: areJidsSameUser(quotedSender, myId),
91
+ }
92
+ : undefined;
93
+
94
+ let cachedTimeString;
95
+ let cachedQuoted;
96
+
97
+ const msg = {
98
+ type,
99
+ name,
100
+ id,
101
+ broadcast,
102
+ isForwarded,
103
+ forwardingScore,
104
+ fromMe,
105
+ jid,
106
+ roomId,
107
+ timestamp: toNumber(messageTimestamp),
108
+ isLid: isLidUser(jid),
109
+ device: getDevice(id),
110
+ isGroup: isJidGroup(roomId),
111
+ ...extractContent(messageData),
112
+ key,
113
+ raw,
114
+ contextInfo: {
115
+ stanzaId: id,
116
+ participant: jid,
117
+ remoteJid: roomId,
118
+ },
119
+ load() {
120
+ return load(this.raw);
121
+ },
122
+ senderIs(targetId) {
123
+ return areJidsSameUser(this.jid, targetId);
124
+ },
125
+ pn() {
126
+ return getPN(sock, this.jid);
127
+ },
128
+ };
129
+
130
+ Object.defineProperty(msg, 'timeString', {
131
+ enumerable: true,
132
+ configurable: true,
133
+ get() {
134
+ if (cachedTimeString === undefined) {
135
+ cachedTimeString = getTimeString(messageTimestamp);
136
+ }
137
+ return cachedTimeString;
138
+ },
139
+ });
140
+
141
+ Object.defineProperty(msg, 'quoted', {
142
+ enumerable: true,
143
+ configurable: true,
144
+ get() {
145
+ if (!quotedData) return undefined;
146
+ if (cachedQuoted === undefined) {
147
+ let cachedQuotedTimeString;
148
+ cachedQuoted = {
149
+ type: quotedType,
150
+ jid: quotedSender,
151
+ id: quotedId,
152
+ ...extractContent(quotedData),
153
+ key: quotedKey,
154
+ contextInfo: {
155
+ stanzaId: quotedId,
156
+ participant: quotedSender,
157
+ remoteJid: roomId,
158
+ },
159
+ raw: {
160
+ key: quotedKey,
161
+ message: quotedMessage,
162
+ },
163
+ load() {
164
+ return load(this.raw);
165
+ },
166
+ senderIs(targetId) {
167
+ return areJidsSameUser(this.jid, targetId);
168
+ },
169
+ pn() {
170
+ return getPN(sock, this.jid);
171
+ },
172
+ };
173
+ Object.defineProperty(cachedQuoted, 'timeString', {
174
+ enumerable: true,
175
+ configurable: true,
176
+ get() {
177
+ if (cachedQuotedTimeString === undefined) {
178
+ cachedQuotedTimeString = getTimeString(messageTimestamp);
179
+ }
180
+ return cachedQuotedTimeString;
181
+ },
182
+ });
183
+ }
184
+ return cachedQuoted;
185
+ },
186
+ });
187
+
188
+ return msg;
189
+ };
package/src/index.js CHANGED
@@ -2,4 +2,5 @@ export * from "#internals.js";
2
2
  export * from "#utils.js";
3
3
  export * from "#auth.js";
4
4
  export * from "#client.js";
5
- export * from "#formatter.js"
5
+ export * from "#formatter.js";
6
+ export * from "baileys";
@@ -1,5 +1,13 @@
1
1
  import { cosmiconfig } from 'cosmiconfig';
2
- import { defu } from 'defu';
2
+ import { createDefu } from 'defu';
3
+ import path from 'path';
4
+
5
+ const mergeConfig = createDefu((obj, key, value) => {
6
+ if (Array.isArray(value)) {
7
+ obj[key] = value;
8
+ return true;
9
+ }
10
+ });
3
11
 
4
12
  const loadDefaultConfig = async () => {
5
13
  try {
@@ -19,7 +27,11 @@ const loadDefaultConfig = async () => {
19
27
  const loadUserConfig = async () => {
20
28
  try {
21
29
  const explorer = cosmiconfig('kittenwa');
22
- const result = await explorer.search();
30
+ const searchFrom = process.argv[1] ? path.dirname(path.resolve(process.argv[1])) : process.cwd();
31
+ let result = await explorer.search(searchFrom);
32
+ if (!result && searchFrom !== process.cwd()) {
33
+ result = await explorer.search(process.cwd());
34
+ }
23
35
  return result?.config ?? {};
24
36
  } catch (err) {
25
37
  throw new Error(`[USER_CONFIG] Error loading user config: ${err.message}`, { cause: err });
@@ -32,7 +44,7 @@ export const loadConfig = async () => {
32
44
  loadDefaultConfig()
33
45
  ]);
34
46
 
35
- return defu(userConfig, defaultConfig);
47
+ return mergeConfig(userConfig, defaultConfig);
36
48
  };
37
49
 
38
50
  let cachedConfig = null;
@@ -1,5 +1,4 @@
1
1
  export * from './config.js';
2
2
  export * from './logger.js';
3
3
  export * from './spinner.js';
4
- export * from './lmdb-manager.js';
5
- export * from './plugin-manager.js'
4
+ export * from './lmdb-manager.js';
@@ -1,54 +1,79 @@
1
- import { open } from 'lmdb';
2
- import { logger } from './logger.js';
3
- import { getConfig } from './config.js';
4
-
5
- const config = await getConfig();
6
-
7
- class LMDBDatabaseManager {
8
- #db = null;
9
- #config = config.db;
10
- #isClosing = false;
11
-
12
- constructor(config) {
13
- this.#config = { ...this.#config, ...config };
14
- }
15
-
16
- get db() {
17
- if (this.#isClosing) {
18
- throw new Error('[LMDBManager] Database is closing');
19
- }
20
-
21
- if (!this.#db) {
22
- this.#db = open(this.#config);
23
- }
24
-
25
- return this.#db;
26
- }
27
-
28
- get isOpen() {
29
- return this.#db !== null && !this.#isClosing;
30
- }
31
-
32
- get config() {
33
- return Object.freeze({ ...this.#config });
34
- }
35
-
36
- async close() {
37
- if (!this.#db || this.#isClosing) return;
38
-
39
- this.#isClosing = true;
40
-
41
- try {
42
- await this.#db.flushed;
43
- await this.#db.close();
44
- } catch (err) {
45
- logger.error(err, '[LMDBManager] Error closing database');
46
- throw err;
47
- } finally {
48
- this.#db = null;
49
- this.#isClosing = false;
50
- }
51
- }
52
- }
53
-
54
- export const LMDBManager = new LMDBDatabaseManager();
1
+ import { open } from 'lmdb';
2
+ import { logger } from './logger.js';
3
+ import { getConfig } from './config.js';
4
+
5
+ const config = await getConfig();
6
+
7
+ class LMDBDatabaseManager {
8
+ #db = null;
9
+ #config = config.db;
10
+ #isClosing = false;
11
+
12
+ constructor(config) {
13
+ this.#config = { ...this.#config, ...config };
14
+ }
15
+
16
+ get db() {
17
+ if (this.#isClosing) {
18
+ throw new Error('[LMDBManager] Database is closing');
19
+ }
20
+
21
+ if (!this.#db) {
22
+ this.#db = open(this.#config);
23
+ }
24
+
25
+ return this.#db;
26
+ }
27
+
28
+ get isOpen() {
29
+ return this.#db !== null && !this.#isClosing;
30
+ }
31
+
32
+ get config() {
33
+ return Object.freeze({ ...this.#config });
34
+ }
35
+
36
+ async sync() {
37
+ if (this.#db && !this.#isClosing) {
38
+ await this.#db.flushed;
39
+ }
40
+ }
41
+
42
+ async close() {
43
+ if (!this.#db || this.#isClosing) return;
44
+
45
+ this.#isClosing = true;
46
+
47
+ try {
48
+ await this.#db.flushed;
49
+ await this.#db.close();
50
+ } catch (err) {
51
+ logger.error(err, '[LMDBManager] Error closing database');
52
+ throw err;
53
+ } finally {
54
+ this.#db = null;
55
+ this.#isClosing = false;
56
+ }
57
+ }
58
+ }
59
+
60
+ export const LMDBManager = new LMDBDatabaseManager();
61
+
62
+ // Graceful shutdown hooks to guarantee asynchronous writes are flushed
63
+ const handleExit = async () => {
64
+ try {
65
+ await LMDBManager.close();
66
+ } catch {
67
+ /* noop */
68
+ }
69
+ };
70
+
71
+ process.once('beforeExit', handleExit);
72
+ process.once('SIGINT', async () => {
73
+ await handleExit();
74
+ process.exit(0);
75
+ });
76
+ process.once('SIGTERM', async () => {
77
+ await handleExit();
78
+ process.exit(0);
79
+ });
@@ -14,7 +14,7 @@ export const {
14
14
  }
15
15
  } = config.plugins;
16
16
 
17
- export const PLUGIN_DIR = path.join(process.cwd(), dir);
17
+ export const PLUGIN_DIR = path.resolve(process.cwd(), dir);
18
18
 
19
19
  export const EVENTS = Object.freeze(new Set([
20
20
  'messaging-history.set', 'chats.upsert', 'chats.update', 'chats.delete',