@torrow/sdk-auth 0.6.0 → 0.7.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.js CHANGED
@@ -1,4 +1,4 @@
1
- // ../../src/auth-session/types.ts
1
+ // ../../src/auth-session/app-credentials.ts
2
2
  var DEFAULT_APP_CREDENTIALS = {
3
3
  clientId: "sdk.torrow.net",
4
4
  clientSecret: "4YM1qYq87faSXaFqXTBcnJrn/jj0AOXl6tTsfubLyCE="
@@ -13,6 +13,278 @@ function appCredentialsToAuthIdentityBasic(appCredentials) {
13
13
  return { username: clientId, password: clientSecret };
14
14
  }
15
15
 
16
+ // ../../src/auth-session/otp-flow.ts
17
+ import {
18
+ isAuthCaptchaType,
19
+ isDeviceType,
20
+ isSendCodeAccountType,
21
+ isVerificationMethod,
22
+ TokenStatusValues as TokenStatusValues2,
23
+ VerificationMethodValues
24
+ } from "@torrow/sdk-client";
25
+
26
+ // ../../src/auth-session/identity-client.ts
27
+ import { TorrowClient } from "@torrow/sdk-client";
28
+ function createIdentityClient(options) {
29
+ const authIdentityBasic = appCredentialsToAuthIdentityBasic(
30
+ resolveAppCredentials(options.appCredentials)
31
+ );
32
+ if (!authIdentityBasic) {
33
+ throw new Error(
34
+ "TokenSession: \u043D\u0435\u043F\u043E\u043B\u043D\u0430\u044F appCredentials (\u043D\u0443\u0436\u043D\u044B \u043D\u0435\u043F\u0443\u0441\u0442\u044B\u0435 clientId \u0438 clientSecret). \u0411\u0435\u0437 \u043E\u043F\u0446\u0438\u0438 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F DEFAULT_APP_CREDENTIALS."
35
+ );
36
+ }
37
+ return new TorrowClient({
38
+ baseUrl: options.baseUrl,
39
+ fetch: options.fetch,
40
+ defaultHeaders: options.defaultHeaders,
41
+ userAgent: options.userAgent,
42
+ authIdentityBasic
43
+ });
44
+ }
45
+
46
+ // ../../src/auth-session/auth-protocol.ts
47
+ import {
48
+ DefaultAuthScopes,
49
+ isTokenStatus,
50
+ TokenStatusValues
51
+ } from "@torrow/sdk-client";
52
+ function buildOtpSendRequest(input) {
53
+ const accountName = input.accountName.trim();
54
+ if (!accountName) throw new Error("runOtpLogin: accountName is empty");
55
+ return {
56
+ accountName,
57
+ type: input.type,
58
+ language: input.language?.trim() || "ru",
59
+ regionStorageId: typeof input.regionStorageId === "number" && Number.isFinite(input.regionStorageId) ? input.regionStorageId : 70,
60
+ ...input.captcha?.trim() ? { captcha: input.captcha.trim() } : {},
61
+ ...input.captchaType ? { captchaType: input.captchaType } : {},
62
+ ...input.inviteSessionId?.trim() ? { inviteSessionId: input.inviteSessionId.trim() } : {},
63
+ ...input.preferredMethod ? { preferredMethod: input.preferredMethod } : {},
64
+ ...input.supportedMethods?.length ? { supportedMethods: input.supportedMethods } : {}
65
+ };
66
+ }
67
+ function sendOtpCode(client, input, signal) {
68
+ return client.auth.sendCode(buildOtpSendRequest(input), { signal });
69
+ }
70
+ function requestAuthToken(client, input, signal) {
71
+ return client.auth.requestToken(
72
+ {
73
+ sessionId: input.sessionId,
74
+ code: input.code,
75
+ deviceInfo: input.deviceInfo,
76
+ scopes: input.scopes?.length ? input.scopes : [...DefaultAuthScopes],
77
+ ...input.splitTokens !== void 0 ? { splitTokens: input.splitTokens } : {}
78
+ },
79
+ { signal }
80
+ );
81
+ }
82
+ function tokenTransition(status, legacy = false) {
83
+ if (legacy && status == null) return TokenStatusValues.TokenReady;
84
+ return typeof status === "string" && isTokenStatus(status) ? status : void 0;
85
+ }
86
+ function tokenResponseFields(o) {
87
+ return {
88
+ access: o.accessToken ?? o.AccessToken ?? o.access_token,
89
+ refresh: o.refreshToken ?? o.RefreshToken ?? o.refresh_token,
90
+ expiration: o.expiration ?? o.Expiration ?? o.expires_in,
91
+ status: o.status ?? o.Status
92
+ };
93
+ }
94
+
95
+ // ../../src/auth-session/otp-flow.ts
96
+ var OtpPhaseValues = /* @__PURE__ */ ((OtpPhaseValues2) => {
97
+ OtpPhaseValues2["AwaitingCode"] = "AwaitingCode";
98
+ OtpPhaseValues2["Pending"] = "Pending";
99
+ return OtpPhaseValues2;
100
+ })(OtpPhaseValues || {});
101
+ var OtpFlowErrorCodeValues = /* @__PURE__ */ ((OtpFlowErrorCodeValues2) => {
102
+ OtpFlowErrorCodeValues2["InvalidArguments"] = "InvalidArguments";
103
+ OtpFlowErrorCodeValues2["InvalidChallenge"] = "InvalidChallenge";
104
+ OtpFlowErrorCodeValues2["InvalidResponse"] = "InvalidResponse";
105
+ OtpFlowErrorCodeValues2["UnsupportedMethod"] = "UnsupportedMethod";
106
+ return OtpFlowErrorCodeValues2;
107
+ })(OtpFlowErrorCodeValues || {});
108
+ var OtpFlowError = class extends Error {
109
+ constructor(code, cleanup) {
110
+ super(`OTP flow: ${code}`);
111
+ this.code = code;
112
+ this.#cleanup = cleanup ? Object.freeze({ ...cleanup }) : void 0;
113
+ }
114
+ code;
115
+ name = "OtpFlowError";
116
+ #cleanup;
117
+ /** Секрет доступен явно; не является перечисляемым полем исключения. */
118
+ get cleanup() {
119
+ return this.#cleanup;
120
+ }
121
+ };
122
+ function createOtpFlow(options) {
123
+ if (!isRecord(options) || !isRecord(options.deviceInfo) || typeof options.deviceInfo.deviceId !== "string" || !options.deviceInfo.deviceId.trim() || typeof options.deviceInfo.deviceType !== "string" || !isDeviceType(options.deviceInfo.deviceType) || options.scopes !== void 0 && (!Array.isArray(options.scopes) || !options.scopes.every(
124
+ (scope) => typeof scope === "string" && scope.trim()
125
+ )) || options.splitTokens !== void 0 && typeof options.splitTokens !== "boolean")
126
+ throw new OtpFlowError("InvalidArguments" /* InvalidArguments */);
127
+ const client = createIdentityClient(options);
128
+ const deviceInfo = { ...options.deviceInfo };
129
+ const scopes = options.scopes ? [...options.scopes] : void 0;
130
+ const splitTokens = options.splitTokens;
131
+ return {
132
+ async start(input, requestOptions) {
133
+ validateStartInput(input);
134
+ requestOptions?.signal?.throwIfAborted();
135
+ const startedAt = Date.now();
136
+ const response = await sendOtpCode(
137
+ client,
138
+ {
139
+ ...input,
140
+ accountName: input.account.accountName,
141
+ type: input.account.accountType
142
+ },
143
+ requestOptions?.signal
144
+ );
145
+ if (!isRecord(response) || typeof response.sessionId !== "string" || !response.sessionId.trim())
146
+ throw new OtpFlowError("InvalidResponse" /* InvalidResponse */);
147
+ if (!supportedMethod(response.usedMethod, input.account.accountType))
148
+ throw new OtpFlowError("UnsupportedMethod" /* UnsupportedMethod */);
149
+ const ttl = response.sessionLifeTimeInSeconds ?? 180;
150
+ if (!positive(ttl)) throw new OtpFlowError("InvalidResponse" /* InvalidResponse */);
151
+ const expiresAtMs = startedAt + ttl * 1e3;
152
+ if (!timestamp(expiresAtMs) || expiresAtMs <= Date.now())
153
+ throw new OtpFlowError("InvalidResponse" /* InvalidResponse */);
154
+ const mobile = response.usedMethod === VerificationMethodValues.MtsMobileId;
155
+ const nextSendAtMs = response.nextAvailableUsageTime instanceof Date ? response.nextAvailableUsageTime.getTime() : typeof response.nextAvailableUsageTime === "string" ? Date.parse(response.nextAvailableUsageTime) : void 0;
156
+ return {
157
+ sessionId: response.sessionId.trim(),
158
+ accountType: input.account.accountType,
159
+ usedMethod: response.usedMethod,
160
+ phase: mobile ? "Pending" /* Pending */ : "AwaitingCode" /* AwaitingCode */,
161
+ expiresAtMs,
162
+ codeLength: codeLength(response.codeLength) ? response.codeLength : input.account.accountType === "Email" && !mobile ? 6 : 4,
163
+ ...mobile ? {
164
+ pollIntervalSeconds: positive(response.pollIntervalSeconds) ? response.pollIntervalSeconds : 3
165
+ } : {},
166
+ ...attempts(response.attemptCountToUseSession) ? { attemptsRemaining: response.attemptCountToUseSession } : {},
167
+ ...timestamp(nextSendAtMs) ? { nextSendAtMs } : {},
168
+ ...methods(response.availableMethods) ? { availableMethods: [...response.availableMethods] } : {}
169
+ };
170
+ },
171
+ async complete(input, requestOptions) {
172
+ if (!isRecord(input)) throw new OtpFlowError("InvalidArguments" /* InvalidArguments */);
173
+ requestOptions?.signal?.throwIfAborted();
174
+ const continuation = validateChallenge(input.challenge);
175
+ if (continuation.phase === "Pending" /* Pending */ && input.code !== void 0 || continuation.phase === "AwaitingCode" /* AwaitingCode */ && (typeof input.code !== "string" || !input.code.trim()))
176
+ throw new OtpFlowError("InvalidArguments" /* InvalidArguments */);
177
+ const raw = await requestAuthToken(
178
+ client,
179
+ {
180
+ sessionId: continuation.sessionId,
181
+ code: input.code?.trim() ?? "",
182
+ deviceInfo,
183
+ scopes,
184
+ splitTokens
185
+ },
186
+ requestOptions?.signal
187
+ );
188
+ if (!isRecord(raw)) throw new OtpFlowError("InvalidResponse" /* InvalidResponse */);
189
+ const fields = tokenResponseFields(raw);
190
+ const refreshToken = typeof fields.refresh === "string" && fields.refresh.trim() ? fields.refresh.trim() : void 0;
191
+ const cleanup = refreshToken ? { refreshToken } : void 0;
192
+ const status = tokenTransition(
193
+ typeof fields.status === "string" ? fields.status.trim() : fields.status
194
+ );
195
+ if (!status || fields.access != null && typeof fields.access !== "string" || fields.refresh != null && typeof fields.refresh !== "string" || fields.expiration != null && (typeof fields.expiration !== "number" || !Number.isFinite(fields.expiration) || fields.expiration < 0))
196
+ throw new OtpFlowError("InvalidResponse" /* InvalidResponse */, cleanup);
197
+ if (status === TokenStatusValues2.Pending)
198
+ return {
199
+ status,
200
+ cleanup,
201
+ challenge: {
202
+ ...continuation,
203
+ phase: "Pending" /* Pending */,
204
+ usedMethod: VerificationMethodValues.MtsMobileId,
205
+ pollIntervalSeconds: continuation.pollIntervalSeconds ?? 3
206
+ }
207
+ };
208
+ if (status === TokenStatusValues2.AwaitingSmsCode) {
209
+ const { pollIntervalSeconds: _interval, ...challenge } = continuation;
210
+ return {
211
+ status,
212
+ cleanup,
213
+ challenge: {
214
+ ...challenge,
215
+ phase: "AwaitingCode" /* AwaitingCode */,
216
+ usedMethod: VerificationMethodValues.Sms,
217
+ codeLength: challenge.codeLength || 4
218
+ }
219
+ };
220
+ }
221
+ if (status === TokenStatusValues2.Failed) return { status, cleanup };
222
+ if (typeof fields.access !== "string" || !fields.access.trim())
223
+ throw new OtpFlowError("InvalidResponse" /* InvalidResponse */, cleanup);
224
+ return {
225
+ status,
226
+ tokens: {
227
+ status,
228
+ accessToken: fields.access.trim(),
229
+ ...refreshToken ? { refreshToken } : {},
230
+ ...typeof fields.expiration === "number" ? { expiration: fields.expiration } : {}
231
+ }
232
+ };
233
+ }
234
+ };
235
+ }
236
+ function isRecord(value) {
237
+ return value !== null && typeof value === "object" && !Array.isArray(value);
238
+ }
239
+ function positive(value) {
240
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
241
+ }
242
+ function codeLength(value) {
243
+ return positive(value) && Number.isInteger(value) && value <= 32;
244
+ }
245
+ function attempts(value) {
246
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
247
+ }
248
+ function timestamp(value) {
249
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 && value <= 864e13;
250
+ }
251
+ function methods(value) {
252
+ return Array.isArray(value) && value.every(
253
+ (method) => typeof method === "string" && isVerificationMethod(method)
254
+ );
255
+ }
256
+ function supportedMethod(value, accountType) {
257
+ return typeof value === "string" && isVerificationMethod(value) && (value !== VerificationMethodValues.UnknownMethod || accountType === "Email");
258
+ }
259
+ function validateStartInput(input) {
260
+ if (!isRecord(input) || !isRecord(input.account) || typeof input.account.accountType !== "string" || !isSendCodeAccountType(input.account.accountType) || typeof input.account.accountName !== "string" || !input.account.accountName.trim())
261
+ throw new OtpFlowError("InvalidArguments" /* InvalidArguments */);
262
+ for (const field of ["language", "captcha", "inviteSessionId"]) {
263
+ if (input[field] !== void 0 && typeof input[field] !== "string")
264
+ throw new OtpFlowError("InvalidArguments" /* InvalidArguments */);
265
+ }
266
+ if (input.regionStorageId !== void 0 && !attempts(input.regionStorageId) || input.captchaType !== void 0 && (typeof input.captchaType !== "string" || !isAuthCaptchaType(input.captchaType)) || input.preferredMethod !== void 0 && (typeof input.preferredMethod !== "string" || !isVerificationMethod(input.preferredMethod)) || input.supportedMethods !== void 0 && !methods(input.supportedMethods))
267
+ throw new OtpFlowError("InvalidArguments" /* InvalidArguments */);
268
+ }
269
+ function validateChallenge(value) {
270
+ if (!isRecord(value) || typeof value.sessionId !== "string" || !value.sessionId.trim() || typeof value.accountType !== "string" || !isSendCodeAccountType(value.accountType) || !supportedMethod(value.usedMethod, value.accountType) || value.phase !== "Pending" /* Pending */ && value.phase !== "AwaitingCode" /* AwaitingCode */ || !timestamp(value.expiresAtMs) || value.expiresAtMs <= Date.now() || value.phase === "Pending" /* Pending */ !== (value.usedMethod === VerificationMethodValues.MtsMobileId))
271
+ throw new OtpFlowError("InvalidChallenge" /* InvalidChallenge */);
272
+ if (value.codeLength !== void 0 && !codeLength(value.codeLength) || value.pollIntervalSeconds !== void 0 && !positive(value.pollIntervalSeconds) || value.attemptsRemaining !== void 0 && !attempts(value.attemptsRemaining) || value.nextSendAtMs !== void 0 && !timestamp(value.nextSendAtMs) || value.availableMethods !== void 0 && !methods(value.availableMethods))
273
+ throw new OtpFlowError("InvalidChallenge" /* InvalidChallenge */);
274
+ return {
275
+ sessionId: value.sessionId.trim(),
276
+ accountType: value.accountType,
277
+ usedMethod: value.usedMethod,
278
+ phase: value.phase,
279
+ expiresAtMs: value.expiresAtMs,
280
+ ...codeLength(value.codeLength) ? { codeLength: value.codeLength } : {},
281
+ ...positive(value.pollIntervalSeconds) ? { pollIntervalSeconds: value.pollIntervalSeconds } : {},
282
+ ...attempts(value.attemptsRemaining) ? { attemptsRemaining: value.attemptsRemaining } : {},
283
+ ...timestamp(value.nextSendAtMs) ? { nextSendAtMs: value.nextSendAtMs } : {},
284
+ ...methods(value.availableMethods) ? { availableMethods: [...value.availableMethods] } : {}
285
+ };
286
+ }
287
+
16
288
  // ../../src/auth-session/token-storage.ts
17
289
  var MemoryTokenStorage = class {
18
290
  snapshot;
@@ -105,11 +377,11 @@ function isAuthSessionNotReadyYet(e) {
105
377
 
106
378
  // ../../src/auth-session/TokenSession.ts
107
379
  import {
108
- DefaultAuthScopes,
109
- TorrowClient,
380
+ DefaultAuthScopes as DefaultAuthScopes2,
381
+ TorrowClient as TorrowClient2,
110
382
  TorrowHttpError as TorrowHttpError2,
111
383
  DeviceTypeValues,
112
- isTokenRespReadyStatus as isTokenRespReadyStatus2
384
+ TokenStatusValues as TokenStatusValues3
113
385
  } from "@torrow/sdk-client";
114
386
 
115
387
  // ../../src/auth-session/fetch-with-401-retry.ts
@@ -151,10 +423,7 @@ function normalizeTokenResp(raw) {
151
423
  }
152
424
  if (typeof raw !== "object") return {};
153
425
  const o = raw;
154
- const access = o.accessToken ?? o.AccessToken ?? o.access_token;
155
- const refresh = o.refreshToken ?? o.RefreshToken ?? o.refresh_token;
156
- const expRaw = o.expiration ?? o.Expiration ?? o.expires_in;
157
- const statusRaw = o.status ?? o.Status;
426
+ const { access, refresh, expiration: expRaw, status: statusRaw } = tokenResponseFields(o);
158
427
  const out = {};
159
428
  if (typeof access === "string" && access.trim()) out.accessToken = access.trim();
160
429
  if (typeof refresh === "string" && refresh.trim()) out.refreshToken = refresh.trim();
@@ -349,14 +618,15 @@ var TokenSession = class _TokenSession {
349
618
  if (!sessionId || !code) {
350
619
  throw new Error("TokenSession.requestTokenWithCode: sessionId and code are required");
351
620
  }
352
- const scopes = args.scopes && args.scopes.length > 0 ? args.scopes : [...DefaultAuthScopes];
621
+ const scopes = args.scopes && args.scopes.length > 0 ? args.scopes : [...DefaultAuthScopes2];
353
622
  const deviceInfo = this.resolveDeviceInfo();
354
623
  let resp;
355
624
  try {
356
625
  resp = normalizeTokenResp(
357
- await this.identityClient().auth.requestToken(
626
+ await requestAuthToken(
627
+ this.identityClient(),
358
628
  { sessionId, code, scopes, deviceInfo },
359
- { signal: args.signal }
629
+ args.signal
360
630
  )
361
631
  );
362
632
  } catch (e) {
@@ -365,7 +635,7 @@ var TokenSession = class _TokenSession {
365
635
  }
366
636
  throw e;
367
637
  }
368
- if (!isTokenRespReadyStatus2(resp.status)) {
638
+ if (tokenTransition(resp.status, true) !== TokenStatusValues3.TokenReady) {
369
639
  throw new AuthSessionNotReadyError(
370
640
  `TokenResp.status=${resp.status} (\u043E\u0436\u0438\u0434\u0430\u043B\u0441\u044F TokenReady)`
371
641
  );
@@ -537,21 +807,7 @@ var TokenSession = class _TokenSession {
537
807
  }
538
808
  /** Identity-клиент с Basic приложения, без Bearer пользователя. */
539
809
  identityClient() {
540
- const authIdentityBasic = appCredentialsToAuthIdentityBasic(
541
- resolveAppCredentials(this.opts.appCredentials)
542
- );
543
- if (!authIdentityBasic) {
544
- throw new Error(
545
- "TokenSession: \u043D\u0435\u043F\u043E\u043B\u043D\u0430\u044F appCredentials (\u043D\u0443\u0436\u043D\u044B \u043D\u0435\u043F\u0443\u0441\u0442\u044B\u0435 clientId \u0438 clientSecret). \u0411\u0435\u0437 \u043E\u043F\u0446\u0438\u0438 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F DEFAULT_APP_CREDENTIALS."
546
- );
547
- }
548
- return new TorrowClient({
549
- baseUrl: this.opts.baseUrl,
550
- fetch: this.opts.fetch,
551
- defaultHeaders: this.opts.defaultHeaders,
552
- userAgent: this.opts.userAgent,
553
- authIdentityBasic
554
- });
810
+ return createIdentityClient(this.opts);
555
811
  }
556
812
  buildClient() {
557
813
  let fetchImpl = this.opts.fetch;
@@ -575,7 +831,7 @@ var TokenSession = class _TokenSession {
575
831
  }
576
832
  });
577
833
  }
578
- return new TorrowClient({
834
+ return new TorrowClient2({
579
835
  baseUrl: this.opts.baseUrl,
580
836
  fetch: fetchImpl,
581
837
  defaultHeaders: this.opts.defaultHeaders,
@@ -594,13 +850,13 @@ var TokenSession = class _TokenSession {
594
850
 
595
851
  // ../../src/auth-session/torrow-auth.ts
596
852
  import {
597
- TorrowClient as TorrowClient2
853
+ TorrowClient as TorrowClient3
598
854
  } from "@torrow/sdk-client";
599
855
 
600
856
  // ../../src/auth-session/link-login.ts
601
857
  import {
602
858
  AccountTypeValues,
603
- DefaultAuthScopes as DefaultAuthScopes2
859
+ DefaultAuthScopes as DefaultAuthScopes3
604
860
  } from "@torrow/sdk-client";
605
861
 
606
862
  // ../../src/auth-session/sleep.ts
@@ -649,7 +905,7 @@ async function runLinkLogin(session, options) {
649
905
  );
650
906
  }
651
907
  await options.onLink(authUrl);
652
- const scopes = options.scopes && options.scopes.length > 0 ? options.scopes : [...DefaultAuthScopes2];
908
+ const scopes = options.scopes && options.scopes.length > 0 ? options.scopes : [...DefaultAuthScopes3];
653
909
  const intervalMs = typeof options.pollIntervalMs === "number" && options.pollIntervalMs > 0 ? options.pollIntervalMs : DEFAULT_POLL_INTERVAL_MS;
654
910
  const timeoutSec = typeof options.pollTimeoutSec === "number" && options.pollTimeoutSec > 0 ? options.pollTimeoutSec : typeof createResp.sessionLifeTimeInSeconds === "number" && createResp.sessionLifeTimeInSeconds > 0 ? createResp.sessionLifeTimeInSeconds : DEFAULT_POLL_TIMEOUT_SEC;
655
911
  const deadline = Date.now() + timeoutSec * 1e3;
@@ -676,23 +932,22 @@ async function runLinkLogin(session, options) {
676
932
 
677
933
  // ../../src/auth-session/otp-login.ts
678
934
  import {
679
- DefaultAuthScopes as DefaultAuthScopes4,
680
- isTokenRespReadyStatus as isTokenRespReadyStatus4,
935
+ DefaultAuthScopes as DefaultAuthScopes5,
681
936
  SendCodeAccountTypeValues,
682
937
  TorrowHttpError as TorrowHttpError3,
683
- VerificationMethodValues
938
+ VerificationMethodValues as VerificationMethodValues2,
939
+ TokenStatusValues as TokenStatusValues5
684
940
  } from "@torrow/sdk-client";
685
941
 
686
942
  // ../../src/auth-session/mobile-id.ts
687
943
  import {
688
- DefaultAuthScopes as DefaultAuthScopes3,
689
- isTokenRespReadyStatus as isTokenRespReadyStatus3,
690
- TokenStatusValues
944
+ DefaultAuthScopes as DefaultAuthScopes4,
945
+ TokenStatusValues as TokenStatusValues4
691
946
  } from "@torrow/sdk-client";
692
947
  var DEFAULT_POLL_INTERVAL_SEC = 3;
693
948
  var DEFAULT_MAX_WAIT_SEC = 180;
694
949
  function scopesOrDefault(scopes) {
695
- return scopes && scopes.length > 0 ? scopes : [...DefaultAuthScopes3];
950
+ return scopes && scopes.length > 0 ? scopes : [...DefaultAuthScopes4];
696
951
  }
697
952
  async function pollMobileIdOnce(client, args) {
698
953
  const sessionId = args.sessionId.trim();
@@ -706,7 +961,7 @@ async function pollMobileIdOnce(client, args) {
706
961
  scopes: scopesOrDefault(args.scopes),
707
962
  deviceInfo: args.deviceInfo
708
963
  };
709
- return normalizeTokenResp(await client.auth.requestToken(body, { signal: args.signal }));
964
+ return normalizeTokenResp(await requestAuthToken(client, body, args.signal));
710
965
  }
711
966
  async function pollMobileIdUntilReady(client, options) {
712
967
  const sessionId = options.sessionId.trim();
@@ -728,15 +983,15 @@ async function pollMobileIdUntilReady(client, options) {
728
983
  signal: options.signal
729
984
  });
730
985
  const status = resp.status;
731
- if (isTokenRespReadyStatus3(status)) {
986
+ if (tokenTransition(status, true) === TokenStatusValues4.TokenReady) {
732
987
  return assertTokenRespReadyForStorage(resp, "pollMobileIdUntilReady");
733
988
  }
734
- if (status === TokenStatusValues.Failed) {
989
+ if (status === TokenStatusValues4.Failed) {
735
990
  throw new Error(
736
991
  "pollMobileIdUntilReady: TokenResp.status=Failed \u2014 \u043D\u0443\u0436\u0435\u043D \u043D\u043E\u0432\u044B\u0439 sendCode."
737
992
  );
738
993
  }
739
- if (status === TokenStatusValues.AwaitingSmsCode) {
994
+ if (status === TokenStatusValues4.AwaitingSmsCode) {
740
995
  const obtain = options.obtainSmsCode;
741
996
  if (!obtain) {
742
997
  throw new Error(
@@ -756,25 +1011,25 @@ async function pollMobileIdUntilReady(client, options) {
756
1011
  code,
757
1012
  signal: options.signal
758
1013
  });
759
- if (isTokenRespReadyStatus3(afterSms.status)) {
1014
+ if (tokenTransition(afterSms.status, true) === TokenStatusValues4.TokenReady) {
760
1015
  return assertTokenRespReadyForStorage(afterSms, "pollMobileIdUntilReady (SMS)");
761
1016
  }
762
- if (afterSms.status === TokenStatusValues.Failed) {
1017
+ if (afterSms.status === TokenStatusValues4.Failed) {
763
1018
  throw new Error(
764
1019
  "pollMobileIdUntilReady: TokenResp.status=Failed \u043F\u043E\u0441\u043B\u0435 SMS \u2014 \u043D\u0443\u0436\u0435\u043D \u043D\u043E\u0432\u044B\u0439 sendCode."
765
1020
  );
766
1021
  }
767
- if (afterSms.status === TokenStatusValues.Pending) {
1022
+ if (afterSms.status === TokenStatusValues4.Pending) {
768
1023
  continue;
769
1024
  }
770
- if (afterSms.status === TokenStatusValues.AwaitingSmsCode) {
1025
+ if (afterSms.status === TokenStatusValues4.AwaitingSmsCode) {
771
1026
  continue;
772
1027
  }
773
1028
  throw new Error(
774
1029
  `pollMobileIdUntilReady: \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 TokenResp.status=${String(afterSms.status)} \u043F\u043E\u0441\u043B\u0435 SMS.`
775
1030
  );
776
1031
  }
777
- if (status !== TokenStatusValues.Pending) {
1032
+ if (status !== TokenStatusValues4.Pending) {
778
1033
  throw new Error(
779
1034
  `pollMobileIdUntilReady: \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 TokenResp.status=${String(status)}.`
780
1035
  );
@@ -789,8 +1044,6 @@ async function pollMobileIdUntilReady(client, options) {
789
1044
  }
790
1045
 
791
1046
  // ../../src/auth-session/otp-login.ts
792
- var DEFAULT_LANGUAGE2 = "ru";
793
- var DEFAULT_REGION2 = 70;
794
1047
  var MOBILE_ID_SMS_CODE_LENGTH = 4;
795
1048
  var OtpCodeRequestLimitExceededError = class extends Error {
796
1049
  name = "OtpCodeRequestLimitExceededError";
@@ -853,24 +1106,7 @@ function httpErrorBody(e) {
853
1106
  return void 0;
854
1107
  }
855
1108
  function scopesOrDefault2(scopes) {
856
- return scopes && scopes.length > 0 ? scopes : [...DefaultAuthScopes4];
857
- }
858
- function buildSendCodeReq(options) {
859
- const accountName = options.accountName.trim();
860
- if (!accountName) {
861
- throw new Error("runOtpLogin: accountName is empty");
862
- }
863
- return {
864
- accountName,
865
- type: options.type,
866
- language: options.language?.trim() || DEFAULT_LANGUAGE2,
867
- regionStorageId: typeof options.regionStorageId === "number" && Number.isFinite(options.regionStorageId) ? options.regionStorageId : DEFAULT_REGION2,
868
- ...options.captcha?.trim() ? { captcha: options.captcha.trim() } : {},
869
- ...options.captchaType ? { captchaType: options.captchaType } : {},
870
- ...options.inviteSessionId?.trim() ? { inviteSessionId: options.inviteSessionId.trim() } : {},
871
- ...options.preferredMethod ? { preferredMethod: options.preferredMethod } : {},
872
- ...options.supportedMethods && options.supportedMethods.length > 0 ? { supportedMethods: options.supportedMethods } : {}
873
- };
1109
+ return scopes && scopes.length > 0 ? scopes : [...DefaultAuthScopes5];
874
1110
  }
875
1111
  function effectiveCodeLength(raw, fallback) {
876
1112
  if (typeof raw === "number" && raw > 0) return raw;
@@ -878,7 +1114,7 @@ function effectiveCodeLength(raw, fallback) {
878
1114
  }
879
1115
  async function requestTokenOrThrow(client, body, signal) {
880
1116
  try {
881
- return normalizeTokenResp(await client.auth.requestToken(body, { signal }));
1117
+ return normalizeTokenResp(await requestAuthToken(client, body, signal));
882
1118
  } catch (e) {
883
1119
  const errBody = httpErrorBody(e);
884
1120
  if (errBody !== void 0 && isAuthHeaderMissingBody(errBody)) {
@@ -888,14 +1124,13 @@ async function requestTokenOrThrow(client, body, signal) {
888
1124
  }
889
1125
  }
890
1126
  async function runOtpLogin(client, options) {
891
- const sendBody = buildSendCodeReq(options);
892
1127
  const accountName = options.accountName.trim();
893
1128
  const accountType = options.type;
894
1129
  const scopes = scopesOrDefault2(options.scopes);
895
1130
  const signal = options.signal;
896
1131
  let sendResp;
897
1132
  try {
898
- sendResp = await client.auth.sendCode(sendBody, { signal });
1133
+ sendResp = await sendOtpCode(client, options, signal);
899
1134
  } catch (e) {
900
1135
  const errBody = httpErrorBody(e);
901
1136
  if (errBody !== void 0 && isSendCodeRateLimitedBody(errBody)) {
@@ -919,7 +1154,7 @@ async function runOtpLogin(client, options) {
919
1154
  nextAvailableUsageTime: sendResp.nextAvailableUsageTime ?? null
920
1155
  };
921
1156
  await options.onSendCode(result);
922
- if (sendResp.usedMethod === VerificationMethodValues.MtsMobileId) {
1157
+ if (sendResp.usedMethod === VerificationMethodValues2.MtsMobileId) {
923
1158
  try {
924
1159
  return await pollMobileIdUntilReady(client, {
925
1160
  sessionId,
@@ -930,10 +1165,10 @@ async function runOtpLogin(client, options) {
930
1165
  signal,
931
1166
  smsCodeLength: typeof sendResp.codeLength === "number" && sendResp.codeLength > 0 ? sendResp.codeLength : MOBILE_ID_SMS_CODE_LENGTH,
932
1167
  obtainSmsCode: async (ctx) => {
933
- const codeLength = effectiveCodeLength(ctx.codeLength, MOBILE_ID_SMS_CODE_LENGTH);
1168
+ const codeLength2 = effectiveCodeLength(ctx.codeLength, MOBILE_ID_SMS_CODE_LENGTH);
934
1169
  return (await options.getCode({
935
1170
  sessionId,
936
- codeLength,
1171
+ codeLength: codeLength2,
937
1172
  usedMethod: sendResp.usedMethod
938
1173
  })).trim();
939
1174
  }
@@ -968,7 +1203,7 @@ async function runOtpLogin(client, options) {
968
1203
  },
969
1204
  signal
970
1205
  );
971
- if (!isTokenRespReadyStatus4(resp.status)) {
1206
+ if (tokenTransition(resp.status, true) !== TokenStatusValues5.TokenReady) {
972
1207
  throw new Error(`runOtpLogin: TokenResp.status=${resp.status} (\u043E\u0436\u0438\u0434\u0430\u043B\u0441\u044F TokenReady)`);
973
1208
  }
974
1209
  return assertTokenRespReadyForStorage(resp, "runOtpLogin");
@@ -993,6 +1228,8 @@ function sessionOpenOptsForLogin(base) {
993
1228
  return { ...sessionOpenOpts(base), skipEnsureFreshOnOpen: true };
994
1229
  }
995
1230
  var TorrowAuth = {
1231
+ /** Пошаговый OTP без storage, polling и refresh. */
1232
+ createOtpFlow,
996
1233
  async connect(options) {
997
1234
  const session = await TokenSession.open(sessionOpenOpts(options));
998
1235
  return { client: session.client, session };
@@ -1058,7 +1295,7 @@ var TorrowAuth = {
1058
1295
  return TorrowAuth.connect(options);
1059
1296
  },
1060
1297
  anonymous(config = {}) {
1061
- return new TorrowClient2({
1298
+ return new TorrowClient3({
1062
1299
  ...config,
1063
1300
  getAccessToken: void 0
1064
1301
  });
@@ -1071,6 +1308,9 @@ export {
1071
1308
  MemoryTokenStorage,
1072
1309
  OtpAuthHeaderMissingError,
1073
1310
  OtpCodeRequestLimitExceededError,
1311
+ OtpFlowError,
1312
+ OtpFlowErrorCodeValues,
1313
+ OtpPhaseValues,
1074
1314
  TokenSession,
1075
1315
  TorrowAuth
1076
1316
  };