@mtcute/core 0.3.0 → 0.5.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 (39) hide show
  1. package/cjs/network/mtproto-session.js +2 -0
  2. package/cjs/network/mtproto-session.js.map +1 -1
  3. package/cjs/network/network-manager.js +1 -1
  4. package/cjs/network/session-connection.js +14 -0
  5. package/cjs/network/session-connection.js.map +1 -1
  6. package/cjs/storage/abstract.d.ts +1 -1
  7. package/cjs/storage/abstract.js.map +1 -1
  8. package/cjs/storage/json-file.d.ts +1 -2
  9. package/cjs/storage/json-file.js +4 -12
  10. package/cjs/storage/json-file.js.map +1 -1
  11. package/cjs/utils/index.d.ts +1 -0
  12. package/cjs/utils/index.js +1 -0
  13. package/cjs/utils/index.js.map +1 -1
  14. package/cjs/utils/platform/exit-hook.d.ts +1 -0
  15. package/cjs/utils/platform/exit-hook.js +45 -0
  16. package/cjs/utils/platform/exit-hook.js.map +1 -0
  17. package/cjs/utils/platform/exit-hook.web.d.ts +1 -0
  18. package/cjs/utils/platform/exit-hook.web.js +21 -0
  19. package/cjs/utils/platform/exit-hook.web.js.map +1 -0
  20. package/esm/network/mtproto-session.js +2 -0
  21. package/esm/network/mtproto-session.js.map +1 -1
  22. package/esm/network/network-manager.js +1 -1
  23. package/esm/network/session-connection.js +14 -0
  24. package/esm/network/session-connection.js.map +1 -1
  25. package/esm/storage/abstract.d.ts +1 -1
  26. package/esm/storage/abstract.js.map +1 -1
  27. package/esm/storage/json-file.d.ts +1 -2
  28. package/esm/storage/json-file.js +4 -12
  29. package/esm/storage/json-file.js.map +1 -1
  30. package/esm/utils/index.d.ts +1 -0
  31. package/esm/utils/index.js +1 -0
  32. package/esm/utils/index.js.map +1 -1
  33. package/esm/utils/platform/exit-hook.d.ts +1 -0
  34. package/esm/utils/platform/exit-hook.js +41 -0
  35. package/esm/utils/platform/exit-hook.js.map +1 -0
  36. package/esm/utils/platform/exit-hook.web.d.ts +1 -0
  37. package/esm/utils/platform/exit-hook.web.js +17 -0
  38. package/esm/utils/platform/exit-hook.web.js.map +1 -0
  39. package/package.json +6 -4
@@ -73,7 +73,7 @@ export interface ITelegramStorage {
73
73
  *
74
74
  * @param [withAuthKeys=false] Whether to also reset auth keys
75
75
  */
76
- reset(withAuthKeys?: boolean): void;
76
+ reset(withAuthKeys?: boolean): MaybeAsync<void>;
77
77
  /**
78
78
  * Set default datacenter to use with this session.
79
79
  */
@@ -1 +1 @@
1
- {"version":3,"file":"abstract.js","sourceRoot":"","sources":["../../../src/storage/abstract.ts"],"names":[],"mappings":"","sourcesContent":["import { mtp, tl } from '@mtcute/tl'\nimport { TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime'\n\nimport { BasicPeerType, MaybeAsync } from '../types/index.js'\nimport { Logger } from '../utils/index.js'\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace ITelegramStorage {\n /** Information about a cached peer */\n export interface PeerInfo {\n /** Peer marked ID */\n id: number\n /** Peer access hash */\n accessHash: tl.Long\n /** Peer type */\n type: BasicPeerType\n /** Peer username, if any */\n username?: string\n /** Peer phone number, if available */\n phone?: string\n\n /** Full TL object with the cached entity */\n full: tl.TypeUser | tl.TypeChat\n }\n\n /** Information about currently logged in user */\n export interface SelfInfo {\n /** Whether this is a bot */\n isBot: boolean\n /** Current user's ID */\n userId: number\n }\n\n /** Information about preferred DC-s for the user */\n export interface DcOptions {\n /** Main DC */\n main: tl.RawDcOption\n /** Media DC. Can be the same as main */\n media: tl.RawDcOption\n }\n}\n\n/**\n * Abstract interface for persistent storage.\n *\n * In some cases you may want to extend existing MemorySession\n * and override save()/load()/destroy() methods, but you are also free\n * to implement your own session (be sure to refer to MemorySession\n * source code to avoid shooting your leg though)\n *\n * Note that even though set methods *can* be async, you should only\n * write updates to the disk when `save()` is called.\n */\nexport interface ITelegramStorage {\n /**\n * This method is called before any other.\n * For storages that use logging, logger instance.\n * For storages that use binary storage, binary maps\n */\n setup?(log: Logger, readerMap: TlReaderMap, writerMap: TlWriterMap): void\n\n /**\n * Load session from some external storage.\n * Should be used either to load session content from file/network/etc\n * to memory, or to open required connections to fetch session content later\n */\n load?(): MaybeAsync<void>\n /**\n * Save session to some external storage.\n * Should be used to commit pending changes in the session.\n * For example, saving session content to file/network/etc,\n * or committing a database transaction\n */\n save?(): MaybeAsync<void>\n /**\n * Cleanup session and release all used resources.\n */\n destroy?(): MaybeAsync<void>\n\n /**\n * Reset session to its default state, optionally resetting auth keys\n *\n * @param [withAuthKeys=false] Whether to also reset auth keys\n */\n reset(withAuthKeys?: boolean): void\n\n /**\n * Set default datacenter to use with this session.\n */\n setDefaultDcs(dcs: ITelegramStorage.DcOptions | null): MaybeAsync<void>\n /**\n * Get default datacenter for this session\n * (by default should return null)\n */\n getDefaultDcs(): MaybeAsync<ITelegramStorage.DcOptions | null>\n\n /**\n * Store information about future salts for a given DC\n */\n setFutureSalts(dcId: number, salts: mtp.RawMt_future_salt[]): MaybeAsync<void>\n /**\n * Get information about future salts for a given DC (if available)\n *\n * You don't need to implement any checks, they will be done by the library.\n * It is enough to just return the same array that was passed to `setFutureSalts`.\n */\n getFutureSalts(dcId: number): MaybeAsync<mtp.RawMt_future_salt[] | null>\n\n /**\n * Get auth_key for a given DC\n * (returning null will start authorization)\n * For temp keys: should also return null if the key has expired\n *\n * @param dcId DC ID\n * @param tempIndex Index of the temporary key (usually 0, used for multi-connections)\n */\n getAuthKeyFor(dcId: number, tempIndex?: number): MaybeAsync<Uint8Array | null>\n /**\n * Set auth_key for a given DC\n */\n setAuthKeyFor(dcId: number, key: Uint8Array | null): MaybeAsync<void>\n /**\n * Set temp_auth_key for a given DC\n * expiresAt is unix time in ms\n */\n setTempAuthKeyFor(dcId: number, index: number, key: Uint8Array | null, expiresAt: number): MaybeAsync<void>\n /**\n * Remove all saved auth keys (both temp and perm)\n * for the given DC. Used when perm_key becomes invalid,\n * meaning all temp_keys also become invalid\n */\n dropAuthKeysFor(dcId: number): MaybeAsync<void>\n\n /**\n * Get information about currently logged in user (if available)\n */\n getSelf(): MaybeAsync<ITelegramStorage.SelfInfo | null>\n /**\n * Save information about currently logged in user\n */\n setSelf(self: ITelegramStorage.SelfInfo | null): MaybeAsync<void>\n\n /**\n * Update local database of input peers from the peer info list\n *\n * Client will call `.save()` after all updates-related methods\n * are called, so you can safely batch these updates\n */\n updatePeers(peers: ITelegramStorage.PeerInfo[]): MaybeAsync<void>\n\n /**\n * Find a peer in local database by its marked ID\n *\n * If no peer was found, the storage should try searching its\n * reference messages database. If a reference message is found,\n * a `inputPeer*FromMessage` constructor should be returned\n */\n getPeerById(peerId: number): MaybeAsync<tl.TypeInputPeer | null>\n\n /**\n * Find a peer in local database by its username\n */\n getPeerByUsername(username: string): MaybeAsync<tl.TypeInputPeer | null>\n\n /**\n * Find a peer in local database by its phone number\n */\n getPeerByPhone(phone: string): MaybeAsync<tl.TypeInputPeer | null>\n\n /**\n * For `*FromMessage` constructors: store a reference to a `peerId` -\n * it was seen in message `messageId` in chat `chatId`.\n *\n * `peerId` and `chatId` are marked peer IDs.\n *\n * Learn more: https://core.telegram.org/api/min\n */\n saveReferenceMessage(peerId: number, chatId: number, messageId: number): MaybeAsync<void>\n\n /**\n * For `*FromMessage` constructors: messages `messageIds` in chat `chatId` were deleted,\n * so remove any stored peer references to them.\n */\n deleteReferenceMessages(chatId: number, messageIds: number[]): MaybeAsync<void>\n\n /**\n * Get updates state (if available), represented as a tuple\n * containing: `pts, qts, date, seq`\n */\n getUpdatesState(): MaybeAsync<[number, number, number, number] | null>\n\n /**\n * Set common `pts` value\n *\n * Client will call `.save()` after all updates-related methods\n * are called, so you can safely batch these updates\n */\n setUpdatesPts(val: number): MaybeAsync<void>\n /**\n * Set common `qts` value\n *\n * Client will call `.save()` after all updates-related methods\n * are called, so you can safely batch these updates\n */\n setUpdatesQts(val: number): MaybeAsync<void>\n /**\n * Set updates `date` value\n *\n * Client will call `.save()` after all updates-related methods\n * are called, so you can safely batch these updates\n */\n setUpdatesDate(val: number): MaybeAsync<void>\n /**\n * Set updates `seq` value\n *\n * Client will call `.save()` after all updates-related methods\n * are called, so you can safely batch these updates\n */\n setUpdatesSeq(val: number): MaybeAsync<void>\n\n /**\n * Get channel `pts` value\n */\n getChannelPts(entityId: number): MaybeAsync<number | null>\n /**\n * Set channels `pts` values in batch.\n *\n * Storage is supposed to replace stored channel `pts` values\n * with given in the object (key is unmarked peer id, value is the `pts`)\n *\n * Client will call `.save()` after all updates-related methods\n * are called, so you can safely batch these updates\n */\n setManyChannelPts(values: Map<number, number>): MaybeAsync<void>\n\n /**\n * Get cached peer information by their marked ID.\n * Return `null` if caching is not supported, or the entity\n * is not cached (yet).\n *\n * This is primarily used when a `min` entity is encountered\n * in an update, or when a *short* update is encountered.\n * Returning `null` will require re-fetching that\n * update with the peers added, which might not be very efficient.\n */\n getFullPeerById(id: number): MaybeAsync<tl.TypeUser | tl.TypeChat | null>\n}\n"]}
1
+ {"version":3,"file":"abstract.js","sourceRoot":"","sources":["../../../src/storage/abstract.ts"],"names":[],"mappings":"","sourcesContent":["import { mtp, tl } from '@mtcute/tl'\nimport { TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime'\n\nimport { BasicPeerType, MaybeAsync } from '../types/index.js'\nimport { Logger } from '../utils/index.js'\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace ITelegramStorage {\n /** Information about a cached peer */\n export interface PeerInfo {\n /** Peer marked ID */\n id: number\n /** Peer access hash */\n accessHash: tl.Long\n /** Peer type */\n type: BasicPeerType\n /** Peer username, if any */\n username?: string\n /** Peer phone number, if available */\n phone?: string\n\n /** Full TL object with the cached entity */\n full: tl.TypeUser | tl.TypeChat\n }\n\n /** Information about currently logged in user */\n export interface SelfInfo {\n /** Whether this is a bot */\n isBot: boolean\n /** Current user's ID */\n userId: number\n }\n\n /** Information about preferred DC-s for the user */\n export interface DcOptions {\n /** Main DC */\n main: tl.RawDcOption\n /** Media DC. Can be the same as main */\n media: tl.RawDcOption\n }\n}\n\n/**\n * Abstract interface for persistent storage.\n *\n * In some cases you may want to extend existing MemorySession\n * and override save()/load()/destroy() methods, but you are also free\n * to implement your own session (be sure to refer to MemorySession\n * source code to avoid shooting your leg though)\n *\n * Note that even though set methods *can* be async, you should only\n * write updates to the disk when `save()` is called.\n */\nexport interface ITelegramStorage {\n /**\n * This method is called before any other.\n * For storages that use logging, logger instance.\n * For storages that use binary storage, binary maps\n */\n setup?(log: Logger, readerMap: TlReaderMap, writerMap: TlWriterMap): void\n\n /**\n * Load session from some external storage.\n * Should be used either to load session content from file/network/etc\n * to memory, or to open required connections to fetch session content later\n */\n load?(): MaybeAsync<void>\n /**\n * Save session to some external storage.\n * Should be used to commit pending changes in the session.\n * For example, saving session content to file/network/etc,\n * or committing a database transaction\n */\n save?(): MaybeAsync<void>\n /**\n * Cleanup session and release all used resources.\n */\n destroy?(): MaybeAsync<void>\n\n /**\n * Reset session to its default state, optionally resetting auth keys\n *\n * @param [withAuthKeys=false] Whether to also reset auth keys\n */\n reset(withAuthKeys?: boolean): MaybeAsync<void>\n\n /**\n * Set default datacenter to use with this session.\n */\n setDefaultDcs(dcs: ITelegramStorage.DcOptions | null): MaybeAsync<void>\n /**\n * Get default datacenter for this session\n * (by default should return null)\n */\n getDefaultDcs(): MaybeAsync<ITelegramStorage.DcOptions | null>\n\n /**\n * Store information about future salts for a given DC\n */\n setFutureSalts(dcId: number, salts: mtp.RawMt_future_salt[]): MaybeAsync<void>\n /**\n * Get information about future salts for a given DC (if available)\n *\n * You don't need to implement any checks, they will be done by the library.\n * It is enough to just return the same array that was passed to `setFutureSalts`.\n */\n getFutureSalts(dcId: number): MaybeAsync<mtp.RawMt_future_salt[] | null>\n\n /**\n * Get auth_key for a given DC\n * (returning null will start authorization)\n * For temp keys: should also return null if the key has expired\n *\n * @param dcId DC ID\n * @param tempIndex Index of the temporary key (usually 0, used for multi-connections)\n */\n getAuthKeyFor(dcId: number, tempIndex?: number): MaybeAsync<Uint8Array | null>\n /**\n * Set auth_key for a given DC\n */\n setAuthKeyFor(dcId: number, key: Uint8Array | null): MaybeAsync<void>\n /**\n * Set temp_auth_key for a given DC\n * expiresAt is unix time in ms\n */\n setTempAuthKeyFor(dcId: number, index: number, key: Uint8Array | null, expiresAt: number): MaybeAsync<void>\n /**\n * Remove all saved auth keys (both temp and perm)\n * for the given DC. Used when perm_key becomes invalid,\n * meaning all temp_keys also become invalid\n */\n dropAuthKeysFor(dcId: number): MaybeAsync<void>\n\n /**\n * Get information about currently logged in user (if available)\n */\n getSelf(): MaybeAsync<ITelegramStorage.SelfInfo | null>\n /**\n * Save information about currently logged in user\n */\n setSelf(self: ITelegramStorage.SelfInfo | null): MaybeAsync<void>\n\n /**\n * Update local database of input peers from the peer info list\n *\n * Client will call `.save()` after all updates-related methods\n * are called, so you can safely batch these updates\n */\n updatePeers(peers: ITelegramStorage.PeerInfo[]): MaybeAsync<void>\n\n /**\n * Find a peer in local database by its marked ID\n *\n * If no peer was found, the storage should try searching its\n * reference messages database. If a reference message is found,\n * a `inputPeer*FromMessage` constructor should be returned\n */\n getPeerById(peerId: number): MaybeAsync<tl.TypeInputPeer | null>\n\n /**\n * Find a peer in local database by its username\n */\n getPeerByUsername(username: string): MaybeAsync<tl.TypeInputPeer | null>\n\n /**\n * Find a peer in local database by its phone number\n */\n getPeerByPhone(phone: string): MaybeAsync<tl.TypeInputPeer | null>\n\n /**\n * For `*FromMessage` constructors: store a reference to a `peerId` -\n * it was seen in message `messageId` in chat `chatId`.\n *\n * `peerId` and `chatId` are marked peer IDs.\n *\n * Learn more: https://core.telegram.org/api/min\n */\n saveReferenceMessage(peerId: number, chatId: number, messageId: number): MaybeAsync<void>\n\n /**\n * For `*FromMessage` constructors: messages `messageIds` in chat `chatId` were deleted,\n * so remove any stored peer references to them.\n */\n deleteReferenceMessages(chatId: number, messageIds: number[]): MaybeAsync<void>\n\n /**\n * Get updates state (if available), represented as a tuple\n * containing: `pts, qts, date, seq`\n */\n getUpdatesState(): MaybeAsync<[number, number, number, number] | null>\n\n /**\n * Set common `pts` value\n *\n * Client will call `.save()` after all updates-related methods\n * are called, so you can safely batch these updates\n */\n setUpdatesPts(val: number): MaybeAsync<void>\n /**\n * Set common `qts` value\n *\n * Client will call `.save()` after all updates-related methods\n * are called, so you can safely batch these updates\n */\n setUpdatesQts(val: number): MaybeAsync<void>\n /**\n * Set updates `date` value\n *\n * Client will call `.save()` after all updates-related methods\n * are called, so you can safely batch these updates\n */\n setUpdatesDate(val: number): MaybeAsync<void>\n /**\n * Set updates `seq` value\n *\n * Client will call `.save()` after all updates-related methods\n * are called, so you can safely batch these updates\n */\n setUpdatesSeq(val: number): MaybeAsync<void>\n\n /**\n * Get channel `pts` value\n */\n getChannelPts(entityId: number): MaybeAsync<number | null>\n /**\n * Set channels `pts` values in batch.\n *\n * Storage is supposed to replace stored channel `pts` values\n * with given in the object (key is unmarked peer id, value is the `pts`)\n *\n * Client will call `.save()` after all updates-related methods\n * are called, so you can safely batch these updates\n */\n setManyChannelPts(values: Map<number, number>): MaybeAsync<void>\n\n /**\n * Get cached peer information by their marked ID.\n * Return `null` if caching is not supported, or the entity\n * is not cached (yet).\n *\n * This is primarily used when a `min` entity is encountered\n * in an update, or when a *short* update is encountered.\n * Returning `null` will require re-fetching that\n * update with the peers added, which might not be very efficient.\n */\n getFullPeerById(id: number): MaybeAsync<tl.TypeUser | tl.TypeChat | null>\n}\n"]}
@@ -14,7 +14,7 @@ import { JsonMemoryStorage } from './json.js';
14
14
  export declare class JsonFileStorage extends JsonMemoryStorage {
15
15
  private readonly _filename;
16
16
  private readonly _safe;
17
- private readonly _cleanup;
17
+ private readonly _cleanupUnregister?;
18
18
  constructor(filename: string, params?: {
19
19
  /**
20
20
  * Whether to save file "safely", meaning that the file will first be saved
@@ -37,7 +37,6 @@ export declare class JsonFileStorage extends JsonMemoryStorage {
37
37
  });
38
38
  load(): Promise<void>;
39
39
  save(): Promise<void>;
40
- private _processExitHandled;
41
40
  private _onProcessExit;
42
41
  destroy(): void;
43
42
  }
@@ -1,7 +1,7 @@
1
1
  // eslint-disable-next-line no-restricted-imports
2
2
  import * as fs from 'fs';
3
+ import { beforeExit } from '../utils/index.js';
3
4
  import { JsonMemoryStorage } from './json.js';
4
- const EVENTS = ['exit', 'SIGINT', 'SIGUSR1', 'SIGUSR2', 'uncaughtException', 'SIGTERM'];
5
5
  /**
6
6
  * mtcute storage that stores data in a JSON file.
7
7
  *
@@ -17,13 +17,10 @@ const EVENTS = ['exit', 'SIGINT', 'SIGUSR1', 'SIGUSR2', 'uncaughtException', 'SI
17
17
  export class JsonFileStorage extends JsonMemoryStorage {
18
18
  constructor(filename, params) {
19
19
  super();
20
- this._processExitHandled = false;
21
20
  this._filename = filename;
22
21
  this._safe = params?.safe ?? true;
23
- this._cleanup = params?.cleanup ?? true;
24
- if (this._cleanup) {
25
- this._onProcessExit = this._onProcessExit.bind(this);
26
- EVENTS.forEach((event) => process.on(event, this._onProcessExit));
22
+ if (params?.cleanup !== false) {
23
+ this._cleanupUnregister = beforeExit(() => this._onProcessExit());
27
24
  }
28
25
  }
29
26
  async load() {
@@ -52,9 +49,6 @@ export class JsonFileStorage extends JsonMemoryStorage {
52
49
  }
53
50
  _onProcessExit() {
54
51
  // on exit handler must be synchronous, thus we use sync methods here
55
- if (this._processExitHandled)
56
- return;
57
- this._processExitHandled = true;
58
52
  try {
59
53
  fs.writeFileSync(this._filename, this._saveJson());
60
54
  }
@@ -67,9 +61,7 @@ export class JsonFileStorage extends JsonMemoryStorage {
67
61
  }
68
62
  }
69
63
  destroy() {
70
- if (this._cleanup) {
71
- EVENTS.forEach((event) => process.off(event, this._onProcessExit));
72
- }
64
+ this._cleanupUnregister?.();
73
65
  }
74
66
  }
75
67
  //# sourceMappingURL=json-file.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"json-file.js","sourceRoot":"","sources":["../../../src/storage/json-file.ts"],"names":[],"mappings":"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","sourcesContent":["// eslint-disable-next-line no-restricted-imports\nimport * as fs from 'fs'\n\nimport { JsonMemoryStorage } from './json.js'\n\nconst EVENTS = ['exit', 'SIGINT', 'SIGUSR1', 'SIGUSR2', 'uncaughtException', 'SIGTERM']\n\n/**\n * mtcute storage that stores data in a JSON file.\n *\n * > **Note**: This storage is **not fully persistent**, meaning that\n * > some data *will* be lost on restart, including entities cache,\n * > FSM and rate limiter states, because JSON file would be too large otherwise.\n * >\n * > This storage should only be used for testing purposes,\n * > and should not be used in production. Use e.g. `@mtcute/sqlite` instead.\n *\n * @deprecated\n */\nexport class JsonFileStorage extends JsonMemoryStorage {\n private readonly _filename: string\n private readonly _safe: boolean\n private readonly _cleanup: boolean\n\n constructor(\n filename: string,\n params?: {\n /**\n * Whether to save file \"safely\", meaning that the file will first be saved\n * to `${filename}.tmp`, and then renamed to `filename`,\n * instead of writing directly to `filename`.\n *\n * This solves the issue with the storage being saved as\n * a blank file because of the app being stopped while\n * the storage is being written.\n *\n * @default `true`\n */\n safe?: boolean\n\n /**\n * Whether to save file on process exit.\n *\n * @default `true`\n */\n cleanup?: boolean\n },\n ) {\n super()\n\n this._filename = filename\n this._safe = params?.safe ?? true\n this._cleanup = params?.cleanup ?? true\n\n if (this._cleanup) {\n this._onProcessExit = this._onProcessExit.bind(this)\n EVENTS.forEach((event) => process.on(event, this._onProcessExit))\n }\n }\n\n async load(): Promise<void> {\n try {\n this._loadJson(\n await new Promise((res, rej) =>\n fs.readFile(this._filename, 'utf-8', (err, data) => (err ? rej(err) : res(data))),\n ),\n )\n } catch (e) {}\n }\n\n save(): Promise<void> {\n return new Promise((resolve, reject) => {\n fs.writeFile(this._safe ? this._filename + '.tmp' : this._filename, this._saveJson(), (err) => {\n if (err) reject(err)\n else if (this._safe) {\n fs.rename(this._filename + '.tmp', this._filename, (err) => {\n if (err && err.code !== 'ENOENT') reject(err)\n else resolve()\n })\n } else resolve()\n })\n })\n }\n\n private _processExitHandled = false\n private _onProcessExit(): void {\n // on exit handler must be synchronous, thus we use sync methods here\n if (this._processExitHandled) return\n this._processExitHandled = true\n\n try {\n fs.writeFileSync(this._filename, this._saveJson())\n } catch (e) {}\n\n if (this._safe) {\n try {\n fs.unlinkSync(this._filename + '.tmp')\n } catch (e) {}\n }\n }\n\n destroy(): void {\n if (this._cleanup) {\n EVENTS.forEach((event) => process.off(event, this._onProcessExit))\n }\n }\n}\n"]}
1
+ {"version":3,"file":"json-file.js","sourceRoot":"","sources":["../../../src/storage/json-file.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AAExB,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAE7C;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,eAAgB,SAAQ,iBAAiB;IAKlD,YACI,QAAgB,EAChB,MAoBC;QAED,KAAK,EAAE,CAAA;QAEP,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAA;QACzB,IAAI,CAAC,KAAK,GAAG,MAAM,EAAE,IAAI,IAAI,IAAI,CAAA;QAEjC,IAAI,MAAM,EAAE,OAAO,KAAK,KAAK,EAAE;YAC3B,IAAI,CAAC,kBAAkB,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,CAAA;SACpE;IACL,CAAC;IAED,KAAK,CAAC,IAAI;QACN,IAAI;YACA,IAAI,CAAC,SAAS,CACV,MAAM,IAAI,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAC3B,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CACpF,CACJ,CAAA;SACJ;QAAC,OAAO,CAAC,EAAE,GAAE;IAClB,CAAC;IAED,IAAI;QACA,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC1F,IAAI,GAAG;oBAAE,MAAM,CAAC,GAAG,CAAC,CAAA;qBACf,IAAI,IAAI,CAAC,KAAK,EAAE;oBACjB,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,GAAG,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE;wBACvD,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ;4BAAE,MAAM,CAAC,GAAG,CAAC,CAAA;;4BACxC,OAAO,EAAE,CAAA;oBAClB,CAAC,CAAC,CAAA;iBACL;;oBAAM,OAAO,EAAE,CAAA;YACpB,CAAC,CAAC,CAAA;QACN,CAAC,CAAC,CAAA;IACN,CAAC;IAEO,cAAc;QAClB,qEAAqE;QACrE,IAAI;YACA,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;SACrD;QAAC,OAAO,CAAC,EAAE,GAAE;QAEd,IAAI,IAAI,CAAC,KAAK,EAAE;YACZ,IAAI;gBACA,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,CAAA;aACzC;YAAC,OAAO,CAAC,EAAE,GAAE;SACjB;IACL,CAAC;IAED,OAAO;QACH,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAA;IAC/B,CAAC;CACJ","sourcesContent":["// eslint-disable-next-line no-restricted-imports\nimport * as fs from 'fs'\n\nimport { beforeExit } from '../utils/index.js'\nimport { JsonMemoryStorage } from './json.js'\n\n/**\n * mtcute storage that stores data in a JSON file.\n *\n * > **Note**: This storage is **not fully persistent**, meaning that\n * > some data *will* be lost on restart, including entities cache,\n * > FSM and rate limiter states, because JSON file would be too large otherwise.\n * >\n * > This storage should only be used for testing purposes,\n * > and should not be used in production. Use e.g. `@mtcute/sqlite` instead.\n *\n * @deprecated\n */\nexport class JsonFileStorage extends JsonMemoryStorage {\n private readonly _filename: string\n private readonly _safe: boolean\n private readonly _cleanupUnregister?: () => void\n\n constructor(\n filename: string,\n params?: {\n /**\n * Whether to save file \"safely\", meaning that the file will first be saved\n * to `${filename}.tmp`, and then renamed to `filename`,\n * instead of writing directly to `filename`.\n *\n * This solves the issue with the storage being saved as\n * a blank file because of the app being stopped while\n * the storage is being written.\n *\n * @default `true`\n */\n safe?: boolean\n\n /**\n * Whether to save file on process exit.\n *\n * @default `true`\n */\n cleanup?: boolean\n },\n ) {\n super()\n\n this._filename = filename\n this._safe = params?.safe ?? true\n\n if (params?.cleanup !== false) {\n this._cleanupUnregister = beforeExit(() => this._onProcessExit())\n }\n }\n\n async load(): Promise<void> {\n try {\n this._loadJson(\n await new Promise((res, rej) =>\n fs.readFile(this._filename, 'utf-8', (err, data) => (err ? rej(err) : res(data))),\n ),\n )\n } catch (e) {}\n }\n\n save(): Promise<void> {\n return new Promise((resolve, reject) => {\n fs.writeFile(this._safe ? this._filename + '.tmp' : this._filename, this._saveJson(), (err) => {\n if (err) reject(err)\n else if (this._safe) {\n fs.rename(this._filename + '.tmp', this._filename, (err) => {\n if (err && err.code !== 'ENOENT') reject(err)\n else resolve()\n })\n } else resolve()\n })\n })\n }\n\n private _onProcessExit(): void {\n // on exit handler must be synchronous, thus we use sync methods here\n try {\n fs.writeFileSync(this._filename, this._saveJson())\n } catch (e) {}\n\n if (this._safe) {\n try {\n fs.unlinkSync(this._filename + '.tmp')\n } catch (e) {}\n }\n }\n\n destroy(): void {\n this._cleanupUnregister?.()\n }\n}\n"]}
@@ -16,6 +16,7 @@ export * from './lru-map.js';
16
16
  export * from './lru-set.js';
17
17
  export * from './misc-utils.js';
18
18
  export * from './peer-utils.js';
19
+ export * from './platform/exit-hook.js';
19
20
  export * from './sorted-array.js';
20
21
  export * from './string-session.js';
21
22
  export * from './tl-json.js';
@@ -16,6 +16,7 @@ export * from './lru-map.js';
16
16
  export * from './lru-set.js';
17
17
  export * from './misc-utils.js';
18
18
  export * from './peer-utils.js';
19
+ export * from './platform/exit-hook.js';
19
20
  export * from './sorted-array.js';
20
21
  export * from './string-session.js';
21
22
  export * from './tl-json.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,yBAAyB,CAAA;AACvC,cAAc,2BAA2B,CAAA;AACzC,cAAc,mBAAmB,CAAA;AACjC,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,qBAAqB,CAAA;AACnC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,mBAAmB,CAAA;AACjC,cAAc,qBAAqB,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,cAAc,sBAAsB,CAAA;AACpC,cAAc,oBAAoB,CAAA","sourcesContent":["export * from './async-lock.js'\nexport * from './bigint-utils.js'\nexport * from './buffer-utils.js'\nexport * from './condition-variable.js'\nexport * from './controllable-promise.js'\nexport * from './crypto/index.js'\nexport * from './default-dcs.js'\nexport * from './deque.js'\nexport * from './early-timer.js'\nexport * from './function-utils.js'\nexport * from './linked-list.js'\nexport * from './links/index.js'\nexport * from './logger.js'\nexport * from './long-utils.js'\nexport * from './lru-map.js'\nexport * from './lru-set.js'\nexport * from './misc-utils.js'\nexport * from './peer-utils.js'\nexport * from './sorted-array.js'\nexport * from './string-session.js'\nexport * from './tl-json.js'\nexport * from './type-assertions.js'\nexport * from '@mtcute/tl-runtime'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,yBAAyB,CAAA;AACvC,cAAc,2BAA2B,CAAA;AACzC,cAAc,mBAAmB,CAAA;AACjC,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAC1B,cAAc,kBAAkB,CAAA;AAChC,cAAc,qBAAqB,CAAA;AACnC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,yBAAyB,CAAA;AACvC,cAAc,mBAAmB,CAAA;AACjC,cAAc,qBAAqB,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,cAAc,sBAAsB,CAAA;AACpC,cAAc,oBAAoB,CAAA","sourcesContent":["export * from './async-lock.js'\nexport * from './bigint-utils.js'\nexport * from './buffer-utils.js'\nexport * from './condition-variable.js'\nexport * from './controllable-promise.js'\nexport * from './crypto/index.js'\nexport * from './default-dcs.js'\nexport * from './deque.js'\nexport * from './early-timer.js'\nexport * from './function-utils.js'\nexport * from './linked-list.js'\nexport * from './links/index.js'\nexport * from './logger.js'\nexport * from './long-utils.js'\nexport * from './lru-map.js'\nexport * from './lru-set.js'\nexport * from './misc-utils.js'\nexport * from './peer-utils.js'\nexport * from './platform/exit-hook.js'\nexport * from './sorted-array.js'\nexport * from './string-session.js'\nexport * from './tl-json.js'\nexport * from './type-assertions.js'\nexport * from '@mtcute/tl-runtime'\n"]}
@@ -0,0 +1 @@
1
+ export declare function beforeExit(fn: () => void): () => void;
@@ -0,0 +1,41 @@
1
+ // roughly based on https://github.com/sindresorhus/exit-hook/blob/main/index.js, MIT license
2
+ let installed = false;
3
+ let handled = false;
4
+ const callbacks = new Set();
5
+ function exit(shouldManuallyExit, signal, event) {
6
+ return function eventHandler() {
7
+ if (handled) {
8
+ return;
9
+ }
10
+ handled = true;
11
+ const exitCode = 128 + signal;
12
+ for (const callback of callbacks) {
13
+ callback();
14
+ }
15
+ if (shouldManuallyExit) {
16
+ // if the user has some custom handlers after us, we don't want to exit the process
17
+ const listeners = process.rawListeners(event);
18
+ const idx = listeners.indexOf(eventHandler);
19
+ if (idx === listeners.length - 1) {
20
+ process.exit(exitCode);
21
+ }
22
+ }
23
+ };
24
+ }
25
+ export function beforeExit(fn) {
26
+ // unsupported platform
27
+ if (typeof process === 'undefined')
28
+ return () => { };
29
+ if (!installed) {
30
+ installed = true;
31
+ process.on('beforeExit', exit(true, -128, 'beforeExit'));
32
+ process.on('SIGINT', exit(true, 2, 'SIGINT'));
33
+ process.on('SIGTERM', exit(true, 15, 'SIGINT'));
34
+ process.on('exit', exit(false, 15, 'exit'));
35
+ }
36
+ callbacks.add(fn);
37
+ return () => {
38
+ callbacks.delete(fn);
39
+ };
40
+ }
41
+ //# sourceMappingURL=exit-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-hook.js","sourceRoot":"","sources":["../../../../src/utils/platform/exit-hook.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAE7F,IAAI,SAAS,GAAG,KAAK,CAAA;AACrB,IAAI,OAAO,GAAG,KAAK,CAAA;AAEnB,MAAM,SAAS,GAAG,IAAI,GAAG,EAAc,CAAA;AAEvC,SAAS,IAAI,CAAC,kBAA2B,EAAE,MAAc,EAAE,KAAa;IACpE,OAAO,SAAS,YAAY;QACxB,IAAI,OAAO,EAAE;YACT,OAAM;SACT;QAED,OAAO,GAAG,IAAI,CAAA;QAEd,MAAM,QAAQ,GAAG,GAAG,GAAG,MAAM,CAAA;QAE7B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;YAC9B,QAAQ,EAAE,CAAA;SACb;QAED,IAAI,kBAAkB,EAAE;YACpB,mFAAmF;YAEnF,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;YAC7C,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;YAE3C,IAAI,GAAG,KAAK,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;gBAC9B,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;aACzB;SACJ;IACL,CAAC,CAAA;AACL,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,EAAc;IACrC,uBAAuB;IACvB,IAAI,OAAO,OAAO,KAAK,WAAW;QAAE,OAAO,GAAG,EAAE,GAAE,CAAC,CAAA;IAEnD,IAAI,CAAC,SAAS,EAAE;QACZ,SAAS,GAAG,IAAI,CAAA;QAEhB,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAA;QACxD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAA;QAC7C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAA;QAC/C,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,CAAA;KAC9C;IAED,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAEjB,OAAO,GAAG,EAAE;QACR,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IACxB,CAAC,CAAA;AACL,CAAC","sourcesContent":["// roughly based on https://github.com/sindresorhus/exit-hook/blob/main/index.js, MIT license\n\nlet installed = false\nlet handled = false\n\nconst callbacks = new Set<() => void>()\n\nfunction exit(shouldManuallyExit: boolean, signal: number, event: string) {\n return function eventHandler() {\n if (handled) {\n return\n }\n\n handled = true\n\n const exitCode = 128 + signal\n\n for (const callback of callbacks) {\n callback()\n }\n\n if (shouldManuallyExit) {\n // if the user has some custom handlers after us, we don't want to exit the process\n\n const listeners = process.rawListeners(event)\n const idx = listeners.indexOf(eventHandler)\n\n if (idx === listeners.length - 1) {\n process.exit(exitCode)\n }\n }\n }\n}\n\nexport function beforeExit(fn: () => void): () => void {\n // unsupported platform\n if (typeof process === 'undefined') return () => {}\n\n if (!installed) {\n installed = true\n\n process.on('beforeExit', exit(true, -128, 'beforeExit'))\n process.on('SIGINT', exit(true, 2, 'SIGINT'))\n process.on('SIGTERM', exit(true, 15, 'SIGINT'))\n process.on('exit', exit(false, 15, 'exit'))\n }\n\n callbacks.add(fn)\n\n return () => {\n callbacks.delete(fn)\n }\n}\n"]}
@@ -0,0 +1 @@
1
+ export declare function beforeExit(fn: () => void): () => void;
@@ -0,0 +1,17 @@
1
+ const callbacks = new Set();
2
+ let registered = false;
3
+ export function beforeExit(fn) {
4
+ if (!registered) {
5
+ registered = true;
6
+ window.addEventListener('beforeunload', () => {
7
+ for (const callback of callbacks) {
8
+ callback();
9
+ }
10
+ });
11
+ }
12
+ callbacks.add(fn);
13
+ return () => {
14
+ callbacks.delete(fn);
15
+ };
16
+ }
17
+ //# sourceMappingURL=exit-hook.web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-hook.web.js","sourceRoot":"","sources":["../../../../src/utils/platform/exit-hook.web.ts"],"names":[],"mappings":"AAAA,MAAM,SAAS,GAAG,IAAI,GAAG,EAAc,CAAA;AAEvC,IAAI,UAAU,GAAG,KAAK,CAAA;AAEtB,MAAM,UAAU,UAAU,CAAC,EAAc;IACrC,IAAI,CAAC,UAAU,EAAE;QACb,UAAU,GAAG,IAAI,CAAA;QAEjB,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,GAAG,EAAE;YACzC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;gBAC9B,QAAQ,EAAE,CAAA;aACb;QACL,CAAC,CAAC,CAAA;KACL;IAED,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAEjB,OAAO,GAAG,EAAE;QACR,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IACxB,CAAC,CAAA;AACL,CAAC","sourcesContent":["const callbacks = new Set<() => void>()\n\nlet registered = false\n\nexport function beforeExit(fn: () => void): () => void {\n if (!registered) {\n registered = true\n\n window.addEventListener('beforeunload', () => {\n for (const callback of callbacks) {\n callback()\n }\n })\n }\n\n callbacks.add(fn)\n\n return () => {\n callbacks.delete(fn)\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mtcute/core",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Core functions and base MTProto client",
5
5
  "author": "Alina Sireneva <alina@tei.su>",
6
6
  "license": "MIT",
@@ -16,13 +16,15 @@
16
16
  "./cjs/utils/platform/logging.js": "./cjs/utils/platform/logging.web.js",
17
17
  "./esm/utils/platform/random.js": "./esm/utils/platform/random.web.js",
18
18
  "./cjs/utils/platform/random.js": "./cjs/utils/platform/random.web.js",
19
+ "./esm/utils/platform/exit-hook.js": "./esm/utils/platform/exit-hook.web.js",
20
+ "./cjs/utils/platform/exit-hook.js": "./cjs/utils/platform/exit-hook.web.js",
19
21
  "./esm/storage/json-file.js": false,
20
22
  "./cjs/storage/json-file.js": false
21
23
  },
22
24
  "dependencies": {
23
- "@mtcute/tl": "^167.0.1",
24
- "@mtcute/tl-runtime": "^0.3.0",
25
- "@mtcute/wasm": "^0.3.0",
25
+ "@mtcute/tl": "^169.0.0",
26
+ "@mtcute/tl-runtime": "^0.5.0",
27
+ "@mtcute/wasm": "^0.5.0",
26
28
  "@types/events": "3.0.0",
27
29
  "events": "3.2.0",
28
30
  "long": "5.2.3"