openxiangda 1.0.50 → 1.0.52

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.
Files changed (50) hide show
  1. package/lib/cli.js +339 -9
  2. package/lib/workspace-init.js +20 -8
  3. package/openxiangda-skills/SKILL.md +4 -3
  4. package/openxiangda-skills/skills/openxiangda-app/SKILL.md +28 -0
  5. package/openxiangda-skills/skills/openxiangda-core/SKILL.md +45 -1
  6. package/openxiangda-skills/skills/openxiangda-permission-settings/SKILL.md +31 -0
  7. package/package.json +7 -1
  8. package/packages/sdk/dist/runtime/index.cjs +3590 -3376
  9. package/packages/sdk/dist/runtime/index.cjs.map +1 -1
  10. package/packages/sdk/dist/runtime/index.d.mts +1 -0
  11. package/packages/sdk/dist/runtime/index.d.ts +1 -0
  12. package/packages/sdk/dist/runtime/index.mjs +3079 -2859
  13. package/packages/sdk/dist/runtime/index.mjs.map +1 -1
  14. package/packages/sdk/dist/runtime/react.cjs +236 -0
  15. package/packages/sdk/dist/runtime/react.cjs.map +1 -0
  16. package/packages/sdk/dist/runtime/react.d.mts +109 -0
  17. package/packages/sdk/dist/runtime/react.d.ts +109 -0
  18. package/packages/sdk/dist/runtime/react.mjs +222 -0
  19. package/packages/sdk/dist/runtime/react.mjs.map +1 -0
  20. package/packages/sdk/src/build-source/scripts/sync-schema.mjs +31 -0
  21. package/templates/openxiangda-react-spa/.env.example +4 -0
  22. package/templates/openxiangda-react-spa/AGENTS.md +69 -0
  23. package/templates/openxiangda-react-spa/app-workspace.config.ts +32 -0
  24. package/templates/openxiangda-react-spa/index.html +12 -0
  25. package/templates/openxiangda-react-spa/package.json +39 -0
  26. package/templates/openxiangda-react-spa/postcss.config.cjs +6 -0
  27. package/templates/openxiangda-react-spa/src/app/router.tsx +97 -0
  28. package/templates/openxiangda-react-spa/src/forms/.gitkeep +1 -0
  29. package/templates/openxiangda-react-spa/src/layouts/AdminShell.tsx +102 -0
  30. package/templates/openxiangda-react-spa/src/layouts/PublicShell.tsx +11 -0
  31. package/templates/openxiangda-react-spa/src/layouts/UserShell.tsx +22 -0
  32. package/templates/openxiangda-react-spa/src/main.tsx +12 -0
  33. package/templates/openxiangda-react-spa/src/pages/admin/RuntimeWorkspacePage.tsx +57 -0
  34. package/templates/openxiangda-react-spa/src/pages/defaults/DataRoutePage.tsx +17 -0
  35. package/templates/openxiangda-react-spa/src/pages/defaults/FilePreviewRoutePage.tsx +14 -0
  36. package/templates/openxiangda-react-spa/src/pages/defaults/FormRoutePage.tsx +62 -0
  37. package/templates/openxiangda-react-spa/src/pages/portal/UserPortalPage.tsx +27 -0
  38. package/templates/openxiangda-react-spa/src/pages/public/PublicHomePage.tsx +10 -0
  39. package/templates/openxiangda-react-spa/src/pages/states/NotFoundPage.tsx +16 -0
  40. package/templates/openxiangda-react-spa/src/resources/menus/menus.json +31 -0
  41. package/templates/openxiangda-react-spa/src/resources/permissions/page-groups/app-admin.json +8 -0
  42. package/templates/openxiangda-react-spa/src/resources/permissions/page-groups/app-user.json +8 -0
  43. package/templates/openxiangda-react-spa/src/resources/roles/roles.json +14 -0
  44. package/templates/openxiangda-react-spa/src/shared/form-schema.ts +135 -0
  45. package/templates/openxiangda-react-spa/src/styles/index.css +23 -0
  46. package/templates/openxiangda-react-spa/tailwind.config.cjs +29 -0
  47. package/templates/openxiangda-react-spa/tsconfig.app.json +36 -0
  48. package/templates/openxiangda-react-spa/tsconfig.json +7 -0
  49. package/templates/openxiangda-react-spa/tsconfig.node.json +10 -0
  50. package/templates/openxiangda-react-spa/vite.config.ts +73 -0
@@ -0,0 +1,236 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // packages/sdk/src/runtime/react/openxiangdaProvider.tsx
21
+ var openxiangdaProvider_exports = {};
22
+ __export(openxiangdaProvider_exports, {
23
+ OpenXiangdaProvider: () => OpenXiangdaProvider,
24
+ PermissionBoundary: () => PermissionBoundary,
25
+ useAppMenus: () => useAppMenus,
26
+ useCanAccessRoute: () => useCanAccessRoute,
27
+ useOpenXiangda: () => useOpenXiangda,
28
+ usePermission: () => usePermission,
29
+ useRuntimeBootstrap: () => useRuntimeBootstrap
30
+ });
31
+ module.exports = __toCommonJS(openxiangdaProvider_exports);
32
+ var import_react = require("react");
33
+ var import_jsx_runtime = require("react/jsx-runtime");
34
+ var OpenXiangdaRuntimeContext = (0, import_react.createContext)(null);
35
+ var OpenXiangdaProvider = ({
36
+ appType,
37
+ servicePrefix = "/service",
38
+ fetchImpl,
39
+ children
40
+ }) => {
41
+ const resolvedFetch = fetchImpl || fetch;
42
+ const resolvedAppType = (0, import_react.useMemo)(
43
+ () => appType || resolveAppTypeFromLocation(),
44
+ [appType]
45
+ );
46
+ const [state, setState] = (0, import_react.useState)({
47
+ data: null,
48
+ loading: true,
49
+ error: null
50
+ });
51
+ const reload = (0, import_react.useCallback)(async () => {
52
+ if (!resolvedAppType) {
53
+ setState({
54
+ data: null,
55
+ loading: false,
56
+ error: new Error("appType \u4E0D\u80FD\u4E3A\u7A7A")
57
+ });
58
+ return;
59
+ }
60
+ setState((prev) => ({ ...prev, loading: true, error: null }));
61
+ try {
62
+ const response = await resolvedFetch(
63
+ buildServiceUrl(
64
+ servicePrefix,
65
+ `/openxiangda-api/v1/apps/${encodeURIComponent(
66
+ resolvedAppType
67
+ )}/runtime/bootstrap`
68
+ ),
69
+ {
70
+ credentials: "include",
71
+ headers: { accept: "application/json" }
72
+ }
73
+ );
74
+ const payload = await response.json();
75
+ if (!response.ok || payload?.code >= 400) {
76
+ throw new Error(payload?.message || `Runtime bootstrap failed: ${response.status}`);
77
+ }
78
+ setState({
79
+ data: payload?.data || null,
80
+ loading: false,
81
+ error: null
82
+ });
83
+ } catch (error) {
84
+ setState({
85
+ data: null,
86
+ loading: false,
87
+ error: error instanceof Error ? error : new Error(String(error))
88
+ });
89
+ }
90
+ }, [resolvedAppType, resolvedFetch, servicePrefix]);
91
+ (0, import_react.useEffect)(() => {
92
+ void reload();
93
+ }, [reload]);
94
+ const value = (0, import_react.useMemo)(
95
+ () => ({
96
+ ...state,
97
+ appType: resolvedAppType,
98
+ servicePrefix,
99
+ fetchImpl: resolvedFetch,
100
+ reload
101
+ }),
102
+ [reload, resolvedAppType, resolvedFetch, servicePrefix, state]
103
+ );
104
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OpenXiangdaRuntimeContext.Provider, { value, children });
105
+ };
106
+ var useOpenXiangda = () => {
107
+ const context = (0, import_react.useContext)(OpenXiangdaRuntimeContext);
108
+ if (!context) {
109
+ throw new Error("useOpenXiangda must be used inside OpenXiangdaProvider");
110
+ }
111
+ return context;
112
+ };
113
+ var useRuntimeBootstrap = () => useOpenXiangda();
114
+ var useAppMenus = () => {
115
+ const runtime = useOpenXiangda();
116
+ return {
117
+ ...runtime,
118
+ data: runtime.data?.menus || []
119
+ };
120
+ };
121
+ var usePermission = () => {
122
+ const runtime = useOpenXiangda();
123
+ return {
124
+ ...runtime,
125
+ data: runtime.data?.permissions || null
126
+ };
127
+ };
128
+ var useCanAccessRoute = (input) => {
129
+ const runtime = useOpenXiangda();
130
+ const [state, setState] = (0, import_react.useState)({
131
+ data: null,
132
+ loading: true,
133
+ error: null
134
+ });
135
+ (0, import_react.useEffect)(() => {
136
+ let disposed = false;
137
+ const check = async () => {
138
+ const permissions = runtime.data?.permissions;
139
+ if (!runtime.appType || runtime.loading) {
140
+ setState((prev) => ({ ...prev, loading: runtime.loading }));
141
+ return;
142
+ }
143
+ if (permissions?.hasFullAccess) {
144
+ setState({
145
+ data: { appType: runtime.appType, canAccess: true, permissions },
146
+ loading: false,
147
+ error: null
148
+ });
149
+ return;
150
+ }
151
+ setState((prev) => ({ ...prev, loading: true, error: null }));
152
+ try {
153
+ const response = await runtime.fetchImpl(
154
+ buildServiceUrl(
155
+ runtime.servicePrefix,
156
+ `/openxiangda-api/v1/apps/${encodeURIComponent(
157
+ runtime.appType
158
+ )}/runtime/routes/check`
159
+ ),
160
+ {
161
+ method: "POST",
162
+ credentials: "include",
163
+ headers: {
164
+ accept: "application/json",
165
+ "content-type": "application/json"
166
+ },
167
+ body: JSON.stringify(input)
168
+ }
169
+ );
170
+ const payload = await response.json();
171
+ if (!disposed) {
172
+ setState({
173
+ data: payload?.data || {
174
+ appType: runtime.appType,
175
+ canAccess: false
176
+ },
177
+ loading: false,
178
+ error: response.ok && payload?.code < 500 ? null : new Error(payload?.message || `Route check failed: ${response.status}`)
179
+ });
180
+ }
181
+ } catch (error) {
182
+ if (!disposed) {
183
+ setState({
184
+ data: null,
185
+ loading: false,
186
+ error: error instanceof Error ? error : new Error(String(error))
187
+ });
188
+ }
189
+ }
190
+ };
191
+ void check();
192
+ return () => {
193
+ disposed = true;
194
+ };
195
+ }, [
196
+ input.menuCode,
197
+ input.path,
198
+ input.routeCode,
199
+ runtime.appType,
200
+ runtime.data?.permissions,
201
+ runtime.fetchImpl,
202
+ runtime.loading,
203
+ runtime.servicePrefix
204
+ ]);
205
+ return {
206
+ ...state,
207
+ canAccess: Boolean(state.data?.canAccess)
208
+ };
209
+ };
210
+ var PermissionBoundary = ({
211
+ children,
212
+ fallback = null,
213
+ loadingFallback = null,
214
+ routeCode,
215
+ menuCode,
216
+ path
217
+ }) => {
218
+ const access = useCanAccessRoute({ routeCode, menuCode, path });
219
+ if (access.loading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: loadingFallback });
220
+ if (!access.canAccess) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: fallback });
221
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
222
+ };
223
+ var buildServiceUrl = (servicePrefix, path) => {
224
+ const prefix = servicePrefix.endsWith("/") ? servicePrefix.slice(0, -1) : servicePrefix;
225
+ const suffix = path.startsWith("/") ? path : `/${path}`;
226
+ return `${prefix}${suffix}`;
227
+ };
228
+ var resolveAppTypeFromLocation = () => {
229
+ if (typeof window === "undefined") return "";
230
+ const segments = window.location.pathname.split("/").filter(Boolean);
231
+ const viewIndex = segments[0] === "view" ? 1 : 0;
232
+ if (segments[viewIndex] === "submit") return segments[viewIndex + 1] || "";
233
+ if (segments[viewIndex] === "preview") return segments[viewIndex + 1] || "";
234
+ return segments[viewIndex] || "";
235
+ };
236
+ //# sourceMappingURL=react.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/runtime/react/openxiangdaProvider.tsx"],"sourcesContent":["import React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\"\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 = fetchImpl || fetch\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"],"mappings":"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","names":[]}
@@ -0,0 +1,109 @@
1
+ import React__default from 'react';
2
+
3
+ interface RuntimeMenuItem {
4
+ id: string;
5
+ name: string;
6
+ resourceCode?: string | null;
7
+ routeCode?: string | null;
8
+ path?: string | null;
9
+ type?: string;
10
+ formUuid?: string | null;
11
+ pageId?: string | null;
12
+ parentId?: string | null;
13
+ sortOrder?: number;
14
+ isHidden?: boolean;
15
+ icon?: string | null;
16
+ children?: RuntimeMenuItem[];
17
+ [key: string]: unknown;
18
+ }
19
+ interface RuntimePagePermissions {
20
+ appType: string;
21
+ hasFullAccess: boolean;
22
+ roleCodes: string[];
23
+ roleSource?: string;
24
+ menuFormUuids: string[];
25
+ menuCodes: string[];
26
+ routeCodes: string[];
27
+ pathPatterns: string[];
28
+ }
29
+ interface RuntimeBootstrap {
30
+ appType: string;
31
+ app?: Record<string, unknown> | null;
32
+ user?: Record<string, unknown> | null;
33
+ runtime?: {
34
+ mode?: "legacy" | "react-spa" | string;
35
+ settings?: Record<string, unknown>;
36
+ activeReleaseId?: string | null;
37
+ activeBuildId?: string | null;
38
+ indexUrl?: string | null;
39
+ assetBaseUrl?: string | null;
40
+ };
41
+ permissions?: RuntimePagePermissions;
42
+ menus?: RuntimeMenuItem[];
43
+ servicePrefix?: string;
44
+ }
45
+ interface RouteAccessResult {
46
+ appType: string;
47
+ canAccess: boolean;
48
+ routeCode?: string;
49
+ menuCode?: string;
50
+ path?: string;
51
+ permissions?: RuntimePagePermissions;
52
+ }
53
+ interface RuntimeRequestState<T> {
54
+ data: T | null;
55
+ loading: boolean;
56
+ error: Error | null;
57
+ }
58
+ interface OpenXiangdaProviderProps {
59
+ appType?: string;
60
+ servicePrefix?: string;
61
+ fetchImpl?: typeof fetch;
62
+ children: React__default.ReactNode;
63
+ }
64
+ interface OpenXiangdaRuntimeStore extends RuntimeRequestState<RuntimeBootstrap> {
65
+ appType: string;
66
+ servicePrefix: string;
67
+ fetchImpl: typeof fetch;
68
+ reload: () => Promise<void>;
69
+ }
70
+ declare const OpenXiangdaProvider: React__default.FC<OpenXiangdaProviderProps>;
71
+ declare const useOpenXiangda: () => OpenXiangdaRuntimeStore;
72
+ declare const useRuntimeBootstrap: () => OpenXiangdaRuntimeStore;
73
+ declare const useAppMenus: () => {
74
+ data: RuntimeMenuItem[];
75
+ appType: string;
76
+ servicePrefix: string;
77
+ fetchImpl: typeof fetch;
78
+ reload: () => Promise<void>;
79
+ loading: boolean;
80
+ error: Error | null;
81
+ };
82
+ declare const usePermission: () => {
83
+ data: RuntimePagePermissions | null;
84
+ appType: string;
85
+ servicePrefix: string;
86
+ fetchImpl: typeof fetch;
87
+ reload: () => Promise<void>;
88
+ loading: boolean;
89
+ error: Error | null;
90
+ };
91
+ interface UseCanAccessRouteInput {
92
+ routeCode?: string;
93
+ menuCode?: string;
94
+ path?: string;
95
+ }
96
+ declare const useCanAccessRoute: (input: UseCanAccessRouteInput) => {
97
+ canAccess: boolean;
98
+ data: RouteAccessResult | null;
99
+ loading: boolean;
100
+ error: Error | null;
101
+ };
102
+ interface PermissionBoundaryProps extends UseCanAccessRouteInput {
103
+ children: React__default.ReactNode;
104
+ fallback?: React__default.ReactNode;
105
+ loadingFallback?: React__default.ReactNode;
106
+ }
107
+ declare const PermissionBoundary: React__default.FC<PermissionBoundaryProps>;
108
+
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 };
@@ -0,0 +1,109 @@
1
+ import React__default from 'react';
2
+
3
+ interface RuntimeMenuItem {
4
+ id: string;
5
+ name: string;
6
+ resourceCode?: string | null;
7
+ routeCode?: string | null;
8
+ path?: string | null;
9
+ type?: string;
10
+ formUuid?: string | null;
11
+ pageId?: string | null;
12
+ parentId?: string | null;
13
+ sortOrder?: number;
14
+ isHidden?: boolean;
15
+ icon?: string | null;
16
+ children?: RuntimeMenuItem[];
17
+ [key: string]: unknown;
18
+ }
19
+ interface RuntimePagePermissions {
20
+ appType: string;
21
+ hasFullAccess: boolean;
22
+ roleCodes: string[];
23
+ roleSource?: string;
24
+ menuFormUuids: string[];
25
+ menuCodes: string[];
26
+ routeCodes: string[];
27
+ pathPatterns: string[];
28
+ }
29
+ interface RuntimeBootstrap {
30
+ appType: string;
31
+ app?: Record<string, unknown> | null;
32
+ user?: Record<string, unknown> | null;
33
+ runtime?: {
34
+ mode?: "legacy" | "react-spa" | string;
35
+ settings?: Record<string, unknown>;
36
+ activeReleaseId?: string | null;
37
+ activeBuildId?: string | null;
38
+ indexUrl?: string | null;
39
+ assetBaseUrl?: string | null;
40
+ };
41
+ permissions?: RuntimePagePermissions;
42
+ menus?: RuntimeMenuItem[];
43
+ servicePrefix?: string;
44
+ }
45
+ interface RouteAccessResult {
46
+ appType: string;
47
+ canAccess: boolean;
48
+ routeCode?: string;
49
+ menuCode?: string;
50
+ path?: string;
51
+ permissions?: RuntimePagePermissions;
52
+ }
53
+ interface RuntimeRequestState<T> {
54
+ data: T | null;
55
+ loading: boolean;
56
+ error: Error | null;
57
+ }
58
+ interface OpenXiangdaProviderProps {
59
+ appType?: string;
60
+ servicePrefix?: string;
61
+ fetchImpl?: typeof fetch;
62
+ children: React__default.ReactNode;
63
+ }
64
+ interface OpenXiangdaRuntimeStore extends RuntimeRequestState<RuntimeBootstrap> {
65
+ appType: string;
66
+ servicePrefix: string;
67
+ fetchImpl: typeof fetch;
68
+ reload: () => Promise<void>;
69
+ }
70
+ declare const OpenXiangdaProvider: React__default.FC<OpenXiangdaProviderProps>;
71
+ declare const useOpenXiangda: () => OpenXiangdaRuntimeStore;
72
+ declare const useRuntimeBootstrap: () => OpenXiangdaRuntimeStore;
73
+ declare const useAppMenus: () => {
74
+ data: RuntimeMenuItem[];
75
+ appType: string;
76
+ servicePrefix: string;
77
+ fetchImpl: typeof fetch;
78
+ reload: () => Promise<void>;
79
+ loading: boolean;
80
+ error: Error | null;
81
+ };
82
+ declare const usePermission: () => {
83
+ data: RuntimePagePermissions | null;
84
+ appType: string;
85
+ servicePrefix: string;
86
+ fetchImpl: typeof fetch;
87
+ reload: () => Promise<void>;
88
+ loading: boolean;
89
+ error: Error | null;
90
+ };
91
+ interface UseCanAccessRouteInput {
92
+ routeCode?: string;
93
+ menuCode?: string;
94
+ path?: string;
95
+ }
96
+ declare const useCanAccessRoute: (input: UseCanAccessRouteInput) => {
97
+ canAccess: boolean;
98
+ data: RouteAccessResult | null;
99
+ loading: boolean;
100
+ error: Error | null;
101
+ };
102
+ interface PermissionBoundaryProps extends UseCanAccessRouteInput {
103
+ children: React__default.ReactNode;
104
+ fallback?: React__default.ReactNode;
105
+ loadingFallback?: React__default.ReactNode;
106
+ }
107
+ declare const PermissionBoundary: React__default.FC<PermissionBoundaryProps>;
108
+
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 };
@@ -0,0 +1,222 @@
1
+ // packages/sdk/src/runtime/react/openxiangdaProvider.tsx
2
+ import {
3
+ createContext,
4
+ useCallback,
5
+ useContext,
6
+ useEffect,
7
+ useMemo,
8
+ useState
9
+ } from "react";
10
+ import { Fragment, jsx } from "react/jsx-runtime";
11
+ var OpenXiangdaRuntimeContext = createContext(null);
12
+ var OpenXiangdaProvider = ({
13
+ appType,
14
+ servicePrefix = "/service",
15
+ fetchImpl,
16
+ children
17
+ }) => {
18
+ const resolvedFetch = fetchImpl || fetch;
19
+ const resolvedAppType = useMemo(
20
+ () => appType || resolveAppTypeFromLocation(),
21
+ [appType]
22
+ );
23
+ const [state, setState] = useState({
24
+ data: null,
25
+ loading: true,
26
+ error: null
27
+ });
28
+ const reload = useCallback(async () => {
29
+ if (!resolvedAppType) {
30
+ setState({
31
+ data: null,
32
+ loading: false,
33
+ error: new Error("appType \u4E0D\u80FD\u4E3A\u7A7A")
34
+ });
35
+ return;
36
+ }
37
+ setState((prev) => ({ ...prev, loading: true, error: null }));
38
+ try {
39
+ const response = await resolvedFetch(
40
+ buildServiceUrl(
41
+ servicePrefix,
42
+ `/openxiangda-api/v1/apps/${encodeURIComponent(
43
+ resolvedAppType
44
+ )}/runtime/bootstrap`
45
+ ),
46
+ {
47
+ credentials: "include",
48
+ headers: { accept: "application/json" }
49
+ }
50
+ );
51
+ const payload = await response.json();
52
+ if (!response.ok || payload?.code >= 400) {
53
+ throw new Error(payload?.message || `Runtime bootstrap failed: ${response.status}`);
54
+ }
55
+ setState({
56
+ data: payload?.data || null,
57
+ loading: false,
58
+ error: null
59
+ });
60
+ } catch (error) {
61
+ setState({
62
+ data: null,
63
+ loading: false,
64
+ error: error instanceof Error ? error : new Error(String(error))
65
+ });
66
+ }
67
+ }, [resolvedAppType, resolvedFetch, servicePrefix]);
68
+ useEffect(() => {
69
+ void reload();
70
+ }, [reload]);
71
+ const value = useMemo(
72
+ () => ({
73
+ ...state,
74
+ appType: resolvedAppType,
75
+ servicePrefix,
76
+ fetchImpl: resolvedFetch,
77
+ reload
78
+ }),
79
+ [reload, resolvedAppType, resolvedFetch, servicePrefix, state]
80
+ );
81
+ return /* @__PURE__ */ jsx(OpenXiangdaRuntimeContext.Provider, { value, children });
82
+ };
83
+ var useOpenXiangda = () => {
84
+ const context = useContext(OpenXiangdaRuntimeContext);
85
+ if (!context) {
86
+ throw new Error("useOpenXiangda must be used inside OpenXiangdaProvider");
87
+ }
88
+ return context;
89
+ };
90
+ var useRuntimeBootstrap = () => useOpenXiangda();
91
+ var useAppMenus = () => {
92
+ const runtime = useOpenXiangda();
93
+ return {
94
+ ...runtime,
95
+ data: runtime.data?.menus || []
96
+ };
97
+ };
98
+ var usePermission = () => {
99
+ const runtime = useOpenXiangda();
100
+ return {
101
+ ...runtime,
102
+ data: runtime.data?.permissions || null
103
+ };
104
+ };
105
+ var useCanAccessRoute = (input) => {
106
+ const runtime = useOpenXiangda();
107
+ const [state, setState] = useState({
108
+ data: null,
109
+ loading: true,
110
+ error: null
111
+ });
112
+ useEffect(() => {
113
+ let disposed = false;
114
+ const check = async () => {
115
+ const permissions = runtime.data?.permissions;
116
+ if (!runtime.appType || runtime.loading) {
117
+ setState((prev) => ({ ...prev, loading: runtime.loading }));
118
+ return;
119
+ }
120
+ if (permissions?.hasFullAccess) {
121
+ setState({
122
+ data: { appType: runtime.appType, canAccess: true, permissions },
123
+ loading: false,
124
+ error: null
125
+ });
126
+ return;
127
+ }
128
+ setState((prev) => ({ ...prev, loading: true, error: null }));
129
+ try {
130
+ const response = await runtime.fetchImpl(
131
+ buildServiceUrl(
132
+ runtime.servicePrefix,
133
+ `/openxiangda-api/v1/apps/${encodeURIComponent(
134
+ runtime.appType
135
+ )}/runtime/routes/check`
136
+ ),
137
+ {
138
+ method: "POST",
139
+ credentials: "include",
140
+ headers: {
141
+ accept: "application/json",
142
+ "content-type": "application/json"
143
+ },
144
+ body: JSON.stringify(input)
145
+ }
146
+ );
147
+ const payload = await response.json();
148
+ if (!disposed) {
149
+ setState({
150
+ data: payload?.data || {
151
+ appType: runtime.appType,
152
+ canAccess: false
153
+ },
154
+ loading: false,
155
+ error: response.ok && payload?.code < 500 ? null : new Error(payload?.message || `Route check failed: ${response.status}`)
156
+ });
157
+ }
158
+ } catch (error) {
159
+ if (!disposed) {
160
+ setState({
161
+ data: null,
162
+ loading: false,
163
+ error: error instanceof Error ? error : new Error(String(error))
164
+ });
165
+ }
166
+ }
167
+ };
168
+ void check();
169
+ return () => {
170
+ disposed = true;
171
+ };
172
+ }, [
173
+ input.menuCode,
174
+ input.path,
175
+ input.routeCode,
176
+ runtime.appType,
177
+ runtime.data?.permissions,
178
+ runtime.fetchImpl,
179
+ runtime.loading,
180
+ runtime.servicePrefix
181
+ ]);
182
+ return {
183
+ ...state,
184
+ canAccess: Boolean(state.data?.canAccess)
185
+ };
186
+ };
187
+ var PermissionBoundary = ({
188
+ children,
189
+ fallback = null,
190
+ loadingFallback = null,
191
+ routeCode,
192
+ menuCode,
193
+ path
194
+ }) => {
195
+ const access = useCanAccessRoute({ routeCode, menuCode, path });
196
+ if (access.loading) return /* @__PURE__ */ jsx(Fragment, { children: loadingFallback });
197
+ if (!access.canAccess) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
198
+ return /* @__PURE__ */ jsx(Fragment, { children });
199
+ };
200
+ var buildServiceUrl = (servicePrefix, path) => {
201
+ const prefix = servicePrefix.endsWith("/") ? servicePrefix.slice(0, -1) : servicePrefix;
202
+ const suffix = path.startsWith("/") ? path : `/${path}`;
203
+ return `${prefix}${suffix}`;
204
+ };
205
+ var resolveAppTypeFromLocation = () => {
206
+ if (typeof window === "undefined") return "";
207
+ const segments = window.location.pathname.split("/").filter(Boolean);
208
+ const viewIndex = segments[0] === "view" ? 1 : 0;
209
+ if (segments[viewIndex] === "submit") return segments[viewIndex + 1] || "";
210
+ if (segments[viewIndex] === "preview") return segments[viewIndex + 1] || "";
211
+ return segments[viewIndex] || "";
212
+ };
213
+ export {
214
+ OpenXiangdaProvider,
215
+ PermissionBoundary,
216
+ useAppMenus,
217
+ useCanAccessRoute,
218
+ useOpenXiangda,
219
+ usePermission,
220
+ useRuntimeBootstrap
221
+ };
222
+ //# sourceMappingURL=react.mjs.map