squarefi-bff-api-module 1.36.31 → 1.36.32

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.
@@ -1,4 +1,4 @@
1
- import { APIKeyRole, CardFormFactor, CardTransactionType, CardType, CurrencyType, IssuingProgramStatus, OrderType, SortingDirection, SubAccountType } from '../../constants';
1
+ import { APIKeyRole, CardFormFactor, CardTransactionType, CardType, CurrencyType, IssuingProgramStatus, OrderStatuses, OrderType, SortingDirection, SubAccountType } from '../../constants';
2
2
  import { components, operations, paths } from './autogen/apiV2.types';
3
3
  import { components as componentsV1Frontend, paths as pathsV1Frontend } from './autogen/apiV1Frontend.types';
4
4
  import { paths as pathsV1Legacy } from './autogen/apiV1Legacy.types';
@@ -664,6 +664,50 @@ export declare namespace API {
664
664
  }
665
665
  }
666
666
  }
667
+ namespace Issuing {
668
+ type CardDepositRoot = pathsV1Frontend['/frontend/issuing/cards/{card_id}/deposit'];
669
+ type CardWithdrawRoot = pathsV1Frontend['/frontend/issuing/cards/{card_id}/withdraw'];
670
+ type SubAccountDepositRoot = pathsV1Frontend['/frontend/issuing/sub-accounts/{sub_account_id}/deposit'];
671
+ type SubAccountWithdrawRoot = pathsV1Frontend['/frontend/issuing/sub-accounts/{sub_account_id}/withdraw'];
672
+ type WithOrderStatus<T extends {
673
+ data?: {
674
+ status?: string;
675
+ };
676
+ }> = Omit<T, 'data'> & {
677
+ data?: Omit<NonNullable<T['data']>, 'status'> & {
678
+ status?: `${OrderStatuses}`;
679
+ };
680
+ };
681
+ export namespace SubAccounts {
682
+ namespace Deposit {
683
+ type Request = {
684
+ sub_account_id: string;
685
+ } & SubAccountDepositRoot['post']['requestBody']['content']['application/json'];
686
+ type Response = WithOrderStatus<SubAccountDepositRoot['post']['responses']['200']['content']['application/json']>;
687
+ }
688
+ namespace Withdraw {
689
+ type Request = {
690
+ sub_account_id: string;
691
+ } & SubAccountWithdrawRoot['post']['requestBody']['content']['application/json'];
692
+ type Response = WithOrderStatus<SubAccountWithdrawRoot['post']['responses']['200']['content']['application/json']>;
693
+ }
694
+ }
695
+ export namespace Cards {
696
+ namespace Deposit {
697
+ type Request = {
698
+ card_id: string;
699
+ } & CardDepositRoot['post']['requestBody']['content']['application/json'];
700
+ type Response = SubAccounts.Deposit.Response;
701
+ }
702
+ namespace Withdraw {
703
+ type Request = {
704
+ card_id: string;
705
+ } & CardWithdrawRoot['post']['requestBody']['content']['application/json'];
706
+ type Response = SubAccounts.Withdraw.Response;
707
+ }
708
+ }
709
+ export {};
710
+ }
667
711
  }
668
712
  namespace Issuing {
669
713
  namespace Programs {
@@ -1799,10 +1843,6 @@ export declare namespace API {
1799
1843
  type Request = componentsV1Frontend['schemas']['FrontendL2FOrderRequest'];
1800
1844
  type Response = OrderEnvelope;
1801
1845
  }
1802
- namespace Card {
1803
- type Request = pathsV1Frontend['/frontend/orders/withdrawal/card']['post']['requestBody']['content']['application/json'];
1804
- type Response = OrderEnvelope;
1805
- }
1806
1846
  }
1807
1847
  namespace Exchange {
1808
1848
  type Request = componentsV1Frontend['schemas']['FrontendExchangeOrderRequest'];
@@ -2270,6 +2310,16 @@ export declare namespace API {
2270
2310
  type Response = operations['UserController_updateMyUserData']['responses']['200']['content']['application/json'];
2271
2311
  }
2272
2312
  }
2313
+ namespace Verification {
2314
+ type Flow = components['schemas']['UserVerificationFlow'];
2315
+ namespace Init {
2316
+ type Request = operations['UserVerificationController_init']['requestBody']['content']['application/json'];
2317
+ type Response = operations['UserVerificationController_init']['responses']['200']['content']['application/json'];
2318
+ }
2319
+ namespace Resume {
2320
+ type Response = operations['UserVerificationController_resume']['responses']['200']['content']['application/json'];
2321
+ }
2322
+ }
2273
2323
  }
2274
2324
  namespace Wallets {
2275
2325
  export interface SimplifiedWallet {
@@ -7,6 +7,10 @@ export declare const user: {
7
7
  get: (options?: GetUserDataOptions) => Promise<API.User.UserData.Get.Response>;
8
8
  update: (data: API.User.UserData.Update.Request) => Promise<API.User.UserData.Update.Response>;
9
9
  };
10
+ verification: {
11
+ init: (data: API.User.Verification.Init.Request) => Promise<API.User.Verification.Init.Response>;
12
+ resume: () => Promise<API.User.Verification.Resume.Response>;
13
+ };
10
14
  update: {
11
15
  phone: {
12
16
  request: (data: API.User.UpdateUser.Phone.RequestOTP.Request) => Promise<void>;
package/dist/api/user.js CHANGED
@@ -4,6 +4,16 @@ export const user = {
4
4
  get: (options) => apiClientV2.getRequest('/user/user-data', options?.bypassUnauthorizedHandler ? { context: { bypassUnauthorizedHandler: true } } : undefined),
5
5
  update: (data) => apiClientV2.patchRequest('/user/user-data', { data }),
6
6
  },
7
+ verification: {
8
+ // Starts (or moves up) the per-user Sumsub level for the requested step and returns the WebSDK
9
+ // credentials. Resolves 404 when the tenant has no level configured for the step. Step results
10
+ // land on user-data (`identity_verification_status` / `face_verification_status`), so poll
11
+ // `user.userData.get()` after the WebSDK reports completion.
12
+ init: (data) => apiClientV2.postRequest('/user/verification/init', { data }),
13
+ // Re-issues the WebSDK access token for the level the user is already on; 404 when the user has
14
+ // never been initialized.
15
+ resume: () => apiClientV2.postRequest('/user/verification/resume'),
16
+ },
7
17
  update: {
8
18
  phone: {
9
19
  request: (data) => apiClientV2.patchRequest('/user/phone', { data }),
@@ -294,6 +294,13 @@ export declare enum KYCStatuses {
294
294
  }
295
295
  export declare const KYCStatusCheck: IsEnumEqualToUnion<KYCStatuses, API.KYC.KYCStatus>;
296
296
  export type KYCStatusMismatch = EnumUnionMismatch<KYCStatuses, API.KYC.KYCStatus>;
297
+ export declare enum UserVerificationFlows {
298
+ DATA = "data",
299
+ DOCUMENTS = "documents",
300
+ FACE = "face"
301
+ }
302
+ export declare const UserVerificationFlowCheck: IsEnumEqualToUnion<UserVerificationFlows, API.User.Verification.Flow>;
303
+ export type UserVerificationFlowMismatch = EnumUnionMismatch<UserVerificationFlows, API.User.Verification.Flow>;
297
304
  export declare enum OrderStatuses {
298
305
  NEW = "NEW",
299
306
  PENDING = "PENDING",
package/dist/constants.js CHANGED
@@ -308,6 +308,14 @@ export var KYCStatuses;
308
308
  KYCStatuses["WAITING_ON_REVIEW"] = "WAITING_ON_REVIEW";
309
309
  })(KYCStatuses || (KYCStatuses = {}));
310
310
  export const KYCStatusCheck = true;
311
+ // Steps of the per-user verification ladder passed to `user.verification.init`.
312
+ export var UserVerificationFlows;
313
+ (function (UserVerificationFlows) {
314
+ UserVerificationFlows["DATA"] = "data";
315
+ UserVerificationFlows["DOCUMENTS"] = "documents";
316
+ UserVerificationFlows["FACE"] = "face";
317
+ })(UserVerificationFlows || (UserVerificationFlows = {}));
318
+ export const UserVerificationFlowCheck = true;
311
319
  export var OrderStatuses;
312
320
  (function (OrderStatuses) {
313
321
  OrderStatuses["NEW"] = "NEW";
@@ -4,7 +4,7 @@ import axios from 'axios';
4
4
  import { telegramSignUpPath, telegramSignInPath, refreshTokenPath } from '../api/auth';
5
5
  import { AppEnviroment, ResponseStatus } from '../constants';
6
6
  import { isExternalAuthMode, resolveAccessToken, triggerReverification, triggerUnauthorized, } from './accessTokenProvider';
7
- import { deleteTokens, getTokens, refreshTokens } from './tokensFactory';
7
+ import { ExternalAuthRequiredError, deleteTokens, getTokens, refreshTokens } from './tokensFactory';
8
8
  // eslint-disable-next-line no-constant-condition
9
9
  // Backend signals that a sensitive request needs a fresh second-factor verification with this code.
10
10
  // Backend error codes are UPPER_SNAKE_CASE, and the code can sit at either `data.code` or
@@ -119,6 +119,15 @@ export const createApiClient = ({ baseURL, isBearerToken, tenantId }) => {
119
119
  }
120
120
  })
121
121
  .catch((tokenRefreshError) => {
122
+ // A Clerk tenant answered the sign-in with a one-time ticket: the SDK cannot complete
123
+ // it here, but the stored session is still valid and the app recovers by registering
124
+ // `setAccessTokenProvider`. Settle the queued requests with the error instead of
125
+ // wiping the tokens and redirecting to logout.
126
+ if (tokenRefreshError instanceof ExternalAuthRequiredError) {
127
+ requestQueue.forEach((request) => request.fail(tokenRefreshError));
128
+ requestQueue = [];
129
+ return;
130
+ }
122
131
  if (typeof window !== 'undefined') {
123
132
  window.location.href = envLogoutURL;
124
133
  deleteTokens();
@@ -140,6 +149,7 @@ export const createApiClient = ({ baseURL, isBearerToken, tenantId }) => {
140
149
  return res(instance(failedRequestConfig));
141
150
  },
142
151
  reject: () => rej(instance(failedRequestConfig)),
152
+ fail: (queuedError) => rej(queuedError),
143
153
  });
144
154
  });
145
155
  }
@@ -2,6 +2,16 @@ type ITokens = {
2
2
  access_token: string;
3
3
  refresh_token?: string | null;
4
4
  };
5
+ /**
6
+ * Raised when the tenant's auth provider answers a sign-in with a one-time Clerk ticket
7
+ * (`{ ticket, expires_at }`) instead of a session. This localStorage flow cannot complete such a
8
+ * sign-in, but the session is **not** dead: the app is expected to exchange the ticket via Clerk JS
9
+ * (`signIn.create({ strategy: 'ticket', ticket })`) and register `setAccessTokenProvider`. Callers
10
+ * must treat it as "retry once the provider is ready", never as a reason to sign the user out.
11
+ */
12
+ export declare class ExternalAuthRequiredError extends Error {
13
+ constructor(message?: string);
14
+ }
5
15
  export declare function setTokens({ access_token, refresh_token }: ITokens): void;
6
16
  export declare function deleteTokens(): void;
7
17
  export declare function refreshTokens(): Promise<ITokens>;
@@ -1,6 +1,19 @@
1
1
  import { initData, isTMA } from '@telegram-apps/sdk-react';
2
2
  import { deleteFromLocalStorage, getFromLocalStorage, setToLocalStorage } from './storage';
3
3
  import { auth } from '../api/auth';
4
+ /**
5
+ * Raised when the tenant's auth provider answers a sign-in with a one-time Clerk ticket
6
+ * (`{ ticket, expires_at }`) instead of a session. This localStorage flow cannot complete such a
7
+ * sign-in, but the session is **not** dead: the app is expected to exchange the ticket via Clerk JS
8
+ * (`signIn.create({ strategy: 'ticket', ticket })`) and register `setAccessTokenProvider`. Callers
9
+ * must treat it as "retry once the provider is ready", never as a reason to sign the user out.
10
+ */
11
+ export class ExternalAuthRequiredError extends Error {
12
+ constructor(message = 'Sign-in returned a Clerk ticket instead of a session; exchange it via Clerk and register setAccessTokenProvider') {
13
+ super(message);
14
+ this.name = 'ExternalAuthRequiredError';
15
+ }
16
+ }
4
17
  export function setTokens({ access_token, refresh_token }) {
5
18
  access_token && setToLocalStorage('access_token', access_token);
6
19
  refresh_token && setToLocalStorage('refresh_token', refresh_token);
@@ -27,6 +40,18 @@ export async function refreshTokens() {
27
40
  hash,
28
41
  init_data_raw,
29
42
  });
43
+ // A malformed body (empty response, HTML error page) leaves the session unusable, so it stays a
44
+ // plain error and drives the caller's sign-out path.
45
+ if (typeof telegramSignInResponse !== 'object' || telegramSignInResponse === null) {
46
+ return Promise.reject(new Error('Telegram sign-in returned an unexpected response body'));
47
+ }
48
+ // Clerk tenants answer with a one-time sign-in ticket instead of a session: there is no bearer
49
+ // token to store here. Those apps exchange the ticket via Clerk JS and register
50
+ // `setAccessTokenProvider`, which bypasses this localStorage flow entirely — so this is a
51
+ // recoverable state, not a dead session.
52
+ if (!('access_token' in telegramSignInResponse)) {
53
+ return Promise.reject(new ExternalAuthRequiredError());
54
+ }
30
55
  setTokens(telegramSignInResponse);
31
56
  return telegramSignInResponse;
32
57
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "squarefi-bff-api-module",
3
- "version": "1.36.31",
3
+ "version": "1.36.32",
4
4
  "description": "Squarefi BFF API client module",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",