@cexy/hoonfca 1.0.7 → 2.0.1

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.
Files changed (191) hide show
  1. package/LICENSE +3 -0
  2. package/examples/login-with-cookies.js +102 -0
  3. package/examples/verify.js +70 -0
  4. package/index.js +2 -8
  5. package/package.json +82 -61
  6. package/src/{api/action → apis}/addExternalModule.js +24 -25
  7. package/src/apis/addUserToGroup.js +108 -0
  8. package/src/apis/changeAdminStatus.js +148 -0
  9. package/src/apis/changeArchivedStatus.js +61 -0
  10. package/src/apis/changeAvatar.js +103 -0
  11. package/src/apis/changeBio.js +69 -0
  12. package/src/apis/changeBlockedStatus.js +54 -0
  13. package/src/apis/changeGroupImage.js +136 -0
  14. package/src/apis/changeThreadColor.js +116 -0
  15. package/src/apis/changeThreadEmoji.js +53 -0
  16. package/src/apis/comment.js +207 -0
  17. package/src/apis/createAITheme.js +129 -0
  18. package/src/apis/createNewGroup.js +79 -0
  19. package/src/apis/createPoll.js +73 -0
  20. package/src/apis/deleteMessage.js +44 -0
  21. package/src/apis/deleteThread.js +52 -0
  22. package/src/apis/e2ee.js +17 -0
  23. package/src/apis/editMessage.js +70 -0
  24. package/src/apis/emoji.js +124 -0
  25. package/src/apis/fetchThemeData.js +82 -0
  26. package/src/apis/follow.js +81 -0
  27. package/src/apis/forwardMessage.js +52 -0
  28. package/src/apis/friend.js +243 -0
  29. package/src/apis/gcmember.js +122 -0
  30. package/src/apis/gcname.js +123 -0
  31. package/src/apis/gcrule.js +119 -0
  32. package/src/apis/getAccess.js +111 -0
  33. package/src/apis/getBotInfo.js +88 -0
  34. package/src/apis/getBotInitialData.js +43 -0
  35. package/src/apis/getFriendsList.js +79 -0
  36. package/src/apis/getMessage.js +423 -0
  37. package/src/apis/getTheme.js +95 -0
  38. package/src/apis/getThemeInfo.js +116 -0
  39. package/src/apis/getThreadHistory.js +239 -0
  40. package/src/apis/getThreadInfo.js +267 -0
  41. package/src/apis/getThreadList.js +232 -0
  42. package/src/apis/getThreadPictures.js +58 -0
  43. package/src/apis/getUserID.js +117 -0
  44. package/src/apis/getUserInfo.js +513 -0
  45. package/src/{api/users → apis}/getUserInfoV2.js +146 -134
  46. package/src/apis/handleMessageRequest.js +50 -0
  47. package/src/apis/httpGet.js +63 -0
  48. package/src/apis/httpPost.js +89 -0
  49. package/src/apis/httpPostFormData.js +69 -0
  50. package/src/apis/listenMqtt.js +1236 -0
  51. package/src/apis/listenSpeed.js +179 -0
  52. package/src/apis/logout.js +87 -0
  53. package/src/apis/markAsDelivered.js +47 -0
  54. package/src/{api/messaging → apis}/markAsRead.js +99 -88
  55. package/src/apis/markAsReadAll.js +40 -0
  56. package/src/apis/markAsSeen.js +70 -0
  57. package/src/apis/mqttDeltaValue.js +278 -0
  58. package/src/apis/muteThread.js +45 -0
  59. package/src/apis/nickname.js +132 -0
  60. package/src/apis/notes.js +163 -0
  61. package/src/apis/pinMessage.js +150 -0
  62. package/src/apis/produceMetaTheme.js +180 -0
  63. package/src/apis/realtime.js +182 -0
  64. package/src/apis/removeUserFromGroup.js +117 -0
  65. package/src/apis/resolvePhotoUrl.js +58 -0
  66. package/src/apis/searchForThread.js +154 -0
  67. package/src/apis/sendMessage.js +354 -0
  68. package/src/apis/sendMessageMqtt.js +249 -0
  69. package/src/apis/sendTypingIndicator.js +91 -0
  70. package/src/apis/setMessageReaction.js +27 -0
  71. package/src/apis/setMessageReactionMqtt.js +61 -0
  72. package/src/apis/setThreadTheme.js +260 -0
  73. package/src/apis/setThreadThemeMqtt.js +94 -0
  74. package/src/apis/share.js +107 -0
  75. package/src/apis/shareContact.js +66 -0
  76. package/src/apis/stickers.js +257 -0
  77. package/src/apis/story.js +181 -0
  78. package/src/apis/theme.js +233 -0
  79. package/src/apis/unfriend.js +47 -0
  80. package/src/apis/unsendMessage.js +17 -0
  81. package/src/engine/client.js +92 -0
  82. package/src/engine/models/buildAPI.js +152 -0
  83. package/src/engine/models/loginHelper.js +519 -0
  84. package/src/engine/models/setOptions.js +88 -0
  85. package/src/security/e2ee.js +109 -0
  86. package/src/types/index.d.ts +498 -0
  87. package/src/utils/antiSuspension.js +506 -0
  88. package/src/utils/auth-helpers.js +149 -0
  89. package/src/utils/autoReLogin.js +336 -0
  90. package/src/utils/axios.js +436 -0
  91. package/src/utils/cache.js +54 -0
  92. package/src/utils/clients.js +282 -0
  93. package/src/utils/constants.js +410 -23
  94. package/src/utils/formatters/data/formatAttachment.js +370 -0
  95. package/src/utils/formatters/data/formatDelta.js +109 -0
  96. package/src/utils/formatters/index.js +159 -0
  97. package/src/utils/formatters/value/formatCookie.js +91 -0
  98. package/src/utils/formatters/value/formatDate.js +36 -0
  99. package/src/utils/formatters/value/formatID.js +16 -0
  100. package/src/utils/formatters.js +1373 -0
  101. package/src/utils/headers.js +214 -99
  102. package/src/utils/index.js +153 -0
  103. package/src/utils/monitoring.js +333 -0
  104. package/src/utils/rateLimiter.js +319 -0
  105. package/src/utils/tokenRefresh.js +657 -0
  106. package/src/utils/user-agents.js +238 -0
  107. package/src/utils/validation.js +157 -0
  108. package/CHANGELOG.md +0 -181
  109. package/DOCS.md +0 -2636
  110. package/LICENSE-MIT +0 -21
  111. package/README.md +0 -632
  112. package/func/checkUpdate.js +0 -233
  113. package/func/logger.js +0 -48
  114. package/index.d.ts +0 -746
  115. package/module/config.js +0 -67
  116. package/module/login.js +0 -154
  117. package/module/loginHelper.js +0 -1034
  118. package/module/options.js +0 -54
  119. package/src/api/action/changeAvatar.js +0 -137
  120. package/src/api/action/changeBio.js +0 -75
  121. package/src/api/action/enableAutoSaveAppState.js +0 -73
  122. package/src/api/action/getCurrentUserID.js +0 -7
  123. package/src/api/action/handleFriendRequest.js +0 -57
  124. package/src/api/action/logout.js +0 -76
  125. package/src/api/action/refreshFb_dtsg.js +0 -48
  126. package/src/api/action/setPostReaction.js +0 -106
  127. package/src/api/action/unfriend.js +0 -54
  128. package/src/api/http/httpGet.js +0 -46
  129. package/src/api/http/httpPost.js +0 -52
  130. package/src/api/http/postFormData.js +0 -47
  131. package/src/api/messaging/addUserToGroup.js +0 -68
  132. package/src/api/messaging/changeAdminStatus.js +0 -122
  133. package/src/api/messaging/changeArchivedStatus.js +0 -55
  134. package/src/api/messaging/changeBlockedStatus.js +0 -48
  135. package/src/api/messaging/changeGroupImage.js +0 -90
  136. package/src/api/messaging/changeNickname.js +0 -70
  137. package/src/api/messaging/changeThreadColor.js +0 -79
  138. package/src/api/messaging/changeThreadEmoji.js +0 -106
  139. package/src/api/messaging/createNewGroup.js +0 -88
  140. package/src/api/messaging/createPoll.js +0 -43
  141. package/src/api/messaging/createThemeAI.js +0 -98
  142. package/src/api/messaging/deleteMessage.js +0 -56
  143. package/src/api/messaging/deleteThread.js +0 -56
  144. package/src/api/messaging/editMessage.js +0 -68
  145. package/src/api/messaging/forwardAttachment.js +0 -51
  146. package/src/api/messaging/getEmojiUrl.js +0 -29
  147. package/src/api/messaging/getFriendsList.js +0 -82
  148. package/src/api/messaging/getMessage.js +0 -829
  149. package/src/api/messaging/getThemePictures.js +0 -62
  150. package/src/api/messaging/handleMessageRequest.js +0 -65
  151. package/src/api/messaging/markAsDelivered.js +0 -57
  152. package/src/api/messaging/markAsReadAll.js +0 -49
  153. package/src/api/messaging/markAsSeen.js +0 -61
  154. package/src/api/messaging/muteThread.js +0 -50
  155. package/src/api/messaging/removeUserFromGroup.js +0 -106
  156. package/src/api/messaging/resolvePhotoUrl.js +0 -43
  157. package/src/api/messaging/scheduler.js +0 -264
  158. package/src/api/messaging/searchForThread.js +0 -52
  159. package/src/api/messaging/sendMessage.js +0 -272
  160. package/src/api/messaging/sendTypingIndicator.js +0 -67
  161. package/src/api/messaging/setMessageReaction.js +0 -76
  162. package/src/api/messaging/setTitle.js +0 -119
  163. package/src/api/messaging/shareContact.js +0 -49
  164. package/src/api/messaging/threadColors.js +0 -128
  165. package/src/api/messaging/unsendMessage.js +0 -81
  166. package/src/api/messaging/uploadAttachment.js +0 -94
  167. package/src/api/socket/core/connectMqtt.js +0 -255
  168. package/src/api/socket/core/emitAuth.js +0 -106
  169. package/src/api/socket/core/getSeqID.js +0 -40
  170. package/src/api/socket/core/getTaskResponseData.js +0 -22
  171. package/src/api/socket/core/markDelivery.js +0 -12
  172. package/src/api/socket/core/parseDelta.js +0 -391
  173. package/src/api/socket/detail/buildStream.js +0 -208
  174. package/src/api/socket/detail/constants.js +0 -24
  175. package/src/api/socket/listenMqtt.js +0 -364
  176. package/src/api/socket/middleware/index.js +0 -216
  177. package/src/api/threads/getThreadHistory.js +0 -664
  178. package/src/api/threads/getThreadInfo.js +0 -438
  179. package/src/api/threads/getThreadList.js +0 -293
  180. package/src/api/threads/getThreadPictures.js +0 -78
  181. package/src/api/users/getUserID.js +0 -65
  182. package/src/api/users/getUserInfo.js +0 -327
  183. package/src/core/sendReqMqtt.js +0 -96
  184. package/src/database/models/index.js +0 -87
  185. package/src/database/models/thread.js +0 -45
  186. package/src/database/models/user.js +0 -46
  187. package/src/database/threadData.js +0 -98
  188. package/src/database/userData.js +0 -89
  189. package/src/utils/client.js +0 -320
  190. package/src/utils/format.js +0 -1115
  191. package/src/utils/request.js +0 -305
@@ -1,364 +0,0 @@
1
- "use strict";
2
- const mqtt = require("mqtt");
3
- const WebSocket = require("ws");
4
- const HttpsProxyAgent = require("https-proxy-agent");
5
- const EventEmitter = require("events");
6
- const logger = require("../../../func/logger");
7
- const { parseAndCheckLogin } = require("../../utils/client");
8
- const { buildProxy, buildStream } = require("./detail/buildStream");
9
- const { topics } = require("./detail/constants");
10
- const createParseDelta = require("./core/parseDelta");
11
- const createListenMqtt = require("./core/connectMqtt");
12
- const createGetSeqID = require("./core/getSeqID");
13
- const markDelivery = require("./core/markDelivery");
14
- const getTaskResponseData = require("./core/getTaskResponseData");
15
- const createEmitAuth = require("./core/emitAuth");
16
- const createMiddlewareSystem = require("./middleware");
17
- const parseDelta = createParseDelta({ markDelivery, parseAndCheckLogin });
18
- // Create emitAuth first so it can be injected into both factories
19
- const emitAuth = createEmitAuth({ logger });
20
- // Pass emitAuth into connectMqtt so errors there can signal auth state
21
- const listenMqtt = createListenMqtt({ WebSocket, mqtt, HttpsProxyAgent, buildStream, buildProxy, topics, parseDelta, getTaskResponseData, logger, emitAuth });
22
- // Inject emitAuth into getSeqID so its catch handler can notify properly
23
- const getSeqIDFactory = createGetSeqID({ parseAndCheckLogin, listenMqtt, logger, emitAuth });
24
-
25
- const MQTT_DEFAULTS = { cycleMs: 60 * 60 * 1000, reconnectDelayMs: 2000, autoReconnect: true, reconnectAfterStop: false };
26
- function mqttConf(ctx, overrides) {
27
- ctx._mqttOpt = Object.assign({}, MQTT_DEFAULTS, ctx._mqttOpt || {}, overrides || {});
28
- if (typeof ctx._mqttOpt.autoReconnect === "boolean") ctx.globalOptions.autoReconnect = ctx._mqttOpt.autoReconnect;
29
- return ctx._mqttOpt;
30
- }
31
-
32
- module.exports = function (defaultFuncs, api, ctx, opts) {
33
- const identity = function () { };
34
- let globalCallback = identity;
35
-
36
- // Initialize middleware system if not already initialized
37
- if (!ctx._middleware) {
38
- ctx._middleware = createMiddlewareSystem();
39
- }
40
- const middleware = ctx._middleware;
41
-
42
- function installPostGuard() {
43
- if (ctx._postGuarded) return defaultFuncs.post;
44
- const rawPost = defaultFuncs.post && defaultFuncs.post.bind(defaultFuncs);
45
- if (!rawPost) return defaultFuncs.post;
46
-
47
- function postSafe(...args) {
48
- return rawPost(...args).catch(err => {
49
- const msg = (err && err.error) || (err && err.message) || String(err || "");
50
- if (/Not logged in|blocked the login/i.test(msg)) {
51
- emitAuth(
52
- ctx,
53
- api,
54
- globalCallback,
55
- /blocked/i.test(msg) ? "login_blocked" : "not_logged_in",
56
- msg
57
- );
58
- }
59
- throw err;
60
- });
61
- }
62
- defaultFuncs.post = postSafe;
63
- ctx._postGuarded = true;
64
- return postSafe;
65
- }
66
-
67
- let conf = mqttConf(ctx, opts);
68
-
69
- function getSeqIDWrapper() {
70
- if (ctx._ending && !ctx._cycling) {
71
- logger("mqtt getSeqID skipped - ending", "warn");
72
- return Promise.resolve();
73
- }
74
- const form = {
75
- av: ctx.globalOptions.pageID,
76
- queries: JSON.stringify({
77
- o0: {
78
- doc_id: "3336396659757871",
79
- query_params: {
80
- limit: 1, before: null, tags: ["INBOX"],
81
- includeDeliveryReceipts: false, includeSeqID: true
82
- }
83
- }
84
- })
85
- };
86
- logger("mqtt getSeqID call", "info");
87
- return getSeqIDFactory(defaultFuncs, api, ctx, globalCallback, form)
88
- .then(() => {
89
- logger("mqtt getSeqID done", "info");
90
- ctx._cycling = false;
91
- })
92
- .catch(e => {
93
- ctx._cycling = false;
94
- const errMsg = e && e.message ? e.message : String(e || "Unknown error");
95
- logger(`mqtt getSeqID error: ${errMsg}`, "error");
96
- // Don't reconnect if we're ending
97
- if (ctx._ending) return;
98
- // Retry after delay if autoReconnect is enabled
99
- if (ctx.globalOptions.autoReconnect) {
100
- const d = conf.reconnectDelayMs;
101
- logger(`mqtt getSeqID will retry in ${d}ms`, "warn");
102
- setTimeout(() => {
103
- if (!ctx._ending) getSeqIDWrapper();
104
- }, d);
105
- }
106
- });
107
- }
108
-
109
- function isConnected() {
110
- return !!(ctx.mqttClient && ctx.mqttClient.connected);
111
- }
112
-
113
- function unsubAll(cb) {
114
- if (!isConnected()) {
115
- if (cb) setTimeout(cb, 0);
116
- return;
117
- }
118
- let pending = topics.length;
119
- if (!pending) {
120
- if (cb) setTimeout(cb, 0);
121
- return;
122
- }
123
- let fired = false;
124
- const timeout = setTimeout(() => {
125
- if (!fired) {
126
- fired = true;
127
- logger("unsubAll timeout, proceeding anyway", "warn");
128
- if (cb) cb();
129
- }
130
- }, 5000); // 5 second timeout
131
-
132
- topics.forEach(t => {
133
- try {
134
- ctx.mqttClient.unsubscribe(t, () => {
135
- if (--pending === 0 && !fired) {
136
- clearTimeout(timeout);
137
- fired = true;
138
- if (cb) cb();
139
- }
140
- });
141
- } catch (err) {
142
- logger(`unsubAll error for topic ${t}: ${err && err.message ? err.message : String(err)}`, "warn");
143
- if (--pending === 0 && !fired) {
144
- clearTimeout(timeout);
145
- fired = true;
146
- if (cb) cb();
147
- }
148
- }
149
- });
150
- }
151
-
152
- function endQuietly(next) {
153
- const finish = () => {
154
- try {
155
- if (ctx.mqttClient) {
156
- ctx.mqttClient.removeAllListeners();
157
- }
158
- } catch (_) { }
159
- ctx.mqttClient = undefined;
160
- ctx.lastSeqId = null;
161
- ctx.syncToken = undefined;
162
- ctx.t_mqttCalled = false;
163
- ctx._ending = false;
164
- ctx._cycling = false;
165
- if (ctx._reconnectTimer) {
166
- clearTimeout(ctx._reconnectTimer);
167
- ctx._reconnectTimer = null;
168
- }
169
- if (ctx._rTimeout) {
170
- clearTimeout(ctx._rTimeout);
171
- ctx._rTimeout = null;
172
- }
173
- // Clean up tasks Map to prevent memory leak
174
- if (ctx.tasks && ctx.tasks instanceof Map) {
175
- ctx.tasks.clear();
176
- }
177
- // Clean up userInfo intervals
178
- if (ctx._userInfoIntervals && Array.isArray(ctx._userInfoIntervals)) {
179
- ctx._userInfoIntervals.forEach(interval => {
180
- try {
181
- clearInterval(interval);
182
- } catch (_) { }
183
- });
184
- ctx._userInfoIntervals = [];
185
- }
186
- // Clean up autoSave intervals
187
- if (ctx._autoSaveInterval && Array.isArray(ctx._autoSaveInterval)) {
188
- ctx._autoSaveInterval.forEach(interval => {
189
- try {
190
- clearInterval(interval);
191
- } catch (_) { }
192
- });
193
- ctx._autoSaveInterval = [];
194
- }
195
- // Clean up scheduler
196
- if (ctx._scheduler && typeof ctx._scheduler.destroy === "function") {
197
- try {
198
- ctx._scheduler.destroy();
199
- } catch (_) { }
200
- ctx._scheduler = undefined;
201
- }
202
- // Clear global mqttClient reference if set
203
- if (global.mqttClient) {
204
- delete global.mqttClient;
205
- }
206
- next && next();
207
- };
208
- try {
209
- if (ctx.mqttClient) {
210
- if (isConnected()) {
211
- try {
212
- ctx.mqttClient.publish("/browser_close", "{}", { qos: 0 });
213
- } catch (_) { }
214
- }
215
- ctx.mqttClient.end(true, finish);
216
- } else finish();
217
- } catch (_) { finish(); }
218
- }
219
-
220
- function delayedReconnect() {
221
- const d = conf.reconnectDelayMs;
222
- logger(`mqtt reconnect in ${d}ms`, "info");
223
- setTimeout(() => getSeqIDWrapper(), d);
224
- }
225
-
226
- function forceCycle() {
227
- if (ctx._cycling) {
228
- logger("mqtt force cycle already in progress", "warn");
229
- return;
230
- }
231
- ctx._cycling = true;
232
- ctx._ending = true;
233
- logger("mqtt force cycle begin", "warn");
234
- unsubAll(() => endQuietly(() => delayedReconnect()));
235
- }
236
-
237
- return function (callback) {
238
- class MessageEmitter extends EventEmitter {
239
- stopListening(callback2) {
240
- const cb = callback2 || function () { };
241
- logger("mqtt stop requested", "info");
242
- globalCallback = identity;
243
-
244
- if (ctx._autoCycleTimer) {
245
- clearInterval(ctx._autoCycleTimer);
246
- ctx._autoCycleTimer = null;
247
- logger("mqtt auto-cycle cleared", "info");
248
- }
249
-
250
- if (ctx._reconnectTimer) {
251
- clearTimeout(ctx._reconnectTimer);
252
- ctx._reconnectTimer = null;
253
- }
254
-
255
- ctx._ending = true;
256
- unsubAll(() => endQuietly(() => {
257
- logger("mqtt stopped", "info");
258
- cb();
259
- conf = mqttConf(ctx, conf);
260
- if (conf.reconnectAfterStop) delayedReconnect();
261
- }));
262
- }
263
- async stopListeningAsync() {
264
- return new Promise(resolve => { this.stopListening(resolve); });
265
- }
266
- }
267
-
268
- const msgEmitter = new MessageEmitter();
269
-
270
- // Original callback without middleware
271
- const originalCallback = callback || function (error, message) {
272
- if (error) { logger("mqtt emit error", "error"); return msgEmitter.emit("error", error); }
273
- msgEmitter.emit("message", message);
274
- };
275
-
276
- // Only wrap callback with middleware if middleware exists
277
- // If no middleware, use callback directly for better performance
278
- if (middleware.count > 0) {
279
- globalCallback = middleware.wrapCallback(originalCallback);
280
- } else {
281
- globalCallback = originalCallback;
282
- }
283
-
284
- conf = mqttConf(ctx, conf);
285
-
286
- installPostGuard();
287
-
288
- if (!ctx.firstListen) ctx.lastSeqId = null;
289
- ctx.syncToken = undefined;
290
- ctx.t_mqttCalled = false;
291
-
292
- if (ctx._autoCycleTimer) { clearInterval(ctx._autoCycleTimer); ctx._autoCycleTimer = null; }
293
- if (conf.cycleMs && conf.cycleMs > 0) {
294
- ctx._autoCycleTimer = setInterval(forceCycle, conf.cycleMs);
295
- logger(`mqtt auto-cycle enabled ${conf.cycleMs}ms`, "info");
296
- } else {
297
- logger("mqtt auto-cycle disabled", "info");
298
- }
299
-
300
- if (!ctx.firstListen || !ctx.lastSeqId) getSeqIDWrapper();
301
- else {
302
- logger("mqtt starting listenMqtt", "info");
303
- listenMqtt(defaultFuncs, api, ctx, globalCallback);
304
- }
305
-
306
- api.stopListening = msgEmitter.stopListening;
307
- api.stopListeningAsync = msgEmitter.stopListeningAsync;
308
-
309
- // Store original callback for re-wrapping when middleware is added/removed
310
- let currentOriginalCallback = originalCallback;
311
- let currentGlobalCallback = globalCallback;
312
-
313
- // Function to re-wrap callback when middleware changes
314
- function rewrapCallbackIfNeeded() {
315
- if (!ctx.mqttClient || ctx._ending) return; // Not listening or ending
316
-
317
- const hasMiddleware = middleware.count > 0;
318
- const isWrapped = currentGlobalCallback !== currentOriginalCallback;
319
-
320
- // If middleware exists but callback is not wrapped, wrap it
321
- if (hasMiddleware && !isWrapped) {
322
- currentGlobalCallback = middleware.wrapCallback(currentOriginalCallback);
323
- globalCallback = currentGlobalCallback;
324
- logger("Middleware added - callback re-wrapped", "info");
325
- }
326
- // If no middleware but callback is wrapped, unwrap it
327
- else if (!hasMiddleware && isWrapped) {
328
- currentGlobalCallback = currentOriginalCallback;
329
- globalCallback = currentGlobalCallback;
330
- logger("All middleware removed - callback unwrapped", "info");
331
- }
332
- }
333
-
334
- // Expose middleware API with re-wrapping support
335
- api.useMiddleware = function (middlewareFn, fn) {
336
- const result = middleware.use(middlewareFn, fn);
337
- rewrapCallbackIfNeeded();
338
- return result;
339
- };
340
- api.removeMiddleware = function (identifier) {
341
- const result = middleware.remove(identifier);
342
- rewrapCallbackIfNeeded();
343
- return result;
344
- };
345
- api.clearMiddleware = function () {
346
- const result = middleware.clear();
347
- rewrapCallbackIfNeeded();
348
- return result;
349
- };
350
- api.listMiddleware = function () {
351
- return middleware.list();
352
- };
353
- api.setMiddlewareEnabled = function (name, enabled) {
354
- const result = middleware.setEnabled(name, enabled);
355
- rewrapCallbackIfNeeded();
356
- return result;
357
- };
358
- Object.defineProperty(api, "middlewareCount", {
359
- get: function () { return middleware.count; }
360
- });
361
-
362
- return msgEmitter;
363
- };
364
- };
@@ -1,216 +0,0 @@
1
- "use strict";
2
- const logger = require("../../../../func/logger");
3
-
4
- /**
5
- * Middleware system for filtering and processing events before they are emitted
6
- *
7
- * Middleware functions receive (event, next) where:
8
- * - event: The event object (can be modified)
9
- * - next: Function to call to continue to next middleware
10
- * - next() - continue to next middleware
11
- * - next(false) or next(null) - stop processing, don't emit event
12
- * - next(error) - emit error instead
13
- */
14
- module.exports = function createMiddlewareSystem() {
15
- const middlewareStack = [];
16
-
17
- /**
18
- * Add middleware to the stack
19
- * @param {Function|string} middleware - Middleware function or name for named middleware
20
- * @param {Function} [fn] - Middleware function (if first param is name)
21
- * @returns {Function} Unsubscribe function
22
- */
23
- function use(middleware, fn) {
24
- let middlewareFn, name;
25
-
26
- if (typeof middleware === "string" && typeof fn === "function") {
27
- name = middleware;
28
- middlewareFn = fn;
29
- } else if (typeof middleware === "function") {
30
- middlewareFn = middleware;
31
- name = `middleware_${middlewareStack.length}`;
32
- } else {
33
- throw new Error("Middleware must be a function or (name, function)");
34
- }
35
-
36
- const wrapped = {
37
- name,
38
- fn: middlewareFn,
39
- enabled: true
40
- };
41
-
42
- middlewareStack.push(wrapped);
43
- logger(`Middleware "${name}" added`, "info");
44
-
45
- // Return unsubscribe function
46
- return function remove() {
47
- const index = middlewareStack.indexOf(wrapped);
48
- if (index !== -1) {
49
- middlewareStack.splice(index, 1);
50
- logger(`Middleware "${name}" removed`, "info");
51
- }
52
- };
53
- }
54
-
55
- /**
56
- * Remove middleware by name or function
57
- * @param {string|Function} identifier - Name or function to remove
58
- * @returns {boolean} True if removed
59
- */
60
- function remove(identifier) {
61
- if (typeof identifier === "string") {
62
- const index = middlewareStack.findIndex(m => m.name === identifier);
63
- if (index !== -1) {
64
- const removed = middlewareStack.splice(index, 1)[0];
65
- logger(`Middleware "${removed.name}" removed`, "info");
66
- return true;
67
- }
68
- return false;
69
- } else if (typeof identifier === "function") {
70
- const index = middlewareStack.findIndex(m => m.fn === identifier);
71
- if (index !== -1) {
72
- const removed = middlewareStack.splice(index, 1)[0];
73
- logger(`Middleware "${removed.name}" removed`, "info");
74
- return true;
75
- }
76
- return false;
77
- }
78
- return false;
79
- }
80
-
81
- /**
82
- * Remove all middleware
83
- */
84
- function clear() {
85
- const count = middlewareStack.length;
86
- middlewareStack.length = 0;
87
- logger(`All middleware cleared (${count} removed)`, "info");
88
- }
89
-
90
- /**
91
- * Get list of middleware names
92
- * @returns {string[]} Array of middleware names
93
- */
94
- function list() {
95
- return middlewareStack.filter(m => m.enabled).map(m => m.name);
96
- }
97
-
98
- /**
99
- * Enable/disable middleware by name
100
- * @param {string} name - Middleware name
101
- * @param {boolean} enabled - Enable or disable
102
- * @returns {boolean} True if found and updated
103
- */
104
- function setEnabled(name, enabled) {
105
- const middleware = middlewareStack.find(m => m.name === name);
106
- if (middleware) {
107
- middleware.enabled = enabled;
108
- logger(`Middleware "${name}" ${enabled ? "enabled" : "disabled"}`, "info");
109
- return true;
110
- }
111
- return false;
112
- }
113
-
114
- /**
115
- * Process event through middleware stack
116
- * @param {*} event - Event object
117
- * @param {Function} finalCallback - Callback to call after all middleware
118
- * @returns {Promise} Promise that resolves when processing is complete
119
- */
120
- function process(event, finalCallback) {
121
- if (!middlewareStack.length) {
122
- return finalCallback(null, event);
123
- }
124
-
125
- let index = 0;
126
- const enabledMiddleware = middlewareStack.filter(m => m.enabled);
127
-
128
- function next(err) {
129
- // Error occurred, stop processing
130
- if (err && err !== false && err !== null) {
131
- return finalCallback(err, null);
132
- }
133
-
134
- // Explicitly stopped (next(false) or next(null))
135
- if (err === false || err === null) {
136
- return finalCallback(null, null); // null event means don't emit
137
- }
138
-
139
- // No more middleware, call final callback
140
- if (index >= enabledMiddleware.length) {
141
- return finalCallback(null, event);
142
- }
143
-
144
- // Get next middleware
145
- const middleware = enabledMiddleware[index++];
146
-
147
- try {
148
- // Call middleware with event and next
149
- const result = middleware.fn(event, next);
150
-
151
- // If middleware returns a promise, handle it
152
- if (result && typeof result.then === "function") {
153
- result
154
- .then(() => next())
155
- .catch(err => next(err));
156
- } else if (result === false || result === null) {
157
- // Middleware returned false/null, stop processing
158
- finalCallback(null, null);
159
- }
160
- // If middleware called next() synchronously, it will continue
161
- } catch (err) {
162
- logger(`Middleware "${middleware.name}" error: ${err && err.message ? err.message : String(err)}`, "error");
163
- next(err);
164
- }
165
- }
166
-
167
- // Start processing
168
- next();
169
- }
170
-
171
- /**
172
- * Wrap a callback with middleware processing
173
- * @param {Function} callback - Original callback (err, event)
174
- * @returns {Function} Wrapped callback
175
- */
176
- function wrapCallback(callback) {
177
- return function wrappedCallback(err, event) {
178
- if (err) {
179
- // Errors bypass middleware
180
- return callback(err, null);
181
- }
182
-
183
- if (!event) {
184
- return callback(null, null);
185
- }
186
-
187
- // Process event through middleware
188
- process(event, (middlewareErr, processedEvent) => {
189
- if (middlewareErr) {
190
- return callback(middlewareErr, null);
191
- }
192
-
193
- // If processedEvent is null, middleware blocked the event
194
- if (processedEvent === null) {
195
- return; // Don't emit
196
- }
197
-
198
- // Emit processed event
199
- callback(null, processedEvent);
200
- });
201
- };
202
- }
203
-
204
- return {
205
- use,
206
- remove,
207
- clear,
208
- list,
209
- setEnabled,
210
- process,
211
- wrapCallback,
212
- get count() {
213
- return middlewareStack.filter(m => m.enabled).length;
214
- }
215
- };
216
- };