itd-api 0.9.3 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +9 -8
  2. package/dist/events/index.cjs +2 -2
  3. package/dist/events/index.d.cts +2 -2
  4. package/dist/events/index.d.ts +2 -2
  5. package/dist/events/index.js +2 -2
  6. package/dist/index.cjs +452 -42
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.cts +229 -49
  9. package/dist/index.d.ts +229 -49
  10. package/dist/index.js +448 -44
  11. package/dist/index.js.map +1 -1
  12. package/dist/rest/index.cjs +2 -2
  13. package/dist/rest/index.d.cts +2 -2
  14. package/dist/rest/index.d.ts +2 -2
  15. package/dist/rest/index.js +2 -2
  16. package/dist/shared/{events-BPxBF0gQ.d.cts → events-CZXU16qU.d.cts} +2 -2
  17. package/dist/shared/{events-BzjI6pn5.js → events-Cipe-Fm9.js} +3 -3
  18. package/dist/shared/{events-BzjI6pn5.js.map → events-Cipe-Fm9.js.map} +1 -1
  19. package/dist/shared/{events-DnwfcLxS.d.ts → events-D3CSlpXR.d.ts} +2 -2
  20. package/dist/shared/{events-C1FudmSe.cjs → events-MtRNe_TF.cjs} +8 -2
  21. package/dist/shared/{events-C1FudmSe.cjs.map → events-MtRNe_TF.cjs.map} +1 -1
  22. package/dist/shared/{render-uFW2kDxp.d.ts → render-Cs6AOXbD.d.ts} +2 -2
  23. package/dist/shared/{render-CtOpp9Pm.js → render-CubTTof_.js} +2 -2
  24. package/dist/shared/{render-CtOpp9Pm.js.map → render-CubTTof_.js.map} +1 -1
  25. package/dist/shared/{render-C1F_QWYD.d.cts → render-bZwOk3CC.d.cts} +2 -2
  26. package/dist/shared/{render-Omy1drH1.cjs → render-dscKp9CC.cjs} +2 -2
  27. package/dist/shared/{render-Omy1drH1.cjs.map → render-dscKp9CC.cjs.map} +1 -1
  28. package/dist/shared/{url-3Ts6EEHQ.js → url-CntTEAxu.js} +65 -3
  29. package/dist/shared/url-CntTEAxu.js.map +1 -0
  30. package/dist/shared/{url-D6wsXm1T.cjs → url-DgTYZN_v.cjs} +100 -2
  31. package/dist/shared/url-DgTYZN_v.cjs.map +1 -0
  32. package/dist/shared/{url-DubjkRR9.d.cts → url-Dum7r_FT.d.cts} +70 -3
  33. package/dist/shared/{url-DubjkRR9.d.ts → url-Dum7r_FT.d.ts} +70 -3
  34. package/package.json +2 -1
  35. package/dist/shared/url-3Ts6EEHQ.js.map +0 -1
  36. package/dist/shared/url-D6wsXm1T.cjs.map +0 -1
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import { $ as orderPluginDefinitions, A as ITD_CATALOG, C as ReportReason, D as ViewReason, E as SpanType, F as operationMethod, G as pickString, I as operationRetrySafety, K as RetrySafety, L as BUCKET_LIMITS, M as defineBuiltInOperation, N as isBuiltInOperationId, O as ViewSource, P as operationBucket, Q as assertPluginRemovable, R as DEFAULT_RATE_LIMIT_BUCKET, S as NotificationType, T as ServiceState, V as pickArray, Z as RequestQueuePool, _ as FeedTab, at as isRecord, b as ItdErrorCode, c as normalizeNotification, d as canonicalNotificationType, et as DEFAULT_BASE_URL, f as isKnownNotificationType, g as EventChannelStatus, h as CommentSort, it as LIBRARY_VERSION, j as OPERATIONS, k as WallAccess, lt as systemClock, m as AttachmentType, n as formatNotificationText, nt as STATUS_SERVICE, o as passthroughOperation, ot as requireOptionalBoolean, p as AccessType, rt as resolveRateLimit, s as voidOperation, st as RateLimitPacing, t as resolveNotificationUrl, ut as installAsyncDisposeFallback, v as IncidentKind, w as ReportTargetType, x as LikesVisibility, y as InteractionType, z as createClientRuntime } from "./shared/url-3Ts6EEHQ.js";
1
+ import { A as ViewReason, B as BUCKET_LIMITS, C as ItdErrorCode, D as ReportTargetType, E as ReportReason, F as defineBuiltInOperation, G as pickArray, H as createClientRuntime, I as isBuiltInOperationId, L as operationBucket, M as WallAccess, N as ITD_CATALOG, O as ServiceState, P as OPERATIONS, R as operationMethod, S as InteractionType, T as NotificationType, U as createApiError, V as DEFAULT_RATE_LIMIT_BUCKET, X as RetrySafety, Y as pickString, _ as CaptchaType, at as orderPluginDefinitions, b as FeedTab, c as normalizeNotification, ct as STATUS_SERVICE, d as canonicalNotificationType, dt as isRecord, et as createRequestAbortScope, f as isKnownNotificationType, ft as requireOptionalBoolean, g as CaptchaField, gt as installAsyncDisposeFallback, h as CaptchaChoice, ht as systemClock, it as assertPluginRemovable, j as ViewSource, k as SpanType, lt as resolveRateLimit, m as AttachmentType, n as formatNotificationText, o as passthroughOperation, ot as DEFAULT_BASE_URL, p as AccessType, pt as RateLimitPacing, rt as RequestQueuePool, s as voidOperation, t as resolveNotificationUrl, tt as requestAbortError, ut as LIBRARY_VERSION, v as CommentSort, w as LikesVisibility, x as IncidentKind, y as EventChannelStatus, z as operationRetrySafety } from "./shared/url-CntTEAxu.js";
2
2
  import { A as isItdStateError, C as isItdError, D as isItdPhoneVerificationError, E as isItdNotFoundError, O as isItdRateLimitError, S as isItdConflictError, T as isItdForbiddenError, _ as ItdStateError, a as ItdConfigError, b as isItdApiError, c as ItdErrorKind, d as ItdForbiddenError, f as ItdNetworkError, g as ItdServerError, h as ItdRateLimitError, i as ItdAuthError, j as isItdValidationError, k as isItdServerError, l as ItdFileError, m as ItdPhoneVerificationError, n as ItdApiError, o as ItdConflictError, p as ItdNotFoundError, r as ItdApiErrorKind, s as ItdError, t as ItdAbortError, u as ItdFileErrorReason, v as ItdTimeoutError, w as isItdFileError, x as isItdAuthError, y as ItdValidationError } from "./shared/errors-GI10kZxk.js";
3
- import { c as REFRESH_COOKIE, l as REFRESH_COOKIE_PATH, s as CookieJar, u as isSerializedCookieEntry, v as RuntimeMode, y as createDeviceId } from "./shared/redact-DJV0XM3n.js";
4
- import { A as utcStampToIso, C as AUDIO_MIME_TYPES, D as isBuilder, E as comment, F as mapPage, I as createFeatureHost, L as ExtensibleOperationCatalog, M as BaseResource, N as PaginationMode, O as createStatusFeature, P as Paginator, S as ALLOWED_MIME_TYPES, T as VIDEO_MIME_TYPES, _ as poll, a as createShopOrderAccessStorage, b as parseHtml, c as ShopOrderStatus, d as isMyProfile, f as fromStream, g as post, h as report, i as MemoryShopOrderAccessStorage, j as NotificationsResource, k as toDate, l as ShopProductCategory, m as createResources, n as renderSpans, o as statusDays, p as fromUrl, r as createShopFeature, s as ShopConsentKind, t as SpanRenderFormat, u as ShopProductStatus, v as autoSpans, w as IMAGE_MIME_TYPES, x as parseMarkdown, y as markup } from "./shared/render-CtOpp9Pm.js";
3
+ import { c as REFRESH_COOKIE, h as joinUrl, l as REFRESH_COOKIE_PATH, s as CookieJar, u as isSerializedCookieEntry, v as RuntimeMode, y as createDeviceId } from "./shared/redact-DJV0XM3n.js";
4
+ import { A as utcStampToIso, C as AUDIO_MIME_TYPES, D as isBuilder, E as comment, F as mapPage, I as createFeatureHost, L as ExtensibleOperationCatalog, M as BaseResource, N as PaginationMode, O as createStatusFeature, P as Paginator, S as ALLOWED_MIME_TYPES, T as VIDEO_MIME_TYPES, _ as poll, a as createShopOrderAccessStorage, b as parseHtml, c as ShopOrderStatus, d as isMyProfile, f as fromStream, g as post, h as report, i as MemoryShopOrderAccessStorage, j as NotificationsResource, k as toDate, l as ShopProductCategory, m as createResources, n as renderSpans, o as statusDays, p as fromUrl, r as createShopFeature, s as ShopConsentKind, t as SpanRenderFormat, u as ShopProductStatus, v as autoSpans, w as IMAGE_MIME_TYPES, x as parseMarkdown, y as markup } from "./shared/render-CubTTof_.js";
5
5
  import { c as FileTransferMode } from "./shared/options-i4LrKfqx.js";
6
- import { _ as reportListenerError, a as WebSocketTransport, c as NotificationEventsTransport, d as NotificationUpdateOrigin, f as NotificationUpdateType, g as Emitter, h as runEventMiddleware, i as createNotificationEventsClient, l as resolveNotificationEventsOptions, m as UnauthorizedStreamError, n as EventRouter, o as EVENT_OPERATIONS, p as EventChannel, r as NotificationEventsClient, s as NotificationEvents, t as EventComposer, u as setNotificationEventsConnectGuard } from "./shared/events-BzjI6pn5.js";
6
+ import { _ as Emitter, a as WebSocketTransport, c as NotificationEventsTransport, d as NotificationUpdateOrigin, f as NotificationUpdateType, g as runEventMiddleware, h as UnauthorizedStreamError, i as createNotificationEventsClient, l as resolveNotificationEventsOptions, m as EventChannel, n as EventRouter, o as EVENT_OPERATIONS, p as createParser, r as NotificationEventsClient, s as NotificationEvents, t as EventComposer, u as setNotificationEventsConnectGuard, v as reportListenerError } from "./shared/events-Cipe-Fm9.js";
7
7
  import { a as isEnumerableKeyValueStore, i as createRecordKeyValueStore, o as withCodec, r as createKeyValueStore, s as withNamespace, t as MemoryKeyValueStore } from "./shared/key-value-store-Bt2PSMxY.js";
8
8
  import { n as copySession, r as createTokenStorage, t as MemoryTokenStorage } from "./shared/storage-DiDe0PZM.js";
9
9
  import { a as scopedTokenStorage, i as isRestorableSession, n as controlledTokenStorage, r as createMultiTokenStorage, t as MemoryMultiTokenStorage } from "./shared/multi-storage-C3Ngtop1.js";
@@ -31,12 +31,37 @@ const SignInStatus = Object.freeze({
31
31
  Authenticated: "authenticated",
32
32
  OtpRequired: "otp_required"
33
33
  });
34
+ /**
35
+ * Поле тела запроса по умолчанию для известных провайдеров.
36
+ *
37
+ * Используется, когда провайдера не спрашивали. Ответ `captchaProvider()` важнее этой таблицы.
38
+ */
39
+ const CAPTCHA_FIELDS = Object.freeze({
40
+ [CaptchaType.Itd]: CaptchaField.Itd,
41
+ [CaptchaType.Cloudflare]: CaptchaField.Cloudflare
42
+ });
43
+ /** Состояния, которые может вернуть проверка QR-входа. */
44
+ const QrLoginStatus = Object.freeze({
45
+ Pending: "pending",
46
+ Scanned: "scanned",
47
+ CaptchaRequired: "captcha_required",
48
+ Authorized: "authorized",
49
+ Rejected: "rejected"
50
+ });
51
+ /** Состояния, приходящие из потокового наблюдения за QR-входом. */
52
+ const QrLoginStreamStatus = Object.freeze({
53
+ Pending: "pending",
54
+ Scanned: "scanned",
55
+ Approved: "approved",
56
+ Rejected: "rejected"
57
+ });
34
58
  function requireString(body, key, message) {
35
59
  const value = pickString(body, key);
36
60
  if (!value) throw new ItdConfigError(message);
37
61
  return value;
38
62
  }
39
63
  const AUTH_CHECK = passthroughOperation("auth.check");
64
+ const AUTH_CAPTCHA_PROVIDER = passthroughOperation("auth.captchaProvider");
40
65
  const AUTH_SIGN_UP = defineBuiltInOperation("auth.signUp", (body) => requireString(body, "flowToken", "Сервер не вернул flowToken при регистрации"));
41
66
  const AUTH_SIGN_IN = defineBuiltInOperation("auth.signIn", (body) => {
42
67
  const accessToken = pickString(body, "accessToken");
@@ -58,6 +83,96 @@ const AUTH_CHANGE_PASSWORD = voidOperation("auth.changePassword");
58
83
  const AUTH_SESSIONS = defineBuiltInOperation("auth.sessions", (body) => pickArray(body, "sessions"));
59
84
  const AUTH_REVOKE_SESSION = voidOperation("auth.revokeSession");
60
85
  const AUTH_REVOKE_OTHER_SESSIONS = voidOperation("auth.revokeOtherSessions");
86
+ const AUTH_QR_START = passthroughOperation("auth.qrStart");
87
+ const AUTH_QR_CLAIM = passthroughOperation("auth.qrClaim");
88
+ //#endregion
89
+ //#region src/session/captcha.ts
90
+ function requireCaptchaText(value, field) {
91
+ if (value !== void 0 && (typeof value !== "string" || value.trim() === "")) throw new ItdConfigError(`${field} должен быть непустой строкой`);
92
+ }
93
+ /**
94
+ * Проверяет форму источника токена и приводит его к объекту.
95
+ *
96
+ * Сам объект сохраняется как есть: `getToken` вызывается на нём, чтобы источнику остался
97
+ * доступен собственный `this`.
98
+ *
99
+ * @throws {ItdConfigError} при некорректных значениях
100
+ */
101
+ function resolveCaptchaSolver(captcha) {
102
+ if (captcha === void 0) return void 0;
103
+ if (typeof captcha === "function") return { getToken: captcha };
104
+ if (!isRecord(captcha)) throw new ItdConfigError("captcha должен быть функцией либо объектом с getToken");
105
+ const { getToken, type, field } = captcha;
106
+ if (typeof getToken !== "function") throw new ItdConfigError("captcha.getToken должен быть функцией");
107
+ requireCaptchaText(type, "captcha.type");
108
+ requireCaptchaText(field, "captcha.field");
109
+ return captcha;
110
+ }
111
+ /**
112
+ * Проверяет форму готового токена капчи.
113
+ *
114
+ * @param path имя опции или аргумента для текста ошибки
115
+ * @throws {ItdConfigError} если токен или его тип не указаны
116
+ */
117
+ function validateCaptchaToken(captcha, path) {
118
+ if (captcha === void 0) return;
119
+ if (!isRecord(captcha)) throw new ItdConfigError(`${path} должен быть объектом { type, token }`);
120
+ const { type, token, field } = captcha;
121
+ if (typeof token !== "string" || token.trim() === "") throw new ItdConfigError(`${path}.token должен быть непустой строкой`);
122
+ if (typeof type !== "string" || type.trim() === "") throw new ItdConfigError(`${path}.type должен быть непустой строкой`);
123
+ requireCaptchaText(field, `${path}.field`);
124
+ }
125
+ /** Разбирает ответ `GET /api/v1/auth/captcha/provider` для автоматического входа. */
126
+ function readCaptchaProvider(body) {
127
+ const config = isRecord(body) ? body : void 0;
128
+ const provider = config?.provider;
129
+ const field = config?.field;
130
+ if (typeof provider !== "string" || provider.trim() === "" || typeof field !== "string" || field.trim() === "") throw new ItdConfigError("Сервер вернул неподдерживаемую конфигурацию капчи");
131
+ return {
132
+ provider,
133
+ field
134
+ };
135
+ }
136
+ /** Куда класть токен: настройка, иначе умолчание провайдера. */
137
+ function resolveField(type, configured) {
138
+ const field = configured ?? CAPTCHA_FIELDS[type];
139
+ if (field) return field;
140
+ throw new ItdConfigError(`Неизвестно, в каком поле сервер ждёт токен капчи «${type}». Передайте captcha.field либо оставьте captcha.type = ${CaptchaChoice.Auto}, чтобы поле назвал сервер.`);
141
+ }
142
+ /** Спрашивает токен у источника и убеждается, что он непустой. */
143
+ async function requireSolvedToken(solver, type) {
144
+ const token = await solver.getToken(type);
145
+ if (typeof token === "string" && token.trim() !== "") return token;
146
+ throw new ItdConfigError(`Источник капчи не вернул токен для провайдера «${type}». Проверьте captcha.getToken.`);
147
+ }
148
+ /**
149
+ * Готовит фрагмент тела запроса, взяв токен у источника.
150
+ *
151
+ * При `CaptchaChoice.Auto` провайдер спрашивается у сервера — тогда и тип виджета,
152
+ * и имя поля приходят оттуда. Явно названный тип обходится без этого запроса.
153
+ *
154
+ * @param askProvider как спросить активного провайдера; вызывается, только если это нужно
155
+ * @throws {ItdConfigError} если токен получить не удалось
156
+ */
157
+ async function solveCaptchaBody(solver, askProvider) {
158
+ const choice = solver.type ?? CaptchaChoice.Auto;
159
+ if (choice === CaptchaChoice.Auto) {
160
+ const { provider, field } = await askProvider();
161
+ return { [field]: await requireSolvedToken(solver, provider) };
162
+ }
163
+ return { [resolveField(choice, solver.field)]: await requireSolvedToken(solver, choice) };
164
+ }
165
+ /**
166
+ * Готовит фрагмент тела из готового токена.
167
+ *
168
+ * Поле берётся из самого токена либо из умолчания провайдера; запроса к серверу нет.
169
+ *
170
+ * @throws {ItdConfigError} если токен или его тип не указаны
171
+ */
172
+ function captchaBody(captcha) {
173
+ validateCaptchaToken(captcha, "captcha");
174
+ return { [resolveField(captcha.type, captcha.field)]: captcha.token };
175
+ }
61
176
  //#endregion
62
177
  //#region src/session/jwt.ts
63
178
  /**
@@ -130,11 +245,10 @@ function validateAuth(auth) {
130
245
  return { ...auth };
131
246
  }
132
247
  if ("email" in auth || "password" in auth) {
133
- const { email, password, turnstileToken, getTurnstileToken } = auth;
248
+ const { email, password, captcha } = auth;
134
249
  if (typeof email !== "string" || email.trim() === "") throw new ItdConfigError("auth.email должен быть непустой строкой");
135
250
  if (typeof password !== "string" || password === "") throw new ItdConfigError("auth.password должен быть непустой строкой");
136
- if (getTurnstileToken !== void 0 && typeof getTurnstileToken !== "function") throw new ItdConfigError("auth.getTurnstileToken должен быть функцией");
137
- if (turnstileToken !== void 0 && (typeof turnstileToken !== "string" || turnstileToken.trim() === "")) throw new ItdConfigError("auth.turnstileToken должен быть непустой строкой");
251
+ validateCaptchaToken(captcha, "auth.captcha");
138
252
  return { ...auth };
139
253
  }
140
254
  throw new ItdConfigError("auth не распознан. Ожидается строка с accessToken либо объект { accessToken }, { email, password } или { getToken }");
@@ -163,6 +277,7 @@ function resolveSessionConfig(options, runtime) {
163
277
  return {
164
278
  ...runtime,
165
279
  auth: validateAuth(options.auth),
280
+ captcha: resolveCaptchaSolver(options.captcha),
166
281
  storage: resolveStorage(options.storage),
167
282
  deviceId: options.deviceId,
168
283
  autoRefresh: options.autoRefresh ?? true,
@@ -181,6 +296,7 @@ function createItdAuth(options, deps) {
181
296
  }
182
297
  /** Пути эндпоинтов авторизации. */
183
298
  const AUTH_PATHS = {
299
+ captchaProvider: "/api/v1/auth/captcha/provider",
184
300
  signUp: "/api/v1/auth/sign-up",
185
301
  signIn: "/api/v1/auth/sign-in",
186
302
  verifyOtp: "/api/v1/auth/verify-otp",
@@ -190,7 +306,10 @@ const AUTH_PATHS = {
190
306
  forgotPassword: "/api/v1/auth/forgot-password",
191
307
  resetPassword: "/api/v1/auth/reset-password",
192
308
  changePassword: "/api/v1/auth/change-password",
193
- sessions: "/api/v1/auth/sessions"
309
+ sessions: "/api/v1/auth/sessions",
310
+ qrStart: "/api/v1/auth/qr/start",
311
+ qrClaim: "/api/v1/auth/qr/claim",
312
+ qrStream: "/api/v1/auth/qr/stream"
194
313
  };
195
314
  /**
196
315
  * Публичный ключ Cloudflare Turnstile платформы итд.com.
@@ -200,14 +319,15 @@ const AUTH_PATHS = {
200
319
  *
201
320
  * Ключ привязан к домену: на чужом origin Cloudflare отказывает виджету с кодом `110200`.
202
321
  * Поэтому отрисовать его может только код, выполняемый на самом итд.com. Остальным
203
- * подходит `@itd-api/turnstile`, готовый токен из другого источника или вовсе вход
322
+ * подходит `@itd-api/captcha`, готовый токен из другого источника или вовсе вход
204
323
  * без капчи — по сохранённой сессии либо по токенам, взятым в браузере.
205
324
  *
206
325
  * @example
207
326
  * ```ts
208
327
  * turnstile.render('#captcha', {
209
328
  * sitekey: TURNSTILE_SITE_KEY,
210
- * callback: (turnstileToken) => itd.auth.signIn({ email, password, turnstileToken }),
329
+ * callback: (token) =>
330
+ * itd.auth.signIn({ email, password, captcha: { type: CaptchaType.Cloudflare, token } }),
211
331
  * });
212
332
  * ```
213
333
  */
@@ -329,6 +449,8 @@ var AuthManager = class {
329
449
  */
330
450
  #authEpoch = 0;
331
451
  #externalReadGeneration = 0;
452
+ /** Разовый токен из `auth.captcha` тратится ровно на один запрос. */
453
+ #configCaptchaSpent = false;
332
454
  #disposed = false;
333
455
  #persistence = Promise.resolve();
334
456
  constructor(config, http, jar, hooks = {}) {
@@ -625,6 +747,13 @@ var AuthManager = class {
625
747
  }
626
748
  /** Сохраняет токен, полученный извне, — например после подтверждения OTP. */
627
749
  async setAccessToken(accessToken, expectedRevision = this.#authEpoch, cookies) {
750
+ return this.#storeAccessToken(accessToken, expectedRevision, cookies, false);
751
+ }
752
+ /** Атомарно принимает токен и cookie завершённого входа как новую сессию. @internal */
753
+ async commitAuthFlow(accessToken, cookies, expectedRevision = this.#authEpoch) {
754
+ return this.#storeAccessToken(accessToken, expectedRevision, cookies, true);
755
+ }
756
+ async #storeAccessToken(accessToken, expectedRevision, cookies, replaceSession) {
628
757
  this.#assertActive();
629
758
  if (typeof accessToken !== "string" || accessToken.trim() === "") throw new ItdConfigError("accessToken должен быть непустой строкой");
630
759
  await this.#loadSession();
@@ -634,7 +763,7 @@ var AuthManager = class {
634
763
  this.#invalidateInFlight();
635
764
  this.#transitionAuth(accessToken);
636
765
  const saved = this.#saveSession({
637
- ...this.#session ?? {},
766
+ ...replaceSession ? {} : this.#session ?? {},
638
767
  accessToken,
639
768
  obtainedAt: this.#config.clock.now()
640
769
  });
@@ -850,28 +979,50 @@ var AuthManager = class {
850
979
  return promise;
851
980
  }
852
981
  /**
853
- * Берёт токен капчи для входа.
982
+ * Готовит фрагмент тела с токеном капчи для запроса, который её требует.
854
983
  *
855
- * `getTurnstileToken` приоритетнее готовой строки: токен Turnstile одноразовый и живёт
856
- * несколько минут, поэтому при повторном входе через сутки годится только свежий.
984
+ * Источники в порядке убывания приоритета: токен, переданный в сам вызов; разовый токен
985
+ * из `auth.captcha`; опция `captcha`. Когда ни одного нет, фрагмент пустой: нужна ли
986
+ * капча этому запросу, решает сервер.
987
+ *
988
+ * @param explicit готовый токен, переданный в вызов
989
+ * @throws {ItdConfigError} если токен неполный или источник его не вернул
857
990
  */
858
- async #resolveTurnstileToken(credentials) {
859
- if (credentials.getTurnstileToken) {
860
- const token = await credentials.getTurnstileToken();
861
- if (token) return token;
862
- }
863
- if (credentials.turnstileToken) return credentials.turnstileToken;
864
- throw new ItdConfigError("Вход по email и паролю требует токен капчи Cloudflare Turnstile: без него сервер отвечает 422. Передайте auth.getTurnstileToken (источник свежего токена) либо разовый auth.turnstileToken. Ключ виджета TURNSTILE_SITE_KEY. В Node токен умеет добывать отдельный пакет: npm i @itd-api/turnstile, затем getTurnstileToken: createTurnstileSolver().");
991
+ async captchaBody(explicit) {
992
+ if (explicit) return captchaBody(explicit);
993
+ const configured = this.#takeConfiguredCaptcha();
994
+ if (configured) return captchaBody(configured);
995
+ const solver = this.#config.captcha;
996
+ if (solver) return solveCaptchaBody(solver, () => this.#resolveCaptchaProvider());
997
+ this.#config.logger?.debug("Запрос уходит без токена капчи: не передан аргумент captcha и не задана опция captcha");
998
+ return {};
999
+ }
1000
+ /** Отдаёт разовый токен из `auth.captcha`, помечая его потраченным. */
1001
+ #takeConfiguredCaptcha() {
1002
+ if (this.#configCaptchaSpent) return void 0;
1003
+ const auth = this.#config.auth;
1004
+ const captcha = isRecord(auth) ? auth.captcha : void 0;
1005
+ if (!captcha) return void 0;
1006
+ this.#configCaptchaSpent = true;
1007
+ return captcha;
1008
+ }
1009
+ /** Спрашивает у сервера активного провайдера и поле, в котором он ждёт токен. */
1010
+ async #resolveCaptchaProvider() {
1011
+ return readCaptchaProvider(await this.#http.execute(AUTH_CAPTCHA_PROVIDER, {
1012
+ path: AUTH_PATHS.captchaProvider,
1013
+ skipAuth: true,
1014
+ skipAuthRefresh: true
1015
+ }));
865
1016
  }
866
1017
  async #performSignIn(credentials, revision) {
867
- const turnstileToken = await this.#resolveTurnstileToken(credentials);
1018
+ const captcha = await this.captchaBody();
868
1019
  const flowCookies = new CookieJar();
869
1020
  const result = await this.#http.execute(AUTH_SIGN_IN, {
870
1021
  path: AUTH_PATHS.signIn,
871
1022
  body: {
872
1023
  email: credentials.email,
873
1024
  password: credentials.password,
874
- turnstileToken
1025
+ ...captcha
875
1026
  },
876
1027
  skipAuth: true,
877
1028
  skipAuthRefresh: true,
@@ -895,6 +1046,125 @@ var AuthManager = class {
895
1046
  }
896
1047
  };
897
1048
  //#endregion
1049
+ //#region src/session/qr-stream.ts
1050
+ const QR_STREAM_STATUSES = new Set(Object.values(QrLoginStreamStatus));
1051
+ function readQrLoginStreamEvent(data) {
1052
+ let value;
1053
+ try {
1054
+ value = JSON.parse(data);
1055
+ } catch {
1056
+ return;
1057
+ }
1058
+ if (!isRecord(value)) return void 0;
1059
+ const event = value;
1060
+ if (typeof event.status !== "string" || !QR_STREAM_STATUSES.has(event.status)) return;
1061
+ return {
1062
+ status: event.status,
1063
+ ...typeof event.expiresIn === "number" && Number.isFinite(event.expiresIn) ? { expiresIn: event.expiresIn } : {}
1064
+ };
1065
+ }
1066
+ /** Читает короткоживущий SSE-поток QR-входа и последовательно доставляет его события. */
1067
+ async function consumeQrLoginStream(body, onEvent, signal) {
1068
+ const reader = body.getReader();
1069
+ const decoder = new TextDecoder();
1070
+ let delivery = Promise.resolve();
1071
+ let completed = false;
1072
+ const cancel = () => {
1073
+ reader.cancel(signal?.reason).catch(() => {});
1074
+ };
1075
+ signal?.addEventListener("abort", cancel, { once: true });
1076
+ const parser = createParser({ onEvent(message) {
1077
+ const event = readQrLoginStreamEvent(message.data);
1078
+ if (!event) return;
1079
+ delivery = delivery.then(() => onEvent(event));
1080
+ } });
1081
+ try {
1082
+ for (;;) {
1083
+ const { done, value } = await reader.read();
1084
+ if (done) break;
1085
+ parser.feed(decoder.decode(value, { stream: true }));
1086
+ await delivery;
1087
+ }
1088
+ parser.feed(decoder.decode());
1089
+ await delivery;
1090
+ if (signal?.aborted) throw signal.reason;
1091
+ completed = true;
1092
+ } finally {
1093
+ signal?.removeEventListener("abort", cancel);
1094
+ if (!completed) await reader.cancel().catch(() => {});
1095
+ reader.releaseLock?.();
1096
+ }
1097
+ }
1098
+ /** Открывает изолированный HTTP/SSE-канал QR-входа. @internal */
1099
+ async function openQrLoginStream(connection, cookies, input, onEvent, signal) {
1100
+ connection.assertActive?.("открыть QR-поток");
1101
+ const path = AUTH_PATHS.qrStream;
1102
+ const method = "POST";
1103
+ const url = joinUrl(connection.baseUrl, path);
1104
+ const abort = createRequestAbortScope(signal, connection.signal, 0, connection.clock);
1105
+ try {
1106
+ const headers = await connection.baseHeaders(url);
1107
+ headers.delete("Authorization");
1108
+ headers.delete("Cookie");
1109
+ headers.set("Accept", "text/event-stream");
1110
+ headers.set("Content-Type", "application/json");
1111
+ const cookie = cookies.getHeader(url);
1112
+ if (cookie) headers.set("Cookie", cookie);
1113
+ let response;
1114
+ try {
1115
+ response = await connection.fetch(url, {
1116
+ method,
1117
+ headers,
1118
+ body: JSON.stringify(input),
1119
+ credentials: "include",
1120
+ signal: abort.signal
1121
+ });
1122
+ } catch (error) {
1123
+ const failure = new ItdNetworkError(`Не удалось открыть QR-поток: ${String(error)}`, {
1124
+ method,
1125
+ path,
1126
+ cause: error
1127
+ });
1128
+ throw requestAbortError(abort, {
1129
+ timeout: 0,
1130
+ method,
1131
+ path
1132
+ }, failure);
1133
+ }
1134
+ cookies.setFromResponse(response.url || url, response);
1135
+ if (!response.ok) {
1136
+ const text = await response.text();
1137
+ let body = text;
1138
+ try {
1139
+ body = JSON.parse(text);
1140
+ } catch {}
1141
+ throw createApiError({
1142
+ method,
1143
+ path,
1144
+ status: response.status,
1145
+ statusText: response.statusText,
1146
+ headers: response.headers,
1147
+ response,
1148
+ body,
1149
+ now: connection.clock.now()
1150
+ });
1151
+ }
1152
+ if (!response.body) throw new ItdNetworkError("Сервер не вернул тело QR-потока", {
1153
+ method,
1154
+ path
1155
+ });
1156
+ await consumeQrLoginStream(response.body, onEvent, abort.signal);
1157
+ } catch (error) {
1158
+ throw requestAbortError(abort, {
1159
+ timeout: 0,
1160
+ method,
1161
+ path
1162
+ }, error);
1163
+ } finally {
1164
+ abort.cleanup();
1165
+ }
1166
+ }
1167
+ //#endregion
898
1168
  //#region src/resources/auth.ts
899
1169
  /**
900
1170
  * Результат входа.
@@ -909,9 +1179,36 @@ var AuthManager = class {
909
1179
  */
910
1180
  var AuthResource = class extends BaseResource {
911
1181
  #auth;
1182
+ #connection;
1183
+ #qrFlows = /* @__PURE__ */ new Map();
912
1184
  constructor(http, deps) {
913
1185
  super(http);
914
1186
  this.#auth = deps.auth;
1187
+ this.#connection = deps.connection;
1188
+ }
1189
+ #pruneQrFlows() {
1190
+ const now = this.#connection.clock.now();
1191
+ for (const [qrId, flow] of this.#qrFlows) if (flow.expiresAt !== void 0 && flow.expiresAt <= now) this.#qrFlows.delete(qrId);
1192
+ }
1193
+ #qrFlow(qrId) {
1194
+ this.#pruneQrFlows();
1195
+ const existing = this.#qrFlows.get(qrId);
1196
+ if (existing) return existing;
1197
+ const flow = {
1198
+ cookies: this.#auth.createCookieFlow(false),
1199
+ expiresAt: void 0,
1200
+ captchaRequired: false
1201
+ };
1202
+ this.#qrFlows.set(qrId, flow);
1203
+ return flow;
1204
+ }
1205
+ #touchQrFlow(flow, expiresIn) {
1206
+ if (typeof expiresIn !== "number" || !Number.isFinite(expiresIn)) return;
1207
+ const expiresAt = this.#connection.clock.now() + Math.max(0, expiresIn) * 1e3;
1208
+ flow.expiresAt = flow.expiresAt === void 0 ? expiresAt : Math.min(flow.expiresAt, expiresAt);
1209
+ }
1210
+ #forgetTerminalQrError(qrId, error) {
1211
+ if (isItdApiError(error) && error.hasCode("QR_EXPIRED", "QR_ALREADY_USED", "QR_TOKEN_MISMATCH")) this.#qrFlows.delete(qrId);
915
1212
  }
916
1213
  /**
917
1214
  * Проверяет состояние авторизации и возвращает текущего пользователя.
@@ -925,14 +1222,109 @@ var AuthResource = class extends BaseResource {
925
1222
  });
926
1223
  }
927
1224
  /**
1225
+ * Узнаёт активного провайдера капчи и поле токена.
1226
+ *
1227
+ * Сервер может переключить провайдера или переименовать поле без выпуска новой версии SDK.
1228
+ * Автоматическому входу этот вызов не нужен — клиент делает его сам.
1229
+ */
1230
+ captchaProvider(options = {}) {
1231
+ return this.http.execute(AUTH_CAPTCHA_PROVIDER, {
1232
+ path: AUTH_PATHS.captchaProvider,
1233
+ skipAuth: true,
1234
+ skipAuthRefresh: true,
1235
+ ...options
1236
+ });
1237
+ }
1238
+ /** Создаёт короткоживущую сессию QR-входа. */
1239
+ async startQrLogin(options = {}) {
1240
+ const cookies = this.#auth.createCookieFlow(false);
1241
+ const result = await this.http.execute(AUTH_QR_START, {
1242
+ path: AUTH_PATHS.qrStart,
1243
+ skipAuth: true,
1244
+ skipAuthRefresh: true,
1245
+ cookieJar: cookies,
1246
+ ...options
1247
+ });
1248
+ if (typeof result.qrId === "string" && result.qrId !== "") {
1249
+ const flow = {
1250
+ cookies,
1251
+ expiresAt: void 0,
1252
+ captchaRequired: false
1253
+ };
1254
+ this.#touchQrFlow(flow, result.expiresIn);
1255
+ this.#qrFlows.set(result.qrId, flow);
1256
+ }
1257
+ return result;
1258
+ }
1259
+ /**
1260
+ * Проверяет QR-сессию и завершает вход после подтверждения на другом устройстве.
1261
+ *
1262
+ * До подтверждения возвращает промежуточный статус. Токен капчи добывается, только когда
1263
+ * сервер о ней попросил — статусом `captcha_required` на прошлой проверке, — либо когда
1264
+ * передан в сам вызов. Полученный `accessToken` автоматически сохраняется в клиенте.
1265
+ */
1266
+ async claimQrLogin(input, options = {}) {
1267
+ const revision = this.#auth.revision();
1268
+ const flow = this.#qrFlow(input.qrId);
1269
+ try {
1270
+ const { captcha, ...rest } = input;
1271
+ const needsCaptcha = captcha !== void 0 || flow.captchaRequired;
1272
+ const result = await this.http.execute(AUTH_QR_CLAIM, {
1273
+ path: AUTH_PATHS.qrClaim,
1274
+ body: {
1275
+ ...rest,
1276
+ ...needsCaptcha ? await this.#auth.captchaBody(captcha) : {}
1277
+ },
1278
+ skipAuth: true,
1279
+ skipAuthRefresh: true,
1280
+ cookieJar: flow.cookies,
1281
+ ...options
1282
+ });
1283
+ this.#touchQrFlow(flow, result.expiresIn);
1284
+ if (result.status === QrLoginStatus.CaptchaRequired) flow.captchaRequired = true;
1285
+ if (result.status === QrLoginStatus.Authorized) {
1286
+ await this.#auth.commitAuthFlow(result.accessToken, flow.cookies, revision);
1287
+ this.#qrFlows.delete(input.qrId);
1288
+ } else if (result.status === QrLoginStatus.Rejected) this.#qrFlows.delete(input.qrId);
1289
+ return result;
1290
+ } catch (error) {
1291
+ this.#forgetTerminalQrError(input.qrId, error);
1292
+ throw error;
1293
+ }
1294
+ }
1295
+ /**
1296
+ * Слушает состояния QR-входа до закрытия ответа или отмены `signal`.
1297
+ *
1298
+ * Событие `approved` означает, что подтверждение завершено: после него вызовите
1299
+ * {@link claimQrLogin}, чтобы получить и сохранить access token.
1300
+ */
1301
+ async streamQrLogin(input, onEvent, options = {}) {
1302
+ if (typeof onEvent !== "function") throw new ItdConfigError("onEvent QR-потока должен быть функцией");
1303
+ const flow = this.#qrFlow(input.qrId);
1304
+ try {
1305
+ await openQrLoginStream(this.#connection, flow.cookies, input, async (event) => {
1306
+ this.#touchQrFlow(flow, event.expiresIn);
1307
+ if (event.status === QrLoginStreamStatus.Rejected) this.#qrFlows.delete(input.qrId);
1308
+ await onEvent(event);
1309
+ }, options.signal);
1310
+ } catch (error) {
1311
+ this.#forgetTerminalQrError(input.qrId, error);
1312
+ throw error;
1313
+ }
1314
+ }
1315
+ /**
928
1316
  * Регистрирует аккаунт и запускает подтверждение по коду.
929
1317
  *
930
1318
  * @returns `flowToken`, который нужно передать в {@link verifyOtp}
931
1319
  */
932
- signUp(credentials, options = {}) {
1320
+ async signUp(credentials, options = {}) {
1321
+ const { captcha, ...rest } = credentials;
933
1322
  return this.http.execute(AUTH_SIGN_UP, {
934
1323
  path: AUTH_PATHS.signUp,
935
- body: credentials,
1324
+ body: {
1325
+ ...rest,
1326
+ ...await this.#auth.captchaBody(captcha)
1327
+ },
936
1328
  skipAuth: true,
937
1329
  skipAuthRefresh: true,
938
1330
  ...options
@@ -946,20 +1338,25 @@ var AuthResource = class extends BaseResource {
946
1338
  *
947
1339
  * При успешном входе токен сохраняется в клиенте автоматически.
948
1340
  *
949
- * @param credentials email, пароль и обязательный токен капчи — см. {@link CaptchaCredentials}
1341
+ * @param credentials email, пароль и токен капчи — см. {@link CredentialsWithCaptcha}
950
1342
  */
951
1343
  async signIn(credentials, options = {}) {
1344
+ const { captcha, ...rest } = credentials;
952
1345
  const revision = this.#auth.revision();
953
1346
  const cookies = this.#auth.createCookieFlow(false);
1347
+ const body = {
1348
+ ...rest,
1349
+ ...await this.#auth.captchaBody(captcha)
1350
+ };
954
1351
  const result = await this.http.execute(AUTH_SIGN_IN, {
955
1352
  path: AUTH_PATHS.signIn,
956
- body: credentials,
1353
+ body,
957
1354
  skipAuth: true,
958
1355
  skipAuthRefresh: true,
959
1356
  cookieJar: cookies,
960
1357
  ...options
961
1358
  });
962
- if (result.status === SignInStatus.Authenticated) await this.#auth.setAccessToken(result.accessToken, revision, cookies);
1359
+ if (result.status === SignInStatus.Authenticated) await this.#auth.commitAuthFlow(result.accessToken, cookies, revision);
963
1360
  else this.#auth.commitCookieFlow(cookies, revision);
964
1361
  return result;
965
1362
  }
@@ -979,7 +1376,7 @@ var AuthResource = class extends BaseResource {
979
1376
  cookieJar: cookies,
980
1377
  ...options
981
1378
  });
982
- await this.#auth.setAccessToken(accessToken, revision, cookies);
1379
+ await this.#auth.commitAuthFlow(accessToken, cookies, revision);
983
1380
  return accessToken;
984
1381
  }
985
1382
  /** Отправляет код подтверждения повторно. */
@@ -1081,10 +1478,13 @@ var AuthResource = class extends BaseResource {
1081
1478
  *
1082
1479
  * @returns `flowToken`, который нужно передать в {@link resetPassword}
1083
1480
  */
1084
- forgotPassword(input, options = {}) {
1481
+ async forgotPassword(input, options = {}) {
1085
1482
  return this.http.execute(AUTH_FORGOT_PASSWORD, {
1086
1483
  path: AUTH_PATHS.forgotPassword,
1087
- body: input,
1484
+ body: {
1485
+ email: input.email,
1486
+ ...await this.#auth.captchaBody(input.captcha)
1487
+ },
1088
1488
  skipAuth: true,
1089
1489
  skipAuthRefresh: true,
1090
1490
  ...options
@@ -1115,23 +1515,21 @@ var AuthResource = class extends BaseResource {
1115
1515
  * ```ts
1116
1516
  * await itd.auth.resetPasswordWithOtp({
1117
1517
  * email,
1118
- * turnstileToken,
1518
+ * captcha: { type: provider, token, field },
1119
1519
  * newPassword,
1120
1520
  * getOtp: () => rl.question('Код из письма: '),
1121
1521
  * });
1122
1522
  * ```
1123
1523
  */
1124
1524
  async resetPasswordWithOtp(input, options = {}) {
1125
- const flowToken = await this.forgotPassword({
1126
- email: input.email,
1127
- turnstileToken: input.turnstileToken
1128
- }, options);
1129
- const otp = await input.getOtp();
1525
+ const { getOtp, newPassword, ...request } = input;
1526
+ const flowToken = await this.forgotPassword(request, options);
1527
+ const otp = await getOtp();
1130
1528
  await this.resetPassword({
1131
1529
  email: input.email,
1132
1530
  otp,
1133
1531
  flowToken,
1134
- newPassword: input.newPassword
1532
+ newPassword
1135
1533
  }, options);
1136
1534
  }
1137
1535
  /**
@@ -1220,8 +1618,9 @@ function createManagedClient(options, internals) {
1220
1618
  * const itd = new ItdClient({
1221
1619
  * // `auth` не обязателен: когда хранилище уже содержит сессию, токен берётся оттуда,
1222
1620
  * // а истёкший продлевается сам. Здесь он нужен на первый запуск.
1223
- * // Вход по паролю требует токена капчи — см. AuthInput и TURNSTILE_SITE_KEY.
1224
- * auth: { email, password, getTurnstileToken },
1621
+ * auth: { email, password },
1622
+ * // Капчу входа решает пакет @itd-api/captcha — см. CaptchaSolver.
1623
+ * captcha: createCaptchaSolver(),
1225
1624
  * storage: new FileTokenStorage('./.itd-session.json'),
1226
1625
  * rateLimit: { concurrency: 4, rps: 8 },
1227
1626
  * });
@@ -1242,7 +1641,10 @@ var ItdClient = class ItdClient {
1242
1641
  #auth;
1243
1642
  /** Авторизация, сессии и пароли. */
1244
1643
  get auth() {
1245
- this.#auth ??= new AuthResource(this.#runtime.http, { auth: this.#runtime.auth });
1644
+ this.#auth ??= new AuthResource(this.#runtime.http, {
1645
+ auth: this.#runtime.auth,
1646
+ connection: this.#runtime.connection()
1647
+ });
1246
1648
  return this.#auth;
1247
1649
  }
1248
1650
  /** Профили, подписки, блокировки, приватность. */
@@ -1732,6 +2134,8 @@ function assertAccountsActive(accounts, action) {
1732
2134
  *
1733
2135
  * await using accounts = new ItdAccounts({
1734
2136
  * storage: new FileMultiTokenStorage('./.itd-sessions.json'),
2137
+ * // Общие опции достаются каждому аккаунту: один источник токена капчи на всех.
2138
+ * captcha: createCaptchaSolver(),
1735
2139
  * rateLimit: { concurrency: 4 },
1736
2140
  * });
1737
2141
  *
@@ -1739,7 +2143,7 @@ function assertAccountsActive(accounts, action) {
1739
2143
  * await accounts.restore();
1740
2144
  *
1741
2145
  * if (!accounts.has('kiow')) {
1742
- * accounts.addAccount('kiow', { auth: { email, password, getTurnstileToken } });
2146
+ * accounts.addAccount('kiow', { auth: { email, password } });
1743
2147
  * }
1744
2148
  *
1745
2149
  * await accounts.account('kiow').posts.create({ content: 'привет' });
@@ -1818,7 +2222,7 @@ var ItdAccounts = class ItdAccounts {
1818
2222
  *
1819
2223
  * @example
1820
2224
  * ```ts
1821
- * accounts.addAccount('bot', { auth: { email, password, getTurnstileToken } });
2225
+ * accounts.addAccount('bot', { auth: { email, password } });
1822
2226
  * accounts.addAccount('reader', { auth: '<accessToken>' });
1823
2227
  * accounts.addAccount('через-прокси', { fetch: proxyFetch('socks5://…') });
1824
2228
  * ```
@@ -2151,6 +2555,6 @@ function createAccounts(options = {}) {
2151
2555
  return new ItdAccounts(options);
2152
2556
  }
2153
2557
  //#endregion
2154
- export { ALLOWED_MIME_TYPES, AUDIO_MIME_TYPES, AccessType, AttachmentType, BUCKET_LIMITS, CommentSort, DEFAULT_BASE_URL, DEFAULT_RATE_LIMIT_BUCKET, EventChannel, EventChannelStatus, EventComposer, EventRouter, FeedTab, FileTransferMode, IMAGE_MIME_TYPES, IncidentKind, InteractionType, ItdAbortError, ItdAccounts, ItdApiError, ItdApiErrorKind, ItdAuthError, ItdClient, ItdConfigError, ItdConflictError, ItdError, ItdErrorCode, ItdErrorKind, ItdFileError, ItdFileErrorReason, ItdForbiddenError, ItdNetworkError, ItdNotFoundError, ItdPhoneVerificationError, ItdRateLimitError, ItdServerError, ItdStateError, ItdTimeoutError, ItdValidationError, LIBRARY_VERSION, LikesVisibility, MemoryKeyValueStore, MemoryMultiTokenStorage, MemoryShopOrderAccessStorage, MemoryTokenStorage, NotificationEvents, NotificationEventsClient, NotificationEventsTransport, NotificationType, NotificationUpdateOrigin, NotificationUpdateType, OPERATIONS, PaginationMode, Paginator, RateLimitPacing, ReportReason, ReportTargetType, RetrySafety, RuntimeMode, STATUS_SERVICE, ServiceState, ShopConsentKind, ShopOrderStatus, ShopProductCategory, ShopProductStatus, SignInStatus, SpanRenderFormat, SpanType, TURNSTILE_SITE_KEY, UnauthorizedStreamError, VIDEO_MIME_TYPES, ViewReason, ViewSource, WallAccess, WebSocketTransport, autoSpans, canonicalNotificationType, comment, createAccounts, createClient, createKeyValueStore, createMultiTokenStorage, createNotificationEventsClient, createRecordKeyValueStore, createShopFeature, createShopOrderAccessStorage, createTokenStorage, formatNotificationText, fromStream, fromUrl, isBuilder, isBuiltInOperationId, isEnumerableKeyValueStore, isItdApiError, isItdAuthError, isItdConflictError, isItdError, isItdFileError, isItdForbiddenError, isItdNotFoundError, isItdPhoneVerificationError, isItdRateLimitError, isItdServerError, isItdStateError, isItdValidationError, isKnownNotificationType, isMyProfile, mapPage, markup, normalizeNotification, operationBucket, operationMethod, operationRetrySafety, parseHtml, parseMarkdown, poll, post, renderSpans, report, resolveNotificationUrl, runEventMiddleware, scopedTokenStorage, statusDays, systemClock, toDate, utcStampToIso, withCodec, withNamespace };
2558
+ export { ALLOWED_MIME_TYPES, AUDIO_MIME_TYPES, AccessType, AttachmentType, BUCKET_LIMITS, CAPTCHA_FIELDS, CaptchaChoice, CaptchaField, CaptchaType, CommentSort, DEFAULT_BASE_URL, DEFAULT_RATE_LIMIT_BUCKET, EventChannel, EventChannelStatus, EventComposer, EventRouter, FeedTab, FileTransferMode, IMAGE_MIME_TYPES, IncidentKind, InteractionType, ItdAbortError, ItdAccounts, ItdApiError, ItdApiErrorKind, ItdAuthError, ItdClient, ItdConfigError, ItdConflictError, ItdError, ItdErrorCode, ItdErrorKind, ItdFileError, ItdFileErrorReason, ItdForbiddenError, ItdNetworkError, ItdNotFoundError, ItdPhoneVerificationError, ItdRateLimitError, ItdServerError, ItdStateError, ItdTimeoutError, ItdValidationError, LIBRARY_VERSION, LikesVisibility, MemoryKeyValueStore, MemoryMultiTokenStorage, MemoryShopOrderAccessStorage, MemoryTokenStorage, NotificationEvents, NotificationEventsClient, NotificationEventsTransport, NotificationType, NotificationUpdateOrigin, NotificationUpdateType, OPERATIONS, PaginationMode, Paginator, QrLoginStatus, QrLoginStreamStatus, RateLimitPacing, ReportReason, ReportTargetType, RetrySafety, RuntimeMode, STATUS_SERVICE, ServiceState, ShopConsentKind, ShopOrderStatus, ShopProductCategory, ShopProductStatus, SignInStatus, SpanRenderFormat, SpanType, TURNSTILE_SITE_KEY, UnauthorizedStreamError, VIDEO_MIME_TYPES, ViewReason, ViewSource, WallAccess, WebSocketTransport, autoSpans, canonicalNotificationType, comment, createAccounts, createClient, createKeyValueStore, createMultiTokenStorage, createNotificationEventsClient, createRecordKeyValueStore, createShopFeature, createShopOrderAccessStorage, createTokenStorage, formatNotificationText, fromStream, fromUrl, isBuilder, isBuiltInOperationId, isEnumerableKeyValueStore, isItdApiError, isItdAuthError, isItdConflictError, isItdError, isItdFileError, isItdForbiddenError, isItdNotFoundError, isItdPhoneVerificationError, isItdRateLimitError, isItdServerError, isItdStateError, isItdValidationError, isKnownNotificationType, isMyProfile, mapPage, markup, normalizeNotification, operationBucket, operationMethod, operationRetrySafety, parseHtml, parseMarkdown, poll, post, renderSpans, report, resolveNotificationUrl, runEventMiddleware, scopedTokenStorage, statusDays, systemClock, toDate, utcStampToIso, withCodec, withNamespace };
2155
2559
 
2156
2560
  //# sourceMappingURL=index.js.map