@0xchain/request 1.1.0-beta.9 → 1.1.0-beta.91

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present 0xchain
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -10,6 +10,7 @@ This library was generated with [Nx](https://nx.dev).
10
10
  - 自动添加通用请求头
11
11
  - 统一的错误处理
12
12
  - 支持返回完整响应对象(包含 headers 信息)
13
+ - 业务信封可选 `toast` 时,客户端派发 `xchain-response-toast`
13
14
 
14
15
  ## 使用方法
15
16
 
@@ -68,6 +69,18 @@ if (response.status === 201) {
68
69
  }
69
70
  ```
70
71
 
72
+ ### 响应体 toast
73
+
74
+ 成功信封可带可选字段 `toast: { amount, title? }`。客户端会派发 `xchain-response-toast`(导出常量 `RESPONSE_TOAST_EVENT`),业务自行监听并展示;SSR 不会派发。没有 toast 时后端应省略该字段。
75
+
76
+ ```typescript
77
+ import axiosInstance, { RESPONSE_TOAST_EVENT } from '@0xchain/request';
78
+
79
+ window.addEventListener(RESPONSE_TOAST_EVENT, (event) => {
80
+ const toast = (event as CustomEvent).detail; // { amount, title? }
81
+ });
82
+ ```
83
+
71
84
  ## API 配置选项
72
85
 
73
86
  ### ApiRequestConfig
package/dist/index.d.ts CHANGED
@@ -1,15 +1,21 @@
1
1
  import { AxiosError } from 'axios';
2
+ import { ResponseToast } from './responseToast';
2
3
  export interface ApiResponse<T> {
3
4
  status: {
4
5
  code: number;
5
6
  msg: string;
6
7
  };
7
8
  data: T;
9
+ toast?: ResponseToast;
8
10
  }
9
11
  export interface ApiError extends AxiosError {
10
12
  need?: boolean;
11
13
  }
12
14
  declare const axiosInstance: import('axios').AxiosInstance;
13
15
  export default axiosInstance;
14
- export type { ApiRequestConfig, Pagination, Status, IResponse, IFilters, IPageRequest, } from './types';
16
+ export { setServerHeaderProvider, setClientLocales } from './interceptors/commonHeader';
17
+ export { refreshAccessToken, getCurrentAccessToken } from './tokenRefresh';
18
+ export { RESPONSE_TOAST_EVENT, emitResponseToast, parseResponseToast, } from './responseToast';
19
+ export type { ResponseToast } from './responseToast';
20
+ export type { ApiRequestConfig, ServerHeaderProvider, Pagination, Status, IResponse, IFilters, IPageRequest, } from './types';
15
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AAQ/C,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,IAAI,EAAE,CAAC,CAAC;CACT;AAED,MAAM,WAAW,QAAS,SAAQ,UAAU;IAC1C,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAGD,QAAA,MAAM,aAAa,+BAYjB,CAAC;AASH,eAAe,aAAa,CAAC;AAE7B,YAAY,EACV,gBAAgB,EAChB,UAAU,EACV,MAAM,EACN,SAAS,EACT,QAAQ,EACR,YAAY,GACb,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AAM/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGrD,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAED,MAAM,WAAW,QAAS,SAAQ,UAAU;IAC1C,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAGD,QAAA,MAAM,aAAa,+BAYjB,CAAC;AASH,eAAe,aAAa,CAAC;AAE7B,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAExF,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE3E,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,UAAU,EACV,MAAM,EACN,SAAS,EACT,QAAQ,EACR,YAAY,GACb,MAAM,SAAS,CAAA"}
package/dist/index.js CHANGED
@@ -1,18 +1,34 @@
1
1
  import axios, { isAxiosError, AxiosError } from "axios";
2
2
  import qs from "qs";
3
3
  import jsCookie from "js-cookie";
4
+ import { envCookieName, getToken, removeAllToken, isTokenExpired } from "@0xchain/token";
4
5
  import { logger } from "@0xchain/logger";
5
- import TokenManager, { isTokenExpired, getToken, removeAllToken } from "@0xchain/token";
6
6
  const isSimplifiedChinese = () => {
7
- return /^(zh-hans|zh-cn|zh-sg|zh-my)$/.test(window == null ? void 0 : window.navigator.language.toLowerCase());
7
+ return /^(zh-hans|zh-cn|zh-sg|zh-my)$/.test(window?.navigator.language.toLowerCase());
8
8
  };
9
9
  const matchSystemLanguage = () => {
10
10
  return isSimplifiedChinese() ? "zh-hans" : "";
11
11
  };
12
+ function isServerRuntime() {
13
+ if (typeof window !== "undefined") {
14
+ return false;
15
+ }
16
+ return true;
17
+ }
12
18
  let httpAgent;
13
19
  let httpsAgent;
14
- function isServerRuntime() {
15
- return typeof window === "undefined" || process.env.IS_SERVER === "true";
20
+ let serverHeaderProvider;
21
+ function setServerHeaderProvider(provider) {
22
+ serverHeaderProvider = provider;
23
+ }
24
+ let clientLocales;
25
+ function setClientLocales(locales) {
26
+ clientLocales = locales;
27
+ }
28
+ function getUrlLocale() {
29
+ if (typeof window === "undefined" || !clientLocales?.length) return void 0;
30
+ const seg = window.location.pathname.split("/")[1];
31
+ return seg && clientLocales.includes(seg) ? seg : void 0;
16
32
  }
17
33
  function isEdgeRuntime() {
18
34
  return process.env.NEXT_RUNTIME === "edge" || typeof globalThis.EdgeRuntime !== "undefined";
@@ -22,51 +38,61 @@ function isNodeRuntime() {
22
38
  }
23
39
  function getHeader(config, key) {
24
40
  const h = config.headers;
25
- if ((h == null ? void 0 : h.get) && typeof h.get === "function") return h.get(key);
26
- return h == null ? void 0 : h[key];
41
+ if (h?.get && typeof h.get === "function") return h.get(key);
42
+ return h?.[key];
27
43
  }
28
44
  function setHeader(config, key, value) {
29
45
  const h = config.headers;
30
- if ((h == null ? void 0 : h.set) && typeof h.set === "function") {
46
+ if (h?.set && typeof h.set === "function") {
31
47
  h.set(key, value);
32
48
  } else {
33
49
  h[key] = value;
34
50
  }
35
51
  }
36
52
  async function commonHeader(config) {
37
- var _a, _b;
38
53
  let access_token = "";
39
54
  let language = "";
40
55
  if (isServerRuntime()) {
41
56
  if (isNodeRuntime()) {
42
57
  try {
43
58
  const http = await import("http");
44
- const https = await import("./__vite-browser-external-2Ng8QIWW.js");
45
- const baseURL = config == null ? void 0 : config.baseURL;
59
+ const https = await import("https");
60
+ const baseURL = config?.baseURL;
46
61
  const isHttps = typeof baseURL === "string" ? baseURL.startsWith("https://") : false;
47
- if (!httpAgent && (http == null ? void 0 : http.Agent)) httpAgent = new http.Agent({ keepAlive: true });
48
- if (!httpsAgent && (https == null ? void 0 : https.Agent)) httpsAgent = new https.Agent({ keepAlive: true });
62
+ if (!httpAgent && http?.Agent) httpAgent = new http.Agent({ keepAlive: true });
63
+ if (!httpsAgent && https?.Agent) httpsAgent = new https.Agent({ keepAlive: true });
49
64
  config.httpAgent = isHttps ? void 0 : httpAgent;
50
65
  config.httpsAgent = isHttps ? httpsAgent : void 0;
51
66
  } catch {
52
67
  }
53
68
  }
54
- try {
69
+ setHeader(config, "x-whistle-nohost-env", process.env.NO_HOST_ENV || "ichaingo");
70
+ if (serverHeaderProvider) {
55
71
  const startLanguage = getHeader(config, "Accept-Language");
56
- setHeader(config, "x-whistle-nohost-env", process.env.NO_HOST_ENV || "ichaingo");
57
- const { cookies, headers } = await import("next/headers");
58
- const cookieStore = await cookies();
59
- access_token = ((_a = cookieStore.get("access_token")) == null ? void 0 : _a.value) || "";
60
- const hList = await headers();
61
- language = startLanguage || hList.get("x-next-intl-locale") || "en";
62
- } catch (error) {
63
- console.error("Error accessing cookies in server component:", error);
72
+ try {
73
+ access_token = await serverHeaderProvider.getAccessToken() || "";
74
+ language = startLanguage || await serverHeaderProvider.getLanguage() || "en";
75
+ } catch (error) {
76
+ console.error("Error accessing server headers via provider:", error);
77
+ }
78
+ } else {
79
+ try {
80
+ const startLanguage = getHeader(config, "Accept-Language");
81
+ const { cookies, headers } = await import("next/headers");
82
+ const cookieStore = await cookies();
83
+ access_token = cookieStore.get(envCookieName("access_token"))?.value || "";
84
+ const hList = await headers();
85
+ language = startLanguage || hList.get("x-next-intl-locale") || "en";
86
+ } catch (error) {
87
+ console.error("Error accessing cookies in server component:", error);
88
+ }
64
89
  }
65
90
  } else {
66
- access_token = jsCookie.get("access_token") || "";
67
- language = jsCookie.get("NEXT_LOCALE") || matchSystemLanguage() || "en";
91
+ access_token = jsCookie.get(envCookieName("access_token")) || "";
92
+ const preset = getHeader(config, "Accept-Language");
93
+ language = preset || getUrlLocale() || jsCookie.get("NEXT_LOCALE") || matchSystemLanguage() || "en";
68
94
  }
69
- const isRefreshToken = (_b = config.headers) == null ? void 0 : _b["isRefreshToken"];
95
+ const isRefreshToken = config.headers?.["isRefreshToken"];
70
96
  setHeader(config, "Accept-Language", language);
71
97
  if (access_token && !isRefreshToken) {
72
98
  setHeader(config, "Authorization", `Bearer ${access_token}`);
@@ -78,13 +104,12 @@ function toUpperMethod(m) {
78
104
  return m ? m.toUpperCase() : void 0;
79
105
  }
80
106
  function getTypeName(v) {
81
- var _a;
82
107
  if (v === null) return "null";
83
108
  if (v === void 0) return "undefined";
84
109
  const t = typeof v;
85
110
  if (t !== "object") return t;
86
111
  try {
87
- return ((_a = v == null ? void 0 : v.constructor) == null ? void 0 : _a.name) || "object";
112
+ return v?.constructor?.name || "object";
88
113
  } catch {
89
114
  return "object";
90
115
  }
@@ -105,15 +130,14 @@ function n(v) {
105
130
  return v === void 0 ? null : v;
106
131
  }
107
132
  function buildErrorMessage(err) {
108
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
109
- const method = toUpperMethod((_a = err.config) == null ? void 0 : _a.method);
110
- const baseURL = ((_b = err.config) == null ? void 0 : _b.baseURL) || "";
111
- const url = ((_c = err.config) == null ? void 0 : _c.url) ? `${baseURL || ""}${err.config.url}` : "";
112
- const status = (_d = err.response) == null ? void 0 : _d.status;
113
- const statusText = (_e = err.response) == null ? void 0 : _e.statusText;
114
- const respData = (_f = err.response) == null ? void 0 : _f.data;
115
- const requestId = ((_h = (_g = err.response) == null ? void 0 : _g.headers) == null ? void 0 : _h["x-request-id"]) || ((_i = respData == null ? void 0 : respData.status) == null ? void 0 : _i.requestId);
116
- const serverMsg = (respData == null ? void 0 : respData.message) || (respData == null ? void 0 : respData.msg) || ((_j = respData == null ? void 0 : respData.status) == null ? void 0 : _j.msg);
133
+ const method = toUpperMethod(err.config?.method);
134
+ const baseURL = err.config?.baseURL || "";
135
+ const url = err.config?.url ? `${baseURL || ""}${err.config.url}` : "";
136
+ const status = err.response?.status;
137
+ const statusText = err.response?.statusText;
138
+ const respData = err.response?.data;
139
+ const requestId = err.response?.headers?.["x-request-id"] || respData?.status?.requestId;
140
+ const serverMsg = respData?.message || respData?.msg || respData?.status?.msg;
117
141
  const summary = [
118
142
  status ? `HTTP ${status}` : "HTTP ERROR",
119
143
  method,
@@ -127,18 +151,17 @@ function buildErrorMessage(err) {
127
151
  return [summary, shortMsg, ridMsg, codeMsg, localMsg].filter(Boolean).join(" | ");
128
152
  }
129
153
  function buildDetails(err) {
130
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
131
154
  const cfg = err.config;
132
- let body = cfg == null ? void 0 : cfg.data;
155
+ let body = cfg?.data;
133
156
  if (typeof body === "string") {
134
157
  try {
135
158
  body = JSON.parse(body);
136
159
  } catch {
137
160
  }
138
161
  }
139
- const baseURL = cfg == null ? void 0 : cfg.baseURL;
140
- const url = (cfg == null ? void 0 : cfg.url) ? baseURL ? `${baseURL}${cfg.url}` : cfg.url : void 0;
141
- const requestId = ((_b = (_a = err.response) == null ? void 0 : _a.headers) == null ? void 0 : _b["x-request-id"]) || ((_e = (_d = (_c = err.response) == null ? void 0 : _c.data) == null ? void 0 : _d.status) == null ? void 0 : _e.requestId);
162
+ const baseURL = cfg?.baseURL;
163
+ const url = cfg?.url ? baseURL ? `${baseURL}${cfg.url}` : cfg.url : void 0;
164
+ const requestId = err.response?.headers?.["x-request-id"] || err.response?.data?.status?.requestId;
142
165
  return {
143
166
  // error 基础信息(保证不会被 stringify 成 {})
144
167
  name: n(err.name),
@@ -146,29 +169,28 @@ function buildDetails(err) {
146
169
  code: n(err.code),
147
170
  stack: n(err.stack),
148
171
  // request 信息
149
- method: n(toUpperMethod(cfg == null ? void 0 : cfg.method)),
172
+ method: n(toUpperMethod(cfg?.method)),
150
173
  baseURL: n(baseURL),
151
174
  url: n(url),
152
- timeout: n(cfg == null ? void 0 : cfg.timeout),
153
- withCredentials: n(cfg == null ? void 0 : cfg.withCredentials),
154
- params: n(cfg == null ? void 0 : cfg.params),
175
+ timeout: n(cfg?.timeout),
176
+ withCredentials: n(cfg?.withCredentials),
177
+ params: n(cfg?.params),
155
178
  data: n(body),
156
179
  // response 信息
157
- status: n((_f = err.response) == null ? void 0 : _f.status),
158
- statusText: n((_g = err.response) == null ? void 0 : _g.statusText),
180
+ status: n(err.response?.status),
181
+ statusText: n(err.response?.statusText),
159
182
  requestId: n(requestId),
160
- responseDataType: n(getTypeName((_h = err.response) == null ? void 0 : _h.data)),
161
- responseData: n(safeResponseData((_i = err.response) == null ? void 0 : _i.data))
183
+ responseDataType: n(getTypeName(err.response?.data)),
184
+ responseData: n(safeResponseData(err.response?.data))
162
185
  };
163
186
  }
164
187
  function errorInterceptor(error) {
165
- var _a, _b, _c;
166
188
  const err = isAxiosError(error) ? error : new AxiosError(String(error));
167
189
  const isTimeout = err.code === "ECONNABORTED" || /timeout/i.test(err.message || "");
168
190
  if (isTimeout) {
169
- const method = toUpperMethod((_a = err.config) == null ? void 0 : _a.method);
170
- const baseURL = ((_b = err.config) == null ? void 0 : _b.baseURL) || "";
171
- const url = ((_c = err.config) == null ? void 0 : _c.url) ? `${baseURL || ""}${err.config.url}` : "";
191
+ const method = toUpperMethod(err.config?.method);
192
+ const baseURL = err.config?.baseURL || "";
193
+ const url = err.config?.url ? `${baseURL || ""}${err.config.url}` : "";
172
194
  const summary = [`TIMEOUT`, method, url].filter(Boolean).join(" | ");
173
195
  err.summary = summary;
174
196
  err.details = buildDetails(err);
@@ -181,40 +203,125 @@ function errorInterceptor(error) {
181
203
  logger.error({ message, details: err.details, errType: "server error" });
182
204
  return Promise.reject(err);
183
205
  }
184
- function ResponseInterceptor(response) {
185
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
186
- const config = response.config;
187
- if (config.returnFullResponse) {
188
- return response;
206
+ const refreshBaseURL = typeof window !== "undefined" ? process.env.NEXT_PUBLIC_AUTH_URL || window.location.origin : process.env.AUTH_INNER_API_URL || process.env.NEXT_PUBLIC_AUTH_URL;
207
+ const refreshClient = axios.create({
208
+ baseURL: refreshBaseURL,
209
+ timeout: 1e4,
210
+ withCredentials: true,
211
+ paramsSerializer(params) {
212
+ return qs.stringify(params, { arrayFormat: "brackets" });
213
+ }
214
+ });
215
+ let refreshPromise = null;
216
+ const REFRESH_DEDUPE_MS = 2e3;
217
+ let lastRefreshAt = 0;
218
+ let lastRefreshResult = null;
219
+ function refreshAccessToken() {
220
+ if (refreshPromise) {
221
+ return refreshPromise;
222
+ }
223
+ if (Date.now() - lastRefreshAt < REFRESH_DEDUPE_MS) {
224
+ return Promise.resolve(lastRefreshResult);
189
225
  }
190
- if (response.status === 401) {
191
- if (typeof window !== "undefined") {
192
- TokenManager.removeAllToken();
226
+ const refresh_token = getToken("refresh_token");
227
+ if (!refresh_token) {
228
+ return Promise.resolve(null);
229
+ }
230
+ const pending = refreshClient.get("/api/refresh/token", {
231
+ params: {
232
+ grant_type: "refresh_token",
233
+ refresh_token
234
+ },
235
+ headers: {
236
+ isRefreshToken: true
237
+ }
238
+ }).then((res) => {
239
+ const data = res?.data?.data;
240
+ if (data?.access_token) {
241
+ if (typeof window !== "undefined") {
242
+ window.dispatchEvent(new CustomEvent("user-profile-updated"));
243
+ }
244
+ return data.access_token;
193
245
  }
246
+ removeAllToken();
247
+ return null;
248
+ }).catch(() => null).then((result) => {
249
+ lastRefreshAt = Date.now();
250
+ lastRefreshResult = result;
251
+ return result;
252
+ }).finally(() => {
253
+ refreshPromise = null;
254
+ });
255
+ refreshPromise = pending;
256
+ return pending;
257
+ }
258
+ function getCurrentAccessToken() {
259
+ return jsCookie.get(envCookieName("access_token")) || getToken("access_token") || "";
260
+ }
261
+ const RESPONSE_TOAST_EVENT = "xchain-response-toast";
262
+ function readToastObject(source) {
263
+ if (!source || typeof source !== "object") return null;
264
+ const raw = source;
265
+ const amount = Number(raw.amount);
266
+ if (!Number.isFinite(amount)) return null;
267
+ return {
268
+ amount,
269
+ title: typeof raw.title === "string" ? raw.title : void 0
270
+ };
271
+ }
272
+ function parseResponseToast(payload) {
273
+ if (!payload || typeof payload !== "object") return null;
274
+ const rec = payload;
275
+ const direct = readToastObject(rec.toast);
276
+ if (direct) return direct;
277
+ if (rec.data && typeof rec.data === "object") {
278
+ return readToastObject(rec.data.toast);
279
+ }
280
+ return null;
281
+ }
282
+ function emitResponseToast(payload) {
283
+ if (isServerRuntime()) return;
284
+ if (typeof window === "undefined") return;
285
+ const toast = parseResponseToast(payload);
286
+ if (!toast) return;
287
+ window.dispatchEvent(
288
+ new CustomEvent(RESPONSE_TOAST_EVENT, { detail: toast })
289
+ );
290
+ }
291
+ function shouldSkipRefresh(config) {
292
+ const url = typeof config?.url === "string" ? config.url : "";
293
+ if (url.includes("/api/refresh/token")) return true;
294
+ if (url.includes("/v2/auth/")) return true;
295
+ if (config?.headers?.isRefreshToken) return true;
296
+ return false;
297
+ }
298
+ function handleBusinessResponse(response) {
299
+ const config = response.config;
300
+ if (config.returnFullResponse) {
301
+ emitResponseToast(response.data);
194
302
  return response;
195
303
  }
196
304
  if (response.status === 200) {
197
- if ((_a = response.headers["content-type"]) == null ? void 0 : _a.includes("text/event-stream")) {
305
+ if (response.headers["content-type"]?.includes("text/event-stream")) {
198
306
  return response;
199
307
  }
200
308
  const data = response.data;
201
309
  const businessStatus = data.status;
202
310
  if (businessStatus && typeof businessStatus.code === "number" && ![0, 200].includes(businessStatus.code) && businessStatus.code !== 401) {
203
311
  const err = new AxiosError(
204
- (businessStatus == null ? void 0 : businessStatus.msg) || "Business error",
312
+ businessStatus?.msg || "Business error",
205
313
  String(businessStatus.code),
206
314
  response.config,
207
315
  response.request,
208
316
  response
209
317
  );
210
- const summary = `BIZ ${businessStatus.code} | ${(_c = (_b = response.config) == null ? void 0 : _b.method) == null ? void 0 : _c.toUpperCase()} | ${((_d = response.config) == null ? void 0 : _d.baseURL) || ""}${((_e = response.config) == null ? void 0 : _e.url) || ""} | server: ${businessStatus == null ? void 0 : businessStatus.msg}`;
318
+ const summary = `BIZ ${businessStatus.code} | ${response.config?.method?.toUpperCase()} | ${response.config?.baseURL || ""}${response.config?.url || ""} | server: ${businessStatus?.msg}`;
211
319
  const details = {
212
- method: (_g = (_f = response.config) == null ? void 0 : _f.method) == null ? void 0 : _g.toUpperCase(),
213
- url: ((_h = response.config) == null ? void 0 : _h.baseURL) ? `${response.config.baseURL}${response.config.url || ""}` : response.config.url,
214
- params: (_i = response.config) == null ? void 0 : _i.params,
320
+ method: response.config?.method?.toUpperCase(),
321
+ url: response.config?.baseURL ? `${response.config.baseURL}${response.config.url || ""}` : response.config.url,
322
+ params: response.config?.params,
215
323
  data: (() => {
216
- var _a2;
217
- let d = (_a2 = response.config) == null ? void 0 : _a2.data;
324
+ let d = response.config?.data;
218
325
  if (typeof d === "string") {
219
326
  try {
220
327
  d = JSON.parse(d);
@@ -225,7 +332,7 @@ function ResponseInterceptor(response) {
225
332
  })(),
226
333
  status: response.status,
227
334
  statusText: response.statusText,
228
- requestId: ((_j = response.headers) == null ? void 0 : _j["x-request-id"]) || (businessStatus == null ? void 0 : businessStatus.requestId),
335
+ requestId: response.headers?.["x-request-id"] || businessStatus?.requestId,
229
336
  responseData: data
230
337
  };
231
338
  if (process.env.NODE_ENV !== "development") {
@@ -233,30 +340,48 @@ function ResponseInterceptor(response) {
233
340
  }
234
341
  throw err;
235
342
  }
343
+ emitResponseToast(data);
236
344
  return data;
237
345
  }
238
346
  return response;
239
347
  }
240
- let refreshPromise = null;
241
- const axiosInstance$1 = axios.create({
242
- baseURL: process.env.AUTH_INNER_API_URL || process.env.NEXT_PUBLIC_AUTH_URL,
243
- timeout: 1e4,
244
- withCredentials: true,
245
- // Always include credentials by default
246
- paramsSerializer: function(params) {
247
- return qs.stringify(params, { arrayFormat: "brackets" });
348
+ function createResponseInterceptor(instance) {
349
+ return async function ResponseInterceptor(response) {
350
+ if (response.status === 401) {
351
+ const config = response.config;
352
+ const canRetry = !isServerRuntime() && !shouldSkipRefresh(config) && !config.__isRetryAfterRefresh;
353
+ if (canRetry) {
354
+ const newAccessToken = await refreshAccessToken();
355
+ if (newAccessToken) {
356
+ config.__isRetryAfterRefresh = true;
357
+ return instance(config);
358
+ }
359
+ }
360
+ return response;
361
+ }
362
+ return handleBusinessResponse(response);
363
+ };
364
+ }
365
+ function setAuthHeader(config, accessToken) {
366
+ const value = `Bearer ${accessToken}`;
367
+ const h = config.headers;
368
+ if (h?.set && typeof h.set === "function") {
369
+ h.set("Authorization", value);
370
+ } else {
371
+ h.Authorization = value;
248
372
  }
249
- });
373
+ }
250
374
  async function refreshToken(config) {
251
- if (typeof window === "undefined" || process.env.IS_SERVER === "true") {
375
+ if (isServerRuntime()) {
252
376
  return config;
253
377
  }
254
378
  if (typeof config.url === "string" && config.url.includes("/api/refresh/token")) {
255
379
  return config;
256
380
  }
257
- const headers = config.headers;
258
- if (refreshPromise) {
259
- await refreshPromise;
381
+ if (typeof config.url === "string" && config.url.includes("/v2/auth/")) {
382
+ return config;
383
+ }
384
+ if (config.headers?.isRefreshToken) {
260
385
  return config;
261
386
  }
262
387
  let expired = false;
@@ -266,42 +391,11 @@ async function refreshToken(config) {
266
391
  expired = false;
267
392
  }
268
393
  if (expired) {
269
- const refresh_token = getToken("refresh_token");
270
- if (!refresh_token) {
271
- removeAllToken();
272
- return config;
394
+ const newAccessToken = await refreshAccessToken();
395
+ const accessToken = newAccessToken || getCurrentAccessToken();
396
+ if (accessToken) {
397
+ setAuthHeader(config, accessToken);
273
398
  }
274
- if (refreshPromise) {
275
- await refreshPromise;
276
- return config;
277
- }
278
- const refreshHeaders = { ...headers };
279
- delete refreshHeaders.Authorization;
280
- delete refreshHeaders.authorization;
281
- refreshHeaders.isRefreshToken = true;
282
- refreshPromise = axiosInstance$1.get(`/api/refresh/token`, {
283
- params: {
284
- grant_type: "refresh_token",
285
- refresh_token
286
- },
287
- headers: {
288
- ...refreshHeaders
289
- }
290
- }).then((res) => {
291
- var _a;
292
- if ((_a = res == null ? void 0 : res.data) == null ? void 0 : _a.data) {
293
- return res.data.data;
294
- } else {
295
- removeAllToken();
296
- return null;
297
- }
298
- }).catch(() => {
299
- removeAllToken();
300
- return null;
301
- }).finally(() => {
302
- refreshPromise = null;
303
- });
304
- await refreshPromise;
305
399
  }
306
400
  return config;
307
401
  }
@@ -319,7 +413,14 @@ const axiosInstance = axios.create({
319
413
  });
320
414
  axiosInstance.interceptors.request.use(refreshToken);
321
415
  axiosInstance.interceptors.request.use(commonHeader, errorInterceptor);
322
- axiosInstance.interceptors.response.use(ResponseInterceptor, errorInterceptor);
416
+ axiosInstance.interceptors.response.use(createResponseInterceptor(axiosInstance), errorInterceptor);
323
417
  export {
324
- axiosInstance as default
418
+ RESPONSE_TOAST_EVENT,
419
+ axiosInstance as default,
420
+ emitResponseToast,
421
+ getCurrentAccessToken,
422
+ parseResponseToast,
423
+ refreshAccessToken,
424
+ setClientLocales,
425
+ setServerHeaderProvider
325
426
  };
@@ -1,3 +1,11 @@
1
1
  import { InternalAxiosRequestConfig } from 'axios';
2
+ import { ServerHeaderProvider } from '../types';
3
+ export declare function setServerHeaderProvider(provider: ServerHeaderProvider): void;
4
+ /**
5
+ * 注入应用支持的 locale 列表后,客户端 Accept-Language 以 URL 首段为准,
6
+ * 避免 iframe 分区(partitioned)或重复的 NEXT_LOCALE cookie 读到旧值。
7
+ * 未调用时行为不变(仍读 cookie)。
8
+ */
9
+ export declare function setClientLocales(locales: readonly string[]): void;
2
10
  export declare function commonHeader(config: InternalAxiosRequestConfig): Promise<InternalAxiosRequestConfig<any>>;
3
11
  //# sourceMappingURL=commonHeader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"commonHeader.d.ts","sourceRoot":"","sources":["../../src/interceptors/commonHeader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoB,0BAA0B,EAAE,MAAM,OAAO,CAAC;AAiCrE,wBAAsB,YAAY,CAChC,MAAM,EAAE,0BAA0B,4CA+CnC"}
1
+ {"version":3,"file":"commonHeader.d.ts","sourceRoot":"","sources":["../../src/interceptors/commonHeader.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoB,0BAA0B,EAAE,MAAM,OAAO,CAAC;AACrE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAQrD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,oBAAoB,QAErE;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,QAE1D;AA+BD,wBAAsB,YAAY,CAChC,MAAM,EAAE,0BAA0B,4CA8DnC"}
@@ -1,3 +1,7 @@
1
1
  import { InternalAxiosRequestConfig } from 'axios';
2
+ /**
3
+ * 请求前的「预测式刷新」:若本地判断 access_token 即将/已过期,提前刷新。
4
+ * 这是一层优化;真正的兜底由响应拦截器的 401 自动刷新+重放保证。
5
+ */
2
6
  export default function refreshToken(config: InternalAxiosRequestConfig): Promise<InternalAxiosRequestConfig<any>>;
3
7
  //# sourceMappingURL=refreshToken.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"refreshToken.d.ts","sourceRoot":"","sources":["../../src/interceptors/refreshToken.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,0BAA0B,EAAE,MAAM,OAAO,CAAC;AAY1D,wBAA8B,YAAY,CACxC,MAAM,EAAE,0BAA0B,4CAqEnC"}
1
+ {"version":3,"file":"refreshToken.d.ts","sourceRoot":"","sources":["../../src/interceptors/refreshToken.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,0BAA0B,EAAE,MAAM,OAAO,CAAC;AAerE;;;GAGG;AACH,wBAA8B,YAAY,CACxC,MAAM,EAAE,0BAA0B,4CAkCnC"}
@@ -1,3 +1,13 @@
1
- import { AxiosResponse } from 'axios';
2
- export default function ResponseInterceptor(response: AxiosResponse): any;
1
+ import { AxiosInstance, AxiosResponse } from 'axios';
2
+ /**
3
+ * 响应拦截器工厂。
4
+ *
5
+ * 业界标准 401 处理:业务接口返回 401 时,用 refresh_token 刷新一次并重放原请求;
6
+ * 仅当刷新失败时把 401 透传给上层(由显式 logout 决定是否清登录态)。
7
+ * - 仅在客户端重试(SSR 无 cookie jar)。
8
+ * - 每个请求最多重试一次,避免死循环。
9
+ * - /v2/auth/*、刷新接口本身不触发重试。
10
+ */
11
+ export declare function createResponseInterceptor(instance: AxiosInstance): (response: AxiosResponse) => Promise<any>;
12
+ export default createResponseInterceptor;
3
13
  //# sourceMappingURL=response.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../src/interceptors/response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,aAAa,EAAE,MAAM,OAAO,CAAC;AAKlD,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,QAAQ,EAAE,aAAa,GAAG,GAAG,CAuDxE"}
1
+ {"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../src/interceptors/response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,aAAa,EAAE,aAAa,EAA8B,MAAM,OAAO,CAAC;AAwE7F;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,aAAa,IACrB,UAAU,aAAa,KAAG,OAAO,CAAC,GAAG,CAAC,CAoBjF;AAED,eAAe,yBAAyB,CAAC"}
@@ -0,0 +1,14 @@
1
+ /** 业务信封里的 toast。无发放时后端应省略该字段。 */
2
+ export type ResponseToast = {
3
+ amount: number;
4
+ title?: string;
5
+ };
6
+ /** 客户端 window 事件名。产品层自行监听并展示 UI,本库不弹 toast。 */
7
+ export declare const RESPONSE_TOAST_EVENT = "xchain-response-toast";
8
+ /**
9
+ * 从业务信封 `{ data, status, toast }` 或 AxiosResponse `{ data: envelope }` 解析 toast。
10
+ * 只认 `toast` 字段,不把业务 `data.amount` 当成提示。
11
+ */
12
+ export declare function parseResponseToast(payload: unknown): ResponseToast | null;
13
+ export declare function emitResponseToast(payload: unknown): void;
14
+ //# sourceMappingURL=responseToast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"responseToast.d.ts","sourceRoot":"","sources":["../src/responseToast.ts"],"names":[],"mappings":"AAEA,iCAAiC;AACjC,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,+CAA+C;AAC/C,eAAO,MAAM,oBAAoB,0BAA0B,CAAC;AAa5D;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,GAAG,IAAI,CASzE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAQxD"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 判断是否处于“服务端运行时”。
3
+ *
4
+ * 关键点:只要存在真实浏览器 window,就一律视为客户端,
5
+ * 避免业务方在客户端 bundle 中固化 IS_SERVER=true 时被误判为服务端,
6
+ * 从而走 next/headers 读 cookie 失败、请求不带 Authorization。
7
+ */
8
+ export declare function isServerRuntime(): boolean;
9
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAKzC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * 触发一次 token 刷新;并发/紧邻调用共享同一个结果。
3
+ *
4
+ * 关键设计:cookie 由服务端 `/api/refresh/token` 的 Set-Cookie 统一写入,
5
+ * 客户端这里「绝不」再用 js-cookie 写一遍,避免双写竞态把 cookie 写坏。
6
+ *
7
+ * @returns 新的 access_token;刷新失败返回 null。
8
+ */
9
+ export declare function refreshAccessToken(): Promise<string | null>;
10
+ export declare function getCurrentAccessToken(): string;
11
+ //# sourceMappingURL=tokenRefresh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenRefresh.d.ts","sourceRoot":"","sources":["../src/tokenRefresh.ts"],"names":[],"mappings":"AAqCA;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwD3D;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C"}
package/dist/types.d.ts CHANGED
@@ -1,4 +1,10 @@
1
1
  import { AxiosRequestConfig } from 'axios';
2
+ import { ResponseToast } from './responseToast';
3
+ export type { ResponseToast };
4
+ export interface ServerHeaderProvider {
5
+ getAccessToken(): Promise<string | undefined>;
6
+ getLanguage(): Promise<string | undefined>;
7
+ }
2
8
  export interface ApiRequestConfig extends AxiosRequestConfig {
3
9
  withCredentials?: boolean;
4
10
  returnFullResponse?: boolean;
@@ -28,6 +34,7 @@ export interface IResponse<T> {
28
34
  data: T;
29
35
  pagination?: null | Pagination;
30
36
  status: Status;
37
+ toast?: ResponseToast;
31
38
  [property: string]: any;
32
39
  }
33
40
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,OAAO,CAAC;AAE3C,MAAM,WAAW,gBAAiB,SAAQ,kBAAkB;IAC1D,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC;CACzB;AAED;;EAEE;AACF,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC;CACzB;AACD;;GAEG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B,IAAI,EAAE,CAAC,CAAC;IACR,UAAU,CAAC,EAAE,IAAI,GAAG,UAAU,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC;CACzB;AAED;;EAEE;AACF,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC;CACzB;AACD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC;CACzB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B,MAAM,WAAW,oBAAoB;IACnC,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC9C,WAAW,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,gBAAiB,SAAQ,kBAAkB;IAC1D,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC;CACzB;AAED;;EAEE;AACF,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B,IAAI,EAAE,CAAC,CAAC;IACR,UAAU,CAAC,EAAE,IAAI,GAAG,UAAU,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC;CACzB;AAED;;EAEE;AACF,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC;CACzB;AACD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC;CACzB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xchain/request",
3
- "version": "1.1.0-beta.9",
3
+ "version": "1.1.0-beta.91",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -17,17 +17,28 @@
17
17
  "dist",
18
18
  "!**/*.tsbuildinfo"
19
19
  ],
20
+ "peerDependencies": {
21
+ "axios": "1.13.2",
22
+ "js-cookie": "3.0.5",
23
+ "next": "16.1.6",
24
+ "qs": "6.14.0"
25
+ },
20
26
  "devDependencies": {
21
27
  "@types/js-cookie": "3.0.6",
22
- "@types/qs": "6.14.0"
23
- },
24
- "dependencies": {
28
+ "@types/qs": "6.14.0",
25
29
  "axios": "1.13.2",
26
30
  "js-cookie": "3.0.5",
27
31
  "next": "16.1.6",
28
- "qs": "6.14.0",
29
- "@0xchain/token": "1.1.0-beta.9",
30
- "@0xchain/logger": "1.1.0-beta.9"
32
+ "qs": "6.14.0"
33
+ },
34
+ "dependencies": {
35
+ "@0xchain/logger": "1.1.0-beta.91",
36
+ "@0xchain/token": "1.1.0-beta.91"
37
+ },
38
+ "nx": {
39
+ "tags": [
40
+ "type:util"
41
+ ]
31
42
  },
32
43
  "publishConfig": {
33
44
  "access": "public"
@@ -1,4 +0,0 @@
1
- const __viteBrowserExternal = {};
2
- export {
3
- __viteBrowserExternal as default
4
- };