itd-api 0.9.1 → 0.9.3

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 (63) hide show
  1. package/dist/events/index.cjs +3 -4
  2. package/dist/events/index.d.cts +3 -3
  3. package/dist/events/index.d.ts +3 -3
  4. package/dist/events/index.js +4 -4
  5. package/dist/index.cjs +283 -90
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.cts +16 -72
  8. package/dist/index.d.ts +16 -72
  9. package/dist/index.js +284 -90
  10. package/dist/index.js.map +1 -1
  11. package/dist/node/index.cjs +3 -3
  12. package/dist/node/index.js +3 -3
  13. package/dist/rest/index.cjs +4 -5
  14. package/dist/rest/index.d.cts +3 -3
  15. package/dist/rest/index.d.ts +3 -3
  16. package/dist/rest/index.js +5 -5
  17. package/dist/shared/{events-BDdJyH2p.d.ts → events-BPxBF0gQ.d.cts} +3 -5
  18. package/dist/shared/{events-D6y0Hxyz.js → events-BzjI6pn5.js} +4 -4
  19. package/dist/shared/{events-D6y0Hxyz.js.map → events-BzjI6pn5.js.map} +1 -1
  20. package/dist/shared/{events-BqFkwwTw.cjs → events-C1FudmSe.cjs} +3 -9
  21. package/dist/shared/{events-BqFkwwTw.cjs.map → events-C1FudmSe.cjs.map} +1 -1
  22. package/dist/shared/{events-BQyH5-S0.d.cts → events-DnwfcLxS.d.ts} +3 -5
  23. package/dist/shared/{multi-storage-SoW05uzO.js → multi-storage-C3Ngtop1.js} +13 -8
  24. package/dist/shared/multi-storage-C3Ngtop1.js.map +1 -0
  25. package/dist/shared/{multi-storage-CDKLa956.cjs → multi-storage-s-fPtjoy.cjs} +13 -8
  26. package/dist/shared/multi-storage-s-fPtjoy.cjs.map +1 -0
  27. package/dist/shared/{options-DOJYtoti.cjs → options-DjEtbVaf.cjs} +2 -2
  28. package/dist/shared/{options-DOJYtoti.cjs.map → options-DjEtbVaf.cjs.map} +1 -1
  29. package/dist/shared/{options-DhgGg7Ms.js → options-i4LrKfqx.js} +2 -2
  30. package/dist/shared/{options-DhgGg7Ms.js.map → options-i4LrKfqx.js.map} +1 -1
  31. package/dist/shared/{redact-Ba5iSVYZ.js → redact-DJV0XM3n.js} +40 -15
  32. package/dist/shared/redact-DJV0XM3n.js.map +1 -0
  33. package/dist/shared/{redact-BP00URmQ.cjs → redact-lAmck1Z6.cjs} +45 -14
  34. package/dist/shared/redact-lAmck1Z6.cjs.map +1 -0
  35. package/dist/shared/{render-BU1_wex8.d.cts → render-C1F_QWYD.d.cts} +82 -19
  36. package/dist/shared/{render-sb1VJhUA.js → render-CtOpp9Pm.js} +127 -124
  37. package/dist/shared/render-CtOpp9Pm.js.map +1 -0
  38. package/dist/shared/{render-DAEeCMk9.cjs → render-Omy1drH1.cjs} +125 -128
  39. package/dist/shared/render-Omy1drH1.cjs.map +1 -0
  40. package/dist/shared/{render-CZ_-F2Tl.d.ts → render-uFW2kDxp.d.ts} +82 -19
  41. package/dist/shared/{storage-QNVxzpDB.cjs → storage-CZJZoaz9.cjs} +4 -2
  42. package/dist/shared/storage-CZJZoaz9.cjs.map +1 -0
  43. package/dist/shared/{storage-CfHKzVHf.js → storage-DiDe0PZM.js} +4 -2
  44. package/dist/shared/storage-DiDe0PZM.js.map +1 -0
  45. package/dist/shared/{url-Dsr4c5r5.js → url-3Ts6EEHQ.js} +301 -96
  46. package/dist/shared/url-3Ts6EEHQ.js.map +1 -0
  47. package/dist/shared/{url-CzHqE-Fg.cjs → url-D6wsXm1T.cjs} +301 -96
  48. package/dist/shared/url-D6wsXm1T.cjs.map +1 -0
  49. package/dist/shared/{url-CZZcyPI0.d.cts → url-DubjkRR9.d.cts} +10 -16
  50. package/dist/shared/{url-CZZcyPI0.d.ts → url-DubjkRR9.d.ts} +10 -16
  51. package/dist/web/index.cjs +1 -1
  52. package/dist/web/index.js +1 -1
  53. package/package.json +5 -5
  54. package/dist/shared/multi-storage-CDKLa956.cjs.map +0 -1
  55. package/dist/shared/multi-storage-SoW05uzO.js.map +0 -1
  56. package/dist/shared/redact-BP00URmQ.cjs.map +0 -1
  57. package/dist/shared/redact-Ba5iSVYZ.js.map +0 -1
  58. package/dist/shared/render-DAEeCMk9.cjs.map +0 -1
  59. package/dist/shared/render-sb1VJhUA.js.map +0 -1
  60. package/dist/shared/storage-CfHKzVHf.js.map +0 -1
  61. package/dist/shared/storage-QNVxzpDB.cjs.map +0 -1
  62. package/dist/shared/url-CzHqE-Fg.cjs.map +0 -1
  63. package/dist/shared/url-Dsr4c5r5.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-D6wsXm1T.cjs","names":["isRecord","ItdConfigError","isRecord","ItdConfigError","RuntimeMode","normalizeBaseUrl","resolveFetch","shouldUseCookieJar","shouldSendCredentials","scoped","ItdConfigError","ItdConfigError","#entries","#removing","#cleanups","#options","#ordered","ItdConfigError","#trackCleanup","#release","#waitForDrain","ItdStateError","ItdAbortError","#concurrency","#minGap","#clock","#buckets","#drain","#cancelWakeup","#active","#cursor","#nextSlot","#armWakeup","#cancelTimer","#wakeupAt","#destination","#bucket","#scheduler","#pacing","#smooth","#flatPause","#seedLimit","#waiting","#spend","#limit","#remaining","#hold","#capacity","#refill","#tokens","#armPause","#tokensAt","#options","#destinations","#featureBuckets","ItdConfigError","#services","#primaryHost","hostOf","ItdConfigError","normalizeBaseUrl","isSameSite","ItdAbortError","ItdTimeoutError","internal","#handler","#plugins","#baseUrl","#timeout","#clock","#lifetimeSignal","#hooks","#assertActive","#runWithLifecycle","#run","joinUrl","buildQuery","ItdConfigError","ItdAbortError","ItdApiError","ItdNetworkError","ItdTimeoutError","ItdFileError","ItdAbortError","normalizeBaseUrl","isItdApiError","isItdRateLimitError","ItdValidationError","ItdRateLimitError","ItdAuthError","ItdForbiddenError","ItdNotFoundError","ItdConflictError","ItdServerError","ItdApiErrorClass","redactBody","ItdPhoneVerificationError","ItdConfigError","isBlob","#config","#deps","#buildHeaders","#toTransportError","#prepareBody","ItdError","#dispatchErrorHook","redactHeaders","redactBody","#readBodyOrFail","joinUrl","buildQuery","ItdTimeoutError","ItdAbortError","ItdNetworkError","CookieJar","originOf","ItdAbortError","createDeviceId"],"sources":["../../src/core/async-dispose.ts","../../src/core/clock.ts","../../src/core/scheduling/pacing.ts","../../src/core/validate.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","import { ItdConfigError } from './errors.js';\n\n/**\n * Проверки, общие для резолверов конфигурации.\n *\n * Настройки исполнения и настройки сессии разбираются в разных модулях, но сообщать\n * об ошибке должны одинаково: пользователю всё равно, какой слой отверг его значение.\n */\n\n/** Похоже ли значение на объект настроек, а не на массив или `null`. */\nexport function isRecord(value: unknown): boolean {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** @throws {ItdConfigError} если значение задано и не является неотрицательным числом */\nexport function requirePositive(value: number, name: string): number {\n if (!Number.isFinite(value) || value < 0) {\n throw new ItdConfigError(`${name} должен быть неотрицательным числом, получено: ${value}`);\n }\n return value;\n}\n\n/** @throws {ItdConfigError} если значение задано и не является boolean */\nexport function requireOptionalBoolean(value: unknown, name: string): void {\n if (value !== undefined && typeof value !== 'boolean') {\n throw new ItdConfigError(`${name} должен быть boolean`);\n }\n}\n","// Этот файл создаётся автоматически: scripts/sync-version.mjs.\n// Менять вручную не нужно — значение берётся из package.json при `npm version` и сборке.\n\n/** Версия библиотеки. Попадает в `User-Agent`. */\nexport const LIBRARY_VERSION = '0.9.3';\n","import type { OperationCatalog } from './catalog.js';\nimport { type ItdClock, systemClock } from './clock.js';\nimport { ItdConfigError } from './errors.js';\nimport type {\n ClientHooks,\n Logger,\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 { isRecord, requireOptionalBoolean, requirePositive } 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 bucketOverrides: Readonly<Record<string, RateLimitBucketOverride>>;\n bucket: ((request: RateLimitBucketContext) => string | undefined) | undefined;\n /**\n * Ёмкость бакетов до первого ответа сервера. Приходит из каталога операций: сама\n * очередь ни одного имени счётчика не знает.\n */\n bucketLimits: Readonly<Record<string, number>>;\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 timeout: 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 (!isRecord(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 (!isRecord(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\nfunction resolveLogger(logger: RuntimeOptions['logger']): Logger | undefined {\n if (logger === undefined || logger === false) return undefined;\n if (logger === true) return consoleLogger();\n if (!isRecord(logger)) throw new ItdConfigError('logger должен быть boolean или объектом Logger');\n\n for (const method of ['debug', 'info', 'warn', 'error'] as const) {\n if (typeof logger[method] !== 'function') {\n throw new ItdConfigError(`logger.${method} должен быть функцией`);\n }\n }\n return logger;\n}\n\n/** Логгер поверх `console` — включается опцией `logger: true`. */\nfunction consoleLogger(): Logger {\n return {\n debug: (message, ...args) => console.debug(`[itd-api] ${message}`, ...args),\n info: (message, ...args) => console.info(`[itd-api] ${message}`, ...args),\n warn: (message, ...args) => console.warn(`[itd-api] ${message}`, ...args),\n error: (message, ...args) => console.error(`[itd-api] ${message}`, ...args),\n };\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 && !isRecord(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 = requirePositive(options.baseDelay ?? 500, 'retry.baseDelay');\n const maxDelay = requirePositive(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 (!isRecord(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 (!isRecord(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 && !isRecord(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 bucketLimits: catalog.bucketLimits,\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) requirePositive(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 bucketLimits: catalog.bucketLimits,\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 (!isRecord(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 (!isRecord(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 (!isRecord(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 = requirePositive(options.timeout ?? DEFAULT_TIMEOUT, 'timeout');\n const shutdownTimeout = requirePositive(\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 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[] {\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 request: OperationRequestOptions,\n context: AttemptContext,\n execute: () => Promise<Response>,\n): Promise<Response> {\n const chain = attemptInterceptorScope(request).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 validatePluginDefinition(plugin);\n if (this.#removing.has(plugin.name)) {\n throw new ItdConfigError(\n `плагин «${plugin.name}» ещё отключается; дождитесь завершения unuse() или dispose()`,\n );\n }\n 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 this.assertCanAdd(plugin);\n const ordered = orderPluginDefinitions([...this.#ordered.map((entry) => entry.plugin), 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 timingChanged(): void {\n this.#cancelWakeup();\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/**\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 /** Последнее, что сказал сервер. Живёт и в режиме `off` — ради `rateLimitState()`. */\n #limit: number | undefined;\n #remaining: number | undefined;\n #active = 0;\n #nextSlot = 0;\n readonly #waiting: BucketTask[] = [];\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 featureDefinition?: RateLimitBucketOverride,\n ) {\n this.#destination = destination;\n this.#bucket = bucket;\n this.#scheduler = scheduler;\n this.#clock = clock;\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 this.#seedLimit = options.buckets\n ? (featureDefinition?.limit ?? seedLimit(bucket, options))\n : undefined;\n this.#concurrency = options.buckets\n ? (featureDefinition?.concurrency ??\n options.bucketOverrides[bucket]?.concurrency ??\n options.bucketConcurrency)\n : options.concurrency;\n const rps = options.buckets\n ? (featureDefinition?.rps ?? options.bucketOverrides[bucket]?.rps)\n : 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 active(): number {\n return this.#active;\n }\n\n /** Запросов бакета ждёт своей очереди. */\n get pending(): number {\n return this.#waiting.length;\n }\n\n /** Есть ли ожидающая задача, для которой свободен локальный слот. */\n get canStart(): boolean {\n return this.#waiting.length > 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: BucketTask;\n const detach = () => signal?.removeEventListener('abort', onAbort);\n const onAbort = () => {\n const index = this.#waiting.indexOf(queued);\n if (index < 0) return;\n this.#waiting.splice(index, 1);\n queued.cancel(queueAbortError());\n this.#scheduler.timingChanged();\n };\n\n queued = {\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 this.#waiting.push(queued);\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.timingChanged();\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.length,\n };\n }\n\n /** Отклоняет ещё не начатые задачи этого бакета. */\n stop(): void {\n this.cancelWaiting(queueStoppedError());\n }\n\n /** Отклоняет ожидающие задачи; используется также при остановке всего направления. */\n cancelWaiting(reason: unknown, notify = true): void {\n const pending = this.#waiting.splice(0, this.#waiting.length);\n for (const task of pending) task.cancel(reason);\n if (notify) this.#scheduler.timingChanged();\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.timingChanged();\n }\n}\n\n/** Лимит бакета до первого ответа: поправка пользователя важнее табличного значения. */\nfunction seedLimit(bucket: string, options: ResolvedRateLimitOptions): number | undefined {\n const override = options.bucketOverrides[bucket]?.limit;\n if (override !== undefined) return override;\n return options.bucketLimits[bucket];\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 /** Динамические определения feature вместе с числом использующих их клиентов. */\n readonly #featureBuckets = new Map<\n string,\n { definition: Readonly<RateLimitBucketOverride>; references: number }\n >();\n constructor(options: ResolvedRateLimitOptions, clock: ItdClock = systemClock) {\n this.#options = options;\n this.#clock = clock;\n }\n\n /**\n * Регистрирует бакет подключаемого feature.\n *\n * Повтор той же декларации разрешён клиентам, разделяющим один pool через `ItdAccounts`.\n * Возвращённая функция откатывает регистрацию, пока очередь бакета ещё не создана.\n */\n defineBucket(name: string, definition: RateLimitBucketOverride): () => void {\n const normalized = Object.freeze({\n ...(definition.limit === undefined ? {} : { limit: definition.limit }),\n ...(definition.concurrency === undefined ? {} : { concurrency: definition.concurrency }),\n ...(definition.rps === undefined ? {} : { rps: definition.rps }),\n });\n const existing = this.#featureBuckets.get(name);\n if (existing) {\n if (\n existing.definition.limit !== normalized.limit ||\n existing.definition.concurrency !== normalized.concurrency ||\n existing.definition.rps !== normalized.rps\n ) {\n throw new ItdConfigError(\n `Бакет feature «${name}» уже зарегистрирован с другими ограничениями`,\n );\n }\n existing.references += 1;\n } else {\n this.#featureBuckets.set(name, { definition: normalized, references: 1 });\n }\n\n let released = false;\n return () => {\n if (released) return;\n released = true;\n const current = this.#featureBuckets.get(name);\n if (!current) return;\n current.references -= 1;\n if (current.references > 0) return;\n const hasQueue = [...this.#destinations.values()].some((entry) => entry.buckets.has(name));\n if (!hasQueue) this.#featureBuckets.delete(name);\n };\n }\n\n /** Очередь бакета на направлении. При `buckets: false` бакет всегда `default`. */\n for(destination: string | undefined, bucket?: string): BucketQueue {\n const fallback = this.#options.defaultBucket;\n const name = this.#options.buckets ? (bucket ?? fallback) : fallback;\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 this.#featureBuckets.get(name)?.definition,\n );\n entry.buckets.set(name, queue);\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 this.#featureBuckets.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, ItdTimeoutError } from '../errors.js';\n\nexport interface RequestAbortScope {\n signal: AbortSignal;\n timedOut(): boolean;\n cleanup(): void;\n}\n\n/** Объединяет отмену вызова, завершение клиента и общий таймаут логической операции. @internal */\nexport function createRequestAbortScope(\n signal: AbortSignal | undefined,\n lifetimeSignal: AbortSignal | undefined,\n timeout: number,\n clock: ItdClock,\n): RequestAbortScope {\n const controller = new AbortController();\n let timeoutReached = false;\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 const cancelTimer =\n timeout > 0\n ? clock.schedule(() => {\n timeoutReached = true;\n controller.abort();\n }, timeout)\n : undefined;\n\n return {\n signal: controller.signal,\n timedOut: () => timeoutReached,\n cleanup: () => {\n cancelTimer?.();\n for (const remove of detach) remove?.();\n },\n };\n}\n\n/** Прерывает только ожидание; исходный промис может корректно завершить общую фоновую работу. @internal */\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/** Возвращает публичную ошибку, соответствующую причине остановки операции. @internal */\nexport function requestAbortError(\n scope: RequestAbortScope,\n request: { timeout: number; method: string; path: string },\n fallback: unknown,\n): unknown {\n if (scope.timedOut()) {\n return new ItdTimeoutError({\n timeout: request.timeout,\n method: request.method.toUpperCase(),\n path: request.path,\n });\n }\n if (scope.signal.aborted && !(fallback instanceof ItdAbortError)) {\n return new ItdAbortError(`Запрос ${request.method.toUpperCase()} ${request.path} отменён`, {\n cause: scope.signal.reason,\n });\n }\n return fallback;\n}\n","import type { OperationId } from '../../domain/operations.js';\nimport type { CookieJar } from '../cookies.js';\nimport type { OperationRequestOptions } from '../options.js';\n\nconst REQUEST_ATTEMPT_STATE = Symbol('itd-api.request-attempt-state');\nconst REQUEST_QUEUE_KEY = Symbol('itd-api.request-queue-key');\nconst REQUEST_AUTH_RECOVERY_STATE = Symbol('itd-api.request-auth-recovery-state');\nconst REQUEST_ERROR_OBSERVATION_STATE = Symbol('itd-api.request-error-observation-state');\nconst DISPOSE_CLEANUP_REQUEST = Symbol('itd-api.dispose-cleanup-request');\n\ninterface RequestAttemptState {\n value: number;\n}\n\ninterface RequestAuthRecoveryState {\n recovered: boolean;\n preparationErrors: Set<unknown>;\n}\n\ninterface RequestErrorObservationState {\n errors: Set<unknown>;\n lifecycleAbortedDuringNotification: boolean;\n}\n\ntype InternalPipelineRequest = PipelineRequest & {\n [REQUEST_ATTEMPT_STATE]?: RequestAttemptState;\n [REQUEST_QUEUE_KEY]?: RequestQueueKey;\n [REQUEST_AUTH_RECOVERY_STATE]?: RequestAuthRecoveryState;\n [REQUEST_ERROR_OBSERVATION_STATE]?: RequestErrorObservationState;\n [DISPOSE_CLEANUP_REQUEST]?: true;\n};\n\n/** Возвращает общее для всех retry состояние восстановления авторизации. @internal */\nexport function requestAuthRecoveryState(request: PipelineRequest): RequestAuthRecoveryState {\n const internal = request as InternalPipelineRequest;\n const current = internal[REQUEST_AUTH_RECOVERY_STATE];\n if (current) return current;\n const state = { recovered: false, preparationErrors: new Set<unknown>() };\n internal[REQUEST_AUTH_RECOVERY_STATE] = state;\n return state;\n}\n\n/** Создаёт общую для копий логического запроса отметку вызова `onError`. @internal */\nexport function trackRequestErrorObservation(request: PipelineRequest): void {\n const internal = request as InternalPipelineRequest;\n internal[REQUEST_ERROR_OBSERVATION_STATE] ??= {\n errors: new Set(),\n lifecycleAbortedDuringNotification: false,\n };\n}\n\n/** Отмечает, что ошибка логического запроса уже была передана в `onError`. @internal */\nexport function markRequestErrorObserved(request: PipelineRequest, error: unknown): void {\n trackRequestErrorObservation(request);\n const state = (request as InternalPipelineRequest)[REQUEST_ERROR_OBSERVATION_STATE];\n state?.errors.add(error);\n}\n\n/** Была ли конкретная ошибка этой логической операции уже передана в `onError`. @internal */\nexport function wasRequestErrorObserved(request: PipelineRequest, error: unknown): boolean {\n return (\n (request as InternalPipelineRequest)[REQUEST_ERROR_OBSERVATION_STATE]?.errors.has(error) ??\n false\n );\n}\n\n/** Отмечает отмену lifecycle во время уже начатого локального `onError`. @internal */\nexport function markRequestErrorNotificationAborted(request: PipelineRequest): void {\n trackRequestErrorObservation(request);\n const state = (request as InternalPipelineRequest)[REQUEST_ERROR_OBSERVATION_STATE];\n if (state) state.lifecycleAbortedDuringNotification = true;\n}\n\n/** Нужно ли верхней границе не запускать тот же `onError` повторно после отмены. @internal */\nexport function wasRequestErrorNotificationAborted(request: PipelineRequest): boolean {\n return (\n (request as InternalPipelineRequest)[REQUEST_ERROR_OBSERVATION_STATE]\n ?.lifecycleAbortedDuringNotification ?? false\n );\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 * должны уметь дописать заголовки так, чтобы пользовательские `headers` всё равно остались\n * важнее. Смешивать их в одном объекте нельзя — тогда слой авторизации перебивал бы\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 trackRequestAttempts(request: PipelineRequest): PipelineRequest {\n const internal = request as InternalPipelineRequest;\n if (internal[REQUEST_ATTEMPT_STATE]) return request;\n return { ...request, [REQUEST_ATTEMPT_STATE]: { value: 0 } } as InternalPipelineRequest;\n}\n\n/** Начинает следующую фактическую транспортную попытку логической операции. @internal */\nexport function beginTransportAttempt(request: PipelineRequest): PipelineRequest {\n const tracked = trackRequestAttempts(request) as InternalPipelineRequest;\n const state = tracked[REQUEST_ATTEMPT_STATE];\n if (!state) throw new Error('request attempt state was not initialized');\n state.value += 1;\n return { ...tracked, attempt: state.value };\n}\n\n/** Возвращает номер последней начатой транспортной попытки. @internal */\nexport function currentTransportAttempt(request: PipelineRequest): number {\n return (request as InternalPipelineRequest)[REQUEST_ATTEMPT_STATE]?.value ?? 0;\n}\n\n/** Куда встаёт запрос: направление и бакет. @internal */\nexport interface RequestQueueKey {\n /** Origin разрешённого URL. `undefined` — направление неизвестно. */\n destination: string | undefined;\n bucket: string;\n}\n\n/**\n * Вычисляет ключ очереди один раз на логическую операцию.\n *\n * Ключ спрашивают трижды: при постановке в очередь, при чтении заголовков ответа и при\n * паузе после `429`. Значение пишется прямо в объект запроса — слои ниже копируют его\n * через spread, и перечислимое символьное поле переходит в копии.\n *\n * @internal\n */\nexport function requestQueueKey(\n request: PipelineRequest,\n compute: (request: PipelineRequest) => RequestQueueKey,\n): RequestQueueKey {\n const internal = request as InternalPipelineRequest;\n const cached = internal[REQUEST_QUEUE_KEY];\n if (cached) return cached;\n\n const key = compute(request);\n internal[REQUEST_QUEUE_KEY] = key;\n return key;\n}\n\n/** Помечает запрос как часть внутренней финализации уже начатого `dispose()`. @internal */\nexport function markDisposeCleanupRequest(request: PipelineRequestInput): PipelineRequestInput {\n return { ...request, [DISPOSE_CLEANUP_REQUEST]: true } as PipelineRequestInput;\n}\n\n/** Разрешено ли запросу завершать внутреннюю очистку после `dispose()`. @internal */\nexport function isDisposeCleanupRequest(request: PipelineRequest): boolean {\n return (request as InternalPipelineRequest)[DISPOSE_CLEANUP_REQUEST] === true;\n}\n\n/** Обработчик запроса. Самый внутренний в цепочке — транспорт. */\nexport type RequestHandler = (request: PipelineRequest) => Promise<unknown>;\n\n/**\n * Слой конвейера запросов.\n *\n * Получает запрос и продолжение цепочки. Может изменить запрос, обработать ошибку\n * продолжения или вовсе не вызывать `next`.\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 type { OperationContract } from '../operation.js';\nimport type { ClientHooks } from '../options.js';\nimport { dispatchRequestHook } from '../plugins/hooks.js';\nimport type { PluginRegistry } from '../plugins/registry.js';\nimport { buildQuery, joinUrl } from '../url.js';\nimport { createRequestAbortScope, requestAbortError, waitForRequest } from './lifecycle.js';\nimport {\n identifyRequest,\n markDisposeCleanupRequest,\n markRequestErrorObserved,\n type PipelineRequest,\n type PipelineRequestInput,\n type RequestHandler,\n trackRequestErrorObservation,\n wasRequestErrorNotificationAborted,\n wasRequestErrorObserved,\n} from './pipeline.js';\n\n/** Что нужно фасаду для работы. */\nexport interface HttpClientDeps {\n /** Готовый обработчик — вся цепочка слоёв поверх транспорта. */\n handler: RequestHandler;\n plugins: PluginRegistry;\n baseUrl: string;\n timeout: number;\n clock: ItdClock;\n lifetimeSignal?: AbortSignal | undefined;\n hooks: ClientHooks;\n assertActive?: (() => void) | undefined;\n}\n\n/** Параметры операции без ID и метода, заданных её контрактом. @internal */\nexport type HttpOperationOptions = Omit<PipelineRequest, 'operationId' | 'method'>;\n\n/**\n * Точка входа ресурсов в конвейер запросов.\n *\n * Принимает готовую цепочку обработки и предоставляет ресурсам методы `request`/`execute`.\n * О слоях и их порядке ресурсы не знают.\n */\nexport class HttpClient {\n readonly #handler: RequestHandler;\n readonly #plugins: PluginRegistry;\n readonly #baseUrl: string;\n readonly #timeout: number;\n readonly #clock: ItdClock;\n readonly #lifetimeSignal: AbortSignal | undefined;\n readonly #hooks: ClientHooks;\n readonly #assertActive: (() => void) | undefined;\n\n constructor(deps: HttpClientDeps) {\n this.#handler = deps.handler;\n this.#plugins = deps.plugins;\n this.#baseUrl = deps.baseUrl;\n this.#timeout = deps.timeout;\n this.#clock = deps.clock;\n this.#lifetimeSignal = deps.lifetimeSignal;\n this.#hooks = deps.hooks;\n this.#assertActive = deps.assertActive;\n }\n\n /** Базовый URL, к которому обращается клиент. */\n get baseUrl(): string {\n return this.#baseUrl;\n }\n\n /**\n * Выполняет запрос к API через собранный конвейер.\n *\n * @typeParam T ожидаемая форма ответа после снятия обёртки `{ data: … }`\n * @throws {ItdApiError} если сервер ответил статусом ≥ 400\n * @throws {ItdTimeoutError} если истёк таймаут\n * @throws {ItdAbortError} если запрос отменён через `signal`\n * @throws {ItdNetworkError} если запрос не дошёл до сервера\n */\n request<T = unknown>(options: PipelineRequestInput): Promise<T> {\n const request = identifyRequest(options);\n return this.#runWithLifecycle(request, (prepared) =>\n this.#handler(prepared as PipelineRequest),\n ) 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(operation, options);\n }\n\n #run<T, TId extends OperationId>(\n operation: OperationContract<T, TId>,\n options: HttpOperationOptions,\n ): Promise<T> {\n const request = identifyRequest({\n ...options,\n operationId: operation.id,\n method: operation.method,\n retrySafety: options.retrySafety ?? operation.retrySafety,\n });\n return this.#runWithLifecycle(request, async (prepared) =>\n operation.read(await this.#handler(prepared as PipelineRequest), prepared as PipelineRequest),\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 const request = identifyRequest({\n ...options,\n operationId: operation.id,\n method: operation.method,\n retrySafety: options.retrySafety ?? operation.retrySafety,\n });\n return this.#runWithLifecycle(\n request,\n async (prepared) => {\n const cleanupRequest = markDisposeCleanupRequest(prepared) as PipelineRequest;\n return operation.read(await this.#handler(cleanupRequest), prepared as PipelineRequest);\n },\n true,\n ) as Promise<T>;\n }\n\n async #runWithLifecycle(\n request: PipelineRequest,\n execute: (prepared: PipelineRequest) => Promise<unknown>,\n allowDisposed = false,\n ): Promise<unknown> {\n if (!allowDisposed) this.#assertActive?.();\n const timeout = request.timeout ?? this.#timeout;\n const scope = createRequestAbortScope(\n request.signal,\n this.#lifetimeSignal,\n timeout,\n this.#clock,\n );\n const startedAt = this.#clock.now();\n trackRequestErrorObservation(request);\n\n try {\n const pending = this.#plugins.run(\n request,\n (prepared) =>\n execute({ ...(prepared as PipelineRequest), signal: scope.signal, timeout: 0 }),\n scope.signal,\n );\n return await waitForRequest(Promise.resolve(pending), scope.signal);\n } catch (error) {\n const failure = requestAbortError(\n scope,\n { timeout, method: request.method, path: request.path },\n error,\n );\n const alreadyReported =\n wasRequestErrorObserved(request, error) ||\n (scope.signal.aborted && wasRequestErrorNotificationAborted(request));\n if (!alreadyReported) {\n markRequestErrorObserved(request, error);\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: scope.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: request.attempt ?? 1,\n duration: this.#clock.now() - startedAt,\n error: failure,\n });\n try {\n await waitForRequest(notification, scope.signal);\n } catch (hookError) {\n // После отмены/таймаута onError остаётся уведомлением и не должен удерживать\n // завершение операции. Его позднее отклонение уже поглощает waitForRequest.\n if (!scope.signal.aborted) throw hookError;\n }\n }\n throw failure;\n } finally {\n scope.cleanup();\n }\n }\n}\n","import { ItdConfigError } from './errors.js';\nimport type { OperationRequestOptions } from './options.js';\n\n/** HTTP-метод операции. */\nexport type OperationMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\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} 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.retrySafetyOf(request.operationId);\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 * `429` гарантирует, что операция не была обработана, поэтому допускает даже unsafe retry.\n * Обрыв сети, timeout и `5xx` такой гарантии не дают и требуют safe/idempotent операции.\n * Ошибка подготовки файла возникает до обращения к серверу и потому зависит только от\n * собственного признака retryable и повторяемости тела.\n */\nfunction isRetryable(error: unknown, policy: RetryPolicy): boolean {\n if (error instanceof ItdAbortError || !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 (error instanceof ItdAbortError || !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 { ItdAbortError, isItdApiError, isItdRateLimitError } from '../errors.js';\nimport type { ClientHooks, Logger, RequestOptions } from '../options.js';\nimport { dispatchRequestHook } from '../plugins/hooks.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 type PipelineRequest,\n type RequestHandler,\n type RequestMiddleware,\n requestAuthRecoveryState,\n trackRequestAttempts,\n withLayerHeaders,\n} from './pipeline.js';\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 * Должен стоять непосредственно вокруг одной транспортной попытки: тогда ожидание 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 * Стоит снаружи повторов и очереди: operation transformers видят запрос и ответ по одному\n * разу, иначе, например, текст поста зашифруется дважды. Здесь же к операции привязывается\n * snapshot attempt interceptors; сами они выполняются транспортом на каждой попытке.\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 async (request, next) => {\n if (!request.skipAuth) {\n const auth = getAuth();\n if (auth.preflight) {\n const pending = auth.preflight(request.skipAuthRefresh !== true);\n await (request.signal ? waitForRequest(pending, request.signal) : pending);\n }\n }\n return next(request);\n };\n}\n\n/**\n * Подготавливает auth state до входа транспортной попытки в очередь.\n *\n * Загрузка storage, внешний `getToken` и ленивый sign-in могут быть асинхронными; sign-in\n * сам входит в ту же queue. Поэтому эти действия обязаны завершиться до захвата её слота.\n */\nexport function createAuthPreparationMiddleware(\n auth: Pick<AuthProvider, 'prepare'>,\n): RequestMiddleware {\n return async (request, next) => {\n if (!request.skipAuth) {\n const pending = auth.prepare();\n try {\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 }\n return next(request);\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 const recovery = requestAuthRecoveryState(request);\n try {\n return await next(request);\n } catch (error) {\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 rateLimitDelays: readonly number[];\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` — экспоненциальным откатом. Настройка `retry`\n * у отдельного запроса имеет приоритет над глобальной.\n */\nexport function createRetryMiddleware(deps: RetryMiddlewareDeps): RequestMiddleware {\n const globalScheduler = deps.retry ? createRetryScheduler(deps.retry) : undefined;\n\n const nextDelay = (\n error: unknown,\n retryAttempt: number,\n rateLimitAttempt: number,\n request: PipelineRequest,\n policy: RetryPolicy,\n backoff: RetryScheduler | undefined,\n ): number | undefined => {\n if (isItdRateLimitError(error)) {\n if (!policy.bodyReplayable) return undefined;\n // Пауза, названную сервером, соблюдаем точно; иначе берём очередной шаг лестницы.\n const wait = error.retryAfter ?? deps.rateLimitDelays[rateLimitAttempt - 1];\n if (wait === undefined) return undefined;\n\n deps.pauseQueue?.(wait, request);\n deps.logger?.debug(`лимит частоты, повтор ${rateLimitAttempt} через ${wait} мс`);\n return wait;\n }\n\n return backoff?.(error, retryAttempt, policy);\n };\n\n return async (request, next) => {\n const trackedRequest = trackRequestAttempts(request);\n const method = request.method.toUpperCase();\n const policy = resolveRetryPolicy(request, deps.catalog);\n const backoff = resolveBackoff(request.retry, globalScheduler);\n let retryAttempt = 0;\n let rateLimitAttempt = 0;\n\n for (;;) {\n try {\n return await next(trackedRequest);\n } catch (error) {\n const transportAttempt = currentTransportAttempt(trackedRequest);\n const rateLimited = isItdRateLimitError(error);\n if (rateLimited) rateLimitAttempt += 1;\n else retryAttempt += 1;\n\n // Дальше идёт именно `trackedRequest`, а не исходный объект: он несёт запомненный\n // ключ очереди, и пауза попадает в тот же бакет, из которого запрос уходил.\n const delay = nextDelay(\n error,\n retryAttempt,\n rateLimitAttempt,\n trackedRequest,\n policy,\n backoff,\n );\n if (delay === undefined) throw error;\n\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 deps.logger?.debug(\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/**\n * Обычный объект — не `null`, не массив.\n *\n * Живёт здесь, а не в каждом разборщике ответа: одна и та же проверка нужна и фабрике\n * ошибок, и приведению уведомлений.\n */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\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 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, isRecord } from './unwrap.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 * Сводит ошибки по полям к единой форме `{ поле: [сообщения] }`.\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 return {\n code: 'UNKNOWN_ERROR',\n message: asString(body.trim()) ?? fallbackMessage,\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: never) => 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 // Сервер отвечает именно так: `{ error: { code: 'NOT_FOUND', message: 'Post not found' } }`.\n NOT_FOUND: ItdNotFoundError,\n ENTITY_ALREADY_EXISTS: ItdConflictError,\n};\n\n/** Соответствие HTTP-статуса классу — запасной вариант, когда код ничего не говорит. */\nfunction classByStatus(status: number): new (init: never) => 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 as never);\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} from '../errors.js';\nimport type { ClientHooks, Logger } from '../options.js';\nimport { 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 } from './lifecycle.js';\nimport {\n identifyRequest,\n markRequestErrorNotificationAborted,\n markRequestErrorObserved,\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 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 */\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 /** Сигнал времени жизни владельца: `dispose()` клиента отменяет начатые запросы. */\n lifetimeSignal: AbortSignal | undefined;\n}\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\n/** Ошибка отмены в формате `fetch`. */\nfunction createAbortError(): Error {\n const error = new Error('Операция прервана');\n error.name = 'AbortError';\n return error;\n}\n\n/** Прерывает ожидание промиса при срабатывании сигнала. */\nfunction abortable<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted) {\n // Результат больше не нужен, но позднее отклонение исходного промиса не должно стать\n // необработанным. Ошибку отмены возвращаем сразу: готовый промис не может её опередить.\n void promise.catch(() => {});\n return Promise.reject(createAbortError());\n }\n\n let onAbort: (() => void) | undefined;\n\n const interrupted = new Promise<never>((_resolve, reject) => {\n onAbort = () => reject(createAbortError());\n signal.addEventListener('abort', onAbort, { once: true });\n });\n\n return Promise.race([promise, interrupted]).finally(() => {\n if (onAbort) signal.removeEventListener('abort', onAbort);\n });\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 /** Базовый URL, к которому обращается транспорт. */\n get baseUrl(): string {\n return this.#config.baseUrl;\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 method = request.method.toUpperCase();\n const url = this.buildUrl(request);\n const attempt = request.attempt ?? 1;\n\n const timeout = request.timeout ?? this.#config.timeout;\n const abort = createRequestAbortScope(\n request.signal,\n this.#deps.lifetimeSignal,\n timeout,\n this.#config.clock,\n );\n const startedAt = this.#config.clock.now();\n let cleanupBody: (() => void | Promise<void>) | undefined;\n\n try {\n const headers = await abortable(this.#buildHeaders(request, url), abort.signal).catch(\n (error) => {\n throw this.#toTransportError(error, abort, request, method, timeout);\n },\n );\n let body: BodyInit | undefined;\n try {\n const prepared = await this.#prepareBody(request, headers, abort.signal, attempt);\n body = prepared.body;\n cleanupBody = prepared.cleanup;\n } catch (error) {\n const failure =\n abort.signal.aborted || error instanceof ItdError\n ? this.#toTransportError(error, abort, request, method, timeout)\n : new ItdConfigError(\n `Не удалось подготовить тело ${method} ${request.path}: ${error instanceof Error ? error.message : String(error)}`,\n { cause: error },\n );\n const context = {\n operationId: request.operationId,\n signal: abort.signal,\n method,\n path: request.path,\n url,\n headers,\n attempt,\n };\n await this.#dispatchErrorHook(\n request,\n {\n ...context,\n duration: this.#config.clock.now() - startedAt,\n error: failure,\n },\n abort,\n timeout,\n );\n throw failure;\n }\n\n const context = {\n operationId: request.operationId,\n signal: abort.signal,\n method,\n path: request.path,\n url,\n headers,\n attempt,\n };\n try {\n await abortable(\n dispatchRequestHook(this.#config.hooks, 'onRequest', context),\n abort.signal,\n );\n } catch (error) {\n const failure = abort.signal.aborted\n ? this.#toTransportError(error, abort, request, method, timeout)\n : error;\n await this.#dispatchErrorHook(\n request,\n {\n ...context,\n duration: this.#config.clock.now() - startedAt,\n error: failure,\n },\n abort,\n timeout,\n );\n throw failure;\n }\n\n this.#config.logger?.debug(`→ ${method} ${request.path}`, {\n headers: redactHeaders(headers),\n body: request.bodyFactory ? '[повторяемое тело]' : redactBody(request.body),\n });\n\n let response: Response;\n try {\n const init: RequestInit & { duplex?: 'half' } = {\n method,\n headers,\n signal: 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 response = await runAttemptInterceptors(\n request,\n { ...context, body, signal: abort.signal },\n async () => {\n try {\n return await this.#config.fetch(url, init);\n } catch (error) {\n throw this.#toTransportError(error, abort, request, method, timeout);\n }\n },\n );\n } catch (error) {\n const duration = this.#config.clock.now() - startedAt;\n\n await this.#dispatchErrorHook(request, { ...context, duration, error }, abort, timeout);\n this.#config.logger?.warn(\n `× ${method} ${request.path} (${duration} мс): ${error instanceof Error ? error.message : String(error)}`,\n );\n\n throw error;\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(response.url || url, response);\n }\n\n // Хук получает собственную ветвь тела: чтение ответа внутри хука не должно лишать\n // транспорт возможности разобрать основной ответ.\n if (response.ok && hasRequestHook(this.#config.hooks, 'onResponse')) {\n const hookResponse = response.clone();\n try {\n await abortable(\n dispatchRequestHook(this.#config.hooks, 'onResponse', {\n ...context,\n status: response.status,\n duration: this.#config.clock.now() - startedAt,\n response: hookResponse,\n }),\n abort.signal,\n );\n } catch (error) {\n void response.body?.cancel().catch(() => {});\n const failure = abort.signal.aborted\n ? this.#toTransportError(error, abort, request, method, timeout)\n : error;\n await this.#dispatchErrorHook(\n request,\n {\n ...context,\n duration: this.#config.clock.now() - startedAt,\n error: failure,\n },\n abort,\n timeout,\n );\n throw failure;\n } finally {\n if (!hookResponse.bodyUsed) void hookResponse.body?.cancel().catch(() => {});\n }\n }\n\n const payload = await this.#readBodyOrFail(\n response,\n context,\n request,\n method,\n abort,\n timeout,\n startedAt,\n );\n const duration = this.#config.clock.now() - startedAt;\n\n if (!response.ok) {\n const error = createApiError({\n 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\n await this.#dispatchErrorHook(request, { ...context, duration, error }, abort, timeout);\n this.#config.logger?.warn(\n `← ${response.status} ${method} ${request.path} (${duration} мс): ${error.message}`,\n );\n\n throw error;\n }\n\n this.#config.logger?.debug(`← ${response.status} ${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(`не удалось закрыть тело ${method} ${request.path}`, error);\n } finally {\n abort.cleanup();\n }\n }\n };\n\n async #dispatchErrorHook(\n request: PipelineRequest,\n context: Parameters<NonNullable<ClientHooks['onError']>>[0],\n abort: RequestAbortScope,\n timeout: number,\n ): Promise<void> {\n markRequestErrorObserved(request, context.error);\n const onAbort = () => markRequestErrorNotificationAborted(request);\n if (abort.signal.aborted) onAbort();\n else abort.signal.addEventListener('abort', onAbort, { once: true });\n try {\n await abortable(dispatchRequestHook(this.#config.hooks, 'onError', context), abort.signal);\n } catch (error) {\n const failure = abort.signal.aborted\n ? this.#toTransportError(error, abort, request, context.method, timeout)\n : error;\n // Верхняя граница не должна повторно сообщать ошибку, выброшенную самим onError.\n markRequestErrorObserved(request, failure);\n throw failure;\n } finally {\n abort.signal.removeEventListener('abort', onAbort);\n }\n }\n\n /** Подготавливает тело внутри попытки, чтобы поток можно было открыть заново при retry. */\n async #prepareBody(\n request: PipelineRequest,\n headers: Headers,\n signal: AbortSignal,\n attempt: number,\n ): Promise<{ body: BodyInit | undefined; cleanup: (() => void | Promise<void>) | undefined }> {\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 }));\n let prepared: PreparedRequestBody;\n try {\n prepared = await abortable(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 `не удалось закрыть отложенное тело ${request.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 /** Читает тело и преобразует ошибку чтения в транспортную ошибку библиотеки. */\n async #readBodyOrFail(\n response: Response,\n context: {\n operationId: PipelineRequest['operationId'];\n signal: AbortSignal;\n method: string;\n path: string;\n url: string;\n headers: Headers;\n attempt: number;\n },\n request: PipelineRequest,\n method: string,\n abort: RequestAbortScope,\n timeout: number,\n startedAt: number,\n ): Promise<unknown> {\n try {\n return await abortable(readBody(response), abort.signal);\n } catch (error) {\n await response.body?.cancel().catch(() => {});\n\n const failure = this.#toTransportError(error, abort, request, method, timeout);\n\n await this.#dispatchErrorHook(\n request,\n {\n ...context,\n duration: this.#config.clock.now() - startedAt,\n error: failure,\n },\n abort,\n timeout,\n );\n this.#config.logger?.warn(\n `× ${method} ${request.path}: не удалось прочитать тело ответа — ${failure.message}`,\n );\n\n throw failure;\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 /**\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 /** Превращает исключение `fetch` в понятную ошибку библиотеки. */\n #toTransportError(\n error: unknown,\n abort: RequestAbortScope,\n request: PipelineRequest,\n method: string,\n timeout: number,\n ): ItdError {\n // Пользовательская отмена с собственным `reason` реджектит `fetch` этим значением, а не\n // `AbortError`, — поэтому опираемся на состояние сигнала, а не только на имя ошибки.\n const aborted = abort.signal.aborted || (error instanceof Error && error.name === 'AbortError');\n\n if (aborted && abort.timedOut()) {\n return new ItdTimeoutError({ timeout, method, path: request.path });\n }\n\n if (aborted) {\n // Причину задаёт `abort(reason)` пользователя либо освобождение клиента.\n const reason = abort.signal.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}: ${error instanceof Error ? error.message : String(error)}`,\n { method, path: request.path, cause: error },\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 { RateLimitBucketOverride, 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 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 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 /** Регистрирует ограничения бакета подключаемого модуля. @internal */\n registerRateLimitBucket(\n name: string,\n definition: RateLimitBucketOverride,\n ): (() => void) | undefined;\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 // Транспорт объединяет этот сигнал с сигналом запроса: 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 const queueKeyFor = (request: PipelineRequest) =>\n requestQueueKey(request, (target) => ({\n destination: originOf(transport.buildUrl(target)) || undefined,\n bucket: bucketFor(target),\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);\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(\n { ...config, hooks: config.hooks },\n {\n // Заголовки читаются и при `pacing: 'off'`: на темп они там не влияют, но остаются\n // единственным источником для rateLimitState().\n onRateLimit: queues ? observeRateLimit : undefined,\n cookies: config.useCookieJar ? jar : undefined,\n getDeviceId: () => auth.deviceId(),\n lifetimeSignal: lifetime.signal,\n },\n );\n\n const stages: 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({\n prepare: () => auth.prepare(),\n }),\n },\n ];\n\n if (queues) {\n stages.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 stages.push({\n name: ClientRuntimeStage.Attempt,\n middleware: createAttemptMiddleware(),\n });\n\n stages.push({\n name: ClientRuntimeStage.AuthHeaders,\n middleware: createAuthHeadersMiddleware({ currentHeaders: () => auth.currentHeaders() }),\n });\n\n const handler = composePipeline(\n stages.map(({ middleware }) => middleware),\n transport.send,\n );\n const clientHandler: 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 handler(request);\n };\n\n const http = new HttpClient({\n handler: clientHandler,\n plugins,\n baseUrl: config.baseUrl,\n timeout: config.timeout,\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 ClientRuntimeStage.OperationPlugins,\n ...stages.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 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 registerRateLimitBucket: (name, definition) => queues?.defineBucket(name, definition),\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 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.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\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 {\n BUCKET_LIMITS,\n DEFAULT_BUCKET_OVERRIDES,\n DEFAULT_RATE_LIMIT_BUCKET,\n isKnownBucket,\n} from './buckets.js';\nimport {\n isBuiltInOperationId,\n OPERATIONS,\n operationBucket,\n operationMethod,\n operationRetrySafety,\n} from './operations.js';\n\n/**\n * Каталог операций итд.com, которым пользуется ядро.\n *\n * Единственное место, где generic request executor встречается с таблицами конкретного API.\n * Собирается из уже существующих функций каталога: собственной логики здесь нет.\n *\n * @internal\n */\nexport const ITD_CATALOG: OperationCatalog = Object.freeze({\n definitionOf: (id) => (isBuiltInOperationId(id) ? OPERATIONS[id] : undefined),\n retrySafetyOf: (id) => (isBuiltInOperationId(id) ? operationRetrySafety(id) : undefined),\n methodOf: (id) => (isBuiltInOperationId(id) ? operationMethod(id) : undefined),\n // Неизвестный ID каталог сам сводит к бакету по умолчанию.\n bucketOf: (id) => operationBucket(id as Parameters<typeof operationBucket>[0]),\n isKnownBucket,\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/** Состояние соединения событийного канала. */\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 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 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, isRecord } from '../core/unwrap.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 prepare: () => Promise.resolve(),\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 prepare: () => Promise.resolve(),\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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"}