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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-Bg61sk_Y.js","names":["scoped","#entries","#removing","#cleanups","#options","#ordered","#orderWith","#trackCleanup","#release","#waitForDrain","#concurrency","#minGap","#clock","#buckets","#drain","#cancelWakeup","#active","#cursor","#nextSlot","#armWakeup","#cancelTimer","#wakeupAt","#size","#tail","#head","#destination","#bucket","#scheduler","#pacing","#smooth","#flatPause","#seedLimit","#definition","#waiting","#spend","#limit","#remaining","#hold","#capacity","#refill","#tokens","#armPause","#tokensAt","#options","#destinations","#services","#primaryHost","#handler","#baseUrl","#deadline","#clock","#lifetimeSignal","#hooks","#assertActive","#activeScopes","#run","#notifyError","ItdApiErrorClass","#config","#deps","#buildHeaders","#toTransportError","#prepareBody","#report","#context","#abortedOr","#fetch","#elapsed"],"sources":["../../src/core/async-dispose.ts","../../src/core/clock.ts","../../src/core/scheduling/pacing.ts","../../src/core/version.ts","../../src/core/config.ts","../../src/core/plugins/attempts.ts","../../src/core/plugins/order.ts","../../src/core/plugins/registry.ts","../../src/core/scheduling/rate-limit.ts","../../src/core/services.ts","../../src/core/plugins/hooks.ts","../../src/core/execution/lifecycle.ts","../../src/core/execution/pipeline.ts","../../src/core/execution/http.ts","../../src/core/operation.ts","../../src/core/scheduling/retry.ts","../../src/core/execution/middleware.ts","../../src/core/unwrap.ts","../../src/core/error-factory.ts","../../src/core/execution/transport.ts","../../src/core/execution/client-runtime.ts","../../src/domain/buckets.ts","../../src/domain/operations.ts","../../src/domain/catalog.ts","../../src/types/enums.ts","../../src/notifications/type-map.ts","../../src/notifications/normalize.ts","../../src/operations/common.ts","../../src/core/auth-provider.ts","../../src/notifications/text.ts","../../src/notifications/url.ts"],"sourcesContent":["declare global {\n interface SymbolConstructor {\n readonly asyncDispose: unique symbol;\n }\n}\n\n/**\n * Подставляет метод `await using` там, где `Symbol.asyncDispose` отсутствует.\n *\n * В Node 18 символа нет, поэтому объявление метода `[Symbol.asyncDispose]()` кладёт его\n * под ключ `\"undefined\"`. Здесь он переносится на ключ, который среда ищет фактически, —\n * `Symbol.for('Symbol.asyncDispose')`.\n *\n * Вызывается из статического блока класса: так поведение привязано к самому классу и не\n * зависит от того, дошёл ли bundler до модуля с побочным эффектом.\n */\nexport function installAsyncDisposeFallback(target: { readonly prototype: object }): void {\n if (typeof (Symbol as SymbolConstructor & { asyncDispose?: symbol }).asyncDispose === 'symbol') {\n return;\n }\n\n const prototype = target.prototype as unknown as Record<PropertyKey, unknown>;\n prototype[Symbol.for('Symbol.asyncDispose')] = prototype.undefined;\n delete prototype.undefined;\n}\n","/**\n * Часы, которыми клиент измеряет время и планирует отложенную работу.\n *\n * Своя реализация нужна прежде всего в тестах: она позволяет проверять тайм-ауты,\n * повторы и переподключение без ожидания в реальном времени.\n */\nexport interface ItdClock {\n /** Текущее время в миллисекундах с начала эпохи Unix. */\n now(): number;\n /** Планирует вызов после завершения текущего стека и возвращает функцию отмены. */\n schedule(callback: () => void, delay: number): () => void;\n}\n\n/** Системные часы, используемые клиентом по умолчанию. */\nexport const systemClock: ItdClock = Object.freeze({\n now: () => Date.now(),\n schedule(callback: () => void, delay: number): () => void {\n const timer = setTimeout(callback, delay);\n return () => clearTimeout(timer);\n },\n});\n\n/** Общий срок на несколько ожиданий. @internal */\nexport interface Deadline {\n /** Ждёт промис. `false` — срок истёк раньше, чем промис завершился. */\n wait(promise: Promise<unknown>): Promise<boolean>;\n /** Снимает таймер. Обязателен: иначе он удерживает event loop до конца срока. */\n cancel(): void;\n}\n\n/**\n * Заводит срок, общий на все ожидания: от ожидания к ожиданию он не продлевается.\n *\n * @param timeout срок в миллисекундах; `0` — ждать без ограничения\n * @internal\n */\nexport function createDeadline(timeout: number, clock: ItdClock = systemClock): Deadline {\n if (timeout <= 0) {\n return {\n wait: async (promise) => {\n await promise;\n return true;\n },\n cancel: () => {},\n };\n }\n\n let expire!: () => void;\n const expired = new Promise<void>((resolve) => {\n expire = resolve;\n });\n\n return {\n wait: (promise) => Promise.race([promise.then(() => true), expired.then(() => false)]),\n cancel: clock.schedule(() => expire(), timeout),\n };\n}\n","/** Реакция на остаток лимита из заголовков ответа. */\nexport const RateLimitPacing = Object.freeze({\n /** Задержек нет, пока в бакете есть остаток; исчерпанный бакет ждёт `60000 / limit`. */\n React: 'react',\n /** Ровный темп в пределах минутного лимита: задержки идут с первого запроса. */\n Smooth: 'smooth',\n /** Остаток на темп не влияет; остаётся пауза после `429`. */\n Off: 'off',\n} as const);\nexport type RateLimitPacing = (typeof RateLimitPacing)[keyof typeof RateLimitPacing];\n","// Этот файл создаётся автоматически: scripts/sync-version.mjs.\n// Менять вручную не нужно — значение берётся из package.json при `npm version` и сборке.\n\n/** Версия библиотеки. Попадает в `User-Agent`. */\nexport const LIBRARY_VERSION = '0.11.0';\n","import type { OperationCatalog } from './catalog.js';\nimport { type ItdClock, systemClock } from './clock.js';\nimport { ItdConfigError } from './errors.js';\nimport { type Logger, resolveLogger } from './logger.js';\nimport type {\n ClientHooks,\n RateLimitBucketContext,\n RateLimitBucketOverride,\n RetryOptions,\n RuntimeOptions,\n} from './options.js';\nimport { RuntimeMode, resolveFetch, shouldSendCredentials, shouldUseCookieJar } from './runtime.js';\nimport { RateLimitPacing } from './scheduling/pacing.js';\nimport type { ServiceDefinition } from './services.js';\nimport { normalizeBaseUrl } from './url.js';\nimport { isObjectLike, requireNonNegative, requireOptionalBoolean } from './validate.js';\nimport { LIBRARY_VERSION } from './version.js';\n\n/** Базовый URL API итд.com. Домен записан в punycode: `итд.com`. */\nexport const DEFAULT_BASE_URL = 'https://xn--d1ah4a.com';\n\n/** Базовый URL страницы статуса. Домен записан в punycode: `статус.итд.com`. */\nexport const DEFAULT_STATUS_BASE_URL = 'https://xn--80a7abcbg.xn--d1ah4a.com';\n\n/** Имя встроенного сервиса статуса. */\nexport const STATUS_SERVICE = 'status';\n\n/** Таймаут запроса по умолчанию — 30 секунд. */\nexport const DEFAULT_TIMEOUT = 30_000;\n\n/** Срок ожидания чужого кода при остановке по умолчанию — 10 секунд. */\nexport const DEFAULT_SHUTDOWN_TIMEOUT = 10_000;\n\n// Значение живёт в отдельном модуле, который порождается из package.json скриптом\n// scripts/sync-version.mjs: две записанные вручную версии рано или поздно разъезжаются.\nexport { LIBRARY_VERSION } from './version.js';\n\n/**\n * `User-Agent` по умолчанию.\n *\n * Сайт стоит за DDoS-Guard, и запросы вовсе без `User-Agent` (так делает `fetch` в Node)\n * имеют шанс не пройти фильтр. Префикс `Mozilla/5.0` — дань традиции таких фильтров,\n * дальше идёт честное имя библиотеки: подделываться под браузер она не должна.\n *\n * В браузере заголовок не выставляется — `User-Agent` там запрещён к изменению, и среда\n * молча его игнорирует.\n */\nexport const DEFAULT_USER_AGENT = `Mozilla/5.0 (compatible; itd-api/${LIBRARY_VERSION}; +https://github.com/KiowDev/itd-api)`;\n\n/**\n * Настройки повторов со всеми значениями по умолчанию.\n *\n * Поля перечислены явно, а не через `Required<RetryOptions>`: тот снимает необязательность,\n * но оставляет `| undefined` в типе значения, раз оно указано в исходном интерфейсе.\n */\nexport interface ResolvedRetryOptions {\n attempts: number;\n baseDelay: number;\n maxDelay: number;\n jitter: number;\n shouldRetry: RetryOptions['shouldRetry'];\n}\n\n/**\n * Паузы перед повторами при ответе `429`.\n *\n * Сервер итд.com не присылает `Retry-After` и не сообщает время сброса окна, поэтому паузу\n * приходится подбирать лестницей: от секунды, если окно почти истекло, до полутора минут.\n */\nexport const DEFAULT_RATE_LIMIT_DELAYS = Object.freeze([1000, 5000, 30_000, 60_000, 90_000]);\n\n/** Настройки очереди со всеми значениями по умолчанию. */\nexport interface ResolvedRateLimitOptions {\n concurrency: number;\n rps: number | undefined;\n retryDelays: readonly number[];\n buckets: boolean;\n pacing: RateLimitPacing;\n bucketConcurrency: number;\n /**\n * Поправки бакетов: встроенные плюс заданные пользователем. Начальные ограничения самих\n * бакетов очередь получает вместе с запросом из каталога операций.\n */\n bucketOverrides: Readonly<Record<string, RateLimitBucketOverride>>;\n bucket: ((request: RateLimitBucketContext) => string | undefined) | undefined;\n /** Счётчик, из которого списывается путь без собственного правила на сервере. */\n defaultBucket: string;\n}\n\n/**\n * Настройки исполнения запросов после подстановки умолчаний и проверок.\n *\n * Сессии здесь нет намеренно: ядро собирает конвейер, ничего не зная про токены,\n * хранилище и вход по паролю. Их разбирает `resolveSessionConfig` в слое авторизации.\n */\nexport interface ResolvedRuntimeConfig {\n baseUrl: string;\n /** Сервисы из опций клиента. Встроенные сюда не входят. */\n services: ServiceDefinition[];\n fetch: typeof fetch;\n clock: ItdClock;\n /** Таймаут одной транспортной попытки. `0` — без срока. */\n timeout: number;\n /** Общий срок логической операции. `0` — без срока. */\n deadline: number;\n /** Срок ожидания чужого кода при остановке. `0` — без срока. */\n shutdownTimeout: number;\n retry: ResolvedRetryOptions | undefined;\n rateLimit: ResolvedRateLimitOptions | undefined;\n hooks: ClientHooks;\n headers: Record<string, string>;\n /** Значение заголовка `User-Agent`. `undefined` — заголовок не выставляется. */\n userAgent: string | undefined;\n mode: RuntimeMode;\n /** Вести ли собственный cookie-jar. */\n useCookieJar: boolean;\n /** Отправлять ли `credentials: 'include'` (в браузере). */\n sendCredentials: boolean;\n logger: Logger | undefined;\n}\n\nfunction resolveHeaders(headers: Record<string, string> | undefined): Record<string, string> {\n if (headers === undefined) return {};\n if (!isObjectLike(headers)) throw new ItdConfigError('headers должен быть объектом строк');\n\n for (const [name, value] of Object.entries(headers)) {\n if (typeof value !== 'string') {\n throw new ItdConfigError(`headers.${name} должен быть строкой`);\n }\n }\n return { ...headers };\n}\n\nfunction resolveHooks(hooks: ClientHooks | undefined): ClientHooks {\n if (hooks === undefined) return {};\n if (!isObjectLike(hooks)) throw new ItdConfigError('hooks должен быть объектом');\n\n for (const name of ['onRequest', 'onResponse', 'onError', 'onRetry'] as const) {\n if (hooks[name] !== undefined && typeof hooks[name] !== 'function') {\n throw new ItdConfigError(`hooks.${name} должен быть функцией`);\n }\n }\n return { ...hooks };\n}\n\n/**\n * Приводит настройки повторов к полному виду.\n *\n * Вызывается и при создании клиента (для глобальной настройки), и на каждый запрос,\n * у которого задан свой `retry`. Возвращает `undefined`, когда повторять не нужно\n * (`retry: false` или единственная попытка).\n *\n * @throws {ItdConfigError} при некорректных значениях\n */\nexport function resolveRetry(retry: RuntimeOptions['retry']): ResolvedRetryOptions | undefined {\n if (retry === false) return undefined;\n if (retry !== undefined && !isObjectLike(retry)) {\n throw new ItdConfigError('retry должен быть объектом или false');\n }\n\n const options = retry ?? {};\n const attempts = options.attempts ?? 3;\n\n if (!Number.isInteger(attempts) || attempts < 1) {\n throw new ItdConfigError(`retry.attempts должен быть целым числом от 1, получено: ${attempts}`);\n }\n\n const jitter = options.jitter ?? 0.3;\n if (!Number.isFinite(jitter) || jitter < 0 || jitter > 1) {\n throw new ItdConfigError(`retry.jitter должен быть в диапазоне 0…1, получено: ${jitter}`);\n }\n if (options.shouldRetry !== undefined && typeof options.shouldRetry !== 'function') {\n throw new ItdConfigError('retry.shouldRetry должен быть функцией');\n }\n\n const baseDelay = requireNonNegative(options.baseDelay ?? 500, 'retry.baseDelay');\n const maxDelay = requireNonNegative(options.maxDelay ?? 30_000, 'retry.maxDelay');\n\n // Одна попытка означает отсутствие повторов — очередь ретраев можно не поднимать.\n if (attempts === 1) return undefined;\n\n return {\n attempts,\n baseDelay,\n maxDelay,\n jitter,\n shouldRetry: options.shouldRetry,\n };\n}\n\n/** Выбор бакета, заданный пользователем вместо встроенной карты. */\nexport type BucketResolver = ((request: RateLimitBucketContext) => string | undefined) | undefined;\n\n/**\n * Сверяет имя бакета со встроенной картой.\n *\n * Своё правило выбора заводит собственное пространство имён, и встроенные имена в нём\n * необязательны — тогда проверка снимается.\n *\n * @param option путь опции для текста ошибки\n * @throws {ItdConfigError} если имени нет во встроенной карте\n *\n * @internal\n */\nexport function assertKnownBucket(\n name: string,\n option: string,\n bucket: BucketResolver,\n catalog: OperationCatalog,\n): void {\n if (bucket !== undefined || catalog.isKnownBucket(name)) return;\n\n throw new ItdConfigError(\n `${option}: бакета «${name}» нет. Известны: ${Object.keys(catalog.bucketLimits).join(', ')}`,\n );\n}\n\nfunction requireConcurrency(value: number, name: string): number {\n if (!Number.isInteger(value) || value < 1) {\n throw new ItdConfigError(`${name} должен быть целым числом от 1, получено: ${value}`);\n }\n return value;\n}\n\nfunction requireRps(value: number, name: string): number {\n if (!Number.isFinite(value) || value <= 0) {\n throw new ItdConfigError(`${name} должен быть положительным числом, получено: ${value}`);\n }\n return value;\n}\n\nfunction resolvePacing(pacing: RateLimitPacing | undefined): RateLimitPacing {\n const known: readonly RateLimitPacing[] = Object.values(RateLimitPacing);\n if (pacing !== undefined && !known.includes(pacing)) {\n throw new ItdConfigError(\n `rateLimit.pacing должен быть одним из ${known.join(', ')}, получено: ${pacing}`,\n );\n }\n return pacing ?? RateLimitPacing.React;\n}\n\n/**\n * Проверяет поправки бакетов и накладывает их на встроенные.\n *\n * Имена сверяются со встроенной картой, пока не задано своё правило выбора бакета.\n * Поля сливаются по отдельности: своя ёмкость `files.upload` не снимает встроенный\n * предел одновременности.\n */\nfunction resolveBucketOverrides(\n overrides: Record<string, RateLimitBucketOverride> | undefined,\n bucket: BucketResolver,\n catalog: OperationCatalog,\n): Readonly<Record<string, RateLimitBucketOverride>> {\n const builtIn = catalog.bucketOverrides;\n if (overrides === undefined) return builtIn;\n if (!isObjectLike(overrides)) {\n throw new ItdConfigError('rateLimit.bucketOverrides должен быть объектом');\n }\n\n const resolved: Record<string, RateLimitBucketOverride> = { ...builtIn };\n for (const [name, override] of Object.entries(overrides)) {\n if (!isObjectLike(override)) {\n throw new ItdConfigError(`rateLimit.bucketOverrides.${name} должен быть объектом`);\n }\n assertKnownBucket(name, 'rateLimit.bucketOverrides', bucket, catalog);\n if (override.concurrency !== undefined) {\n requireConcurrency(override.concurrency, `rateLimit.bucketOverrides.${name}.concurrency`);\n }\n if (override.limit !== undefined && (!Number.isFinite(override.limit) || override.limit <= 0)) {\n throw new ItdConfigError(\n `rateLimit.bucketOverrides.${name}.limit должен быть положительным числом, ` +\n `получено: ${override.limit}`,\n );\n }\n if (override.rps !== undefined) {\n requireRps(override.rps, `rateLimit.bucketOverrides.${name}.rps`);\n }\n\n const built = builtIn[name];\n resolved[name] = Object.freeze({\n concurrency: override.concurrency ?? built?.concurrency,\n rps: override.rps ?? built?.rps,\n limit: override.limit ?? built?.limit,\n });\n }\n return Object.freeze(resolved);\n}\n\n/**\n * Приводит настройки очереди к полному виду. `undefined` — очередь не нужна.\n *\n * Кроме создания клиента вызывается ещё из {@link ItdAccounts}: общая на всех аккаунтов\n * очередь заводится из тех же опций и с теми же проверками.\n *\n * @throws {ItdConfigError} при некорректных значениях\n *\n * @internal\n */\nexport function resolveRateLimit(\n rateLimit: RuntimeOptions['rateLimit'],\n catalog: OperationCatalog,\n): ResolvedRateLimitOptions | undefined {\n if (rateLimit === false) return undefined;\n if (rateLimit !== undefined && !isObjectLike(rateLimit)) {\n throw new ItdConfigError('rateLimit должен быть объектом или false');\n }\n\n const defaults: ResolvedRateLimitOptions = {\n concurrency: 6,\n rps: undefined,\n retryDelays: DEFAULT_RATE_LIMIT_DELAYS,\n buckets: true,\n pacing: RateLimitPacing.React,\n bucketConcurrency: 6,\n bucketOverrides: catalog.bucketOverrides,\n bucket: undefined,\n defaultBucket: catalog.defaultBucket,\n };\n if (!rateLimit) return defaults;\n\n const concurrency = requireConcurrency(rateLimit.concurrency ?? 6, 'rateLimit.concurrency');\n\n if (rateLimit.rps !== undefined) requireRps(rateLimit.rps, 'rateLimit.rps');\n\n const retryDelays = rateLimit.retryDelays ?? defaults.retryDelays;\n if (!Array.isArray(retryDelays)) {\n throw new ItdConfigError('rateLimit.retryDelays должен быть массивом чисел');\n }\n for (const delay of retryDelays) requireNonNegative(delay, 'rateLimit.retryDelays');\n requireOptionalBoolean(rateLimit.buckets, 'rateLimit.buckets');\n\n if (rateLimit.bucket !== undefined && typeof rateLimit.bucket !== 'function') {\n throw new ItdConfigError('rateLimit.bucket должен быть функцией');\n }\n\n return {\n concurrency,\n rps: rateLimit.rps,\n retryDelays: [...retryDelays],\n buckets: rateLimit.buckets ?? true,\n pacing: resolvePacing(rateLimit.pacing),\n bucketConcurrency: requireConcurrency(\n rateLimit.bucketConcurrency ?? concurrency,\n 'rateLimit.bucketConcurrency',\n ),\n bucketOverrides: resolveBucketOverrides(rateLimit.bucketOverrides, rateLimit.bucket, catalog),\n bucket: rateLimit.bucket,\n defaultBucket: catalog.defaultBucket,\n };\n}\n\n/**\n * Разворачивает запись сервисов из опций в определения: имя берётся из ключа, строка\n * означает один только базовый URL. URL проверяется при регистрации сервиса.\n */\nfunction resolveServices(services: RuntimeOptions['services']): ServiceDefinition[] {\n if (services === undefined) return [];\n if (!isObjectLike(services)) throw new ItdConfigError('services должен быть объектом');\n\n return Object.entries(services).map(([name, value]) => {\n if (typeof value === 'string') return { name, baseUrl: value };\n if (!isObjectLike(value)) {\n throw new ItdConfigError(`services.${name} должен быть URL или объектом сервиса`);\n }\n return { ...value, name } as ServiceDefinition;\n });\n}\n\n/**\n * Приводит настройки исполнения запросов к полному виду.\n *\n * Все проверки выполняются здесь, до единого сетевого запроса: неверная настройка должна\n * проявляться при создании клиента, а не через полчаса работы бота. Сессионные опции\n * разбирает `resolveSessionConfig` — ядру они не нужны.\n *\n * @throws {ItdConfigError} при некорректных значениях\n */\nexport function resolveRuntimeConfig(\n options: RuntimeOptions,\n catalog: OperationCatalog,\n): ResolvedRuntimeConfig {\n if (!isObjectLike(options)) throw new ItdConfigError('опции клиента должны быть объектом');\n\n const mode: RuntimeMode = options.mode ?? RuntimeMode.Auto;\n\n if (!Object.values(RuntimeMode).includes(mode)) {\n throw new ItdConfigError(\n `mode должен быть одним из ${Object.values(RuntimeMode).join(', ')}, получено: ${mode}`,\n );\n }\n\n const timeout = requireNonNegative(options.timeout ?? DEFAULT_TIMEOUT, 'timeout');\n const deadline = requireNonNegative(options.deadline ?? 0, 'deadline');\n const shutdownTimeout = requireNonNegative(\n options.shutdownTimeout ?? DEFAULT_SHUTDOWN_TIMEOUT,\n 'shutdownTimeout',\n );\n\n if (\n options.clock !== undefined &&\n (typeof options.clock !== 'object' ||\n options.clock === null ||\n typeof options.clock.now !== 'function' ||\n typeof options.clock.schedule !== 'function')\n ) {\n throw new ItdConfigError('clock должен предоставлять методы now() и schedule()');\n }\n\n if (\n options.userAgent !== undefined &&\n options.userAgent !== false &&\n typeof options.userAgent !== 'string'\n ) {\n throw new ItdConfigError('userAgent должен быть строкой или false');\n }\n\n return {\n baseUrl: normalizeBaseUrl(options.baseUrl ?? DEFAULT_BASE_URL),\n services: resolveServices(options.services),\n fetch: resolveFetch(options.fetch),\n clock: options.clock ?? systemClock,\n timeout,\n deadline,\n shutdownTimeout,\n retry: resolveRetry(options.retry),\n rateLimit: resolveRateLimit(options.rateLimit, catalog),\n hooks: resolveHooks(options.hooks),\n headers: resolveHeaders(options.headers),\n // `false` — способ не слать заголовок вовсе; строка заменяет умолчание.\n userAgent: options.userAgent === false ? undefined : (options.userAgent ?? DEFAULT_USER_AGENT),\n mode,\n useCookieJar: shouldUseCookieJar(mode),\n sendCredentials: shouldSendCredentials(mode),\n logger: resolveLogger(options.logger),\n };\n}\n","import { ItdConfigError } from '../errors.js';\nimport type { OperationRequestOptions } from '../options.js';\nimport type { AttemptContext, AttemptInterceptor } from './contracts.js';\n\n/** Зарегистрированный interceptor вместе с именем владельца для диагностик. */\nexport interface RegisteredAttemptInterceptor {\n readonly plugin: string;\n readonly interceptor: AttemptInterceptor;\n}\n\nconst ATTEMPT_SCOPE: unique symbol = Symbol('itd-api.attempt-interceptors');\ntype ScopedRequest = OperationRequestOptions & {\n [ATTEMPT_SCOPE]?: readonly RegisteredAttemptInterceptor[];\n};\n\n/** Структурная проверка сохраняет совместимость с fetch-polyfill из другого realm. */\nfunction isResponse(value: unknown): value is Response {\n if (typeof value !== 'object' || value === null) return false;\n const candidate = value as Partial<Response>;\n return (\n typeof candidate.status === 'number' &&\n typeof candidate.clone === 'function' &&\n typeof candidate.headers?.get === 'function'\n );\n}\n\n/** Привязывает к логической операции неизменяемый снимок attempt interceptors. @internal */\nexport function withAttemptInterceptorScope<T extends OperationRequestOptions>(\n request: T,\n interceptors: readonly RegisteredAttemptInterceptor[],\n): T {\n const scoped = request as ScopedRequest;\n return scoped[ATTEMPT_SCOPE] === interceptors\n ? request\n : ({ ...request, [ATTEMPT_SCOPE]: interceptors } as T);\n}\n\n/** Читает снимок attempt interceptors логической операции. @internal */\nexport function attemptInterceptorScope(\n request: OperationRequestOptions,\n): readonly RegisteredAttemptInterceptor[] | undefined {\n return (request as ScopedRequest)[ATTEMPT_SCOPE];\n}\n\n/**\n * Выполняет обёртки одной попытки.\n *\n * Каждый `next` одноразовый: interceptor может short-circuit попытку синтетическим\n * `Response`, но не может незаметно породить два сетевых запроса внутри одного attempt.\n */\nexport async function runAttemptInterceptors(\n interceptors: readonly RegisteredAttemptInterceptor[],\n context: AttemptContext,\n execute: () => Promise<Response>,\n): Promise<Response> {\n const chain = interceptors.reduceRight<() => Promise<Response>>(\n (next, { plugin, interceptor }) =>\n async () => {\n let called = false;\n const response = await interceptor(context, () => {\n if (called) {\n throw new ItdConfigError(\n `attempt interceptor плагина «${plugin}» вызвал next() больше одного раза`,\n );\n }\n called = true;\n return next();\n });\n\n if (!isResponse(response)) {\n throw new ItdConfigError(\n `attempt interceptor плагина «${plugin}» должен вернуть Response`,\n );\n }\n return response;\n },\n execute,\n );\n\n return chain();\n}\n","import { ItdConfigError } from '../errors.js';\nimport type { ClientPlugin } from './contracts.js';\n\nconst RELATION_FIELDS = ['requires', 'conflicts', 'before', 'after'] as const;\nconst PLUGIN_NAME_PART = '[a-z][a-z0-9]*(?:[-_.][a-z0-9]+)*';\nconst PLUGIN_NAME_PATTERN = new RegExp(\n `^(?:${PLUGIN_NAME_PART}|@${PLUGIN_NAME_PART}(?:/${PLUGIN_NAME_PART})?(?::${PLUGIN_NAME_PART})?)$`,\n);\nconst PLUGIN_NAME_FORMAT =\n 'name, @package[:addon] или @scope/package[:addon] с разделителями -, _ и .';\n\nfunction isPluginName(value: string): boolean {\n return PLUGIN_NAME_PATTERN.test(value);\n}\n\nfunction validateNameList(plugin: ClientPlugin, field: (typeof RELATION_FIELDS)[number]): void {\n const values = plugin[field];\n if (values === undefined) return;\n if (!Array.isArray(values)) {\n throw new ItdConfigError(`плагин «${plugin.name}»: ${field} должен быть массивом`);\n }\n\n const seen = new Set<string>();\n for (const value of values as readonly unknown[]) {\n if (typeof value !== 'string' || value.trim() === '') {\n throw new ItdConfigError(`плагин «${plugin.name}»: ${field} содержит пустое имя плагина`);\n }\n if (!isPluginName(value)) {\n throw new ItdConfigError(\n `плагин «${plugin.name}»: имя «${value}» в ${field} должно соответствовать ${PLUGIN_NAME_FORMAT}`,\n );\n }\n if (value === plugin.name) {\n throw new ItdConfigError(`плагин «${plugin.name}» не может указать себя в ${field}`);\n }\n if (seen.has(value)) {\n throw new ItdConfigError(`плагин «${plugin.name}»: ${field} повторяет имя «${value}»`);\n }\n seen.add(value);\n }\n}\n\n/**\n * Проверяет описание плагина без его установки.\n *\n * Нужна не только {@link PluginRegistry}: контейнер аккаунтов обязан отклонять сломанный\n * плагин сразу, даже когда внутри ещё нет ни одного клиента, которому можно поручить\n * полноценную установку.\n *\n * @internal\n */\nexport function validatePluginDefinition(plugin: ClientPlugin): void {\n if (typeof plugin?.install !== 'function') {\n throw new ItdConfigError('Плагин должен быть объектом с методом install()');\n }\n\n const name = plugin.name;\n if (typeof name !== 'string' || name.trim() === '') {\n throw new ItdConfigError('У плагина должно быть непустое имя');\n }\n if (!isPluginName(name)) {\n throw new ItdConfigError(`Имя плагина «${name}» должно соответствовать ${PLUGIN_NAME_FORMAT}`);\n }\n\n for (const field of RELATION_FIELDS) validateNameList(plugin, field);\n}\n\ninterface OrderedPlugin {\n plugin: ClientPlugin;\n sequence: number;\n}\n\nfunction addEdge(\n from: string,\n to: string,\n edges: Map<string, Set<string>>,\n indegree: Map<string, number>,\n): void {\n const targets = edges.get(from);\n if (!targets || targets.has(to)) return;\n targets.add(to);\n indegree.set(to, (indegree.get(to) ?? 0) + 1);\n}\n\n/**\n * Проверяет зависимости и возвращает плагины в порядке обёрток: внешний идёт раньше.\n *\n * @internal\n */\nexport function orderPluginDefinitions(plugins: readonly ClientPlugin[]): ClientPlugin[] {\n const entries: OrderedPlugin[] = [];\n const byName = new Map<string, OrderedPlugin>();\n\n for (const [sequence, plugin] of plugins.entries()) {\n validatePluginDefinition(plugin);\n if (byName.has(plugin.name)) {\n throw new ItdConfigError(`плагин «${plugin.name}» уже подключён`);\n }\n const entry = { plugin, sequence };\n entries.push(entry);\n byName.set(plugin.name, entry);\n }\n\n for (const { plugin } of entries) {\n for (const required of plugin.requires ?? []) {\n if (!byName.has(required)) {\n throw new ItdConfigError(`плагину «${plugin.name}» требуется плагин «${required}»`);\n }\n }\n for (const conflict of plugin.conflicts ?? []) {\n if (byName.has(conflict)) {\n throw new ItdConfigError(`плагин «${plugin.name}» несовместим с плагином «${conflict}»`);\n }\n }\n for (const { plugin: other } of entries) {\n if (other.conflicts?.includes(plugin.name)) {\n throw new ItdConfigError(`плагин «${plugin.name}» несовместим с плагином «${other.name}»`);\n }\n }\n }\n\n const edges = new Map<string, Set<string>>();\n const indegree = new Map<string, number>();\n for (const { plugin } of entries) {\n edges.set(plugin.name, new Set());\n indegree.set(plugin.name, 0);\n }\n for (const { plugin } of entries) {\n for (const required of plugin.requires ?? []) addEdge(required, plugin.name, edges, indegree);\n for (const target of plugin.before ?? []) {\n if (byName.has(target)) addEdge(plugin.name, target, edges, indegree);\n }\n for (const target of plugin.after ?? []) {\n if (byName.has(target)) addEdge(target, plugin.name, edges, indegree);\n }\n }\n\n const ready = entries.filter(({ plugin }) => indegree.get(plugin.name) === 0);\n ready.sort((a, b) => a.sequence - b.sequence);\n const ordered: ClientPlugin[] = [];\n while (ready.length > 0) {\n const current = ready.shift();\n if (!current) break;\n ordered.push(current.plugin);\n for (const target of edges.get(current.plugin.name) ?? []) {\n const next = (indegree.get(target) ?? 0) - 1;\n indegree.set(target, next);\n if (next === 0) {\n const entry = byName.get(target);\n if (entry) {\n ready.push(entry);\n ready.sort((a, b) => a.sequence - b.sequence);\n }\n }\n }\n }\n\n if (ordered.length !== entries.length) {\n const cycle = entries\n .filter(({ plugin }) => (indegree.get(plugin.name) ?? 0) > 0)\n .map(({ plugin }) => plugin.name);\n throw new ItdConfigError(`циклический порядок плагинов: ${cycle.join(' → ')}`);\n }\n return ordered;\n}\n\n/** Проверяет, можно ли удалить плагин без нарушения обязательных зависимостей. @internal */\nexport function assertPluginRemovable(plugins: readonly ClientPlugin[], name: string): void {\n const dependent = plugins.find((plugin) => plugin.requires?.includes(name));\n if (dependent) {\n throw new ItdConfigError(\n `нельзя отключить плагин «${name}»: от него зависит «${dependent.name}»`,\n );\n }\n}\n","import { createDeadline, type Deadline, type ItdClock } from '../clock.js';\nimport { ItdConfigError, ItdStateError } from '../errors.js';\nimport type { OperationMetadata } from '../operation.js';\nimport type { OperationRequestOptions } from '../options.js';\nimport { type RegisteredAttemptInterceptor, withAttemptInterceptorScope } from './attempts.js';\nimport type {\n AttemptInterceptor,\n ClientPlugin,\n OperationTransformContext,\n OperationTransformer,\n PluginApi,\n PluginTeardown,\n} from './contracts.js';\nimport {\n assertPluginRemovable,\n orderPluginDefinitions,\n validatePluginDefinition,\n} from './order.js';\n\ninterface InstalledPlugin {\n plugin: ClientPlugin;\n transformers: OperationTransformer[];\n interceptors: AttemptInterceptor[];\n teardown: PluginTeardown | undefined;\n activeRequests: number;\n drain: Promise<void> | undefined;\n finishDrain: (() => void) | undefined;\n}\n\n/** Что реестру нужно знать об остановке. @internal */\nexport interface PluginRegistryOptions {\n /** Срок ожидания операций плагина при его отключении, мс. `0` — ждать без ограничения. */\n shutdownTimeout: number;\n clock: ItdClock;\n /** Возвращает публичные метаданные встроенной или feature-операции. */\n operationMetadata: (\n operationId: OperationRequestOptions['operationId'],\n ) => OperationMetadata | undefined;\n}\n\n/**\n * Список подключённых плагинов и зарегистрированных ими расширений.\n *\n * {@link run} собирает operation transformers вокруг одной логической операции и прикрепляет\n * к ней неизменяемый снимок attempt interceptors. Transport исполняет этот снимок отдельно\n * для каждой сетевой попытки. Порядок плагинов одинаков для обеих цепочек.\n *\n * @internal\n */\nexport class PluginRegistry {\n readonly #entries = new Map<string, InstalledPlugin>();\n readonly #removing = new Set<string>();\n readonly #cleanups = new Set<Promise<void>>();\n readonly #options: PluginRegistryOptions;\n #ordered: InstalledPlugin[] = [];\n\n constructor(options: PluginRegistryOptions) {\n this.#options = options;\n }\n\n /** Сколько плагинов подключено. */\n get size(): number {\n return this.#entries.size;\n }\n\n /** Имена плагинов в фактическом порядке выполнения. */\n names(): string[] {\n return this.#ordered.map(({ plugin }) => plugin.name);\n }\n\n /** Подключён ли плагин с таким именем. */\n has(name: string): boolean {\n return this.#entries.has(name);\n }\n\n /** Проверяет добавление без вызова `install()`. @internal */\n assertCanAdd(plugin: ClientPlugin): void {\n this.#orderWith(plugin);\n }\n\n /** Проверяет плагин и возвращает порядок обёрток вместе с ним. */\n #orderWith(plugin: ClientPlugin): ClientPlugin[] {\n validatePluginDefinition(plugin);\n if (this.#removing.has(plugin.name)) {\n throw new ItdConfigError(\n `плагин «${plugin.name}» ещё отключается; дождитесь завершения unuse() или dispose()`,\n );\n }\n return orderPluginDefinitions([...this.#ordered.map((entry) => entry.plugin), plugin]);\n }\n\n /** Проверяет удаление без изменения реестра. @internal */\n assertCanRemove(name: string): void {\n const entry = this.#entries.get(name);\n if (!entry) return;\n assertPluginRemovable(\n this.#ordered.map((current) => current.plugin),\n name,\n );\n }\n\n /**\n * Подключает плагин.\n *\n * `install()` выполняется синхронно. Каждая регистрация принадлежит установившему её\n * плагину и участвует в общем порядке `before`/`after`.\n *\n * @throws {ItdConfigError} если плагин задан неверно, уже подключён или нарушает зависимости\n */\n add(plugin: ClientPlugin, context: Omit<PluginApi, 'operations' | 'attempts'>): void {\n const ordered = this.#orderWith(plugin);\n const transformers: OperationTransformer[] = [];\n const interceptors: AttemptInterceptor[] = [];\n const register = <T>(values: T[], value: T, kind: string): (() => void) => {\n if (typeof value !== 'function') {\n throw new ItdConfigError(`плагин «${plugin.name}» передал в ${kind}.use() не функцию`);\n }\n values.push(value);\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n const index = values.indexOf(value);\n if (index >= 0) values.splice(index, 1);\n };\n };\n const installed = plugin.install({\n ...context,\n operations: {\n get: this.#options.operationMetadata,\n use: (transformer) => register(transformers, transformer, 'operations'),\n },\n attempts: {\n use: (interceptor) => register(interceptors, interceptor, 'attempts'),\n },\n });\n if (installed !== undefined && typeof installed !== 'function') {\n throw new ItdConfigError(\n `install() плагина «${plugin.name}» должен вернуть функцию или void`,\n );\n }\n const teardown = installed as PluginTeardown | undefined;\n\n this.#entries.set(plugin.name, {\n plugin,\n transformers,\n interceptors,\n teardown,\n activeRequests: 0,\n drain: undefined,\n finishDrain: undefined,\n });\n this.#ordered = ordered.map((definition) => {\n const entry = this.#entries.get(definition.name);\n if (!entry) throw new ItdConfigError(`плагин «${definition.name}» не установлен`);\n return entry;\n });\n }\n\n /**\n * Отключает плагин и вызывает его функцию очистки.\n *\n * Новые запросы перестают видеть расширения плагина сразу. Снимок уже начавшейся операции,\n * включая её будущие retry, остаётся неизменным; очистка дождётся завершения операции,\n * но не дольше отведённого срока.\n *\n * @returns `false`, если такого плагина не было\n * @throws {ItdStateError} если операции плагина не завершились за отведённый срок\n */\n async remove(name: string): Promise<boolean> {\n const entry = this.#entries.get(name);\n if (!entry) return false;\n this.assertCanRemove(name);\n this.#entries.delete(name);\n this.#ordered = this.#ordered.filter((current) => current !== entry);\n this.#removing.add(name);\n\n const deadline = createDeadline(this.#options.shutdownTimeout, this.#options.clock);\n const cleanup = this.#trackCleanup(\n (async () => {\n const expirationErrors = await this.#release(entry, deadline);\n if (expirationErrors.length === 1) throw expirationErrors[0];\n if (expirationErrors.length > 1) {\n throw new AggregateError(expirationErrors, `Не удалось отключить плагин «${name}»`);\n }\n })(),\n );\n try {\n await cleanup;\n return true;\n } finally {\n deadline.cancel();\n this.#removing.delete(name);\n }\n }\n\n /**\n * Отключает все плагины окончательно.\n *\n * Очистка идёт изнутри наружу — в порядке, обратном выполнению расширений. Срок ожидания\n * общий на все плагины.\n */\n async dispose(): Promise<void> {\n const entries = [...this.#ordered].reverse();\n const previousCleanups = [...this.#cleanups];\n this.#entries.clear();\n this.#ordered = [];\n for (const { plugin } of entries) this.#removing.add(plugin.name);\n\n const deadline = createDeadline(this.#options.shutdownTimeout, this.#options.clock);\n const cleanup = this.#trackCleanup(\n (async () => {\n const errors: unknown[] = [];\n const previous = await Promise.allSettled(previousCleanups);\n for (const result of previous) {\n if (result.status === 'rejected') errors.push(result.reason);\n }\n for (const entry of entries) {\n try {\n errors.push(...(await this.#release(entry, deadline)));\n } catch (error) {\n errors.push(error);\n } finally {\n this.#removing.delete(entry.plugin.name);\n }\n }\n if (errors.length > 0) {\n throw new AggregateError(errors, 'Не удалось освободить ресурсы плагинов');\n }\n })(),\n );\n try {\n await cleanup;\n } finally {\n deadline.cancel();\n }\n }\n\n /**\n * Прогоняет запрос через operation transformers и прикрепляет attempt interceptors.\n *\n * Снимки обеих цепочек берутся в начале: `unuse()` влияет на новые операции, но не меняет\n * уже выполняющуюся и не удаляет interceptors из её последующих retry.\n *\n * Каждый `next` одноразовый: transformer может завершить операцию сам, но не может породить\n * вторую — для `posts.create` это была бы вторая публикация.\n *\n * @param execute выполнение логической операции, вызываемое самым внутренним transformer\n */\n async run(\n request: OperationRequestOptions,\n execute: (request: OperationRequestOptions) => Promise<unknown>,\n signal: AbortSignal,\n ): Promise<unknown> {\n const ordered = this.#ordered;\n if (ordered.length === 0) return execute(request);\n const entries = [...ordered];\n for (const entry of entries) entry.activeRequests += 1;\n const interceptorScope: RegisteredAttemptInterceptor[] = entries.flatMap((entry) =>\n entry.interceptors.map((interceptor) => ({ plugin: entry.plugin.name, interceptor })),\n );\n const operationId = request.operationId;\n const method = request.method.toUpperCase();\n const retrySafety = request.retrySafety;\n const context: OperationTransformContext = Object.freeze({ signal });\n const scoped = (current: OperationRequestOptions): OperationRequestOptions => {\n const prepared = current.retrySafety === undefined ? { ...current, retrySafety } : current;\n return interceptorScope.length === 0\n ? prepared\n : withAttemptInterceptorScope(prepared, interceptorScope);\n };\n const validateContract = (prepared: OperationRequestOptions): void => {\n if (prepared.operationId !== operationId) {\n throw new ItdConfigError(\n `operation transformer не может заменить operationId «${operationId}» на «${prepared.operationId}»`,\n );\n }\n if (prepared.method.toUpperCase() !== method) {\n throw new ItdConfigError(\n `operation transformer не может заменить метод «${method}» операции «${operationId}» на «${prepared.method}»`,\n );\n }\n if (prepared.retrySafety !== undefined && prepared.retrySafety !== retrySafety) {\n throw new ItdConfigError(\n `operation transformer не может заменить retrySafety операции «${operationId}»`,\n );\n }\n };\n const chain = entries\n .flatMap((entry) =>\n entry.transformers.map((transformer) => ({ plugin: entry.plugin.name, transformer })),\n )\n .reduceRight<(request: OperationRequestOptions) => Promise<unknown>>(\n (next, { plugin, transformer }) =>\n (current) => {\n let called = false;\n return transformer(\n scoped(current),\n (prepared) => {\n if (called) {\n throw new ItdConfigError(\n `operation transformer плагина «${plugin}» вызвал next() больше одного раза`,\n );\n }\n called = true;\n validateContract(prepared);\n return next(scoped(prepared));\n },\n context,\n );\n },\n (current) => {\n validateContract(current);\n return execute(scoped(current));\n },\n );\n\n try {\n return await chain(scoped(request));\n } finally {\n for (const entry of entries) {\n entry.activeRequests -= 1;\n if (entry.activeRequests === 0) {\n entry.finishDrain?.();\n entry.finishDrain = undefined;\n entry.drain = undefined;\n }\n }\n }\n }\n\n /**\n * Дожидается операций плагина и освобождает его ресурсы.\n *\n * Функция очистки запускается после ожидания активных операций. Обе стадии ограничены\n * общим сроком.\n *\n * @returns ошибки истёкшего срока для незавершённых стадий\n */\n async #release(entry: InstalledPlugin, deadline: Deadline): Promise<ItdStateError[]> {\n const errors: ItdStateError[] = [];\n const operationsFinished = await deadline.wait(this.#waitForDrain(entry));\n if (!operationsFinished) {\n errors.push(\n new ItdStateError(\n `плагин «${entry.plugin.name}» не завершил операции за ${this.#options.shutdownTimeout} мс`,\n ),\n );\n }\n\n let teardownFailed = false;\n let teardownFailure: unknown;\n const teardown = Promise.resolve()\n .then(() => entry.teardown?.())\n .catch((error: unknown) => {\n teardownFailed = true;\n teardownFailure = error;\n });\n const teardownFinished = await deadline.wait(teardown);\n if (!teardownFinished) {\n errors.push(\n new ItdStateError(\n `плагин «${entry.plugin.name}» не завершил teardown за ${this.#options.shutdownTimeout} мс`,\n ),\n );\n } else if (teardownFailed) {\n throw teardownFailure;\n }\n\n return errors;\n }\n\n #waitForDrain(entry: InstalledPlugin): Promise<void> {\n if (entry.activeRequests === 0) return Promise.resolve();\n entry.drain ??= new Promise<void>((resolve) => {\n entry.finishDrain = resolve;\n });\n return entry.drain;\n }\n\n #trackCleanup(cleanup: Promise<void>): Promise<void> {\n this.#cleanups.add(cleanup);\n void cleanup.then(\n () => this.#cleanups.delete(cleanup),\n () => this.#cleanups.delete(cleanup),\n );\n return cleanup;\n }\n}\n","import { type ItdClock, systemClock } from '../clock.js';\nimport type { ResolvedRateLimitOptions } from '../config.js';\nimport { ItdAbortError, ItdConfigError } from '../errors.js';\nimport type { RateLimitBucketOverride } from '../options.js';\nimport { RateLimitPacing } from './pacing.js';\n\n/** Ошибка отмены запроса, который ещё не дошёл до транспорта. */\nfunction queueAbortError(): ItdAbortError {\n return new ItdAbortError('Запрос отменён во время ожидания очереди');\n}\n\n/** Ошибка запроса, которого застала остановка очереди. */\nfunction queueStoppedError(): ItdAbortError {\n return new ItdAbortError('Клиент закрыт, запрос отменён');\n}\n\n/** Длина окна лимита на сервере. */\nconst RATE_LIMIT_WINDOW = 60_000;\n\n/**\n * Пауза при исчерпании бакета неизвестной ёмкости.\n *\n * Ёмкость приходит в заголовке вместе с остатком, поэтому случай возможен только у чужого\n * прокси, который прислал `remaining` без `limit`.\n */\nconst UNKNOWN_CAPACITY_PAUSE = 1000;\n\n/** Снимок одного бакета. */\nexport interface RateLimitBucketState {\n /** Origin, на котором ведётся счётчик. `undefined` — очередь без известного направления. */\n destination: string | undefined;\n bucket: string;\n /** Ёмкость из последнего ответа; `undefined`, пока ответов не было. */\n limit: number | undefined;\n /** Остаток из последнего ответа. */\n remaining: number | undefined;\n /** Запросов бакета прошло в общую очередь и ещё не завершилось. */\n active: number;\n /** Запросов бакета ждёт своей очереди — из-за паузы или предела одновременности. */\n pending: number;\n}\n\n/**\n * Единый планировщик одного направления.\n *\n * Он выбирает готовый бакет и только перед фактическим запуском атомарно занимает общий\n * и локальный слоты. Одно ближайшее пробуждение обслуживает все бакеты направления.\n */\nclass DestinationScheduler {\n readonly #concurrency: number;\n readonly #minGap: number;\n readonly #clock: ItdClock;\n readonly #buckets: BucketQueue[] = [];\n #active = 0;\n #nextSlot = 0;\n #cursor = 0;\n #cancelTimer: (() => void) | undefined;\n #wakeupAt: number | undefined;\n\n constructor(options: ResolvedRateLimitOptions, clock: ItdClock) {\n this.#concurrency = options.concurrency;\n this.#minGap = options.rps ? 1000 / options.rps : 0;\n this.#clock = clock;\n }\n\n register(bucket: BucketQueue): void {\n this.#buckets.push(bucket);\n }\n\n /** Пересчитывает запуск; существующий таймер заменяется только более ранним. */\n changed(): void {\n this.#drain();\n }\n\n /** Отклоняет ожидающие задачи, сохраняя паузы и темп для повторного запуска клиента. */\n stop(): void {\n this.#cancelWakeup();\n for (const bucket of this.#buckets) bucket.cancelWaiting(queueStoppedError(), false);\n }\n\n #drain(): void {\n if (this.#active >= this.#concurrency) return;\n\n const now = this.#clock.now();\n let selected: BucketQueue | undefined;\n let selectedIndex = -1;\n let earliest = Number.POSITIVE_INFINITY;\n\n for (let offset = 0; offset < this.#buckets.length; offset += 1) {\n const index = (this.#cursor + offset) % this.#buckets.length;\n const bucket = this.#buckets[index];\n if (!bucket?.canStart) continue;\n\n const readyAt = Math.max(this.#nextSlot, bucket.readyAt);\n if (readyAt < earliest) earliest = readyAt;\n if (readyAt <= now) {\n selected = bucket;\n selectedIndex = index;\n break;\n }\n }\n\n if (!selected) {\n if (Number.isFinite(earliest)) this.#armWakeup(Math.max(0, earliest - now));\n else this.#cancelWakeup();\n return;\n }\n\n this.#cursor = (selectedIndex + 1) % this.#buckets.length;\n this.#active += 1;\n if (this.#minGap > 0) this.#nextSlot = now + this.#minGap;\n selected.dispatch(now, () => {\n this.#active -= 1;\n this.changed();\n });\n\n this.#drain();\n }\n\n #armWakeup(delay: number): void {\n const wakeupAt = this.#clock.now() + delay;\n if (this.#cancelTimer && (this.#wakeupAt ?? Number.POSITIVE_INFINITY) <= wakeupAt) return;\n this.#cancelWakeup();\n this.#wakeupAt = wakeupAt;\n this.#cancelTimer = this.#clock.schedule(() => {\n this.#cancelTimer = undefined;\n this.#wakeupAt = undefined;\n this.#drain();\n }, delay);\n }\n\n #cancelWakeup(): void {\n this.#cancelTimer?.();\n this.#cancelTimer = undefined;\n this.#wakeupAt = undefined;\n }\n}\n\n/** Задача, ожидающая окончательного запуска планировщиком направления. */\ninterface BucketTask {\n start: (complete: () => void) => void;\n cancel: (reason: unknown) => void;\n}\n\n/** Узел очереди ожидания. */\ninterface WaitingNode {\n readonly task: BucketTask;\n prev: WaitingNode | undefined;\n next: WaitingNode | undefined;\n /** Стоит ли узел в очереди; снятый узел повторно не снимается. */\n linked: boolean;\n}\n\n/**\n * Очередь ожидающих задач в порядке постановки.\n *\n * Постановка в хвост, снятие головы, снятие произвольного узла при отмене и полная\n * очистка — за O(1) при любой длине: очередь рассчитана на десятки тысяч задач, разом\n * упёршихся в паузу `429`.\n */\nclass WaitingList {\n #head: WaitingNode | undefined;\n #tail: WaitingNode | undefined;\n #size = 0;\n\n get size(): number {\n return this.#size;\n }\n\n push(task: BucketTask): WaitingNode {\n const node: WaitingNode = { task, prev: this.#tail, next: undefined, linked: true };\n if (this.#tail) this.#tail.next = node;\n else this.#head = node;\n this.#tail = node;\n this.#size += 1;\n return node;\n }\n\n shift(): BucketTask | undefined {\n const node = this.#head;\n if (!node) return undefined;\n this.remove(node);\n return node.task;\n }\n\n /** Снимает узел; `false`, если он уже снят. */\n remove(node: WaitingNode): boolean {\n if (!node.linked) return false;\n node.linked = false;\n if (node.prev) node.prev.next = node.next;\n else this.#head = node.next;\n if (node.next) node.next.prev = node.prev;\n else this.#tail = node.prev;\n node.prev = undefined;\n node.next = undefined;\n this.#size -= 1;\n return true;\n }\n\n /** Снимает все узлы; задачи возвращаются в порядке постановки. */\n drain(): BucketTask[] {\n const tasks: BucketTask[] = [];\n let node = this.#head;\n while (node) {\n const following = node.next;\n node.linked = false;\n node.prev = undefined;\n node.next = undefined;\n tasks.push(node.task);\n node = following;\n }\n this.#head = undefined;\n this.#tail = undefined;\n this.#size = 0;\n return tasks;\n }\n}\n\n/**\n * Состояние и очередь одного серверного бакета.\n *\n * Класс хранит локальную конкурентность, темп и серверную квоту, а решение о старте\n * делегирует общему планировщику направления.\n *\n * @internal\n */\nexport class BucketQueue {\n readonly #destination: string | undefined;\n readonly #bucket: string;\n readonly #scheduler: DestinationScheduler;\n readonly #clock: ItdClock;\n readonly #pacing: RateLimitPacing;\n readonly #concurrency: number;\n readonly #minGap: number;\n /** Ровный темп. Требует раздельных бакетов: без них ёмкость счётчика неизвестна. */\n readonly #smooth: boolean;\n /**\n * Пауза на исчерпанный остаток в режиме `buckets: false`; `undefined` — бакеты разделены.\n *\n * Одна очередь на направление принимает заголовки всех счётчиков вперемешку, поэтому\n * `x-ratelimit-limit` принадлежит тому счётчику, который ответил последним, и ёмкость\n * очереди из него не выводится: ответ `posts.create` с ёмкостью 5 остановил бы всё\n * направление на двенадцать секунд. Вместо расчёта берётся первая ступень `retryDelays`.\n */\n readonly #flatPause: number | undefined;\n /** Лимит бакета до первого ответа. */\n readonly #seedLimit: number | undefined;\n /** Начальные ограничения из каталога, с которыми создана очередь. */\n readonly #definition: Readonly<RateLimitBucketOverride> | undefined;\n\n /** Последнее, что сказал сервер. Живёт и в режиме `off` — ради `rateLimitState()`. */\n #limit: number | undefined;\n #remaining: number | undefined;\n #active = 0;\n #nextSlot = 0;\n readonly #waiting = new WaitingList();\n\n /**\n * Оценка остатка для режима `smooth`.\n *\n * Начинается с единицы, а не с полной ёмкости: где сейчас граница минутного окна,\n * из ответа не вывести, и считать бакет нетронутым нельзя.\n */\n #tokens = 1;\n #tokensAt: number | undefined;\n constructor(\n destination: string | undefined,\n bucket: string,\n scheduler: DestinationScheduler,\n options: ResolvedRateLimitOptions,\n clock: ItdClock,\n definition: Readonly<RateLimitBucketOverride> | undefined,\n ) {\n this.#destination = destination;\n this.#bucket = bucket;\n this.#scheduler = scheduler;\n this.#clock = clock;\n this.#definition = definition;\n this.#pacing = options.pacing;\n this.#smooth = options.buckets && options.pacing === RateLimitPacing.Smooth;\n this.#flatPause = options.buckets ? undefined : (options.retryDelays[0] ?? 0);\n // Поправка из настроек клиента важнее начального ограничения из каталога.\n const override = options.buckets ? options.bucketOverrides[bucket] : undefined;\n this.#seedLimit = options.buckets ? (override?.limit ?? definition?.limit) : undefined;\n this.#concurrency = options.buckets\n ? (override?.concurrency ?? definition?.concurrency ?? options.bucketConcurrency)\n : options.concurrency;\n const rps = options.buckets ? (override?.rps ?? definition?.rps) : undefined;\n this.#minGap = rps ? 1000 / rps : 0;\n scheduler.register(this);\n }\n\n /** Имя счётчика. При `buckets: false` — всегда `default`, каким бы ни был запрос. */\n get bucket(): string {\n return this.#bucket;\n }\n\n /** Начальные ограничения из каталога, с которыми создана очередь. */\n get definition(): Readonly<RateLimitBucketOverride> | undefined {\n return this.#definition;\n }\n\n /** Запросов бакета прошло в общую очередь и ещё не завершилось. */\n get active(): number {\n return this.#active;\n }\n\n /** Запросов бакета ждёт своей очереди. */\n get pending(): number {\n return this.#waiting.size;\n }\n\n /** Есть ли ожидающая задача, для которой свободен локальный слот. */\n get canStart(): boolean {\n return this.#waiting.size > 0 && this.#active < this.#concurrency;\n }\n\n /** Момент, раньше которого локальное ограничение не разрешает следующий старт. */\n get readyAt(): number {\n return this.#nextSlot;\n }\n\n /** Ставит запрос в очередь единого планировщика направления. */\n schedule<T>(task: () => Promise<T>, signal?: AbortSignal): Promise<T> {\n if (signal?.aborted) return Promise.reject(queueAbortError());\n\n return new Promise<T>((resolve, reject) => {\n let queued: WaitingNode;\n const detach = () => signal?.removeEventListener('abort', onAbort);\n const onAbort = () => {\n if (!this.#waiting.remove(queued)) return;\n queued.task.cancel(queueAbortError());\n this.#scheduler.changed();\n };\n\n queued = this.#waiting.push({\n start: (complete) => {\n detach();\n Promise.resolve().then(task).then(resolve, reject).finally(complete);\n },\n cancel: (reason) => {\n detach();\n reject(reason);\n },\n });\n\n signal?.addEventListener('abort', onAbort, { once: true });\n if (signal?.aborted) onAbort();\n else this.#scheduler.changed();\n });\n }\n\n /** Запускает первую задачу; вызывается только планировщиком направления. */\n dispatch(now: number, complete: () => void): void {\n const task = this.#waiting.shift();\n if (!task) {\n complete();\n return;\n }\n\n this.#active += 1;\n if (this.#smooth) this.#spend();\n if (this.#minGap > 0) this.#nextSlot = Math.max(this.#nextSlot, now + this.#minGap);\n task.start(() => {\n this.#active -= 1;\n complete();\n });\n }\n\n /**\n * Учитывает заголовки ответа.\n *\n * Вызывается после каждого ответа, включая ошибочные: сервер списывает квоту одинаково\n * с `404`, `422` и `200`.\n *\n * @returns на сколько миллисекунд придержан бакет; `0` — темп не ограничен\n */\n observe(limit: number | undefined, remaining: number | undefined): number {\n // Основной транспорт уже отбрасывает некорректный заголовок, но очередь остаётся\n // самостоятельным внутренним примитивом: не позволяем прямому вызову записать\n // нулевую ёмкость и получить бесконечный таймер в режиме smooth.\n if (limit !== undefined && Number.isFinite(limit) && limit > 0) this.#limit = limit;\n if (remaining !== undefined) this.#remaining = remaining;\n if (this.#pacing === RateLimitPacing.Off || remaining === undefined) return 0;\n\n if (this.#flatPause !== undefined) {\n if (remaining > 0) return 0;\n this.#hold(this.#flatPause);\n return this.#flatPause;\n }\n\n const capacity = this.#capacity();\n\n if (this.#smooth) {\n if (capacity === undefined) return 0;\n this.#refill(capacity);\n // Заголовок только опускает оценку: большое `remaining` в начале окна не значит,\n // что столько же можно потратить прямо сейчас. Вверх её двигает лишь `#refill`,\n // по мере того как сервер действительно возвращает квоту.\n if (remaining < this.#tokens) this.#tokens = remaining;\n const wait = this.#armPause(capacity);\n this.#scheduler.changed();\n return wait;\n }\n\n if (remaining > 0) return 0;\n\n // Нижняя оценка ожидания: столько нужно серверу, чтобы вернуть одну единицу квоты,\n // если он возвращает её линейно. Граница окна из ответа не выводится, поэтому ждать\n // может потребоваться дольше — оставшийся путь доделает лестница `retryDelays`.\n const wait =\n capacity === undefined\n ? UNKNOWN_CAPACITY_PAUSE\n : Math.ceil(RATE_LIMIT_WINDOW / Math.max(capacity, 1));\n this.#hold(wait);\n return wait;\n }\n\n /** Придерживает бакет на названное время — путь ответа `429`. Оценка остатка обнуляется. */\n pause(ms: number): void {\n if (this.#smooth) {\n this.#tokens = 0;\n this.#tokensAt = this.#clock.now();\n }\n this.#hold(ms);\n }\n\n /** Снимок для `rateLimitState()`. */\n state(): RateLimitBucketState {\n return {\n destination: this.#destination,\n bucket: this.#bucket,\n limit: this.#limit,\n remaining: this.#remaining,\n active: this.#active,\n pending: this.#waiting.size,\n };\n }\n\n /** Отклоняет ещё не начатые задачи этого бакета. */\n stop(): void {\n this.cancelWaiting(queueStoppedError());\n }\n\n /** Отклоняет ожидающие задачи; используется также при остановке всего направления. */\n cancelWaiting(reason: unknown, notify = true): void {\n for (const task of this.#waiting.drain()) task.cancel(reason);\n if (notify) this.#scheduler.changed();\n }\n\n /** Лимит бакета: сказанный сервером, иначе табличный. */\n #capacity(): number | undefined {\n return this.#limit ?? this.#seedLimit;\n }\n\n /** Списывает токен на уходящий запрос и придерживает бакет до следующего. */\n #spend(): void {\n const capacity = this.#capacity();\n if (capacity === undefined) return;\n\n this.#refill(capacity);\n this.#tokens -= 1;\n this.#armPause(capacity);\n }\n\n /** Возвращает накопленное с прошлой проверки: `limit` единиц за минуту. */\n #refill(capacity: number): void {\n const now = this.#clock.now();\n if (this.#tokensAt !== undefined) {\n const restored = ((now - this.#tokensAt) * capacity) / RATE_LIMIT_WINDOW;\n this.#tokens = Math.min(capacity, this.#tokens + restored);\n }\n this.#tokensAt = now;\n }\n\n /** Держит бакет, пока не накопится хотя бы один токен. */\n #armPause(capacity: number): number {\n if (this.#tokens >= 1) return 0;\n\n const wait = Math.ceil(((1 - this.#tokens) * RATE_LIMIT_WINDOW) / capacity);\n this.#nextSlot = Math.max(this.#nextSlot, this.#clock.now() + wait);\n return wait;\n }\n\n /** Отодвигает ближайший допустимый старт и перепланирует общее пробуждение. */\n #hold(ms: number): void {\n if (ms <= 0) return;\n this.#nextSlot = Math.max(this.#nextSlot, this.#clock.now() + ms);\n this.#scheduler.changed();\n }\n}\n\n/** Совпадают ли начальные ограничения по всем трём полям. */\nfunction sameDefinition(\n left: Readonly<RateLimitBucketOverride> | undefined,\n right: Readonly<RateLimitBucketOverride> | undefined,\n): boolean {\n return (\n left?.limit === right?.limit &&\n left?.concurrency === right?.concurrency &&\n left?.rps === right?.rps\n );\n}\n\n/** Ограничения бакета для текста ошибки. */\nfunction describeDefinition(definition: Readonly<RateLimitBucketOverride> | undefined): string {\n const parts = [\n definition?.limit === undefined ? [] : [`limit ${definition.limit}`],\n definition?.concurrency === undefined ? [] : [`concurrency ${definition.concurrency}`],\n definition?.rps === undefined ? [] : [`rps ${definition.rps}`],\n ].flat();\n return parts.length > 0 ? parts.join(', ') : 'без ограничений';\n}\n\n/** Планировщик направления и зарегистрированные в нём бакеты. */\ninterface DestinationQueues {\n scheduler: DestinationScheduler;\n buckets: Map<string, BucketQueue>;\n}\n\n/**\n * Очереди по парам «направление — серверный счётчик частоты».\n *\n * Направление — origin уже разрешённого URL: разные локальные имена одного хоста делят\n * лимит, а запрос с разовым внешним `baseUrl` не попадает в основную очередь. Созданные\n * очереди сохраняются до `clear()`/`dispose()`, чтобы не терять известное состояние лимитов.\n *\n * @internal\n */\nexport class RequestQueuePool {\n readonly #options: ResolvedRateLimitOptions;\n readonly #clock: ItdClock;\n /** Ключ `undefined` — основная очередь внутренних клиентов без известного направления. */\n readonly #destinations = new Map<string | undefined, DestinationQueues>();\n\n constructor(options: ResolvedRateLimitOptions, clock: ItdClock = systemClock) {\n this.#options = options;\n this.#clock = clock;\n }\n\n /**\n * Очередь бакета на направлении. При `buckets: false` бакет всегда `default`.\n *\n * Начальные ограничения приходят из каталога вызывающего клиента и запоминаются при\n * создании очереди. Клиенты, разделяющие один пул через `ItdAccounts`, обязаны описывать\n * бакет одинаково: расхождение обнаруживается при обращении к уже созданной очереди.\n *\n * @throws {ItdConfigError} если очередь бакета создана с другими ограничениями\n */\n for(\n destination: string | undefined,\n bucket?: string,\n definition?: Readonly<RateLimitBucketOverride>,\n ): BucketQueue {\n const fallback = this.#options.defaultBucket;\n const name = this.#options.buckets ? (bucket ?? fallback) : fallback;\n const limits = this.#options.buckets ? definition : undefined;\n\n let entry = this.#destinations.get(destination);\n if (!entry) {\n entry = {\n scheduler: new DestinationScheduler(this.#options, this.#clock),\n buckets: new Map(),\n };\n this.#destinations.set(destination, entry);\n }\n\n let queue = entry.buckets.get(name);\n if (!queue) {\n queue = new BucketQueue(\n destination,\n name,\n entry.scheduler,\n this.#options,\n this.#clock,\n limits,\n );\n entry.buckets.set(name, queue);\n } else if (!sameDefinition(queue.definition, limits)) {\n throw new ItdConfigError(\n `Бакет «${name}» уже используется с другими ограничениями: ` +\n `${describeDefinition(queue.definition)} против ${describeDefinition(limits)}`,\n );\n }\n return queue;\n }\n\n /** Снимки всех бакетов, о которых что-то известно. */\n states(): RateLimitBucketState[] {\n const states: RateLimitBucketState[] = [];\n for (const entry of this.#destinations.values()) {\n for (const queue of entry.buckets.values()) states.push(queue.state());\n }\n return states;\n }\n\n /**\n * Останавливает планировщики: ожидающие задачи отклоняются, а состояние счётчиков\n * и отложенные паузы сохраняются до следующего запуска — путь `close()`.\n */\n stop(): void {\n for (const entry of this.#destinations.values()) {\n entry.scheduler.stop();\n }\n }\n\n /** Останавливает очереди и забывает всё, что известно о счётчиках, — путь `dispose()`. */\n clear(): void {\n this.stop();\n this.#destinations.clear();\n }\n}\n","import { ItdConfigError } from './errors.js';\nimport { hostOf, isSameSite, normalizeBaseUrl } from './url.js';\n\n/** Сервис платформы на отдельном домене. */\nexport interface ServiceDefinition {\n /** Имя, по которому запрос выбирает сервис: `{ service: 'status' }`. */\n name: string;\n /** Базовый URL сервиса. */\n baseUrl: string;\n /** Заголовки, добавляемые к каждому запросу сервиса. Заголовки вызова важнее. */\n headers?: Record<string, string> | undefined;\n /**\n * Слать ли заголовок авторизации.\n *\n * По умолчанию включено для основного хоста и его поддоменов. Для остальных хостов\n * авторизацию нужно разрешить явно: `auth: true`.\n */\n auth?: boolean | undefined;\n}\n\n/**\n * Накладывает пользовательское определение на встроенное.\n *\n * `auth` и `headers` наследуются от встроенного, пока ключ не задан явно: авторизация\n * относится к сервису, а не к адресу. Явный `undefined` возвращает вывод по хосту.\n *\n * @internal\n */\nexport function mergeService(\n builtIn: ServiceDefinition,\n override: ServiceDefinition,\n): ServiceDefinition {\n const auth = 'auth' in override ? override.auth : builtIn.auth;\n const headers = 'headers' in override ? override.headers : builtIn.headers;\n\n return {\n name: builtIn.name,\n baseUrl: override.baseUrl,\n ...(headers === undefined ? {} : { headers }),\n ...(auth === undefined ? {} : { auth }),\n };\n}\n\n/**\n * Именованные сервисы клиента.\n *\n * @internal\n */\nexport class ServiceRegistry {\n readonly #services = new Map<string, ServiceDefinition>();\n /** Хост основного API. */\n readonly #primaryHost: string;\n\n /** @param primaryBaseUrl базовый URL клиента */\n constructor(primaryBaseUrl?: string) {\n this.#primaryHost = primaryBaseUrl ? hostOf(primaryBaseUrl) : '';\n }\n\n /**\n * Регистрирует сервис. Имя очищается от краевых пробелов, базовый URL приводится\n * к каноничному виду, а незаданный `auth` выводится из хоста.\n *\n * @throws {ItdConfigError} если имя пустое, имя занято или `baseUrl` не абсолютный URL\n */\n define(definition: ServiceDefinition): void {\n const raw = definition?.name;\n if (typeof raw !== 'string' || raw.trim() === '') {\n throw new ItdConfigError('У сервиса должно быть непустое имя');\n }\n\n const name = raw.trim();\n if (this.#services.has(name)) {\n throw new ItdConfigError(`Сервис «${name}» уже зарегистрирован и не может быть заменён`);\n }\n\n const baseUrl = normalizeBaseUrl(definition.baseUrl);\n if (definition.auth !== undefined && typeof definition.auth !== 'boolean') {\n throw new ItdConfigError(`services.${name}.auth должен быть boolean`);\n }\n\n let headers: Readonly<Record<string, string>> | undefined;\n if (definition.headers !== undefined) {\n if (\n typeof definition.headers !== 'object' ||\n definition.headers === null ||\n Array.isArray(definition.headers)\n ) {\n throw new ItdConfigError(`services.${name}.headers должен быть объектом строк`);\n }\n for (const [header, value] of Object.entries(definition.headers)) {\n if (typeof value !== 'string') {\n throw new ItdConfigError(`services.${name}.headers.${header} должен быть строкой`);\n }\n }\n headers = Object.freeze({ ...definition.headers });\n }\n\n const normalized = {\n ...definition,\n name,\n baseUrl,\n auth: definition.auth ?? isSameSite(this.#primaryHost, hostOf(baseUrl)),\n ...(headers ? { headers } : {}),\n } satisfies ServiceDefinition;\n\n this.#services.set(name, Object.freeze(normalized));\n }\n\n /** Определение сервиса либо `undefined`, если такого нет. */\n get(name: string): ServiceDefinition | undefined {\n return this.#services.get(name);\n }\n\n /** Зарегистрирован ли сервис с таким именем. */\n has(name: string): boolean {\n return this.#services.has(name);\n }\n\n /** Удаляет сервис при откате атомарной установки feature. @internal */\n delete(name: string): boolean {\n return this.#services.delete(name);\n }\n\n /**\n * Атомарно заменяет существующее определение и возвращает прежнее.\n * Используется feature, накладывающим default на сервис из опций клиента.\n *\n * @internal\n */\n replace(definition: ServiceDefinition): ServiceDefinition {\n const name = definition.name.trim();\n const previous = this.require(name);\n this.#services.delete(name);\n try {\n this.define(definition);\n } catch (error) {\n this.#services.set(name, previous);\n throw error;\n }\n return previous;\n }\n\n /**\n * Определение сервиса.\n *\n * @throws {ItdConfigError} если сервис не зарегистрирован\n */\n require(name: string): ServiceDefinition {\n const service = this.#services.get(name);\n if (!service) {\n const known = [...this.#services.keys()];\n throw new ItdConfigError(\n `Сервис «${name}» не зарегистрирован. ` +\n (known.length > 0\n ? `Известны: ${known.join(', ')}`\n : 'Зарегистрируйте его через itd.defineService() или опцию services'),\n );\n }\n return service;\n }\n\n /**\n * Базовый URL сервиса.\n *\n * @throws {ItdConfigError} если сервис не зарегистрирован\n */\n resolveBaseUrl(name: string): string {\n return this.require(name).baseUrl;\n }\n\n /**\n * Принадлежит ли URL основному хосту клиента или его поддомену.\n *\n * Используется для безопасного значения по умолчанию у разового `baseUrl`: Bearer-токен\n * не должен уходить на посторонний хост без явного `skipAuth: false`.\n *\n * @internal\n */\n isPrimarySite(baseUrl: string): boolean {\n return isSameSite(this.#primaryHost, hostOf(baseUrl));\n }\n}\n","import type { ClientHooks } from '../options.js';\n\ntype HookName = keyof ClientHooks;\ntype HookContext<K extends HookName> = Parameters<NonNullable<ClientHooks[K]>>[0];\n\n/** Проверяет наличие публичного hook, не создавая дорогой контекст. @internal */\nexport function hasRequestHook(hooks: ClientHooks, field: HookName): boolean {\n return hooks[field] !== undefined;\n}\n\n/** Последовательно вызывает публичный hook конструктора. @internal */\nexport async function dispatchRequestHook<K extends HookName>(\n hooks: ClientHooks,\n field: K,\n context: HookContext<K>,\n): Promise<void> {\n const hook = hooks[field] as ((value: HookContext<K>) => void | Promise<void>) | undefined;\n await hook?.(context);\n}\n","import type { ItdClock } from '../clock.js';\nimport { ItdAbortError, type ItdError, ItdTimeoutError } from '../errors.js';\n\nexport interface RequestAbortScope {\n signal: AbortSignal;\n abort(reason?: unknown): void;\n /** Ошибка истёкшего срока, если сигнал сработал по таймеру. */\n expired(): ItdError | undefined;\n /** Снимает таймер срока, оставляя связь с отменой вызова и владельца. */\n disarm(): void;\n cleanup(): void;\n}\n\n/** Срок ожидания области отмены и ошибка, которой он истекает. */\nexport interface AbortScopeExpiry {\n /** Срок в миллисекундах; `0` — без срока. */\n after: number;\n /** Создаёт ошибку истёкшего срока: она становится `signal.reason`. */\n error: () => ItdError;\n}\n\n/**\n * Объединяет отмену вызова, завершение владельца и срок ожидания в один сигнал.\n *\n * Истечение срока отменяет сигнал ошибкой из `expiry.error`; она же становится\n * `signal.reason`.\n *\n * @internal\n */\nexport function createRequestAbortScope(\n signal: AbortSignal | undefined,\n lifetimeSignal: AbortSignal | undefined,\n clock: ItdClock,\n expiry?: AbortScopeExpiry,\n): RequestAbortScope {\n const controller = new AbortController();\n let expired: ItdError | undefined;\n\n const link = (source: AbortSignal | undefined): (() => void) | undefined => {\n if (!source) return undefined;\n if (source.aborted) {\n controller.abort(source.reason);\n return undefined;\n }\n const onAbort = () => controller.abort(source.reason);\n source.addEventListener('abort', onAbort, { once: true });\n return () => source.removeEventListener('abort', onAbort);\n };\n\n const detach = [link(signal), link(lifetimeSignal)];\n let cancelTimer =\n expiry && expiry.after > 0\n ? clock.schedule(() => {\n cancelTimer = undefined;\n if (controller.signal.aborted) return;\n expired = expiry.error();\n controller.abort(expired);\n }, expiry.after)\n : undefined;\n\n const disarm = () => {\n cancelTimer?.();\n cancelTimer = undefined;\n };\n\n return {\n signal: controller.signal,\n abort: (reason) => controller.abort(reason),\n expired: () => expired,\n disarm,\n cleanup: () => {\n disarm();\n for (const remove of detach) remove?.();\n },\n };\n}\n\n/**\n * Прерывает только ожидание: исходный промис может корректно завершить фоновую работу,\n * а его позднее отклонение не станет необработанным.\n *\n * @internal\n */\nexport function waitForRequest<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted) {\n void promise.catch(() => {});\n return Promise.reject(new ItdAbortError(undefined, { cause: signal.reason }));\n }\n\n let onAbort: (() => void) | undefined;\n const aborted = new Promise<never>((_resolve, reject) => {\n onAbort = () => reject(new ItdAbortError(undefined, { cause: signal.reason }));\n signal.addEventListener('abort', onAbort, { once: true });\n });\n\n return Promise.race([promise, aborted]).finally(() => {\n if (onAbort) signal.removeEventListener('abort', onAbort);\n });\n}\n\n/**\n * Возвращает публичную ошибку, соответствующую причине остановки ожидания.\n *\n * Истёкший срок отдаёт ошибку, созданную таймером области. Отмена с причиной-ошибкой\n * библиотеки (истёкший срок родительской области) отдаёт саму причину; прочая отмена\n * оборачивается в {@link ItdAbortError}.\n *\n * @internal\n */\nexport function requestAbortError(\n scope: RequestAbortScope,\n request: { method: string; path: string },\n fallback: unknown,\n): unknown {\n const expired = scope.expired();\n if (expired) return expired;\n if (!scope.signal.aborted) return fallback;\n\n const reason: unknown = scope.signal.reason;\n if (reason instanceof ItdTimeoutError) return reason;\n if (fallback instanceof ItdAbortError) return fallback;\n return new ItdAbortError(`Запрос ${request.method.toUpperCase()} ${request.path} отменён`, {\n cause: reason,\n });\n}\n","import type { OperationId } from '../../domain/operations.js';\nimport type { CookieJar } from '../cookies.js';\nimport type { OperationRequestOptions, RateLimitBucketOverride } from '../options.js';\n\n/*\n * Служебное состояние одной логической операции лежит в объекте запроса под перечислимым\n * символом: spread-копии слоёв переносят его дальше, а `Object.entries` и `JSON.stringify`\n * в пользовательском коде — например в ключе кэша — его не видят. Внешняя граница каждого\n * нового запроса безусловно заменяет скопированный контейнер через {@link initializeOperationState}.\n */\nconst OPERATION_STATE = Symbol('itd-api.operation-state');\n\n/** Преобразует разобранное тело HTTP-ответа в результат операции. */\nexport type OperationReader = (\n body: unknown,\n request: Readonly<OperationRequestOptions>,\n) => unknown;\n\ninterface RequestAuthRecoveryState {\n recovered: boolean;\n preparationErrors: Set<unknown>;\n}\n\n/**\n * Учёт вызовов `onError` одной логической операции.\n *\n * `errors` — ошибки, уже переданные хуку. `abortReported` — отмена операции уже передана\n * хуку одним из уровней: верхней границей операции либо транспортной попыткой, чья ошибка\n * и есть эта отмена. Второй уровень тот же хук не вызывает.\n */\ninterface RequestErrorReportingState {\n errors: Set<unknown>;\n abortReported: boolean;\n}\n\ninterface OperationState {\n attempt?: number;\n queueKey?: RequestQueueKey;\n authRecovery?: RequestAuthRecoveryState;\n errorReporting?: RequestErrorReportingState;\n lifecycleSignal?: AbortSignal;\n reader?: OperationReader;\n disposeCleanup?: true;\n}\n\ntype InternalPipelineRequest = PipelineRequest & {\n [OPERATION_STATE]?: OperationState;\n};\n\nfunction operationState(request: PipelineRequest): OperationState {\n const internal = request as InternalPipelineRequest;\n let state = internal[OPERATION_STATE];\n if (!state) {\n state = {};\n internal[OPERATION_STATE] = state;\n }\n return state;\n}\n\ninterface InitialOperationState {\n lifecycleSignal: AbortSignal;\n reader?: OperationReader | undefined;\n disposeCleanup?: boolean | undefined;\n}\n\n/**\n * Начинает новую логическую операцию со свежим служебным состоянием.\n *\n * Контейнер заменяется безусловно: пользовательский код мог передать spread-копию запроса,\n * уже прошедшего через pipeline. Такое повторное обращение является новой операцией и не\n * должно наследовать её попытки, очередь, auth recovery, reader или учёт `onError`.\n *\n * @internal\n */\nexport function initializeOperationState<T extends PipelineRequest>(\n request: T,\n initial: InitialOperationState,\n): T {\n const state: OperationState = {\n lifecycleSignal: initial.lifecycleSignal,\n ...(initial.reader === undefined ? {} : { reader: initial.reader }),\n ...(initial.disposeCleanup ? { disposeCleanup: true as const } : {}),\n };\n return { ...request, [OPERATION_STATE]: state };\n}\n\n/** Функция чтения контракта операции, если запрос её несёт. @internal */\nexport function operationReaderOf(request: PipelineRequest): OperationReader | undefined {\n return (request as InternalPipelineRequest)[OPERATION_STATE]?.reader;\n}\n\n/** Переносит служебное состояние логической операции на новый объект запроса. @internal */\nexport function withOperationState(\n prepared: PipelineRequest,\n source: PipelineRequest,\n): PipelineRequest {\n const from = source as InternalPipelineRequest;\n const to = prepared as InternalPipelineRequest;\n to[OPERATION_STATE] = from[OPERATION_STATE] ?? {};\n return prepared;\n}\n\n/** Общий сигнал операции, сохранённый {@link initializeOperationState}. @internal */\nexport function lifecycleSignalOf(request: PipelineRequest): AbortSignal | undefined {\n return (request as InternalPipelineRequest)[OPERATION_STATE]?.lifecycleSignal;\n}\n\n/** Возвращает общее для всех retry состояние восстановления авторизации. @internal */\nexport function requestAuthRecoveryState(request: PipelineRequest): RequestAuthRecoveryState {\n const state = operationState(request);\n const current = state.authRecovery;\n if (current) return current;\n const recovery = { recovered: false, preparationErrors: new Set<unknown>() };\n state.authRecovery = recovery;\n return recovery;\n}\n\n/** Создаёт общий для копий логического запроса учёт вызовов `onError`. @internal */\nexport function trackRequestErrorReporting(request: PipelineRequest): void {\n const state = operationState(request);\n state.errorReporting ??= { errors: new Set(), abortReported: false };\n}\n\nfunction errorReportingState(request: PipelineRequest): RequestErrorReportingState {\n trackRequestErrorReporting(request);\n return operationState(request).errorReporting as RequestErrorReportingState;\n}\n\n/** Отмечает, что ошибка логического запроса уже была передана в `onError`. @internal */\nexport function markRequestErrorReported(request: PipelineRequest, error: unknown): void {\n errorReportingState(request).errors.add(error);\n}\n\n/** Была ли конкретная ошибка этой логической операции уже передана в `onError`. @internal */\nexport function wasRequestErrorReported(request: PipelineRequest, error: unknown): boolean {\n return (\n (request as InternalPipelineRequest)[OPERATION_STATE]?.errorReporting?.errors.has(error) ??\n false\n );\n}\n\n/**\n * Отмечает, что отмена операции передана в `onError`.\n *\n * @returns `false`, если это уже сделал другой уровень — повторно вызывать хук не нужно\n * @internal\n */\nexport function claimAbortReport(request: PipelineRequest): boolean {\n const state = errorReportingState(request);\n if (state.abortReported) return false;\n state.abortReported = true;\n return true;\n}\n\n/** Тело, заново подготовленное для одной транспортной попытки. */\nexport interface PreparedRequestBody {\n body: BodyInit;\n /** Заголовки тела, например multipart boundary. Пользовательские заголовки важнее. */\n headers?: Record<string, string> | undefined;\n /** Освобождает открытый файл или входящий HTTP-поток. */\n cleanup?: (() => void | Promise<void>) | undefined;\n}\n\n/** Контекст подготовки повторяемого тела. */\nexport interface RequestBodyContext {\n signal: AbortSignal;\n attempt: number;\n}\n\n/** Создаёт новое тело для каждой транспортной попытки. */\nexport type RequestBodyFactory = (\n context: RequestBodyContext,\n) => PreparedRequestBody | Promise<PreparedRequestBody>;\n\n/**\n * Описание запроса внутри конвейера.\n *\n * Отличается от публичного {@link RawRequestOptions} служебными полями. Главное из них —\n * `layerHeaders`: слои конвейера дописывают заголовки так, чтобы пользовательские `headers`\n * остались важнее, иначе слой авторизации перебивал бы `Authorization`, заданный вручную.\n */\nexport interface PipelineRequest extends OperationRequestOptions {\n /** Изолированный cookie jar конкретного auth-flow. @internal */\n cookieJar?: CookieJar | undefined;\n /** Повторяемое тело. Используется внутренними ресурсами вместо `body`. @internal */\n bodyFactory?: RequestBodyFactory | undefined;\n /**\n * Заголовки, добавленные слоями конвейера.\n *\n * Ставятся до пользовательских `headers` и потому могут быть ими переопределены.\n *\n * @internal\n */\n layerHeaders?: Record<string, string> | undefined;\n /**\n * Номер фактически начатой транспортной попытки, начиная с 1. Проставляет attempt layer.\n *\n * @internal\n */\n attempt?: number | undefined;\n}\n\n/** Запрос на внешней границе pipeline. Низкоуровневый вызов без ID считается `raw`. */\nexport type PipelineRequestInput = Omit<PipelineRequest, 'operationId'> & {\n operationId?: OperationId | undefined;\n};\n\n/** Один раз присваивает низкоуровневому запросу семантический ID до входа в middleware. */\nexport function identifyRequest(request: PipelineRequestInput): PipelineRequest {\n return request.operationId === undefined\n ? { ...request, operationId: 'raw' }\n : (request as PipelineRequest);\n}\n\n/** Начинает следующую фактическую транспортную попытку логической операции. @internal */\nexport function beginTransportAttempt(request: PipelineRequest): PipelineRequest {\n const state = operationState(request);\n state.attempt = (state.attempt ?? 0) + 1;\n return { ...request, attempt: state.attempt };\n}\n\n/** Возвращает номер последней начатой транспортной попытки. @internal */\nexport function currentTransportAttempt(request: PipelineRequest): number {\n return (request as InternalPipelineRequest)[OPERATION_STATE]?.attempt ?? 0;\n}\n\n/** Куда встаёт запрос: направление и бакет. @internal */\nexport interface RequestQueueKey {\n /** Origin разрешённого URL. `undefined` — направление неизвестно. */\n destination: string | undefined;\n bucket: string;\n /** Начальные ограничения бакета из каталога на момент постановки в очередь. */\n definition: Readonly<RateLimitBucketOverride> | undefined;\n}\n\n/**\n * Вычисляет ключ очереди один раз на логическую операцию.\n *\n * Ключ спрашивают трижды: при постановке в очередь, при чтении заголовков ответа и при\n * паузе после `429`. Значение хранится в общем состоянии операции, поэтому его видят все\n * копии запроса ниже по конвейеру. Ограничения бакета фиксируются вместе с ключом:\n * освобождение feature во время запроса не меняет очередь операции.\n *\n * @internal\n */\nexport function requestQueueKey(\n request: PipelineRequest,\n compute: (request: PipelineRequest) => RequestQueueKey,\n): RequestQueueKey {\n const state = operationState(request);\n const cached = state.queueKey;\n if (cached) return cached;\n\n const key = compute(request);\n state.queueKey = key;\n return key;\n}\n\n/** Разрешено ли запросу завершать внутреннюю очистку после `dispose()`. @internal */\nexport function isDisposeCleanupRequest(request: PipelineRequest): boolean {\n return (request as InternalPipelineRequest)[OPERATION_STATE]?.disposeCleanup === true;\n}\n\n/** Обработчик запроса. Самый внутренний в цепочке — транспорт. */\nexport type RequestHandler = (request: PipelineRequest) => Promise<unknown>;\n\n/**\n * Слой конвейера запросов.\n *\n * Получает запрос и продолжение цепочки. Может изменить запрос, обработать ошибку\n * продолжения или вовсе не вызывать `next`. Вправе вернуть `next()` без `await` и бросить\n * синхронно: вход в конвейер принимает и отклонение, и исключение.\n */\nexport type RequestMiddleware = (\n request: PipelineRequest,\n next: RequestHandler,\n) => Promise<unknown>;\n\n/**\n * Собирает слои в один обработчик.\n *\n * Первый слой становится внешним.\n *\n * @example\n * ```ts\n * const handler = composePipeline(\n * [plugins, services, retry, authRecovery, authPreparation, queue, attempt, authHeaders],\n * transport.send,\n * );\n * ```\n */\nexport function composePipeline(\n middlewares: readonly RequestMiddleware[],\n final: RequestHandler,\n): RequestHandler {\n return middlewares.reduceRight<RequestHandler>(\n (next, middleware) => (request) => middleware(request, next),\n final,\n );\n}\n\n/** Добавляет заголовки слоя, не трогая пользовательские. */\nexport function withLayerHeaders(\n request: PipelineRequest,\n headers: Record<string, string>,\n): PipelineRequest {\n return { ...request, layerHeaders: { ...request.layerHeaders, ...headers } };\n}\n","import type { OperationId } from '../../domain/operations.js';\nimport type { ItdClock } from '../clock.js';\nimport { ItdTimeoutError, TimeoutBudget } from '../errors.js';\nimport type { OperationContract } from '../operation.js';\nimport type { ClientHooks } from '../options.js';\nimport { dispatchRequestHook, hasRequestHook } from '../plugins/hooks.js';\nimport { buildQuery, joinUrl } from '../url.js';\nimport {\n createRequestAbortScope,\n type RequestAbortScope,\n requestAbortError,\n waitForRequest,\n} from './lifecycle.js';\nimport {\n claimAbortReport,\n currentTransportAttempt,\n identifyRequest,\n initializeOperationState,\n markRequestErrorReported,\n type OperationReader,\n type PipelineRequest,\n type PipelineRequestInput,\n type RequestHandler,\n wasRequestErrorReported,\n} from './pipeline.js';\n\n/** Что нужно точке входа в конвейер. */\nexport interface HttpClientDeps {\n /** Готовый обработчик — вся цепочка стадий поверх транспорта. */\n handler: RequestHandler;\n baseUrl: string;\n /** Общий срок логической операции по умолчанию; `0` — без срока. */\n deadline: number;\n clock: ItdClock;\n lifetimeSignal?: AbortSignal | undefined;\n hooks: ClientHooks;\n assertActive?: (() => void) | undefined;\n}\n\n/** Параметры операции без полей, которые задаёт её контракт или проставляют стадии. @internal */\nexport type HttpOperationOptions = Omit<\n PipelineRequest,\n 'operationId' | 'method' | 'layerHeaders' | 'attempt'\n>;\n\n/** Собирает запрос конвейера из контракта операции и параметров вызова. */\nfunction operationRequest<T, TId extends OperationId>(\n operation: OperationContract<T, TId>,\n options: HttpOperationOptions,\n): PipelineRequest {\n return {\n ...options,\n operationId: operation.id,\n method: operation.method,\n retrySafety: options.retrySafety ?? operation.retrySafety,\n };\n}\n\ninterface RunOptions {\n allowDisposed?: boolean | undefined;\n reader?: OperationReader | undefined;\n disposeCleanup?: boolean | undefined;\n}\n\n/**\n * Точка входа ресурсов в конвейер запросов.\n *\n * Заводит общий lifecycle логической операции — отмену, освобождение клиента и `deadline`, —\n * передаёт запрос собранной цепочке стадий и сообщает в `onError` об ошибках, которые\n * не дошли до транспорта. О стадиях и их порядке ресурсы не знают.\n */\nexport class HttpClient {\n readonly #handler: RequestHandler;\n readonly #baseUrl: string;\n readonly #deadline: number;\n readonly #clock: ItdClock;\n readonly #lifetimeSignal: AbortSignal | undefined;\n readonly #hooks: ClientHooks;\n readonly #assertActive: (() => void) | undefined;\n readonly #activeScopes = new Set<RequestAbortScope>();\n\n constructor(deps: HttpClientDeps) {\n this.#handler = deps.handler;\n this.#baseUrl = deps.baseUrl;\n this.#deadline = deps.deadline;\n this.#clock = deps.clock;\n this.#lifetimeSignal = deps.lifetimeSignal;\n this.#hooks = deps.hooks;\n this.#assertActive = deps.assertActive;\n if (this.#lifetimeSignal && !this.#lifetimeSignal.aborted) {\n this.#lifetimeSignal.addEventListener(\n 'abort',\n () => {\n for (const scope of this.#activeScopes) scope.abort(this.#lifetimeSignal?.reason);\n },\n { once: true },\n );\n }\n }\n\n /**\n * Выполняет низкоуровневый запрос через собранный конвейер.\n *\n * @typeParam T ожидаемая форма ответа после снятия обёртки `{ data: … }`\n * @throws {ItdApiError} если сервер ответил статусом ≥ 400\n * @throws {ItdTimeoutError} если истёк `timeout` попытки или `deadline` операции\n * @throws {ItdAbortError} если запрос отменён через `signal`\n * @throws {ItdNetworkError} если запрос не дошёл до сервера\n */\n request<T = unknown>(options: PipelineRequestInput): Promise<T> {\n return this.#run(identifyRequest(options)) as Promise<T>;\n }\n\n /** Выполняет контракт операции; `next()` плагина возвращает результат после `read`. */\n execute<T, TId extends OperationId>(\n operation: OperationContract<T, TId>,\n options: HttpOperationOptions,\n ): Promise<T> {\n return this.#run(operationRequest(operation, options), {\n reader: operation.read,\n }) as Promise<T>;\n }\n\n /** Выполняет внутреннюю операцию финализации после начала `ItdClient.dispose()`. @internal */\n cleanupOperation<T, TId extends OperationId>(\n operation: OperationContract<T, TId>,\n options: HttpOperationOptions,\n ): Promise<T> {\n return this.#run(operationRequest(operation, options), {\n allowDisposed: true,\n reader: operation.read,\n disposeCleanup: true,\n }) as Promise<T>;\n }\n\n async #run(request: PipelineRequest, options: RunOptions = {}): Promise<unknown> {\n if (!options.allowDisposed) this.#assertActive?.();\n const deadline = request.deadline ?? this.#deadline;\n const scope = createRequestAbortScope(request.signal, undefined, this.#clock, {\n after: deadline,\n error: () =>\n new ItdTimeoutError({\n timeout: deadline,\n method: request.method.toUpperCase(),\n path: request.path,\n budget: TimeoutBudget.Deadline,\n }),\n });\n if (this.#lifetimeSignal?.aborted) scope.abort(this.#lifetimeSignal.reason);\n else this.#activeScopes.add(scope);\n const startedAt = this.#clock.now();\n const tracked = initializeOperationState(request, {\n lifecycleSignal: scope.signal,\n reader: options.reader,\n disposeCleanup: options.disposeCleanup,\n });\n\n try {\n return await waitForRequest(this.#handler(tracked), scope.signal);\n } catch (error) {\n const failure = requestAbortError(scope, request, error);\n if (hasRequestHook(this.#hooks, 'onError')) {\n // Транспортная попытка сообщает о своих ошибках сама. Отмену операции сообщает тот\n // уровень, который заметил её первым: попытка, если отмена застала её внутри хука,\n // иначе — эта граница.\n const reported =\n wasRequestErrorReported(tracked, error) ||\n wasRequestErrorReported(tracked, failure) ||\n (scope.signal.aborted && !claimAbortReport(tracked));\n if (!reported) {\n markRequestErrorReported(tracked, error);\n markRequestErrorReported(tracked, failure);\n await this.#notifyError(tracked, scope.signal, startedAt, failure);\n }\n }\n throw failure;\n } finally {\n this.#activeScopes.delete(scope);\n scope.cleanup();\n }\n }\n\n /** Сообщает об ошибке, которую транспорт не видел: очередь, авторизация, плагины, отмена. */\n async #notifyError(\n request: PipelineRequest,\n signal: AbortSignal,\n startedAt: number,\n error: unknown,\n ): Promise<void> {\n let headers: Headers;\n try {\n headers = new Headers({ ...request.layerHeaders, ...request.headers });\n } catch {\n headers = new Headers();\n }\n const notification = dispatchRequestHook(this.#hooks, 'onError', {\n operationId: request.operationId,\n signal,\n method: request.method.toUpperCase(),\n path: request.path,\n url: joinUrl(request.baseUrl ?? this.#baseUrl, request.path) + buildQuery(request.query),\n headers,\n attempt: currentTransportAttempt(request) || 1,\n duration: this.#clock.now() - startedAt,\n error,\n });\n try {\n await waitForRequest(notification, signal);\n } catch (hookError) {\n // После отмены onError остаётся уведомлением и не удерживает завершение операции.\n if (!signal.aborted) throw hookError;\n }\n }\n}\n","import { ItdConfigError } from './errors.js';\nimport type { OperationRequestOptions } from './options.js';\n\n/** HTTP-метод операции. */\nexport const OperationMethod = Object.freeze({\n Get: 'GET',\n Post: 'POST',\n Put: 'PUT',\n Patch: 'PATCH',\n Delete: 'DELETE',\n} as const);\nexport type OperationMethod = (typeof OperationMethod)[keyof typeof OperationMethod];\n\n/** ID операции подключаемого модуля: `<featureName>.<operationName>`. */\nexport type FeatureOperationId<\n TFeatureName extends string = string,\n TOperationName extends string = string,\n> = `${TFeatureName}.${TOperationName}`;\n\n/** Семантическая безопасность автоматического повтора операции. */\nexport const RetrySafety = Object.freeze({\n /** Автоматический повтор не создаёт неприемлемого эффекта; обычно это чтение. */\n Safe: 'safe',\n /** Повтор операции приводит к тому же состоянию, что и один вызов. */\n Idempotent: 'idempotent',\n /** Повтор может создать ещё один побочный эффект. */\n Unsafe: 'unsafe',\n} as const);\nexport type RetrySafety = (typeof RetrySafety)[keyof typeof RetrySafety];\n\n/** Расширяемые метаданные операции. Плагины добавляют собственные поля. */\n// biome-ignore lint/suspicious/noEmptyInterface: extended by optional plugin packages.\nexport interface OperationAnnotations {}\n\n/** Публичные неизменяемые метаданные семантической операции. */\nexport interface OperationMetadata {\n readonly method: OperationMethod;\n readonly retrySafety: RetrySafety;\n readonly bucket?: string;\n readonly annotations?: Readonly<OperationAnnotations>;\n}\n\n/**\n * Контракт результата одного HTTP-запроса.\n *\n * Функция чтения принадлежит исполнителю и не входит в API плагинов. Все вызовы одного `id`\n * используют один контракт, поэтому форма результата не зависит от места вызова.\n */\nexport interface OperationContract<T = unknown, TId extends string = string>\n extends OperationMetadata {\n readonly id: TId;\n /** Преобразует разобранное тело HTTP-ответа в результат операции. @internal */\n readonly read: (body: unknown, request: Readonly<OperationRequestOptions>) => T;\n}\n\nfunction snapshotAnnotation(\n value: unknown,\n operationId: string,\n copies: Map<object, unknown>,\n): unknown {\n if (value === null || (typeof value !== 'object' && typeof value !== 'function')) return value;\n if (typeof value === 'function') {\n throw new ItdConfigError(`annotations операции «${operationId}» не должны содержать функции`);\n }\n\n const existing = copies.get(value);\n if (existing !== undefined) return existing;\n\n if (Array.isArray(value)) {\n const copy: unknown[] = [];\n copies.set(value, copy);\n for (const item of value) copy.push(snapshotAnnotation(item, operationId, copies));\n return Object.freeze(copy);\n }\n\n const prototype = Object.getPrototypeOf(value);\n if (prototype !== Object.prototype && prototype !== null) {\n throw new ItdConfigError(\n `annotations операции «${operationId}» должны состоять из обычных объектов, массивов и примитивов`,\n );\n }\n\n const copy = Object.create(prototype) as Record<PropertyKey, unknown>;\n copies.set(value, copy);\n for (const key of Reflect.ownKeys(value)) {\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (!descriptor?.enumerable) continue;\n if (!('value' in descriptor)) {\n throw new ItdConfigError(\n `annotations операции «${operationId}» не должны содержать getters или setters`,\n );\n }\n Object.defineProperty(copy, key, {\n value: snapshotAnnotation(descriptor.value, operationId, copies),\n enumerable: true,\n writable: true,\n configurable: true,\n });\n }\n return Object.freeze(copy);\n}\n\n/** Создаёт неизменяемый контракт результата. @internal */\nexport function defineOperation<T, TId extends string>(\n id: TId,\n metadata: OperationMetadata,\n read: (body: unknown, request: Readonly<OperationRequestOptions>) => T,\n): OperationContract<T, TId> {\n const annotations =\n metadata.annotations === undefined\n ? undefined\n : (snapshotAnnotation(metadata.annotations, id, new Map()) as OperationAnnotations);\n return Object.freeze({\n id,\n ...metadata,\n ...(annotations === undefined ? {} : { annotations }),\n read,\n });\n}\n\n/** Возвращает разобранное тело без дополнительного преобразования. @internal */\nexport function identityResult<T>(body: unknown): T {\n return body as T;\n}\n\n/** Отбрасывает служебное тело операции без результата. @internal */\nexport function voidResult(): void {}\n\n/**\n * Минимальное стабильное описание операции, доступное core и плагинам.\n *\n * Форма описания принадлежит ядру; заполненный ими каталог — доменному слою.\n */\nexport interface OperationDefinition extends OperationMetadata {\n /**\n * Бакет операции. Опущено — операция списывает из бакета по умолчанию.\n *\n * Счётчик определяется парой «путь + метод»: `GET /api/users/me` — 40 запросов\n * в минуту, `PUT` того же пути — 3, `DELETE` — 150.\n */\n readonly bucket?: string;\n}\n","import type { OperationCatalog } from '../catalog.js';\nimport type { ResolvedRetryOptions } from '../config.js';\nimport {\n ItdAbortError,\n ItdApiError,\n ItdFileError,\n ItdNetworkError,\n ItdTimeoutError,\n TimeoutBudget,\n} from '../errors.js';\nimport type { PipelineRequest } from '../execution/pipeline.js';\nimport { RetrySafety } from '../operation.js';\nimport type { RetryDecisionContext } from '../options.js';\n\n/** Политика конкретного логического запроса, передаваемая планировщику повторов. */\nexport type RetryPolicy = RetryDecisionContext;\n\n/**\n * Решает, повторять ли запрос.\n *\n * @returns пауза в миллисекундах перед следующей попыткой либо `undefined`, если повторять не нужно\n */\nexport type RetryScheduler = (\n error: unknown,\n retryAttempt: number,\n policy: RetryPolicy,\n) => number | undefined;\n\n/** Методы raw-запроса, безопасность которых гарантирована самим HTTP-контрактом. */\nconst SAFE_RAW_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);\n\n/** Может ли транспорт заново получить эквивалентное тело запроса. */\nexport function isRequestBodyReplayable(request: PipelineRequest): boolean {\n if (request.bodyFactory !== undefined) return true;\n return !(typeof ReadableStream !== 'undefined' && request.body instanceof ReadableStream);\n}\n\n/** Разрешает retrySafety запроса из явного override, каталога либо raw fallback. */\nexport function resolveRetryPolicy(\n request: PipelineRequest,\n catalog: OperationCatalog,\n): RetryPolicy {\n let retrySafety: RetrySafety;\n const known = catalog.definitionOf(request.operationId)?.retrySafety;\n\n if (request.retrySafety !== undefined) {\n retrySafety = request.retrySafety;\n } else if (known !== undefined) {\n retrySafety = known;\n } else if (request.operationId === 'raw' && SAFE_RAW_METHODS.has(request.method.toUpperCase())) {\n retrySafety = RetrySafety.Safe;\n } else {\n // Custom operation должна явно описать семантику; угадывать её по HTTP method нельзя.\n retrySafety = RetrySafety.Unsafe;\n }\n\n return {\n operationId: request.operationId,\n retrySafety,\n bodyReplayable: isRequestBodyReplayable(request),\n method: request.method.toUpperCase(),\n path: request.path,\n };\n}\n\n/**\n * Ошибка, после которой повтор невозможен в принципе: отмена либо истёкший общий срок операции.\n * Таймаут отдельной попытки сюда не входит — он повторяется как сетевой сбой.\n */\nfunction isTerminal(error: unknown): boolean {\n return (\n error instanceof ItdAbortError ||\n (error instanceof ItdTimeoutError && error.budget === TimeoutBudget.Deadline)\n );\n}\n\n/**\n * Стоит ли повторять запрос после этой ошибки.\n *\n * `429` гарантирует, что операция не была обработана, поэтому допускает даже unsafe retry.\n * Обрыв сети, таймаут попытки и `5xx` такой гарантии не дают и требуют safe/idempotent операции.\n * Ошибка подготовки файла возникает до обращения к серверу и потому зависит только от\n * собственного признака retryable и повторяемости тела.\n */\nfunction isRetryable(error: unknown, policy: RetryPolicy): boolean {\n if (isTerminal(error) || !policy.bodyReplayable) return false;\n\n // Неизвестное runtime-значение (например, из JavaScript без типов) должно вести себя\n // консервативно, а не случайно разрешать повтор unsafe-операции.\n const repeatableOperation =\n policy.retrySafety === RetrySafety.Safe || policy.retrySafety === RetrySafety.Idempotent;\n\n if (error instanceof ItdApiError) {\n if (error.status === 429) return true;\n if (error.status >= 500) return repeatableOperation;\n return false;\n }\n\n if (error instanceof ItdNetworkError || error instanceof ItdTimeoutError) {\n return repeatableOperation;\n }\n\n if (error instanceof ItdFileError) return error.retryable;\n\n return false;\n}\n\n/** Экспоненциальная пауза со случайным разбросом. */\nfunction backoffDelay(\n retryAttempt: number,\n options: ResolvedRetryOptions,\n random: () => number,\n): number {\n const exponential = options.baseDelay * 2 ** (retryAttempt - 1);\n const capped = Math.min(exponential, options.maxDelay);\n const spread = capped * options.jitter * (random() * 2 - 1);\n\n return Math.max(0, Math.round(capped + spread));\n}\n\n/**\n * Собирает планировщик обычных повторов для транспорта.\n *\n * Поведение при `Retry-After`: пауза, названная сервером, соблюдается точно. Если сервер\n * просит ждать дольше `maxDelay`, повтор не выполняется — вызывающий код получает ошибку.\n * Rate-limit ladder основного pipeline ведёт отдельный счётчик и обрабатывается middleware.\n */\nexport function createRetryScheduler(\n options: ResolvedRetryOptions,\n random: () => number = Math.random,\n): RetryScheduler {\n return (error, retryAttempt, policy) => {\n if (retryAttempt >= options.attempts) return undefined;\n if (isTerminal(error) || !policy.bodyReplayable) return undefined;\n\n if (options.shouldRetry) {\n return options.shouldRetry(error, retryAttempt, policy)\n ? backoffDelay(retryAttempt, options, random)\n : undefined;\n }\n\n if (!isRetryable(error, policy)) return undefined;\n\n if (error instanceof ItdApiError && error.retryAfter !== undefined) {\n return error.retryAfter > options.maxDelay ? undefined : error.retryAfter;\n }\n\n return backoffDelay(retryAttempt, options, random);\n };\n}\n","import type { AuthProvider } from '../auth-provider.js';\nimport type { OperationCatalog } from '../catalog.js';\nimport { type ItdClock, systemClock } from '../clock.js';\nimport { type ResolvedRetryOptions, resolveRetry } from '../config.js';\nimport {\n ItdAbortError,\n type ItdRateLimitError,\n isItdApiError,\n isItdRateLimitError,\n} from '../errors.js';\nimport type { Logger } from '../logger.js';\nimport type { ClientHooks, RequestOptions } from '../options.js';\nimport { dispatchRequestHook, hasRequestHook } from '../plugins/hooks.js';\nimport type { PluginRegistry } from '../plugins/registry.js';\nimport {\n createRetryScheduler,\n type RetryPolicy,\n type RetryScheduler,\n resolveRetryPolicy,\n} from '../scheduling/retry.js';\nimport type { ServiceRegistry } from '../services.js';\nimport { normalizeBaseUrl } from '../url.js';\nimport { waitForRequest } from './lifecycle.js';\nimport {\n beginTransportAttempt,\n currentTransportAttempt,\n lifecycleSignalOf,\n operationReaderOf,\n type PipelineRequest,\n type RequestHandler,\n type RequestMiddleware,\n requestAuthRecoveryState,\n withLayerHeaders,\n withOperationState,\n} from './pipeline.js';\n\n/** Сигнал для запроса без lifecycle: никогда не срабатывает. */\nconst IDLE_SIGNAL = new AbortController().signal;\n\n/** Ожидание повтора, которое уважает отмену запроса. */\nfunction sleep(clock: ItdClock, ms: number, signal?: AbortSignal): Promise<void> {\n if (!signal) return new Promise((resolve) => clock.schedule(resolve, ms));\n if (signal.aborted) {\n return Promise.reject(new ItdAbortError('Запрос отменён во время ожидания повтора'));\n }\n\n return new Promise((resolve, reject) => {\n const cancel = clock.schedule(() => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n cancel();\n reject(new ItdAbortError('Запрос отменён во время ожидания повтора'));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/**\n * Слой плагинов: обёртки логической операции.\n *\n * Transformer видит запрос и результат по одному разу, независимо от повторов и обновления\n * авторизации, и получает запрос с пользовательским `signal`; слои ниже — с общим сигналом\n * операции. Служебное состояние операции переносится на запрос, собранный обёрткой заново.\n * Здесь же к операции привязывается снимок attempt interceptors; сами они выполняются\n * транспортом на каждой попытке.\n */\nexport function createPluginsMiddleware(plugins: Pick<PluginRegistry, 'run'>): RequestMiddleware {\n return (request, next) => {\n const lifecycle = lifecycleSignalOf(request) ?? request.signal;\n return plugins.run(\n request,\n (prepared) => {\n const scoped = {\n ...(prepared as PipelineRequest),\n ...(lifecycle ? { signal: lifecycle } : {}),\n };\n return next(withOperationState(scoped, request));\n },\n lifecycle ?? IDLE_SIGNAL,\n );\n };\n}\n\n/**\n * Слой контракта операции: превращает разобранное тело ответа в публичный результат.\n *\n * Обёртки операции получают готовый результат метода, а не форму ответа сервера. У\n * `raw`-запроса функции чтения нет, тело возвращается как есть.\n */\nexport function createDecodeMiddleware(): RequestMiddleware {\n return async (request, next) => {\n const body = await next(request);\n const read = operationReaderOf(request);\n return read ? read(body, request) : body;\n };\n}\n\n/**\n * Слой очереди: ограничение конкурентности и частоты.\n *\n * Должен стоять непосредственно вокруг одной транспортной попытки: тогда ожидание retry\n * не занимает слот, а каждый реальный HTTP-вызов заново учитывается ограничителем частоты.\n *\n * `skipQueue` оставляет продвинутому вызывающему явный способ обойти планировщик.\n */\nexport function createQueueMiddleware(\n schedule: <T>(request: PipelineRequest, task: () => Promise<T>) => Promise<T>,\n): RequestMiddleware {\n return (request, next) =>\n request.skipQueue ? next(request) : schedule(request, () => next(request));\n}\n\n/**\n * Слой сервисов.\n *\n * Запросу с полем `service` подставляет хост сервиса, его заголовки и `skipAuth`, если\n * сервис объявлен публичным. Заданный у запроса `baseUrl` не трогает.\n *\n * Стоит снаружи повторов и авторизации, чтобы выставленный здесь `skipAuth` был ей виден.\n */\nexport function createServicesMiddleware(registry: ServiceRegistry): RequestMiddleware {\n return async (request, next) => {\n const service = request.service === undefined ? undefined : registry.require(request.service);\n let prepared = request;\n\n if (request.baseUrl !== undefined) {\n const baseUrl = normalizeBaseUrl(request.baseUrl);\n if (baseUrl !== request.baseUrl) prepared = { ...prepared, baseUrl };\n\n // Разовый хост не наследует разрешение авторизации от сервиса с другим URL.\n // Явное `skipAuth: false` остаётся способом осознанно отправить токен наружу.\n const matchesService = service?.baseUrl === baseUrl;\n const mayAuthorize = matchesService\n ? service.auth !== false\n : registry.isPrimarySite(baseUrl);\n if (!mayAuthorize && prepared.skipAuth === undefined) {\n prepared = { ...prepared, skipAuth: true };\n }\n }\n\n if (!service) return next(prepared);\n\n if (prepared.baseUrl === undefined) prepared = { ...prepared, baseUrl: service.baseUrl };\n\n if (service.headers) prepared = withLayerHeaders(prepared, service.headers);\n if (service.auth === false && prepared.skipAuth === undefined) {\n prepared = { ...prepared, skipAuth: true };\n }\n\n return next(prepared);\n };\n}\n\n/** Однократная auth-подготовка вне retry исходного запроса. */\nexport function createAuthPreflightMiddleware(\n getAuth: () => Pick<AuthProvider, 'preflight'>,\n): RequestMiddleware {\n return (request, next) => {\n if (request.skipAuth) return next(request);\n\n const auth = getAuth();\n const preflight = auth.preflight;\n if (!preflight) return next(request);\n\n return (async () => {\n const pending = preflight.call(auth, request.skipAuthRefresh !== true);\n await (request.signal ? waitForRequest(pending, request.signal) : pending);\n return next(request);\n })();\n };\n}\n\n/**\n * Подготавливает auth state до входа транспортной попытки в очередь.\n *\n * Загрузка storage, внешний `getToken` и ленивый sign-in могут быть асинхронными; sign-in\n * сам входит в ту же queue. Поэтому эти действия обязаны завершиться до захвата её слота.\n */\nexport function createAuthPreparationMiddleware(\n getAuth: () => Pick<AuthProvider, 'prepare'>,\n): RequestMiddleware {\n return (request, next) => {\n if (request.skipAuth) return next(request);\n\n const auth = getAuth();\n const prepare = auth.prepare;\n if (!prepare) return next(request);\n\n return (async () => {\n try {\n const pending = prepare.call(auth);\n await (request.signal ? waitForRequest(pending, request.signal) : pending);\n } catch (error) {\n // Recovery пропускает только эту ошибку; retry не считается восстановлением.\n requestAuthRecoveryState(request).preparationErrors.add(error);\n throw error;\n }\n return next(request);\n })();\n };\n}\n\n/**\n * Добавляет уже подготовленные заголовки непосредственно перед transport.\n *\n * Слой стоит внутри queue, поэтому источник заголовков обязан быть синхронным и не\n * запускать I/O — это выражено типом {@link AuthProvider.currentHeaders}. Если token\n * изменился, пока запрос ждал slot, будет использовано новое значение.\n */\nexport function createAuthHeadersMiddleware(\n auth: Pick<AuthProvider, 'currentHeaders'>,\n): RequestMiddleware {\n return (request, next) => {\n if (request.skipAuth) return next(request);\n\n const headers = auth.currentHeaders();\n return next(Object.keys(headers).length > 0 ? withLayerHeaders(request, headers) : request);\n };\n}\n\n/**\n * Нумерует фактические входы в transport для одной логической операции.\n *\n * Слой находится внутри auth recovery: повтор исходного запроса после успешного refresh\n * получает следующий номер, а сам `auth.refresh` ведёт собственный счётчик.\n */\nexport function createAttemptMiddleware(): RequestMiddleware {\n return (request, next) => next(beginTransportAttempt(request));\n}\n\n/**\n * Обрабатывает `401`: обновляет токен и повторяет транспортную попытку ровно один раз.\n *\n * Стоит снаружи подготовки auth и очереди, поэтому не удерживает её slot во время refresh.\n * Его `next` включает все эти слои: повтор заново готовит auth state и планируется.\n */\nexport function createAuthRecoveryMiddleware(\n auth: Pick<AuthProvider, 'recover'>,\n): RequestMiddleware {\n return async (request, next) => {\n try {\n return await next(request);\n } catch (error) {\n const recovery = requestAuthRecoveryState(request);\n const preparationFailed = recovery.preparationErrors.delete(error);\n // Обновляем и повторяем ровно один раз, чтобы не зациклиться, если сервер\n // отдаёт 401 и на свежем токене.\n if (\n request.skipAuthRefresh ||\n recovery.recovered ||\n preparationFailed ||\n !isItdApiError(error) ||\n error.status !== 401\n ) {\n throw error;\n }\n\n const pending = auth.recover();\n const refreshed = await (request.signal ? waitForRequest(pending, request.signal) : pending);\n if (!refreshed) throw error;\n\n recovery.recovered = true;\n return next({ ...request, skipAuthRefresh: true });\n }\n };\n}\n\n/** Что нужно слою повторов. */\nexport interface RetryMiddlewareDeps {\n clock?: ItdClock;\n /** Откуда берётся семантика операции: её повторяемость знает домен, а не ядро. */\n catalog: OperationCatalog;\n /** Глобальные настройки повторов. `undefined` — по умолчанию не повторять. */\n retry: ResolvedRetryOptions | undefined;\n /**\n * Паузы перед повторами при ответе `429`.\n *\n * Живут отдельно от `retry`: сервер не присылает `Retry-After`, и экспоненциальный откат\n * тут бесполезен — окно измеряется десятками секунд. Не зависят от `retry.attempts`.\n * Длина лестницы ограничивает число повторов и тогда, когда паузу называет сервер, а её\n * самая длинная ступень — саму паузу: `Retry-After` дольше не соблюдается, повтора нет.\n * Пустая лестница — повторов после `429` нет. `undefined` — очереди нет, и `429` уходит\n * обычной политике `retry` как рядовая ошибка.\n */\n rateLimitDelays: readonly number[] | undefined;\n /**\n * Придерживает очередь запроса на паузу `429`. `undefined`, если очереди нет.\n *\n * Тормозится очередь того счётчика, который ответил отказом.\n */\n pauseQueue: ((ms: number, request: PipelineRequest) => void) | undefined;\n hooks: ClientHooks;\n logger: Logger | undefined;\n buildUrl: (request: PipelineRequest) => string;\n}\n\n/**\n * Выбирает планировщик отката для конкретного запроса.\n *\n * `retry` у запроса переопределяет глобальную настройку: `false` выключает повторы,\n * объект задаёт свои. Обработка `429` от этого не зависит — она общая.\n */\nfunction resolveBackoff(\n retry: RequestOptions['retry'],\n global: RetryScheduler | undefined,\n): RetryScheduler | undefined {\n if (retry === undefined) return global;\n if (retry === false) return undefined;\n\n const resolved = resolveRetry(retry);\n return resolved ? createRetryScheduler(resolved) : undefined;\n}\n\n/**\n * Слой повторов.\n *\n * Ответ `429` обрабатывается отдельно от прочих ошибок лестницей пауз и с придержанием\n * всей очереди; сетевые сбои, таймаут попытки и `5xx` — экспоненциальным откатом.\n * Настройка `retry` у отдельного запроса имеет приоритет над глобальной.\n */\nexport function createRetryMiddleware(deps: RetryMiddlewareDeps): RequestMiddleware {\n const globalScheduler = deps.retry ? createRetryScheduler(deps.retry) : undefined;\n const ladder = deps.rateLimitDelays;\n const ladderCeiling = ladder && ladder.length > 0 ? Math.max(...ladder) : 0;\n\n /** Пауза по лестнице `429`; `undefined` — лестница пройдена или пауза сервера слишком велика. */\n const ladderDelay = (\n error: ItdRateLimitError,\n rateLimitAttempt: number,\n request: PipelineRequest,\n policy: RetryPolicy,\n ): number | undefined => {\n if (!ladder || !policy.bodyReplayable || rateLimitAttempt > ladder.length) return undefined;\n if (error.retryAfter !== undefined && error.retryAfter > ladderCeiling) return undefined;\n\n // Паузу, названную сервером, соблюдаем точно; иначе берём очередной шаг лестницы.\n const wait = error.retryAfter ?? ladder[rateLimitAttempt - 1];\n if (wait === undefined) return undefined;\n\n deps.pauseQueue?.(wait, request);\n deps.logger?.info(\n `лимит частоты ${request.method.toUpperCase()} ${request.path}, ` +\n `повтор ${rateLimitAttempt} через ${wait} мс`,\n );\n return wait;\n };\n\n return (request, next) => {\n const backoff = resolveBackoff(request.retry, globalScheduler);\n if (!backoff && (!ladder || ladder.length === 0)) return next(request);\n\n const method = request.method.toUpperCase();\n const policy = resolveRetryPolicy(request, deps.catalog);\n\n return (async () => {\n let retryAttempt = 0;\n let rateLimitAttempt = 0;\n\n for (;;) {\n try {\n return await next(request);\n } catch (error) {\n // Отменённую операцию не повторяют и о повторе не сообщают.\n if (request.signal?.aborted) throw error;\n\n const transportAttempt = currentTransportAttempt(request);\n // Без очереди `429` — рядовая ошибка: её повторяет обычная политика в общий счёт попыток.\n const rateLimited = ladder !== undefined && isItdRateLimitError(error);\n if (rateLimited) rateLimitAttempt += 1;\n else retryAttempt += 1;\n\n const delay = rateLimited\n ? ladderDelay(error, rateLimitAttempt, request, policy)\n : backoff?.(error, retryAttempt, policy);\n if (delay === undefined) throw error;\n\n if (hasRequestHook(deps.hooks, 'onRetry')) {\n const notification = dispatchRequestHook(deps.hooks, 'onRetry', {\n operationId: request.operationId,\n signal: request.signal,\n method,\n path: request.path,\n url: deps.buildUrl(request),\n // Умолчания транспорта добавляются после слоя повторов и сюда не входят.\n headers: new Headers({ ...request.layerHeaders, ...request.headers }),\n attempt: transportAttempt,\n error,\n delay,\n });\n await (request.signal ? waitForRequest(notification, request.signal) : notification);\n }\n\n deps.logger?.info(\n `повтор ${method} ${request.path}, попытка ${transportAttempt + 1} через ${delay} мс`,\n );\n\n await sleep(deps.clock ?? systemClock, delay, request.signal);\n }\n }\n })();\n };\n}\n\nexport { composePipeline } from './pipeline.js';\nexport type { RequestHandler, RequestMiddleware };\n","/**\n * Снимает внешнюю обёртку `{ data: … }`.\n *\n * Это единственное преобразование ответа, которое делает транспортный слой. Формы ответов у\n * итд.com непоследовательны: одни эндпоинты заворачивают полезную нагрузку в `data`, другие\n * отдают её напрямую (`GET /api/notifications/` → `{ notifications, hasMore }`), третьи кладут\n * список в поле по имени сущности. Угадывать имя поля опасно, поэтому его разбирает каждый\n * метод ресурса явно, а здесь снимается только однозначная обёртка.\n *\n * Обёртка считается обёрткой, лишь когда `data` — **единственный** ключ объекта. Ответ\n * `{ data: …, meta: … }` вернётся как есть.\n *\n * @example\n * ```ts\n * unwrapData({ data: { posts: [] } }); // { posts: [] }\n * unwrapData({ notifications: [], hasMore }); // без изменений\n * unwrapData({ data: [], hasMore: true }); // без изменений — ключей больше одного\n * ```\n */\nexport function unwrapData(body: unknown): unknown {\n if (typeof body !== 'object' || body === null || Array.isArray(body)) return body;\n\n const keys = Object.keys(body);\n if (keys.length !== 1 || keys[0] !== 'data') return body;\n\n return (body as { data: unknown }).data;\n}\n\n/** Непустая строка либо `undefined`. Отличается от {@link pickString} тем, что берёт значение, а не поле. */\nexport function asString(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\n/**\n * Достаёт поле-список из ответа, уже прошедшего {@link unwrapData}.\n *\n * Если поля нет или оно не массив, возвращается пустой массив: сервер иногда опускает\n * пустые коллекции, и падать из-за этого библиотека не должна.\n */\nexport function pickArray<T>(source: unknown, field: string): T[] {\n if (typeof source !== 'object' || source === null) return [];\n const value = (source as Record<string, unknown>)[field];\n return Array.isArray(value) ? (value as T[]) : [];\n}\n\n/** Достаёт объект по имени поля. Возвращает `undefined`, если это не объект. */\nexport function pickObject(source: unknown, field: string): Record<string, unknown> | undefined {\n if (typeof source !== 'object' || source === null) return undefined;\n const value = (source as Record<string, unknown>)[field];\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined;\n return value as Record<string, unknown>;\n}\n\n/** Достаёт булево поле. Возвращает `fallback`, если поля нет или тип не тот. */\nexport function pickBoolean(source: unknown, field: string, fallback = false): boolean {\n if (typeof source !== 'object' || source === null) return fallback;\n const value = (source as Record<string, unknown>)[field];\n return typeof value === 'boolean' ? value : fallback;\n}\n\n/** Достаёт числовое поле. Возвращает `fallback`, если поля нет или значение не конечное число. */\nexport function pickNumber(source: unknown, field: string, fallback: number): number {\n if (typeof source !== 'object' || source === null) return fallback;\n const value = (source as Record<string, unknown>)[field];\n return typeof value === 'number' && Number.isFinite(value) ? value : fallback;\n}\n\n/** Достаёт строковое поле. Возвращает `undefined`, если поля нет, оно пустое или не строка. */\nexport function pickString(source: unknown, field: string): string | undefined {\n if (typeof source !== 'object' || source === null) return undefined;\n const value = (source as Record<string, unknown>)[field];\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n","import type { ItdErrorCode } from '../types/enums.js';\nimport {\n type ItdApiError,\n ItdApiError as ItdApiErrorClass,\n type ItdApiErrorInit,\n ItdAuthError,\n ItdConflictError,\n type ItdFieldErrors,\n ItdForbiddenError,\n ItdNotFoundError,\n ItdPhoneVerificationError,\n ItdRateLimitError,\n ItdServerError,\n ItdValidationError,\n} from './errors.js';\nimport { redactBody } from './redact.js';\nimport { asString } from './unwrap.js';\nimport { isRecord } from './validate.js';\n\n/** Разобранное тело ошибки, приведённое к одной форме. */\nexport interface ParsedErrorBody {\n code: ItdErrorCode;\n message: string;\n detail: string | undefined;\n title: string | undefined;\n fieldErrors: ItdFieldErrors;\n /** Идентификатор пользователя, если сервер его вернул (нужен для ссылки подтверждения телефона). */\n userId: string | undefined;\n}\n\n/**\n * Отличает строковый машинный код (`NOT_FOUND`) от обычного текста и HTML страницы прокси.\n * Ограничение длины не даёт случайно принять большое служебное тело за код ошибки.\n */\nfunction readPlainTextErrorCode(value: string): ItdErrorCode | undefined {\n return value.length <= 128 && /^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$/.test(value)\n ? (value as ItdErrorCode)\n : undefined;\n}\n\n/**\n * Сводит ошибки по полям к единой форме `{ поле: [сообщения] }`.\n *\n * Понимает две документированные формы:\n * - `errors: { email: ['…'] }` либо `errors: { email: '…' }`\n * - `violations: [{ field: 'email', message: '…' }]`\n */\nfunction collectFieldErrors(source: Record<string, unknown>): ItdFieldErrors {\n const result: ItdFieldErrors = {};\n\n const errors = source.errors;\n if (isRecord(errors)) {\n for (const [field, value] of Object.entries(errors)) {\n if (Array.isArray(value)) {\n const messages = value.filter((item): item is string => typeof item === 'string');\n if (messages.length > 0) result[field] = messages;\n } else if (typeof value === 'string') {\n result[field] = [value];\n }\n }\n }\n\n const violations = source.violations;\n if (Array.isArray(violations)) {\n for (const violation of violations) {\n if (!isRecord(violation)) continue;\n const field = asString(violation.field) ?? asString(violation.property);\n const message = asString(violation.message);\n if (!field || !message) continue;\n const existing = result[field];\n if (existing) existing.push(message);\n else result[field] = [message];\n }\n }\n\n return result;\n}\n\n/**\n * Разбирает тело ответа с ошибкой.\n *\n * API отдаёт ошибки в двух формах — с обёрткой `{ error: … }` и без неё, — а при сбое на\n * уровне прокси может вернуть вообще не JSON. Все три случая сводятся к одной структуре.\n *\n * @param body тело ответа: разобранный JSON, строка или `undefined`\n * @param status HTTP-статус, используется для сообщения по умолчанию\n * @param statusText текст статуса из ответа\n */\nexport function parseErrorBody(body: unknown, status: number, statusText = ''): ParsedErrorBody {\n const fallbackMessage = statusText ? `HTTP ${status} ${statusText}` : `HTTP ${status}`;\n\n // Не-JSON: HTML от прокси, простой текст, пустое тело.\n if (typeof body === 'string') {\n const message = asString(body.trim()) ?? fallbackMessage;\n return {\n code: readPlainTextErrorCode(message) ?? 'UNKNOWN_ERROR',\n message,\n detail: undefined,\n title: undefined,\n fieldErrors: {},\n userId: undefined,\n };\n }\n\n if (!isRecord(body)) {\n return {\n code: 'UNKNOWN_ERROR',\n message: fallbackMessage,\n detail: undefined,\n title: undefined,\n fieldErrors: {},\n userId: undefined,\n };\n }\n\n // Ответ вида `{ type: \"validation\", on: \"query\", found: {…} }` — так сервер сообщает\n // о непрошедшей проверке параметров. Ни кода, ни текста в нём нет.\n if (body.type === 'validation') {\n const target = asString(body.on);\n\n return {\n code: 'VALIDATION_ERROR',\n message: target\n ? `Проверка не пройдена: некорректные данные в «${target}»`\n : 'Проверка входных данных не пройдена',\n detail: undefined,\n title: undefined,\n fieldErrors: {},\n userId: undefined,\n };\n }\n\n // Форма `{ error: { code, message, … } }` — работаем с вложенным объектом,\n // но поля верхнего уровня остаются запасным источником.\n const inner = isRecord(body.error) ? body.error : body;\n\n const message =\n asString(inner.message) ??\n asString(inner.detail) ??\n asString(inner.title) ??\n // `{ \"error\": \"Invalid token\" }` — так отвечает сервер на недействительный токен.\n asString(body.error) ??\n fallbackMessage;\n\n return {\n code: (asString(inner.code) ?? asString(body.code) ?? 'UNKNOWN_ERROR') as ItdErrorCode,\n message,\n detail: asString(inner.detail),\n title: asString(inner.title),\n fieldErrors: { ...collectFieldErrors(body), ...collectFieldErrors(inner) },\n userId: asString(inner.userId) ?? asString(body.userId),\n };\n}\n\n/**\n * Переводит заголовок `Retry-After` в миллисекунды.\n *\n * Поддерживает обе формы из спецификации HTTP: число секунд и дату.\n * Возвращает `undefined`, если заголовка нет или он не разбирается.\n */\nexport function parseRetryAfter(\n header: string | null | undefined,\n now = Date.now(),\n): number | undefined {\n if (!header) return undefined;\n\n const seconds = Number(header);\n if (Number.isFinite(seconds)) return Math.max(0, seconds * 1000);\n\n const date = Date.parse(header);\n if (Number.isFinite(date)) return Math.max(0, date - now);\n\n return undefined;\n}\n\n/** Читает целое число из заголовка. */\nfunction readIntHeader(headers: Headers | undefined, name: string): number | undefined {\n const raw = headers?.get(name);\n if (raw === null || raw === undefined) return undefined;\n\n const value = Number.parseInt(raw, 10);\n return Number.isFinite(value) ? value : undefined;\n}\n\n/** Читает положительное целое число из заголовка. */\nfunction readPositiveIntHeader(headers: Headers | undefined, name: string): number | undefined {\n const value = readIntHeader(headers, name);\n return value !== undefined && value > 0 ? value : undefined;\n}\n\n/**\n * Читает сведения об ограничении частоты.\n *\n * Сервер сообщает размер окна и остаток, но **не сообщает время сброса** — поэтому\n * точный момент, когда можно повторить, из ответа не вывести.\n */\nexport function readRateLimit(headers: Headers | undefined): {\n limit: number | undefined;\n remaining: number | undefined;\n} {\n return {\n // Нулевой или отрицательный размер бакета не имеет смысла и привёл бы к делению\n // на ноль в режиме smooth. Считаем такой заголовок отсутствующим и используем\n // табличную ёмкость бакета.\n limit: readPositiveIntHeader(headers, 'x-ratelimit-limit'),\n remaining: readIntHeader(headers, 'x-ratelimit-remaining'),\n };\n}\n\nconst REQUEST_ID_HEADERS = ['x-request-id', 'x-requestid', 'request-id', 'x-correlation-id'];\n\n/** Достаёт идентификатор запроса из заголовков ответа — пригодится при обращении в поддержку. */\nexport function getRequestId(headers: Headers | undefined): string | undefined {\n if (!headers) return undefined;\n for (const name of REQUEST_ID_HEADERS) {\n const value = headers.get(name);\n if (value) return value;\n }\n return undefined;\n}\n\n/** Соответствие кода ошибки конкретному классу. Приоритетнее, чем HTTP-статус. */\nconst CODE_TO_CLASS: Record<string, new (init: ItdApiErrorInit) => ItdApiError> = {\n VALIDATION_ERROR: ItdValidationError,\n RATE_LIMIT_EXCEEDED: ItdRateLimitError,\n UNAUTHORIZED: ItdAuthError,\n SESSION_EXPIRED: ItdAuthError,\n SESSION_REVOKED: ItdAuthError,\n SESSION_INVALID_REFRESH_TOKEN: ItdAuthError,\n // Оба приходят с `/auth/refresh`: первый — когда cookie refresh_token не долетела,\n // второй — когда она есть, но сессия за ней уже мертва.\n REFRESH_TOKEN_MISSING: ItdAuthError,\n SESSION_NOT_FOUND: ItdAuthError,\n ACCOUNT_INVALID_CREDENTIALS: ItdAuthError,\n ACCESS_DENIED: ItdForbiddenError,\n ENTITY_NOT_FOUND: ItdNotFoundError,\n // Приходит как JSON-код либо как text/plain тело `NOT_FOUND`.\n NOT_FOUND: ItdNotFoundError,\n ENTITY_ALREADY_EXISTS: ItdConflictError,\n};\n\n/** Соответствие HTTP-статуса классу — запасной вариант, когда код ничего не говорит. */\nfunction classByStatus(status: number): new (init: ItdApiErrorInit) => ItdApiError {\n if (status === 401) return ItdAuthError;\n if (status === 403) return ItdForbiddenError;\n if (status === 404) return ItdNotFoundError;\n if (status === 409) return ItdConflictError;\n if (status === 422) return ItdValidationError;\n if (status === 429) return ItdRateLimitError;\n if (status >= 500) return ItdServerError;\n return ItdApiErrorClass;\n}\n\n/**\n * Готовит тело ответа к сохранению в `ItdApiError.raw`.\n *\n * При `422` сервер возвращает присланное тело эхом: `{ type: 'validation', on: 'body',\n * found: { email: '…', password: '…' } }`. Ошибка обычно доезжает до логов и систем сбора\n * вроде Sentry — пароль в ней оказаться не должен. Имена полей для диагностики остаются,\n * значения секретов заменяются заглушкой.\n */\nfunction safeRawBody(body: unknown): unknown {\n if (!isRecord(body) || body.type !== 'validation' || !isRecord(body.found)) return body;\n\n return { ...body, found: redactBody(body.found) };\n}\n\n/** Что нужно знать о запросе, чтобы построить ошибку. */\nexport interface ErrorContext {\n method: string;\n path: string;\n status: number;\n /** Текущее время в миллисекундах с начала эпохи Unix. */\n now?: number | undefined;\n statusText?: string | undefined;\n headers?: Headers | undefined;\n response?: Response | undefined;\n /** Тело ответа: разобранный JSON либо строка. */\n body: unknown;\n}\n\n/**\n * Строит типизированную ошибку из ответа сервера.\n *\n * Класс выбирается сначала по коду ошибки, затем по HTTP-статусу — так `VALIDATION_ERROR`\n * со статусом `400` всё равно станет {@link ItdValidationError}.\n */\nexport function createApiError(context: ErrorContext): ItdApiError {\n const parsed = parseErrorBody(context.body, context.status, context.statusText);\n const rateLimit = readRateLimit(context.headers);\n\n const init = {\n rateLimit: rateLimit.limit,\n rateLimitRemaining: rateLimit.remaining,\n status: context.status,\n code: parsed.code,\n message: parsed.message,\n detail: parsed.detail,\n title: parsed.title,\n fieldErrors: parsed.fieldErrors,\n requestId: getRequestId(context.headers),\n method: context.method,\n path: context.path,\n raw: safeRawBody(context.body),\n response: context.response,\n retryAfter: parseRetryAfter(context.headers?.get('retry-after'), context.now),\n };\n\n if (parsed.code === 'PHONE_VERIFICATION_REQUIRED') {\n return new ItdPhoneVerificationError({ ...init, userId: parsed.userId });\n }\n\n const Ctor = CODE_TO_CLASS[parsed.code] ?? classByStatus(context.status);\n return new Ctor(init);\n}\n","import type { ItdClock } from '../clock.js';\nimport type { CookieJar } from '../cookies.js';\nimport { createApiError, readRateLimit } from '../error-factory.js';\nimport {\n ItdAbortError,\n ItdConfigError,\n ItdError,\n ItdNetworkError,\n ItdTimeoutError,\n TimeoutBudget,\n} from '../errors.js';\nimport { isLevelEnabled, type Logger, LogLevel } from '../logger.js';\nimport type { ClientHooks, RequestContext } from '../options.js';\nimport { attemptInterceptorScope, runAttemptInterceptors } from '../plugins/attempts.js';\nimport { dispatchRequestHook, hasRequestHook } from '../plugins/hooks.js';\nimport { redactBody, redactHeaders } from '../redact.js';\nimport { isBlob } from '../runtime.js';\nimport { unwrapData } from '../unwrap.js';\nimport { buildQuery, joinUrl } from '../url.js';\nimport { createRequestAbortScope, type RequestAbortScope, waitForRequest } from './lifecycle.js';\nimport {\n claimAbortReport,\n identifyRequest,\n markRequestErrorReported,\n type PipelineRequest,\n type PipelineRequestInput,\n type PreparedRequestBody,\n} from './pipeline.js';\n\n/**\n * Настройки, нужные транспорту.\n *\n * Узкий срез общей конфигурации: авторизация, хранилище, повторы и очередь транспорта\n * не касаются, и он не должен иметь к ним доступ.\n */\nexport interface TransportConfig {\n baseUrl: string;\n fetch: typeof fetch;\n /** Срок одной попытки по умолчанию; `0` — без срока. */\n timeout: number;\n clock: ItdClock;\n headers: Record<string, string>;\n /** Значение заголовка `User-Agent`. `undefined` — заголовок не выставляется. */\n userAgent: string | undefined;\n useCookieJar: boolean;\n sendCredentials: boolean;\n hooks: ClientHooks;\n logger: Logger | undefined;\n}\n\n/**\n * Внешние части, которыми пользуется транспорт.\n *\n * Все обязательны к передаче и все могут отсутствовать по существу: cookie-jar не нужен\n * в браузере, идентификатор устройства — при выключенной авторизации, а сведения об\n * ограничении частоты интересны только тогда, когда есть очередь. Освобождение клиента\n * приходит через `signal` запроса: его выставляет lifecycle операции.\n */\nexport interface TransportDeps {\n /** Хранилище cookie. `undefined` — cookie ведёт сама среда. */\n cookies: CookieJar | undefined;\n /**\n * Идентификатор устройства для заголовка `X-Device-Id`. Отправляется на всех запросах,\n * включая анонимные (`sign-in`).\n */\n getDeviceId: (() => Promise<string>) | undefined;\n /**\n * Сообщает об остатке лимита из заголовков ответа.\n *\n * Вызывается после **каждого** ответа, включая ошибочные, — так очередь узнаёт\n * об исчерпании лимита заранее и успевает притормозить до отказа сервера.\n */\n onRateLimit:\n | ((limit: number | undefined, remaining: number | undefined, request: PipelineRequest) => void)\n | undefined;\n}\n\n/** Одна транспортная попытка: всё, что нужно хукам, ошибкам и журналу. */\ninterface Attempt {\n readonly request: PipelineRequest;\n /** Нормализованный HTTP-метод. */\n readonly method: string;\n readonly url: string;\n /** Отмена вызова, освобождение клиента и срок попытки одним сигналом. */\n readonly abort: RequestAbortScope;\n readonly startedAt: number;\n /** Номер попытки, начиная с 1. */\n readonly number: number;\n}\n\ntype AttemptHookContext = RequestContext & { signal: AbortSignal };\n\ntype BodyCleanup = () => void | Promise<void>;\n\n/** Ставит заголовок, превращая ошибку среды в понятную ошибку конфигурации. */\nfunction setHeader(headers: Headers, name: string, value: string): void {\n try {\n headers.set(name, value);\n } catch (cause) {\n throw new ItdConfigError(\n `Некорректный HTTP-заголовок ${JSON.stringify(name)}: проверьте его имя и значение.`,\n { cause },\n );\n }\n}\n\n/** Тело, которое отправляется как есть, без сериализации в JSON. */\nfunction isRawBody(body: unknown): body is BodyInit {\n if (typeof body !== 'object' || body === null) return typeof body === 'string';\n return (\n (typeof FormData !== 'undefined' && body instanceof FormData) ||\n isBlob(body) ||\n (typeof URLSearchParams !== 'undefined' && body instanceof URLSearchParams) ||\n (typeof ReadableStream !== 'undefined' && body instanceof ReadableStream) ||\n body instanceof ArrayBuffer ||\n ArrayBuffer.isView(body)\n );\n}\n\n/**\n * Читает тело ответа один раз.\n *\n * Ответ можно прочитать только однократно, а тело нужно и при успехе, и при ошибке,\n * поэтому чтение происходит здесь, до ветвления по статусу.\n */\nasync function readBody(response: Response): Promise<unknown> {\n if (response.status === 204 || response.status === 205) return undefined;\n if (response.headers.get('content-length') === '0') return undefined;\n\n const contentType = response.headers.get('content-type') ?? '';\n\n if (contentType.includes('json')) {\n const text = await response.text();\n if (text === '') return undefined;\n try {\n return JSON.parse(text) as unknown;\n } catch {\n // Заголовок обещал JSON, но тело им не является — отдаём как текст,\n // чтобы сообщение об ошибке осталось информативным.\n return text;\n }\n }\n\n const text = await response.text();\n return text === '' ? undefined : text;\n}\n\nfunction describe(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * Единственное место, откуда библиотека ходит в сеть.\n *\n * Отвечает за сборку URL, заголовки, cookie, срок одной попытки, разбор ответа и превращение\n * любой неудачи в типизированную ошибку. Авторизация, повторы, очередь и плагины — отдельные\n * стадии конвейера, и транспорт о них не знает.\n */\nexport class Transport {\n readonly #config: TransportConfig;\n readonly #deps: TransportDeps;\n\n constructor(config: TransportConfig, deps: TransportDeps) {\n this.#config = config;\n this.#deps = deps;\n }\n\n /**\n * Выполняет один сетевой запрос.\n *\n * @throws {ItdApiError} если сервер ответил статусом ≥ 400\n * @throws {ItdTimeoutError} если истёк срок попытки\n * @throws {ItdAbortError} если запрос отменён через `signal`\n * @throws {ItdNetworkError} если запрос не дошёл до сервера\n */\n send = async (input: PipelineRequestInput): Promise<unknown> => {\n const request = identifyRequest(input);\n const timeout = request.timeout ?? this.#config.timeout;\n const method = request.method.toUpperCase();\n const attempt: Attempt = {\n request,\n method,\n url: this.buildUrl(request),\n abort: createRequestAbortScope(request.signal, undefined, this.#config.clock, {\n after: timeout,\n error: () =>\n new ItdTimeoutError({\n timeout,\n method,\n path: request.path,\n budget: TimeoutBudget.Attempt,\n }),\n }),\n startedAt: this.#config.clock.now(),\n number: request.attempt ?? 1,\n };\n const { signal } = attempt.abort;\n let cleanupBody: BodyCleanup | undefined;\n\n try {\n let headers: Headers;\n try {\n headers = await waitForRequest(this.#buildHeaders(request, attempt.url), signal);\n } catch (error) {\n throw this.#toTransportError(attempt, error);\n }\n\n let body: BodyInit | undefined;\n try {\n const prepared = await this.#prepareBody(attempt, headers);\n body = prepared.body;\n cleanupBody = prepared.cleanup;\n } catch (error) {\n const failure =\n signal.aborted || error instanceof ItdError\n ? this.#toTransportError(attempt, error)\n : new ItdConfigError(\n `Не удалось подготовить тело ${attempt.method} ${request.path}: ${describe(error)}`,\n { cause: error },\n );\n await this.#report(attempt, headers, failure);\n throw failure;\n }\n\n // Контекст попытки строится не более одного раза и только если он кому-то нужен.\n let context: AttemptHookContext | undefined;\n const contextOf = () => (context ??= this.#context(attempt, headers));\n\n if (hasRequestHook(this.#config.hooks, 'onRequest')) {\n try {\n // Хук получает собственную копию: `headers` общие, остальные поля его правки не переживут.\n await waitForRequest(\n dispatchRequestHook(this.#config.hooks, 'onRequest', { ...contextOf() }),\n signal,\n );\n } catch (error) {\n const failure = this.#abortedOr(attempt, error);\n await this.#report(attempt, headers, failure);\n throw failure;\n }\n }\n\n // Маскирование обходит заголовки и копирует тело: без включённого debug оно не нужно.\n const logger = this.#config.logger;\n if (logger && isLevelEnabled(logger, LogLevel.Debug)) {\n logger.debug(`→ ${attempt.method} ${request.path}`, {\n headers: redactHeaders(headers),\n body: request.bodyFactory ? '[повторяемое тело]' : redactBody(request.body),\n });\n }\n\n let response: Response;\n try {\n // Срок попытки действует и на `fetch`, который не слушает `signal`, и на перехватчик.\n response = await waitForRequest(this.#fetch(attempt, headers, body, contextOf), signal);\n } catch (error) {\n const failure = this.#abortedOr(attempt, error);\n await this.#report(attempt, headers, failure);\n this.#config.logger?.warn(\n `× ${attempt.method} ${request.path} (${this.#elapsed(attempt)} мс): ${describe(failure)}`,\n );\n throw failure;\n }\n\n if (this.#deps.onRateLimit) {\n const { limit, remaining } = readRateLimit(response.headers);\n this.#deps.onRateLimit(limit, remaining, request);\n }\n\n if (this.#config.useCookieJar) {\n (request.cookieJar ?? this.#deps.cookies)?.setFromResponse(\n response.url || attempt.url,\n response,\n );\n }\n\n // Хук получает собственную ветвь тела: чтение ответа внутри хука не должно лишать\n // транспорт возможности разобрать основной ответ.\n if (response.ok && hasRequestHook(this.#config.hooks, 'onResponse')) {\n const hookResponse = response.clone();\n try {\n await waitForRequest(\n dispatchRequestHook(this.#config.hooks, 'onResponse', {\n ...contextOf(),\n status: response.status,\n duration: this.#elapsed(attempt),\n response: hookResponse,\n }),\n signal,\n );\n } catch (error) {\n void response.body?.cancel().catch(() => {});\n const failure = this.#abortedOr(attempt, error);\n await this.#report(attempt, headers, failure);\n throw failure;\n } finally {\n if (!hookResponse.bodyUsed) void hookResponse.body?.cancel().catch(() => {});\n }\n }\n\n let payload: unknown;\n try {\n payload = await waitForRequest(readBody(response), signal);\n // Срок попытки снят: разбор ответа и хук onError им не ограничены.\n attempt.abort.disarm();\n } catch (error) {\n await response.body?.cancel().catch(() => {});\n const failure = this.#toTransportError(attempt, error);\n await this.#report(attempt, headers, failure);\n this.#config.logger?.warn(\n `× ${attempt.method} ${request.path}: не удалось прочитать тело ответа — ${failure.message}`,\n );\n throw failure;\n }\n\n const duration = this.#elapsed(attempt);\n if (!response.ok) {\n const error = createApiError({\n method: attempt.method,\n path: request.path,\n status: response.status,\n now: this.#config.clock.now(),\n statusText: response.statusText,\n headers: response.headers,\n response,\n body: payload,\n });\n await this.#report(attempt, headers, error);\n this.#config.logger?.warn(\n `← ${response.status} ${attempt.method} ${request.path} (${duration} мс): ${error.message}`,\n );\n throw error;\n }\n\n this.#config.logger?.debug(\n `← ${response.status} ${attempt.method} ${request.path} (${duration} мс)`,\n );\n return request.raw ? payload : unwrapData(payload);\n } finally {\n try {\n await cleanupBody?.();\n } catch (error) {\n this.#config.logger?.warn(\n `не удалось закрыть тело ${attempt.method} ${request.path}`,\n error,\n );\n } finally {\n attempt.abort.cleanup();\n }\n }\n };\n\n /**\n * Итоговый URL со строкой запроса. Нужен и слою повторов — для хука `onRetry`.\n *\n * Хост берётся из самого запроса, если он там задан: у сервисов платформы свои домены.\n */\n buildUrl(request: PipelineRequest): string {\n const base = request.baseUrl ?? this.#config.baseUrl;\n return joinUrl(base, request.path) + buildQuery(request.query);\n }\n\n /**\n * Собирает общие заголовки клиента: `User-Agent`, идентификатор устройства,\n * заголовки конфигурации и cookie для указанного адреса.\n */\n async platformHeaders(\n url: string,\n cookieJar: CookieJar | undefined = this.#deps.cookies,\n ): Promise<Headers> {\n const headers = new Headers();\n\n // Сервер этот заголовок не требует, но ожидает: дешевле отправить, чем разбираться,\n // почему часть запросов не проходит фильтры.\n headers.set('X-Requested-With', 'XMLHttpRequest');\n\n // В браузере это запрещённый заголовок: среда молча его игнорирует, ошибки не будет.\n if (this.#config.userAgent) setHeader(headers, 'User-Agent', this.#config.userAgent);\n\n if (this.#deps.getDeviceId) {\n setHeader(headers, 'X-Device-Id', await this.#deps.getDeviceId());\n }\n\n for (const [name, value] of Object.entries(this.#config.headers))\n setHeader(headers, name, value);\n\n if (this.#config.useCookieJar && cookieJar) {\n const cookie = cookieJar.getHeader(url);\n if (cookie) setHeader(headers, 'Cookie', cookie);\n }\n\n return headers;\n }\n\n /** Данные попытки для хуков `onRequest`, `onResponse` и перехватчиков. */\n #context(attempt: Attempt, headers: Headers): AttemptHookContext {\n return {\n operationId: attempt.request.operationId,\n signal: attempt.abort.signal,\n method: attempt.method,\n path: attempt.request.path,\n url: attempt.url,\n headers,\n attempt: attempt.number,\n };\n }\n\n #elapsed(attempt: Attempt): number {\n return this.#config.clock.now() - attempt.startedAt;\n }\n\n /** Ошибка хука: отмена во время его работы становится транспортной ошибкой, остальное — как есть. */\n #abortedOr(attempt: Attempt, error: unknown): unknown {\n return attempt.abort.signal.aborted ? this.#toTransportError(attempt, error) : error;\n }\n\n /**\n * Дополняет общие заголовки значением `Accept`, заголовками конвейера и вызова.\n * Заголовки вызова применяются последними.\n */\n async #buildHeaders(request: PipelineRequest, url: string): Promise<Headers> {\n const headers = await this.platformHeaders(url, request.cookieJar);\n\n // Заголовок из конфигурации имеет приоритет над значением по умолчанию.\n if (!headers.has('Accept')) headers.set('Accept', 'application/json');\n\n for (const [name, value] of Object.entries(request.layerHeaders ?? {}))\n setHeader(headers, name, value);\n\n for (const [name, value] of Object.entries(request.headers ?? {})) {\n setHeader(headers, name, value);\n }\n\n return headers;\n }\n\n /** Подготавливает тело внутри попытки, чтобы поток можно было открыть заново при retry. */\n async #prepareBody(\n attempt: Attempt,\n headers: Headers,\n ): Promise<{ body: BodyInit | undefined; cleanup: BodyCleanup | undefined }> {\n const { request } = attempt;\n const { signal } = attempt.abort;\n\n if (request.bodyFactory) {\n if (request.body !== undefined && request.body !== null) {\n throw new ItdConfigError('body и bodyFactory нельзя задавать одновременно');\n }\n\n const pending = Promise.resolve(request.bodyFactory({ signal, attempt: attempt.number }));\n let prepared: PreparedRequestBody;\n try {\n prepared = await waitForRequest(pending, signal);\n } catch (error) {\n if (signal.aborted) {\n void pending\n .then(async (late) => {\n try {\n await late.cleanup?.();\n } catch (cleanupError) {\n this.#config.logger?.warn(\n `не удалось закрыть отложенное тело ${attempt.method} ${request.path}`,\n cleanupError,\n );\n }\n })\n .catch(() => {});\n }\n throw error;\n }\n for (const [name, value] of Object.entries(prepared.headers ?? {})) {\n if (!headers.has(name)) setHeader(headers, name, value);\n }\n return { body: prepared.body, cleanup: prepared.cleanup };\n }\n\n if (request.body === undefined || request.body === null) {\n return { body: undefined, cleanup: undefined };\n }\n if (isRawBody(request.body)) {\n return { body: request.body, cleanup: undefined };\n }\n\n if (!headers.has('Content-Type')) headers.set('Content-Type', 'application/json');\n return { body: JSON.stringify(request.body), cleanup: undefined };\n }\n\n /** Вызывает `fetch` через перехватчики попытки; сбой сети становится ошибкой библиотеки. */\n #fetch(\n attempt: Attempt,\n headers: Headers,\n body: BodyInit | undefined,\n contextOf: () => AttemptHookContext,\n ): Promise<Response> {\n const init: RequestInit & { duplex?: 'half' } = {\n method: attempt.method,\n headers,\n signal: attempt.abort.signal,\n ...(body !== undefined ? { body } : {}),\n ...(this.#config.sendCredentials ? { credentials: 'include' as const } : {}),\n };\n if (typeof ReadableStream !== 'undefined' && body instanceof ReadableStream) {\n init.duplex = 'half';\n }\n\n const execute = async () => {\n try {\n return await this.#config.fetch(attempt.url, init);\n } catch (error) {\n throw this.#toTransportError(attempt, error);\n }\n };\n const interceptors = attemptInterceptorScope(attempt.request);\n if (!interceptors) return execute();\n\n return runAttemptInterceptors(interceptors, { ...contextOf(), body }, execute);\n }\n\n /**\n * Сообщает хуку `onError` об ошибке попытки и отмечает её как переданную.\n *\n * Ожидание хука ограничено lifecycle операции; срок попытки на него не действует.\n * Если ошибка попытки — сама отмена операции, о ней сообщает тот уровень, который заметил\n * её первым; второй хук не вызывает. Отмена, заставшая хук с другой ошибкой, остаётся за\n * верхней границей операции.\n *\n * @throws ошибку самого хука, если операция не отменена\n */\n async #report(attempt: Attempt, headers: Headers, error: unknown): Promise<void> {\n const { request } = attempt;\n attempt.abort.disarm();\n if (!hasRequestHook(this.#config.hooks, 'onError')) return;\n markRequestErrorReported(request, error);\n\n const lifecycle = request.signal;\n const notify = () =>\n dispatchRequestHook(this.#config.hooks, 'onError', {\n ...this.#context(attempt, headers),\n duration: this.#elapsed(attempt),\n error,\n });\n\n if (lifecycle?.aborted) {\n // После отмены уведомление не ожидается.\n if (claimAbortReport(request)) void notify().catch(() => {});\n return;\n }\n\n try {\n const pending = notify();\n await (lifecycle ? waitForRequest(pending, lifecycle) : pending);\n } catch (hookError) {\n if (lifecycle?.aborted) return;\n markRequestErrorReported(request, hookError);\n throw hookError;\n }\n }\n\n /** Превращает исключение `fetch` или отмену в понятную ошибку библиотеки. */\n #toTransportError(attempt: Attempt, error: unknown): ItdError {\n const { abort, method, request } = attempt;\n // Пользовательская отмена с собственным `reason` реджектит `fetch` этим значением, а не\n // `AbortError`, — поэтому опираемся на состояние сигнала, а не только на имя ошибки.\n const aborted = abort.signal.aborted || (error instanceof Error && error.name === 'AbortError');\n\n if (aborted) {\n // Истёкший срок — попытки или операции — приходит готовой ошибкой в reason: все\n // уровни отдают один объект. Прочую причину задаёт `abort(reason)` пользователя\n // либо освобождение клиента.\n const expired = abort.expired();\n if (expired) return expired;\n const reason: unknown = abort.signal.reason;\n if (reason instanceof ItdTimeoutError) return reason;\n return new ItdAbortError(\n `Запрос ${method} ${request.path} отменён`,\n reason !== undefined ? { cause: reason } : undefined,\n );\n }\n\n if (error instanceof ItdError) return error;\n\n return new ItdNetworkError(\n `Не удалось выполнить ${method} ${request.path}: ${describe(error)}`,\n {\n method,\n path: request.path,\n cause: error,\n },\n );\n }\n}\n","import type { AuthProvider, AuthProviderDeps } from '../auth-provider.js';\nimport type { OperationCatalog } from '../catalog.js';\nimport { assertKnownBucket, type ResolvedRuntimeConfig, resolveRuntimeConfig } from '../config.js';\nimport type { ClientConnection } from '../connection.js';\nimport { CookieJar } from '../cookies.js';\nimport { ItdAbortError } from '../errors.js';\nimport type { RuntimeOptions } from '../options.js';\nimport { PluginRegistry } from '../plugins/registry.js';\nimport { type RateLimitBucketState, RequestQueuePool } from '../scheduling/rate-limit.js';\nimport { ServiceRegistry } from '../services.js';\nimport { originOf } from '../url.js';\nimport { HttpClient } from './http.js';\nimport {\n composePipeline,\n createAttemptMiddleware,\n createAuthHeadersMiddleware,\n createAuthPreflightMiddleware,\n createAuthPreparationMiddleware,\n createAuthRecoveryMiddleware,\n createDecodeMiddleware,\n createPluginsMiddleware,\n createQueueMiddleware,\n createRetryMiddleware,\n createServicesMiddleware,\n type RequestMiddleware,\n} from './middleware.js';\nimport {\n isDisposeCleanupRequest,\n type PipelineRequest,\n type RequestHandler,\n requestQueueKey,\n} from './pipeline.js';\nimport { Transport } from './transport.js';\n\n/** Имена стадий обработки запроса в порядке выполнения. @internal */\nexport const ClientRuntimeStage = Object.freeze({\n OperationPlugins: 'operation_plugins',\n Decode: 'decode',\n Services: 'services',\n AuthPreflight: 'auth_preflight',\n Retry: 'retry',\n AuthRecovery: 'auth_recovery',\n AuthPreparation: 'auth_preparation',\n Queue: 'queue',\n Attempt: 'attempt',\n AuthHeaders: 'auth_headers',\n Transport: 'transport',\n} as const);\n/** @internal */\nexport type ClientRuntimeStage = (typeof ClientRuntimeStage)[keyof typeof ClientRuntimeStage];\n\n/** Скрытые зависимости runtime, которыми владеет внешний контейнер. @internal */\nexport interface ClientRuntimeInternals<A extends AuthProvider> {\n /**\n * Фабрика авторизации. Обязательна: умолчание сослалось бы на конкретную реализацию\n * сессии, и та осталась бы достижимой из любой сборки, включая анонимную.\n *\n * Готовый обработчик приходит фабрике внутрь: вход и продление проходят через тот же\n * конвейер, что и ресурсы, — с точечными skip-флагами вместо второго пути.\n */\n auth: (deps: AuthProviderDeps) => A;\n /**\n * Каталог операций, которым пользуется ядро.\n *\n * Позволяет использовать другой набор операций в тестах и специализированных клиентах.\n */\n catalog: OperationCatalog;\n /** Общая очередь нескольких клиентов; освобождается её владельцем. */\n queues?: RequestQueuePool | undefined;\n /** Проверяет состояние клиента до выполнения запроса. */\n assertActive?: ((action: string) => void) | undefined;\n}\n\n/**\n * Собранная внутренняя часть клиента.\n *\n * Содержит сетевую механику и реестры клиента.\n *\n * Параметризован реализацией авторизации: ядру достаточно {@link AuthProvider}, а фасад\n * получает обратно ровно тот тип, который создала его фабрика.\n *\n * @internal\n */\nexport interface ClientRuntime<A extends AuthProvider = AuthProvider> {\n readonly config: ResolvedRuntimeConfig;\n readonly http: HttpClient;\n readonly auth: A;\n readonly cookies: CookieJar;\n readonly plugins: PluginRegistry;\n readonly services: ServiceRegistry;\n /** Фактический порядок стадий для тестов и диагностики. */\n readonly stageOrder: readonly ClientRuntimeStage[];\n /** Разрешает окружение основного API либо именованного сервиса. */\n connection(serviceName?: string): ClientConnection;\n platformHeaders(url: string): Promise<Headers>;\n /** Снимок известных бакетов. Пустой, когда очередь отключена. */\n rateLimitState(): RateLimitBucketState[];\n /**\n * Временно останавливает принадлежащие клиенту очереди.\n *\n * Накопленный остаток квоты сохраняется: клиент после `close()` может работать дальше,\n * а серверные счётчики от закрытия клиента не сбрасываются.\n */\n close(): void;\n /** Отменяет начатые запросы, снимает auth listeners и освобождает плагины. */\n dispose(): Promise<void>;\n}\n\ninterface PipelineStage {\n name: ClientRuntimeStage;\n middleware: RequestMiddleware;\n}\n\n/** Регистрирует сервисы, заранее объявленные в опциях клиента. */\nfunction createServiceRegistry(config: ResolvedRuntimeConfig): ServiceRegistry {\n const services = new ServiceRegistry(config.baseUrl);\n for (const service of config.services) services.define(service);\n\n return services;\n}\n\n/** Собирает внутренние компоненты и цепочку запросов клиента. @internal */\nexport function createClientRuntime<A extends AuthProvider>(\n options: RuntimeOptions,\n internals: ClientRuntimeInternals<A>,\n): ClientRuntime<A> {\n const catalog = internals.catalog;\n const config = resolveRuntimeConfig(options, catalog);\n const jar = new CookieJar();\n const plugins = new PluginRegistry({\n shutdownTimeout: config.shutdownTimeout,\n clock: config.clock,\n operationMetadata: (operationId) => catalog.definitionOf(operationId),\n });\n const services = createServiceRegistry(config);\n\n // HttpClient отменяет этим сигналом активные области запросов: dispose() прерывает начатые.\n const lifetime = new AbortController();\n\n // Общая очередь принадлежит ItdAccounts. `rateLimit: false` исключает отдельный клиент\n // из неё, поэтому переданный pool учитывается только при включённом ограничителе.\n const sharedQueues = config.rateLimit ? internals.queues : undefined;\n const queues =\n sharedQueues ??\n (config.rateLimit ? new RequestQueuePool(config.rateLimit, config.clock) : undefined);\n const ownsQueues = sharedQueues === undefined;\n\n // Transport читает deviceId авторизации, а та отправляет свои запросы через готовый\n // pipeline. Цикл замыкается ленивыми callbacks строго внутри этой фабрики.\n let auth!: A;\n let transport!: Transport;\n\n /**\n * Бакет, из которого спишется запрос.\n *\n * Источники по убыванию приоритета: `rateLimitBucket` запроса, правило `rateLimit.bucket`,\n * каталог операций.\n */\n const bucketFor = (request: PipelineRequest): string => {\n if (request.rateLimitBucket !== undefined) return request.rateLimitBucket;\n\n const custom = config.rateLimit?.bucket?.({\n operationId: request.operationId,\n method: request.method,\n path: request.path,\n });\n return custom ?? catalog.bucketOf(request.operationId);\n };\n\n /** Origin направления, мемоизированный по базовому адресу. */\n const origins = new Map<string, string | undefined>();\n const destinationOf = (baseUrl: string): string | undefined => {\n if (origins.has(baseUrl)) return origins.get(baseUrl);\n if (origins.size >= 256) origins.clear();\n const origin = originOf(baseUrl) || undefined;\n origins.set(baseUrl, origin);\n return origin;\n };\n\n const queueKeyFor = (request: PipelineRequest) =>\n requestQueueKey(request, (target) => {\n const bucket = bucketFor(target);\n return {\n destination: destinationOf(target.baseUrl ?? config.baseUrl),\n bucket,\n definition: catalog.bucketDefinitionOf(bucket),\n };\n });\n\n const queueFor = (request: PipelineRequest) => {\n if (!queues) return undefined;\n\n const key = queueKeyFor(request);\n return queues.for(key.destination, key.bucket, key.definition);\n };\n\n /** Передаёт остаток из заголовков ответа бакету запроса; тот решает, тормозить ли себя. */\n const observeRateLimit = (\n limit: number | undefined,\n remaining: number | undefined,\n request: PipelineRequest,\n ): void => {\n const queue = queueFor(request);\n if (!queue) return;\n\n const waited = queue.observe(limit, remaining);\n if (waited > 0) {\n config.logger?.debug(\n `остаток лимита ${remaining} из ${limit ?? '?'}, ` +\n `бакет ${queue.bucket} ждёт ${waited} мс`,\n );\n }\n };\n\n transport = new Transport(config, {\n // Заголовки читаются и при `pacing: 'off'`: на темп они там не влияют, но остаются\n // единственным источником для rateLimitState().\n onRateLimit: queues ? observeRateLimit : undefined,\n cookies: config.useCookieJar ? jar : undefined,\n getDeviceId: () => auth.deviceId(),\n });\n\n /** Стадии логической операции: выполняются один раз на вызов метода. */\n const operationStages: PipelineStage[] = [\n { name: ClientRuntimeStage.OperationPlugins, middleware: createPluginsMiddleware(plugins) },\n { name: ClientRuntimeStage.Decode, middleware: createDecodeMiddleware() },\n ];\n\n /** Стадии исполнения: от выбора сервиса до транспортной попытки. */\n const executionStages: PipelineStage[] = [\n {\n name: ClientRuntimeStage.Services,\n middleware: createServicesMiddleware(services),\n },\n {\n name: ClientRuntimeStage.AuthPreflight,\n middleware: createAuthPreflightMiddleware(() => auth),\n },\n {\n name: ClientRuntimeStage.Retry,\n middleware: createRetryMiddleware({\n clock: config.clock,\n catalog,\n retry: config.retry,\n rateLimitDelays: config.rateLimit?.retryDelays,\n pauseQueue: queues ? (ms, request) => queueFor(request)?.pause(ms) : undefined,\n hooks: config.hooks,\n logger: config.logger,\n buildUrl: (request) => transport.buildUrl(request),\n }),\n },\n {\n name: ClientRuntimeStage.AuthRecovery,\n middleware: createAuthRecoveryMiddleware({ recover: () => auth.recover() }),\n },\n {\n name: ClientRuntimeStage.AuthPreparation,\n middleware: createAuthPreparationMiddleware(() => auth),\n },\n ];\n\n if (queues) {\n executionStages.push({\n name: ClientRuntimeStage.Queue,\n middleware: createQueueMiddleware((request, task) => {\n const queue = queueFor(request);\n return queue ? queue.schedule(task, request.signal) : task();\n }),\n });\n }\n\n executionStages.push(\n { name: ClientRuntimeStage.Attempt, middleware: createAttemptMiddleware() },\n {\n name: ClientRuntimeStage.AuthHeaders,\n middleware: createAuthHeadersMiddleware({ currentHeaders: () => auth.currentHeaders() }),\n },\n );\n\n const execution = composePipeline(\n executionStages.map(({ middleware }) => middleware),\n transport.send,\n );\n\n /**\n * Проверки между стадиями операции и исполнения: обёртка плагина уже могла изменить запрос,\n * а после начала `dispose()` завершаются только служебные запросы финализации.\n */\n const guardedExecution: RequestHandler = (request) => {\n try {\n if (!isDisposeCleanupRequest(request)) {\n internals.assertActive?.('выполнить новый запрос');\n }\n if (request.rateLimitBucket !== undefined) {\n assertKnownBucket(\n request.rateLimitBucket,\n 'rateLimitBucket',\n config.rateLimit?.bucket,\n catalog,\n );\n }\n } catch (error) {\n return Promise.reject(error);\n }\n return execution(request);\n };\n\n const handler = composePipeline(\n operationStages.map(({ middleware }) => middleware),\n guardedExecution,\n );\n\n const http = new HttpClient({\n handler,\n baseUrl: config.baseUrl,\n deadline: config.deadline,\n clock: config.clock,\n lifetimeSignal: lifetime.signal,\n hooks: config.hooks,\n assertActive: () => internals.assertActive?.('выполнить новый запрос'),\n });\n // Auth использует тот же executor: sign-in и refresh объявляют skip-флаги точечно,\n // вместо отдельного pipeline с постепенно расходящимся порядком стадий.\n auth = internals.auth({ config, http, cookies: jar });\n const stageOrder = Object.freeze([\n ...operationStages.map(({ name }) => name),\n ...executionStages.map(({ name }) => name),\n ClientRuntimeStage.Transport,\n ]);\n\n return {\n config,\n http,\n auth,\n cookies: jar,\n plugins,\n services,\n stageOrder,\n connection: (serviceName) => {\n const service = serviceName === undefined ? undefined : services.require(serviceName);\n const baseUrl = service?.baseUrl ?? config.baseUrl;\n\n return Object.freeze({\n baseUrl,\n authorize: service?.auth ?? true,\n fetch: config.fetch,\n clock: config.clock,\n logger: config.logger,\n signal: lifetime.signal,\n assertActive: (action: string) => internals.assertActive?.(action),\n baseHeaders: async (url: string) => {\n const headers = await transport.platformHeaders(url);\n for (const [name, value] of Object.entries(service?.headers ?? {})) {\n headers.set(name, value);\n }\n return headers;\n },\n getToken: () => auth.token(),\n refreshAuth: () => auth.recover(),\n });\n },\n platformHeaders: (url) => transport.platformHeaders(url),\n rateLimitState: () => queues?.states() ?? [],\n close: () => {\n if (ownsQueues) queues?.stop();\n },\n dispose: async () => {\n // Порядок: после отправки телеметрии в #close() фасада и до ожидания плагинов.\n lifetime.abort(new ItdAbortError('Клиент освобождён через dispose(), запрос отменён'));\n // В отличие от close(), это освобождение терминальное: состояние счётчиков больше\n // никому не пригодится, и держать карту очередей незачем.\n if (ownsQueues) queues?.clear();\n auth.dispose();\n await plugins.dispose();\n },\n };\n}\n","import type { RateLimitBucketOverride } from '../core/options.js';\n\n/**\n * Ёмкость серверных счётчиков частоты, запросов в минуту.\n *\n * Таблица действует до первого ответа бакета; дальше ёмкость берётся из заголовка\n * `x-ratelimit-limit` и заменяет табличную. `default` — счётчик любого пути без\n * собственного правила на сервере.\n */\nexport const BUCKET_LIMITS = Object.freeze({\n 'posts.stats': 180,\n default: 150,\n feed: 90,\n 'posts.like': 85,\n 'posts.comments': 80,\n hashtags: 50,\n users: 40,\n notifications: 40,\n 'files.get': 40,\n auth: 35,\n 'auth.refresh': 25,\n 'auth.qr': 40,\n 'auth.qrClaim': 300,\n search: 25,\n 'comments.like': 22,\n 'files.upload': 15,\n 'files.remove': 15,\n 'posts.comment': 14,\n 'hashtags.trending': 13,\n 'posts.repost': 7,\n 'users.follow': 7,\n 'verification.status': 6,\n 'posts.create': 5,\n 'users.updateMe': 3,\n 'reports.create': 3,\n 'verification.submit': 3,\n shop: 150,\n 'shop.delivery.cities': 60,\n 'shop.delivery.calculate': 45,\n 'shop.delivery.points': 30,\n 'shop.consents.record': 15,\n 'shop.orders.pay': 13,\n 'shop.orders.verifyAccessCode': 13,\n 'shop.orders.create': 12,\n 'shop.orders.requestAccessCode': 4,\n} as const satisfies Record<string, number>);\n\n/** Имя встроенного бакета. */\nexport type RateLimitBucket = keyof typeof BUCKET_LIMITS;\n\n/** Счётчик, из которого списывается путь без собственного правила на сервере. */\nexport const DEFAULT_RATE_LIMIT_BUCKET: RateLimitBucket = 'default';\n\n/** Известно ли библиотеке имя бакета. */\nexport function isKnownBucket(name: string): name is RateLimitBucket {\n return Object.hasOwn(BUCKET_LIMITS, name);\n}\n\n/**\n * Встроенные поправки бакетов.\n *\n * Таймаут загрузки файла — пять минут против обычных тридцати секунд, поэтому её\n * одновременность ограничена одним запросом.\n */\nexport const DEFAULT_BUCKET_OVERRIDES: Readonly<Record<string, RateLimitBucketOverride>> =\n Object.freeze({\n 'files.upload': Object.freeze({ concurrency: 1 }),\n });\n","import {\n defineOperation,\n type FeatureOperationId,\n identityResult,\n type OperationContract,\n type OperationDefinition,\n type OperationMethod,\n RetrySafety,\n} from '../core/operation.js';\nimport { DEFAULT_RATE_LIMIT_BUCKET, type RateLimitBucket } from './buckets.js';\n\n/** Описание встроенной операции: та же форма, что знает ядро, но с именем известного бакета. */\nexport interface ItdOperationDefinition extends OperationDefinition {\n readonly bucket?: RateLimitBucket;\n}\n\nfunction freezeOperations<const T extends Record<string, ItdOperationDefinition>>(\n operations: T,\n): Readonly<{ readonly [K in keyof T]: Readonly<T[K]> }> {\n for (const definition of Object.values(operations)) Object.freeze(definition);\n return Object.freeze(operations);\n}\n\n/**\n * Каталог встроенных операций.\n *\n * ID описывает смысл вызова и не меняется при переносе HTTP-пути. Method и retrySafety\n * хранятся здесь, чтобы resources, retry и плагины не вели независимые таблицы операций.\n */\nexport const OPERATIONS = freezeOperations({\n 'auth.check': { method: 'GET', retrySafety: RetrySafety.Safe },\n 'auth.captchaProvider': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'auth' },\n 'auth.captchaPage': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'auth' },\n 'auth.signUp': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'auth' },\n 'auth.signIn': { method: 'POST', retrySafety: RetrySafety.Safe, bucket: 'auth' },\n 'auth.verifyOtp': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'auth' },\n 'auth.resendOtp': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'auth' },\n 'auth.refresh': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'auth.refresh' },\n 'auth.logout': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'auth' },\n 'auth.forgotPassword': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'auth' },\n 'auth.resetPassword': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'auth' },\n 'auth.changePassword': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'auth' },\n 'auth.sessions': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'auth' },\n 'auth.revokeSession': { method: 'DELETE', retrySafety: RetrySafety.Unsafe, bucket: 'auth' },\n 'auth.revokeOtherSessions': {\n method: 'DELETE',\n retrySafety: RetrySafety.Unsafe,\n bucket: 'auth',\n },\n 'auth.qrStart': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'auth.qr' },\n 'auth.qrClaim': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'auth.qrClaim' },\n 'auth.qrScan': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'auth.qr' },\n 'auth.qrApprove': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'auth.qr' },\n 'auth.qrReject': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'auth.qr' },\n\n 'users.me': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'users' },\n 'users.updateMe': {\n method: 'PUT',\n retrySafety: RetrySafety.Idempotent,\n bucket: 'users.updateMe',\n },\n 'users.deactivate': { method: 'DELETE', retrySafety: RetrySafety.Unsafe },\n 'users.restore': { method: 'POST', retrySafety: RetrySafety.Unsafe },\n 'users.createProfile': { method: 'POST', retrySafety: RetrySafety.Unsafe },\n 'users.get': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'users' },\n 'users.checkUsername': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'users' },\n 'users.whoToFollow': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'users' },\n 'users.topClans': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'users' },\n 'users.follow': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'users.follow' },\n 'users.unfollow': { method: 'DELETE', retrySafety: RetrySafety.Unsafe, bucket: 'users.follow' },\n 'users.followers': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'users' },\n 'users.following': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'users' },\n 'users.followStatus': { method: 'POST', retrySafety: RetrySafety.Safe },\n 'users.block': { method: 'POST', retrySafety: RetrySafety.Unsafe },\n 'users.unblock': { method: 'DELETE', retrySafety: RetrySafety.Unsafe },\n 'users.blocked': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'users' },\n 'users.getPrivacy': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'users' },\n 'users.updatePrivacy': { method: 'PUT', retrySafety: RetrySafety.Idempotent },\n 'users.pins': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'users' },\n 'users.setPin': { method: 'PUT', retrySafety: RetrySafety.Idempotent },\n 'users.removePin': { method: 'DELETE', retrySafety: RetrySafety.Unsafe },\n\n 'posts.list': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'feed' },\n 'posts.create': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'posts.create' },\n 'posts.get': { method: 'GET', retrySafety: RetrySafety.Safe },\n 'posts.update': { method: 'PUT', retrySafety: RetrySafety.Idempotent },\n 'posts.remove': { method: 'DELETE', retrySafety: RetrySafety.Unsafe },\n 'posts.restore': { method: 'POST', retrySafety: RetrySafety.Unsafe },\n 'posts.like': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'posts.like' },\n 'posts.unlike': { method: 'DELETE', retrySafety: RetrySafety.Unsafe, bucket: 'posts.like' },\n 'posts.repost': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'posts.repost' },\n 'posts.unrepost': { method: 'DELETE', retrySafety: RetrySafety.Unsafe, bucket: 'posts.repost' },\n 'posts.pin': { method: 'POST', retrySafety: RetrySafety.Unsafe },\n 'posts.unpin': { method: 'DELETE', retrySafety: RetrySafety.Unsafe },\n 'posts.vote': { method: 'POST', retrySafety: RetrySafety.Unsafe },\n 'posts.stats': { method: 'POST', retrySafety: RetrySafety.Safe, bucket: 'posts.stats' },\n 'posts.byUser': { method: 'GET', retrySafety: RetrySafety.Safe },\n 'posts.likedByUser': { method: 'GET', retrySafety: RetrySafety.Safe },\n 'posts.comments': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'posts.comments' },\n 'posts.comment': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'posts.comment' },\n\n 'comments.replies': { method: 'GET', retrySafety: RetrySafety.Safe },\n 'comments.reply': { method: 'POST', retrySafety: RetrySafety.Unsafe },\n 'comments.update': { method: 'PATCH', retrySafety: RetrySafety.Idempotent },\n 'comments.remove': { method: 'DELETE', retrySafety: RetrySafety.Unsafe },\n 'comments.restore': { method: 'POST', retrySafety: RetrySafety.Unsafe },\n 'comments.like': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'comments.like' },\n 'comments.unlike': {\n method: 'DELETE',\n retrySafety: RetrySafety.Unsafe,\n bucket: 'comments.like',\n },\n\n 'files.upload': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'files.upload' },\n 'files.get': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'files.get' },\n 'files.remove': { method: 'DELETE', retrySafety: RetrySafety.Unsafe, bucket: 'files.remove' },\n\n 'notifications.list': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'notifications' },\n 'notifications.count': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'notifications' },\n 'notifications.markRead': { method: 'POST', retrySafety: RetrySafety.Idempotent },\n 'notifications.markReadBatch': { method: 'POST', retrySafety: RetrySafety.Idempotent },\n 'notifications.markAllRead': { method: 'POST', retrySafety: RetrySafety.Idempotent },\n 'notifications.getSettings': {\n method: 'GET',\n retrySafety: RetrySafety.Safe,\n bucket: 'notifications',\n },\n 'notifications.updateSettings': { method: 'PUT', retrySafety: RetrySafety.Idempotent },\n\n // Опрос уведомлений идёт по тем же двум маршрутам, что notifications.list и .count,\n // и делит с ними один серверный счётчик: при интервале 2 секунды фоновый поток\n // съедает три четверти бакета.\n 'events.notifications.poll.updates': {\n method: 'GET',\n retrySafety: RetrySafety.Safe,\n bucket: 'notifications',\n },\n 'events.notifications.poll.unread': {\n method: 'GET',\n retrySafety: RetrySafety.Safe,\n bucket: 'notifications',\n },\n\n 'hashtags.trending': {\n method: 'GET',\n retrySafety: RetrySafety.Safe,\n bucket: 'hashtags.trending',\n },\n 'hashtags.posts': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'hashtags' },\n 'search.all': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'search' },\n 'reports.create': { method: 'POST', retrySafety: RetrySafety.Unsafe, bucket: 'reports.create' },\n\n 'subscription.status': { method: 'GET', retrySafety: RetrySafety.Safe },\n 'subscription.pay': { method: 'POST', retrySafety: RetrySafety.Unsafe },\n 'subscription.setAutoRenewal': { method: 'POST', retrySafety: RetrySafety.Idempotent },\n 'subscription.bindCard': { method: 'POST', retrySafety: RetrySafety.Unsafe },\n 'subscription.methods': { method: 'GET', retrySafety: RetrySafety.Safe },\n 'subscription.setDefaultMethod': { method: 'POST', retrySafety: RetrySafety.Idempotent },\n 'subscription.removeMethod': { method: 'DELETE', retrySafety: RetrySafety.Unsafe },\n\n 'verification.status': {\n method: 'GET',\n retrySafety: RetrySafety.Safe,\n bucket: 'verification.status',\n },\n 'verification.submit': {\n method: 'POST',\n retrySafety: RetrySafety.Unsafe,\n bucket: 'verification.submit',\n },\n\n 'platform.version': { method: 'GET', retrySafety: RetrySafety.Safe },\n 'platform.changelog': { method: 'GET', retrySafety: RetrySafety.Safe },\n 'platform.announcements': { method: 'GET', retrySafety: RetrySafety.Safe },\n 'platform.portal': { method: 'GET', retrySafety: RetrySafety.Safe },\n\n 'telemetry.dwell': { method: 'POST', retrySafety: RetrySafety.Unsafe },\n 'telemetry.interaction': { method: 'POST', retrySafety: RetrySafety.Unsafe },\n\n 'shop.products.list': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'shop' },\n 'shop.products.get': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'shop' },\n 'shop.delivery.countries': { method: 'GET', retrySafety: RetrySafety.Safe, bucket: 'shop' },\n 'shop.delivery.cities': {\n method: 'GET',\n retrySafety: RetrySafety.Safe,\n bucket: 'shop.delivery.cities',\n },\n 'shop.delivery.points': {\n method: 'GET',\n retrySafety: RetrySafety.Safe,\n bucket: 'shop.delivery.points',\n },\n 'shop.delivery.calculate': {\n method: 'POST',\n retrySafety: RetrySafety.Safe,\n bucket: 'shop.delivery.calculate',\n },\n 'shop.orders.create': {\n method: 'POST',\n retrySafety: RetrySafety.Idempotent,\n bucket: 'shop.orders.create',\n },\n 'shop.orders.list': { method: 'GET', retrySafety: RetrySafety.Safe },\n 'shop.orders.get': { method: 'GET', retrySafety: RetrySafety.Safe },\n 'shop.orders.pay': {\n method: 'POST',\n retrySafety: RetrySafety.Unsafe,\n bucket: 'shop.orders.pay',\n },\n 'shop.orders.requestAccessCode': {\n method: 'POST',\n retrySafety: RetrySafety.Unsafe,\n bucket: 'shop.orders.requestAccessCode',\n },\n 'shop.orders.verifyAccessCode': {\n method: 'POST',\n retrySafety: RetrySafety.Unsafe,\n bucket: 'shop.orders.verifyAccessCode',\n },\n 'shop.consents.record': {\n method: 'POST',\n retrySafety: RetrySafety.Unsafe,\n bucket: 'shop.consents.record',\n },\n} as const satisfies Record<string, ItdOperationDefinition>);\n\n/** Стабильный ID встроенной операции. */\nexport type BuiltInOperationId = keyof typeof OPERATIONS;\n\n/** Пользовательская семантическая операция низкоуровневого запроса. */\nexport type CustomOperationId = `custom:${string}`;\n\n/** ID любого запроса, видимый transformers и hooks. */\nexport type OperationId = BuiltInOperationId | FeatureOperationId | CustomOperationId | 'raw';\n\n/** Создаёт контракт результата встроенной операции с проверяемым ID. */\nexport function defineBuiltInOperation<T, TId extends BuiltInOperationId = BuiltInOperationId>(\n id: TId,\n read: OperationContract<T>['read'] = identityResult<T>,\n): OperationContract<T, TId> {\n return defineOperation(id, OPERATIONS[id], read);\n}\n\nconst BUILT_IN_IDS: ReadonlySet<string> = new Set(Object.keys(OPERATIONS));\n\n/** Проверяет принадлежность ID встроенному каталогу. */\nexport function isBuiltInOperationId(value: string): value is BuiltInOperationId {\n return BUILT_IN_IDS.has(value);\n}\n\n/** HTTP-метод встроенной операции. */\nexport function operationMethod(id: BuiltInOperationId): OperationMethod {\n return OPERATIONS[id].method;\n}\n\n/** Политика автоматического повтора встроенной операции. */\nexport function operationRetrySafety(id: BuiltInOperationId): RetrySafety {\n return OPERATIONS[id].retrySafety;\n}\n\n/**\n * Бакет операции.\n *\n * `raw` и `custom:*` попадают в `default`; назвать бакет явно позволяет\n * `rateLimitBucket` у запроса.\n */\nexport function operationBucket(id: OperationId): RateLimitBucket {\n if (!isBuiltInOperationId(id)) return DEFAULT_RATE_LIMIT_BUCKET;\n // Литеральный тип каталога не сохраняет необязательное поле у операций без бакета.\n const definition: ItdOperationDefinition = OPERATIONS[id];\n return definition.bucket ?? DEFAULT_RATE_LIMIT_BUCKET;\n}\n","import type { OperationCatalog } from '../core/catalog.js';\nimport type { RateLimitBucketOverride } from '../core/options.js';\nimport {\n BUCKET_LIMITS,\n DEFAULT_BUCKET_OVERRIDES,\n DEFAULT_RATE_LIMIT_BUCKET,\n isKnownBucket,\n} from './buckets.js';\nimport { isBuiltInOperationId, OPERATIONS, operationBucket } from './operations.js';\n\n/** Ограничения встроенных бакетов: ёмкость из таблицы плюс встроенные поправки. */\nconst BUCKET_DEFINITIONS: Readonly<Record<string, Readonly<RateLimitBucketOverride>>> =\n Object.freeze(\n Object.fromEntries(\n Object.entries(BUCKET_LIMITS).map(([name, limit]) => [\n name,\n Object.freeze({ limit, ...DEFAULT_BUCKET_OVERRIDES[name] }),\n ]),\n ),\n );\n\n/**\n * Каталог операций итд.com, которым пользуется ядро.\n *\n * Единственное место, где generic request executor встречается с таблицами конкретного API.\n *\n * @internal\n */\nexport const ITD_CATALOG: OperationCatalog = Object.freeze({\n definitionOf: (id) => (isBuiltInOperationId(id) ? OPERATIONS[id] : undefined),\n // Неизвестный ID каталог сам сводит к бакету по умолчанию.\n bucketOf: (id) => operationBucket(id as Parameters<typeof operationBucket>[0]),\n isKnownBucket,\n bucketDefinitionOf: (name) => BUCKET_DEFINITIONS[name],\n bucketLimits: BUCKET_LIMITS,\n bucketOverrides: DEFAULT_BUCKET_OVERRIDES,\n defaultBucket: DEFAULT_RATE_LIMIT_BUCKET,\n} satisfies OperationCatalog);\n","/**\n * Enum API итд.com.\n *\n * Здесь намеренно не используется `enum` из TypeScript. Вместо него — пара «замороженный\n * объект + одноимённый тип». Такой приём даёт всё, ради чего берут `enum`\n * (`FeedTab.Popular`, перебор значений в рантайме), и при этом:\n *\n * - **стирается без остатка** — `enum` порождает рантайм-код и отвергается средами,\n * которые просто срезают типы (`node --experimental-strip-types`);\n * - **не запрещает обычные строки** — `itd.posts.list({ tab: 'popular' })` остаётся валидным,\n * тогда как строковый `enum` считает это ошибкой типа и вынуждает всех импортировать себя;\n * - **позволяет открытые множества** — там, где документация перечисляет значения не полностью,\n * тип расширяется через {@link Loose}, а объект остаётся справочником известных значений.\n *\n * @example\n * ```ts\n * import { FeedTab } from 'itd-api';\n *\n * await itd.posts.list({ tab: FeedTab.Popular }); // без магических строк\n * await itd.posts.list({ tab: 'popular' }); // и так тоже можно\n *\n * Object.values(FeedTab); // ['popular', 'following', 'clan']\n * ```\n *\n * @packageDocumentation\n */\n\n/**\n * Открытый строковый enum.\n *\n * Даёт автодополнение известных значений, но не ломается, если сервер пришлёт новое.\n * Используется там, где документация API перечисляет значения не полностью («`everyone` и др.»).\n */\nexport type Loose<T extends string> = T | (string & {});\n\n/**\n * Вкладка ленты `GET /api/posts`.\n *\n * Множество закрытое: неизвестное значение сервер отвергнет.\n */\nexport const FeedTab = Object.freeze({\n /** Популярное. Курсор здесь — номер страницы в виде строки (`\"2\"`, `\"6\"`…). */\n Popular: 'popular',\n /** Записи тех, на кого вы подписаны. Курсор — отметка времени последнего поста. */\n Following: 'following',\n /** Лента клана. Курсор, как и в подписках, — отметка времени. */\n Clan: 'clan',\n} as const);\nexport type FeedTab = (typeof FeedTab)[keyof typeof FeedTab];\n\n/** Порядок комментариев к посту. */\nexport const CommentSort = Object.freeze({\n /** Сначала новые. */\n Newest: 'newest',\n /** Сначала старые. */\n Oldest: 'oldest',\n /** Сначала популярные. */\n Popular: 'popular',\n} as const);\nexport type CommentSort = (typeof CommentSort)[keyof typeof CommentSort];\n\n/** Тип вложения. */\nexport const AttachmentType = Object.freeze({\n Image: 'image',\n Video: 'video',\n /** Голосовые комментарии: `audio/ogg`, с полем `duration`. */\n Audio: 'audio',\n} as const);\nexport type AttachmentType = (typeof AttachmentType)[keyof typeof AttachmentType];\n\n/**\n * Тип фрагмента разметки в тексте поста или комментария.\n *\n * Первые два сервер расставляет сам при разборе текста, остальные приходят от редактора.\n * Тип открытый: набор может пополниться.\n *\n * @example\n * ```ts\n * await itd.posts.update(postId, {\n * content: 'жирное слово',\n * spans: [{ type: SpanType.Bold, offset: 0, length: 6 }],\n * });\n * ```\n */\nexport const SpanType = Object.freeze({\n /** Хэштег. Название без решётки лежит в `tag`. */\n Hashtag: 'hashtag',\n /** Упоминание. Имя пользователя лежит в `tag`. */\n Mention: 'mention',\n /** Ссылка. Адрес лежит в `url`, а не в `tag`. */\n Link: 'link',\n Bold: 'bold',\n Italic: 'italic',\n Underline: 'underline',\n /** Зачёркнутый. */\n Strike: 'strike',\n /** Спойлер: текст скрыт до нажатия. */\n Spoiler: 'spoiler',\n /** Моноширинный. */\n Monospace: 'monospace',\n Quote: 'quote',\n} as const);\nexport type SpanType = Loose<(typeof SpanType)[keyof typeof SpanType]>;\n\n/** На что подаётся жалоба. */\nexport const ReportTargetType = Object.freeze({\n Post: 'post',\n Comment: 'comment',\n User: 'user',\n} as const);\nexport type ReportTargetType = (typeof ReportTargetType)[keyof typeof ReportTargetType];\n\n/** Причина жалобы. Множество закрытое. */\nexport const ReportReason = Object.freeze({\n Spam: 'spam',\n Violence: 'violence',\n Hate: 'hate',\n Adult: 'adult',\n Fraud: 'fraud',\n Other: 'other',\n} as const);\nexport type ReportReason = (typeof ReportReason)[keyof typeof ReportReason];\n\n/**\n * Провайдер капчи, которую сервер требует пройти при входе. Тип открытый.\n *\n * Активного сообщает `itd.auth.captchaProvider()`.\n */\nexport const CaptchaType = Object.freeze({\n /** Собственная капча ИТД. */\n Itd: 'itd',\n /** Cloudflare Turnstile. */\n Cloudflare: 'cloudflare',\n} as const);\nexport type CaptchaType = Loose<(typeof CaptchaType)[keyof typeof CaptchaType]>;\n\n/**\n * Какую капчу проходить при входе по логину и паролю.\n *\n * `CaptchaChoice.Auto` — спросить сервер перед каждым входом; названный провайдер\n * обходится без этого запроса.\n */\nexport const CaptchaChoice = Object.freeze({\n /** Провайдера называет сервер. */\n Auto: 'auto',\n Itd: CaptchaType.Itd,\n Cloudflare: CaptchaType.Cloudflare,\n} as const);\nexport type CaptchaChoice = Loose<(typeof CaptchaChoice)[keyof typeof CaptchaChoice]>;\n\n/**\n * Насколько точно сервер определил, откуда просят вход по QR-коду. Тип открытый.\n *\n * Приходит в `QrLoginTarget.precision` рядом с координатами.\n */\nexport const QrLocationPrecision = Object.freeze({\n /** Координаты города. */\n City: 'city',\n /** Координаты страны. */\n Country: 'country',\n} as const);\nexport type QrLocationPrecision = Loose<\n (typeof QrLocationPrecision)[keyof typeof QrLocationPrecision]\n>;\n\n/**\n * Поле тела запроса, в котором сервер ждёт токен капчи. Тип открытый.\n *\n * При `CaptchaChoice.Auto` имя берётся из ответа сервера; эти значения — умолчания\n * для явно выбранного провайдера.\n */\nexport const CaptchaField = Object.freeze({\n /** Поле собственной капчи ИТД. */\n Itd: 'token',\n /** Поле Cloudflare Turnstile. */\n Cloudflare: 'turnstileToken',\n} as const);\nexport type CaptchaField = Loose<(typeof CaptchaField)[keyof typeof CaptchaField]>;\n\n/** Состояние соединения событийного канала. */\nexport const EventChannelStatus = Object.freeze({\n Connecting: 'connecting',\n Connected: 'connected',\n Error: 'error',\n Disconnected: 'disconnected',\n} as const);\nexport type EventChannelStatus = (typeof EventChannelStatus)[keyof typeof EventChannelStatus];\n\n/** Состояние сервиса платформы. Тип открытый. */\nexport const ServiceState = Object.freeze({\n /** Работает штатно. */\n Operational: 'operational',\n /** Работает с деградацией. */\n Degraded: 'degraded',\n /** Недоступен. */\n Downtime: 'downtime',\n} as const);\nexport type ServiceState = Loose<(typeof ServiceState)[keyof typeof ServiceState]>;\n\n/** Вид происшествия в истории сервиса. Тип открытый. */\nexport const IncidentKind = Object.freeze({\n /** Недоступен. */\n Down: 'down',\n /** Деградация. */\n Degraded: 'deg',\n} as const);\nexport type IncidentKind = Loose<(typeof IncidentKind)[keyof typeof IncidentKind]>;\n\n/**\n * Уровень доступа к разделу профиля.\n *\n * Общий набор значений для полей `wallAccess` и `likesVisibility` настроек приватности.\n * Тип открытый: сервер может прислать значение вне этого перечня.\n */\nexport const AccessType = Object.freeze({\n /** Никто. */\n Nobody: 'nobody',\n /** Только взаимные подписки. */\n Mutual: 'mutual',\n /** Подписчики. */\n Followers: 'followers',\n /** Все. */\n Everyone: 'everyone',\n} as const);\nexport type AccessType = Loose<(typeof AccessType)[keyof typeof AccessType]>;\n\n/** Кто может писать на стену профиля. Псевдоним {@link AccessType}. */\nexport const WallAccess = AccessType;\nexport type WallAccess = AccessType;\n\n/** Кто видит реакции пользователя. Псевдоним {@link AccessType}. */\nexport const LikesVisibility = AccessType;\nexport type LikesVisibility = AccessType;\n\n/**\n * Канонический тип уведомления (новое поколение имён).\n *\n * REST-эндпоинт `/api/notifications/` отдаёт старые имена (`like`, `comment`, `reply`,\n * `repost`, `mention`), SSE-поток — новые. Библиотека приводит их к этому набору,\n * сохраняя исходное значение в поле `rawType`.\n */\nexport const NotificationType = Object.freeze({\n /** Реакция на пост. Старое имя — `like`. */\n PostReaction: 'post_reaction',\n /** Комментарий к посту. Старое имя — `comment`. */\n PostComment: 'post_comment',\n /** Ответ на комментарий. Старое имя — `reply`. */\n CommentReply: 'comment_reply',\n /** Репост. Старое имя — `repost`. */\n PostRepost: 'post_repost',\n /** Упоминание в посте. Старое имя — `mention`. */\n PostMention: 'post_mention',\n /** Реакция на комментарий. */\n CommentReaction: 'comment_reaction',\n /** Упоминание в комментарии. */\n CommentMention: 'comment_mention',\n /** Запись на вашей стене. */\n WallPost: 'wall_post',\n /** На вас подписались. */\n Follow: 'follow',\n /** Заявка на подписку (закрытый профиль). */\n FollowRequest: 'follow_request',\n /** Заявка на подписку принята. */\n FollowAccepted: 'follow_accepted',\n /** Верификация одобрена. Приходит только по REST. */\n VerificationApproved: 'verification_approved',\n /** Верификация отклонена. Приходит только по REST. */\n VerificationRejected: 'verification_rejected',\n} as const);\nexport type NotificationType = Loose<(typeof NotificationType)[keyof typeof NotificationType]>;\n\n/**\n * Тип взаимодействия с контентом в телеметрии (`POST /api/v1/x`, поле `t`).\n *\n * Кодируется числом.\n */\nexport const InteractionType = Object.freeze({\n /** Открытие фотографии. */\n PhotoOpen: 1,\n /** Прогресс просмотра видео. Несёт поля `pm`/`dm`. */\n VideoProgress: 2,\n} as const);\nexport type InteractionType = (typeof InteractionType)[keyof typeof InteractionType];\n\n/**\n * Источник показа поста в телеметрии (поле `s`).\n *\n * Кодируется числом. Поле применимо к источникам `PostPage` и `Link`; для лент источник\n * передаётся контекстом `sc`.\n */\nexport const ViewSource = Object.freeze({\n FeedGlobal: 1,\n FeedFollowing: 2,\n FeedClan: 3,\n Profile: 4,\n Hashtag: 5,\n PostPage: 6,\n Link: 7,\n Search: 8,\n} as const);\nexport type ViewSource = (typeof ViewSource)[keyof typeof ViewSource];\n\n/**\n * Причина завершения просмотра поста в телеметрии (`POST /api/v1/i`, поле `r`).\n *\n * Кодируется числом.\n */\nexport const ViewReason = Object.freeze({\n /** Пост ушёл из зоны видимости при обычной прокрутке. */\n Normal: 0,\n /** Потеря фокуса окна. */\n Blur: 1,\n /** Вкладка скрыта. */\n Hidden: 2,\n /** Уход со страницы (`pagehide`). */\n PageHide: 3,\n /** Элемент перестал наблюдаться. */\n Unobserve: 4,\n /** Достигнут порог времени просмотра. */\n ThresholdMet: 5,\n} as const);\nexport type ViewReason = (typeof ViewReason)[keyof typeof ViewReason];\n\n/**\n * Строковые коды ошибок из поля `code`.\n *\n * Ключи намеренно повторяют написание сервера: код из ответа API можно найти здесь\n * поиском один в один, без мысленного перевода регистра.\n *\n * Список открыт — сервер может добавить новый код, и это не должно ломать типизацию.\n *\n * @example\n * ```ts\n * if (err.hasCode(ItdErrorCode.OTP_INVALID)) await restartOtpFlow();\n * ```\n */\nexport const ItdErrorCode = Object.freeze({\n BAD_REQUEST: 'BAD_REQUEST',\n UNAUTHORIZED: 'UNAUTHORIZED',\n ACCESS_DENIED: 'ACCESS_DENIED',\n ENTITY_NOT_FOUND: 'ENTITY_NOT_FOUND',\n ENTITY_ALREADY_EXISTS: 'ENTITY_ALREADY_EXISTS',\n VALIDATION_ERROR: 'VALIDATION_ERROR',\n BUSINESS_RULE_VIOLATION: 'BUSINESS_RULE_VIOLATION',\n RATE_LIMIT_EXCEEDED: 'RATE_LIMIT_EXCEEDED',\n UNKNOWN_ERROR: 'UNKNOWN_ERROR',\n /** Сервер отвечает так на `404`, `ENTITY_NOT_FOUND` в этом случае не приходит. */\n NOT_FOUND: 'NOT_FOUND',\n /** На практике не приходит: вместо него сервер шлёт `TURNSTILE_VERIFICATION_FAILED`. */\n CAPTCHA_FAILED: 'CAPTCHA_FAILED',\n /** Капча не пройдена: токен Turnstile недействителен, просрочен или уже использован. */\n TURNSTILE_VERIFICATION_FAILED: 'TURNSTILE_VERIFICATION_FAILED',\n /** Собственная captcha ИТД не подтвердила целостность проверки. */\n INTEGRITY_CHECK_FAILED: 'INTEGRITY_CHECK_FAILED',\n OTP_INVALID: 'OTP_INVALID',\n /** `flowToken` неизвестен или просрочен — поток подтверждения нужно начинать заново. */\n INVALID_FLOW_TOKEN: 'INVALID_FLOW_TOKEN',\n ACCOUNT_DEACTIVATED: 'ACCOUNT_DEACTIVATED',\n ACCOUNT_EMAIL_DOMAIN_NOT_ALLOWED: 'ACCOUNT_EMAIL_DOMAIN_NOT_ALLOWED',\n ACCOUNT_INVALID_CREDENTIALS: 'ACCOUNT_INVALID_CREDENTIALS',\n ACCOUNT_TEMPORARILY_LOCKED: 'ACCOUNT_TEMPORARILY_LOCKED',\n ACCOUNT_CURRENT_PASSWORD_INCORRECT: 'ACCOUNT_CURRENT_PASSWORD_INCORRECT',\n SESSION_EXPIRED: 'SESSION_EXPIRED',\n SESSION_REVOKED: 'SESSION_REVOKED',\n SESSION_INVALID_REFRESH_TOKEN: 'SESSION_INVALID_REFRESH_TOKEN',\n /** Запрос обновления пришёл без cookie `refresh_token` — продлевать нечего. */\n REFRESH_TOKEN_MISSING: 'REFRESH_TOKEN_MISSING',\n /** Cookie `refresh_token` есть, но сессии за ней уже нет: отозвана или истекла. */\n SESSION_NOT_FOUND: 'SESSION_NOT_FOUND',\n MISSING_FLOW_TOKEN: 'MISSING_FLOW_TOKEN',\n QR_EXPIRED: 'QR_EXPIRED',\n QR_TOKEN_MISMATCH: 'QR_TOKEN_MISMATCH',\n QR_ALREADY_USED: 'QR_ALREADY_USED',\n QR_NOT_SCANNED: 'QR_NOT_SCANNED',\n QR_APPROVER_NOT_ALLOWED: 'QR_APPROVER_NOT_ALLOWED',\n USER_INACTIVE: 'USER_INACTIVE',\n TOO_MANY_REQUESTS: 'TOO_MANY_REQUESTS',\n PROFILE_USERNAME_TAKEN: 'PROFILE_USERNAME_TAKEN',\n PROFILE_USERNAME_RESERVED: 'PROFILE_USERNAME_RESERVED',\n PROFILE_RESTRICTION_ACTIVE: 'PROFILE_RESTRICTION_ACTIVE',\n PROFILE_MODIFICATION_RESTRICTED: 'PROFILE_MODIFICATION_RESTRICTED',\n CONTENT_MODERATION_FAILED: 'CONTENT_MODERATION_FAILED',\n FILE_TOO_LARGE: 'FILE_TOO_LARGE',\n UNSUPPORTED_FILE_TYPE: 'UNSUPPORTED_FILE_TYPE',\n UPLOAD_FAILED: 'UPLOAD_FAILED',\n VIDEO_REQUIRES_VERIFICATION: 'VIDEO_REQUIRES_VERIFICATION',\n PHONE_VERIFICATION_REQUIRED: 'PHONE_VERIFICATION_REQUIRED',\n WRITE_ACCESS_RESTRICTED: 'WRITE_ACCESS_RESTRICTED',\n} as const);\nexport type ItdErrorCode = Loose<(typeof ItdErrorCode)[keyof typeof ItdErrorCode]>;\n","import { NotificationType } from '../types/enums.js';\n\n/**\n * Соответствие коротких имён типов уведомлений развёрнутым.\n *\n * Сервер — и в списке, и в потоке событий — присылает короткие имена: `like`, `comment`,\n * `reply`, `repost`, `comment_like`. Развёрнутые (`post_reaction`, `post_comment`)\n * встречаются в оформлении интерфейса, поэтому библиотека приводит типы к ним:\n * они однозначно называют и объект, и действие.\n *\n * Пришедшее значение всегда остаётся в поле `rawType`.\n */\nexport const NOTIFICATION_TYPE_ALIASES: Readonly<Record<string, NotificationType>> = Object.freeze({\n like: NotificationType.PostReaction,\n comment: NotificationType.PostComment,\n comment_like: NotificationType.CommentReaction,\n reply: NotificationType.CommentReply,\n repost: NotificationType.PostRepost,\n mention: NotificationType.PostMention,\n});\n\nconst KNOWN_TYPES = new Set<string>(Object.values(NotificationType));\n\n/**\n * Приводит имя типа к каноническому.\n *\n * Неизвестное значение возвращается без изменений, чтобы не менять смысл нового типа\n * уведомления на другой.\n *\n * @example\n * ```ts\n * canonicalNotificationType('like'); // 'post_reaction'\n * canonicalNotificationType('post_reaction'); // 'post_reaction'\n * canonicalNotificationType('новое_событие'); // 'новое_событие'\n * ```\n */\nexport function canonicalNotificationType(rawType: string): NotificationType {\n return NOTIFICATION_TYPE_ALIASES[rawType] ?? rawType;\n}\n\n/**\n * Известен ли библиотеке этот тип уведомления.\n *\n * Полезно, чтобы решить, показывать ли уведомление, для которого нет своего оформления.\n */\nexport function isKnownNotificationType(type: string): boolean {\n return KNOWN_TYPES.has(canonicalNotificationType(type));\n}\n","import { asString } from '../core/unwrap.js';\nimport { isRecord } from '../core/validate.js';\nimport type { Notification } from '../models/notifications.js';\nimport type { Actor } from '../models/users.js';\nimport { canonicalNotificationType } from './type-map.js';\n\n/** Событие потока уведомлений после разбора. */\nexport interface NotificationEvent {\n /** Само уведомление в единой форме. */\n notification: Notification;\n /**\n * Актуальное число непрочитанных, если сервер его сообщил.\n *\n * Клиент не увеличивает счётчик сам: значение приходит с сервера.\n */\n unreadCount: number | undefined;\n /** Нужно ли проиграть звук. */\n sound: boolean;\n}\n\nfunction asActor(value: unknown): Actor | undefined {\n if (!isRecord(value)) return undefined;\n const id = asString(value.id);\n if (!id) return undefined;\n\n return {\n id,\n username: asString(value.username) ?? '',\n displayName: asString(value.displayName) ?? '',\n avatar: asString(value.avatar) ?? '',\n ...(typeof value.isFollowing === 'boolean' ? { isFollowing: value.isFollowing } : {}),\n ...(typeof value.isFollowedBy === 'boolean' ? { isFollowedBy: value.isFollowedBy } : {}),\n };\n}\n\n/** Собирает участников: сервер присылает либо одного `actor`, либо массив `actors`. */\nfunction readActors(source: Record<string, unknown>): Actor[] {\n if (Array.isArray(source.actors)) {\n return source.actors.map(asActor).filter((actor): actor is Actor => actor !== undefined);\n }\n\n const single = asActor(source.actor);\n return single ? [single] : [];\n}\n\n/**\n * Приводит уведомление к единой форме.\n *\n * Нужна потому, что REST-список и поток событий описывают одно и то же событие по-разному:\n * различаются имена типов (`like` против `post_reaction`), имена полей\n * (`targetId`/`entityId`, `read`/`isRead`, `preview`/`entityPreview`) и число участников\n * (`actor` против массива `actors`). После приведения объекты из обоих источников\n * можно складывать в один список.\n *\n * Исходные данные не теряются: имя типа с сервера остаётся в `rawType`,\n * весь объект целиком — в `raw`.\n *\n * @param input уведомление из REST-ответа либо полезная нагрузка события потока\n *\n * @example\n * ```ts\n * const fromRest = normalizeNotification(restItem);\n * const fromStream = normalizeNotification(event.payload);\n * // одинаковая форма — можно объединять\n * ```\n */\nexport function normalizeNotification(input: unknown): Notification {\n const source = isRecord(input) ? input : {};\n\n // Поток кладёт полезную нагрузку то в payload, то прямо в корень события.\n const payload = isRecord(source.payload) ? source.payload : source;\n\n const rawType = asString(payload.type) ?? asString(source.type) ?? '';\n const createdAt = asString(payload.createdAt) ?? asString(source.createdAt) ?? '';\n const readAt = asString(payload.readAt) ?? asString(source.readAt);\n\n const isRead =\n typeof payload.isRead === 'boolean'\n ? payload.isRead\n : typeof payload.read === 'boolean'\n ? payload.read\n : Boolean(readAt);\n\n // Сервер описывает событие парой «цель — предмет», и смысл пары зависит от типа:\n //\n // комментарий, реакция на него — цель = пост, предмет = комментарий\n // репост — цель = сам репост, предмет = исходный пост\n // реакция на пост, подписка — предмета нет\n //\n // Событие относится к предмету, только когда тот является комментарием; иначе объект\n // события — цель. Без этого различия ссылка на репост вела бы на чужой исходный пост.\n const subjectId = asString(payload.subjectId);\n const targetId = asString(payload.targetId);\n const subjectIsComment = payload.subjectType === 'comment';\n const clickUrl = asString(payload.clickUrl);\n\n return {\n id: asString(payload.id) ?? asString(source.id) ?? '',\n type: canonicalNotificationType(rawType),\n rawType,\n entityId:\n asString(payload.entityId) ?? (subjectIsComment ? (subjectId ?? targetId) : targetId) ?? null,\n parentEntityId:\n asString(payload.parentEntityId) ?? (subjectIsComment ? (targetId ?? null) : null),\n isRead,\n actors: readActors(payload),\n count: typeof payload.count === 'number' && payload.count > 0 ? payload.count : 1,\n preview: asString(payload.entityPreview) ?? asString(payload.preview) ?? null,\n ...(clickUrl ? { clickUrl } : {}),\n createdAt,\n updatedAt: asString(payload.updatedAt) ?? readAt ?? createdAt,\n raw: input,\n };\n}\n\n/**\n * Разбирает событие `notification` из потока.\n *\n * Кроме самого уведомления событие несёт служебные поля уровня конверта: актуальный\n * счётчик непрочитанных и признак звука.\n */\nexport function readNotificationEvent(data: unknown): NotificationEvent {\n const source = isRecord(data) ? data : {};\n\n return {\n notification: normalizeNotification(data),\n unreadCount: typeof source.unreadCount === 'number' ? source.unreadCount : undefined,\n sound: source.sound === true,\n };\n}\n\n/**\n * Разбирает событие `unread_count` из потока.\n *\n * Возвращает `undefined`, если сервер прислал событие без вложенного `payload`.\n */\nexport function readUnreadCountEvent(data: unknown): number | undefined {\n if (!isRecord(data)) return undefined;\n\n const payload = isRecord(data.payload) ? data.payload : undefined;\n if (!payload) return undefined;\n\n return typeof payload.count === 'number' ? payload.count : undefined;\n}\n","import { voidResult } from '../core/operation.js';\nimport { type BuiltInOperationId, defineBuiltInOperation } from '../domain/operations.js';\n\n/** Контракт встроенной операции без дополнительного преобразования результата. */\nexport function passthroughOperation<T, TId extends BuiltInOperationId = BuiltInOperationId>(\n id: TId,\n) {\n return defineBuiltInOperation<T, TId>(id);\n}\n\n/** Контракт встроенной операции без возвращаемого значения. */\nexport function voidOperation<TId extends BuiltInOperationId>(id: TId) {\n return defineBuiltInOperation<void, TId>(id, voidResult);\n}\n","import type { UserId } from '../models/common.js';\nimport type { ResolvedRuntimeConfig } from './config.js';\nimport type { CookieJar } from './cookies.js';\nimport type { HttpClient } from './execution/http.js';\nimport { createDeviceId } from './runtime.js';\n\n/** Области аккаунта и конкретной сессии для локального состояния плагинов. */\nexport interface AuthIdentity {\n /** Идентификатор пользователя; отсутствует у непрозрачного или повреждённого токена. */\n userId?: UserId | undefined;\n /** Идентификатор серверной сессии; отсутствует у непрозрачного или повреждённого токена. */\n sessionId?: string | undefined;\n}\n\n/**\n * Что конвейер запросов спрашивает у авторизации.\n *\n * Узкий контракт вместо полноценного менеджера сессии: pipeline не должен знать ни про\n * refresh-токены, ни про хранилище, ни про вход по паролю. Благодаря этому клиент с готовым\n * токеном не тянет за собой сессионную машинерию — она подставляется вызывающим кодом.\n *\n * Каждый метод соответствует ровно одной стадии конвейера. Готовые реализации —\n * `bearerToken()`, `tokenProvider()` и `anonymousAuth()`.\n */\nexport interface AuthProvider {\n /**\n * Текущий токен доступа.\n *\n * Нужен там, где заголовок не поставить: SSE в браузере и WebSocket передают токен\n * параметром адреса. Конвейеру запросов достаточно {@link currentHeaders}.\n */\n token(): Promise<string | null>;\n /**\n * Один раз готовит авторизацию до retry исходного запроса.\n * Вложенные auth-операции используют собственную retry-политику.\n *\n * @param allowRefresh можно ли заранее обновить токен\n */\n preflight?(allowRefresh: boolean): Promise<void>;\n /** Перед каждой попыткой читает внешний источник токена до захвата слота очереди. */\n prepare?(): Promise<void>;\n /**\n * Заголовки уже подготовленной авторизации.\n *\n * Синхронность существенна: слой стоит внутри очереди, непосредственно перед транспортом,\n * и не должен запускать I/O. Зато запрос, отстоявший в очереди, получает самый свежий токен.\n */\n currentHeaders(): Record<string, string>;\n /**\n * Реакция на ответ `401`.\n *\n * @returns `true`, если токен обновлён и повторять попытку имеет смысл\n */\n recover(): Promise<boolean>;\n /** Значение заголовка `X-Device-Id`. Отправляется и с анонимными запросами. */\n deviceId(): Promise<string>;\n /** Снимает подписки при терминальном освобождении владельца. */\n dispose(): void;\n}\n\n/**\n * Что фабрика авторизации получает от собранного runtime.\n *\n * `http` — тот же исполнитель, которым пользуются ресурсы: вход и продление проходят\n * через общий конвейер с точечными skip-флагами, а не через второй, независимо\n * эволюционирующий путь.\n *\n * @internal\n */\nexport interface AuthProviderDeps {\n config: ResolvedRuntimeConfig;\n http: HttpClient;\n cookies: CookieJar;\n /** Вызывается синхронно перед сменой владельца авторизации. */\n onAccountChange?: (() => void) | undefined;\n}\n\n/**\n * Идентификатор устройства, общий для провайдеров без сессии.\n *\n * Значение своё у каждого провайдера: сервер различает по нему записи в списке сессий,\n * поэтому делить его между клиентами нельзя. Хранилища нет, так что перезапуск процесса\n * значение не переживает — в этом и разница с полноценной сессией.\n */\nfunction localDeviceId(): () => Promise<string> {\n let deviceId: string | undefined;\n\n return () => {\n deviceId ??= createDeviceId();\n return Promise.resolve(deviceId);\n };\n}\n\n/**\n * Авторизации нет: заголовок не подставляется, ответ `401` не восстанавливается.\n *\n * @example\n * ```ts\n * const api = createRestClient(); // публичные эндпоинты доступны и без токена\n * ```\n */\nexport function anonymousAuth(): AuthProvider {\n return {\n token: () => Promise.resolve(null),\n currentHeaders: () => ({}),\n recover: () => Promise.resolve(false),\n deviceId: localDeviceId(),\n dispose: () => {},\n };\n}\n\n/**\n * Готовый Bearer-токен: ни хранилища, ни продления.\n *\n * Ответ `401` уходит вызывающему коду как есть — обновить токен провайдеру нечем.\n * Для сессии, которая продлевает себя сама, нужен полный клиент.\n *\n * @example\n * ```ts\n * const api = createRestClient({ auth: bearerToken(process.env.ITD_TOKEN) });\n * ```\n */\nexport function bearerToken(accessToken: string): AuthProvider {\n const headers = { Authorization: `Bearer ${accessToken}` };\n\n return {\n token: () => Promise.resolve(accessToken),\n currentHeaders: () => headers,\n recover: () => Promise.resolve(false),\n deviceId: localDeviceId(),\n dispose: () => {},\n };\n}\n\n/**\n * Токен из внешнего источника — хранилища секретов, кэша, соседнего сервиса.\n *\n * Источник спрашивается на стадии подготовки, до входа в очередь: там ожидание безопасно,\n * а слот транспорта ещё не занят. Значение держится до следующей подготовки, потому что\n * подстановка заголовков обязана быть синхронной.\n *\n * @example\n * ```ts\n * const api = createRestClient({ auth: tokenProvider(() => vault.read('itd')) });\n * ```\n */\nexport function tokenProvider(\n getToken: () => string | null | Promise<string | null>,\n): AuthProvider {\n let cached: string | null = null;\n\n const read = async () => {\n cached = await getToken();\n return cached;\n };\n\n return {\n token: read,\n prepare: async () => {\n await read();\n },\n currentHeaders: () => (cached ? { Authorization: `Bearer ${cached}` } : {}),\n recover: () => Promise.resolve(false),\n deviceId: localDeviceId(),\n dispose: () => {\n cached = null;\n },\n };\n}\n","import type { Notification } from '../models/notifications.js';\nimport { NotificationType } from '../types/enums.js';\n\n/** Имя, которое подставляется, если участник неизвестен. */\nconst UNKNOWN_ACTOR = 'Пользователь';\n\n/** Текст, который подставляется для неизвестного типа уведомления. */\nconst FALLBACK_TEXT = 'Новое уведомление';\n\n/**\n * Шаблоны текстов уведомлений.\n *\n * Для каждого типа задано две формы: для одного участника и для схлопнутого уведомления,\n * где действие совершили несколько человек.\n */\nconst TEMPLATES: Readonly<\n Record<string, { one: (name: string) => string; many: (name: string, others: number) => string }>\n> = Object.freeze({\n [NotificationType.Follow]: {\n one: (name) => `${name} подписался(-ась) на вас`,\n many: (name, others) => `${name} и ещё ${others} подписались на вас`,\n },\n [NotificationType.FollowRequest]: {\n one: (name) => `${name} хочет подписаться на вас`,\n many: (name, others) => `${name} и ещё ${others} хотят подписаться на вас`,\n },\n [NotificationType.FollowAccepted]: {\n one: (name) => `${name} принял(а) вашу заявку`,\n many: (name, others) => `${name} и ещё ${others} приняли вашу заявку`,\n },\n [NotificationType.PostReaction]: {\n one: (name) => `${name} оценил(а) ваш пост`,\n many: (name, others) => `${name} и ещё ${others} оценили ваш пост`,\n },\n [NotificationType.PostComment]: {\n one: (name) => `${name} прокомментировал(а) ваш пост`,\n many: (name, others) => `${name} и ещё ${others} прокомментировали ваш пост`,\n },\n [NotificationType.PostRepost]: {\n one: (name) => `${name} сделал(а) репост`,\n many: (name, others) => `${name} и ещё ${others} сделали репост`,\n },\n [NotificationType.CommentReaction]: {\n one: (name) => `${name} оценил(а) ваш комментарий`,\n many: (name, others) => `${name} и ещё ${others} оценили ваш комментарий`,\n },\n [NotificationType.CommentReply]: {\n one: (name) => `${name} ответил(а) на ваш комментарий`,\n many: (name, others) => `${name} и ещё ${others} ответили на ваш комментарий`,\n },\n [NotificationType.PostMention]: {\n one: (name) => `${name} упомянул(а) вас в посте`,\n many: (name, others) => `${name} и ещё ${others} упомянули вас в посте`,\n },\n [NotificationType.CommentMention]: {\n one: (name) => `${name} упомянул(а) вас в комментарии`,\n many: (name, others) => `${name} и ещё ${others} упомянули вас в комментарии`,\n },\n [NotificationType.WallPost]: {\n one: (name) => `${name} написал(а) на вашей стене`,\n many: (name, others) => `${name} и ещё ${others} написали на вашей стене`,\n },\n [NotificationType.VerificationApproved]: {\n one: () => 'Ваша заявка на верификацию одобрена',\n many: () => 'Ваша заявка на верификацию одобрена',\n },\n [NotificationType.VerificationRejected]: {\n one: () => 'Ваша заявка на верификацию отклонена',\n many: () => 'Ваша заявка на верификацию отклонена',\n },\n});\n\n/**\n * Собирает текст уведомления на русском.\n *\n * Повторяет формулировки сайта итд.com. Для неизвестного типа возвращает\n * «Новое уведомление» — библиотека не выдумывает текст, которого нет.\n *\n * @example\n * ```ts\n * formatNotificationText(notification);\n * // 'Аня и ещё 2 оценили ваш пост'\n * ```\n */\nexport function formatNotificationText(notification: Notification): string {\n const template = TEMPLATES[notification.type];\n if (!template) return FALLBACK_TEXT;\n\n const first = notification.actors[0];\n const name = first?.displayName || first?.username || UNKNOWN_ACTOR;\n\n const others = notification.count - 1;\n return others > 0 ? template.many(name, others) : template.one(name);\n}\n","import type { Notification } from '../models/notifications.js';\nimport { NotificationType } from '../types/enums.js';\n\n/** Типы, ведущие на пост. */\nconst POST_TYPES = new Set<string>([\n NotificationType.PostReaction,\n NotificationType.PostRepost,\n NotificationType.PostMention,\n NotificationType.WallPost,\n]);\n\n/** Типы, ведущие на комментарий внутри поста. */\nconst COMMENT_TYPES = new Set<string>([\n NotificationType.PostComment,\n NotificationType.CommentReaction,\n NotificationType.CommentReply,\n NotificationType.CommentMention,\n]);\n\n/** Типы, ведущие на профиль. */\nconst FOLLOW_TYPES = new Set<string>([\n NotificationType.Follow,\n NotificationType.FollowRequest,\n NotificationType.FollowAccepted,\n]);\n\n/**\n * Вычисляет адрес, на который ведёт уведомление.\n *\n * Возвращает путь внутри сайта — без домена, чтобы его можно было передать роутеру\n * приложения. Поле `clickUrl` от сервера используется только как запасной вариант:\n * вычисленный путь точнее, поскольку учитывает родительский пост у комментариев.\n *\n * @example\n * ```ts\n * const url = resolveNotificationUrl(notification);\n * // '/@nowkie/post/9f1c…?comment=2b7e…'\n * ```\n */\nexport function resolveNotificationUrl(notification: Notification): string {\n const { type, entityId, parentEntityId, clickUrl } = notification;\n const username = notification.actors[0]?.username;\n\n if (username && entityId) {\n if (POST_TYPES.has(type)) return `/@${username}/post/${entityId}`;\n\n if (COMMENT_TYPES.has(type)) {\n return parentEntityId\n ? `/@${username}/post/${parentEntityId}?comment=${entityId}`\n : `/@${username}/post/${entityId}`;\n }\n }\n\n if (username && FOLLOW_TYPES.has(type)) return `/@${username}`;\n\n return clickUrl || '/notifications';\n}\n"],"mappings":"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"}