rubjs 3.0.0 → 3.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 (56) hide show
  1. package/README.md +8 -8
  2. package/lib/clients/VoiceChatClient.d.ts +4 -3
  3. package/lib/clients/VoiceChatClient.js +60 -92
  4. package/lib/clients/loginClient.d.ts +1 -1
  5. package/lib/clients/loginClient.js +1 -1
  6. package/lib/{core → clients}/network_login.js +1 -1
  7. package/lib/core/client.d.ts +10 -19
  8. package/lib/core/client.js +32 -20
  9. package/lib/{types → core/context}/activities.type.d.ts +2 -2
  10. package/lib/{types → core/context}/chat.type.d.ts +2 -2
  11. package/lib/core/context/contextConstructors.d.ts +10 -0
  12. package/lib/core/context/contextConstructors.js +16 -0
  13. package/lib/core/context/index.d.ts +5 -0
  14. package/lib/core/context/index.js +14 -0
  15. package/lib/{types → core/context}/message.type.d.ts +2 -2
  16. package/lib/{types → core/context}/notifications.type.d.ts +2 -2
  17. package/lib/core/methods/extras/onEditMessages.d.ts +1 -1
  18. package/lib/core/methods/groups/joinGroup.js +0 -1
  19. package/lib/core/methods/index.d.ts +4 -3
  20. package/lib/core/methods/index.js +8 -17
  21. package/lib/core/methods/utilities/download.d.ts +4 -0
  22. package/lib/core/methods/utilities/download.js +6 -0
  23. package/lib/core/methods/utilities/downloadProfilePicture.d.ts +4 -0
  24. package/lib/core/methods/utilities/downloadProfilePicture.js +28 -0
  25. package/lib/core/methods/utilities/index.d.ts +3 -3
  26. package/lib/core/methods/utilities/index.js +5 -5
  27. package/lib/core/methods/utilities/start.js +0 -1
  28. package/lib/core/network/api.d.ts +16 -0
  29. package/lib/core/network/api.js +95 -0
  30. package/lib/core/network/file.d.ts +3 -0
  31. package/lib/core/network/file.js +117 -0
  32. package/lib/core/network/index.d.ts +25 -0
  33. package/lib/core/network/index.js +31 -0
  34. package/lib/core/network/utils.d.ts +9 -0
  35. package/lib/core/network/utils.js +34 -0
  36. package/lib/core/network/websocket.d.ts +3 -0
  37. package/lib/core/network/websocket.js +190 -0
  38. package/lib/index.d.ts +7 -5
  39. package/lib/index.js +2 -4
  40. package/lib/types/client.type.d.ts +10 -12
  41. package/lib/types/index.type.d.ts +1 -3
  42. package/lib/types/index.type.js +1 -8
  43. package/package.json +1 -1
  44. package/lib/core/methods/utilities/runErrorMiddlewares.d.ts +0 -3
  45. package/lib/core/methods/utilities/runErrorMiddlewares.js +0 -13
  46. package/lib/core/methods/utilities/useError.d.ts +0 -4
  47. package/lib/core/methods/utilities/useError.js +0 -6
  48. package/lib/core/network.d.ts +0 -49
  49. package/lib/core/network.js +0 -436
  50. /package/lib/{core → clients}/network_login.d.ts +0 -0
  51. /package/lib/{types → core/context}/activities.type.js +0 -0
  52. /package/lib/{types → core/context}/chat.type.js +0 -0
  53. /package/lib/{types → core/context}/message.type.js +0 -0
  54. /package/lib/{types → core/context}/notifications.type.js +0 -0
  55. /package/lib/{core → utils}/utils.d.ts +0 -0
  56. /package/lib/{core → utils}/utils.js +0 -0
@@ -0,0 +1,4 @@
1
+ import Client from "../../client";
2
+ import { Buffer } from "buffer";
3
+ declare function downloadProfilePicture(this: Client, object_guid: string): Promise<Buffer | null>;
4
+ export default downloadProfilePicture;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const undici_1 = require("undici");
4
+ const buffer_1 = require("buffer");
5
+ async function downloadProfilePicture(object_guid) {
6
+ const avatarsInfo = await this.getAvatars(object_guid);
7
+ if (!avatarsInfo || !avatarsInfo.avatars?.[0]?.main)
8
+ return null;
9
+ const avatar = avatarsInfo.avatars[0].main;
10
+ const url = `https://messenger${avatar.dc_id}.iranlms.ir/InternFile.ashx?id=${avatar.file_id}&ach=${avatar.access_hash_rec}`;
11
+ try {
12
+ const { statusCode, body } = await (0, undici_1.request)(url, {
13
+ method: "GET",
14
+ });
15
+ if (statusCode !== 200 || !body)
16
+ return null;
17
+ const chunks = [];
18
+ for await (const chunk of body) {
19
+ chunks.push(typeof chunk === "string" ? buffer_1.Buffer.from(chunk) : chunk);
20
+ }
21
+ return buffer_1.Buffer.concat(chunks);
22
+ }
23
+ catch (err) {
24
+ console.error("Failed to download profile picture:", err);
25
+ return null;
26
+ }
27
+ }
28
+ exports.default = downloadProfilePicture;
@@ -2,7 +2,7 @@ import run from './run';
2
2
  import requestSendFile from './requestSendFile';
3
3
  import start from './start';
4
4
  import thumbnail from './thumbnail';
5
- import useError from './useError';
6
5
  import usePlugin from './usePlugin';
7
- import runErrorMiddlewares from './runErrorMiddlewares';
8
- export { run, useError, usePlugin, requestSendFile, start, thumbnail, runErrorMiddlewares, };
6
+ import download from './download';
7
+ import downloadProfilePicture from './downloadProfilePicture';
8
+ export { run, start, download, thumbnail, usePlugin, requestSendFile, downloadProfilePicture };
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.runErrorMiddlewares = exports.thumbnail = exports.start = exports.requestSendFile = exports.usePlugin = exports.useError = exports.run = void 0;
6
+ exports.downloadProfilePicture = exports.requestSendFile = exports.usePlugin = exports.thumbnail = exports.download = exports.start = exports.run = void 0;
7
7
  const run_1 = __importDefault(require("./run"));
8
8
  exports.run = run_1.default;
9
9
  const requestSendFile_1 = __importDefault(require("./requestSendFile"));
@@ -12,9 +12,9 @@ const start_1 = __importDefault(require("./start"));
12
12
  exports.start = start_1.default;
13
13
  const thumbnail_1 = __importDefault(require("./thumbnail"));
14
14
  exports.thumbnail = thumbnail_1.default;
15
- const useError_1 = __importDefault(require("./useError"));
16
- exports.useError = useError_1.default;
17
15
  const usePlugin_1 = __importDefault(require("./usePlugin"));
18
16
  exports.usePlugin = usePlugin_1.default;
19
- const runErrorMiddlewares_1 = __importDefault(require("./runErrorMiddlewares"));
20
- exports.runErrorMiddlewares = runErrorMiddlewares_1.default;
17
+ const download_1 = __importDefault(require("./download"));
18
+ exports.download = download_1.default;
19
+ const downloadProfilePicture_1 = __importDefault(require("./downloadProfilePicture"));
20
+ exports.downloadProfilePicture = downloadProfilePicture_1.default;
@@ -36,7 +36,6 @@ async function start() {
36
36
  }
37
37
  }
38
38
  let result = await this.sendCode(phone_number);
39
- console.log(result);
40
39
  if (result.status == 'SendPassKey') {
41
40
  while (true) {
42
41
  let pass_key = await (0, prompt_1.default)(`Password [${result.hint_pass_key}] > `);
@@ -0,0 +1,16 @@
1
+ import Network from '.';
2
+ interface SendPayloadInputs {
3
+ input?: Record<string, any>;
4
+ method?: string;
5
+ tmp_session: boolean;
6
+ }
7
+ /**
8
+ * Retrieves API and WSS server URLs
9
+ */
10
+ export declare function getDcs(network: Network): Promise<boolean>;
11
+ /**
12
+ * Sends a POST request with retry logic and enhanced error reporting
13
+ */
14
+ export declare function sendRequest(network: Network, url: string, data: any): Promise<unknown>;
15
+ export declare function sendPayload(network: Network, datas: SendPayloadInputs): Promise<any>;
16
+ export {};
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getDcs = getDcs;
7
+ exports.sendRequest = sendRequest;
8
+ exports.sendPayload = sendPayload;
9
+ const undici_1 = require("undici");
10
+ const crypto_1 = __importDefault(require("../crypto"));
11
+ /**
12
+ * Retrieves API and WSS server URLs
13
+ */
14
+ async function getDcs(network) {
15
+ const url = 'https://getdcmess.iranlms.ir/';
16
+ const RETRY_DELAY = 3000;
17
+ while (true) {
18
+ try {
19
+ const res = await (0, undici_1.request)(url, {
20
+ method: 'GET',
21
+ dispatcher: network.agent,
22
+ });
23
+ if (res.statusCode === 200) {
24
+ const body = (await res.body.json());
25
+ if (body?.data) {
26
+ const dcs = body.data;
27
+ network.apiUrl = `${dcs.API[dcs.default_api]}/`;
28
+ network.wssUrl = dcs.socket[dcs.default_socket];
29
+ return true;
30
+ }
31
+ }
32
+ console.warn('[getDcs] Unexpected status or data format:', res.statusCode);
33
+ }
34
+ catch (error) {
35
+ console.error('[getDcs] Error:', error);
36
+ }
37
+ await network.delay(RETRY_DELAY);
38
+ }
39
+ }
40
+ /**
41
+ * Sends a POST request with retry logic and enhanced error reporting
42
+ */
43
+ async function sendRequest(network, url, data) {
44
+ const MAX_ATTEMPTS = 3;
45
+ for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
46
+ try {
47
+ const res = await (0, undici_1.request)(url, {
48
+ method: 'POST',
49
+ headers: {
50
+ 'content-type': 'application/json',
51
+ ...network.headers,
52
+ },
53
+ body: JSON.stringify(data),
54
+ dispatcher: network.agent,
55
+ });
56
+ if (res.statusCode === 200) {
57
+ const responseData = await res.body.json();
58
+ return responseData;
59
+ }
60
+ else {
61
+ console.warn(`[request] Attempt ${attempt}: Unexpected status ${res.statusCode}`);
62
+ }
63
+ }
64
+ catch (error) {
65
+ console.error(`[request] Attempt ${attempt} failed:`, error);
66
+ }
67
+ await network.delay(1000);
68
+ }
69
+ throw new Error(`[request] Failed after ${MAX_ATTEMPTS} attempts: ${url}`);
70
+ }
71
+ async function sendPayload(network, datas) {
72
+ await network.getDcs();
73
+ while (!network.apiUrl) {
74
+ await network.delay(1000);
75
+ }
76
+ const { auth, decode_auth, key, privateKey } = network.client;
77
+ if (!key)
78
+ return;
79
+ const credentialsKey = datas.tmp_session ? 'tmp_session' : 'auth';
80
+ const credentialsValue = datas.tmp_session ? auth : decode_auth;
81
+ const dataPayload = JSON.stringify({
82
+ client: network.defaultPlatform,
83
+ method: datas.method,
84
+ input: datas.input,
85
+ });
86
+ const payload = {
87
+ api_version: '6',
88
+ data_enc: crypto_1.default.encrypt(dataPayload, key),
89
+ [credentialsKey]: credentialsValue,
90
+ };
91
+ if (!datas.tmp_session && privateKey) {
92
+ payload.sign = crypto_1.default.sign(payload.data_enc, privateKey);
93
+ }
94
+ return network.request(network.apiUrl, payload);
95
+ }
@@ -0,0 +1,3 @@
1
+ import Network from '.';
2
+ export declare function uploadFile(network: Network, filePath: string, chunkSize?: number): Promise<any>;
3
+ export declare function download(network: Network, dc_id: number, file_id: number, access_hash: string, size: number, chunk?: number): Promise<Buffer>;
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.uploadFile = uploadFile;
7
+ exports.download = download;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const undici_1 = require("undici");
11
+ async function uploadFile(network, filePath, chunkSize = 1048576) {
12
+ if (!fs_1.default.existsSync(filePath))
13
+ throw new Error('File not found in the given path');
14
+ const stat = await fs_1.default.promises.stat(filePath);
15
+ const fileSize = stat.size;
16
+ const fileName = path_1.default.basename(filePath);
17
+ const mime = filePath.split('.').pop();
18
+ let result = await network.client.requestSendFile(fileName, fileSize, mime);
19
+ let id = result.id;
20
+ let dc_id = result.dc_id;
21
+ let upload_url = result.upload_url;
22
+ let access_hash_send = result.access_hash_send;
23
+ let totalParts = Math.ceil(fileSize / chunkSize);
24
+ const stream = fs_1.default.createReadStream(filePath, { highWaterMark: chunkSize });
25
+ let index = 0;
26
+ for await (const chunk of stream) {
27
+ try {
28
+ const res = await (0, undici_1.request)(upload_url, {
29
+ method: 'POST',
30
+ headers: {
31
+ auth: network.client.auth,
32
+ 'file-id': id,
33
+ 'total-part': totalParts.toString(),
34
+ 'part-number': (index + 1).toString(),
35
+ 'chunk-size': chunk.length.toString(),
36
+ 'access-hash-send': access_hash_send,
37
+ },
38
+ body: chunk,
39
+ dispatcher: network.agent,
40
+ });
41
+ const response = await res.body.json();
42
+ if (response.status === 'ERROR_TRY_AGAIN') {
43
+ console.log('Retrying upload...');
44
+ stream.close();
45
+ result = await network.client.requestSendFile(fileName, fileSize, mime);
46
+ id = result.id;
47
+ dc_id = result.dc_id;
48
+ upload_url = result.upload_url;
49
+ access_hash_send = result.access_hash_send;
50
+ index = 0;
51
+ return uploadFile(network, filePath, chunkSize);
52
+ }
53
+ index++;
54
+ if (response.status === 'OK' &&
55
+ response.status_det === 'OK' &&
56
+ response.data?.access_hash_rec) {
57
+ return {
58
+ mime,
59
+ size: fileSize,
60
+ dc_id,
61
+ file_id: id,
62
+ file_name: fileName,
63
+ access_hash_rec: response.data.access_hash_rec,
64
+ };
65
+ }
66
+ }
67
+ catch (error) {
68
+ console.error('Upload error:', error);
69
+ await new Promise((resolve) => setTimeout(resolve, 5000));
70
+ }
71
+ }
72
+ throw new Error('Upload failed completely.');
73
+ }
74
+ async function download(network, dc_id, file_id, access_hash, size, chunk = 131072) {
75
+ const headersBase = {
76
+ auth: network.client.auth,
77
+ 'access-hash-rec': access_hash,
78
+ 'file-id': String(file_id),
79
+ 'user-agent': network.userAgent,
80
+ };
81
+ const base_url = `https://messenger${dc_id}.iranlms.ir`;
82
+ const fetchChunk = async (start_index, last_index) => {
83
+ const headers = {
84
+ ...headersBase,
85
+ 'start-index': String(start_index),
86
+ 'last-index': String(last_index),
87
+ };
88
+ try {
89
+ const { body, statusCode } = await (0, undici_1.request)(`${base_url}/GetFile.ashx`, {
90
+ method: 'POST',
91
+ headers,
92
+ });
93
+ if (statusCode !== 200 || !body)
94
+ return Buffer.alloc(0);
95
+ const chunks = [];
96
+ for await (const chunk of body) {
97
+ chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);
98
+ }
99
+ return Buffer.concat(chunks);
100
+ }
101
+ catch (err) {
102
+ console.error(`[fetchChunk] Failed at ${start_index}-${last_index}`, err);
103
+ return Buffer.alloc(0);
104
+ }
105
+ };
106
+ let result = Buffer.alloc(0);
107
+ let start_index = 0;
108
+ while (start_index < size) {
109
+ const last_index = Math.min(start_index + chunk, size) - 1;
110
+ const chunkData = await fetchChunk(start_index, last_index);
111
+ if (chunkData.length === 0)
112
+ break;
113
+ result = Buffer.concat([result, chunkData]);
114
+ start_index = last_index + 1;
115
+ }
116
+ return result;
117
+ }
@@ -0,0 +1,25 @@
1
+ import Client from '../client';
2
+ import { Agent, WebSocket as UndiciWebSocket } from 'undici';
3
+ import { delay } from './utils';
4
+ import { NetworkTypes } from '../../types/index.type';
5
+ export default class Network {
6
+ client: Client;
7
+ headers: Record<string, string>;
8
+ defaultPlatform: NetworkTypes.Platform;
9
+ agent: Agent;
10
+ userAgent: string;
11
+ ws?: InstanceType<typeof UndiciWebSocket>;
12
+ apiUrl?: string;
13
+ wssUrl?: string;
14
+ heartbeatInterval?: NodeJS.Timeout;
15
+ inactivityTimeout?: NodeJS.Timeout;
16
+ reconnecting: boolean;
17
+ constructor(client: Client);
18
+ getDcs: () => Promise<boolean>;
19
+ request: (url: string, data: any) => Promise<unknown>;
20
+ send: (opts: any) => Promise<any>;
21
+ getUpdates: () => Promise<void>;
22
+ uploadFile: (filePath: string, chunkSize?: number) => Promise<any>;
23
+ download: (dc_id: number, file_id: number, access_hash: string, size: number, chunk?: number) => Promise<Buffer<ArrayBufferLike>>;
24
+ delay: typeof delay;
25
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const undici_1 = require("undici");
7
+ const utils_1 = require("./utils");
8
+ const api_1 = require("./api");
9
+ const websocket_1 = require("./websocket");
10
+ const user_agents_1 = __importDefault(require("user-agents"));
11
+ const file_1 = require("./file");
12
+ class Network {
13
+ constructor(client) {
14
+ this.client = client;
15
+ this.userAgent = new user_agents_1.default().toString();
16
+ this.reconnecting = false;
17
+ this.getDcs = () => (0, api_1.getDcs)(this);
18
+ this.request = (url, data) => (0, api_1.sendRequest)(this, url, data);
19
+ this.send = (opts) => (0, api_1.sendPayload)(this, opts);
20
+ this.getUpdates = async () => (0, websocket_1.setupWebSocket)(this);
21
+ this.uploadFile = (filePath, chunkSize) => (0, file_1.uploadFile)(this, filePath, chunkSize);
22
+ this.download = (dc_id, file_id, access_hash, size, chunk = 131072) => (0, file_1.download)(this, dc_id, file_id, access_hash, size, chunk);
23
+ this.delay = utils_1.delay;
24
+ this.defaultPlatform = (0, utils_1.resolvePlatform)(client.platform);
25
+ this.headers = (0, utils_1.buildHeaders)(client.platform);
26
+ this.agent = new undici_1.Agent({
27
+ connect: { rejectUnauthorized: false },
28
+ });
29
+ }
30
+ }
31
+ exports.default = Network;
@@ -0,0 +1,9 @@
1
+ export declare function delay(ms: number): Promise<unknown>;
2
+ export declare function resolvePlatform(platform: string): {
3
+ app_name: string;
4
+ app_version: string;
5
+ platform: string;
6
+ package: string;
7
+ lang_code: string;
8
+ };
9
+ export declare function buildHeaders(platform: string): Record<string, string>;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.delay = delay;
7
+ exports.resolvePlatform = resolvePlatform;
8
+ exports.buildHeaders = buildHeaders;
9
+ const user_agents_1 = __importDefault(require("user-agents"));
10
+ function delay(ms) {
11
+ return new Promise((resolve) => setTimeout(resolve, ms));
12
+ }
13
+ function resolvePlatform(platform) {
14
+ const isAndroid = platform?.toLowerCase() === 'android';
15
+ return {
16
+ app_name: 'Main',
17
+ app_version: isAndroid ? '3.6.4' : '4.4.9',
18
+ platform: isAndroid ? 'Android' : 'Web',
19
+ package: isAndroid ? 'app.rbmain.a' : 'web.rubika.ir',
20
+ lang_code: 'fa',
21
+ };
22
+ }
23
+ function buildHeaders(platform) {
24
+ const headers = {
25
+ 'content-type': 'application/json',
26
+ connection: 'keep-alive',
27
+ 'user-agent': new user_agents_1.default().toString(),
28
+ };
29
+ if (platform.toLowerCase() !== 'android') {
30
+ headers.origin = 'https://web.rubika.ir';
31
+ headers.referer = 'https://web.rubika.ir/';
32
+ }
33
+ return headers;
34
+ }
@@ -0,0 +1,3 @@
1
+ import Network from '.';
2
+ export declare function setupWebSocket(network: Network): Promise<void>;
3
+ export declare function openSocket(network: Network): Promise<void>;
@@ -0,0 +1,190 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.setupWebSocket = setupWebSocket;
7
+ exports.openSocket = openSocket;
8
+ const crypto_1 = __importDefault(require("../crypto"));
9
+ const undici_1 = require("undici");
10
+ const contextConstructors_1 = require("../context/contextConstructors");
11
+ const TYPES = {
12
+ chat: 'chat_updates',
13
+ message: 'message_updates',
14
+ activities: 'show_activities',
15
+ notifications: 'show_notifications',
16
+ };
17
+ async function setupWebSocket(network) {
18
+ while (!network.wssUrl) {
19
+ await network.delay(1000);
20
+ }
21
+ network.ws = new undici_1.WebSocket(network.wssUrl);
22
+ network.ws.addEventListener('open', async () => await openSocket(network));
23
+ network.ws.addEventListener('message', async (event) => await getMessage(event.data, network));
24
+ network.ws.addEventListener('error', async () => {
25
+ if (!network.reconnecting) {
26
+ console.error('WebSocket error, reconnecting...');
27
+ network.reconnecting = true;
28
+ await resetConnection(network);
29
+ }
30
+ });
31
+ network.ws.addEventListener('close', async () => {
32
+ if (!network.reconnecting) {
33
+ console.warn('WebSocket closed, reconnecting...');
34
+ network.reconnecting = true;
35
+ await resetConnection(network);
36
+ }
37
+ });
38
+ }
39
+ async function openSocket(network) {
40
+ try {
41
+ console.log('Starting bot...');
42
+ if (network.ws && network.ws.readyState === undici_1.WebSocket.OPEN) {
43
+ const payload = JSON.stringify({
44
+ api_version: '5',
45
+ auth: network.client.auth,
46
+ data: '',
47
+ method: 'handShake',
48
+ });
49
+ network.ws.send(payload);
50
+ if (network.heartbeatInterval)
51
+ clearInterval(network.heartbeatInterval);
52
+ network.heartbeatInterval = setInterval(() => {
53
+ try {
54
+ if (network.ws?.readyState === undici_1.WebSocket.OPEN) {
55
+ network.ws.send(JSON.stringify({}));
56
+ }
57
+ }
58
+ catch (err) {
59
+ console.error('Error sending heartbeat', err);
60
+ }
61
+ }, 30000);
62
+ }
63
+ else {
64
+ console.warn('WebSocket is not open; cannot send handshake');
65
+ }
66
+ }
67
+ catch (err) {
68
+ console.error('Error during openSocket execution', err);
69
+ }
70
+ }
71
+ async function resetConnection(network) {
72
+ network.ws?.close();
73
+ network.ws = undefined;
74
+ setTimeout(async () => {
75
+ try {
76
+ await network.getUpdates();
77
+ }
78
+ catch (e) {
79
+ console.error('Failed to reconnect:', e);
80
+ }
81
+ finally {
82
+ network.reconnecting = false;
83
+ }
84
+ }, 5000);
85
+ }
86
+ function resetInactivityTimer(network) {
87
+ if (network.inactivityTimeout)
88
+ clearTimeout(network.inactivityTimeout);
89
+ network.inactivityTimeout = setTimeout(() => {
90
+ console.warn('No updates received for 10 minutes. Reconnecting WebSocket...');
91
+ void resetConnection(network).catch((err) => {
92
+ console.error('Error during inactivity reset:', err);
93
+ });
94
+ }, 10 * 60 * 1000);
95
+ }
96
+ async function getMessage(message, network) {
97
+ try {
98
+ const { data_enc } = JSON.parse(message);
99
+ if (!data_enc || !network.client.key)
100
+ return;
101
+ resetInactivityTimer(network);
102
+ const update = JSON.parse(crypto_1.default.decrypt(data_enc, network.client.key));
103
+ const tasks = [];
104
+ for (const ctxKey of Object.keys(TYPES)) {
105
+ const updateKey = TYPES[ctxKey];
106
+ const author_title = getAuthorTitle(update);
107
+ const items = update[updateKey];
108
+ if (!Array.isArray(items) || items.length === 0)
109
+ continue;
110
+ const handlers = network.client.handlers[ctxKey];
111
+ if (!handlers || handlers.length === 0)
112
+ continue;
113
+ tasks.push(handleCategory(ctxKey, handlers, items, network, author_title));
114
+ }
115
+ if (tasks.length === 1) {
116
+ await tasks[0];
117
+ }
118
+ else if (tasks.length > 1) {
119
+ await Promise.all(tasks);
120
+ }
121
+ }
122
+ catch (err) {
123
+ console.error('[getMessage] Failed to decrypt or process message:', err);
124
+ }
125
+ }
126
+ async function handleCategory(type, handlers, updates, network, author_title) {
127
+ const CtxClass = contextConstructors_1.ContextConstructors[type];
128
+ if (!CtxClass) {
129
+ console.warn(`[handleCategory] No constructor found for type: ${type}`);
130
+ return;
131
+ }
132
+ for (let update of updates) {
133
+ if (!update.message)
134
+ update.message = {};
135
+ update.client_guid = network.client.userGuid;
136
+ update.message.author_title = author_title;
137
+ const ctx = new CtxClass(network.client, update);
138
+ for (const { filters, handler, prefix } of handlers) {
139
+ // Prefix logic
140
+ if (type === 'message' && prefix) {
141
+ const text = ctx.message.text;
142
+ if (!text)
143
+ continue;
144
+ if (typeof prefix === 'string' && text !== prefix)
145
+ continue;
146
+ if (prefix instanceof RegExp && !prefix.test(text))
147
+ continue;
148
+ }
149
+ // filters
150
+ const passed = await checkFilters(ctx, filters);
151
+ if (passed) {
152
+ await handler(ctx);
153
+ }
154
+ }
155
+ }
156
+ }
157
+ // utils
158
+ async function checkFilters(ctx, filters) {
159
+ for (const filter of filters) {
160
+ if (Array.isArray(filter)) {
161
+ // OR logic
162
+ const results = await Promise.all(filter.map((f) => Promise.resolve(f(ctx))));
163
+ if (!results.some(Boolean))
164
+ return false;
165
+ }
166
+ else {
167
+ // AND logic
168
+ const result = await Promise.resolve(filter(ctx));
169
+ if (!result)
170
+ return false;
171
+ }
172
+ }
173
+ return true;
174
+ }
175
+ const getAuthorTitle = (update) => {
176
+ const notification = update.show_notifications?.[0];
177
+ const chatUpdate = update.chat_updates?.[0];
178
+ if (notification) {
179
+ const objectGuid = notification?.message_data?.object_guid;
180
+ if (objectGuid?.startsWith('u0'))
181
+ return notification.title;
182
+ else if (objectGuid?.startsWith('g0'))
183
+ return notification.text?.split(':')[0];
184
+ }
185
+ else if (chatUpdate) {
186
+ return chatUpdate.chat?.last_message?.author_title || 'Unknown User';
187
+ }
188
+ else
189
+ return 'Unknown User';
190
+ };
package/lib/index.d.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  import Client from './core/client';
2
2
  import Filters from './core/filters';
3
- import Utils from './core/utils';
4
- import { Middleware, RubPlugin } from './types/client.type';
5
- import type MessageType from './types/message.type';
6
- import * as ContextTypes from './types/index.type';
3
+ import Utils from './utils/utils';
4
+ import { RubPlugin } from './types/client.type';
5
+ import type MessageType from './core/context/message.type';
6
+ import type ActivitiesType from './core/context/activities.type';
7
+ import type ChatType from './core/context/chat.type';
8
+ import type NotificationsType from './core/context/notifications.type';
7
9
  import * as Clients from './clients';
8
- export { Client, Filters, Utils, Middleware, MessageType, RubPlugin, ContextTypes, Clients, };
10
+ export { Client, Filters, Utils, RubPlugin, ChatType, MessageType, ActivitiesType, NotificationsType, Clients, };
9
11
  export default Client;
package/lib/index.js CHANGED
@@ -36,15 +36,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.Clients = exports.ContextTypes = exports.Utils = exports.Filters = exports.Client = void 0;
39
+ exports.Clients = exports.Utils = exports.Filters = exports.Client = void 0;
40
40
  const client_1 = __importDefault(require("./core/client"));
41
41
  exports.Client = client_1.default;
42
42
  const filters_1 = __importDefault(require("./core/filters"));
43
43
  exports.Filters = filters_1.default;
44
- const utils_1 = __importDefault(require("./core/utils"));
44
+ const utils_1 = __importDefault(require("./utils/utils"));
45
45
  exports.Utils = utils_1.default;
46
- const ContextTypes = __importStar(require("./types/index.type"));
47
- exports.ContextTypes = ContextTypes;
48
46
  const Clients = __importStar(require("./clients"));
49
47
  exports.Clients = Clients;
50
48
  exports.default = client_1.default;