@mtcute/core 0.27.3 → 0.27.4

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.
@@ -2035,7 +2035,16 @@ export interface TelegramClient extends ITelegramClient {
2035
2035
  *
2036
2036
  * @param params Download parameters
2037
2037
  */
2038
- downloadAsIterable(input: FileDownloadLocation, params?: FileDownloadParameters): AsyncIterableIterator<Uint8Array>;
2038
+ downloadAsIterable(input: FileDownloadLocation, params?: FileDownloadParameters & {
2039
+ /**
2040
+ * A function to apply backpressure to the download.
2041
+ *
2042
+ * If the consumer isn't keeping up, the function is supposed to return a promise that resolves when the consumer is ready to receive more data.
2043
+ *
2044
+ * Note that this function will likely get called multiple times simultaneously, since the download is parallelized.
2045
+ */
2046
+ throttle?: (chunkSize: number) => MaybePromise<void>;
2047
+ }): AsyncIterableIterator<Uint8Array>;
2039
2048
  /**
2040
2049
  * Download a remote file as a Node.js Readable stream.
2041
2050
  *
@@ -2045,14 +2054,25 @@ export interface TelegramClient extends ITelegramClient {
2045
2054
  */
2046
2055
  downloadAsNodeStream(location: FileDownloadLocation, params?: FileDownloadParameters): import('node:stream').Readable;
2047
2056
  /**
2048
- * Download a file and return it as a `@fuman/io` stream,
2057
+ * Download a file and return it as a Web Stream,
2049
2058
  * streaming file contents.
2050
2059
  *
2051
2060
  * **Available**: ✅ both users and bots
2052
2061
  *
2053
2062
  * @param params File download parameters
2054
2063
  */
2055
- downloadAsStream(location: FileDownloadLocation, params?: FileDownloadParameters): ReadableStream<Uint8Array>;
2064
+ downloadAsStream(location: FileDownloadLocation, params?: FileDownloadParameters & {
2065
+ /**
2066
+ * If passed, the maximum number of bytes that can be buffered in the stream.
2067
+ *
2068
+ * If the consumer isn't keeping up, the stream will pause until the buffer is below this limit.
2069
+ *
2070
+ * Note that this parameter is not guaranteed to be strictly the maximum number of bytes
2071
+ * buffered at once, since the underlying download is parallelized, and is treated merely as a hint.
2072
+ * The actual number of bytes buffered at once can be as much as `partSize * numWorkers`
2073
+ */
2074
+ highWaterMark?: number;
2075
+ }): ReadableStream<Uint8Array>;
2056
2076
  /**
2057
2077
  * Normalize a {@link InputFileLike} to `InputFile`,
2058
2078
  * uploading it if needed.
@@ -2035,7 +2035,16 @@ export interface TelegramClient extends ITelegramClient {
2035
2035
  *
2036
2036
  * @param params Download parameters
2037
2037
  */
2038
- downloadAsIterable(input: FileDownloadLocation, params?: FileDownloadParameters): AsyncIterableIterator<Uint8Array>;
2038
+ downloadAsIterable(input: FileDownloadLocation, params?: FileDownloadParameters & {
2039
+ /**
2040
+ * A function to apply backpressure to the download.
2041
+ *
2042
+ * If the consumer isn't keeping up, the function is supposed to return a promise that resolves when the consumer is ready to receive more data.
2043
+ *
2044
+ * Note that this function will likely get called multiple times simultaneously, since the download is parallelized.
2045
+ */
2046
+ throttle?: (chunkSize: number) => MaybePromise<void>;
2047
+ }): AsyncIterableIterator<Uint8Array>;
2039
2048
  /**
2040
2049
  * Download a remote file as a Node.js Readable stream.
2041
2050
  *
@@ -2045,14 +2054,25 @@ export interface TelegramClient extends ITelegramClient {
2045
2054
  */
2046
2055
  downloadAsNodeStream(location: FileDownloadLocation, params?: FileDownloadParameters): import('node:stream').Readable;
2047
2056
  /**
2048
- * Download a file and return it as a `@fuman/io` stream,
2057
+ * Download a file and return it as a Web Stream,
2049
2058
  * streaming file contents.
2050
2059
  *
2051
2060
  * **Available**: ✅ both users and bots
2052
2061
  *
2053
2062
  * @param params File download parameters
2054
2063
  */
2055
- downloadAsStream(location: FileDownloadLocation, params?: FileDownloadParameters): ReadableStream<Uint8Array>;
2064
+ downloadAsStream(location: FileDownloadLocation, params?: FileDownloadParameters & {
2065
+ /**
2066
+ * If passed, the maximum number of bytes that can be buffered in the stream.
2067
+ *
2068
+ * If the consumer isn't keeping up, the stream will pause until the buffer is below this limit.
2069
+ *
2070
+ * Note that this parameter is not guaranteed to be strictly the maximum number of bytes
2071
+ * buffered at once, since the underlying download is parallelized, and is treated merely as a hint.
2072
+ * The actual number of bytes buffered at once can be as much as `partSize * numWorkers`
2073
+ */
2074
+ highWaterMark?: number;
2075
+ }): ReadableStream<Uint8Array>;
2056
2076
  /**
2057
2077
  * Normalize a {@link InputFileLike} to `InputFile`,
2058
2078
  * uploading it if needed.
@@ -121,6 +121,10 @@ async function* downloadAsIterable(client, input, params) {
121
121
  if (ended) {
122
122
  return;
123
123
  }
124
+ const throttlePromise = params?.throttle?.(chunkSize);
125
+ if (throttlePromise) {
126
+ await throttlePromise;
127
+ }
124
128
  try {
125
129
  result = await client.call(
126
130
  {
@@ -1,3 +1,4 @@
1
+ import { MaybePromise } from '@fuman/utils';
1
2
  import { ITelegramClient } from '../../client.types.js';
2
3
  import { FileDownloadLocation, FileDownloadParameters } from '../../types/index.js';
3
4
  import { tl } from '@mtcute/tl';
@@ -13,4 +14,13 @@ export declare function _normalizeFileDownloadLocation(client: ITelegramClient,
13
14
  *
14
15
  * @param params Download parameters
15
16
  */
16
- export declare function downloadAsIterable(client: ITelegramClient, input: FileDownloadLocation, params?: FileDownloadParameters): AsyncIterableIterator<Uint8Array>;
17
+ export declare function downloadAsIterable(client: ITelegramClient, input: FileDownloadLocation, params?: FileDownloadParameters & {
18
+ /**
19
+ * A function to apply backpressure to the download.
20
+ *
21
+ * If the consumer isn't keeping up, the function is supposed to return a promise that resolves when the consumer is ready to receive more data.
22
+ *
23
+ * Note that this function will likely get called multiple times simultaneously, since the download is parallelized.
24
+ */
25
+ throttle?: (chunkSize: number) => MaybePromise<void>;
26
+ }): AsyncIterableIterator<Uint8Array>;
@@ -1,3 +1,4 @@
1
+ import { MaybePromise } from '@fuman/utils';
1
2
  import { ITelegramClient } from '../../client.types.js';
2
3
  import { FileDownloadLocation, FileDownloadParameters } from '../../types/index.js';
3
4
  import { tl } from '@mtcute/tl';
@@ -13,4 +14,13 @@ export declare function _normalizeFileDownloadLocation(client: ITelegramClient,
13
14
  *
14
15
  * @param params Download parameters
15
16
  */
16
- export declare function downloadAsIterable(client: ITelegramClient, input: FileDownloadLocation, params?: FileDownloadParameters): AsyncIterableIterator<Uint8Array>;
17
+ export declare function downloadAsIterable(client: ITelegramClient, input: FileDownloadLocation, params?: FileDownloadParameters & {
18
+ /**
19
+ * A function to apply backpressure to the download.
20
+ *
21
+ * If the consumer isn't keeping up, the function is supposed to return a promise that resolves when the consumer is ready to receive more data.
22
+ *
23
+ * Note that this function will likely get called multiple times simultaneously, since the download is parallelized.
24
+ */
25
+ throttle?: (chunkSize: number) => MaybePromise<void>;
26
+ }): AsyncIterableIterator<Uint8Array>;
@@ -114,6 +114,10 @@ async function* downloadAsIterable(client, input, params) {
114
114
  if (ended) {
115
115
  return;
116
116
  }
117
+ const throttlePromise = params?.throttle?.(chunkSize);
118
+ if (throttlePromise) {
119
+ await throttlePromise;
120
+ }
117
121
  try {
118
122
  result = await client.call(
119
123
  {
@@ -5,6 +5,7 @@ if (typeof globalThis !== "undefined" && !globalThis._MTCUTE_CJS_DEPRECATION_WAR
5
5
  }
6
6
  "use strict";
7
7
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
8
+ const utils = require("@fuman/utils");
8
9
  const downloadIterable = require("./download-iterable.cjs");
9
10
  const fileLocation = require("../../types/files/file-location.cjs");
10
11
  function downloadAsStream(client, location, params) {
@@ -23,18 +24,31 @@ function downloadAsStream(client, location, params) {
23
24
  cancel.abort();
24
25
  });
25
26
  }
27
+ const backpressureCv = new utils.ConditionVariable();
26
28
  return new ReadableStream({
27
29
  start(controller) {
28
30
  (async () => {
31
+ const params_ = params ?? {};
32
+ params_.throttle = () => {
33
+ if (controller.desiredSize != null && controller.desiredSize <= 0) {
34
+ return backpressureCv.wait();
35
+ }
36
+ };
29
37
  for await (const chunk of downloadIterable.downloadAsIterable(client, location, params)) {
30
38
  controller.enqueue(chunk);
31
39
  }
32
40
  controller.close();
33
41
  })().catch((e) => controller.error(e));
34
42
  },
43
+ pull() {
44
+ backpressureCv.notify();
45
+ },
35
46
  cancel() {
36
47
  cancel.abort();
37
48
  }
49
+ }, {
50
+ highWaterMark: params?.highWaterMark,
51
+ size: (chunk) => chunk?.length ?? 0
38
52
  });
39
53
  }
40
54
  exports.downloadAsStream = downloadAsStream;
@@ -1,9 +1,20 @@
1
1
  import { ITelegramClient } from '../../client.types.js';
2
2
  import { FileDownloadLocation, FileDownloadParameters } from '../../types/index.js';
3
3
  /**
4
- * Download a file and return it as a `@fuman/io` stream,
4
+ * Download a file and return it as a Web Stream,
5
5
  * streaming file contents.
6
6
  *
7
7
  * @param params File download parameters
8
8
  */
9
- export declare function downloadAsStream(client: ITelegramClient, location: FileDownloadLocation, params?: FileDownloadParameters): ReadableStream<Uint8Array>;
9
+ export declare function downloadAsStream(client: ITelegramClient, location: FileDownloadLocation, params?: FileDownloadParameters & {
10
+ /**
11
+ * If passed, the maximum number of bytes that can be buffered in the stream.
12
+ *
13
+ * If the consumer isn't keeping up, the stream will pause until the buffer is below this limit.
14
+ *
15
+ * Note that this parameter is not guaranteed to be strictly the maximum number of bytes
16
+ * buffered at once, since the underlying download is parallelized, and is treated merely as a hint.
17
+ * The actual number of bytes buffered at once can be as much as `partSize * numWorkers`
18
+ */
19
+ highWaterMark?: number;
20
+ }): ReadableStream<Uint8Array>;
@@ -1,9 +1,20 @@
1
1
  import { ITelegramClient } from '../../client.types.js';
2
2
  import { FileDownloadLocation, FileDownloadParameters } from '../../types/index.js';
3
3
  /**
4
- * Download a file and return it as a `@fuman/io` stream,
4
+ * Download a file and return it as a Web Stream,
5
5
  * streaming file contents.
6
6
  *
7
7
  * @param params File download parameters
8
8
  */
9
- export declare function downloadAsStream(client: ITelegramClient, location: FileDownloadLocation, params?: FileDownloadParameters): ReadableStream<Uint8Array>;
9
+ export declare function downloadAsStream(client: ITelegramClient, location: FileDownloadLocation, params?: FileDownloadParameters & {
10
+ /**
11
+ * If passed, the maximum number of bytes that can be buffered in the stream.
12
+ *
13
+ * If the consumer isn't keeping up, the stream will pause until the buffer is below this limit.
14
+ *
15
+ * Note that this parameter is not guaranteed to be strictly the maximum number of bytes
16
+ * buffered at once, since the underlying download is parallelized, and is treated merely as a hint.
17
+ * The actual number of bytes buffered at once can be as much as `partSize * numWorkers`
18
+ */
19
+ highWaterMark?: number;
20
+ }): ReadableStream<Uint8Array>;
@@ -1,3 +1,4 @@
1
+ import { ConditionVariable } from "@fuman/utils";
1
2
  import { downloadAsIterable } from "./download-iterable.js";
2
3
  import { FileLocation as FileLocation$1 } from "../../types/files/file-location.js";
3
4
  function downloadAsStream(client, location, params) {
@@ -16,18 +17,31 @@ function downloadAsStream(client, location, params) {
16
17
  cancel.abort();
17
18
  });
18
19
  }
20
+ const backpressureCv = new ConditionVariable();
19
21
  return new ReadableStream({
20
22
  start(controller) {
21
23
  (async () => {
24
+ const params_ = params ?? {};
25
+ params_.throttle = () => {
26
+ if (controller.desiredSize != null && controller.desiredSize <= 0) {
27
+ return backpressureCv.wait();
28
+ }
29
+ };
22
30
  for await (const chunk of downloadAsIterable(client, location, params)) {
23
31
  controller.enqueue(chunk);
24
32
  }
25
33
  controller.close();
26
34
  })().catch((e) => controller.error(e));
27
35
  },
36
+ pull() {
37
+ backpressureCv.notify();
38
+ },
28
39
  cancel() {
29
40
  cancel.abort();
30
41
  }
42
+ }, {
43
+ highWaterMark: params?.highWaterMark,
44
+ size: (chunk) => chunk?.length ?? 0
31
45
  });
32
46
  }
33
47
  export {
@@ -28,7 +28,7 @@ function parseDocument(doc, media) {
28
28
  switch (attr._) {
29
29
  case "documentAttributeAudio":
30
30
  if (attr.voice) {
31
- return new voice.Voice(doc, attr);
31
+ return new voice.Voice(doc, attr, media);
32
32
  }
33
33
  return new audio.Audio(doc, attr);
34
34
  case "documentAttributeVideo":
@@ -21,7 +21,7 @@ function parseDocument(doc, media) {
21
21
  switch (attr._) {
22
22
  case "documentAttributeAudio":
23
23
  if (attr.voice) {
24
- return new Voice$2(doc, attr);
24
+ return new Voice$2(doc, attr, media);
25
25
  }
26
26
  return new Audio$2(doc, attr);
27
27
  case "documentAttributeVideo":
@@ -11,9 +11,10 @@ const voiceUtils = require("../../utils/voice-utils.cjs");
11
11
  const document = require("./document.cjs");
12
12
  const inspectable = require("../../utils/inspectable.cjs");
13
13
  class Voice extends document.RawDocument {
14
- constructor(doc, attr) {
14
+ constructor(doc, attr, media) {
15
15
  super(doc);
16
16
  this.attr = attr;
17
+ this.media = media;
17
18
  }
18
19
  type = "voice";
19
20
  _fileIdType() {
@@ -34,6 +35,10 @@ class Voice extends document.RawDocument {
34
35
  get waveform() {
35
36
  return voiceUtils.decodeWaveform(this.attr.waveform);
36
37
  }
38
+ /** For self-destructing voice notes, TTL in seconds */
39
+ get ttlSeconds() {
40
+ return this.media?.ttlSeconds ?? null;
41
+ }
37
42
  }
38
43
  const Voice$1 = /* @__PURE__ */ memoize.memoizeGetters(Voice, ["fileName", "thumbnails", "fileId", "uniqueFileId", "waveform"]);
39
44
  const Voice$2 = /* @__PURE__ */ inspectable.makeInspectable(Voice$1, ["fileSize", "dcId"], ["inputMedia", "inputDocument", "waveform"]);
@@ -6,9 +6,10 @@ import { RawDocument } from './document.js';
6
6
  */
7
7
  export declare class Voice extends RawDocument {
8
8
  readonly attr: tl.RawDocumentAttributeAudio;
9
+ readonly media?: tl.RawMessageMediaDocument | undefined;
9
10
  readonly type: "voice";
10
11
  protected _fileIdType(): tdFileId.FileType;
11
- constructor(doc: tl.RawDocument, attr: tl.RawDocumentAttributeAudio);
12
+ constructor(doc: tl.RawDocument, attr: tl.RawDocumentAttributeAudio, media?: tl.RawMessageMediaDocument | undefined);
12
13
  /**
13
14
  * Duration of the voice note in seconds.
14
15
  */
@@ -20,4 +21,6 @@ export declare class Voice extends RawDocument {
20
21
  * usually has length of 100
21
22
  */
22
23
  get waveform(): number[];
24
+ /** For self-destructing voice notes, TTL in seconds */
25
+ get ttlSeconds(): number | null;
23
26
  }
@@ -6,9 +6,10 @@ import { RawDocument } from './document.js';
6
6
  */
7
7
  export declare class Voice extends RawDocument {
8
8
  readonly attr: tl.RawDocumentAttributeAudio;
9
+ readonly media?: tl.RawMessageMediaDocument | undefined;
9
10
  readonly type: "voice";
10
11
  protected _fileIdType(): tdFileId.FileType;
11
- constructor(doc: tl.RawDocument, attr: tl.RawDocumentAttributeAudio);
12
+ constructor(doc: tl.RawDocument, attr: tl.RawDocumentAttributeAudio, media?: tl.RawMessageMediaDocument | undefined);
12
13
  /**
13
14
  * Duration of the voice note in seconds.
14
15
  */
@@ -20,4 +21,6 @@ export declare class Voice extends RawDocument {
20
21
  * usually has length of 100
21
22
  */
22
23
  get waveform(): number[];
24
+ /** For self-destructing voice notes, TTL in seconds */
25
+ get ttlSeconds(): number | null;
23
26
  }
@@ -4,9 +4,10 @@ import { decodeWaveform } from "../../utils/voice-utils.js";
4
4
  import { RawDocument } from "./document.js";
5
5
  import { makeInspectable } from "../../utils/inspectable.js";
6
6
  class Voice extends RawDocument {
7
- constructor(doc, attr) {
7
+ constructor(doc, attr, media) {
8
8
  super(doc);
9
9
  this.attr = attr;
10
+ this.media = media;
10
11
  }
11
12
  type = "voice";
12
13
  _fileIdType() {
@@ -27,6 +28,10 @@ class Voice extends RawDocument {
27
28
  get waveform() {
28
29
  return decodeWaveform(this.attr.waveform);
29
30
  }
31
+ /** For self-destructing voice notes, TTL in seconds */
32
+ get ttlSeconds() {
33
+ return this.media?.ttlSeconds ?? null;
34
+ }
30
35
  }
31
36
  const Voice$1 = /* @__PURE__ */ memoizeGetters(Voice, ["fileName", "thumbnails", "fileId", "uniqueFileId", "waveform"]);
32
37
  const Voice$2 = /* @__PURE__ */ makeInspectable(Voice$1, ["fileSize", "dcId"], ["inputMedia", "inputDocument", "waveform"]);
@@ -225,7 +225,7 @@ class NetworkManager {
225
225
  _: "initConnection",
226
226
  deviceModel,
227
227
  systemVersion: "1.0",
228
- appVersion: "0.27.3",
228
+ appVersion: "0.27.4",
229
229
  systemLangCode: "en",
230
230
  langPack: "",
231
231
  // "langPacks are for official apps only"
@@ -218,7 +218,7 @@ class NetworkManager {
218
218
  _: "initConnection",
219
219
  deviceModel,
220
220
  systemVersion: "1.0",
221
- appVersion: "0.27.3",
221
+ appVersion: "0.27.4",
222
222
  systemLangCode: "en",
223
223
  langPack: "",
224
224
  // "langPacks are for official apps only"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mtcute/core",
3
3
  "type": "module",
4
- "version": "0.27.3",
4
+ "version": "0.27.4",
5
5
  "description": "Type-safe library for MTProto (Telegram API)",
6
6
  "license": "MIT",
7
7
  "scripts": {},