@roidev/kachina-md 2.1.0 → 2.1.2

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.
@@ -3,7 +3,27 @@ import { JSONFile } from 'lowdb/node';
3
3
  import fs from 'fs';
4
4
  import path from 'path';
5
5
 
6
+ /**
7
+ * @typedef {Object} DatabaseOptions
8
+ * @property {string} [path='./database'] - Path to database directory
9
+ */
10
+
11
+ /**
12
+ * Simple JSON-based database wrapper using LowDB
13
+ * Provides key-value storage organized by collections
14
+ * Each collection is stored as a separate JSON file
15
+ *
16
+ * @class Database
17
+ * @example
18
+ * const db = new Database({ path: './data' });
19
+ * await db.set('users', 'john', { name: 'John', age: 30 });
20
+ * const user = await db.get('users', 'john');
21
+ */
6
22
  export class Database {
23
+ /**
24
+ * Creates a new Database instance
25
+ * @param {DatabaseOptions} [options={}] - Database configuration
26
+ */
7
27
  constructor(options = {}) {
8
28
  this.path = options.path || './database';
9
29
  this.collections = new Map();
@@ -14,6 +34,17 @@ export class Database {
14
34
  }
15
35
  }
16
36
 
37
+ /**
38
+ * Get or create a collection (LowDB instance)
39
+ * @async
40
+ * @param {string} name - Collection name (becomes filename)
41
+ * @param {Object} [defaultData={}] - Default data if collection doesn't exist
42
+ * @returns {Promise<Low>} LowDB instance
43
+ * @example
44
+ * const usersDb = await db.collection('users');
45
+ * usersDb.data.john = { name: 'John' };
46
+ * await usersDb.write();
47
+ */
17
48
  async collection(name, defaultData = {}) {
18
49
  if (this.collections.has(name)) {
19
50
  return this.collections.get(name);
@@ -31,12 +62,34 @@ export class Database {
31
62
  return db;
32
63
  }
33
64
 
65
+ /**
66
+ * Get a value from collection
67
+ * @async
68
+ * @template T
69
+ * @param {string} collection - Collection name
70
+ * @param {string} key - Key to retrieve
71
+ * @param {T} [defaultValue=null] - Default value if key doesn't exist
72
+ * @returns {Promise<T>} Value or default value
73
+ * @example
74
+ * const user = await db.get('users', 'john', { name: 'Unknown' });
75
+ */
34
76
  async get(collection, key, defaultValue = null) {
35
77
  const db = await this.collection(collection, {});
36
78
  await db.read();
37
79
  return db.data[key] ?? defaultValue;
38
80
  }
39
81
 
82
+ /**
83
+ * Set a value in collection
84
+ * @async
85
+ * @template T
86
+ * @param {string} collection - Collection name
87
+ * @param {string} key - Key to set
88
+ * @param {T} value - Value to store
89
+ * @returns {Promise<T>} The value that was set
90
+ * @example
91
+ * await db.set('users', 'john', { name: 'John', age: 30 });
92
+ */
40
93
  async set(collection, key, value) {
41
94
  const db = await this.collection(collection, {});
42
95
  await db.read();
@@ -45,12 +98,32 @@ export class Database {
45
98
  return value;
46
99
  }
47
100
 
101
+ /**
102
+ * Check if key exists in collection
103
+ * @async
104
+ * @param {string} collection - Collection name
105
+ * @param {string} key - Key to check
106
+ * @returns {Promise<boolean>} True if key exists
107
+ * @example
108
+ * if (await db.has('users', 'john')) {
109
+ * console.log('User exists');
110
+ * }
111
+ */
48
112
  async has(collection, key) {
49
113
  const db = await this.collection(collection, {});
50
114
  await db.read();
51
115
  return key in db.data;
52
116
  }
53
117
 
118
+ /**
119
+ * Delete a key from collection
120
+ * @async
121
+ * @param {string} collection - Collection name
122
+ * @param {string} key - Key to delete
123
+ * @returns {Promise<boolean>} True if successful
124
+ * @example
125
+ * await db.delete('users', 'john');
126
+ */
54
127
  async delete(collection, key) {
55
128
  const db = await this.collection(collection, {});
56
129
  await db.read();
@@ -59,12 +132,29 @@ export class Database {
59
132
  return true;
60
133
  }
61
134
 
135
+ /**
136
+ * Get all data from collection
137
+ * @async
138
+ * @param {string} collection - Collection name
139
+ * @returns {Promise<Object>} All collection data
140
+ * @example
141
+ * const allUsers = await db.all('users');
142
+ * console.log(Object.keys(allUsers)); // ['john', 'jane', ...]
143
+ */
62
144
  async all(collection) {
63
145
  const db = await this.collection(collection, {});
64
146
  await db.read();
65
147
  return db.data;
66
148
  }
67
149
 
150
+ /**
151
+ * Clear all data from collection
152
+ * @async
153
+ * @param {string} collection - Collection name
154
+ * @returns {Promise<boolean>} True if successful
155
+ * @example
156
+ * await db.clear('users'); // Removes all users
157
+ */
68
158
  async clear(collection) {
69
159
  const db = await this.collection(collection, {});
70
160
  db.data = {};
@@ -72,6 +162,19 @@ export class Database {
72
162
  return true;
73
163
  }
74
164
 
165
+ /**
166
+ * Update a value in collection
167
+ * @async
168
+ * @param {string} collection - Collection name
169
+ * @param {string} key - Key to update
170
+ * @param {Function|Object} updater - Function that receives old value and returns new value, or object to merge
171
+ * @returns {Promise<*>} Updated value
172
+ * @example
173
+ * // Using function
174
+ * await db.update('users', 'john', (user) => ({ ...user, age: 31 }));
175
+ * // Using object merge
176
+ * await db.update('users', 'john', { age: 31 });
177
+ */
75
178
  async update(collection, key, updater) {
76
179
  const db = await this.collection(collection, {});
77
180
  await db.read();
@@ -86,6 +189,20 @@ export class Database {
86
189
  return db.data[key];
87
190
  }
88
191
 
192
+ /**
193
+ * Increment a numeric field in a stored object
194
+ * @async
195
+ * @param {string} collection - Collection name
196
+ * @param {string} key - Key of object to update
197
+ * @param {string} field - Field name to increment
198
+ * @param {number} [amount=1] - Amount to increment by
199
+ * @returns {Promise<Object>} Updated object
200
+ * @example
201
+ * // Increment user score by 10
202
+ * await db.increment('users', 'john', 'score', 10);
203
+ * // Increment by 1 (default)
204
+ * await db.increment('users', 'john', 'loginCount');
205
+ */
89
206
  async increment(collection, key, field, amount = 1) {
90
207
  return await this.update(collection, key, (data) => {
91
208
  data = data || {};
@@ -94,6 +211,18 @@ export class Database {
94
211
  });
95
212
  }
96
213
 
214
+ /**
215
+ * Push a value to an array
216
+ * @async
217
+ * @param {string} collection - Collection name
218
+ * @param {string} key - Key of array to update
219
+ * @param {*} value - Value to push
220
+ * @returns {Promise<Array>} Updated array
221
+ * @example
222
+ * await db.push('chats', 'john', 'Hello');
223
+ * await db.push('chats', 'john', 'How are you?');
224
+ * // chats.john = ['Hello', 'How are you?']
225
+ */
97
226
  async push(collection, key, value) {
98
227
  return await this.update(collection, key, (data) => {
99
228
  data = data || [];
@@ -104,6 +233,17 @@ export class Database {
104
233
  });
105
234
  }
106
235
 
236
+ /**
237
+ * Remove a value from an array
238
+ * @async
239
+ * @param {string} collection - Collection name
240
+ * @param {string} key - Key of array to update
241
+ * @param {*} value - Value to remove
242
+ * @returns {Promise<Array>} Updated array
243
+ * @example
244
+ * await db.pull('chats', 'john', 'Hello');
245
+ * // Removes 'Hello' from the array
246
+ */
107
247
  async pull(collection, key, value) {
108
248
  return await this.update(collection, key, (data) => {
109
249
  if (Array.isArray(data)) {
@@ -4,10 +4,27 @@ export { Logger } from './logger.js';
4
4
  export * from './sticker.js';
5
5
 
6
6
  // Utility functions
7
+
8
+ /**
9
+ * Sleep for specified milliseconds
10
+ * @param {number} ms - Milliseconds to sleep
11
+ * @returns {Promise<void>}
12
+ * @example
13
+ * await sleep(1000); // Sleep for 1 second
14
+ */
7
15
  export function sleep(ms) {
8
16
  return new Promise(resolve => setTimeout(resolve, ms));
9
17
  }
10
18
 
19
+ /**
20
+ * Format seconds into human-readable time string
21
+ * @param {number} seconds - Seconds to format
22
+ * @returns {string} Formatted time string (e.g., "1d 2h 30m" or "5m 30s")
23
+ * @example
24
+ * formatTime(90); // "1m 30s"
25
+ * formatTime(3661); // "1h 1m 1s"
26
+ * formatTime(90000); // "1d 1h 0m"
27
+ */
11
28
  export function formatTime(seconds) {
12
29
  const days = Math.floor(seconds / 86400);
13
30
  const hours = Math.floor((seconds % 86400) / 3600);
@@ -20,6 +37,15 @@ export function formatTime(seconds) {
20
37
  return `${secs}s`;
21
38
  }
22
39
 
40
+ /**
41
+ * Format bytes into human-readable size string
42
+ * @param {number} bytes - Bytes to format
43
+ * @returns {string} Formatted size string (e.g., "1.5 MB", "500 KB")
44
+ * @example
45
+ * formatBytes(1024); // "1 KB"
46
+ * formatBytes(1536000); // "1.46 MB"
47
+ * formatBytes(0); // "0 B"
48
+ */
23
49
  export function formatBytes(bytes) {
24
50
  if (bytes === 0) return '0 B';
25
51
  const k = 1024;
@@ -28,6 +54,16 @@ export function formatBytes(bytes) {
28
54
  return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
29
55
  }
30
56
 
57
+ /**
58
+ * Parse command from text message
59
+ * @param {string} text - Text to parse
60
+ * @param {string} [prefix='!'] - Command prefix
61
+ * @returns {{command: string, args: Array<string>, text: string}|null} Parsed command object or null if no command
62
+ * @example
63
+ * parseCommand('!help me', '!');
64
+ * // { command: 'help', args: ['me'], text: 'me' }
65
+ * parseCommand('hello'); // null
66
+ */
31
67
  export function parseCommand(text, prefix = '!') {
32
68
  if (!text.startsWith(prefix)) return null;
33
69
 
@@ -39,15 +75,39 @@ export function parseCommand(text, prefix = '!') {
39
75
  };
40
76
  }
41
77
 
78
+ /**
79
+ * Check if text is a URL
80
+ * @param {string} text - Text to check
81
+ * @returns {boolean} True if text is a URL
82
+ * @example
83
+ * isUrl('https://example.com'); // true
84
+ * isUrl('hello world'); // false
85
+ */
42
86
  export function isUrl(text) {
43
87
  return /^https?:\/\//i.test(text);
44
88
  }
45
89
 
90
+ /**
91
+ * Extract all URLs from text
92
+ * @param {string} text - Text to extract URLs from
93
+ * @returns {Array<string>} Array of URLs found
94
+ * @example
95
+ * extractUrls('Visit https://example.com and http://test.com');
96
+ * // ['https://example.com', 'http://test.com']
97
+ */
46
98
  export function extractUrls(text) {
47
99
  const urlRegex = /https?:\/\/[^\s]+/gi;
48
100
  return text.match(urlRegex) || [];
49
101
  }
50
102
 
103
+ /**
104
+ * Generate random alphanumeric string
105
+ * @param {number} [length=10] - Length of string
106
+ * @returns {string} Random string
107
+ * @example
108
+ * randomString(5); // "aB3xZ"
109
+ * randomString(); // "a1B2c3D4e5" (10 chars)
110
+ */
51
111
  export function randomString(length = 10) {
52
112
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
53
113
  let result = '';
@@ -57,14 +117,39 @@ export function randomString(length = 10) {
57
117
  return result;
58
118
  }
59
119
 
120
+ /**
121
+ * Generate random number in range
122
+ * @param {number} min - Minimum value (inclusive)
123
+ * @param {number} max - Maximum value (inclusive)
124
+ * @returns {number} Random number
125
+ * @example
126
+ * randomNumber(1, 10); // Random number between 1 and 10
127
+ */
60
128
  export function randomNumber(min, max) {
61
129
  return Math.floor(Math.random() * (max - min + 1)) + min;
62
130
  }
63
131
 
132
+ /**
133
+ * Pick random element from array
134
+ * @template T
135
+ * @param {Array<T>} array - Array to pick from
136
+ * @returns {T} Random element
137
+ * @example
138
+ * pickRandom(['red', 'blue', 'green']); // One of the colors
139
+ */
64
140
  export function pickRandom(array) {
65
141
  return array[Math.floor(Math.random() * array.length)];
66
142
  }
67
143
 
144
+ /**
145
+ * Split array into chunks of specified size
146
+ * @template T
147
+ * @param {Array<T>} array - Array to chunk
148
+ * @param {number} size - Chunk size
149
+ * @returns {Array<Array<T>>} Array of chunks
150
+ * @example
151
+ * chunk([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]]
152
+ */
68
153
  export function chunk(array, size) {
69
154
  const chunks = [];
70
155
  for (let i = 0; i < array.length; i += size) {
@@ -1,6 +1,25 @@
1
1
  import chalk from 'chalk';
2
2
 
3
+ /**
4
+ * @typedef {Object} LoggerOptions
5
+ * @property {'debug'|'info'|'success'|'warn'|'error'} [level='info'] - Minimum log level to display
6
+ * @property {string} [prefix=''] - Prefix for all log messages
7
+ */
8
+
9
+ /**
10
+ * Colored console logger with different log levels
11
+ * @class Logger
12
+ * @example
13
+ * const logger = new Logger({ prefix: 'MyBot', level: 'debug' });
14
+ * logger.info('Bot started');
15
+ * logger.success('Connected successfully');
16
+ * logger.error('Connection failed');
17
+ */
3
18
  export class Logger {
19
+ /**
20
+ * Creates a new Logger instance
21
+ * @param {LoggerOptions} [options={}] - Logger configuration
22
+ */
4
23
  constructor(options = {}) {
5
24
  this.level = options.level || 'info';
6
25
  this.prefix = options.prefix || '';
@@ -13,46 +32,96 @@ export class Logger {
13
32
  };
14
33
  }
15
34
 
35
+ /**
36
+ * Check if message should be logged based on log level
37
+ * @private
38
+ * @param {string} level - Log level to check
39
+ * @returns {boolean} True if should log
40
+ */
16
41
  shouldLog(level) {
17
42
  return this.levels[level] >= this.levels[this.level];
18
43
  }
19
44
 
45
+ /**
46
+ * Format log message with timestamp and prefix
47
+ * @private
48
+ * @param {string} level - Log level
49
+ * @param {...*} args - Arguments to format
50
+ * @returns {string} Formatted message
51
+ */
20
52
  format(level, ...args) {
21
53
  const timestamp = new Date().toLocaleTimeString();
22
54
  const prefix = this.prefix ? `[${this.prefix}] ` : '';
23
55
  return `${chalk.gray(timestamp)} ${prefix}${args.join(' ')}`;
24
56
  }
25
57
 
58
+ /**
59
+ * Log debug message (gray)
60
+ * @param {...*} args - Values to log
61
+ * @example
62
+ * logger.debug('Debugging info', { data: 'value' });
63
+ */
26
64
  debug(...args) {
27
65
  if (this.shouldLog('debug')) {
28
66
  console.log(chalk.gray('[DEBUG]'), this.format('debug', ...args));
29
67
  }
30
68
  }
31
69
 
70
+ /**
71
+ * Log info message (blue)
72
+ * @param {...*} args - Values to log
73
+ * @example
74
+ * logger.info('Bot started successfully');
75
+ */
32
76
  info(...args) {
33
77
  if (this.shouldLog('info')) {
34
78
  console.log(chalk.blue('[INFO]'), this.format('info', ...args));
35
79
  }
36
80
  }
37
81
 
82
+ /**
83
+ * Log success message (green)
84
+ * @param {...*} args - Values to log
85
+ * @example
86
+ * logger.success('Connected to WhatsApp');
87
+ */
38
88
  success(...args) {
39
89
  if (this.shouldLog('success')) {
40
90
  console.log(chalk.green('[SUCCESS]'), this.format('success', ...args));
41
91
  }
42
92
  }
43
93
 
94
+ /**
95
+ * Log warning message (yellow)
96
+ * @param {...*} args - Values to log
97
+ * @example
98
+ * logger.warn('Rate limit approaching');
99
+ */
44
100
  warn(...args) {
45
101
  if (this.shouldLog('warn')) {
46
102
  console.log(chalk.yellow('[WARN]'), this.format('warn', ...args));
47
103
  }
48
104
  }
49
105
 
106
+ /**
107
+ * Log error message (red)
108
+ * @param {...*} args - Values to log
109
+ * @example
110
+ * logger.error('Connection failed:', error);
111
+ */
50
112
  error(...args) {
51
113
  if (this.shouldLog('error')) {
52
114
  console.error(chalk.red('[ERROR]'), this.format('error', ...args));
53
115
  }
54
116
  }
55
117
 
118
+ /**
119
+ * Log command execution (cyan)
120
+ * @param {string} command - Command name
121
+ * @param {string} from - Sender information
122
+ * @example
123
+ * logger.command('!ping', 'User@s.whatsapp.net');
124
+ */
56
125
  command(command, from) {
57
126
  console.log(
58
127
  chalk.cyan('[CMD]'),
@@ -1,6 +1,43 @@
1
1
  import { downloadMediaMessage, getContentType } from 'baileys';
2
2
  import { fileTypeFromBuffer } from 'file-type';
3
3
 
4
+ /**
5
+ * @typedef {Object} SerializedMessage
6
+ * @property {Object} key - Message key
7
+ * @property {string} chat - Chat JID (remoteJid)
8
+ * @property {boolean} fromMe - Whether message is from bot
9
+ * @property {string} id - Message ID
10
+ * @property {boolean} isGroup - Whether chat is a group
11
+ * @property {string} sender - Sender JID
12
+ * @property {string} pushName - Sender push name
13
+ * @property {string} type - Message type (e.g., 'conversation', 'imageMessage')
14
+ * @property {Object} message - Raw message object
15
+ * @property {string} body - Message text content
16
+ * @property {SerializedMessage} [quoted] - Quoted/replied message
17
+ * @property {string} caption - Media caption
18
+ * @property {string} mimetype - Media mime type
19
+ * @property {number} fileSize - Media file size
20
+ * @property {Array<string>} mentions - Mentioned JIDs
21
+ * @property {Function} reply - Reply to message
22
+ * @property {Function} react - React to message with emoji
23
+ * @property {Function} download - Download media from message
24
+ * @property {Function} delete - Delete message
25
+ * @property {Function} forward - Forward message
26
+ * @property {Function} copyNForward - Copy and forward message
27
+ */
28
+
29
+ /**
30
+ * Serialize raw Baileys message into standardized format with helper methods
31
+ * @async
32
+ * @param {Object} msg - Raw Baileys message object
33
+ * @param {Object} sock - WhatsApp socket instance
34
+ * @returns {Promise<SerializedMessage>} Serialized message object
35
+ * @example
36
+ * const m = await serialize(rawMessage, sock);
37
+ * console.log(m.body); // Message text
38
+ * await m.reply('Hello!'); // Reply to message
39
+ * await m.react('👍'); // React with emoji
40
+ */
4
41
  export async function serialize(msg, sock) {
5
42
  if (!msg) return msg;
6
43
 
@@ -86,6 +123,12 @@ export async function serialize(msg, sock) {
86
123
  return m;
87
124
  }
88
125
 
126
+ /**
127
+ * Extract text body from various message types
128
+ * @private
129
+ * @param {Object} message - Message object
130
+ * @returns {string} Extracted text content
131
+ */
89
132
  function getBody(message) {
90
133
  if (!message) return '';
91
134
 
@@ -1,10 +1,28 @@
1
1
  import { Sticker, StickerTypes } from 'wa-sticker-formatter';
2
2
 
3
+ /**
4
+ * @typedef {Object} StickerOptions
5
+ * @property {string} [pack='Sticker'] - Sticker pack name
6
+ * @property {string} [author='Kachina Bot'] - Sticker author name
7
+ * @property {string} [type] - Sticker type (DEFAULT, FULL, CROPPED, CIRCLE, ROUNDED)
8
+ * @property {Array<string>} [categories=[]] - Sticker categories
9
+ * @property {string} [id=''] - Sticker ID
10
+ * @property {number} [quality=50] - Image quality (1-100)
11
+ * @property {string} [background='transparent'] - Background color
12
+ */
13
+
3
14
  /**
4
15
  * Create sticker from image/video buffer
5
- * @param {Buffer} buffer - Image or video buffer
6
- * @param {Object} options - Sticker options
7
- * @returns {Promise<Buffer>} Sticker buffer
16
+ * @async
17
+ * @param {Buffer|string} buffer - Image or video buffer, or file path/URL
18
+ * @param {StickerOptions} [options={}] - Sticker configuration options
19
+ * @returns {Promise<Buffer>} Sticker buffer ready to send
20
+ * @example
21
+ * const stickerBuffer = await createSticker(imageBuffer, {
22
+ * pack: 'My Stickers',
23
+ * author: 'My Bot',
24
+ * type: StickerTypes.FULL
25
+ * });
8
26
  */
9
27
  export async function createSticker(buffer, options = {}) {
10
28
  const sticker = new Sticker(buffer, {
@@ -21,7 +39,16 @@ export async function createSticker(buffer, options = {}) {
21
39
  }
22
40
 
23
41
  /**
24
- * Create full sticker (no crop)
42
+ * Create full sticker without cropping (preserves original aspect ratio)
43
+ * @async
44
+ * @param {Buffer|string} buffer - Image or video buffer, or file path/URL
45
+ * @param {StickerOptions} [options={}] - Sticker configuration options
46
+ * @returns {Promise<Buffer>} Full sticker buffer
47
+ * @example
48
+ * const sticker = await createFullSticker(imageBuffer, {
49
+ * pack: 'My Pack',
50
+ * author: 'Bot'
51
+ * });
25
52
  */
26
53
  export async function createFullSticker(buffer, options = {}) {
27
54
  return await createSticker(buffer, {
@@ -31,7 +58,13 @@ export async function createFullSticker(buffer, options = {}) {
31
58
  }
32
59
 
33
60
  /**
34
- * Create cropped sticker
61
+ * Create cropped sticker (1:1 aspect ratio, center-cropped)
62
+ * @async
63
+ * @param {Buffer|string} buffer - Image or video buffer, or file path/URL
64
+ * @param {StickerOptions} [options={}] - Sticker configuration options
65
+ * @returns {Promise<Buffer>} Cropped sticker buffer
66
+ * @example
67
+ * const sticker = await createCroppedSticker(imageBuffer);
35
68
  */
36
69
  export async function createCroppedSticker(buffer, options = {}) {
37
70
  return await createSticker(buffer, {
@@ -41,7 +74,13 @@ export async function createCroppedSticker(buffer, options = {}) {
41
74
  }
42
75
 
43
76
  /**
44
- * Create circle sticker
77
+ * Create circle-shaped sticker
78
+ * @async
79
+ * @param {Buffer|string} buffer - Image or video buffer, or file path/URL
80
+ * @param {StickerOptions} [options={}] - Sticker configuration options
81
+ * @returns {Promise<Buffer>} Circle sticker buffer
82
+ * @example
83
+ * const sticker = await createCircleSticker(profilePicBuffer);
45
84
  */
46
85
  export async function createCircleSticker(buffer, options = {}) {
47
86
  return await createSticker(buffer, {
@@ -51,7 +90,13 @@ export async function createCircleSticker(buffer, options = {}) {
51
90
  }
52
91
 
53
92
  /**
54
- * Create rounded sticker
93
+ * Create sticker with rounded corners
94
+ * @async
95
+ * @param {Buffer|string} buffer - Image or video buffer, or file path/URL
96
+ * @param {StickerOptions} [options={}] - Sticker configuration options
97
+ * @returns {Promise<Buffer>} Rounded sticker buffer
98
+ * @example
99
+ * const sticker = await createRoundedSticker(imageBuffer);
55
100
  */
56
101
  export async function createRoundedSticker(buffer, options = {}) {
57
102
  return await createSticker(buffer, {