itd-api 0.10.2 → 0.10.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.
- package/dist/events/index.cjs +2 -2
- package/dist/events/index.d.cts +2 -2
- package/dist/events/index.d.ts +2 -2
- package/dist/events/index.js +2 -2
- package/dist/index.cjs +19 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +19 -8
- package/dist/index.js.map +1 -1
- package/dist/rest/index.cjs +2 -2
- package/dist/rest/index.d.cts +2 -2
- package/dist/rest/index.d.ts +2 -2
- package/dist/rest/index.js +2 -2
- package/dist/shared/{events-8OLqvKwQ.cjs → events-BVfqWyBw.cjs} +2 -2
- package/dist/shared/{events-8OLqvKwQ.cjs.map → events-BVfqWyBw.cjs.map} +1 -1
- package/dist/shared/{events-DXooQkyB.d.ts → events-Cp7ITueA.d.ts} +2 -2
- package/dist/shared/{events-0I_Pixnq.js → events-Cwj7UPAa.js} +2 -2
- package/dist/shared/{events-0I_Pixnq.js.map → events-Cwj7UPAa.js.map} +1 -1
- package/dist/shared/{events-Cr1Mc2Gl.d.cts → events-D0Wtt-If.d.cts} +2 -2
- package/dist/shared/{render-GQw5m1-o.js → render-BT74nC1l.js} +2 -2
- package/dist/shared/{render-GQw5m1-o.js.map → render-BT74nC1l.js.map} +1 -1
- package/dist/shared/{render-BxPM234w.d.cts → render-CJO_L2CD.d.cts} +2 -2
- package/dist/shared/{render-CnpKoGO8.cjs → render-CYJSDypQ.cjs} +2 -2
- package/dist/shared/{render-CnpKoGO8.cjs.map → render-CYJSDypQ.cjs.map} +1 -1
- package/dist/shared/{render-D69bOsxu.d.ts → render-DRmuHoEy.d.ts} +2 -2
- package/dist/shared/{url-Qv7smwHP.d.cts → url-BLnX-LYt.d.cts} +2 -2
- package/dist/shared/{url-Qv7smwHP.d.ts → url-BLnX-LYt.d.ts} +2 -2
- package/dist/shared/{url-BnaioEsz.cjs → url-BnO1aWsd.cjs} +2 -2
- package/dist/shared/{url-BnaioEsz.cjs.map → url-BnO1aWsd.cjs.map} +1 -1
- package/dist/shared/{url-D0KJ5pws.js → url-DS0-lrl-.js} +2 -2
- package/dist/shared/{url-D0KJ5pws.js.map → url-DS0-lrl-.js.map} +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["NotificationsResource","#createEvents","#events","CaptchaType","CaptchaField","pickString","ItdConfigError","passthroughOperation","defineBuiltInOperation","voidOperation","pickArray","ItdConfigError","isRecord","CaptchaChoice","ItdConfigError","MemoryTokenStorage","isRecord","copySession","isSerializedCookieEntry","#config","#http","#jar","#emitter","#hooks","Emitter","reportListenerError","#assertActive","#disposed","#externalReadGeneration","#invalidateInFlight","#tokenMetadata","#authScope","#loadSession","#identityForToken","#readExternalToken","#session","#sessionFromConfig","#externalIdentity","#authEpoch","CookieJar","ItdStateError","#metadataForToken","#externalToken","#rotateAuthScope","#hasRefreshSession","#signInWithCredentials","#refreshDeduplicated","#deviceId","#deviceIdLoading","#resolveDeviceId","createDeviceId","#saveSession","#noRefreshSessionError","ItdAuthError","#storeAccessToken","#transitionAuth","#seedRefreshCookie","#enqueuePersistence","#loading","#performLoad","REFRESH_COOKIE","REFRESH_COOKIE_PATH","#persistence","#refreshing","#performRefresh","#matchesRefreshExpectation","#currentAccessToken","#reloginOrNull","#signingIn","#performSignIn","#takeConfiguredCaptcha","#resolveCaptchaProvider","#configCaptchaSpent","isRecord","createParser","joinUrl","createRequestAbortScope","ItdNetworkError","requestAbortError","createApiError","BaseResource","#auth","#connection","#qrFlows","#pruneQrFlows","isItdApiError","#touchQrFlow","#qrFlow","#forgetTerminalQrError","ItdConfigError","ItdStateError","#runtime","#features","#resources","#auth","resolveNotificationEventsOptions","ExtensibleOperationCatalog","ITD_CATALOG","createClientRuntime","createFeatureHost","createStatusFeature","createResources","NotificationEvents","EVENT_OPERATIONS","ItdConfigError","#close","#disposePromise","#dispose","ItdConfigError","ItdStateError","#base","#storage","#clients","#removing","#accountRemovals","#storageControls","#eventUnsubscribers","#plugins","#features","#removingPlugins","#queues","#rateLimitScope","#emitter","#logger","MemoryMultiTokenStorage","orderPluginDefinitions","resolveRateLimit","ITD_CATALOG","RequestQueuePool","systemClock","Emitter","reportListenerError","controlledTokenStorage","#mergeOptions","#reportCleanup","#forwardEvents","isRestorableSession","#disposePromise","#dispose"],"sources":["../src/notifications-api.ts","../src/operations/auth.ts","../src/session/captcha.ts","../src/session/jwt.ts","../src/session/auth.ts","../src/session/qr-stream.ts","../src/resources/auth.ts","../src/client.ts","../src/accounts.ts"],"sourcesContent":["import type { HttpClient } from './core/execution/http.js';\nimport type { NotificationEvents } from './events/stream.js';\nimport { NotificationsResource } from './resources/notifications.js';\n\n/** Уведомления полного клиента: REST-методы и стабильный канал событий. */\nexport interface NotificationsApi extends NotificationsResource {\n /** Один канал событий уведомлений на всё время жизни клиента. */\n readonly events: NotificationEvents;\n}\n\nclass ClientNotifications extends NotificationsResource implements NotificationsApi {\n readonly #createEvents: (resource: NotificationsResource) => NotificationEvents;\n #events: NotificationEvents | undefined;\n\n constructor(\n http: HttpClient,\n createEvents: (resource: NotificationsResource) => NotificationEvents,\n ) {\n super(http);\n this.#createEvents = createEvents;\n }\n\n get events(): NotificationEvents {\n this.#events ??= this.#createEvents(this);\n return this.#events;\n }\n}\n\n/** Создаёт API уведомлений полного клиента. @internal */\nexport function createNotificationsApi(\n http: HttpClient,\n createEvents: (resource: NotificationsResource) => NotificationEvents,\n): NotificationsApi {\n return new ClientNotifications(http, createEvents);\n}\n","import { ItdConfigError } from '../core/errors.js';\nimport { pickArray, pickString } from '../core/unwrap.js';\nimport { defineBuiltInOperation } from '../domain/operations.js';\nimport type { QrLoginTarget, Session } from '../models/account.js';\nimport type { AuthState } from '../models/users.js';\nimport { CaptchaField, CaptchaType } from '../types/enums.js';\nimport { passthroughOperation, voidOperation } from './common.js';\n\n/** Чем закончился запрос входа. */\nexport const SignInStatus = Object.freeze({\n Authenticated: 'authenticated',\n OtpRequired: 'otp_required',\n} as const);\nexport type SignInStatus = (typeof SignInStatus)[keyof typeof SignInStatus];\n\n/** Результат входа: готовый токен либо продолжение через код подтверждения. */\nexport type SignInResult =\n | { status: 'authenticated'; accessToken: string }\n | { status: 'otp_required'; flowToken: string | undefined };\n\n/**\n * Активный провайдер капчи и поле запроса, в котором сервер ждёт токен.\n *\n * Оба значения открытые: провайдер может появиться новый, а имя поля сервер вправе сменить.\n */\nexport interface CaptchaProvider {\n provider: CaptchaType;\n field: CaptchaField;\n}\n\n/**\n * Активный провайдер капчи вместе с адресом готовой страницы виджета.\n *\n * Страница собрана на домене итд.com, поэтому ключ виджета на ней действителен: её открывают\n * во встроенном браузере и забирают токен оттуда.\n */\nexport interface CaptchaPage extends CaptchaProvider {\n url: string;\n}\n\n/**\n * Доказательство прохождения капчи: токен и его провайдер.\n *\n * Имя поля тела запроса SDK подставляет сам — из {@link CaptchaToken.field}, иначе\n * из {@link CAPTCHA_FIELDS}.\n */\nexport interface CaptchaToken {\n type: CaptchaType;\n token: string;\n /** Поле тела запроса. Нужно, только если сервер переименовал его. */\n field?: CaptchaField | undefined;\n}\n\n/**\n * Поле тела запроса по умолчанию для известных провайдеров.\n *\n * Используется, когда провайдера не спрашивали. Ответ `captchaProvider()` важнее этой таблицы.\n */\nexport const CAPTCHA_FIELDS = Object.freeze({\n [CaptchaType.Itd]: CaptchaField.Itd,\n [CaptchaType.Cloudflare]: CaptchaField.Cloudflare,\n} as const);\n\n/** Данные, из которых клиент строит QR-код входа. */\nexport interface QrLoginStart {\n qrId: string;\n claimToken: string;\n payload: string;\n expiresIn: number;\n captchaRequired: boolean;\n}\n\n/** Состояния, которые может вернуть проверка QR-входа. */\nexport const QrLoginStatus = Object.freeze({\n Pending: 'pending',\n Scanned: 'scanned',\n CaptchaRequired: 'captcha_required',\n Authorized: 'authorized',\n Rejected: 'rejected',\n} as const);\nexport type QrLoginStatus = (typeof QrLoginStatus)[keyof typeof QrLoginStatus];\n\n/** Результат проверки QR-входа. */\nexport type QrLoginClaim =\n | { status: 'authorized'; accessToken: string; expiresIn?: number }\n | {\n status: 'pending' | 'scanned' | 'captcha_required' | 'rejected';\n expiresIn?: number;\n };\n\n/** Состояния, приходящие из потокового наблюдения за QR-входом. */\nexport const QrLoginStreamStatus = Object.freeze({\n Pending: 'pending',\n Scanned: 'scanned',\n Approved: 'approved',\n Rejected: 'rejected',\n} as const);\nexport type QrLoginStreamStatus = (typeof QrLoginStreamStatus)[keyof typeof QrLoginStreamStatus];\n\n/** Одно событие `POST /api/v1/auth/qr/stream`. */\nexport interface QrLoginStreamEvent {\n status: QrLoginStreamStatus;\n expiresIn?: number;\n}\n\nfunction requireString(body: unknown, key: string, message: string): string {\n const value = pickString(body, key);\n if (!value) throw new ItdConfigError(message);\n return value;\n}\n\nexport const AUTH_CHECK = passthroughOperation<AuthState>('auth.check');\nexport const AUTH_CAPTCHA_PROVIDER = passthroughOperation<CaptchaProvider>('auth.captchaProvider');\nexport const AUTH_CAPTCHA_PAGE = passthroughOperation<CaptchaPage>('auth.captchaPage');\nexport const AUTH_SIGN_UP = defineBuiltInOperation<string>('auth.signUp', (body) =>\n requireString(body, 'flowToken', 'Сервер не вернул flowToken при регистрации'),\n);\nexport const AUTH_SIGN_IN = defineBuiltInOperation<SignInResult>('auth.signIn', (body) => {\n const accessToken = pickString(body, 'accessToken');\n return accessToken\n ? { status: SignInStatus.Authenticated, accessToken }\n : { status: SignInStatus.OtpRequired, flowToken: pickString(body, 'flowToken') };\n});\nexport const AUTH_VERIFY_OTP = defineBuiltInOperation<string>('auth.verifyOtp', (body) =>\n requireString(body, 'accessToken', 'Сервер не вернул accessToken после подтверждения кода'),\n);\nexport const AUTH_REFRESH = defineBuiltInOperation<string>('auth.refresh', (body) =>\n requireString(body, 'accessToken', 'Сервер не вернул accessToken при обновлении сессии'),\n);\nexport const AUTH_RESEND_OTP = voidOperation('auth.resendOtp');\nexport const AUTH_LOGOUT = voidOperation('auth.logout');\nexport const AUTH_FORGOT_PASSWORD = defineBuiltInOperation<string>('auth.forgotPassword', (body) =>\n requireString(body, 'flowToken', 'Сервер не вернул flowToken при запросе сброса пароля'),\n);\nexport const AUTH_RESET_PASSWORD = voidOperation('auth.resetPassword');\nexport const AUTH_CHANGE_PASSWORD = voidOperation('auth.changePassword');\nexport const AUTH_SESSIONS = defineBuiltInOperation<Session[]>('auth.sessions', (body) =>\n pickArray<Session>(body, 'sessions'),\n);\nexport const AUTH_REVOKE_SESSION = voidOperation('auth.revokeSession');\nexport const AUTH_REVOKE_OTHER_SESSIONS = voidOperation('auth.revokeOtherSessions');\nexport const AUTH_QR_START = passthroughOperation<QrLoginStart>('auth.qrStart');\nexport const AUTH_QR_CLAIM = passthroughOperation<QrLoginClaim>('auth.qrClaim');\nexport const AUTH_QR_SCAN = passthroughOperation<QrLoginTarget>('auth.qrScan');\nexport const AUTH_QR_APPROVE = voidOperation('auth.qrApprove');\nexport const AUTH_QR_REJECT = voidOperation('auth.qrReject');\n","import { ItdConfigError } from '../core/errors.js';\nimport { isRecord } from '../core/validate.js';\nimport { CAPTCHA_FIELDS, type CaptchaProvider, type CaptchaToken } from '../operations/auth.js';\nimport { CaptchaChoice, type CaptchaField, type CaptchaType } from '../types/enums.js';\nimport type { CaptchaSolver } from './options.js';\n\n/** Капча запросов, которые её требуют: входа, регистрации, сброса пароля и QR-подтверждения. */\n\n/** Готовый фрагмент тела запроса: имя поля и токен в нём. */\nexport type CaptchaBody = Record<string, string>;\n\nfunction requireCaptchaText(value: unknown, field: string): void {\n if (value !== undefined && (typeof value !== 'string' || value.trim() === '')) {\n throw new ItdConfigError(`${field} должен быть непустой строкой`);\n }\n}\n\n/**\n * Проверяет форму источника токена и приводит его к объекту.\n *\n * Сам объект сохраняется как есть: `getToken` вызывается на нём, чтобы источнику остался\n * доступен собственный `this`.\n *\n * @throws {ItdConfigError} при некорректных значениях\n */\nexport function resolveCaptchaSolver(captcha: unknown): CaptchaSolver | undefined {\n if (captcha === undefined) return undefined;\n\n if (typeof captcha === 'function') {\n return { getToken: captcha as CaptchaSolver['getToken'] };\n }\n\n if (!isRecord(captcha)) {\n throw new ItdConfigError('captcha должен быть функцией либо объектом с getToken');\n }\n\n const { getToken, type, field } = captcha as Record<string, unknown>;\n\n if (typeof getToken !== 'function') {\n throw new ItdConfigError('captcha.getToken должен быть функцией');\n }\n requireCaptchaText(type, 'captcha.type');\n requireCaptchaText(field, 'captcha.field');\n\n return captcha as unknown as CaptchaSolver;\n}\n\n/**\n * Проверяет форму готового токена капчи.\n *\n * @param path имя опции или аргумента для текста ошибки\n * @throws {ItdConfigError} если токен или его тип не указаны\n */\nexport function validateCaptchaToken(captcha: unknown, path: string): void {\n if (captcha === undefined) return;\n if (!isRecord(captcha)) {\n throw new ItdConfigError(`${path} должен быть объектом { type, token }`);\n }\n\n const { type, token, field } = captcha as Record<string, unknown>;\n\n if (typeof token !== 'string' || token.trim() === '') {\n throw new ItdConfigError(`${path}.token должен быть непустой строкой`);\n }\n if (typeof type !== 'string' || type.trim() === '') {\n throw new ItdConfigError(`${path}.type должен быть непустой строкой`);\n }\n requireCaptchaText(field, `${path}.field`);\n}\n\n/** Разбирает ответ `GET /api/v1/auth/captcha/provider` для автоматического входа. */\nexport function readCaptchaProvider(body: unknown): CaptchaProvider {\n const config = isRecord(body) ? (body as Record<string, unknown>) : undefined;\n const provider = config?.provider;\n const field = config?.field;\n\n if (\n typeof provider !== 'string' ||\n provider.trim() === '' ||\n typeof field !== 'string' ||\n field.trim() === ''\n ) {\n throw new ItdConfigError('Сервер вернул неподдерживаемую конфигурацию капчи');\n }\n\n return { provider, field };\n}\n\n/** Куда класть токен: настройка, иначе умолчание провайдера. */\nfunction resolveField(type: CaptchaType, configured: CaptchaField | undefined): CaptchaField {\n const field = configured ?? CAPTCHA_FIELDS[type as keyof typeof CAPTCHA_FIELDS];\n if (field) return field;\n\n throw new ItdConfigError(\n `Неизвестно, в каком поле сервер ждёт токен капчи «${type}». Передайте captcha.field ` +\n `либо оставьте captcha.type = ${CaptchaChoice.Auto}, чтобы поле назвал сервер.`,\n );\n}\n\n/** Спрашивает токен у источника и убеждается, что он непустой. */\nasync function requireSolvedToken(solver: CaptchaSolver, type: CaptchaType): Promise<string> {\n const token = await solver.getToken(type);\n if (typeof token === 'string' && token.trim() !== '') return token;\n\n throw new ItdConfigError(\n `Источник капчи не вернул токен для провайдера «${type}». Проверьте captcha.getToken.`,\n );\n}\n\n/**\n * Готовит фрагмент тела запроса, взяв токен у источника.\n *\n * При `CaptchaChoice.Auto` провайдер спрашивается у сервера — тогда и тип виджета,\n * и имя поля приходят оттуда. Явно названный тип обходится без этого запроса.\n *\n * @param askProvider как спросить активного провайдера; вызывается, только если это нужно\n * @throws {ItdConfigError} если токен получить не удалось\n */\nexport async function solveCaptchaBody(\n solver: CaptchaSolver,\n askProvider: () => Promise<CaptchaProvider>,\n): Promise<CaptchaBody> {\n const choice = solver.type ?? CaptchaChoice.Auto;\n\n if (choice === CaptchaChoice.Auto) {\n const { provider, field } = await askProvider();\n return { [field]: await requireSolvedToken(solver, provider) };\n }\n\n return { [resolveField(choice, solver.field)]: await requireSolvedToken(solver, choice) };\n}\n\n/**\n * Готовит фрагмент тела из готового токена.\n *\n * Поле берётся из самого токена либо из умолчания провайдера; запроса к серверу нет.\n *\n * @throws {ItdConfigError} если токен или его тип не указаны\n */\nexport function captchaBody(captcha: CaptchaToken): CaptchaBody {\n validateCaptchaToken(captcha, 'captcha');\n\n return { [resolveField(captcha.type, captcha.field)]: captcha.token };\n}\n","/**\n * Разбирает строку base64url.\n *\n * `atob` понимает только обычный base64, поэтому алфавит приводится к нему, а недостающее\n * выравнивание добивается. Результат декодируется как UTF-8: в полезной нагрузке токена\n * может оказаться кириллица, и «бинарная» строка из `atob` сломала бы `JSON.parse`.\n */\nfunction decodeBase64Url(segment: string): string {\n const base64 = segment.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), '=');\n\n const binary = atob(padded);\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n\n return new TextDecoder().decode(bytes);\n}\n\n/** Читает полезную нагрузку JWT без проверки подписи. */\nfunction readTokenPayload(token: string): Record<string, unknown> | undefined {\n try {\n const payload = token.split('.')[1];\n if (!payload) return undefined;\n\n const parsed: unknown = JSON.parse(decodeBase64Url(payload));\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return undefined;\n return parsed as Record<string, unknown>;\n } catch {\n // Непрозрачный или повреждённый токен допустим: его свойства просто неизвестны.\n return undefined;\n }\n}\n\n/** Идентификаторы владельца и сессии, прочитанные из JWT без проверки подписи. */\nexport interface TokenIdentity {\n subject?: string | undefined;\n sessionId?: string | undefined;\n}\n\n/** Локально используемые поля JWT. */\nexport interface TokenMetadata extends TokenIdentity {\n expiresAt?: number | undefined;\n}\n\n/** Читает используемые клиентом поля JWT за один раз. */\nexport function readTokenMetadata(token: string): TokenMetadata {\n const payload = readTokenPayload(token);\n if (!payload) return {};\n\n const { sub, sid, exp } = payload;\n const expiresAt = typeof exp === 'number' && Number.isFinite(exp) ? exp * 1000 : undefined;\n return {\n ...(typeof sub === 'string' && sub.length > 0 ? { subject: sub } : {}),\n ...(typeof sid === 'string' && sid.length > 0 ? { sessionId: sid } : {}),\n ...(expiresAt !== undefined && Number.isFinite(expiresAt) ? { expiresAt } : {}),\n };\n}\n\n/**\n * Читает `sub` и `sid` из полезной нагрузки JWT.\n *\n * Подпись не проверяется — ключа для проверки у клиента нет. Прочитанные значения служат\n * лишь метками для разделения локального состояния и не дают доступа: его определяет сервер.\n */\nexport function readTokenIdentity(token: string): TokenIdentity {\n const { subject, sessionId } = readTokenMetadata(token);\n return { ...(subject ? { subject } : {}), ...(sessionId ? { sessionId } : {}) };\n}\n\n/**\n * Читает срок действия JWT из claim `exp`.\n *\n * JWT хранит NumericDate в секундах, а остальное ядро использует миллисекунды. Подпись\n * намеренно не проверяется: значение служит только подсказкой для раннего refresh, а\n * окончательное решение о действительности токена всё равно принимает сервер.\n *\n * @returns момент истечения в миллисекундах либо `undefined` для непрозрачного,\n * повреждённого JWT или некорректного `exp`\n */\nexport function readTokenExpiration(token: string): number | undefined {\n return readTokenMetadata(token).expiresAt;\n}\n\n/**\n * Читает `sub` из полезной нагрузки JWT.\n *\n * @returns идентификатор владельца токена; `undefined`, если токен не JWT, повреждён\n * или поля `sub` в нём нет\n */\nexport function readTokenSubject(token: string): string | undefined {\n return readTokenIdentity(token).subject;\n}\n","import type { AuthIdentity, AuthProvider, AuthProviderDeps } from '../core/auth-provider.js';\nimport type { ItdClock } from '../core/clock.js';\nimport {\n AUTH_FLAG_COOKIE,\n CookieJar,\n isSerializedCookieEntry,\n REFRESH_COOKIE,\n REFRESH_COOKIE_PATH,\n} from '../core/cookies.js';\nimport { Emitter, reportListenerError } from '../core/emitter.js';\nimport { ItdAuthError, ItdConfigError, ItdStateError } from '../core/errors.js';\nimport type { HttpClient } from '../core/execution/http.js';\nimport type { Logger } from '../core/options.js';\nimport { createDeviceId } from '../core/runtime.js';\nimport { isRecord, requireOptionalBoolean } from '../core/validate.js';\nimport type { UserId } from '../models/common.js';\nimport {\n AUTH_CAPTCHA_PROVIDER,\n AUTH_REFRESH,\n AUTH_SIGN_IN,\n type CaptchaProvider,\n type CaptchaToken,\n SignInStatus,\n} from '../operations/auth.js';\nimport {\n type CaptchaBody,\n captchaBody,\n readCaptchaProvider,\n resolveCaptchaSolver,\n solveCaptchaBody,\n validateCaptchaToken,\n} from './captcha.js';\nimport { readTokenMetadata, type TokenMetadata } from './jwt.js';\nimport type { AuthInput, CaptchaSolver, CredentialsAuth, SessionOptions } from './options.js';\nimport { copySession, type ItdSession, MemoryTokenStorage, type TokenStorage } from './storage.js';\n\n/** Запас до истечения токена на очередь и выполнение запроса. */\nconst ACCESS_TOKEN_REFRESH_LEEWAY_MS = 30_000;\n\n/**\n * Настройки сессии после подстановки умолчаний и проверок.\n *\n * Часть полей заимствована у {@link ResolvedRuntimeConfig}: сессия ходит на тот же хост,\n * теми же часами и с тем же логгером, но остальные настройки исполнения ей не нужны.\n */\nexport interface SessionConfig {\n baseUrl: string;\n clock: ItdClock;\n useCookieJar: boolean;\n logger: Logger | undefined;\n auth: AuthInput | undefined;\n captcha: CaptchaSolver | undefined;\n storage: TokenStorage;\n deviceId: string | undefined;\n autoRefresh: boolean;\n reloginOnRefreshFailure: boolean;\n}\n\n/**\n * Проверяет форму `auth` и сообщает о типичных ошибках понятным текстом.\n *\n * Молчаливое игнорирование неверной формы приводит к загадочным `401`, поэтому\n * ошибка возникает сразу при создании клиента.\n */\nfunction validateAuth(auth: AuthInput | undefined): AuthInput | undefined {\n if (auth === undefined) return undefined;\n\n if (typeof auth === 'string') {\n if (auth.trim() === '') {\n throw new ItdConfigError('auth: передана пустая строка вместо accessToken');\n }\n return auth;\n }\n\n if (typeof auth !== 'object' || auth === null) {\n throw new ItdConfigError(\n `auth должен быть строкой с токеном или объектом, получено: ${typeof auth}`,\n );\n }\n\n const modes = [\n 'getToken' in auth,\n 'accessToken' in auth || 'refreshToken' in auth,\n 'email' in auth || 'password' in auth,\n ].filter(Boolean).length;\n if (modes > 1) {\n throw new ItdConfigError(\n 'auth должен описывать ровно один способ авторизации: getToken, accessToken или email/password',\n );\n }\n\n if ('getToken' in auth) {\n if (typeof auth.getToken !== 'function') {\n throw new ItdConfigError('auth.getToken должен быть функцией');\n }\n return { ...auth };\n }\n\n if ('accessToken' in auth) {\n if (typeof auth.accessToken !== 'string' || auth.accessToken.trim() === '') {\n throw new ItdConfigError('auth.accessToken должен быть непустой строкой');\n }\n if (\n auth.refreshToken !== undefined &&\n (typeof auth.refreshToken !== 'string' || auth.refreshToken.trim() === '')\n ) {\n throw new ItdConfigError('auth.refreshToken должен быть непустой строкой');\n }\n return { ...auth };\n }\n\n if ('email' in auth || 'password' in auth) {\n const { email, password, captcha } = auth as {\n email?: unknown;\n password?: unknown;\n captcha?: unknown;\n };\n if (typeof email !== 'string' || email.trim() === '') {\n throw new ItdConfigError('auth.email должен быть непустой строкой');\n }\n if (typeof password !== 'string' || password === '') {\n throw new ItdConfigError('auth.password должен быть непустой строкой');\n }\n\n validateCaptchaToken(captcha, 'auth.captcha');\n\n return { ...auth };\n }\n\n throw new ItdConfigError(\n 'auth не распознан. Ожидается строка с accessToken либо объект ' +\n '{ accessToken }, { email, password } или { getToken }',\n );\n}\n\nfunction resolveStorage(storage: TokenStorage | undefined): TokenStorage {\n if (storage === undefined) return new MemoryTokenStorage();\n if (!isRecord(storage)) throw new ItdConfigError('storage должен быть объектом TokenStorage');\n\n for (const method of ['get', 'set', 'clear'] as const) {\n if (typeof storage[method] !== 'function') {\n throw new ItdConfigError(`storage.${method} должен быть функцией`);\n }\n }\n return storage;\n}\n\n/**\n * Приводит настройки сессии к полному виду.\n *\n * @param runtime уже разрешённая конфигурация исполнения — из неё берутся общие поля\n * @throws {ItdConfigError} при некорректных значениях\n */\nexport function resolveSessionConfig(\n options: SessionOptions,\n runtime: Pick<SessionConfig, 'baseUrl' | 'clock' | 'useCookieJar' | 'logger'>,\n): SessionConfig {\n if (!isRecord(options)) throw new ItdConfigError('опции клиента должны быть объектом');\n\n requireOptionalBoolean(options.autoRefresh, 'autoRefresh');\n requireOptionalBoolean(options.reloginOnRefreshFailure, 'reloginOnRefreshFailure');\n\n if (\n options.deviceId !== undefined &&\n (typeof options.deviceId !== 'string' || options.deviceId.trim() === '')\n ) {\n throw new ItdConfigError('deviceId должен быть непустой строкой');\n }\n\n return {\n ...runtime,\n auth: validateAuth(options.auth),\n captcha: resolveCaptchaSolver(options.captcha),\n storage: resolveStorage(options.storage),\n deviceId: options.deviceId,\n autoRefresh: options.autoRefresh ?? true,\n reloginOnRefreshFailure: options.reloginOnRefreshFailure ?? true,\n };\n}\n\n/**\n * Собирает менеджер сессии итд.com как реализацию {@link AuthProvider}.\n *\n * Единственная точка, где конвейер запросов встречается с полноценной авторизацией.\n * Ядро её не вызывает — фабрику передаёт фасад клиента, иначе ссылка на сессию оказалась бы\n * достижимой из любой сборки, включая анонимную.\n */\nexport function createItdAuth(options: SessionOptions, deps: AuthProviderDeps): AuthManager {\n return new AuthManager(resolveSessionConfig(options, deps.config), deps.http, deps.cookies, {\n onAccountChange: deps.onAccountChange,\n });\n}\n\n/** Пути эндпоинтов авторизации. */\nexport const AUTH_PATHS = {\n captchaProvider: '/api/v1/auth/captcha/provider',\n captchaPage: '/api/v1/auth/captcha/page',\n signUp: '/api/v1/auth/sign-up',\n signIn: '/api/v1/auth/sign-in',\n verifyOtp: '/api/v1/auth/verify-otp',\n resendOtp: '/api/v1/auth/resend-otp',\n refresh: '/api/v1/auth/refresh',\n logout: '/api/v1/auth/logout',\n forgotPassword: '/api/v1/auth/forgot-password',\n resetPassword: '/api/v1/auth/reset-password',\n changePassword: '/api/v1/auth/change-password',\n sessions: '/api/v1/auth/sessions',\n qrStart: '/api/v1/auth/qr/start',\n qrClaim: '/api/v1/auth/qr/claim',\n qrStream: '/api/v1/auth/qr/stream',\n qrScan: '/api/v1/auth/qr/scan',\n qrApprove: '/api/v1/auth/qr/approve',\n qrReject: '/api/v1/auth/qr/reject',\n} as const;\n\n/**\n * Публичный ключ Cloudflare Turnstile платформы итд.com.\n *\n * Нужен, чтобы отрисовать виджет капчи и получить токен для `signIn`, `signUp`\n * и `forgotPassword`.\n *\n * Ключ привязан к домену: на чужом origin Cloudflare отказывает виджету с кодом `110200`.\n * Поэтому отрисовать его может только код, выполняемый на самом итд.com. Остальным\n * подходит `@itd-api/captcha`, готовый токен из другого источника или вовсе вход\n * без капчи — по сохранённой сессии либо по токенам, взятым в браузере.\n *\n * @example\n * ```ts\n * turnstile.render('#captcha', {\n * sitekey: TURNSTILE_SITE_KEY,\n * callback: (token) =>\n * itd.auth.signIn({ email, password, captcha: { type: CaptchaType.Cloudflare, token } }),\n * });\n * ```\n */\nexport const TURNSTILE_SITE_KEY = '0x4AAAAAACHhxczw6fJGwPBg';\n\n/** События слоя авторизации. */\nexport interface AuthEvents {\n /** Токен получен или обновлён. */\n tokens: { accessToken: string };\n /** Выполнен вход. */\n signIn: { accessToken: string };\n /** Сессия очищена — вручную или из-за неудачного обновления. */\n signOut: undefined;\n /** Обновить сессию не удалось; дальнейшие запросы будут падать с 401. */\n authError: { error: unknown };\n}\n\n/** Убирает поле, которое сохраняли промежуточные версии с поддержкой `getUserId()`. */\nfunction withoutLegacyUserId(session: ItdSession): ItdSession {\n const clean = copySession(session);\n delete (clean as ItdSession & { userId?: unknown }).userId;\n return clean;\n}\n\nfunction normalizeSessionValue(\n value: unknown,\n source: string,\n mode: 'strict' | 'stored' = 'strict',\n logger?: Logger,\n): ItdSession | null {\n const tolerant = mode === 'stored';\n if (!isRecord(value)) {\n if (tolerant) {\n logger?.warn(`${source} вернула не объект сессии; сохранённая запись пропущена`);\n return null;\n }\n throw new ItdConfigError(`${source} должна быть объектом сессии`);\n }\n const record = value as Record<string, unknown>;\n // Неизвестные поля могут принадлежать более новой версии библиотеки. Сохраняем их,\n // а известные поля проверяем и исправляем ниже.\n const normalized: Record<string, unknown> = { ...record };\n delete normalized.userId;\n\n const normalizeString = (field: 'accessToken' | 'refreshToken' | 'deviceId'): void => {\n const item = record[field];\n if (item === undefined) {\n delete normalized[field];\n return;\n }\n if (item !== undefined && (typeof item !== 'string' || item.trim() === '')) {\n if (tolerant) {\n logger?.warn(`${source}.${field} повреждена; поле сохранённой сессии пропущено`);\n delete normalized[field];\n return;\n }\n throw new ItdConfigError(`${source}.${field} должна быть непустой строкой`);\n }\n normalized[field] = item;\n };\n\n normalizeString('accessToken');\n normalizeString('refreshToken');\n normalizeString('deviceId');\n\n if (record.obtainedAt === undefined) {\n delete normalized.obtainedAt;\n } else if (typeof record.obtainedAt !== 'number' || !Number.isFinite(record.obtainedAt)) {\n if (!tolerant) {\n throw new ItdConfigError(`${source}.obtainedAt должна быть конечным числом`);\n } else {\n logger?.warn(`${source}.obtainedAt повреждена; поле сохранённой сессии пропущено`);\n delete normalized.obtainedAt;\n }\n }\n\n if (record.cookies === undefined) {\n delete normalized.cookies;\n } else {\n if (!Array.isArray(record.cookies)) {\n if (tolerant) {\n logger?.warn(`${source}.cookies повреждена; поле сохранённой сессии пропущено`);\n delete normalized.cookies;\n } else {\n throw new ItdConfigError(`${source}.cookies должна быть массивом`);\n }\n } else {\n // Одна повреждённая или устаревшая запись не должна блокировать рабочие токены.\n // CookieJar.deserialize придерживается той же мягкой политики.\n const valid = record.cookies.filter(\n (cookie: unknown): cookie is string =>\n typeof cookie === 'string' && isSerializedCookieEntry(cookie),\n );\n if (valid.length > 0) normalized.cookies = valid;\n else delete normalized.cookies;\n }\n }\n\n return normalized as ItdSession;\n}\n\nfunction normalizeSession(value: unknown, source: string): ItdSession {\n const normalized = normalizeSessionValue(value, source);\n if (!normalized) throw new ItdConfigError(`${source} должна быть объектом сессии`);\n return normalized;\n}\n\nlet authScopeSequence = 0;\n\nfunction nextAuthScope(): string {\n authScopeSequence += 1;\n return String(authScopeSequence);\n}\n\ninterface AuthManagerHooks {\n /** Вызывается синхронно перед заменой владельца авторизации. */\n onAccountChange?: (() => void) | undefined;\n}\n\ninterface RefreshExpectation {\n epoch: number;\n accessToken?: string | undefined;\n}\n\ninterface InFlightRefresh {\n epoch: number;\n promise: Promise<string | null>;\n}\n\n/**\n * Хранит сессию и продлевает её.\n *\n * Главное здесь — **дедупликация обновления**. Когда десять параллельных запросов\n * одновременно получают `401`, обновление должно произойти один раз, а остальные обязаны\n * дождаться его результата. Иначе сервер увидит десять параллельных `refresh`, и все,\n * кроме первого, скорее всего получат отказ по уже использованному токену.\n */\nexport class AuthManager implements AuthProvider {\n readonly #config: SessionConfig;\n readonly #http: HttpClient;\n readonly #jar: CookieJar;\n readonly #emitter: Emitter<AuthEvents>;\n readonly #hooks: AuthManagerHooks;\n\n /** `undefined` — сессия ещё не читалась из хранилища. */\n #session: ItdSession | null | undefined;\n /**\n * Общий промис чтения сессии из хранилища. Дедупликация: параллельные запросы на холодном\n * старте читают хранилище один раз и не заводят каждый свой `deviceId`.\n */\n #loading: Promise<ItdSession | null> | null = null;\n /** Текущее обновление: к нему присоединяются запросы той же ревизии. */\n #refreshing: InFlightRefresh | null = null;\n /** Общий промис входа по логину и паролю. */\n #signingIn: Promise<string | null> | null = null;\n /** Fallback-область для изоляции состояния плагинов, когда JWT-идентичность недоступна. */\n #authScope = nextAuthScope();\n /** Последний токен внешнего источника; `undefined` означает, что источник ещё не читался. */\n #externalToken: string | null | undefined;\n /** Идентификаторы последнего токена внешнего источника для синхронных потребителей. */\n #externalIdentity: AuthIdentity | undefined;\n #tokenMetadata: { accessToken: string; value: TokenMetadata } | undefined;\n /**\n * Идентификатор устройства.\n *\n * Держится отдельно от сессии намеренно: выход из аккаунта не меняет устройство,\n * поэтому `clear()` его не трогает.\n */\n #deviceId: string | undefined;\n /** Общий промис первичной выдачи `deviceId` — чтобы параллельные запросы получили один. */\n #deviceIdLoading: Promise<string> | null = null;\n /**\n * Счётчик смен владельца авторизации.\n *\n * Растёт при каждой операции, которая заменяет или очищает сессию извне: `clear`,\n * `setSession`, `setAccessToken`, вход. Refresh сверяет снимок до и после сетевого запроса.\n */\n #authEpoch = 0;\n #externalReadGeneration = 0;\n /** Разовый токен из `auth.captcha` тратится ровно на один запрос. */\n #configCaptchaSpent = false;\n #disposed = false;\n #persistence: Promise<void> = Promise.resolve();\n\n constructor(\n config: SessionConfig,\n http: HttpClient,\n jar: CookieJar,\n hooks: AuthManagerHooks = {},\n ) {\n this.#config = config;\n this.#http = http;\n this.#jar = jar;\n this.#hooks = hooks;\n this.#emitter = new Emitter<AuthEvents>((error) =>\n reportListenerError(config.logger, 'авторизации', error),\n );\n }\n\n /** Подписка на события авторизации. */\n get on(): Emitter<AuthEvents>['on'] {\n return ((...args: Parameters<Emitter<AuthEvents>['on']>) => {\n this.#assertActive();\n return this.#emitter.on(...args);\n }) as Emitter<AuthEvents>['on'];\n }\n\n /** Подписка на одно срабатывание. */\n get once(): Emitter<AuthEvents>['once'] {\n return ((...args: Parameters<Emitter<AuthEvents>['once']>) => {\n this.#assertActive();\n return this.#emitter.once(...args);\n }) as Emitter<AuthEvents>['once'];\n }\n\n /** Снимает служебные подписки при окончательном освобождении владельца. @internal */\n dispose(): void {\n if (this.#disposed) return;\n this.#disposed = true;\n this.#externalReadGeneration += 1;\n this.#invalidateInFlight();\n this.#tokenMetadata = undefined;\n this.#emitter.removeAllListeners();\n }\n\n /**\n * Непрозрачная fallback-область авторизации.\n *\n * Изолирует состояние плагинов, когда идентичность аккаунта из JWT недоступна (непрозрачный\n * токен): значение уникально для владельца и сменяется при замене или очистке сессии.\n */\n getAuthScope(): string {\n return this.#authScope;\n }\n\n /** Загружает сессию и возвращает идентификаторы аккаунта и сессии для плагинов. */\n async getAuthIdentity(): Promise<AuthIdentity> {\n this.#assertActive();\n const session = await this.#loadSession();\n if (session?.accessToken) return this.#identityForToken(session.accessToken);\n\n const auth = this.#config.auth;\n if (typeof auth === 'object' && auth !== null && 'getToken' in auth) {\n const token = await this.#readExternalToken(() => auth.getToken());\n return this.#identityForToken(token ?? undefined);\n }\n\n return {};\n }\n\n /** Идентификаторы аккаунта и сессии без чтения хранилища. @internal */\n getCurrentAuthIdentity(): AuthIdentity {\n const session =\n this.#session === undefined ? this.#sessionFromConfig(this.#config.auth) : this.#session;\n return session?.accessToken\n ? this.#identityForToken(session.accessToken)\n : (this.#externalIdentity ?? {});\n }\n\n #rotateAuthScope(): void {\n this.#authScope = nextAuthScope();\n }\n\n /** Отмечает смену владельца авторизации — обесценивает результат идущего обновления. */\n #invalidateInFlight(): void {\n this.#authEpoch += 1;\n this.#externalReadGeneration += 1;\n }\n\n /** Ревизия владельца сессии для условного commit внешнего auth-flow. @internal */\n revision(): number {\n this.#assertActive();\n return this.#authEpoch;\n }\n\n /** Создаёт изолированный jar для сетевого auth-flow. @internal */\n createCookieFlow(inherit = true): CookieJar {\n this.#assertActive();\n return inherit ? this.#jar.clone() : new CookieJar();\n }\n\n /** Применяет cookies только если владелец сессии не сменился. @internal */\n commitCookieFlow(cookies: CookieJar, expectedRevision: number): boolean {\n this.#assertActive();\n if (this.#authEpoch !== expectedRevision) return false;\n this.#jar.replaceWith(cookies);\n return true;\n }\n\n #assertActive(): void {\n if (this.#disposed) throw new ItdStateError('Менеджер авторизации уже освобождён');\n }\n\n #currentAccessToken(): string | null {\n return this.#session?.accessToken ?? null;\n }\n\n #identityForToken(accessToken: string | undefined): AuthIdentity {\n const token = this.#metadataForToken(accessToken);\n return {\n ...(token.subject ? { userId: token.subject as UserId } : {}),\n ...(token.sessionId ? { sessionId: token.sessionId } : {}),\n };\n }\n\n #metadataForToken(accessToken: string | undefined): TokenMetadata {\n if (!accessToken) {\n this.#tokenMetadata = undefined;\n return {};\n }\n if (this.#tokenMetadata?.accessToken === accessToken) return this.#tokenMetadata.value;\n\n const value = readTokenMetadata(accessToken);\n this.#tokenMetadata = { accessToken, value };\n return value;\n }\n\n async #readExternalToken(\n getToken: () => string | null | Promise<string | null>,\n ): Promise<string | null> {\n this.#assertActive();\n const generation = ++this.#externalReadGeneration;\n const token = (await getToken()) ?? null;\n this.#assertActive();\n if (generation !== this.#externalReadGeneration) return token;\n const current = this.#identityForToken(token ?? undefined);\n\n if (this.#externalToken !== undefined && this.#externalToken !== token) {\n this.#rotateAuthScope();\n const previous = this.#externalIdentity ?? {};\n const changed =\n previous.userId !== undefined && current.userId !== undefined\n ? previous.userId !== current.userId\n : true;\n if (changed) this.#hooks.onAccountChange?.();\n }\n\n this.#externalToken = token;\n this.#externalIdentity = current;\n return token;\n }\n\n /** Обновляет резервный идентификатор и закрывает события при смене аккаунта. */\n #transitionAuth(accessToken: string | undefined, rotateFallback = true): void {\n const knownPrevious = this.#session !== undefined;\n const previous = this.#identityForToken(this.#session?.accessToken);\n const current = this.#identityForToken(accessToken);\n const changed =\n previous.userId !== undefined && current.userId !== undefined\n ? previous.userId !== current.userId\n : previous.userId !== current.userId || rotateFallback;\n\n if (rotateFallback || changed) this.#rotateAuthScope();\n if (knownPrevious && changed) this.#hooks.onAccountChange?.();\n }\n\n /**\n * Есть ли признак живой refresh-сессии.\n *\n * Рядом с refresh-токеном сервер ставит незакрытую cookie `is_auth` — по ней видно,\n * что продлевать сессию вообще есть смысл, и API не дёргается у анонимов.\n * В браузере cookie ведёт сама среда, поэтому там ответ всегда `true`.\n *\n * Асинхронный, потому что признак может лежать в {@link TokenStorage}: до чтения оттуда\n * ответ был бы `false` даже при полностью рабочей сохранённой сессии.\n */\n async hasRefreshSession(): Promise<boolean> {\n this.#assertActive();\n await this.#loadSession();\n return this.#hasRefreshSession();\n }\n\n /** То же самое, но без чтения хранилища — для вызовов, где сессия уже загружена. */\n #hasRefreshSession(): boolean {\n if (!this.#config.useCookieJar) return true;\n // Флаг должен принадлежать основному API, а не другому сервису.\n if (this.#jar.has(AUTH_FLAG_COOKIE, this.#config.baseUrl)) return true;\n\n // Явно переданный refresh-токен — тоже основание пробовать.\n return Boolean(this.#session?.refreshToken);\n }\n\n /** Готовит внутреннюю сессию до retry исходного запроса. */\n async preflight(allowRefresh: boolean): Promise<void> {\n this.#assertActive();\n const session = await this.#loadSession();\n let accessToken = session?.accessToken;\n\n if (!accessToken) {\n const auth = this.#config.auth;\n if (typeof auth === 'object' && auth !== null && 'email' in auth) {\n accessToken = (await this.#signInWithCredentials(auth)) ?? undefined;\n }\n }\n\n if (!accessToken || !allowRefresh || !this.#config.autoRefresh) return;\n\n const expiresAt = this.#metadataForToken(accessToken).expiresAt;\n if (\n expiresAt === undefined ||\n expiresAt > this.#config.clock.now() + ACCESS_TOKEN_REFRESH_LEEWAY_MS ||\n !this.#hasRefreshSession()\n ) {\n return;\n }\n\n try {\n await this.#refreshDeduplicated({ epoch: this.#authEpoch, accessToken });\n } catch (error) {\n this.#emitter.emit('authError', { error });\n throw error;\n }\n }\n\n /** Перед каждой попыткой перечитывает внешний источник токена. */\n async prepare(): Promise<void> {\n this.#assertActive();\n const session = await this.#loadSession();\n if (session?.accessToken) return;\n\n const auth = this.#config.auth;\n if (typeof auth === 'object' && auth !== null && 'getToken' in auth) {\n await this.#readExternalToken(() => auth.getToken());\n }\n }\n\n /**\n * Заголовки уже подготовленной авторизации без чтения storage или вызова внешнего источника.\n *\n * Используются после ожидания транспортной очереди: к этому моменту {@link prepare} уже\n * был вызван снаружи неё, но token мог успеть смениться из-за refresh или `setSession()`.\n */\n currentHeaders(): Record<string, string> {\n const session =\n this.#session === undefined ? this.#sessionFromConfig(this.#config.auth) : this.#session;\n const token = session?.accessToken ?? this.#externalToken ?? null;\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n\n /**\n * Реакция конвейера на `401`. Стадия `auth_recovery`.\n *\n * При выключенном `autoRefresh` ничего не делает: вызывающий код обновляет сессию сам\n * через `itd.auth.refresh()`, а библиотека просто пробрасывает {@link ItdAuthError}.\n */\n recover(): Promise<boolean> {\n this.#assertActive();\n return this.#config.autoRefresh ? this.onUnauthorized() : Promise.resolve(false);\n }\n\n /**\n * Идентификатор устройства для заголовка `X-Device-Id`.\n *\n * Заводится один раз и сохраняется в сессии, чтобы пережить перезапуск процесса:\n * сервер связывает с ним запись в списке сессий, и плавающее значение плодило бы\n * по новой сессии на каждый старт.\n */\n deviceId(): Promise<string> {\n this.#assertActive();\n if (this.#deviceId) return Promise.resolve(this.#deviceId);\n\n // Дедупликация: параллельные вызовы на холодном клиенте получают один `X-Device-Id`.\n this.#deviceIdLoading ??= this.#resolveDeviceId().finally(() => {\n this.#deviceIdLoading = null;\n });\n\n return this.#deviceIdLoading;\n }\n\n async #resolveDeviceId(): Promise<string> {\n const revision = this.#authEpoch;\n const session = await this.#loadSession();\n this.#assertActive();\n const deviceId = this.#config.deviceId ?? session?.deviceId ?? createDeviceId();\n\n this.#deviceId = deviceId;\n if (this.#authEpoch !== revision) return deviceId;\n\n // Записываем, только если значение действительно новое, — иначе каждый первый запрос\n // дёргал бы хранилище без всякой пользы.\n if (session?.deviceId !== deviceId) {\n await this.#saveSession({ ...(session ?? {}), deviceId });\n }\n\n return deviceId;\n }\n\n /**\n * Текущий токен доступа.\n *\n * При необходимости выполняет отложенный вход: если в конфигурации переданы логин\n * и пароль, первый же запрос сам заведёт сессию.\n */\n async token(): Promise<string | null> {\n this.#assertActive();\n const session = await this.#loadSession();\n if (session?.accessToken) return session.accessToken;\n\n const auth = this.#config.auth;\n if (!auth) return null;\n\n // Внешний источник токена спрашиваем каждый раз: он сам решает, когда обновлять.\n if (typeof auth === 'object' && 'getToken' in auth) {\n return this.#readExternalToken(() => auth.getToken());\n }\n\n if (typeof auth === 'object' && 'email' in auth) {\n return this.#signInWithCredentials(auth);\n }\n\n return null;\n }\n\n /**\n * Реакция транспорта на ответ `401`.\n *\n * @returns `true`, если токен обновлён и запрос имеет смысл повторить\n */\n async onUnauthorized(): Promise<boolean> {\n this.#assertActive();\n try {\n const token = await this.#refreshDeduplicated();\n if (token !== null) return true;\n\n // Обновлять нечем — это тоже отказ авторизации, и подписчик должен о нём узнать.\n this.#emitter.emit('authError', { error: this.#noRefreshSessionError() });\n return false;\n } catch (error) {\n this.#emitter.emit('authError', { error });\n return false;\n }\n }\n\n /**\n * Ошибка «сессию продлить нечем».\n *\n * Возникает, только когда обновление даже не начиналось: нет ни cookie `is_auth`,\n * ни refresh-токена. Если сервер ответил отказом, наружу уходит **его** ошибка —\n * подменять её этой значило бы прятать причину (`REFRESH_TOKEN_MISSING`,\n * `SESSION_NOT_FOUND`, `SESSION_REVOKED` — разные поводы и разные действия).\n */\n #noRefreshSessionError(): ItdAuthError {\n return new ItdAuthError({\n status: 401,\n code: 'SESSION_EXPIRED',\n message:\n 'Не удалось обновить сессию: нет ни cookie is_auth, ни refresh-токена. ' +\n 'Войдите заново либо передайте refreshToken в auth.',\n method: 'POST',\n path: AUTH_PATHS.refresh,\n raw: undefined,\n });\n }\n\n /**\n * Обновляет токен доступа.\n *\n * Параллельные вызовы объединяются в один сетевой запрос.\n *\n * @throws {ItdAuthError} если обновить сессию не удалось\n */\n async refresh(): Promise<string> {\n this.#assertActive();\n const token = await this.#refreshDeduplicated();\n if (token === null) throw this.#noRefreshSessionError();\n return token;\n }\n\n /** Сохраняет токен, полученный извне, — например после подтверждения OTP. */\n async setAccessToken(\n accessToken: string,\n expectedRevision = this.#authEpoch,\n cookies?: CookieJar,\n ): Promise<boolean> {\n return this.#storeAccessToken(accessToken, expectedRevision, cookies, false);\n }\n\n /** Атомарно принимает токен и cookie завершённого входа как новую сессию. @internal */\n async commitAuthFlow(\n accessToken: string,\n cookies: CookieJar,\n expectedRevision = this.#authEpoch,\n ): Promise<boolean> {\n return this.#storeAccessToken(accessToken, expectedRevision, cookies, true);\n }\n\n async #storeAccessToken(\n accessToken: string,\n expectedRevision: number,\n cookies: CookieJar | undefined,\n replaceSession: boolean,\n ): Promise<boolean> {\n this.#assertActive();\n if (typeof accessToken !== 'string' || accessToken.trim() === '') {\n throw new ItdConfigError('accessToken должен быть непустой строкой');\n }\n await this.#loadSession();\n this.#assertActive();\n if (this.#authEpoch !== expectedRevision) return false;\n if (cookies) this.#jar.replaceWith(cookies);\n this.#invalidateInFlight();\n this.#transitionAuth(accessToken);\n const saved = this.#saveSession({\n ...(replaceSession ? {} : (this.#session ?? {})),\n accessToken,\n obtainedAt: this.#config.clock.now(),\n });\n this.#emitter.emit('tokens', { accessToken });\n await saved;\n return true;\n }\n\n /** Текущая сессия целиком. Полезно, чтобы сохранить её самому. */\n async getSession(): Promise<ItdSession | null> {\n this.#assertActive();\n const session = await this.#loadSession();\n return session ? copySession(session) : null;\n }\n\n /**\n * Идентификатор владельца сессии.\n *\n * Считается непосредственно из текущего токена и отдельно не сохраняется: после замены\n * токена идентификатор прежнего владельца остаться не может.\n */\n async getUserId(): Promise<UserId | undefined> {\n this.#assertActive();\n const session = await this.#loadSession();\n return session?.accessToken ? this.#identityForToken(session.accessToken).userId : undefined;\n }\n\n /** Заменяет сессию и связанные с ней cookie целиком. */\n async setSession(session: ItdSession): Promise<void> {\n this.#assertActive();\n const normalized = normalizeSession(session, 'session');\n await this.#loadSession();\n this.#assertActive();\n this.#invalidateInFlight();\n this.#transitionAuth(normalized.accessToken);\n this.#jar.clear();\n this.#jar.deserialize(normalized.cookies);\n\n if (normalized.deviceId) this.#deviceId = normalized.deviceId;\n\n // Refresh-cookie добавляется до сериализации сессии.\n this.#session = normalized;\n this.#seedRefreshCookie();\n\n await this.#saveSession(normalized);\n }\n\n /**\n * Забывает сессию и cookie. Сетевой запрос не выполняется.\n *\n * Идентификатор устройства выход переживает: иначе каждая пара «выход — вход» плодила бы\n * новую запись в списке сессий.\n */\n async clear(): Promise<void> {\n this.#assertActive();\n await this.#loadSession();\n this.#assertActive();\n this.#invalidateInFlight();\n this.#transitionAuth(undefined);\n this.#jar.clear();\n const retained = this.#deviceId ? { deviceId: this.#deviceId } : null;\n this.#session = retained;\n this.#emitter.emit('signOut', undefined);\n await this.#enqueuePersistence(async () => {\n await this.#config.storage.clear();\n if (retained) await this.#config.storage.set(copySession(retained));\n });\n }\n\n #loadSession(): Promise<ItdSession | null> {\n if (this.#session !== undefined) return Promise.resolve(this.#session);\n\n this.#loading ??= this.#performLoad().finally(() => {\n this.#loading = null;\n });\n\n return this.#loading;\n }\n\n async #performLoad(): Promise<ItdSession | null> {\n const loaded = (await this.#config.storage.get()) ?? null;\n this.#assertActive();\n const stored =\n loaded === null\n ? null\n : normalizeSessionValue(loaded, 'storage.get()', 'stored', this.#config.logger);\n\n // Восстанавливаем cookie: без них не выйдет обновить токен после перезапуска процесса.\n if (stored?.cookies) this.#jar.deserialize(stored.cookies);\n\n const fromConfig = this.#sessionFromConfig(this.#config.auth);\n\n // Хранилище отвечает за состояние сессии и всегда важнее, но недостающие поля\n // берутся из конфигурации: типичный случай — сохранён только accessToken,\n // а refresh-токен приходит из настроек приложения.\n this.#session =\n stored && fromConfig\n ? {\n ...stored,\n accessToken: stored.accessToken ?? fromConfig.accessToken,\n refreshToken: stored.refreshToken ?? fromConfig.refreshToken,\n }\n : (stored ?? fromConfig);\n\n this.#seedRefreshCookie();\n\n return this.#session;\n }\n\n /**\n * Кладёт refresh-токен в jar как cookie `refresh_token`.\n *\n * `POST /api/v1/auth/refresh` читает токен только из cookie, поэтому переданный строкой\n * приходится превращать в неё. В браузере это невозможно — cookie помечена `HttpOnly`,\n * и там обновление работает только на той, что поставил сам сервер.\n */\n #seedRefreshCookie(): void {\n if (!this.#config.useCookieJar) return;\n\n const refreshToken = this.#session?.refreshToken;\n if (!refreshToken) return;\n if (this.#jar.has(REFRESH_COOKIE, this.#config.baseUrl + REFRESH_COOKIE_PATH)) return;\n\n this.#jar.set(this.#config.baseUrl, REFRESH_COOKIE, refreshToken, REFRESH_COOKIE_PATH);\n }\n\n #sessionFromConfig(auth: AuthInput | undefined): ItdSession | null {\n if (!auth) return null;\n if (typeof auth === 'string') {\n return { accessToken: auth, obtainedAt: this.#config.clock.now() };\n }\n\n if ('accessToken' in auth) {\n return {\n accessToken: auth.accessToken,\n refreshToken: auth.refreshToken,\n obtainedAt: this.#config.clock.now(),\n };\n }\n\n return null;\n }\n\n async #saveSession(session: ItdSession): Promise<void> {\n const cookies = this.#config.useCookieJar ? this.#jar.serialize() : undefined;\n const deviceId = session.deviceId ?? this.#deviceId;\n const { cookies: _staleCookies, ...withoutCookies } = copySession(session);\n\n const next = withoutLegacyUserId({\n ...withoutCookies,\n ...(cookies?.length ? { cookies } : {}),\n ...(deviceId ? { deviceId } : {}),\n });\n\n this.#session = next;\n await this.#enqueuePersistence(() => this.#config.storage.set(copySession(next)));\n }\n\n #enqueuePersistence(operation: () => void | Promise<void>): Promise<void> {\n const pending = this.#persistence.then(operation, operation);\n this.#persistence = pending.catch(() => {});\n return pending;\n }\n\n /** Дедуплицирует refresh одной ревизии; следующая ждёт завершения предыдущей. */\n #refreshDeduplicated(\n expectation: RefreshExpectation = { epoch: this.#authEpoch },\n ): Promise<string | null> {\n const current = this.#refreshing;\n if (current) {\n if (current.epoch === expectation.epoch) return current.promise;\n return current.promise.then(\n () => this.#refreshDeduplicated(expectation),\n () => this.#refreshDeduplicated(expectation),\n );\n }\n\n const promise = this.#performRefresh(expectation).finally(() => {\n if (this.#refreshing?.promise === promise) this.#refreshing = null;\n });\n\n this.#refreshing = { epoch: expectation.epoch, promise };\n return promise;\n }\n\n #matchesRefreshExpectation(expectation: RefreshExpectation): boolean {\n return (\n this.#authEpoch === expectation.epoch &&\n (expectation.accessToken === undefined ||\n this.#session?.accessToken === expectation.accessToken)\n );\n }\n\n async #performRefresh(expectation: RefreshExpectation): Promise<string | null> {\n this.#assertActive();\n await this.#loadSession();\n if (!this.#matchesRefreshExpectation(expectation)) return this.#currentAccessToken();\n\n if (!this.#hasRefreshSession()) {\n // Нет признаков сессии — обновлять нечего. При наличии логина и пароля\n // пробуем войти заново.\n return this.#reloginOrNull();\n }\n\n const flowCookies = this.#jar.clone();\n\n try {\n // Служебный запрос идёт через общий pipeline. Слой авторизации он пропускает, чтобы\n // не отправлять устаревший Bearer и не запускать рекурсивный refresh. Очередь безопасна:\n // исходная неудачная транспортная попытка освободила свой слот до вызова этого метода.\n const accessToken = await this.#http.execute(AUTH_REFRESH, {\n path: AUTH_PATHS.refresh,\n skipAuth: true,\n skipAuthRefresh: true,\n cookieJar: flowCookies,\n // Тела нет намеренно: сервер читает refresh-токен только из cookie — см.\n // #seedRefreshCookie. По той же причине не нужен и устаревший Bearer.\n });\n\n if (!this.#matchesRefreshExpectation(expectation)) {\n // Пока шёл refresh, владельца сменили (signOut / setSession / вход): его результат\n // устарел. Не воскрешаем сохранённую сессию, отдаём актуальный токен как есть.\n return this.#session?.accessToken ?? null;\n }\n\n this.#jar.replaceWith(flowCookies);\n\n // Сервер выдаёт при обновлении **новый** refresh-токен (`Set-Cookie: refresh_token=…;\n // Max-Age=2592000`) и тут же гасит прежний. Забрать его из jar обязательно: иначе\n // сохранённая строка протухнет и восстановление сессии из хранилища перестанет работать.\n const rotated = this.#jar.getValue(\n REFRESH_COOKIE,\n this.#config.baseUrl + REFRESH_COOKIE_PATH,\n );\n\n // Refresh продолжает ту же серверную сессию. Для непрозрачного токена это единственная\n // надёжная возможность сохранить scope; смена пользователя в JWT всё равно будет обнаружена.\n this.#transitionAuth(accessToken, false);\n const saved = this.#saveSession({\n ...(this.#session ?? {}),\n accessToken,\n ...(rotated ? { refreshToken: rotated } : {}),\n obtainedAt: this.#config.clock.now(),\n });\n\n this.#emitter.emit('tokens', { accessToken });\n await saved;\n if (this.#authEpoch !== expectation.epoch) return this.#currentAccessToken();\n return accessToken;\n } catch (error) {\n if (this.#authEpoch !== expectation.epoch) return this.#currentAccessToken();\n if (error instanceof ItdAuthError) {\n // Сессия недействительна — чистим её, иначе будем биться в стену на каждом запросе.\n this.#invalidateInFlight();\n const clearedRevision = this.#authEpoch;\n this.#transitionAuth(undefined);\n this.#session = null;\n this.#jar.clear();\n await this.#enqueuePersistence(() => this.#config.storage.clear());\n if (this.#authEpoch !== clearedRevision) return this.#currentAccessToken();\n\n const relogged = await this.#reloginOrNull();\n if (relogged !== null) return relogged;\n\n // Войти заново нечем — отдаём ошибку сервера как есть. Именно она объясняет,\n // что произошло: REFRESH_TOKEN_MISSING, SESSION_NOT_FOUND, SESSION_REVOKED.\n throw error;\n }\n throw error;\n }\n }\n\n /** Повторный вход, если разрешён настройкой и есть логин с паролем. */\n async #reloginOrNull(): Promise<string | null> {\n const auth = this.#config.auth;\n\n if (\n !this.#config.reloginOnRefreshFailure ||\n !auth ||\n typeof auth !== 'object' ||\n !('email' in auth)\n ) {\n return null;\n }\n\n try {\n return await this.#signInWithCredentials(auth);\n } catch (error) {\n this.#config.logger?.warn('Автоматический повторный вход не удался', error);\n return null;\n }\n }\n\n /**\n * Вход по логину и паролю.\n *\n * Параллельные вызовы объединяются: одновременный старт нескольких запросов не должен\n * приводить к нескольким попыткам входа и блокировке аккаунта.\n */\n #signInWithCredentials(credentials: CredentialsAuth): Promise<string | null> {\n if (this.#signingIn) return this.#signingIn;\n\n const revision = this.#authEpoch;\n const promise = this.#performSignIn(credentials, revision).finally(() => {\n this.#signingIn = null;\n });\n\n this.#signingIn = promise;\n return promise;\n }\n\n /**\n * Готовит фрагмент тела с токеном капчи для запроса, который её требует.\n *\n * Источники в порядке убывания приоритета: токен, переданный в сам вызов; разовый токен\n * из `auth.captcha`; опция `captcha`. Когда ни одного нет, фрагмент пустой: нужна ли\n * капча этому запросу, решает сервер.\n *\n * @param explicit готовый токен, переданный в вызов\n * @throws {ItdConfigError} если токен неполный или источник его не вернул\n */\n async captchaBody(explicit?: CaptchaToken | undefined): Promise<CaptchaBody> {\n if (explicit) return captchaBody(explicit);\n\n const configured = this.#takeConfiguredCaptcha();\n if (configured) return captchaBody(configured);\n\n const solver = this.#config.captcha;\n if (solver) return solveCaptchaBody(solver, () => this.#resolveCaptchaProvider());\n\n this.#config.logger?.debug(\n 'Запрос уходит без токена капчи: не передан аргумент captcha и не задана опция captcha',\n );\n return {};\n }\n\n /** Отдаёт разовый токен из `auth.captcha`, помечая его потраченным. */\n #takeConfiguredCaptcha(): CaptchaToken | undefined {\n if (this.#configCaptchaSpent) return undefined;\n\n const auth = this.#config.auth;\n const captcha = isRecord(auth) ? (auth as CredentialsAuth).captcha : undefined;\n if (!captcha) return undefined;\n\n this.#configCaptchaSpent = true;\n return captcha;\n }\n\n /** Спрашивает у сервера активного провайдера и поле, в котором он ждёт токен. */\n async #resolveCaptchaProvider(): Promise<CaptchaProvider> {\n const provider: unknown = await this.#http.execute(AUTH_CAPTCHA_PROVIDER, {\n path: AUTH_PATHS.captchaProvider,\n skipAuth: true,\n skipAuthRefresh: true,\n });\n\n return readCaptchaProvider(provider);\n }\n\n async #performSignIn(credentials: CredentialsAuth, revision: number): Promise<string | null> {\n const captcha = await this.captchaBody();\n const flowCookies = new CookieJar();\n\n // Через общий pipeline: плагины, повторы и очередь сохраняются, а слой авторизации\n // пропускается, потому что токена ещё нет.\n const result = await this.#http.execute(AUTH_SIGN_IN, {\n path: AUTH_PATHS.signIn,\n body: { email: credentials.email, password: credentials.password, ...captcha },\n skipAuth: true,\n skipAuthRefresh: true,\n cookieJar: flowCookies,\n });\n\n if (result.status !== SignInStatus.Authenticated) {\n // Сервер запросил подтверждение по коду — автоматически это не пройти.\n throw new ItdConfigError(\n 'Вход по email и паролю требует подтверждения кодом из письма. Автоматический вход ' +\n 'невозможен: воспользуйтесь itd.auth.signInWithOtp() и передайте полученный ' +\n 'accessToken в конфигурацию клиента.',\n );\n }\n const accessToken = result.accessToken;\n this.#assertActive();\n if (this.#authEpoch !== revision) return this.#session?.accessToken ?? null;\n this.#jar.replaceWith(flowCookies);\n\n // Прежний refresh-токен и cookie намеренно не переносятся: вход выдал новую сессию,\n // и держаться за старую было бы ошибкой. Идентификатор устройства добавит #saveSession.\n this.#invalidateInFlight();\n this.#transitionAuth(accessToken);\n const saved = this.#saveSession({ accessToken, obtainedAt: this.#config.clock.now() });\n this.#emitter.emit('tokens', { accessToken });\n this.#emitter.emit('signIn', { accessToken });\n await saved;\n\n return accessToken;\n }\n}\n","import { createParser } from 'eventsource-parser';\nimport type { ClientConnection } from '../core/connection.js';\nimport type { CookieJar } from '../core/cookies.js';\nimport { createApiError } from '../core/error-factory.js';\nimport { ItdNetworkError } from '../core/errors.js';\nimport { createRequestAbortScope, requestAbortError } from '../core/execution/lifecycle.js';\nimport { joinUrl } from '../core/url.js';\nimport { isRecord } from '../core/validate.js';\nimport {\n type QrLoginStreamEvent,\n QrLoginStreamStatus,\n type QrLoginStreamStatus as QrLoginStreamStatusValue,\n} from '../operations/auth.js';\nimport { AUTH_PATHS } from './auth.js';\n\ninterface QrLoginStreamCredentials {\n qrId: string;\n claimToken: string;\n}\n\nconst QR_STREAM_STATUSES = new Set<QrLoginStreamStatusValue>(Object.values(QrLoginStreamStatus));\n\nfunction readQrLoginStreamEvent(data: string): QrLoginStreamEvent | undefined {\n let value: unknown;\n try {\n value = JSON.parse(data);\n } catch {\n return undefined;\n }\n if (!isRecord(value)) return undefined;\n const event = value as Record<string, unknown>;\n if (\n typeof event.status !== 'string' ||\n !QR_STREAM_STATUSES.has(event.status as QrLoginStreamStatusValue)\n ) {\n return undefined;\n }\n return {\n status: event.status as QrLoginStreamStatusValue,\n ...(typeof event.expiresIn === 'number' && Number.isFinite(event.expiresIn)\n ? { expiresIn: event.expiresIn }\n : {}),\n };\n}\n\n/** Читает короткоживущий SSE-поток QR-входа и последовательно доставляет его события. */\nexport async function consumeQrLoginStream(\n body: ReadableStream<Uint8Array>,\n onEvent: (event: QrLoginStreamEvent) => void | Promise<void>,\n signal?: AbortSignal,\n): Promise<void> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let delivery = Promise.resolve();\n let completed = false;\n const cancel = () => {\n void reader.cancel(signal?.reason).catch(() => {});\n };\n signal?.addEventListener('abort', cancel, { once: true });\n\n const parser = createParser({\n onEvent(message) {\n const event = readQrLoginStreamEvent(message.data);\n // Один повреждённый или неизвестный кадр не должен обрывать оставшийся поток.\n if (!event) return;\n delivery = delivery.then(() => onEvent(event));\n },\n });\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n parser.feed(decoder.decode(value, { stream: true }));\n await delivery;\n }\n parser.feed(decoder.decode());\n await delivery;\n if (signal?.aborted) throw signal.reason;\n completed = true;\n } finally {\n signal?.removeEventListener('abort', cancel);\n if (!completed) await reader.cancel().catch(() => {});\n reader.releaseLock?.();\n }\n}\n\n/** Открывает изолированный HTTP/SSE-канал QR-входа. @internal */\nexport async function openQrLoginStream(\n connection: ClientConnection,\n cookies: CookieJar,\n input: QrLoginStreamCredentials,\n onEvent: (event: QrLoginStreamEvent) => void | Promise<void>,\n signal?: AbortSignal,\n): Promise<void> {\n connection.assertActive?.('открыть QR-поток');\n const path = AUTH_PATHS.qrStream;\n const method = 'POST';\n const url = joinUrl(connection.baseUrl, path);\n const abort = createRequestAbortScope(signal, connection.signal, 0, connection.clock);\n\n try {\n const headers = await connection.baseHeaders(url);\n // Базовые заголовки могут содержать cookie основной сессии; QR-сессия живёт отдельно.\n headers.delete('Authorization');\n headers.delete('Cookie');\n headers.set('Accept', 'text/event-stream');\n headers.set('Content-Type', 'application/json');\n const cookie = cookies.getHeader(url);\n if (cookie) headers.set('Cookie', cookie);\n\n let response: Response;\n try {\n response = await connection.fetch(url, {\n method,\n headers,\n body: JSON.stringify(input),\n // Браузеру это передаёт cookie; серверный fetch использует заголовок из jar выше.\n credentials: 'include',\n signal: abort.signal,\n });\n } catch (error) {\n const failure = new ItdNetworkError(`Не удалось открыть QR-поток: ${String(error)}`, {\n method,\n path,\n cause: error,\n });\n throw requestAbortError(abort, { timeout: 0, method, path }, failure);\n }\n\n cookies.setFromResponse(response.url || url, response);\n if (!response.ok) {\n const text = await response.text();\n let body: unknown = text;\n try {\n body = JSON.parse(text);\n } catch {}\n throw createApiError({\n method,\n path,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n response,\n body,\n now: connection.clock.now(),\n });\n }\n if (!response.body) {\n throw new ItdNetworkError('Сервер не вернул тело QR-потока', { method, path });\n }\n\n await consumeQrLoginStream(response.body, onEvent, abort.signal);\n } catch (error) {\n throw requestAbortError(abort, { timeout: 0, method, path }, error);\n } finally {\n abort.cleanup();\n }\n}\n","import type { ClientConnection } from '../core/connection.js';\nimport type { CookieJar } from '../core/cookies.js';\nimport { ItdConfigError, isItdApiError } from '../core/errors.js';\nimport type { HttpClient } from '../core/execution/http.js';\nimport type { RequestOptions } from '../core/options.js';\nimport type { QrLoginTarget, Session } from '../models/account.js';\nimport type { AuthState } from '../models/users.js';\nimport {\n AUTH_CAPTCHA_PAGE,\n AUTH_CAPTCHA_PROVIDER,\n AUTH_CHANGE_PASSWORD,\n AUTH_CHECK,\n AUTH_FORGOT_PASSWORD,\n AUTH_LOGOUT,\n AUTH_QR_APPROVE,\n AUTH_QR_CLAIM,\n AUTH_QR_REJECT,\n AUTH_QR_SCAN,\n AUTH_QR_START,\n AUTH_RESEND_OTP,\n AUTH_RESET_PASSWORD,\n AUTH_REVOKE_OTHER_SESSIONS,\n AUTH_REVOKE_SESSION,\n AUTH_SESSIONS,\n AUTH_SIGN_IN,\n AUTH_SIGN_UP,\n AUTH_VERIFY_OTP,\n type CaptchaPage,\n type CaptchaProvider,\n type CaptchaToken,\n type QrLoginClaim,\n type QrLoginStart,\n QrLoginStatus,\n type QrLoginStreamEvent,\n QrLoginStreamStatus,\n type SignInResult,\n SignInStatus,\n} from '../operations/auth.js';\nimport { AUTH_PATHS, type AuthManager } from '../session/auth.js';\nimport { openQrLoginStream } from '../session/qr-stream.js';\nimport { BaseResource } from './base.js';\n\n/** Учётные данные для входа. */\nexport interface Credentials {\n email: string;\n password: string;\n}\n\n/**\n * Учётные данные вместе с токеном капчи.\n *\n * Токен нужен, только когда у клиента не задана опция `captcha`: с ней клиент получает его\n * сам. Какой виджет сейчас требует сервер, сообщает {@link AuthResource.captchaProvider};\n * в Node токен добывает `@itd-api/captcha`. Токен одноразовый и живёт несколько минут.\n *\n * @example\n * ```ts\n * const { provider, field } = await itd.auth.captchaProvider();\n * const token = await solveCaptcha(provider);\n *\n * await itd.auth.signIn({ email, password, captcha: { type: provider, token, field } });\n * ```\n */\nexport type CredentialsWithCaptcha = Credentials & { captcha?: CaptchaToken | undefined };\n\n/** Запрос письма для сброса пароля. Капча обязательна, как и при входе. */\nexport interface ForgotPasswordInput {\n email: string;\n captcha?: CaptchaToken | undefined;\n}\n\n/** Секреты QR-сессии и капча для завершения входа. */\nexport interface QrLoginClaimInput {\n qrId: string;\n claimToken: string;\n captcha?: CaptchaToken | undefined;\n}\n\n/** Секреты QR-сессии для потокового наблюдения. */\nexport interface QrLoginStreamInput {\n qrId: string;\n claimToken: string;\n}\n\n/**\n * Секреты QR-кода со стороны сканирующего устройства.\n *\n * Оба значения лежат во fragment {@link QrLoginStart.payload} — ссылки вида\n * `https://итд.com/qr#i=<qrId>&s=<secret>`, которую и кодирует QR-код. `secret` — не то же\n * самое, что `claimToken`: этот секрет предъявляет тот, кто сканирует, а `claimToken` — тот,\n * кто код показывает.\n */\nexport interface QrLoginSecrets {\n qrId: string;\n secret: string;\n}\n\n/** Управление временем жизни потокового запроса. */\nexport interface QrLoginStreamOptions {\n signal?: AbortSignal | undefined;\n}\n\n/** Обработчик одного события QR-потока. */\nexport type QrLoginStreamListener = (event: QrLoginStreamEvent) => void | Promise<void>;\n\n/**\n * Установка нового пароля.\n *\n * Сброс идёт тем же потоком с кодом, что и вход: {@link AuthResource.forgotPassword} выдаёт\n * `flowToken`, письмо приносит `otp`, и всё это вместе с новым паролем уходит сюда.\n */\nexport interface ResetPasswordInput {\n email: string;\n otp: string;\n flowToken: string;\n newPassword: string;\n}\n\nexport type { QrLoginTarget } from '../models/account.js';\nexport type {\n CaptchaPage,\n CaptchaProvider,\n CaptchaToken,\n QrLoginClaim,\n QrLoginStart,\n QrLoginStreamEvent,\n SignInResult,\n SignInStatus as SignInStatusValue,\n} from '../operations/auth.js';\n/** Состояния обычного входа и QR-входа. */\nexport {\n CAPTCHA_FIELDS,\n QrLoginStatus,\n QrLoginStreamStatus,\n SignInStatus,\n} from '../operations/auth.js';\n\ninterface QrCookieFlow {\n cookies: CookieJar;\n expiresAt: number | undefined;\n /** Сервер потребовал капчу для этой сессии — в ответе `start` либо на прошлой проверке. */\n captchaRequired: boolean;\n}\n\n/**\n * Результат входа.\n *\n * Сервер может как сразу выдать токен, так и потребовать код подтверждения — размеченное\n * объединение делает оба случая явными.\n */\n\n/**\n * Авторизация, сессии и пароли.\n *\n * Доступна как `itd.auth`.\n */\nexport class AuthResource extends BaseResource {\n readonly #auth: AuthManager;\n readonly #connection: ClientConnection;\n readonly #qrFlows = new Map<string, QrCookieFlow>();\n\n constructor(http: HttpClient, deps: { auth: AuthManager; connection: ClientConnection }) {\n super(http);\n this.#auth = deps.auth;\n this.#connection = deps.connection;\n }\n\n #pruneQrFlows(): void {\n const now = this.#connection.clock.now();\n for (const [qrId, flow] of this.#qrFlows) {\n if (flow.expiresAt !== undefined && flow.expiresAt <= now) this.#qrFlows.delete(qrId);\n }\n }\n\n #qrFlow(qrId: string): QrCookieFlow {\n this.#pruneQrFlows();\n const existing = this.#qrFlows.get(qrId);\n if (existing) return existing;\n const flow = {\n cookies: this.#auth.createCookieFlow(false),\n expiresAt: undefined,\n captchaRequired: false,\n };\n this.#qrFlows.set(qrId, flow);\n return flow;\n }\n\n #touchQrFlow(flow: QrCookieFlow, expiresIn: number | undefined): void {\n if (typeof expiresIn !== 'number' || !Number.isFinite(expiresIn)) return;\n const expiresAt = this.#connection.clock.now() + Math.max(0, expiresIn) * 1_000;\n flow.expiresAt = flow.expiresAt === undefined ? expiresAt : Math.min(flow.expiresAt, expiresAt);\n }\n\n #forgetTerminalQrError(qrId: string, error: unknown): void {\n if (\n isItdApiError(error) &&\n error.hasCode('QR_EXPIRED', 'QR_ALREADY_USED', 'QR_TOKEN_MISMATCH')\n ) {\n this.#qrFlows.delete(qrId);\n }\n }\n\n /**\n * Проверяет состояние авторизации и возвращает текущего пользователя.\n *\n * Без авторизации возвращает `authenticated: false` и `user: null`.\n */\n check(options: RequestOptions = {}): Promise<AuthState> {\n return this.http.execute(AUTH_CHECK, {\n path: '/api/profile',\n ...options,\n });\n }\n\n /**\n * Узнаёт активного провайдера капчи и поле токена.\n *\n * Сервер может переключить провайдера или переименовать поле без выпуска новой версии SDK.\n * Автоматическому входу этот вызов не нужен — клиент делает его сам.\n */\n captchaProvider(options: RequestOptions = {}): Promise<CaptchaProvider> {\n return this.http.execute(AUTH_CAPTCHA_PROVIDER, {\n path: AUTH_PATHS.captchaProvider,\n skipAuth: true,\n skipAuthRefresh: true,\n ...options,\n });\n }\n\n /**\n * Узнаёт активного провайдера капчи вместе с адресом страницы виджета.\n *\n * То же, что {@link captchaProvider}, плюс `url` — готовая страница на домене итд.com,\n * где ключ виджета действителен. Пригодится встроенному браузеру: открыть её и забрать\n * токен, ничего не собирая самому.\n */\n captchaPage(options: RequestOptions = {}): Promise<CaptchaPage> {\n return this.http.execute(AUTH_CAPTCHA_PAGE, {\n path: AUTH_PATHS.captchaPage,\n skipAuth: true,\n skipAuthRefresh: true,\n ...options,\n });\n }\n\n /** Создаёт короткоживущую сессию QR-входа. */\n async startQrLogin(options: RequestOptions = {}): Promise<QrLoginStart> {\n const cookies = this.#auth.createCookieFlow(false);\n const result = await this.http.execute(AUTH_QR_START, {\n path: AUTH_PATHS.qrStart,\n skipAuth: true,\n skipAuthRefresh: true,\n cookieJar: cookies,\n ...options,\n });\n if (typeof result.qrId === 'string' && result.qrId !== '') {\n const flow = { cookies, expiresAt: undefined, captchaRequired: false };\n this.#touchQrFlow(flow, result.expiresIn);\n this.#qrFlows.set(result.qrId, flow);\n }\n return result;\n }\n\n /**\n * Проверяет QR-сессию и завершает вход после подтверждения на другом устройстве.\n *\n * До подтверждения возвращает промежуточный статус. Токен капчи добывается, только когда\n * сервер о ней попросил — статусом `captcha_required` на прошлой проверке, — либо когда\n * передан в сам вызов. Полученный `accessToken` автоматически сохраняется в клиенте.\n */\n async claimQrLogin(\n input: QrLoginClaimInput,\n options: RequestOptions = {},\n ): Promise<QrLoginClaim> {\n const revision = this.#auth.revision();\n const flow = this.#qrFlow(input.qrId);\n try {\n const { captcha, ...rest } = input;\n const needsCaptcha = captcha !== undefined || flow.captchaRequired;\n const result = await this.http.execute(AUTH_QR_CLAIM, {\n path: AUTH_PATHS.qrClaim,\n body: { ...rest, ...(needsCaptcha ? await this.#auth.captchaBody(captcha) : {}) },\n skipAuth: true,\n skipAuthRefresh: true,\n cookieJar: flow.cookies,\n ...options,\n });\n\n this.#touchQrFlow(flow, result.expiresIn);\n if (result.status === QrLoginStatus.CaptchaRequired) flow.captchaRequired = true;\n if (result.status === QrLoginStatus.Authorized) {\n await this.#auth.commitAuthFlow(result.accessToken, flow.cookies, revision);\n this.#qrFlows.delete(input.qrId);\n } else if (result.status === QrLoginStatus.Rejected) {\n this.#qrFlows.delete(input.qrId);\n }\n return result;\n } catch (error) {\n this.#forgetTerminalQrError(input.qrId, error);\n throw error;\n }\n }\n\n /**\n * Слушает состояния QR-входа до закрытия ответа или отмены `signal`.\n *\n * Событие `approved` означает, что подтверждение завершено: после него вызовите\n * {@link claimQrLogin}, чтобы получить и сохранить access token.\n */\n async streamQrLogin(\n input: QrLoginStreamInput,\n onEvent: QrLoginStreamListener,\n options: QrLoginStreamOptions = {},\n ): Promise<void> {\n if (typeof onEvent !== 'function') {\n throw new ItdConfigError('onEvent QR-потока должен быть функцией');\n }\n\n const flow = this.#qrFlow(input.qrId);\n try {\n await openQrLoginStream(\n this.#connection,\n flow.cookies,\n input,\n async (event) => {\n this.#touchQrFlow(flow, event.expiresIn);\n if (event.status === QrLoginStreamStatus.Rejected) this.#qrFlows.delete(input.qrId);\n await onEvent(event);\n },\n options.signal,\n );\n } catch (error) {\n this.#forgetTerminalQrError(input.qrId, error);\n throw error;\n }\n }\n\n /**\n * Отмечает QR-код отсканированным и узнаёт, кого впускают.\n *\n * Обратная сторона QR-входа: этот и два соседних метода вызывает устройство, где сессия\n * уже есть. Показывающая сторона увидит статус `scanned`, но вход ещё не состоится —\n * его завершают {@link approveQrLogin} или {@link rejectQrLogin}.\n *\n * Сервер принимает только сессию, созданную мобильным клиентом. Обычный web access token\n * отклоняется с кодом `QR_APPROVER_NOT_ALLOWED`, даже если добавить мобильные заголовки\n * уже после выдачи токена.\n *\n * @param input секреты из отсканированного кода — см. {@link QrLoginSecrets}\n * @returns описание устройства, которое просит вход\n */\n scanQrLogin(input: QrLoginSecrets, options: RequestOptions = {}): Promise<QrLoginTarget> {\n return this.http.execute(AUTH_QR_SCAN, {\n path: AUTH_PATHS.qrScan,\n body: input,\n ...options,\n });\n }\n\n /**\n * Подтверждает вход по QR-коду: показавшее код устройство получит access token.\n *\n * Осмысленно после {@link scanQrLogin} — человек должен увидеть, что подтверждает.\n * Требует мобильную сессию, как и `scanQrLogin()`.\n */\n approveQrLogin(input: QrLoginSecrets, options: RequestOptions = {}): Promise<void> {\n return this.voidOperation(AUTH_QR_APPROVE, {\n path: AUTH_PATHS.qrApprove,\n body: input,\n ...options,\n });\n }\n\n /**\n * Отклоняет вход по QR-коду: показавшее код устройство получит статус `rejected`.\n * Требует мобильную сессию, как и `scanQrLogin()`.\n */\n rejectQrLogin(input: QrLoginSecrets, options: RequestOptions = {}): Promise<void> {\n return this.voidOperation(AUTH_QR_REJECT, {\n path: AUTH_PATHS.qrReject,\n body: input,\n ...options,\n });\n }\n\n /**\n * Регистрирует аккаунт и запускает подтверждение по коду.\n *\n * @returns `flowToken`, который нужно передать в {@link verifyOtp}\n */\n async signUp(credentials: CredentialsWithCaptcha, options: RequestOptions = {}): Promise<string> {\n const { captcha, ...rest } = credentials;\n return this.http.execute(AUTH_SIGN_UP, {\n path: AUTH_PATHS.signUp,\n body: { ...rest, ...(await this.#auth.captchaBody(captcha)) },\n skipAuth: true,\n skipAuthRefresh: true,\n ...options,\n });\n }\n\n /**\n * Выполняет вход.\n *\n * Если сервер потребовал код подтверждения, вернётся `status: 'otp_required'` —\n * тогда продолжайте через {@link verifyOtp} либо воспользуйтесь {@link signInWithOtp}.\n *\n * При успешном входе токен сохраняется в клиенте автоматически.\n *\n * @param credentials email, пароль и токен капчи — см. {@link CredentialsWithCaptcha}\n */\n async signIn(\n credentials: CredentialsWithCaptcha,\n options: RequestOptions = {},\n ): Promise<SignInResult> {\n const { captcha, ...rest } = credentials;\n const revision = this.#auth.revision();\n const cookies = this.#auth.createCookieFlow(false);\n const body = { ...rest, ...(await this.#auth.captchaBody(captcha)) };\n const result = await this.http.execute(AUTH_SIGN_IN, {\n path: AUTH_PATHS.signIn,\n body,\n skipAuth: true,\n skipAuthRefresh: true,\n cookieJar: cookies,\n ...options,\n });\n\n if (result.status === SignInStatus.Authenticated) {\n await this.#auth.commitAuthFlow(result.accessToken, cookies, revision);\n } else {\n this.#auth.commitCookieFlow(cookies, revision);\n }\n return result;\n }\n\n /**\n * Подтверждает вход кодом из письма.\n *\n * Полученный токен сохраняется в клиенте автоматически.\n */\n async verifyOtp(\n input: Credentials & { otp: string; flowToken: string },\n options: RequestOptions = {},\n ): Promise<string> {\n const revision = this.#auth.revision();\n const cookies = this.#auth.createCookieFlow();\n const accessToken = await this.http.execute(AUTH_VERIFY_OTP, {\n path: AUTH_PATHS.verifyOtp,\n body: input,\n skipAuth: true,\n skipAuthRefresh: true,\n cookieJar: cookies,\n ...options,\n });\n\n await this.#auth.commitAuthFlow(accessToken, cookies, revision);\n return accessToken;\n }\n\n /** Отправляет код подтверждения повторно. */\n resendOtp(\n input: { email: string; flowToken: string },\n options: RequestOptions = {},\n ): Promise<void> {\n return this.voidOperation(AUTH_RESEND_OTP, {\n path: AUTH_PATHS.resendOtp,\n body: input,\n skipAuth: true,\n skipAuthRefresh: true,\n ...options,\n });\n }\n\n /**\n * Полный вход с подтверждением по коду.\n *\n * Удобно для скриптов и ботов: код запрашивается функцией `getOtp`, а всё остальное\n * библиотека делает сама.\n *\n * @example\n * ```ts\n * import { createInterface } from 'node:readline/promises';\n *\n * const rl = createInterface({ input: process.stdin, output: process.stdout });\n *\n * const token = await itd.auth.signInWithOtp({\n * email, password,\n * getOtp: () => rl.question('Код из письма: '),\n * });\n * ```\n */\n async signInWithOtp(\n input: CredentialsWithCaptcha & { getOtp: () => string | Promise<string> },\n options: RequestOptions = {},\n ): Promise<string> {\n const { getOtp, ...credentials } = input;\n const result = await this.signIn(credentials, options);\n\n if (result.status === SignInStatus.Authenticated) return result.accessToken;\n\n if (!result.flowToken) {\n throw new ItdConfigError(\n 'Сервер запросил код подтверждения, но не вернул flowToken — продолжить вход невозможно',\n );\n }\n\n const otp = await getOtp();\n\n // Токен капчи сюда не передаётся: он одноразовый и уже потрачен на sign-in,\n // а verify-otp капчу не требует.\n return this.verifyOtp(\n {\n email: credentials.email,\n password: credentials.password,\n otp,\n flowToken: result.flowToken,\n },\n options,\n );\n }\n\n /**\n * Обновляет токен доступа.\n *\n * Параллельные вызовы объединяются в один сетевой запрос. При включённом `autoRefresh`\n * вызывать вручную обычно не нужно.\n */\n refresh(): Promise<string> {\n return this.#auth.refresh();\n }\n\n /**\n * Есть ли признак живой сессии обновления.\n *\n * Проверяет cookie `is_auth`, которую сервер ставит рядом с refresh-токеном, а также\n * refresh-токен, переданный строкой. Позволяет не дёргать API у неавторизованного\n * пользователя. В браузере всегда `true`: cookie ведёт сама среда, и прочитать её\n * из JS нельзя.\n *\n * Читает {@link TokenStorage}, поэтому результат верен и до первого запроса.\n *\n * @example\n * ```ts\n * if (await itd.auth.hasRefreshSession()) await itd.auth.refresh();\n * else redirectToLogin();\n * ```\n */\n hasRefreshSession(): Promise<boolean> {\n return this.#auth.hasRefreshSession();\n }\n\n /** Завершает текущую сессию на сервере и очищает локальную. */\n async logout(options: RequestOptions = {}): Promise<void> {\n await this.voidOperation(AUTH_LOGOUT, {\n path: AUTH_PATHS.logout,\n skipAuthRefresh: true,\n ...options,\n });\n\n await this.#auth.clear();\n }\n\n /**\n * Завершает все сессии пользователя и очищает локальную.\n *\n * Собран из двух запросов, потому что единого эндпоинта на сервере нет:\n * `POST /api/v1/auth/logout-all` отвечает `404`. Сначала отзываются все прочие сессии\n * (`DELETE /api/v1/auth/sessions`), затем завершается текущая — в обратном порядке\n * отзывать было бы уже нечем.\n */\n async logoutAll(options: RequestOptions = {}): Promise<void> {\n await this.revokeOtherSessions(options);\n await this.logout(options);\n }\n\n /** Забывает сессию локально, не обращаясь к серверу. */\n signOut(): Promise<void> {\n return this.#auth.clear();\n }\n\n /**\n * Запрашивает письмо с кодом для сброса пароля.\n *\n * @returns `flowToken`, который нужно передать в {@link resetPassword}\n */\n async forgotPassword(input: ForgotPasswordInput, options: RequestOptions = {}): Promise<string> {\n return this.http.execute(AUTH_FORGOT_PASSWORD, {\n path: AUTH_PATHS.forgotPassword,\n body: { email: input.email, ...(await this.#auth.captchaBody(input.captcha)) },\n skipAuth: true,\n skipAuthRefresh: true,\n ...options,\n });\n }\n\n /**\n * Устанавливает новый пароль по коду из письма.\n *\n * Сервер ждёт все четыре поля сразу — `email`, `otp`, `flowToken` и `newPassword`;\n * при нехватке любого отвечает `422`.\n */\n resetPassword(input: ResetPasswordInput, options: RequestOptions = {}): Promise<void> {\n return this.voidOperation(AUTH_RESET_PASSWORD, {\n path: AUTH_PATHS.resetPassword,\n body: input,\n skipAuth: true,\n skipAuthRefresh: true,\n ...options,\n });\n }\n\n /**\n * Полный сброс пароля с кодом из письма.\n *\n * Тот же приём, что и {@link signInWithOtp}: код запрашивается функцией `getOtp`,\n * остальное библиотека делает сама.\n *\n * @example\n * ```ts\n * await itd.auth.resetPasswordWithOtp({\n * email,\n * captcha: { type: provider, token, field },\n * newPassword,\n * getOtp: () => rl.question('Код из письма: '),\n * });\n * ```\n */\n async resetPasswordWithOtp(\n input: ForgotPasswordInput & {\n newPassword: string;\n getOtp: () => string | Promise<string>;\n },\n options: RequestOptions = {},\n ): Promise<void> {\n const { getOtp, newPassword, ...request } = input;\n const flowToken = await this.forgotPassword(request, options);\n\n const otp = await getOtp();\n\n await this.resetPassword({ email: input.email, otp, flowToken, newPassword }, options);\n }\n\n /**\n * Меняет пароль. Требует действующей сессии.\n *\n * При неверном текущем пароле сервер отвечает `ACCOUNT_CURRENT_PASSWORD_INCORRECT`.\n *\n * @example\n * ```ts\n * await itd.auth.changePassword({ currentPassword, newPassword });\n * ```\n */\n changePassword(\n input: { currentPassword: string; newPassword: string },\n options: RequestOptions = {},\n ): Promise<void> {\n return this.voidOperation(AUTH_CHANGE_PASSWORD, {\n path: AUTH_PATHS.changePassword,\n body: { currentPassword: input.currentPassword, newPassword: input.newPassword },\n ...options,\n });\n }\n\n /** Загружает список активных сессий. У текущей поле `isCurrent` равно `true`. */\n sessions(options: RequestOptions = {}): Promise<Session[]> {\n return this.http.execute(AUTH_SESSIONS, {\n path: AUTH_PATHS.sessions,\n ...options,\n });\n }\n\n /** Завершает указанную сессию. */\n revokeSession(sessionId: string, options: RequestOptions = {}): Promise<void> {\n return this.voidOperation(AUTH_REVOKE_SESSION, {\n path: `${AUTH_PATHS.sessions}/${encodeURIComponent(sessionId)}`,\n ...options,\n });\n }\n\n /** Завершает все сессии, кроме текущей. */\n revokeOtherSessions(options: RequestOptions = {}): Promise<void> {\n return this.voidOperation(AUTH_REVOKE_OTHER_SESSIONS, {\n path: AUTH_PATHS.sessions,\n ...options,\n });\n }\n}\n","import { installAsyncDisposeFallback } from './core/async-dispose.js';\nimport type { Listener, Unsubscribe } from './core/emitter.js';\nimport { ItdConfigError, ItdStateError } from './core/errors.js';\nimport { type ClientRuntime, createClientRuntime } from './core/execution/client-runtime.js';\nimport { ExtensibleOperationCatalog } from './core/feature-catalog.js';\nimport { type ClientFeatureHost, createFeatureHost } from './core/feature-host.js';\nimport type { ClientFeature } from './core/features.js';\nimport type { RawRequestOptions } from './core/options.js';\nimport type { ClientPlugin } from './core/plugins/contracts.js';\nimport type { PluginRegistry } from './core/plugins/registry.js';\nimport type { RateLimitBucketState, RequestQueuePool } from './core/scheduling/rate-limit.js';\nimport type { ServiceDefinition } from './core/services.js';\nimport { ITD_CATALOG } from './domain/catalog.js';\nimport {\n NotificationEvents,\n resolveNotificationEventsOptions,\n setNotificationEventsConnectGuard,\n} from './events/stream.js';\nimport type { UserId } from './models/common.js';\nimport { createNotificationsApi, type NotificationsApi } from './notifications-api.js';\nimport { EVENT_OPERATIONS } from './operations/events.js';\nimport type { ItdClientOptions } from './options.js';\nimport { AuthResource } from './resources/auth.js';\nimport type { CommentsResource } from './resources/comments.js';\nimport type { FilesResource } from './resources/files.js';\nimport type { HashtagsResource } from './resources/hashtags.js';\nimport type { PlatformResource } from './resources/platform.js';\nimport type { PostsResource } from './resources/posts.js';\nimport type { ReportsResource } from './resources/reports.js';\nimport type { SearchResource } from './resources/search.js';\nimport type { ShopResource } from './resources/shop.js';\nimport { createStatusFeature } from './resources/status.js';\nimport type { SubscriptionResource } from './resources/subscription.js';\nimport type { TelemetryResource } from './resources/telemetry.js';\nimport type { UsersResource } from './resources/users.js';\nimport type { VerificationResource } from './resources/verification.js';\nimport { createResources, type RestResources } from './rest/resources.js';\nimport { type AuthEvents, type AuthManager, createItdAuth } from './session/auth.js';\nimport type { ItdSession } from './session/storage.js';\n\nconst CLIENT_PLUGIN_REGISTRIES = new WeakMap<ItdClient, PluginRegistry>();\nconst DISPOSED_CLIENTS = new WeakSet<ItdClient>();\n\nfunction assertClientActive(client: ItdClient, action: string): void {\n if (!DISPOSED_CLIENTS.has(client)) return;\n throw new ItdStateError(\n `ItdClient уже окончательно освобождён через dispose(); нельзя ${action}. Создайте новый клиент`,\n );\n}\n\n/** Проверяет возможность подключить плагин к клиенту без вызова `install()`. @internal */\nexport function assertClientCanUsePlugin(client: ItdClient, plugin: ClientPlugin): void {\n assertClientActive(client, 'подключить плагин');\n CLIENT_PLUGIN_REGISTRIES.get(client)?.assertCanAdd(plugin);\n}\n\n/** Проверяет возможность отключить плагин клиента без изменения реестра. @internal */\nexport function assertClientCanUnusePlugin(client: ItdClient, name: string): void {\n CLIENT_PLUGIN_REGISTRIES.get(client)?.assertCanRemove(name);\n}\n\n/**\n * Скрытые параметры конструктора — не часть публичного API.\n *\n * @internal\n */\ninterface ItdClientInternals {\n /**\n * Готовая очередь запросов — так {@link ItdAccounts} с `rateLimitScope: 'shared'` даёт\n * нескольким клиентам одну на всех. Свою клиент в этом случае не заводит и, что важнее,\n * не гасит при `close()`: чужие ожидающие запросы это отменило бы.\n */\n queues?: RequestQueuePool | undefined;\n}\n\nconst CLIENT_INTERNALS = new WeakMap<ItdClientOptions, ItdClientInternals>();\n\n/** Создаёт клиент с зависимостями внешнего контейнера, не расширяя публичный конструктор. @internal */\nexport function createManagedClient(\n options: ItdClientOptions,\n internals: ItdClientInternals,\n): ItdClient {\n const managedOptions = { ...options };\n CLIENT_INTERNALS.set(managedOptions, internals);\n return new ItdClient(managedOptions);\n}\n\n/**\n * Клиент API итд.com.\n *\n * Методы сгруппированы по разделам: `itd.posts`, `itd.users`, `itd.comments`, `itd.auth`,\n * `itd.files`. Авторизация, обновление токена, повторы и очередь запросов работают сами.\n *\n * @example Готовый токен — для разового вызова\n * ```ts\n * const itd = new ItdClient({ auth: '<accessToken>' });\n * const me = await itd.users.me();\n * ```\n *\n * @example Полноценная сессия для бота\n * ```ts\n * import { ItdClient } from 'itd-api';\n * import { FileTokenStorage } from 'itd-api/node';\n *\n * const itd = new ItdClient({\n * // `auth` не обязателен: когда хранилище уже содержит сессию, токен берётся оттуда,\n * // а истёкший продлевается сам. Здесь он нужен на первый запуск.\n * auth: { email, password },\n * // Капчу входа решает пакет @itd-api/captcha — см. CaptchaSolver.\n * captcha: createCaptchaSolver(),\n * storage: new FileTokenStorage('./.itd-session.json'),\n * rateLimit: { concurrency: 4, rps: 8 },\n * });\n *\n * for await (const post of itd.posts.iterate({ tab: 'following' })) {\n * if (!post.isLiked) await itd.posts.like(post.id);\n * }\n * ```\n */\nexport class ItdClient {\n readonly #runtime: ClientRuntime<AuthManager>;\n readonly #features: ClientFeatureHost;\n /** Общий результат терминальной очистки для идемпотентных повторных вызовов. */\n #disposePromise: Promise<void> | undefined;\n\n /** Ресурсы конвейера запросов; создаются при первом обращении. */\n readonly #resources: RestResources<NotificationsApi>;\n /** Сессионный ресурс живёт у фасада: он управляет входом и продлением. */\n #auth: AuthResource | undefined;\n\n /** Авторизация, сессии и пароли. */\n get auth(): AuthResource {\n this.#auth ??= new AuthResource(this.#runtime.http, {\n auth: this.#runtime.auth,\n connection: this.#runtime.connection(),\n });\n return this.#auth;\n }\n\n /** Профили, подписки, блокировки, приватность. */\n get users(): UsersResource {\n return this.#resources.users;\n }\n\n /** Лента, публикация, реакции, репосты, комментарии к постам. */\n get posts(): PostsResource {\n return this.#resources.posts;\n }\n\n /** Ответы на комментарии и действия над ними. */\n get comments(): CommentsResource {\n return this.#resources.comments;\n }\n\n /** Загрузка файлов и медиа. */\n get files(): FilesResource {\n return this.#resources.files;\n }\n\n /** Уведомления: список, счётчик, отметки о прочтении, настройки. */\n get notifications(): NotificationsApi {\n return this.#resources.notifications;\n }\n\n /** Хэштеги и посты по ним. */\n get hashtags(): HashtagsResource {\n return this.#resources.hashtags;\n }\n\n /** Глобальный поиск по пользователям и хэштегам. */\n get search(): SearchResource {\n return this.#resources.search;\n }\n\n /** Жалобы на контент и пользователей. */\n get reports(): ReportsResource {\n return this.#resources.reports;\n }\n\n /** Верификация профиля. */\n get verification(): VerificationResource {\n return this.#resources.verification;\n }\n\n /** Подписка и способы оплаты. */\n get subscription(): SubscriptionResource {\n return this.#resources.subscription;\n }\n\n /** Сведения о платформе: версии приложений, изменения, анонсы, баннер события. */\n get platform(): PlatformResource {\n return this.#resources.platform;\n }\n\n /** Телеметрия просмотров. */\n get telemetry(): TelemetryResource {\n return this.#resources.telemetry;\n }\n\n /** Каталог, доставка и заказы магазина ИТД. */\n get shop(): ShopResource {\n return this.#resources.shop;\n }\n\n constructor(options: ItdClientOptions = {}) {\n const notificationEventsOptions = resolveNotificationEventsOptions(\n options.events?.notifications,\n );\n const internals = CLIENT_INTERNALS.get(options) ?? {};\n const catalog = new ExtensibleOperationCatalog(ITD_CATALOG);\n let featureHost: ClientFeatureHost | undefined;\n this.#runtime = createClientRuntime(options, {\n catalog,\n queues: internals.queues,\n assertActive: (action) => assertClientActive(this, action),\n // Полноценную сессию подставляет фасад: ядро о ней не знает, и клиент с готовым\n // токеном не потянет за собой ни хранилище, ни вход по паролю.\n auth: (deps) =>\n createItdAuth(options, { ...deps, onAccountChange: () => featureHost?.stop() }),\n });\n this.#features = featureHost = createFeatureHost(this.#runtime, {\n catalog,\n assertActive: (action) => assertClientActive(this, action),\n });\n const status = this.#features.install(createStatusFeature());\n this.#resources = createResources({\n http: this.#runtime.http,\n files: this.#features.files,\n status,\n createNotifications: (http) =>\n createNotificationsApi(http, (notifications) => {\n let events!: NotificationEvents;\n let lifecycleGeneration = 0;\n let lifecycleActive = false;\n let unregister: (() => void) | undefined;\n\n const releaseAfterDrain = (generation: number): void => {\n void events.drain().then(() => {\n if (lifecycleActive || generation !== lifecycleGeneration) return;\n unregister?.();\n unregister = undefined;\n });\n };\n\n events = new NotificationEvents(\n {\n connection: this.#runtime.connection(),\n request: ({ operationId, path, query, signal }) =>\n this.#runtime.http.execute(EVENT_OPERATIONS[operationId], {\n path,\n query,\n signal,\n }),\n getAuthIdentity: () => this.#runtime.auth.getCurrentAuthIdentity(),\n getAuthScope: () => this.#runtime.auth.getAuthScope(),\n fetchUnreadCount: (signal) => notifications.count({ signal }),\n onConnect: () => {\n lifecycleGeneration += 1;\n unregister ??= this.#features.manage({\n kind: `notifications:${events.transport}`,\n stop: () => {\n if (lifecycleActive) events.disconnect();\n },\n drain: () => events.drain(),\n });\n lifecycleActive = true;\n },\n onClose: () => {\n lifecycleActive = false;\n releaseAfterDrain(++lifecycleGeneration);\n },\n logger: this.#runtime.config.logger,\n clock: this.#runtime.config.clock,\n },\n notificationEventsOptions,\n );\n setNotificationEventsConnectGuard(events, () =>\n assertClientActive(this, 'подключить канал событий уведомлений'),\n );\n return events;\n }),\n });\n CLIENT_PLUGIN_REGISTRIES.set(this, this.#runtime.plugins);\n }\n\n /** Базовый URL, к которому обращается клиент. */\n get baseUrl(): string {\n return this.#runtime.config.baseUrl;\n }\n\n /**\n * Выполняет произвольный запрос к API.\n *\n * Запасной путь для случаев, когда нужного метода ещё нет или ответ сервера разошёлся\n * с документацией. Проходит через ту же авторизацию, очередь и обработку ошибок.\n *\n * @example\n * ```ts\n * const raw = await itd.request({ method: 'GET', path: '/api/posts', raw: true });\n * ```\n *\n * @throws {ItdStateError} если клиент уже освобождён через {@link dispose}\n */\n request<T = unknown>(options: RawRequestOptions): Promise<T> {\n return this.#runtime.http.request<T>({\n ...options,\n operationId: options.operationId ?? 'raw',\n });\n }\n\n /**\n * Остаток серверных лимитов по бакетам, через которые уже проходили запросы.\n *\n * Значения берутся из последнего ответа каждого бакета и быстро устаревают: сервер\n * восстанавливает квоту линейно и границу окна не сообщает. Пустой массив при\n * `rateLimit: false`. {@link close} снимок сохраняет, {@link dispose} очищает.\n *\n * @example\n * ```ts\n * const posts = itd.rateLimitState().find((state) => state.bucket === 'posts.create');\n * if ((posts?.remaining ?? Number.POSITIVE_INFINITY) < 3) await sleep(60_000);\n * ```\n */\n rateLimitState(): RateLimitBucketState[] {\n return this.#runtime.rateLimitState();\n }\n\n /**\n * Устанавливает предметный модуль с общей сессией и обработкой запросов клиента.\n *\n * Сервисы, операции и бакеты регистрируются до синхронного `setup()`. Возвращает\n * типизированный API модуля.\n */\n install<TApi>(feature: ClientFeature<TApi>): TApi {\n return this.#features.install(feature);\n }\n\n /**\n * Устанавливает модуль и добавляет его API в свойство клиента только для чтения.\n *\n * Возвращаемое пересечение сохраняет тип уже подключённых свойств, поэтому вызовы можно\n * объединять в цепочку: `new ItdClient().withFeature('pixelBattle', pixelBattleFeature)`.\n */\n withFeature<const K extends string, TApi>(\n key: K,\n feature: ClientFeature<TApi>,\n ): this & { readonly [P in K]: TApi } {\n assertClientActive(this, 'установить feature');\n if (typeof key !== 'string' || key.trim() === '' || key !== key.trim()) {\n throw new ItdConfigError('Свойство feature должно иметь непустое имя без краевых пробелов');\n }\n if (key === 'then' || key in this) {\n throw new ItdConfigError(`Свойство клиента «${key}» уже занято или зарезервировано`);\n }\n if (!Object.isExtensible(this)) {\n throw new ItdConfigError('Нельзя опубликовать feature на нерасширяемом клиенте');\n }\n\n const api = this.install(feature);\n Object.defineProperty(this, key, {\n value: api,\n enumerable: true,\n configurable: false,\n writable: false,\n });\n return this as this & { readonly [P in K]: TApi };\n }\n\n /** Имена установленных модулей в порядке установки. */\n featureNames(): string[] {\n return this.#features.names();\n }\n\n /** Установлен ли модуль с таким именем. */\n hasFeature(name: string): boolean {\n return this.#features.has(name);\n }\n\n /**\n * Подключает плагин.\n *\n * Плагин может регистрировать обёртки операций и перехватчики сетевых попыток.\n *\n * @throws {ItdConfigError} если плагин задан неверно или уже подключён\n * @throws {ItdStateError} если клиент уже освобождён через {@link dispose}\n *\n * @example\n * ```ts\n * import { crypt } from '@itd-api/crypto';\n *\n * itd.use(crypt());\n * await itd.posts.create({\n * content: 'секрет',\n * }, {\n * extensions: { crypto: { encrypt: 'invisible' } },\n * });\n * ```\n */\n use(plugin: ClientPlugin): this {\n assertClientActive(this, 'подключить плагин');\n this.#runtime.plugins.add(plugin, {\n baseUrl: this.#runtime.config.baseUrl,\n logger: this.#runtime.config.logger,\n getAuthScope: () => this.#runtime.auth.getAuthScope(),\n getAuthIdentity: () => this.#runtime.auth.getAuthIdentity(),\n });\n return this;\n }\n\n /** Имена подключённых плагинов в фактическом порядке выполнения обёрток. */\n pluginNames(): string[] {\n return this.#runtime.plugins.names();\n }\n\n /** Подключён ли плагин с таким именем. */\n hasPlugin(name: string): boolean {\n return this.#runtime.plugins.has(name);\n }\n\n /**\n * Отключает плагин и освобождает заведённые им ресурсы.\n *\n * Новые запросы перестают видеть плагин сразу. Очистка дождётся логического запроса,\n * который уже проходил через его обёртку.\n *\n * @returns `false`, если такого плагина не было\n * @throws {ItdConfigError} если от плагина зависит другой подключённый плагин\n */\n unuse(name: string): Promise<boolean> {\n return this.#runtime.plugins.remove(name);\n }\n\n /**\n * Регистрирует сервис платформы — домен, отличный от основного.\n *\n * Запросы с `{ service: 'имя' }` уходят на его хост с его заголовками. То же самое умеет\n * опция `services` конструктора. Занятое имя не переопределяется — ни своё, ни встроенное:\n * разовому запросу хост задаётся полем `baseUrl`.\n *\n * Заголовок авторизации по умолчанию уходит только своим — домену клиента и его\n * поддоменам. Стороннему хосту токен нужно разрешить явно: `auth: true`.\n *\n * @throws {ItdConfigError} если определение неверно или имя уже занято\n * @throws {ItdStateError} если клиент уже освобождён через {@link dispose}\n *\n * @example Сервис платформы на поддомене — токен уходит сам\n * ```ts\n * itd.defineService({\n * name: 'pb',\n * baseUrl: 'https://pbapi.xn--d1ah4a.com',\n * headers: { Referer: 'https://pixel.xn--d1ah4a.com/' },\n * });\n *\n * await itd.request({ method: 'GET', service: 'pb', path: '/api/pixel-info' });\n * ```\n */\n defineService(definition: ServiceDefinition): this {\n assertClientActive(this, 'зарегистрировать сервис');\n this.#runtime.services.define(definition);\n return this;\n }\n\n /**\n * Базовый URL зарегистрированного сервиса.\n *\n * @throws {ItdConfigError} если сервис не зарегистрирован\n */\n serviceBaseUrl(name: string): string {\n return this.#runtime.services.resolveBaseUrl(name);\n }\n\n /**\n * Подписывается на события авторизации.\n *\n * Полезно, чтобы сохранять сессию во внешнее хранилище или узнавать, что вход\n * окончательно потерян.\n *\n * @returns функция отписки\n *\n * @example\n * ```ts\n * itd.on('tokens', ({ accessToken }) => cache.set('itd', accessToken));\n * itd.on('authError', () => notifyUser('Сессия истекла, войдите заново'));\n * ```\n */\n on<K extends keyof AuthEvents>(event: K, listener: Listener<AuthEvents[K]>): Unsubscribe {\n assertClientActive(this, 'подписаться на события');\n return this.#runtime.auth.on(event, listener);\n }\n\n /**\n * Освобождает ресурсы клиента: закрывает все потоки уведомлений, отправляет открытые\n * накопители {@link telemetry}, затем останавливает очередь запросов.\n *\n * Метод дожидается завершения активных обработчиков и освобождения ресурсов остановленных\n * событийных соединений, но не дольше `shutdownTimeout`. После вызова клиентом можно\n * пользоваться снова; ранее созданный поток можно запустить повторным `connect()`.\n *\n * Общая очередь, полученная от {@link ItdAccounts}, не останавливается: её гасит сам\n * контейнер, когда закрывает все аккаунты разом.\n *\n * Терминальное освобождение — это {@link dispose}.\n *\n * @throws {ItdStateError} если остановка событийного соединения не завершилась за отведённый срок\n */\n async close(): Promise<void> {\n return this.#close(false);\n }\n\n async #close(disposeCleanup: boolean): Promise<void> {\n // Terminal cleanup должен пометить batch до первого await: параллельный обычный close()\n // мог уже начать drain потоков, но ещё не дойти до отправки телеметрии.\n if (disposeCleanup) this.#resources.prepareTelemetryClose();\n const errors: unknown[] = [];\n try {\n try {\n await this.#features.close();\n } catch (error) {\n errors.push(error);\n }\n\n // Через геттер закрытие клиента поднимало бы накопитель телеметрии только ради\n // того, чтобы его тут же закрыть.\n try {\n await this.#resources.closeTelemetry(disposeCleanup);\n } catch (error) {\n errors.push(error);\n }\n } finally {\n this.#runtime.close();\n }\n if (errors.length === 1) throw errors[0];\n if (errors.length > 1) throw new AggregateError(errors, 'Не удалось закрыть клиент');\n }\n\n /**\n * Окончательно освобождает клиент: выполняет {@link close}, отменяет незавершённые\n * запросы и отключает все плагины.\n *\n * Терминальное состояние устанавливается сразу при первом вызове. После этого новые\n * запросы, подключение плагинов, регистрация сервисов и создание или повторный запуск\n * событийных каналов завершаются с {@link ItdStateError}. Повторные вызовы возвращают\n * тот же результат очистки.\n *\n * Ожидание остановки событийных соединений и операций плагинов ограничено\n * `shutdownTimeout`.\n *\n * @example\n * ```ts\n * await using itd = new ItdClient({ auth: token });\n * // …работа…\n * // dispose() вызовется сам на выходе из блока\n * ```\n */\n dispose(): Promise<void> {\n if (this.#disposePromise) return this.#disposePromise;\n DISPOSED_CLIENTS.add(this);\n this.#disposePromise = this.#dispose();\n return this.#disposePromise;\n }\n\n async #dispose(): Promise<void> {\n const errors: unknown[] = [];\n try {\n // Сначала завершаем потоки и телеметрию через ещё установленные плагины.\n await this.#close(true);\n } catch (error) {\n errors.push(error);\n }\n try {\n await this.#features.dispose();\n } catch (error) {\n errors.push(error);\n }\n try {\n await this.#runtime.dispose();\n } catch (error) {\n errors.push(error);\n }\n if (errors.length > 0) throw new AggregateError(errors, 'Не удалось освободить клиент');\n }\n\n /** Позволяет использовать клиент с `await using`. */\n [Symbol.asyncDispose](): Promise<void> {\n return this.dispose();\n }\n\n static {\n installAsyncDisposeFallback(ItdClient);\n }\n\n /** Текущая сессия целиком — чтобы сохранить её самостоятельно. */\n getSession(): Promise<ItdSession | null> {\n return this.#runtime.auth.getSession();\n }\n\n /**\n * Идентификатор аккаунта, под которым работает клиент.\n *\n * Читается из токена доступа и не стоит ни одного запроса. `undefined`, когда сессии\n * ещё нет или токен выдан не в формате JWT. Полезен прежде всего с {@link ItdAccounts}:\n * показывает, какому профилю соответствует восстановленная из хранилища запись.\n * Свежий профиль целиком отдаёт `itd.users.me()`.\n *\n * @remarks\n * JWT только декодируется: его подпись не проверяется. Результат подходит для локального\n * разделения состояния, но не доказывает личность пользователя и не заменяет проверку\n * авторизации сервером.\n *\n * @example\n * ```ts\n * for (const [name, itd] of accounts) console.log(name, await itd.getUserId());\n * ```\n */\n getUserId(): Promise<UserId | undefined> {\n return this.#runtime.auth.getUserId();\n }\n\n /**\n * Восстанавливает сохранённую сессию, включая cookie.\n *\n * @throws {ItdStateError} если клиент уже освобождён через {@link dispose}\n */\n setSession(session: ItdSession): Promise<void> {\n try {\n assertClientActive(this, 'изменить сессию');\n } catch (error) {\n return Promise.reject(error);\n }\n return this.#runtime.auth.setSession(session);\n }\n}\n\n/**\n * Создаёт клиент API итд.com.\n *\n * То же, что `new ItdClient(options)`, — для тех, кому привычнее фабрика.\n *\n * @example\n * ```ts\n * const itd = createClient({ auth: token });\n * ```\n */\nexport function createClient(options: ItdClientOptions = {}): ItdClient {\n return new ItdClient(options);\n}\n","import {\n assertClientCanUnusePlugin,\n assertClientCanUsePlugin,\n createManagedClient,\n type ItdClient,\n} from './client.js';\nimport { installAsyncDisposeFallback } from './core/async-dispose.js';\nimport { systemClock } from './core/clock.js';\nimport { DEFAULT_BASE_URL, resolveRateLimit } from './core/config.js';\nimport { Emitter, type Listener, reportListenerError, type Unsubscribe } from './core/emitter.js';\nimport { ItdConfigError, ItdStateError } from './core/errors.js';\nimport type { ClientFeature } from './core/features.js';\nimport type { Logger } from './core/options.js';\nimport type { ClientPlugin } from './core/plugins/contracts.js';\nimport { assertPluginRemovable, orderPluginDefinitions } from './core/plugins/order.js';\nimport { RequestQueuePool } from './core/scheduling/rate-limit.js';\nimport { ITD_CATALOG } from './domain/catalog.js';\nimport type { ItdClientOptions } from './options.js';\nimport {\n type ControlledTokenStorage,\n controlledTokenStorage,\n isRestorableSession,\n MemoryMultiTokenStorage,\n type MultiTokenStorage,\n} from './session/multi-storage.js';\nimport type { TokenStorage } from './session/storage.js';\n\n/** Как аккаунты делят между собой очередь запросов. */\nexport type RateLimitScope = 'account' | 'shared';\n\n/**\n * Фабрика подключаемого модуля для клиентов {@link ItdAccounts}.\n *\n * `create()` вызывается отдельно для каждого аккаунта, поэтому описание модуля и его API\n * между клиентами не разделяется. `key` публикует API как readonly-свойство клиента.\n */\nexport interface AccountFeature<TApi = unknown> {\n readonly key?: string | undefined;\n create(): ClientFeature<TApi>;\n}\n\n/**\n * Опции конструктора {@link ItdAccounts}.\n *\n * Всё, что понимает `ItdClient`, кроме `auth` и `deviceId`: они у каждого аккаунта свои\n * и задаются в {@link ItdAccounts.addAccount}. Остальное достаётся каждому клиенту —\n * источник токена капчи, заданный здесь, работает для всех аккаунтов. Обычный `TokenStorage`\n * клиента здесь заменён\n * общей опцией {@link ItdAccountsOptions.storage} типа {@link MultiTokenStorage}; контейнер\n * сам выдаёт каждому клиенту изолированный срез по имени. Общий `deviceId` особенно вреден —\n * сервер различает по нему записи в списке сессий, и один на всех сложил бы все аккаунты\n * в одну.\n */\nexport interface ItdAccountsOptions\n extends Omit<ItdClientOptions, 'auth' | 'storage' | 'deviceId'> {\n /** Общее хранилище сессий всех аккаунтов. По умолчанию {@link MemoryMultiTokenStorage}. */\n storage?: MultiTokenStorage | undefined;\n /** Плагины, подключаемые каждому аккаунту, в том числе добавленному позже. */\n plugins?: readonly ClientPlugin[] | undefined;\n /** Модули, создаваемые и устанавливаемые отдельно для каждого аккаунта. */\n features?: readonly AccountFeature[] | undefined;\n /**\n * Как делить очередь запросов. По умолчанию `'shared'` — одна на всех.\n *\n * Лимиты итд.com считаются по IP, поэтому аккаунты с одного адреса тратят общую квоту.\n * `'account'` даёт каждому свою очередь и нужен, когда у аккаунтов разные адреса —\n * например, при своём прокси у каждого.\n *\n * В режиме `'shared'` настройки очереди берутся из общей опции `rateLimit`; аккаунту\n * разрешён только `rateLimit: false`, выводящий его из общей очереди.\n */\n rateLimitScope?: RateLimitScope | undefined;\n}\n\n/**\n * Настройки одного аккаунта. Общее мультихранилище задаёт контейнер, а аккаунт получает\n * свой срез автоматически; остальное — как у `ItdClient`.\n *\n * При `rateLimitScope: 'shared'` (умолчание) объект `rateLimit` задаётся только\n * контейнеру; аккаунту разрешено передать `false`, чтобы не ставить его запросы\n * в общую очередь.\n */\nexport type AddAccountOptions = Omit<ItdClientOptions, 'storage'>;\n\n/** Что можно уточнить при удалении аккаунта. */\nexport interface RemoveAccountOptions {\n /**\n * Удалить и сохранённую сессию. По умолчанию `false` — аккаунт убирается только\n * из памяти, а его токены остаются в хранилище и переживут перезапуск.\n */\n forget?: boolean | undefined;\n}\n\n/**\n * События авторизации всех аккаунтов сразу.\n *\n * Те же, что у одиночного клиента, плюс имя аккаунта: подписка на контейнер избавляет\n * от нужды вешать обработчик на каждого.\n */\nexport interface AccountEvents {\n /** Токен получен или обновлён. */\n tokens: { account: string; accessToken: string };\n /** Выполнен вход. */\n signIn: { account: string; accessToken: string };\n /** Сессия очищена — вручную или из-за неудачного обновления. */\n signOut: { account: string };\n /** Обновить сессию не удалось; дальнейшие запросы этого аккаунта будут падать с 401. */\n authError: { account: string; error: unknown };\n}\n\n/** Проверяет имя до создания клиента или частичного восстановления контейнера. */\nfunction validateAccountName(name: string): void {\n if (typeof name !== 'string' || name.trim() === '') {\n throw new ItdConfigError('имя аккаунта должно быть непустой строкой');\n }\n}\n\n/** Проверяет фабрики до создания первого аккаунта. */\nfunction resolveAccountFeatures(features: readonly AccountFeature[] | undefined): AccountFeature[] {\n if (features === undefined) return [];\n if (!Array.isArray(features)) {\n throw new ItdConfigError('features должен быть массивом фабрик подключаемых модулей');\n }\n\n const keys = new Set<string>();\n return features.map((feature, index) => {\n if (typeof feature !== 'object' || feature === null || typeof feature.create !== 'function') {\n throw new ItdConfigError(`features[${index}] должен предоставлять create()`);\n }\n if (feature.key !== undefined) {\n if (\n typeof feature.key !== 'string' ||\n feature.key.trim() === '' ||\n feature.key !== feature.key.trim()\n ) {\n throw new ItdConfigError(\n `features[${index}].key должен быть непустой строкой без пробелов`,\n );\n }\n if (keys.has(feature.key)) {\n throw new ItdConfigError(\n `Свойство подключаемого модуля «${feature.key}» объявлено повторно`,\n );\n }\n keys.add(feature.key);\n }\n const create = feature.create.bind(feature);\n return Object.freeze({\n ...(feature.key === undefined ? {} : { key: feature.key }),\n create,\n });\n });\n}\n\nconst DISPOSED_ACCOUNTS = new WeakSet<ItdAccounts>();\n\nfunction assertAccountsActive(accounts: ItdAccounts, action: string): void {\n if (!DISPOSED_ACCOUNTS.has(accounts)) return;\n throw new ItdStateError(\n `ItdAccounts уже окончательно освобождён через dispose(); нельзя ${action}. Создайте новый контейнер`,\n );\n}\n\n/**\n * Несколько аккаунтов итд.com в одном месте.\n *\n * Контейнер именованных `ItdClient`: каждый аккаунт получает собственный токен, cookie\n * и `deviceId`, а сессии всех складываются в одно хранилище — обычно в один файл, а не\n * в десяток. Имя аккаунта выбираете вы; сервер о нём ничего не знает.\n *\n * @example Бот на нескольких аккаунтах\n * ```ts\n * import { ItdAccounts } from 'itd-api';\n * import { FileMultiTokenStorage } from 'itd-api/node';\n *\n * await using accounts = new ItdAccounts({\n * storage: new FileMultiTokenStorage('./.itd-sessions.json'),\n * // Общие опции достаются каждому аккаунту: один источник токена капчи на всех.\n * captcha: createCaptchaSolver(),\n * rateLimit: { concurrency: 4 },\n * });\n *\n * // Восстанавливаем тех, кто уже входил раньше: токен возьмётся из хранилища.\n * await accounts.restore();\n *\n * if (!accounts.has('kiow')) {\n * accounts.addAccount('kiow', { auth: { email, password } });\n * }\n *\n * await accounts.account('kiow').posts.create({ content: 'привет' });\n *\n * for (const [name, itd] of accounts) {\n * console.log(name, await itd.getUserId());\n * }\n * ```\n */\nexport class ItdAccounts {\n /** Опции, общие для всех аккаунтов, — без полей, которые задаются поаккаунтно. */\n readonly #base: Omit<ItdClientOptions, 'auth' | 'storage' | 'deviceId'>;\n readonly #storage: MultiTokenStorage;\n readonly #clients = new Map<string, ItdClient>();\n /** Имена, чьё удаление ещё не завершилось: повторно занять их пока нельзя. */\n readonly #removing = new Set<string>();\n /** Уже начатые удаления, которых должен дождаться терминальный dispose(). */\n readonly #accountRemovals = new Set<Promise<void>>();\n /** Управляемые срезы хранилища: после удаления аккаунт больше не может писать через свой. */\n readonly #storageControls = new Map<string, ControlledTokenStorage>();\n /** Подписки на события клиентов — снимаются вместе с аккаунтом. */\n readonly #eventUnsubscribers = new Map<string, Unsubscribe[]>();\n /** Плагины для всех: и для уже заведённых аккаунтов, и для будущих. */\n readonly #plugins: ClientPlugin[];\n /** Фабрики модулей для новых и восстанавливаемых аккаунтов. */\n readonly #features: AccountFeature[];\n /** Имена плагинов, чья асинхронная очистка ещё не завершилась. */\n readonly #removingPlugins = new Set<string>();\n /** Общая очередь. `undefined`, когда у каждого аккаунта своя. */\n readonly #queues: RequestQueuePool | undefined;\n readonly #rateLimitScope: RateLimitScope;\n readonly #emitter: Emitter<AccountEvents>;\n readonly #logger: Logger | undefined;\n /** Общий результат терминальной очистки для идемпотентных повторных вызовов. */\n #disposePromise: Promise<void> | undefined;\n\n constructor(options: ItdAccountsOptions = {}) {\n const { storage, plugins, features, rateLimitScope, ...base } = options;\n\n if (\n rateLimitScope !== undefined &&\n rateLimitScope !== 'account' &&\n rateLimitScope !== 'shared'\n ) {\n throw new ItdConfigError(\"rateLimitScope должен быть 'account' или 'shared'\");\n }\n\n this.#base = base;\n this.#storage = storage ?? new MemoryMultiTokenStorage();\n this.#plugins = orderPluginDefinitions(plugins ?? []);\n this.#features = resolveAccountFeatures(features);\n this.#rateLimitScope = rateLimitScope ?? 'shared';\n\n // Общая очередь заводится сразу: проверить опции лучше при создании контейнера,\n // а не при добавлении первого аккаунта.\n const rateLimit =\n this.#rateLimitScope === 'shared' ? resolveRateLimit(base.rateLimit, ITD_CATALOG) : undefined;\n this.#queues = rateLimit\n ? new RequestQueuePool(rateLimit, base.clock ?? systemClock)\n : undefined;\n\n const logger = typeof base.logger === 'object' ? base.logger : undefined;\n this.#logger = logger;\n this.#emitter = new Emitter<AccountEvents>((error) =>\n reportListenerError(logger, 'аккаунтов', error),\n );\n }\n\n /** Общее хранилище сессий — то же, что передано опцией `storage`. */\n get storage(): MultiTokenStorage {\n return this.#storage;\n }\n\n /** Сколько аккаунтов заведено. */\n get size(): number {\n return this.#clients.size;\n }\n\n /** Имена заведённых аккаунтов в порядке добавления. */\n names(): string[] {\n return [...this.#clients.keys()];\n }\n\n /** Заведён ли аккаунт с таким именем. */\n has(name: string): boolean {\n return this.#clients.has(name);\n }\n\n /**\n * Заводит аккаунт.\n *\n * Возвращается обычный `ItdClient` — со всеми ресурсами, плагинами и каналом событий.\n * Хранилище ему подставляется само: срез общего по имени аккаунта.\n *\n * Опция `auth` не обязательна: когда сессия этого аккаунта уже лежит в хранилище,\n * токен возьмётся оттуда, а истёкший продлится сам.\n *\n * @throws {ItdConfigError} если имя пустое или уже занято\n *\n * @example\n * ```ts\n * accounts.addAccount('bot', { auth: { email, password } });\n * accounts.addAccount('reader', { auth: '<accessToken>' });\n * accounts.addAccount('через-прокси', { fetch: proxyFetch('socks5://…') });\n * ```\n */\n addAccount(name: string, options: AddAccountOptions = {}): ItdClient {\n assertAccountsActive(this, 'добавить аккаунт');\n validateAccountName(name);\n if (this.#clients.has(name)) {\n throw new ItdConfigError(\n `аккаунт «${name}» уже добавлен. Возьмите его через accounts.account('${name}')`,\n );\n }\n if (this.#removing.has(name)) {\n throw new ItdConfigError(\n `аккаунт «${name}» ещё удаляется. Дождитесь завершения removeAccount() перед повторным добавлением`,\n );\n }\n if (\n this.#rateLimitScope === 'shared' &&\n options.rateLimit !== undefined &&\n options.rateLimit !== false\n ) {\n throw new ItdConfigError(\n \"при rateLimitScope: 'shared' настройки rateLimit задаются контейнеру; \" +\n 'аккаунту можно передать только rateLimit: false',\n );\n }\n\n const storageControl = controlledTokenStorage(this.#storage, name);\n let client: ItdClient | undefined;\n try {\n client = createManagedClient(\n this.#mergeOptions(options, storageControl.storage),\n this.#queues ? { queues: this.#queues } : {},\n );\n\n for (const plugin of this.#plugins) client.use(plugin);\n for (const feature of this.#features) {\n const manifest = feature.create();\n if (feature.key === undefined) client.install(manifest);\n else client.withFeature(feature.key, manifest);\n }\n } catch (error) {\n storageControl.revoke();\n if (client) {\n void client.dispose().catch((cleanupError: unknown) => {\n this.#reportCleanup('неудачного добавления аккаунта', cleanupError);\n });\n }\n throw error;\n }\n\n const unsubscribers = this.#forwardEvents(name, client);\n this.#storageControls.set(name, storageControl);\n this.#eventUnsubscribers.set(name, unsubscribers);\n this.#clients.set(name, client);\n\n return client;\n }\n\n /**\n * Клиент аккаунта.\n *\n * @throws {ItdConfigError} если такого аккаунта нет\n *\n * @example\n * ```ts\n * await accounts.account('kiow').posts.like(postId);\n * ```\n */\n account(name: string): ItdClient {\n assertAccountsActive(this, 'получить клиент аккаунта');\n const client = this.#clients.get(name);\n if (!client) {\n const known = this.names();\n throw new ItdConfigError(\n `аккаунт «${name}» не заведён. ` +\n (known.length > 0\n ? `Известны: ${known.join(', ')}`\n : 'Ни одного аккаунта нет — добавьте его через addAccount() или restore()'),\n );\n }\n\n return client;\n }\n\n /**\n * Поднимает аккаунты, сессии которых уже лежат в хранилище.\n *\n * То, ради чего мультихранилище знает свой состав: после перезапуска процесса\n * ни `auth`, ни капча не нужны — токен, `deviceId` и cookie берутся из сохранённого.\n * Уже заведённые аккаунты не трогаются. Записи, в которых после выхода остался только\n * `deviceId`, пропускаются: авторизованной сессии в них уже нет.\n *\n * @returns имена добавленных аккаунтов\n *\n * @example\n * ```ts\n * const restored = await accounts.restore();\n * console.log(`подняли ${restored.length} аккаунтов без единого входа`);\n * ```\n */\n async restore(): Promise<string[]> {\n assertAccountsActive(this, 'восстановить аккаунты');\n const saved = await this.#storage.accounts();\n for (const name of saved) validateAccountName(name);\n\n const candidates = [...new Set(saved)].filter((name) => !this.#clients.has(name));\n const sessions = await Promise.all(\n candidates.map(async (name) => ({ name, session: await this.#storage.get(name) })),\n );\n const added: string[] = [];\n\n for (const { name, session } of sessions) {\n if (!isRestorableSession(session, this.#base.baseUrl ?? DEFAULT_BASE_URL)) continue;\n // Пока читали хранилище, аккаунт могли добавить вручную или начать удалять.\n if (this.#clients.has(name) || this.#removing.has(name)) continue;\n this.addAccount(name);\n added.push(name);\n }\n\n return added;\n }\n\n /**\n * Убирает аккаунт: закрывает его клиента и, если попросить, забывает сессию.\n *\n * Сетевого запроса не выполняет. Чтобы завершить сессию на сервере, вызовите\n * `itd.auth.logout()` до удаления.\n *\n * @returns `false`, если такого аккаунта и не было\n */\n async removeAccount(name: string, options: RemoveAccountOptions = {}): Promise<boolean> {\n assertAccountsActive(this, 'удалить аккаунт');\n const client = this.#clients.get(name);\n if (!client) return false;\n\n this.#removing.add(name);\n this.#clients.delete(name);\n const storageControl = this.#storageControls.get(name);\n storageControl?.revoke();\n this.#storageControls.delete(name);\n\n for (const unsubscribe of this.#eventUnsubscribers.get(name) ?? []) unsubscribe();\n this.#eventUnsubscribers.delete(name);\n\n const removal = (async () => {\n const errors: unknown[] = [];\n const closing = await Promise.allSettled([\n client.dispose(),\n storageControl?.drain() ?? Promise.resolve(),\n ]);\n for (const result of closing) {\n if (result.status === 'rejected') errors.push(result.reason);\n }\n\n if (options.forget) {\n await Promise.resolve(this.#storage.clear(name)).catch((error: unknown) => {\n errors.push(error);\n });\n }\n\n if (errors.length > 0) throw errors[0];\n })();\n this.#accountRemovals.add(removal);\n\n try {\n await removal;\n return true;\n } finally {\n this.#accountRemovals.delete(removal);\n this.#removing.delete(name);\n }\n }\n\n /**\n * Подключает плагин всем аккаунтам — и заведённым, и будущим.\n *\n * @throws {ItdConfigError} если плагин задан неверно или уже подключён\n *\n * @example\n * ```ts\n * accounts.use(crypt());\n * ```\n */\n use(plugin: ClientPlugin): this {\n assertAccountsActive(this, 'подключить плагин');\n if (this.#removingPlugins.has(plugin?.name)) {\n throw new ItdConfigError(\n `плагин «${plugin.name}» ещё отключается; дождитесь завершения accounts.unuse()`,\n );\n }\n const ordered = orderPluginDefinitions([...this.#plugins, plugin]);\n const clients = [...this.#clients.values()];\n for (const client of clients) assertClientCanUsePlugin(client, plugin);\n\n const installed: ItdClient[] = [];\n try {\n for (const client of clients) {\n client.use(plugin);\n installed.push(client);\n }\n } catch (error) {\n // remove() исключает запись из реестра до первого await, поэтому видимое состояние\n // откатывается синхронно, а асинхронные teardown завершаются в фоне.\n for (const client of installed.reverse()) {\n void client.unuse(plugin.name).catch((cleanupError: unknown) => {\n this.#reportCleanup(`отката плагина «${plugin.name}»`, cleanupError);\n });\n }\n throw error;\n }\n this.#plugins.splice(0, this.#plugins.length, ...ordered);\n\n return this;\n }\n\n /** Имена общих плагинов в фактическом порядке выполнения обёрток. */\n pluginNames(): string[] {\n return this.#plugins.map((plugin) => plugin.name);\n }\n\n /** Подключён ли общий плагин с таким именем. */\n hasPlugin(name: string): boolean {\n return this.#plugins.some((plugin) => plugin.name === name);\n }\n\n /**\n * Отключает общий плагин у существующих клиентов и не применяет его к будущим.\n *\n * @returns `false`, если такого плагина не было\n * @throws {ItdConfigError} если от плагина зависит другой общий плагин\n */\n async unuse(name: string): Promise<boolean> {\n const index = this.#plugins.findIndex((plugin) => plugin.name === name);\n if (index < 0) return false;\n assertPluginRemovable(this.#plugins, name);\n const clients = [...this.#clients.values()];\n for (const client of clients) assertClientCanUnusePlugin(client, name);\n this.#plugins.splice(index, 1);\n this.#removingPlugins.add(name);\n\n try {\n const results = await Promise.allSettled(clients.map((client) => client.unuse(name)));\n const errors = results\n .filter((result): result is PromiseRejectedResult => result.status === 'rejected')\n .map((result) => result.reason);\n if (errors.length > 0) {\n throw new AggregateError(errors, `Не удалось отключить плагин «${name}» у всех аккаунтов`);\n }\n return true;\n } finally {\n this.#removingPlugins.delete(name);\n }\n }\n\n /**\n * Подписывается на события авторизации всех аккаунтов сразу.\n *\n * @returns функция отписки\n *\n * @example\n * ```ts\n * accounts.on('authError', ({ account }) => console.warn(`${account}: сессия потеряна`));\n * ```\n */\n on<K extends keyof AccountEvents>(event: K, listener: Listener<AccountEvents[K]>): Unsubscribe {\n assertAccountsActive(this, 'подписаться на события');\n return this.#emitter.on(event, listener);\n }\n\n /**\n * Перебор аккаунтов парами «имя — клиент».\n *\n * @example\n * ```ts\n * for (const [name, itd] of accounts) {\n * const me = await itd.users.me();\n * console.log(name, me.nickname);\n * }\n * ```\n */\n [Symbol.iterator](): IterableIterator<[string, ItdClient]> {\n return this.#clients.entries();\n }\n\n /**\n * Закрывает все аккаунты и останавливает общую очередь.\n *\n * Аккаунты остаются в контейнере и работоспособны: новые запросы поднимут всё заново,\n * но уже созданные потоки уведомлений останутся закрытыми.\n *\n * @example\n * ```ts\n * await using accounts = new ItdAccounts({ storage });\n * // …работа…\n * // dispose() вызовется сам на выходе из блока\n * ```\n */\n async close(): Promise<void> {\n try {\n await Promise.all([...this.#clients.values()].map((client) => client.close()));\n } finally {\n this.#queues?.stop();\n }\n }\n\n /**\n * Окончательно освобождает контейнер и отключает общие плагины у всех аккаунтов.\n *\n * Для временной остановки потоков и очереди без отключения плагинов используйте\n * {@link close}. Терминальное состояние устанавливается сразу: контейнер отзывает\n * storage-срезы и подписки, а новые аккаунты, запросы его клиентов и плагины после\n * первого `dispose()` больше не допускаются.\n */\n dispose(): Promise<void> {\n if (this.#disposePromise) return this.#disposePromise;\n DISPOSED_ACCOUNTS.add(this);\n this.#disposePromise = this.#dispose();\n return this.#disposePromise;\n }\n\n async #dispose(): Promise<void> {\n const clients = [...this.#clients.values()];\n const controls = [...this.#storageControls.values()];\n const accountRemovals = [...this.#accountRemovals];\n\n for (const control of controls) control.revoke();\n for (const unsubscribers of this.#eventUnsubscribers.values()) {\n for (const unsubscribe of unsubscribers) unsubscribe();\n }\n this.#eventUnsubscribers.clear();\n this.#storageControls.clear();\n this.#clients.clear();\n this.#emitter.removeAllListeners();\n\n const results = await Promise.allSettled([\n ...clients.map((client) => client.dispose()),\n ...controls.map((control) => control.drain()),\n ...accountRemovals,\n Promise.resolve().then(() => this.#queues?.clear()),\n ]);\n this.#plugins.splice(0);\n this.#features.splice(0);\n this.#removingPlugins.clear();\n\n const errors = results\n .filter((result): result is PromiseRejectedResult => result.status === 'rejected')\n .map((result) => result.reason);\n if (errors.length > 0) throw new AggregateError(errors, 'Не удалось освободить аккаунты');\n }\n\n /** Позволяет использовать контейнер с `await using`. */\n [Symbol.asyncDispose](): Promise<void> {\n return this.dispose();\n }\n\n static {\n installAsyncDisposeFallback(ItdAccounts);\n }\n\n /**\n * Собирает опции клиента: общие, поверх них — аккаунтные, и обязательно свой срез\n * хранилища.\n *\n * `headers` и `services` сливаются по ключам, а не заменяются целиком: иначе один свой\n * заголовок у аккаунта стирал бы весь общий набор.\n */\n #mergeOptions(options: AddAccountOptions, storage: TokenStorage): ItdClientOptions {\n const base = this.#base;\n\n return {\n ...base,\n ...options,\n ...(base.headers || options.headers\n ? { headers: { ...base.headers, ...options.headers } }\n : {}),\n ...(base.services || options.services\n ? { services: { ...base.services, ...options.services } }\n : {}),\n storage,\n };\n }\n\n /** Не теряет ошибку фонового освобождения ресурсов, которого синхронный API не ждёт. */\n #reportCleanup(scope: string, error: unknown): void {\n const message = `Не удалось освободить ресурсы после ${scope}`;\n if (this.#logger) this.#logger.error(message, error);\n else console.error(`[itd-api] ${message}`, error);\n }\n\n /** Ретранслирует события клиента наружу, добавляя к ним имя аккаунта. */\n #forwardEvents(account: string, client: ItdClient): Unsubscribe[] {\n return [\n client.on('tokens', ({ accessToken }) =>\n this.#emitter.emit('tokens', { account, accessToken }),\n ),\n client.on('signIn', ({ accessToken }) =>\n this.#emitter.emit('signIn', { account, accessToken }),\n ),\n client.on('signOut', () => this.#emitter.emit('signOut', { account })),\n client.on('authError', ({ error }) => this.#emitter.emit('authError', { account, error })),\n ];\n }\n}\n\n/**\n * Создаёт контейнер аккаунтов.\n *\n * То же, что `new ItdAccounts(options)`, — для тех, кому привычнее фабрика.\n */\nexport function createAccounts(options: ItdAccountsOptions = {}): ItdAccounts {\n return new ItdAccounts(options);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["NotificationsResource","#createEvents","#events","CaptchaType","CaptchaField","pickString","ItdConfigError","passthroughOperation","defineBuiltInOperation","voidOperation","pickArray","ItdConfigError","isRecord","CaptchaChoice","ItdConfigError","MemoryTokenStorage","isRecord","copySession","isSerializedCookieEntry","#config","#http","#jar","#emitter","#hooks","Emitter","reportListenerError","#assertActive","#disposed","#externalReadGeneration","#invalidateInFlight","#tokenMetadata","#authScope","#loadSession","#identityForToken","#readExternalToken","#session","#sessionFromConfig","#externalIdentity","#authEpoch","CookieJar","ItdStateError","#metadataForToken","#externalToken","#rotateAuthScope","#hasRefreshSession","#signInWithCredentials","#refreshDeduplicated","#deviceId","#deviceIdLoading","#resolveDeviceId","createDeviceId","#saveSession","#noRefreshSessionError","ItdAuthError","#storeAccessToken","#transitionAuth","#seedRefreshCookie","#enqueuePersistence","#loading","#performLoad","REFRESH_COOKIE","REFRESH_COOKIE_PATH","#persistence","#refreshing","#performRefresh","#matchesRefreshExpectation","#currentAccessToken","#reloginOrNull","#signingIn","#performSignIn","#takeConfiguredCaptcha","#resolveCaptchaProvider","#configCaptchaSpent","isItdApiError","ItdErrorCode","CaptchaType","CaptchaField","isRecord","createParser","joinUrl","createRequestAbortScope","ItdNetworkError","requestAbortError","createApiError","BaseResource","#auth","#connection","#qrFlows","#pruneQrFlows","isItdApiError","#touchQrFlow","#qrFlow","#forgetTerminalQrError","ItdConfigError","ItdStateError","#runtime","#features","#resources","#auth","resolveNotificationEventsOptions","ExtensibleOperationCatalog","ITD_CATALOG","createClientRuntime","createFeatureHost","createStatusFeature","createResources","NotificationEvents","EVENT_OPERATIONS","ItdConfigError","#close","#disposePromise","#dispose","ItdConfigError","ItdStateError","#base","#storage","#clients","#removing","#accountRemovals","#storageControls","#eventUnsubscribers","#plugins","#features","#removingPlugins","#queues","#rateLimitScope","#emitter","#logger","MemoryMultiTokenStorage","orderPluginDefinitions","resolveRateLimit","ITD_CATALOG","RequestQueuePool","systemClock","Emitter","reportListenerError","controlledTokenStorage","#mergeOptions","#reportCleanup","#forwardEvents","isRestorableSession","#disposePromise","#dispose"],"sources":["../src/notifications-api.ts","../src/operations/auth.ts","../src/session/captcha.ts","../src/session/jwt.ts","../src/session/auth.ts","../src/session/qr-stream.ts","../src/resources/auth.ts","../src/client.ts","../src/accounts.ts"],"sourcesContent":["import type { HttpClient } from './core/execution/http.js';\nimport type { NotificationEvents } from './events/stream.js';\nimport { NotificationsResource } from './resources/notifications.js';\n\n/** Уведомления полного клиента: REST-методы и стабильный канал событий. */\nexport interface NotificationsApi extends NotificationsResource {\n /** Один канал событий уведомлений на всё время жизни клиента. */\n readonly events: NotificationEvents;\n}\n\nclass ClientNotifications extends NotificationsResource implements NotificationsApi {\n readonly #createEvents: (resource: NotificationsResource) => NotificationEvents;\n #events: NotificationEvents | undefined;\n\n constructor(\n http: HttpClient,\n createEvents: (resource: NotificationsResource) => NotificationEvents,\n ) {\n super(http);\n this.#createEvents = createEvents;\n }\n\n get events(): NotificationEvents {\n this.#events ??= this.#createEvents(this);\n return this.#events;\n }\n}\n\n/** Создаёт API уведомлений полного клиента. @internal */\nexport function createNotificationsApi(\n http: HttpClient,\n createEvents: (resource: NotificationsResource) => NotificationEvents,\n): NotificationsApi {\n return new ClientNotifications(http, createEvents);\n}\n","import { ItdConfigError } from '../core/errors.js';\nimport { pickArray, pickString } from '../core/unwrap.js';\nimport { defineBuiltInOperation } from '../domain/operations.js';\nimport type { QrLoginTarget, Session } from '../models/account.js';\nimport type { AuthState } from '../models/users.js';\nimport { CaptchaField, CaptchaType } from '../types/enums.js';\nimport { passthroughOperation, voidOperation } from './common.js';\n\n/** Чем закончился запрос входа. */\nexport const SignInStatus = Object.freeze({\n Authenticated: 'authenticated',\n OtpRequired: 'otp_required',\n} as const);\nexport type SignInStatus = (typeof SignInStatus)[keyof typeof SignInStatus];\n\n/** Результат входа: готовый токен либо продолжение через код подтверждения. */\nexport type SignInResult =\n | { status: 'authenticated'; accessToken: string }\n | { status: 'otp_required'; flowToken: string | undefined };\n\n/**\n * Активный провайдер капчи и поле запроса, в котором сервер ждёт токен.\n *\n * Оба значения открытые: провайдер может появиться новый, а имя поля сервер вправе сменить.\n */\nexport interface CaptchaProvider {\n provider: CaptchaType;\n field: CaptchaField;\n}\n\n/**\n * Активный провайдер капчи вместе с адресом готовой страницы виджета.\n *\n * Страница собрана на домене итд.com, поэтому ключ виджета на ней действителен: её открывают\n * во встроенном браузере и забирают токен оттуда.\n */\nexport interface CaptchaPage extends CaptchaProvider {\n url: string;\n}\n\n/**\n * Доказательство прохождения капчи: токен и его провайдер.\n *\n * Имя поля тела запроса SDK подставляет сам — из {@link CaptchaToken.field}, иначе\n * из {@link CAPTCHA_FIELDS}.\n */\nexport interface CaptchaToken {\n type: CaptchaType;\n token: string;\n /** Поле тела запроса. Нужно, только если сервер переименовал его. */\n field?: CaptchaField | undefined;\n}\n\n/**\n * Поле тела запроса по умолчанию для известных провайдеров.\n *\n * Используется, когда провайдера не спрашивали. Ответ `captchaProvider()` важнее этой таблицы.\n */\nexport const CAPTCHA_FIELDS = Object.freeze({\n [CaptchaType.Itd]: CaptchaField.Itd,\n [CaptchaType.Cloudflare]: CaptchaField.Cloudflare,\n} as const);\n\n/** Данные, из которых клиент строит QR-код входа. */\nexport interface QrLoginStart {\n qrId: string;\n claimToken: string;\n payload: string;\n expiresIn: number;\n captchaRequired: boolean;\n}\n\n/** Состояния, которые может вернуть проверка QR-входа. */\nexport const QrLoginStatus = Object.freeze({\n Pending: 'pending',\n Scanned: 'scanned',\n CaptchaRequired: 'captcha_required',\n Authorized: 'authorized',\n Rejected: 'rejected',\n} as const);\nexport type QrLoginStatus = (typeof QrLoginStatus)[keyof typeof QrLoginStatus];\n\n/** Результат проверки QR-входа. */\nexport type QrLoginClaim =\n | { status: 'authorized'; accessToken: string; expiresIn?: number }\n | {\n status: 'pending' | 'scanned' | 'captcha_required' | 'rejected';\n expiresIn?: number;\n };\n\n/** Состояния, приходящие из потокового наблюдения за QR-входом. */\nexport const QrLoginStreamStatus = Object.freeze({\n Pending: 'pending',\n Scanned: 'scanned',\n Approved: 'approved',\n Rejected: 'rejected',\n} as const);\nexport type QrLoginStreamStatus = (typeof QrLoginStreamStatus)[keyof typeof QrLoginStreamStatus];\n\n/** Одно событие `POST /api/v1/auth/qr/stream`. */\nexport interface QrLoginStreamEvent {\n status: QrLoginStreamStatus;\n expiresIn?: number;\n}\n\nfunction requireString(body: unknown, key: string, message: string): string {\n const value = pickString(body, key);\n if (!value) throw new ItdConfigError(message);\n return value;\n}\n\nexport const AUTH_CHECK = passthroughOperation<AuthState>('auth.check');\nexport const AUTH_CAPTCHA_PROVIDER = passthroughOperation<CaptchaProvider>('auth.captchaProvider');\nexport const AUTH_CAPTCHA_PAGE = passthroughOperation<CaptchaPage>('auth.captchaPage');\nexport const AUTH_SIGN_UP = defineBuiltInOperation<string>('auth.signUp', (body) =>\n requireString(body, 'flowToken', 'Сервер не вернул flowToken при регистрации'),\n);\nexport const AUTH_SIGN_IN = defineBuiltInOperation<SignInResult>('auth.signIn', (body) => {\n const accessToken = pickString(body, 'accessToken');\n return accessToken\n ? { status: SignInStatus.Authenticated, accessToken }\n : { status: SignInStatus.OtpRequired, flowToken: pickString(body, 'flowToken') };\n});\nexport const AUTH_VERIFY_OTP = defineBuiltInOperation<string>('auth.verifyOtp', (body) =>\n requireString(body, 'accessToken', 'Сервер не вернул accessToken после подтверждения кода'),\n);\nexport const AUTH_REFRESH = defineBuiltInOperation<string>('auth.refresh', (body) =>\n requireString(body, 'accessToken', 'Сервер не вернул accessToken при обновлении сессии'),\n);\nexport const AUTH_RESEND_OTP = voidOperation('auth.resendOtp');\nexport const AUTH_LOGOUT = voidOperation('auth.logout');\nexport const AUTH_FORGOT_PASSWORD = defineBuiltInOperation<string>('auth.forgotPassword', (body) =>\n requireString(body, 'flowToken', 'Сервер не вернул flowToken при запросе сброса пароля'),\n);\nexport const AUTH_RESET_PASSWORD = voidOperation('auth.resetPassword');\nexport const AUTH_CHANGE_PASSWORD = voidOperation('auth.changePassword');\nexport const AUTH_SESSIONS = defineBuiltInOperation<Session[]>('auth.sessions', (body) =>\n pickArray<Session>(body, 'sessions'),\n);\nexport const AUTH_REVOKE_SESSION = voidOperation('auth.revokeSession');\nexport const AUTH_REVOKE_OTHER_SESSIONS = voidOperation('auth.revokeOtherSessions');\nexport const AUTH_QR_START = passthroughOperation<QrLoginStart>('auth.qrStart');\nexport const AUTH_QR_CLAIM = passthroughOperation<QrLoginClaim>('auth.qrClaim');\nexport const AUTH_QR_SCAN = passthroughOperation<QrLoginTarget>('auth.qrScan');\nexport const AUTH_QR_APPROVE = voidOperation('auth.qrApprove');\nexport const AUTH_QR_REJECT = voidOperation('auth.qrReject');\n","import { ItdConfigError } from '../core/errors.js';\nimport { isRecord } from '../core/validate.js';\nimport { CAPTCHA_FIELDS, type CaptchaProvider, type CaptchaToken } from '../operations/auth.js';\nimport { CaptchaChoice, type CaptchaField, type CaptchaType } from '../types/enums.js';\nimport type { CaptchaSolver } from './options.js';\n\n/** Капча запросов, которые её требуют: входа, регистрации, сброса пароля и QR-подтверждения. */\n\n/** Готовый фрагмент тела запроса: имя поля и токен в нём. */\nexport type CaptchaBody = Record<string, string>;\n\nfunction requireCaptchaText(value: unknown, field: string): void {\n if (value !== undefined && (typeof value !== 'string' || value.trim() === '')) {\n throw new ItdConfigError(`${field} должен быть непустой строкой`);\n }\n}\n\n/**\n * Проверяет форму источника токена и приводит его к объекту.\n *\n * Сам объект сохраняется как есть: `getToken` вызывается на нём, чтобы источнику остался\n * доступен собственный `this`.\n *\n * @throws {ItdConfigError} при некорректных значениях\n */\nexport function resolveCaptchaSolver(captcha: unknown): CaptchaSolver | undefined {\n if (captcha === undefined) return undefined;\n\n if (typeof captcha === 'function') {\n return { getToken: captcha as CaptchaSolver['getToken'] };\n }\n\n if (!isRecord(captcha)) {\n throw new ItdConfigError('captcha должен быть функцией либо объектом с getToken');\n }\n\n const { getToken, type, field } = captcha as Record<string, unknown>;\n\n if (typeof getToken !== 'function') {\n throw new ItdConfigError('captcha.getToken должен быть функцией');\n }\n requireCaptchaText(type, 'captcha.type');\n requireCaptchaText(field, 'captcha.field');\n\n return captcha as unknown as CaptchaSolver;\n}\n\n/**\n * Проверяет форму готового токена капчи.\n *\n * @param path имя опции или аргумента для текста ошибки\n * @throws {ItdConfigError} если токен или его тип не указаны\n */\nexport function validateCaptchaToken(captcha: unknown, path: string): void {\n if (captcha === undefined) return;\n if (!isRecord(captcha)) {\n throw new ItdConfigError(`${path} должен быть объектом { type, token }`);\n }\n\n const { type, token, field } = captcha as Record<string, unknown>;\n\n if (typeof token !== 'string' || token.trim() === '') {\n throw new ItdConfigError(`${path}.token должен быть непустой строкой`);\n }\n if (typeof type !== 'string' || type.trim() === '') {\n throw new ItdConfigError(`${path}.type должен быть непустой строкой`);\n }\n requireCaptchaText(field, `${path}.field`);\n}\n\n/** Разбирает ответ `GET /api/v1/auth/captcha/provider` для автоматического входа. */\nexport function readCaptchaProvider(body: unknown): CaptchaProvider {\n const config = isRecord(body) ? (body as Record<string, unknown>) : undefined;\n const provider = config?.provider;\n const field = config?.field;\n\n if (\n typeof provider !== 'string' ||\n provider.trim() === '' ||\n typeof field !== 'string' ||\n field.trim() === ''\n ) {\n throw new ItdConfigError('Сервер вернул неподдерживаемую конфигурацию капчи');\n }\n\n return { provider, field };\n}\n\n/** Куда класть токен: настройка, иначе умолчание провайдера. */\nfunction resolveField(type: CaptchaType, configured: CaptchaField | undefined): CaptchaField {\n const field = configured ?? CAPTCHA_FIELDS[type as keyof typeof CAPTCHA_FIELDS];\n if (field) return field;\n\n throw new ItdConfigError(\n `Неизвестно, в каком поле сервер ждёт токен капчи «${type}». Передайте captcha.field ` +\n `либо оставьте captcha.type = ${CaptchaChoice.Auto}, чтобы поле назвал сервер.`,\n );\n}\n\n/** Спрашивает токен у источника и убеждается, что он непустой. */\nasync function requireSolvedToken(solver: CaptchaSolver, type: CaptchaType): Promise<string> {\n const token = await solver.getToken(type);\n if (typeof token === 'string' && token.trim() !== '') return token;\n\n throw new ItdConfigError(\n `Источник капчи не вернул токен для провайдера «${type}». Проверьте captcha.getToken.`,\n );\n}\n\n/**\n * Готовит фрагмент тела запроса, взяв токен у источника.\n *\n * При `CaptchaChoice.Auto` провайдер спрашивается у сервера — тогда и тип виджета,\n * и имя поля приходят оттуда. Явно названный тип обходится без этого запроса.\n *\n * @param askProvider как спросить активного провайдера; вызывается, только если это нужно\n * @throws {ItdConfigError} если токен получить не удалось\n */\nexport async function solveCaptchaBody(\n solver: CaptchaSolver,\n askProvider: () => Promise<CaptchaProvider>,\n): Promise<CaptchaBody> {\n const choice = solver.type ?? CaptchaChoice.Auto;\n\n if (choice === CaptchaChoice.Auto) {\n const { provider, field } = await askProvider();\n return { [field]: await requireSolvedToken(solver, provider) };\n }\n\n return { [resolveField(choice, solver.field)]: await requireSolvedToken(solver, choice) };\n}\n\n/**\n * Готовит фрагмент тела из готового токена.\n *\n * Поле берётся из самого токена либо из умолчания провайдера; запроса к серверу нет.\n *\n * @throws {ItdConfigError} если токен или его тип не указаны\n */\nexport function captchaBody(captcha: CaptchaToken): CaptchaBody {\n validateCaptchaToken(captcha, 'captcha');\n\n return { [resolveField(captcha.type, captcha.field)]: captcha.token };\n}\n","/**\n * Разбирает строку base64url.\n *\n * `atob` понимает только обычный base64, поэтому алфавит приводится к нему, а недостающее\n * выравнивание добивается. Результат декодируется как UTF-8: в полезной нагрузке токена\n * может оказаться кириллица, и «бинарная» строка из `atob` сломала бы `JSON.parse`.\n */\nfunction decodeBase64Url(segment: string): string {\n const base64 = segment.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), '=');\n\n const binary = atob(padded);\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n\n return new TextDecoder().decode(bytes);\n}\n\n/** Читает полезную нагрузку JWT без проверки подписи. */\nfunction readTokenPayload(token: string): Record<string, unknown> | undefined {\n try {\n const payload = token.split('.')[1];\n if (!payload) return undefined;\n\n const parsed: unknown = JSON.parse(decodeBase64Url(payload));\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return undefined;\n return parsed as Record<string, unknown>;\n } catch {\n // Непрозрачный или повреждённый токен допустим: его свойства просто неизвестны.\n return undefined;\n }\n}\n\n/** Идентификаторы владельца и сессии, прочитанные из JWT без проверки подписи. */\nexport interface TokenIdentity {\n subject?: string | undefined;\n sessionId?: string | undefined;\n}\n\n/** Локально используемые поля JWT. */\nexport interface TokenMetadata extends TokenIdentity {\n expiresAt?: number | undefined;\n}\n\n/** Читает используемые клиентом поля JWT за один раз. */\nexport function readTokenMetadata(token: string): TokenMetadata {\n const payload = readTokenPayload(token);\n if (!payload) return {};\n\n const { sub, sid, exp } = payload;\n const expiresAt = typeof exp === 'number' && Number.isFinite(exp) ? exp * 1000 : undefined;\n return {\n ...(typeof sub === 'string' && sub.length > 0 ? { subject: sub } : {}),\n ...(typeof sid === 'string' && sid.length > 0 ? { sessionId: sid } : {}),\n ...(expiresAt !== undefined && Number.isFinite(expiresAt) ? { expiresAt } : {}),\n };\n}\n\n/**\n * Читает `sub` и `sid` из полезной нагрузки JWT.\n *\n * Подпись не проверяется — ключа для проверки у клиента нет. Прочитанные значения служат\n * лишь метками для разделения локального состояния и не дают доступа: его определяет сервер.\n */\nexport function readTokenIdentity(token: string): TokenIdentity {\n const { subject, sessionId } = readTokenMetadata(token);\n return { ...(subject ? { subject } : {}), ...(sessionId ? { sessionId } : {}) };\n}\n\n/**\n * Читает срок действия JWT из claim `exp`.\n *\n * JWT хранит NumericDate в секундах, а остальное ядро использует миллисекунды. Подпись\n * намеренно не проверяется: значение служит только подсказкой для раннего refresh, а\n * окончательное решение о действительности токена всё равно принимает сервер.\n *\n * @returns момент истечения в миллисекундах либо `undefined` для непрозрачного,\n * повреждённого JWT или некорректного `exp`\n */\nexport function readTokenExpiration(token: string): number | undefined {\n return readTokenMetadata(token).expiresAt;\n}\n\n/**\n * Читает `sub` из полезной нагрузки JWT.\n *\n * @returns идентификатор владельца токена; `undefined`, если токен не JWT, повреждён\n * или поля `sub` в нём нет\n */\nexport function readTokenSubject(token: string): string | undefined {\n return readTokenIdentity(token).subject;\n}\n","import type { AuthIdentity, AuthProvider, AuthProviderDeps } from '../core/auth-provider.js';\nimport type { ItdClock } from '../core/clock.js';\nimport {\n AUTH_FLAG_COOKIE,\n CookieJar,\n isSerializedCookieEntry,\n REFRESH_COOKIE,\n REFRESH_COOKIE_PATH,\n} from '../core/cookies.js';\nimport { Emitter, reportListenerError } from '../core/emitter.js';\nimport { ItdAuthError, ItdConfigError, ItdStateError, isItdApiError } from '../core/errors.js';\nimport type { HttpClient } from '../core/execution/http.js';\nimport type { Logger } from '../core/options.js';\nimport { createDeviceId } from '../core/runtime.js';\nimport { isRecord, requireOptionalBoolean } from '../core/validate.js';\nimport type { UserId } from '../models/common.js';\nimport {\n AUTH_CAPTCHA_PROVIDER,\n AUTH_REFRESH,\n AUTH_SIGN_IN,\n type CaptchaProvider,\n type CaptchaToken,\n SignInStatus,\n} from '../operations/auth.js';\nimport { CaptchaField, CaptchaType, ItdErrorCode } from '../types/enums.js';\nimport {\n type CaptchaBody,\n captchaBody,\n readCaptchaProvider,\n resolveCaptchaSolver,\n solveCaptchaBody,\n validateCaptchaToken,\n} from './captcha.js';\nimport { readTokenMetadata, type TokenMetadata } from './jwt.js';\nimport type { AuthInput, CaptchaSolver, CredentialsAuth, SessionOptions } from './options.js';\nimport { copySession, type ItdSession, MemoryTokenStorage, type TokenStorage } from './storage.js';\n\n/** Запас до истечения токена на очередь и выполнение запроса. */\nconst ACCESS_TOKEN_REFRESH_LEEWAY_MS = 30_000;\n\n/**\n * Настройки сессии после подстановки умолчаний и проверок.\n *\n * Часть полей заимствована у {@link ResolvedRuntimeConfig}: сессия ходит на тот же хост,\n * теми же часами и с тем же логгером, но остальные настройки исполнения ей не нужны.\n */\nexport interface SessionConfig {\n baseUrl: string;\n clock: ItdClock;\n useCookieJar: boolean;\n logger: Logger | undefined;\n auth: AuthInput | undefined;\n captcha: CaptchaSolver | undefined;\n storage: TokenStorage;\n deviceId: string | undefined;\n autoRefresh: boolean;\n reloginOnRefreshFailure: boolean;\n}\n\n/**\n * Проверяет форму `auth` и сообщает о типичных ошибках понятным текстом.\n *\n * Молчаливое игнорирование неверной формы приводит к загадочным `401`, поэтому\n * ошибка возникает сразу при создании клиента.\n */\nfunction validateAuth(auth: AuthInput | undefined): AuthInput | undefined {\n if (auth === undefined) return undefined;\n\n if (typeof auth === 'string') {\n if (auth.trim() === '') {\n throw new ItdConfigError('auth: передана пустая строка вместо accessToken');\n }\n return auth;\n }\n\n if (typeof auth !== 'object' || auth === null) {\n throw new ItdConfigError(\n `auth должен быть строкой с токеном или объектом, получено: ${typeof auth}`,\n );\n }\n\n const modes = [\n 'getToken' in auth,\n 'accessToken' in auth || 'refreshToken' in auth,\n 'email' in auth || 'password' in auth,\n ].filter(Boolean).length;\n if (modes > 1) {\n throw new ItdConfigError(\n 'auth должен описывать ровно один способ авторизации: getToken, accessToken или email/password',\n );\n }\n\n if ('getToken' in auth) {\n if (typeof auth.getToken !== 'function') {\n throw new ItdConfigError('auth.getToken должен быть функцией');\n }\n return { ...auth };\n }\n\n if ('accessToken' in auth) {\n if (typeof auth.accessToken !== 'string' || auth.accessToken.trim() === '') {\n throw new ItdConfigError('auth.accessToken должен быть непустой строкой');\n }\n if (\n auth.refreshToken !== undefined &&\n (typeof auth.refreshToken !== 'string' || auth.refreshToken.trim() === '')\n ) {\n throw new ItdConfigError('auth.refreshToken должен быть непустой строкой');\n }\n return { ...auth };\n }\n\n if ('email' in auth || 'password' in auth) {\n const { email, password, captcha } = auth as {\n email?: unknown;\n password?: unknown;\n captcha?: unknown;\n };\n if (typeof email !== 'string' || email.trim() === '') {\n throw new ItdConfigError('auth.email должен быть непустой строкой');\n }\n if (typeof password !== 'string' || password === '') {\n throw new ItdConfigError('auth.password должен быть непустой строкой');\n }\n\n validateCaptchaToken(captcha, 'auth.captcha');\n\n return { ...auth };\n }\n\n throw new ItdConfigError(\n 'auth не распознан. Ожидается строка с accessToken либо объект ' +\n '{ accessToken }, { email, password } или { getToken }',\n );\n}\n\nfunction resolveStorage(storage: TokenStorage | undefined): TokenStorage {\n if (storage === undefined) return new MemoryTokenStorage();\n if (!isRecord(storage)) throw new ItdConfigError('storage должен быть объектом TokenStorage');\n\n for (const method of ['get', 'set', 'clear'] as const) {\n if (typeof storage[method] !== 'function') {\n throw new ItdConfigError(`storage.${method} должен быть функцией`);\n }\n }\n return storage;\n}\n\n/**\n * Приводит настройки сессии к полному виду.\n *\n * @param runtime уже разрешённая конфигурация исполнения — из неё берутся общие поля\n * @throws {ItdConfigError} при некорректных значениях\n */\nexport function resolveSessionConfig(\n options: SessionOptions,\n runtime: Pick<SessionConfig, 'baseUrl' | 'clock' | 'useCookieJar' | 'logger'>,\n): SessionConfig {\n if (!isRecord(options)) throw new ItdConfigError('опции клиента должны быть объектом');\n\n requireOptionalBoolean(options.autoRefresh, 'autoRefresh');\n requireOptionalBoolean(options.reloginOnRefreshFailure, 'reloginOnRefreshFailure');\n\n if (\n options.deviceId !== undefined &&\n (typeof options.deviceId !== 'string' || options.deviceId.trim() === '')\n ) {\n throw new ItdConfigError('deviceId должен быть непустой строкой');\n }\n\n return {\n ...runtime,\n auth: validateAuth(options.auth),\n captcha: resolveCaptchaSolver(options.captcha),\n storage: resolveStorage(options.storage),\n deviceId: options.deviceId,\n autoRefresh: options.autoRefresh ?? true,\n reloginOnRefreshFailure: options.reloginOnRefreshFailure ?? true,\n };\n}\n\n/**\n * Собирает менеджер сессии итд.com как реализацию {@link AuthProvider}.\n *\n * Единственная точка, где конвейер запросов встречается с полноценной авторизацией.\n * Ядро её не вызывает — фабрику передаёт фасад клиента, иначе ссылка на сессию оказалась бы\n * достижимой из любой сборки, включая анонимную.\n */\nexport function createItdAuth(options: SessionOptions, deps: AuthProviderDeps): AuthManager {\n return new AuthManager(resolveSessionConfig(options, deps.config), deps.http, deps.cookies, {\n onAccountChange: deps.onAccountChange,\n });\n}\n\n/** Пути эндпоинтов авторизации. */\nexport const AUTH_PATHS = {\n captchaProvider: '/api/v1/auth/captcha/provider',\n captchaPage: '/api/v1/auth/captcha/page',\n signUp: '/api/v1/auth/sign-up',\n signIn: '/api/v1/auth/sign-in',\n verifyOtp: '/api/v1/auth/verify-otp',\n resendOtp: '/api/v1/auth/resend-otp',\n refresh: '/api/v1/auth/refresh',\n logout: '/api/v1/auth/logout',\n forgotPassword: '/api/v1/auth/forgot-password',\n resetPassword: '/api/v1/auth/reset-password',\n changePassword: '/api/v1/auth/change-password',\n sessions: '/api/v1/auth/sessions',\n qrStart: '/api/v1/auth/qr/start',\n qrClaim: '/api/v1/auth/qr/claim',\n qrStream: '/api/v1/auth/qr/stream',\n qrScan: '/api/v1/auth/qr/scan',\n qrApprove: '/api/v1/auth/qr/approve',\n qrReject: '/api/v1/auth/qr/reject',\n} as const;\n\n/**\n * Публичный ключ Cloudflare Turnstile платформы итд.com.\n *\n * Нужен, чтобы отрисовать виджет капчи и получить токен для `signIn`, `signUp`\n * и `forgotPassword`.\n *\n * Ключ привязан к домену: на чужом origin Cloudflare отказывает виджету с кодом `110200`.\n * Поэтому отрисовать его может только код, выполняемый на самом итд.com. Остальным\n * подходит `@itd-api/captcha`, готовый токен из другого источника или вовсе вход\n * без капчи — по сохранённой сессии либо по токенам, взятым в браузере.\n *\n * @example\n * ```ts\n * turnstile.render('#captcha', {\n * sitekey: TURNSTILE_SITE_KEY,\n * callback: (token) =>\n * itd.auth.signIn({ email, password, captcha: { type: CaptchaType.Cloudflare, token } }),\n * });\n * ```\n */\nexport const TURNSTILE_SITE_KEY = '0x4AAAAAACHhxczw6fJGwPBg';\n\n/** События слоя авторизации. */\nexport interface AuthEvents {\n /** Токен получен или обновлён. */\n tokens: { accessToken: string };\n /** Выполнен вход. */\n signIn: { accessToken: string };\n /** Сессия очищена — вручную или из-за неудачного обновления. */\n signOut: undefined;\n /** Обновить сессию не удалось; дальнейшие запросы будут падать с 401. */\n authError: { error: unknown };\n}\n\n/** Убирает поле, которое сохраняли промежуточные версии с поддержкой `getUserId()`. */\nfunction withoutLegacyUserId(session: ItdSession): ItdSession {\n const clean = copySession(session);\n delete (clean as ItdSession & { userId?: unknown }).userId;\n return clean;\n}\n\nfunction normalizeSessionValue(\n value: unknown,\n source: string,\n mode: 'strict' | 'stored' = 'strict',\n logger?: Logger,\n): ItdSession | null {\n const tolerant = mode === 'stored';\n if (!isRecord(value)) {\n if (tolerant) {\n logger?.warn(`${source} вернула не объект сессии; сохранённая запись пропущена`);\n return null;\n }\n throw new ItdConfigError(`${source} должна быть объектом сессии`);\n }\n const record = value as Record<string, unknown>;\n // Неизвестные поля могут принадлежать более новой версии библиотеки. Сохраняем их,\n // а известные поля проверяем и исправляем ниже.\n const normalized: Record<string, unknown> = { ...record };\n delete normalized.userId;\n\n const normalizeString = (field: 'accessToken' | 'refreshToken' | 'deviceId'): void => {\n const item = record[field];\n if (item === undefined) {\n delete normalized[field];\n return;\n }\n if (item !== undefined && (typeof item !== 'string' || item.trim() === '')) {\n if (tolerant) {\n logger?.warn(`${source}.${field} повреждена; поле сохранённой сессии пропущено`);\n delete normalized[field];\n return;\n }\n throw new ItdConfigError(`${source}.${field} должна быть непустой строкой`);\n }\n normalized[field] = item;\n };\n\n normalizeString('accessToken');\n normalizeString('refreshToken');\n normalizeString('deviceId');\n\n if (record.obtainedAt === undefined) {\n delete normalized.obtainedAt;\n } else if (typeof record.obtainedAt !== 'number' || !Number.isFinite(record.obtainedAt)) {\n if (!tolerant) {\n throw new ItdConfigError(`${source}.obtainedAt должна быть конечным числом`);\n } else {\n logger?.warn(`${source}.obtainedAt повреждена; поле сохранённой сессии пропущено`);\n delete normalized.obtainedAt;\n }\n }\n\n if (record.cookies === undefined) {\n delete normalized.cookies;\n } else {\n if (!Array.isArray(record.cookies)) {\n if (tolerant) {\n logger?.warn(`${source}.cookies повреждена; поле сохранённой сессии пропущено`);\n delete normalized.cookies;\n } else {\n throw new ItdConfigError(`${source}.cookies должна быть массивом`);\n }\n } else {\n // Одна повреждённая или устаревшая запись не должна блокировать рабочие токены.\n // CookieJar.deserialize придерживается той же мягкой политики.\n const valid = record.cookies.filter(\n (cookie: unknown): cookie is string =>\n typeof cookie === 'string' && isSerializedCookieEntry(cookie),\n );\n if (valid.length > 0) normalized.cookies = valid;\n else delete normalized.cookies;\n }\n }\n\n return normalized as ItdSession;\n}\n\nfunction normalizeSession(value: unknown, source: string): ItdSession {\n const normalized = normalizeSessionValue(value, source);\n if (!normalized) throw new ItdConfigError(`${source} должна быть объектом сессии`);\n return normalized;\n}\n\nlet authScopeSequence = 0;\n\nfunction nextAuthScope(): string {\n authScopeSequence += 1;\n return String(authScopeSequence);\n}\n\ninterface AuthManagerHooks {\n /** Вызывается синхронно перед заменой владельца авторизации. */\n onAccountChange?: (() => void) | undefined;\n}\n\ninterface RefreshExpectation {\n epoch: number;\n accessToken?: string | undefined;\n}\n\ninterface InFlightRefresh {\n epoch: number;\n promise: Promise<string | null>;\n}\n\n/**\n * Хранит сессию и продлевает её.\n *\n * Главное здесь — **дедупликация обновления**. Когда десять параллельных запросов\n * одновременно получают `401`, обновление должно произойти один раз, а остальные обязаны\n * дождаться его результата. Иначе сервер увидит десять параллельных `refresh`, и все,\n * кроме первого, скорее всего получат отказ по уже использованному токену.\n */\nexport class AuthManager implements AuthProvider {\n readonly #config: SessionConfig;\n readonly #http: HttpClient;\n readonly #jar: CookieJar;\n readonly #emitter: Emitter<AuthEvents>;\n readonly #hooks: AuthManagerHooks;\n\n /** `undefined` — сессия ещё не читалась из хранилища. */\n #session: ItdSession | null | undefined;\n /**\n * Общий промис чтения сессии из хранилища. Дедупликация: параллельные запросы на холодном\n * старте читают хранилище один раз и не заводят каждый свой `deviceId`.\n */\n #loading: Promise<ItdSession | null> | null = null;\n /** Текущее обновление: к нему присоединяются запросы той же ревизии. */\n #refreshing: InFlightRefresh | null = null;\n /** Общий промис входа по логину и паролю. */\n #signingIn: Promise<string | null> | null = null;\n /** Fallback-область для изоляции состояния плагинов, когда JWT-идентичность недоступна. */\n #authScope = nextAuthScope();\n /** Последний токен внешнего источника; `undefined` означает, что источник ещё не читался. */\n #externalToken: string | null | undefined;\n /** Идентификаторы последнего токена внешнего источника для синхронных потребителей. */\n #externalIdentity: AuthIdentity | undefined;\n #tokenMetadata: { accessToken: string; value: TokenMetadata } | undefined;\n /**\n * Идентификатор устройства.\n *\n * Держится отдельно от сессии намеренно: выход из аккаунта не меняет устройство,\n * поэтому `clear()` его не трогает.\n */\n #deviceId: string | undefined;\n /** Общий промис первичной выдачи `deviceId` — чтобы параллельные запросы получили один. */\n #deviceIdLoading: Promise<string> | null = null;\n /**\n * Счётчик смен владельца авторизации.\n *\n * Растёт при каждой операции, которая заменяет или очищает сессию извне: `clear`,\n * `setSession`, `setAccessToken`, вход. Refresh сверяет снимок до и после сетевого запроса.\n */\n #authEpoch = 0;\n #externalReadGeneration = 0;\n /** Разовый токен из `auth.captcha` тратится ровно на один запрос. */\n #configCaptchaSpent = false;\n #disposed = false;\n #persistence: Promise<void> = Promise.resolve();\n\n constructor(\n config: SessionConfig,\n http: HttpClient,\n jar: CookieJar,\n hooks: AuthManagerHooks = {},\n ) {\n this.#config = config;\n this.#http = http;\n this.#jar = jar;\n this.#hooks = hooks;\n this.#emitter = new Emitter<AuthEvents>((error) =>\n reportListenerError(config.logger, 'авторизации', error),\n );\n }\n\n /** Подписка на события авторизации. */\n get on(): Emitter<AuthEvents>['on'] {\n return ((...args: Parameters<Emitter<AuthEvents>['on']>) => {\n this.#assertActive();\n return this.#emitter.on(...args);\n }) as Emitter<AuthEvents>['on'];\n }\n\n /** Подписка на одно срабатывание. */\n get once(): Emitter<AuthEvents>['once'] {\n return ((...args: Parameters<Emitter<AuthEvents>['once']>) => {\n this.#assertActive();\n return this.#emitter.once(...args);\n }) as Emitter<AuthEvents>['once'];\n }\n\n /** Снимает служебные подписки при окончательном освобождении владельца. @internal */\n dispose(): void {\n if (this.#disposed) return;\n this.#disposed = true;\n this.#externalReadGeneration += 1;\n this.#invalidateInFlight();\n this.#tokenMetadata = undefined;\n this.#emitter.removeAllListeners();\n }\n\n /**\n * Непрозрачная fallback-область авторизации.\n *\n * Изолирует состояние плагинов, когда идентичность аккаунта из JWT недоступна (непрозрачный\n * токен): значение уникально для владельца и сменяется при замене или очистке сессии.\n */\n getAuthScope(): string {\n return this.#authScope;\n }\n\n /** Загружает сессию и возвращает идентификаторы аккаунта и сессии для плагинов. */\n async getAuthIdentity(): Promise<AuthIdentity> {\n this.#assertActive();\n const session = await this.#loadSession();\n if (session?.accessToken) return this.#identityForToken(session.accessToken);\n\n const auth = this.#config.auth;\n if (typeof auth === 'object' && auth !== null && 'getToken' in auth) {\n const token = await this.#readExternalToken(() => auth.getToken());\n return this.#identityForToken(token ?? undefined);\n }\n\n return {};\n }\n\n /** Идентификаторы аккаунта и сессии без чтения хранилища. @internal */\n getCurrentAuthIdentity(): AuthIdentity {\n const session =\n this.#session === undefined ? this.#sessionFromConfig(this.#config.auth) : this.#session;\n return session?.accessToken\n ? this.#identityForToken(session.accessToken)\n : (this.#externalIdentity ?? {});\n }\n\n #rotateAuthScope(): void {\n this.#authScope = nextAuthScope();\n }\n\n /** Отмечает смену владельца авторизации — обесценивает результат идущего обновления. */\n #invalidateInFlight(): void {\n this.#authEpoch += 1;\n this.#externalReadGeneration += 1;\n }\n\n /** Ревизия владельца сессии для условного commit внешнего auth-flow. @internal */\n revision(): number {\n this.#assertActive();\n return this.#authEpoch;\n }\n\n /** Создаёт изолированный jar для сетевого auth-flow. @internal */\n createCookieFlow(inherit = true): CookieJar {\n this.#assertActive();\n return inherit ? this.#jar.clone() : new CookieJar();\n }\n\n /** Применяет cookies только если владелец сессии не сменился. @internal */\n commitCookieFlow(cookies: CookieJar, expectedRevision: number): boolean {\n this.#assertActive();\n if (this.#authEpoch !== expectedRevision) return false;\n this.#jar.replaceWith(cookies);\n return true;\n }\n\n #assertActive(): void {\n if (this.#disposed) throw new ItdStateError('Менеджер авторизации уже освобождён');\n }\n\n #currentAccessToken(): string | null {\n return this.#session?.accessToken ?? null;\n }\n\n #identityForToken(accessToken: string | undefined): AuthIdentity {\n const token = this.#metadataForToken(accessToken);\n return {\n ...(token.subject ? { userId: token.subject as UserId } : {}),\n ...(token.sessionId ? { sessionId: token.sessionId } : {}),\n };\n }\n\n #metadataForToken(accessToken: string | undefined): TokenMetadata {\n if (!accessToken) {\n this.#tokenMetadata = undefined;\n return {};\n }\n if (this.#tokenMetadata?.accessToken === accessToken) return this.#tokenMetadata.value;\n\n const value = readTokenMetadata(accessToken);\n this.#tokenMetadata = { accessToken, value };\n return value;\n }\n\n async #readExternalToken(\n getToken: () => string | null | Promise<string | null>,\n ): Promise<string | null> {\n this.#assertActive();\n const generation = ++this.#externalReadGeneration;\n const token = (await getToken()) ?? null;\n this.#assertActive();\n if (generation !== this.#externalReadGeneration) return token;\n const current = this.#identityForToken(token ?? undefined);\n\n if (this.#externalToken !== undefined && this.#externalToken !== token) {\n this.#rotateAuthScope();\n const previous = this.#externalIdentity ?? {};\n const changed =\n previous.userId !== undefined && current.userId !== undefined\n ? previous.userId !== current.userId\n : true;\n if (changed) this.#hooks.onAccountChange?.();\n }\n\n this.#externalToken = token;\n this.#externalIdentity = current;\n return token;\n }\n\n /** Обновляет резервный идентификатор и закрывает события при смене аккаунта. */\n #transitionAuth(accessToken: string | undefined, rotateFallback = true): void {\n const knownPrevious = this.#session !== undefined;\n const previous = this.#identityForToken(this.#session?.accessToken);\n const current = this.#identityForToken(accessToken);\n const changed =\n previous.userId !== undefined && current.userId !== undefined\n ? previous.userId !== current.userId\n : previous.userId !== current.userId || rotateFallback;\n\n if (rotateFallback || changed) this.#rotateAuthScope();\n if (knownPrevious && changed) this.#hooks.onAccountChange?.();\n }\n\n /**\n * Есть ли признак живой refresh-сессии.\n *\n * Рядом с refresh-токеном сервер ставит незакрытую cookie `is_auth` — по ней видно,\n * что продлевать сессию вообще есть смысл, и API не дёргается у анонимов.\n * В браузере cookie ведёт сама среда, поэтому там ответ всегда `true`.\n *\n * Асинхронный, потому что признак может лежать в {@link TokenStorage}: до чтения оттуда\n * ответ был бы `false` даже при полностью рабочей сохранённой сессии.\n */\n async hasRefreshSession(): Promise<boolean> {\n this.#assertActive();\n await this.#loadSession();\n return this.#hasRefreshSession();\n }\n\n /** То же самое, но без чтения хранилища — для вызовов, где сессия уже загружена. */\n #hasRefreshSession(): boolean {\n if (!this.#config.useCookieJar) return true;\n // Флаг должен принадлежать основному API, а не другому сервису.\n if (this.#jar.has(AUTH_FLAG_COOKIE, this.#config.baseUrl)) return true;\n\n // Явно переданный refresh-токен — тоже основание пробовать.\n return Boolean(this.#session?.refreshToken);\n }\n\n /** Готовит внутреннюю сессию до retry исходного запроса. */\n async preflight(allowRefresh: boolean): Promise<void> {\n this.#assertActive();\n const session = await this.#loadSession();\n let accessToken = session?.accessToken;\n\n if (!accessToken) {\n const auth = this.#config.auth;\n if (typeof auth === 'object' && auth !== null && 'email' in auth) {\n accessToken = (await this.#signInWithCredentials(auth)) ?? undefined;\n }\n }\n\n if (!accessToken || !allowRefresh || !this.#config.autoRefresh) return;\n\n const expiresAt = this.#metadataForToken(accessToken).expiresAt;\n if (\n expiresAt === undefined ||\n expiresAt > this.#config.clock.now() + ACCESS_TOKEN_REFRESH_LEEWAY_MS ||\n !this.#hasRefreshSession()\n ) {\n return;\n }\n\n try {\n await this.#refreshDeduplicated({ epoch: this.#authEpoch, accessToken });\n } catch (error) {\n this.#emitter.emit('authError', { error });\n throw error;\n }\n }\n\n /** Перед каждой попыткой перечитывает внешний источник токена. */\n async prepare(): Promise<void> {\n this.#assertActive();\n const session = await this.#loadSession();\n if (session?.accessToken) return;\n\n const auth = this.#config.auth;\n if (typeof auth === 'object' && auth !== null && 'getToken' in auth) {\n await this.#readExternalToken(() => auth.getToken());\n }\n }\n\n /**\n * Заголовки уже подготовленной авторизации без чтения storage или вызова внешнего источника.\n *\n * Используются после ожидания транспортной очереди: к этому моменту {@link prepare} уже\n * был вызван снаружи неё, но token мог успеть смениться из-за refresh или `setSession()`.\n */\n currentHeaders(): Record<string, string> {\n const session =\n this.#session === undefined ? this.#sessionFromConfig(this.#config.auth) : this.#session;\n const token = session?.accessToken ?? this.#externalToken ?? null;\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n\n /**\n * Реакция конвейера на `401`. Стадия `auth_recovery`.\n *\n * При выключенном `autoRefresh` ничего не делает: вызывающий код обновляет сессию сам\n * через `itd.auth.refresh()`, а библиотека просто пробрасывает {@link ItdAuthError}.\n */\n recover(): Promise<boolean> {\n this.#assertActive();\n return this.#config.autoRefresh ? this.onUnauthorized() : Promise.resolve(false);\n }\n\n /**\n * Идентификатор устройства для заголовка `X-Device-Id`.\n *\n * Заводится один раз и сохраняется в сессии, чтобы пережить перезапуск процесса:\n * сервер связывает с ним запись в списке сессий, и плавающее значение плодило бы\n * по новой сессии на каждый старт.\n */\n deviceId(): Promise<string> {\n this.#assertActive();\n if (this.#deviceId) return Promise.resolve(this.#deviceId);\n\n // Дедупликация: параллельные вызовы на холодном клиенте получают один `X-Device-Id`.\n this.#deviceIdLoading ??= this.#resolveDeviceId().finally(() => {\n this.#deviceIdLoading = null;\n });\n\n return this.#deviceIdLoading;\n }\n\n async #resolveDeviceId(): Promise<string> {\n const revision = this.#authEpoch;\n const session = await this.#loadSession();\n this.#assertActive();\n const deviceId = this.#config.deviceId ?? session?.deviceId ?? createDeviceId();\n\n this.#deviceId = deviceId;\n if (this.#authEpoch !== revision) return deviceId;\n\n // Записываем, только если значение действительно новое, — иначе каждый первый запрос\n // дёргал бы хранилище без всякой пользы.\n if (session?.deviceId !== deviceId) {\n await this.#saveSession({ ...(session ?? {}), deviceId });\n }\n\n return deviceId;\n }\n\n /**\n * Текущий токен доступа.\n *\n * При необходимости выполняет отложенный вход: если в конфигурации переданы логин\n * и пароль, первый же запрос сам заведёт сессию.\n */\n async token(): Promise<string | null> {\n this.#assertActive();\n const session = await this.#loadSession();\n if (session?.accessToken) return session.accessToken;\n\n const auth = this.#config.auth;\n if (!auth) return null;\n\n // Внешний источник токена спрашиваем каждый раз: он сам решает, когда обновлять.\n if (typeof auth === 'object' && 'getToken' in auth) {\n return this.#readExternalToken(() => auth.getToken());\n }\n\n if (typeof auth === 'object' && 'email' in auth) {\n return this.#signInWithCredentials(auth);\n }\n\n return null;\n }\n\n /**\n * Реакция транспорта на ответ `401`.\n *\n * @returns `true`, если токен обновлён и запрос имеет смысл повторить\n */\n async onUnauthorized(): Promise<boolean> {\n this.#assertActive();\n try {\n const token = await this.#refreshDeduplicated();\n if (token !== null) return true;\n\n // Обновлять нечем — это тоже отказ авторизации, и подписчик должен о нём узнать.\n this.#emitter.emit('authError', { error: this.#noRefreshSessionError() });\n return false;\n } catch (error) {\n this.#emitter.emit('authError', { error });\n return false;\n }\n }\n\n /**\n * Ошибка «сессию продлить нечем».\n *\n * Возникает, только когда обновление даже не начиналось: нет ни cookie `is_auth`,\n * ни refresh-токена. Если сервер ответил отказом, наружу уходит **его** ошибка —\n * подменять её этой значило бы прятать причину (`REFRESH_TOKEN_MISSING`,\n * `SESSION_NOT_FOUND`, `SESSION_REVOKED` — разные поводы и разные действия).\n */\n #noRefreshSessionError(): ItdAuthError {\n return new ItdAuthError({\n status: 401,\n code: 'SESSION_EXPIRED',\n message:\n 'Не удалось обновить сессию: нет ни cookie is_auth, ни refresh-токена. ' +\n 'Войдите заново либо передайте refreshToken в auth.',\n method: 'POST',\n path: AUTH_PATHS.refresh,\n raw: undefined,\n });\n }\n\n /**\n * Обновляет токен доступа.\n *\n * Параллельные вызовы объединяются в один сетевой запрос.\n *\n * @throws {ItdAuthError} если обновить сессию не удалось\n */\n async refresh(): Promise<string> {\n this.#assertActive();\n const token = await this.#refreshDeduplicated();\n if (token === null) throw this.#noRefreshSessionError();\n return token;\n }\n\n /** Сохраняет токен, полученный извне, — например после подтверждения OTP. */\n async setAccessToken(\n accessToken: string,\n expectedRevision = this.#authEpoch,\n cookies?: CookieJar,\n ): Promise<boolean> {\n return this.#storeAccessToken(accessToken, expectedRevision, cookies, false);\n }\n\n /** Атомарно принимает токен и cookie завершённого входа как новую сессию. @internal */\n async commitAuthFlow(\n accessToken: string,\n cookies: CookieJar,\n expectedRevision = this.#authEpoch,\n ): Promise<boolean> {\n return this.#storeAccessToken(accessToken, expectedRevision, cookies, true);\n }\n\n async #storeAccessToken(\n accessToken: string,\n expectedRevision: number,\n cookies: CookieJar | undefined,\n replaceSession: boolean,\n ): Promise<boolean> {\n this.#assertActive();\n if (typeof accessToken !== 'string' || accessToken.trim() === '') {\n throw new ItdConfigError('accessToken должен быть непустой строкой');\n }\n await this.#loadSession();\n this.#assertActive();\n if (this.#authEpoch !== expectedRevision) return false;\n if (cookies) this.#jar.replaceWith(cookies);\n this.#invalidateInFlight();\n this.#transitionAuth(accessToken);\n const saved = this.#saveSession({\n ...(replaceSession ? {} : (this.#session ?? {})),\n accessToken,\n obtainedAt: this.#config.clock.now(),\n });\n this.#emitter.emit('tokens', { accessToken });\n await saved;\n return true;\n }\n\n /** Текущая сессия целиком. Полезно, чтобы сохранить её самому. */\n async getSession(): Promise<ItdSession | null> {\n this.#assertActive();\n const session = await this.#loadSession();\n return session ? copySession(session) : null;\n }\n\n /**\n * Идентификатор владельца сессии.\n *\n * Считается непосредственно из текущего токена и отдельно не сохраняется: после замены\n * токена идентификатор прежнего владельца остаться не может.\n */\n async getUserId(): Promise<UserId | undefined> {\n this.#assertActive();\n const session = await this.#loadSession();\n return session?.accessToken ? this.#identityForToken(session.accessToken).userId : undefined;\n }\n\n /** Заменяет сессию и связанные с ней cookie целиком. */\n async setSession(session: ItdSession): Promise<void> {\n this.#assertActive();\n const normalized = normalizeSession(session, 'session');\n await this.#loadSession();\n this.#assertActive();\n this.#invalidateInFlight();\n this.#transitionAuth(normalized.accessToken);\n this.#jar.clear();\n this.#jar.deserialize(normalized.cookies);\n\n if (normalized.deviceId) this.#deviceId = normalized.deviceId;\n\n // Refresh-cookie добавляется до сериализации сессии.\n this.#session = normalized;\n this.#seedRefreshCookie();\n\n await this.#saveSession(normalized);\n }\n\n /**\n * Забывает сессию и cookie. Сетевой запрос не выполняется.\n *\n * Идентификатор устройства выход переживает: иначе каждая пара «выход — вход» плодила бы\n * новую запись в списке сессий.\n */\n async clear(): Promise<void> {\n this.#assertActive();\n await this.#loadSession();\n this.#assertActive();\n this.#invalidateInFlight();\n this.#transitionAuth(undefined);\n this.#jar.clear();\n const retained = this.#deviceId ? { deviceId: this.#deviceId } : null;\n this.#session = retained;\n this.#emitter.emit('signOut', undefined);\n await this.#enqueuePersistence(async () => {\n await this.#config.storage.clear();\n if (retained) await this.#config.storage.set(copySession(retained));\n });\n }\n\n #loadSession(): Promise<ItdSession | null> {\n if (this.#session !== undefined) return Promise.resolve(this.#session);\n\n this.#loading ??= this.#performLoad().finally(() => {\n this.#loading = null;\n });\n\n return this.#loading;\n }\n\n async #performLoad(): Promise<ItdSession | null> {\n const loaded = (await this.#config.storage.get()) ?? null;\n this.#assertActive();\n const stored =\n loaded === null\n ? null\n : normalizeSessionValue(loaded, 'storage.get()', 'stored', this.#config.logger);\n\n // Восстанавливаем cookie: без них не выйдет обновить токен после перезапуска процесса.\n if (stored?.cookies) this.#jar.deserialize(stored.cookies);\n\n const fromConfig = this.#sessionFromConfig(this.#config.auth);\n\n // Хранилище отвечает за состояние сессии и всегда важнее, но недостающие поля\n // берутся из конфигурации: типичный случай — сохранён только accessToken,\n // а refresh-токен приходит из настроек приложения.\n this.#session =\n stored && fromConfig\n ? {\n ...stored,\n accessToken: stored.accessToken ?? fromConfig.accessToken,\n refreshToken: stored.refreshToken ?? fromConfig.refreshToken,\n }\n : (stored ?? fromConfig);\n\n this.#seedRefreshCookie();\n\n return this.#session;\n }\n\n /**\n * Кладёт refresh-токен в jar как cookie `refresh_token`.\n *\n * `POST /api/v1/auth/refresh` читает токен только из cookie, поэтому переданный строкой\n * приходится превращать в неё. В браузере это невозможно — cookie помечена `HttpOnly`,\n * и там обновление работает только на той, что поставил сам сервер.\n */\n #seedRefreshCookie(): void {\n if (!this.#config.useCookieJar) return;\n\n const refreshToken = this.#session?.refreshToken;\n if (!refreshToken) return;\n if (this.#jar.has(REFRESH_COOKIE, this.#config.baseUrl + REFRESH_COOKIE_PATH)) return;\n\n this.#jar.set(this.#config.baseUrl, REFRESH_COOKIE, refreshToken, REFRESH_COOKIE_PATH);\n }\n\n #sessionFromConfig(auth: AuthInput | undefined): ItdSession | null {\n if (!auth) return null;\n if (typeof auth === 'string') {\n return { accessToken: auth, obtainedAt: this.#config.clock.now() };\n }\n\n if ('accessToken' in auth) {\n return {\n accessToken: auth.accessToken,\n refreshToken: auth.refreshToken,\n obtainedAt: this.#config.clock.now(),\n };\n }\n\n return null;\n }\n\n async #saveSession(session: ItdSession): Promise<void> {\n const cookies = this.#config.useCookieJar ? this.#jar.serialize() : undefined;\n const deviceId = session.deviceId ?? this.#deviceId;\n const { cookies: _staleCookies, ...withoutCookies } = copySession(session);\n\n const next = withoutLegacyUserId({\n ...withoutCookies,\n ...(cookies?.length ? { cookies } : {}),\n ...(deviceId ? { deviceId } : {}),\n });\n\n this.#session = next;\n await this.#enqueuePersistence(() => this.#config.storage.set(copySession(next)));\n }\n\n #enqueuePersistence(operation: () => void | Promise<void>): Promise<void> {\n const pending = this.#persistence.then(operation, operation);\n this.#persistence = pending.catch(() => {});\n return pending;\n }\n\n /** Дедуплицирует refresh одной ревизии; следующая ждёт завершения предыдущей. */\n #refreshDeduplicated(\n expectation: RefreshExpectation = { epoch: this.#authEpoch },\n ): Promise<string | null> {\n const current = this.#refreshing;\n if (current) {\n if (current.epoch === expectation.epoch) return current.promise;\n return current.promise.then(\n () => this.#refreshDeduplicated(expectation),\n () => this.#refreshDeduplicated(expectation),\n );\n }\n\n const promise = this.#performRefresh(expectation).finally(() => {\n if (this.#refreshing?.promise === promise) this.#refreshing = null;\n });\n\n this.#refreshing = { epoch: expectation.epoch, promise };\n return promise;\n }\n\n #matchesRefreshExpectation(expectation: RefreshExpectation): boolean {\n return (\n this.#authEpoch === expectation.epoch &&\n (expectation.accessToken === undefined ||\n this.#session?.accessToken === expectation.accessToken)\n );\n }\n\n async #performRefresh(expectation: RefreshExpectation): Promise<string | null> {\n this.#assertActive();\n await this.#loadSession();\n if (!this.#matchesRefreshExpectation(expectation)) return this.#currentAccessToken();\n\n if (!this.#hasRefreshSession()) {\n // Нет признаков сессии — обновлять нечего. При наличии логина и пароля\n // пробуем войти заново.\n return this.#reloginOrNull();\n }\n\n const flowCookies = this.#jar.clone();\n\n try {\n // Служебный запрос идёт через общий pipeline. Слой авторизации он пропускает, чтобы\n // не отправлять устаревший Bearer и не запускать рекурсивный refresh. Очередь безопасна:\n // исходная неудачная транспортная попытка освободила свой слот до вызова этого метода.\n const accessToken = await this.#http.execute(AUTH_REFRESH, {\n path: AUTH_PATHS.refresh,\n skipAuth: true,\n skipAuthRefresh: true,\n cookieJar: flowCookies,\n // Тела нет намеренно: сервер читает refresh-токен только из cookie — см.\n // #seedRefreshCookie. По той же причине не нужен и устаревший Bearer.\n });\n\n if (!this.#matchesRefreshExpectation(expectation)) {\n // Пока шёл refresh, владельца сменили (signOut / setSession / вход): его результат\n // устарел. Не воскрешаем сохранённую сессию, отдаём актуальный токен как есть.\n return this.#session?.accessToken ?? null;\n }\n\n this.#jar.replaceWith(flowCookies);\n\n // Сервер выдаёт при обновлении **новый** refresh-токен (`Set-Cookie: refresh_token=…;\n // Max-Age=2592000`) и тут же гасит прежний. Забрать его из jar обязательно: иначе\n // сохранённая строка протухнет и восстановление сессии из хранилища перестанет работать.\n const rotated = this.#jar.getValue(\n REFRESH_COOKIE,\n this.#config.baseUrl + REFRESH_COOKIE_PATH,\n );\n\n // Refresh продолжает ту же серверную сессию. Для непрозрачного токена это единственная\n // надёжная возможность сохранить scope; смена пользователя в JWT всё равно будет обнаружена.\n this.#transitionAuth(accessToken, false);\n const saved = this.#saveSession({\n ...(this.#session ?? {}),\n accessToken,\n ...(rotated ? { refreshToken: rotated } : {}),\n obtainedAt: this.#config.clock.now(),\n });\n\n this.#emitter.emit('tokens', { accessToken });\n await saved;\n if (this.#authEpoch !== expectation.epoch) return this.#currentAccessToken();\n return accessToken;\n } catch (error) {\n if (this.#authEpoch !== expectation.epoch) return this.#currentAccessToken();\n if (error instanceof ItdAuthError) {\n // Сессия недействительна — чистим её, иначе будем биться в стену на каждом запросе.\n this.#invalidateInFlight();\n const clearedRevision = this.#authEpoch;\n this.#transitionAuth(undefined);\n this.#session = null;\n this.#jar.clear();\n await this.#enqueuePersistence(() => this.#config.storage.clear());\n if (this.#authEpoch !== clearedRevision) return this.#currentAccessToken();\n\n const relogged = await this.#reloginOrNull();\n if (relogged !== null) return relogged;\n\n // Войти заново нечем — отдаём ошибку сервера как есть. Именно она объясняет,\n // что произошло: REFRESH_TOKEN_MISSING, SESSION_NOT_FOUND, SESSION_REVOKED.\n throw error;\n }\n throw error;\n }\n }\n\n /** Повторный вход, если разрешён настройкой и есть логин с паролем. */\n async #reloginOrNull(): Promise<string | null> {\n const auth = this.#config.auth;\n\n if (\n !this.#config.reloginOnRefreshFailure ||\n !auth ||\n typeof auth !== 'object' ||\n !('email' in auth)\n ) {\n return null;\n }\n\n try {\n return await this.#signInWithCredentials(auth);\n } catch (error) {\n this.#config.logger?.warn('Автоматический повторный вход не удался', error);\n return null;\n }\n }\n\n /**\n * Вход по логину и паролю.\n *\n * Параллельные вызовы объединяются: одновременный старт нескольких запросов не должен\n * приводить к нескольким попыткам входа и блокировке аккаунта.\n */\n #signInWithCredentials(credentials: CredentialsAuth): Promise<string | null> {\n if (this.#signingIn) return this.#signingIn;\n\n const revision = this.#authEpoch;\n const promise = this.#performSignIn(credentials, revision).finally(() => {\n this.#signingIn = null;\n });\n\n this.#signingIn = promise;\n return promise;\n }\n\n /**\n * Готовит фрагмент тела с токеном капчи для запроса, который её требует.\n *\n * Источники в порядке убывания приоритета: токен, переданный в сам вызов; разовый токен\n * из `auth.captcha`; опция `captcha`. Когда ни одного нет, фрагмент пустой: нужна ли\n * капча этому запросу, решает сервер.\n *\n * @param explicit готовый токен, переданный в вызов\n * @throws {ItdConfigError} если токен неполный или источник его не вернул\n */\n async captchaBody(explicit?: CaptchaToken | undefined): Promise<CaptchaBody> {\n if (explicit) return captchaBody(explicit);\n\n const configured = this.#takeConfiguredCaptcha();\n if (configured) return captchaBody(configured);\n\n const solver = this.#config.captcha;\n if (solver) return solveCaptchaBody(solver, () => this.#resolveCaptchaProvider());\n\n this.#config.logger?.debug(\n 'Запрос уходит без токена капчи: не передан аргумент captcha и не задана опция captcha',\n );\n return {};\n }\n\n /** Отдаёт разовый токен из `auth.captcha`, помечая его потраченным. */\n #takeConfiguredCaptcha(): CaptchaToken | undefined {\n if (this.#configCaptchaSpent) return undefined;\n\n const auth = this.#config.auth;\n const captcha = isRecord(auth) ? (auth as CredentialsAuth).captcha : undefined;\n if (!captcha) return undefined;\n\n this.#configCaptchaSpent = true;\n return captcha;\n }\n\n /** Спрашивает у сервера активного провайдера и поле, в котором он ждёт токен. */\n async #resolveCaptchaProvider(): Promise<CaptchaProvider> {\n try {\n const provider: unknown = await this.#http.execute(AUTH_CAPTCHA_PROVIDER, {\n path: AUTH_PATHS.captchaProvider,\n skipAuth: true,\n skipAuthRefresh: true,\n });\n\n return readCaptchaProvider(provider);\n } catch (error) {\n if (isItdApiError(error) && error.status === 404 && error.code === ItdErrorCode.NOT_FOUND) {\n this.#config.logger?.warn(\n 'Сервер отключил определение провайдера капчи; используется Cloudflare Turnstile',\n );\n return { provider: CaptchaType.Cloudflare, field: CaptchaField.Cloudflare };\n }\n throw error;\n }\n }\n\n async #performSignIn(credentials: CredentialsAuth, revision: number): Promise<string | null> {\n const captcha = await this.captchaBody();\n const flowCookies = new CookieJar();\n\n // Через общий pipeline: плагины, повторы и очередь сохраняются, а слой авторизации\n // пропускается, потому что токена ещё нет.\n const result = await this.#http.execute(AUTH_SIGN_IN, {\n path: AUTH_PATHS.signIn,\n body: { email: credentials.email, password: credentials.password, ...captcha },\n skipAuth: true,\n skipAuthRefresh: true,\n cookieJar: flowCookies,\n });\n\n if (result.status !== SignInStatus.Authenticated) {\n // Сервер запросил подтверждение по коду — автоматически это не пройти.\n throw new ItdConfigError(\n 'Вход по email и паролю требует подтверждения кодом из письма. Автоматический вход ' +\n 'невозможен: воспользуйтесь itd.auth.signInWithOtp() и передайте полученный ' +\n 'accessToken в конфигурацию клиента.',\n );\n }\n const accessToken = result.accessToken;\n this.#assertActive();\n if (this.#authEpoch !== revision) return this.#session?.accessToken ?? null;\n this.#jar.replaceWith(flowCookies);\n\n // Прежний refresh-токен и cookie намеренно не переносятся: вход выдал новую сессию,\n // и держаться за старую было бы ошибкой. Идентификатор устройства добавит #saveSession.\n this.#invalidateInFlight();\n this.#transitionAuth(accessToken);\n const saved = this.#saveSession({ accessToken, obtainedAt: this.#config.clock.now() });\n this.#emitter.emit('tokens', { accessToken });\n this.#emitter.emit('signIn', { accessToken });\n await saved;\n\n return accessToken;\n }\n}\n","import { createParser } from 'eventsource-parser';\nimport type { ClientConnection } from '../core/connection.js';\nimport type { CookieJar } from '../core/cookies.js';\nimport { createApiError } from '../core/error-factory.js';\nimport { ItdNetworkError } from '../core/errors.js';\nimport { createRequestAbortScope, requestAbortError } from '../core/execution/lifecycle.js';\nimport { joinUrl } from '../core/url.js';\nimport { isRecord } from '../core/validate.js';\nimport {\n type QrLoginStreamEvent,\n QrLoginStreamStatus,\n type QrLoginStreamStatus as QrLoginStreamStatusValue,\n} from '../operations/auth.js';\nimport { AUTH_PATHS } from './auth.js';\n\ninterface QrLoginStreamCredentials {\n qrId: string;\n claimToken: string;\n}\n\nconst QR_STREAM_STATUSES = new Set<QrLoginStreamStatusValue>(Object.values(QrLoginStreamStatus));\n\nfunction readQrLoginStreamEvent(data: string): QrLoginStreamEvent | undefined {\n let value: unknown;\n try {\n value = JSON.parse(data);\n } catch {\n return undefined;\n }\n if (!isRecord(value)) return undefined;\n const event = value as Record<string, unknown>;\n if (\n typeof event.status !== 'string' ||\n !QR_STREAM_STATUSES.has(event.status as QrLoginStreamStatusValue)\n ) {\n return undefined;\n }\n return {\n status: event.status as QrLoginStreamStatusValue,\n ...(typeof event.expiresIn === 'number' && Number.isFinite(event.expiresIn)\n ? { expiresIn: event.expiresIn }\n : {}),\n };\n}\n\n/** Читает короткоживущий SSE-поток QR-входа и последовательно доставляет его события. */\nexport async function consumeQrLoginStream(\n body: ReadableStream<Uint8Array>,\n onEvent: (event: QrLoginStreamEvent) => void | Promise<void>,\n signal?: AbortSignal,\n): Promise<void> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let delivery = Promise.resolve();\n let completed = false;\n const cancel = () => {\n void reader.cancel(signal?.reason).catch(() => {});\n };\n signal?.addEventListener('abort', cancel, { once: true });\n\n const parser = createParser({\n onEvent(message) {\n const event = readQrLoginStreamEvent(message.data);\n // Один повреждённый или неизвестный кадр не должен обрывать оставшийся поток.\n if (!event) return;\n delivery = delivery.then(() => onEvent(event));\n },\n });\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n parser.feed(decoder.decode(value, { stream: true }));\n await delivery;\n }\n parser.feed(decoder.decode());\n await delivery;\n if (signal?.aborted) throw signal.reason;\n completed = true;\n } finally {\n signal?.removeEventListener('abort', cancel);\n if (!completed) await reader.cancel().catch(() => {});\n reader.releaseLock?.();\n }\n}\n\n/** Открывает изолированный HTTP/SSE-канал QR-входа. @internal */\nexport async function openQrLoginStream(\n connection: ClientConnection,\n cookies: CookieJar,\n input: QrLoginStreamCredentials,\n onEvent: (event: QrLoginStreamEvent) => void | Promise<void>,\n signal?: AbortSignal,\n): Promise<void> {\n connection.assertActive?.('открыть QR-поток');\n const path = AUTH_PATHS.qrStream;\n const method = 'POST';\n const url = joinUrl(connection.baseUrl, path);\n const abort = createRequestAbortScope(signal, connection.signal, 0, connection.clock);\n\n try {\n const headers = await connection.baseHeaders(url);\n // Базовые заголовки могут содержать cookie основной сессии; QR-сессия живёт отдельно.\n headers.delete('Authorization');\n headers.delete('Cookie');\n headers.set('Accept', 'text/event-stream');\n headers.set('Content-Type', 'application/json');\n const cookie = cookies.getHeader(url);\n if (cookie) headers.set('Cookie', cookie);\n\n let response: Response;\n try {\n response = await connection.fetch(url, {\n method,\n headers,\n body: JSON.stringify(input),\n // Браузеру это передаёт cookie; серверный fetch использует заголовок из jar выше.\n credentials: 'include',\n signal: abort.signal,\n });\n } catch (error) {\n const failure = new ItdNetworkError(`Не удалось открыть QR-поток: ${String(error)}`, {\n method,\n path,\n cause: error,\n });\n throw requestAbortError(abort, { timeout: 0, method, path }, failure);\n }\n\n cookies.setFromResponse(response.url || url, response);\n if (!response.ok) {\n const text = await response.text();\n let body: unknown = text;\n try {\n body = JSON.parse(text);\n } catch {}\n throw createApiError({\n method,\n path,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n response,\n body,\n now: connection.clock.now(),\n });\n }\n if (!response.body) {\n throw new ItdNetworkError('Сервер не вернул тело QR-потока', { method, path });\n }\n\n await consumeQrLoginStream(response.body, onEvent, abort.signal);\n } catch (error) {\n throw requestAbortError(abort, { timeout: 0, method, path }, error);\n } finally {\n abort.cleanup();\n }\n}\n","import type { ClientConnection } from '../core/connection.js';\nimport type { CookieJar } from '../core/cookies.js';\nimport { ItdConfigError, isItdApiError } from '../core/errors.js';\nimport type { HttpClient } from '../core/execution/http.js';\nimport type { RequestOptions } from '../core/options.js';\nimport type { QrLoginTarget, Session } from '../models/account.js';\nimport type { AuthState } from '../models/users.js';\nimport {\n AUTH_CAPTCHA_PAGE,\n AUTH_CAPTCHA_PROVIDER,\n AUTH_CHANGE_PASSWORD,\n AUTH_CHECK,\n AUTH_FORGOT_PASSWORD,\n AUTH_LOGOUT,\n AUTH_QR_APPROVE,\n AUTH_QR_CLAIM,\n AUTH_QR_REJECT,\n AUTH_QR_SCAN,\n AUTH_QR_START,\n AUTH_RESEND_OTP,\n AUTH_RESET_PASSWORD,\n AUTH_REVOKE_OTHER_SESSIONS,\n AUTH_REVOKE_SESSION,\n AUTH_SESSIONS,\n AUTH_SIGN_IN,\n AUTH_SIGN_UP,\n AUTH_VERIFY_OTP,\n type CaptchaPage,\n type CaptchaProvider,\n type CaptchaToken,\n type QrLoginClaim,\n type QrLoginStart,\n QrLoginStatus,\n type QrLoginStreamEvent,\n QrLoginStreamStatus,\n type SignInResult,\n SignInStatus,\n} from '../operations/auth.js';\nimport { AUTH_PATHS, type AuthManager } from '../session/auth.js';\nimport { openQrLoginStream } from '../session/qr-stream.js';\nimport { BaseResource } from './base.js';\n\n/** Учётные данные для входа. */\nexport interface Credentials {\n email: string;\n password: string;\n}\n\n/**\n * Учётные данные вместе с токеном капчи.\n *\n * Токен нужен, только когда у клиента не задана опция `captcha`: с ней клиент получает его\n * сам. Какой виджет сейчас требует сервер, сообщает {@link AuthResource.captchaProvider};\n * в Node токен добывает `@itd-api/captcha`. Токен одноразовый и живёт несколько минут.\n *\n * @example\n * ```ts\n * const { provider, field } = await itd.auth.captchaProvider();\n * const token = await solveCaptcha(provider);\n *\n * await itd.auth.signIn({ email, password, captcha: { type: provider, token, field } });\n * ```\n */\nexport type CredentialsWithCaptcha = Credentials & { captcha?: CaptchaToken | undefined };\n\n/** Запрос письма для сброса пароля. Капча обязательна, как и при входе. */\nexport interface ForgotPasswordInput {\n email: string;\n captcha?: CaptchaToken | undefined;\n}\n\n/** Секреты QR-сессии и капча для завершения входа. */\nexport interface QrLoginClaimInput {\n qrId: string;\n claimToken: string;\n captcha?: CaptchaToken | undefined;\n}\n\n/** Секреты QR-сессии для потокового наблюдения. */\nexport interface QrLoginStreamInput {\n qrId: string;\n claimToken: string;\n}\n\n/**\n * Секреты QR-кода со стороны сканирующего устройства.\n *\n * Оба значения лежат во fragment {@link QrLoginStart.payload} — ссылки вида\n * `https://итд.com/qr#i=<qrId>&s=<secret>`, которую и кодирует QR-код. `secret` — не то же\n * самое, что `claimToken`: этот секрет предъявляет тот, кто сканирует, а `claimToken` — тот,\n * кто код показывает.\n */\nexport interface QrLoginSecrets {\n qrId: string;\n secret: string;\n}\n\n/** Управление временем жизни потокового запроса. */\nexport interface QrLoginStreamOptions {\n signal?: AbortSignal | undefined;\n}\n\n/** Обработчик одного события QR-потока. */\nexport type QrLoginStreamListener = (event: QrLoginStreamEvent) => void | Promise<void>;\n\n/**\n * Установка нового пароля.\n *\n * Сброс идёт тем же потоком с кодом, что и вход: {@link AuthResource.forgotPassword} выдаёт\n * `flowToken`, письмо приносит `otp`, и всё это вместе с новым паролем уходит сюда.\n */\nexport interface ResetPasswordInput {\n email: string;\n otp: string;\n flowToken: string;\n newPassword: string;\n}\n\nexport type { QrLoginTarget } from '../models/account.js';\nexport type {\n CaptchaPage,\n CaptchaProvider,\n CaptchaToken,\n QrLoginClaim,\n QrLoginStart,\n QrLoginStreamEvent,\n SignInResult,\n SignInStatus as SignInStatusValue,\n} from '../operations/auth.js';\n/** Состояния обычного входа и QR-входа. */\nexport {\n CAPTCHA_FIELDS,\n QrLoginStatus,\n QrLoginStreamStatus,\n SignInStatus,\n} from '../operations/auth.js';\n\ninterface QrCookieFlow {\n cookies: CookieJar;\n expiresAt: number | undefined;\n /** Сервер потребовал капчу для этой сессии — в ответе `start` либо на прошлой проверке. */\n captchaRequired: boolean;\n}\n\n/**\n * Результат входа.\n *\n * Сервер может как сразу выдать токен, так и потребовать код подтверждения — размеченное\n * объединение делает оба случая явными.\n */\n\n/**\n * Авторизация, сессии и пароли.\n *\n * Доступна как `itd.auth`.\n */\nexport class AuthResource extends BaseResource {\n readonly #auth: AuthManager;\n readonly #connection: ClientConnection;\n readonly #qrFlows = new Map<string, QrCookieFlow>();\n\n constructor(http: HttpClient, deps: { auth: AuthManager; connection: ClientConnection }) {\n super(http);\n this.#auth = deps.auth;\n this.#connection = deps.connection;\n }\n\n #pruneQrFlows(): void {\n const now = this.#connection.clock.now();\n for (const [qrId, flow] of this.#qrFlows) {\n if (flow.expiresAt !== undefined && flow.expiresAt <= now) this.#qrFlows.delete(qrId);\n }\n }\n\n #qrFlow(qrId: string): QrCookieFlow {\n this.#pruneQrFlows();\n const existing = this.#qrFlows.get(qrId);\n if (existing) return existing;\n const flow = {\n cookies: this.#auth.createCookieFlow(false),\n expiresAt: undefined,\n captchaRequired: false,\n };\n this.#qrFlows.set(qrId, flow);\n return flow;\n }\n\n #touchQrFlow(flow: QrCookieFlow, expiresIn: number | undefined): void {\n if (typeof expiresIn !== 'number' || !Number.isFinite(expiresIn)) return;\n const expiresAt = this.#connection.clock.now() + Math.max(0, expiresIn) * 1_000;\n flow.expiresAt = flow.expiresAt === undefined ? expiresAt : Math.min(flow.expiresAt, expiresAt);\n }\n\n #forgetTerminalQrError(qrId: string, error: unknown): void {\n if (\n isItdApiError(error) &&\n error.hasCode('QR_EXPIRED', 'QR_ALREADY_USED', 'QR_TOKEN_MISMATCH')\n ) {\n this.#qrFlows.delete(qrId);\n }\n }\n\n /**\n * Проверяет состояние авторизации и возвращает текущего пользователя.\n *\n * Без авторизации возвращает `authenticated: false` и `user: null`.\n */\n check(options: RequestOptions = {}): Promise<AuthState> {\n return this.http.execute(AUTH_CHECK, {\n path: '/api/profile',\n ...options,\n });\n }\n\n /**\n * Узнаёт активного провайдера капчи и поле токена.\n *\n * Сервер может переключить провайдера или переименовать поле без выпуска новой версии SDK.\n * Автоматическому входу этот вызов не нужен — клиент делает его сам.\n */\n captchaProvider(options: RequestOptions = {}): Promise<CaptchaProvider> {\n return this.http.execute(AUTH_CAPTCHA_PROVIDER, {\n path: AUTH_PATHS.captchaProvider,\n skipAuth: true,\n skipAuthRefresh: true,\n ...options,\n });\n }\n\n /**\n * Узнаёт активного провайдера капчи вместе с адресом страницы виджета.\n *\n * То же, что {@link captchaProvider}, плюс `url` — готовая страница на домене итд.com,\n * где ключ виджета действителен. Пригодится встроенному браузеру: открыть её и забрать\n * токен, ничего не собирая самому.\n */\n captchaPage(options: RequestOptions = {}): Promise<CaptchaPage> {\n return this.http.execute(AUTH_CAPTCHA_PAGE, {\n path: AUTH_PATHS.captchaPage,\n skipAuth: true,\n skipAuthRefresh: true,\n ...options,\n });\n }\n\n /** Создаёт короткоживущую сессию QR-входа. */\n async startQrLogin(options: RequestOptions = {}): Promise<QrLoginStart> {\n const cookies = this.#auth.createCookieFlow(false);\n const result = await this.http.execute(AUTH_QR_START, {\n path: AUTH_PATHS.qrStart,\n skipAuth: true,\n skipAuthRefresh: true,\n cookieJar: cookies,\n ...options,\n });\n if (typeof result.qrId === 'string' && result.qrId !== '') {\n const flow = { cookies, expiresAt: undefined, captchaRequired: false };\n this.#touchQrFlow(flow, result.expiresIn);\n this.#qrFlows.set(result.qrId, flow);\n }\n return result;\n }\n\n /**\n * Проверяет QR-сессию и завершает вход после подтверждения на другом устройстве.\n *\n * До подтверждения возвращает промежуточный статус. Токен капчи добывается, только когда\n * сервер о ней попросил — статусом `captcha_required` на прошлой проверке, — либо когда\n * передан в сам вызов. Полученный `accessToken` автоматически сохраняется в клиенте.\n */\n async claimQrLogin(\n input: QrLoginClaimInput,\n options: RequestOptions = {},\n ): Promise<QrLoginClaim> {\n const revision = this.#auth.revision();\n const flow = this.#qrFlow(input.qrId);\n try {\n const { captcha, ...rest } = input;\n const needsCaptcha = captcha !== undefined || flow.captchaRequired;\n const result = await this.http.execute(AUTH_QR_CLAIM, {\n path: AUTH_PATHS.qrClaim,\n body: { ...rest, ...(needsCaptcha ? await this.#auth.captchaBody(captcha) : {}) },\n skipAuth: true,\n skipAuthRefresh: true,\n cookieJar: flow.cookies,\n ...options,\n });\n\n this.#touchQrFlow(flow, result.expiresIn);\n if (result.status === QrLoginStatus.CaptchaRequired) flow.captchaRequired = true;\n if (result.status === QrLoginStatus.Authorized) {\n await this.#auth.commitAuthFlow(result.accessToken, flow.cookies, revision);\n this.#qrFlows.delete(input.qrId);\n } else if (result.status === QrLoginStatus.Rejected) {\n this.#qrFlows.delete(input.qrId);\n }\n return result;\n } catch (error) {\n this.#forgetTerminalQrError(input.qrId, error);\n throw error;\n }\n }\n\n /**\n * Слушает состояния QR-входа до закрытия ответа или отмены `signal`.\n *\n * Событие `approved` означает, что подтверждение завершено: после него вызовите\n * {@link claimQrLogin}, чтобы получить и сохранить access token.\n */\n async streamQrLogin(\n input: QrLoginStreamInput,\n onEvent: QrLoginStreamListener,\n options: QrLoginStreamOptions = {},\n ): Promise<void> {\n if (typeof onEvent !== 'function') {\n throw new ItdConfigError('onEvent QR-потока должен быть функцией');\n }\n\n const flow = this.#qrFlow(input.qrId);\n try {\n await openQrLoginStream(\n this.#connection,\n flow.cookies,\n input,\n async (event) => {\n this.#touchQrFlow(flow, event.expiresIn);\n if (event.status === QrLoginStreamStatus.Rejected) this.#qrFlows.delete(input.qrId);\n await onEvent(event);\n },\n options.signal,\n );\n } catch (error) {\n this.#forgetTerminalQrError(input.qrId, error);\n throw error;\n }\n }\n\n /**\n * Отмечает QR-код отсканированным и узнаёт, кого впускают.\n *\n * Обратная сторона QR-входа: этот и два соседних метода вызывает устройство, где сессия\n * уже есть. Показывающая сторона увидит статус `scanned`, но вход ещё не состоится —\n * его завершают {@link approveQrLogin} или {@link rejectQrLogin}.\n *\n * Сервер принимает только сессию, созданную мобильным клиентом. Обычный web access token\n * отклоняется с кодом `QR_APPROVER_NOT_ALLOWED`, даже если добавить мобильные заголовки\n * уже после выдачи токена.\n *\n * @param input секреты из отсканированного кода — см. {@link QrLoginSecrets}\n * @returns описание устройства, которое просит вход\n */\n scanQrLogin(input: QrLoginSecrets, options: RequestOptions = {}): Promise<QrLoginTarget> {\n return this.http.execute(AUTH_QR_SCAN, {\n path: AUTH_PATHS.qrScan,\n body: input,\n ...options,\n });\n }\n\n /**\n * Подтверждает вход по QR-коду: показавшее код устройство получит access token.\n *\n * Осмысленно после {@link scanQrLogin} — человек должен увидеть, что подтверждает.\n * Требует мобильную сессию, как и `scanQrLogin()`.\n */\n approveQrLogin(input: QrLoginSecrets, options: RequestOptions = {}): Promise<void> {\n return this.voidOperation(AUTH_QR_APPROVE, {\n path: AUTH_PATHS.qrApprove,\n body: input,\n ...options,\n });\n }\n\n /**\n * Отклоняет вход по QR-коду: показавшее код устройство получит статус `rejected`.\n * Требует мобильную сессию, как и `scanQrLogin()`.\n */\n rejectQrLogin(input: QrLoginSecrets, options: RequestOptions = {}): Promise<void> {\n return this.voidOperation(AUTH_QR_REJECT, {\n path: AUTH_PATHS.qrReject,\n body: input,\n ...options,\n });\n }\n\n /**\n * Регистрирует аккаунт и запускает подтверждение по коду.\n *\n * @returns `flowToken`, который нужно передать в {@link verifyOtp}\n */\n async signUp(credentials: CredentialsWithCaptcha, options: RequestOptions = {}): Promise<string> {\n const { captcha, ...rest } = credentials;\n return this.http.execute(AUTH_SIGN_UP, {\n path: AUTH_PATHS.signUp,\n body: { ...rest, ...(await this.#auth.captchaBody(captcha)) },\n skipAuth: true,\n skipAuthRefresh: true,\n ...options,\n });\n }\n\n /**\n * Выполняет вход.\n *\n * Если сервер потребовал код подтверждения, вернётся `status: 'otp_required'` —\n * тогда продолжайте через {@link verifyOtp} либо воспользуйтесь {@link signInWithOtp}.\n *\n * При успешном входе токен сохраняется в клиенте автоматически.\n *\n * @param credentials email, пароль и токен капчи — см. {@link CredentialsWithCaptcha}\n */\n async signIn(\n credentials: CredentialsWithCaptcha,\n options: RequestOptions = {},\n ): Promise<SignInResult> {\n const { captcha, ...rest } = credentials;\n const revision = this.#auth.revision();\n const cookies = this.#auth.createCookieFlow(false);\n const body = { ...rest, ...(await this.#auth.captchaBody(captcha)) };\n const result = await this.http.execute(AUTH_SIGN_IN, {\n path: AUTH_PATHS.signIn,\n body,\n skipAuth: true,\n skipAuthRefresh: true,\n cookieJar: cookies,\n ...options,\n });\n\n if (result.status === SignInStatus.Authenticated) {\n await this.#auth.commitAuthFlow(result.accessToken, cookies, revision);\n } else {\n this.#auth.commitCookieFlow(cookies, revision);\n }\n return result;\n }\n\n /**\n * Подтверждает вход кодом из письма.\n *\n * Полученный токен сохраняется в клиенте автоматически.\n */\n async verifyOtp(\n input: Credentials & { otp: string; flowToken: string },\n options: RequestOptions = {},\n ): Promise<string> {\n const revision = this.#auth.revision();\n const cookies = this.#auth.createCookieFlow();\n const accessToken = await this.http.execute(AUTH_VERIFY_OTP, {\n path: AUTH_PATHS.verifyOtp,\n body: input,\n skipAuth: true,\n skipAuthRefresh: true,\n cookieJar: cookies,\n ...options,\n });\n\n await this.#auth.commitAuthFlow(accessToken, cookies, revision);\n return accessToken;\n }\n\n /** Отправляет код подтверждения повторно. */\n resendOtp(\n input: { email: string; flowToken: string },\n options: RequestOptions = {},\n ): Promise<void> {\n return this.voidOperation(AUTH_RESEND_OTP, {\n path: AUTH_PATHS.resendOtp,\n body: input,\n skipAuth: true,\n skipAuthRefresh: true,\n ...options,\n });\n }\n\n /**\n * Полный вход с подтверждением по коду.\n *\n * Удобно для скриптов и ботов: код запрашивается функцией `getOtp`, а всё остальное\n * библиотека делает сама.\n *\n * @example\n * ```ts\n * import { createInterface } from 'node:readline/promises';\n *\n * const rl = createInterface({ input: process.stdin, output: process.stdout });\n *\n * const token = await itd.auth.signInWithOtp({\n * email, password,\n * getOtp: () => rl.question('Код из письма: '),\n * });\n * ```\n */\n async signInWithOtp(\n input: CredentialsWithCaptcha & { getOtp: () => string | Promise<string> },\n options: RequestOptions = {},\n ): Promise<string> {\n const { getOtp, ...credentials } = input;\n const result = await this.signIn(credentials, options);\n\n if (result.status === SignInStatus.Authenticated) return result.accessToken;\n\n if (!result.flowToken) {\n throw new ItdConfigError(\n 'Сервер запросил код подтверждения, но не вернул flowToken — продолжить вход невозможно',\n );\n }\n\n const otp = await getOtp();\n\n // Токен капчи сюда не передаётся: он одноразовый и уже потрачен на sign-in,\n // а verify-otp капчу не требует.\n return this.verifyOtp(\n {\n email: credentials.email,\n password: credentials.password,\n otp,\n flowToken: result.flowToken,\n },\n options,\n );\n }\n\n /**\n * Обновляет токен доступа.\n *\n * Параллельные вызовы объединяются в один сетевой запрос. При включённом `autoRefresh`\n * вызывать вручную обычно не нужно.\n */\n refresh(): Promise<string> {\n return this.#auth.refresh();\n }\n\n /**\n * Есть ли признак живой сессии обновления.\n *\n * Проверяет cookie `is_auth`, которую сервер ставит рядом с refresh-токеном, а также\n * refresh-токен, переданный строкой. Позволяет не дёргать API у неавторизованного\n * пользователя. В браузере всегда `true`: cookie ведёт сама среда, и прочитать её\n * из JS нельзя.\n *\n * Читает {@link TokenStorage}, поэтому результат верен и до первого запроса.\n *\n * @example\n * ```ts\n * if (await itd.auth.hasRefreshSession()) await itd.auth.refresh();\n * else redirectToLogin();\n * ```\n */\n hasRefreshSession(): Promise<boolean> {\n return this.#auth.hasRefreshSession();\n }\n\n /** Завершает текущую сессию на сервере и очищает локальную. */\n async logout(options: RequestOptions = {}): Promise<void> {\n await this.voidOperation(AUTH_LOGOUT, {\n path: AUTH_PATHS.logout,\n skipAuthRefresh: true,\n ...options,\n });\n\n await this.#auth.clear();\n }\n\n /**\n * Завершает все сессии пользователя и очищает локальную.\n *\n * Собран из двух запросов, потому что единого эндпоинта на сервере нет:\n * `POST /api/v1/auth/logout-all` отвечает `404`. Сначала отзываются все прочие сессии\n * (`DELETE /api/v1/auth/sessions`), затем завершается текущая — в обратном порядке\n * отзывать было бы уже нечем.\n */\n async logoutAll(options: RequestOptions = {}): Promise<void> {\n await this.revokeOtherSessions(options);\n await this.logout(options);\n }\n\n /** Забывает сессию локально, не обращаясь к серверу. */\n signOut(): Promise<void> {\n return this.#auth.clear();\n }\n\n /**\n * Запрашивает письмо с кодом для сброса пароля.\n *\n * @returns `flowToken`, который нужно передать в {@link resetPassword}\n */\n async forgotPassword(input: ForgotPasswordInput, options: RequestOptions = {}): Promise<string> {\n return this.http.execute(AUTH_FORGOT_PASSWORD, {\n path: AUTH_PATHS.forgotPassword,\n body: { email: input.email, ...(await this.#auth.captchaBody(input.captcha)) },\n skipAuth: true,\n skipAuthRefresh: true,\n ...options,\n });\n }\n\n /**\n * Устанавливает новый пароль по коду из письма.\n *\n * Сервер ждёт все четыре поля сразу — `email`, `otp`, `flowToken` и `newPassword`;\n * при нехватке любого отвечает `422`.\n */\n resetPassword(input: ResetPasswordInput, options: RequestOptions = {}): Promise<void> {\n return this.voidOperation(AUTH_RESET_PASSWORD, {\n path: AUTH_PATHS.resetPassword,\n body: input,\n skipAuth: true,\n skipAuthRefresh: true,\n ...options,\n });\n }\n\n /**\n * Полный сброс пароля с кодом из письма.\n *\n * Тот же приём, что и {@link signInWithOtp}: код запрашивается функцией `getOtp`,\n * остальное библиотека делает сама.\n *\n * @example\n * ```ts\n * await itd.auth.resetPasswordWithOtp({\n * email,\n * captcha: { type: provider, token, field },\n * newPassword,\n * getOtp: () => rl.question('Код из письма: '),\n * });\n * ```\n */\n async resetPasswordWithOtp(\n input: ForgotPasswordInput & {\n newPassword: string;\n getOtp: () => string | Promise<string>;\n },\n options: RequestOptions = {},\n ): Promise<void> {\n const { getOtp, newPassword, ...request } = input;\n const flowToken = await this.forgotPassword(request, options);\n\n const otp = await getOtp();\n\n await this.resetPassword({ email: input.email, otp, flowToken, newPassword }, options);\n }\n\n /**\n * Меняет пароль. Требует действующей сессии.\n *\n * При неверном текущем пароле сервер отвечает `ACCOUNT_CURRENT_PASSWORD_INCORRECT`.\n *\n * @example\n * ```ts\n * await itd.auth.changePassword({ currentPassword, newPassword });\n * ```\n */\n changePassword(\n input: { currentPassword: string; newPassword: string },\n options: RequestOptions = {},\n ): Promise<void> {\n return this.voidOperation(AUTH_CHANGE_PASSWORD, {\n path: AUTH_PATHS.changePassword,\n body: { currentPassword: input.currentPassword, newPassword: input.newPassword },\n ...options,\n });\n }\n\n /** Загружает список активных сессий. У текущей поле `isCurrent` равно `true`. */\n sessions(options: RequestOptions = {}): Promise<Session[]> {\n return this.http.execute(AUTH_SESSIONS, {\n path: AUTH_PATHS.sessions,\n ...options,\n });\n }\n\n /** Завершает указанную сессию. */\n revokeSession(sessionId: string, options: RequestOptions = {}): Promise<void> {\n return this.voidOperation(AUTH_REVOKE_SESSION, {\n path: `${AUTH_PATHS.sessions}/${encodeURIComponent(sessionId)}`,\n ...options,\n });\n }\n\n /** Завершает все сессии, кроме текущей. */\n revokeOtherSessions(options: RequestOptions = {}): Promise<void> {\n return this.voidOperation(AUTH_REVOKE_OTHER_SESSIONS, {\n path: AUTH_PATHS.sessions,\n ...options,\n });\n }\n}\n","import { installAsyncDisposeFallback } from './core/async-dispose.js';\nimport type { Listener, Unsubscribe } from './core/emitter.js';\nimport { ItdConfigError, ItdStateError } from './core/errors.js';\nimport { type ClientRuntime, createClientRuntime } from './core/execution/client-runtime.js';\nimport { ExtensibleOperationCatalog } from './core/feature-catalog.js';\nimport { type ClientFeatureHost, createFeatureHost } from './core/feature-host.js';\nimport type { ClientFeature } from './core/features.js';\nimport type { RawRequestOptions } from './core/options.js';\nimport type { ClientPlugin } from './core/plugins/contracts.js';\nimport type { PluginRegistry } from './core/plugins/registry.js';\nimport type { RateLimitBucketState, RequestQueuePool } from './core/scheduling/rate-limit.js';\nimport type { ServiceDefinition } from './core/services.js';\nimport { ITD_CATALOG } from './domain/catalog.js';\nimport {\n NotificationEvents,\n resolveNotificationEventsOptions,\n setNotificationEventsConnectGuard,\n} from './events/stream.js';\nimport type { UserId } from './models/common.js';\nimport { createNotificationsApi, type NotificationsApi } from './notifications-api.js';\nimport { EVENT_OPERATIONS } from './operations/events.js';\nimport type { ItdClientOptions } from './options.js';\nimport { AuthResource } from './resources/auth.js';\nimport type { CommentsResource } from './resources/comments.js';\nimport type { FilesResource } from './resources/files.js';\nimport type { HashtagsResource } from './resources/hashtags.js';\nimport type { PlatformResource } from './resources/platform.js';\nimport type { PostsResource } from './resources/posts.js';\nimport type { ReportsResource } from './resources/reports.js';\nimport type { SearchResource } from './resources/search.js';\nimport type { ShopResource } from './resources/shop.js';\nimport { createStatusFeature } from './resources/status.js';\nimport type { SubscriptionResource } from './resources/subscription.js';\nimport type { TelemetryResource } from './resources/telemetry.js';\nimport type { UsersResource } from './resources/users.js';\nimport type { VerificationResource } from './resources/verification.js';\nimport { createResources, type RestResources } from './rest/resources.js';\nimport { type AuthEvents, type AuthManager, createItdAuth } from './session/auth.js';\nimport type { ItdSession } from './session/storage.js';\n\nconst CLIENT_PLUGIN_REGISTRIES = new WeakMap<ItdClient, PluginRegistry>();\nconst DISPOSED_CLIENTS = new WeakSet<ItdClient>();\n\nfunction assertClientActive(client: ItdClient, action: string): void {\n if (!DISPOSED_CLIENTS.has(client)) return;\n throw new ItdStateError(\n `ItdClient уже окончательно освобождён через dispose(); нельзя ${action}. Создайте новый клиент`,\n );\n}\n\n/** Проверяет возможность подключить плагин к клиенту без вызова `install()`. @internal */\nexport function assertClientCanUsePlugin(client: ItdClient, plugin: ClientPlugin): void {\n assertClientActive(client, 'подключить плагин');\n CLIENT_PLUGIN_REGISTRIES.get(client)?.assertCanAdd(plugin);\n}\n\n/** Проверяет возможность отключить плагин клиента без изменения реестра. @internal */\nexport function assertClientCanUnusePlugin(client: ItdClient, name: string): void {\n CLIENT_PLUGIN_REGISTRIES.get(client)?.assertCanRemove(name);\n}\n\n/**\n * Скрытые параметры конструктора — не часть публичного API.\n *\n * @internal\n */\ninterface ItdClientInternals {\n /**\n * Готовая очередь запросов — так {@link ItdAccounts} с `rateLimitScope: 'shared'` даёт\n * нескольким клиентам одну на всех. Свою клиент в этом случае не заводит и, что важнее,\n * не гасит при `close()`: чужие ожидающие запросы это отменило бы.\n */\n queues?: RequestQueuePool | undefined;\n}\n\nconst CLIENT_INTERNALS = new WeakMap<ItdClientOptions, ItdClientInternals>();\n\n/** Создаёт клиент с зависимостями внешнего контейнера, не расширяя публичный конструктор. @internal */\nexport function createManagedClient(\n options: ItdClientOptions,\n internals: ItdClientInternals,\n): ItdClient {\n const managedOptions = { ...options };\n CLIENT_INTERNALS.set(managedOptions, internals);\n return new ItdClient(managedOptions);\n}\n\n/**\n * Клиент API итд.com.\n *\n * Методы сгруппированы по разделам: `itd.posts`, `itd.users`, `itd.comments`, `itd.auth`,\n * `itd.files`. Авторизация, обновление токена, повторы и очередь запросов работают сами.\n *\n * @example Готовый токен — для разового вызова\n * ```ts\n * const itd = new ItdClient({ auth: '<accessToken>' });\n * const me = await itd.users.me();\n * ```\n *\n * @example Полноценная сессия для бота\n * ```ts\n * import { ItdClient } from 'itd-api';\n * import { FileTokenStorage } from 'itd-api/node';\n *\n * const itd = new ItdClient({\n * // `auth` не обязателен: когда хранилище уже содержит сессию, токен берётся оттуда,\n * // а истёкший продлевается сам. Здесь он нужен на первый запуск.\n * auth: { email, password },\n * // Капчу входа решает пакет @itd-api/captcha — см. CaptchaSolver.\n * captcha: createCaptchaSolver(),\n * storage: new FileTokenStorage('./.itd-session.json'),\n * rateLimit: { concurrency: 4, rps: 8 },\n * });\n *\n * for await (const post of itd.posts.iterate({ tab: 'following' })) {\n * if (!post.isLiked) await itd.posts.like(post.id);\n * }\n * ```\n */\nexport class ItdClient {\n readonly #runtime: ClientRuntime<AuthManager>;\n readonly #features: ClientFeatureHost;\n /** Общий результат терминальной очистки для идемпотентных повторных вызовов. */\n #disposePromise: Promise<void> | undefined;\n\n /** Ресурсы конвейера запросов; создаются при первом обращении. */\n readonly #resources: RestResources<NotificationsApi>;\n /** Сессионный ресурс живёт у фасада: он управляет входом и продлением. */\n #auth: AuthResource | undefined;\n\n /** Авторизация, сессии и пароли. */\n get auth(): AuthResource {\n this.#auth ??= new AuthResource(this.#runtime.http, {\n auth: this.#runtime.auth,\n connection: this.#runtime.connection(),\n });\n return this.#auth;\n }\n\n /** Профили, подписки, блокировки, приватность. */\n get users(): UsersResource {\n return this.#resources.users;\n }\n\n /** Лента, публикация, реакции, репосты, комментарии к постам. */\n get posts(): PostsResource {\n return this.#resources.posts;\n }\n\n /** Ответы на комментарии и действия над ними. */\n get comments(): CommentsResource {\n return this.#resources.comments;\n }\n\n /** Загрузка файлов и медиа. */\n get files(): FilesResource {\n return this.#resources.files;\n }\n\n /** Уведомления: список, счётчик, отметки о прочтении, настройки. */\n get notifications(): NotificationsApi {\n return this.#resources.notifications;\n }\n\n /** Хэштеги и посты по ним. */\n get hashtags(): HashtagsResource {\n return this.#resources.hashtags;\n }\n\n /** Глобальный поиск по пользователям и хэштегам. */\n get search(): SearchResource {\n return this.#resources.search;\n }\n\n /** Жалобы на контент и пользователей. */\n get reports(): ReportsResource {\n return this.#resources.reports;\n }\n\n /** Верификация профиля. */\n get verification(): VerificationResource {\n return this.#resources.verification;\n }\n\n /** Подписка и способы оплаты. */\n get subscription(): SubscriptionResource {\n return this.#resources.subscription;\n }\n\n /** Сведения о платформе: версии приложений, изменения, анонсы, баннер события. */\n get platform(): PlatformResource {\n return this.#resources.platform;\n }\n\n /** Телеметрия просмотров. */\n get telemetry(): TelemetryResource {\n return this.#resources.telemetry;\n }\n\n /** Каталог, доставка и заказы магазина ИТД. */\n get shop(): ShopResource {\n return this.#resources.shop;\n }\n\n constructor(options: ItdClientOptions = {}) {\n const notificationEventsOptions = resolveNotificationEventsOptions(\n options.events?.notifications,\n );\n const internals = CLIENT_INTERNALS.get(options) ?? {};\n const catalog = new ExtensibleOperationCatalog(ITD_CATALOG);\n let featureHost: ClientFeatureHost | undefined;\n this.#runtime = createClientRuntime(options, {\n catalog,\n queues: internals.queues,\n assertActive: (action) => assertClientActive(this, action),\n // Полноценную сессию подставляет фасад: ядро о ней не знает, и клиент с готовым\n // токеном не потянет за собой ни хранилище, ни вход по паролю.\n auth: (deps) =>\n createItdAuth(options, { ...deps, onAccountChange: () => featureHost?.stop() }),\n });\n this.#features = featureHost = createFeatureHost(this.#runtime, {\n catalog,\n assertActive: (action) => assertClientActive(this, action),\n });\n const status = this.#features.install(createStatusFeature());\n this.#resources = createResources({\n http: this.#runtime.http,\n files: this.#features.files,\n status,\n createNotifications: (http) =>\n createNotificationsApi(http, (notifications) => {\n let events!: NotificationEvents;\n let lifecycleGeneration = 0;\n let lifecycleActive = false;\n let unregister: (() => void) | undefined;\n\n const releaseAfterDrain = (generation: number): void => {\n void events.drain().then(() => {\n if (lifecycleActive || generation !== lifecycleGeneration) return;\n unregister?.();\n unregister = undefined;\n });\n };\n\n events = new NotificationEvents(\n {\n connection: this.#runtime.connection(),\n request: ({ operationId, path, query, signal }) =>\n this.#runtime.http.execute(EVENT_OPERATIONS[operationId], {\n path,\n query,\n signal,\n }),\n getAuthIdentity: () => this.#runtime.auth.getCurrentAuthIdentity(),\n getAuthScope: () => this.#runtime.auth.getAuthScope(),\n fetchUnreadCount: (signal) => notifications.count({ signal }),\n onConnect: () => {\n lifecycleGeneration += 1;\n unregister ??= this.#features.manage({\n kind: `notifications:${events.transport}`,\n stop: () => {\n if (lifecycleActive) events.disconnect();\n },\n drain: () => events.drain(),\n });\n lifecycleActive = true;\n },\n onClose: () => {\n lifecycleActive = false;\n releaseAfterDrain(++lifecycleGeneration);\n },\n logger: this.#runtime.config.logger,\n clock: this.#runtime.config.clock,\n },\n notificationEventsOptions,\n );\n setNotificationEventsConnectGuard(events, () =>\n assertClientActive(this, 'подключить канал событий уведомлений'),\n );\n return events;\n }),\n });\n CLIENT_PLUGIN_REGISTRIES.set(this, this.#runtime.plugins);\n }\n\n /** Базовый URL, к которому обращается клиент. */\n get baseUrl(): string {\n return this.#runtime.config.baseUrl;\n }\n\n /**\n * Выполняет произвольный запрос к API.\n *\n * Запасной путь для случаев, когда нужного метода ещё нет или ответ сервера разошёлся\n * с документацией. Проходит через ту же авторизацию, очередь и обработку ошибок.\n *\n * @example\n * ```ts\n * const raw = await itd.request({ method: 'GET', path: '/api/posts', raw: true });\n * ```\n *\n * @throws {ItdStateError} если клиент уже освобождён через {@link dispose}\n */\n request<T = unknown>(options: RawRequestOptions): Promise<T> {\n return this.#runtime.http.request<T>({\n ...options,\n operationId: options.operationId ?? 'raw',\n });\n }\n\n /**\n * Остаток серверных лимитов по бакетам, через которые уже проходили запросы.\n *\n * Значения берутся из последнего ответа каждого бакета и быстро устаревают: сервер\n * восстанавливает квоту линейно и границу окна не сообщает. Пустой массив при\n * `rateLimit: false`. {@link close} снимок сохраняет, {@link dispose} очищает.\n *\n * @example\n * ```ts\n * const posts = itd.rateLimitState().find((state) => state.bucket === 'posts.create');\n * if ((posts?.remaining ?? Number.POSITIVE_INFINITY) < 3) await sleep(60_000);\n * ```\n */\n rateLimitState(): RateLimitBucketState[] {\n return this.#runtime.rateLimitState();\n }\n\n /**\n * Устанавливает предметный модуль с общей сессией и обработкой запросов клиента.\n *\n * Сервисы, операции и бакеты регистрируются до синхронного `setup()`. Возвращает\n * типизированный API модуля.\n */\n install<TApi>(feature: ClientFeature<TApi>): TApi {\n return this.#features.install(feature);\n }\n\n /**\n * Устанавливает модуль и добавляет его API в свойство клиента только для чтения.\n *\n * Возвращаемое пересечение сохраняет тип уже подключённых свойств, поэтому вызовы можно\n * объединять в цепочку: `new ItdClient().withFeature('pixelBattle', pixelBattleFeature)`.\n */\n withFeature<const K extends string, TApi>(\n key: K,\n feature: ClientFeature<TApi>,\n ): this & { readonly [P in K]: TApi } {\n assertClientActive(this, 'установить feature');\n if (typeof key !== 'string' || key.trim() === '' || key !== key.trim()) {\n throw new ItdConfigError('Свойство feature должно иметь непустое имя без краевых пробелов');\n }\n if (key === 'then' || key in this) {\n throw new ItdConfigError(`Свойство клиента «${key}» уже занято или зарезервировано`);\n }\n if (!Object.isExtensible(this)) {\n throw new ItdConfigError('Нельзя опубликовать feature на нерасширяемом клиенте');\n }\n\n const api = this.install(feature);\n Object.defineProperty(this, key, {\n value: api,\n enumerable: true,\n configurable: false,\n writable: false,\n });\n return this as this & { readonly [P in K]: TApi };\n }\n\n /** Имена установленных модулей в порядке установки. */\n featureNames(): string[] {\n return this.#features.names();\n }\n\n /** Установлен ли модуль с таким именем. */\n hasFeature(name: string): boolean {\n return this.#features.has(name);\n }\n\n /**\n * Подключает плагин.\n *\n * Плагин может регистрировать обёртки операций и перехватчики сетевых попыток.\n *\n * @throws {ItdConfigError} если плагин задан неверно или уже подключён\n * @throws {ItdStateError} если клиент уже освобождён через {@link dispose}\n *\n * @example\n * ```ts\n * import { crypt } from '@itd-api/crypto';\n *\n * itd.use(crypt());\n * await itd.posts.create({\n * content: 'секрет',\n * }, {\n * extensions: { crypto: { encrypt: 'invisible' } },\n * });\n * ```\n */\n use(plugin: ClientPlugin): this {\n assertClientActive(this, 'подключить плагин');\n this.#runtime.plugins.add(plugin, {\n baseUrl: this.#runtime.config.baseUrl,\n logger: this.#runtime.config.logger,\n getAuthScope: () => this.#runtime.auth.getAuthScope(),\n getAuthIdentity: () => this.#runtime.auth.getAuthIdentity(),\n });\n return this;\n }\n\n /** Имена подключённых плагинов в фактическом порядке выполнения обёрток. */\n pluginNames(): string[] {\n return this.#runtime.plugins.names();\n }\n\n /** Подключён ли плагин с таким именем. */\n hasPlugin(name: string): boolean {\n return this.#runtime.plugins.has(name);\n }\n\n /**\n * Отключает плагин и освобождает заведённые им ресурсы.\n *\n * Новые запросы перестают видеть плагин сразу. Очистка дождётся логического запроса,\n * который уже проходил через его обёртку.\n *\n * @returns `false`, если такого плагина не было\n * @throws {ItdConfigError} если от плагина зависит другой подключённый плагин\n */\n unuse(name: string): Promise<boolean> {\n return this.#runtime.plugins.remove(name);\n }\n\n /**\n * Регистрирует сервис платформы — домен, отличный от основного.\n *\n * Запросы с `{ service: 'имя' }` уходят на его хост с его заголовками. То же самое умеет\n * опция `services` конструктора. Занятое имя не переопределяется — ни своё, ни встроенное:\n * разовому запросу хост задаётся полем `baseUrl`.\n *\n * Заголовок авторизации по умолчанию уходит только своим — домену клиента и его\n * поддоменам. Стороннему хосту токен нужно разрешить явно: `auth: true`.\n *\n * @throws {ItdConfigError} если определение неверно или имя уже занято\n * @throws {ItdStateError} если клиент уже освобождён через {@link dispose}\n *\n * @example Сервис платформы на поддомене — токен уходит сам\n * ```ts\n * itd.defineService({\n * name: 'pb',\n * baseUrl: 'https://pbapi.xn--d1ah4a.com',\n * headers: { Referer: 'https://pixel.xn--d1ah4a.com/' },\n * });\n *\n * await itd.request({ method: 'GET', service: 'pb', path: '/api/pixel-info' });\n * ```\n */\n defineService(definition: ServiceDefinition): this {\n assertClientActive(this, 'зарегистрировать сервис');\n this.#runtime.services.define(definition);\n return this;\n }\n\n /**\n * Базовый URL зарегистрированного сервиса.\n *\n * @throws {ItdConfigError} если сервис не зарегистрирован\n */\n serviceBaseUrl(name: string): string {\n return this.#runtime.services.resolveBaseUrl(name);\n }\n\n /**\n * Подписывается на события авторизации.\n *\n * Полезно, чтобы сохранять сессию во внешнее хранилище или узнавать, что вход\n * окончательно потерян.\n *\n * @returns функция отписки\n *\n * @example\n * ```ts\n * itd.on('tokens', ({ accessToken }) => cache.set('itd', accessToken));\n * itd.on('authError', () => notifyUser('Сессия истекла, войдите заново'));\n * ```\n */\n on<K extends keyof AuthEvents>(event: K, listener: Listener<AuthEvents[K]>): Unsubscribe {\n assertClientActive(this, 'подписаться на события');\n return this.#runtime.auth.on(event, listener);\n }\n\n /**\n * Освобождает ресурсы клиента: закрывает все потоки уведомлений, отправляет открытые\n * накопители {@link telemetry}, затем останавливает очередь запросов.\n *\n * Метод дожидается завершения активных обработчиков и освобождения ресурсов остановленных\n * событийных соединений, но не дольше `shutdownTimeout`. После вызова клиентом можно\n * пользоваться снова; ранее созданный поток можно запустить повторным `connect()`.\n *\n * Общая очередь, полученная от {@link ItdAccounts}, не останавливается: её гасит сам\n * контейнер, когда закрывает все аккаунты разом.\n *\n * Терминальное освобождение — это {@link dispose}.\n *\n * @throws {ItdStateError} если остановка событийного соединения не завершилась за отведённый срок\n */\n async close(): Promise<void> {\n return this.#close(false);\n }\n\n async #close(disposeCleanup: boolean): Promise<void> {\n // Terminal cleanup должен пометить batch до первого await: параллельный обычный close()\n // мог уже начать drain потоков, но ещё не дойти до отправки телеметрии.\n if (disposeCleanup) this.#resources.prepareTelemetryClose();\n const errors: unknown[] = [];\n try {\n try {\n await this.#features.close();\n } catch (error) {\n errors.push(error);\n }\n\n // Через геттер закрытие клиента поднимало бы накопитель телеметрии только ради\n // того, чтобы его тут же закрыть.\n try {\n await this.#resources.closeTelemetry(disposeCleanup);\n } catch (error) {\n errors.push(error);\n }\n } finally {\n this.#runtime.close();\n }\n if (errors.length === 1) throw errors[0];\n if (errors.length > 1) throw new AggregateError(errors, 'Не удалось закрыть клиент');\n }\n\n /**\n * Окончательно освобождает клиент: выполняет {@link close}, отменяет незавершённые\n * запросы и отключает все плагины.\n *\n * Терминальное состояние устанавливается сразу при первом вызове. После этого новые\n * запросы, подключение плагинов, регистрация сервисов и создание или повторный запуск\n * событийных каналов завершаются с {@link ItdStateError}. Повторные вызовы возвращают\n * тот же результат очистки.\n *\n * Ожидание остановки событийных соединений и операций плагинов ограничено\n * `shutdownTimeout`.\n *\n * @example\n * ```ts\n * await using itd = new ItdClient({ auth: token });\n * // …работа…\n * // dispose() вызовется сам на выходе из блока\n * ```\n */\n dispose(): Promise<void> {\n if (this.#disposePromise) return this.#disposePromise;\n DISPOSED_CLIENTS.add(this);\n this.#disposePromise = this.#dispose();\n return this.#disposePromise;\n }\n\n async #dispose(): Promise<void> {\n const errors: unknown[] = [];\n try {\n // Сначала завершаем потоки и телеметрию через ещё установленные плагины.\n await this.#close(true);\n } catch (error) {\n errors.push(error);\n }\n try {\n await this.#features.dispose();\n } catch (error) {\n errors.push(error);\n }\n try {\n await this.#runtime.dispose();\n } catch (error) {\n errors.push(error);\n }\n if (errors.length > 0) throw new AggregateError(errors, 'Не удалось освободить клиент');\n }\n\n /** Позволяет использовать клиент с `await using`. */\n [Symbol.asyncDispose](): Promise<void> {\n return this.dispose();\n }\n\n static {\n installAsyncDisposeFallback(ItdClient);\n }\n\n /** Текущая сессия целиком — чтобы сохранить её самостоятельно. */\n getSession(): Promise<ItdSession | null> {\n return this.#runtime.auth.getSession();\n }\n\n /**\n * Идентификатор аккаунта, под которым работает клиент.\n *\n * Читается из токена доступа и не стоит ни одного запроса. `undefined`, когда сессии\n * ещё нет или токен выдан не в формате JWT. Полезен прежде всего с {@link ItdAccounts}:\n * показывает, какому профилю соответствует восстановленная из хранилища запись.\n * Свежий профиль целиком отдаёт `itd.users.me()`.\n *\n * @remarks\n * JWT только декодируется: его подпись не проверяется. Результат подходит для локального\n * разделения состояния, но не доказывает личность пользователя и не заменяет проверку\n * авторизации сервером.\n *\n * @example\n * ```ts\n * for (const [name, itd] of accounts) console.log(name, await itd.getUserId());\n * ```\n */\n getUserId(): Promise<UserId | undefined> {\n return this.#runtime.auth.getUserId();\n }\n\n /**\n * Восстанавливает сохранённую сессию, включая cookie.\n *\n * @throws {ItdStateError} если клиент уже освобождён через {@link dispose}\n */\n setSession(session: ItdSession): Promise<void> {\n try {\n assertClientActive(this, 'изменить сессию');\n } catch (error) {\n return Promise.reject(error);\n }\n return this.#runtime.auth.setSession(session);\n }\n}\n\n/**\n * Создаёт клиент API итд.com.\n *\n * То же, что `new ItdClient(options)`, — для тех, кому привычнее фабрика.\n *\n * @example\n * ```ts\n * const itd = createClient({ auth: token });\n * ```\n */\nexport function createClient(options: ItdClientOptions = {}): ItdClient {\n return new ItdClient(options);\n}\n","import {\n assertClientCanUnusePlugin,\n assertClientCanUsePlugin,\n createManagedClient,\n type ItdClient,\n} from './client.js';\nimport { installAsyncDisposeFallback } from './core/async-dispose.js';\nimport { systemClock } from './core/clock.js';\nimport { DEFAULT_BASE_URL, resolveRateLimit } from './core/config.js';\nimport { Emitter, type Listener, reportListenerError, type Unsubscribe } from './core/emitter.js';\nimport { ItdConfigError, ItdStateError } from './core/errors.js';\nimport type { ClientFeature } from './core/features.js';\nimport type { Logger } from './core/options.js';\nimport type { ClientPlugin } from './core/plugins/contracts.js';\nimport { assertPluginRemovable, orderPluginDefinitions } from './core/plugins/order.js';\nimport { RequestQueuePool } from './core/scheduling/rate-limit.js';\nimport { ITD_CATALOG } from './domain/catalog.js';\nimport type { ItdClientOptions } from './options.js';\nimport {\n type ControlledTokenStorage,\n controlledTokenStorage,\n isRestorableSession,\n MemoryMultiTokenStorage,\n type MultiTokenStorage,\n} from './session/multi-storage.js';\nimport type { TokenStorage } from './session/storage.js';\n\n/** Как аккаунты делят между собой очередь запросов. */\nexport type RateLimitScope = 'account' | 'shared';\n\n/**\n * Фабрика подключаемого модуля для клиентов {@link ItdAccounts}.\n *\n * `create()` вызывается отдельно для каждого аккаунта, поэтому описание модуля и его API\n * между клиентами не разделяется. `key` публикует API как readonly-свойство клиента.\n */\nexport interface AccountFeature<TApi = unknown> {\n readonly key?: string | undefined;\n create(): ClientFeature<TApi>;\n}\n\n/**\n * Опции конструктора {@link ItdAccounts}.\n *\n * Всё, что понимает `ItdClient`, кроме `auth` и `deviceId`: они у каждого аккаунта свои\n * и задаются в {@link ItdAccounts.addAccount}. Остальное достаётся каждому клиенту —\n * источник токена капчи, заданный здесь, работает для всех аккаунтов. Обычный `TokenStorage`\n * клиента здесь заменён\n * общей опцией {@link ItdAccountsOptions.storage} типа {@link MultiTokenStorage}; контейнер\n * сам выдаёт каждому клиенту изолированный срез по имени. Общий `deviceId` особенно вреден —\n * сервер различает по нему записи в списке сессий, и один на всех сложил бы все аккаунты\n * в одну.\n */\nexport interface ItdAccountsOptions\n extends Omit<ItdClientOptions, 'auth' | 'storage' | 'deviceId'> {\n /** Общее хранилище сессий всех аккаунтов. По умолчанию {@link MemoryMultiTokenStorage}. */\n storage?: MultiTokenStorage | undefined;\n /** Плагины, подключаемые каждому аккаунту, в том числе добавленному позже. */\n plugins?: readonly ClientPlugin[] | undefined;\n /** Модули, создаваемые и устанавливаемые отдельно для каждого аккаунта. */\n features?: readonly AccountFeature[] | undefined;\n /**\n * Как делить очередь запросов. По умолчанию `'shared'` — одна на всех.\n *\n * Лимиты итд.com считаются по IP, поэтому аккаунты с одного адреса тратят общую квоту.\n * `'account'` даёт каждому свою очередь и нужен, когда у аккаунтов разные адреса —\n * например, при своём прокси у каждого.\n *\n * В режиме `'shared'` настройки очереди берутся из общей опции `rateLimit`; аккаунту\n * разрешён только `rateLimit: false`, выводящий его из общей очереди.\n */\n rateLimitScope?: RateLimitScope | undefined;\n}\n\n/**\n * Настройки одного аккаунта. Общее мультихранилище задаёт контейнер, а аккаунт получает\n * свой срез автоматически; остальное — как у `ItdClient`.\n *\n * При `rateLimitScope: 'shared'` (умолчание) объект `rateLimit` задаётся только\n * контейнеру; аккаунту разрешено передать `false`, чтобы не ставить его запросы\n * в общую очередь.\n */\nexport type AddAccountOptions = Omit<ItdClientOptions, 'storage'>;\n\n/** Что можно уточнить при удалении аккаунта. */\nexport interface RemoveAccountOptions {\n /**\n * Удалить и сохранённую сессию. По умолчанию `false` — аккаунт убирается только\n * из памяти, а его токены остаются в хранилище и переживут перезапуск.\n */\n forget?: boolean | undefined;\n}\n\n/**\n * События авторизации всех аккаунтов сразу.\n *\n * Те же, что у одиночного клиента, плюс имя аккаунта: подписка на контейнер избавляет\n * от нужды вешать обработчик на каждого.\n */\nexport interface AccountEvents {\n /** Токен получен или обновлён. */\n tokens: { account: string; accessToken: string };\n /** Выполнен вход. */\n signIn: { account: string; accessToken: string };\n /** Сессия очищена — вручную или из-за неудачного обновления. */\n signOut: { account: string };\n /** Обновить сессию не удалось; дальнейшие запросы этого аккаунта будут падать с 401. */\n authError: { account: string; error: unknown };\n}\n\n/** Проверяет имя до создания клиента или частичного восстановления контейнера. */\nfunction validateAccountName(name: string): void {\n if (typeof name !== 'string' || name.trim() === '') {\n throw new ItdConfigError('имя аккаунта должно быть непустой строкой');\n }\n}\n\n/** Проверяет фабрики до создания первого аккаунта. */\nfunction resolveAccountFeatures(features: readonly AccountFeature[] | undefined): AccountFeature[] {\n if (features === undefined) return [];\n if (!Array.isArray(features)) {\n throw new ItdConfigError('features должен быть массивом фабрик подключаемых модулей');\n }\n\n const keys = new Set<string>();\n return features.map((feature, index) => {\n if (typeof feature !== 'object' || feature === null || typeof feature.create !== 'function') {\n throw new ItdConfigError(`features[${index}] должен предоставлять create()`);\n }\n if (feature.key !== undefined) {\n if (\n typeof feature.key !== 'string' ||\n feature.key.trim() === '' ||\n feature.key !== feature.key.trim()\n ) {\n throw new ItdConfigError(\n `features[${index}].key должен быть непустой строкой без пробелов`,\n );\n }\n if (keys.has(feature.key)) {\n throw new ItdConfigError(\n `Свойство подключаемого модуля «${feature.key}» объявлено повторно`,\n );\n }\n keys.add(feature.key);\n }\n const create = feature.create.bind(feature);\n return Object.freeze({\n ...(feature.key === undefined ? {} : { key: feature.key }),\n create,\n });\n });\n}\n\nconst DISPOSED_ACCOUNTS = new WeakSet<ItdAccounts>();\n\nfunction assertAccountsActive(accounts: ItdAccounts, action: string): void {\n if (!DISPOSED_ACCOUNTS.has(accounts)) return;\n throw new ItdStateError(\n `ItdAccounts уже окончательно освобождён через dispose(); нельзя ${action}. Создайте новый контейнер`,\n );\n}\n\n/**\n * Несколько аккаунтов итд.com в одном месте.\n *\n * Контейнер именованных `ItdClient`: каждый аккаунт получает собственный токен, cookie\n * и `deviceId`, а сессии всех складываются в одно хранилище — обычно в один файл, а не\n * в десяток. Имя аккаунта выбираете вы; сервер о нём ничего не знает.\n *\n * @example Бот на нескольких аккаунтах\n * ```ts\n * import { ItdAccounts } from 'itd-api';\n * import { FileMultiTokenStorage } from 'itd-api/node';\n *\n * await using accounts = new ItdAccounts({\n * storage: new FileMultiTokenStorage('./.itd-sessions.json'),\n * // Общие опции достаются каждому аккаунту: один источник токена капчи на всех.\n * captcha: createCaptchaSolver(),\n * rateLimit: { concurrency: 4 },\n * });\n *\n * // Восстанавливаем тех, кто уже входил раньше: токен возьмётся из хранилища.\n * await accounts.restore();\n *\n * if (!accounts.has('kiow')) {\n * accounts.addAccount('kiow', { auth: { email, password } });\n * }\n *\n * await accounts.account('kiow').posts.create({ content: 'привет' });\n *\n * for (const [name, itd] of accounts) {\n * console.log(name, await itd.getUserId());\n * }\n * ```\n */\nexport class ItdAccounts {\n /** Опции, общие для всех аккаунтов, — без полей, которые задаются поаккаунтно. */\n readonly #base: Omit<ItdClientOptions, 'auth' | 'storage' | 'deviceId'>;\n readonly #storage: MultiTokenStorage;\n readonly #clients = new Map<string, ItdClient>();\n /** Имена, чьё удаление ещё не завершилось: повторно занять их пока нельзя. */\n readonly #removing = new Set<string>();\n /** Уже начатые удаления, которых должен дождаться терминальный dispose(). */\n readonly #accountRemovals = new Set<Promise<void>>();\n /** Управляемые срезы хранилища: после удаления аккаунт больше не может писать через свой. */\n readonly #storageControls = new Map<string, ControlledTokenStorage>();\n /** Подписки на события клиентов — снимаются вместе с аккаунтом. */\n readonly #eventUnsubscribers = new Map<string, Unsubscribe[]>();\n /** Плагины для всех: и для уже заведённых аккаунтов, и для будущих. */\n readonly #plugins: ClientPlugin[];\n /** Фабрики модулей для новых и восстанавливаемых аккаунтов. */\n readonly #features: AccountFeature[];\n /** Имена плагинов, чья асинхронная очистка ещё не завершилась. */\n readonly #removingPlugins = new Set<string>();\n /** Общая очередь. `undefined`, когда у каждого аккаунта своя. */\n readonly #queues: RequestQueuePool | undefined;\n readonly #rateLimitScope: RateLimitScope;\n readonly #emitter: Emitter<AccountEvents>;\n readonly #logger: Logger | undefined;\n /** Общий результат терминальной очистки для идемпотентных повторных вызовов. */\n #disposePromise: Promise<void> | undefined;\n\n constructor(options: ItdAccountsOptions = {}) {\n const { storage, plugins, features, rateLimitScope, ...base } = options;\n\n if (\n rateLimitScope !== undefined &&\n rateLimitScope !== 'account' &&\n rateLimitScope !== 'shared'\n ) {\n throw new ItdConfigError(\"rateLimitScope должен быть 'account' или 'shared'\");\n }\n\n this.#base = base;\n this.#storage = storage ?? new MemoryMultiTokenStorage();\n this.#plugins = orderPluginDefinitions(plugins ?? []);\n this.#features = resolveAccountFeatures(features);\n this.#rateLimitScope = rateLimitScope ?? 'shared';\n\n // Общая очередь заводится сразу: проверить опции лучше при создании контейнера,\n // а не при добавлении первого аккаунта.\n const rateLimit =\n this.#rateLimitScope === 'shared' ? resolveRateLimit(base.rateLimit, ITD_CATALOG) : undefined;\n this.#queues = rateLimit\n ? new RequestQueuePool(rateLimit, base.clock ?? systemClock)\n : undefined;\n\n const logger = typeof base.logger === 'object' ? base.logger : undefined;\n this.#logger = logger;\n this.#emitter = new Emitter<AccountEvents>((error) =>\n reportListenerError(logger, 'аккаунтов', error),\n );\n }\n\n /** Общее хранилище сессий — то же, что передано опцией `storage`. */\n get storage(): MultiTokenStorage {\n return this.#storage;\n }\n\n /** Сколько аккаунтов заведено. */\n get size(): number {\n return this.#clients.size;\n }\n\n /** Имена заведённых аккаунтов в порядке добавления. */\n names(): string[] {\n return [...this.#clients.keys()];\n }\n\n /** Заведён ли аккаунт с таким именем. */\n has(name: string): boolean {\n return this.#clients.has(name);\n }\n\n /**\n * Заводит аккаунт.\n *\n * Возвращается обычный `ItdClient` — со всеми ресурсами, плагинами и каналом событий.\n * Хранилище ему подставляется само: срез общего по имени аккаунта.\n *\n * Опция `auth` не обязательна: когда сессия этого аккаунта уже лежит в хранилище,\n * токен возьмётся оттуда, а истёкший продлится сам.\n *\n * @throws {ItdConfigError} если имя пустое или уже занято\n *\n * @example\n * ```ts\n * accounts.addAccount('bot', { auth: { email, password } });\n * accounts.addAccount('reader', { auth: '<accessToken>' });\n * accounts.addAccount('через-прокси', { fetch: proxyFetch('socks5://…') });\n * ```\n */\n addAccount(name: string, options: AddAccountOptions = {}): ItdClient {\n assertAccountsActive(this, 'добавить аккаунт');\n validateAccountName(name);\n if (this.#clients.has(name)) {\n throw new ItdConfigError(\n `аккаунт «${name}» уже добавлен. Возьмите его через accounts.account('${name}')`,\n );\n }\n if (this.#removing.has(name)) {\n throw new ItdConfigError(\n `аккаунт «${name}» ещё удаляется. Дождитесь завершения removeAccount() перед повторным добавлением`,\n );\n }\n if (\n this.#rateLimitScope === 'shared' &&\n options.rateLimit !== undefined &&\n options.rateLimit !== false\n ) {\n throw new ItdConfigError(\n \"при rateLimitScope: 'shared' настройки rateLimit задаются контейнеру; \" +\n 'аккаунту можно передать только rateLimit: false',\n );\n }\n\n const storageControl = controlledTokenStorage(this.#storage, name);\n let client: ItdClient | undefined;\n try {\n client = createManagedClient(\n this.#mergeOptions(options, storageControl.storage),\n this.#queues ? { queues: this.#queues } : {},\n );\n\n for (const plugin of this.#plugins) client.use(plugin);\n for (const feature of this.#features) {\n const manifest = feature.create();\n if (feature.key === undefined) client.install(manifest);\n else client.withFeature(feature.key, manifest);\n }\n } catch (error) {\n storageControl.revoke();\n if (client) {\n void client.dispose().catch((cleanupError: unknown) => {\n this.#reportCleanup('неудачного добавления аккаунта', cleanupError);\n });\n }\n throw error;\n }\n\n const unsubscribers = this.#forwardEvents(name, client);\n this.#storageControls.set(name, storageControl);\n this.#eventUnsubscribers.set(name, unsubscribers);\n this.#clients.set(name, client);\n\n return client;\n }\n\n /**\n * Клиент аккаунта.\n *\n * @throws {ItdConfigError} если такого аккаунта нет\n *\n * @example\n * ```ts\n * await accounts.account('kiow').posts.like(postId);\n * ```\n */\n account(name: string): ItdClient {\n assertAccountsActive(this, 'получить клиент аккаунта');\n const client = this.#clients.get(name);\n if (!client) {\n const known = this.names();\n throw new ItdConfigError(\n `аккаунт «${name}» не заведён. ` +\n (known.length > 0\n ? `Известны: ${known.join(', ')}`\n : 'Ни одного аккаунта нет — добавьте его через addAccount() или restore()'),\n );\n }\n\n return client;\n }\n\n /**\n * Поднимает аккаунты, сессии которых уже лежат в хранилище.\n *\n * То, ради чего мультихранилище знает свой состав: после перезапуска процесса\n * ни `auth`, ни капча не нужны — токен, `deviceId` и cookie берутся из сохранённого.\n * Уже заведённые аккаунты не трогаются. Записи, в которых после выхода остался только\n * `deviceId`, пропускаются: авторизованной сессии в них уже нет.\n *\n * @returns имена добавленных аккаунтов\n *\n * @example\n * ```ts\n * const restored = await accounts.restore();\n * console.log(`подняли ${restored.length} аккаунтов без единого входа`);\n * ```\n */\n async restore(): Promise<string[]> {\n assertAccountsActive(this, 'восстановить аккаунты');\n const saved = await this.#storage.accounts();\n for (const name of saved) validateAccountName(name);\n\n const candidates = [...new Set(saved)].filter((name) => !this.#clients.has(name));\n const sessions = await Promise.all(\n candidates.map(async (name) => ({ name, session: await this.#storage.get(name) })),\n );\n const added: string[] = [];\n\n for (const { name, session } of sessions) {\n if (!isRestorableSession(session, this.#base.baseUrl ?? DEFAULT_BASE_URL)) continue;\n // Пока читали хранилище, аккаунт могли добавить вручную или начать удалять.\n if (this.#clients.has(name) || this.#removing.has(name)) continue;\n this.addAccount(name);\n added.push(name);\n }\n\n return added;\n }\n\n /**\n * Убирает аккаунт: закрывает его клиента и, если попросить, забывает сессию.\n *\n * Сетевого запроса не выполняет. Чтобы завершить сессию на сервере, вызовите\n * `itd.auth.logout()` до удаления.\n *\n * @returns `false`, если такого аккаунта и не было\n */\n async removeAccount(name: string, options: RemoveAccountOptions = {}): Promise<boolean> {\n assertAccountsActive(this, 'удалить аккаунт');\n const client = this.#clients.get(name);\n if (!client) return false;\n\n this.#removing.add(name);\n this.#clients.delete(name);\n const storageControl = this.#storageControls.get(name);\n storageControl?.revoke();\n this.#storageControls.delete(name);\n\n for (const unsubscribe of this.#eventUnsubscribers.get(name) ?? []) unsubscribe();\n this.#eventUnsubscribers.delete(name);\n\n const removal = (async () => {\n const errors: unknown[] = [];\n const closing = await Promise.allSettled([\n client.dispose(),\n storageControl?.drain() ?? Promise.resolve(),\n ]);\n for (const result of closing) {\n if (result.status === 'rejected') errors.push(result.reason);\n }\n\n if (options.forget) {\n await Promise.resolve(this.#storage.clear(name)).catch((error: unknown) => {\n errors.push(error);\n });\n }\n\n if (errors.length > 0) throw errors[0];\n })();\n this.#accountRemovals.add(removal);\n\n try {\n await removal;\n return true;\n } finally {\n this.#accountRemovals.delete(removal);\n this.#removing.delete(name);\n }\n }\n\n /**\n * Подключает плагин всем аккаунтам — и заведённым, и будущим.\n *\n * @throws {ItdConfigError} если плагин задан неверно или уже подключён\n *\n * @example\n * ```ts\n * accounts.use(crypt());\n * ```\n */\n use(plugin: ClientPlugin): this {\n assertAccountsActive(this, 'подключить плагин');\n if (this.#removingPlugins.has(plugin?.name)) {\n throw new ItdConfigError(\n `плагин «${plugin.name}» ещё отключается; дождитесь завершения accounts.unuse()`,\n );\n }\n const ordered = orderPluginDefinitions([...this.#plugins, plugin]);\n const clients = [...this.#clients.values()];\n for (const client of clients) assertClientCanUsePlugin(client, plugin);\n\n const installed: ItdClient[] = [];\n try {\n for (const client of clients) {\n client.use(plugin);\n installed.push(client);\n }\n } catch (error) {\n // remove() исключает запись из реестра до первого await, поэтому видимое состояние\n // откатывается синхронно, а асинхронные teardown завершаются в фоне.\n for (const client of installed.reverse()) {\n void client.unuse(plugin.name).catch((cleanupError: unknown) => {\n this.#reportCleanup(`отката плагина «${plugin.name}»`, cleanupError);\n });\n }\n throw error;\n }\n this.#plugins.splice(0, this.#plugins.length, ...ordered);\n\n return this;\n }\n\n /** Имена общих плагинов в фактическом порядке выполнения обёрток. */\n pluginNames(): string[] {\n return this.#plugins.map((plugin) => plugin.name);\n }\n\n /** Подключён ли общий плагин с таким именем. */\n hasPlugin(name: string): boolean {\n return this.#plugins.some((plugin) => plugin.name === name);\n }\n\n /**\n * Отключает общий плагин у существующих клиентов и не применяет его к будущим.\n *\n * @returns `false`, если такого плагина не было\n * @throws {ItdConfigError} если от плагина зависит другой общий плагин\n */\n async unuse(name: string): Promise<boolean> {\n const index = this.#plugins.findIndex((plugin) => plugin.name === name);\n if (index < 0) return false;\n assertPluginRemovable(this.#plugins, name);\n const clients = [...this.#clients.values()];\n for (const client of clients) assertClientCanUnusePlugin(client, name);\n this.#plugins.splice(index, 1);\n this.#removingPlugins.add(name);\n\n try {\n const results = await Promise.allSettled(clients.map((client) => client.unuse(name)));\n const errors = results\n .filter((result): result is PromiseRejectedResult => result.status === 'rejected')\n .map((result) => result.reason);\n if (errors.length > 0) {\n throw new AggregateError(errors, `Не удалось отключить плагин «${name}» у всех аккаунтов`);\n }\n return true;\n } finally {\n this.#removingPlugins.delete(name);\n }\n }\n\n /**\n * Подписывается на события авторизации всех аккаунтов сразу.\n *\n * @returns функция отписки\n *\n * @example\n * ```ts\n * accounts.on('authError', ({ account }) => console.warn(`${account}: сессия потеряна`));\n * ```\n */\n on<K extends keyof AccountEvents>(event: K, listener: Listener<AccountEvents[K]>): Unsubscribe {\n assertAccountsActive(this, 'подписаться на события');\n return this.#emitter.on(event, listener);\n }\n\n /**\n * Перебор аккаунтов парами «имя — клиент».\n *\n * @example\n * ```ts\n * for (const [name, itd] of accounts) {\n * const me = await itd.users.me();\n * console.log(name, me.nickname);\n * }\n * ```\n */\n [Symbol.iterator](): IterableIterator<[string, ItdClient]> {\n return this.#clients.entries();\n }\n\n /**\n * Закрывает все аккаунты и останавливает общую очередь.\n *\n * Аккаунты остаются в контейнере и работоспособны: новые запросы поднимут всё заново,\n * но уже созданные потоки уведомлений останутся закрытыми.\n *\n * @example\n * ```ts\n * await using accounts = new ItdAccounts({ storage });\n * // …работа…\n * // dispose() вызовется сам на выходе из блока\n * ```\n */\n async close(): Promise<void> {\n try {\n await Promise.all([...this.#clients.values()].map((client) => client.close()));\n } finally {\n this.#queues?.stop();\n }\n }\n\n /**\n * Окончательно освобождает контейнер и отключает общие плагины у всех аккаунтов.\n *\n * Для временной остановки потоков и очереди без отключения плагинов используйте\n * {@link close}. Терминальное состояние устанавливается сразу: контейнер отзывает\n * storage-срезы и подписки, а новые аккаунты, запросы его клиентов и плагины после\n * первого `dispose()` больше не допускаются.\n */\n dispose(): Promise<void> {\n if (this.#disposePromise) return this.#disposePromise;\n DISPOSED_ACCOUNTS.add(this);\n this.#disposePromise = this.#dispose();\n return this.#disposePromise;\n }\n\n async #dispose(): Promise<void> {\n const clients = [...this.#clients.values()];\n const controls = [...this.#storageControls.values()];\n const accountRemovals = [...this.#accountRemovals];\n\n for (const control of controls) control.revoke();\n for (const unsubscribers of this.#eventUnsubscribers.values()) {\n for (const unsubscribe of unsubscribers) unsubscribe();\n }\n this.#eventUnsubscribers.clear();\n this.#storageControls.clear();\n this.#clients.clear();\n this.#emitter.removeAllListeners();\n\n const results = await Promise.allSettled([\n ...clients.map((client) => client.dispose()),\n ...controls.map((control) => control.drain()),\n ...accountRemovals,\n Promise.resolve().then(() => this.#queues?.clear()),\n ]);\n this.#plugins.splice(0);\n this.#features.splice(0);\n this.#removingPlugins.clear();\n\n const errors = results\n .filter((result): result is PromiseRejectedResult => result.status === 'rejected')\n .map((result) => result.reason);\n if (errors.length > 0) throw new AggregateError(errors, 'Не удалось освободить аккаунты');\n }\n\n /** Позволяет использовать контейнер с `await using`. */\n [Symbol.asyncDispose](): Promise<void> {\n return this.dispose();\n }\n\n static {\n installAsyncDisposeFallback(ItdAccounts);\n }\n\n /**\n * Собирает опции клиента: общие, поверх них — аккаунтные, и обязательно свой срез\n * хранилища.\n *\n * `headers` и `services` сливаются по ключам, а не заменяются целиком: иначе один свой\n * заголовок у аккаунта стирал бы весь общий набор.\n */\n #mergeOptions(options: AddAccountOptions, storage: TokenStorage): ItdClientOptions {\n const base = this.#base;\n\n return {\n ...base,\n ...options,\n ...(base.headers || options.headers\n ? { headers: { ...base.headers, ...options.headers } }\n : {}),\n ...(base.services || options.services\n ? { services: { ...base.services, ...options.services } }\n : {}),\n storage,\n };\n }\n\n /** Не теряет ошибку фонового освобождения ресурсов, которого синхронный API не ждёт. */\n #reportCleanup(scope: string, error: unknown): void {\n const message = `Не удалось освободить ресурсы после ${scope}`;\n if (this.#logger) this.#logger.error(message, error);\n else console.error(`[itd-api] ${message}`, error);\n }\n\n /** Ретранслирует события клиента наружу, добавляя к ним имя аккаунта. */\n #forwardEvents(account: string, client: ItdClient): Unsubscribe[] {\n return [\n client.on('tokens', ({ accessToken }) =>\n this.#emitter.emit('tokens', { account, accessToken }),\n ),\n client.on('signIn', ({ accessToken }) =>\n this.#emitter.emit('signIn', { account, accessToken }),\n ),\n client.on('signOut', () => this.#emitter.emit('signOut', { account })),\n client.on('authError', ({ error }) => this.#emitter.emit('authError', { account, error })),\n ];\n }\n}\n\n/**\n * Создаёт контейнер аккаунтов.\n *\n * То же, что `new ItdAccounts(options)`, — для тех, кому привычнее фабрика.\n */\nexport function createAccounts(options: ItdAccountsOptions = {}): ItdAccounts {\n return new ItdAccounts(options);\n}\n"],"mappings":"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"}
|