squarefi-bff-api-module 1.36.16 → 1.36.18
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/api/types/autogen/apiV1External.types.d.ts +3 -3
- package/dist/api/types/autogen/apiV2.types.d.ts +5 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/utils/accessTokenProvider.d.ts +22 -0
- package/dist/utils/accessTokenProvider.js +50 -0
- package/dist/utils/apiClientFactory.js +29 -9
- package/package.json +1 -1
|
@@ -43,7 +43,7 @@ export interface paths {
|
|
|
43
43
|
id?: string;
|
|
44
44
|
name?: string;
|
|
45
45
|
/** @enum {string} */
|
|
46
|
-
role?: "READ_ONLY" | "DEVELOPER" | "PRODUCTION" | "
|
|
46
|
+
role?: "READ_ONLY" | "DEVELOPER" | "PRODUCTION" | "OWNER";
|
|
47
47
|
is_enabled?: boolean;
|
|
48
48
|
/** Format: date-time */
|
|
49
49
|
created_at?: string;
|
|
@@ -111,7 +111,7 @@ export interface paths {
|
|
|
111
111
|
id?: string;
|
|
112
112
|
name?: string;
|
|
113
113
|
/** @enum {string} */
|
|
114
|
-
role?: "READ_ONLY" | "DEVELOPER" | "PRODUCTION" | "
|
|
114
|
+
role?: "READ_ONLY" | "DEVELOPER" | "PRODUCTION" | "OWNER";
|
|
115
115
|
/** Format: uuid */
|
|
116
116
|
wallet_id?: string;
|
|
117
117
|
/** Format: uuid */
|
|
@@ -7774,7 +7774,7 @@ export interface components {
|
|
|
7774
7774
|
* @description Permission level of the API key
|
|
7775
7775
|
* @enum {string}
|
|
7776
7776
|
*/
|
|
7777
|
-
role?: "READ_ONLY" | "DEVELOPER" | "PRODUCTION" | "
|
|
7777
|
+
role?: "READ_ONLY" | "DEVELOPER" | "PRODUCTION" | "OWNER";
|
|
7778
7778
|
/**
|
|
7779
7779
|
* Format: uuid
|
|
7780
7780
|
* @description Associated wallet ID
|
|
@@ -2297,6 +2297,10 @@ export interface components {
|
|
|
2297
2297
|
readonly support_text?: string | null;
|
|
2298
2298
|
readonly support_phone?: string | null;
|
|
2299
2299
|
};
|
|
2300
|
+
SupportedLocalesEntity: {
|
|
2301
|
+
default: string;
|
|
2302
|
+
supported: string[];
|
|
2303
|
+
};
|
|
2300
2304
|
SystemConfigDto: {
|
|
2301
2305
|
/** @enum {string} */
|
|
2302
2306
|
default_theme_mode: "dark" | "light";
|
|
@@ -2316,6 +2320,7 @@ export interface components {
|
|
|
2316
2320
|
readonly statement_branding?: components["schemas"]["StatementBrandingEntity"] | null;
|
|
2317
2321
|
/** @enum {string} */
|
|
2318
2322
|
kyc_data_provider: "persona" | "sumsub";
|
|
2323
|
+
readonly supported_locales?: components["schemas"]["SupportedLocalesEntity"] | null;
|
|
2319
2324
|
base_currency: string;
|
|
2320
2325
|
};
|
|
2321
2326
|
SystemChainsResponseDto: {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { squarefi_bff_api_client } from './api';
|
|
2
2
|
export * from './utils/apiClientFactory';
|
|
3
|
+
export { setAccessTokenProvider, setOnUnauthorized, type AccessTokenProvider, type ResolveTokenOptions, type UnauthorizedHandler, } from './utils/accessTokenProvider';
|
|
3
4
|
export * from './utils/tokensFactory';
|
|
4
5
|
export * from './utils/fileStorage';
|
|
5
6
|
export * from './constants';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { squarefi_bff_api_client } from './api';
|
|
2
2
|
export * from './utils/apiClientFactory';
|
|
3
|
+
export { setAccessTokenProvider, setOnUnauthorized, } from './utils/accessTokenProvider';
|
|
3
4
|
export * from './utils/tokensFactory';
|
|
4
5
|
export * from './utils/fileStorage';
|
|
5
6
|
export * from './constants';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type ResolveTokenOptions = {
|
|
2
|
+
/** Force the provider to mint a fresh token, bypassing any cache (used on 401 retry). */
|
|
3
|
+
forceRefresh?: boolean;
|
|
4
|
+
};
|
|
5
|
+
export type AccessTokenProvider = (options?: ResolveTokenOptions) => Promise<string | null | undefined>;
|
|
6
|
+
export type UnauthorizedHandler = () => void;
|
|
7
|
+
/**
|
|
8
|
+
* Register an external source of the access token (e.g. Clerk `getToken`).
|
|
9
|
+
* When set, the API clients stop reading tokens from localStorage and delegate
|
|
10
|
+
* token acquisition (and refresh) to the provider. Pass `null` to fall back to
|
|
11
|
+
* the legacy localStorage flow.
|
|
12
|
+
*/
|
|
13
|
+
export declare const setAccessTokenProvider: (provider: AccessTokenProvider | null) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Register a callback invoked when a request is unauthorized and cannot be
|
|
16
|
+
* recovered by refreshing the token (e.g. to trigger a Clerk sign-out).
|
|
17
|
+
*/
|
|
18
|
+
export declare const setOnUnauthorized: (handler: UnauthorizedHandler | null) => void;
|
|
19
|
+
/** Whether an external token provider is active (Clerk mode). */
|
|
20
|
+
export declare const isExternalAuthMode: () => boolean;
|
|
21
|
+
export declare const resolveAccessToken: (options?: ResolveTokenOptions) => Promise<string | null>;
|
|
22
|
+
export declare const triggerUnauthorized: () => void;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { getFromLocalStorage } from './storage';
|
|
2
|
+
let accessTokenProvider = null;
|
|
3
|
+
let unauthorizedHandler = null;
|
|
4
|
+
let inFlightRefresh = null;
|
|
5
|
+
/**
|
|
6
|
+
* Register an external source of the access token (e.g. Clerk `getToken`).
|
|
7
|
+
* When set, the API clients stop reading tokens from localStorage and delegate
|
|
8
|
+
* token acquisition (and refresh) to the provider. Pass `null` to fall back to
|
|
9
|
+
* the legacy localStorage flow.
|
|
10
|
+
*/
|
|
11
|
+
export const setAccessTokenProvider = (provider) => {
|
|
12
|
+
accessTokenProvider = provider;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Register a callback invoked when a request is unauthorized and cannot be
|
|
16
|
+
* recovered by refreshing the token (e.g. to trigger a Clerk sign-out).
|
|
17
|
+
*/
|
|
18
|
+
export const setOnUnauthorized = (handler) => {
|
|
19
|
+
unauthorizedHandler = handler;
|
|
20
|
+
};
|
|
21
|
+
/** Whether an external token provider is active (Clerk mode). */
|
|
22
|
+
export const isExternalAuthMode = () => accessTokenProvider !== null;
|
|
23
|
+
export const resolveAccessToken = async (options) => {
|
|
24
|
+
if (accessTokenProvider) {
|
|
25
|
+
// Coalesce concurrent force-refreshes so a burst of 401s triggers a single provider refresh.
|
|
26
|
+
if (options?.forceRefresh) {
|
|
27
|
+
if (!inFlightRefresh) {
|
|
28
|
+
const provider = accessTokenProvider;
|
|
29
|
+
inFlightRefresh = Promise.resolve()
|
|
30
|
+
.then(() => provider(options))
|
|
31
|
+
.then((token) => token ?? null)
|
|
32
|
+
.catch(() => null)
|
|
33
|
+
.finally(() => {
|
|
34
|
+
inFlightRefresh = null;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return inFlightRefresh;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
return (await accessTokenProvider(options)) ?? null;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return getFromLocalStorage('access_token');
|
|
47
|
+
};
|
|
48
|
+
export const triggerUnauthorized = () => {
|
|
49
|
+
unauthorizedHandler?.();
|
|
50
|
+
};
|
|
@@ -3,6 +3,7 @@ import { isTMA } from '@telegram-apps/sdk-react';
|
|
|
3
3
|
import axios from 'axios';
|
|
4
4
|
import { telegramSignUpPath, telegramSignInPath, refreshTokenPath } from '../api/auth';
|
|
5
5
|
import { AppEnviroment, ResponseStatus } from '../constants';
|
|
6
|
+
import { isExternalAuthMode, resolveAccessToken, triggerUnauthorized } from './accessTokenProvider';
|
|
6
7
|
import { deleteTokens, getTokens, refreshTokens } from './tokensFactory';
|
|
7
8
|
// eslint-disable-next-line no-constant-condition
|
|
8
9
|
const apiV1BaseURL = process.env.API_URL ?? 'ENV variable API_URL is not defined';
|
|
@@ -17,8 +18,8 @@ export const createApiClient = ({ baseURL, isBearerToken, tenantId }) => {
|
|
|
17
18
|
baseURL,
|
|
18
19
|
timeout: 60000,
|
|
19
20
|
});
|
|
20
|
-
instance.interceptors.request.use((config) => {
|
|
21
|
-
const
|
|
21
|
+
instance.interceptors.request.use(async (config) => {
|
|
22
|
+
const access_token = await resolveAccessToken();
|
|
22
23
|
const modifiedHeaders = {
|
|
23
24
|
...config.headers,
|
|
24
25
|
'x-tenant-id': tenantId,
|
|
@@ -43,8 +44,27 @@ export const createApiClient = ({ baseURL, isBearerToken, tenantId }) => {
|
|
|
43
44
|
if (error?.response?.status === ResponseStatus.UNAUTHORIZED &&
|
|
44
45
|
!error?.response?.config.context?.bypassUnauthorizedHandler) {
|
|
45
46
|
const { response, config: failedRequestConfig } = error;
|
|
46
|
-
const { refresh_token } = getTokens();
|
|
47
47
|
const isRetryRequest = failedRequestConfig.context?.isRetryRequest;
|
|
48
|
+
// External auth mode (e.g. Clerk): the provider owns token refresh. Force a fresh token and
|
|
49
|
+
// retry once; sign out if there is no fresh token or the retry still fails.
|
|
50
|
+
if (isExternalAuthMode()) {
|
|
51
|
+
if (isRetryRequest) {
|
|
52
|
+
triggerUnauthorized();
|
|
53
|
+
return Promise.reject(error);
|
|
54
|
+
}
|
|
55
|
+
return resolveAccessToken({ forceRefresh: true }).then((freshToken) => {
|
|
56
|
+
if (!freshToken) {
|
|
57
|
+
triggerUnauthorized();
|
|
58
|
+
return Promise.reject(error);
|
|
59
|
+
}
|
|
60
|
+
failedRequestConfig.context = {
|
|
61
|
+
...failedRequestConfig.context,
|
|
62
|
+
isRetryRequest: true,
|
|
63
|
+
};
|
|
64
|
+
return instance(failedRequestConfig);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
const { refresh_token } = getTokens();
|
|
48
68
|
const isRefreshTokenRequest = failedRequestConfig.url?.includes(refreshTokenPath);
|
|
49
69
|
const isTelegramSignInRequest = failedRequestConfig.url?.includes(telegramSignInPath);
|
|
50
70
|
const isTelegramSignUpRequest = failedRequestConfig.url?.includes(telegramSignUpPath);
|
|
@@ -144,8 +164,8 @@ export const createFetchApiClient = ({ baseURL, isBearerToken, tenantId }) => {
|
|
|
144
164
|
});
|
|
145
165
|
return `${fullUrl}?${searchParams.toString()}`;
|
|
146
166
|
};
|
|
147
|
-
const getHeaders = (additionalHeaders) => {
|
|
148
|
-
const
|
|
167
|
+
const getHeaders = async (additionalHeaders) => {
|
|
168
|
+
const access_token = await resolveAccessToken();
|
|
149
169
|
const headers = {
|
|
150
170
|
'Content-Type': 'application/json',
|
|
151
171
|
'x-tenant-id': tenantId,
|
|
@@ -186,7 +206,7 @@ export const createFetchApiClient = ({ baseURL, isBearerToken, tenantId }) => {
|
|
|
186
206
|
const fullUrl = buildUrl(url, config?.params);
|
|
187
207
|
const response = await fetch(fullUrl, {
|
|
188
208
|
method: 'GET',
|
|
189
|
-
headers: getHeaders(config?.headers),
|
|
209
|
+
headers: await getHeaders(config?.headers),
|
|
190
210
|
});
|
|
191
211
|
return handleResponse(response, config?.responseType);
|
|
192
212
|
};
|
|
@@ -194,7 +214,7 @@ export const createFetchApiClient = ({ baseURL, isBearerToken, tenantId }) => {
|
|
|
194
214
|
const fullUrl = buildUrl(url);
|
|
195
215
|
const response = await fetch(fullUrl, {
|
|
196
216
|
method: 'POST',
|
|
197
|
-
headers: getHeaders(config?.headers),
|
|
217
|
+
headers: await getHeaders(config?.headers),
|
|
198
218
|
body: config?.data ? JSON.stringify(config.data) : undefined,
|
|
199
219
|
});
|
|
200
220
|
return handleResponse(response, config?.responseType);
|
|
@@ -203,7 +223,7 @@ export const createFetchApiClient = ({ baseURL, isBearerToken, tenantId }) => {
|
|
|
203
223
|
const fullUrl = buildUrl(url);
|
|
204
224
|
const response = await fetch(fullUrl, {
|
|
205
225
|
method: 'PATCH',
|
|
206
|
-
headers: getHeaders(config?.headers),
|
|
226
|
+
headers: await getHeaders(config?.headers),
|
|
207
227
|
body: config?.data ? JSON.stringify(config.data) : undefined,
|
|
208
228
|
});
|
|
209
229
|
return handleResponse(response, config?.responseType);
|
|
@@ -212,7 +232,7 @@ export const createFetchApiClient = ({ baseURL, isBearerToken, tenantId }) => {
|
|
|
212
232
|
const fullUrl = buildUrl(url);
|
|
213
233
|
const response = await fetch(fullUrl, {
|
|
214
234
|
method: 'DELETE',
|
|
215
|
-
headers: getHeaders(config?.headers),
|
|
235
|
+
headers: await getHeaders(config?.headers),
|
|
216
236
|
body: config?.data ? JSON.stringify(config.data) : undefined,
|
|
217
237
|
});
|
|
218
238
|
return handleResponse(response, config?.responseType);
|