openxiangda 1.0.55 → 1.0.57

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.
@@ -30,6 +30,14 @@ __export(openxiangdaProvider_exports, {
30
30
  });
31
31
  module.exports = __toCommonJS(openxiangdaProvider_exports);
32
32
  var import_react = require("react");
33
+
34
+ // packages/sdk/src/runtime/core/fetch.ts
35
+ var createBoundFetch = (fetchImpl) => {
36
+ const baseFetch = fetchImpl || globalThis.fetch;
37
+ return ((input, init) => baseFetch.call(globalThis, input, init));
38
+ };
39
+
40
+ // packages/sdk/src/runtime/react/openxiangdaProvider.tsx
33
41
  var import_jsx_runtime = require("react/jsx-runtime");
34
42
  var OpenXiangdaRuntimeContext = (0, import_react.createContext)(null);
35
43
  var OpenXiangdaProvider = ({
@@ -38,7 +46,7 @@ var OpenXiangdaProvider = ({
38
46
  fetchImpl,
39
47
  children
40
48
  }) => {
41
- const resolvedFetch = fetchImpl || fetch;
49
+ const resolvedFetch = (0, import_react.useMemo)(() => createBoundFetch(fetchImpl), [fetchImpl]);
42
50
  const resolvedAppType = (0, import_react.useMemo)(
43
51
  () => appType || resolveAppTypeFromLocation(),
44
52
  [appType]
@@ -1 +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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAOO;AAyJH;AA7EJ,IAAM,gCACJ,4BAA8C,IAAI;AAE7C,IAAM,sBAA0D,CAAC;AAAA,EACtE;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA;AACF,MAAM;AACJ,QAAM,gBAAgB,aAAa;AACnC,QAAM,sBAAkB;AAAA,IACtB,MAAM,WAAW,2BAA2B;AAAA,IAC5C,CAAC,OAAO;AAAA,EACV;AACA,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAgD;AAAA,IACxE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO;AAAA,EACT,CAAC;AAED,QAAM,aAAS,0BAAY,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,8BAAU,MAAM;AACd,SAAK,OAAO;AAAA,EACd,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,YAAQ;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,4CAAC,0BAA0B,UAA1B,EAAmC,OACjC,UACH;AAEJ;AAEO,IAAM,iBAAiB,MAAM;AAClC,QAAM,cAAU,yBAAW,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,QAAI,uBAAiD;AAAA,IACzE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO;AAAA,EACT,CAAC;AAED,8BAAU,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,2EAAG,2BAAgB;AAC9C,MAAI,CAAC,OAAO,UAAW,QAAO,2EAAG,oBAAS;AAC1C,SAAO,2EAAG,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 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":"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","names":[]}
@@ -7,6 +7,14 @@ import {
7
7
  useMemo,
8
8
  useState
9
9
  } from "react";
10
+
11
+ // packages/sdk/src/runtime/core/fetch.ts
12
+ var createBoundFetch = (fetchImpl) => {
13
+ const baseFetch = fetchImpl || globalThis.fetch;
14
+ return ((input, init) => baseFetch.call(globalThis, input, init));
15
+ };
16
+
17
+ // packages/sdk/src/runtime/react/openxiangdaProvider.tsx
10
18
  import { Fragment, jsx } from "react/jsx-runtime";
11
19
  var OpenXiangdaRuntimeContext = createContext(null);
12
20
  var OpenXiangdaProvider = ({
@@ -15,7 +23,7 @@ var OpenXiangdaProvider = ({
15
23
  fetchImpl,
16
24
  children
17
25
  }) => {
18
- const resolvedFetch = fetchImpl || fetch;
26
+ const resolvedFetch = useMemo(() => createBoundFetch(fetchImpl), [fetchImpl]);
19
27
  const resolvedAppType = useMemo(
20
28
  () => appType || resolveAppTypeFromLocation(),
21
29
  [appType]
@@ -1 +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":[]}
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":"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","names":[]}
@@ -10,7 +10,7 @@ import { createRequire } from "node:module";
10
10
  import path from "node:path";
11
11
  import { fileURLToPath } from "node:url";
12
12
  import minimist from "minimist";
13
- import { rootDir } from "./utils/load-config.mjs";
13
+ import { loadConfig, rootDir } from "./utils/load-config.mjs";
14
14
  import {
15
15
  discoverWorkspaceModules,
16
16
  commitIncrementalPublish,
@@ -55,6 +55,7 @@ publish-all - 同步、构建、上传并注册应用工作区产物
55
55
  --changed 只发布 git 变更触达的 src/forms/* 和 src/pages/*
56
56
  --since <ref> 配合 --changed 使用,默认 HEAD
57
57
  --force 忽略增量缓存,强制发布
58
+ --legacy-form-bundle React SPA 下仍发布旧表单 bundle 到 OSS
58
59
  --help, -h 显示帮助信息
59
60
  `);
60
61
  process.exit(0);
@@ -137,6 +138,11 @@ function run(script, scriptArgs = []) {
137
138
 
138
139
  const maybeDryRun = dryRun ? ["--dry-run"] : [];
139
140
  const maybeForce = force ? ["--force"] : [];
141
+ const config = await loadConfig();
142
+ const publishLegacyFormBundle =
143
+ config.runtimeMode !== "react-spa" ||
144
+ Boolean(args["legacy-form-bundle"]) ||
145
+ Boolean(config.forms?.publishLegacyBundle);
140
146
 
141
147
  const allModules = discoverWorkspaceModules();
142
148
  const plan = planIncrementalPublish(allModules, { force, only });
@@ -155,9 +161,18 @@ const publishedModules = [];
155
161
  for (const moduleItem of plan.changed) {
156
162
  if (moduleItem.kind === "forms") {
157
163
  await run("sync-schema.mjs", ["--form", moduleItem.name, ...maybeDryRun]);
158
- await run("build-forms.mjs", ["--form", moduleItem.name, ...maybeForce]);
159
- await run("publish-oss.mjs", ["--form", moduleItem.name, ...maybeDryRun]);
160
- await run("register.mjs", ["--form", moduleItem.name, ...maybeDryRun]);
164
+ if (publishLegacyFormBundle) {
165
+ await run("build-forms.mjs", ["--form", moduleItem.name, ...maybeForce]);
166
+ await run("publish-oss.mjs", ["--form", moduleItem.name, ...maybeDryRun]);
167
+ await run("register.mjs", ["--form", moduleItem.name, ...maybeDryRun]);
168
+ } else {
169
+ console.log(
170
+ `[publish] React SPA 表单 ${moduleItem.name}: 已同步 schema,跳过旧表单 bundle/OSS/register。`,
171
+ );
172
+ console.log(
173
+ "[publish] 如需兼容旧表单页面 bundle,请传 --legacy-form-bundle 或配置 forms.publishLegacyBundle=true。",
174
+ );
175
+ }
161
176
  publishedModules.push(moduleItem);
162
177
  } else if (moduleItem.kind === "pages") {
163
178
  await run("build-pages.mjs", ["--page", moduleItem.name, ...maybeForce]);
@@ -121,6 +121,11 @@ function normalizeCssIsolation(value) {
121
121
  return "none";
122
122
  }
123
123
 
124
+ function normalizeRuntimeMode(value) {
125
+ if (value === "react-spa" || value === "spa") return "react-spa";
126
+ return value === "legacy" ? "legacy" : "";
127
+ }
128
+
124
129
  export function resolveOpenXiangdaEndpointConfig(baseUrl) {
125
130
  const raw = normalizeBaseUrl(baseUrl);
126
131
  if (!raw) {
@@ -174,6 +179,11 @@ export async function loadConfig() {
174
179
  ...source,
175
180
  appType: process.env.OPENXIANGDA_APP_TYPE || source.appType || process.env.APP_TYPE,
176
181
  appName: source.appName || process.env.APP_NAME || "低代码应用",
182
+ runtimeMode: normalizeRuntimeMode(
183
+ process.env.OPENXIANGDA_RUNTIME_MODE ||
184
+ process.env.APP_RUNTIME_MODE ||
185
+ source.runtimeMode,
186
+ ),
177
187
  platformUrl,
178
188
  servicePrefix:
179
189
  openXiangdaEndpoint?.servicePrefix ??
@@ -3,6 +3,7 @@ import { defineAppWorkspaceConfig } from "openxiangda/build";
3
3
  export default defineAppWorkspaceConfig({
4
4
  appType: process.env.APP_TYPE || process.env.OPENXIANGDA_APP_TYPE || "APP_XXXXXXXXXXXXXXXX",
5
5
  appName: process.env.APP_NAME || "OpenXiangda React SPA",
6
+ runtimeMode: "react-spa",
6
7
  platformUrl:
7
8
  process.env.APP_PLATFORM_URL ||
8
9
  process.env.OPENXIANGDA_BASE_URL ||
@@ -1,6 +1,7 @@
1
1
  export interface AppWorkspaceConfig {
2
2
  appType: string;
3
3
  appName: string;
4
+ runtimeMode?: "legacy" | "react-spa";
4
5
  platformUrl: string;
5
6
  servicePrefix: string;
6
7
  appKey: string;
@@ -24,6 +25,10 @@ export interface AppWorkspaceConfig {
24
25
  pageMenuParentId: string;
25
26
  pageMenuIcon: string;
26
27
  };
28
+ forms?: {
29
+ dir?: string;
30
+ publishLegacyBundle?: boolean;
31
+ };
27
32
  }
28
33
 
29
34
  export type CustomPageEntryMode = "app-shell" | "plain-page";