@gz-fronted/gz-pc 0.1.1-beta.1 → 0.1.1-beta.2
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/README.md +67 -0
- package/dist/fetch/index.cjs +143 -1
- package/dist/fetch/index.d.cts +12 -1
- package/dist/fetch/index.d.ts +12 -1
- package/dist/fetch/index.js +144 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -185,6 +185,7 @@ const result = await gzFetch<SaveResult, SaveParams>({
|
|
|
185
185
|
| `showErrorMessage` | `boolean` | `true` | 实例级错误提示开关 |
|
|
186
186
|
| `auth.headerName` | `string` | `Authorization` | Token 请求头名称 |
|
|
187
187
|
| `auth.formatToken` | `(token: string) => string` | `Bearer ${token}` | Token 格式化函数 |
|
|
188
|
+
| `unauthorized` | `GzFetchUnauthorizedOptions` | 未开启 | 可选的 HTTP 401 统一处理 |
|
|
188
189
|
| `middlewares` | `readonly GzFetchMiddleware[]` | `[]` | 请求、响应和错误中间件 |
|
|
189
190
|
|
|
190
191
|
需要覆盖默认成功状态时,只在应用初始化层配置:
|
|
@@ -284,6 +285,72 @@ controller.abort();
|
|
|
284
285
|
await promise;
|
|
285
286
|
```
|
|
286
287
|
|
|
288
|
+
## HTTP 401 统一处理
|
|
289
|
+
|
|
290
|
+
401 统一处理默认关闭,未显式开启时继续执行原有 HTTP 错误提示和抛错逻辑,不弹窗、
|
|
291
|
+
不跳转。需要启用时,在应用初始化配置中传入 `unauthorized.enabled: true`:
|
|
292
|
+
|
|
293
|
+
```ts
|
|
294
|
+
configureGzFetch({
|
|
295
|
+
baseURL: '/api',
|
|
296
|
+
getToken: () => runtimeToken,
|
|
297
|
+
unauthorized: {
|
|
298
|
+
enabled: true,
|
|
299
|
+
loginUrl: '/login',
|
|
300
|
+
modalTitle: '登录失效',
|
|
301
|
+
modalMessage: '当前登录状态已失效,请重新登录。',
|
|
302
|
+
},
|
|
303
|
+
});
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
配置默认值如下:
|
|
307
|
+
|
|
308
|
+
| 字段 | 类型 | 默认值 |
|
|
309
|
+
| ---------------- | ------------ | --------------------------------------- |
|
|
310
|
+
| `enabled` | `boolean` | `false` |
|
|
311
|
+
| `loginUrl` | `string` | `/login` |
|
|
312
|
+
| `modalTitle` | `string` | `登录失效` |
|
|
313
|
+
| `modalMessage` | `string` | `当前登录状态已失效,请重新登录。` |
|
|
314
|
+
| `onUnauthorized` | `() => void` | 无;确认后使用 `window.location.assign` |
|
|
315
|
+
|
|
316
|
+
为了让弹窗继承宿主项目当前的 gg-ui 主题,需要在应用根部的 `ConfigProvider` 内挂载一次
|
|
317
|
+
`GzFetchUnauthorizedModal`:
|
|
318
|
+
|
|
319
|
+
```tsx
|
|
320
|
+
import { GzFetchUnauthorizedModal } from '@gz-fronted/gz-pc/fetch';
|
|
321
|
+
import { ConfigProvider } from '@chenhui996/gg-ui';
|
|
322
|
+
|
|
323
|
+
<ConfigProvider themeMode={themeMode}>
|
|
324
|
+
<GzFetchUnauthorizedModal />
|
|
325
|
+
<App />
|
|
326
|
+
</ConfigProvider>;
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
该组件使用受控 gg-ui `Modal`,不会调用脱离 React 上下文的静态
|
|
330
|
+
`Modal.confirm`,因此主题切换时会继续读取宿主 `ConfigProvider` 的主题 Token,
|
|
331
|
+
无需复制亮色或暗色样式。业务页面不需要维护 401 状态或重复渲染弹窗。
|
|
332
|
+
|
|
333
|
+
所有由同一份 gz-pc 包创建的默认客户端和独立客户端共享一个 401 管理器。首个 401
|
|
334
|
+
打开弹窗,后续并发 401 不会创建新弹窗;取消或弹窗关闭动画结束后会释放状态,后续
|
|
335
|
+
独立发生的 401 可以再次打开。确认操作也有同一状态锁,不会重复执行登录跳转。
|
|
336
|
+
|
|
337
|
+
业务项目需要自定义 SSO、登出或状态清理时传入 `onUnauthorized`。用户确认后优先执行
|
|
338
|
+
该回调;只有未提供回调时才通过 `window.location.assign(loginUrl)` 跳转:
|
|
339
|
+
|
|
340
|
+
```ts
|
|
341
|
+
configureGzFetch({
|
|
342
|
+
unauthorized: {
|
|
343
|
+
enabled: true,
|
|
344
|
+
onUnauthorized: () => {
|
|
345
|
+
authService.logout();
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
开启该能力后,401 仍会作为 `GzFetchError` 抛给调用方,但请求核心不会再为同一个
|
|
352
|
+
401 额外调用普通 `message.error`。其他 HTTP 错误、网络错误、超时和取消请求行为不变。
|
|
353
|
+
|
|
287
354
|
## 中间件
|
|
288
355
|
|
|
289
356
|
中间件的 `onRequest`、`onResponse` 和 `onError` 都按注册顺序执行,不采用洋葱
|
package/dist/fetch/index.cjs
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var ggUi = require('@chenhui996/gg-ui');
|
|
4
4
|
var axios = require('axios');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
7
|
|
|
6
8
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
9
|
|
|
@@ -96,6 +98,103 @@ async function runErrorMiddlewares(error, context, middlewares) {
|
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
100
|
|
|
101
|
+
// src/fetch/unauthorized.ts
|
|
102
|
+
var DEFAULT_UNAUTHORIZED_LOGIN_URL = "/login";
|
|
103
|
+
var DEFAULT_UNAUTHORIZED_MODAL_TITLE = "登录失效";
|
|
104
|
+
var DEFAULT_UNAUTHORIZED_MODAL_MESSAGE = "当前登录状态已失效,请重新登录。";
|
|
105
|
+
var IDLE_SNAPSHOT = { phase: "idle" };
|
|
106
|
+
var snapshot = IDLE_SNAPSHOT;
|
|
107
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
108
|
+
var modalHosts = /* @__PURE__ */ new Set();
|
|
109
|
+
var emitChange = () => {
|
|
110
|
+
for (const listener of listeners) {
|
|
111
|
+
listener();
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
var setSnapshot = (nextSnapshot) => {
|
|
115
|
+
snapshot = nextSnapshot;
|
|
116
|
+
emitChange();
|
|
117
|
+
};
|
|
118
|
+
var resolveUnauthorizedOptions = (options) => {
|
|
119
|
+
var _a, _b, _c, _d;
|
|
120
|
+
return {
|
|
121
|
+
enabled: (_a = options == null ? void 0 : options.enabled) != null ? _a : false,
|
|
122
|
+
loginUrl: (_b = options == null ? void 0 : options.loginUrl) != null ? _b : DEFAULT_UNAUTHORIZED_LOGIN_URL,
|
|
123
|
+
modalTitle: (_c = options == null ? void 0 : options.modalTitle) != null ? _c : DEFAULT_UNAUTHORIZED_MODAL_TITLE,
|
|
124
|
+
modalMessage: (_d = options == null ? void 0 : options.modalMessage) != null ? _d : DEFAULT_UNAUTHORIZED_MODAL_MESSAGE,
|
|
125
|
+
...(options == null ? void 0 : options.onUnauthorized) === void 0 ? {} : { onUnauthorized: options.onUnauthorized }
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
var getUnauthorizedSnapshot = () => snapshot;
|
|
129
|
+
var getUnauthorizedServerSnapshot = () => IDLE_SNAPSHOT;
|
|
130
|
+
var subscribeUnauthorized = (listener) => {
|
|
131
|
+
listeners.add(listener);
|
|
132
|
+
return () => listeners.delete(listener);
|
|
133
|
+
};
|
|
134
|
+
var registerUnauthorizedModalHost = (hostId) => {
|
|
135
|
+
modalHosts.add(hostId);
|
|
136
|
+
if (snapshot.activeHostId === void 0) {
|
|
137
|
+
setSnapshot({ ...snapshot, activeHostId: hostId });
|
|
138
|
+
}
|
|
139
|
+
return () => {
|
|
140
|
+
modalHosts.delete(hostId);
|
|
141
|
+
if (snapshot.activeHostId !== hostId) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const nextHost = modalHosts.values().next();
|
|
145
|
+
const nextHostId = nextHost.done ? void 0 : nextHost.value;
|
|
146
|
+
if (snapshot.phase === "closing") {
|
|
147
|
+
setSnapshot(
|
|
148
|
+
nextHostId === void 0 ? IDLE_SNAPSHOT : { activeHostId: nextHostId, phase: "idle" }
|
|
149
|
+
);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (nextHostId === void 0) {
|
|
153
|
+
setSnapshot(
|
|
154
|
+
snapshot.options === void 0 ? { phase: snapshot.phase } : { options: snapshot.options, phase: snapshot.phase }
|
|
155
|
+
);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
setSnapshot({ ...snapshot, activeHostId: nextHostId });
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
var openUnauthorizedModal = (options) => {
|
|
162
|
+
if (!options.enabled || snapshot.phase !== "idle") {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
setSnapshot({
|
|
166
|
+
...snapshot.activeHostId === void 0 ? {} : { activeHostId: snapshot.activeHostId },
|
|
167
|
+
options,
|
|
168
|
+
phase: "open"
|
|
169
|
+
});
|
|
170
|
+
return true;
|
|
171
|
+
};
|
|
172
|
+
var beginCloseUnauthorizedModal = () => {
|
|
173
|
+
if (snapshot.phase !== "open" || snapshot.options === void 0) {
|
|
174
|
+
return void 0;
|
|
175
|
+
}
|
|
176
|
+
const { options } = snapshot;
|
|
177
|
+
setSnapshot({ ...snapshot, phase: "closing" });
|
|
178
|
+
return options;
|
|
179
|
+
};
|
|
180
|
+
var cancelUnauthorizedModal = () => beginCloseUnauthorizedModal() !== void 0;
|
|
181
|
+
var confirmUnauthorizedModal = () => beginCloseUnauthorizedModal();
|
|
182
|
+
var completeUnauthorizedModal = () => {
|
|
183
|
+
if (snapshot.phase !== "closing") {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
setSnapshot(
|
|
187
|
+
snapshot.activeHostId === void 0 ? IDLE_SNAPSHOT : { activeHostId: snapshot.activeHostId, phase: "idle" }
|
|
188
|
+
);
|
|
189
|
+
};
|
|
190
|
+
var executeUnauthorizedAction = (options, navigate = (loginUrl) => window.location.assign(loginUrl)) => {
|
|
191
|
+
if (options.onUnauthorized) {
|
|
192
|
+
options.onUnauthorized();
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
navigate(options.loginUrl);
|
|
196
|
+
};
|
|
197
|
+
|
|
99
198
|
// src/fetch/client.ts
|
|
100
199
|
var DEFAULT_TIMEOUT = 15e3;
|
|
101
200
|
var DEFAULT_AUTH_HEADER = "Authorization";
|
|
@@ -115,6 +214,7 @@ function createGzFetch(options = {}) {
|
|
|
115
214
|
const showInstanceErrorMessage = (_b = options.showErrorMessage) != null ? _b : true;
|
|
116
215
|
const headerName = (_d = (_c = options.auth) == null ? void 0 : _c.headerName) != null ? _d : DEFAULT_AUTH_HEADER;
|
|
117
216
|
const formatToken = (_f = (_e = options.auth) == null ? void 0 : _e.formatToken) != null ? _f : ((token) => `Bearer ${token}`);
|
|
217
|
+
const unauthorizedOptions = resolveUnauthorizedOptions(options.unauthorized);
|
|
118
218
|
const instance = axios__default.default.create({
|
|
119
219
|
...options.baseURL === void 0 ? {} : { baseURL: options.baseURL },
|
|
120
220
|
timeout: (_g = options.timeout) != null ? _g : DEFAULT_TIMEOUT,
|
|
@@ -156,9 +256,13 @@ function createGzFetch(options = {}) {
|
|
|
156
256
|
return await runResponseMiddlewares(response.data, context, middlewares);
|
|
157
257
|
} catch (originalError) {
|
|
158
258
|
const error = toGzFetchError(originalError);
|
|
259
|
+
const shouldHandleUnauthorized = unauthorizedOptions.enabled && error.type === "HTTP_ERROR" && error.status === 401;
|
|
260
|
+
if (shouldHandleUnauthorized) {
|
|
261
|
+
openUnauthorizedModal(unauthorizedOptions);
|
|
262
|
+
}
|
|
159
263
|
await runErrorMiddlewares(error, { config: currentConfig }, middlewares);
|
|
160
264
|
const shouldShowError = (_a2 = currentConfig.showErrorMessage) != null ? _a2 : showInstanceErrorMessage;
|
|
161
|
-
if (shouldShowError && error.type !== "CANCELED_ERROR") {
|
|
265
|
+
if (shouldShowError && error.type !== "CANCELED_ERROR" && !shouldHandleUnauthorized) {
|
|
162
266
|
ggUi.message.error(error.message);
|
|
163
267
|
}
|
|
164
268
|
throw error;
|
|
@@ -194,8 +298,46 @@ async function gzFetch(config) {
|
|
|
194
298
|
}
|
|
195
299
|
return defaultClient(config);
|
|
196
300
|
}
|
|
301
|
+
var GzFetchUnauthorizedModal = () => {
|
|
302
|
+
var _a, _b, _c;
|
|
303
|
+
const hostIdRef = react.useRef(void 0);
|
|
304
|
+
(_a = hostIdRef.current) != null ? _a : hostIdRef.current = /* @__PURE__ */ Symbol("gz-fetch-unauthorized-modal-host");
|
|
305
|
+
const hostId = hostIdRef.current;
|
|
306
|
+
const snapshot2 = react.useSyncExternalStore(
|
|
307
|
+
subscribeUnauthorized,
|
|
308
|
+
getUnauthorizedSnapshot,
|
|
309
|
+
getUnauthorizedServerSnapshot
|
|
310
|
+
);
|
|
311
|
+
react.useEffect(() => registerUnauthorizedModalHost(hostId), [hostId]);
|
|
312
|
+
if (snapshot2.activeHostId !== hostId) {
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
const handleConfirm = () => {
|
|
316
|
+
const options = confirmUnauthorizedModal();
|
|
317
|
+
if (options) {
|
|
318
|
+
executeUnauthorizedAction(options);
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
322
|
+
ggUi.Modal,
|
|
323
|
+
{
|
|
324
|
+
afterClose: completeUnauthorizedModal,
|
|
325
|
+
cancelText: "取消",
|
|
326
|
+
closable: true,
|
|
327
|
+
okText: "重新登录",
|
|
328
|
+
open: snapshot2.phase === "open",
|
|
329
|
+
title: (_b = snapshot2.options) == null ? void 0 : _b.modalTitle,
|
|
330
|
+
onCancel: cancelUnauthorizedModal,
|
|
331
|
+
onOk: handleConfirm,
|
|
332
|
+
children: (_c = snapshot2.options) == null ? void 0 : _c.modalMessage
|
|
333
|
+
}
|
|
334
|
+
);
|
|
335
|
+
};
|
|
336
|
+
GzFetchUnauthorizedModal.displayName = "GzFetchUnauthorizedModal";
|
|
337
|
+
var GzFetchUnauthorizedModal_default = GzFetchUnauthorizedModal;
|
|
197
338
|
|
|
198
339
|
exports.GzFetchError = GzFetchError;
|
|
340
|
+
exports.GzFetchUnauthorizedModal = GzFetchUnauthorizedModal_default;
|
|
199
341
|
exports.configureGzFetch = configureGzFetch;
|
|
200
342
|
exports.createGzFetch = createGzFetch;
|
|
201
343
|
exports.getResponseMessage = getResponseMessage;
|
package/dist/fetch/index.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiosHeaders } from 'axios';
|
|
2
|
+
import { FC } from 'react';
|
|
2
3
|
|
|
3
4
|
type GzFetchErrorType = 'HTTP_ERROR' | 'NETWORK_ERROR' | 'TIMEOUT_ERROR' | 'CANCELED_ERROR' | 'UNKNOWN_ERROR';
|
|
4
5
|
interface GzFetchErrorOptions {
|
|
@@ -54,6 +55,13 @@ interface GzFetchAuthOptions {
|
|
|
54
55
|
headerName?: string;
|
|
55
56
|
formatToken?: (token: string) => string;
|
|
56
57
|
}
|
|
58
|
+
interface GzFetchUnauthorizedOptions {
|
|
59
|
+
enabled?: boolean;
|
|
60
|
+
loginUrl?: string;
|
|
61
|
+
modalTitle?: string;
|
|
62
|
+
modalMessage?: string;
|
|
63
|
+
onUnauthorized?: () => void;
|
|
64
|
+
}
|
|
57
65
|
interface CreateGzFetchOptions {
|
|
58
66
|
baseURL?: string;
|
|
59
67
|
timeout?: number;
|
|
@@ -61,6 +69,7 @@ interface CreateGzFetchOptions {
|
|
|
61
69
|
getToken?: () => string | undefined | Promise<string | undefined>;
|
|
62
70
|
showErrorMessage?: boolean;
|
|
63
71
|
auth?: GzFetchAuthOptions;
|
|
72
|
+
unauthorized?: GzFetchUnauthorizedOptions;
|
|
64
73
|
middlewares?: readonly GzFetchMiddleware[];
|
|
65
74
|
}
|
|
66
75
|
interface GzFetchClient {
|
|
@@ -77,4 +86,6 @@ declare function createGzFetch(options?: CreateGzFetchOptions): GzFetchClient;
|
|
|
77
86
|
declare function configureGzFetch(options: CreateGzFetchOptions): void;
|
|
78
87
|
declare function gzFetch<TResponse, TRequestParams = unknown>(config: GzRequestConfig<TRequestParams>): Promise<TResponse>;
|
|
79
88
|
|
|
80
|
-
|
|
89
|
+
declare const GzFetchUnauthorizedModal: FC;
|
|
90
|
+
|
|
91
|
+
export { type CreateGzFetchOptions, type GzErrorContext, type GzFetch, type GzFetchAuthOptions, type GzFetchClient, GzFetchError, type GzFetchErrorOptions, type GzFetchErrorType, type GzFetchMiddleware, GzFetchUnauthorizedModal, type GzFetchUnauthorizedOptions, type GzInternalRequestConfig, type GzRequestConfig, type GzRequestHeaders, type GzRequestMethod, type GzRequestOptions, type GzRequestParams, type GzResponseContext, type GzResponseType, configureGzFetch, createGzFetch, getResponseMessage, gzFetch, toGzFetchError };
|
package/dist/fetch/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiosHeaders } from 'axios';
|
|
2
|
+
import { FC } from 'react';
|
|
2
3
|
|
|
3
4
|
type GzFetchErrorType = 'HTTP_ERROR' | 'NETWORK_ERROR' | 'TIMEOUT_ERROR' | 'CANCELED_ERROR' | 'UNKNOWN_ERROR';
|
|
4
5
|
interface GzFetchErrorOptions {
|
|
@@ -54,6 +55,13 @@ interface GzFetchAuthOptions {
|
|
|
54
55
|
headerName?: string;
|
|
55
56
|
formatToken?: (token: string) => string;
|
|
56
57
|
}
|
|
58
|
+
interface GzFetchUnauthorizedOptions {
|
|
59
|
+
enabled?: boolean;
|
|
60
|
+
loginUrl?: string;
|
|
61
|
+
modalTitle?: string;
|
|
62
|
+
modalMessage?: string;
|
|
63
|
+
onUnauthorized?: () => void;
|
|
64
|
+
}
|
|
57
65
|
interface CreateGzFetchOptions {
|
|
58
66
|
baseURL?: string;
|
|
59
67
|
timeout?: number;
|
|
@@ -61,6 +69,7 @@ interface CreateGzFetchOptions {
|
|
|
61
69
|
getToken?: () => string | undefined | Promise<string | undefined>;
|
|
62
70
|
showErrorMessage?: boolean;
|
|
63
71
|
auth?: GzFetchAuthOptions;
|
|
72
|
+
unauthorized?: GzFetchUnauthorizedOptions;
|
|
64
73
|
middlewares?: readonly GzFetchMiddleware[];
|
|
65
74
|
}
|
|
66
75
|
interface GzFetchClient {
|
|
@@ -77,4 +86,6 @@ declare function createGzFetch(options?: CreateGzFetchOptions): GzFetchClient;
|
|
|
77
86
|
declare function configureGzFetch(options: CreateGzFetchOptions): void;
|
|
78
87
|
declare function gzFetch<TResponse, TRequestParams = unknown>(config: GzRequestConfig<TRequestParams>): Promise<TResponse>;
|
|
79
88
|
|
|
80
|
-
|
|
89
|
+
declare const GzFetchUnauthorizedModal: FC;
|
|
90
|
+
|
|
91
|
+
export { type CreateGzFetchOptions, type GzErrorContext, type GzFetch, type GzFetchAuthOptions, type GzFetchClient, GzFetchError, type GzFetchErrorOptions, type GzFetchErrorType, type GzFetchMiddleware, GzFetchUnauthorizedModal, type GzFetchUnauthorizedOptions, type GzInternalRequestConfig, type GzRequestConfig, type GzRequestHeaders, type GzRequestMethod, type GzRequestOptions, type GzRequestParams, type GzResponseContext, type GzResponseType, configureGzFetch, createGzFetch, getResponseMessage, gzFetch, toGzFetchError };
|
package/dist/fetch/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { message } from '@chenhui996/gg-ui';
|
|
1
|
+
import { Modal, message } from '@chenhui996/gg-ui';
|
|
2
2
|
import axios, { AxiosError, AxiosHeaders } from 'axios';
|
|
3
|
+
import { useRef, useSyncExternalStore, useEffect } from 'react';
|
|
4
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
5
|
|
|
4
6
|
// src/fetch/client.ts
|
|
5
7
|
var GzFetchError = class extends Error {
|
|
@@ -90,6 +92,103 @@ async function runErrorMiddlewares(error, context, middlewares) {
|
|
|
90
92
|
}
|
|
91
93
|
}
|
|
92
94
|
|
|
95
|
+
// src/fetch/unauthorized.ts
|
|
96
|
+
var DEFAULT_UNAUTHORIZED_LOGIN_URL = "/login";
|
|
97
|
+
var DEFAULT_UNAUTHORIZED_MODAL_TITLE = "登录失效";
|
|
98
|
+
var DEFAULT_UNAUTHORIZED_MODAL_MESSAGE = "当前登录状态已失效,请重新登录。";
|
|
99
|
+
var IDLE_SNAPSHOT = { phase: "idle" };
|
|
100
|
+
var snapshot = IDLE_SNAPSHOT;
|
|
101
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
102
|
+
var modalHosts = /* @__PURE__ */ new Set();
|
|
103
|
+
var emitChange = () => {
|
|
104
|
+
for (const listener of listeners) {
|
|
105
|
+
listener();
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
var setSnapshot = (nextSnapshot) => {
|
|
109
|
+
snapshot = nextSnapshot;
|
|
110
|
+
emitChange();
|
|
111
|
+
};
|
|
112
|
+
var resolveUnauthorizedOptions = (options) => {
|
|
113
|
+
var _a, _b, _c, _d;
|
|
114
|
+
return {
|
|
115
|
+
enabled: (_a = options == null ? void 0 : options.enabled) != null ? _a : false,
|
|
116
|
+
loginUrl: (_b = options == null ? void 0 : options.loginUrl) != null ? _b : DEFAULT_UNAUTHORIZED_LOGIN_URL,
|
|
117
|
+
modalTitle: (_c = options == null ? void 0 : options.modalTitle) != null ? _c : DEFAULT_UNAUTHORIZED_MODAL_TITLE,
|
|
118
|
+
modalMessage: (_d = options == null ? void 0 : options.modalMessage) != null ? _d : DEFAULT_UNAUTHORIZED_MODAL_MESSAGE,
|
|
119
|
+
...(options == null ? void 0 : options.onUnauthorized) === void 0 ? {} : { onUnauthorized: options.onUnauthorized }
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
var getUnauthorizedSnapshot = () => snapshot;
|
|
123
|
+
var getUnauthorizedServerSnapshot = () => IDLE_SNAPSHOT;
|
|
124
|
+
var subscribeUnauthorized = (listener) => {
|
|
125
|
+
listeners.add(listener);
|
|
126
|
+
return () => listeners.delete(listener);
|
|
127
|
+
};
|
|
128
|
+
var registerUnauthorizedModalHost = (hostId) => {
|
|
129
|
+
modalHosts.add(hostId);
|
|
130
|
+
if (snapshot.activeHostId === void 0) {
|
|
131
|
+
setSnapshot({ ...snapshot, activeHostId: hostId });
|
|
132
|
+
}
|
|
133
|
+
return () => {
|
|
134
|
+
modalHosts.delete(hostId);
|
|
135
|
+
if (snapshot.activeHostId !== hostId) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const nextHost = modalHosts.values().next();
|
|
139
|
+
const nextHostId = nextHost.done ? void 0 : nextHost.value;
|
|
140
|
+
if (snapshot.phase === "closing") {
|
|
141
|
+
setSnapshot(
|
|
142
|
+
nextHostId === void 0 ? IDLE_SNAPSHOT : { activeHostId: nextHostId, phase: "idle" }
|
|
143
|
+
);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (nextHostId === void 0) {
|
|
147
|
+
setSnapshot(
|
|
148
|
+
snapshot.options === void 0 ? { phase: snapshot.phase } : { options: snapshot.options, phase: snapshot.phase }
|
|
149
|
+
);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
setSnapshot({ ...snapshot, activeHostId: nextHostId });
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
var openUnauthorizedModal = (options) => {
|
|
156
|
+
if (!options.enabled || snapshot.phase !== "idle") {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
setSnapshot({
|
|
160
|
+
...snapshot.activeHostId === void 0 ? {} : { activeHostId: snapshot.activeHostId },
|
|
161
|
+
options,
|
|
162
|
+
phase: "open"
|
|
163
|
+
});
|
|
164
|
+
return true;
|
|
165
|
+
};
|
|
166
|
+
var beginCloseUnauthorizedModal = () => {
|
|
167
|
+
if (snapshot.phase !== "open" || snapshot.options === void 0) {
|
|
168
|
+
return void 0;
|
|
169
|
+
}
|
|
170
|
+
const { options } = snapshot;
|
|
171
|
+
setSnapshot({ ...snapshot, phase: "closing" });
|
|
172
|
+
return options;
|
|
173
|
+
};
|
|
174
|
+
var cancelUnauthorizedModal = () => beginCloseUnauthorizedModal() !== void 0;
|
|
175
|
+
var confirmUnauthorizedModal = () => beginCloseUnauthorizedModal();
|
|
176
|
+
var completeUnauthorizedModal = () => {
|
|
177
|
+
if (snapshot.phase !== "closing") {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
setSnapshot(
|
|
181
|
+
snapshot.activeHostId === void 0 ? IDLE_SNAPSHOT : { activeHostId: snapshot.activeHostId, phase: "idle" }
|
|
182
|
+
);
|
|
183
|
+
};
|
|
184
|
+
var executeUnauthorizedAction = (options, navigate = (loginUrl) => window.location.assign(loginUrl)) => {
|
|
185
|
+
if (options.onUnauthorized) {
|
|
186
|
+
options.onUnauthorized();
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
navigate(options.loginUrl);
|
|
190
|
+
};
|
|
191
|
+
|
|
93
192
|
// src/fetch/client.ts
|
|
94
193
|
var DEFAULT_TIMEOUT = 15e3;
|
|
95
194
|
var DEFAULT_AUTH_HEADER = "Authorization";
|
|
@@ -109,6 +208,7 @@ function createGzFetch(options = {}) {
|
|
|
109
208
|
const showInstanceErrorMessage = (_b = options.showErrorMessage) != null ? _b : true;
|
|
110
209
|
const headerName = (_d = (_c = options.auth) == null ? void 0 : _c.headerName) != null ? _d : DEFAULT_AUTH_HEADER;
|
|
111
210
|
const formatToken = (_f = (_e = options.auth) == null ? void 0 : _e.formatToken) != null ? _f : ((token) => `Bearer ${token}`);
|
|
211
|
+
const unauthorizedOptions = resolveUnauthorizedOptions(options.unauthorized);
|
|
112
212
|
const instance = axios.create({
|
|
113
213
|
...options.baseURL === void 0 ? {} : { baseURL: options.baseURL },
|
|
114
214
|
timeout: (_g = options.timeout) != null ? _g : DEFAULT_TIMEOUT,
|
|
@@ -150,9 +250,13 @@ function createGzFetch(options = {}) {
|
|
|
150
250
|
return await runResponseMiddlewares(response.data, context, middlewares);
|
|
151
251
|
} catch (originalError) {
|
|
152
252
|
const error = toGzFetchError(originalError);
|
|
253
|
+
const shouldHandleUnauthorized = unauthorizedOptions.enabled && error.type === "HTTP_ERROR" && error.status === 401;
|
|
254
|
+
if (shouldHandleUnauthorized) {
|
|
255
|
+
openUnauthorizedModal(unauthorizedOptions);
|
|
256
|
+
}
|
|
153
257
|
await runErrorMiddlewares(error, { config: currentConfig }, middlewares);
|
|
154
258
|
const shouldShowError = (_a2 = currentConfig.showErrorMessage) != null ? _a2 : showInstanceErrorMessage;
|
|
155
|
-
if (shouldShowError && error.type !== "CANCELED_ERROR") {
|
|
259
|
+
if (shouldShowError && error.type !== "CANCELED_ERROR" && !shouldHandleUnauthorized) {
|
|
156
260
|
message.error(error.message);
|
|
157
261
|
}
|
|
158
262
|
throw error;
|
|
@@ -188,5 +292,42 @@ async function gzFetch(config) {
|
|
|
188
292
|
}
|
|
189
293
|
return defaultClient(config);
|
|
190
294
|
}
|
|
295
|
+
var GzFetchUnauthorizedModal = () => {
|
|
296
|
+
var _a, _b, _c;
|
|
297
|
+
const hostIdRef = useRef(void 0);
|
|
298
|
+
(_a = hostIdRef.current) != null ? _a : hostIdRef.current = /* @__PURE__ */ Symbol("gz-fetch-unauthorized-modal-host");
|
|
299
|
+
const hostId = hostIdRef.current;
|
|
300
|
+
const snapshot2 = useSyncExternalStore(
|
|
301
|
+
subscribeUnauthorized,
|
|
302
|
+
getUnauthorizedSnapshot,
|
|
303
|
+
getUnauthorizedServerSnapshot
|
|
304
|
+
);
|
|
305
|
+
useEffect(() => registerUnauthorizedModalHost(hostId), [hostId]);
|
|
306
|
+
if (snapshot2.activeHostId !== hostId) {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
const handleConfirm = () => {
|
|
310
|
+
const options = confirmUnauthorizedModal();
|
|
311
|
+
if (options) {
|
|
312
|
+
executeUnauthorizedAction(options);
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
return /* @__PURE__ */ jsx(
|
|
316
|
+
Modal,
|
|
317
|
+
{
|
|
318
|
+
afterClose: completeUnauthorizedModal,
|
|
319
|
+
cancelText: "取消",
|
|
320
|
+
closable: true,
|
|
321
|
+
okText: "重新登录",
|
|
322
|
+
open: snapshot2.phase === "open",
|
|
323
|
+
title: (_b = snapshot2.options) == null ? void 0 : _b.modalTitle,
|
|
324
|
+
onCancel: cancelUnauthorizedModal,
|
|
325
|
+
onOk: handleConfirm,
|
|
326
|
+
children: (_c = snapshot2.options) == null ? void 0 : _c.modalMessage
|
|
327
|
+
}
|
|
328
|
+
);
|
|
329
|
+
};
|
|
330
|
+
GzFetchUnauthorizedModal.displayName = "GzFetchUnauthorizedModal";
|
|
331
|
+
var GzFetchUnauthorizedModal_default = GzFetchUnauthorizedModal;
|
|
191
332
|
|
|
192
|
-
export { GzFetchError, configureGzFetch, createGzFetch, getResponseMessage, gzFetch, toGzFetchError };
|
|
333
|
+
export { GzFetchError, GzFetchUnauthorizedModal_default as GzFetchUnauthorizedModal, configureGzFetch, createGzFetch, getResponseMessage, gzFetch, toGzFetchError };
|