@bruch/max-client 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +168 -0
  3. package/UPSTREAM.md +10 -0
  4. package/dist/api/account.d.ts +24 -0
  5. package/dist/api/account.d.ts.map +1 -0
  6. package/dist/api/auth.d.ts +57 -0
  7. package/dist/api/auth.d.ts.map +1 -0
  8. package/dist/api/bots.d.ts +8 -0
  9. package/dist/api/bots.d.ts.map +1 -0
  10. package/dist/api/chats.d.ts +41 -0
  11. package/dist/api/chats.d.ts.map +1 -0
  12. package/dist/api/facade.d.ts +19 -0
  13. package/dist/api/facade.d.ts.map +1 -0
  14. package/dist/api/index.d.ts +10 -0
  15. package/dist/api/index.d.ts.map +1 -0
  16. package/dist/api/messages.d.ts +35 -0
  17. package/dist/api/messages.d.ts.map +1 -0
  18. package/dist/api/response.d.ts +7 -0
  19. package/dist/api/response.d.ts.map +1 -0
  20. package/dist/api/runtime.d.ts +19 -0
  21. package/dist/api/runtime.d.ts.map +1 -0
  22. package/dist/api/uploads.d.ts +23 -0
  23. package/dist/api/uploads.d.ts.map +1 -0
  24. package/dist/api/users.d.ts +25 -0
  25. package/dist/api/users.d.ts.map +1 -0
  26. package/dist/app.d.ts +55 -0
  27. package/dist/app.d.ts.map +1 -0
  28. package/dist/auth/flows.d.ts +27 -0
  29. package/dist/auth/flows.d.ts.map +1 -0
  30. package/dist/auth/index.d.ts +3 -0
  31. package/dist/auth/index.d.ts.map +1 -0
  32. package/dist/auth/index.js +109 -0
  33. package/dist/auth/index.js.map +11 -0
  34. package/dist/auth/providers.d.ts +11 -0
  35. package/dist/auth/providers.d.ts.map +1 -0
  36. package/dist/client.d.ts +139 -0
  37. package/dist/client.d.ts.map +1 -0
  38. package/dist/config.d.ts +80 -0
  39. package/dist/config.d.ts.map +1 -0
  40. package/dist/connection/connection.d.ts +25 -0
  41. package/dist/connection/connection.d.ts.map +1 -0
  42. package/dist/connection/index.d.ts +4 -0
  43. package/dist/connection/index.d.ts.map +1 -0
  44. package/dist/connection/pending.d.ts +9 -0
  45. package/dist/connection/pending.d.ts.map +1 -0
  46. package/dist/connection/readers.d.ts +17 -0
  47. package/dist/connection/readers.d.ts.map +1 -0
  48. package/dist/dispatch/dispatcher.d.ts +16 -0
  49. package/dist/dispatch/dispatcher.d.ts.map +1 -0
  50. package/dist/dispatch/index.d.ts +3 -0
  51. package/dist/dispatch/index.d.ts.map +1 -0
  52. package/dist/dispatch/router.d.ts +64 -0
  53. package/dist/dispatch/router.d.ts.map +1 -0
  54. package/dist/errors.d.ts +24 -0
  55. package/dist/errors.d.ts.map +1 -0
  56. package/dist/files/file.d.ts +29 -0
  57. package/dist/files/file.d.ts.map +1 -0
  58. package/dist/files/index.d.ts +2 -0
  59. package/dist/files/index.d.ts.map +1 -0
  60. package/dist/files/index.js +95 -0
  61. package/dist/files/index.js.map +10 -0
  62. package/dist/formatting/index.d.ts +2 -0
  63. package/dist/formatting/index.d.ts.map +1 -0
  64. package/dist/formatting/markdown.d.ts +13 -0
  65. package/dist/formatting/markdown.d.ts.map +1 -0
  66. package/dist/index.d.ts +15 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +3967 -0
  69. package/dist/index.js.map +48 -0
  70. package/dist/logging.d.ts +10 -0
  71. package/dist/logging.d.ts.map +1 -0
  72. package/dist/protocol/compression.d.ts +8 -0
  73. package/dist/protocol/compression.d.ts.map +1 -0
  74. package/dist/protocol/enums.d.ts +175 -0
  75. package/dist/protocol/enums.d.ts.map +1 -0
  76. package/dist/protocol/index.d.ts +6 -0
  77. package/dist/protocol/index.d.ts.map +1 -0
  78. package/dist/protocol/index.js +438 -0
  79. package/dist/protocol/index.js.map +13 -0
  80. package/dist/protocol/tcp.d.ts +35 -0
  81. package/dist/protocol/tcp.d.ts.map +1 -0
  82. package/dist/protocol/types.d.ts +38 -0
  83. package/dist/protocol/types.d.ts.map +1 -0
  84. package/dist/protocol/websocket.d.ts +7 -0
  85. package/dist/protocol/websocket.d.ts.map +1 -0
  86. package/dist/session/index.d.ts +3 -0
  87. package/dist/session/index.d.ts.map +1 -0
  88. package/dist/session/index.js +179 -0
  89. package/dist/session/index.js.map +12 -0
  90. package/dist/session/store.d.ts +18 -0
  91. package/dist/session/store.d.ts.map +1 -0
  92. package/dist/session/types.d.ts +29 -0
  93. package/dist/session/types.d.ts.map +1 -0
  94. package/dist/telemetry/index.d.ts +4 -0
  95. package/dist/telemetry/index.d.ts.map +1 -0
  96. package/dist/telemetry/index.js +831 -0
  97. package/dist/telemetry/index.js.map +17 -0
  98. package/dist/telemetry/navigation.d.ts +41 -0
  99. package/dist/telemetry/navigation.d.ts.map +1 -0
  100. package/dist/telemetry/payloads.d.ts +30 -0
  101. package/dist/telemetry/payloads.d.ts.map +1 -0
  102. package/dist/telemetry/service.d.ts +53 -0
  103. package/dist/telemetry/service.d.ts.map +1 -0
  104. package/dist/transport/base.d.ts +18 -0
  105. package/dist/transport/base.d.ts.map +1 -0
  106. package/dist/transport/index.d.ts +4 -0
  107. package/dist/transport/index.d.ts.map +1 -0
  108. package/dist/transport/tcp.d.ts +28 -0
  109. package/dist/transport/tcp.d.ts.map +1 -0
  110. package/dist/transport/websocket.d.ts +14 -0
  111. package/dist/transport/websocket.d.ts.map +1 -0
  112. package/dist/types/attachments.d.ts +18 -0
  113. package/dist/types/attachments.d.ts.map +1 -0
  114. package/dist/types/index.d.ts +4 -0
  115. package/dist/types/index.d.ts.map +1 -0
  116. package/dist/types/index.js +376 -0
  117. package/dist/types/index.js.map +12 -0
  118. package/dist/types/models.d.ts +210 -0
  119. package/dist/types/models.d.ts.map +1 -0
  120. package/dist/types/utils.d.ts +10 -0
  121. package/dist/types/utils.d.ts.map +1 -0
  122. package/package.json +95 -0
  123. package/src/api/account.ts +93 -0
  124. package/src/api/auth.ts +312 -0
  125. package/src/api/bots.ts +21 -0
  126. package/src/api/chats.ts +234 -0
  127. package/src/api/facade.ts +28 -0
  128. package/src/api/index.ts +9 -0
  129. package/src/api/messages.ts +230 -0
  130. package/src/api/response.ts +24 -0
  131. package/src/api/runtime.ts +27 -0
  132. package/src/api/uploads.ts +91 -0
  133. package/src/api/users.ts +68 -0
  134. package/src/app.ts +271 -0
  135. package/src/auth/flows.ts +103 -0
  136. package/src/auth/index.ts +2 -0
  137. package/src/auth/providers.ts +30 -0
  138. package/src/client.ts +506 -0
  139. package/src/config.ts +161 -0
  140. package/src/connection/connection.ts +93 -0
  141. package/src/connection/index.ts +3 -0
  142. package/src/connection/pending.ts +49 -0
  143. package/src/connection/readers.ts +33 -0
  144. package/src/dispatch/dispatcher.ts +194 -0
  145. package/src/dispatch/index.ts +2 -0
  146. package/src/dispatch/router.ts +149 -0
  147. package/src/errors.ts +41 -0
  148. package/src/files/file.ts +92 -0
  149. package/src/files/index.ts +1 -0
  150. package/src/formatting/index.ts +1 -0
  151. package/src/formatting/markdown.ts +123 -0
  152. package/src/index.ts +15 -0
  153. package/src/logging.ts +67 -0
  154. package/src/protocol/compression.ts +69 -0
  155. package/src/protocol/enums.ts +175 -0
  156. package/src/protocol/index.ts +5 -0
  157. package/src/protocol/tcp.ts +139 -0
  158. package/src/protocol/types.ts +45 -0
  159. package/src/protocol/websocket.ts +47 -0
  160. package/src/session/index.ts +2 -0
  161. package/src/session/store.ts +154 -0
  162. package/src/session/types.ts +45 -0
  163. package/src/telemetry/index.ts +3 -0
  164. package/src/telemetry/navigation.ts +160 -0
  165. package/src/telemetry/payloads.ts +84 -0
  166. package/src/telemetry/service.ts +194 -0
  167. package/src/transport/base.ts +43 -0
  168. package/src/transport/index.ts +3 -0
  169. package/src/transport/tcp.ts +296 -0
  170. package/src/transport/websocket.ts +63 -0
  171. package/src/types/attachments.ts +24 -0
  172. package/src/types/index.ts +3 -0
  173. package/src/types/models.ts +461 -0
  174. package/src/types/utils.ts +45 -0
package/src/client.ts ADDED
@@ -0,0 +1,506 @@
1
+ import type { AccountApi, AuthApi, BotsApi, ChatApi, ContactInfo, UserApi } from "./api/index.ts";
2
+ import { App } from "./app.ts";
3
+ import {
4
+ QrAuthFlow,
5
+ SmsAuthFlow,
6
+ type AuthFlow,
7
+ type PasswordProvider,
8
+ type QrHandler,
9
+ type SmsCodeProvider,
10
+ } from "./auth/index.ts";
11
+ import { resolveConfig, type ExtraConfig, type ResolvedConfig } from "./config.ts";
12
+ import { ConnectionManager, TcpReader, WsReader } from "./connection/index.ts";
13
+ import {
14
+ Router,
15
+ type DisconnectHandler,
16
+ type ErrorHandler,
17
+ type Filter,
18
+ type Handler,
19
+ type StartHandler,
20
+ } from "./dispatch/index.ts";
21
+ import { configureLogging } from "./logging.ts";
22
+ import { TcpProtocol, WsProtocol, type InboundFrame } from "./protocol/index.ts";
23
+ import type { SessionInfo } from "./session/index.ts";
24
+ import { TcpTransport, WebSocketTransport } from "./transport/index.ts";
25
+ import type {
26
+ Chat,
27
+ ChatActions,
28
+ EditMessageOptions,
29
+ ForwardMessageOptions,
30
+ HistoryOptions,
31
+ MaxId,
32
+ Message,
33
+ MessageActions,
34
+ MessageDeleteEvent,
35
+ MessageReadEvent,
36
+ PresenceEvent,
37
+ ReactionInfo,
38
+ ReactionUpdateEvent,
39
+ ReadState,
40
+ SendMessageOptions,
41
+ TypingEvent,
42
+ User,
43
+ UserActions,
44
+ } from "./types/index.ts";
45
+
46
+ export interface ClientOptions {
47
+ phone: string;
48
+ sessionName?: string;
49
+ workDir?: string;
50
+ extraConfig?: ExtraConfig;
51
+ authFlow?: AuthFlow;
52
+ smsCodeProvider?: SmsCodeProvider;
53
+ passwordProvider?: PasswordProvider;
54
+ }
55
+
56
+ export interface WebClientOptions {
57
+ sessionName?: string;
58
+ workDir?: string;
59
+ extraConfig?: ExtraConfig;
60
+ authFlow?: AuthFlow;
61
+ qrHandler?: QrHandler;
62
+ passwordProvider?: PasswordProvider;
63
+ }
64
+
65
+ export abstract class BaseClient implements MessageActions, ChatActions, UserActions {
66
+ readonly router = new Router<BaseClient>();
67
+ protected app: App<BaseClient>;
68
+ readonly config: ResolvedConfig;
69
+ private stopping = false;
70
+
71
+ protected constructor(config: ResolvedConfig, _authFlow: AuthFlow, app: App<BaseClient>) {
72
+ this.config = config;
73
+ configureLogging(config.logLevel);
74
+ this.app = app;
75
+ this.app.bindClient(this);
76
+ }
77
+
78
+ get me() {
79
+ return this.app.me;
80
+ }
81
+ get chats(): Chat[] {
82
+ return this.app.chats;
83
+ }
84
+ get contacts(): Array<User | null> {
85
+ return this.app.contacts;
86
+ }
87
+ get messages(): Map<bigint, Message[]> {
88
+ return this.app.messages;
89
+ }
90
+ get session(): SessionInfo | null {
91
+ return this.app.session;
92
+ }
93
+ get api() {
94
+ return this.app.api;
95
+ }
96
+ get account(): AccountApi {
97
+ return this.api.account;
98
+ }
99
+ get auth(): AuthApi {
100
+ return this.api.auth;
101
+ }
102
+ get bots(): BotsApi {
103
+ return this.api.bots;
104
+ }
105
+ get chatApi(): ChatApi {
106
+ return this.api.chats;
107
+ }
108
+ get users(): UserApi {
109
+ return this.api.users;
110
+ }
111
+
112
+ async start(): Promise<void> {
113
+ this.stopping = false;
114
+ for (;;) {
115
+ try {
116
+ await this.app.start();
117
+ await this.app.dispatcher.emitStart();
118
+ await this.app.connection.waitClosed();
119
+ await this.app.close();
120
+ return;
121
+ } catch (error) {
122
+ await this.app.close();
123
+ if (this.stopping) return;
124
+ const failure = error instanceof Error ? error : new Error(String(error));
125
+ await this.app.dispatcher.emitDisconnect(
126
+ failure,
127
+ this.config.reconnect,
128
+ this.config.reconnectDelay,
129
+ );
130
+ if (!this.config.reconnect) throw failure;
131
+ await Bun.sleep(this.config.reconnectDelay * 1000);
132
+ this.app = this.rebuildApp();
133
+ this.app.bindClient(this);
134
+ }
135
+ }
136
+ }
137
+
138
+ async stop(): Promise<void> {
139
+ this.stopping = true;
140
+ await this.app.close();
141
+ }
142
+ async close(): Promise<void> {
143
+ await this.stop();
144
+ }
145
+ async relogin(start = true): Promise<void> {
146
+ if (!this.app.session) throw new Error("Cannot relogin before session is loaded");
147
+ await this.app.store.deleteSession(this.app.session.token);
148
+ await this.app.close();
149
+ this.config.token = null;
150
+ this.app = this.rebuildApp();
151
+ this.app.bindClient(this);
152
+ if (start) await this.start();
153
+ }
154
+
155
+ includeRouter(router: Router<BaseClient>): () => void {
156
+ return this.router.includeRouter(router);
157
+ }
158
+ onStart(handler: StartHandler<BaseClient>): () => void {
159
+ return this.router.onStart(handler);
160
+ }
161
+ onError(handler: ErrorHandler<BaseClient>): () => void {
162
+ return this.router.onError(handler);
163
+ }
164
+ onDisconnect(handler: DisconnectHandler): () => void {
165
+ return this.router.onDisconnect(handler);
166
+ }
167
+ onMessage(handler: Handler<Message, BaseClient>, ...filters: Filter<Message>[]): () => void {
168
+ return this.router.onMessage(handler, ...filters);
169
+ }
170
+ onMessageEdit(handler: Handler<Message, BaseClient>, ...filters: Filter<Message>[]): () => void {
171
+ return this.router.onMessageEdit(handler, ...filters);
172
+ }
173
+ onMessageDelete(
174
+ handler: Handler<MessageDeleteEvent, BaseClient>,
175
+ ...filters: Filter<MessageDeleteEvent>[]
176
+ ): () => void {
177
+ return this.router.onMessageDelete(handler, ...filters);
178
+ }
179
+ onMessageRead(
180
+ handler: Handler<MessageReadEvent, BaseClient>,
181
+ ...filters: Filter<MessageReadEvent>[]
182
+ ): () => void {
183
+ return this.router.onMessageRead(handler, ...filters);
184
+ }
185
+ onTyping(
186
+ handler: Handler<TypingEvent, BaseClient>,
187
+ ...filters: Filter<TypingEvent>[]
188
+ ): () => void {
189
+ return this.router.onTyping(handler, ...filters);
190
+ }
191
+ onPresence(
192
+ handler: Handler<PresenceEvent, BaseClient>,
193
+ ...filters: Filter<PresenceEvent>[]
194
+ ): () => void {
195
+ return this.router.onPresence(handler, ...filters);
196
+ }
197
+ onReactionUpdate(
198
+ handler: Handler<ReactionUpdateEvent, BaseClient>,
199
+ ...filters: Filter<ReactionUpdateEvent>[]
200
+ ): () => void {
201
+ return this.router.onReactionUpdate(handler, ...filters);
202
+ }
203
+ onChatUpdate(handler: Handler<Chat, BaseClient>, ...filters: Filter<Chat>[]): () => void {
204
+ return this.router.onChatUpdate(handler, ...filters);
205
+ }
206
+ onRaw(
207
+ handler: Handler<InboundFrame, BaseClient>,
208
+ ...filters: Filter<InboundFrame>[]
209
+ ): () => void {
210
+ return this.router.onRaw(handler, ...filters);
211
+ }
212
+
213
+ async sendMessage(options: SendMessageOptions): Promise<Message | null> {
214
+ return await this.api.messages.sendMessage(options);
215
+ }
216
+ async forwardMessage(options: ForwardMessageOptions): Promise<Message | null> {
217
+ return await this.api.messages.forwardMessage(options);
218
+ }
219
+ async getMessages(chatId: MaxId, messageIds: MaxId[]): Promise<Message[]> {
220
+ return await this.api.messages.getMessages(chatId, messageIds);
221
+ }
222
+ async getMessage(chatId: MaxId, messageId: MaxId): Promise<Message | null> {
223
+ return await this.api.messages.getMessage(chatId, messageId);
224
+ }
225
+ async editMessage(options: EditMessageOptions): Promise<Message> {
226
+ return await this.api.messages.editMessage(options);
227
+ }
228
+ async fetchHistory(options: HistoryOptions): Promise<Message[] | null> {
229
+ return await this.api.messages.fetchHistory(options);
230
+ }
231
+ async deleteMessage(options: {
232
+ chatId: MaxId;
233
+ messageIds: MaxId[];
234
+ forMe: boolean;
235
+ }): Promise<boolean> {
236
+ return await this.api.messages.deleteMessage(options);
237
+ }
238
+ async pinMessage(options: {
239
+ chatId: MaxId;
240
+ messageId: MaxId;
241
+ notifyPin: boolean;
242
+ }): Promise<boolean> {
243
+ return await this.api.messages.pinMessage(options);
244
+ }
245
+ async readMessage(messageId: MaxId, chatId: MaxId): Promise<ReadState> {
246
+ return await this.api.messages.readMessage(messageId, chatId);
247
+ }
248
+ async addReaction(
249
+ chatId: MaxId,
250
+ messageId: MaxId,
251
+ reaction: string,
252
+ ): Promise<ReactionInfo | null> {
253
+ return await this.api.messages.addReaction(chatId, messageId, reaction);
254
+ }
255
+ async removeReaction(chatId: MaxId, messageId: MaxId): Promise<ReactionInfo | null> {
256
+ return await this.api.messages.removeReaction(chatId, messageId);
257
+ }
258
+ async getReactions(chatId: MaxId, messageIds: MaxId[]): Promise<Map<MaxId, ReactionInfo> | null> {
259
+ return await this.api.messages.getReactions(chatId, messageIds);
260
+ }
261
+ async getVideoById(chatId: MaxId, messageId: MaxId, videoId: number) {
262
+ return await this.api.messages.getVideoById(chatId, messageId, videoId);
263
+ }
264
+ async getFileById(chatId: MaxId, messageId: MaxId, fileId: number) {
265
+ return await this.api.messages.getFileById(chatId, messageId, fileId);
266
+ }
267
+
268
+ async createGroup(name: string, participantIds: MaxId[] = [], notify = true) {
269
+ return await this.api.chats.createGroup(name, participantIds, notify);
270
+ }
271
+ async inviteUsersToGroup(
272
+ chatId: MaxId,
273
+ userIds: MaxId[],
274
+ showHistory = true,
275
+ ): Promise<Chat | null> {
276
+ return await this.api.chats.inviteUsersToGroup(chatId, userIds, showHistory);
277
+ }
278
+ async inviteUsersToChannel(
279
+ chatId: MaxId,
280
+ userIds: MaxId[],
281
+ showHistory = true,
282
+ ): Promise<Chat | null> {
283
+ return await this.api.chats.inviteUsersToChannel(chatId, userIds, showHistory);
284
+ }
285
+ async removeUsersFromGroup(chatId: MaxId, userIds: MaxId[]): Promise<Chat | null> {
286
+ return await this.api.chats.removeUsersFromGroup(chatId, userIds);
287
+ }
288
+ async getChats(chatIds: MaxId[]): Promise<Chat[]> {
289
+ return await this.api.chats.getChats(chatIds);
290
+ }
291
+ async getChat(chatId: MaxId): Promise<Chat> {
292
+ return await this.api.chats.getChat(chatId);
293
+ }
294
+ async fetchChats(marker?: number): Promise<Chat[]> {
295
+ return await this.api.chats.fetchChats(marker);
296
+ }
297
+ async joinGroup(link: string): Promise<Chat> {
298
+ return await this.api.chats.joinGroup(link);
299
+ }
300
+ async joinChannel(link: string): Promise<Chat> {
301
+ return await this.api.chats.joinChannel(link);
302
+ }
303
+ async leaveGroup(chatId: MaxId): Promise<void> {
304
+ await this.api.chats.leaveGroup(chatId);
305
+ }
306
+ async leaveChannel(chatId: MaxId): Promise<void> {
307
+ await this.api.chats.leaveChannel(chatId);
308
+ }
309
+ async deleteChat(chatId: MaxId, forMe = true): Promise<boolean> {
310
+ return await this.api.chats.deleteChat(chatId, forMe);
311
+ }
312
+ async changeGroupSettings(
313
+ chatId: MaxId,
314
+ settings: Parameters<ChatApi["changeGroupSettings"]>[1],
315
+ ): Promise<void> {
316
+ await this.api.chats.changeGroupSettings(chatId, settings);
317
+ }
318
+ async changeGroupProfile(
319
+ chatId: MaxId,
320
+ name: string | null,
321
+ description: string | null = null,
322
+ ): Promise<void> {
323
+ await this.api.chats.changeGroupProfile(chatId, name, description);
324
+ }
325
+ async resolveGroupByLink(link: string): Promise<Chat | null> {
326
+ return await this.api.chats.resolveGroupByLink(link);
327
+ }
328
+ async reworkInviteLink(chatId: MaxId): Promise<Chat> {
329
+ return await this.api.chats.reworkInviteLink(chatId);
330
+ }
331
+ async getJoinRequests(chatId: MaxId, count = 100) {
332
+ return await this.api.chats.getJoinRequests(chatId, count);
333
+ }
334
+ async confirmJoinRequests(
335
+ chatId: MaxId,
336
+ userIds: MaxId[],
337
+ showHistory = true,
338
+ ): Promise<Chat | null> {
339
+ return await this.api.chats.confirmJoinRequests(chatId, userIds, showHistory);
340
+ }
341
+ async confirmJoinRequest(chatId: MaxId, userId: MaxId, showHistory = true): Promise<Chat | null> {
342
+ return await this.api.chats.confirmJoinRequest(chatId, userId, showHistory);
343
+ }
344
+ async declineJoinRequests(chatId: MaxId, userIds: MaxId[]): Promise<Chat | null> {
345
+ return await this.api.chats.declineJoinRequests(chatId, userIds);
346
+ }
347
+ async declineJoinRequest(chatId: MaxId, userId: MaxId): Promise<Chat | null> {
348
+ return await this.api.chats.declineJoinRequest(chatId, userId);
349
+ }
350
+
351
+ getCachedUser(userId: MaxId): User | null {
352
+ return this.api.users.getCachedUser(userId);
353
+ }
354
+ async getUsers(userIds: MaxId[]): Promise<User[]> {
355
+ return await this.api.users.getUsers(userIds);
356
+ }
357
+ async getUser(userId: MaxId): Promise<User | null> {
358
+ return await this.api.users.getUser(userId);
359
+ }
360
+ async fetchUsers(userIds: MaxId[]): Promise<User[]> {
361
+ return await this.api.users.fetchUsers(userIds);
362
+ }
363
+ async searchByPhone(phone: string): Promise<User> {
364
+ return await this.api.users.searchByPhone(phone);
365
+ }
366
+ async addContact(contactId: MaxId): Promise<User> {
367
+ return await this.api.users.addContact(contactId);
368
+ }
369
+ async removeContact(contactId: MaxId): Promise<boolean> {
370
+ return await this.api.users.removeContact(contactId);
371
+ }
372
+ async importContacts(contacts: ContactInfo[]): Promise<User[]> {
373
+ return await this.api.users.importContacts(contacts);
374
+ }
375
+ getChatId(firstUserId: MaxId, secondUserId: MaxId): MaxId {
376
+ return this.api.users.getChatId(firstUserId, secondUserId);
377
+ }
378
+
379
+ async setTwoFactor(options: Parameters<AuthApi["setTwoFactor"]>[0]): Promise<boolean> {
380
+ return await this.auth.setTwoFactor(options);
381
+ }
382
+ async removeTwoFactor(password: string): Promise<boolean> {
383
+ return await this.auth.removeTwoFactor(password);
384
+ }
385
+ async changePassword(oldPassword: string, newPassword: string): Promise<boolean> {
386
+ return await this.auth.changePassword(oldPassword, newPassword);
387
+ }
388
+ async authorizeQrLogin(qrLink: string): Promise<boolean> {
389
+ return await this.auth.authorizeQrLogin(qrLink);
390
+ }
391
+ async checkTwoFactor(): Promise<boolean> {
392
+ return await this.auth.checkTwoFactor();
393
+ }
394
+ async changeProfile(options: Parameters<AccountApi["changeProfile"]>[0]): Promise<boolean> {
395
+ return await this.account.changeProfile(options);
396
+ }
397
+ async requestProfilePhotoUploadUrl(): Promise<string> {
398
+ return await this.account.requestProfilePhotoUploadUrl();
399
+ }
400
+ async createFolder(
401
+ title: string,
402
+ chatInclude: MaxId[],
403
+ filters: unknown[] = [],
404
+ ): Promise<Record<string, unknown>> {
405
+ return await this.account.createFolder(title, chatInclude, filters);
406
+ }
407
+ async getFolders(folderSync = 0): Promise<Record<string, unknown>> {
408
+ return await this.account.getFolders(folderSync);
409
+ }
410
+ async updateFolder(
411
+ folderId: string,
412
+ title: string,
413
+ chatInclude: MaxId[] = [],
414
+ filters: unknown[] = [],
415
+ options: unknown[] = [],
416
+ ): Promise<Record<string, unknown>> {
417
+ return await this.account.updateFolder(folderId, title, chatInclude, filters, options);
418
+ }
419
+ async deleteFolder(folderId: string): Promise<Record<string, unknown>> {
420
+ return await this.account.deleteFolder(folderId);
421
+ }
422
+ async closeAllSessions(): Promise<boolean> {
423
+ return await this.account.closeAllSessions();
424
+ }
425
+ async logout(): Promise<boolean> {
426
+ return await this.account.logout();
427
+ }
428
+ async getSessions(): Promise<Record<string, unknown>[]> {
429
+ return await this.users.getSessions();
430
+ }
431
+ async getBotInitData(botId: MaxId, chatId?: MaxId | null, startParam?: string | null) {
432
+ return await this.bots.getBotInitData(botId, chatId, startParam);
433
+ }
434
+
435
+ protected abstract rebuildApp(): App<BaseClient>;
436
+ }
437
+
438
+ export class Client extends BaseClient {
439
+ private readonly authFlow: AuthFlow;
440
+
441
+ constructor(options: ClientOptions) {
442
+ const config = resolveConfig({
443
+ phone: options.phone,
444
+ ...(options.workDir !== undefined ? { workDir: options.workDir } : {}),
445
+ ...(options.sessionName !== undefined ? { sessionName: options.sessionName } : {}),
446
+ ...(options.extraConfig !== undefined ? { extra: options.extraConfig } : {}),
447
+ });
448
+ const authFlow =
449
+ options.authFlow ?? new SmsAuthFlow(options.smsCodeProvider, options.passwordProvider);
450
+ const transport = new TcpTransport(config.host, config.port, config.useTls, config.proxy);
451
+ const connection = new ConnectionManager(
452
+ new TcpReader(transport),
453
+ transport,
454
+ new TcpProtocol(),
455
+ );
456
+ const placeholder = new Router<BaseClient>();
457
+ const app = new App(connection, config, authFlow, placeholder);
458
+ super(config, authFlow, app);
459
+ this.authFlow = authFlow;
460
+ app.dispatcher.rootRouter.children.push(this.router);
461
+ }
462
+
463
+ protected rebuildApp(): App<BaseClient> {
464
+ const transport = new TcpTransport(
465
+ this.config.host,
466
+ this.config.port,
467
+ this.config.useTls,
468
+ this.config.proxy,
469
+ );
470
+ const connection = new ConnectionManager(
471
+ new TcpReader(transport),
472
+ transport,
473
+ new TcpProtocol(),
474
+ );
475
+ return new App(connection, this.config, this.authFlow, this.router);
476
+ }
477
+ }
478
+
479
+ export class WebClient extends BaseClient {
480
+ private readonly authFlow: AuthFlow;
481
+
482
+ constructor(options: WebClientOptions = {}) {
483
+ const config = resolveConfig({
484
+ phone: null,
485
+ ...(options.workDir !== undefined ? { workDir: options.workDir } : {}),
486
+ ...(options.sessionName !== undefined ? { sessionName: options.sessionName } : {}),
487
+ web: true,
488
+ ...(options.extraConfig !== undefined ? { extra: options.extraConfig } : {}),
489
+ });
490
+ const authFlow =
491
+ options.authFlow ?? new QrAuthFlow(options.qrHandler, options.passwordProvider);
492
+ const transport = new WebSocketTransport(config.url, config.proxy);
493
+ const connection = new ConnectionManager(new WsReader(transport), transport, new WsProtocol());
494
+ const placeholder = new Router<BaseClient>();
495
+ const app = new App(connection, config, authFlow, placeholder);
496
+ super(config, authFlow, app);
497
+ this.authFlow = authFlow;
498
+ app.dispatcher.rootRouter.children.push(this.router);
499
+ }
500
+
501
+ protected rebuildApp(): App<BaseClient> {
502
+ const transport = new WebSocketTransport(this.config.url, this.config.proxy);
503
+ const connection = new ConnectionManager(new WsReader(transport), transport, new WsProtocol());
504
+ return new App(connection, this.config, this.authFlow, this.router);
505
+ }
506
+ }
package/src/config.ts ADDED
@@ -0,0 +1,161 @@
1
+ import { defaultSyncState, type SessionStore, type SyncOverrides } from "./session/index.ts";
2
+
3
+ export const DeviceType = {
4
+ WEB: "WEB",
5
+ ANDROID: "ANDROID",
6
+ IOS: "IOS",
7
+ DESKTOP: "DESKTOP",
8
+ } as const;
9
+ export type DeviceType = (typeof DeviceType)[keyof typeof DeviceType];
10
+
11
+ export interface UserAgent {
12
+ deviceType: DeviceType;
13
+ appVersion: string;
14
+ osVersion: string;
15
+ timezone: string;
16
+ screen: string;
17
+ locale: string;
18
+ deviceName: string;
19
+ deviceLocale: string;
20
+ pushDeviceType?: string;
21
+ arch?: string;
22
+ buildNumber?: number;
23
+ release?: number;
24
+ headerUserAgent?: string;
25
+ }
26
+
27
+ export interface RegistrationConfig {
28
+ firstName: string;
29
+ lastName?: string | null;
30
+ }
31
+
32
+ export interface ExtraConfig {
33
+ token?: string | null;
34
+ registrationConfig?: RegistrationConfig | null;
35
+ host?: string;
36
+ port?: number;
37
+ url?: string;
38
+ useTls?: boolean;
39
+ proxy?: string | null;
40
+ reconnect?: boolean;
41
+ reconnectDelay?: number;
42
+ deviceId?: string;
43
+ deviceType?: DeviceType;
44
+ userAgent?: UserAgent;
45
+ mtInstanceId?: string;
46
+ requestTimeout?: number;
47
+ logLevel?: "DEBUG" | "INFO" | "WARN" | "ERROR" | "SILENT";
48
+ telemetry?: boolean;
49
+ store?: SessionStore;
50
+ sync?: SyncOverrides;
51
+ }
52
+
53
+ export interface ResolvedConfig {
54
+ phone: string | null;
55
+ workDir: string;
56
+ sessionName: string;
57
+ token: string | null;
58
+ registrationConfig: RegistrationConfig | null;
59
+ host: string;
60
+ port: number;
61
+ url: string;
62
+ useTls: boolean;
63
+ proxy: string | null;
64
+ reconnect: boolean;
65
+ reconnectDelay: number;
66
+ requestTimeout: number;
67
+ logLevel: "DEBUG" | "INFO" | "WARN" | "ERROR" | "SILENT";
68
+ telemetry: boolean;
69
+ store?: SessionStore;
70
+ sync: SyncOverrides;
71
+ device: {
72
+ deviceId: string;
73
+ mtInstanceId: string;
74
+ clientSessionId: number;
75
+ userAgent: UserAgent;
76
+ };
77
+ }
78
+
79
+ const androidAgents: readonly Omit<UserAgent, "appVersion" | "buildNumber">[] = [
80
+ {
81
+ deviceType: DeviceType.ANDROID,
82
+ osVersion: "Android 14",
83
+ timezone: "Europe/Moscow",
84
+ screen: "411dpi 411dpi 1080x2400",
85
+ pushDeviceType: "GCM",
86
+ arch: "arm64-v8a",
87
+ locale: "ru",
88
+ deviceName: "Pixel 8",
89
+ deviceLocale: "ru",
90
+ },
91
+ {
92
+ deviceType: DeviceType.ANDROID,
93
+ osVersion: "Android 14",
94
+ timezone: "Europe/Moscow",
95
+ screen: "425dpi 425dpi 1080x2340",
96
+ pushDeviceType: "GCM",
97
+ arch: "arm64-v8a",
98
+ locale: "ru",
99
+ deviceName: "Samsung SM-S911B",
100
+ deviceLocale: "ru",
101
+ },
102
+ ];
103
+
104
+ export function resolveConfig(options: {
105
+ phone?: string | null;
106
+ workDir?: string;
107
+ sessionName?: string;
108
+ web?: boolean;
109
+ extra?: ExtraConfig;
110
+ }): ResolvedConfig {
111
+ const extra = options.extra ?? {};
112
+ const userAgent = extra.userAgent ?? (options.web ? createWebAgent() : createMobileAgent());
113
+ return {
114
+ phone: options.phone ?? null,
115
+ workDir: options.workDir ?? ".",
116
+ sessionName: options.sessionName ?? "session.db",
117
+ token: extra.token ?? null,
118
+ registrationConfig: extra.registrationConfig ?? null,
119
+ host: extra.host ?? "api.oneme.ru",
120
+ port: extra.port ?? 443,
121
+ url: extra.url ?? "wss://ws-api.oneme.ru/websocket",
122
+ useTls: extra.useTls ?? true,
123
+ proxy: extra.proxy ?? null,
124
+ reconnect: extra.reconnect ?? true,
125
+ reconnectDelay: extra.reconnectDelay ?? 1,
126
+ requestTimeout: extra.requestTimeout ?? 30,
127
+ logLevel: extra.logLevel ?? "INFO",
128
+ telemetry: extra.telemetry ?? true,
129
+ ...(extra.store ? { store: extra.store } : {}),
130
+ sync: extra.sync ?? defaultSyncState(),
131
+ device: {
132
+ deviceId: extra.deviceId ?? crypto.randomUUID(),
133
+ mtInstanceId: extra.mtInstanceId ?? crypto.randomUUID(),
134
+ clientSessionId: Math.floor(Math.random() * 70) + 1,
135
+ userAgent,
136
+ },
137
+ };
138
+ }
139
+
140
+ function createMobileAgent(): UserAgent {
141
+ const base = androidAgents[Math.floor(Math.random() * androidAgents.length)] as Omit<
142
+ UserAgent,
143
+ "appVersion" | "buildNumber"
144
+ >;
145
+ return { ...base, appVersion: "26.14.1", buildNumber: 6686 };
146
+ }
147
+
148
+ function createWebAgent(): UserAgent {
149
+ return {
150
+ deviceType: DeviceType.WEB,
151
+ appVersion: "26.5.5",
152
+ osVersion: "Linux",
153
+ timezone: "Europe/Moscow",
154
+ screen: "1080x1920 1.0x",
155
+ locale: "ru",
156
+ deviceName: "Chrome",
157
+ deviceLocale: "ru",
158
+ headerUserAgent:
159
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
160
+ };
161
+ }