@mtkruto/node 0.1.102 → 0.1.104

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 (35) hide show
  1. package/esm/4_constants.d.ts +1 -1
  2. package/esm/4_constants.js +1 -1
  3. package/esm/client/3_types.d.ts +25 -1
  4. package/esm/client/4_client.d.ts +30 -32
  5. package/esm/client/4_client.js +83 -11
  6. package/esm/storage/0_storage.d.ts +3 -1
  7. package/esm/storage/0_storage.js +7 -0
  8. package/esm/storage/0_utilities.d.ts +2 -1
  9. package/esm/storage/0_utilities.js +63 -0
  10. package/esm/storage/1_storage_indexed_db.d.ts +2 -1
  11. package/esm/storage/1_storage_indexed_db.js +18 -1
  12. package/esm/storage/1_storage_local_storage.d.ts +1 -0
  13. package/esm/storage/1_storage_local_storage.js +16 -0
  14. package/esm/storage/1_storage_memory.d.ts +1 -0
  15. package/esm/storage/1_storage_memory.js +14 -1
  16. package/esm/storage/1_storage_session_storage.d.ts +1 -0
  17. package/esm/storage/1_storage_session_storage.js +16 -0
  18. package/package.json +1 -1
  19. package/script/4_constants.d.ts +1 -1
  20. package/script/4_constants.js +1 -1
  21. package/script/client/3_types.d.ts +25 -1
  22. package/script/client/4_client.d.ts +30 -32
  23. package/script/client/4_client.js +83 -11
  24. package/script/storage/0_storage.d.ts +3 -1
  25. package/script/storage/0_storage.js +7 -0
  26. package/script/storage/0_utilities.d.ts +2 -1
  27. package/script/storage/0_utilities.js +65 -1
  28. package/script/storage/1_storage_indexed_db.d.ts +2 -1
  29. package/script/storage/1_storage_indexed_db.js +17 -0
  30. package/script/storage/1_storage_local_storage.d.ts +1 -0
  31. package/script/storage/1_storage_local_storage.js +16 -0
  32. package/script/storage/1_storage_memory.d.ts +1 -0
  33. package/script/storage/1_storage_memory.js +13 -0
  34. package/script/storage/1_storage_session_storage.d.ts +1 -0
  35. package/script/storage/1_storage_session_storage.js +16 -0
@@ -5,7 +5,7 @@ export declare const PUBLIC_KEYS: PublicKeys;
5
5
  export declare const VECTOR_CONSTRUCTOR = 481674261;
6
6
  export declare const INITIAL_DC: DC;
7
7
  export declare const LAYER = 161;
8
- export declare const APP_VERSION = "MTKruto 0.1.102";
8
+ export declare const APP_VERSION = "MTKruto 0.1.104";
9
9
  export declare const DEVICE_MODEL: string;
10
10
  export declare const LANG_CODE: string;
11
11
  export declare const LANG_PACK = "";
@@ -54,7 +54,7 @@ export const PUBLIC_KEYS = Object.freeze([
54
54
  export const VECTOR_CONSTRUCTOR = 0x1CB5C415;
55
55
  export const INITIAL_DC = "2-test";
56
56
  export const LAYER = 161;
57
- export const APP_VERSION = "MTKruto 0.1.102";
57
+ export const APP_VERSION = "MTKruto 0.1.104";
58
58
  // @ts-ignore: lib
59
59
  export const DEVICE_MODEL = typeof dntShim.Deno === "undefined" ? typeof navigator === "undefined" ? typeof process === "undefined" ? "Unknown" : process.platform + "-" + process.arch : navigator.userAgent.split(" ")[0] : dntShim.Deno.build.os + "-" + dntShim.Deno.build.arch;
60
60
  export const LANG_CODE = typeof navigator === "undefined" ? "en" : navigator.language.split("-")[0];
@@ -1,6 +1,6 @@
1
1
  import { MaybePromise } from "../1_utilities.js";
2
2
  import { functions, types } from "../2_tl.js";
3
- import { CallbackQuery, ChatID, ForceReply, InlineKeyboardMarkup, InlineQuery, Message, MessageEntity, ReplyKeyboardMarkup, ReplyKeyboardRemove } from "../3_types.js";
3
+ import { BotCommandScope, CallbackQuery, ChatID, ForceReply, InlineKeyboardMarkup, InlineQuery, InlineQueryResultButton, Message, MessageEntity, ReplyKeyboardMarkup, ReplyKeyboardRemove } from "../3_types.js";
4
4
  import { With } from "./0_utilities.js";
5
5
  import { ClientPlainParams } from "./2_client_plain.js";
6
6
  export type ParseMode = "HTML" | null;
@@ -194,6 +194,30 @@ export interface SendPollParams {
194
194
  */
195
195
  protectContent?: boolean;
196
196
  }
197
+ export interface DownloadParams {
198
+ /** Size of each download chunk in bytes. */
199
+ chunkSize?: number;
200
+ }
201
+ export interface UploadParams {
202
+ /** The file name to assign. */
203
+ fileName?: string;
204
+ /** Size of each upload chunk in bytes. */
205
+ chunkSize?: number;
206
+ /** Upload abort signal. */
207
+ signal?: AbortSignal | null;
208
+ }
209
+ export interface AnswerInlineQueryParams {
210
+ cacheTime?: number;
211
+ isPersonal?: boolean;
212
+ nextOffset?: string;
213
+ isGallery?: boolean;
214
+ button?: InlineQueryResultButton;
215
+ }
216
+ export interface SetMyCommandsParams {
217
+ languageCode?: string;
218
+ scope?: BotCommandScope;
219
+ }
220
+ export type GetMyCommandsParams = SetMyCommandsParams;
197
221
  export type ConnectionState = "notConnected" | "updating" | "ready";
198
222
  export type AuthorizationState = {
199
223
  authorized: boolean;
@@ -2,11 +2,11 @@ import { MaybePromise } from "../1_utilities.js";
2
2
  import { functions, ReadObject, types } from "../2_tl.js";
3
3
  import { Storage } from "../3_storage.js";
4
4
  import { DC } from "../3_transport.js";
5
- import { BotCommand, BotCommandScope, ChatAction, ChatID, InlineQueryResult, InlineQueryResultButton, Message } from "../3_types.js";
5
+ import { BotCommand, ChatAction, ChatID, InlineQueryResult, Message } from "../3_types.js";
6
6
  import { Migrate } from "../4_errors.js";
7
7
  import { With } from "./0_utilities.js";
8
8
  import { ClientAbstract } from "./1_client_abstract.js";
9
- import { AnswerCallbackQueryParams, AuthorizeUserParams, ClientParams, EditMessageParams, FilterableUpdates, FilterUpdate, ForwardMessagesParams, Handler, ParseMode, SendMessagesParams, SendPollParams, Update } from "./3_types.js";
9
+ import { AnswerCallbackQueryParams, AnswerInlineQueryParams, AuthorizeUserParams, ClientParams, DownloadParams, EditMessageParams, FilterableUpdates, FilterUpdate, ForwardMessagesParams, GetMyCommandsParams, Handler, ParseMode, SendMessagesParams, SendPollParams, SetMyCommandsParams, Update, UploadParams } from "./3_types.js";
10
10
  export declare const getEntity: unique symbol;
11
11
  export declare const getStickerSetName: unique symbol;
12
12
  export declare const handleMigrationError: unique symbol;
@@ -70,6 +70,8 @@ export declare class Client extends ClientAbstract {
70
70
  private initConnection;
71
71
  private lastPropagatedAuthorizationState;
72
72
  private propagateAuthorizationState;
73
+ private selfId;
74
+ private getSelfId;
73
75
  /**
74
76
  * Calls [initConnection](1) and authorizes the client with one of the following:
75
77
  *
@@ -168,9 +170,7 @@ export declare class Client extends ClientAbstract {
168
170
  *
169
171
  * @param fileId The identifier of the file to download.
170
172
  */
171
- download(fileId: string, params?: {
172
- chunkSize?: number;
173
- }): Promise<AsyncGenerator<Uint8Array, void, unknown>>;
173
+ download(fileId: string, params?: DownloadParams): Promise<AsyncGenerator<Uint8Array, void, unknown>>;
174
174
  [getStickerSetName](inputStickerSet: types.InputStickerSetID, hash?: number): Promise<string>;
175
175
  /**
176
176
  * Forward multiple messages.
@@ -223,49 +223,47 @@ export declare class Client extends ClientAbstract {
223
223
  *
224
224
  * @param contents The contents of the file.
225
225
  */
226
- upload(contents: Uint8Array, params?: {
227
- fileName?: string;
228
- chunkSize?: number;
229
- signal?: AbortSignal | null;
230
- }): Promise<types.InputFile | types.InputFileBig>;
231
- setMyCommands(commands: BotCommand[], params?: {
232
- languageCode?: string;
233
- scope?: BotCommandScope;
234
- }): Promise<void>;
235
- getMyCommands(params?: {
236
- languageCode?: string;
237
- scope?: BotCommandScope;
238
- }): Promise<BotCommand[]>;
239
- answerInlineQuery(id: string, results: InlineQueryResult[], params?: {
240
- cacheTime?: number;
241
- isPersonal?: boolean;
242
- nextOffset?: string;
243
- isGallery?: boolean;
244
- button: InlineQueryResultButton;
245
- }): Promise<void>;
226
+ upload(contents: Uint8Array, params?: UploadParams): Promise<types.InputFile | types.InputFileBig>;
227
+ /**
228
+ * Set the bot's commands in the given scope and/or language. Bot-only.
229
+ *
230
+ * @param commands The commands to set.
231
+ */
232
+ setMyCommands(commands: BotCommand[], params?: SetMyCommandsParams): Promise<void>;
233
+ /**
234
+ * Get the bot's commands in the given scope and/or language. Bot-only.
235
+ */
236
+ getMyCommands(params?: GetMyCommandsParams): Promise<BotCommand[]>;
237
+ /**
238
+ * Answer an inline query. Bot-only.
239
+ *
240
+ * @param id The ID of the inline query to answer.
241
+ * @param results The results to answer with.
242
+ */
243
+ answerInlineQuery(id: string, results: InlineQueryResult[], params?: AnswerInlineQueryParams): Promise<void>;
246
244
  private handle;
247
245
  use(handler: Handler): void;
248
246
  branch(predicate: (upd: Update) => MaybePromise<boolean>, trueHandler: Handler, falseHandler: Handler): void;
249
247
  filter<D extends Update>(predicate: (update: Update) => update is D, handler: Handler<D>): void;
250
248
  filter(predicate: (update: Update) => MaybePromise<boolean>, handler: Handler): void;
251
249
  on<T extends keyof Update, F extends keyof NonNullable<Update[T]>>(filter: T extends FilterableUpdates ? T | [T, F, ...F[]] : T, handler: Handler<FilterUpdate<Update, T, F>>): void;
252
- setMyInfo(info: Omit<ConstructorParameters<typeof functions["BotsSetBotInfo"]>[0], "bot">): Promise<void>;
250
+ private setMyInfo;
253
251
  /**
254
- * Use this method to change the bot's description, which is shown in the chat with the bot if the chat is empty.
252
+ * Set the bot's description in the given language. Bot-only.
255
253
  */
256
254
  setMyDescription({ description, languageCode }: {
257
255
  description?: string;
258
256
  languageCode?: string;
259
257
  }): Promise<void>;
260
258
  /**
261
- * Use this method to change the bot's name.
259
+ * Set the bot's name in the given language. Bot-only.
262
260
  */
263
261
  setMyName({ name, languageCode }: {
264
262
  name?: string;
265
263
  languageCode?: string;
266
264
  }): Promise<void>;
267
265
  /**
268
- * Use this method to change the bot's short description, which is shown on the bot's profile page and is sent together with the link when users share the bot.
266
+ * Set the bot's short description in the given language. Bot-only.
269
267
  */
270
268
  setMyShortDescription({ shortDescription: about, languageCode }: {
271
269
  shortDescription?: string;
@@ -273,15 +271,15 @@ export declare class Client extends ClientAbstract {
273
271
  }): Promise<void>;
274
272
  private getMyInfo;
275
273
  /**
276
- * Use this method to get the current bot description for the given user language.
274
+ * Get the bot's description in the given language. Bot-only.
277
275
  */
278
276
  getMyDescription(languageCode?: string): Promise<string>;
279
277
  /**
280
- * Use this method to get the current bot name for the given user language.
278
+ * Set the bot's name in the given language. Bot-only.
281
279
  */
282
280
  getMyName(languageCode?: string): Promise<string>;
283
281
  /**
284
- * Use this method to get the current bot short description for the given user language.
282
+ * Get the bot's short description in the given language. Bot-only.
285
283
  */
286
284
  getMyShortDescription(languageCode?: string): Promise<string>;
287
285
  }
@@ -198,6 +198,12 @@ export class Client extends ClientAbstract {
198
198
  writable: true,
199
199
  value: null
200
200
  });
201
+ Object.defineProperty(this, "selfId", {
202
+ enumerable: true,
203
+ configurable: true,
204
+ writable: true,
205
+ value: null
206
+ });
201
207
  Object.defineProperty(this, "pingLoopStarted", {
202
208
  enumerable: true,
203
209
  configurable: true,
@@ -380,6 +386,12 @@ export class Client extends ClientAbstract {
380
386
  this.lastPropagatedAuthorizationState = authorized;
381
387
  }
382
388
  }
389
+ async getSelfId() {
390
+ if (this.selfId == null) {
391
+ this.selfId = await this.getMe().then((v) => v.id);
392
+ }
393
+ return this.selfId;
394
+ }
383
395
  /**
384
396
  * Calls [initConnection](1) and authorizes the client with one of the following:
385
397
  *
@@ -429,7 +441,8 @@ export class Client extends ClientAbstract {
429
441
  if (typeof params === "string") {
430
442
  while (true) {
431
443
  try {
432
- await this.invoke(new functions.AuthImportBotAuthorization({ apiId: this.apiId, apiHash: this.apiHash, botAuthToken: params, flags: 0 }));
444
+ const auth = await this.invoke(new functions.AuthImportBotAuthorization({ apiId: this.apiId, apiHash: this.apiHash, botAuthToken: params, flags: 0 }));
445
+ this.selfId = Number(auth[as](types.AuthAuthorization).user.id);
433
446
  await this.storage.setAccountType("bot");
434
447
  break;
435
448
  }
@@ -494,11 +507,12 @@ export class Client extends ClientAbstract {
494
507
  while (true) {
495
508
  const code = typeof params.code === "string" ? params.code : await params.code();
496
509
  try {
497
- await this.invoke(new functions.AuthSignIn({
510
+ const auth = await this.invoke(new functions.AuthSignIn({
498
511
  phoneNumber: phone,
499
512
  phoneCode: code,
500
513
  phoneCodeHash: sentCode.phoneCodeHash,
501
514
  }));
515
+ this.selfId = Number(auth[as](types.AuthAuthorization).user.id);
502
516
  await this.storage.setAccountType("user");
503
517
  dAuth("authorized as user");
504
518
  await this.propagateAuthorizationState(true);
@@ -526,7 +540,8 @@ export class Client extends ClientAbstract {
526
540
  try {
527
541
  const password = typeof params.password === "string" ? params.password : await params.password(ap.hint ?? null);
528
542
  const input = await checkPassword(password, ap);
529
- await this.invoke(new functions.AuthCheckPassword({ password: input }));
543
+ const auth = await this.invoke(new functions.AuthCheckPassword({ password: input }));
544
+ this.selfId = Number(auth[as](types.AuthAuthorization).user.id);
530
545
  await this.storage.setAccountType("user");
531
546
  dAuth("authorized as user");
532
547
  await this.propagateAuthorizationState(true);
@@ -986,8 +1001,7 @@ export class Client extends ClientAbstract {
986
1001
  }
987
1002
  }
988
1003
  else if (difference instanceof types.UpdatesDifferenceTooLong) {
989
- // TODO: we actually do now
990
- // stored messages should be invalidated in case we store messages in the future
1004
+ await this.storage.deleteMessages();
991
1005
  state.pts = difference.pts;
992
1006
  dGap("received differenceTooLong");
993
1007
  }
@@ -1481,6 +1495,50 @@ export class Client extends ClientAbstract {
1481
1495
  }
1482
1496
  // TODO: log errors
1483
1497
  async handleUpdate(update) {
1498
+ if (update instanceof types.UpdateShortMessage) {
1499
+ update = new types.UpdateNewMessage({
1500
+ message: new types.Message({
1501
+ out: update.out,
1502
+ mentioned: update.mentioned,
1503
+ mediaUnread: update.mediaUnread,
1504
+ silent: update.silent,
1505
+ id: update.id,
1506
+ fromId: update.out ? new types.PeerUser({ userId: await this.getSelfId().then(BigInt) }) : new types.PeerUser({ userId: update.userId }),
1507
+ peerId: new types.PeerChat({ chatId: update.userId }),
1508
+ message: update.message,
1509
+ date: update.date,
1510
+ fwdFrom: update.fwdFrom,
1511
+ viaBotId: update.viaBotId,
1512
+ replyTo: update.replyTo,
1513
+ entities: update.entities,
1514
+ ttlPeriod: update.ttlPeriod,
1515
+ }),
1516
+ pts: update.pts,
1517
+ ptsCount: update.ptsCount,
1518
+ });
1519
+ }
1520
+ else if (update instanceof types.UpdateShortChatMessage) {
1521
+ update = new types.UpdateNewMessage({
1522
+ message: new types.Message({
1523
+ out: update.out,
1524
+ mentioned: update.mentioned,
1525
+ mediaUnread: update.mediaUnread,
1526
+ silent: update.silent,
1527
+ id: update.id,
1528
+ fromId: new types.PeerUser({ userId: update.fromId }),
1529
+ peerId: new types.PeerChat({ chatId: update.chatId }),
1530
+ fwdFrom: update.fwdFrom,
1531
+ viaBotId: update.viaBotId,
1532
+ replyTo: update.replyTo,
1533
+ date: update.date,
1534
+ message: update.message,
1535
+ entities: update.entities,
1536
+ ttlPeriod: update.ttlPeriod,
1537
+ }),
1538
+ pts: update.pts,
1539
+ ptsCount: update.ptsCount,
1540
+ });
1541
+ }
1484
1542
  if (update instanceof types.UpdateNewMessage || update instanceof types.UpdateNewMessage || update instanceof types.UpdateNewChannelMessage || update instanceof types.UpdateNewChannelMessage) {
1485
1543
  if (update.message instanceof types.Message || update.message instanceof types.MessageService) {
1486
1544
  await this.storage.setMessage(peerToChatId(update.message.peerId), update.message.id, update.message);
@@ -1747,6 +1805,11 @@ export class Client extends ClientAbstract {
1747
1805
  return new types.InputFile({ id: fileId, name, parts: part, md5Checksum: "" });
1748
1806
  }
1749
1807
  }
1808
+ /**
1809
+ * Set the bot's commands in the given scope and/or language. Bot-only.
1810
+ *
1811
+ * @param commands The commands to set.
1812
+ */
1750
1813
  async setMyCommands(commands, params) {
1751
1814
  await this.invoke(new functions.BotsSetBotCommands({
1752
1815
  commands: commands.map((v) => new types.BotCommand(v)),
@@ -1754,6 +1817,9 @@ export class Client extends ClientAbstract {
1754
1817
  scope: await botCommandScopeToTlObject(params?.scope ?? { type: "default" }, this.getInputPeer.bind(this)),
1755
1818
  }));
1756
1819
  }
1820
+ /**
1821
+ * Get the bot's commands in the given scope and/or language. Bot-only.
1822
+ */
1757
1823
  async getMyCommands(params) {
1758
1824
  const commands_ = await this.invoke(new functions.BotsGetBotCommands({
1759
1825
  langCode: params?.languageCode ?? "",
@@ -1761,6 +1827,12 @@ export class Client extends ClientAbstract {
1761
1827
  }));
1762
1828
  return commands_.map((v) => ({ command: v.command, description: v.description }));
1763
1829
  }
1830
+ /**
1831
+ * Answer an inline query. Bot-only.
1832
+ *
1833
+ * @param id The ID of the inline query to answer.
1834
+ * @param results The results to answer with.
1835
+ */
1764
1836
  async answerInlineQuery(id, results, params) {
1765
1837
  await this.invoke(new functions.MessagesSetInlineBotResults({
1766
1838
  queryId: BigInt(id),
@@ -1823,21 +1895,21 @@ export class Client extends ClientAbstract {
1823
1895
  await this.invoke(new functions.BotsSetBotInfo({ bot: new types.InputUserSelf(), ...info }));
1824
1896
  }
1825
1897
  /**
1826
- * Use this method to change the bot's description, which is shown in the chat with the bot if the chat is empty.
1898
+ * Set the bot's description in the given language. Bot-only.
1827
1899
  */
1828
1900
  async setMyDescription({ description, languageCode }) {
1829
1901
  await this.assertBot("setMyDescription");
1830
1902
  await this.setMyInfo({ description, langCode: languageCode ?? "" });
1831
1903
  }
1832
1904
  /**
1833
- * Use this method to change the bot's name.
1905
+ * Set the bot's name in the given language. Bot-only.
1834
1906
  */
1835
1907
  async setMyName({ name, languageCode }) {
1836
1908
  await this.assertBot("setMyName");
1837
1909
  await this.setMyInfo({ name, langCode: languageCode ?? "" });
1838
1910
  }
1839
1911
  /**
1840
- * Use this method to change the bot's short description, which is shown on the bot's profile page and is sent together with the link when users share the bot.
1912
+ * Set the bot's short description in the given language. Bot-only.
1841
1913
  */
1842
1914
  async setMyShortDescription({ shortDescription: about, languageCode }) {
1843
1915
  await this.assertBot("setMyShortDescription");
@@ -1847,21 +1919,21 @@ export class Client extends ClientAbstract {
1847
1919
  return this.invoke(new functions.BotsGetBotInfo({ bot: new types.InputUserSelf(), langCode: languageCode ?? "" }));
1848
1920
  }
1849
1921
  /**
1850
- * Use this method to get the current bot description for the given user language.
1922
+ * Get the bot's description in the given language. Bot-only.
1851
1923
  */
1852
1924
  async getMyDescription(languageCode) {
1853
1925
  await this.assertBot("getMyDescription");
1854
1926
  return await this.getMyInfo(languageCode).then((v) => v.description);
1855
1927
  }
1856
1928
  /**
1857
- * Use this method to get the current bot name for the given user language.
1929
+ * Set the bot's name in the given language. Bot-only.
1858
1930
  */
1859
1931
  async getMyName(languageCode) {
1860
1932
  await this.assertBot("getMyName");
1861
1933
  return await this.getMyInfo(languageCode).then((v) => v.description);
1862
1934
  }
1863
1935
  /**
1864
- * Use this method to get the current bot short description for the given user language.
1936
+ * Get the bot's short description in the given language. Bot-only.
1865
1937
  */
1866
1938
  async getMyShortDescription(languageCode) {
1867
1939
  await this.assertBot("getMyShortDescription");
@@ -1,12 +1,13 @@
1
1
  import { MaybePromise } from "../1_utilities.js";
2
2
  import { TLObject, types } from "../2_tl.js";
3
3
  import { DC } from "../3_transport.js";
4
- export type StorageKeyPart = string | number | bigint | Uint8Array;
4
+ export type StorageKeyPart = string | number | bigint;
5
5
  export declare abstract class Storage {
6
6
  private _authKeyId;
7
7
  abstract init(): MaybePromise<void>;
8
8
  abstract set(key: readonly StorageKeyPart[], value: unknown): MaybePromise<void>;
9
9
  abstract get<T>(key: readonly StorageKeyPart[]): MaybePromise<T | null>;
10
+ abstract getMany<T>(prefix: readonly StorageKeyPart[]): MaybePromise<Generator<[readonly StorageKeyPart[], T]> | AsyncGenerator<[readonly StorageKeyPart[], T]>>;
10
11
  setDc(dc: DC | null): MaybePromise<void>;
11
12
  getDc(): MaybePromise<DC | null>;
12
13
  private resetAuthKeyId;
@@ -24,6 +25,7 @@ export declare abstract class Storage {
24
25
  setState(state: types.UpdatesState): Promise<void>;
25
26
  getState(): Promise<types.UpdatesState | null>;
26
27
  setMessage(chatId: number, messageId: number, message: types.TypeMessage | null): Promise<void>;
28
+ deleteMessages(): Promise<void>;
27
29
  getMessageChat(messageId: number): MaybePromise<number | null>;
28
30
  getMessage(chatId: number, messageId: number): Promise<types.TypeMessage | null>;
29
31
  setChannelPts(channelId: bigint, pts: number): Promise<void>;
@@ -104,6 +104,13 @@ export class Storage {
104
104
  }
105
105
  await this.setTlObject(KPARTS_MESSAGE(chatId, messageId), message);
106
106
  }
107
+ async deleteMessages() {
108
+ const maybePromises = new Array();
109
+ for await (const [k, o] of await this.getMany(["messageRefs"])) {
110
+ maybePromises.push(Promise.all([this.set(k, null), o == null ? Promise.resolve() : this.set(KPARTS_MESSAGE(o, k[1]), null)]).then(() => { }));
111
+ }
112
+ await Promise.all(maybePromises.filter((v) => v instanceof Promise));
113
+ }
107
114
  getMessageChat(messageId) {
108
115
  return this.get(KPARTS_MESSAGE_REF(messageId));
109
116
  }
@@ -10,4 +10,5 @@ export declare enum ValueType {
10
10
  }
11
11
  export declare function toString(value: unknown): string;
12
12
  export declare function fromString<T>(string: string): any;
13
- export declare function fixKey(key: StorageKeyPart[]): (string | number | Uint8Array)[];
13
+ export declare function fixKey(key: readonly StorageKeyPart[]): (string | number)[];
14
+ export declare function getPrefixKeyRange(prefix: any): IDBKeyRange;
@@ -60,3 +60,66 @@ export function fromString(string) {
60
60
  export function fixKey(key) {
61
61
  return key.map((v) => typeof v === "bigint" ? String(v) : v);
62
62
  }
63
+ // Source: https://gist.github.com/inexorabletash/5462871
64
+ // deno-lint-ignore no-explicit-any
65
+ export function getPrefixKeyRange(prefix) {
66
+ // Ensure prefix is a valid key itself:
67
+ if (indexedDB.cmp(prefix, prefix) !== 0)
68
+ throw new TypeError();
69
+ const upperKey = successor(prefix);
70
+ if (upperKey === undefined)
71
+ return IDBKeyRange.lowerBound(prefix);
72
+ return IDBKeyRange.bound(prefix, upperKey, false, true);
73
+ }
74
+ const MAX_DATE_VALUE = 8640000000000000;
75
+ const UPPER_BOUND = {
76
+ NUMBER: new Date(-MAX_DATE_VALUE),
77
+ DATE: "",
78
+ STRING: [],
79
+ ARRAY: undefined,
80
+ };
81
+ // deno-lint-ignore no-explicit-any
82
+ function successor(key) {
83
+ if (typeof key === "number") {
84
+ if (key === Infinity)
85
+ return UPPER_BOUND.NUMBER;
86
+ if (key === -Infinity)
87
+ return -Number.MAX_VALUE;
88
+ if (key === 0)
89
+ return Number.MIN_VALUE;
90
+ let epsilon = Math.abs(key);
91
+ while (key + epsilon / 2 !== key)
92
+ epsilon = epsilon / 2;
93
+ return key + epsilon;
94
+ }
95
+ if (key instanceof Date) {
96
+ if (key.valueOf() + 1 > MAX_DATE_VALUE)
97
+ return UPPER_BOUND.DATE;
98
+ return new Date(key.valueOf() + 1);
99
+ }
100
+ if (typeof key === "string") {
101
+ let len = key.length;
102
+ while (len > 0) {
103
+ const head = key.substring(0, len - 1), tail = key.charCodeAt(len - 1);
104
+ if (tail !== 0xffff)
105
+ return head + String.fromCharCode(tail + 1);
106
+ key = head;
107
+ --len;
108
+ }
109
+ return UPPER_BOUND.STRING;
110
+ }
111
+ if (Array.isArray(key)) {
112
+ key = key.slice(); // Operate on a copy.
113
+ let len = key.length;
114
+ while (len > 0) {
115
+ const tail = successor(key.pop());
116
+ if (tail !== undefined) {
117
+ key.push(tail);
118
+ return key;
119
+ }
120
+ --len;
121
+ }
122
+ return UPPER_BOUND.ARRAY;
123
+ }
124
+ throw new TypeError();
125
+ }
@@ -5,5 +5,6 @@ export declare class StorageIndexedDB extends Storage {
5
5
  constructor(name: string);
6
6
  init(): Promise<void>;
7
7
  set(k: StorageKeyPart[], v: unknown): Promise<void>;
8
- get<T>(k: StorageKeyPart[]): Promise<T | null>;
8
+ get<T>(k: readonly StorageKeyPart[]): Promise<T | null>;
9
+ getMany<T>(prefix: readonly StorageKeyPart[]): AsyncGenerator<[readonly StorageKeyPart[], T], void, unknown>;
9
10
  }
@@ -1,5 +1,5 @@
1
1
  import { Storage } from "./0_storage.js";
2
- import { fixKey } from "./0_utilities.js";
2
+ import { fixKey, getPrefixKeyRange } from "./0_utilities.js";
3
3
  const VERSION = 1;
4
4
  const KV_OBJECT_STORE = "kv";
5
5
  export class StorageIndexedDB extends Storage {
@@ -72,4 +72,21 @@ export class StorageIndexedDB extends Storage {
72
72
  };
73
73
  });
74
74
  }
75
+ async *getMany(prefix) {
76
+ if (!this.database) {
77
+ throw new Error("Not initialized");
78
+ }
79
+ const keys = await new Promise((res, rej) => {
80
+ const tx = this.database.transaction(KV_OBJECT_STORE, "readonly")
81
+ .objectStore(KV_OBJECT_STORE)
82
+ .getAllKeys(getPrefixKeyRange(prefix));
83
+ tx.onerror = rej;
84
+ tx.onsuccess = () => {
85
+ res(tx.result);
86
+ };
87
+ });
88
+ for (const key of keys) {
89
+ yield [key, await this.get(key)];
90
+ }
91
+ }
75
92
  }
@@ -5,5 +5,6 @@ export declare class StorageLocalStorage extends Storage implements Storage {
5
5
  constructor(prefix: string);
6
6
  init(): void;
7
7
  get(key_: readonly StorageKeyPart[]): any;
8
+ getMany<T>(prefix: readonly StorageKeyPart[]): Generator<[readonly StorageKeyPart[], T], void, unknown>;
8
9
  set(key_: readonly StorageKeyPart[], value: unknown): MaybePromise<void>;
9
10
  }
@@ -31,6 +31,22 @@ export class StorageLocalStorage extends Storage {
31
31
  return null;
32
32
  }
33
33
  }
34
+ *getMany(prefix) {
35
+ for (let [key, value] of Object.entries(localStorage)) {
36
+ if (key.startsWith(this.prefix)) {
37
+ key = key.slice(this.prefix.length);
38
+ }
39
+ const parts = fromString(key);
40
+ if (Array.isArray(parts)) {
41
+ for (const [i, p] of prefix.entries()) {
42
+ if (toString(p) != toString(parts[i])) {
43
+ continue;
44
+ }
45
+ yield [parts, fromString(value)];
46
+ }
47
+ }
48
+ }
49
+ }
34
50
  set(key_, value) {
35
51
  const key = this.prefix + toString(key_);
36
52
  if (value != null) {
@@ -4,5 +4,6 @@ export declare class StorageMemory extends Storage implements Storage {
4
4
  protected map: Map<string, unknown>;
5
5
  init(): void;
6
6
  get<T>(key: readonly StorageKeyPart[]): NonNullable<T> | null;
7
+ getMany<T>(prefix: readonly StorageKeyPart[]): Generator<[readonly StorageKeyPart[], T], void, unknown>;
7
8
  set(key_: readonly StorageKeyPart[], value: unknown): MaybePromise<void>;
8
9
  }
@@ -1,5 +1,5 @@
1
1
  import { Storage } from "./0_storage.js";
2
- import { toString } from "./0_utilities.js";
2
+ import { fromString, toString } from "./0_utilities.js";
3
3
  export class StorageMemory extends Storage {
4
4
  constructor() {
5
5
  super(...arguments);
@@ -15,6 +15,19 @@ export class StorageMemory extends Storage {
15
15
  get(key) {
16
16
  return this.map.get(toString(key)) ?? null;
17
17
  }
18
+ *getMany(prefix) {
19
+ for (const [key, value] of this.map.entries()) {
20
+ const parts = fromString(key);
21
+ if (Array.isArray(parts)) {
22
+ for (const [i, p] of prefix.entries()) {
23
+ if (toString(p) != toString(parts[i])) {
24
+ continue;
25
+ }
26
+ yield [parts, value];
27
+ }
28
+ }
29
+ }
30
+ }
18
31
  set(key_, value) {
19
32
  const key = toString(key_);
20
33
  if (value != null) {
@@ -5,5 +5,6 @@ export declare class StorageSessionStorage extends Storage implements Storage {
5
5
  constructor(prefix: string);
6
6
  init(): void;
7
7
  get(key_: readonly StorageKeyPart[]): any;
8
+ getMany<T>(prefix: readonly StorageKeyPart[]): Generator<[readonly StorageKeyPart[], T], void, unknown>;
8
9
  set(key_: readonly StorageKeyPart[], value: unknown): MaybePromise<void>;
9
10
  }
@@ -31,6 +31,22 @@ export class StorageSessionStorage extends Storage {
31
31
  return null;
32
32
  }
33
33
  }
34
+ *getMany(prefix) {
35
+ for (let [key, value] of Object.entries(localStorage)) {
36
+ if (key.startsWith(this.prefix)) {
37
+ key = key.slice(this.prefix.length);
38
+ }
39
+ const parts = fromString(key);
40
+ if (Array.isArray(parts)) {
41
+ for (const [i, p] of prefix.entries()) {
42
+ if (toString(p) != toString(parts[i])) {
43
+ continue;
44
+ }
45
+ yield [parts, fromString(value)];
46
+ }
47
+ }
48
+ }
49
+ }
34
50
  set(key_, value) {
35
51
  const key = this.prefix + toString(key_);
36
52
  if (value != null) {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "module": "./esm/mod.js",
3
3
  "main": "./script/mod.js",
4
4
  "name": "@mtkruto/node",
5
- "version": "0.1.102",
5
+ "version": "0.1.104",
6
6
  "description": "MTKruto for Node.js",
7
7
  "author": "Roj <rojvv@icloud.com>",
8
8
  "license": "LGPL-3.0-or-later",
@@ -5,7 +5,7 @@ export declare const PUBLIC_KEYS: PublicKeys;
5
5
  export declare const VECTOR_CONSTRUCTOR = 481674261;
6
6
  export declare const INITIAL_DC: DC;
7
7
  export declare const LAYER = 161;
8
- export declare const APP_VERSION = "MTKruto 0.1.102";
8
+ export declare const APP_VERSION = "MTKruto 0.1.104";
9
9
  export declare const DEVICE_MODEL: string;
10
10
  export declare const LANG_CODE: string;
11
11
  export declare const LANG_PACK = "";