@realvare/based 2.5.2 → 2.5.5
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 +1194 -829
- package/lib/Socket/messages-send.js +1406 -901
- package/lib/Socket/socket.js +41 -0
- package/lib/Utils/cache-manager.js +73 -0
- package/lib/Utils/messages.js +55 -39
- package/lib/Utils/performance-config.d.ts +60 -60
- package/lib/Utils/performance-config.js +153 -150
- package/lib/Utils/retry.js +66 -66
- package/lib/WABinary/decode.js +24 -10
- package/lib/WABinary/encode.js +15 -1
- package/lib/WABinary/jid-utils.js +217 -140
- package/lib/index.js +3 -4
- package/package.json +111 -111
- package/lib/WABinary/jid-utils.js.bak +0 -83
|
@@ -1,150 +1,153 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PerformanceConfig = exports.setPerformanceConfig = exports.getPerformanceConfig = void 0;
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Configurazione performance per ottimizzazioni LID/JID
|
|
7
|
-
*/
|
|
8
|
-
class PerformanceConfig {
|
|
9
|
-
constructor() {
|
|
10
|
-
// Cache settings
|
|
11
|
-
this.cache = {
|
|
12
|
-
lidCache: {
|
|
13
|
-
ttl: 5 * 60 * 1000, // 5 minuti
|
|
14
|
-
maxSize: 10000,
|
|
15
|
-
cleanupInterval: 2 * 60 * 1000 // 2 minuti
|
|
16
|
-
},
|
|
17
|
-
jidCache: {
|
|
18
|
-
ttl: 5 * 60 * 1000, // 5 minuti
|
|
19
|
-
maxSize: 10000,
|
|
20
|
-
cleanupInterval: 2 * 60 * 1000 // 2 minuti
|
|
21
|
-
},
|
|
22
|
-
lidToJidCache: {
|
|
23
|
-
ttl: 5 * 60 * 1000, // 5 minuti
|
|
24
|
-
maxSize: 5000,
|
|
25
|
-
cleanupInterval: 3 * 60 * 1000 // 3 minuti
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
// Performance settings
|
|
30
|
-
this.performance = {
|
|
31
|
-
enableCache: true,
|
|
32
|
-
enableLogging: false,
|
|
33
|
-
enableMetrics: false,
|
|
34
|
-
batchSize: 100,
|
|
35
|
-
maxRetries:
|
|
36
|
-
retryDelay: 1000
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
if (config.
|
|
108
|
-
globalConfig.
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PerformanceConfig = exports.setPerformanceConfig = exports.getPerformanceConfig = void 0;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Configurazione performance per ottimizzazioni LID/JID
|
|
7
|
+
*/
|
|
8
|
+
class PerformanceConfig {
|
|
9
|
+
constructor() {
|
|
10
|
+
// Cache settings
|
|
11
|
+
this.cache = {
|
|
12
|
+
lidCache: {
|
|
13
|
+
ttl: 5 * 60 * 1000, // 5 minuti
|
|
14
|
+
maxSize: 10000,
|
|
15
|
+
cleanupInterval: 2 * 60 * 1000 // 2 minuti
|
|
16
|
+
},
|
|
17
|
+
jidCache: {
|
|
18
|
+
ttl: 5 * 60 * 1000, // 5 minuti
|
|
19
|
+
maxSize: 10000,
|
|
20
|
+
cleanupInterval: 2 * 60 * 1000 // 2 minuti
|
|
21
|
+
},
|
|
22
|
+
lidToJidCache: {
|
|
23
|
+
ttl: 5 * 60 * 1000, // 5 minuti
|
|
24
|
+
maxSize: 5000,
|
|
25
|
+
cleanupInterval: 3 * 60 * 1000 // 3 minuti
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Performance settings
|
|
30
|
+
this.performance = {
|
|
31
|
+
enableCache: true,
|
|
32
|
+
enableLogging: false,
|
|
33
|
+
enableMetrics: false,
|
|
34
|
+
batchSize: 100,
|
|
35
|
+
maxRetries: 5,
|
|
36
|
+
retryDelay: 1000,
|
|
37
|
+
retryBackoffMultiplier: 1.5,
|
|
38
|
+
maxRetryDelay: 30000,
|
|
39
|
+
memoryThreshold: 0.85 // 85% memory usage threshold
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Debug settings
|
|
43
|
+
this.debug = {
|
|
44
|
+
enableLidLogging: process.env.DEBUG_LID === 'true',
|
|
45
|
+
enablePerformanceLogging: process.env.DEBUG_PERFORMANCE === 'true',
|
|
46
|
+
enableErrorLogging: true,
|
|
47
|
+
logLevel: process.env.LOG_LEVEL || 'error'
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Aggiorna configurazione cache
|
|
53
|
+
*/
|
|
54
|
+
updateCacheConfig(cacheType, config) {
|
|
55
|
+
if (this.cache[cacheType]) {
|
|
56
|
+
this.cache[cacheType] = { ...this.cache[cacheType], ...config };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Aggiorna configurazione performance
|
|
62
|
+
*/
|
|
63
|
+
updatePerformanceConfig(config) {
|
|
64
|
+
this.performance = { ...this.performance, ...config };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Aggiorna configurazione debug
|
|
69
|
+
*/
|
|
70
|
+
updateDebugConfig(config) {
|
|
71
|
+
this.debug = { ...this.debug, ...config };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Verifica se il logging è abilitato per un livello specifico
|
|
76
|
+
*/
|
|
77
|
+
shouldLog(level) {
|
|
78
|
+
const levels = ['error', 'warn', 'info', 'debug'];
|
|
79
|
+
const currentLevelIndex = levels.indexOf(this.debug.logLevel);
|
|
80
|
+
const requestedLevelIndex = levels.indexOf(level);
|
|
81
|
+
return requestedLevelIndex <= currentLevelIndex;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Istanza globale della configurazione
|
|
86
|
+
let globalConfig = new PerformanceConfig();
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Ottieni la configurazione performance globale
|
|
90
|
+
*/
|
|
91
|
+
const getPerformanceConfig = () => globalConfig;
|
|
92
|
+
exports.getPerformanceConfig = getPerformanceConfig;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Imposta una nuova configurazione performance
|
|
96
|
+
*/
|
|
97
|
+
const setPerformanceConfig = (config) => {
|
|
98
|
+
if (config instanceof PerformanceConfig) {
|
|
99
|
+
globalConfig = config;
|
|
100
|
+
} else {
|
|
101
|
+
// Merge con configurazione esistente
|
|
102
|
+
if (config.cache) {
|
|
103
|
+
Object.keys(config.cache).forEach(key => {
|
|
104
|
+
globalConfig.updateCacheConfig(key, config.cache[key]);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if (config.performance) {
|
|
108
|
+
globalConfig.updatePerformanceConfig(config.performance);
|
|
109
|
+
}
|
|
110
|
+
if (config.debug) {
|
|
111
|
+
globalConfig.updateDebugConfig(config.debug);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
exports.setPerformanceConfig = setPerformanceConfig;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Utility per logging condizionale
|
|
119
|
+
*/
|
|
120
|
+
class Logger {
|
|
121
|
+
static error(message, ...args) {
|
|
122
|
+
if (globalConfig.shouldLog('error')) {
|
|
123
|
+
console.error(`[LID/JID Error] ${message}`, ...args);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static warn(message, ...args) {
|
|
128
|
+
if (globalConfig.shouldLog('warn')) {
|
|
129
|
+
console.warn(`[LID/JID Warning] ${message}`, ...args);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
static info(message, ...args) {
|
|
134
|
+
if (globalConfig.shouldLog('info')) {
|
|
135
|
+
console.info(`[LID/JID Info] ${message}`, ...args);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
static debug(message, ...args) {
|
|
140
|
+
if (globalConfig.shouldLog('debug')) {
|
|
141
|
+
console.debug(`[LID/JID Debug] ${message}`, ...args);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
static performance(message, ...args) {
|
|
146
|
+
if (globalConfig.debug.enablePerformanceLogging) {
|
|
147
|
+
console.log(`[LID/JID Performance] ${message}`, ...args);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
exports.Logger = Logger;
|
|
153
|
+
exports.PerformanceConfig = PerformanceConfig;
|
package/lib/Utils/retry.js
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.retryWithBackoff = void 0;
|
|
4
|
-
|
|
5
|
-
async function sleep(ms, signal) {
|
|
6
|
-
return new Promise((resolve, reject) => {
|
|
7
|
-
const t = setTimeout(resolve, ms);
|
|
8
|
-
if (signal) {
|
|
9
|
-
const onAbort = () => {
|
|
10
|
-
clearTimeout(t);
|
|
11
|
-
reject(Object.assign(new Error('aborted'), { code: 'ABORT_ERR' }));
|
|
12
|
-
};
|
|
13
|
-
if (signal.aborted) {
|
|
14
|
-
onAbort();
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
signal.addEventListener('abort', onAbort, { once: true });
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function computeDelay(attempt, baseMs, maxMs, jitter) {
|
|
23
|
-
const exp = Math.min(maxMs, baseMs * Math.pow(2, attempt));
|
|
24
|
-
if (!jitter) return exp;
|
|
25
|
-
// full jitter strategy: random between 0 and exp
|
|
26
|
-
const rand = Math.random() * exp;
|
|
27
|
-
return Math.min(maxMs, rand);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async function retryWithBackoff(fn, opts = {}) {
|
|
31
|
-
const {
|
|
32
|
-
retries = 3,
|
|
33
|
-
baseMs = 300,
|
|
34
|
-
maxMs = 5000,
|
|
35
|
-
jitter = true,
|
|
36
|
-
timeoutPerAttemptMs,
|
|
37
|
-
signal,
|
|
38
|
-
onRetry,
|
|
39
|
-
shouldRetry
|
|
40
|
-
} = opts;
|
|
41
|
-
let lastErr;
|
|
42
|
-
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
43
|
-
try {
|
|
44
|
-
if (timeoutPerAttemptMs && timeoutPerAttemptMs > 0) {
|
|
45
|
-
const ctrl = new AbortController();
|
|
46
|
-
const timer = setTimeout(() => ctrl.abort(), timeoutPerAttemptMs);
|
|
47
|
-
try {
|
|
48
|
-
return await fn({ signal: ctrl.signal });
|
|
49
|
-
} finally {
|
|
50
|
-
clearTimeout(timer);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return await fn({ signal });
|
|
54
|
-
} catch (err) {
|
|
55
|
-
lastErr = err;
|
|
56
|
-
if (attempt === retries) break;
|
|
57
|
-
if (shouldRetry && !shouldRetry(err)) break;
|
|
58
|
-
if (onRetry) {
|
|
59
|
-
try { onRetry(err, attempt + 1); } catch {}
|
|
60
|
-
}
|
|
61
|
-
await sleep(computeDelay(attempt, baseMs, maxMs, jitter), signal);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
throw lastErr;
|
|
65
|
-
}
|
|
66
|
-
exports.retryWithBackoff = retryWithBackoff;
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.retryWithBackoff = void 0;
|
|
4
|
+
|
|
5
|
+
async function sleep(ms, signal) {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
const t = setTimeout(resolve, ms);
|
|
8
|
+
if (signal) {
|
|
9
|
+
const onAbort = () => {
|
|
10
|
+
clearTimeout(t);
|
|
11
|
+
reject(Object.assign(new Error('aborted'), { code: 'ABORT_ERR' }));
|
|
12
|
+
};
|
|
13
|
+
if (signal.aborted) {
|
|
14
|
+
onAbort();
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function computeDelay(attempt, baseMs, maxMs, jitter) {
|
|
23
|
+
const exp = Math.min(maxMs, baseMs * Math.pow(2, attempt));
|
|
24
|
+
if (!jitter) return exp;
|
|
25
|
+
// full jitter strategy: random between 0 and exp
|
|
26
|
+
const rand = Math.random() * exp;
|
|
27
|
+
return Math.min(maxMs, rand);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function retryWithBackoff(fn, opts = {}) {
|
|
31
|
+
const {
|
|
32
|
+
retries = 3,
|
|
33
|
+
baseMs = 300,
|
|
34
|
+
maxMs = 5000,
|
|
35
|
+
jitter = true,
|
|
36
|
+
timeoutPerAttemptMs,
|
|
37
|
+
signal,
|
|
38
|
+
onRetry,
|
|
39
|
+
shouldRetry
|
|
40
|
+
} = opts;
|
|
41
|
+
let lastErr;
|
|
42
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
43
|
+
try {
|
|
44
|
+
if (timeoutPerAttemptMs && timeoutPerAttemptMs > 0) {
|
|
45
|
+
const ctrl = new AbortController();
|
|
46
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutPerAttemptMs);
|
|
47
|
+
try {
|
|
48
|
+
return await fn({ signal: ctrl.signal });
|
|
49
|
+
} finally {
|
|
50
|
+
clearTimeout(timer);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return await fn({ signal });
|
|
54
|
+
} catch (err) {
|
|
55
|
+
lastErr = err;
|
|
56
|
+
if (attempt === retries) break;
|
|
57
|
+
if (shouldRetry && !shouldRetry(err)) break;
|
|
58
|
+
if (onRetry) {
|
|
59
|
+
try { onRetry(err, attempt + 1); } catch {}
|
|
60
|
+
}
|
|
61
|
+
await sleep(computeDelay(attempt, baseMs, maxMs, jitter), signal);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
throw lastErr;
|
|
65
|
+
}
|
|
66
|
+
exports.retryWithBackoff = retryWithBackoff;
|
package/lib/WABinary/decode.js
CHANGED
|
@@ -148,19 +148,33 @@ const decodeDecompressedBinaryNode = (buffer, opts, indexRef = { index: 0 }) =>
|
|
|
148
148
|
}
|
|
149
149
|
};
|
|
150
150
|
const readJidPair = () => {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
151
|
+
try {
|
|
152
|
+
const i = readString(readByte());
|
|
153
|
+
const j = readString(readByte());
|
|
154
|
+
if (typeof j === 'string' && j.length > 0) {
|
|
155
|
+
return (i || '') + '@' + j;
|
|
156
|
+
}
|
|
157
|
+
throw new Error(`invalid jid pair: ${i || '<empty>'}, ${j || '<empty>'}`);
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
throw new Error(`Failed to parse JID pair: ${err && err.message ? err.message : err}`);
|
|
155
161
|
}
|
|
156
|
-
throw new Error('invalid jid pair: ' + i + ', ' + j);
|
|
157
162
|
};
|
|
158
163
|
const readAdJid = () => {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
+
try {
|
|
165
|
+
const rawDomainType = readByte();
|
|
166
|
+
const domainType = Number(rawDomainType);
|
|
167
|
+
if (Number.isNaN(domainType))
|
|
168
|
+
throw new Error('invalid domain type');
|
|
169
|
+
const device = readByte();
|
|
170
|
+
const user = readString(readByte());
|
|
171
|
+
if (typeof user !== 'string')
|
|
172
|
+
throw new Error('invalid user in AD JID');
|
|
173
|
+
return (0, jid_utils_1.jidEncode)(user, domainType === 0 || domainType === 128 ? 's.whatsapp.net' : 'lid', device);
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
throw new Error(`Failed to parse AD_JID: ${err && err.message ? err.message : err}`);
|
|
177
|
+
}
|
|
164
178
|
};
|
|
165
179
|
const readString = (tag) => {
|
|
166
180
|
if (tag >= 1 && tag < SINGLE_BYTE_TOKENS.length) {
|
package/lib/WABinary/encode.js
CHANGED
|
@@ -78,6 +78,9 @@ const encodeBinaryNodeInner = ({ tag, attrs, content }, opts, buffer) => {
|
|
|
78
78
|
pushBytes(bytes);
|
|
79
79
|
};
|
|
80
80
|
const writeJid = ({ domainType, device, user, server }) => {
|
|
81
|
+
if (typeof user !== 'string' || typeof server !== 'string') {
|
|
82
|
+
throw new Error(`Invalid JID to write: user=${String(user)}, server=${String(server)}`);
|
|
83
|
+
}
|
|
81
84
|
if (typeof device !== 'undefined') {
|
|
82
85
|
pushByte(TAGS.AD_JID);
|
|
83
86
|
pushByte(domainType || 0);
|
|
@@ -126,8 +129,11 @@ const encodeBinaryNodeInner = ({ tag, attrs, content }, opts, buffer) => {
|
|
|
126
129
|
throw new Error(`Invalid hex char "${char}"`);
|
|
127
130
|
};
|
|
128
131
|
const writePackedBytes = (str, type) => {
|
|
132
|
+
if (typeof str !== 'string') {
|
|
133
|
+
throw new Error('writePackedBytes expects a string');
|
|
134
|
+
}
|
|
129
135
|
if (str.length > TAGS.PACKED_MAX) {
|
|
130
|
-
throw new Error(
|
|
136
|
+
throw new Error(`Too many bytes to pack: ${str.length} > ${TAGS.PACKED_MAX}`);
|
|
131
137
|
}
|
|
132
138
|
pushByte(type === 'nibble' ? TAGS.NIBBLE_8 : TAGS.HEX_8);
|
|
133
139
|
let roundedLength = Math.ceil(str.length / 2.0);
|
|
@@ -179,6 +185,14 @@ const encodeBinaryNodeInner = ({ tag, attrs, content }, opts, buffer) => {
|
|
|
179
185
|
pushByte(TAGS.LIST_EMPTY);
|
|
180
186
|
return;
|
|
181
187
|
}
|
|
188
|
+
if (typeof str !== 'string') {
|
|
189
|
+
// allow decoded JID objects below, but not other types
|
|
190
|
+
const decoded = (0, jid_utils_1.jidDecode)(str);
|
|
191
|
+
if (!decoded) {
|
|
192
|
+
throw new Error(`writeString expects string or decodable JID, got ${typeof str}`);
|
|
193
|
+
}
|
|
194
|
+
// fallthrough to handle decoded JID
|
|
195
|
+
}
|
|
182
196
|
const tokenIndex = TOKEN_MAP[str];
|
|
183
197
|
if (tokenIndex) {
|
|
184
198
|
if (typeof tokenIndex.dict === 'number') {
|