openxiangda 1.0.61 → 1.0.63
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/package.json +1 -1
- package/packages/sdk/dist/components/index.cjs +3 -3
- package/packages/sdk/dist/components/index.cjs.map +1 -1
- package/packages/sdk/dist/components/index.mjs +3 -3
- package/packages/sdk/dist/components/index.mjs.map +1 -1
- package/packages/sdk/dist/runtime/index.cjs +279 -16
- package/packages/sdk/dist/runtime/index.cjs.map +1 -1
- package/packages/sdk/dist/runtime/index.d.mts +1 -1
- package/packages/sdk/dist/runtime/index.d.ts +1 -1
- package/packages/sdk/dist/runtime/index.mjs +279 -16
- package/packages/sdk/dist/runtime/index.mjs.map +1 -1
- package/packages/sdk/dist/runtime/react.cjs +277 -13
- package/packages/sdk/dist/runtime/react.cjs.map +1 -1
- package/packages/sdk/dist/runtime/react.d.mts +60 -7
- package/packages/sdk/dist/runtime/react.d.ts +60 -7
- package/packages/sdk/dist/runtime/react.mjs +277 -13
- package/packages/sdk/dist/runtime/react.mjs.map +1 -1
- package/templates/openxiangda-react-spa/src/app/router.tsx +12 -1
- package/templates/openxiangda-react-spa/src/layouts/AdminShell.tsx +374 -96
- package/templates/openxiangda-react-spa/src/layouts/PublicShell.tsx +25 -3
- package/templates/openxiangda-react-spa/src/layouts/UserShell.tsx +101 -22
- package/templates/openxiangda-react-spa/src/pages/admin/RuntimeWorkspacePage.tsx +203 -41
- package/templates/openxiangda-react-spa/src/pages/defaults/DataRoutePage.tsx +80 -11
- package/templates/openxiangda-react-spa/src/pages/defaults/FilePreviewRoutePage.tsx +67 -14
- package/templates/openxiangda-react-spa/src/pages/defaults/FormRoutePage.tsx +153 -30
- package/templates/openxiangda-react-spa/src/pages/portal/UserPortalPage.tsx +53 -14
- package/templates/openxiangda-react-spa/src/pages/public/PublicHomePage.tsx +46 -6
- package/templates/openxiangda-react-spa/src/pages/states/NotFoundPage.tsx +26 -11
- package/templates/openxiangda-react-spa/src/shared/mac-admin.tsx +332 -0
- package/templates/openxiangda-react-spa/src/styles/index.css +42 -4
- package/templates/openxiangda-react-spa/tailwind.config.cjs +8 -0
- package/templates/openxiangda-react-spa/vite.config.ts +31 -0
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
import React__default from 'react';
|
|
2
2
|
|
|
3
|
+
type RuntimeErrorType = "unauthenticated" | "forbidden" | "network" | "unknown";
|
|
4
|
+
type RuntimeRequestError = Error & {
|
|
5
|
+
type?: RuntimeErrorType;
|
|
6
|
+
status?: number;
|
|
7
|
+
code?: number | string;
|
|
8
|
+
payload?: unknown;
|
|
9
|
+
};
|
|
10
|
+
interface RuntimeErrorSnapshot {
|
|
11
|
+
type: RuntimeErrorType;
|
|
12
|
+
status?: number;
|
|
13
|
+
code?: number | string;
|
|
14
|
+
message: string;
|
|
15
|
+
payload?: unknown;
|
|
16
|
+
}
|
|
17
|
+
declare class RuntimeHttpError extends Error {
|
|
18
|
+
type: RuntimeErrorType;
|
|
19
|
+
status?: number;
|
|
20
|
+
code?: number | string;
|
|
21
|
+
payload?: unknown;
|
|
22
|
+
constructor(snapshot: RuntimeErrorSnapshot);
|
|
23
|
+
}
|
|
3
24
|
interface RuntimeMenuItem {
|
|
4
25
|
id: string;
|
|
5
26
|
name: string;
|
|
@@ -48,12 +69,17 @@ interface RouteAccessResult {
|
|
|
48
69
|
routeCode?: string;
|
|
49
70
|
menuCode?: string;
|
|
50
71
|
path?: string;
|
|
72
|
+
status?: number;
|
|
73
|
+
code?: number | string;
|
|
74
|
+
message?: string;
|
|
75
|
+
errorType?: RuntimeErrorType;
|
|
76
|
+
payload?: unknown;
|
|
51
77
|
permissions?: RuntimePagePermissions;
|
|
52
78
|
}
|
|
53
79
|
interface RuntimeRequestState<T> {
|
|
54
80
|
data: T | null;
|
|
55
81
|
loading: boolean;
|
|
56
|
-
error:
|
|
82
|
+
error: RuntimeRequestError | null;
|
|
57
83
|
}
|
|
58
84
|
interface OpenXiangdaProviderProps {
|
|
59
85
|
appType?: string;
|
|
@@ -77,7 +103,7 @@ declare const useAppMenus: () => {
|
|
|
77
103
|
fetchImpl: typeof fetch;
|
|
78
104
|
reload: () => Promise<void>;
|
|
79
105
|
loading: boolean;
|
|
80
|
-
error:
|
|
106
|
+
error: RuntimeRequestError | null;
|
|
81
107
|
};
|
|
82
108
|
declare const usePermission: () => {
|
|
83
109
|
data: RuntimePagePermissions | null;
|
|
@@ -86,7 +112,7 @@ declare const usePermission: () => {
|
|
|
86
112
|
fetchImpl: typeof fetch;
|
|
87
113
|
reload: () => Promise<void>;
|
|
88
114
|
loading: boolean;
|
|
89
|
-
error:
|
|
115
|
+
error: RuntimeRequestError | null;
|
|
90
116
|
};
|
|
91
117
|
interface UseCanAccessRouteInput {
|
|
92
118
|
routeCode?: string;
|
|
@@ -97,13 +123,40 @@ declare const useCanAccessRoute: (input: UseCanAccessRouteInput) => {
|
|
|
97
123
|
canAccess: boolean;
|
|
98
124
|
data: RouteAccessResult | null;
|
|
99
125
|
loading: boolean;
|
|
100
|
-
error:
|
|
126
|
+
error: RuntimeRequestError | null;
|
|
101
127
|
};
|
|
102
128
|
interface PermissionBoundaryProps extends UseCanAccessRouteInput {
|
|
103
129
|
children: React__default.ReactNode;
|
|
104
|
-
fallback?: React__default.ReactNode;
|
|
105
|
-
loadingFallback?: React__default.ReactNode;
|
|
130
|
+
fallback?: React__default.ReactNode | PermissionBoundaryFallback;
|
|
131
|
+
loadingFallback?: React__default.ReactNode | PermissionBoundaryFallback;
|
|
132
|
+
}
|
|
133
|
+
interface PermissionBoundaryFallbackState {
|
|
134
|
+
access: ReturnType<typeof useCanAccessRoute>;
|
|
135
|
+
runtime: ReturnType<typeof useOpenXiangda>;
|
|
136
|
+
error: RuntimeRequestError | null;
|
|
137
|
+
errorType: RuntimeErrorType;
|
|
138
|
+
status?: number;
|
|
139
|
+
code?: number | string;
|
|
140
|
+
message: string;
|
|
106
141
|
}
|
|
142
|
+
type PermissionBoundaryFallback = (state: PermissionBoundaryFallbackState) => React__default.ReactNode;
|
|
107
143
|
declare const PermissionBoundary: React__default.FC<PermissionBoundaryProps>;
|
|
144
|
+
interface RuntimeResolveLoginOptions {
|
|
145
|
+
redirectUri?: string;
|
|
146
|
+
loginUrl?: string;
|
|
147
|
+
domain?: string;
|
|
148
|
+
}
|
|
149
|
+
interface RuntimeRedirectLoginOptions extends RuntimeResolveLoginOptions {
|
|
150
|
+
replace?: boolean;
|
|
151
|
+
}
|
|
152
|
+
interface RuntimeLogoutOptions extends RuntimeRedirectLoginOptions {
|
|
153
|
+
continueOnError?: boolean;
|
|
154
|
+
}
|
|
155
|
+
declare const useRuntimeAuth: () => {
|
|
156
|
+
logout: () => Promise<any>;
|
|
157
|
+
logoutAndRedirect: (options?: RuntimeLogoutOptions) => Promise<string>;
|
|
158
|
+
redirectToLogin: (options?: RuntimeRedirectLoginOptions) => Promise<string>;
|
|
159
|
+
resolveLoginUrl: (options?: RuntimeResolveLoginOptions) => Promise<string>;
|
|
160
|
+
};
|
|
108
161
|
|
|
109
|
-
export { OpenXiangdaProvider, type OpenXiangdaProviderProps, PermissionBoundary, type PermissionBoundaryProps, type RouteAccessResult, type RuntimeBootstrap, type RuntimeMenuItem, type RuntimePagePermissions, type RuntimeRequestState, type UseCanAccessRouteInput, useAppMenus, useCanAccessRoute, useOpenXiangda, usePermission, useRuntimeBootstrap };
|
|
162
|
+
export { OpenXiangdaProvider, type OpenXiangdaProviderProps, PermissionBoundary, type PermissionBoundaryFallback, type PermissionBoundaryFallbackState, type PermissionBoundaryProps, type RouteAccessResult, type RuntimeBootstrap, type RuntimeErrorSnapshot, type RuntimeErrorType, RuntimeHttpError, type RuntimeLogoutOptions, type RuntimeMenuItem, type RuntimePagePermissions, type RuntimeRedirectLoginOptions, type RuntimeRequestError, type RuntimeRequestState, type RuntimeResolveLoginOptions, type UseCanAccessRouteInput, useAppMenus, useCanAccessRoute, useOpenXiangda, usePermission, useRuntimeAuth, useRuntimeBootstrap };
|
|
@@ -16,6 +16,16 @@ var createBoundFetch = (fetchImpl) => {
|
|
|
16
16
|
|
|
17
17
|
// packages/sdk/src/runtime/react/openxiangdaProvider.tsx
|
|
18
18
|
import { Fragment, jsx } from "react/jsx-runtime";
|
|
19
|
+
var RuntimeHttpError = class extends Error {
|
|
20
|
+
constructor(snapshot) {
|
|
21
|
+
super(snapshot.message);
|
|
22
|
+
this.name = "RuntimeHttpError";
|
|
23
|
+
this.type = snapshot.type;
|
|
24
|
+
this.status = snapshot.status;
|
|
25
|
+
this.code = snapshot.code;
|
|
26
|
+
this.payload = snapshot.payload;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
19
29
|
var OpenXiangdaRuntimeContext = createContext(null);
|
|
20
30
|
var OpenXiangdaProvider = ({
|
|
21
31
|
appType,
|
|
@@ -38,7 +48,10 @@ var OpenXiangdaProvider = ({
|
|
|
38
48
|
setState({
|
|
39
49
|
data: null,
|
|
40
50
|
loading: false,
|
|
41
|
-
error:
|
|
51
|
+
error: createRuntimeError({
|
|
52
|
+
message: "appType \u4E0D\u80FD\u4E3A\u7A7A",
|
|
53
|
+
type: "unknown"
|
|
54
|
+
})
|
|
42
55
|
});
|
|
43
56
|
return;
|
|
44
57
|
}
|
|
@@ -56,9 +69,13 @@ var OpenXiangdaProvider = ({
|
|
|
56
69
|
headers: { accept: "application/json" }
|
|
57
70
|
}
|
|
58
71
|
);
|
|
59
|
-
const payload = await response
|
|
72
|
+
const payload = await readJsonPayload(response);
|
|
60
73
|
if (!response.ok || payload?.code >= 400) {
|
|
61
|
-
throw
|
|
74
|
+
throw createRuntimeHttpError(
|
|
75
|
+
response,
|
|
76
|
+
payload,
|
|
77
|
+
payload?.message || `Runtime bootstrap failed: ${response.status}`
|
|
78
|
+
);
|
|
62
79
|
}
|
|
63
80
|
setState({
|
|
64
81
|
data: payload?.data || null,
|
|
@@ -69,7 +86,7 @@ var OpenXiangdaProvider = ({
|
|
|
69
86
|
setState({
|
|
70
87
|
data: null,
|
|
71
88
|
loading: false,
|
|
72
|
-
error:
|
|
89
|
+
error: normalizeRuntimeError(error)
|
|
73
90
|
});
|
|
74
91
|
}
|
|
75
92
|
}, [resolvedAppType, resolvedFetch, servicePrefix]);
|
|
@@ -125,6 +142,23 @@ var useCanAccessRoute = (input) => {
|
|
|
125
142
|
setState((prev) => ({ ...prev, loading: runtime.loading }));
|
|
126
143
|
return;
|
|
127
144
|
}
|
|
145
|
+
if (runtime.error && !runtime.data) {
|
|
146
|
+
const snapshot = toRuntimeErrorSnapshot(runtime.error);
|
|
147
|
+
setState({
|
|
148
|
+
data: {
|
|
149
|
+
appType: runtime.appType,
|
|
150
|
+
canAccess: false,
|
|
151
|
+
status: snapshot.status,
|
|
152
|
+
code: snapshot.code,
|
|
153
|
+
message: snapshot.message,
|
|
154
|
+
errorType: snapshot.type,
|
|
155
|
+
payload: snapshot.payload
|
|
156
|
+
},
|
|
157
|
+
loading: false,
|
|
158
|
+
error: runtime.error
|
|
159
|
+
});
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
128
162
|
if (permissions?.hasFullAccess) {
|
|
129
163
|
setState({
|
|
130
164
|
data: { appType: runtime.appType, canAccess: true, permissions },
|
|
@@ -152,15 +186,33 @@ var useCanAccessRoute = (input) => {
|
|
|
152
186
|
body: JSON.stringify(input)
|
|
153
187
|
}
|
|
154
188
|
);
|
|
155
|
-
const payload = await response
|
|
189
|
+
const payload = await readJsonPayload(response);
|
|
190
|
+
const code = payload?.code ?? response.status;
|
|
191
|
+
const canAccess = Boolean(payload?.data?.canAccess);
|
|
192
|
+
const errorType = canAccess ? void 0 : classifyRuntimeError(response.status, code);
|
|
193
|
+
const data = {
|
|
194
|
+
...payload?.data || {
|
|
195
|
+
appType: runtime.appType,
|
|
196
|
+
canAccess: false
|
|
197
|
+
},
|
|
198
|
+
appType: payload?.data?.appType || runtime.appType,
|
|
199
|
+
canAccess,
|
|
200
|
+
status: response.status,
|
|
201
|
+
code,
|
|
202
|
+
message: payload?.message,
|
|
203
|
+
errorType,
|
|
204
|
+
payload
|
|
205
|
+
};
|
|
156
206
|
if (!disposed) {
|
|
207
|
+
const shouldTreatAsError = !response.ok || typeof code === "number" && code >= 500;
|
|
157
208
|
setState({
|
|
158
|
-
data
|
|
159
|
-
appType: runtime.appType,
|
|
160
|
-
canAccess: false
|
|
161
|
-
},
|
|
209
|
+
data,
|
|
162
210
|
loading: false,
|
|
163
|
-
error:
|
|
211
|
+
error: shouldTreatAsError ? createRuntimeHttpError(
|
|
212
|
+
response,
|
|
213
|
+
payload,
|
|
214
|
+
payload?.message || `Route check failed: ${response.status}`
|
|
215
|
+
) : null
|
|
164
216
|
});
|
|
165
217
|
}
|
|
166
218
|
} catch (error) {
|
|
@@ -168,7 +220,7 @@ var useCanAccessRoute = (input) => {
|
|
|
168
220
|
setState({
|
|
169
221
|
data: null,
|
|
170
222
|
loading: false,
|
|
171
|
-
error:
|
|
223
|
+
error: normalizeRuntimeError(error)
|
|
172
224
|
});
|
|
173
225
|
}
|
|
174
226
|
}
|
|
@@ -200,16 +252,226 @@ var PermissionBoundary = ({
|
|
|
200
252
|
menuCode,
|
|
201
253
|
path
|
|
202
254
|
}) => {
|
|
255
|
+
const runtime = useOpenXiangda();
|
|
203
256
|
const access = useCanAccessRoute({ routeCode, menuCode, path });
|
|
204
|
-
|
|
205
|
-
if (
|
|
257
|
+
const fallbackState = createPermissionFallbackState(access, runtime);
|
|
258
|
+
if (access.loading) {
|
|
259
|
+
return /* @__PURE__ */ jsx(Fragment, { children: renderBoundaryFallback(loadingFallback, fallbackState) });
|
|
260
|
+
}
|
|
261
|
+
if (!access.canAccess) {
|
|
262
|
+
return /* @__PURE__ */ jsx(Fragment, { children: renderBoundaryFallback(fallback, fallbackState) });
|
|
263
|
+
}
|
|
206
264
|
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
207
265
|
};
|
|
266
|
+
var useRuntimeAuth = () => {
|
|
267
|
+
const runtime = useOpenXiangda();
|
|
268
|
+
const resolveLoginUrl = useCallback(
|
|
269
|
+
async (options = {}) => {
|
|
270
|
+
const redirectUri = options.redirectUri || getCurrentHref();
|
|
271
|
+
const domain = options.domain || getCurrentHostname();
|
|
272
|
+
const appTenantId = getRecordString(runtime.data?.app, "tenantId");
|
|
273
|
+
try {
|
|
274
|
+
const statusUrl = withQuery(
|
|
275
|
+
buildServiceUrl(runtime.servicePrefix, "/api/sso/status"),
|
|
276
|
+
{ domain }
|
|
277
|
+
);
|
|
278
|
+
const statusResponse = await runtime.fetchImpl(statusUrl, {
|
|
279
|
+
credentials: "include",
|
|
280
|
+
headers: { accept: "application/json" }
|
|
281
|
+
});
|
|
282
|
+
const statusPayload = await readJsonPayload(statusResponse);
|
|
283
|
+
const sso = statusPayload?.data || {};
|
|
284
|
+
const enabled = Boolean(sso.enabled);
|
|
285
|
+
const shouldUseSso = Boolean(
|
|
286
|
+
enabled && (sso.forceLogin ?? sso.autoRedirect ?? true)
|
|
287
|
+
);
|
|
288
|
+
if (shouldUseSso) {
|
|
289
|
+
const loginUrlResponse = await runtime.fetchImpl(
|
|
290
|
+
withQuery(buildServiceUrl(runtime.servicePrefix, "/api/sso/login-url"), {
|
|
291
|
+
domain,
|
|
292
|
+
redirectUri,
|
|
293
|
+
...sso.tenantId || appTenantId ? { tenantId: String(sso.tenantId || appTenantId) } : {},
|
|
294
|
+
...sso.protocol ? { protocol: String(sso.protocol) } : {}
|
|
295
|
+
}),
|
|
296
|
+
{
|
|
297
|
+
credentials: "include",
|
|
298
|
+
headers: { accept: "application/json" }
|
|
299
|
+
}
|
|
300
|
+
);
|
|
301
|
+
const loginUrlPayload = await readJsonPayload(loginUrlResponse);
|
|
302
|
+
const loginUrl = loginUrlPayload?.data?.loginUrl || loginUrlPayload?.data?.url || loginUrlPayload?.loginUrl || loginUrlPayload?.url;
|
|
303
|
+
if (loginUrl) return String(loginUrl);
|
|
304
|
+
}
|
|
305
|
+
} catch {
|
|
306
|
+
}
|
|
307
|
+
const configuredLoginUrl = options.loginUrl || getRuntimeEnv("OPENXIANGDA_LOGIN_URL") || getRuntimeEnv("VITE_OPENXIANGDA_LOGIN_URL") || getRuntimeEnv("APP_LOGIN_URL") || getRuntimeEnv("VITE_APP_LOGIN_URL") || getRuntimeEnv("VITE_BATH_AUTH_URL") || getRuntimeEnv("BATH_AUTH_URL");
|
|
308
|
+
if (configuredLoginUrl) {
|
|
309
|
+
return attachCallback(configuredLoginUrl, redirectUri);
|
|
310
|
+
}
|
|
311
|
+
return attachCallback("/login", redirectUri);
|
|
312
|
+
},
|
|
313
|
+
[runtime.data?.app, runtime.fetchImpl, runtime.servicePrefix]
|
|
314
|
+
);
|
|
315
|
+
const redirectToLogin = useCallback(
|
|
316
|
+
async (options = {}) => {
|
|
317
|
+
const loginUrl = await resolveLoginUrl(options);
|
|
318
|
+
if (typeof window !== "undefined") {
|
|
319
|
+
if (options.replace === false) {
|
|
320
|
+
window.location.assign(loginUrl);
|
|
321
|
+
} else {
|
|
322
|
+
window.location.replace(loginUrl);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return loginUrl;
|
|
326
|
+
},
|
|
327
|
+
[resolveLoginUrl]
|
|
328
|
+
);
|
|
329
|
+
const logout = useCallback(async () => {
|
|
330
|
+
const response = await runtime.fetchImpl(
|
|
331
|
+
buildServiceUrl(runtime.servicePrefix, "/api/auth/logout"),
|
|
332
|
+
{
|
|
333
|
+
method: "POST",
|
|
334
|
+
credentials: "include",
|
|
335
|
+
headers: { accept: "application/json" }
|
|
336
|
+
}
|
|
337
|
+
);
|
|
338
|
+
const payload = await readJsonPayload(response);
|
|
339
|
+
if (!response.ok || payload?.code >= 400) {
|
|
340
|
+
throw createRuntimeHttpError(
|
|
341
|
+
response,
|
|
342
|
+
payload,
|
|
343
|
+
payload?.message || `Logout failed: ${response.status}`
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
return payload;
|
|
347
|
+
}, [runtime.fetchImpl, runtime.servicePrefix]);
|
|
348
|
+
const logoutAndRedirect = useCallback(
|
|
349
|
+
async (options = {}) => {
|
|
350
|
+
try {
|
|
351
|
+
await logout();
|
|
352
|
+
} catch (error) {
|
|
353
|
+
if (options.continueOnError === false) throw error;
|
|
354
|
+
}
|
|
355
|
+
return redirectToLogin(options);
|
|
356
|
+
},
|
|
357
|
+
[logout, redirectToLogin]
|
|
358
|
+
);
|
|
359
|
+
return {
|
|
360
|
+
logout,
|
|
361
|
+
logoutAndRedirect,
|
|
362
|
+
redirectToLogin,
|
|
363
|
+
resolveLoginUrl
|
|
364
|
+
};
|
|
365
|
+
};
|
|
208
366
|
var buildServiceUrl = (servicePrefix, path) => {
|
|
209
367
|
const prefix = servicePrefix.endsWith("/") ? servicePrefix.slice(0, -1) : servicePrefix;
|
|
210
368
|
const suffix = path.startsWith("/") ? path : `/${path}`;
|
|
211
369
|
return `${prefix}${suffix}`;
|
|
212
370
|
};
|
|
371
|
+
var readJsonPayload = async (response) => {
|
|
372
|
+
try {
|
|
373
|
+
return await response.json();
|
|
374
|
+
} catch {
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
var createRuntimeHttpError = (response, payload, fallbackMessage) => createRuntimeError({
|
|
379
|
+
type: classifyRuntimeError(
|
|
380
|
+
response.status,
|
|
381
|
+
getRecordValue(payload, "code")
|
|
382
|
+
),
|
|
383
|
+
status: response.status,
|
|
384
|
+
code: getRecordValue(payload, "code"),
|
|
385
|
+
message: getRecordValue(payload, "message") || fallbackMessage,
|
|
386
|
+
payload
|
|
387
|
+
});
|
|
388
|
+
var createRuntimeError = (snapshot) => new RuntimeHttpError({
|
|
389
|
+
...snapshot,
|
|
390
|
+
type: snapshot.type || "unknown",
|
|
391
|
+
message: snapshot.message || "Runtime request failed"
|
|
392
|
+
});
|
|
393
|
+
var normalizeRuntimeError = (error) => {
|
|
394
|
+
if (error instanceof RuntimeHttpError) return error;
|
|
395
|
+
if (error instanceof Error) {
|
|
396
|
+
const runtimeError = error;
|
|
397
|
+
runtimeError.type = runtimeError.type || classifyRuntimeError(runtimeError.status, runtimeError.code);
|
|
398
|
+
return runtimeError;
|
|
399
|
+
}
|
|
400
|
+
return createRuntimeError({
|
|
401
|
+
type: "unknown",
|
|
402
|
+
message: String(error)
|
|
403
|
+
});
|
|
404
|
+
};
|
|
405
|
+
var toRuntimeErrorSnapshot = (error) => ({
|
|
406
|
+
type: error.type || classifyRuntimeError(error.status, error.code),
|
|
407
|
+
status: error.status,
|
|
408
|
+
code: error.code,
|
|
409
|
+
message: error.message || "Runtime request failed",
|
|
410
|
+
payload: error.payload
|
|
411
|
+
});
|
|
412
|
+
var classifyRuntimeError = (status, code) => {
|
|
413
|
+
const normalizedCode = typeof code === "string" ? Number(code) : code;
|
|
414
|
+
if (status === 401 || normalizedCode === 401) return "unauthenticated";
|
|
415
|
+
if (status === 403 || normalizedCode === 403) return "forbidden";
|
|
416
|
+
if (!status && !normalizedCode) return "network";
|
|
417
|
+
return "unknown";
|
|
418
|
+
};
|
|
419
|
+
var createPermissionFallbackState = (access, runtime) => {
|
|
420
|
+
const error = access.error || runtime.error;
|
|
421
|
+
const accessData = access.data;
|
|
422
|
+
const errorType = accessData?.errorType || error?.type || (!access.canAccess ? "forbidden" : "unknown");
|
|
423
|
+
return {
|
|
424
|
+
access,
|
|
425
|
+
runtime,
|
|
426
|
+
error,
|
|
427
|
+
errorType,
|
|
428
|
+
status: accessData?.status || error?.status,
|
|
429
|
+
code: accessData?.code || error?.code,
|
|
430
|
+
message: accessData?.message || error?.message || (errorType === "unauthenticated" ? "\u5F53\u524D\u8D26\u53F7\u5C1A\u672A\u767B\u5F55" : "\u5F53\u524D\u8D26\u53F7\u6CA1\u6709\u8BBF\u95EE\u6743\u9650")
|
|
431
|
+
};
|
|
432
|
+
};
|
|
433
|
+
var renderBoundaryFallback = (fallback, state) => typeof fallback === "function" ? fallback(state) : fallback;
|
|
434
|
+
var withQuery = (url, params) => {
|
|
435
|
+
const query = new URLSearchParams();
|
|
436
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
437
|
+
if (value === void 0 || value === "") return;
|
|
438
|
+
query.set(key, String(value));
|
|
439
|
+
});
|
|
440
|
+
const serialized = query.toString();
|
|
441
|
+
if (!serialized) return url;
|
|
442
|
+
return `${url}${url.includes("?") ? "&" : "?"}${serialized}`;
|
|
443
|
+
};
|
|
444
|
+
var attachCallback = (loginUrl, callback) => {
|
|
445
|
+
if (!callback) return loginUrl;
|
|
446
|
+
try {
|
|
447
|
+
const base = typeof window !== "undefined" ? window.location.origin : "http://localhost";
|
|
448
|
+
const parsed = new URL(loginUrl, base);
|
|
449
|
+
if (!parsed.searchParams.has("callback") && !parsed.searchParams.has("redirectUri")) {
|
|
450
|
+
parsed.searchParams.set("callback", callback);
|
|
451
|
+
}
|
|
452
|
+
if (loginUrl.startsWith("http://") || loginUrl.startsWith("https://")) {
|
|
453
|
+
return parsed.toString();
|
|
454
|
+
}
|
|
455
|
+
return `${parsed.pathname}${parsed.search}${parsed.hash}`;
|
|
456
|
+
} catch {
|
|
457
|
+
const separator = loginUrl.includes("?") ? "&" : "?";
|
|
458
|
+
return `${loginUrl}${separator}callback=${encodeURIComponent(callback)}`;
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
var getCurrentHref = () => typeof window === "undefined" ? "" : window.location.href;
|
|
462
|
+
var getCurrentHostname = () => typeof window === "undefined" ? "" : window.location.hostname;
|
|
463
|
+
var getRuntimeEnv = (key) => {
|
|
464
|
+
const env = typeof process !== "undefined" ? process.env : void 0;
|
|
465
|
+
return env?.[key];
|
|
466
|
+
};
|
|
467
|
+
var getRecordValue = (value, key) => {
|
|
468
|
+
if (!value || typeof value !== "object") return void 0;
|
|
469
|
+
return value[key];
|
|
470
|
+
};
|
|
471
|
+
var getRecordString = (value, key) => {
|
|
472
|
+
const result = getRecordValue(value, key);
|
|
473
|
+
return typeof result === "string" ? result : void 0;
|
|
474
|
+
};
|
|
213
475
|
var resolveAppTypeFromLocation = () => {
|
|
214
476
|
if (typeof window === "undefined") return "";
|
|
215
477
|
const segments = window.location.pathname.split("/").filter(Boolean);
|
|
@@ -221,10 +483,12 @@ var resolveAppTypeFromLocation = () => {
|
|
|
221
483
|
export {
|
|
222
484
|
OpenXiangdaProvider,
|
|
223
485
|
PermissionBoundary,
|
|
486
|
+
RuntimeHttpError,
|
|
224
487
|
useAppMenus,
|
|
225
488
|
useCanAccessRoute,
|
|
226
489
|
useOpenXiangda,
|
|
227
490
|
usePermission,
|
|
491
|
+
useRuntimeAuth,
|
|
228
492
|
useRuntimeBootstrap
|
|
229
493
|
};
|
|
230
494
|
//# sourceMappingURL=react.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/runtime/react/openxiangdaProvider.tsx","../../src/runtime/core/fetch.ts"],"sourcesContent":["import React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\"\nimport { createBoundFetch } from \"../core/fetch\"\n\nexport interface RuntimeMenuItem {\n id: string\n name: string\n resourceCode?: string | null\n routeCode?: string | null\n path?: string | null\n type?: string\n formUuid?: string | null\n pageId?: string | null\n parentId?: string | null\n sortOrder?: number\n isHidden?: boolean\n icon?: string | null\n children?: RuntimeMenuItem[]\n [key: string]: unknown\n}\n\nexport interface RuntimePagePermissions {\n appType: string\n hasFullAccess: boolean\n roleCodes: string[]\n roleSource?: string\n menuFormUuids: string[]\n menuCodes: string[]\n routeCodes: string[]\n pathPatterns: string[]\n}\n\nexport interface RuntimeBootstrap {\n appType: string\n app?: Record<string, unknown> | null\n user?: Record<string, unknown> | null\n runtime?: {\n mode?: \"legacy\" | \"react-spa\" | string\n settings?: Record<string, unknown>\n activeReleaseId?: string | null\n activeBuildId?: string | null\n indexUrl?: string | null\n assetBaseUrl?: string | null\n }\n permissions?: RuntimePagePermissions\n menus?: RuntimeMenuItem[]\n servicePrefix?: string\n}\n\nexport interface RouteAccessResult {\n appType: string\n canAccess: boolean\n routeCode?: string\n menuCode?: string\n path?: string\n permissions?: RuntimePagePermissions\n}\n\nexport interface RuntimeRequestState<T> {\n data: T | null\n loading: boolean\n error: Error | null\n}\n\nexport interface OpenXiangdaProviderProps {\n appType?: string\n servicePrefix?: string\n fetchImpl?: typeof fetch\n children: React.ReactNode\n}\n\ninterface OpenXiangdaRuntimeStore extends RuntimeRequestState<RuntimeBootstrap> {\n appType: string\n servicePrefix: string\n fetchImpl: typeof fetch\n reload: () => Promise<void>\n}\n\nconst OpenXiangdaRuntimeContext =\n createContext<OpenXiangdaRuntimeStore | null>(null)\n\nexport const OpenXiangdaProvider: React.FC<OpenXiangdaProviderProps> = ({\n appType,\n servicePrefix = \"/service\",\n fetchImpl,\n children,\n}) => {\n const resolvedFetch = useMemo(() => createBoundFetch(fetchImpl), [fetchImpl])\n const resolvedAppType = useMemo(\n () => appType || resolveAppTypeFromLocation(),\n [appType],\n )\n const [state, setState] = useState<RuntimeRequestState<RuntimeBootstrap>>({\n data: null,\n loading: true,\n error: null,\n })\n\n const reload = useCallback(async () => {\n if (!resolvedAppType) {\n setState({\n data: null,\n loading: false,\n error: new Error(\"appType 不能为空\"),\n })\n return\n }\n setState(prev => ({ ...prev, loading: true, error: null }))\n try {\n const response = await resolvedFetch(\n buildServiceUrl(\n servicePrefix,\n `/openxiangda-api/v1/apps/${encodeURIComponent(\n resolvedAppType,\n )}/runtime/bootstrap`,\n ),\n {\n credentials: \"include\",\n headers: { accept: \"application/json\" },\n },\n )\n const payload = await response.json()\n if (!response.ok || payload?.code >= 400) {\n throw new Error(payload?.message || `Runtime bootstrap failed: ${response.status}`)\n }\n setState({\n data: payload?.data || null,\n loading: false,\n error: null,\n })\n } catch (error) {\n setState({\n data: null,\n loading: false,\n error: error instanceof Error ? error : new Error(String(error)),\n })\n }\n }, [resolvedAppType, resolvedFetch, servicePrefix])\n\n useEffect(() => {\n void reload()\n }, [reload])\n\n const value = useMemo<OpenXiangdaRuntimeStore>(\n () => ({\n ...state,\n appType: resolvedAppType,\n servicePrefix,\n fetchImpl: resolvedFetch,\n reload,\n }),\n [reload, resolvedAppType, resolvedFetch, servicePrefix, state],\n )\n\n return (\n <OpenXiangdaRuntimeContext.Provider value={value}>\n {children}\n </OpenXiangdaRuntimeContext.Provider>\n )\n}\n\nexport const useOpenXiangda = () => {\n const context = useContext(OpenXiangdaRuntimeContext)\n if (!context) {\n throw new Error(\"useOpenXiangda must be used inside OpenXiangdaProvider\")\n }\n return context\n}\n\nexport const useRuntimeBootstrap = () => useOpenXiangda()\n\nexport const useAppMenus = () => {\n const runtime = useOpenXiangda()\n return {\n ...runtime,\n data: runtime.data?.menus || [],\n }\n}\n\nexport const usePermission = () => {\n const runtime = useOpenXiangda()\n return {\n ...runtime,\n data: runtime.data?.permissions || null,\n }\n}\n\nexport interface UseCanAccessRouteInput {\n routeCode?: string\n menuCode?: string\n path?: string\n}\n\nexport const useCanAccessRoute = (input: UseCanAccessRouteInput) => {\n const runtime = useOpenXiangda()\n const [state, setState] = useState<RuntimeRequestState<RouteAccessResult>>({\n data: null,\n loading: true,\n error: null,\n })\n\n useEffect(() => {\n let disposed = false\n const check = async () => {\n const permissions = runtime.data?.permissions\n if (!runtime.appType || runtime.loading) {\n setState(prev => ({ ...prev, loading: runtime.loading }))\n return\n }\n if (permissions?.hasFullAccess) {\n setState({\n data: { appType: runtime.appType, canAccess: true, permissions },\n loading: false,\n error: null,\n })\n return\n }\n setState(prev => ({ ...prev, loading: true, error: null }))\n try {\n const response = await runtime.fetchImpl(\n buildServiceUrl(\n runtime.servicePrefix,\n `/openxiangda-api/v1/apps/${encodeURIComponent(\n runtime.appType,\n )}/runtime/routes/check`,\n ),\n {\n method: \"POST\",\n credentials: \"include\",\n headers: {\n accept: \"application/json\",\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(input),\n },\n )\n const payload = await response.json()\n if (!disposed) {\n setState({\n data: payload?.data || {\n appType: runtime.appType,\n canAccess: false,\n },\n loading: false,\n error:\n response.ok && payload?.code < 500\n ? null\n : new Error(payload?.message || `Route check failed: ${response.status}`),\n })\n }\n } catch (error) {\n if (!disposed) {\n setState({\n data: null,\n loading: false,\n error: error instanceof Error ? error : new Error(String(error)),\n })\n }\n }\n }\n void check()\n return () => {\n disposed = true\n }\n }, [\n input.menuCode,\n input.path,\n input.routeCode,\n runtime.appType,\n runtime.data?.permissions,\n runtime.fetchImpl,\n runtime.loading,\n runtime.servicePrefix,\n ])\n\n return {\n ...state,\n canAccess: Boolean(state.data?.canAccess),\n }\n}\n\nexport interface PermissionBoundaryProps extends UseCanAccessRouteInput {\n children: React.ReactNode\n fallback?: React.ReactNode\n loadingFallback?: React.ReactNode\n}\n\nexport const PermissionBoundary: React.FC<PermissionBoundaryProps> = ({\n children,\n fallback = null,\n loadingFallback = null,\n routeCode,\n menuCode,\n path,\n}) => {\n const access = useCanAccessRoute({ routeCode, menuCode, path })\n if (access.loading) return <>{loadingFallback}</>\n if (!access.canAccess) return <>{fallback}</>\n return <>{children}</>\n}\n\nconst buildServiceUrl = (servicePrefix: string, path: string) => {\n const prefix = servicePrefix.endsWith(\"/\")\n ? servicePrefix.slice(0, -1)\n : servicePrefix\n const suffix = path.startsWith(\"/\") ? path : `/${path}`\n return `${prefix}${suffix}`\n}\n\nconst resolveAppTypeFromLocation = () => {\n if (typeof window === \"undefined\") return \"\"\n const segments = window.location.pathname.split(\"/\").filter(Boolean)\n const viewIndex = segments[0] === \"view\" ? 1 : 0\n if (segments[viewIndex] === \"submit\") return segments[viewIndex + 1] || \"\"\n if (segments[viewIndex] === \"preview\") return segments[viewIndex + 1] || \"\"\n return segments[viewIndex] || \"\"\n}\n","export const createBoundFetch = (fetchImpl?: typeof fetch): typeof fetch => {\n const baseFetch = fetchImpl || globalThis.fetch;\n return ((input, init) => baseFetch.call(globalThis, input, init)) as typeof fetch;\n};\n"],"mappings":";AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACPA,IAAM,mBAAmB,CAAC,cAA2C;AAC1E,QAAM,YAAY,aAAa,WAAW;AAC1C,UAAQ,CAAC,OAAO,SAAS,UAAU,KAAK,YAAY,OAAO,IAAI;AACjE;;;AD8JI,SA6IyB,UA7IzB;AA7EJ,IAAM,4BACJ,cAA8C,IAAI;AAE7C,IAAM,sBAA0D,CAAC;AAAA,EACtE;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA;AACF,MAAM;AACJ,QAAM,gBAAgB,QAAQ,MAAM,iBAAiB,SAAS,GAAG,CAAC,SAAS,CAAC;AAC5E,QAAM,kBAAkB;AAAA,IACtB,MAAM,WAAW,2BAA2B;AAAA,IAC5C,CAAC,OAAO;AAAA,EACV;AACA,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAgD;AAAA,IACxE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO;AAAA,EACT,CAAC;AAED,QAAM,SAAS,YAAY,YAAY;AACrC,QAAI,CAAC,iBAAiB;AACpB,eAAS;AAAA,QACP,MAAM;AAAA,QACN,SAAS;AAAA,QACT,OAAO,IAAI,MAAM,kCAAc;AAAA,MACjC,CAAC;AACD;AAAA,IACF;AACA,aAAS,WAAS,EAAE,GAAG,MAAM,SAAS,MAAM,OAAO,KAAK,EAAE;AAC1D,QAAI;AACF,YAAM,WAAW,MAAM;AAAA,QACrB;AAAA,UACE;AAAA,UACA,4BAA4B;AAAA,YAC1B;AAAA,UACF,CAAC;AAAA,QACH;AAAA,QACA;AAAA,UACE,aAAa;AAAA,UACb,SAAS,EAAE,QAAQ,mBAAmB;AAAA,QACxC;AAAA,MACF;AACA,YAAM,UAAU,MAAM,SAAS,KAAK;AACpC,UAAI,CAAC,SAAS,MAAM,SAAS,QAAQ,KAAK;AACxC,cAAM,IAAI,MAAM,SAAS,WAAW,6BAA6B,SAAS,MAAM,EAAE;AAAA,MACpF;AACA,eAAS;AAAA,QACP,MAAM,SAAS,QAAQ;AAAA,QACvB,SAAS;AAAA,QACT,OAAO;AAAA,MACT,CAAC;AAAA,IACH,SAAS,OAAO;AACd,eAAS;AAAA,QACP,MAAM;AAAA,QACN,SAAS;AAAA,QACT,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,MACjE,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,iBAAiB,eAAe,aAAa,CAAC;AAElD,YAAU,MAAM;AACd,SAAK,OAAO;AAAA,EACd,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,QAAQ;AAAA,IACZ,OAAO;AAAA,MACL,GAAG;AAAA,MACH,SAAS;AAAA,MACT;AAAA,MACA,WAAW;AAAA,MACX;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,iBAAiB,eAAe,eAAe,KAAK;AAAA,EAC/D;AAEA,SACE,oBAAC,0BAA0B,UAA1B,EAAmC,OACjC,UACH;AAEJ;AAEO,IAAM,iBAAiB,MAAM;AAClC,QAAM,UAAU,WAAW,yBAAyB;AACpD,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,SAAO;AACT;AAEO,IAAM,sBAAsB,MAAM,eAAe;AAEjD,IAAM,cAAc,MAAM;AAC/B,QAAM,UAAU,eAAe;AAC/B,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM,QAAQ,MAAM,SAAS,CAAC;AAAA,EAChC;AACF;AAEO,IAAM,gBAAgB,MAAM;AACjC,QAAM,UAAU,eAAe;AAC/B,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM,QAAQ,MAAM,eAAe;AAAA,EACrC;AACF;AAQO,IAAM,oBAAoB,CAAC,UAAkC;AAClE,QAAM,UAAU,eAAe;AAC/B,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAiD;AAAA,IACzE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO;AAAA,EACT,CAAC;AAED,YAAU,MAAM;AACd,QAAI,WAAW;AACf,UAAM,QAAQ,YAAY;AACxB,YAAM,cAAc,QAAQ,MAAM;AAClC,UAAI,CAAC,QAAQ,WAAW,QAAQ,SAAS;AACvC,iBAAS,WAAS,EAAE,GAAG,MAAM,SAAS,QAAQ,QAAQ,EAAE;AACxD;AAAA,MACF;AACA,UAAI,aAAa,eAAe;AAC9B,iBAAS;AAAA,UACP,MAAM,EAAE,SAAS,QAAQ,SAAS,WAAW,MAAM,YAAY;AAAA,UAC/D,SAAS;AAAA,UACT,OAAO;AAAA,QACT,CAAC;AACD;AAAA,MACF;AACA,eAAS,WAAS,EAAE,GAAG,MAAM,SAAS,MAAM,OAAO,KAAK,EAAE;AAC1D,UAAI;AACF,cAAM,WAAW,MAAM,QAAQ;AAAA,UAC7B;AAAA,YACE,QAAQ;AAAA,YACR,4BAA4B;AAAA,cAC1B,QAAQ;AAAA,YACV,CAAC;AAAA,UACH;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,aAAa;AAAA,YACb,SAAS;AAAA,cACP,QAAQ;AAAA,cACR,gBAAgB;AAAA,YAClB;AAAA,YACA,MAAM,KAAK,UAAU,KAAK;AAAA,UAC5B;AAAA,QACF;AACA,cAAM,UAAU,MAAM,SAAS,KAAK;AACpC,YAAI,CAAC,UAAU;AACb,mBAAS;AAAA,YACP,MAAM,SAAS,QAAQ;AAAA,cACrB,SAAS,QAAQ;AAAA,cACjB,WAAW;AAAA,YACb;AAAA,YACA,SAAS;AAAA,YACT,OACE,SAAS,MAAM,SAAS,OAAO,MAC3B,OACA,IAAI,MAAM,SAAS,WAAW,uBAAuB,SAAS,MAAM,EAAE;AAAA,UAC9E,CAAC;AAAA,QACH;AAAA,MACF,SAAS,OAAO;AACd,YAAI,CAAC,UAAU;AACb,mBAAS;AAAA,YACP,MAAM;AAAA,YACN,SAAS;AAAA,YACT,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,UACjE,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AACA,SAAK,MAAM;AACX,WAAO,MAAM;AACX,iBAAW;AAAA,IACb;AAAA,EACF,GAAG;AAAA,IACD,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ,MAAM;AAAA,IACd,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV,CAAC;AAED,SAAO;AAAA,IACL,GAAG;AAAA,IACH,WAAW,QAAQ,MAAM,MAAM,SAAS;AAAA,EAC1C;AACF;AAQO,IAAM,qBAAwD,CAAC;AAAA,EACpE;AAAA,EACA,WAAW;AAAA,EACX,kBAAkB;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,SAAS,kBAAkB,EAAE,WAAW,UAAU,KAAK,CAAC;AAC9D,MAAI,OAAO,QAAS,QAAO,gCAAG,2BAAgB;AAC9C,MAAI,CAAC,OAAO,UAAW,QAAO,gCAAG,oBAAS;AAC1C,SAAO,gCAAG,UAAS;AACrB;AAEA,IAAM,kBAAkB,CAAC,eAAuB,SAAiB;AAC/D,QAAM,SAAS,cAAc,SAAS,GAAG,IACrC,cAAc,MAAM,GAAG,EAAE,IACzB;AACJ,QAAM,SAAS,KAAK,WAAW,GAAG,IAAI,OAAO,IAAI,IAAI;AACrD,SAAO,GAAG,MAAM,GAAG,MAAM;AAC3B;AAEA,IAAM,6BAA6B,MAAM;AACvC,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,QAAM,WAAW,OAAO,SAAS,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AACnE,QAAM,YAAY,SAAS,CAAC,MAAM,SAAS,IAAI;AAC/C,MAAI,SAAS,SAAS,MAAM,SAAU,QAAO,SAAS,YAAY,CAAC,KAAK;AACxE,MAAI,SAAS,SAAS,MAAM,UAAW,QAAO,SAAS,YAAY,CAAC,KAAK;AACzE,SAAO,SAAS,SAAS,KAAK;AAChC;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/react/openxiangdaProvider.tsx","../../src/runtime/core/fetch.ts"],"sourcesContent":["import React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\"\nimport { createBoundFetch } from \"../core/fetch\"\n\nexport type RuntimeErrorType =\n | \"unauthenticated\"\n | \"forbidden\"\n | \"network\"\n | \"unknown\"\n\nexport type RuntimeRequestError = Error & {\n type?: RuntimeErrorType\n status?: number\n code?: number | string\n payload?: unknown\n}\n\nexport interface RuntimeErrorSnapshot {\n type: RuntimeErrorType\n status?: number\n code?: number | string\n message: string\n payload?: unknown\n}\n\nexport class RuntimeHttpError extends Error {\n type: RuntimeErrorType\n status?: number\n code?: number | string\n payload?: unknown\n\n constructor(snapshot: RuntimeErrorSnapshot) {\n super(snapshot.message)\n this.name = \"RuntimeHttpError\"\n this.type = snapshot.type\n this.status = snapshot.status\n this.code = snapshot.code\n this.payload = snapshot.payload\n }\n}\n\nexport interface RuntimeMenuItem {\n id: string\n name: string\n resourceCode?: string | null\n routeCode?: string | null\n path?: string | null\n type?: string\n formUuid?: string | null\n pageId?: string | null\n parentId?: string | null\n sortOrder?: number\n isHidden?: boolean\n icon?: string | null\n children?: RuntimeMenuItem[]\n [key: string]: unknown\n}\n\nexport interface RuntimePagePermissions {\n appType: string\n hasFullAccess: boolean\n roleCodes: string[]\n roleSource?: string\n menuFormUuids: string[]\n menuCodes: string[]\n routeCodes: string[]\n pathPatterns: string[]\n}\n\nexport interface RuntimeBootstrap {\n appType: string\n app?: Record<string, unknown> | null\n user?: Record<string, unknown> | null\n runtime?: {\n mode?: \"legacy\" | \"react-spa\" | string\n settings?: Record<string, unknown>\n activeReleaseId?: string | null\n activeBuildId?: string | null\n indexUrl?: string | null\n assetBaseUrl?: string | null\n }\n permissions?: RuntimePagePermissions\n menus?: RuntimeMenuItem[]\n servicePrefix?: string\n}\n\nexport interface RouteAccessResult {\n appType: string\n canAccess: boolean\n routeCode?: string\n menuCode?: string\n path?: string\n status?: number\n code?: number | string\n message?: string\n errorType?: RuntimeErrorType\n payload?: unknown\n permissions?: RuntimePagePermissions\n}\n\nexport interface RuntimeRequestState<T> {\n data: T | null\n loading: boolean\n error: RuntimeRequestError | null\n}\n\nexport interface OpenXiangdaProviderProps {\n appType?: string\n servicePrefix?: string\n fetchImpl?: typeof fetch\n children: React.ReactNode\n}\n\ninterface OpenXiangdaRuntimeStore extends RuntimeRequestState<RuntimeBootstrap> {\n appType: string\n servicePrefix: string\n fetchImpl: typeof fetch\n reload: () => Promise<void>\n}\n\nconst OpenXiangdaRuntimeContext =\n createContext<OpenXiangdaRuntimeStore | null>(null)\n\nexport const OpenXiangdaProvider: React.FC<OpenXiangdaProviderProps> = ({\n appType,\n servicePrefix = \"/service\",\n fetchImpl,\n children,\n}) => {\n const resolvedFetch = useMemo(() => createBoundFetch(fetchImpl), [fetchImpl])\n const resolvedAppType = useMemo(\n () => appType || resolveAppTypeFromLocation(),\n [appType],\n )\n const [state, setState] = useState<RuntimeRequestState<RuntimeBootstrap>>({\n data: null,\n loading: true,\n error: null,\n })\n\n const reload = useCallback(async () => {\n if (!resolvedAppType) {\n setState({\n data: null,\n loading: false,\n error: createRuntimeError({\n message: \"appType 不能为空\",\n type: \"unknown\",\n }),\n })\n return\n }\n setState(prev => ({ ...prev, loading: true, error: null }))\n try {\n const response = await resolvedFetch(\n buildServiceUrl(\n servicePrefix,\n `/openxiangda-api/v1/apps/${encodeURIComponent(\n resolvedAppType,\n )}/runtime/bootstrap`,\n ),\n {\n credentials: \"include\",\n headers: { accept: \"application/json\" },\n },\n )\n const payload = await readJsonPayload(response)\n if (!response.ok || payload?.code >= 400) {\n throw createRuntimeHttpError(\n response,\n payload,\n payload?.message || `Runtime bootstrap failed: ${response.status}`,\n )\n }\n setState({\n data: payload?.data || null,\n loading: false,\n error: null,\n })\n } catch (error) {\n setState({\n data: null,\n loading: false,\n error: normalizeRuntimeError(error),\n })\n }\n }, [resolvedAppType, resolvedFetch, servicePrefix])\n\n useEffect(() => {\n void reload()\n }, [reload])\n\n const value = useMemo<OpenXiangdaRuntimeStore>(\n () => ({\n ...state,\n appType: resolvedAppType,\n servicePrefix,\n fetchImpl: resolvedFetch,\n reload,\n }),\n [reload, resolvedAppType, resolvedFetch, servicePrefix, state],\n )\n\n return (\n <OpenXiangdaRuntimeContext.Provider value={value}>\n {children}\n </OpenXiangdaRuntimeContext.Provider>\n )\n}\n\nexport const useOpenXiangda = () => {\n const context = useContext(OpenXiangdaRuntimeContext)\n if (!context) {\n throw new Error(\"useOpenXiangda must be used inside OpenXiangdaProvider\")\n }\n return context\n}\n\nexport const useRuntimeBootstrap = () => useOpenXiangda()\n\nexport const useAppMenus = () => {\n const runtime = useOpenXiangda()\n return {\n ...runtime,\n data: runtime.data?.menus || [],\n }\n}\n\nexport const usePermission = () => {\n const runtime = useOpenXiangda()\n return {\n ...runtime,\n data: runtime.data?.permissions || null,\n }\n}\n\nexport interface UseCanAccessRouteInput {\n routeCode?: string\n menuCode?: string\n path?: string\n}\n\nexport const useCanAccessRoute = (input: UseCanAccessRouteInput) => {\n const runtime = useOpenXiangda()\n const [state, setState] = useState<RuntimeRequestState<RouteAccessResult>>({\n data: null,\n loading: true,\n error: null,\n })\n\n useEffect(() => {\n let disposed = false\n const check = async () => {\n const permissions = runtime.data?.permissions\n if (!runtime.appType || runtime.loading) {\n setState(prev => ({ ...prev, loading: runtime.loading }))\n return\n }\n if (runtime.error && !runtime.data) {\n const snapshot = toRuntimeErrorSnapshot(runtime.error)\n setState({\n data: {\n appType: runtime.appType,\n canAccess: false,\n status: snapshot.status,\n code: snapshot.code,\n message: snapshot.message,\n errorType: snapshot.type,\n payload: snapshot.payload,\n },\n loading: false,\n error: runtime.error,\n })\n return\n }\n if (permissions?.hasFullAccess) {\n setState({\n data: { appType: runtime.appType, canAccess: true, permissions },\n loading: false,\n error: null,\n })\n return\n }\n setState(prev => ({ ...prev, loading: true, error: null }))\n try {\n const response = await runtime.fetchImpl(\n buildServiceUrl(\n runtime.servicePrefix,\n `/openxiangda-api/v1/apps/${encodeURIComponent(\n runtime.appType,\n )}/runtime/routes/check`,\n ),\n {\n method: \"POST\",\n credentials: \"include\",\n headers: {\n accept: \"application/json\",\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(input),\n },\n )\n const payload = await readJsonPayload(response)\n const code = payload?.code ?? response.status\n const canAccess = Boolean(payload?.data?.canAccess)\n const errorType = canAccess\n ? undefined\n : classifyRuntimeError(response.status, code)\n const data: RouteAccessResult = {\n ...(payload?.data || {\n appType: runtime.appType,\n canAccess: false,\n }),\n appType: payload?.data?.appType || runtime.appType,\n canAccess,\n status: response.status,\n code,\n message: payload?.message,\n errorType,\n payload,\n }\n if (!disposed) {\n const shouldTreatAsError =\n !response.ok || (typeof code === \"number\" && code >= 500)\n setState({\n data,\n loading: false,\n error: shouldTreatAsError\n ? createRuntimeHttpError(\n response,\n payload,\n payload?.message || `Route check failed: ${response.status}`,\n )\n : null,\n })\n }\n } catch (error) {\n if (!disposed) {\n setState({\n data: null,\n loading: false,\n error: normalizeRuntimeError(error),\n })\n }\n }\n }\n void check()\n return () => {\n disposed = true\n }\n }, [\n input.menuCode,\n input.path,\n input.routeCode,\n runtime.appType,\n runtime.data?.permissions,\n runtime.fetchImpl,\n runtime.loading,\n runtime.servicePrefix,\n ])\n\n return {\n ...state,\n canAccess: Boolean(state.data?.canAccess),\n }\n}\n\nexport interface PermissionBoundaryProps extends UseCanAccessRouteInput {\n children: React.ReactNode\n fallback?: React.ReactNode | PermissionBoundaryFallback\n loadingFallback?: React.ReactNode | PermissionBoundaryFallback\n}\n\nexport interface PermissionBoundaryFallbackState {\n access: ReturnType<typeof useCanAccessRoute>\n runtime: ReturnType<typeof useOpenXiangda>\n error: RuntimeRequestError | null\n errorType: RuntimeErrorType\n status?: number\n code?: number | string\n message: string\n}\n\nexport type PermissionBoundaryFallback = (\n state: PermissionBoundaryFallbackState,\n) => React.ReactNode\n\nexport const PermissionBoundary: React.FC<PermissionBoundaryProps> = ({\n children,\n fallback = null,\n loadingFallback = null,\n routeCode,\n menuCode,\n path,\n}) => {\n const runtime = useOpenXiangda()\n const access = useCanAccessRoute({ routeCode, menuCode, path })\n const fallbackState = createPermissionFallbackState(access, runtime)\n if (access.loading) {\n return <>{renderBoundaryFallback(loadingFallback, fallbackState)}</>\n }\n if (!access.canAccess) {\n return <>{renderBoundaryFallback(fallback, fallbackState)}</>\n }\n return <>{children}</>\n}\n\nexport interface RuntimeResolveLoginOptions {\n redirectUri?: string\n loginUrl?: string\n domain?: string\n}\n\nexport interface RuntimeRedirectLoginOptions extends RuntimeResolveLoginOptions {\n replace?: boolean\n}\n\nexport interface RuntimeLogoutOptions extends RuntimeRedirectLoginOptions {\n continueOnError?: boolean\n}\n\nexport const useRuntimeAuth = () => {\n const runtime = useOpenXiangda()\n\n const resolveLoginUrl = useCallback(\n async (options: RuntimeResolveLoginOptions = {}) => {\n const redirectUri = options.redirectUri || getCurrentHref()\n const domain = options.domain || getCurrentHostname()\n const appTenantId = getRecordString(runtime.data?.app, \"tenantId\")\n\n try {\n const statusUrl = withQuery(\n buildServiceUrl(runtime.servicePrefix, \"/api/sso/status\"),\n { domain },\n )\n const statusResponse = await runtime.fetchImpl(statusUrl, {\n credentials: \"include\",\n headers: { accept: \"application/json\" },\n })\n const statusPayload = await readJsonPayload(statusResponse)\n const sso = statusPayload?.data || {}\n const enabled = Boolean(sso.enabled)\n const shouldUseSso = Boolean(\n enabled && (sso.forceLogin ?? sso.autoRedirect ?? true),\n )\n if (shouldUseSso) {\n const loginUrlResponse = await runtime.fetchImpl(\n withQuery(buildServiceUrl(runtime.servicePrefix, \"/api/sso/login-url\"), {\n domain,\n redirectUri,\n ...(sso.tenantId || appTenantId\n ? { tenantId: String(sso.tenantId || appTenantId) }\n : {}),\n ...(sso.protocol ? { protocol: String(sso.protocol) } : {}),\n }),\n {\n credentials: \"include\",\n headers: { accept: \"application/json\" },\n },\n )\n const loginUrlPayload = await readJsonPayload(loginUrlResponse)\n const loginUrl =\n loginUrlPayload?.data?.loginUrl ||\n loginUrlPayload?.data?.url ||\n loginUrlPayload?.loginUrl ||\n loginUrlPayload?.url\n if (loginUrl) return String(loginUrl)\n }\n } catch {\n // Login resolution must always have a local fallback so logged-out\n // users are not stranded behind a permission state.\n }\n\n const configuredLoginUrl =\n options.loginUrl ||\n getRuntimeEnv(\"OPENXIANGDA_LOGIN_URL\") ||\n getRuntimeEnv(\"VITE_OPENXIANGDA_LOGIN_URL\") ||\n getRuntimeEnv(\"APP_LOGIN_URL\") ||\n getRuntimeEnv(\"VITE_APP_LOGIN_URL\") ||\n getRuntimeEnv(\"VITE_BATH_AUTH_URL\") ||\n getRuntimeEnv(\"BATH_AUTH_URL\")\n if (configuredLoginUrl) {\n return attachCallback(configuredLoginUrl, redirectUri)\n }\n return attachCallback(\"/login\", redirectUri)\n },\n [runtime.data?.app, runtime.fetchImpl, runtime.servicePrefix],\n )\n\n const redirectToLogin = useCallback(\n async (options: RuntimeRedirectLoginOptions = {}) => {\n const loginUrl = await resolveLoginUrl(options)\n if (typeof window !== \"undefined\") {\n if (options.replace === false) {\n window.location.assign(loginUrl)\n } else {\n window.location.replace(loginUrl)\n }\n }\n return loginUrl\n },\n [resolveLoginUrl],\n )\n\n const logout = useCallback(async () => {\n const response = await runtime.fetchImpl(\n buildServiceUrl(runtime.servicePrefix, \"/api/auth/logout\"),\n {\n method: \"POST\",\n credentials: \"include\",\n headers: { accept: \"application/json\" },\n },\n )\n const payload = await readJsonPayload(response)\n if (!response.ok || payload?.code >= 400) {\n throw createRuntimeHttpError(\n response,\n payload,\n payload?.message || `Logout failed: ${response.status}`,\n )\n }\n return payload\n }, [runtime.fetchImpl, runtime.servicePrefix])\n\n const logoutAndRedirect = useCallback(\n async (options: RuntimeLogoutOptions = {}) => {\n try {\n await logout()\n } catch (error) {\n if (options.continueOnError === false) throw error\n }\n return redirectToLogin(options)\n },\n [logout, redirectToLogin],\n )\n\n return {\n logout,\n logoutAndRedirect,\n redirectToLogin,\n resolveLoginUrl,\n }\n}\n\nconst buildServiceUrl = (servicePrefix: string, path: string) => {\n const prefix = servicePrefix.endsWith(\"/\")\n ? servicePrefix.slice(0, -1)\n : servicePrefix\n const suffix = path.startsWith(\"/\") ? path : `/${path}`\n return `${prefix}${suffix}`\n}\n\nconst readJsonPayload = async (response: Response) => {\n try {\n return await response.json()\n } catch {\n return null\n }\n}\n\nconst createRuntimeHttpError = (\n response: Response,\n payload: unknown,\n fallbackMessage: string,\n): RuntimeRequestError =>\n createRuntimeError({\n type: classifyRuntimeError(\n response.status,\n getRecordValue(payload, \"code\") as number | string | undefined,\n ),\n status: response.status,\n code: getRecordValue(payload, \"code\") as number | string | undefined,\n message:\n (getRecordValue(payload, \"message\") as string | undefined) ||\n fallbackMessage,\n payload,\n })\n\nconst createRuntimeError = (\n snapshot: RuntimeErrorSnapshot,\n): RuntimeRequestError =>\n new RuntimeHttpError({\n ...snapshot,\n type: snapshot.type || \"unknown\",\n message: snapshot.message || \"Runtime request failed\",\n })\n\nconst normalizeRuntimeError = (error: unknown): RuntimeRequestError => {\n if (error instanceof RuntimeHttpError) return error\n if (error instanceof Error) {\n const runtimeError = error as RuntimeRequestError\n runtimeError.type = runtimeError.type || classifyRuntimeError(runtimeError.status, runtimeError.code)\n return runtimeError\n }\n return createRuntimeError({\n type: \"unknown\",\n message: String(error),\n })\n}\n\nconst toRuntimeErrorSnapshot = (\n error: RuntimeRequestError,\n): RuntimeErrorSnapshot => ({\n type: error.type || classifyRuntimeError(error.status, error.code),\n status: error.status,\n code: error.code,\n message: error.message || \"Runtime request failed\",\n payload: error.payload,\n})\n\nconst classifyRuntimeError = (\n status?: number,\n code?: number | string,\n): RuntimeErrorType => {\n const normalizedCode = typeof code === \"string\" ? Number(code) : code\n if (status === 401 || normalizedCode === 401) return \"unauthenticated\"\n if (status === 403 || normalizedCode === 403) return \"forbidden\"\n if (!status && !normalizedCode) return \"network\"\n return \"unknown\"\n}\n\nconst createPermissionFallbackState = (\n access: ReturnType<typeof useCanAccessRoute>,\n runtime: ReturnType<typeof useOpenXiangda>,\n): PermissionBoundaryFallbackState => {\n const error = access.error || runtime.error\n const accessData = access.data\n const errorType =\n accessData?.errorType ||\n error?.type ||\n (!access.canAccess ? \"forbidden\" : \"unknown\")\n return {\n access,\n runtime,\n error,\n errorType,\n status: accessData?.status || error?.status,\n code: accessData?.code || error?.code,\n message:\n accessData?.message ||\n error?.message ||\n (errorType === \"unauthenticated\"\n ? \"当前账号尚未登录\"\n : \"当前账号没有访问权限\"),\n }\n}\n\nconst renderBoundaryFallback = (\n fallback: React.ReactNode | PermissionBoundaryFallback,\n state: PermissionBoundaryFallbackState,\n) => (typeof fallback === \"function\" ? fallback(state) : fallback)\n\nconst withQuery = (\n url: string,\n params: Record<string, string | number | boolean | undefined>,\n) => {\n const query = new URLSearchParams()\n Object.entries(params).forEach(([key, value]) => {\n if (value === undefined || value === \"\") return\n query.set(key, String(value))\n })\n const serialized = query.toString()\n if (!serialized) return url\n return `${url}${url.includes(\"?\") ? \"&\" : \"?\"}${serialized}`\n}\n\nconst attachCallback = (loginUrl: string, callback: string) => {\n if (!callback) return loginUrl\n try {\n const base =\n typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\"\n const parsed = new URL(loginUrl, base)\n if (!parsed.searchParams.has(\"callback\") && !parsed.searchParams.has(\"redirectUri\")) {\n parsed.searchParams.set(\"callback\", callback)\n }\n if (loginUrl.startsWith(\"http://\") || loginUrl.startsWith(\"https://\")) {\n return parsed.toString()\n }\n return `${parsed.pathname}${parsed.search}${parsed.hash}`\n } catch {\n const separator = loginUrl.includes(\"?\") ? \"&\" : \"?\"\n return `${loginUrl}${separator}callback=${encodeURIComponent(callback)}`\n }\n}\n\nconst getCurrentHref = () =>\n typeof window === \"undefined\" ? \"\" : window.location.href\n\nconst getCurrentHostname = () =>\n typeof window === \"undefined\" ? \"\" : window.location.hostname\n\nconst getRuntimeEnv = (key: string) => {\n const env =\n typeof process !== \"undefined\"\n ? (process as unknown as { env?: Record<string, string | undefined> }).env\n : undefined\n return env?.[key]\n}\n\nconst getRecordValue = (value: unknown, key: string) => {\n if (!value || typeof value !== \"object\") return undefined\n return (value as Record<string, unknown>)[key]\n}\n\nconst getRecordString = (value: unknown, key: string) => {\n const result = getRecordValue(value, key)\n return typeof result === \"string\" ? result : undefined\n}\n\nconst resolveAppTypeFromLocation = () => {\n if (typeof window === \"undefined\") return \"\"\n const segments = window.location.pathname.split(\"/\").filter(Boolean)\n const viewIndex = segments[0] === \"view\" ? 1 : 0\n if (segments[viewIndex] === \"submit\") return segments[viewIndex + 1] || \"\"\n if (segments[viewIndex] === \"preview\") return segments[viewIndex + 1] || \"\"\n return segments[viewIndex] || \"\"\n}\n","export const createBoundFetch = (fetchImpl?: typeof fetch): typeof fetch => {\n const baseFetch = fetchImpl || globalThis.fetch;\n return ((input, init) => baseFetch.call(globalThis, input, init)) as typeof fetch;\n};\n"],"mappings":"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","names":[]}
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
useParams,
|
|
6
6
|
} from "react-router-dom";
|
|
7
7
|
import { lazy, Suspense, type ReactNode } from "react";
|
|
8
|
+
import { Sparkles } from "lucide-react";
|
|
8
9
|
import { OpenXiangdaProvider } from "openxiangda/runtime/react";
|
|
9
10
|
|
|
10
11
|
import { AdminShell } from "@/layouts/AdminShell";
|
|
@@ -14,6 +15,7 @@ import { RuntimeWorkspacePage } from "@/pages/admin/RuntimeWorkspacePage";
|
|
|
14
15
|
import { UserPortalPage } from "@/pages/portal/UserPortalPage";
|
|
15
16
|
import { PublicHomePage } from "@/pages/public/PublicHomePage";
|
|
16
17
|
import { NotFoundPage } from "@/pages/states/NotFoundPage";
|
|
18
|
+
import { MacStatePage } from "@/shared/mac-admin";
|
|
17
19
|
|
|
18
20
|
const servicePrefix = process.env.APP_SERVICE_PREFIX || "/service";
|
|
19
21
|
const DataRoutePage = lazy(() =>
|
|
@@ -33,7 +35,16 @@ const FormRoutePage = lazy(() =>
|
|
|
33
35
|
);
|
|
34
36
|
|
|
35
37
|
const routeElement = (element: ReactNode) => (
|
|
36
|
-
<Suspense
|
|
38
|
+
<Suspense
|
|
39
|
+
fallback={
|
|
40
|
+
<MacStatePage
|
|
41
|
+
description="正在加载页面组件。"
|
|
42
|
+
icon={<Sparkles size={24} />}
|
|
43
|
+
status="LOADING"
|
|
44
|
+
title="加载中"
|
|
45
|
+
/>
|
|
46
|
+
}
|
|
47
|
+
>
|
|
37
48
|
{element}
|
|
38
49
|
</Suspense>
|
|
39
50
|
);
|