itd-api 0.7.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -27
- package/dist/events/index.cjs +53 -0
- package/dist/events/index.d.cts +3 -0
- package/dist/events/index.d.ts +3 -0
- package/dist/events/index.js +5 -0
- package/dist/index.cjs +234 -200
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +70 -64
- package/dist/index.d.ts +70 -64
- package/dist/index.js +202 -179
- package/dist/index.js.map +1 -1
- package/dist/node/index.cjs +6 -5
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.cts +2 -2
- package/dist/node/index.d.ts +2 -2
- package/dist/node/index.js +5 -4
- package/dist/node/index.js.map +1 -1
- package/dist/rest/index.cjs +32 -26
- package/dist/rest/index.cjs.map +1 -1
- package/dist/rest/index.d.cts +9 -7
- package/dist/rest/index.d.ts +9 -7
- package/dist/rest/index.js +19 -21
- package/dist/rest/index.js.map +1 -1
- package/dist/shared/{errors-DfU8M5eS.cjs → errors-BmP3TKoW.cjs} +3 -3
- package/dist/shared/{errors-DfU8M5eS.cjs.map → errors-BmP3TKoW.cjs.map} +1 -1
- package/dist/shared/{errors-Bhrd2fJd.js → errors-GI10kZxk.js} +3 -3
- package/dist/shared/{errors-Bhrd2fJd.js.map → errors-GI10kZxk.js.map} +1 -1
- package/dist/shared/{websocket-BLR8eVJV.js → events-C5wnTXPT.js} +770 -490
- package/dist/shared/events-C5wnTXPT.js.map +1 -0
- package/dist/shared/events-CqtkP65d.d.ts +698 -0
- package/dist/shared/events-DGAWlCaI.d.cts +698 -0
- package/dist/shared/{websocket-C_eI4H2o.cjs → events-FZfnEez0.cjs} +834 -518
- package/dist/shared/events-FZfnEez0.cjs.map +1 -0
- package/dist/shared/{storage-BPJR_k4-.cjs → key-value-store-B5GYVEYZ.cjs} +2 -86
- package/dist/shared/key-value-store-B5GYVEYZ.cjs.map +1 -0
- package/dist/shared/{storage-D86edNCB.js → key-value-store-Bt2PSMxY.js} +3 -69
- package/dist/shared/key-value-store-Bt2PSMxY.js.map +1 -0
- package/dist/shared/key-value-store-COZaNHZS.d.cts +69 -0
- package/dist/shared/key-value-store-COZaNHZS.d.ts +69 -0
- package/dist/shared/{multi-storage-DccjD7Ww.d.ts → multi-storage-BEL7tcKn.d.cts} +3 -2
- package/dist/shared/{multi-storage--yTEqiod.cjs → multi-storage-CDKLa956.cjs} +11 -10
- package/dist/shared/{multi-storage--yTEqiod.cjs.map → multi-storage-CDKLa956.cjs.map} +1 -1
- package/dist/shared/{multi-storage-CjAPB5Kq.d.cts → multi-storage-LkljOSzA.d.ts} +3 -2
- package/dist/shared/{multi-storage-CkvTUC5m.js → multi-storage-SoW05uzO.js} +5 -4
- package/dist/shared/{multi-storage-CkvTUC5m.js.map → multi-storage-SoW05uzO.js.map} +1 -1
- package/dist/shared/{options-Dg5N3r1V.cjs → options-DOJYtoti.cjs} +8 -6
- package/dist/shared/options-DOJYtoti.cjs.map +1 -0
- package/dist/shared/{options-DtATYdLr.js → options-DhgGg7Ms.js} +8 -6
- package/dist/shared/options-DhgGg7Ms.js.map +1 -0
- package/dist/shared/{cookies-DZwFq6kr.cjs → redact-BP00URmQ.cjs} +312 -2
- package/dist/shared/redact-BP00URmQ.cjs.map +1 -0
- package/dist/shared/{cookies-tX2sNwxb.js → redact-Ba5iSVYZ.js} +235 -3
- package/dist/shared/redact-Ba5iSVYZ.js.map +1 -0
- package/dist/shared/{render-CgwKdOzu.d.ts → render-B4qis7Sb.d.ts} +775 -313
- package/dist/shared/{render-DO0F5YSm.d.cts → render-DDwy2Ame.d.cts} +775 -313
- package/dist/shared/{render-mcuELiYi.cjs → render-Dqi8Owqk.cjs} +1464 -662
- package/dist/shared/render-Dqi8Owqk.cjs.map +1 -0
- package/dist/shared/{render-C6HRPs10.js → render-hiWFh2s4.js} +1366 -618
- package/dist/shared/render-hiWFh2s4.js.map +1 -0
- package/dist/shared/storage-BQrtKon9.d.cts +86 -0
- package/dist/shared/storage-CTRGT5wF.d.ts +86 -0
- package/dist/shared/storage-CfHKzVHf.js +71 -0
- package/dist/shared/storage-CfHKzVHf.js.map +1 -0
- package/dist/shared/storage-QNVxzpDB.cjs +88 -0
- package/dist/shared/storage-QNVxzpDB.cjs.map +1 -0
- package/dist/shared/{url-BaMCQpYH.cjs → url-Bsb3xE5U.cjs} +577 -466
- package/dist/shared/url-Bsb3xE5U.cjs.map +1 -0
- package/dist/shared/{url-IU0xN9wX.js → url-DP33mp3s.js} +508 -409
- package/dist/shared/url-DP33mp3s.js.map +1 -0
- package/dist/shared/{url-DTfZ2toq.d.ts → url-XBsMdAcv.d.cts} +1313 -1200
- package/dist/shared/{url-DTfZ2toq.d.cts → url-XBsMdAcv.d.ts} +1313 -1200
- package/dist/web/index.cjs +5 -4
- package/dist/web/index.cjs.map +1 -1
- package/dist/web/index.d.cts +1 -1
- package/dist/web/index.d.ts +1 -1
- package/dist/web/index.js +3 -2
- package/dist/web/index.js.map +1 -1
- package/package.json +16 -15
- package/dist/realtime/index.cjs +0 -165
- package/dist/realtime/index.cjs.map +0 -1
- package/dist/realtime/index.d.cts +0 -51
- package/dist/realtime/index.d.ts +0 -51
- package/dist/realtime/index.js +0 -120
- package/dist/realtime/index.js.map +0 -1
- package/dist/shared/auth-provider-CG8oCQ9F.cjs +0 -108
- package/dist/shared/auth-provider-CG8oCQ9F.cjs.map +0 -1
- package/dist/shared/auth-provider-mYqxsSVa.js +0 -91
- package/dist/shared/auth-provider-mYqxsSVa.js.map +0 -1
- package/dist/shared/cookies-DZwFq6kr.cjs.map +0 -1
- package/dist/shared/cookies-tX2sNwxb.js.map +0 -1
- package/dist/shared/options-Dg5N3r1V.cjs.map +0 -1
- package/dist/shared/options-DtATYdLr.js.map +0 -1
- package/dist/shared/render-C6HRPs10.js.map +0 -1
- package/dist/shared/render-mcuELiYi.cjs.map +0 -1
- package/dist/shared/storage-BPJR_k4-.cjs.map +0 -1
- package/dist/shared/storage-C_eICCep.d.cts +0 -152
- package/dist/shared/storage-C_eICCep.d.ts +0 -152
- package/dist/shared/storage-D86edNCB.js.map +0 -1
- package/dist/shared/url-BaMCQpYH.cjs.map +0 -1
- package/dist/shared/url-IU0xN9wX.js.map +0 -1
- package/dist/shared/websocket-BLR8eVJV.js.map +0 -1
- package/dist/shared/websocket-C_eI4H2o.cjs.map +0 -1
- package/dist/shared/websocket-DF7XIMiX.d.cts +0 -562
- package/dist/shared/websocket-DYKBr8HF.d.ts +0 -562
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events-C5wnTXPT.js","names":["#listeners","#onError","#options","#hooks","#middleware","#handlers","#queue","#activeKeys","#drainWaiters","#keysFor","#pump","#resolveDrain","#active","#run","#deps","#options","#dispatcher","#emitter","#clock","#maxAttempts","#retiredSessions","#backgroundTasks","#reportDispatchError","#handleOverflow","#status","#wanted","#starting","#attachEnvironmentListeners","#startAttempt","#generation","#cancelTimer","#detachEnvironment","#abortSession","#attempt","#setStatus","#session","#isCurrentGeneration","#scheduleReconnect","#createSession","#runTransport","#initialize","#openGate","#isCurrentSession","#handleFailure","#runSessionTask","#handleEvent","#emitEngine","#dispatchFrame","#dispatch","#runBackgroundTask","#refreshAndReconnect","#giveUp","#reconnect","#runTrackedTask","#interval","#limit","#clock","#request","#readUpdates","#readCount","#wait","#idleTimeout","#handshakeTimeout","#clock","#lastEventId","#handshake","#read","#deps","#engine","#handleFrame","#deliver","#syncUnreadCount","#closeLifecycle","#lifecycleActive","#path","#webSocketImpl","#auth","#idleTimeout","#keepAlive","#handshakeTimeout","#classifyOpenFailure","#clock","#globalImplementation","#urls","#listen","#runtime","#disposed","#disposePromise","#dispose","#selector","#routes","#fallback","#registration","#captureMiddleware","#middleware","#captureMiddleware"],"sources":["../../src/core/emitter.ts","../../src/events/middleware.ts","../../src/events/reconnect.ts","../../src/events/transports/transport.ts","../../src/events/engine.ts","../../src/events/transports/poll.ts","../../node_modules/eventsource-parser/dist/index.js","../../src/events/transports/sse.ts","../../src/events/updates.ts","../../src/events/stream.ts","../../src/operations/events.ts","../../src/events/transports/websocket.ts","../../src/events/client.ts","../../src/events/router.ts","../../src/events/composer.ts"],"sourcesContent":["import type { Logger } from './options.js';\n\n/** Обработчик события. */\nexport type Listener<T> = (payload: T) => void;\n\n/** Функция отписки, которую возвращает подписка на событие. */\nexport type Unsubscribe = () => void;\n\n/**\n * Минимальный типизированный источник событий.\n *\n * Своя реализация вместо `EventTarget` и `EventEmitter`: первый есть не везде и требует\n * обёрток `CustomEvent`, второй существует только в Node. Нужны ровно подписка и рассылка.\n *\n * Исключение в обработчике не прерывает рассылку остальным и не роняет библиотеку.\n *\n * @typeParam Events карта «имя события → тип полезной нагрузки». Задаётся интерфейсом,\n * поэтому ограничение на индексную сигнатуру намеренно не накладывается.\n */\nexport class Emitter<Events> {\n readonly #listeners = new Map<keyof Events, Set<Listener<never>>>();\n readonly #onError: ((error: unknown) => void) | undefined;\n\n constructor(onListenerError?: (error: unknown) => void) {\n this.#onError = onListenerError;\n }\n\n /**\n * Подписывается на событие.\n *\n * @returns функция отписки\n *\n * @example\n * ```ts\n * const off = events.on('notification', (event) => console.log(event));\n * off();\n * ```\n */\n on<K extends keyof Events>(event: K, listener: Listener<Events[K]>): Unsubscribe {\n const set = this.#listeners.get(event) ?? new Set();\n set.add(listener as Listener<never>);\n this.#listeners.set(event, set);\n\n return () => this.off(event, listener);\n }\n\n /** Подписывается на одно срабатывание. */\n once<K extends keyof Events>(event: K, listener: Listener<Events[K]>): Unsubscribe {\n const off = this.on(event, (payload) => {\n off();\n listener(payload);\n });\n return off;\n }\n\n /** Отписывается от события. */\n off<K extends keyof Events>(event: K, listener: Listener<Events[K]>): void {\n this.#listeners.get(event)?.delete(listener as Listener<never>);\n }\n\n /** Рассылает событие подписчикам. */\n emit<K extends keyof Events>(event: K, payload: Events[K]): void {\n const set = this.#listeners.get(event);\n if (!set) return;\n\n // Копия нужна: обработчик вправе отписаться прямо во время рассылки.\n for (const listener of [...set]) {\n try {\n (listener as Listener<Events[K]>)(payload);\n } catch (error) {\n this.#onError?.(error);\n }\n }\n }\n\n /** Сколько подписчиков у события. */\n listenerCount(event: keyof Events): number {\n return this.#listeners.get(event)?.size ?? 0;\n }\n\n /** Снимает все подписки. */\n removeAllListeners(): void {\n this.#listeners.clear();\n }\n}\n\n/**\n * Сообщает об исключении из пользовательского обработчика события: пишет в логгер,\n * при его отсутствии — в консоль.\n *\n * Ошибка чужого обработчика не должна ронять библиотеку, но и пропадать молча ей нельзя:\n * иначе подписка, падающая на каждом событии, выглядит как её отсутствие.\n *\n * @param scope о чьих событиях речь — попадает в текст сообщения\n *\n * @internal\n */\nexport function reportListenerError(\n logger: Logger | undefined,\n scope: string,\n error: unknown,\n): void {\n const message = `Ошибка в обработчике события ${scope}`;\n if (logger) logger.error(message, error);\n else console.error(`[itd-api] ${message}`, error);\n}\n","import type { Unsubscribe } from '../core/emitter.js';\nimport { ItdConfigError } from '../core/errors.js';\nimport type { EventContext, NotificationEventContext } from './updates.js';\n\n/** Продолжает цепочку промежуточных обработчиков потока. */\nexport type EventNext = () => Promise<void>;\n\n/** Обрабатывает обновление потока до его передачи подписчикам. */\nexport type EventMiddleware<C extends EventContext = NotificationEventContext> = (\n context: C,\n next: EventNext,\n) => void | Promise<void>;\n\n/** Объект, предоставляющий снимок промежуточного обработчика потока. */\nexport interface EventMiddlewareObject<C extends EventContext = NotificationEventContext> {\n middleware(): EventMiddleware<C>;\n}\n\n/** Асинхронный обработчик нормализованного обновления потока. */\nexport type EventHandler<C extends EventContext = NotificationEventContext> = (\n context: C,\n) => unknown | Promise<unknown>;\n\n/** Условие отбора контекста потока. */\nexport type EventPredicate<C extends EventContext = NotificationEventContext> = (\n context: C,\n) => boolean;\n\n/** Проверка, сужающая тип контекста потока. */\nexport type EventTypeGuard<C extends B, B extends EventContext = NotificationEventContext> = (\n context: B,\n) => context is C;\n\n/** Ключи, по которым обновления нельзя обрабатывать одновременно. */\nexport type EventSequentializer<C extends EventContext = NotificationEventContext> = (\n context: C,\n) => PropertyKey | readonly PropertyKey[] | undefined;\n\nconst EVENT_MIDDLEWARE_SNAPSHOT = Symbol('itd-api.events.middlewareSnapshot');\n\ntype SnapshottingEventMiddleware<C extends EventContext> = EventMiddleware<C> & {\n [EVENT_MIDDLEWARE_SNAPSHOT]?: () => EventMiddleware<C>;\n};\n\n/** @internal */\nexport function captureEventMiddleware<C extends EventContext>(\n middleware: EventMiddleware<C>,\n): EventMiddleware<C> {\n const capture = (middleware as SnapshottingEventMiddleware<C>)[EVENT_MIDDLEWARE_SNAPSHOT];\n if (!capture) return middleware;\n\n const snapshot = capture();\n if (typeof snapshot !== 'function') {\n throw new TypeError('Снимок промежуточного обработчика должен быть функцией');\n }\n return snapshot;\n}\n\n/** @internal */\nexport function withEventMiddlewareSnapshot<C extends EventContext>(\n middleware: EventMiddleware<C>,\n capture: () => EventMiddleware<C>,\n): EventMiddleware<C> {\n Object.defineProperty(middleware, EVENT_MIDDLEWARE_SNAPSHOT, { value: capture });\n return middleware;\n}\n\n/** Создаёт отложенный промежуточный обработчик для объекта. @internal */\nexport function deferEventMiddleware<C extends EventContext>(\n source: EventMiddlewareObject<C>,\n): EventMiddleware<C> {\n const capture = (): EventMiddleware<C> => {\n const middleware = source.middleware();\n if (typeof middleware !== 'function') {\n throw new ItdConfigError('events middleware() должен возвращать функцию обработки');\n }\n return captureEventMiddleware(middleware);\n };\n\n const deferred: EventMiddleware<C> = (context, next) => capture()(context, next);\n return withEventMiddlewareSnapshot(deferred, capture);\n}\n\ninterface HandlerRegistration<C extends EventContext> {\n readonly predicate: EventPredicate<C>;\n readonly handler: EventHandler<C>;\n}\n\ninterface DispatchWork<C extends EventContext> {\n readonly context: C;\n readonly middleware: readonly EventMiddleware<C>[];\n readonly handlers: readonly HandlerRegistration<C>[];\n readonly keys: readonly PropertyKey[];\n /** Ключ снимка: ожидающая работа с тем же ключом заменяется новой. */\n readonly coalesceKey: PropertyKey | undefined;\n}\n\n/** Предел обновлений, ожидающих обработки. @internal */\nexport const MAX_PENDING_UPDATES = 256;\n\nexport interface EventDispatcherOptions<C extends EventContext = NotificationEventContext> {\n concurrency: number;\n sequentialize?: EventSequentializer<C> | undefined;\n}\n\nexport interface EventDispatcherHooks<C extends EventContext = NotificationEventContext> {\n deliver: (context: C) => void;\n middlewareError: (error: unknown, context: C) => void;\n handlerError: (error: unknown, context: C) => void;\n /** Очередь достигла предела: обновление не принято, поток обязан прекратить их приём. */\n overflow: () => void;\n}\n\n/** Выполняет промежуточные обработчики по порядку и запрещает повторный вызов `next()`. */\nexport async function runEventMiddleware<C extends EventContext>(\n middleware: readonly EventMiddleware<C>[],\n context: C,\n terminal: EventNext,\n): Promise<void> {\n let lastIndex = -1;\n\n const dispatch = async (index: number): Promise<void> => {\n if (index <= lastIndex) throw new Error('next() в промежуточном обработчике вызван повторно');\n lastIndex = index;\n\n const current = middleware[index];\n if (!current) {\n await terminal();\n return;\n }\n\n let downstream: Promise<void> | undefined;\n let duplicateCalls: Promise<void> | undefined;\n let failure: { error: unknown } | undefined;\n\n const next: EventNext = () => {\n if (!downstream) {\n downstream = dispatch(index + 1);\n return downstream;\n }\n\n const duplicate = Promise.reject(\n new Error('next() в одном промежуточном обработчике вызван повторно'),\n );\n duplicateCalls = Promise.all(duplicateCalls ? [duplicateCalls, duplicate] : [duplicate]).then(\n () => undefined,\n );\n return duplicate;\n };\n\n try {\n await current(context, next);\n } catch (error) {\n failure = { error };\n }\n\n try {\n await downstream;\n await duplicateCalls;\n } catch (error) {\n failure ??= { error };\n }\n\n if (failure) throw failure.error;\n };\n\n await dispatch(0);\n}\n\n/** Планирует нормализованные обновления и отслеживает незавершённые обработчики. */\nexport class EventDispatcher<C extends EventContext = NotificationEventContext> {\n readonly #options: EventDispatcherOptions<C>;\n readonly #hooks: EventDispatcherHooks<C>;\n readonly #middleware: EventMiddleware<C>[] = [];\n readonly #handlers: HandlerRegistration<C>[] = [];\n readonly #queue: DispatchWork<C>[] = [];\n readonly #activeKeys = new Set<PropertyKey>();\n readonly #drainWaiters = new Set<() => void>();\n\n #active = 0;\n\n constructor(options: EventDispatcherOptions<C>, hooks: EventDispatcherHooks<C>) {\n this.#options = options;\n this.#hooks = hooks;\n }\n\n use(middleware: EventMiddleware<C>): Unsubscribe {\n this.#middleware.push(middleware);\n return () => {\n const index = this.#middleware.indexOf(middleware);\n if (index >= 0) this.#middleware.splice(index, 1);\n };\n }\n\n on(predicate: EventPredicate<C>, handler: EventHandler<C>): Unsubscribe {\n const registration = { predicate, handler };\n this.#handlers.push(registration);\n\n return () => {\n const index = this.#handlers.indexOf(registration);\n if (index >= 0) this.#handlers.splice(index, 1);\n };\n }\n\n /**\n * Принимает обновление к обработке.\n *\n * @param coalesceKey ожидающая работа с тем же ключом заменяется новой\n */\n dispatch(context: C, coalesceKey?: PropertyKey): void {\n let keys: readonly PropertyKey[];\n let middleware: readonly EventMiddleware<C>[];\n try {\n keys = this.#keysFor(context);\n middleware = this.#middleware.map(captureEventMiddleware);\n } catch (error) {\n this.#hooks.middlewareError(error, context);\n return;\n }\n\n const replaced =\n coalesceKey === undefined\n ? -1\n : this.#queue.findIndex((pending) => pending.coalesceKey === coalesceKey);\n if (replaced < 0 && this.#queue.length >= MAX_PENDING_UPDATES) {\n this.#hooks.overflow();\n return;\n }\n\n const work: DispatchWork<C> = {\n context,\n middleware,\n handlers: [...this.#handlers],\n keys,\n coalesceKey,\n };\n if (replaced >= 0) this.#queue[replaced] = work;\n else this.#queue.push(work);\n\n this.#pump();\n }\n\n /** Отбрасывает обновления, обработка которых ещё не началась. */\n clearPending(): void {\n this.#queue.length = 0;\n this.#resolveDrain();\n }\n\n /** Ждёт завершения активных и поставленных в очередь обновлений. */\n drain(): Promise<void> {\n if (this.#active === 0 && this.#queue.length === 0) return Promise.resolve();\n return new Promise<void>((resolve) => this.#drainWaiters.add(resolve));\n }\n\n #keysFor(context: C): readonly PropertyKey[] {\n const value = this.#options.sequentialize?.(context);\n if (value === undefined) return [];\n\n const values = Array.isArray(value) ? value : [value];\n for (const key of values) {\n if (typeof key !== 'string' && typeof key !== 'number' && typeof key !== 'symbol') {\n throw new TypeError('sequentialize() должен возвращать PropertyKey или их список');\n }\n }\n return [...new Set(values)];\n }\n\n #pump(): void {\n while (this.#active < this.#options.concurrency) {\n const blockedKeys = new Set(this.#activeKeys);\n const index = this.#queue.findIndex(({ keys }) => {\n const runnable = keys.every((key) => !blockedKeys.has(key));\n if (!runnable) {\n for (const key of keys) blockedKeys.add(key);\n }\n return runnable;\n });\n if (index < 0) break;\n\n const [work] = this.#queue.splice(index, 1);\n if (!work) break;\n\n this.#active += 1;\n for (const key of work.keys) this.#activeKeys.add(key);\n void this.#run(work);\n }\n\n this.#resolveDrain();\n }\n\n async #run(work: DispatchWork<C>): Promise<void> {\n try {\n await runEventMiddleware(work.middleware, work.context, async () => {\n for (const { predicate, handler } of work.handlers) {\n try {\n if (predicate(work.context)) await handler(work.context);\n } catch (error) {\n this.#hooks.handlerError(error, work.context);\n }\n }\n\n this.#hooks.deliver(work.context);\n });\n } catch (error) {\n this.#hooks.middlewareError(error, work.context);\n } finally {\n this.#active -= 1;\n for (const key of work.keys) this.#activeKeys.delete(key);\n this.#pump();\n }\n }\n\n #resolveDrain(): void {\n if (this.#active !== 0 || this.#queue.length !== 0) return;\n for (const resolve of this.#drainWaiters) resolve();\n this.#drainWaiters.clear();\n }\n}\n","/**\n * Паузы перед попытками переподключения, мс.\n *\n * Значения совпадают с теми, что использует сайт итд.com, — поведение библиотеки\n * не отличается от привычного пользователю.\n */\nexport const RECONNECT_BACKOFF = Object.freeze([1000, 2000, 4000, 8000, 16000, 30000]);\n\n/** Доля случайного разброса паузы. */\nexport const RECONNECT_JITTER = 0.3;\n\n/**\n * Сколько раз пытаться переподключиться подряд.\n *\n * После исчерпания поток сообщает `giveup` и ждёт ручного `connect()`.\n */\nexport const MAX_RECONNECT_ATTEMPTS = 15;\n\n/** Настройки переподключения. */\nexport interface ReconnectOptions {\n /** Таблица пауз. Последнее значение действует для всех дальнейших попыток. */\n backoff?: readonly number[];\n /** Доля разброса, 0…1. */\n jitter?: number;\n /** Предел числа попыток. */\n maxAttempts?: number;\n}\n\n/**\n * Вычисляет паузу перед попыткой переподключения.\n *\n * Разброс нужен, чтобы клиенты, отключившиеся одновременно из-за перезапуска сервера,\n * не вернулись тоже одновременно.\n *\n * @param attempt номер попытки, начиная с нуля\n * @param random источник случайности; подменяется в тестах\n */\nexport function reconnectDelay(\n attempt: number,\n options: ReconnectOptions = {},\n random: () => number = Math.random,\n): number {\n const backoff = options.backoff ?? RECONNECT_BACKOFF;\n const jitter = options.jitter ?? RECONNECT_JITTER;\n\n const base = backoff[Math.min(attempt, backoff.length - 1)] ?? 30_000;\n const spread = base * jitter * (random() * 2 - 1);\n\n return Math.max(0, Math.round(base + spread));\n}\n","import type { ClientConnection } from '../../core/connection.js';\nimport type { QueryParams } from '../../core/url.js';\n\n/** Идентификаторы операций транспорта уведомлений. */\nexport type EventOperationId =\n | 'events.notifications.poll.updates'\n | 'events.notifications.poll.unread';\n\n/** Запрос транспорта к конвейеру клиента. */\nexport interface EventRequestInput {\n operationId: EventOperationId;\n path: string;\n query?: QueryParams | undefined;\n /**\n * Сигнал отмены текущей попытки соединения.\n */\n signal?: AbortSignal | undefined;\n}\n\n/**\n * Запрос через очередь, авторизацию, повторы, плагины и обработчики клиента.\n *\n * Ответ приходит уже разобранным и без обёртки `{ data: … }`, а неудача — типизированной\n * ошибкой библиотеки.\n */\nexport type EventRequest = (input: EventRequestInput) => Promise<unknown>;\n\n/** Событие, пришедшее по каналу реального времени. */\nexport interface EventTransportFrame {\n /** Имя события: `notification`, `unread_count` и другие. */\n name: string;\n /** Полезная нагрузка, уже разобранная из JSON. */\n data: unknown;\n}\n\n/** Что транспорт получает от клиента при подключении. */\nexport interface EventTransportContext\n extends Pick<ClientConnection, 'baseUrl' | 'authorize' | 'fetch' | 'baseHeaders' | 'getToken'> {\n /** Отмена подключения. */\n signal: AbortSignal;\n /** Сообщает о полученном событии. */\n onEvent: (event: EventTransportFrame) => void;\n /** Сообщает о разобранном, но некорректном сообщении. Соединение при этом живёт. */\n onParseError: (error: unknown, raw: string) => void;\n /** Вызывается, когда соединение установлено. */\n onOpen: () => void;\n}\n\n/** Канал получения исходных событий в реальном времени. */\nexport interface EventTransport {\n /** Понятное имя для логов и диагностики. */\n readonly name: string;\n\n /**\n * Держит соединение, пока оно живо.\n *\n * Должен завершиться, когда поток закрылся, и бросить исключение при ошибке.\n * Отмена через `context.signal` должна приводить к `AbortError`.\n */\n connect(context: EventTransportContext): Promise<void>;\n}\n\n/** Ошибка, по которой видно, что сервер отверг авторизацию потока. */\nexport class UnauthorizedStreamError extends Error {\n constructor() {\n super('Поток событий отверг токен доступа');\n this.name = 'UnauthorizedStreamError';\n }\n}\n","import { type ItdClock, systemClock } from '../core/clock.js';\nimport type { ClientConnection } from '../core/connection.js';\nimport { Emitter, type Listener, reportListenerError, type Unsubscribe } from '../core/emitter.js';\nimport { ItdAbortError, ItdConfigError } from '../core/errors.js';\nimport type { Logger } from '../core/options.js';\nimport { EventChannelStatus } from '../types/enums.js';\nimport {\n deferEventMiddleware,\n EventDispatcher,\n type EventHandler,\n type EventMiddleware,\n type EventMiddlewareObject,\n type EventPredicate,\n type EventSequentializer,\n MAX_PENDING_UPDATES,\n} from './middleware.js';\nimport { MAX_RECONNECT_ATTEMPTS, type ReconnectOptions, reconnectDelay } from './reconnect.js';\nimport {\n type EventTransport,\n type EventTransportFrame,\n UnauthorizedStreamError,\n} from './transports/transport.js';\nimport type { EventContext } from './updates.js';\n\n/** Зачем движок просит домен синхронизироваться. */\nexport type EventSyncReason = 'initial' | 'reconnect';\n\n/** Параметры постановки доменного события из REST или другого внешнего источника. */\nexport interface EventEnqueueOptions<O = unknown> {\n readonly origin: O;\n readonly raw?: EventTransportFrame | undefined;\n}\n\n/** Контекст одной попытки подключения, теряющий актуальность после её завершения. */\nexport interface EventSession<U, O = unknown> {\n readonly signal: AbortSignal;\n /** Завершается только после фактического `EventTransportContext.onOpen` этой попытки. */\n readonly opened: Promise<void>;\n /** Ставит нормализованное событие только пока эта попытка актуальна. */\n enqueue(update: U, options: EventEnqueueOptions<O>): void;\n}\n\n/**\n * События, которые движок рассылает сам.\n *\n * Ни одно из них не зависит от домена, поэтому они одинаковы у любого потока.\n * Домен расширяет эту карту своими событиями.\n */\nexport interface EventChannelEvents<C extends EventContext = EventContext> {\n /** Изменилось состояние соединения. */\n status: EventChannelStatus;\n /** Соединение оборвалось; будет предпринята попытка переподключения. */\n error: { error: unknown; willReconnect: boolean };\n /** Сообщение не удалось разобрать. Соединение при этом продолжает работать. */\n parseError: { error: unknown; raw: string };\n /** Запланировано переподключение. */\n reconnect: { attempt: number; delay: number };\n /** Попытки исчерпаны — соединение восстановится только ручным `connect()`. */\n giveup: undefined;\n /** Любой исходный кадр транспорта. Отправляется до нормализации и обработчиков. */\n message: EventTransportFrame;\n /** Промежуточный обработчик потока завершился исключением. */\n middlewareError: { error: unknown; context: C };\n /** Обработчик обновления завершился исключением. */\n handlerError: { error: unknown; context: C };\n}\n\n/**\n * Что движок получает от домена.\n *\n * @typeParam U нормализованное обновление домена\n * @typeParam C контекст обработки, который домен собирает вокруг обновления\n *\n */\nexport interface EventChannelDeps<U, C extends EventContext<U, unknown, O>, O = unknown> {\n connection: ClientConnection;\n clock?: ItdClock | undefined;\n logger?: Logger | undefined;\n\n transport: EventTransport;\n /** Источник, который домен назначает нормализованным кадрам транспорта. */\n streamOrigin: O;\n\n /**\n * Доменная обработка сырого кадра до нормализации. `true` — кадр поглощён и дальше\n * не идёт. Нужна там, где кадр не является обновлением: у уведомлений так приходит\n * `connected`.\n */\n handleFrame?: ((event: EventTransportFrame) => boolean) | undefined;\n /** Превращает кадр в доменное обновление; `undefined` — кадр игнорируется. */\n readUpdate: (event: EventTransportFrame) => U | undefined;\n /**\n * Ключ коалесцирования: ожидающее обновление с тем же ключом заменяется новым.\n * `undefined` — обновление не коалесцируется.\n */\n coalesceKey?: ((update: U) => PropertyKey | undefined) | undefined;\n /** Собирает контекст. Точка, куда домен добавляет свои поля и действия. */\n createContext: (update: U, raw: EventTransportFrame | undefined, origin: O) => C;\n /** Доставляет обновление доменным подписчикам после цепочки обработчиков. */\n deliver: (update: U) => void;\n /** Проверяет, можно ли запустить канал. */\n connectGuard?: (() => void) | undefined;\n /** Подготовка одной попытки соединения. */\n initialize?:\n | ((reason: EventSyncReason, session: EventSession<U, O>) => Promise<void>)\n | undefined;\n /** Открывает транспорт до подготовки и накапливает выбранные кадры до её завершения. */\n openBeforeInitialize?: boolean | undefined;\n /** Ошибка подготовки отклоняет первый `connect()`. */\n initializationRequired?: boolean | undefined;\n /** Выбирает кадры, которые нужно накопить до завершения подготовки. По умолчанию все. */\n bufferFrame?: ((event: EventTransportFrame) => boolean) | undefined;\n}\n\ninterface ActiveEventSession<U, O> {\n readonly generation: number;\n readonly controller: AbortController;\n readonly handle: EventSession<U, O>;\n readonly resolveOpened: () => void;\n readonly rejectOpened: (error: unknown) => void;\n readonly buffer: EventTransportFrame[];\n readonly tasks: Set<Promise<unknown>>;\n readonly drained: Promise<void>;\n readonly resolveDrained: () => void;\n retired: boolean;\n ready: boolean;\n}\n\nconst EVENT_CHANNEL_GIVEUP_HOOKS = new WeakMap<object, () => void>();\n\n/** Регистрирует обработчик окончательной остановки канала. @internal */\nexport function setEventChannelGiveUpHook(channel: object, hook: () => void): void {\n EVENT_CHANNEL_GIVEUP_HOOKS.set(channel, hook);\n}\n\n/** Настройки движка: переподключение, параллелизм и реакция на среду. */\nexport interface EventChannelOptions<C extends EventContext = EventContext>\n extends ReconnectOptions {\n /** Максимальное число одновременно обрабатываемых обновлений. По умолчанию 1. */\n concurrency?: number | undefined;\n /** Возвращает ключи обновлений, которые нельзя обрабатывать одновременно. */\n sequentialize?: EventSequentializer<C> | undefined;\n /** Переподключаться, когда вкладка снова становится видимой. По умолчанию `true`. */\n reconnectOnVisible?: boolean | undefined;\n /** Переподключаться при восстановлении сети. По умолчанию `true`. */\n reconnectOnOnline?: boolean | undefined;\n}\n\n/** Проверяет настройки общей механики потока. */\nexport function resolveEventChannelOptions<C extends EventContext>(\n options: EventChannelOptions<C> = {},\n): Readonly<EventChannelOptions<C>> {\n const positiveInteger = (value: number | undefined, name: string): void => {\n if (value === undefined) return;\n if (!Number.isInteger(value) || value < 0) {\n throw new ItdConfigError(\n `events.${name} должен быть целым неотрицательным числом, получено: ${value}`,\n );\n }\n };\n const duration = (value: number, name: string): void => {\n if (!Number.isFinite(value) || value < 0) {\n throw new ItdConfigError(`events.${name} должен быть числом не меньше 0, получено: ${value}`);\n }\n };\n\n positiveInteger(options.maxAttempts, 'maxAttempts');\n positiveInteger(options.concurrency, 'concurrency');\n if (options.concurrency === 0) {\n throw new ItdConfigError('events.concurrency должен быть больше нуля');\n }\n if (options.jitter !== undefined && !(options.jitter >= 0 && options.jitter <= 1)) {\n throw new ItdConfigError(\n `events.jitter должен быть в диапазоне 0…1, получено: ${options.jitter}`,\n );\n }\n if (options.backoff !== undefined) {\n if (!Array.isArray(options.backoff) || options.backoff.length === 0) {\n throw new ItdConfigError('events.backoff должен быть непустым списком пауз');\n }\n for (const delay of options.backoff) duration(delay, 'backoff');\n }\n if (options.sequentialize !== undefined && typeof options.sequentialize !== 'function') {\n throw new ItdConfigError('events.sequentialize должен быть функцией');\n }\n\n return Object.freeze({\n ...options,\n ...(options.backoff ? { backoff: Object.freeze([...options.backoff]) } : {}),\n });\n}\n\n/**\n * Общая механика потока событий: соединение, переподключение с задержкой, обновление\n * токена, реакция на среду, статусы и очередь обработчиков.\n *\n * Ничего не знает о домене: что считать обновлением, как собрать контекст и кому его\n * доставить, решают {@link EventChannelDeps}. Поэтому один и тот же движок несёт\n * и поток уведомлений, и любой другой.\n *\n */\nexport class EventChannel<\n U,\n C extends EventContext<U, unknown, O>,\n E extends EventChannelEvents<C> = EventChannelEvents<C>,\n O = unknown,\n> {\n readonly #deps: EventChannelDeps<U, C, O>;\n readonly #options: Readonly<EventChannelOptions<C>>;\n readonly #dispatcher: EventDispatcher<C>;\n readonly #emitter: Emitter<E>;\n readonly #clock: ItdClock;\n readonly #maxAttempts: number;\n /** Остановленные сессии, чьи подготовка или транспорт ещё освобождают ресурсы. */\n readonly #retiredSessions = new Set<Promise<void>>();\n /** Фоновые операции канала вне сессии, например обновление авторизации. */\n readonly #backgroundTasks = new Set<Promise<unknown>>();\n\n #session: ActiveEventSession<U, O> | undefined;\n /**\n * Хочет ли вызывающий код, чтобы соединение было живо.\n *\n * Отдельно от `#controller`, потому что тот появляется только после `await` внутри\n * {@link connect}. Без этого флага два вызова подряд проскочили бы проверку оба\n * и подняли два соединения, а `disconnect()` во время синхронизации не был бы замечен\n * и соединение поднялось бы уже после отмены.\n */\n #wanted = false;\n #status: EventChannelStatus = EventChannelStatus.Disconnected;\n #attempt = 0;\n #generation = 0;\n #starting: Promise<void> | undefined;\n #cancelTimer: (() => void) | undefined;\n #detachEnvironment: (() => void) | undefined;\n\n constructor(deps: EventChannelDeps<U, C, O>, options: EventChannelOptions<C> = {}) {\n options = resolveEventChannelOptions(options);\n\n this.#deps = deps;\n this.#options = options;\n this.#clock = deps.clock ?? systemClock;\n this.#maxAttempts = options.maxAttempts ?? MAX_RECONNECT_ATTEMPTS;\n this.#emitter = new Emitter<E>((error) => reportListenerError(deps.logger, 'событий', error));\n this.#dispatcher = new EventDispatcher<C>(\n {\n concurrency: options.concurrency ?? 1,\n ...(options.sequentialize ? { sequentialize: options.sequentialize } : {}),\n },\n {\n deliver: (context) => this.#deps.deliver(context.update),\n middlewareError: (error, context) =>\n this.#reportDispatchError('middlewareError', error, context),\n handlerError: (error, context) => this.#reportDispatchError('handlerError', error, context),\n overflow: () => this.#handleOverflow(),\n },\n );\n }\n\n /** Текущее состояние соединения. */\n get status(): EventChannelStatus {\n return this.#status;\n }\n\n /** Имя используемого транспорта. */\n get transport(): string {\n return this.#deps.transport.name;\n }\n\n /** Подписывается на событие потока. @returns функция отписки */\n on<K extends keyof E>(event: K, listener: Listener<E[K]>): Unsubscribe {\n return this.#emitter.on(event, listener);\n }\n\n /** Подписывается на одно срабатывание события потока. */\n once<K extends keyof E>(event: K, listener: Listener<E[K]>): Unsubscribe {\n return this.#emitter.once(event, listener);\n }\n\n /** Рассылает доменное событие через общий эмиттер потока. */\n emit<K extends keyof E>(event: K, payload: E[K]): void {\n this.#emitter.emit(event, payload);\n }\n\n /** Снимает подписки на события. Обработчики обновлений и middleware остаются. */\n removeAllListeners(): void {\n this.#emitter.removeAllListeners();\n }\n\n /** Добавляет промежуточный обработчик. @returns функция его удаления */\n use(middleware: EventMiddleware<C> | EventMiddlewareObject<C>): Unsubscribe {\n if (typeof middleware === 'function') return this.#dispatcher.use(middleware);\n if (\n typeof middleware !== 'object' ||\n middleware === null ||\n typeof middleware.middleware !== 'function'\n ) {\n throw new ItdConfigError(\n 'events.use() принимает функцию обработки или объект с middleware()',\n );\n }\n return this.#dispatcher.use(deferEventMiddleware(middleware));\n }\n\n /** Подписывает обработчик обновлений, подходящих под условие. */\n onUpdate(predicate: EventPredicate<C>, handler: EventHandler<C>): Unsubscribe {\n return this.#dispatcher.on(predicate, handler);\n }\n\n /**\n * Поднимает соединение.\n *\n * Повторный вызов при уже живом соединении ничего не делает. Возвращает управление\n * сразу после запуска: соединение живёт в фоне.\n */\n async connect(): Promise<void> {\n this.#deps.connectGuard?.();\n if (this.#wanted) return this.#starting;\n this.#wanted = true;\n this.#attachEnvironmentListeners();\n const starting = this.#startAttempt('initial');\n this.#starting = starting;\n try {\n await starting;\n } finally {\n if (this.#starting === starting) this.#starting = undefined;\n }\n }\n\n /** Закрывает соединение и отменяет запланированные попытки. */\n disconnect(): void {\n this.#wanted = false;\n this.#generation += 1;\n this.#starting = undefined;\n\n if (this.#cancelTimer) {\n this.#cancelTimer();\n this.#cancelTimer = undefined;\n }\n\n this.#detachEnvironment?.();\n this.#detachEnvironment = undefined;\n\n this.#abortSession(new ItdAbortError('Событийное соединение остановлено'));\n this.#attempt = 0;\n this.#dispatcher.clearPending();\n\n this.#setStatus(EventChannelStatus.Disconnected);\n }\n\n /**\n * Ждёт обработчики и полное завершение уже остановленной сессии соединения.\n *\n * Работающий транспорт намеренно не блокирует `drain()`: сначала владелец вызывает\n * {@link disconnect}, который синхронно отменяет сессию. После этого `drain()` ждёт\n * завершения подготовки, транспорта и фонового обновления авторизации, включая их\n * асинхронное освобождение ресурсов.\n */\n async drain(): Promise<void> {\n const sessions = [...this.#retiredSessions];\n const background = [...this.#backgroundTasks];\n await Promise.all([this.#dispatcher.drain(), ...sessions, ...background]);\n }\n\n /** Пропускает актуальное обновление через цепочку обработчиков. */\n #dispatch(update: U, raw: EventTransportFrame | undefined, origin: O): void {\n if (!this.#wanted) return;\n this.#dispatcher.dispatch(\n this.#deps.createContext(update, raw, origin),\n this.#deps.coalesceKey?.(update),\n );\n }\n\n /**\n * Очередь обновлений достигла предела: закрывает соединение и переподключается,\n * когда обработчики разберут очередь.\n */\n #handleOverflow(): void {\n const session = this.#session;\n if (!this.#wanted || !session) return;\n\n const generation = session.generation;\n this.#abortSession(new ItdAbortError('Очередь событий переполнена'));\n this.#setStatus(EventChannelStatus.Error);\n\n const error = new Error('Обработчики не успевают за потоком: очередь обновлений переполнена');\n void this.#dispatcher.drain().then(() => {\n if (this.#isCurrentGeneration(generation) && !this.#session) {\n this.#scheduleReconnect(error);\n }\n });\n }\n\n /** Создаёт новую попытку соединения и выполняет её подготовку. */\n async #startAttempt(reason: EventSyncReason): Promise<void> {\n if (!this.#wanted) return;\n this.#abortSession(new ItdAbortError('Событийное соединение заменено новой попыткой'));\n const session = this.#createSession(++this.#generation);\n this.#session = session;\n\n try {\n if (this.#deps.openBeforeInitialize) {\n this.#runTransport(session);\n await session.handle.opened;\n await this.#initialize(reason, session);\n this.#openGate(session);\n } else {\n await this.#initialize(reason, session);\n this.#openGate(session);\n if (this.#isCurrentSession(session)) this.#runTransport(session);\n }\n } catch (error) {\n if (!this.#isCurrentSession(session)) return;\n this.#abortSession(error);\n if (reason === 'initial' && this.#deps.initializationRequired) {\n this.#wanted = false;\n this.#detachEnvironment?.();\n this.#detachEnvironment = undefined;\n this.#setStatus(EventChannelStatus.Disconnected);\n throw error;\n }\n this.#handleFailure(error);\n }\n }\n\n async #initialize(reason: EventSyncReason, session: ActiveEventSession<U, O>): Promise<void> {\n const initialize = this.#deps.initialize;\n if (!initialize) return;\n const task = this.#runSessionTask(session, () => initialize(reason, session.handle));\n try {\n await task;\n } catch (error) {\n if (this.#deps.initializationRequired) throw error;\n this.#deps.logger?.debug(`не удалось синхронизировать поток (${reason})`, error);\n }\n }\n\n /** Запускает транспорт одной попытки. */\n #runTransport(session: ActiveEventSession<U, O>): void {\n if (!this.#isCurrentSession(session)) return;\n this.#setStatus(EventChannelStatus.Connecting);\n\n this.#runSessionTask(session, () =>\n Promise.resolve(\n this.#deps.transport.connect({\n ...this.#deps.connection,\n signal: session.controller.signal,\n onOpen: () => {\n if (!this.#isCurrentSession(session)) return;\n this.#attempt = 0;\n session.resolveOpened();\n this.#setStatus(EventChannelStatus.Connected);\n },\n onEvent: (event) => {\n if (this.#isCurrentSession(session)) this.#handleEvent(session, event);\n },\n onParseError: (error, raw) => {\n if (this.#isCurrentSession(session)) {\n this.#emitEngine('parseError', { error, raw });\n }\n },\n }),\n ).then(\n () => {\n // Штатное закрытие потока — тоже повод переподключиться.\n if (this.#isCurrentSession(session)) {\n this.#handleFailure(new Error('Соединение с потоком событий закрыто'));\n }\n },\n (error: unknown) => {\n if (this.#isCurrentSession(session)) this.#handleFailure(error);\n },\n ),\n );\n }\n\n #handleEvent(session: ActiveEventSession<U, O>, event: EventTransportFrame): void {\n if (!this.#wanted) return;\n this.#emitEngine('message', event);\n\n if (!session.ready && (this.#deps.bufferFrame?.(event) ?? true)) {\n if (session.buffer.length >= MAX_PENDING_UPDATES) {\n this.#handleOverflow();\n return;\n }\n session.buffer.push(event);\n return;\n }\n\n this.#dispatchFrame(event);\n }\n\n #dispatchFrame(event: EventTransportFrame): void {\n if (this.#deps.handleFrame?.(event)) return;\n\n const update = this.#deps.readUpdate(event);\n if (update !== undefined) this.#dispatch(update, event, this.#deps.streamOrigin);\n }\n\n #reportDispatchError(\n event: 'middlewareError' | 'handlerError',\n error: unknown,\n context: C,\n ): void {\n if (this.#emitter.listenerCount(event) > 0) {\n this.#emitEngine(event, { error, context });\n return;\n }\n\n const message =\n event === 'middlewareError'\n ? 'Ошибка в промежуточном обработчике потока'\n : 'Ошибка в обработчике обновления потока';\n if (this.#deps.logger) this.#deps.logger.error(message, error);\n else console.error(`[itd-api] ${message}`, error);\n }\n\n #handleFailure(error: unknown): void {\n this.#abortSession(error);\n\n if (error instanceof UnauthorizedStreamError) {\n this.#runBackgroundTask(() => this.#refreshAndReconnect(error));\n return;\n }\n\n this.#setStatus(EventChannelStatus.Error);\n this.#scheduleReconnect(error);\n }\n\n /** Обновляет токен и переподключается; при неудаче прекращает попытки. */\n async #refreshAndReconnect(error: unknown): Promise<void> {\n const generation = this.#generation;\n this.#setStatus(EventChannelStatus.Error);\n\n const refreshed = await this.#deps.connection.refreshAuth().catch(() => false);\n\n if (!this.#isCurrentGeneration(generation)) return;\n\n if (!refreshed) {\n this.#giveUp(error);\n return;\n }\n\n this.#scheduleReconnect(error);\n }\n\n #scheduleReconnect(error: unknown): void {\n if (!this.#wanted) return;\n\n if (this.#attempt >= this.#maxAttempts) {\n this.#giveUp(error);\n return;\n }\n\n const delay = reconnectDelay(this.#attempt, this.#options);\n this.#attempt += 1;\n\n this.#emitEngine('error', { error, willReconnect: true });\n this.#emitEngine('reconnect', { attempt: this.#attempt, delay });\n\n this.#cancelTimer = this.#clock.schedule(() => {\n this.#cancelTimer = undefined;\n void this.#reconnect();\n }, delay);\n }\n\n /** Догон через REST идёт до сокета: он же обновляет протухший токен. */\n async #reconnect(): Promise<void> {\n if (!this.#wanted || this.#starting) return;\n const starting = this.#startAttempt('reconnect');\n this.#starting = starting;\n try {\n await starting;\n } finally {\n if (this.#starting === starting) this.#starting = undefined;\n }\n }\n\n /**\n * Завершает автоматические попытки переподключения.\n *\n * Владелец узнаёт об этом через `giveup` и может тут же вызвать `connect()`.\n */\n #giveUp(error: unknown): void {\n this.#wanted = false;\n this.#generation += 1;\n this.#starting = undefined;\n this.#attempt = 0;\n this.#abortSession(error);\n\n this.#detachEnvironment?.();\n this.#detachEnvironment = undefined;\n\n EVENT_CHANNEL_GIVEUP_HOOKS.get(this)?.();\n this.#emitEngine('error', { error, willReconnect: false });\n this.#emitEngine('giveup', undefined);\n }\n\n /**\n * Подписывается на события среды.\n *\n * Возврат вкладки из фона и восстановление сети — самые частые причины «мёртвого»\n * соединения. У сайта итд.com такой обработки нет.\n */\n #attachEnvironmentListeners(): void {\n if (this.#detachEnvironment) return;\n\n const target = globalThis as unknown as {\n addEventListener?: (type: string, listener: () => void) => void;\n removeEventListener?: (type: string, listener: () => void) => void;\n document?: { visibilityState?: string };\n };\n\n if (typeof target.addEventListener !== 'function') return;\n\n const wake = () => {\n // Реагируем, только если соединения сейчас нет и попытка не запланирована.\n if (this.#session || this.#cancelTimer || this.#starting) return;\n if (this.#status === EventChannelStatus.Disconnected) return;\n\n this.#attempt = 0;\n void this.#reconnect();\n };\n\n const onVisibility = () => {\n if (target.document?.visibilityState === 'visible') wake();\n };\n\n const listeners: [string, () => void][] = [];\n\n if (this.#options.reconnectOnVisible !== false && target.document) {\n listeners.push(['visibilitychange', onVisibility]);\n }\n if (this.#options.reconnectOnOnline !== false) {\n listeners.push(['online', wake]);\n }\n\n for (const [type, listener] of listeners) target.addEventListener(type, listener);\n\n this.#detachEnvironment = () => {\n for (const [type, listener] of listeners) target.removeEventListener?.(type, listener);\n };\n }\n\n #setStatus(status: EventChannelStatus): void {\n if (this.#status === status) return;\n this.#status = status;\n this.#emitEngine('status', status);\n }\n\n #isCurrentGeneration(generation: number): boolean {\n return this.#wanted && this.#generation === generation;\n }\n\n #isCurrentSession(session: ActiveEventSession<U, O>): boolean {\n return (\n this.#isCurrentGeneration(session.generation) &&\n this.#session === session &&\n !session.controller.signal.aborted\n );\n }\n\n #createSession(generation: number): ActiveEventSession<U, O> {\n const controller = new AbortController();\n let resolveOpened!: () => void;\n let rejectOpened!: (error: unknown) => void;\n let resolveDrained!: () => void;\n const opened = new Promise<void>((resolve, reject) => {\n resolveOpened = resolve;\n rejectOpened = reject;\n });\n const drained = new Promise<void>((resolve) => {\n resolveDrained = resolve;\n });\n void opened.catch(() => {});\n\n const session = {} as ActiveEventSession<U, O>;\n const handle: EventSession<U, O> = Object.freeze({\n signal: controller.signal,\n opened,\n enqueue: (update: U, options: EventEnqueueOptions<O>) => {\n if (!this.#isCurrentSession(session)) return;\n this.#dispatch(update, options.raw, options.origin);\n },\n });\n Object.assign(session, {\n generation,\n controller,\n handle,\n resolveOpened,\n rejectOpened,\n buffer: [],\n tasks: new Set(),\n drained,\n resolveDrained,\n retired: false,\n ready: false,\n });\n return session;\n }\n\n /**\n * Учитывает работу, принадлежащую одной сессии соединения.\n *\n * Маркер добавляется до синхронного входа в операцию: она может повторным вызовом\n * остановить канал из `onOpen` или подготовки, и такая сессия всё равно должна\n * остаться в `drain()` до завершения операции.\n */\n #runSessionTask<T>(\n session: ActiveEventSession<U, O>,\n operation: () => T | PromiseLike<T>,\n ): Promise<T> {\n return this.#runTrackedTask(session.tasks, operation, () => {\n if (session.retired && session.tasks.size === 0) session.resolveDrained();\n });\n }\n\n /** Учитывает работу канала до синхронного входа в операцию вне сессии транспорта. */\n #runBackgroundTask(operation: () => unknown | PromiseLike<unknown>): void {\n void this.#runTrackedTask(this.#backgroundTasks, operation);\n }\n\n /** Запускает операцию без окна между входом в неё и регистрацией маркера завершения. */\n #runTrackedTask<T>(\n tasks: Set<Promise<unknown>>,\n operation: () => T | PromiseLike<T>,\n afterFinish?: () => void,\n ): Promise<T> {\n let finish!: () => void;\n const marker = new Promise<void>((resolve) => {\n finish = resolve;\n });\n tasks.add(marker);\n\n let task: Promise<T>;\n try {\n task = Promise.resolve(operation());\n } catch (error) {\n task = Promise.reject(error);\n }\n\n const settle = (): void => {\n tasks.delete(marker);\n finish();\n afterFinish?.();\n };\n void task.then(settle, settle);\n return task;\n }\n\n #openGate(session: ActiveEventSession<U, O>): void {\n if (!this.#isCurrentSession(session) || session.ready) return;\n session.ready = true;\n const buffered = session.buffer.splice(0);\n for (const event of buffered) {\n if (!this.#isCurrentSession(session)) break;\n this.#dispatchFrame(event);\n }\n }\n\n #abortSession(reason: unknown): void {\n const session = this.#session;\n if (!session) return;\n this.#session = undefined;\n session.buffer.length = 0;\n session.retired = true;\n this.#retiredSessions.add(session.drained);\n void session.drained.then(() => this.#retiredSessions.delete(session.drained));\n session.rejectOpened(reason);\n session.controller.abort(reason);\n if (session.tasks.size === 0) session.resolveDrained();\n }\n\n /** Рассылает событие из общей части карты, не теряя доменные события типа `E`. */\n #emitEngine<K extends keyof EventChannelEvents<C>>(\n event: K,\n payload: EventChannelEvents<C>[K],\n ): void {\n // `E` гарантированно содержит общую карту. Приведение нужно только потому, что\n // TypeScript допускает теоретическое сужение унаследованного поля в подтипе `E`.\n (this.#emitter as unknown as Emitter<EventChannelEvents<C>>).emit(event, payload);\n }\n}\n","import { type ItdClock, systemClock } from '../../core/clock.js';\nimport { isItdAuthError } from '../../core/errors.js';\nimport { pickArray, pickNumber } from '../../core/unwrap.js';\nimport type { EventRequest, EventTransport, EventTransportContext } from './transport.js';\nimport { UnauthorizedStreamError } from './transport.js';\n\n/** Настройки опроса. */\nexport interface PollTransportOptions {\n /** Доменный adapter notification REST-операций. */\n request: EventRequest;\n /** Часы опроса. Обычно подменяются только в тестах. */\n clock?: ItdClock;\n /** Как часто опрашивать сервер, мс. По умолчанию 15 000. */\n interval?: number;\n /** Сколько уведомлений запрашивать за раз. По умолчанию 20. */\n limit?: number;\n}\n\n/**\n * Запасной транспорт: обычный опрос REST вместо потока.\n *\n * Нужен там, где `fetch` не умеет отдавать тело по частям, — например в части сборок\n * React Native. Наружу выдаёт те же события, что и {@link SseTransport}, поэтому\n * вызывающий код разницы не замечает.\n *\n * Новыми считаются уведомления, которых не было в предыдущем ответе; чтобы список\n * известных не рос бесконечно, он ограничен последними двумя страницами.\n */\nexport class PollTransport implements EventTransport {\n readonly name = 'poll';\n\n readonly #interval: number;\n readonly #limit: number;\n readonly #clock: ItdClock;\n readonly #request: EventRequest;\n\n constructor(options: PollTransportOptions) {\n this.#request = options.request;\n this.#clock = options.clock ?? systemClock;\n this.#interval = options.interval ?? 15_000;\n this.#limit = options.limit ?? 20;\n }\n\n async connect(context: EventTransportContext): Promise<void> {\n const seen = new Set<string>();\n let firstRun = true;\n let lastUnreadCount: number | undefined;\n\n while (!context.signal.aborted) {\n const payload = await this.#readUpdates(this.#request, context.signal);\n\n // Соединение считается установленным только после первого успешного ответа: иначе\n // при постоянно недоступной сети каждая попытка обнуляла бы счётчик и maxAttempts\n // не срабатывал бы никогда.\n context.onOpen();\n\n const items = pickArray<Record<string, unknown>>(payload, 'notifications');\n\n for (const item of [...items].reverse()) {\n const id = typeof item.id === 'string' ? item.id : undefined;\n if (!id || seen.has(id)) continue;\n\n seen.add(id);\n // На первом проходе список уже существующих уведомлений не считается новыми\n // событиями: иначе подключение сразу выдало бы всю историю.\n if (!firstRun) context.onEvent({ name: 'notification', data: { payload: item } });\n }\n\n // Ограничиваем память: держим только последние две страницы идентификаторов.\n if (seen.size > this.#limit * 2) {\n const excess = [...seen].slice(0, seen.size - this.#limit * 2);\n for (const id of excess) seen.delete(id);\n }\n\n const count = await this.#readCount(this.#request, context.signal);\n if (count !== undefined && count !== lastUnreadCount) {\n lastUnreadCount = count;\n context.onEvent({ name: 'unread_count', data: { payload: { count } } });\n }\n\n firstRun = false;\n await this.#wait(context.signal);\n }\n }\n\n async #readUpdates(request: EventRequest, signal: AbortSignal): Promise<unknown> {\n try {\n return await request({\n operationId: 'events.notifications.poll.updates',\n path: '/api/notifications/',\n query: { limit: this.#limit, offset: 0 },\n signal,\n });\n } catch (error) {\n // Для потока это тот же отказ авторизации, что и `401` от сервера событий.\n if (isItdAuthError(error)) throw new UnauthorizedStreamError();\n throw error;\n }\n }\n\n async #readCount(request: EventRequest, signal: AbortSignal): Promise<number | undefined> {\n try {\n const payload = await request({\n operationId: 'events.notifications.poll.unread',\n path: '/api/notifications/count',\n signal,\n });\n return pickNumber(payload, 'count', 0);\n } catch {\n // Счётчик — вспомогательная величина: его недоступность не должна рвать опрос.\n return undefined;\n }\n }\n\n /** Ждёт следующего опроса, прерываясь при отмене. */\n #wait(signal: AbortSignal): Promise<void> {\n // Подписка на уже сработавший сигнал не вызывается никогда — без этой проверки\n // отмена, пришедшая перед самым ожиданием, стоила бы лишнего интервала.\n if (signal.aborted) return Promise.resolve();\n\n return new Promise<void>((resolve) => {\n const cancel = this.#clock.schedule(finish, this.#interval);\n\n function finish() {\n cancel();\n signal.removeEventListener('abort', finish);\n resolve();\n }\n\n signal.addEventListener('abort', finish, { once: true });\n });\n }\n}\n","class ParseError extends Error {\n constructor(message, options) {\n super(message), this.name = \"ParseError\", this.type = options.type, this.field = options.field, this.value = options.value, this.line = options.line;\n }\n}\nconst LF = 10, CR = 13, SPACE = 32;\nfunction noop(_arg) {\n}\nfunction createParser(config) {\n if (typeof config == \"function\")\n throw new TypeError(\n \"`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?\"\n );\n const { onEvent = noop, onError = noop, onRetry = noop, onComment, maxBufferSize } = config, pendingFragments = [];\n let pendingFragmentsLength = 0, isFirstChunk = !0, id, data = \"\", dataLines = 0, eventType, terminated = !1;\n function feed(chunk) {\n if (terminated)\n throw new Error(\n \"Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing.\"\n );\n if (isFirstChunk && (isFirstChunk = !1, chunk.charCodeAt(0) === 239 && chunk.charCodeAt(1) === 187 && chunk.charCodeAt(2) === 191 && (chunk = chunk.slice(3))), pendingFragments.length === 0) {\n const trailing2 = processLines(chunk);\n trailing2 !== \"\" && (pendingFragments.push(trailing2), pendingFragmentsLength = trailing2.length), checkBufferSize();\n return;\n }\n if (chunk.indexOf(`\n`) === -1 && chunk.indexOf(\"\\r\") === -1) {\n pendingFragments.push(chunk), pendingFragmentsLength += chunk.length, checkBufferSize();\n return;\n }\n pendingFragments.push(chunk);\n const input = pendingFragments.join(\"\");\n pendingFragments.length = 0, pendingFragmentsLength = 0;\n const trailing = processLines(input);\n trailing !== \"\" && (pendingFragments.push(trailing), pendingFragmentsLength = trailing.length), checkBufferSize();\n }\n function checkBufferSize() {\n maxBufferSize !== void 0 && (pendingFragmentsLength + data.length <= maxBufferSize || (terminated = !0, pendingFragments.length = 0, pendingFragmentsLength = 0, id = void 0, data = \"\", dataLines = 0, eventType = void 0, onError(\n new ParseError(`Buffered data exceeded max buffer size of ${maxBufferSize} characters`, {\n type: \"max-buffer-size-exceeded\"\n })\n )));\n }\n function processLines(chunk) {\n let searchIndex = 0;\n if (chunk.indexOf(\"\\r\") === -1) {\n let lfIndex = chunk.indexOf(`\n`, searchIndex);\n for (; lfIndex !== -1; ) {\n if (searchIndex === lfIndex) {\n dataLines > 0 && onEvent({ id, event: eventType, data }), id = void 0, data = \"\", dataLines = 0, eventType = void 0, searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`\n`, searchIndex);\n continue;\n }\n const firstCharCode = chunk.charCodeAt(searchIndex);\n if (isDataPrefix(chunk, searchIndex, firstCharCode)) {\n const valueStart = chunk.charCodeAt(searchIndex + 5) === SPACE ? searchIndex + 6 : searchIndex + 5, value = chunk.slice(valueStart, lfIndex);\n if (dataLines === 0 && chunk.charCodeAt(lfIndex + 1) === LF) {\n onEvent({ id, event: eventType, data: value }), id = void 0, data = \"\", eventType = void 0, searchIndex = lfIndex + 2, lfIndex = chunk.indexOf(`\n`, searchIndex);\n continue;\n }\n data = dataLines === 0 ? value : `${data}\n${value}`, dataLines++;\n } else isEventPrefix(chunk, searchIndex, firstCharCode) ? eventType = chunk.slice(\n chunk.charCodeAt(searchIndex + 6) === SPACE ? searchIndex + 7 : searchIndex + 6,\n lfIndex\n ) || void 0 : parseLine(chunk, searchIndex, lfIndex);\n searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`\n`, searchIndex);\n }\n return chunk.slice(searchIndex);\n }\n for (; searchIndex < chunk.length; ) {\n const crIndex = chunk.indexOf(\"\\r\", searchIndex), lfIndex = chunk.indexOf(`\n`, searchIndex);\n let lineEnd = -1;\n if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = crIndex < lfIndex ? crIndex : lfIndex : crIndex !== -1 ? crIndex === chunk.length - 1 ? lineEnd = -1 : lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1)\n break;\n parseLine(chunk, searchIndex, lineEnd), searchIndex = lineEnd + 1, chunk.charCodeAt(searchIndex - 1) === CR && chunk.charCodeAt(searchIndex) === LF && searchIndex++;\n }\n return chunk.slice(searchIndex);\n }\n function parseLine(chunk, start, end) {\n if (start === end) {\n dispatchEvent();\n return;\n }\n const firstCharCode = chunk.charCodeAt(start);\n if (isDataPrefix(chunk, start, firstCharCode)) {\n const valueStart = chunk.charCodeAt(start + 5) === SPACE ? start + 6 : start + 5, value2 = chunk.slice(valueStart, end);\n data = dataLines === 0 ? value2 : `${data}\n${value2}`, dataLines++;\n return;\n }\n if (isEventPrefix(chunk, start, firstCharCode)) {\n eventType = chunk.slice(chunk.charCodeAt(start + 6) === SPACE ? start + 7 : start + 6, end) || void 0;\n return;\n }\n if (firstCharCode === 105 && chunk.charCodeAt(start + 1) === 100 && chunk.charCodeAt(start + 2) === 58) {\n const value2 = chunk.slice(chunk.charCodeAt(start + 3) === SPACE ? start + 4 : start + 3, end);\n value2.includes(\"\\0\") || (id = value2);\n return;\n }\n if (firstCharCode === 58) {\n if (onComment) {\n const line2 = chunk.slice(start, end);\n onComment(line2.slice(chunk.charCodeAt(start + 1) === SPACE ? 2 : 1));\n }\n return;\n }\n const line = chunk.slice(start, end), fieldSeparatorIndex = line.indexOf(\":\");\n if (fieldSeparatorIndex === -1) {\n processField(line, \"\", line);\n return;\n }\n const field = line.slice(0, fieldSeparatorIndex), offset = line.charCodeAt(fieldSeparatorIndex + 1) === SPACE ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset);\n processField(field, value, line);\n }\n function processField(field, value, line) {\n switch (field) {\n case \"event\":\n eventType = value || void 0;\n break;\n case \"data\":\n data = dataLines === 0 ? value : `${data}\n${value}`, dataLines++;\n break;\n case \"id\":\n value.includes(\"\\0\") || (id = value);\n break;\n case \"retry\":\n /^\\d+$/.test(value) ? onRetry(parseInt(value, 10)) : onError(\n new ParseError(`Invalid \\`retry\\` value: \"${value}\"`, {\n type: \"invalid-retry\",\n value,\n line\n })\n );\n break;\n default:\n onError(\n new ParseError(\n `Unknown field \"${field.length > 20 ? `${field.slice(0, 20)}\\u2026` : field}\"`,\n { type: \"unknown-field\", field, value, line }\n )\n );\n break;\n }\n }\n function dispatchEvent() {\n dataLines > 0 && onEvent({\n id,\n event: eventType,\n data\n }), id = void 0, data = \"\", dataLines = 0, eventType = void 0;\n }\n function reset(options = {}) {\n if (options.consume && pendingFragments.length > 0) {\n const incompleteLine = pendingFragments.join(\"\");\n parseLine(incompleteLine, 0, incompleteLine.length);\n }\n isFirstChunk = !0, id = void 0, data = \"\", dataLines = 0, eventType = void 0, pendingFragments.length = 0, pendingFragmentsLength = 0, terminated = !1;\n }\n return { feed, reset };\n}\nfunction isDataPrefix(chunk, i, firstCharCode) {\n return firstCharCode === 100 && chunk.charCodeAt(i + 1) === 97 && chunk.charCodeAt(i + 2) === 116 && chunk.charCodeAt(i + 3) === 97 && chunk.charCodeAt(i + 4) === 58;\n}\nfunction isEventPrefix(chunk, i, firstCharCode) {\n return firstCharCode === 101 && chunk.charCodeAt(i + 1) === 118 && chunk.charCodeAt(i + 2) === 101 && chunk.charCodeAt(i + 3) === 110 && chunk.charCodeAt(i + 4) === 116 && chunk.charCodeAt(i + 5) === 58;\n}\nexport {\n ParseError,\n createParser\n};\n//# sourceMappingURL=index.js.map\n","import { createParser } from 'eventsource-parser';\nimport { type ItdClock, systemClock } from '../../core/clock.js';\nimport { joinUrl } from '../../core/url.js';\nimport {\n type EventTransport,\n type EventTransportContext,\n UnauthorizedStreamError,\n} from './transport.js';\n\n/** Путь потока уведомлений. */\nexport const STREAM_PATH = '/api/notifications/stream';\n\n/** Настройки SSE-транспорта. */\nexport interface SseTransportOptions {\n /** Часы потока. Обычно подменяются только в тестах. */\n clock?: ItdClock;\n /**\n * Сколько миллисекунд ждать данных, прежде чем считать соединение мёртвым.\n *\n * Сервер не присылает keep-alive, а оборванное TCP-соединение может не закрыться\n * само — без этой проверки поток «тихо умирает» и новых уведомлений не приходит.\n * По умолчанию 90 000. `0` отключает проверку.\n */\n idleTimeout?: number;\n /**\n * Сколько миллисекунд ждать ответа на запрос потока, прежде чем оборвать попытку.\n *\n * Проверка молчания ({@link idleTimeout}) начинается только после получения тела ответа.\n * Если `fetch` завис на установке соединения, без этого таймаута переподключение не\n * запустится до системного сетевого таймаута. По умолчанию 20 000. `0` отключает проверку.\n */\n handshakeTimeout?: number;\n}\n\n/**\n * Транспорт поверх Server-Sent Events.\n *\n * Нативный `EventSource` не подходит: он не умеет отправлять заголовок `Authorization`,\n * а поток требует Bearer-токен. Поэтому используется `fetch` с чтением тела по частям.\n *\n * Разбор кадров делегирован `eventsource-parser`, который корректно обрабатывает\n * многострочный `data:`, перевод строки `\\r\\n`, `data:` без пробела и кадр, разорванный\n * между сетевыми чанками. В разборе на сайте итд.com каждый из этих случаев обрабатывается\n * неверно.\n */\nexport class SseTransport implements EventTransport {\n readonly name = 'sse';\n\n readonly #idleTimeout: number;\n readonly #handshakeTimeout: number;\n readonly #clock: ItdClock;\n /** Идентификатор последнего события — отправляется при переподключении. */\n #lastEventId: string | undefined;\n\n constructor(options: SseTransportOptions = {}) {\n this.#clock = options.clock ?? systemClock;\n this.#idleTimeout = options.idleTimeout ?? 90_000;\n this.#handshakeTimeout = options.handshakeTimeout ?? 20_000;\n }\n\n async connect(context: EventTransportContext): Promise<void> {\n const token = context.authorize ? await context.getToken() : null;\n if (context.authorize && !token) throw new UnauthorizedStreamError();\n\n const url = joinUrl(context.baseUrl, STREAM_PATH);\n\n const headers = await context.baseHeaders(url);\n headers.set('Accept', 'text/event-stream');\n if (token) headers.set('Authorization', `Bearer ${token}`);\n headers.set('Cache-Control', 'no-cache');\n\n // Сервер пока не присылает id, но поддержка не мешает и пригодится, если начнёт.\n if (this.#lastEventId) headers.set('Last-Event-ID', this.#lastEventId);\n\n // Отдельный контроллер, связанный с сигналом потока: помимо внешней отмены он позволяет\n // оборвать зависшее рукопожатие своим таймаутом. Живёт до конца чтения тела.\n const controller = new AbortController();\n const relayAbort = () => controller.abort(context.signal.reason);\n if (context.signal.aborted) controller.abort(context.signal.reason);\n else context.signal.addEventListener('abort', relayAbort, { once: true });\n\n try {\n const response = await this.#handshake(url, headers, context, controller);\n\n if (context.authorize && response.status === 401) throw new UnauthorizedStreamError();\n if (!response.ok) throw new Error(`Поток уведомлений вернул статус ${response.status}`);\n if (!response.body) throw new Error('Ответ потока уведомлений пуст');\n\n context.onOpen();\n\n await this.#read(response.body, context);\n } finally {\n context.signal.removeEventListener('abort', relayAbort);\n }\n }\n\n /** Выполняет запрос потока, обрывая его, если ответ не пришёл за отведённое время. */\n async #handshake(\n url: string,\n headers: Headers,\n context: EventTransportContext,\n controller: AbortController,\n ): Promise<Response> {\n let expired = false;\n const cancelTimer =\n this.#handshakeTimeout > 0\n ? this.#clock.schedule(() => {\n expired = true;\n // Абортим связанный контроллер: `fetch` реджектит, и внешний код переподключится.\n controller.abort(new Error('Истёк таймаут рукопожатия SSE'));\n }, this.#handshakeTimeout)\n : undefined;\n\n try {\n return await context.fetch(url, { method: 'GET', headers, signal: controller.signal });\n } catch (error) {\n if (expired) throw new Error('Поток уведомлений не ответил: истёк таймаут рукопожатия');\n throw error;\n } finally {\n cancelTimer?.();\n }\n }\n\n async #read(body: ReadableStream<Uint8Array>, context: EventTransportContext): Promise<void> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n\n const parser = createParser({\n onEvent: (message) => {\n if (message.id) this.#lastEventId = message.id;\n\n let data: unknown;\n try {\n data = JSON.parse(message.data);\n } catch (error) {\n // Одно битое сообщение не повод рвать соединение.\n context.onParseError(error, message.data);\n return;\n }\n\n // Имя события может отсутствовать — тогда тип лежит внутри полезной нагрузки.\n const name =\n message.event ??\n (typeof data === 'object' && data !== null && 'type' in data\n ? String((data as { type: unknown }).type)\n : 'message');\n\n context.onEvent({ name, data });\n },\n });\n\n let cancelIdleTimer: (() => void) | undefined;\n\n const armIdleTimer = () => {\n if (this.#idleTimeout <= 0) return;\n cancelIdleTimer?.();\n\n cancelIdleTimer = this.#clock.schedule(() => {\n // Отмена чтения завершит цикл, и внешний код переподключится.\n void reader.cancel(new Error('Поток молчит дольше допустимого')).catch(() => {});\n }, this.#idleTimeout);\n };\n\n armIdleTimer();\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n\n armIdleTimer();\n parser.feed(decoder.decode(value, { stream: true }));\n }\n } finally {\n cancelIdleTimer?.();\n reader.releaseLock?.();\n }\n }\n}\n","import { ItdConfigError } from '../core/errors.js';\nimport type { Notification } from '../models/notifications.js';\nimport type { NotificationEvent } from '../notifications/normalize.js';\nimport { readNotificationEvent, readUnreadCountEvent } from '../notifications/normalize.js';\nimport type { NotificationType } from '../types/enums.js';\nimport type { NotificationEvents } from './stream.js';\nimport type { EventTransportFrame } from './transports/transport.js';\n\n/** Типы нормализованных обновлений потока. */\nexport const NotificationUpdateType = Object.freeze({\n Notification: 'notification',\n UnreadCount: 'unreadCount',\n Unknown: 'unknown',\n} as const);\n\n/** Источники нормализованных обновлений потока. */\nexport const NotificationUpdateOrigin = Object.freeze({\n Stream: 'stream',\n Sync: 'sync',\n} as const);\nexport type NotificationUpdateOrigin =\n (typeof NotificationUpdateOrigin)[keyof typeof NotificationUpdateOrigin];\n\n/** Уведомление с типом, суженным фильтром потока. */\nexport type NotificationOfType<T extends NotificationType> = Omit<Notification, 'type'> & {\n type: T;\n};\n\n/** Конверт уведомления с типом, суженным фильтром потока. */\nexport type NotificationEventOfType<T extends NotificationType> = Omit<\n NotificationEvent,\n 'notification'\n> & {\n notification: NotificationOfType<T>;\n};\n\n/** Нормализованное уведомление из потока. */\nexport interface NotificationUpdate<T extends NotificationType = NotificationType> {\n readonly type: typeof NotificationUpdateType.Notification;\n readonly data: NotificationEventOfType<T>;\n}\n\n/** Актуальное число непрочитанных уведомлений. */\nexport interface UnreadCountUpdate {\n readonly type: typeof NotificationUpdateType.UnreadCount;\n readonly data: number;\n}\n\n/** Неизвестное библиотеке событие потока. */\nexport interface UnknownNotificationUpdate {\n readonly type: typeof NotificationUpdateType.Unknown;\n readonly name: string;\n readonly data: unknown;\n}\n\n/** Данные, проходящие через промежуточные обработчики потока. */\nexport type NotificationEventsUpdate =\n | NotificationUpdate\n | UnreadCountUpdate\n | UnknownNotificationUpdate;\n\n/** Тип нормализованного обновления потока. */\nexport type NotificationUpdateType = NotificationEventsUpdate['type'];\n\n/** Обновление потока указанного типа. */\nexport type NotificationUpdateOfType<T extends NotificationUpdateType> = Extract<\n NotificationEventsUpdate,\n { type: T }\n>;\n\n/**\n * Общая форма контекста обработки: то, что есть у любого потока независимо от домена.\n *\n * Контекст — обычный объектный литерал, а не класс с геттерами и не `Object.freeze`:\n * плагины-флейворы присваивают в него свои поля (`ctx.session = …`), а `@itd-api/hydrate`\n * подменяет `update` и `stream` через `Object.defineProperty`.\n *\n * @typeParam U нормализованное обновление домена\n * @typeParam S поток, который его получил\n */\nexport interface EventContext<U = unknown, S = unknown, O = unknown> {\n /** Нормализованные данные обновления. */\n readonly update: U;\n /** Поток, который получил обновление. */\n readonly stream: S;\n /** Исходный кадр транспорта. Для начальной REST-синхронизации равен `undefined`. */\n readonly raw: EventTransportFrame | undefined;\n /** Откуда получены данные. */\n readonly origin: O;\n}\n\n/** Контекст обработки одного обновления потока уведомлений. */\nexport type NotificationEventContext<\n U extends NotificationEventsUpdate = NotificationEventsUpdate,\n> = EventContext<U, NotificationEvents, NotificationUpdateOrigin>;\n\n/** Контекст уведомления с типом, суженным фильтром. */\nexport type NotificationContext<T extends NotificationType = NotificationType> =\n NotificationEventContext<NotificationUpdate<T>>;\n\n/** Условия отбора уведомлений. Все указанные поля объединяются через логическое И. */\nexport interface NotificationEventFilter<T extends NotificationType = NotificationType> {\n /** Один или несколько канонических типов уведомления. */\n type?: T | readonly T[];\n /** Идентификатор хотя бы одного участника уведомления. */\n actorId?: string;\n /** Идентификатор объекта события. */\n entityId?: string | null;\n /** Идентификатор родительского объекта. */\n parentEntityId?: string | null;\n /** Дополнительная проверка после сопоставления полей. */\n predicate?: (context: NotificationContext<T>) => boolean;\n}\n\n/** Краткая или объектная форма фильтра уведомлений. */\nexport type NotificationEventSelector<T extends NotificationType = NotificationType> =\n | T\n | readonly T[]\n | NotificationEventFilter<T>;\n\n/** Проверяет форму фильтра уведомлений. */\nexport function validateNotificationSelector(selector: unknown): void {\n if (typeof selector === 'string') {\n if (selector.length === 0) throw new ItdConfigError('Тип уведомления не должен быть пустым');\n return;\n }\n\n if (Array.isArray(selector)) {\n if (selector.length === 0 || selector.some((type) => typeof type !== 'string' || !type)) {\n throw new ItdConfigError('Список типов уведомлений должен содержать непустые строки');\n }\n return;\n }\n\n if (typeof selector !== 'object' || selector === null) {\n throw new ItdConfigError('Фильтр уведомлений должен быть строкой, списком или объектом');\n }\n\n const filter = selector as Record<string, unknown>;\n if (filter.type !== undefined) validateNotificationSelector(filter.type);\n if (filter.actorId !== undefined && typeof filter.actorId !== 'string') {\n throw new ItdConfigError('Фильтр уведомлений: actorId должен быть строкой');\n }\n for (const field of ['entityId', 'parentEntityId'] as const) {\n const value = filter[field];\n if (value !== undefined && value !== null && typeof value !== 'string') {\n throw new ItdConfigError(`Фильтр уведомлений: ${field} должен быть строкой или null`);\n }\n }\n if (filter.predicate !== undefined && typeof filter.predicate !== 'function') {\n throw new ItdConfigError('Фильтр уведомлений: predicate должен быть функцией');\n }\n}\n\n/** Преобразует транспортный кадр в одно логическое обновление. */\nexport function readNotificationEventsUpdate(\n event: EventTransportFrame,\n): NotificationEventsUpdate | undefined {\n if (event.name === 'notification') {\n return {\n type: NotificationUpdateType.Notification,\n data: readNotificationEvent(event.data),\n };\n }\n\n if (event.name === 'unread_count') {\n const count = readUnreadCountEvent(event.data);\n return count === undefined\n ? undefined\n : { type: NotificationUpdateType.UnreadCount, data: count };\n }\n\n return { type: NotificationUpdateType.Unknown, name: event.name, data: event.data };\n}\n\n/** Проверяет объектный или краткий фильтр уведомления. */\nexport function matchesNotification<T extends NotificationType>(\n context: NotificationContext,\n selector: NotificationEventSelector<T>,\n): context is NotificationContext<T> {\n const notification = context.update.data.notification;\n\n if (typeof selector === 'string') return notification.type === selector;\n if (Array.isArray(selector)) return selector.includes(notification.type as T);\n\n const filter = selector as NotificationEventFilter<T>;\n const types = filter.type === undefined ? undefined : [filter.type].flat();\n\n if (types && !types.includes(notification.type as T)) return false;\n if (\n filter.actorId !== undefined &&\n !notification.actors.some(({ id }) => id === filter.actorId)\n ) {\n return false;\n }\n if (filter.entityId !== undefined && notification.entityId !== filter.entityId) return false;\n if (\n filter.parentEntityId !== undefined &&\n notification.parentEntityId !== filter.parentEntityId\n ) {\n return false;\n }\n\n return filter.predicate?.(context as NotificationContext<T>) ?? true;\n}\n\n/** Сужает произвольный контекст потока до контекста уведомления. */\nexport function isNotificationContext(\n context: NotificationEventContext,\n): context is NotificationContext {\n return context.update.type === NotificationUpdateType.Notification;\n}\n","import type { AuthIdentity } from '../core/auth-provider.js';\nimport type { ItdClock } from '../core/clock.js';\nimport type { ClientConnection } from '../core/connection.js';\nimport type { Listener, Unsubscribe } from '../core/emitter.js';\nimport { ItdConfigError } from '../core/errors.js';\nimport type { Logger } from '../core/options.js';\nimport { supportsStreamingBody } from '../core/runtime.js';\nimport { pickString } from '../core/unwrap.js';\nimport type { NotificationEvent } from '../notifications/normalize.js';\nimport type { EventChannelStatus, NotificationType } from '../types/enums.js';\nimport {\n EventChannel,\n type EventChannelEvents,\n type EventSyncReason,\n resolveEventChannelOptions,\n setEventChannelGiveUpHook,\n} from './engine.js';\nimport type {\n EventHandler,\n EventMiddleware,\n EventMiddlewareObject,\n EventPredicate,\n EventSequentializer,\n EventTypeGuard,\n} from './middleware.js';\nimport type { ReconnectOptions } from './reconnect.js';\nimport { PollTransport } from './transports/poll.js';\nimport { SseTransport } from './transports/sse.js';\nimport type { EventRequest, EventTransport, EventTransportFrame } from './transports/transport.js';\nimport {\n isNotificationContext,\n matchesNotification,\n type NotificationContext,\n type NotificationEventContext,\n type NotificationEventSelector,\n type NotificationEventsUpdate,\n type NotificationUpdateOfType,\n NotificationUpdateOrigin,\n NotificationUpdateType,\n readNotificationEventsUpdate,\n validateNotificationSelector,\n} from './updates.js';\n\n/**\n * События потока уведомлений.\n *\n * Общая часть — {@link EventChannelEvents}: статусы, ошибки и переподключение одинаковы\n * у любого потока. Ниже — то, что есть только у уведомлений.\n */\nexport interface NotificationEventsMap<\n C extends NotificationEventContext = NotificationEventContext,\n> extends EventChannelEvents<C> {\n /** Пришло новое уведомление. */\n notification: NotificationEvent;\n /**\n * Сервер подтвердил подключение и назвал получателя событий.\n *\n * Приходит первым кадром сразу после установки соединения.\n */\n ready: { userId: string | undefined };\n /**\n * Получено актуальное число непрочитанных.\n *\n * При подключении клиент может запросить начальное значение через REST. Затем событие\n * возникает, только если счётчик пришёл в потоке. В остальных случаях обновляйте его\n * в приложении либо запрашивайте `itd.notifications.count()`.\n */\n unreadCount: number;\n}\n\n/** Способ получения событий. */\nexport const NotificationEventsTransport = Object.freeze({\n /** Поток событий, если среда умеет читать тело по частям, иначе опрос. */\n Auto: 'auto',\n /** Поток `text/event-stream`. */\n Sse: 'sse',\n /** Периодический опрос REST. */\n Poll: 'poll',\n} as const);\nexport type NotificationEventsTransport =\n (typeof NotificationEventsTransport)[keyof typeof NotificationEventsTransport];\n\n/** Настройки потока уведомлений. */\nexport interface NotificationEventsOptions<\n C extends NotificationEventContext = NotificationEventContext,\n> extends ReconnectOptions {\n /**\n * Транспорт. По умолчанию `auto`: поток событий, если среда умеет читать тело ответа\n * по частям, иначе опрос.\n *\n * Можно передать и свою реализацию {@link EventTransport} — это пригодится, если\n * у платформы появится WebSocket либо нужен нестандартный способ доставки.\n */\n transport?: NotificationEventsTransport | EventTransport;\n /**\n * Молчание сервера, после которого соединение считается мёртвым, мс. По умолчанию 90 000.\n *\n * Сервер не присылает keep-alive, поэтому без этой проверки оборванное соединение\n * может незаметно «зависнуть».\n */\n idleTimeout?: number;\n /**\n * Сколько ждать ответа на запрос потока, прежде чем оборвать попытку, мс. По умолчанию\n * 20 000. Защищает от зависания на установке соединения, когда {@link idleTimeout} ещё\n * не действует. `0` отключает проверку. Только для потокового транспорта.\n */\n handshakeTimeout?: number;\n /** Как часто опрашивать сервер, если используется запасной транспорт. */\n pollInterval?: number;\n /**\n * Запрашивать число непрочитанных при подключении. По умолчанию `true`.\n *\n * Так поступает сайт итд.com: поток присылает только новые события, а начальное\n * значение счётчика нужно получить отдельно.\n */\n syncCount?: boolean;\n /**\n * Переподключаться, когда вкладка снова становится видимой. По умолчанию `true`.\n *\n * Только в браузере. У сайта итд.com такой обработки нет, из-за чего вкладка,\n * пролежавшая в фоне, может остаться без соединения.\n */\n reconnectOnVisible?: boolean;\n /** Переподключаться при восстановлении сети. По умолчанию `true`. Только в браузере. */\n reconnectOnOnline?: boolean;\n /** Максимальное число одновременно обрабатываемых обновлений. По умолчанию 1. */\n concurrency?: number;\n /** Возвращает ключи обновлений, которые нельзя обрабатывать одновременно. */\n sequentialize?: EventSequentializer<C>;\n}\n\n/** Проверяет настройки потока. @throws {ItdConfigError} при некорректных значениях */\nexport function resolveNotificationEventsOptions<C extends NotificationEventContext>(\n options: NotificationEventsOptions<C> = {},\n): Readonly<NotificationEventsOptions<C>> {\n resolveEventChannelOptions(options);\n const duration = (value: number | undefined, name: string, min: number): void => {\n if (value === undefined) return;\n if (!Number.isFinite(value) || value < min) {\n throw new ItdConfigError(\n `events.notifications.${name} должен быть числом не меньше ${min}, получено: ${value}`,\n );\n }\n };\n\n duration(options.pollInterval, 'pollInterval', 1);\n duration(options.idleTimeout, 'idleTimeout', 0);\n duration(options.handshakeTimeout, 'handshakeTimeout', 0);\n return Object.freeze({\n ...options,\n ...(options.backoff ? { backoff: Object.freeze([...options.backoff]) } : {}),\n });\n}\n\n/** Что поток получает от клиента. */\nexport interface NotificationEventsDeps {\n connection: ClientConnection;\n /** Конвейер клиента — см. {@link EventTransportContext.request}. */\n request?: EventRequest | undefined;\n clock?: ItdClock;\n /** Идентификаторы аккаунта и сессии создавшего поток клиента. */\n getAuthIdentity?: (() => AuthIdentity) | undefined;\n /** Непрозрачная область авторизации создавшего поток клиента. */\n getAuthScope?: (() => string) | undefined;\n /** Загружает начальное число непрочитанных. */\n fetchUnreadCount: (signal: AbortSignal) => Promise<number>;\n /** Вызывается при явном закрытии потока. */\n onClose?: (() => void) | undefined;\n /** Вызывается при запуске ранее закрытого потока. */\n onConnect?: (() => void) | undefined;\n logger?: Logger | undefined;\n}\n\nconst EVENT_CONNECT_GUARDS = new WeakMap<object, () => void>();\n\n/** Регистрирует проверку состояния создавшего поток клиента. @internal */\nexport function setNotificationEventsConnectGuard<C extends NotificationEventContext>(\n stream: NotificationEvents<C>,\n guard: () => void,\n): void {\n EVENT_CONNECT_GUARDS.set(stream, guard);\n}\n\n/**\n * Поток уведомлений в реальном времени.\n *\n * Доступен как стабильное свойство `itd.notifications.events`. Соединение поднимается методом {@link connect}\n * и держится само: обрывы, обновление токена и повторные попытки библиотека берёт на себя.\n *\n * Параметр типа задаёт форму контекста: плагин может расширить её своими полями\n * (`NotificationEvents<NotificationEventContext & SessionFlavor<S>>`) и типизировать обработчики.\n *\n * @example\n * ```ts\n * import { NotificationType } from 'itd-api';\n *\n * const stream = itd.notifications.events;\n *\n * stream.onNotification(NotificationType.PostComment, async ({ update }) => {\n * await saveCommentNotification(update.data.notification);\n * });\n * stream.on('status', (status) => console.log('соединение:', status));\n *\n * await stream.connect();\n * // …позже\n * stream.disconnect();\n * await stream.drain();\n * ```\n */\nexport class NotificationEvents<C extends NotificationEventContext = NotificationEventContext> {\n readonly #deps: NotificationEventsDeps;\n readonly #engine: EventChannel<\n NotificationEventsUpdate,\n C,\n NotificationEventsMap<C>,\n NotificationUpdateOrigin\n >;\n #lifecycleActive = false;\n\n /** @internal */\n constructor(deps: NotificationEventsDeps, options: NotificationEventsOptions<C> = {}) {\n options = resolveNotificationEventsOptions(options);\n\n this.#deps = deps;\n this.#engine = new EventChannel<\n NotificationEventsUpdate,\n C,\n NotificationEventsMap<C>,\n NotificationUpdateOrigin\n >(\n {\n connection: deps.connection,\n clock: deps.clock,\n logger: deps.logger,\n\n transport: createTransport(deps, options),\n streamOrigin: NotificationUpdateOrigin.Stream,\n handleFrame: (event) => this.#handleFrame(event),\n readUpdate: readNotificationEventsUpdate,\n coalesceKey: (update) =>\n update.type === NotificationUpdateType.UnreadCount ? update.type : undefined,\n createContext: (update, raw, origin) =>\n // Дополнительные поля позже добавляют плагины в своих обработчиках.\n ({ update, stream: this, raw, origin }) as unknown as C,\n deliver: (update) => this.#deliver(update),\n ...(options.syncCount === false\n ? {}\n : {\n initialize: (reason: EventSyncReason, session) =>\n this.#syncUnreadCount(reason, session.signal, (update) =>\n session.enqueue(update, { origin: NotificationUpdateOrigin.Sync }),\n ),\n }),\n },\n options,\n );\n setEventChannelGiveUpHook(this.#engine, () => this.#closeLifecycle());\n }\n\n /** Текущее состояние соединения. */\n get status(): EventChannelStatus {\n return this.#engine.status;\n }\n\n /** Имя используемого транспорта. */\n get transport(): string {\n return this.#engine.transport;\n }\n\n /** Базовый URL клиента, создавшего поток. @internal */\n get baseUrl(): string {\n return this.#deps.connection.baseUrl;\n }\n\n /** Идентификаторы аккаунта и сессии клиента, создавшего поток. @internal */\n getAuthIdentity(): AuthIdentity | undefined {\n return this.#deps.getAuthIdentity?.();\n }\n\n /** Непрозрачная область авторизации создавшего поток клиента. @internal */\n getAuthScope(): string | undefined {\n return this.#deps.getAuthScope?.();\n }\n\n /** Подписывается на событие потока. @returns функция отписки */\n on<K extends keyof NotificationEventsMap<C>>(\n event: K,\n listener: Listener<NotificationEventsMap<C>[K]>,\n ): Unsubscribe {\n return this.#engine.on(event, listener);\n }\n\n /** Подписывается на одно срабатывание. */\n once<K extends keyof NotificationEventsMap<C>>(\n event: K,\n listener: Listener<NotificationEventsMap<C>[K]>,\n ): Unsubscribe {\n return this.#engine.once(event, listener);\n }\n\n /**\n * Добавляет промежуточный обработчик или объект, предоставляющий его через `middleware()`.\n *\n * Обработчики выполняются в порядке регистрации. Если `next()` не вызван, обновление не\n * передаётся дальше по цепочке, асинхронным обработчикам и слушателям событий.\n *\n * @returns функция удаления обработчика\n */\n use(middleware: EventMiddleware<C> | EventMiddlewareObject<C>): Unsubscribe {\n return this.#engine.use(middleware);\n }\n\n /** Подписывает асинхронный обработчик на все нормализованные обновления. */\n onUpdate(handler: EventHandler<C>): Unsubscribe;\n /** Подписывает асинхронный обработчик на обновление указанного типа. */\n onUpdate<T extends NotificationUpdateType>(\n type: T,\n handler: EventHandler<C & NotificationEventContext<NotificationUpdateOfType<T>>>,\n ): Unsubscribe;\n /** Подписывает асинхронный обработчик по функции сужения типа. */\n onUpdate<N extends C>(guard: EventTypeGuard<N, C>, handler: EventHandler<N>): Unsubscribe;\n /** Подписывает асинхронный обработчик по пользовательскому условию. */\n onUpdate(predicate: EventPredicate<C>, handler: EventHandler<C>): Unsubscribe;\n onUpdate(\n selectorOrHandler: NotificationUpdateType | EventPredicate<C> | EventHandler<C>,\n selectedHandler?: EventHandler<C>,\n ): Unsubscribe {\n const selectAll = selectedHandler === undefined;\n const handler = selectAll ? (selectorOrHandler as EventHandler<C>) : selectedHandler;\n if (typeof handler !== 'function') {\n throw new ItdConfigError('events.onUpdate() принимает функцию обработчика');\n }\n if (\n !selectAll &&\n typeof selectorOrHandler !== 'function' &&\n !Object.values(NotificationUpdateType).includes(selectorOrHandler)\n ) {\n throw new ItdConfigError(`Неизвестный тип обновления потока: ${String(selectorOrHandler)}`);\n }\n\n let predicate: EventPredicate<C>;\n if (selectAll) {\n predicate = () => true;\n } else {\n const selector = selectorOrHandler as NotificationUpdateType | EventPredicate<C>;\n predicate =\n typeof selector === 'function' ? selector : (context) => context.update.type === selector;\n }\n\n return this.#engine.onUpdate(predicate, handler);\n }\n\n /** Подписывает асинхронный обработчик на уведомления, подходящие под фильтр. */\n onNotification<T extends NotificationType>(\n selector: NotificationEventSelector<T>,\n handler: EventHandler<C & NotificationContext<T>>,\n ): Unsubscribe;\n /** Подписывает асинхронный обработчик по функции сужения типа уведомления. */\n onNotification<N extends C & NotificationContext>(\n guard: (context: C & NotificationContext) => context is N,\n handler: EventHandler<N>,\n ): Unsubscribe;\n /** Подписывает асинхронный обработчик по пользовательскому условию. */\n onNotification(\n predicate: (context: C & NotificationContext) => boolean,\n handler: EventHandler<C & NotificationContext>,\n ): Unsubscribe;\n onNotification(\n selector: NotificationEventSelector | ((context: C & NotificationContext) => boolean),\n handler: (context: never) => unknown | Promise<unknown>,\n ): Unsubscribe {\n if (typeof handler !== 'function') {\n throw new ItdConfigError('events.onNotification() принимает функцию обработчика');\n }\n if (typeof selector !== 'function') validateNotificationSelector(selector);\n\n const predicate: EventPredicate<C> = (context) => {\n if (!isNotificationContext(context)) return false;\n return typeof selector === 'function'\n ? selector(context)\n : matchesNotification(context, selector);\n };\n\n return this.#engine.onUpdate(predicate, handler as EventHandler<C>);\n }\n\n /**\n * Поднимает соединение.\n *\n * Повторный вызов при уже живом соединении ничего не делает — это защита от двойного\n * подключения при перерисовке интерфейса.\n *\n * Возвращает управление сразу после запуска: соединение живёт в фоне.\n *\n * @throws если создавший поток клиент уже освобождён\n */\n async connect(): Promise<void> {\n EVENT_CONNECT_GUARDS.get(this)?.();\n if (this.#lifecycleActive) return this.#engine.connect();\n\n this.#lifecycleActive = true;\n try {\n this.#deps.onConnect?.();\n await this.#engine.connect();\n } catch (error) {\n this.#closeLifecycle();\n throw error;\n }\n }\n\n /** Закрывает соединение и отменяет запланированные попытки. */\n disconnect(): void {\n this.#engine.disconnect();\n this.#closeLifecycle();\n }\n\n /** Ждёт завершения принятых обновлений и освобождения ресурсов остановленной сессии. */\n drain(): Promise<void> {\n return this.#engine.drain();\n }\n\n /** Снимает подписки `on()` и `once()`. Остальные обработчики остаются. */\n removeAllListeners(): void {\n this.#engine.removeAllListeners();\n }\n\n #closeLifecycle(): void {\n if (!this.#lifecycleActive) return;\n this.#lifecycleActive = false;\n this.#deps.onClose?.();\n }\n\n /** Кадр `connected` — не обновление, а подтверждение подключения. */\n #handleFrame(event: EventTransportFrame): boolean {\n if (event.name !== 'connected') return false;\n\n // Строго строка: `String(null)` дал бы подписчику осмысленно выглядящее «null».\n this.#engine.emit('ready', { userId: pickString(event.data, 'userId') });\n return true;\n }\n\n /**\n * Загружает начальное число непрочитанных.\n *\n * Только при первом подключении: поток присылает счётчик сам, а лишний запрос\n * на каждой попытке переподключения нагружал бы сервер во время недоступности сети.\n */\n async #syncUnreadCount(\n reason: EventSyncReason,\n signal: AbortSignal,\n dispatch: (update: NotificationEventsUpdate) => void,\n ): Promise<void> {\n if (reason !== 'initial') return;\n\n const count = await this.#deps.fetchUnreadCount(signal);\n dispatch({ type: NotificationUpdateType.UnreadCount, data: count });\n }\n\n #deliver(update: NotificationEventsUpdate): void {\n if (update.type === NotificationUpdateType.Notification) {\n this.#engine.emit('notification', update.data);\n if (update.data.unreadCount !== undefined) {\n this.#engine.emit('unreadCount', update.data.unreadCount);\n }\n return;\n }\n\n if (update.type === NotificationUpdateType.UnreadCount) {\n this.#engine.emit('unreadCount', update.data);\n return;\n }\n\n if (update.type === NotificationUpdateType.Unknown) return;\n\n assertNeverUpdate(update);\n }\n}\n\n/** Выбирает транспорт по настройкам и возможностям среды. */\nfunction createTransport<C extends NotificationEventContext>(\n deps: NotificationEventsDeps,\n options: NotificationEventsOptions<C>,\n): EventTransport {\n const kind = options.transport ?? NotificationEventsTransport.Auto;\n\n if (typeof kind === 'object') return kind;\n\n if (\n kind === NotificationEventsTransport.Poll ||\n (kind === NotificationEventsTransport.Auto && !supportsStreamingBody())\n ) {\n if (!deps.request) {\n throw new ItdConfigError('Poll transport requires a notification request adapter');\n }\n return new PollTransport({\n request: deps.request,\n ...(deps.clock ? { clock: deps.clock } : {}),\n ...(options.pollInterval !== undefined ? { interval: options.pollInterval } : {}),\n });\n }\n\n return new SseTransport({\n ...(deps.clock ? { clock: deps.clock } : {}),\n ...(options.idleTimeout !== undefined ? { idleTimeout: options.idleTimeout } : {}),\n ...(options.handshakeTimeout !== undefined\n ? { handshakeTimeout: options.handshakeTimeout }\n : {}),\n });\n}\n\nfunction assertNeverUpdate(update: never): never {\n throw new TypeError(`Необработанное обновление потока: ${String(update)}`);\n}\n","import { passthroughOperation } from './common.js';\n\n/** Контракты HTTP-запросов событийного канала. */\nexport const EVENT_OPERATIONS = Object.freeze({\n 'events.notifications.poll.updates': passthroughOperation<unknown>(\n 'events.notifications.poll.updates',\n ),\n 'events.notifications.poll.unread': passthroughOperation<unknown>(\n 'events.notifications.poll.unread',\n ),\n});\n","import { type ItdClock, systemClock } from '../../core/clock.js';\nimport { ItdConfigError } from '../../core/errors.js';\nimport { maskSecret, redactUrl } from '../../core/redact.js';\nimport { buildQuery, joinUrl } from '../../core/url.js';\nimport {\n type EventTransport,\n type EventTransportContext,\n UnauthorizedStreamError,\n} from './transport.js';\n\n/** Стандартный путь WebSocket-подключения. */\nexport const WEBSOCKET_PATH = '/api/ws';\n\n/** Предел кадров, ожидающих разбора. Переполнение закрывает соединение. @internal */\nexport const MAX_PENDING_FRAMES = 256;\n\n/** Дополнительные параметры конструктора, поддерживаемые Node-реализациями вроде `ws`. */\nexport interface WebSocketImplementationOptions {\n headers?: Record<string, string> | undefined;\n handshakeTimeout?: number | undefined;\n}\n\n/** Конструктор WebSocket, который можно передать вместо глобальной реализации. */\nexport interface WebSocketLike {\n new (\n url: string | URL,\n protocols?: string | string[],\n options?: WebSocketImplementationOptions,\n ): unknown;\n}\n\n/** Определяет, был ли отказ до открытия сокета вызван недействительным токеном. */\nexport type WebSocketOpenFailureClassifier = (\n error: unknown,\n signal: AbortSignal,\n) => boolean | Promise<boolean>;\n\n/** Настройки WebSocket-транспорта. */\nexport interface WebSocketTransportOptions {\n /** Путь апгрейда. По умолчанию `/api/ws`. */\n path?: string | undefined;\n /** Реализация WebSocket для сред без глобальной либо для передачи заголовков апгрейда. */\n webSocketImpl?: WebSocketLike | undefined;\n /** Способ передачи токена. `auto` выбирает заголовок при инъекции и query иначе. */\n auth?: 'query' | 'header' | 'auto' | undefined;\n /** Молчание открытого соединения до переподключения, мс. По умолчанию 90 000. */\n idleTimeout?: number | undefined;\n /** Период текстового `ping`, мс. По умолчанию 30 000. */\n keepAlive?: number | undefined;\n /** Максимальное время установки соединения, мс. По умолчанию 20 000. */\n handshakeTimeout?: number | undefined;\n /**\n * Проверяет отказ до `open`, когда среда скрыла HTTP-статус WebSocket-upgrade.\n * `true` преобразует отказ в {@link UnauthorizedStreamError}.\n */\n classifyOpenFailure?: WebSocketOpenFailureClassifier | undefined;\n /** Часы транспорта. Обычно подменяются только в тестах. */\n clock?: ItdClock | undefined;\n}\n\ninterface SocketMessageEvent {\n readonly data: unknown;\n}\n\ninterface SocketCloseEvent {\n readonly code?: unknown;\n readonly reason?: unknown;\n readonly wasClean?: unknown;\n}\n\ninterface WebSocketConnection {\n readonly readyState: number;\n binaryType?: string;\n addEventListener(type: string, listener: (event: unknown) => void): void;\n removeEventListener(type: string, listener: (event: unknown) => void): void;\n send(data: string): void;\n close(code?: number, reason?: string): void;\n}\n\nconst CONNECTING = 0;\nconst OPEN = 1;\nconst NORMAL_CLOSURE = 1000;\nconst UNAUTHORIZED_CLOSE_CODES = new Set([1008, 4401]);\n\nfunction validateDuration(value: number | undefined, name: string): void {\n if (value !== undefined && (!Number.isFinite(value) || value < 0)) {\n throw new ItdConfigError(\n `WebSocketTransport.${name} должен быть числом не меньше 0, получено: ${value}`,\n );\n }\n}\n\nfunction isWebSocketConnection(value: unknown): value is WebSocketConnection {\n if (typeof value !== 'object' || value === null) return false;\n const socket = value as Partial<WebSocketConnection>;\n return (\n typeof socket.readyState === 'number' &&\n typeof socket.addEventListener === 'function' &&\n typeof socket.removeEventListener === 'function' &&\n typeof socket.send === 'function' &&\n typeof socket.close === 'function'\n );\n}\n\nfunction abortError(signal: AbortSignal): unknown {\n if (signal.reason !== undefined) return signal.reason;\n const error = new Error('WebSocket-подключение отменено');\n error.name = 'AbortError';\n return error;\n}\n\nfunction errorMessage(error: unknown): string | undefined {\n if (error instanceof Error && error.message) return error.message;\n if (typeof error === 'object' && error !== null && 'message' in error) {\n const message = (error as { message?: unknown }).message;\n if (typeof message === 'string' && message) return message;\n }\n return undefined;\n}\n\nfunction safeDetail(error: unknown, url: string, token: string | null): string | undefined {\n const message = errorMessage(error);\n if (!message) return undefined;\n const safe = message.replaceAll(url, redactUrl(url));\n return token ? safe.replaceAll(token, maskSecret(token)) : safe;\n}\n\nfunction readCloseEvent(event: unknown): { code: number; reason: string; wasClean: boolean } {\n const close =\n typeof event === 'object' && event !== null ? (event as SocketCloseEvent) : undefined;\n return {\n code: typeof close?.code === 'number' ? close.code : 1006,\n reason: typeof close?.reason === 'string' ? close.reason : '',\n wasClean: close?.wasClean === true,\n };\n}\n\nfunction readMessage(event: unknown): string | Promise<string> | undefined {\n const data =\n typeof event === 'object' && event !== null && 'data' in event\n ? (event as SocketMessageEvent).data\n : undefined;\n\n if (typeof data === 'string') return data;\n if (data instanceof ArrayBuffer) return new TextDecoder().decode(data);\n if (ArrayBuffer.isView(data)) {\n return new TextDecoder().decode(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));\n }\n if (typeof Blob !== 'undefined' && data instanceof Blob) return data.text();\n return undefined;\n}\n\nfunction eventName(data: unknown): string {\n return typeof data === 'object' && data !== null && 'type' in data\n ? String((data as { type: unknown }).type)\n : 'message';\n}\n\n/** Транспорт исходных событий поверх стандартного WebSocket. */\nexport class WebSocketTransport implements EventTransport {\n readonly name = 'ws';\n\n readonly #path: string;\n readonly #webSocketImpl: WebSocketLike | undefined;\n readonly #auth: 'query' | 'header' | 'auto';\n readonly #idleTimeout: number;\n readonly #keepAlive: number;\n readonly #handshakeTimeout: number;\n readonly #classifyOpenFailure: WebSocketOpenFailureClassifier | undefined;\n readonly #clock: ItdClock;\n\n constructor(options: WebSocketTransportOptions = {}) {\n const path = options.path ?? WEBSOCKET_PATH;\n if (\n typeof path !== 'string' ||\n path.trim() === '' ||\n path.includes('?') ||\n path.includes('#') ||\n /^[a-z][a-z\\d+.-]*:/i.test(path)\n ) {\n throw new ItdConfigError('WebSocketTransport.path должен быть путём без query и fragment');\n }\n if (options.webSocketImpl !== undefined && typeof options.webSocketImpl !== 'function') {\n throw new ItdConfigError('WebSocketTransport.webSocketImpl должен быть конструктором');\n }\n if (\n options.classifyOpenFailure !== undefined &&\n typeof options.classifyOpenFailure !== 'function'\n ) {\n throw new ItdConfigError('WebSocketTransport.classifyOpenFailure должен быть функцией');\n }\n\n const auth = options.auth ?? 'auto';\n if (auth !== 'auto' && auth !== 'query' && auth !== 'header') {\n throw new ItdConfigError(`Неизвестный способ авторизации WebSocket: ${String(auth)}`);\n }\n if (auth === 'header' && !options.webSocketImpl) {\n throw new ItdConfigError(\n 'WebSocketTransport.auth=\"header\" требует webSocketImpl с поддержкой заголовков',\n );\n }\n\n validateDuration(options.idleTimeout, 'idleTimeout');\n validateDuration(options.keepAlive, 'keepAlive');\n validateDuration(options.handshakeTimeout, 'handshakeTimeout');\n\n this.#path = path;\n this.#webSocketImpl = options.webSocketImpl;\n this.#auth = auth;\n this.#idleTimeout = options.idleTimeout ?? 90_000;\n this.#keepAlive = options.keepAlive ?? 30_000;\n this.#handshakeTimeout = options.handshakeTimeout ?? 20_000;\n this.#classifyOpenFailure = options.classifyOpenFailure;\n this.#clock = options.clock ?? systemClock;\n }\n\n async connect(context: EventTransportContext): Promise<void> {\n if (context.signal.aborted) throw abortError(context.signal);\n\n const token = context.authorize ? await context.getToken() : null;\n if (context.signal.aborted) throw abortError(context.signal);\n if (context.authorize && !token) throw new UnauthorizedStreamError();\n\n const injected = this.#webSocketImpl !== undefined;\n const implementation = this.#webSocketImpl ?? this.#globalImplementation();\n const auth = this.#auth === 'auto' ? (injected ? 'header' : 'query') : this.#auth;\n const { requestUrl, socketUrl } = this.#urls(context.baseUrl);\n const url = auth === 'query' && token ? `${socketUrl}${buildQuery({ token })}` : socketUrl;\n\n let headers: Record<string, string> | undefined;\n if (injected) {\n const resolved = await context.baseHeaders(requestUrl);\n if (context.signal.aborted) throw abortError(context.signal);\n if (auth === 'header' && token) resolved.set('Authorization', `Bearer ${token}`);\n headers = Object.fromEntries(resolved.entries());\n }\n\n let value: unknown;\n try {\n value = injected\n ? new implementation(url, [], {\n ...(headers ? { headers } : {}),\n ...(this.#handshakeTimeout > 0 ? { handshakeTimeout: this.#handshakeTimeout } : {}),\n })\n : new implementation(url);\n } catch (error) {\n const detail = safeDetail(error, url, token);\n throw new Error(\n `Не удалось создать WebSocket ${redactUrl(url)}${detail ? `: ${detail}` : ''}`,\n );\n }\n\n if (!isWebSocketConnection(value)) {\n throw new ItdConfigError(\n 'webSocketImpl вернул объект без WebSocket-методов addEventListener, send и close',\n );\n }\n\n try {\n value.binaryType = 'arraybuffer';\n } catch {\n // Не все совместимые реализации позволяют менять способ выдачи бинарных кадров.\n }\n\n return this.#listen(value, url, token, context);\n }\n\n #globalImplementation(): WebSocketLike {\n const implementation = Reflect.get(globalThis, 'WebSocket');\n if (typeof implementation !== 'function') {\n throw new ItdConfigError(\n 'В этой среде нет WebSocket: передайте реализацию через webSocketImpl',\n );\n }\n return implementation as WebSocketLike;\n }\n\n #urls(baseUrl: string): { requestUrl: string; socketUrl: string } {\n const request = new URL(joinUrl(baseUrl, this.#path));\n const socket = new URL(request);\n if (request.protocol === 'https:') socket.protocol = 'wss:';\n else if (request.protocol === 'http:') socket.protocol = 'ws:';\n else {\n throw new ItdConfigError(\n `WebSocketTransport требует baseUrl с http или https, получено: ${request.protocol}`,\n );\n }\n return { requestUrl: request.toString(), socketUrl: socket.toString() };\n }\n\n #listen(\n socket: WebSocketConnection,\n url: string,\n token: string | null,\n context: EventTransportContext,\n ): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n let settled = false;\n let finishing = false;\n let opened = false;\n let discardMessages = false;\n let socketError: unknown;\n let messageQueue = Promise.resolve();\n let pendingFrames = 0;\n let cancelHandshake: (() => void) | undefined;\n let cancelIdle: (() => void) | undefined;\n let cancelKeepAlive: (() => void) | undefined;\n\n const stopSocketListeners = () => {\n cancelHandshake?.();\n cancelIdle?.();\n cancelKeepAlive?.();\n cancelHandshake = undefined;\n cancelIdle = undefined;\n cancelKeepAlive = undefined;\n socket.removeEventListener('open', onOpen);\n socket.removeEventListener('message', onMessage);\n socket.removeEventListener('error', onError);\n socket.removeEventListener('close', onClose);\n };\n\n const finish = (error?: unknown) => {\n if (settled) return;\n settled = true;\n stopSocketListeners();\n context.signal.removeEventListener('abort', onAbort);\n if (error !== undefined) reject(error);\n else resolve();\n };\n\n const closeWithError = (error: unknown, code = 4000, reason = 'transport error') => {\n if (settled || finishing) return;\n socketError = error;\n finishing = true;\n stopSocketListeners();\n try {\n if (socket.readyState === CONNECTING || socket.readyState === OPEN) {\n socket.close(code, reason);\n }\n } catch {\n // Ошибка уже сохранена и будет возвращена вызывающему коду.\n }\n void messageQueue.then(\n () => finish(error),\n (queueError: unknown) => finish(queueError),\n );\n };\n\n const armIdleTimer = () => {\n cancelIdle?.();\n if (this.#idleTimeout <= 0) return;\n cancelIdle = this.#clock.schedule(() => {\n closeWithError(\n new Error(`WebSocket ${redactUrl(url)} молчит дольше допустимого`),\n 4000,\n 'idle timeout',\n );\n }, this.#idleTimeout);\n };\n\n const scheduleKeepAlive = () => {\n if (this.#keepAlive <= 0 || settled || finishing) return;\n cancelKeepAlive = this.#clock.schedule(() => {\n if (settled || finishing || socket.readyState !== OPEN) return;\n try {\n socket.send('ping');\n } catch (error) {\n const detail = safeDetail(error, url, token);\n closeWithError(\n new Error(\n `Не удалось отправить WebSocket ping ${redactUrl(url)}` +\n (detail ? `: ${detail}` : ''),\n ),\n );\n return;\n }\n scheduleKeepAlive();\n }, this.#keepAlive);\n };\n\n const onOpen = () => {\n if (settled || finishing || opened) return;\n opened = true;\n cancelHandshake?.();\n cancelHandshake = undefined;\n armIdleTimer();\n scheduleKeepAlive();\n try {\n context.onOpen();\n } catch (error) {\n closeWithError(error);\n }\n };\n\n const onMessage = (event: unknown) => {\n if (settled || finishing) return;\n armIdleTimer();\n let pending: Promise<{ readonly raw: string } | { readonly error: unknown }> | undefined;\n try {\n const raw = readMessage(event);\n if (raw !== undefined) {\n pending = Promise.resolve(raw).then(\n (value) => ({ raw: value }),\n (error: unknown) => ({ error }),\n );\n }\n } catch (error) {\n pending = Promise.resolve({ error });\n }\n if (pending === undefined) return;\n\n if (pendingFrames >= MAX_PENDING_FRAMES) {\n closeWithError(\n new Error(`WebSocket ${redactUrl(url)}: очередь кадров переполнена`),\n 4000,\n 'queue overflow',\n );\n return;\n }\n\n pendingFrames += 1;\n messageQueue = messageQueue\n .then(async () => {\n pendingFrames -= 1;\n if (settled || discardMessages) return;\n\n const decoded = await pending;\n if ('error' in decoded) {\n context.onParseError(decoded.error, '[binary WebSocket frame]');\n return;\n }\n const { raw } = decoded;\n if (settled || discardMessages || raw === 'pong') return;\n\n let data: unknown;\n try {\n data = JSON.parse(raw) as unknown;\n } catch (error) {\n context.onParseError(error, raw);\n return;\n }\n context.onEvent({ name: eventName(data), data });\n })\n .catch((error: unknown) => {\n if (finishing) throw error;\n closeWithError(error);\n });\n };\n\n const onError = (event: unknown) => {\n if (settled || finishing) return;\n socketError =\n typeof event === 'object' && event !== null && 'error' in event\n ? (event as { error?: unknown }).error\n : event;\n };\n\n const finishClose = async (event: unknown): Promise<void> => {\n const { code, reason, wasClean } = readCloseEvent(event);\n let outcome: unknown;\n\n if (context.authorize && UNAUTHORIZED_CLOSE_CODES.has(code)) {\n outcome = new UnauthorizedStreamError();\n } else if (socketError !== undefined) {\n const detail = safeDetail(socketError, url, token);\n outcome = new Error(\n `WebSocket ${redactUrl(url)} завершился ошибкой${detail ? `: ${detail}` : ''}`,\n );\n } else if (opened && code === NORMAL_CLOSURE && wasClean) {\n outcome = undefined;\n } else {\n const safeReason = token ? reason.replaceAll(token, maskSecret(token)) : reason;\n outcome = new Error(\n `WebSocket ${redactUrl(url)} закрыт с кодом ${code}` +\n (safeReason ? `: ${safeReason}` : ''),\n );\n }\n\n if (\n !opened &&\n context.authorize &&\n !(outcome instanceof UnauthorizedStreamError) &&\n this.#classifyOpenFailure\n ) {\n try {\n if (await this.#classifyOpenFailure(outcome, context.signal)) {\n outcome = new UnauthorizedStreamError();\n }\n } catch {\n // Ошибка проверки не должна скрывать исходную ошибку соединения.\n }\n }\n\n if (context.signal.aborted) {\n discardMessages = true;\n finish(abortError(context.signal));\n return;\n }\n\n try {\n await messageQueue;\n finish(outcome);\n } catch (error) {\n finish(error);\n }\n };\n\n const onClose = (event: unknown) => {\n if (settled || finishing) return;\n if (context.signal.aborted) {\n discardMessages = true;\n finish(abortError(context.signal));\n return;\n }\n finishing = true;\n stopSocketListeners();\n void finishClose(event);\n };\n\n const onAbort = () => {\n if (settled) return;\n const error = abortError(context.signal);\n discardMessages = true;\n finishing = true;\n stopSocketListeners();\n try {\n if (socket.readyState === CONNECTING || socket.readyState === OPEN) {\n socket.close(NORMAL_CLOSURE, 'aborted');\n }\n } catch {\n // Отмена всё равно завершает connect(), даже если реализация уже закрыла сокет.\n }\n finish(error);\n };\n\n socket.addEventListener('open', onOpen);\n socket.addEventListener('message', onMessage);\n socket.addEventListener('error', onError);\n socket.addEventListener('close', onClose);\n context.signal.addEventListener('abort', onAbort, { once: true });\n\n if (this.#handshakeTimeout > 0) {\n cancelHandshake = this.#clock.schedule(() => {\n closeWithError(\n new Error(`Истёк таймаут установки WebSocket ${redactUrl(url)}`),\n 4000,\n 'handshake timeout',\n );\n }, this.#handshakeTimeout);\n }\n\n if (context.signal.aborted) onAbort();\n });\n }\n}\n","import { installAsyncDisposeFallback } from '../core/async-dispose.js';\nimport { type AuthProvider, anonymousAuth, bearerToken } from '../core/auth-provider.js';\nimport { ItdStateError } from '../core/errors.js';\nimport { type ClientRuntime, createClientRuntime } from '../core/execution/client-runtime.js';\nimport type { RuntimeOptions } from '../core/options.js';\nimport { pickNumber } from '../core/unwrap.js';\nimport { ITD_CATALOG } from '../domain/catalog.js';\nimport { EVENT_OPERATIONS } from '../operations/events.js';\nimport {\n NotificationEvents,\n type NotificationEventsDeps,\n type NotificationEventsOptions,\n setNotificationEventsConnectGuard,\n} from './stream.js';\nimport type { NotificationEventContext } from './updates.js';\n\n/** Опции конструктора {@link NotificationEventsClient}. */\nexport interface NotificationEventsClientOptions<\n C extends NotificationEventContext = NotificationEventContext,\n> extends RuntimeOptions,\n NotificationEventsOptions<C> {\n /**\n * Авторизация. Строка — сокращение для `bearerToken()`.\n *\n * Без неё поток идёт анонимно. Токен считается готовым: продлевать его клиент не умеет,\n * а на отказ авторизации переподключение спрашивает токен заново. Сессия, которая входит\n * по паролю и продлевает себя сама, живёт в полном `ItdClient`.\n */\n auth?: string | AuthProvider | undefined;\n}\n\n/**\n * Поток уведомлений с собственным конвейером запросов.\n *\n * Тот же {@link NotificationEvents}, что доступен как `itd.notifications.events`, но собранный без полного клиента:\n * ресурсы, билдеры и сессия сюда не входят. Нужен приложениям, которым от API нужны только\n * события, — виджетам, счётчикам непрочитанного, фоновым слушателям.\n *\n * @example\n * ```ts\n * import { createNotificationEventsClient } from 'itd-api/events';\n *\n * await using stream = createNotificationEventsClient({ auth: token });\n * stream.on('notification', ({ notification }) => console.log(notification.type));\n * await stream.connect();\n * ```\n */\nexport class NotificationEventsClient<\n C extends NotificationEventContext = NotificationEventContext,\n> extends NotificationEvents<C> {\n readonly #runtime: ClientRuntime;\n /** Общий результат терминальной очистки для идемпотентных повторных вызовов. */\n #disposePromise: Promise<void> | undefined;\n #disposed = false;\n\n constructor(options: NotificationEventsClientOptions<C> = {}) {\n const runtime = createClientRuntime(options, {\n catalog: ITD_CATALOG,\n auth: () => resolveAuthProvider(options.auth),\n });\n\n super(notificationEventsDeps(runtime), options);\n this.#runtime = runtime;\n\n setNotificationEventsConnectGuard<C>(this, () => {\n if (!this.#disposed) return;\n throw new ItdStateError(\n 'Поток уже окончательно освобождён через dispose(); нельзя подключить его снова. ' +\n 'Создайте новый',\n );\n });\n }\n\n /**\n * Окончательно освобождает поток и его конвейер: отключает соединение, дожидается\n * обработчиков и останавливает очередь запросов.\n *\n * Повторные вызовы возвращают тот же результат очистки.\n */\n dispose(): Promise<void> {\n if (this.#disposePromise) return this.#disposePromise;\n this.#disposed = true;\n this.#disposePromise = this.#dispose();\n return this.#disposePromise;\n }\n\n async #dispose(): Promise<void> {\n const errors: unknown[] = [];\n this.disconnect();\n try {\n await this.drain();\n } catch (error) {\n errors.push(error);\n }\n try {\n this.#runtime.close();\n await this.#runtime.dispose();\n } catch (error) {\n errors.push(error);\n }\n if (errors.length > 0) throw new AggregateError(errors, 'Не удалось освободить поток');\n }\n\n /** Позволяет использовать поток с `await using`. */\n [Symbol.asyncDispose](): Promise<void> {\n return this.dispose();\n }\n\n static {\n installAsyncDisposeFallback(NotificationEventsClient);\n }\n}\n\n/** Приводит опцию `auth` к провайдеру конвейера. */\nfunction resolveAuthProvider(auth: NotificationEventsClientOptions['auth']): AuthProvider {\n if (auth === undefined) return anonymousAuth();\n return typeof auth === 'string' ? bearerToken(auth) : auth;\n}\n\n/**\n * Связывает поток с собранным конвейером.\n *\n * Начальный счётчик непрочитанных берётся той же операцией, что и при опросе\n * (`events.notifications.poll.unread`): ресурс уведомлений потоку для этого не нужен.\n */\nfunction notificationEventsDeps(runtime: ClientRuntime): NotificationEventsDeps {\n const request: NonNullable<NotificationEventsDeps['request']> = ({\n operationId,\n path,\n query,\n signal,\n }) => runtime.http.execute(EVENT_OPERATIONS[operationId], { path, query, signal });\n\n return {\n connection: runtime.connection(),\n clock: runtime.config.clock,\n logger: runtime.config.logger,\n request,\n fetchUnreadCount: async (signal) => {\n const payload = await request({\n operationId: 'events.notifications.poll.unread',\n path: '/api/notifications/count',\n signal,\n });\n return pickNumber(payload, 'count', 0);\n },\n };\n}\n\n/**\n * Создаёт поток уведомлений с собственным конвейером. Равнозначно конструктору\n * {@link NotificationEventsClient}.\n */\nexport function createNotificationEventsClient<\n C extends NotificationEventContext = NotificationEventContext,\n>(options: NotificationEventsClientOptions<C> = {}): NotificationEventsClient<C> {\n return new NotificationEventsClient<C>(options);\n}\n","import type { Unsubscribe } from '../core/emitter.js';\nimport { ItdConfigError } from '../core/errors.js';\nimport {\n captureEventMiddleware,\n type EventMiddleware,\n type EventMiddlewareObject,\n runEventMiddleware,\n withEventMiddlewareSnapshot,\n} from './middleware.js';\nimport type { EventContext, NotificationEventContext } from './updates.js';\n\n/** Выбирает маршрут обновления. `undefined` и `null` означают отсутствие маршрута. */\nexport type EventRouteSelector<\n K extends PropertyKey,\n C extends EventContext = NotificationEventContext,\n> = (context: C) => K | null | undefined | Promise<K | null | undefined>;\n\ninterface RouteRegistration<C extends EventContext> {\n readonly middleware: readonly EventMiddleware<C>[];\n}\n\n/**\n * Направляет обновления потока в именованные цепочки промежуточных обработчиков.\n *\n * @example\n * ```ts\n * import { EventRouter, NotificationUpdateType } from 'itd-api/events';\n *\n * const router = new EventRouter((context) => context.update.type);\n * router.route(NotificationUpdateType.Notification, async (context, next) => {\n * if (context.update.type === NotificationUpdateType.Notification) {\n * await handleNotification(context.update.data.notification);\n * }\n * await next();\n * });\n * stream.use(router);\n * ```\n */\nexport class EventRouter<\n K extends PropertyKey = PropertyKey,\n C extends EventContext = NotificationEventContext,\n> implements EventMiddlewareObject<C>\n{\n readonly #selector: EventRouteSelector<K, C>;\n readonly #routes = new Map<K, RouteRegistration<C>[]>();\n readonly #fallback: RouteRegistration<C>[] = [];\n\n constructor(selector: EventRouteSelector<K, C>) {\n if (typeof selector !== 'function') {\n throw new ItdConfigError('EventRouter принимает функцию выбора маршрута');\n }\n this.#selector = selector;\n }\n\n /** Добавляет промежуточные обработчики к маршруту и возвращает функцию их удаления. */\n route(key: K, ...middleware: readonly EventMiddleware<C>[]): Unsubscribe {\n if (!isPropertyKey(key))\n throw new ItdConfigError('Ключ маршрута событий должен быть PropertyKey');\n const registration = this.#registration(middleware);\n const registrations = this.#routes.get(key) ?? [];\n registrations.push(registration);\n this.#routes.set(key, registrations);\n\n return () => {\n const current = this.#routes.get(key);\n if (!current) return;\n const index = current.indexOf(registration);\n if (index >= 0) current.splice(index, 1);\n if (current.length === 0) this.#routes.delete(key);\n };\n }\n\n /** Добавляет промежуточные обработчики для обновлений без зарегистрированного маршрута. */\n otherwise(...middleware: readonly EventMiddleware<C>[]): Unsubscribe {\n const registration = this.#registration(middleware);\n this.#fallback.push(registration);\n\n return () => {\n const index = this.#fallback.indexOf(registration);\n if (index >= 0) this.#fallback.splice(index, 1);\n };\n }\n\n /** Возвращает снимок маршрутов для `stream.use(router)` или ручной композиции. */\n middleware(): EventMiddleware<C> {\n const middleware: EventMiddleware<C> = (context, next) =>\n this.#captureMiddleware()(context, next);\n return withEventMiddlewareSnapshot(middleware, () => this.#captureMiddleware());\n }\n\n #captureMiddleware(): EventMiddleware<C> {\n const routes = new Map<K, readonly EventMiddleware<C>[]>();\n for (const [key, registrations] of this.#routes) {\n routes.set(\n key,\n registrations.flatMap(({ middleware }) => middleware).map(captureEventMiddleware),\n );\n }\n const fallback = this.#fallback\n .flatMap(({ middleware }) => middleware)\n .map(captureEventMiddleware);\n\n return async (context, next) => {\n const key = await this.#selector(context);\n if (key != null && !isPropertyKey(key)) {\n throw new ItdConfigError(\n 'Функция выбора маршрута должна возвращать PropertyKey, null или undefined',\n );\n }\n const route = key == null ? undefined : routes.get(key);\n const chain = route && route.length > 0 ? route : fallback;\n\n if (chain.length === 0) {\n await next();\n return;\n }\n\n await runEventMiddleware(chain, context, next);\n };\n }\n\n #registration(middleware: readonly EventMiddleware<C>[]): RouteRegistration<C> {\n if (middleware.length === 0) {\n throw new ItdConfigError('Маршрут должен содержать хотя бы один обработчик');\n }\n for (const item of middleware) {\n if (typeof item !== 'function') {\n throw new ItdConfigError('Маршрут принимает только функции обработки');\n }\n }\n return { middleware: [...middleware] };\n }\n}\n\nfunction isPropertyKey(value: unknown): value is PropertyKey {\n return typeof value === 'string' || typeof value === 'number' || typeof value === 'symbol';\n}\n","import { ItdConfigError } from '../core/errors.js';\nimport {\n captureEventMiddleware,\n deferEventMiddleware,\n type EventMiddleware,\n type EventMiddlewareObject,\n type EventNext,\n type EventTypeGuard,\n runEventMiddleware,\n withEventMiddlewareSnapshot,\n} from './middleware.js';\nimport { EventRouter, type EventRouteSelector } from './router.js';\nimport type { EventContext, NotificationEventContext } from './updates.js';\n\n/** Функция или объект промежуточного обработчика для {@link EventComposer}. */\nexport type EventMiddlewareLike<C extends EventContext = NotificationEventContext> =\n | EventMiddleware<C>\n | EventMiddlewareObject<C>;\n\n/** Один или несколько промежуточных обработчиков ветки. */\nexport type EventMiddlewareGroup<C extends EventContext = NotificationEventContext> =\n | EventMiddlewareLike<C>\n | readonly EventMiddlewareLike<C>[];\n\n/** Синхронное или асинхронное условие ветвления. */\nexport type EventFilter<C extends EventContext = NotificationEventContext> = (\n context: C,\n) => boolean | Promise<boolean>;\n\n/** Ошибка локальной ветки событий вместе с контекстом обрабатываемого обновления. */\nexport interface EventErrorContext<C extends EventContext = NotificationEventContext> {\n /** Исходное исключение обработчика. */\n readonly error: unknown;\n /** Контекст обновления, на котором завершилась ветка. */\n readonly context: C;\n}\n\n/** Обработчик локальной границы ошибок. */\nexport type EventErrorBoundary<C extends EventContext = NotificationEventContext> = (\n failure: EventErrorContext<C>,\n next: EventNext,\n) => unknown | Promise<unknown>;\n\n/** Именованные ветки для `EventComposer.route()`. */\nexport type EventRouteTable<\n K extends string | symbol,\n C extends EventContext = NotificationEventContext,\n> = Partial<Record<K, EventMiddlewareGroup<C>>>;\n\nfunction middlewareFunction<C extends EventContext>(\n middleware: EventMiddlewareLike<C>,\n): EventMiddleware<C> {\n if (typeof middleware === 'function') return middleware;\n if (\n typeof middleware !== 'object' ||\n middleware === null ||\n typeof middleware.middleware !== 'function'\n ) {\n throw new ItdConfigError('EventComposer принимает функцию обработки или объект с middleware()');\n }\n return deferEventMiddleware(middleware);\n}\n\nfunction middlewareGroup<C extends EventContext>(\n group: EventMiddlewareGroup<C>,\n): EventMiddleware<C>[] {\n const middleware = Array.isArray(group) ? group : [group];\n if (middleware.length === 0) {\n throw new ItdConfigError('Ветка EventComposer должна содержать хотя бы один middleware');\n }\n return middleware.map((item) => middlewareFunction(item));\n}\n\ninterface BoundaryContinuation {\n readonly next: EventNext;\n readonly called: () => boolean;\n readonly settled: () => Promise<void>;\n}\n\nfunction boundaryContinuation(): BoundaryContinuation {\n let called = false;\n let duplicate: Promise<void> | undefined;\n\n return {\n next: () => {\n if (!called) {\n called = true;\n return Promise.resolve();\n }\n\n const failure = Promise.reject(\n new Error('next() в обработчике границы ошибок событий вызван повторно'),\n );\n duplicate = Promise.all(duplicate ? [duplicate, failure] : [failure]).then(() => undefined);\n return failure;\n },\n called: () => called,\n settled: async () => {\n await duplicate;\n },\n };\n}\n\nasync function runBoundaryStep(\n run: () => unknown | Promise<unknown>,\n continuation: BoundaryContinuation,\n): Promise<void> {\n let failure: { error: unknown } | undefined;\n try {\n await run();\n } catch (error) {\n failure = { error };\n }\n try {\n await continuation.settled();\n } catch (error) {\n failure ??= { error };\n }\n if (failure) throw failure.error;\n}\n\n/**\n * Собирает переиспользуемую цепочку обработчиков событий.\n *\n * Не открывает соединение. Готовый объект подключается через `stream.use(composer)`.\n * Для каждого обновления используется текущий снимок вложенных обработчиков.\n *\n * @example\n * ```ts\n * const feature = new EventComposer<AppEventContext>();\n * const safe = feature.errorBoundary(reportFeatureError);\n * safe.filter(isPostUpdate).use(handlePost);\n * stream.use(feature);\n * ```\n */\nexport class EventComposer<C extends EventContext = NotificationEventContext>\n implements EventMiddlewareObject<C>\n{\n readonly #middleware: EventMiddleware<C>[] = [];\n\n constructor(...middleware: readonly EventMiddlewareLike<C>[]) {\n this.use(...middleware);\n }\n\n /** Добавляет промежуточные обработчики в конец цепочки. */\n use(...middleware: readonly EventMiddlewareLike<C>[]): this {\n const normalized = middleware.map(middlewareFunction);\n this.#middleware.push(...normalized);\n return this;\n }\n\n /** Создаёт дочернюю ветку для контекста указанного типа. */\n filter<N extends C>(\n predicate: EventTypeGuard<N, C>,\n ...middleware: readonly EventMiddlewareLike<N>[]\n ): EventComposer<N>;\n /** Создаёт дочернюю ветку по синхронному или асинхронному условию. */\n filter(\n predicate: EventFilter<C>,\n ...middleware: readonly EventMiddlewareLike<C>[]\n ): EventComposer<C>;\n filter<N extends C>(\n predicate: EventFilter<C>,\n ...middleware: readonly EventMiddlewareLike<N>[]\n ): EventComposer<N> {\n if (typeof predicate !== 'function') {\n throw new ItdConfigError('EventComposer.filter() принимает функцию условия');\n }\n\n const child = new EventComposer<N>(...middleware);\n const source: EventMiddlewareObject<C> = {\n middleware: () => {\n const nested = captureEventMiddleware(child.middleware());\n return async (context, next) => {\n if (await predicate(context)) await nested(context as N, next);\n else await next();\n };\n },\n };\n this.#middleware.push(deferEventMiddleware(source));\n return child;\n }\n\n /**\n * Направляет контекст в одну именованную ветку.\n *\n * Неизвестный ключ без запасной ветки передаёт обновление следующему обработчику. Для\n * динамической регистрации и числовых ключей используйте {@link EventRouter} напрямую.\n */\n route<K extends string | symbol>(\n selector: EventRouteSelector<K, C>,\n routes: EventRouteTable<K, C>,\n fallback?: EventMiddlewareGroup<C>,\n ): this {\n if (typeof routes !== 'object' || routes === null || Array.isArray(routes)) {\n throw new ItdConfigError('EventComposer.route() принимает объект именованных веток');\n }\n\n const router = new EventRouter<K, C>(selector);\n let registrations = 0;\n for (const key of Reflect.ownKeys(routes)) {\n const group = routes[key as K];\n if (group === undefined) continue;\n router.route(key as K, ...middlewareGroup(group));\n registrations += 1;\n }\n if (fallback !== undefined) {\n router.otherwise(...middlewareGroup(fallback));\n registrations += 1;\n }\n if (registrations === 0) {\n throw new ItdConfigError('EventComposer.route() требует хотя бы одну ветку или fallback');\n }\n\n return this.use(router);\n }\n\n /**\n * Создаёт дочернюю ветку с локальной границей ошибок.\n *\n * Перехватывает ошибки только из дочерней ветки. Вызов `next()` в обработчике ошибки\n * продолжает внешнюю цепочку.\n */\n errorBoundary(\n handler: EventErrorBoundary<C>,\n ...middleware: readonly EventMiddlewareLike<C>[]\n ): EventComposer<C> {\n if (typeof handler !== 'function') {\n throw new ItdConfigError('EventComposer.errorBoundary() принимает обработчик ошибки');\n }\n\n const child = new EventComposer<C>(...middleware);\n const source: EventMiddlewareObject<C> = {\n middleware: () => {\n const nested = captureEventMiddleware(child.middleware());\n return async (context, next) => {\n let continuation = boundaryContinuation();\n try {\n await runBoundaryStep(() => nested(context, continuation.next), continuation);\n } catch (error) {\n continuation = boundaryContinuation();\n await runBoundaryStep(\n () => handler({ error, context }, continuation.next),\n continuation,\n );\n }\n\n if (continuation.called()) await next();\n };\n },\n };\n this.#middleware.push(deferEventMiddleware(source));\n return child;\n }\n\n /** Возвращает промежуточный обработчик для `stream.use()` или вложенной цепочки. */\n middleware(): EventMiddleware<C> {\n const middleware: EventMiddleware<C> = (context, next) =>\n this.#captureMiddleware()(context, next);\n return withEventMiddlewareSnapshot(middleware, () => this.#captureMiddleware());\n }\n\n #captureMiddleware(): EventMiddleware<C> {\n const snapshot = this.#middleware.map(captureEventMiddleware);\n return (context, next) => runEventMiddleware(snapshot, context, next);\n }\n}\n"],"x_google_ignoreList":[6],"mappings":"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"}
|