@mtcute/core 0.8.0 → 0.9.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 (60) hide show
  1. package/LICENSE +1 -1
  2. package/cjs/highlevel/methods/files/upload-file.js +9 -0
  3. package/cjs/highlevel/methods/files/upload-file.js.map +1 -1
  4. package/cjs/highlevel/types/files/utils.d.ts +9 -6
  5. package/cjs/highlevel/types/files/utils.js.map +1 -1
  6. package/cjs/network/network-manager.js +1 -1
  7. package/cjs/storage/index.d.ts +1 -0
  8. package/cjs/storage/index.js +1 -0
  9. package/cjs/storage/index.js.map +1 -1
  10. package/cjs/storage/sqlite/driver.d.ts +24 -0
  11. package/cjs/storage/sqlite/driver.js +129 -0
  12. package/cjs/storage/sqlite/driver.js.map +1 -0
  13. package/cjs/storage/sqlite/index.d.ts +17 -0
  14. package/cjs/storage/sqlite/index.js +35 -0
  15. package/cjs/storage/sqlite/index.js.map +1 -0
  16. package/cjs/storage/sqlite/repository/auth-keys.d.ts +20 -0
  17. package/cjs/storage/sqlite/repository/auth-keys.js +68 -0
  18. package/cjs/storage/sqlite/repository/auth-keys.js.map +1 -0
  19. package/cjs/storage/sqlite/repository/kv.d.ts +14 -0
  20. package/cjs/storage/sqlite/repository/kv.js +96 -0
  21. package/cjs/storage/sqlite/repository/kv.js.map +1 -0
  22. package/cjs/storage/sqlite/repository/peers.d.ts +16 -0
  23. package/cjs/storage/sqlite/repository/peers.js +77 -0
  24. package/cjs/storage/sqlite/repository/peers.js.map +1 -0
  25. package/cjs/storage/sqlite/repository/ref-messages.d.ts +16 -0
  26. package/cjs/storage/sqlite/repository/ref-messages.js +49 -0
  27. package/cjs/storage/sqlite/repository/ref-messages.js.map +1 -0
  28. package/cjs/storage/sqlite/types.d.ts +18 -0
  29. package/cjs/storage/sqlite/types.js +3 -0
  30. package/cjs/storage/sqlite/types.js.map +1 -0
  31. package/esm/highlevel/methods/files/upload-file.js +9 -0
  32. package/esm/highlevel/methods/files/upload-file.js.map +1 -1
  33. package/esm/highlevel/types/files/utils.d.ts +9 -6
  34. package/esm/highlevel/types/files/utils.js.map +1 -1
  35. package/esm/network/network-manager.js +1 -1
  36. package/esm/storage/index.d.ts +1 -0
  37. package/esm/storage/index.js +1 -0
  38. package/esm/storage/index.js.map +1 -1
  39. package/esm/storage/sqlite/driver.d.ts +24 -0
  40. package/esm/storage/sqlite/driver.js +125 -0
  41. package/esm/storage/sqlite/driver.js.map +1 -0
  42. package/esm/storage/sqlite/index.d.ts +17 -0
  43. package/esm/storage/sqlite/index.js +17 -0
  44. package/esm/storage/sqlite/index.js.map +1 -0
  45. package/esm/storage/sqlite/repository/auth-keys.d.ts +20 -0
  46. package/esm/storage/sqlite/repository/auth-keys.js +64 -0
  47. package/esm/storage/sqlite/repository/auth-keys.js.map +1 -0
  48. package/esm/storage/sqlite/repository/kv.d.ts +14 -0
  49. package/esm/storage/sqlite/repository/kv.js +92 -0
  50. package/esm/storage/sqlite/repository/kv.js.map +1 -0
  51. package/esm/storage/sqlite/repository/peers.d.ts +16 -0
  52. package/esm/storage/sqlite/repository/peers.js +73 -0
  53. package/esm/storage/sqlite/repository/peers.js.map +1 -0
  54. package/esm/storage/sqlite/repository/ref-messages.d.ts +16 -0
  55. package/esm/storage/sqlite/repository/ref-messages.js +45 -0
  56. package/esm/storage/sqlite/repository/ref-messages.js.map +1 -0
  57. package/esm/storage/sqlite/types.d.ts +18 -0
  58. package/esm/storage/sqlite/types.js +2 -0
  59. package/esm/storage/sqlite/types.js.map +1 -0
  60. package/package.json +4 -4
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SqliteKeyValueRepository = void 0;
4
+ const reader_js_1 = require("@mtcute/tl/binary/reader.js");
5
+ const writer_js_1 = require("@mtcute/tl/binary/writer.js");
6
+ const current_user_js_1 = require("../../../highlevel/storage/service/current-user.js");
7
+ const updates_js_1 = require("../../../highlevel/storage/service/updates.js");
8
+ const default_dcs_js_1 = require("../../service/default-dcs.js");
9
+ class SqliteKeyValueRepository {
10
+ constructor(_driver) {
11
+ this._driver = _driver;
12
+ _driver.registerMigration('kv', 1, (db) => {
13
+ db.exec(`
14
+ create table key_value (
15
+ key text primary key,
16
+ value blob not null
17
+ );
18
+ `);
19
+ });
20
+ _driver.onLoad((db) => {
21
+ this._get = db.prepare('select value from key_value where key = ?');
22
+ this._set = db.prepare('insert or replace into key_value (key, value) values (?, ?)');
23
+ this._del = db.prepare('delete from key_value where key = ?');
24
+ this._delAll = db.prepare('delete from key_value');
25
+ });
26
+ // awkward dependencies, unsafe code, awful crutches
27
+ // all in the name of backwards compatibility
28
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any */
29
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-floating-promises */
30
+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
31
+ _driver.registerLegacyMigration('kv', (db) => {
32
+ // fetch all values from the old table
33
+ const all = db.prepare('select key, value from kv').all();
34
+ const obj = {};
35
+ for (const { key, value } of all) {
36
+ obj[key] = JSON.parse(value);
37
+ }
38
+ db.exec('drop table kv');
39
+ // lol
40
+ const options = {
41
+ driver: this._driver,
42
+ readerMap: reader_js_1.__tlReaderMap,
43
+ writerMap: writer_js_1.__tlWriterMap,
44
+ // eslint-disable-next-line dot-notation
45
+ log: this._driver['_log'],
46
+ };
47
+ if (obj.self) {
48
+ new current_user_js_1.CurrentUserService(this, options).store({
49
+ userId: obj.self.userId,
50
+ isBot: obj.self.isBot,
51
+ isPremium: false,
52
+ usernames: [],
53
+ });
54
+ }
55
+ if (obj.pts) {
56
+ const svc = new updates_js_1.UpdatesStateService(this, options);
57
+ svc.setPts(obj.pts);
58
+ if (obj.qts)
59
+ svc.setQts(obj.qts);
60
+ if (obj.date)
61
+ svc.setDate(obj.date);
62
+ if (obj.seq)
63
+ svc.setSeq(obj.seq);
64
+ // also fetch channel states. they were moved to kv from a separate table
65
+ const channels = db.prepare('select * from pts').all();
66
+ for (const channel of channels) {
67
+ svc.setChannelPts(channel.channel_id, channel.pts);
68
+ }
69
+ }
70
+ db.exec('drop table pts');
71
+ if (obj.def_dc) {
72
+ new default_dcs_js_1.DefaultDcsService(this, options).store(obj.def_dc);
73
+ }
74
+ });
75
+ /* eslint-enable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any */
76
+ /* eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-floating-promises */
77
+ /* eslint-enable @typescript-eslint/no-unsafe-argument */
78
+ }
79
+ set(key, value) {
80
+ this._driver._writeLater(this._set, [key, value]);
81
+ }
82
+ get(key) {
83
+ const res = this._get.get(key);
84
+ if (!res)
85
+ return null;
86
+ return res.value;
87
+ }
88
+ delete(key) {
89
+ this._del.run(key);
90
+ }
91
+ deleteAll() {
92
+ this._delAll.run();
93
+ }
94
+ }
95
+ exports.SqliteKeyValueRepository = SqliteKeyValueRepository;
96
+ //# sourceMappingURL=kv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kv.js","sourceRoot":"","sources":["../../../../../src/storage/sqlite/repository/kv.ts"],"names":[],"mappings":"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","sourcesContent":["import { __tlReaderMap } from '@mtcute/tl/binary/reader.js'\nimport { __tlWriterMap } from '@mtcute/tl/binary/writer.js'\n\nimport { CurrentUserService } from '../../../highlevel/storage/service/current-user.js'\nimport { UpdatesStateService } from '../../../highlevel/storage/service/updates.js'\nimport { IKeyValueRepository } from '../../repository/key-value.js'\nimport { ServiceOptions } from '../../service/base.js'\nimport { DefaultDcsService } from '../../service/default-dcs.js'\nimport { BaseSqliteStorageDriver } from '../driver.js'\nimport { ISqliteStatement } from '../types.js'\n\ninterface KeyValueDto {\n key: string\n value: Uint8Array\n}\n\nexport class SqliteKeyValueRepository implements IKeyValueRepository {\n constructor(readonly _driver: BaseSqliteStorageDriver) {\n _driver.registerMigration('kv', 1, (db) => {\n db.exec(`\n create table key_value (\n key text primary key,\n value blob not null\n );\n `)\n })\n _driver.onLoad((db) => {\n this._get = db.prepare('select value from key_value where key = ?')\n this._set = db.prepare('insert or replace into key_value (key, value) values (?, ?)')\n this._del = db.prepare('delete from key_value where key = ?')\n this._delAll = db.prepare('delete from key_value')\n })\n\n // awkward dependencies, unsafe code, awful crutches\n // all in the name of backwards compatibility\n /* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any */\n /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-floating-promises */\n /* eslint-disable @typescript-eslint/no-unsafe-argument */\n _driver.registerLegacyMigration('kv', (db) => {\n // fetch all values from the old table\n const all = db.prepare('select key, value from kv').all() as { key: string; value: string }[]\n const obj: Record<string, any> = {}\n\n for (const { key, value } of all) {\n obj[key] = JSON.parse(value)\n }\n\n db.exec('drop table kv')\n\n // lol\n const options: ServiceOptions = {\n driver: this._driver,\n readerMap: __tlReaderMap,\n writerMap: __tlWriterMap,\n // eslint-disable-next-line dot-notation\n log: this._driver['_log'],\n }\n\n if (obj.self) {\n new CurrentUserService(this, options).store({\n userId: obj.self.userId,\n isBot: obj.self.isBot,\n isPremium: false,\n usernames: [],\n })\n }\n\n if (obj.pts) {\n const svc = new UpdatesStateService(this, options)\n svc.setPts(obj.pts)\n if (obj.qts) svc.setQts(obj.qts)\n if (obj.date) svc.setDate(obj.date)\n if (obj.seq) svc.setSeq(obj.seq)\n\n // also fetch channel states. they were moved to kv from a separate table\n const channels = db.prepare('select * from pts').all() as any[]\n\n for (const channel of channels) {\n svc.setChannelPts(channel.channel_id, channel.pts)\n }\n }\n db.exec('drop table pts')\n\n if (obj.def_dc) {\n new DefaultDcsService(this, options).store(obj.def_dc)\n }\n })\n /* eslint-enable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any */\n /* eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-floating-promises */\n /* eslint-enable @typescript-eslint/no-unsafe-argument */\n }\n\n private _set!: ISqliteStatement\n set(key: string, value: Uint8Array): void {\n this._driver._writeLater(this._set, [key, value])\n }\n\n private _get!: ISqliteStatement\n get(key: string): Uint8Array | null {\n const res = this._get.get(key)\n if (!res) return null\n\n return (res as KeyValueDto).value\n }\n\n private _del!: ISqliteStatement\n delete(key: string): void {\n this._del.run(key)\n }\n\n private _delAll!: ISqliteStatement\n deleteAll(): void {\n this._delAll.run()\n }\n}\n"]}
@@ -0,0 +1,16 @@
1
+ import { IPeersRepository } from '../../../highlevel/storage/repository/peers.js';
2
+ import { BaseSqliteStorageDriver } from '../driver.js';
3
+ export declare class SqlitePeersRepository implements IPeersRepository {
4
+ readonly _driver: BaseSqliteStorageDriver;
5
+ constructor(_driver: BaseSqliteStorageDriver);
6
+ private _store;
7
+ store(peer: IPeersRepository.PeerInfo): void;
8
+ private _getById;
9
+ getById(id: number): IPeersRepository.PeerInfo | null;
10
+ private _getByUsername;
11
+ getByUsername(username: string): IPeersRepository.PeerInfo | null;
12
+ private _getByPhone;
13
+ getByPhone(phone: string): IPeersRepository.PeerInfo | null;
14
+ private _delAll;
15
+ deleteAll(): void;
16
+ }
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SqlitePeersRepository = void 0;
4
+ function mapPeerDto(dto) {
5
+ return {
6
+ id: dto.id,
7
+ accessHash: dto.hash,
8
+ usernames: JSON.parse(dto.usernames),
9
+ updated: dto.updated,
10
+ phone: dto.phone || undefined,
11
+ complete: dto.complete,
12
+ };
13
+ }
14
+ class SqlitePeersRepository {
15
+ constructor(_driver) {
16
+ this._driver = _driver;
17
+ _driver.registerMigration('peers', 1, (db) => {
18
+ db.exec(`
19
+ create table peers (
20
+ id integer primary key,
21
+ hash text not null,
22
+ usernames json not null,
23
+ updated integer not null,
24
+ phone text,
25
+ complete blob
26
+ );
27
+ create index idx_peers_usernames on peers (usernames);
28
+ create index idx_peers_phone on peers (phone);
29
+ `);
30
+ });
31
+ _driver.onLoad((db) => {
32
+ this._store = db.prepare('insert or replace into peers (id, hash, usernames, updated, phone, complete) values (?, ?, ?, ?, ?, ?)');
33
+ this._getById = db.prepare('select * from peers where id = ?');
34
+ this._getByUsername = db.prepare('select * from peers where exists (select 1 from json_each(usernames) where value = ?)');
35
+ this._getByPhone = db.prepare('select * from peers where phone = ?');
36
+ this._delAll = db.prepare('delete from peers');
37
+ });
38
+ _driver.registerLegacyMigration('peers', (db) => {
39
+ // not too important information, just drop the table
40
+ db.exec('drop table entities');
41
+ });
42
+ }
43
+ store(peer) {
44
+ this._driver._writeLater(this._store, [
45
+ peer.id,
46
+ peer.accessHash,
47
+ // add commas to make it easier to search with LIKE
48
+ JSON.stringify(peer.usernames),
49
+ peer.updated,
50
+ peer.phone,
51
+ peer.complete,
52
+ ]);
53
+ }
54
+ getById(id) {
55
+ const row = this._getById.get(id);
56
+ if (!row)
57
+ return null;
58
+ return mapPeerDto(row);
59
+ }
60
+ getByUsername(username) {
61
+ const row = this._getByUsername.get(username);
62
+ if (!row)
63
+ return null;
64
+ return mapPeerDto(row);
65
+ }
66
+ getByPhone(phone) {
67
+ const row = this._getByPhone.get(phone);
68
+ if (!row)
69
+ return null;
70
+ return mapPeerDto(row);
71
+ }
72
+ deleteAll() {
73
+ this._delAll.run();
74
+ }
75
+ }
76
+ exports.SqlitePeersRepository = SqlitePeersRepository;
77
+ //# sourceMappingURL=peers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"peers.js","sourceRoot":"","sources":["../../../../../src/storage/sqlite/repository/peers.ts"],"names":[],"mappings":";;;AAcA,SAAS,UAAU,CAAC,GAAY;IAC5B,OAAO;QACH,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,UAAU,EAAE,GAAG,CAAC,IAAI;QACpB,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAa;QAChD,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,SAAS;QAC7B,QAAQ,EAAE,GAAG,CAAC,QAAQ;KACzB,CAAA;AACL,CAAC;AAED,MAAa,qBAAqB;IAC9B,YAAqB,OAAgC;QAAhC,YAAO,GAAP,OAAO,CAAyB;QACjD,OAAO,CAAC,iBAAiB,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE;YACzC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;aAWP,CAAC,CAAA;QACN,CAAC,CAAC,CAAA;QACF,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE;YAClB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,OAAO,CACpB,wGAAwG,CAC3G,CAAA;YAED,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAA;YAC9D,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,OAAO,CAC5B,uFAAuF,CAC1F,CAAA;YACD,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC,OAAO,CAAC,qCAAqC,CAAC,CAAA;YAEpE,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAA;QAClD,CAAC,CAAC,CAAA;QACF,OAAO,CAAC,uBAAuB,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE;YAC5C,qDAAqD;YACrD,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAA;QAClC,CAAC,CAAC,CAAA;IACN,CAAC;IAGD,KAAK,CAAC,IAA+B;QACjC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE;YAClC,IAAI,CAAC,EAAE;YACP,IAAI,CAAC,UAAU;YACf,mDAAmD;YACnD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC;YAC9B,IAAI,CAAC,OAAO;YACZ,IAAI,CAAC,KAAK;YACV,IAAI,CAAC,QAAQ;SAChB,CAAC,CAAA;IACN,CAAC;IAGD,OAAO,CAAC,EAAU;QACd,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACjC,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAA;QAErB,OAAO,UAAU,CAAC,GAAc,CAAC,CAAA;IACrC,CAAC;IAGD,aAAa,CAAC,QAAgB;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QAC7C,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAA;QAErB,OAAO,UAAU,CAAC,GAAc,CAAC,CAAA;IACrC,CAAC;IAGD,UAAU,CAAC,KAAa;QACpB,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACvC,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAA;QAErB,OAAO,UAAU,CAAC,GAAc,CAAC,CAAA;IACrC,CAAC;IAGD,SAAS;QACL,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAA;IACtB,CAAC;CACJ;AA5ED,sDA4EC","sourcesContent":["import { IPeersRepository } from '../../../highlevel/storage/repository/peers.js'\nimport { BaseSqliteStorageDriver } from '../driver.js'\nimport { ISqliteStatement } from '../types.js'\n\ninterface PeerDto {\n id: number\n hash: string\n usernames: string\n updated: number\n phone: string | null\n // eslint-disable-next-line no-restricted-globals\n complete: Buffer\n}\n\nfunction mapPeerDto(dto: PeerDto): IPeersRepository.PeerInfo {\n return {\n id: dto.id,\n accessHash: dto.hash,\n usernames: JSON.parse(dto.usernames) as string[],\n updated: dto.updated,\n phone: dto.phone || undefined,\n complete: dto.complete,\n }\n}\n\nexport class SqlitePeersRepository implements IPeersRepository {\n constructor(readonly _driver: BaseSqliteStorageDriver) {\n _driver.registerMigration('peers', 1, (db) => {\n db.exec(`\n create table peers (\n id integer primary key,\n hash text not null,\n usernames json not null,\n updated integer not null,\n phone text,\n complete blob\n );\n create index idx_peers_usernames on peers (usernames);\n create index idx_peers_phone on peers (phone);\n `)\n })\n _driver.onLoad((db) => {\n this._store = db.prepare(\n 'insert or replace into peers (id, hash, usernames, updated, phone, complete) values (?, ?, ?, ?, ?, ?)',\n )\n\n this._getById = db.prepare('select * from peers where id = ?')\n this._getByUsername = db.prepare(\n 'select * from peers where exists (select 1 from json_each(usernames) where value = ?)',\n )\n this._getByPhone = db.prepare('select * from peers where phone = ?')\n\n this._delAll = db.prepare('delete from peers')\n })\n _driver.registerLegacyMigration('peers', (db) => {\n // not too important information, just drop the table\n db.exec('drop table entities')\n })\n }\n\n private _store!: ISqliteStatement\n store(peer: IPeersRepository.PeerInfo): void {\n this._driver._writeLater(this._store, [\n peer.id,\n peer.accessHash,\n // add commas to make it easier to search with LIKE\n JSON.stringify(peer.usernames),\n peer.updated,\n peer.phone,\n peer.complete,\n ])\n }\n\n private _getById!: ISqliteStatement\n getById(id: number): IPeersRepository.PeerInfo | null {\n const row = this._getById.get(id)\n if (!row) return null\n\n return mapPeerDto(row as PeerDto)\n }\n\n private _getByUsername!: ISqliteStatement\n getByUsername(username: string): IPeersRepository.PeerInfo | null {\n const row = this._getByUsername.get(username)\n if (!row) return null\n\n return mapPeerDto(row as PeerDto)\n }\n\n private _getByPhone!: ISqliteStatement\n getByPhone(phone: string): IPeersRepository.PeerInfo | null {\n const row = this._getByPhone.get(phone)\n if (!row) return null\n\n return mapPeerDto(row as PeerDto)\n }\n\n private _delAll!: ISqliteStatement\n deleteAll(): void {\n this._delAll.run()\n }\n}\n"]}
@@ -0,0 +1,16 @@
1
+ import { IReferenceMessagesRepository } from '@mtcute/core';
2
+ import { BaseSqliteStorageDriver } from '../driver.js';
3
+ export declare class SqliteRefMessagesRepository implements IReferenceMessagesRepository {
4
+ readonly _driver: BaseSqliteStorageDriver;
5
+ constructor(_driver: BaseSqliteStorageDriver);
6
+ private _store;
7
+ store(peerId: number, chatId: number, msgId: number): void;
8
+ private _getByPeer;
9
+ getByPeer(peerId: number): [number, number] | null;
10
+ private _del;
11
+ delete(chatId: number, msgIds: number[]): void;
12
+ private _delByPeer;
13
+ deleteByPeer(peerId: number): void;
14
+ private _delAll;
15
+ deleteAll(): void;
16
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SqliteRefMessagesRepository = void 0;
4
+ class SqliteRefMessagesRepository {
5
+ constructor(_driver) {
6
+ this._driver = _driver;
7
+ _driver.registerMigration('ref_messages', 1, (db) => {
8
+ db.exec(`
9
+ create table if not exists message_refs (
10
+ peer_id integer not null,
11
+ chat_id integer not null,
12
+ msg_id integer not null
13
+ );
14
+ create index if not exists idx_message_refs_peer on message_refs (peer_id);
15
+ create index if not exists idx_message_refs on message_refs (chat_id, msg_id);
16
+ `);
17
+ });
18
+ _driver.onLoad(() => {
19
+ this._store = this._driver.db.prepare('insert or replace into message_refs (peer_id, chat_id, msg_id) values (?, ?, ?)');
20
+ this._getByPeer = this._driver.db.prepare('select chat_id, msg_id from message_refs where peer_id = ?');
21
+ this._del = this._driver.db.prepare('delete from message_refs where chat_id = ? and msg_id = ?');
22
+ this._delByPeer = this._driver.db.prepare('delete from message_refs where peer_id = ?');
23
+ this._delAll = this._driver.db.prepare('delete from message_refs');
24
+ });
25
+ }
26
+ store(peerId, chatId, msgId) {
27
+ this._store.run(peerId, chatId, msgId);
28
+ }
29
+ getByPeer(peerId) {
30
+ const res = this._getByPeer.get(peerId);
31
+ if (!res)
32
+ return null;
33
+ const res_ = res;
34
+ return [res_.chat_id, res_.msg_id];
35
+ }
36
+ delete(chatId, msgIds) {
37
+ for (const msgId of msgIds) {
38
+ this._driver._writeLater(this._del, [chatId, msgId]);
39
+ }
40
+ }
41
+ deleteByPeer(peerId) {
42
+ this._delByPeer.run(peerId);
43
+ }
44
+ deleteAll() {
45
+ this._delAll.run();
46
+ }
47
+ }
48
+ exports.SqliteRefMessagesRepository = SqliteRefMessagesRepository;
49
+ //# sourceMappingURL=ref-messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ref-messages.js","sourceRoot":"","sources":["../../../../../src/storage/sqlite/repository/ref-messages.ts"],"names":[],"mappings":";;;AAWA,MAAa,2BAA2B;IACpC,YAAqB,OAAgC;QAAhC,YAAO,GAAP,OAAO,CAAyB;QACjD,OAAO,CAAC,iBAAiB,CAAC,cAAc,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE;YAChD,EAAE,CAAC,IAAI,CAAC;;;;;;;;aAQP,CAAC,CAAA;QACN,CAAC,CAAC,CAAA;QACF,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE;YAChB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CACjC,iFAAiF,CACpF,CAAA;YAED,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,4DAA4D,CAAC,CAAA;YAEvG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,2DAA2D,CAAC,CAAA;YAChG,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,4CAA4C,CAAC,CAAA;YACvF,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAA;QACtE,CAAC,CAAC,CAAA;IACN,CAAC;IAGD,KAAK,CAAC,MAAc,EAAE,MAAc,EAAE,KAAa;QAC/C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;IAC1C,CAAC;IAGD,SAAS,CAAC,MAAc;QACpB,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACvC,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAA;QAErB,MAAM,IAAI,GAAG,GAA0B,CAAA;QAEvC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;IACtC,CAAC;IAGD,MAAM,CAAC,MAAc,EAAE,MAAgB;QACnC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;YACxB,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAA;SACvD;IACL,CAAC;IAGD,YAAY,CAAC,MAAc;QACvB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IAC/B,CAAC;IAGD,SAAS;QACL,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAA;IACtB,CAAC;CACJ;AAzDD,kEAyDC","sourcesContent":["import { IReferenceMessagesRepository } from '@mtcute/core'\n\nimport { BaseSqliteStorageDriver } from '../driver.js'\nimport { ISqliteStatement } from '../types.js'\n\ninterface ReferenceMessageDto {\n peer_id: number\n chat_id: number\n msg_id: number\n}\n\nexport class SqliteRefMessagesRepository implements IReferenceMessagesRepository {\n constructor(readonly _driver: BaseSqliteStorageDriver) {\n _driver.registerMigration('ref_messages', 1, (db) => {\n db.exec(`\n create table if not exists message_refs (\n peer_id integer not null,\n chat_id integer not null,\n msg_id integer not null\n );\n create index if not exists idx_message_refs_peer on message_refs (peer_id);\n create index if not exists idx_message_refs on message_refs (chat_id, msg_id);\n `)\n })\n _driver.onLoad(() => {\n this._store = this._driver.db.prepare(\n 'insert or replace into message_refs (peer_id, chat_id, msg_id) values (?, ?, ?)',\n )\n\n this._getByPeer = this._driver.db.prepare('select chat_id, msg_id from message_refs where peer_id = ?')\n\n this._del = this._driver.db.prepare('delete from message_refs where chat_id = ? and msg_id = ?')\n this._delByPeer = this._driver.db.prepare('delete from message_refs where peer_id = ?')\n this._delAll = this._driver.db.prepare('delete from message_refs')\n })\n }\n\n private _store!: ISqliteStatement\n store(peerId: number, chatId: number, msgId: number): void {\n this._store.run(peerId, chatId, msgId)\n }\n\n private _getByPeer!: ISqliteStatement\n getByPeer(peerId: number): [number, number] | null {\n const res = this._getByPeer.get(peerId)\n if (!res) return null\n\n const res_ = res as ReferenceMessageDto\n\n return [res_.chat_id, res_.msg_id]\n }\n\n private _del!: ISqliteStatement\n delete(chatId: number, msgIds: number[]): void {\n for (const msgId of msgIds) {\n this._driver._writeLater(this._del, [chatId, msgId])\n }\n }\n\n private _delByPeer!: ISqliteStatement\n deleteByPeer(peerId: number): void {\n this._delByPeer.run(peerId)\n }\n\n private _delAll!: ISqliteStatement\n deleteAll(): void {\n this._delAll.run()\n }\n}\n"]}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * An abstract interface for a SQLite database.
3
+ *
4
+ * Roughly based on `better-sqlite3`'s `Database` class,
5
+ * (which can be used as-is), but only with the methods
6
+ * that are used by mtcute.
7
+ */
8
+ export interface ISqliteDatabase {
9
+ transaction<F extends (...args: any[]) => any>(fn: F): F;
10
+ prepare<BindParameters extends unknown[]>(sql: string): ISqliteStatement<BindParameters>;
11
+ exec(sql: string): void;
12
+ close(): void;
13
+ }
14
+ export interface ISqliteStatement<BindParameters extends unknown[] = unknown[]> {
15
+ run(...params: BindParameters): void;
16
+ get(...params: BindParameters): unknown;
17
+ all(...params: BindParameters): unknown[];
18
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/storage/sqlite/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * An abstract interface for a SQLite database.\n *\n * Roughly based on `better-sqlite3`'s `Database` class,\n * (which can be used as-is), but only with the methods\n * that are used by mtcute.\n */\nexport interface ISqliteDatabase {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n transaction<F extends (...args: any[]) => any>(fn: F): F\n\n prepare<BindParameters extends unknown[]>(sql: string): ISqliteStatement<BindParameters>\n\n exec(sql: string): void\n close(): void\n}\n\nexport interface ISqliteStatement<BindParameters extends unknown[] = unknown[]> {\n run(...params: BindParameters): void\n get(...params: BindParameters): unknown\n all(...params: BindParameters): unknown[]\n}\n"]}
@@ -18,6 +18,8 @@ const MAX_PART_COUNT_PREMIUM = 8000; // 512 kb * 8000 = 4000 MiB
18
18
  // platform-specific
19
19
  const HAS_FILE = typeof File !== 'undefined';
20
20
  const HAS_RESPONSE = typeof Response !== 'undefined';
21
+ const HAS_URL = typeof URL !== 'undefined';
22
+ const HAS_BLOB = typeof Blob !== 'undefined';
21
23
  // @available=both
22
24
  /**
23
25
  * Upload a file to Telegram servers, without actually
@@ -54,6 +56,13 @@ export async function uploadFile(client, params) {
54
56
  fileSize = file.size;
55
57
  file = file.stream();
56
58
  }
59
+ if (HAS_URL && file instanceof URL) {
60
+ file = await fetch(file);
61
+ }
62
+ if (HAS_BLOB && file instanceof Blob) {
63
+ fileSize = file.size;
64
+ file = file.stream();
65
+ }
57
66
  if (HAS_RESPONSE && file instanceof Response) {
58
67
  const length = parseInt(file.headers.get('content-length') || '0');
59
68
  if (!isNaN(length) && length)
@@ -1 +1 @@
1
- {"version":3,"file":"upload-file.js","sourceRoot":"","sources":["../../../../../src/highlevel/methods/files/upload-file.ts"],"names":[],"mappings":"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","sourcesContent":["import { tl } from '@mtcute/tl'\n\nimport { getPlatform } from '../../../platform.js'\nimport { MtArgumentError } from '../../../types/errors.js'\nimport { randomLong } from '../../../utils/long-utils.js'\nimport { ITelegramClient } from '../../client.types.js'\nimport { UploadedFile, UploadFileLike } from '../../types/index.js'\nimport { guessFileMime } from '../../utils/file-type.js'\nimport { determinePartSize, isProbablyPlainText } from '../../utils/file-utils.js'\nimport { bufferToStream, createChunkedReader, streamToBuffer } from '../../utils/stream-utils.js'\n\nconst OVERRIDE_MIME: Record<string, string> = {\n // tg doesn't interpret `audio/opus` files as voice messages for some reason\n 'audio/opus': 'audio/ogg',\n}\n\n// small files (less than 128 kb) are uploaded using the current connection and not the \"upload\" pool\nconst SMALL_FILE_MAX_SIZE = 131072\nconst BIG_FILE_MIN_SIZE = 10485760 // files >10 MB are considered \"big\"\nconst DEFAULT_FILE_NAME = 'unnamed'\nconst REQUESTS_PER_CONNECTION = 3\nconst MAX_PART_COUNT = 4000 // 512 kb * 4000 = 2000 MiB\nconst MAX_PART_COUNT_PREMIUM = 8000 // 512 kb * 8000 = 4000 MiB\n\n// platform-specific\nconst HAS_FILE = typeof File !== 'undefined'\nconst HAS_RESPONSE = typeof Response !== 'undefined'\n\n// @available=both\n/**\n * Upload a file to Telegram servers, without actually\n * sending a message anywhere. Useful when an `InputFile` is required.\n *\n * This method is quite low-level, and you should use other\n * methods like {@link sendMedia} that handle this under the hood.\n *\n * @param params Upload parameters\n */\nexport async function uploadFile(\n client: ITelegramClient,\n params: {\n /**\n * Upload file source.\n */\n file: UploadFileLike\n\n /**\n * File name for the uploaded file. Is usually inferred from path,\n * but should be provided for files sent as `Buffer` or stream.\n *\n * When file name can't be inferred, it falls back to \"unnamed\"\n */\n fileName?: string\n\n /**\n * Total file size. Automatically inferred for Buffer, File and local files.\n */\n fileSize?: number\n\n /**\n * If the file size is unknown, you can provide an estimate,\n * which will be used to determine appropriate part size.\n */\n estimatedSize?: number\n\n /**\n * File MIME type. By default is automatically inferred from magic number\n * If MIME can't be inferred, it defaults to `application/octet-stream`\n */\n fileMime?: string\n\n /**\n * Upload part size (in KB).\n *\n * By default, automatically selected by file size.\n * Must not be bigger than 512 and must not be a fraction.\n */\n partSize?: number\n\n /**\n * Number of parts to be sent in parallel per connection.\n */\n requestsPerConnection?: number\n\n /**\n * Function that will be called after some part has been uploaded.\n *\n * @param uploaded Number of bytes already uploaded\n * @param total Total file size, if known\n */\n progressCallback?: (uploaded: number, total: number) => void\n\n /**\n * When using `inputMediaUploadedPhoto` (e.g. when sending an uploaded photo) require\n * the file size to be known beforehand.\n *\n * In case this is set to `true`, a stream is passed as `file` and the file size is unknown,\n * the stream will be buffered in memory and the file size will be inferred from the buffer.\n */\n requireFileSize?: boolean\n },\n): Promise<UploadedFile> {\n // normalize params\n let file = params.file\n let fileSize = -1 // unknown\n let fileName = DEFAULT_FILE_NAME\n let fileMime = params.fileMime\n\n const platform = getPlatform()\n\n if (platform.normalizeFile) {\n const res = await platform.normalizeFile(file)\n\n if (res?.file) {\n file = res.file\n if (res.fileSize) fileSize = res.fileSize\n if (res.fileName) fileName = res.fileName\n }\n }\n\n if (ArrayBuffer.isView(file)) {\n fileSize = file.length\n file = bufferToStream(file)\n }\n\n if (HAS_FILE && file instanceof File) {\n fileName = file.name\n fileSize = file.size\n file = file.stream()\n }\n\n if (HAS_RESPONSE && file instanceof Response) {\n const length = parseInt(file.headers.get('content-length') || '0')\n if (!isNaN(length) && length) fileSize = length\n\n fileMime = file.headers.get('content-type')?.split(';')[0]\n\n const disposition = file.headers.get('content-disposition')\n\n if (disposition) {\n const idx = disposition.indexOf('filename=')\n\n if (idx > -1) {\n const raw = disposition.slice(idx + 9).split(';')[0]\n fileName = JSON.parse(raw) as string\n }\n }\n\n if (fileName === DEFAULT_FILE_NAME) {\n // try to infer from url\n const url = new URL(file.url)\n const name = url.pathname.split('/').pop()\n\n if (name && name.includes('.')) {\n fileName = name\n }\n }\n\n if (!file.body) {\n throw new MtArgumentError('Fetch response contains `null` body')\n }\n\n file = file.body\n }\n\n if (!(file instanceof ReadableStream)) {\n throw new MtArgumentError('Could not convert input `file` to stream!')\n }\n\n // override file name and mime (if any)\n if (params.fileName) fileName = params.fileName\n\n // set file size if not automatically inferred\n if (fileSize === -1 && params.fileSize) fileSize = params.fileSize\n\n if (fileSize === -1 && params.requireFileSize) {\n // buffer the entire stream in memory, then convert it back to stream (bruh)\n const buffer = await streamToBuffer(file)\n fileSize = buffer.length\n file = bufferToStream(buffer)\n }\n\n let partSizeKb = params.partSize\n\n if (!partSizeKb) {\n if (fileSize === -1) {\n partSizeKb = params.estimatedSize ? determinePartSize(params.estimatedSize) : 64\n } else {\n partSizeKb = determinePartSize(fileSize)\n }\n }\n\n if (partSizeKb > 512) {\n throw new MtArgumentError(`Invalid part size: ${partSizeKb}KB`)\n }\n const partSize = partSizeKb * 1024\n\n let partCount = fileSize === -1 ? -1 : ~~((fileSize + partSize - 1) / partSize)\n const maxPartCount = client.storage.self.getCached()?.isPremium ? MAX_PART_COUNT_PREMIUM : MAX_PART_COUNT\n\n if (partCount > maxPartCount) {\n throw new MtArgumentError(`File is too large (max ${maxPartCount} parts, got ${partCount})`)\n }\n\n const isBig = fileSize === -1 || fileSize > BIG_FILE_MIN_SIZE\n const isSmall = fileSize !== -1 && fileSize < SMALL_FILE_MAX_SIZE\n const connectionKind = isSmall ? 'main' : 'upload'\n // streamed uploads must be serialized, otherwise we'll get FILE_PART_SIZE_INVALID\n const connectionPoolSize = Math.min(await client.getPoolSize(connectionKind), partCount)\n const requestsPerConnection = params.requestsPerConnection ?? REQUESTS_PER_CONNECTION\n\n client.log.debug(\n 'uploading %d bytes file in %d chunks, each %d bytes in %s connection pool of size %d',\n fileSize,\n partCount,\n partSize,\n connectionKind,\n connectionPoolSize,\n )\n\n // why is the file id generated by the client?\n // isn't the server supposed to generate it and handle collisions?\n const fileId = randomLong()\n const stream = file\n\n let pos = 0\n let idx = 0\n const reader = createChunkedReader(stream, partSize)\n\n const uploadNextPart = async (): Promise<void> => {\n const thisIdx = idx++\n\n let part = await reader.read()\n\n if (!part && fileSize !== -1) {\n throw new MtArgumentError(`Unexpected EOS (there were only ${idx - 1} parts, but expected ${partCount})`)\n }\n\n if (fileSize === -1 && (reader.ended() || !part)) {\n fileSize = pos + (part?.length ?? 0)\n partCount = ~~((fileSize + partSize - 1) / partSize)\n if (!part) part = new Uint8Array(0)\n client.log.debug('readable ended, file size = %d, part count = %d', fileSize, partCount)\n }\n\n if (!ArrayBuffer.isView(part)) {\n throw new MtArgumentError(`Part ${thisIdx} was not a Uint8Array!`)\n }\n if (part.length > partSize) {\n throw new MtArgumentError(`Part ${thisIdx} had invalid size (expected ${partSize}, got ${part.length})`)\n }\n\n if (thisIdx === 0 && fileMime === undefined) {\n const mime = guessFileMime(part)\n\n if (mime) {\n fileMime = mime\n } else {\n // either plain text or random binary gibberish\n // make an assumption based on the first 8 bytes\n // if all 8 bytes are printable ASCII characters,\n // the entire file is probably plain text\n const isPlainText = isProbablyPlainText(part.slice(0, 8))\n fileMime = isPlainText ? 'text/plain' : 'application/octet-stream'\n }\n }\n\n // why\n const request = isBig ?\n ({\n _: 'upload.saveBigFilePart',\n fileId,\n filePart: thisIdx,\n fileTotalParts: partCount,\n bytes: part,\n } satisfies tl.upload.RawSaveBigFilePartRequest) :\n ({\n _: 'upload.saveFilePart',\n fileId,\n filePart: thisIdx,\n bytes: part,\n } satisfies tl.upload.RawSaveFilePartRequest)\n\n const result = await client.call(request, { kind: connectionKind })\n if (!result) throw new Error(`Failed to upload part ${idx}`)\n\n pos += part.length\n\n params.progressCallback?.(pos, fileSize)\n\n if (idx === partCount) return\n\n return uploadNextPart()\n }\n\n let poolSize = partCount === -1 ? 1 : connectionPoolSize * requestsPerConnection\n if (partCount !== -1 && poolSize > partCount) poolSize = partCount\n\n await Promise.all(Array.from({ length: poolSize }, uploadNextPart))\n\n let inputFile: tl.TypeInputFile\n\n if (isBig) {\n inputFile = {\n _: 'inputFileBig',\n id: fileId,\n parts: partCount,\n name: fileName,\n }\n } else {\n inputFile = {\n _: 'inputFile',\n id: fileId,\n parts: partCount,\n name: fileName,\n md5Checksum: '', // tdlib doesn't do this, why should we?\n }\n }\n\n if (fileMime! in OVERRIDE_MIME) fileMime = OVERRIDE_MIME[fileMime!]\n\n return {\n inputFile,\n size: fileSize,\n mime: fileMime!,\n }\n}\n"]}
1
+ {"version":3,"file":"upload-file.js","sourceRoot":"","sources":["../../../../../src/highlevel/methods/files/upload-file.ts"],"names":[],"mappings":"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","sourcesContent":["import { tl } from '@mtcute/tl'\n\nimport { getPlatform } from '../../../platform.js'\nimport { MtArgumentError } from '../../../types/errors.js'\nimport { randomLong } from '../../../utils/long-utils.js'\nimport { ITelegramClient } from '../../client.types.js'\nimport { UploadedFile, UploadFileLike } from '../../types/index.js'\nimport { guessFileMime } from '../../utils/file-type.js'\nimport { determinePartSize, isProbablyPlainText } from '../../utils/file-utils.js'\nimport { bufferToStream, createChunkedReader, streamToBuffer } from '../../utils/stream-utils.js'\n\nconst OVERRIDE_MIME: Record<string, string> = {\n // tg doesn't interpret `audio/opus` files as voice messages for some reason\n 'audio/opus': 'audio/ogg',\n}\n\n// small files (less than 128 kb) are uploaded using the current connection and not the \"upload\" pool\nconst SMALL_FILE_MAX_SIZE = 131072\nconst BIG_FILE_MIN_SIZE = 10485760 // files >10 MB are considered \"big\"\nconst DEFAULT_FILE_NAME = 'unnamed'\nconst REQUESTS_PER_CONNECTION = 3\nconst MAX_PART_COUNT = 4000 // 512 kb * 4000 = 2000 MiB\nconst MAX_PART_COUNT_PREMIUM = 8000 // 512 kb * 8000 = 4000 MiB\n\n// platform-specific\nconst HAS_FILE = typeof File !== 'undefined'\nconst HAS_RESPONSE = typeof Response !== 'undefined'\nconst HAS_URL = typeof URL !== 'undefined'\nconst HAS_BLOB = typeof Blob !== 'undefined'\n\n// @available=both\n/**\n * Upload a file to Telegram servers, without actually\n * sending a message anywhere. Useful when an `InputFile` is required.\n *\n * This method is quite low-level, and you should use other\n * methods like {@link sendMedia} that handle this under the hood.\n *\n * @param params Upload parameters\n */\nexport async function uploadFile(\n client: ITelegramClient,\n params: {\n /**\n * Upload file source.\n */\n file: UploadFileLike\n\n /**\n * File name for the uploaded file. Is usually inferred from path,\n * but should be provided for files sent as `Buffer` or stream.\n *\n * When file name can't be inferred, it falls back to \"unnamed\"\n */\n fileName?: string\n\n /**\n * Total file size. Automatically inferred for Buffer, File and local files.\n */\n fileSize?: number\n\n /**\n * If the file size is unknown, you can provide an estimate,\n * which will be used to determine appropriate part size.\n */\n estimatedSize?: number\n\n /**\n * File MIME type. By default is automatically inferred from magic number\n * If MIME can't be inferred, it defaults to `application/octet-stream`\n */\n fileMime?: string\n\n /**\n * Upload part size (in KB).\n *\n * By default, automatically selected by file size.\n * Must not be bigger than 512 and must not be a fraction.\n */\n partSize?: number\n\n /**\n * Number of parts to be sent in parallel per connection.\n */\n requestsPerConnection?: number\n\n /**\n * Function that will be called after some part has been uploaded.\n *\n * @param uploaded Number of bytes already uploaded\n * @param total Total file size, if known\n */\n progressCallback?: (uploaded: number, total: number) => void\n\n /**\n * When using `inputMediaUploadedPhoto` (e.g. when sending an uploaded photo) require\n * the file size to be known beforehand.\n *\n * In case this is set to `true`, a stream is passed as `file` and the file size is unknown,\n * the stream will be buffered in memory and the file size will be inferred from the buffer.\n */\n requireFileSize?: boolean\n },\n): Promise<UploadedFile> {\n // normalize params\n let file = params.file\n let fileSize = -1 // unknown\n let fileName = DEFAULT_FILE_NAME\n let fileMime = params.fileMime\n\n const platform = getPlatform()\n\n if (platform.normalizeFile) {\n const res = await platform.normalizeFile(file)\n\n if (res?.file) {\n file = res.file\n if (res.fileSize) fileSize = res.fileSize\n if (res.fileName) fileName = res.fileName\n }\n }\n\n if (ArrayBuffer.isView(file)) {\n fileSize = file.length\n file = bufferToStream(file)\n }\n\n if (HAS_FILE && file instanceof File) {\n fileName = file.name\n fileSize = file.size\n file = file.stream()\n }\n\n if (HAS_URL && file instanceof URL) {\n file = await fetch(file)\n }\n\n if (HAS_BLOB && file instanceof Blob) {\n fileSize = file.size\n file = file.stream()\n }\n\n if (HAS_RESPONSE && file instanceof Response) {\n const length = parseInt(file.headers.get('content-length') || '0')\n if (!isNaN(length) && length) fileSize = length\n\n fileMime = file.headers.get('content-type')?.split(';')[0]\n\n const disposition = file.headers.get('content-disposition')\n\n if (disposition) {\n const idx = disposition.indexOf('filename=')\n\n if (idx > -1) {\n const raw = disposition.slice(idx + 9).split(';')[0]\n fileName = JSON.parse(raw) as string\n }\n }\n\n if (fileName === DEFAULT_FILE_NAME) {\n // try to infer from url\n const url = new URL(file.url)\n const name = url.pathname.split('/').pop()\n\n if (name && name.includes('.')) {\n fileName = name\n }\n }\n\n if (!file.body) {\n throw new MtArgumentError('Fetch response contains `null` body')\n }\n\n file = file.body\n }\n\n if (!(file instanceof ReadableStream)) {\n throw new MtArgumentError('Could not convert input `file` to stream!')\n }\n\n // override file name and mime (if any)\n if (params.fileName) fileName = params.fileName\n\n // set file size if not automatically inferred\n if (fileSize === -1 && params.fileSize) fileSize = params.fileSize\n\n if (fileSize === -1 && params.requireFileSize) {\n // buffer the entire stream in memory, then convert it back to stream (bruh)\n const buffer = await streamToBuffer(file)\n fileSize = buffer.length\n file = bufferToStream(buffer)\n }\n\n let partSizeKb = params.partSize\n\n if (!partSizeKb) {\n if (fileSize === -1) {\n partSizeKb = params.estimatedSize ? determinePartSize(params.estimatedSize) : 64\n } else {\n partSizeKb = determinePartSize(fileSize)\n }\n }\n\n if (partSizeKb > 512) {\n throw new MtArgumentError(`Invalid part size: ${partSizeKb}KB`)\n }\n const partSize = partSizeKb * 1024\n\n let partCount = fileSize === -1 ? -1 : ~~((fileSize + partSize - 1) / partSize)\n const maxPartCount = client.storage.self.getCached()?.isPremium ? MAX_PART_COUNT_PREMIUM : MAX_PART_COUNT\n\n if (partCount > maxPartCount) {\n throw new MtArgumentError(`File is too large (max ${maxPartCount} parts, got ${partCount})`)\n }\n\n const isBig = fileSize === -1 || fileSize > BIG_FILE_MIN_SIZE\n const isSmall = fileSize !== -1 && fileSize < SMALL_FILE_MAX_SIZE\n const connectionKind = isSmall ? 'main' : 'upload'\n // streamed uploads must be serialized, otherwise we'll get FILE_PART_SIZE_INVALID\n const connectionPoolSize = Math.min(await client.getPoolSize(connectionKind), partCount)\n const requestsPerConnection = params.requestsPerConnection ?? REQUESTS_PER_CONNECTION\n\n client.log.debug(\n 'uploading %d bytes file in %d chunks, each %d bytes in %s connection pool of size %d',\n fileSize,\n partCount,\n partSize,\n connectionKind,\n connectionPoolSize,\n )\n\n // why is the file id generated by the client?\n // isn't the server supposed to generate it and handle collisions?\n const fileId = randomLong()\n const stream = file\n\n let pos = 0\n let idx = 0\n const reader = createChunkedReader(stream, partSize)\n\n const uploadNextPart = async (): Promise<void> => {\n const thisIdx = idx++\n\n let part = await reader.read()\n\n if (!part && fileSize !== -1) {\n throw new MtArgumentError(`Unexpected EOS (there were only ${idx - 1} parts, but expected ${partCount})`)\n }\n\n if (fileSize === -1 && (reader.ended() || !part)) {\n fileSize = pos + (part?.length ?? 0)\n partCount = ~~((fileSize + partSize - 1) / partSize)\n if (!part) part = new Uint8Array(0)\n client.log.debug('readable ended, file size = %d, part count = %d', fileSize, partCount)\n }\n\n if (!ArrayBuffer.isView(part)) {\n throw new MtArgumentError(`Part ${thisIdx} was not a Uint8Array!`)\n }\n if (part.length > partSize) {\n throw new MtArgumentError(`Part ${thisIdx} had invalid size (expected ${partSize}, got ${part.length})`)\n }\n\n if (thisIdx === 0 && fileMime === undefined) {\n const mime = guessFileMime(part)\n\n if (mime) {\n fileMime = mime\n } else {\n // either plain text or random binary gibberish\n // make an assumption based on the first 8 bytes\n // if all 8 bytes are printable ASCII characters,\n // the entire file is probably plain text\n const isPlainText = isProbablyPlainText(part.slice(0, 8))\n fileMime = isPlainText ? 'text/plain' : 'application/octet-stream'\n }\n }\n\n // why\n const request = isBig ?\n ({\n _: 'upload.saveBigFilePart',\n fileId,\n filePart: thisIdx,\n fileTotalParts: partCount,\n bytes: part,\n } satisfies tl.upload.RawSaveBigFilePartRequest) :\n ({\n _: 'upload.saveFilePart',\n fileId,\n filePart: thisIdx,\n bytes: part,\n } satisfies tl.upload.RawSaveFilePartRequest)\n\n const result = await client.call(request, { kind: connectionKind })\n if (!result) throw new Error(`Failed to upload part ${idx}`)\n\n pos += part.length\n\n params.progressCallback?.(pos, fileSize)\n\n if (idx === partCount) return\n\n return uploadNextPart()\n }\n\n let poolSize = partCount === -1 ? 1 : connectionPoolSize * requestsPerConnection\n if (partCount !== -1 && poolSize > partCount) poolSize = partCount\n\n await Promise.all(Array.from({ length: poolSize }, uploadNextPart))\n\n let inputFile: tl.TypeInputFile\n\n if (isBig) {\n inputFile = {\n _: 'inputFileBig',\n id: fileId,\n parts: partCount,\n name: fileName,\n }\n } else {\n inputFile = {\n _: 'inputFile',\n id: fileId,\n parts: partCount,\n name: fileName,\n md5Checksum: '', // tdlib doesn't do this, why should we?\n }\n }\n\n if (fileMime! in OVERRIDE_MIME) fileMime = OVERRIDE_MIME[fileMime!]\n\n return {\n inputFile,\n size: fileSize,\n mime: fileMime!,\n }\n}\n"]}
@@ -9,14 +9,16 @@ import { UploadedFile } from './uploaded-file.js';
9
9
  * Describes types that can be used in {@link TelegramClient.uploadFile}
10
10
  * method. Can be one of:
11
11
  * - `Uint8Array`/`Buffer`, which will be interpreted as raw file contents
12
- * - `File` (from the Web API)
12
+ * - `File`, `Blob` (from the Web API)
13
13
  * - `string`, which will be interpreted as file path (**non-browser only!**)
14
- * - `ReadStream` (for NodeJS, from the `fs` module)
14
+ * - `URL` (from the Web API, will be `fetch()`-ed; `file://` URLs are not available in browsers)
15
+ * - `ReadStream` (for Node.js/Bun, from the `fs` module)
16
+ * - `BunFile` (from `Bun.file()`)
15
17
  * - `ReadableStream` (Web API readable stream)
16
- * - `Readable` (NodeJS readable stream)
18
+ * - `Readable` (Node.js/Bun readable stream)
17
19
  * - `Response` (from `window.fetch`)
18
20
  */
19
- export type UploadFileLike = Uint8Array | File | string | ReadStream | ReadableStream<Uint8Array> | NodeJS.ReadableStream | Response;
21
+ export type UploadFileLike = URL | Uint8Array | File | Blob | string | ReadStream | ReadableStream<Uint8Array> | NodeJS.ReadableStream | Response;
20
22
  /**
21
23
  * Describes types that can be used as an input
22
24
  * to any methods that send media (like {@link TelegramClient.sendPhoto})
@@ -24,14 +26,15 @@ export type UploadFileLike = Uint8Array | File | string | ReadStream | ReadableS
24
26
  * Can be one of:
25
27
  * - `Buffer`, which will be interpreted as raw file contents
26
28
  * - `File` (from the Web API)
27
- * - `ReadStream` (for NodeJS, from the `fs` module)
29
+ * - `ReadStream` (for Node.js/Bun, from the `fs` module)
28
30
  * - `ReadableStream` (from the Web API, base readable stream)
29
- * - `Readable` (for NodeJS, base readable stream)
31
+ * - `Readable` (for Node.js/Bun, base readable stream)
30
32
  * - {@link UploadedFile} returned from {@link TelegramClient.uploadFile}
31
33
  * - `tl.TypeInputFile` and `tl.TypeInputMedia` TL objects
32
34
  * - `string` with a path to a local file prepended with `file:` (non-browser only) (e.g. `file:image.jpg`)
33
35
  * - `string` with a URL to remote files (e.g. `https://example.com/image.jpg`)
34
36
  * - `string` with TDLib and Bot API compatible File ID.
37
+ * - `URL` (from the Web API, will be `fetch()`-ed if needed; `file://` URLs are not available in browsers)
35
38
  * - `td.RawFullRemoteFileLocation` (parsed File ID)
36
39
  */
37
40
  export type InputFileLike = UploadFileLike | UploadedFile | tl.TypeInputFile | tl.TypeInputMedia | tdFileId.RawFullRemoteFileLocation;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../../src/highlevel/types/files/utils.ts"],"names":[],"mappings":"","sourcesContent":["/* eslint-disable no-restricted-imports */\nimport type { ReadStream } from 'fs'\n\nimport { tdFileId } from '@mtcute/file-id'\nimport { tl } from '@mtcute/tl'\n\nimport { FileLocation } from './file-location.js'\nimport { UploadedFile } from './uploaded-file.js'\n\n/**\n * Describes types that can be used in {@link TelegramClient.uploadFile}\n * method. Can be one of:\n * - `Uint8Array`/`Buffer`, which will be interpreted as raw file contents\n * - `File` (from the Web API)\n * - `string`, which will be interpreted as file path (**non-browser only!**)\n * - `ReadStream` (for NodeJS, from the `fs` module)\n * - `ReadableStream` (Web API readable stream)\n * - `Readable` (NodeJS readable stream)\n * - `Response` (from `window.fetch`)\n */\nexport type UploadFileLike =\n | Uint8Array\n | File\n | string\n | ReadStream\n | ReadableStream<Uint8Array>\n | NodeJS.ReadableStream\n | Response\n\n/**\n * Describes types that can be used as an input\n * to any methods that send media (like {@link TelegramClient.sendPhoto})\n *\n * Can be one of:\n * - `Buffer`, which will be interpreted as raw file contents\n * - `File` (from the Web API)\n * - `ReadStream` (for NodeJS, from the `fs` module)\n * - `ReadableStream` (from the Web API, base readable stream)\n * - `Readable` (for NodeJS, base readable stream)\n * - {@link UploadedFile} returned from {@link TelegramClient.uploadFile}\n * - `tl.TypeInputFile` and `tl.TypeInputMedia` TL objects\n * - `string` with a path to a local file prepended with `file:` (non-browser only) (e.g. `file:image.jpg`)\n * - `string` with a URL to remote files (e.g. `https://example.com/image.jpg`)\n * - `string` with TDLib and Bot API compatible File ID.\n * - `td.RawFullRemoteFileLocation` (parsed File ID)\n */\nexport type InputFileLike =\n | UploadFileLike\n | UploadedFile\n | tl.TypeInputFile\n | tl.TypeInputMedia\n | tdFileId.RawFullRemoteFileLocation\n\n/**\n * File location which should be downloaded.\n * You can also provide TDLib and Bot API compatible File ID\n */\nexport type FileDownloadLocation = tl.TypeInputFileLocation | tl.TypeInputWebFileLocation | FileLocation | string\n\nexport interface FileDownloadParameters {\n /**\n * Total file size, if known.\n * Used to determine upload part size.\n * In some cases can be inferred from `file` automatically.\n */\n fileSize?: number\n\n /**\n * Download part size (in KB).\n * By default, automatically selected depending on the file size\n * (or 64, if not provided). Must not be bigger than 512,\n * must not be a fraction, and must be divisible by 4.\n */\n partSize?: number\n\n /**\n * DC id from which the file will be downloaded.\n *\n * If provided DC is not the one storing the file,\n * redirection will be handled automatically.\n */\n dcId?: number\n\n /**\n * Offset in bytes. Must be divisible by 4096 (4 KB).\n */\n offset?: number\n\n /**\n * Number of bytes to be downloaded.\n * By default, downloads the entire file\n */\n limit?: number\n\n /**\n * Function that will be called after some part has been downloaded.\n *\n * @param uploaded Number of bytes already downloaded\n * @param total Total file size (`Infinity` if not available)\n */\n progressCallback?: (downloaded: number, total: number) => void\n\n /**\n * Abort signal that can be used to cancel the download.\n */\n abortSignal?: AbortSignal\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../../src/highlevel/types/files/utils.ts"],"names":[],"mappings":"","sourcesContent":["/* eslint-disable no-restricted-imports */\nimport type { ReadStream } from 'fs'\n\nimport { tdFileId } from '@mtcute/file-id'\nimport { tl } from '@mtcute/tl'\n\nimport { FileLocation } from './file-location.js'\nimport { UploadedFile } from './uploaded-file.js'\n\n/**\n * Describes types that can be used in {@link TelegramClient.uploadFile}\n * method. Can be one of:\n * - `Uint8Array`/`Buffer`, which will be interpreted as raw file contents\n * - `File`, `Blob` (from the Web API)\n * - `string`, which will be interpreted as file path (**non-browser only!**)\n * - `URL` (from the Web API, will be `fetch()`-ed; `file://` URLs are not available in browsers)\n * - `ReadStream` (for Node.js/Bun, from the `fs` module)\n * - `BunFile` (from `Bun.file()`)\n * - `ReadableStream` (Web API readable stream)\n * - `Readable` (Node.js/Bun readable stream)\n * - `Response` (from `window.fetch`)\n */\nexport type UploadFileLike =\n | URL\n | Uint8Array\n | File\n | Blob\n | string\n | ReadStream\n | ReadableStream<Uint8Array>\n | NodeJS.ReadableStream\n | Response\n\n/**\n * Describes types that can be used as an input\n * to any methods that send media (like {@link TelegramClient.sendPhoto})\n *\n * Can be one of:\n * - `Buffer`, which will be interpreted as raw file contents\n * - `File` (from the Web API)\n * - `ReadStream` (for Node.js/Bun, from the `fs` module)\n * - `ReadableStream` (from the Web API, base readable stream)\n * - `Readable` (for Node.js/Bun, base readable stream)\n * - {@link UploadedFile} returned from {@link TelegramClient.uploadFile}\n * - `tl.TypeInputFile` and `tl.TypeInputMedia` TL objects\n * - `string` with a path to a local file prepended with `file:` (non-browser only) (e.g. `file:image.jpg`)\n * - `string` with a URL to remote files (e.g. `https://example.com/image.jpg`)\n * - `string` with TDLib and Bot API compatible File ID.\n * - `URL` (from the Web API, will be `fetch()`-ed if needed; `file://` URLs are not available in browsers)\n * - `td.RawFullRemoteFileLocation` (parsed File ID)\n */\nexport type InputFileLike =\n | UploadFileLike\n | UploadedFile\n | tl.TypeInputFile\n | tl.TypeInputMedia\n | tdFileId.RawFullRemoteFileLocation\n\n/**\n * File location which should be downloaded.\n * You can also provide TDLib and Bot API compatible File ID\n */\nexport type FileDownloadLocation = tl.TypeInputFileLocation | tl.TypeInputWebFileLocation | FileLocation | string\n\nexport interface FileDownloadParameters {\n /**\n * Total file size, if known.\n * Used to determine upload part size.\n * In some cases can be inferred from `file` automatically.\n */\n fileSize?: number\n\n /**\n * Download part size (in KB).\n * By default, automatically selected depending on the file size\n * (or 64, if not provided). Must not be bigger than 512,\n * must not be a fraction, and must be divisible by 4.\n */\n partSize?: number\n\n /**\n * DC id from which the file will be downloaded.\n *\n * If provided DC is not the one storing the file,\n * redirection will be handled automatically.\n */\n dcId?: number\n\n /**\n * Offset in bytes. Must be divisible by 4096 (4 KB).\n */\n offset?: number\n\n /**\n * Number of bytes to be downloaded.\n * By default, downloads the entire file\n */\n limit?: number\n\n /**\n * Function that will be called after some part has been downloaded.\n *\n * @param uploaded Number of bytes already downloaded\n * @param total Total file size (`Infinity` if not available)\n */\n progressCallback?: (downloaded: number, total: number) => void\n\n /**\n * Abort signal that can be used to cancel the download.\n */\n abortSignal?: AbortSignal\n}\n"]}
@@ -229,7 +229,7 @@ export class NetworkManager {
229
229
  _: 'initConnection',
230
230
  deviceModel,
231
231
  systemVersion: '1.0',
232
- appVersion: '0.8.0',
232
+ appVersion: '0.9.0',
233
233
  systemLangCode: 'en',
234
234
  langPack: '',
235
235
  langCode: 'en',
@@ -2,4 +2,5 @@ export * from './driver.js';
2
2
  export * from './memory/index.js';
3
3
  export * from './provider.js';
4
4
  export * from './repository/index.js';
5
+ export * from './sqlite/index.js';
5
6
  export * from './storage.js';
@@ -2,5 +2,6 @@ export * from './driver.js';
2
2
  export * from './memory/index.js';
3
3
  export * from './provider.js';
4
4
  export * from './repository/index.js';
5
+ export * from './sqlite/index.js';
5
6
  export * from './storage.js';
6
7
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/storage/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,uBAAuB,CAAA;AACrC,cAAc,cAAc,CAAA","sourcesContent":["export * from './driver.js'\nexport * from './memory/index.js'\nexport * from './provider.js'\nexport * from './repository/index.js'\nexport * from './storage.js'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/storage/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA;AACjC,cAAc,cAAc,CAAA","sourcesContent":["export * from './driver.js'\nexport * from './memory/index.js'\nexport * from './provider.js'\nexport * from './repository/index.js'\nexport * from './sqlite/index.js'\nexport * from './storage.js'\n"]}
@@ -0,0 +1,24 @@
1
+ import { BaseStorageDriver } from '../driver.js';
2
+ import { ISqliteDatabase, ISqliteStatement } from './types.js';
3
+ type MigrationFunction = (db: ISqliteDatabase) => void;
4
+ export declare abstract class BaseSqliteStorageDriver extends BaseStorageDriver {
5
+ db: ISqliteDatabase;
6
+ private _pending;
7
+ private _runMany;
8
+ private _cleanup?;
9
+ private _migrations;
10
+ private _maxVersion;
11
+ private _legacyMigrations;
12
+ registerLegacyMigration(repo: string, migration: MigrationFunction): void;
13
+ registerMigration(repo: string, version: number, migration: MigrationFunction): void;
14
+ private _onLoad;
15
+ onLoad(cb: (db: ISqliteDatabase) => void): void;
16
+ _writeLater(stmt: ISqliteStatement, params: unknown[]): void;
17
+ private _runLegacyMigrations;
18
+ _initialize(): void;
19
+ abstract _createDatabase(): ISqliteDatabase;
20
+ _load(): void;
21
+ _save(): void;
22
+ _destroy(): void;
23
+ }
24
+ export {};