@torrow/sdk-auth 0.6.0 → 0.8.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/dist/index.d.ts CHANGED
@@ -1,51 +1,93 @@
1
- import { T as TokenStorage, A as AuthTokenSnapshot, a as TokenSessionOptions, b as TokenSessionStatus, c as TokenSessionStatusListener } from './types-LCuPy3dY.js';
2
- export { d as AppCredentials, D as DEFAULT_APP_CREDENTIALS, R as RefreshFailureAction } from './types-LCuPy3dY.js';
3
- import { TorrowClient, DeviceInfo, TokenResp, AuthScope, VerificationMethod, SendCodeAccountType, AuthCaptchaType, AccountType } from '@torrow/sdk-client';
1
+ import { A as AppCredentials, T as TokenSessionOptions, a as TokenStorage, b as TokenSessionStatus, c as TokenSessionStatusListener, d as AuthTokenSnapshot } from './types-C4e90uOw.js';
2
+ export { R as RefreshFailureAction } from './types-C4e90uOw.js';
3
+ import { SendCodeAccountType, VerificationMethod, TorrowClient, DeviceInfo, TokenResp, AuthScope, AuthCaptchaType, AccountType, TokenStatusValues } from '@torrow/sdk-client';
4
+
5
+ /** Defaults и преобразование credentials приложения в HTTP Basic. */
4
6
 
5
7
  /**
6
- * In-memory реализация {@link TokenStorage}.
8
+ * Дефолтные app credentials SDK для `/api/v1/auth/*`, если {@link TokenSessionOptions.appCredentials}
9
+ * не передан. Своё приложение может переопределить явной парой.
7
10
  *
8
- * Тесты, эфемерные процессы, `TorrowAuth.fromTokens` без диска.
9
- * Для Node-примеров обычно {@link FileTokenStorage}; для браузера —
10
- * {@link LocalStorageTokenStorage}.
11
+ * Публикуется в npm `@torrow/sdk-auth` (inspectable); свой prod-secret — только override / BFF.
11
12
  */
12
-
13
- /** In-memory хранилище токенов сессии. */
14
- declare class MemoryTokenStorage implements TokenStorage {
15
- private snapshot;
16
- constructor(initial?: AuthTokenSnapshot);
17
- load(): Promise<AuthTokenSnapshot>;
18
- save(snapshot: AuthTokenSnapshot): Promise<void>;
19
- }
13
+ declare const DEFAULT_APP_CREDENTIALS: AppCredentials;
20
14
 
21
15
  /**
22
- * Persist snapshot в браузерный **`localStorage`** — реализация {@link TokenStorage}.
16
+ * Внутренний оркестратор OTP-логина (не публичный export целиком; типы UI — да).
23
17
  *
24
- * Для виджетов / SPA (`TorrowAuth.fromTokens` / `connect`). В Node без
25
- * `globalThis.localStorage` конструктор бросит. Не путать с {@link FileTokenStorage}.
18
+ * **`sendCode`** → ветка по **`usedMethod`** (Mobile ID poll | classic код) →
19
+ * **`TokenResp`**. UI снаружи: **`onSendCode`** + **`getCode`**.
20
+ * IMAP / stdin / env — в app / `examples/node/_shared`, не здесь.
21
+ *
22
+ * Вызывается из `TorrowAuth.loginWithOtp`; Mobile ID — `mobile-id.ts`.
26
23
  */
27
24
 
28
- type LocalStorageLike = {
29
- getItem(key: string): string | null;
30
- setItem(key: string, value: string): void;
31
- removeItem?(key: string): void;
25
+ /**
26
+ * Аргумент **`onSendCode`**: снимок **после** успешного `sendCode` (в основном поля **`SendCodeResp`**).
27
+ * Не путать с телом запроса: в `sendCode` уходят `supportedMethods` / `preferredMethod`
28
+ * (см. {@link RunOtpLoginOptions}); здесь — что сервер **выбрал** и что ещё доступно.
29
+ *
30
+ * Типичный UI: по `usedMethod` показать «ждём SMS» / «код на email» / «подтвердите push»;
31
+ * по `codeLength` — маску поля ввода.
32
+ */
33
+ type OtpSendCodeResult = {
34
+ /** Аккаунт из `SendCodeReq` (телефон / email). */
35
+ accountName: string;
36
+ /** `Phone` \| `Email` из запроса (не путать с `usedMethod`). */
37
+ accountType: SendCodeAccountType;
38
+ /** Id auth-сессии для последующего `requestToken` / Mobile ID poll. */
39
+ sessionId: string;
40
+ /**
41
+ * Фактический канал из **`SendCodeResp.usedMethod`** — ради этого и нужен `onSendCode`.
42
+ * Sms / Email / FlashCall / TelegramGateway / MtsMobileId / …
43
+ */
44
+ usedMethod?: VerificationMethod;
45
+ /** Длина кода для input/маски; у Mobile ID часто `0` (keypad не нужен). */
46
+ codeLength?: number;
47
+ /** Интервал poll при Mobile ID (`SendCodeResp.pollIntervalSeconds`). */
48
+ pollIntervalSeconds?: number;
49
+ /**
50
+ * Из **`SendCodeResp`** (не тело `sendCode`): методы, доступные для этого аккаунта
51
+ * (UX «другой способ»). В запрос передаётся {@link RunOtpLoginOptions.supportedMethods}.
52
+ */
53
+ availableMethods?: VerificationMethod[] | null;
54
+ /** TTL auth-сессии `sendCode` (сек); для Mobile ID — ориентир max wait. */
55
+ sessionLifeTimeInSeconds?: number;
56
+ /** Когда снова можно дернуть `sendCode` (rate-limit hint из ответа). */
57
+ nextAvailableUsageTime?: Date | null;
32
58
  };
33
59
  /**
34
- * Persist snapshot токенов в браузерный `localStorage` (виджет / SPA).
60
+ * Аргумент **`getCode`**: только когда нужны цифры (stdin / UI / IMAP снаружи).
61
+ *
62
+ * UI-экран уже выбран в **`onSendCode`** (`usedMethod`). Здесь — собрать код
63
+ * (длина из `codeLength`). На happy-path Mobile ID (push) **`getCode` не вызывается**;
64
+ * SMS-fallback после poll — тот же колбэк, без отдельного `reason`.
65
+ *
66
+ * `accountName` / `accountType` не дублируются — они в options и в `onSendCode`.
35
67
  */
36
- declare class LocalStorageTokenStorage implements TokenStorage {
37
- readonly key: string;
38
- private readonly store;
39
- constructor(key: string, store?: LocalStorageLike);
40
- load(): Promise<AuthTokenSnapshot>;
41
- save(snapshot: AuthTokenSnapshot): Promise<void>;
68
+ type OtpGetCodeContext = {
69
+ sessionId: string;
70
+ /** Эффективная длина для валидации (Mobile ID SMS fallback: при `0` с сервера → 4). */
71
+ codeLength?: number;
72
+ /** Канал из `sendCode` (опциональная подсказка; экран уже из `onSendCode`). */
73
+ usedMethod?: VerificationMethod;
74
+ };
75
+ /** Превышен лимит `sendCode` (`CODE_REQUEST_LIMIT_EXCEEDED`). */
76
+ declare class OtpCodeRequestLimitExceededError extends Error {
77
+ readonly name = "OtpCodeRequestLimitExceededError";
78
+ readonly minutes?: string;
79
+ readonly seconds?: string;
80
+ readonly traceUrl?: string;
81
+ readonly apiMessage?: string;
82
+ readonly body: unknown;
83
+ constructor(body: unknown);
42
84
  }
43
-
44
- /** Сессия auth ещё не подтверждена (например Telegram до Start у бота). */
45
- declare class AuthSessionNotReadyError extends Error {
46
- readonly name = "AuthSessionNotReadyError";
47
- readonly cause?: unknown;
48
- constructor(message?: string, cause?: unknown);
85
+ /** Нет Basic на `/auth/token` (`AUTH_HEADER_MISSING`). */
86
+ declare class OtpAuthHeaderMissingError extends Error {
87
+ readonly name = "OtpAuthHeaderMissingError";
88
+ readonly body: unknown;
89
+ readonly systemMessage?: string;
90
+ constructor(body: unknown);
49
91
  }
50
92
 
51
93
  /**
@@ -144,88 +186,10 @@ declare class TokenSession {
144
186
  private persist;
145
187
  }
146
188
 
147
- /**
148
- * Внутренний оркестратор OTP-логина (не публичный export целиком; типы UI — да).
149
- *
150
- * **`sendCode`** → ветка по **`usedMethod`** (Mobile ID poll | classic код) →
151
- * **`TokenResp`**. UI снаружи: **`onSendCode`** + **`getCode`**.
152
- * IMAP / stdin / env — в app / `examples/node/_shared`, не здесь.
153
- *
154
- * Вызывается из `TorrowAuth.loginWithOtp`; Mobile ID — `mobile-id.ts`.
155
- */
156
-
157
- /**
158
- * Аргумент **`onSendCode`**: снимок **после** успешного `sendCode` (в основном поля **`SendCodeResp`**).
159
- * Не путать с телом запроса: в `sendCode` уходят `supportedMethods` / `preferredMethod`
160
- * (см. {@link RunOtpLoginOptions}); здесь — что сервер **выбрал** и что ещё доступно.
161
- *
162
- * Типичный UI: по `usedMethod` показать «ждём SMS» / «код на email» / «подтвердите push»;
163
- * по `codeLength` — маску поля ввода.
164
- */
165
- type OtpSendCodeResult = {
166
- /** Аккаунт из `SendCodeReq` (телефон / email). */
167
- accountName: string;
168
- /** `Phone` \| `Email` из запроса (не путать с `usedMethod`). */
169
- accountType: SendCodeAccountType;
170
- /** Id auth-сессии для последующего `requestToken` / Mobile ID poll. */
171
- sessionId: string;
172
- /**
173
- * Фактический канал из **`SendCodeResp.usedMethod`** — ради этого и нужен `onSendCode`.
174
- * Sms / Email / FlashCall / TelegramGateway / MtsMobileId / …
175
- */
176
- usedMethod?: VerificationMethod;
177
- /** Длина кода для input/маски; у Mobile ID часто `0` (keypad не нужен). */
178
- codeLength?: number;
179
- /** Интервал poll при Mobile ID (`SendCodeResp.pollIntervalSeconds`). */
180
- pollIntervalSeconds?: number;
181
- /**
182
- * Из **`SendCodeResp`** (не тело `sendCode`): методы, доступные для этого аккаунта
183
- * (UX «другой способ»). В запрос передаётся {@link RunOtpLoginOptions.supportedMethods}.
184
- */
185
- availableMethods?: VerificationMethod[] | null;
186
- /** TTL auth-сессии `sendCode` (сек); для Mobile ID — ориентир max wait. */
187
- sessionLifeTimeInSeconds?: number;
188
- /** Когда снова можно дернуть `sendCode` (rate-limit hint из ответа). */
189
- nextAvailableUsageTime?: Date | null;
190
- };
191
- /**
192
- * Аргумент **`getCode`**: только когда нужны цифры (stdin / UI / IMAP снаружи).
193
- *
194
- * UI-экран уже выбран в **`onSendCode`** (`usedMethod`). Здесь — собрать код
195
- * (длина из `codeLength`). На happy-path Mobile ID (push) **`getCode` не вызывается**;
196
- * SMS-fallback после poll — тот же колбэк, без отдельного `reason`.
197
- *
198
- * `accountName` / `accountType` не дублируются — они в options и в `onSendCode`.
199
- */
200
- type OtpGetCodeContext = {
201
- sessionId: string;
202
- /** Эффективная длина для валидации (Mobile ID SMS fallback: при `0` с сервера → 4). */
203
- codeLength?: number;
204
- /** Канал из `sendCode` (опциональная подсказка; экран уже из `onSendCode`). */
205
- usedMethod?: VerificationMethod;
206
- };
207
- /** Превышен лимит `sendCode` (`CODE_REQUEST_LIMIT_EXCEEDED`). */
208
- declare class OtpCodeRequestLimitExceededError extends Error {
209
- readonly name = "OtpCodeRequestLimitExceededError";
210
- readonly minutes?: string;
211
- readonly seconds?: string;
212
- readonly traceUrl?: string;
213
- readonly apiMessage?: string;
214
- readonly body: unknown;
215
- constructor(body: unknown);
216
- }
217
- /** Нет Basic на `/auth/token` (`AUTH_HEADER_MISSING`). */
218
- declare class OtpAuthHeaderMissingError extends Error {
219
- readonly name = "OtpAuthHeaderMissingError";
220
- readonly body: unknown;
221
- readonly systemMessage?: string;
222
- constructor(body: unknown);
223
- }
224
-
225
189
  /**
226
190
  * Публичный фасад аутентификации **`TorrowAuth`**.
227
191
  *
228
- * Точка входа приложения: `connect` / `loginWithOtp` / `loginWithLink` /
192
+ * Точка входа приложения: `createOtpFlow` / `connect` / `loginWithOtp` / `loginWithLink` /
229
193
  * `fromTokens` / `anonymous`. Возвращает {@link TorrowAuthResult}
230
194
  * (`{ client, session }`), кроме `anonymous` (только `TorrowClient`).
231
195
  *
@@ -294,6 +258,7 @@ type TorrowAuthLoginWithOtpOptions = TorrowAuthSessionBase & {
294
258
  preferredMethod?: VerificationMethod;
295
259
  /**
296
260
  * Capability клиента → `SendCodeReq.supportedMethods`.
261
+ * Порядок задаёт приоритет: для телефона рекомендуется `TelegramGateway`, `MtsMobileId`, `Sms`.
297
262
  * Без `MtsMobileId` сервер обычно не выберет Mobile ID.
298
263
  */
299
264
  supportedMethods?: VerificationMethod[];
@@ -334,12 +299,15 @@ type TorrowAuthFromTokensOptions = TorrowAuthSessionBase & {
334
299
  * Фасад аутентификации для приложений и виджетов.
335
300
  *
336
301
  * - {@link TorrowAuth.connect} — restore / refresh
302
+ * - {@link TorrowAuth.createOtpFlow} — раздельные OTP-шаги без сессии
337
303
  * - {@link TorrowAuth.loginWithOtp} — OTP (Phone/Email, Mobile ID / classic)
338
304
  * - {@link TorrowAuth.loginWithLink} — Telegram deep-link
339
305
  * - {@link TorrowAuth.fromTokens} — сид токенов от хоста
340
306
  * - {@link TorrowAuth.anonymous} — клиент без Bearer
341
307
  */
342
308
  declare const TorrowAuth: {
309
+ /** Пошаговый OTP без storage, polling и refresh. */
310
+ readonly createOtpFlow: typeof createOtpFlow;
343
311
  readonly connect: (options: TorrowAuthConnectOptions) => Promise<TorrowAuthResult>;
344
312
  readonly loginWithOtp: (options: TorrowAuthLoginWithOtpOptions) => Promise<TorrowAuthResult>;
345
313
  readonly loginWithLink: (options: TorrowAuthLoginWithLinkOptions) => Promise<TorrowAuthResult>;
@@ -347,4 +315,231 @@ declare const TorrowAuth: {
347
315
  readonly anonymous: (config?: Pick<TokenSessionOptions, "baseUrl" | "fetch" | "defaultHeaders" | "userAgent">) => TorrowClient;
348
316
  };
349
317
 
350
- export { AuthSessionNotReadyError, AuthTokenSnapshot, LocalStorageTokenStorage, MemoryTokenStorage, OtpAuthHeaderMissingError, OtpCodeRequestLimitExceededError, type OtpGetCodeContext, type OtpSendCodeResult, TokenSession, TokenSessionOptions, TokenSessionStatus, TokenSessionStatusListener, TokenStorage, TorrowAuth, type TorrowAuthAccount, type TorrowAuthConnectOptions, type TorrowAuthFromTokensOptions, type TorrowAuthLoginWithLinkOptions, type TorrowAuthLoginWithOtpOptions, type TorrowAuthResult, type TorrowAuthSessionBase };
318
+ /**
319
+ * Опции пошагового входа без TokenStorage и пользовательской сессии.
320
+ *
321
+ * HTTP-настройки из {@link TokenSessionOptions} применяются к обоим шагам:
322
+ * - `baseUrl` — адрес шлюза без `/api/v1`; по умолчанию `https://torrow.net`.
323
+ * - `fetch` — реализация HTTP-транспорта; по умолчанию глобальный `fetch`.
324
+ * - `defaultHeaders` — дополнительные заголовки каждого запроса.
325
+ * - `userAgent` — значение заголовка `User-Agent` для диагностики сервера.
326
+ *
327
+ * Между `start` и `complete`, в том числе на разных экземплярах flow,
328
+ * приложение сохраняет одинаковые deviceInfo, scopes и splitTokens.
329
+ */
330
+ type TorrowAuthOtpFlowOptions = Pick<TokenSessionOptions, "baseUrl" | "fetch" | "defaultHeaders" | "userAgent"> & {
331
+ /**
332
+ * Учётные данные приложения для Basic на `/api/v1/auth/*`.
333
+ * Если не заданы — используется {@link DEFAULT_APP_CREDENTIALS};
334
+ * явная пара полностью заменяет default и требует непустых clientId/clientSecret.
335
+ */
336
+ appCredentials?: AppCredentials;
337
+ /**
338
+ * Обязательное описание устройства для `TokenReq.deviceInfo` при `complete`.
339
+ * Требуются непустой deviceId и поддерживаемый deviceType; flow не генерирует deviceId.
340
+ */
341
+ deviceInfo: DeviceInfo;
342
+ /**
343
+ * Запрашиваемые области доступа → `TokenReq.scopes` при `complete`.
344
+ * Если поле отсутствует или массив пуст — `user_api` и `offline_access`.
345
+ */
346
+ scopes?: AuthScope[];
347
+ /**
348
+ * Разделение access/refresh сервером → `TokenReq.splitTokens` при `complete`.
349
+ * false: полные токены в JSON; используйте для Node, MCP и интеграционных ключей.
350
+ * true: части токенов в JSON, остальные части в HttpOnly cookies;
351
+ * только для браузерного приложения с настроенной передачей cookies.
352
+ * SDK не управляет cookies и не восстанавливает полные токены из частей.
353
+ * Явные true/false передаются без изменения; отсутствующее поле не отправляется.
354
+ */
355
+ splitTokens?: boolean;
356
+ };
357
+ /**
358
+ * Вход отправки кода; поля наследуются из {@link TorrowAuthLoginWithOtpOptions}.
359
+ * account задаёт Phone/Email и получателя; language — язык (default ru),
360
+ * regionStorageId — регион (default 70), captcha/captchaType — ответ и провайдер captcha,
361
+ * inviteSessionId — приглашение. preferredMethod — пожелание серверу,
362
+ * supportedMethods — способы, которые приложение умеет обработать, в порядке приоритета.
363
+ * Для телефона рекомендуется TelegramGateway → MtsMobileId → Sms.
364
+ * UI и получение captcha остаются в приложении.
365
+ */
366
+ type OtpStartInput = Pick<TorrowAuthLoginWithOtpOptions, "account" | "language" | "regionStorageId" | "captcha" | "captchaType" | "inviteSessionId" | "preferredMethod" | "supportedMethods">;
367
+ /** Опции одного HTTP-шага. */
368
+ type OtpRequestOptions = {
369
+ /** Отмена текущего HTTP-шага; не отменяет независимый cleanup приложения. */
370
+ signal?: AbortSignal;
371
+ };
372
+ /**
373
+ * Действие приложения для продолжения входа, отдельно от серверного TokenStatus.
374
+ * AwaitingCode — первоначальный ввод classic OTP либо новая фаза ввода SMS-кода
375
+ * после fallback из Pending в той же Mobile ID auth-сессии.
376
+ * Pending — ожидание Mobile ID, complete вызывается без кода.
377
+ */
378
+ declare enum OtpPhaseValues {
379
+ /** Требуется первоначальный OTP или SMS-код после Mobile ID fallback. */
380
+ AwaitingCode = "AwaitingCode",
381
+ /** Ожидание Mobile ID; следующий запрос выполняется без кода. */
382
+ Pending = "Pending"
383
+ }
384
+ /** JSON-значение фазы; принимает строковый литерал или член {@link OtpPhaseValues}. */
385
+ type OtpPhase = `${OtpPhaseValues}`;
386
+ /** Переносимое продолжение; приложение обеспечивает его целостность. */
387
+ type OtpChallenge = {
388
+ /** Идентификатор auth-сессии из SendCodeResp; сохраняется между шагами. */
389
+ sessionId: string;
390
+ /** Тип получателя первоначального кода: Phone или Email. */
391
+ accountType: SendCodeAccountType;
392
+ /** Фактический способ подтверждения; при SMS fallback меняется на Sms. */
393
+ usedMethod: VerificationMethod;
394
+ /** Следующее действие приложения: ввод кода или ожидание без кода. */
395
+ phase: OtpPhase;
396
+ /** Локальный deadline в Unix milliseconds, без продления; не гарантирует серверный срок. TTL из SendCodeResp либо 180 секунд от начала start. */
397
+ expiresAtMs: number;
398
+ /** Подсказка длины кода из SendCodeResp; default 6 для classic Email, 4 для Phone/Mobile ID. В переносимом challenge может отсутствовать. */
399
+ codeLength?: number;
400
+ /** Интервал ожидания в секундах для Pending; default 3. SDK сам не выполняет polling. */
401
+ pollIntervalSeconds?: number;
402
+ /** Оставшиеся попытки из SendCodeResp.attemptCountToUseSession; SDK не уменьшает их. Отсутствие означает, что корректная подсказка не получена. */
403
+ attemptsRemaining?: number;
404
+ /** Время следующей отправки из SendCodeResp.nextAvailableUsageTime в Unix milliseconds; отсутствует без корректной подсказки. */
405
+ nextSendAtMs?: number;
406
+ /** Доступные способы из SendCodeResp; отсутствуют, если список отсутствовал или содержал неизвестные значения. */
407
+ availableMethods?: VerificationMethod[];
408
+ };
409
+ /** Параметры одной попытки обмена или ожидания. */
410
+ type OtpCompleteInput = {
411
+ /** Переносимое продолжение; проверяется перед запросом, целостность обеспечивает приложение. */
412
+ challenge: OtpChallenge;
413
+ /** Непустой OTP в AwaitingCode; в Pending поле должно отсутствовать. */
414
+ code?: string;
415
+ };
416
+ /** Данные для явного cleanup вызывающим приложением. */
417
+ type OtpCleanupData = {
418
+ /** Refresh-секрет для явного отзыва приложением; не предназначен для диагностики. */
419
+ refreshToken: string;
420
+ };
421
+ /** Причины локального отказа; HTTP и отмена пробрасываются без преобразования. */
422
+ declare enum OtpFlowErrorCodeValues {
423
+ /** Некорректные опции, вход start или код для текущей фазы. */
424
+ InvalidArguments = "InvalidArguments",
425
+ /** Повреждённое, противоречивое или просроченное продолжение. */
426
+ InvalidChallenge = "InvalidChallenge",
427
+ /** Ответ не соответствует строгому контракту шага. */
428
+ InvalidResponse = "InvalidResponse",
429
+ /** Фактический способ подтверждения отсутствует или не поддерживается для аккаунта. */
430
+ UnsupportedMethod = "UnsupportedMethod"
431
+ }
432
+ /** Строковое представление безопасной причины отказа. */
433
+ type OtpFlowErrorCode = `${OtpFlowErrorCodeValues}`;
434
+ /** Отказ с безопасной диагностикой и отдельно доступным секретом для cleanup. */
435
+ declare class OtpFlowError extends Error {
436
+ #private;
437
+ /** Безопасная причина локального отказа, без исходного ответа и секретов. */
438
+ readonly code: OtpFlowErrorCode;
439
+ readonly name = "OtpFlowError";
440
+ constructor(
441
+ /** Безопасная причина локального отказа, без исходного ответа и секретов. */
442
+ code: OtpFlowErrorCode, cleanup?: OtpCleanupData);
443
+ /** Секрет доступен явно; не является перечисляемым полем исключения. */
444
+ get cleanup(): OtpCleanupData | undefined;
445
+ }
446
+ /**
447
+ * Результат одного шага: серверный статус отдельно от фазы challenge.
448
+ * Pending — сервер ещё не завершил аутентификацию, следующий запрос без кода.
449
+ * AwaitingSmsCode — продолжение Mobile ID-сценария через SMS fallback,
450
+ * если аутентификацию через Mobile ID не удалось завершить. Возвращённый challenge
451
+ * меняет фазу Pending на AwaitingCode и метод на Sms; sessionId и deadline сохраняются.
452
+ * TokenReady — токены выданы; Failed — терминальный отказ без продолжения.
453
+ * Обычный Email/SMS OTP начинается с AwaitingCode после start,
454
+ * без отдельного серверного AwaitingEmailCode.
455
+ */
456
+ type OtpCompleteResult = {
457
+ /** Сервер ещё ожидает подтверждения либо запросил SMS fallback. */
458
+ status: TokenStatusValues.Pending | TokenStatusValues.AwaitingSmsCode;
459
+ /** Продолжение с новым действием приложения и прежним deadline. */
460
+ challenge: OtpChallenge;
461
+ /** Неожиданный refresh для явного отзыва; отсутствует, если сервер его не выдал. */
462
+ cleanup?: OtpCleanupData;
463
+ } | {
464
+ /** Терминальный отказ сервера; продолжение не возвращается. */
465
+ status: TokenStatusValues.Failed;
466
+ /** Неожиданный refresh для явного отзыва; отсутствует без refresh в ответе. */
467
+ cleanup?: OtpCleanupData;
468
+ } | {
469
+ /** Сервер явно подтвердил выдачу токенов. */
470
+ status: TokenStatusValues.TokenReady;
471
+ /**
472
+ * Проверенные поля TokenResp: accessToken обязателен, refreshToken и expiration
473
+ * (TTL в секундах) сохраняются при наличии; splitTokens определяет полноту токенов.
474
+ */
475
+ tokens: Omit<TokenResp, "status" | "accessToken"> & {
476
+ /** Явный статус готовности из token-ответа. */
477
+ status: TokenStatusValues.TokenReady;
478
+ /** Непустой access token из ответа после нормализации aliases. */
479
+ accessToken: string;
480
+ };
481
+ };
482
+ /** Пошаговый интерфейс: каждый метод выполняет только один upstream-запрос. */
483
+ interface OtpFlow {
484
+ /** Отправляет один код и возвращает переносимое продолжение без токенов. */
485
+ start(input: OtpStartInput, options?: OtpRequestOptions): Promise<OtpChallenge>;
486
+ /** Проверяет продолжение и выполняет одну попытку обмена/ожидания без сохранения. */
487
+ complete(input: OtpCompleteInput, options?: OtpRequestOptions): Promise<OtpCompleteResult>;
488
+ }
489
+ /**
490
+ * Создаёт OTP-flow с фиксированными настройками транспорта и token-обмена.
491
+ * Создание не выполняет HTTP; start и complete выполняют по одному запросу.
492
+ * Challenge и токены остаются у приложения, без storage, polling и refresh внутри flow.
493
+ * @param options Настройки HTTP, credentials приложения, устройства и выдачи токенов.
494
+ * @returns Независимые шаги отправки кода и завершения/ожидания аутентификации.
495
+ * @throws OtpFlowError При некорректных опциях устройства, scopes или splitTokens.
496
+ */
497
+ declare function createOtpFlow(options: TorrowAuthOtpFlowOptions): OtpFlow;
498
+
499
+ /**
500
+ * In-memory реализация {@link TokenStorage}.
501
+ *
502
+ * Тесты, эфемерные процессы, `TorrowAuth.fromTokens` без диска.
503
+ * Для Node-примеров обычно {@link FileTokenStorage}; для браузера —
504
+ * {@link LocalStorageTokenStorage}.
505
+ */
506
+
507
+ /** In-memory хранилище токенов сессии. */
508
+ declare class MemoryTokenStorage implements TokenStorage {
509
+ private snapshot;
510
+ constructor(initial?: AuthTokenSnapshot);
511
+ load(): Promise<AuthTokenSnapshot>;
512
+ save(snapshot: AuthTokenSnapshot): Promise<void>;
513
+ }
514
+
515
+ /**
516
+ * Persist snapshot в браузерный **`localStorage`** — реализация {@link TokenStorage}.
517
+ *
518
+ * Для виджетов / SPA (`TorrowAuth.fromTokens` / `connect`). В Node без
519
+ * `globalThis.localStorage` конструктор бросит. Не путать с {@link FileTokenStorage}.
520
+ */
521
+
522
+ type LocalStorageLike = {
523
+ getItem(key: string): string | null;
524
+ setItem(key: string, value: string): void;
525
+ removeItem?(key: string): void;
526
+ };
527
+ /**
528
+ * Persist snapshot токенов в браузерный `localStorage` (виджет / SPA).
529
+ */
530
+ declare class LocalStorageTokenStorage implements TokenStorage {
531
+ readonly key: string;
532
+ private readonly store;
533
+ constructor(key: string, store?: LocalStorageLike);
534
+ load(): Promise<AuthTokenSnapshot>;
535
+ save(snapshot: AuthTokenSnapshot): Promise<void>;
536
+ }
537
+
538
+ /** Сессия auth ещё не подтверждена (например Telegram до Start у бота). */
539
+ declare class AuthSessionNotReadyError extends Error {
540
+ readonly name = "AuthSessionNotReadyError";
541
+ readonly cause?: unknown;
542
+ constructor(message?: string, cause?: unknown);
543
+ }
544
+
545
+ export { AppCredentials, AuthSessionNotReadyError, AuthTokenSnapshot, DEFAULT_APP_CREDENTIALS, LocalStorageTokenStorage, MemoryTokenStorage, OtpAuthHeaderMissingError, type OtpChallenge, type OtpCleanupData, OtpCodeRequestLimitExceededError, type OtpCompleteInput, type OtpCompleteResult, type OtpFlow, OtpFlowError, type OtpFlowErrorCode, OtpFlowErrorCodeValues, type OtpGetCodeContext, type OtpPhase, OtpPhaseValues, type OtpRequestOptions, type OtpSendCodeResult, type OtpStartInput, TokenSession, TokenSessionOptions, TokenSessionStatus, TokenSessionStatusListener, TokenStorage, TorrowAuth, type TorrowAuthAccount, type TorrowAuthConnectOptions, type TorrowAuthFromTokensOptions, type TorrowAuthLoginWithLinkOptions, type TorrowAuthLoginWithOtpOptions, type TorrowAuthOtpFlowOptions, type TorrowAuthResult, type TorrowAuthSessionBase };