itd-api 0.7.0 → 0.7.1

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 (89) hide show
  1. package/dist/index.cjs +465 -9804
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +231 -4950
  4. package/dist/index.d.ts +231 -4950
  5. package/dist/index.js +331 -9670
  6. package/dist/index.js.map +1 -1
  7. package/dist/{node.cjs → node/index.cjs} +16 -14
  8. package/dist/node/index.cjs.map +1 -0
  9. package/dist/{node.d.cts → node/index.d.cts} +4 -3
  10. package/dist/{node.d.ts → node/index.d.ts} +4 -3
  11. package/dist/{node.js → node/index.js} +5 -3
  12. package/dist/node/index.js.map +1 -0
  13. package/dist/realtime/index.cjs +165 -0
  14. package/dist/realtime/index.cjs.map +1 -0
  15. package/dist/realtime/index.d.cts +51 -0
  16. package/dist/realtime/index.d.ts +51 -0
  17. package/dist/realtime/index.js +120 -0
  18. package/dist/realtime/index.js.map +1 -0
  19. package/dist/rest/index.cjs +334 -0
  20. package/dist/rest/index.cjs.map +1 -0
  21. package/dist/rest/index.d.cts +138 -0
  22. package/dist/rest/index.d.ts +138 -0
  23. package/dist/rest/index.js +238 -0
  24. package/dist/rest/index.js.map +1 -0
  25. package/dist/shared/auth-provider-BfogACAb.js +91 -0
  26. package/dist/shared/auth-provider-BfogACAb.js.map +1 -0
  27. package/dist/shared/auth-provider-CTJkKfgy.cjs +108 -0
  28. package/dist/shared/auth-provider-CTJkKfgy.cjs.map +1 -0
  29. package/dist/shared/contracts-BoT7msmq.d.cts +84 -0
  30. package/dist/shared/contracts-BoT7msmq.d.ts +84 -0
  31. package/dist/{multi-storage-Bf84xiO8.cjs → shared/cookies-DZwFq6kr.cjs} +98 -429
  32. package/dist/shared/cookies-DZwFq6kr.cjs.map +1 -0
  33. package/dist/{multi-storage-BUZaLAPO.js → shared/cookies-tX2sNwxb.js} +99 -352
  34. package/dist/shared/cookies-tX2sNwxb.js.map +1 -0
  35. package/dist/{storage-IHdXw52v.js → shared/errors-Bhrd2fJd.js} +2 -229
  36. package/dist/shared/errors-Bhrd2fJd.js.map +1 -0
  37. package/dist/{storage-DnzZPS_9.cjs → shared/errors-DfU8M5eS.cjs} +1 -288
  38. package/dist/shared/errors-DfU8M5eS.cjs.map +1 -0
  39. package/dist/shared/multi-storage--yTEqiod.cjs +150 -0
  40. package/dist/shared/multi-storage--yTEqiod.cjs.map +1 -0
  41. package/dist/shared/multi-storage-CjAPB5Kq.d.cts +72 -0
  42. package/dist/shared/multi-storage-CkvTUC5m.js +121 -0
  43. package/dist/shared/multi-storage-CkvTUC5m.js.map +1 -0
  44. package/dist/shared/multi-storage-DccjD7Ww.d.ts +72 -0
  45. package/dist/shared/options-Dg5N3r1V.cjs +189 -0
  46. package/dist/shared/options-Dg5N3r1V.cjs.map +1 -0
  47. package/dist/shared/options-DtATYdLr.js +142 -0
  48. package/dist/shared/options-DtATYdLr.js.map +1 -0
  49. package/dist/shared/render-DMp_3Nzk.d.cts +2250 -0
  50. package/dist/shared/render-DZrxhC5_.d.ts +2250 -0
  51. package/dist/shared/render-DyeHJNBw.cjs +4147 -0
  52. package/dist/shared/render-DyeHJNBw.cjs.map +1 -0
  53. package/dist/shared/render-vtLixIiU.js +3992 -0
  54. package/dist/shared/render-vtLixIiU.js.map +1 -0
  55. package/dist/shared/storage-BPJR_k4-.cjs +290 -0
  56. package/dist/shared/storage-BPJR_k4-.cjs.map +1 -0
  57. package/dist/{storage-BqMxs76Y.d.ts → shared/storage-C_eICCep.d.cts} +2 -2
  58. package/dist/{storage-BqMxs76Y.d.cts → shared/storage-C_eICCep.d.ts} +2 -2
  59. package/dist/shared/storage-D86edNCB.js +231 -0
  60. package/dist/shared/storage-D86edNCB.js.map +1 -0
  61. package/dist/shared/url-B6-bXHKt.d.cts +2083 -0
  62. package/dist/shared/url-B6-bXHKt.d.ts +2083 -0
  63. package/dist/shared/url-CYXgxqGx.js +3673 -0
  64. package/dist/shared/url-CYXgxqGx.js.map +1 -0
  65. package/dist/shared/url-yjl2c8Ie.cjs +4032 -0
  66. package/dist/shared/url-yjl2c8Ie.cjs.map +1 -0
  67. package/dist/shared/websocket-BMtihD56.d.ts +562 -0
  68. package/dist/shared/websocket-CbzB1Leq.js +1874 -0
  69. package/dist/shared/websocket-CbzB1Leq.js.map +1 -0
  70. package/dist/shared/websocket-D1p32SB2.d.cts +562 -0
  71. package/dist/shared/websocket-sYlynrr0.cjs +1945 -0
  72. package/dist/shared/websocket-sYlynrr0.cjs.map +1 -0
  73. package/dist/{web.cjs → web/index.cjs} +4 -3
  74. package/dist/web/index.cjs.map +1 -0
  75. package/dist/{web.d.cts → web/index.d.cts} +2 -2
  76. package/dist/{web.d.ts → web/index.d.ts} +2 -2
  77. package/dist/{web.js → web/index.js} +3 -2
  78. package/dist/web/index.js.map +1 -0
  79. package/package.json +40 -12
  80. package/dist/multi-storage-BUZaLAPO.js.map +0 -1
  81. package/dist/multi-storage-BUoEoW8f.d.cts +0 -154
  82. package/dist/multi-storage-Bf84xiO8.cjs.map +0 -1
  83. package/dist/multi-storage-CQSlI_kn.d.ts +0 -154
  84. package/dist/node.cjs.map +0 -1
  85. package/dist/node.js.map +0 -1
  86. package/dist/storage-DnzZPS_9.cjs.map +0 -1
  87. package/dist/storage-IHdXw52v.js.map +0 -1
  88. package/dist/web.cjs.map +0 -1
  89. package/dist/web.js.map +0 -1
@@ -1,6 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_multi_storage = require("./multi-storage-Bf84xiO8.cjs");
3
- const require_storage = require("./storage-DnzZPS_9.cjs");
2
+ const require_errors = require("../shared/errors-DfU8M5eS.cjs");
3
+ const require_storage = require("../shared/storage-BPJR_k4-.cjs");
4
+ const require_options = require("../shared/options-Dg5N3r1V.cjs");
5
+ const require_multi_storage = require("../shared/multi-storage--yTEqiod.cjs");
4
6
  //#region src/node.ts
5
7
  /**
6
8
  * `itd-api/node` — файловая система для Node, Bun и Deno.
@@ -27,8 +29,8 @@ function hasErrorCode(error, code) {
27
29
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
28
30
  }
29
31
  function fromPath(path, options = {}) {
30
- const resolved = require_multi_storage.resolveFileStreamOptions(options);
31
- if (resolved.mode === require_multi_storage.FileTransferMode.Stream) return { open: async ({ signal }) => {
32
+ const resolved = require_options.resolveFileStreamOptions(options);
33
+ if (resolved.mode === require_options.FileTransferMode.Stream) return { open: async ({ signal }) => {
32
34
  const [{ createReadStream }, { stat }, { basename }, { Readable }] = await Promise.all([
33
35
  import("node:fs"),
34
36
  import("node:fs/promises"),
@@ -36,8 +38,8 @@ function fromPath(path, options = {}) {
36
38
  import("node:stream")
37
39
  ]);
38
40
  const info = await stat(path);
39
- if (resolved.maxBytes !== void 0 && info.size > resolved.maxBytes) throw new require_storage.ItdFileError(`файл ${path} больше предела в ${resolved.maxBytes} байт: ${info.size}`, {
40
- reason: require_storage.ItdFileErrorReason.TooLarge,
41
+ if (resolved.maxBytes !== void 0 && info.size > resolved.maxBytes) throw new require_errors.ItdFileError(`файл ${path} больше предела в ${resolved.maxBytes} байт: ${info.size}`, {
42
+ reason: require_errors.ItdFileErrorReason.TooLarge,
41
43
  limit: resolved.maxBytes,
42
44
  actual: info.size
43
45
  });
@@ -47,7 +49,7 @@ function fromPath(path, options = {}) {
47
49
  });
48
50
  const source = Readable.toWeb(file);
49
51
  return {
50
- stream: require_multi_storage.boundedFileStream(source, {
52
+ stream: require_options.boundedFileStream(source, {
51
53
  ...resolved.maxBytes !== void 0 ? { maxBytes: resolved.maxBytes } : {},
52
54
  streamBufferBytes: resolved.streamBufferBytes,
53
55
  ...signal ? { signal } : {}
@@ -64,15 +66,15 @@ function fromPath(path, options = {}) {
64
66
  const [{ readFile, stat }, { basename }] = await Promise.all([import("node:fs/promises"), import("node:path")]);
65
67
  if (resolved.maxBytes !== void 0) {
66
68
  const info = await stat(path);
67
- if (info.size > resolved.maxBytes) throw new require_storage.ItdFileError(`файл ${path} больше предела в ${resolved.maxBytes} байт: ${info.size}`, {
68
- reason: require_storage.ItdFileErrorReason.TooLarge,
69
+ if (info.size > resolved.maxBytes) throw new require_errors.ItdFileError(`файл ${path} больше предела в ${resolved.maxBytes} байт: ${info.size}`, {
70
+ reason: require_errors.ItdFileErrorReason.TooLarge,
69
71
  limit: resolved.maxBytes,
70
72
  actual: info.size
71
73
  });
72
74
  }
73
75
  const file = new Uint8Array(await readFile(path, signal ? { signal } : void 0));
74
- if (resolved.maxBytes !== void 0 && file.byteLength > resolved.maxBytes) throw new require_storage.ItdFileError(`файл ${path} больше предела в ${resolved.maxBytes} байт: ${file.byteLength}`, {
75
- reason: require_storage.ItdFileErrorReason.TooLarge,
76
+ if (resolved.maxBytes !== void 0 && file.byteLength > resolved.maxBytes) throw new require_errors.ItdFileError(`файл ${path} больше предела в ${resolved.maxBytes} байт: ${file.byteLength}`, {
77
+ reason: require_errors.ItdFileErrorReason.TooLarge,
76
78
  limit: resolved.maxBytes,
77
79
  actual: file.byteLength
78
80
  });
@@ -101,7 +103,7 @@ async function readJsonFile(path) {
101
103
  try {
102
104
  return JSON.parse(raw);
103
105
  } catch {
104
- throw new require_storage.ItdConfigError(`Файл ${path} повреждён: ожидался JSON key-value хранилища. Исправьте файл или перенесите его перед следующим сохранением.`);
106
+ throw new require_errors.ItdConfigError(`Файл ${path} повреждён: ожидался JSON key-value хранилища. Исправьте файл или перенесите его перед следующим сохранением.`);
105
107
  }
106
108
  }
107
109
  /**
@@ -168,7 +170,7 @@ var FileKeyValueStore = class {
168
170
  const parsed = await readJsonFile(this.#path);
169
171
  if (parsed === void 0) return void 0;
170
172
  const envelope = typeof parsed === "object" && parsed !== null ? parsed : void 0;
171
- if (envelope?.version !== FILE_STORE_VERSION || typeof envelope.values !== "object" || envelope.values === null || Array.isArray(envelope.values)) throw new require_storage.ItdConfigError(`Файл ${this.#path} имеет неподдерживаемый формат: ожидается { version: ${FILE_STORE_VERSION}, values }. Возьмите другой путь, чтобы не перезаписать посторонние данные.`);
173
+ if (envelope?.version !== FILE_STORE_VERSION || typeof envelope.values !== "object" || envelope.values === null || Array.isArray(envelope.values)) throw new require_errors.ItdConfigError(`Файл ${this.#path} имеет неподдерживаемый формат: ожидается { version: ${FILE_STORE_VERSION}, values }. Возьмите другой путь, чтобы не перезаписать посторонние данные.`);
172
174
  return envelope.values;
173
175
  }
174
176
  };
@@ -246,4 +248,4 @@ exports.FileMultiTokenStorage = FileMultiTokenStorage;
246
248
  exports.FileTokenStorage = FileTokenStorage;
247
249
  exports.fromPath = fromPath;
248
250
 
249
- //# sourceMappingURL=node.cjs.map
251
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["resolveFileStreamOptions","FileTransferMode","ItdFileError","ItdFileErrorReason","boundedFileStream","ItdConfigError","#path","#inner","createRecordKeyValueStore","#read","createTokenStorage","createMultiTokenStorage"],"sources":["../../src/node.ts"],"sourcesContent":["/**\n * `itd-api/node` — файловая система для Node, Bun и Deno.\n *\n * Здесь лежит только то, что требует `node:fs` и потому не может попасть в основной бандл:\n * иначе браузерные сборщики пытались бы разрешить этот модуль. Клиент, аккаунты, билдеры,\n * типы и всё остальное берутся из `itd-api` — одинаково на всех платформах.\n *\n * @example\n * ```ts\n * import { ItdClient } from 'itd-api';\n * import { FileTokenStorage, fromPath } from 'itd-api/node';\n *\n * // Когда сессия уже сохранена, `auth` не нужен — токен возьмётся из хранилища.\n * const itd = new ItdClient({ storage: new FileTokenStorage('./.itd-session.json') });\n *\n * await itd.posts.create((p) => p.content('привет').attach(fromPath('./photo.jpg')));\n * ```\n *\n * @packageDocumentation\n */\n\nimport { boundedFileStream } from './core/attachments/bounded-stream.js';\nimport {\n type FileStreamOptions,\n FileTransferMode,\n type LazyFile,\n type StreamFile,\n} from './core/attachments/contracts.js';\nimport { resolveFileStreamOptions } from './core/attachments/options.js';\nimport { ItdConfigError, ItdFileError, ItdFileErrorReason } from './core/errors.js';\nimport { createRecordKeyValueStore, type EnumerableKeyValueStore } from './core/key-value-store.js';\nimport { createMultiTokenStorage, type MultiTokenStorage } from './session/multi-storage.js';\nimport { createTokenStorage, type ItdSession, type TokenStorage } from './session/storage.js';\n\n/** Проверяет код системной ошибки без привязки к типам конкретного рантайма. */\nfunction hasErrorCode(error: unknown, code: string): boolean {\n return typeof error === 'object' && error !== null && 'code' in error && error.code === code;\n}\n\n/** Что можно уточнить у файла с диска. */\nexport interface PathFileOptions extends FileStreamOptions {\n /** Имя файла. По умолчанию — имя из пути. */\n filename?: string | undefined;\n /** MIME-тип. По умолчанию определяется по расширению. */\n contentType?: string | undefined;\n}\n\n/**\n * Вложение из файла на диске.\n *\n * Клиент настраивать не нужно: чтение диска приезжает вместе со значением, а не через\n * опцию, поэтому один и тот же клиент принимает и файлы с диска, и всё остальное.\n *\n * По умолчанию файл читается целиком непосредственно перед отправкой. Режим\n * `{ mode: 'stream' }` передаёт его частями и открывает заново при повторной попытке.\n * Модуль `node:fs` подключается динамически.\n *\n * @example\n * ```ts\n * import { ItdClient } from 'itd-api';\n * import { fromPath } from 'itd-api/node';\n *\n * const itd = new ItdClient({ auth });\n *\n * await itd.posts.create((p) =>\n * p.content('смотрите').attach(fromPath('./photo.jpg')),\n * );\n * ```\n */\nexport function fromPath(\n path: string,\n options: PathFileOptions & { mode: typeof FileTransferMode.Stream },\n): StreamFile;\nexport function fromPath(\n path: string,\n options?: PathFileOptions & { mode?: typeof FileTransferMode.Buffer },\n): LazyFile;\nexport function fromPath(path: string, options: PathFileOptions): LazyFile | StreamFile;\nexport function fromPath(path: string, options: PathFileOptions = {}): LazyFile | StreamFile {\n const resolved = resolveFileStreamOptions(options);\n\n if (resolved.mode === FileTransferMode.Stream) {\n return {\n open: async ({ signal }) => {\n const [{ createReadStream }, { stat }, { basename }, { Readable }] = await Promise.all([\n import('node:fs'),\n import('node:fs/promises'),\n import('node:path'),\n import('node:stream'),\n ]);\n const info = await stat(path);\n if (resolved.maxBytes !== undefined && info.size > resolved.maxBytes) {\n throw new ItdFileError(\n `файл ${path} больше предела в ${resolved.maxBytes} байт: ${info.size}`,\n {\n reason: ItdFileErrorReason.TooLarge,\n limit: resolved.maxBytes,\n actual: info.size,\n },\n );\n }\n\n const file = createReadStream(path, {\n highWaterMark: Math.min(resolved.streamBufferBytes, 1024 * 1024),\n ...(signal ? { signal } : {}),\n });\n const source = Readable.toWeb(file) as ReadableStream<Uint8Array>;\n return {\n stream: boundedFileStream(source, {\n ...(resolved.maxBytes !== undefined ? { maxBytes: resolved.maxBytes } : {}),\n streamBufferBytes: resolved.streamBufferBytes,\n ...(signal ? { signal } : {}),\n }),\n filename: options.filename ?? basename(path),\n ...(options.contentType ? { contentType: options.contentType } : {}),\n size: info.size,\n close: () => {\n file.destroy();\n },\n };\n },\n };\n }\n\n return {\n load: async ({ signal }) => {\n const [{ readFile, stat }, { basename }] = await Promise.all([\n import('node:fs/promises'),\n import('node:path'),\n ]);\n if (resolved.maxBytes !== undefined) {\n const info = await stat(path);\n if (info.size > resolved.maxBytes) {\n throw new ItdFileError(\n `файл ${path} больше предела в ${resolved.maxBytes} байт: ${info.size}`,\n {\n reason: ItdFileErrorReason.TooLarge,\n limit: resolved.maxBytes,\n actual: info.size,\n },\n );\n }\n }\n\n const file = new Uint8Array(await readFile(path, signal ? { signal } : undefined));\n if (resolved.maxBytes !== undefined && file.byteLength > resolved.maxBytes) {\n throw new ItdFileError(\n `файл ${path} больше предела в ${resolved.maxBytes} байт: ${file.byteLength}`,\n {\n reason: ItdFileErrorReason.TooLarge,\n limit: resolved.maxBytes,\n actual: file.byteLength,\n },\n );\n }\n\n return {\n file,\n filename: options.filename ?? basename(path),\n ...(options.contentType ? { contentType: options.contentType } : {}),\n };\n },\n };\n}\n\n/**\n * Читает и разбирает JSON-файл.\n *\n * Отсутствующий файл означает `undefined`. Повреждённый JSON не считается пустым хранилищем:\n * иначе следующая запись могла бы незаметно затереть данные.\n */\nasync function readJsonFile(path: string): Promise<unknown> {\n let raw: string;\n try {\n const { readFile } = await import('node:fs/promises');\n raw = await readFile(path, 'utf8');\n } catch (error) {\n if (hasErrorCode(error, 'ENOENT')) return undefined;\n throw error;\n }\n\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n throw new ItdConfigError(\n `Файл ${path} повреждён: ожидался JSON key-value хранилища. ` +\n 'Исправьте файл или перенесите его перед следующим сохранением.',\n );\n }\n}\n\n/**\n * Записывает JSON во временный файл и переименовывает его поверх целевого.\n *\n * Права `0600` (чтение и запись только владельцу) — в файле лежат токены. Переименование\n * атомарно, поэтому падение процесса посреди сохранения не оставит повреждённого файла.\n */\nasync function writeJsonAtomic(path: string, value: unknown): Promise<void> {\n const { writeFile, rename, unlink } = await import('node:fs/promises');\n\n // Временный файл уникален на процесс и вызов — иначе параллельные записи (в том числе\n // из разных процессов) делят один `.tmp`.\n const pid = typeof process !== 'undefined' ? process.pid : 0;\n const temporary = `${path}.${pid}.${Math.random().toString(36).slice(2)}.tmp`;\n\n try {\n await writeFile(temporary, JSON.stringify(value, null, 2), { encoding: 'utf8', mode: 0o600 });\n await rename(temporary, path);\n } catch (error) {\n await unlink(temporary).catch(() => {});\n throw error;\n }\n}\n\n/** Удаляет файл. Благодаря `force` отсутствие файла ошибкой не считается. */\nasync function removeFile(path: string): Promise<void> {\n const { rm } = await import('node:fs/promises');\n await rm(path, { force: true });\n}\n\n/** Версия общего формата файлового key-value backend. */\nconst FILE_STORE_VERSION = 1;\n\n/**\n * Key-value backend в одном JSON-файле.\n *\n * Изменения сериализуются внутри экземпляра и записываются атомарным переименованием. Несколько\n * экземпляров или процессов, направленных на один путь, требуют внешней синхронизации.\n */\nexport class FileKeyValueStore<T> {\n readonly #path: string;\n readonly #inner: EnumerableKeyValueStore<T>;\n\n /** @param path путь к JSON-файлу. Для секретов добавьте его в `.gitignore`. */\n constructor(path: string) {\n this.#path = path;\n this.#inner = createRecordKeyValueStore<T>({\n read: () => this.#read(),\n write: (values) => writeJsonAtomic(path, { version: FILE_STORE_VERSION, values }),\n delete: () => removeFile(path),\n });\n }\n\n get(key: string): Promise<T | undefined> {\n return Promise.resolve(this.#inner.get(key));\n }\n\n set(key: string, value: T): Promise<void> {\n return Promise.resolve(this.#inner.set(key, value));\n }\n\n delete(key: string): Promise<void> {\n return Promise.resolve(this.#inner.delete(key));\n }\n\n keys(prefix?: string): Promise<Iterable<string> | AsyncIterable<string>> {\n return Promise.resolve(this.#inner.keys(prefix));\n }\n\n async #read(): Promise<Readonly<Record<string, T>> | undefined> {\n const parsed = await readJsonFile(this.#path);\n if (parsed === undefined) return undefined;\n const envelope =\n typeof parsed === 'object' && parsed !== null\n ? (parsed as { version?: unknown; values?: unknown })\n : undefined;\n if (\n envelope?.version !== FILE_STORE_VERSION ||\n typeof envelope.values !== 'object' ||\n envelope.values === null ||\n Array.isArray(envelope.values)\n ) {\n throw new ItdConfigError(\n `Файл ${this.#path} имеет неподдерживаемый формат: ожидается ` +\n `{ version: ${FILE_STORE_VERSION}, values }. Возьмите другой путь, чтобы не ` +\n 'перезаписать посторонние данные.',\n );\n }\n return envelope.values as Readonly<Record<string, T>>;\n }\n}\n\n/**\n * Хранит сессию в файле.\n *\n * Нужна долгоживущим процессам: без неё бот при каждом запуске входит заново — а вход\n * требует решённой капчи, да и серия входов подряд может привести к временной блокировке\n * аккаунта. С сохранённой сессией опция `auth` не нужна вовсе.\n *\n * Файл создаётся с правами `0600` (чтение и запись только владельцу) — в нём лежат токены.\n * Запись идёт через временный файл с последующим переименованием, поэтому падение процесса\n * посреди сохранения не оставит повреждённую сессию.\n *\n * @example\n * ```ts\n * const itd = new ItdClient({ storage: new FileTokenStorage('./.itd-session.json') });\n * ```\n */\nexport class FileTokenStorage implements TokenStorage {\n readonly #inner: TokenStorage;\n\n /** @param path путь к файлу сессии. Добавьте его в `.gitignore`. */\n constructor(path: string) {\n this.#inner = createTokenStorage(new FileKeyValueStore<ItdSession>(path));\n }\n\n get(): Promise<ItdSession | null> {\n return Promise.resolve(this.#inner.get());\n }\n\n set(session: ItdSession): Promise<void> {\n return Promise.resolve(this.#inner.set(session));\n }\n\n clear(): Promise<void> {\n return Promise.resolve(this.#inner.clear());\n }\n}\n\n/**\n * Хранит сессии нескольких аккаунтов в одном файле.\n *\n * Разбирается с гонкой «прочитать, изменить, записать»: десять аккаунтов пишут в один файл,\n * и без общего слепка с очередью записей они теряли бы сессии друг друга. Как и\n * {@link FileTokenStorage}, пишет через временный файл с правами `0600`.\n *\n * Использует тот же версионированный {@link FileKeyValueStore}, что и одиночное хранилище.\n *\n * @example\n * ```ts\n * const accounts = new ItdAccounts({\n * storage: new FileMultiTokenStorage('./.itd-sessions.json'),\n * });\n * await accounts.restore();\n * ```\n */\nexport class FileMultiTokenStorage implements MultiTokenStorage {\n readonly #inner: MultiTokenStorage;\n\n /** @param path путь к файлу сессий. Добавьте его в `.gitignore`. */\n constructor(path: string) {\n this.#inner = createMultiTokenStorage(new FileKeyValueStore<ItdSession>(path));\n }\n\n get(account: string): Promise<ItdSession | null> {\n return Promise.resolve(this.#inner.get(account));\n }\n\n set(account: string, session: ItdSession): Promise<void> {\n return Promise.resolve(this.#inner.set(account, session));\n }\n\n clear(account: string): Promise<void> {\n return Promise.resolve(this.#inner.clear(account));\n }\n\n accounts(): Promise<readonly string[]> {\n return Promise.resolve(this.#inner.accounts());\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
- import { r as TokenStorage, t as ItdSession } from "./storage-BqMxs76Y.cjs";
2
- import { d as FileTransferMode, m as StreamFile, n as MultiTokenStorage, p as LazyFile, u as FileStreamOptions } from "./multi-storage-BUoEoW8f.cjs";
1
+ import { r as TokenStorage, t as ItdSession } from "../shared/storage-C_eICCep.cjs";
2
+ import { a as FileStreamOptions, c as LazyFile, l as StreamFile, o as FileTransferMode } from "../shared/contracts-BoT7msmq.cjs";
3
+ import { n as MultiTokenStorage } from "../shared/multi-storage-CjAPB5Kq.cjs";
3
4
  //#region src/node.d.ts
4
5
  /** Что можно уточнить у файла с диска. */
5
6
  interface PathFileOptions extends FileStreamOptions {
@@ -104,4 +105,4 @@ declare class FileMultiTokenStorage implements MultiTokenStorage {
104
105
  }
105
106
  //#endregion
106
107
  export { FileKeyValueStore, FileMultiTokenStorage, FileTokenStorage, PathFileOptions, fromPath };
107
- //# sourceMappingURL=node.d.cts.map
108
+ //# sourceMappingURL=index.d.cts.map
@@ -1,5 +1,6 @@
1
- import { r as TokenStorage, t as ItdSession } from "./storage-BqMxs76Y.js";
2
- import { d as FileTransferMode, m as StreamFile, n as MultiTokenStorage, p as LazyFile, u as FileStreamOptions } from "./multi-storage-CQSlI_kn.js";
1
+ import { r as TokenStorage, t as ItdSession } from "../shared/storage-C_eICCep.js";
2
+ import { a as FileStreamOptions, c as LazyFile, l as StreamFile, o as FileTransferMode } from "../shared/contracts-BoT7msmq.js";
3
+ import { n as MultiTokenStorage } from "../shared/multi-storage-DccjD7Ww.js";
3
4
  //#region src/node.d.ts
4
5
  /** Что можно уточнить у файла с диска. */
5
6
  interface PathFileOptions extends FileStreamOptions {
@@ -104,4 +105,4 @@ declare class FileMultiTokenStorage implements MultiTokenStorage {
104
105
  }
105
106
  //#endregion
106
107
  export { FileKeyValueStore, FileMultiTokenStorage, FileTokenStorage, PathFileOptions, fromPath };
107
- //# sourceMappingURL=node.d.ts.map
108
+ //# sourceMappingURL=index.d.ts.map
@@ -1,5 +1,7 @@
1
- import { o as resolveFileStreamOptions, p as FileTransferMode, r as createMultiTokenStorage, s as boundedFileStream } from "./multi-storage-BUZaLAPO.js";
2
- import { b as ItdFileErrorReason, h as ItdConfigError, r as createTokenStorage, s as createRecordKeyValueStore, y as ItdFileError } from "./storage-IHdXw52v.js";
1
+ import { a as ItdConfigError, l as ItdFileError, u as ItdFileErrorReason } from "../shared/errors-Bhrd2fJd.js";
2
+ import { r as createTokenStorage, s as createRecordKeyValueStore } from "../shared/storage-D86edNCB.js";
3
+ import { c as FileTransferMode, n as boundedFileStream, t as resolveFileStreamOptions } from "../shared/options-DtATYdLr.js";
4
+ import { r as createMultiTokenStorage } from "../shared/multi-storage-CkvTUC5m.js";
3
5
  //#region src/node.ts
4
6
  /**
5
7
  * `itd-api/node` — файловая система для Node, Bun и Deno.
@@ -242,4 +244,4 @@ var FileMultiTokenStorage = class {
242
244
  //#endregion
243
245
  export { FileKeyValueStore, FileMultiTokenStorage, FileTokenStorage, fromPath };
244
246
 
245
- //# sourceMappingURL=node.js.map
247
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["#path","#inner","#read"],"sources":["../../src/node.ts"],"sourcesContent":["/**\n * `itd-api/node` — файловая система для Node, Bun и Deno.\n *\n * Здесь лежит только то, что требует `node:fs` и потому не может попасть в основной бандл:\n * иначе браузерные сборщики пытались бы разрешить этот модуль. Клиент, аккаунты, билдеры,\n * типы и всё остальное берутся из `itd-api` — одинаково на всех платформах.\n *\n * @example\n * ```ts\n * import { ItdClient } from 'itd-api';\n * import { FileTokenStorage, fromPath } from 'itd-api/node';\n *\n * // Когда сессия уже сохранена, `auth` не нужен — токен возьмётся из хранилища.\n * const itd = new ItdClient({ storage: new FileTokenStorage('./.itd-session.json') });\n *\n * await itd.posts.create((p) => p.content('привет').attach(fromPath('./photo.jpg')));\n * ```\n *\n * @packageDocumentation\n */\n\nimport { boundedFileStream } from './core/attachments/bounded-stream.js';\nimport {\n type FileStreamOptions,\n FileTransferMode,\n type LazyFile,\n type StreamFile,\n} from './core/attachments/contracts.js';\nimport { resolveFileStreamOptions } from './core/attachments/options.js';\nimport { ItdConfigError, ItdFileError, ItdFileErrorReason } from './core/errors.js';\nimport { createRecordKeyValueStore, type EnumerableKeyValueStore } from './core/key-value-store.js';\nimport { createMultiTokenStorage, type MultiTokenStorage } from './session/multi-storage.js';\nimport { createTokenStorage, type ItdSession, type TokenStorage } from './session/storage.js';\n\n/** Проверяет код системной ошибки без привязки к типам конкретного рантайма. */\nfunction hasErrorCode(error: unknown, code: string): boolean {\n return typeof error === 'object' && error !== null && 'code' in error && error.code === code;\n}\n\n/** Что можно уточнить у файла с диска. */\nexport interface PathFileOptions extends FileStreamOptions {\n /** Имя файла. По умолчанию — имя из пути. */\n filename?: string | undefined;\n /** MIME-тип. По умолчанию определяется по расширению. */\n contentType?: string | undefined;\n}\n\n/**\n * Вложение из файла на диске.\n *\n * Клиент настраивать не нужно: чтение диска приезжает вместе со значением, а не через\n * опцию, поэтому один и тот же клиент принимает и файлы с диска, и всё остальное.\n *\n * По умолчанию файл читается целиком непосредственно перед отправкой. Режим\n * `{ mode: 'stream' }` передаёт его частями и открывает заново при повторной попытке.\n * Модуль `node:fs` подключается динамически.\n *\n * @example\n * ```ts\n * import { ItdClient } from 'itd-api';\n * import { fromPath } from 'itd-api/node';\n *\n * const itd = new ItdClient({ auth });\n *\n * await itd.posts.create((p) =>\n * p.content('смотрите').attach(fromPath('./photo.jpg')),\n * );\n * ```\n */\nexport function fromPath(\n path: string,\n options: PathFileOptions & { mode: typeof FileTransferMode.Stream },\n): StreamFile;\nexport function fromPath(\n path: string,\n options?: PathFileOptions & { mode?: typeof FileTransferMode.Buffer },\n): LazyFile;\nexport function fromPath(path: string, options: PathFileOptions): LazyFile | StreamFile;\nexport function fromPath(path: string, options: PathFileOptions = {}): LazyFile | StreamFile {\n const resolved = resolveFileStreamOptions(options);\n\n if (resolved.mode === FileTransferMode.Stream) {\n return {\n open: async ({ signal }) => {\n const [{ createReadStream }, { stat }, { basename }, { Readable }] = await Promise.all([\n import('node:fs'),\n import('node:fs/promises'),\n import('node:path'),\n import('node:stream'),\n ]);\n const info = await stat(path);\n if (resolved.maxBytes !== undefined && info.size > resolved.maxBytes) {\n throw new ItdFileError(\n `файл ${path} больше предела в ${resolved.maxBytes} байт: ${info.size}`,\n {\n reason: ItdFileErrorReason.TooLarge,\n limit: resolved.maxBytes,\n actual: info.size,\n },\n );\n }\n\n const file = createReadStream(path, {\n highWaterMark: Math.min(resolved.streamBufferBytes, 1024 * 1024),\n ...(signal ? { signal } : {}),\n });\n const source = Readable.toWeb(file) as ReadableStream<Uint8Array>;\n return {\n stream: boundedFileStream(source, {\n ...(resolved.maxBytes !== undefined ? { maxBytes: resolved.maxBytes } : {}),\n streamBufferBytes: resolved.streamBufferBytes,\n ...(signal ? { signal } : {}),\n }),\n filename: options.filename ?? basename(path),\n ...(options.contentType ? { contentType: options.contentType } : {}),\n size: info.size,\n close: () => {\n file.destroy();\n },\n };\n },\n };\n }\n\n return {\n load: async ({ signal }) => {\n const [{ readFile, stat }, { basename }] = await Promise.all([\n import('node:fs/promises'),\n import('node:path'),\n ]);\n if (resolved.maxBytes !== undefined) {\n const info = await stat(path);\n if (info.size > resolved.maxBytes) {\n throw new ItdFileError(\n `файл ${path} больше предела в ${resolved.maxBytes} байт: ${info.size}`,\n {\n reason: ItdFileErrorReason.TooLarge,\n limit: resolved.maxBytes,\n actual: info.size,\n },\n );\n }\n }\n\n const file = new Uint8Array(await readFile(path, signal ? { signal } : undefined));\n if (resolved.maxBytes !== undefined && file.byteLength > resolved.maxBytes) {\n throw new ItdFileError(\n `файл ${path} больше предела в ${resolved.maxBytes} байт: ${file.byteLength}`,\n {\n reason: ItdFileErrorReason.TooLarge,\n limit: resolved.maxBytes,\n actual: file.byteLength,\n },\n );\n }\n\n return {\n file,\n filename: options.filename ?? basename(path),\n ...(options.contentType ? { contentType: options.contentType } : {}),\n };\n },\n };\n}\n\n/**\n * Читает и разбирает JSON-файл.\n *\n * Отсутствующий файл означает `undefined`. Повреждённый JSON не считается пустым хранилищем:\n * иначе следующая запись могла бы незаметно затереть данные.\n */\nasync function readJsonFile(path: string): Promise<unknown> {\n let raw: string;\n try {\n const { readFile } = await import('node:fs/promises');\n raw = await readFile(path, 'utf8');\n } catch (error) {\n if (hasErrorCode(error, 'ENOENT')) return undefined;\n throw error;\n }\n\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n throw new ItdConfigError(\n `Файл ${path} повреждён: ожидался JSON key-value хранилища. ` +\n 'Исправьте файл или перенесите его перед следующим сохранением.',\n );\n }\n}\n\n/**\n * Записывает JSON во временный файл и переименовывает его поверх целевого.\n *\n * Права `0600` (чтение и запись только владельцу) — в файле лежат токены. Переименование\n * атомарно, поэтому падение процесса посреди сохранения не оставит повреждённого файла.\n */\nasync function writeJsonAtomic(path: string, value: unknown): Promise<void> {\n const { writeFile, rename, unlink } = await import('node:fs/promises');\n\n // Временный файл уникален на процесс и вызов — иначе параллельные записи (в том числе\n // из разных процессов) делят один `.tmp`.\n const pid = typeof process !== 'undefined' ? process.pid : 0;\n const temporary = `${path}.${pid}.${Math.random().toString(36).slice(2)}.tmp`;\n\n try {\n await writeFile(temporary, JSON.stringify(value, null, 2), { encoding: 'utf8', mode: 0o600 });\n await rename(temporary, path);\n } catch (error) {\n await unlink(temporary).catch(() => {});\n throw error;\n }\n}\n\n/** Удаляет файл. Благодаря `force` отсутствие файла ошибкой не считается. */\nasync function removeFile(path: string): Promise<void> {\n const { rm } = await import('node:fs/promises');\n await rm(path, { force: true });\n}\n\n/** Версия общего формата файлового key-value backend. */\nconst FILE_STORE_VERSION = 1;\n\n/**\n * Key-value backend в одном JSON-файле.\n *\n * Изменения сериализуются внутри экземпляра и записываются атомарным переименованием. Несколько\n * экземпляров или процессов, направленных на один путь, требуют внешней синхронизации.\n */\nexport class FileKeyValueStore<T> {\n readonly #path: string;\n readonly #inner: EnumerableKeyValueStore<T>;\n\n /** @param path путь к JSON-файлу. Для секретов добавьте его в `.gitignore`. */\n constructor(path: string) {\n this.#path = path;\n this.#inner = createRecordKeyValueStore<T>({\n read: () => this.#read(),\n write: (values) => writeJsonAtomic(path, { version: FILE_STORE_VERSION, values }),\n delete: () => removeFile(path),\n });\n }\n\n get(key: string): Promise<T | undefined> {\n return Promise.resolve(this.#inner.get(key));\n }\n\n set(key: string, value: T): Promise<void> {\n return Promise.resolve(this.#inner.set(key, value));\n }\n\n delete(key: string): Promise<void> {\n return Promise.resolve(this.#inner.delete(key));\n }\n\n keys(prefix?: string): Promise<Iterable<string> | AsyncIterable<string>> {\n return Promise.resolve(this.#inner.keys(prefix));\n }\n\n async #read(): Promise<Readonly<Record<string, T>> | undefined> {\n const parsed = await readJsonFile(this.#path);\n if (parsed === undefined) return undefined;\n const envelope =\n typeof parsed === 'object' && parsed !== null\n ? (parsed as { version?: unknown; values?: unknown })\n : undefined;\n if (\n envelope?.version !== FILE_STORE_VERSION ||\n typeof envelope.values !== 'object' ||\n envelope.values === null ||\n Array.isArray(envelope.values)\n ) {\n throw new ItdConfigError(\n `Файл ${this.#path} имеет неподдерживаемый формат: ожидается ` +\n `{ version: ${FILE_STORE_VERSION}, values }. Возьмите другой путь, чтобы не ` +\n 'перезаписать посторонние данные.',\n );\n }\n return envelope.values as Readonly<Record<string, T>>;\n }\n}\n\n/**\n * Хранит сессию в файле.\n *\n * Нужна долгоживущим процессам: без неё бот при каждом запуске входит заново — а вход\n * требует решённой капчи, да и серия входов подряд может привести к временной блокировке\n * аккаунта. С сохранённой сессией опция `auth` не нужна вовсе.\n *\n * Файл создаётся с правами `0600` (чтение и запись только владельцу) — в нём лежат токены.\n * Запись идёт через временный файл с последующим переименованием, поэтому падение процесса\n * посреди сохранения не оставит повреждённую сессию.\n *\n * @example\n * ```ts\n * const itd = new ItdClient({ storage: new FileTokenStorage('./.itd-session.json') });\n * ```\n */\nexport class FileTokenStorage implements TokenStorage {\n readonly #inner: TokenStorage;\n\n /** @param path путь к файлу сессии. Добавьте его в `.gitignore`. */\n constructor(path: string) {\n this.#inner = createTokenStorage(new FileKeyValueStore<ItdSession>(path));\n }\n\n get(): Promise<ItdSession | null> {\n return Promise.resolve(this.#inner.get());\n }\n\n set(session: ItdSession): Promise<void> {\n return Promise.resolve(this.#inner.set(session));\n }\n\n clear(): Promise<void> {\n return Promise.resolve(this.#inner.clear());\n }\n}\n\n/**\n * Хранит сессии нескольких аккаунтов в одном файле.\n *\n * Разбирается с гонкой «прочитать, изменить, записать»: десять аккаунтов пишут в один файл,\n * и без общего слепка с очередью записей они теряли бы сессии друг друга. Как и\n * {@link FileTokenStorage}, пишет через временный файл с правами `0600`.\n *\n * Использует тот же версионированный {@link FileKeyValueStore}, что и одиночное хранилище.\n *\n * @example\n * ```ts\n * const accounts = new ItdAccounts({\n * storage: new FileMultiTokenStorage('./.itd-sessions.json'),\n * });\n * await accounts.restore();\n * ```\n */\nexport class FileMultiTokenStorage implements MultiTokenStorage {\n readonly #inner: MultiTokenStorage;\n\n /** @param path путь к файлу сессий. Добавьте его в `.gitignore`. */\n constructor(path: string) {\n this.#inner = createMultiTokenStorage(new FileKeyValueStore<ItdSession>(path));\n }\n\n get(account: string): Promise<ItdSession | null> {\n return Promise.resolve(this.#inner.get(account));\n }\n\n set(account: string, session: ItdSession): Promise<void> {\n return Promise.resolve(this.#inner.set(account, session));\n }\n\n clear(account: string): Promise<void> {\n return Promise.resolve(this.#inner.clear(account));\n }\n\n accounts(): Promise<readonly string[]> {\n return Promise.resolve(this.#inner.accounts());\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,165 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_url = require("../shared/url-yjl2c8Ie.cjs");
3
+ const require_errors = require("../shared/errors-DfU8M5eS.cjs");
4
+ const require_websocket = require("../shared/websocket-sYlynrr0.cjs");
5
+ const require_auth_provider = require("../shared/auth-provider-CTJkKfgy.cjs");
6
+ //#region src/realtime/client.ts
7
+ /**
8
+ * Поток уведомлений с собственным конвейером запросов.
9
+ *
10
+ * Тот же {@link ItdRealtime}, что отдаёт `itd.realtime()`, но собранный без полного клиента:
11
+ * ресурсы, билдеры и сессия сюда не входят. Нужен приложениям, которым от API нужны только
12
+ * события, — виджетам, счётчикам непрочитанного, фоновым слушателям.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { createRealtimeClient } from 'itd-api/realtime';
17
+ *
18
+ * await using stream = createRealtimeClient({ auth: token });
19
+ * stream.on('notification', ({ notification }) => console.log(notification.type));
20
+ * await stream.connect();
21
+ * ```
22
+ */
23
+ var ItdRealtimeClient = class ItdRealtimeClient extends require_websocket.ItdRealtime {
24
+ #runtime;
25
+ /** Общий результат терминальной очистки для идемпотентных повторных вызовов. */
26
+ #disposePromise;
27
+ #disposed = false;
28
+ constructor(options = {}) {
29
+ const runtime = require_url.createClientRuntime(options, {
30
+ catalog: require_url.ITD_CATALOG,
31
+ auth: () => resolveAuthProvider(options.auth)
32
+ });
33
+ super(realtimeDeps(runtime), options);
34
+ this.#runtime = runtime;
35
+ require_websocket.setRealtimeConnectGuard(this, () => {
36
+ if (!this.#disposed) return;
37
+ throw new require_errors.ItdStateError("Поток уже окончательно освобождён через dispose(); нельзя подключить его снова. Создайте новый");
38
+ });
39
+ }
40
+ /**
41
+ * Окончательно освобождает поток и его конвейер: отключает соединение, дожидается
42
+ * обработчиков и останавливает очередь запросов.
43
+ *
44
+ * Повторные вызовы возвращают тот же результат очистки.
45
+ */
46
+ dispose() {
47
+ if (this.#disposePromise) return this.#disposePromise;
48
+ this.#disposed = true;
49
+ this.#disposePromise = this.#dispose();
50
+ return this.#disposePromise;
51
+ }
52
+ async #dispose() {
53
+ const errors = [];
54
+ this.disconnect();
55
+ try {
56
+ await this.drain();
57
+ } catch (error) {
58
+ errors.push(error);
59
+ }
60
+ try {
61
+ this.#runtime.close();
62
+ await this.#runtime.dispose();
63
+ } catch (error) {
64
+ errors.push(error);
65
+ }
66
+ if (errors.length > 0) throw new AggregateError(errors, "Не удалось освободить поток");
67
+ }
68
+ /** Позволяет использовать поток с `await using`. */
69
+ [Symbol.asyncDispose]() {
70
+ return this.dispose();
71
+ }
72
+ static {
73
+ require_url.installAsyncDisposeFallback(ItdRealtimeClient);
74
+ }
75
+ };
76
+ /** Приводит опцию `auth` к провайдеру конвейера. */
77
+ function resolveAuthProvider(auth) {
78
+ if (auth === void 0) return require_auth_provider.anonymousAuth();
79
+ return typeof auth === "string" ? require_auth_provider.bearerToken(auth) : auth;
80
+ }
81
+ /**
82
+ * Связывает поток с собранным конвейером.
83
+ *
84
+ * Начальный счётчик непрочитанных берётся той же операцией, что и при опросе
85
+ * (`realtime.poll.unread`): ресурс уведомлений потоку для этого не нужен.
86
+ */
87
+ function realtimeDeps(runtime) {
88
+ const request = ({ operationId, path, query, signal }) => runtime.http.operation(operationId, {
89
+ path,
90
+ query,
91
+ signal
92
+ });
93
+ return {
94
+ baseUrl: runtime.config.baseUrl,
95
+ fetch: runtime.config.fetch,
96
+ clock: runtime.config.clock,
97
+ logger: runtime.config.logger,
98
+ request,
99
+ baseHeaders: (url) => runtime.platformHeaders(url),
100
+ getToken: () => runtime.auth.token(),
101
+ refresh: () => runtime.auth.recover(),
102
+ fetchUnreadCount: async () => {
103
+ const payload = await request({
104
+ operationId: "realtime.poll.unread",
105
+ path: "/api/notifications/count"
106
+ });
107
+ return require_url.pickNumber(payload, "count", 0);
108
+ }
109
+ };
110
+ }
111
+ /**
112
+ * Создаёт поток уведомлений с собственным конвейером. Равнозначно конструктору
113
+ * {@link ItdRealtimeClient}.
114
+ */
115
+ function createRealtimeClient(options = {}) {
116
+ return new ItdRealtimeClient(options);
117
+ }
118
+ //#endregion
119
+ exports.DEFAULT_BASE_URL = require_url.DEFAULT_BASE_URL;
120
+ exports.ItdAbortError = require_errors.ItdAbortError;
121
+ exports.ItdApiError = require_errors.ItdApiError;
122
+ exports.ItdApiErrorKind = require_errors.ItdApiErrorKind;
123
+ exports.ItdAuthError = require_errors.ItdAuthError;
124
+ exports.ItdConfigError = require_errors.ItdConfigError;
125
+ exports.ItdError = require_errors.ItdError;
126
+ exports.ItdErrorKind = require_errors.ItdErrorKind;
127
+ exports.ItdForbiddenError = require_errors.ItdForbiddenError;
128
+ exports.ItdNetworkError = require_errors.ItdNetworkError;
129
+ exports.ItdNotFoundError = require_errors.ItdNotFoundError;
130
+ exports.ItdRateLimitError = require_errors.ItdRateLimitError;
131
+ exports.ItdRealtime = require_websocket.ItdRealtime;
132
+ exports.ItdRealtimeClient = ItdRealtimeClient;
133
+ exports.ItdServerError = require_errors.ItdServerError;
134
+ exports.ItdStateError = require_errors.ItdStateError;
135
+ exports.ItdTimeoutError = require_errors.ItdTimeoutError;
136
+ exports.ItdValidationError = require_errors.ItdValidationError;
137
+ exports.LIBRARY_VERSION = require_url.LIBRARY_VERSION;
138
+ exports.NotificationType = require_url.NotificationType;
139
+ exports.RealtimeComposer = require_websocket.RealtimeComposer;
140
+ exports.RealtimeRouter = require_websocket.RealtimeRouter;
141
+ exports.RealtimeStatus = require_url.RealtimeStatus;
142
+ exports.RealtimeTransportKind = require_websocket.RealtimeTransportKind;
143
+ exports.RealtimeUpdateOrigin = require_websocket.RealtimeUpdateOrigin;
144
+ exports.RealtimeUpdateType = require_websocket.RealtimeUpdateType;
145
+ exports.RuntimeMode = require_url.RuntimeMode;
146
+ exports.UnauthorizedStreamError = require_websocket.UnauthorizedStreamError;
147
+ exports.WebSocketTransport = require_websocket.WebSocketTransport;
148
+ exports.anonymousAuth = require_auth_provider.anonymousAuth;
149
+ exports.bearerToken = require_auth_provider.bearerToken;
150
+ exports.canonicalNotificationType = require_url.canonicalNotificationType;
151
+ exports.createRealtimeClient = createRealtimeClient;
152
+ exports.formatNotificationText = require_url.formatNotificationText;
153
+ exports.isItdApiError = require_errors.isItdApiError;
154
+ exports.isItdAuthError = require_errors.isItdAuthError;
155
+ exports.isItdError = require_errors.isItdError;
156
+ exports.isItdRateLimitError = require_errors.isItdRateLimitError;
157
+ exports.isItdStateError = require_errors.isItdStateError;
158
+ exports.isKnownNotificationType = require_url.isKnownNotificationType;
159
+ exports.normalizeNotification = require_url.normalizeNotification;
160
+ exports.resolveNotificationUrl = require_url.resolveNotificationUrl;
161
+ exports.runRealtimeMiddleware = require_websocket.runRealtimeMiddleware;
162
+ exports.systemClock = require_url.systemClock;
163
+ exports.tokenProvider = require_auth_provider.tokenProvider;
164
+
165
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["ItdRealtime","#runtime","createClientRuntime","ITD_CATALOG","#disposed","ItdStateError","#disposePromise","#dispose","anonymousAuth","bearerToken","pickNumber"],"sources":["../../src/realtime/client.ts"],"sourcesContent":["import { installAsyncDisposeFallback } from '../core/async-dispose.js';\nimport { type AuthProvider, anonymousAuth, bearerToken } from '../core/auth-provider.js';\nimport { ItdStateError } from '../core/errors.js';\nimport { type ClientRuntime, createClientRuntime } from '../core/execution/client-runtime.js';\nimport type { RuntimeOptions } from '../core/options.js';\nimport { pickNumber } from '../core/unwrap.js';\nimport { ITD_CATALOG } from '../domain/catalog.js';\nimport {\n ItdRealtime,\n type RealtimeDeps,\n type RealtimeOptions,\n setRealtimeConnectGuard,\n} from './stream.js';\nimport type { RealtimeContext } from './updates.js';\n\n/** Опции конструктора {@link ItdRealtimeClient}. */\nexport interface RealtimeClientOptions<C extends RealtimeContext = RealtimeContext>\n extends RuntimeOptions,\n RealtimeOptions<C> {\n /**\n * Авторизация. Строка — сокращение для {@link bearerToken}.\n *\n * Без неё поток идёт анонимно. Токен считается готовым: продлевать его клиент не умеет,\n * а на отказ авторизации переподключение спрашивает токен заново. Сессия, которая входит\n * по паролю и продлевает себя сама, живёт в полном `ItdClient`.\n */\n auth?: string | AuthProvider | undefined;\n}\n\n/**\n * Поток уведомлений с собственным конвейером запросов.\n *\n * Тот же {@link ItdRealtime}, что отдаёт `itd.realtime()`, но собранный без полного клиента:\n * ресурсы, билдеры и сессия сюда не входят. Нужен приложениям, которым от API нужны только\n * события, — виджетам, счётчикам непрочитанного, фоновым слушателям.\n *\n * @example\n * ```ts\n * import { createRealtimeClient } from 'itd-api/realtime';\n *\n * await using stream = createRealtimeClient({ auth: token });\n * stream.on('notification', ({ notification }) => console.log(notification.type));\n * await stream.connect();\n * ```\n */\nexport class ItdRealtimeClient<C extends RealtimeContext = RealtimeContext> extends ItdRealtime<C> {\n readonly #runtime: ClientRuntime;\n /** Общий результат терминальной очистки для идемпотентных повторных вызовов. */\n #disposePromise: Promise<void> | undefined;\n #disposed = false;\n\n constructor(options: RealtimeClientOptions<C> = {}) {\n const runtime = createClientRuntime(options, {\n catalog: ITD_CATALOG,\n auth: () => resolveAuthProvider(options.auth),\n });\n\n super(realtimeDeps(runtime), options);\n this.#runtime = runtime;\n\n setRealtimeConnectGuard<C>(this, () => {\n if (!this.#disposed) return;\n throw new ItdStateError(\n 'Поток уже окончательно освобождён через dispose(); нельзя подключить его снова. ' +\n 'Создайте новый',\n );\n });\n }\n\n /**\n * Окончательно освобождает поток и его конвейер: отключает соединение, дожидается\n * обработчиков и останавливает очередь запросов.\n *\n * Повторные вызовы возвращают тот же результат очистки.\n */\n dispose(): Promise<void> {\n if (this.#disposePromise) return this.#disposePromise;\n this.#disposed = true;\n this.#disposePromise = this.#dispose();\n return this.#disposePromise;\n }\n\n async #dispose(): Promise<void> {\n const errors: unknown[] = [];\n this.disconnect();\n try {\n await this.drain();\n } catch (error) {\n errors.push(error);\n }\n try {\n this.#runtime.close();\n await this.#runtime.dispose();\n } catch (error) {\n errors.push(error);\n }\n if (errors.length > 0) throw new AggregateError(errors, 'Не удалось освободить поток');\n }\n\n /** Позволяет использовать поток с `await using`. */\n [Symbol.asyncDispose](): Promise<void> {\n return this.dispose();\n }\n\n static {\n installAsyncDisposeFallback(ItdRealtimeClient);\n }\n}\n\n/** Приводит опцию `auth` к провайдеру конвейера. */\nfunction resolveAuthProvider(auth: RealtimeClientOptions['auth']): AuthProvider {\n if (auth === undefined) return anonymousAuth();\n return typeof auth === 'string' ? bearerToken(auth) : auth;\n}\n\n/**\n * Связывает поток с собранным конвейером.\n *\n * Начальный счётчик непрочитанных берётся той же операцией, что и при опросе\n * (`realtime.poll.unread`): ресурс уведомлений потоку для этого не нужен.\n */\nfunction realtimeDeps(runtime: ClientRuntime): RealtimeDeps {\n const request: NonNullable<RealtimeDeps['request']> = ({ operationId, path, query, signal }) =>\n runtime.http.operation(operationId, { path, query, signal });\n\n return {\n baseUrl: runtime.config.baseUrl,\n fetch: runtime.config.fetch,\n clock: runtime.config.clock,\n logger: runtime.config.logger,\n request,\n baseHeaders: (url) => runtime.platformHeaders(url),\n getToken: () => runtime.auth.token(),\n refresh: () => runtime.auth.recover(),\n fetchUnreadCount: async () => {\n const payload = await request({\n operationId: 'realtime.poll.unread',\n path: '/api/notifications/count',\n });\n return pickNumber(payload, 'count', 0);\n },\n };\n}\n\n/**\n * Создаёт поток уведомлений с собственным конвейером. Равнозначно конструктору\n * {@link ItdRealtimeClient}.\n */\nexport function createRealtimeClient<C extends RealtimeContext = RealtimeContext>(\n options: RealtimeClientOptions<C> = {},\n): ItdRealtimeClient<C> {\n return new ItdRealtimeClient<C>(options);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA6CA,IAAa,oBAAb,MAAa,0BAAuEA,kBAAAA,YAAe;CACjG;;CAEA;CACA,YAAY;CAEZ,YAAY,UAAoC,CAAC,GAAG;EAClD,MAAM,UAAUE,YAAAA,oBAAoB,SAAS;GAC3C,SAASC,YAAAA;GACT,YAAY,oBAAoB,QAAQ,IAAI;EAC9C,CAAC;EAED,MAAM,aAAa,OAAO,GAAG,OAAO;EACpC,KAAKF,WAAW;EAEhB,kBAAA,wBAA2B,YAAY;GACrC,IAAI,CAAC,KAAKG,WAAW;GACrB,MAAM,IAAIC,eAAAA,cACR,gGAEF;EACF,CAAC;CACH;;;;;;;CAQA,UAAyB;EACvB,IAAI,KAAKC,iBAAiB,OAAO,KAAKA;EACtC,KAAKF,YAAY;EACjB,KAAKE,kBAAkB,KAAKC,SAAS;EACrC,OAAO,KAAKD;CACd;CAEA,MAAMC,WAA0B;EAC9B,MAAM,SAAoB,CAAC;EAC3B,KAAK,WAAW;EAChB,IAAI;GACF,MAAM,KAAK,MAAM;EACnB,SAAS,OAAO;GACd,OAAO,KAAK,KAAK;EACnB;EACA,IAAI;GACF,KAAKN,SAAS,MAAM;GACpB,MAAM,KAAKA,SAAS,QAAQ;EAC9B,SAAS,OAAO;GACd,OAAO,KAAK,KAAK;EACnB;EACA,IAAI,OAAO,SAAS,GAAG,MAAM,IAAI,eAAe,QAAQ,6BAA6B;CACvF;;CAGA,CAAC,OAAO,gBAA+B;EACrC,OAAO,KAAK,QAAQ;CACtB;CAEA;EACE,YAAA,4BAA4B,iBAAiB;CAC/C;AACF;;AAGA,SAAS,oBAAoB,MAAmD;CAC9E,IAAI,SAAS,KAAA,GAAW,OAAOO,sBAAAA,cAAc;CAC7C,OAAO,OAAO,SAAS,WAAWC,sBAAAA,YAAY,IAAI,IAAI;AACxD;;;;;;;AAQA,SAAS,aAAa,SAAsC;CAC1D,MAAM,WAAiD,EAAE,aAAa,MAAM,OAAO,aACjF,QAAQ,KAAK,UAAU,aAAa;EAAE;EAAM;EAAO;CAAO,CAAC;CAE7D,OAAO;EACL,SAAS,QAAQ,OAAO;EACxB,OAAO,QAAQ,OAAO;EACtB,OAAO,QAAQ,OAAO;EACtB,QAAQ,QAAQ,OAAO;EACvB;EACA,cAAc,QAAQ,QAAQ,gBAAgB,GAAG;EACjD,gBAAgB,QAAQ,KAAK,MAAM;EACnC,eAAe,QAAQ,KAAK,QAAQ;EACpC,kBAAkB,YAAY;GAC5B,MAAM,UAAU,MAAM,QAAQ;IAC5B,aAAa;IACb,MAAM;GACR,CAAC;GACD,OAAOC,YAAAA,WAAW,SAAS,SAAS,CAAC;EACvC;CACF;AACF;;;;;AAMA,SAAgB,qBACd,UAAoC,CAAC,GACf;CACtB,OAAO,IAAI,kBAAqB,OAAO;AACzC"}
@@ -0,0 +1,51 @@
1
+ import { B as Notification, C as ItdStateError, D as isItdAuthError, E as isItdApiError, Ft as Logger, I as isItdStateError, Mt as Unsubscribe, Nt as ClientHooks, P as isItdRateLimitError, R as NotificationEvent, S as ItdServerError, St as RealtimeStatus, T as ItdValidationError, V as NotificationSettings, Yt as RuntimeOptions, _ as ItdForbiddenError, a as ItdAbortError, at as DEFAULT_BASE_URL, bt as Loose, c as ItdApiErrorKind, en as RuntimeMode, et as AuthIdentity, f as ItdError, i as formatNotificationText, it as tokenProvider, jt as Listener, k as isItdError, l as ItdAuthError, n as canonicalNotificationType, nn as systemClock, nt as anonymousAuth, o as ItdApiError, p as ItdErrorKind, r as isKnownNotificationType, rt as bearerToken, st as LIBRARY_VERSION, t as resolveNotificationUrl, tn as ItdClock, tt as AuthProvider, u as ItdConfigError, v as ItdNetworkError, w as ItdTimeoutError, x as ItdRateLimitError, xt as NotificationType, y as ItdNotFoundError, z as normalizeNotification } from "../shared/url-B6-bXHKt.cjs";
2
+ import { A as NotificationOfType, B as RealtimeUpdateOfType, C as RealtimeMiddlewareObj, D as RealtimeTypeGuard, E as RealtimeSequentializer, F as RealtimeNotificationSelector, G as RealtimeTransport, H as RealtimeUpdateType, I as RealtimeNotificationUpdate, J as UnauthorizedStreamError, K as TransportContext, L as RealtimeUnknownUpdate, M as RealtimeContextBase, N as RealtimeNotificationContext, O as runRealtimeMiddleware, P as RealtimeNotificationFilter, R as RealtimeUnreadCountUpdate, S as RealtimeMiddleware, T as RealtimePredicate, U as RealtimeRequest, V as RealtimeUpdateOrigin, W as RealtimeRequestInput, _ as RealtimeOptions, a as WebSocketTransportOptions, b as ReconnectOptions, c as RealtimeErrorContext, d as RealtimeMiddlewareLike, f as RealtimeRouteTable, g as RealtimeEvents, h as ItdRealtime, i as WebSocketTransport, j as RealtimeContext, k as NotificationEventOfType, l as RealtimeFilter, m as RealtimeRouter, n as WebSocketLike, o as RealtimeComposer, p as RealtimeRouteSelector, q as TransportEvent, r as WebSocketOpenFailureClassifier, s as RealtimeErrorBoundary, t as WebSocketImplementationOptions, u as RealtimeMiddlewareGroup, v as RealtimeTransportKind, w as RealtimeNext, x as RealtimeHandler, y as RealtimeEngineEvents, z as RealtimeUpdate } from "../shared/websocket-D1p32SB2.cjs";
3
+ //#region src/realtime/client.d.ts
4
+ /** Опции конструктора {@link ItdRealtimeClient}. */
5
+ interface RealtimeClientOptions<C extends RealtimeContext = RealtimeContext> extends RuntimeOptions, RealtimeOptions<C> {
6
+ /**
7
+ * Авторизация. Строка — сокращение для {@link bearerToken}.
8
+ *
9
+ * Без неё поток идёт анонимно. Токен считается готовым: продлевать его клиент не умеет,
10
+ * а на отказ авторизации переподключение спрашивает токен заново. Сессия, которая входит
11
+ * по паролю и продлевает себя сама, живёт в полном `ItdClient`.
12
+ */
13
+ auth?: string | AuthProvider | undefined;
14
+ }
15
+ /**
16
+ * Поток уведомлений с собственным конвейером запросов.
17
+ *
18
+ * Тот же {@link ItdRealtime}, что отдаёт `itd.realtime()`, но собранный без полного клиента:
19
+ * ресурсы, билдеры и сессия сюда не входят. Нужен приложениям, которым от API нужны только
20
+ * события, — виджетам, счётчикам непрочитанного, фоновым слушателям.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * import { createRealtimeClient } from 'itd-api/realtime';
25
+ *
26
+ * await using stream = createRealtimeClient({ auth: token });
27
+ * stream.on('notification', ({ notification }) => console.log(notification.type));
28
+ * await stream.connect();
29
+ * ```
30
+ */
31
+ declare class ItdRealtimeClient<C extends RealtimeContext = RealtimeContext> extends ItdRealtime<C> {
32
+ #private;
33
+ constructor(options?: RealtimeClientOptions<C>);
34
+ /**
35
+ * Окончательно освобождает поток и его конвейер: отключает соединение, дожидается
36
+ * обработчиков и останавливает очередь запросов.
37
+ *
38
+ * Повторные вызовы возвращают тот же результат очистки.
39
+ */
40
+ dispose(): Promise<void>;
41
+ /** Позволяет использовать поток с `await using`. */
42
+ [Symbol.asyncDispose](): Promise<void>;
43
+ }
44
+ /**
45
+ * Создаёт поток уведомлений с собственным конвейером. Равнозначно конструктору
46
+ * {@link ItdRealtimeClient}.
47
+ */
48
+ declare function createRealtimeClient<C extends RealtimeContext = RealtimeContext>(options?: RealtimeClientOptions<C>): ItdRealtimeClient<C>;
49
+ //#endregion
50
+ export { type AuthIdentity, type AuthProvider, type ClientHooks, DEFAULT_BASE_URL, ItdAbortError, ItdApiError, ItdApiErrorKind, ItdAuthError, type ItdClock, ItdConfigError, ItdError, ItdErrorKind, ItdForbiddenError, ItdNetworkError, ItdNotFoundError, ItdRateLimitError, ItdRealtime, ItdRealtimeClient, ItdServerError, ItdStateError, ItdTimeoutError, ItdValidationError, LIBRARY_VERSION, type Listener, type Logger, type Loose, type Notification, type NotificationEvent, type NotificationEventOfType, type NotificationOfType, type NotificationSettings, NotificationType, type RealtimeClientOptions, RealtimeComposer, type RealtimeContext, type RealtimeContextBase, type RealtimeEngineEvents, type RealtimeErrorBoundary, type RealtimeErrorContext, type RealtimeEvents, type RealtimeFilter, type RealtimeHandler, type RealtimeMiddleware, type RealtimeMiddlewareGroup, type RealtimeMiddlewareLike, type RealtimeMiddlewareObj, type RealtimeNext, type RealtimeNotificationContext, type RealtimeNotificationFilter, type RealtimeNotificationSelector, type RealtimeNotificationUpdate, type RealtimeOptions, type RealtimePredicate, type RealtimeRequest, type RealtimeRequestInput, type RealtimeRouteSelector, type RealtimeRouteTable, RealtimeRouter, type RealtimeSequentializer, RealtimeStatus, type RealtimeTransport, RealtimeTransportKind, type RealtimeTypeGuard, type RealtimeUnknownUpdate, type RealtimeUnreadCountUpdate, type RealtimeUpdate, type RealtimeUpdateOfType, RealtimeUpdateOrigin, RealtimeUpdateType, type ReconnectOptions, RuntimeMode, type RuntimeOptions, type TransportContext, type TransportEvent, UnauthorizedStreamError, type Unsubscribe, type WebSocketImplementationOptions, type WebSocketLike, type WebSocketOpenFailureClassifier, WebSocketTransport, type WebSocketTransportOptions, anonymousAuth, bearerToken, canonicalNotificationType, createRealtimeClient, formatNotificationText, isItdApiError, isItdAuthError, isItdError, isItdRateLimitError, isItdStateError, isKnownNotificationType, normalizeNotification, resolveNotificationUrl, runRealtimeMiddleware, systemClock, tokenProvider };
51
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1,51 @@
1
+ import { B as Notification, C as ItdStateError, D as isItdAuthError, E as isItdApiError, Ft as Logger, I as isItdStateError, Mt as Unsubscribe, Nt as ClientHooks, P as isItdRateLimitError, R as NotificationEvent, S as ItdServerError, St as RealtimeStatus, T as ItdValidationError, V as NotificationSettings, Yt as RuntimeOptions, _ as ItdForbiddenError, a as ItdAbortError, at as DEFAULT_BASE_URL, bt as Loose, c as ItdApiErrorKind, en as RuntimeMode, et as AuthIdentity, f as ItdError, i as formatNotificationText, it as tokenProvider, jt as Listener, k as isItdError, l as ItdAuthError, n as canonicalNotificationType, nn as systemClock, nt as anonymousAuth, o as ItdApiError, p as ItdErrorKind, r as isKnownNotificationType, rt as bearerToken, st as LIBRARY_VERSION, t as resolveNotificationUrl, tn as ItdClock, tt as AuthProvider, u as ItdConfigError, v as ItdNetworkError, w as ItdTimeoutError, x as ItdRateLimitError, xt as NotificationType, y as ItdNotFoundError, z as normalizeNotification } from "../shared/url-B6-bXHKt.js";
2
+ import { A as NotificationOfType, B as RealtimeUpdateOfType, C as RealtimeMiddlewareObj, D as RealtimeTypeGuard, E as RealtimeSequentializer, F as RealtimeNotificationSelector, G as RealtimeTransport, H as RealtimeUpdateType, I as RealtimeNotificationUpdate, J as UnauthorizedStreamError, K as TransportContext, L as RealtimeUnknownUpdate, M as RealtimeContextBase, N as RealtimeNotificationContext, O as runRealtimeMiddleware, P as RealtimeNotificationFilter, R as RealtimeUnreadCountUpdate, S as RealtimeMiddleware, T as RealtimePredicate, U as RealtimeRequest, V as RealtimeUpdateOrigin, W as RealtimeRequestInput, _ as RealtimeOptions, a as WebSocketTransportOptions, b as ReconnectOptions, c as RealtimeErrorContext, d as RealtimeMiddlewareLike, f as RealtimeRouteTable, g as RealtimeEvents, h as ItdRealtime, i as WebSocketTransport, j as RealtimeContext, k as NotificationEventOfType, l as RealtimeFilter, m as RealtimeRouter, n as WebSocketLike, o as RealtimeComposer, p as RealtimeRouteSelector, q as TransportEvent, r as WebSocketOpenFailureClassifier, s as RealtimeErrorBoundary, t as WebSocketImplementationOptions, u as RealtimeMiddlewareGroup, v as RealtimeTransportKind, w as RealtimeNext, x as RealtimeHandler, y as RealtimeEngineEvents, z as RealtimeUpdate } from "../shared/websocket-BMtihD56.js";
3
+ //#region src/realtime/client.d.ts
4
+ /** Опции конструктора {@link ItdRealtimeClient}. */
5
+ interface RealtimeClientOptions<C extends RealtimeContext = RealtimeContext> extends RuntimeOptions, RealtimeOptions<C> {
6
+ /**
7
+ * Авторизация. Строка — сокращение для {@link bearerToken}.
8
+ *
9
+ * Без неё поток идёт анонимно. Токен считается готовым: продлевать его клиент не умеет,
10
+ * а на отказ авторизации переподключение спрашивает токен заново. Сессия, которая входит
11
+ * по паролю и продлевает себя сама, живёт в полном `ItdClient`.
12
+ */
13
+ auth?: string | AuthProvider | undefined;
14
+ }
15
+ /**
16
+ * Поток уведомлений с собственным конвейером запросов.
17
+ *
18
+ * Тот же {@link ItdRealtime}, что отдаёт `itd.realtime()`, но собранный без полного клиента:
19
+ * ресурсы, билдеры и сессия сюда не входят. Нужен приложениям, которым от API нужны только
20
+ * события, — виджетам, счётчикам непрочитанного, фоновым слушателям.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * import { createRealtimeClient } from 'itd-api/realtime';
25
+ *
26
+ * await using stream = createRealtimeClient({ auth: token });
27
+ * stream.on('notification', ({ notification }) => console.log(notification.type));
28
+ * await stream.connect();
29
+ * ```
30
+ */
31
+ declare class ItdRealtimeClient<C extends RealtimeContext = RealtimeContext> extends ItdRealtime<C> {
32
+ #private;
33
+ constructor(options?: RealtimeClientOptions<C>);
34
+ /**
35
+ * Окончательно освобождает поток и его конвейер: отключает соединение, дожидается
36
+ * обработчиков и останавливает очередь запросов.
37
+ *
38
+ * Повторные вызовы возвращают тот же результат очистки.
39
+ */
40
+ dispose(): Promise<void>;
41
+ /** Позволяет использовать поток с `await using`. */
42
+ [Symbol.asyncDispose](): Promise<void>;
43
+ }
44
+ /**
45
+ * Создаёт поток уведомлений с собственным конвейером. Равнозначно конструктору
46
+ * {@link ItdRealtimeClient}.
47
+ */
48
+ declare function createRealtimeClient<C extends RealtimeContext = RealtimeContext>(options?: RealtimeClientOptions<C>): ItdRealtimeClient<C>;
49
+ //#endregion
50
+ export { type AuthIdentity, type AuthProvider, type ClientHooks, DEFAULT_BASE_URL, ItdAbortError, ItdApiError, ItdApiErrorKind, ItdAuthError, type ItdClock, ItdConfigError, ItdError, ItdErrorKind, ItdForbiddenError, ItdNetworkError, ItdNotFoundError, ItdRateLimitError, ItdRealtime, ItdRealtimeClient, ItdServerError, ItdStateError, ItdTimeoutError, ItdValidationError, LIBRARY_VERSION, type Listener, type Logger, type Loose, type Notification, type NotificationEvent, type NotificationEventOfType, type NotificationOfType, type NotificationSettings, NotificationType, type RealtimeClientOptions, RealtimeComposer, type RealtimeContext, type RealtimeContextBase, type RealtimeEngineEvents, type RealtimeErrorBoundary, type RealtimeErrorContext, type RealtimeEvents, type RealtimeFilter, type RealtimeHandler, type RealtimeMiddleware, type RealtimeMiddlewareGroup, type RealtimeMiddlewareLike, type RealtimeMiddlewareObj, type RealtimeNext, type RealtimeNotificationContext, type RealtimeNotificationFilter, type RealtimeNotificationSelector, type RealtimeNotificationUpdate, type RealtimeOptions, type RealtimePredicate, type RealtimeRequest, type RealtimeRequestInput, type RealtimeRouteSelector, type RealtimeRouteTable, RealtimeRouter, type RealtimeSequentializer, RealtimeStatus, type RealtimeTransport, RealtimeTransportKind, type RealtimeTypeGuard, type RealtimeUnknownUpdate, type RealtimeUnreadCountUpdate, type RealtimeUpdate, type RealtimeUpdateOfType, RealtimeUpdateOrigin, RealtimeUpdateType, type ReconnectOptions, RuntimeMode, type RuntimeOptions, type TransportContext, type TransportEvent, UnauthorizedStreamError, type Unsubscribe, type WebSocketImplementationOptions, type WebSocketLike, type WebSocketOpenFailureClassifier, WebSocketTransport, type WebSocketTransportOptions, anonymousAuth, bearerToken, canonicalNotificationType, createRealtimeClient, formatNotificationText, isItdApiError, isItdAuthError, isItdError, isItdRateLimitError, isItdStateError, isKnownNotificationType, normalizeNotification, resolveNotificationUrl, runRealtimeMiddleware, systemClock, tokenProvider };
51
+ //# sourceMappingURL=index.d.ts.map