itd-api 0.10.4 → 0.11.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 (79) hide show
  1. package/README.md +2 -1
  2. package/dist/events/index.cjs +27 -25
  3. package/dist/events/index.d.cts +3 -3
  4. package/dist/events/index.d.ts +3 -3
  5. package/dist/events/index.js +5 -5
  6. package/dist/index.cjs +136 -116
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.cts +18 -7
  9. package/dist/index.d.ts +18 -7
  10. package/dist/index.js +46 -30
  11. package/dist/index.js.map +1 -1
  12. package/dist/node/index.cjs +13 -13
  13. package/dist/node/index.cjs.map +1 -1
  14. package/dist/node/index.js +5 -5
  15. package/dist/rest/index.cjs +43 -40
  16. package/dist/rest/index.cjs.map +1 -1
  17. package/dist/rest/index.d.cts +3 -3
  18. package/dist/rest/index.d.ts +3 -3
  19. package/dist/rest/index.js +6 -6
  20. package/dist/shared/{events-B8cjz_Ed.cjs → events-C6tmj8aW.cjs} +63 -59
  21. package/dist/shared/events-C6tmj8aW.cjs.map +1 -0
  22. package/dist/shared/{events-DGdU8q1X.d.ts → events-CAb9G7Sf.d.ts} +2 -2
  23. package/dist/shared/{events-D2n7Yu1P.js → events-MWNcnfrq.js} +19 -15
  24. package/dist/shared/events-MWNcnfrq.js.map +1 -0
  25. package/dist/shared/{events-CK3zHntT.d.cts → events-Sc75x6rT.d.cts} +2 -2
  26. package/dist/shared/{key-value-store-B5GYVEYZ.cjs → key-value-store-DYSPsqwq.cjs} +11 -14
  27. package/dist/shared/key-value-store-DYSPsqwq.cjs.map +1 -0
  28. package/dist/shared/{key-value-store-Bt2PSMxY.js → key-value-store-w1Dn5Pjb.js} +5 -8
  29. package/dist/shared/key-value-store-w1Dn5Pjb.js.map +1 -0
  30. package/dist/shared/{multi-storage-C3Ngtop1.js → multi-storage-BLBrGN9Q.js} +6 -6
  31. package/dist/shared/multi-storage-BLBrGN9Q.js.map +1 -0
  32. package/dist/shared/{multi-storage-s-fPtjoy.cjs → multi-storage-C7-Gz6Z7.cjs} +8 -8
  33. package/dist/shared/multi-storage-C7-Gz6Z7.cjs.map +1 -0
  34. package/dist/shared/{options-DjEtbVaf.cjs → options-5tywTYId.cjs} +13 -13
  35. package/dist/shared/{options-DjEtbVaf.cjs.map → options-5tywTYId.cjs.map} +1 -1
  36. package/dist/shared/{options-i4LrKfqx.js → options-BerKicCs.js} +3 -3
  37. package/dist/shared/{options-i4LrKfqx.js.map → options-BerKicCs.js.map} +1 -1
  38. package/dist/shared/{redact-DJV0XM3n.js → redact-C5oxIvcc.js} +79 -18
  39. package/dist/shared/redact-C5oxIvcc.js.map +1 -0
  40. package/dist/shared/{redact-lAmck1Z6.cjs → redact-DoC7lSsp.cjs} +109 -24
  41. package/dist/shared/redact-DoC7lSsp.cjs.map +1 -0
  42. package/dist/shared/{render-UsOGMRzS.d.ts → render-CBroJPcV.d.ts} +178 -252
  43. package/dist/shared/{render-9F_kR6sq.d.cts → render-DM7AhTZW.d.cts} +178 -252
  44. package/dist/shared/{render-C6CJ343E.js → render-DRh5_aRe.js} +128 -135
  45. package/dist/shared/render-DRh5_aRe.js.map +1 -0
  46. package/dist/shared/{render-BrrZOSV5.cjs → render-Dnc84B4M.cjs} +234 -241
  47. package/dist/shared/render-Dnc84B4M.cjs.map +1 -0
  48. package/dist/shared/{storage-DiDe0PZM.js → storage-86wiHeXD.js} +3 -3
  49. package/dist/shared/{storage-DiDe0PZM.js.map → storage-86wiHeXD.js.map} +1 -1
  50. package/dist/shared/{storage-CZJZoaz9.cjs → storage-CIjejZDt.cjs} +4 -4
  51. package/dist/shared/{storage-CZJZoaz9.cjs.map → storage-CIjejZDt.cjs.map} +1 -1
  52. package/dist/shared/{url-yB6T_H_-.d.ts → url-BOi-_mJT.d.cts} +143 -79
  53. package/dist/shared/{url-yB6T_H_-.d.cts → url-BOi-_mJT.d.ts} +143 -79
  54. package/dist/shared/{url-Dc7wLikf.js → url-Bg61sk_Y.js} +723 -590
  55. package/dist/shared/url-Bg61sk_Y.js.map +1 -0
  56. package/dist/shared/{url-BNTKqBMB.cjs → url-DTgkCWv5.cjs} +830 -709
  57. package/dist/shared/url-DTgkCWv5.cjs.map +1 -0
  58. package/dist/shared/{errors-BmP3TKoW.cjs → validate-CFx2dISs.cjs} +84 -5
  59. package/dist/shared/validate-CFx2dISs.cjs.map +1 -0
  60. package/dist/shared/{errors-GI10kZxk.js → validate-D7_kq3g5.js} +55 -6
  61. package/dist/shared/validate-D7_kq3g5.js.map +1 -0
  62. package/dist/web/index.cjs +4 -4
  63. package/dist/web/index.cjs.map +1 -1
  64. package/dist/web/index.js +3 -3
  65. package/package.json +1 -1
  66. package/dist/shared/errors-BmP3TKoW.cjs.map +0 -1
  67. package/dist/shared/errors-GI10kZxk.js.map +0 -1
  68. package/dist/shared/events-B8cjz_Ed.cjs.map +0 -1
  69. package/dist/shared/events-D2n7Yu1P.js.map +0 -1
  70. package/dist/shared/key-value-store-B5GYVEYZ.cjs.map +0 -1
  71. package/dist/shared/key-value-store-Bt2PSMxY.js.map +0 -1
  72. package/dist/shared/multi-storage-C3Ngtop1.js.map +0 -1
  73. package/dist/shared/multi-storage-s-fPtjoy.cjs.map +0 -1
  74. package/dist/shared/redact-DJV0XM3n.js.map +0 -1
  75. package/dist/shared/redact-lAmck1Z6.cjs.map +0 -1
  76. package/dist/shared/render-BrrZOSV5.cjs.map +0 -1
  77. package/dist/shared/render-C6CJ343E.js.map +0 -1
  78. package/dist/shared/url-BNTKqBMB.cjs.map +0 -1
  79. package/dist/shared/url-Dc7wLikf.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { a as ItdConfigError } from "./errors-GI10kZxk.js";
2
- import { r as createKeyValueStore, t as MemoryKeyValueStore } from "./key-value-store-Bt2PSMxY.js";
1
+ import { l as ItdConfigError } from "./validate-D7_kq3g5.js";
2
+ import { r as createKeyValueStore, t as MemoryKeyValueStore } from "./key-value-store-w1Dn5Pjb.js";
3
3
  //#region src/session/storage.ts
4
4
  /**
5
5
  * Создаёт независимый снимок сессии.
@@ -70,4 +70,4 @@ function createTokenStorage(store, options = {}) {
70
70
  //#endregion
71
71
  export { copySession as n, createTokenStorage as r, MemoryTokenStorage as t };
72
72
 
73
- //# sourceMappingURL=storage-DiDe0PZM.js.map
73
+ //# sourceMappingURL=storage-86wiHeXD.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage-DiDe0PZM.js","names":["#store"],"sources":["../../src/session/storage.ts"],"sourcesContent":["import { ItdConfigError } from '../core/errors.js';\nimport {\n createKeyValueStore,\n type KeyValueStore,\n MemoryKeyValueStore,\n} from '../core/key-value-store.js';\n\n/**\n * Сохранённая сессия.\n *\n * Кроме токенов сюда попадают cookie: refresh-токен итд.com живёт именно в cookie, и без них\n * восстановить сессию после перезапуска процесса невозможно.\n */\nexport interface ItdSession {\n /** Токен доступа для заголовка `Authorization: Bearer`. */\n accessToken?: string | undefined;\n /**\n * Refresh-токен, если удалось получить его явным значением.\n *\n * Обычно сервер держит его в httpOnly-cookie и наружу не отдаёт — тогда поле останется\n * пустым, а обновление пойдёт через {@link ItdSession.cookies}.\n */\n refreshToken?: string | undefined;\n /** Сырые cookie в форме `имя=значение`, привязанные к origin API. */\n cookies?: string[] | undefined;\n /**\n * Идентификатор устройства для заголовка `X-Device-Id`.\n *\n * Сервер различает по нему записи в списке сессий, поэтому значение должно пережить\n * перезапуск процесса — иначе каждый старт бота порождает новую сессию. Библиотека\n * заводит его сама при первом запросе и хранит здесь.\n */\n deviceId?: string | undefined;\n /** Когда сессия получена, мс с начала эпохи. Нужно для диагностики. */\n obtainedAt?: number | undefined;\n}\n\n/**\n * Создаёт независимый снимок сессии.\n *\n * Сессии пересекают границу пользовательского кода и внутреннего состояния клиента.\n * Возвращать или сохранять их по ссылке нельзя: последующая мутация объекта или массива\n * cookie меняла бы уже сохранённую сессию без вызова `set()`.\n *\n * @internal\n */\nexport function copySession(session: ItdSession): ItdSession {\n // Storage — runtime-граница: декодированный backend может нарушить TypeScript-контракт.\n // Не преобразуем такое значение до проверки AuthManager и клонируем cookies только как массив.\n if (typeof session !== 'object' || session === null || Array.isArray(session)) return session;\n const cookies = (session as { cookies?: unknown }).cookies;\n return {\n ...session,\n ...(Array.isArray(cookies) ? { cookies: [...cookies] } : {}),\n };\n}\n\n/**\n * Хранилище сессии.\n *\n * Подключаемый компонент: библиотека не знает, где вы держите токены, и обращается к ним\n * только через этот интерфейс. Все методы могут быть как синхронными, так и асинхронными.\n *\n * @example Своё хранилище поверх AsyncStorage в React Native\n * ```ts\n * const backend = withCodec(createKeyValueStore({\n * get: (key) => AsyncStorage.getItem(key).then((value) => value ?? undefined),\n * set: (key, value) => AsyncStorage.setItem(key, value),\n * delete: (key) => AsyncStorage.removeItem(key),\n * }), { encode: JSON.stringify, decode: JSON.parse });\n * const storage = createTokenStorage(withNamespace(backend, 'my-app'));\n * ```\n */\nexport interface TokenStorage {\n /** Прочитать сессию. `null`, если её нет. */\n get(): ItdSession | null | Promise<ItdSession | null>;\n /** Сохранить сессию целиком. */\n set(session: ItdSession): void | Promise<void>;\n /** Удалить сессию. Вызывается при выходе и при неудачном обновлении токена. */\n clear(): void | Promise<void>;\n}\n\n/**\n * Хранилище в памяти процесса — вариант по умолчанию.\n *\n * Сессия теряется при перезапуске. Для долгоживущих ботов возьмите `FileTokenStorage`\n * из `itd-api/node`, для браузера — `LocalStorageTokenStorage` или\n * `SessionStorageTokenStorage` из `itd-api/web`.\n */\nexport class MemoryTokenStorage implements TokenStorage {\n readonly #store = new MemoryKeyValueStore<ItdSession>();\n\n constructor(initial?: ItdSession | null) {\n if (initial) this.#store.set(TOKEN_STORAGE_KEY, copySession(initial));\n }\n\n get(): ItdSession | null {\n const session = this.#store.get(TOKEN_STORAGE_KEY);\n return session ? copySession(session) : null;\n }\n\n set(session: ItdSession): void {\n this.#store.set(TOKEN_STORAGE_KEY, copySession(session));\n }\n\n clear(): void {\n this.#store.delete(TOKEN_STORAGE_KEY);\n }\n}\n\nconst TOKEN_STORAGE_KEY = 'session';\n\n/** Настройки доменного адаптера одной сессии. */\nexport interface TokenStorageAdapterOptions {\n /** Ключ сессии в backend. По умолчанию `session`. */\n key?: string | undefined;\n}\n\nfunction isPromise<T>(value: T | Promise<T>): value is Promise<T> {\n return (\n typeof value === 'object' && value !== null && typeof (value as Promise<T>).then === 'function'\n );\n}\n\n/**\n * Создаёт доменное хранилище сессии поверх общего {@link KeyValueStore}.\n *\n * @example\n * ```ts\n * const storage = createTokenStorage(withNamespace(redisStore, 'itd'));\n * ```\n */\nexport function createTokenStorage(\n store: KeyValueStore<ItdSession>,\n options: TokenStorageAdapterOptions = {},\n): TokenStorage {\n const key = options.key ?? TOKEN_STORAGE_KEY;\n if (typeof key !== 'string') throw new ItdConfigError('key TokenStorage должен быть строкой');\n const backend = createKeyValueStore(store);\n return {\n get() {\n const value = backend.get(key);\n if (isPromise(value)) {\n return value.then((session) => (session ? copySession(session) : null));\n }\n return value ? copySession(value) : null;\n },\n set: (session) => backend.set(key, copySession(session)),\n clear: () => backend.delete(key),\n };\n}\n"],"mappings":";;;;;;;;;;;;AA8CA,SAAgB,YAAY,SAAiC;CAG3D,IAAI,OAAO,YAAY,YAAY,YAAY,QAAQ,MAAM,QAAQ,OAAO,GAAG,OAAO;CACtF,MAAM,UAAW,QAAkC;CACnD,OAAO;EACL,GAAG;EACH,GAAI,MAAM,QAAQ,OAAO,IAAI,EAAE,SAAS,CAAC,GAAG,OAAO,EAAE,IAAI,CAAC;CAC5D;AACF;;;;;;;;AAkCA,IAAa,qBAAb,MAAwD;CACtD,SAAkB,IAAI,oBAAgC;CAEtD,YAAY,SAA6B;EACvC,IAAI,SAAS,KAAKA,OAAO,IAAI,mBAAmB,YAAY,OAAO,CAAC;CACtE;CAEA,MAAyB;EACvB,MAAM,UAAU,KAAKA,OAAO,IAAI,iBAAiB;EACjD,OAAO,UAAU,YAAY,OAAO,IAAI;CAC1C;CAEA,IAAI,SAA2B;EAC7B,KAAKA,OAAO,IAAI,mBAAmB,YAAY,OAAO,CAAC;CACzD;CAEA,QAAc;EACZ,KAAKA,OAAO,OAAO,iBAAiB;CACtC;AACF;AAEA,MAAM,oBAAoB;AAQ1B,SAAS,UAAa,OAA4C;CAChE,OACE,OAAO,UAAU,YAAY,UAAU,QAAQ,OAAQ,MAAqB,SAAS;AAEzF;;;;;;;;;AAUA,SAAgB,mBACd,OACA,UAAsC,CAAC,GACzB;CACd,MAAM,MAAM,QAAQ,OAAO;CAC3B,IAAI,OAAO,QAAQ,UAAU,MAAM,IAAI,eAAe,sCAAsC;CAC5F,MAAM,UAAU,oBAAoB,KAAK;CACzC,OAAO;EACL,MAAM;GACJ,MAAM,QAAQ,QAAQ,IAAI,GAAG;GAC7B,IAAI,UAAU,KAAK,GACjB,OAAO,MAAM,MAAM,YAAa,UAAU,YAAY,OAAO,IAAI,IAAK;GAExE,OAAO,QAAQ,YAAY,KAAK,IAAI;EACtC;EACA,MAAM,YAAY,QAAQ,IAAI,KAAK,YAAY,OAAO,CAAC;EACvD,aAAa,QAAQ,OAAO,GAAG;CACjC;AACF"}
1
+ {"version":3,"file":"storage-86wiHeXD.js","names":["#store"],"sources":["../../src/session/storage.ts"],"sourcesContent":["import { ItdConfigError } from '../core/errors.js';\nimport {\n createKeyValueStore,\n type KeyValueStore,\n MemoryKeyValueStore,\n} from '../core/key-value-store.js';\n\n/**\n * Сохранённая сессия.\n *\n * Кроме токенов сюда попадают cookie: refresh-токен итд.com живёт именно в cookie, и без них\n * восстановить сессию после перезапуска процесса невозможно.\n */\nexport interface ItdSession {\n /** Токен доступа для заголовка `Authorization: Bearer`. */\n accessToken?: string | undefined;\n /**\n * Refresh-токен, если удалось получить его явным значением.\n *\n * Обычно сервер держит его в httpOnly-cookie и наружу не отдаёт — тогда поле останется\n * пустым, а обновление пойдёт через {@link ItdSession.cookies}.\n */\n refreshToken?: string | undefined;\n /** Сырые cookie в форме `имя=значение`, привязанные к origin API. */\n cookies?: string[] | undefined;\n /**\n * Идентификатор устройства для заголовка `X-Device-Id`.\n *\n * Сервер различает по нему записи в списке сессий, поэтому значение должно пережить\n * перезапуск процесса — иначе каждый старт бота порождает новую сессию. Библиотека\n * заводит его сама при первом запросе и хранит здесь.\n */\n deviceId?: string | undefined;\n /** Когда сессия получена, мс с начала эпохи. Нужно для диагностики. */\n obtainedAt?: number | undefined;\n}\n\n/**\n * Создаёт независимый снимок сессии.\n *\n * Сессии пересекают границу пользовательского кода и внутреннего состояния клиента.\n * Возвращать или сохранять их по ссылке нельзя: последующая мутация объекта или массива\n * cookie меняла бы уже сохранённую сессию без вызова `set()`.\n *\n * @internal\n */\nexport function copySession(session: ItdSession): ItdSession {\n // Storage — runtime-граница: декодированный backend может нарушить TypeScript-контракт.\n // Не преобразуем такое значение до проверки AuthManager и клонируем cookies только как массив.\n if (typeof session !== 'object' || session === null || Array.isArray(session)) return session;\n const cookies = (session as { cookies?: unknown }).cookies;\n return {\n ...session,\n ...(Array.isArray(cookies) ? { cookies: [...cookies] } : {}),\n };\n}\n\n/**\n * Хранилище сессии.\n *\n * Подключаемый компонент: библиотека не знает, где вы держите токены, и обращается к ним\n * только через этот интерфейс. Все методы могут быть как синхронными, так и асинхронными.\n *\n * @example Своё хранилище поверх AsyncStorage в React Native\n * ```ts\n * const backend = withCodec(createKeyValueStore({\n * get: (key) => AsyncStorage.getItem(key).then((value) => value ?? undefined),\n * set: (key, value) => AsyncStorage.setItem(key, value),\n * delete: (key) => AsyncStorage.removeItem(key),\n * }), { encode: JSON.stringify, decode: JSON.parse });\n * const storage = createTokenStorage(withNamespace(backend, 'my-app'));\n * ```\n */\nexport interface TokenStorage {\n /** Прочитать сессию. `null`, если её нет. */\n get(): ItdSession | null | Promise<ItdSession | null>;\n /** Сохранить сессию целиком. */\n set(session: ItdSession): void | Promise<void>;\n /** Удалить сессию. Вызывается при выходе и при неудачном обновлении токена. */\n clear(): void | Promise<void>;\n}\n\n/**\n * Хранилище в памяти процесса — вариант по умолчанию.\n *\n * Сессия теряется при перезапуске. Для долгоживущих ботов возьмите `FileTokenStorage`\n * из `itd-api/node`, для браузера — `LocalStorageTokenStorage` или\n * `SessionStorageTokenStorage` из `itd-api/web`.\n */\nexport class MemoryTokenStorage implements TokenStorage {\n readonly #store = new MemoryKeyValueStore<ItdSession>();\n\n constructor(initial?: ItdSession | null) {\n if (initial) this.#store.set(TOKEN_STORAGE_KEY, copySession(initial));\n }\n\n get(): ItdSession | null {\n const session = this.#store.get(TOKEN_STORAGE_KEY);\n return session ? copySession(session) : null;\n }\n\n set(session: ItdSession): void {\n this.#store.set(TOKEN_STORAGE_KEY, copySession(session));\n }\n\n clear(): void {\n this.#store.delete(TOKEN_STORAGE_KEY);\n }\n}\n\nconst TOKEN_STORAGE_KEY = 'session';\n\n/** Настройки доменного адаптера одной сессии. */\nexport interface TokenStorageAdapterOptions {\n /** Ключ сессии в backend. По умолчанию `session`. */\n key?: string | undefined;\n}\n\nfunction isPromise<T>(value: T | Promise<T>): value is Promise<T> {\n return (\n typeof value === 'object' && value !== null && typeof (value as Promise<T>).then === 'function'\n );\n}\n\n/**\n * Создаёт доменное хранилище сессии поверх общего {@link KeyValueStore}.\n *\n * @example\n * ```ts\n * const storage = createTokenStorage(withNamespace(redisStore, 'itd'));\n * ```\n */\nexport function createTokenStorage(\n store: KeyValueStore<ItdSession>,\n options: TokenStorageAdapterOptions = {},\n): TokenStorage {\n const key = options.key ?? TOKEN_STORAGE_KEY;\n if (typeof key !== 'string') throw new ItdConfigError('key TokenStorage должен быть строкой');\n const backend = createKeyValueStore(store);\n return {\n get() {\n const value = backend.get(key);\n if (isPromise(value)) {\n return value.then((session) => (session ? copySession(session) : null));\n }\n return value ? copySession(value) : null;\n },\n set: (session) => backend.set(key, copySession(session)),\n clear: () => backend.delete(key),\n };\n}\n"],"mappings":";;;;;;;;;;;;AA8CA,SAAgB,YAAY,SAAiC;CAG3D,IAAI,OAAO,YAAY,YAAY,YAAY,QAAQ,MAAM,QAAQ,OAAO,GAAG,OAAO;CACtF,MAAM,UAAW,QAAkC;CACnD,OAAO;EACL,GAAG;EACH,GAAI,MAAM,QAAQ,OAAO,IAAI,EAAE,SAAS,CAAC,GAAG,OAAO,EAAE,IAAI,CAAC;CAC5D;AACF;;;;;;;;AAkCA,IAAa,qBAAb,MAAwD;CACtD,SAAkB,IAAI,oBAAgC;CAEtD,YAAY,SAA6B;EACvC,IAAI,SAAS,KAAKA,OAAO,IAAI,mBAAmB,YAAY,OAAO,CAAC;CACtE;CAEA,MAAyB;EACvB,MAAM,UAAU,KAAKA,OAAO,IAAI,iBAAiB;EACjD,OAAO,UAAU,YAAY,OAAO,IAAI;CAC1C;CAEA,IAAI,SAA2B;EAC7B,KAAKA,OAAO,IAAI,mBAAmB,YAAY,OAAO,CAAC;CACzD;CAEA,QAAc;EACZ,KAAKA,OAAO,OAAO,iBAAiB;CACtC;AACF;AAEA,MAAM,oBAAoB;AAQ1B,SAAS,UAAa,OAA4C;CAChE,OACE,OAAO,UAAU,YAAY,UAAU,QAAQ,OAAQ,MAAqB,SAAS;AAEzF;;;;;;;;;AAUA,SAAgB,mBACd,OACA,UAAsC,CAAC,GACzB;CACd,MAAM,MAAM,QAAQ,OAAO;CAC3B,IAAI,OAAO,QAAQ,UAAU,MAAM,IAAI,eAAe,sCAAsC;CAC5F,MAAM,UAAU,oBAAoB,KAAK;CACzC,OAAO;EACL,MAAM;GACJ,MAAM,QAAQ,QAAQ,IAAI,GAAG;GAC7B,IAAI,UAAU,KAAK,GACjB,OAAO,MAAM,MAAM,YAAa,UAAU,YAAY,OAAO,IAAI,IAAK;GAExE,OAAO,QAAQ,YAAY,KAAK,IAAI;EACtC;EACA,MAAM,YAAY,QAAQ,IAAI,KAAK,YAAY,OAAO,CAAC;EACvD,aAAa,QAAQ,OAAO,GAAG;CACjC;AACF"}
@@ -1,5 +1,5 @@
1
- const require_errors = require("./errors-BmP3TKoW.cjs");
2
- const require_key_value_store = require("./key-value-store-B5GYVEYZ.cjs");
1
+ const require_validate = require("./validate-CFx2dISs.cjs");
2
+ const require_key_value_store = require("./key-value-store-DYSPsqwq.cjs");
3
3
  //#region src/session/storage.ts
4
4
  /**
5
5
  * Создаёт независимый снимок сессии.
@@ -55,7 +55,7 @@ function isPromise(value) {
55
55
  */
56
56
  function createTokenStorage(store, options = {}) {
57
57
  const key = options.key ?? TOKEN_STORAGE_KEY;
58
- if (typeof key !== "string") throw new require_errors.ItdConfigError("key TokenStorage должен быть строкой");
58
+ if (typeof key !== "string") throw new require_validate.ItdConfigError("key TokenStorage должен быть строкой");
59
59
  const backend = require_key_value_store.createKeyValueStore(store);
60
60
  return {
61
61
  get() {
@@ -87,4 +87,4 @@ Object.defineProperty(exports, "createTokenStorage", {
87
87
  }
88
88
  });
89
89
 
90
- //# sourceMappingURL=storage-CZJZoaz9.cjs.map
90
+ //# sourceMappingURL=storage-CIjejZDt.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage-CZJZoaz9.cjs","names":["#store","MemoryKeyValueStore","ItdConfigError","createKeyValueStore"],"sources":["../../src/session/storage.ts"],"sourcesContent":["import { ItdConfigError } from '../core/errors.js';\nimport {\n createKeyValueStore,\n type KeyValueStore,\n MemoryKeyValueStore,\n} from '../core/key-value-store.js';\n\n/**\n * Сохранённая сессия.\n *\n * Кроме токенов сюда попадают cookie: refresh-токен итд.com живёт именно в cookie, и без них\n * восстановить сессию после перезапуска процесса невозможно.\n */\nexport interface ItdSession {\n /** Токен доступа для заголовка `Authorization: Bearer`. */\n accessToken?: string | undefined;\n /**\n * Refresh-токен, если удалось получить его явным значением.\n *\n * Обычно сервер держит его в httpOnly-cookie и наружу не отдаёт — тогда поле останется\n * пустым, а обновление пойдёт через {@link ItdSession.cookies}.\n */\n refreshToken?: string | undefined;\n /** Сырые cookie в форме `имя=значение`, привязанные к origin API. */\n cookies?: string[] | undefined;\n /**\n * Идентификатор устройства для заголовка `X-Device-Id`.\n *\n * Сервер различает по нему записи в списке сессий, поэтому значение должно пережить\n * перезапуск процесса — иначе каждый старт бота порождает новую сессию. Библиотека\n * заводит его сама при первом запросе и хранит здесь.\n */\n deviceId?: string | undefined;\n /** Когда сессия получена, мс с начала эпохи. Нужно для диагностики. */\n obtainedAt?: number | undefined;\n}\n\n/**\n * Создаёт независимый снимок сессии.\n *\n * Сессии пересекают границу пользовательского кода и внутреннего состояния клиента.\n * Возвращать или сохранять их по ссылке нельзя: последующая мутация объекта или массива\n * cookie меняла бы уже сохранённую сессию без вызова `set()`.\n *\n * @internal\n */\nexport function copySession(session: ItdSession): ItdSession {\n // Storage — runtime-граница: декодированный backend может нарушить TypeScript-контракт.\n // Не преобразуем такое значение до проверки AuthManager и клонируем cookies только как массив.\n if (typeof session !== 'object' || session === null || Array.isArray(session)) return session;\n const cookies = (session as { cookies?: unknown }).cookies;\n return {\n ...session,\n ...(Array.isArray(cookies) ? { cookies: [...cookies] } : {}),\n };\n}\n\n/**\n * Хранилище сессии.\n *\n * Подключаемый компонент: библиотека не знает, где вы держите токены, и обращается к ним\n * только через этот интерфейс. Все методы могут быть как синхронными, так и асинхронными.\n *\n * @example Своё хранилище поверх AsyncStorage в React Native\n * ```ts\n * const backend = withCodec(createKeyValueStore({\n * get: (key) => AsyncStorage.getItem(key).then((value) => value ?? undefined),\n * set: (key, value) => AsyncStorage.setItem(key, value),\n * delete: (key) => AsyncStorage.removeItem(key),\n * }), { encode: JSON.stringify, decode: JSON.parse });\n * const storage = createTokenStorage(withNamespace(backend, 'my-app'));\n * ```\n */\nexport interface TokenStorage {\n /** Прочитать сессию. `null`, если её нет. */\n get(): ItdSession | null | Promise<ItdSession | null>;\n /** Сохранить сессию целиком. */\n set(session: ItdSession): void | Promise<void>;\n /** Удалить сессию. Вызывается при выходе и при неудачном обновлении токена. */\n clear(): void | Promise<void>;\n}\n\n/**\n * Хранилище в памяти процесса — вариант по умолчанию.\n *\n * Сессия теряется при перезапуске. Для долгоживущих ботов возьмите `FileTokenStorage`\n * из `itd-api/node`, для браузера — `LocalStorageTokenStorage` или\n * `SessionStorageTokenStorage` из `itd-api/web`.\n */\nexport class MemoryTokenStorage implements TokenStorage {\n readonly #store = new MemoryKeyValueStore<ItdSession>();\n\n constructor(initial?: ItdSession | null) {\n if (initial) this.#store.set(TOKEN_STORAGE_KEY, copySession(initial));\n }\n\n get(): ItdSession | null {\n const session = this.#store.get(TOKEN_STORAGE_KEY);\n return session ? copySession(session) : null;\n }\n\n set(session: ItdSession): void {\n this.#store.set(TOKEN_STORAGE_KEY, copySession(session));\n }\n\n clear(): void {\n this.#store.delete(TOKEN_STORAGE_KEY);\n }\n}\n\nconst TOKEN_STORAGE_KEY = 'session';\n\n/** Настройки доменного адаптера одной сессии. */\nexport interface TokenStorageAdapterOptions {\n /** Ключ сессии в backend. По умолчанию `session`. */\n key?: string | undefined;\n}\n\nfunction isPromise<T>(value: T | Promise<T>): value is Promise<T> {\n return (\n typeof value === 'object' && value !== null && typeof (value as Promise<T>).then === 'function'\n );\n}\n\n/**\n * Создаёт доменное хранилище сессии поверх общего {@link KeyValueStore}.\n *\n * @example\n * ```ts\n * const storage = createTokenStorage(withNamespace(redisStore, 'itd'));\n * ```\n */\nexport function createTokenStorage(\n store: KeyValueStore<ItdSession>,\n options: TokenStorageAdapterOptions = {},\n): TokenStorage {\n const key = options.key ?? TOKEN_STORAGE_KEY;\n if (typeof key !== 'string') throw new ItdConfigError('key TokenStorage должен быть строкой');\n const backend = createKeyValueStore(store);\n return {\n get() {\n const value = backend.get(key);\n if (isPromise(value)) {\n return value.then((session) => (session ? copySession(session) : null));\n }\n return value ? copySession(value) : null;\n },\n set: (session) => backend.set(key, copySession(session)),\n clear: () => backend.delete(key),\n };\n}\n"],"mappings":";;;;;;;;;;;;AA8CA,SAAgB,YAAY,SAAiC;CAG3D,IAAI,OAAO,YAAY,YAAY,YAAY,QAAQ,MAAM,QAAQ,OAAO,GAAG,OAAO;CACtF,MAAM,UAAW,QAAkC;CACnD,OAAO;EACL,GAAG;EACH,GAAI,MAAM,QAAQ,OAAO,IAAI,EAAE,SAAS,CAAC,GAAG,OAAO,EAAE,IAAI,CAAC;CAC5D;AACF;;;;;;;;AAkCA,IAAa,qBAAb,MAAwD;CACtD,SAAkB,IAAIC,wBAAAA,oBAAgC;CAEtD,YAAY,SAA6B;EACvC,IAAI,SAAS,KAAKD,OAAO,IAAI,mBAAmB,YAAY,OAAO,CAAC;CACtE;CAEA,MAAyB;EACvB,MAAM,UAAU,KAAKA,OAAO,IAAI,iBAAiB;EACjD,OAAO,UAAU,YAAY,OAAO,IAAI;CAC1C;CAEA,IAAI,SAA2B;EAC7B,KAAKA,OAAO,IAAI,mBAAmB,YAAY,OAAO,CAAC;CACzD;CAEA,QAAc;EACZ,KAAKA,OAAO,OAAO,iBAAiB;CACtC;AACF;AAEA,MAAM,oBAAoB;AAQ1B,SAAS,UAAa,OAA4C;CAChE,OACE,OAAO,UAAU,YAAY,UAAU,QAAQ,OAAQ,MAAqB,SAAS;AAEzF;;;;;;;;;AAUA,SAAgB,mBACd,OACA,UAAsC,CAAC,GACzB;CACd,MAAM,MAAM,QAAQ,OAAO;CAC3B,IAAI,OAAO,QAAQ,UAAU,MAAM,IAAIE,eAAAA,eAAe,sCAAsC;CAC5F,MAAM,UAAUC,wBAAAA,oBAAoB,KAAK;CACzC,OAAO;EACL,MAAM;GACJ,MAAM,QAAQ,QAAQ,IAAI,GAAG;GAC7B,IAAI,UAAU,KAAK,GACjB,OAAO,MAAM,MAAM,YAAa,UAAU,YAAY,OAAO,IAAI,IAAK;GAExE,OAAO,QAAQ,YAAY,KAAK,IAAI;EACtC;EACA,MAAM,YAAY,QAAQ,IAAI,KAAK,YAAY,OAAO,CAAC;EACvD,aAAa,QAAQ,OAAO,GAAG;CACjC;AACF"}
1
+ {"version":3,"file":"storage-CIjejZDt.cjs","names":["#store","MemoryKeyValueStore","ItdConfigError","createKeyValueStore"],"sources":["../../src/session/storage.ts"],"sourcesContent":["import { ItdConfigError } from '../core/errors.js';\nimport {\n createKeyValueStore,\n type KeyValueStore,\n MemoryKeyValueStore,\n} from '../core/key-value-store.js';\n\n/**\n * Сохранённая сессия.\n *\n * Кроме токенов сюда попадают cookie: refresh-токен итд.com живёт именно в cookie, и без них\n * восстановить сессию после перезапуска процесса невозможно.\n */\nexport interface ItdSession {\n /** Токен доступа для заголовка `Authorization: Bearer`. */\n accessToken?: string | undefined;\n /**\n * Refresh-токен, если удалось получить его явным значением.\n *\n * Обычно сервер держит его в httpOnly-cookie и наружу не отдаёт — тогда поле останется\n * пустым, а обновление пойдёт через {@link ItdSession.cookies}.\n */\n refreshToken?: string | undefined;\n /** Сырые cookie в форме `имя=значение`, привязанные к origin API. */\n cookies?: string[] | undefined;\n /**\n * Идентификатор устройства для заголовка `X-Device-Id`.\n *\n * Сервер различает по нему записи в списке сессий, поэтому значение должно пережить\n * перезапуск процесса — иначе каждый старт бота порождает новую сессию. Библиотека\n * заводит его сама при первом запросе и хранит здесь.\n */\n deviceId?: string | undefined;\n /** Когда сессия получена, мс с начала эпохи. Нужно для диагностики. */\n obtainedAt?: number | undefined;\n}\n\n/**\n * Создаёт независимый снимок сессии.\n *\n * Сессии пересекают границу пользовательского кода и внутреннего состояния клиента.\n * Возвращать или сохранять их по ссылке нельзя: последующая мутация объекта или массива\n * cookie меняла бы уже сохранённую сессию без вызова `set()`.\n *\n * @internal\n */\nexport function copySession(session: ItdSession): ItdSession {\n // Storage — runtime-граница: декодированный backend может нарушить TypeScript-контракт.\n // Не преобразуем такое значение до проверки AuthManager и клонируем cookies только как массив.\n if (typeof session !== 'object' || session === null || Array.isArray(session)) return session;\n const cookies = (session as { cookies?: unknown }).cookies;\n return {\n ...session,\n ...(Array.isArray(cookies) ? { cookies: [...cookies] } : {}),\n };\n}\n\n/**\n * Хранилище сессии.\n *\n * Подключаемый компонент: библиотека не знает, где вы держите токены, и обращается к ним\n * только через этот интерфейс. Все методы могут быть как синхронными, так и асинхронными.\n *\n * @example Своё хранилище поверх AsyncStorage в React Native\n * ```ts\n * const backend = withCodec(createKeyValueStore({\n * get: (key) => AsyncStorage.getItem(key).then((value) => value ?? undefined),\n * set: (key, value) => AsyncStorage.setItem(key, value),\n * delete: (key) => AsyncStorage.removeItem(key),\n * }), { encode: JSON.stringify, decode: JSON.parse });\n * const storage = createTokenStorage(withNamespace(backend, 'my-app'));\n * ```\n */\nexport interface TokenStorage {\n /** Прочитать сессию. `null`, если её нет. */\n get(): ItdSession | null | Promise<ItdSession | null>;\n /** Сохранить сессию целиком. */\n set(session: ItdSession): void | Promise<void>;\n /** Удалить сессию. Вызывается при выходе и при неудачном обновлении токена. */\n clear(): void | Promise<void>;\n}\n\n/**\n * Хранилище в памяти процесса — вариант по умолчанию.\n *\n * Сессия теряется при перезапуске. Для долгоживущих ботов возьмите `FileTokenStorage`\n * из `itd-api/node`, для браузера — `LocalStorageTokenStorage` или\n * `SessionStorageTokenStorage` из `itd-api/web`.\n */\nexport class MemoryTokenStorage implements TokenStorage {\n readonly #store = new MemoryKeyValueStore<ItdSession>();\n\n constructor(initial?: ItdSession | null) {\n if (initial) this.#store.set(TOKEN_STORAGE_KEY, copySession(initial));\n }\n\n get(): ItdSession | null {\n const session = this.#store.get(TOKEN_STORAGE_KEY);\n return session ? copySession(session) : null;\n }\n\n set(session: ItdSession): void {\n this.#store.set(TOKEN_STORAGE_KEY, copySession(session));\n }\n\n clear(): void {\n this.#store.delete(TOKEN_STORAGE_KEY);\n }\n}\n\nconst TOKEN_STORAGE_KEY = 'session';\n\n/** Настройки доменного адаптера одной сессии. */\nexport interface TokenStorageAdapterOptions {\n /** Ключ сессии в backend. По умолчанию `session`. */\n key?: string | undefined;\n}\n\nfunction isPromise<T>(value: T | Promise<T>): value is Promise<T> {\n return (\n typeof value === 'object' && value !== null && typeof (value as Promise<T>).then === 'function'\n );\n}\n\n/**\n * Создаёт доменное хранилище сессии поверх общего {@link KeyValueStore}.\n *\n * @example\n * ```ts\n * const storage = createTokenStorage(withNamespace(redisStore, 'itd'));\n * ```\n */\nexport function createTokenStorage(\n store: KeyValueStore<ItdSession>,\n options: TokenStorageAdapterOptions = {},\n): TokenStorage {\n const key = options.key ?? TOKEN_STORAGE_KEY;\n if (typeof key !== 'string') throw new ItdConfigError('key TokenStorage должен быть строкой');\n const backend = createKeyValueStore(store);\n return {\n get() {\n const value = backend.get(key);\n if (isPromise(value)) {\n return value.then((session) => (session ? copySession(session) : null));\n }\n return value ? copySession(value) : null;\n },\n set: (session) => backend.set(key, copySession(session)),\n clear: () => backend.delete(key),\n };\n}\n"],"mappings":";;;;;;;;;;;;AA8CA,SAAgB,YAAY,SAAiC;CAG3D,IAAI,OAAO,YAAY,YAAY,YAAY,QAAQ,MAAM,QAAQ,OAAO,GAAG,OAAO;CACtF,MAAM,UAAW,QAAkC;CACnD,OAAO;EACL,GAAG;EACH,GAAI,MAAM,QAAQ,OAAO,IAAI,EAAE,SAAS,CAAC,GAAG,OAAO,EAAE,IAAI,CAAC;CAC5D;AACF;;;;;;;;AAkCA,IAAa,qBAAb,MAAwD;CACtD,SAAkB,IAAIC,wBAAAA,oBAAgC;CAEtD,YAAY,SAA6B;EACvC,IAAI,SAAS,KAAKD,OAAO,IAAI,mBAAmB,YAAY,OAAO,CAAC;CACtE;CAEA,MAAyB;EACvB,MAAM,UAAU,KAAKA,OAAO,IAAI,iBAAiB;EACjD,OAAO,UAAU,YAAY,OAAO,IAAI;CAC1C;CAEA,IAAI,SAA2B;EAC7B,KAAKA,OAAO,IAAI,mBAAmB,YAAY,OAAO,CAAC;CACzD;CAEA,QAAc;EACZ,KAAKA,OAAO,OAAO,iBAAiB;CACtC;AACF;AAEA,MAAM,oBAAoB;AAQ1B,SAAS,UAAa,OAA4C;CAChE,OACE,OAAO,UAAU,YAAY,UAAU,QAAQ,OAAQ,MAAqB,SAAS;AAEzF;;;;;;;;;AAUA,SAAgB,mBACd,OACA,UAAsC,CAAC,GACzB;CACd,MAAM,MAAM,QAAQ,OAAO;CAC3B,IAAI,OAAO,QAAQ,UAAU,MAAM,IAAIE,iBAAAA,eAAe,sCAAsC;CAC5F,MAAM,UAAUC,wBAAAA,oBAAoB,KAAK;CACzC,OAAO;EACL,MAAM;GACJ,MAAM,QAAQ,QAAQ,IAAI,GAAG;GAC7B,IAAI,UAAU,KAAK,GACjB,OAAO,MAAM,MAAM,YAAa,UAAU,YAAY,OAAO,IAAI,IAAK;GAExE,OAAO,QAAQ,YAAY,KAAK,IAAI;EACtC;EACA,MAAM,YAAY,QAAQ,IAAI,KAAK,YAAY,OAAO,CAAC;EACvD,aAAa,QAAQ,OAAO,GAAG;CACjC;AACF"}
@@ -1041,6 +1041,28 @@ interface ItdClock {
1041
1041
  /** Системные часы, используемые клиентом по умолчанию. */
1042
1042
  declare const systemClock: ItdClock;
1043
1043
  //#endregion
1044
+ //#region src/core/logger.d.ts
1045
+ /**
1046
+ * Логгер библиотеки. Совместим с `console`: к сообщению прилагается не больше одного
1047
+ * аргумента — объект с деталями либо ошибка.
1048
+ */
1049
+ interface Logger {
1050
+ debug(message: string, ...args: unknown[]): void;
1051
+ info(message: string, ...args: unknown[]): void;
1052
+ warn(message: string, ...args: unknown[]): void;
1053
+ error(message: string, ...args: unknown[]): void;
1054
+ /** Пишет ли логгер этот уровень; без метода считается, что пишет все. Есть у winston и pino. */
1055
+ isLevelEnabled?(level: LogLevel): boolean;
1056
+ }
1057
+ /** Уровень записи журнала. */
1058
+ declare const LogLevel: Readonly<{
1059
+ readonly Debug: "debug";
1060
+ readonly Info: "info";
1061
+ readonly Warn: "warn";
1062
+ readonly Error: "error";
1063
+ }>;
1064
+ type LogLevel = (typeof LogLevel)[keyof typeof LogLevel];
1065
+ //#endregion
1044
1066
  //#region src/core/runtime.d.ts
1045
1067
  /**
1046
1068
  * Как библиотека обращается с cookie.
@@ -1096,13 +1118,6 @@ type QueryValue = string | number | boolean | null | undefined | readonly (strin
1096
1118
  type QueryParams = Record<string, QueryValue>;
1097
1119
  //#endregion
1098
1120
  //#region src/core/options.d.ts
1099
- /** Логгер библиотеки. Совместим с `console`. */
1100
- interface Logger {
1101
- debug(message: string, ...args: unknown[]): void;
1102
- info(message: string, ...args: unknown[]): void;
1103
- warn(message: string, ...args: unknown[]): void;
1104
- error(message: string, ...args: unknown[]): void;
1105
- }
1106
1121
  /** Настройки повторных попыток. */
1107
1122
  interface RetryOptions {
1108
1123
  /** Сколько всего попыток, включая первую. По умолчанию 3. */
@@ -1186,39 +1201,39 @@ interface RateLimitOptions {
1186
1201
  */
1187
1202
  retryDelays?: readonly number[] | undefined;
1188
1203
  }
1189
- /** Данные о запросе, доступные хукам. */
1204
+ /** Данные о запросе, доступные хукам. Изменяем только объект `headers`. */
1190
1205
  interface RequestContext {
1191
1206
  /** Стабильная семантическая операция; `raw` у низкоуровневого вызова без явного ID. */
1192
- operationId: OperationId;
1193
- /** Общий сигнал пользовательской отмены, timeout и освобождения клиента. */
1194
- signal: AbortSignal | undefined;
1195
- method: string;
1207
+ readonly operationId: OperationId;
1208
+ /** Общий сигнал пользовательской отмены, истёкших сроков и освобождения клиента. */
1209
+ readonly signal: AbortSignal | undefined;
1210
+ readonly method: string;
1196
1211
  /** Путь без базового URL, например `/api/posts`. */
1197
- path: string;
1212
+ readonly path: string;
1198
1213
  /** Итоговый URL со строкой запроса. */
1199
- url: string;
1200
- headers: Headers;
1214
+ readonly url: string;
1215
+ readonly headers: Headers;
1201
1216
  /** Номер попытки, начиная с 1. */
1202
- attempt: number;
1217
+ readonly attempt: number;
1203
1218
  }
1204
1219
  /** Данные об успешном ответе. */
1205
1220
  interface ResponseContext extends RequestContext {
1206
- status: number;
1221
+ readonly status: number;
1207
1222
  /** Длительность запроса в мс. */
1208
- duration: number;
1223
+ readonly duration: number;
1209
1224
  /** Отдельная копия ответа: её тело можно прочитать, не мешая разбору внутри SDK. */
1210
- response: Response;
1225
+ readonly response: Response;
1211
1226
  }
1212
1227
  /** Данные об ошибке запроса. */
1213
1228
  interface ErrorContextHook extends RequestContext {
1214
- duration: number;
1215
- error: unknown;
1229
+ readonly duration: number;
1230
+ readonly error: unknown;
1216
1231
  }
1217
1232
  /** Данные о предстоящем повторе. */
1218
1233
  interface RetryContext extends RequestContext {
1219
- error: unknown;
1234
+ readonly error: unknown;
1220
1235
  /** Пауза перед следующей попыткой в мс. */
1221
- delay: number;
1236
+ readonly delay: number;
1222
1237
  }
1223
1238
  /**
1224
1239
  * Хуки запроса.
@@ -1273,8 +1288,24 @@ interface RuntimeOptions {
1273
1288
  * ```
1274
1289
  */
1275
1290
  services?: Record<string, string | Omit<ServiceDefinition, 'name'>> | undefined;
1276
- /** Таймаут запроса в мс. По умолчанию 30000 — столько же использует сайт итд.com. `0` снимает ограничение. */
1291
+ /**
1292
+ * Таймаут одной транспортной попытки в мс. По умолчанию 30000 — столько же использует
1293
+ * сайт итд.com. `0` снимает ограничение.
1294
+ *
1295
+ * Охватывает сборку заголовков, хуки `onRequest` и `onResponse`, перехватчики попытки,
1296
+ * запрос и чтение тела ответа. Ожидание очереди, паузы между повторами и хук `onError`
1297
+ * в него не входят. Истечение даёт {@link ItdTimeoutError} с `budget: 'attempt'`;
1298
+ * safe- и idempotent-операции повторяются.
1299
+ */
1277
1300
  timeout?: number | undefined;
1301
+ /**
1302
+ * Общий срок логической операции в мс: очередь, повторы, обновление авторизации, плагины
1303
+ * и хуки. По умолчанию не ограничен.
1304
+ *
1305
+ * Истечение даёт {@link ItdTimeoutError} с `budget: 'deadline'` и не повторяется. Тот же
1306
+ * эффект даёт `signal: AbortSignal.timeout(ms)`, но с {@link ItdAbortError}.
1307
+ */
1308
+ deadline?: number | undefined;
1278
1309
  /**
1279
1310
  * Сколько `close()` и `dispose()` ждут чужой код, мс. По умолчанию 10000.
1280
1311
  *
@@ -1305,8 +1336,8 @@ interface RuntimeOptions {
1305
1336
  userAgent?: string | false | undefined;
1306
1337
  /** Хуки запросов. */
1307
1338
  hooks?: ClientHooks | undefined;
1308
- /** Логгер. `true` — использовать `console`. */
1309
- logger?: Logger | boolean | undefined;
1339
+ /** Логгер. `true` — консоль с уровня `info`, `LogLevel` — с указанного уровня, объект — свой. */
1340
+ logger?: Logger | LogLevel | boolean | undefined;
1310
1341
  }
1311
1342
  /**
1312
1343
  * Настройки плагинов для отдельной операции.
@@ -1318,11 +1349,16 @@ interface RequestExtensions {}
1318
1349
  interface RequestOptions {
1319
1350
  /** Отмена запроса извне. */
1320
1351
  signal?: AbortSignal | undefined;
1321
- /** Таймаут только для этого запроса, мс. */
1352
+ /** Таймаут одной транспортной попытки только для этого запроса, мс. */
1322
1353
  timeout?: number | undefined;
1354
+ /** Общий срок только для этого запроса, мс. См. {@link RuntimeOptions.deadline}. */
1355
+ deadline?: number | undefined;
1323
1356
  /** Дополнительные заголовки. */
1324
1357
  headers?: Record<string, string> | undefined;
1325
- /** Повторы только для этого запроса. Переопределяют глобальную настройку `retry`. */
1358
+ /**
1359
+ * Повторы только для этого запроса. Переопределяют глобальную настройку `retry`.
1360
+ * Лестницу пауз после `429` не затрагивают — как и глобальное `retry: false`.
1361
+ */
1326
1362
  retry?: RetryOptions | false | undefined;
1327
1363
  /**
1328
1364
  * Явно переопределяет безопасность повтора операции.
@@ -1400,7 +1436,14 @@ interface OperationRequestOptions extends RawRequestOptions {
1400
1436
  //#endregion
1401
1437
  //#region src/core/operation.d.ts
1402
1438
  /** HTTP-метод операции. */
1403
- type OperationMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
1439
+ declare const OperationMethod: Readonly<{
1440
+ readonly Get: "GET";
1441
+ readonly Post: "POST";
1442
+ readonly Put: "PUT";
1443
+ readonly Patch: "PATCH";
1444
+ readonly Delete: "DELETE";
1445
+ }>;
1446
+ type OperationMethod = (typeof OperationMethod)[keyof typeof OperationMethod];
1404
1447
  /** ID операции подключаемого модуля: `<featureName>.<operationName>`. */
1405
1448
  type FeatureOperationId<TFeatureName extends string = string, TOperationName extends string = string> = `${TFeatureName}.${TOperationName}`;
1406
1449
  /** Семантическая безопасность автоматического повтора операции. */
@@ -1450,7 +1493,7 @@ interface OperationDefinition extends OperationMetadata {
1450
1493
  //#endregion
1451
1494
  //#region src/core/version.d.ts
1452
1495
  /** Версия библиотеки. Попадает в `User-Agent`. */
1453
- declare const LIBRARY_VERSION = "0.10.4";
1496
+ declare const LIBRARY_VERSION = "0.11.0";
1454
1497
  //#endregion
1455
1498
  //#region src/core/config.d.ts
1456
1499
  /** Базовый URL API итд.com. Домен записан в punycode: `итд.com`. */
@@ -1458,49 +1501,6 @@ declare const DEFAULT_BASE_URL = "https://xn--d1ah4a.com";
1458
1501
  /** Имя встроенного сервиса статуса. */
1459
1502
  declare const STATUS_SERVICE = "status";
1460
1503
  //#endregion
1461
- //#region src/core/emitter.d.ts
1462
- /** Обработчик события. */
1463
- type Listener<T> = (payload: T) => void;
1464
- /** Функция отписки, которую возвращает подписка на событие. */
1465
- type Unsubscribe = () => void;
1466
- /**
1467
- * Минимальный типизированный источник событий.
1468
- *
1469
- * Своя реализация вместо `EventTarget` и `EventEmitter`: первый есть не везде и требует
1470
- * обёрток `CustomEvent`, второй существует только в Node. Нужны ровно подписка и рассылка.
1471
- *
1472
- * Исключение в обработчике не прерывает рассылку остальным и не роняет библиотеку.
1473
- *
1474
- * @typeParam Events карта «имя события → тип полезной нагрузки». Задаётся интерфейсом,
1475
- * поэтому ограничение на индексную сигнатуру намеренно не накладывается.
1476
- */
1477
- declare class Emitter<Events> {
1478
- #private;
1479
- constructor(onListenerError?: (error: unknown) => void);
1480
- /**
1481
- * Подписывается на событие.
1482
- *
1483
- * @returns функция отписки
1484
- *
1485
- * @example
1486
- * ```ts
1487
- * const off = events.on('notification', (event) => console.log(event));
1488
- * off();
1489
- * ```
1490
- */
1491
- on<K extends keyof Events>(event: K, listener: Listener<Events[K]>): Unsubscribe;
1492
- /** Подписывается на одно срабатывание. */
1493
- once<K extends keyof Events>(event: K, listener: Listener<Events[K]>): Unsubscribe;
1494
- /** Отписывается от события. */
1495
- off<K extends keyof Events>(event: K, listener: Listener<Events[K]>): void;
1496
- /** Рассылает событие подписчикам. */
1497
- emit<K extends keyof Events>(event: K, payload: Events[K]): void;
1498
- /** Сколько подписчиков у события. */
1499
- listenerCount(event: keyof Events): number;
1500
- /** Снимает все подписки. */
1501
- removeAllListeners(): void;
1502
- }
1503
- //#endregion
1504
1504
  //#region src/core/auth-provider.d.ts
1505
1505
  /** Области аккаунта и конкретной сессии для локального состояния плагинов. */
1506
1506
  interface AuthIdentity {
@@ -1535,7 +1535,7 @@ interface AuthProvider {
1535
1535
  */
1536
1536
  preflight?(allowRefresh: boolean): Promise<void>;
1537
1537
  /** Перед каждой попыткой читает внешний источник токена до захвата слота очереди. */
1538
- prepare(): Promise<void>;
1538
+ prepare?(): Promise<void>;
1539
1539
  /**
1540
1540
  * Заголовки уже подготовленной авторизации.
1541
1541
  *
@@ -1615,6 +1615,49 @@ interface ClientConnection {
1615
1615
  refreshAuth(): Promise<boolean>;
1616
1616
  }
1617
1617
  //#endregion
1618
+ //#region src/core/emitter.d.ts
1619
+ /** Обработчик события. */
1620
+ type Listener<T> = (payload: T) => void;
1621
+ /** Функция отписки, которую возвращает подписка на событие. */
1622
+ type Unsubscribe = () => void;
1623
+ /**
1624
+ * Минимальный типизированный источник событий.
1625
+ *
1626
+ * Своя реализация вместо `EventTarget` и `EventEmitter`: первый есть не везде и требует
1627
+ * обёрток `CustomEvent`, второй существует только в Node. Нужны ровно подписка и рассылка.
1628
+ *
1629
+ * Исключение в обработчике не прерывает рассылку остальным и не роняет библиотеку.
1630
+ *
1631
+ * @typeParam Events карта «имя события → тип полезной нагрузки». Задаётся интерфейсом,
1632
+ * поэтому ограничение на индексную сигнатуру намеренно не накладывается.
1633
+ */
1634
+ declare class Emitter<Events> {
1635
+ #private;
1636
+ constructor(onListenerError?: (error: unknown) => void);
1637
+ /**
1638
+ * Подписывается на событие.
1639
+ *
1640
+ * @returns функция отписки
1641
+ *
1642
+ * @example
1643
+ * ```ts
1644
+ * const off = events.on('notification', (event) => console.log(event));
1645
+ * off();
1646
+ * ```
1647
+ */
1648
+ on<K extends keyof Events>(event: K, listener: Listener<Events[K]>): Unsubscribe;
1649
+ /** Подписывается на одно срабатывание. */
1650
+ once<K extends keyof Events>(event: K, listener: Listener<Events[K]>): Unsubscribe;
1651
+ /** Отписывается от события. */
1652
+ off<K extends keyof Events>(event: K, listener: Listener<Events[K]>): void;
1653
+ /** Рассылает событие подписчикам. */
1654
+ emit<K extends keyof Events>(event: K, payload: Events[K]): void;
1655
+ /** Сколько подписчиков у события. */
1656
+ listenerCount(event: keyof Events): number;
1657
+ /** Снимает все подписки. */
1658
+ removeAllListeners(): void;
1659
+ }
1660
+ //#endregion
1618
1661
  //#region src/core/errors.d.ts
1619
1662
  /** Бренд, по которому ошибки библиотеки распознаются надёжнее, чем через `instanceof`. */
1620
1663
  declare const ITD_ERROR: unique symbol;
@@ -1786,7 +1829,12 @@ declare class ItdApiError extends ItdError {
1786
1829
  * ```
1787
1830
  */
1788
1831
  hasCode(...codes: ItdErrorCode[]): boolean;
1789
- /** Имеет ли смысл повторить запрос: `429` и серверные ошибки `5xx`. */
1832
+ /**
1833
+ * Временная ошибка сервера, которую политика повторов считает повторяемой: `429` или `5xx`.
1834
+ *
1835
+ * Повторит ли библиотека саму операцию, зависит ещё от её `retrySafety`: `5xx` на
1836
+ * небезопасной операции не повторяется, `429` — повторяется всегда.
1837
+ */
1790
1838
  get isRetryable(): boolean;
1791
1839
  }
1792
1840
  /** `400` / `422` — данные не прошли валидацию. Подробности в {@link ItdApiError.fieldErrors}. */
@@ -1883,18 +1931,34 @@ declare class ItdNetworkError extends ItdError {
1883
1931
  cause?: unknown;
1884
1932
  });
1885
1933
  }
1886
- /** Истёк таймаут запроса, заданный опцией `timeout`. */
1934
+ /** Какой бюджет времени исчерпан. */
1935
+ declare const TimeoutBudget: Readonly<{
1936
+ /** Срок одной транспортной попытки — опция `timeout`. */
1937
+ readonly Attempt: "attempt";
1938
+ /** Общий срок логической операции — опция `deadline`. */
1939
+ readonly Deadline: "deadline";
1940
+ }>;
1941
+ type TimeoutBudget = (typeof TimeoutBudget)[keyof typeof TimeoutBudget];
1942
+ /**
1943
+ * Истёк срок, заданный опцией `timeout` (одна попытка) или `deadline` (операция целиком).
1944
+ *
1945
+ * Истёкший `timeout` для safe- и idempotent-операций повторяется; истёкший `deadline` —
1946
+ * нет.
1947
+ */
1887
1948
  declare class ItdTimeoutError extends ItdError {
1888
- /** Значение таймаута в миллисекундах. */
1949
+ /** Истёкший срок в миллисекундах. */
1889
1950
  readonly timeout: number;
1890
1951
  /** HTTP-метод запроса. */
1891
1952
  readonly method: string;
1892
1953
  /** Путь запроса без базового URL. */
1893
1954
  readonly path: string;
1955
+ /** Какой из двух сроков истёк. */
1956
+ readonly budget: TimeoutBudget;
1894
1957
  constructor(init: {
1895
1958
  timeout: number;
1896
1959
  method: string;
1897
1960
  path: string;
1961
+ budget?: TimeoutBudget | undefined;
1898
1962
  });
1899
1963
  }
1900
1964
  /** Запрос отменён через переданный `AbortSignal`. */
@@ -2298,5 +2362,5 @@ declare function isKnownNotificationType(type: string): boolean;
2298
2362
  */
2299
2363
  declare function resolveNotificationUrl(notification: Notification): string;
2300
2364
  //#endregion
2301
- export { isItdStateError as $, DEFAULT_RATE_LIMIT_BUCKET as $t, ItdErrorKind as A, RequestOptions as At, ItdStateError as B, RuntimeMode as Bt, ItdApiError as C, SpanType as Cn, PaginationOptions as Ct, ItdConfigError as D, RawRequestOptions as Dt, ItdAuthError as E, WallAccess as En, RateLimitOptions as Et, ItdNetworkError as F, RuntimeOptions as Ft, isItdConflictError as G, ItdOperationDefinition as Gt, ItdValidationError as H, systemClock as Ht, ItdNotFoundError as I, QueryParams as It, isItdForbiddenError as J, isBuiltInOperationId as Jt, isItdError as K, OPERATIONS as Kt, ItdPhoneVerificationError as L, QueryValue as Lt, ItdFileError as M, RetryContext as Mt, ItdFileErrorReason as N, RetryDecisionContext as Nt, ItdConflictError as O, RequestContext as Ot, ItdForbiddenError as P, RetryOptions as Pt, isItdServerError as Q, BUCKET_LIMITS as Qt, ItdRateLimitError as R, ServiceDefinition as Rt, ItdAbortError as S, ServiceState as Sn, OperationRequestOptions as St, ItdApiErrorKind as T, ViewSource as Tn, RateLimitBucketOverride as Tt, isItdApiError as U, BuiltInOperationId as Ut, ItdTimeoutError as V, ItdClock as Vt, isItdAuthError as W, CustomOperationId as Wt, isItdPhoneVerificationError as X, operationMethod as Xt, isItdNotFoundError as Y, operationBucket as Yt, isItdRateLimitError as Z, operationRetrySafety as Zt, PrivacySettings as _, Loose as _n, OperationMethod as _t, NotificationEvent as a, AccessType as an, bearerToken as at, SubscriptionState as b, ReportReason as bn, ErrorContextHook as bt, NotificationSettings as c, CaptchaField as cn, Listener as ct, AuthUser as d, EventChannelStatus as dn, STATUS_SERVICE as dt, RateLimitBucket as en, isItdValidationError as et, Author as f, FeedTab as fn, LIBRARY_VERSION as ft, PinsResult as g, LikesVisibility as gn, OperationMetadata as gt, Pin as h, ItdErrorCode as hn, OperationContract as ht, formatNotificationText as i, UserRef as in, anonymousAuth as it, ItdFieldErrors as j, ResponseContext as jt, ItdError as k, RequestExtensions as kt, Actor as l, CaptchaType as ln, Unsubscribe as lt, MyProfile as m, InteractionType as mn, OperationAnnotations as mt, canonicalNotificationType as n, Span as nn, AuthIdentity as nt, normalizeNotification as o, AttachmentType as on, tokenProvider as ot, FollowResult as p, IncidentKind as pn, FeatureOperationId as pt, isItdFileError as q, OperationId as qt, isKnownNotificationType as r, UserId as rn, AuthProvider as rt, Notification as s, CaptchaChoice as sn, Emitter as st, resolveNotificationUrl as t, IsoDate as tn, ClientConnection as tt, AuthState as u, CommentSort as un, DEFAULT_BASE_URL as ut, Profile as v, NotificationType as vn, RetrySafety as vt, ItdApiErrorInit as w, ViewReason as wn, RateLimitBucketContext as wt, UserSummary as x, ReportTargetType as xn, Logger as xt, PublicProfile as y, QrLocationPrecision as yn, ClientHooks as yt, ItdServerError as z, RateLimitPacing as zt };
2302
- //# sourceMappingURL=url-yB6T_H_-.d.ts.map
2365
+ export { isItdServerError as $, operationRetrySafety as $t, ItdErrorKind as A, RequestOptions as At, ItdStateError as B, RuntimeMode as Bt, ItdApiError as C, ReportTargetType as Cn, PaginationOptions as Ct, ItdConfigError as D, ViewSource as Dn, RawRequestOptions as Dt, ItdAuthError as E, ViewReason as En, RateLimitOptions as Et, ItdNetworkError as F, RuntimeOptions as Ft, isItdAuthError as G, BuiltInOperationId as Gt, ItdValidationError as H, Logger as Ht, ItdNotFoundError as I, QueryParams as It, isItdFileError as J, OPERATIONS as Jt, isItdConflictError as K, CustomOperationId as Kt, ItdPhoneVerificationError as L, QueryValue as Lt, ItdFileError as M, RetryContext as Mt, ItdFileErrorReason as N, RetryDecisionContext as Nt, ItdConflictError as O, WallAccess as On, RequestContext as Ot, ItdForbiddenError as P, RetryOptions as Pt, isItdRateLimitError as Q, operationMethod as Qt, ItdRateLimitError as R, ServiceDefinition as Rt, ItdAbortError as S, ReportReason as Sn, OperationRequestOptions as St, ItdApiErrorKind as T, SpanType as Tn, RateLimitBucketOverride as Tt, TimeoutBudget as U, ItdClock as Ut, ItdTimeoutError as V, LogLevel as Vt, isItdApiError as W, systemClock as Wt, isItdNotFoundError as X, isBuiltInOperationId as Xt, isItdForbiddenError as Y, OperationId as Yt, isItdPhoneVerificationError as Z, operationBucket as Zt, PrivacySettings as _, ItdErrorCode as _n, OperationMetadata as _t, NotificationEvent as a, UserId as an, ClientConnection as at, SubscriptionState as b, NotificationType as bn, ClientHooks as bt, NotificationSettings as c, AttachmentType as cn, anonymousAuth as ct, AuthUser as d, CaptchaType as dn, DEFAULT_BASE_URL as dt, BUCKET_LIMITS as en, isItdStateError as et, Author as f, CommentSort as fn, STATUS_SERVICE as ft, PinsResult as g, InteractionType as gn, OperationContract as gt, Pin as h, IncidentKind as hn, OperationAnnotations as ht, formatNotificationText as i, Span as in, Unsubscribe as it, ItdFieldErrors as j, ResponseContext as jt, ItdError as k, RequestExtensions as kt, Actor as l, CaptchaChoice as ln, bearerToken as lt, MyProfile as m, FeedTab as mn, FeatureOperationId as mt, canonicalNotificationType as n, RateLimitBucket as nn, Emitter as nt, normalizeNotification as o, UserRef as on, AuthIdentity as ot, FollowResult as p, EventChannelStatus as pn, LIBRARY_VERSION as pt, isItdError as q, ItdOperationDefinition as qt, isKnownNotificationType as r, IsoDate as rn, Listener as rt, Notification as s, AccessType as sn, AuthProvider as st, resolveNotificationUrl as t, DEFAULT_RATE_LIMIT_BUCKET as tn, isItdValidationError as tt, AuthState as u, CaptchaField as un, tokenProvider as ut, Profile as v, LikesVisibility as vn, OperationMethod as vt, ItdApiErrorInit as w, ServiceState as wn, RateLimitBucketContext as wt, UserSummary as x, QrLocationPrecision as xn, ErrorContextHook as xt, PublicProfile as y, Loose as yn, RetrySafety as yt, ItdServerError as z, RateLimitPacing as zt };
2366
+ //# sourceMappingURL=url-BOi-_mJT.d.cts.map