@chatbi-v/core 2.1.1 → 2.1.3

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/dist/index.js CHANGED
@@ -114,6 +114,7 @@ __export(index_exports, {
114
114
  ServiceRegistry: () => ServiceRegistry,
115
115
  SidebarIconSkeleton: () => SidebarIconSkeleton,
116
116
  Slot: () => Slot,
117
+ SlotSkeletons: () => SlotSkeletons,
117
118
  StatusBarItemSkeleton: () => StatusBarItemSkeleton,
118
119
  StorageManager: () => StorageManager,
119
120
  apiEngine: () => apiEngine,
@@ -542,6 +543,9 @@ var useApi = () => {
542
543
  init_config_manager();
543
544
 
544
545
  // src/components/PluginErrorBoundary.tsx
546
+ var import_react3 = require("react");
547
+
548
+ // src/domain/plugin-manager.ts
545
549
  var import_react2 = require("react");
546
550
 
547
551
  // src/adapters/local-storage-adapter.ts
@@ -1378,6 +1382,8 @@ var PluginManager = class {
1378
1382
  sharedContext = null;
1379
1383
  /** 收集到的插件工具函数集合 */
1380
1384
  utils = {};
1385
+ /** 是否正在初始化插件中,防止重入导致多次加载 */
1386
+ isInitializing = false;
1381
1387
  /**
1382
1388
  * 构造函数
1383
1389
  * @param storage - 底层存储适配器
@@ -1450,18 +1456,20 @@ var PluginManager = class {
1450
1456
  * @param affectedSlot - (可选) 受影响的插槽位置
1451
1457
  */
1452
1458
  notify(affectedSlot) {
1453
- if (affectedSlot) {
1454
- this.memoizedExtensions.delete(String(affectedSlot));
1455
- } else {
1456
- this.memoizedExtensions.clear();
1457
- this.memoizedRoutes = null;
1458
- }
1459
- this.listeners.forEach((listener) => listener());
1460
- if (affectedSlot) {
1461
- this.slotListeners.get(String(affectedSlot))?.forEach((listener) => listener());
1462
- } else {
1463
- this.slotListeners.forEach((set) => set.forEach((listener) => listener()));
1464
- }
1459
+ (0, import_react2.startTransition)(() => {
1460
+ if (affectedSlot) {
1461
+ this.memoizedExtensions.delete(String(affectedSlot));
1462
+ } else {
1463
+ this.memoizedExtensions.clear();
1464
+ this.memoizedRoutes = null;
1465
+ }
1466
+ this.listeners.forEach((listener) => listener());
1467
+ if (affectedSlot) {
1468
+ this.slotListeners.get(String(affectedSlot))?.forEach((listener) => listener());
1469
+ } else {
1470
+ this.slotListeners.forEach((set) => set.forEach((listener) => listener()));
1471
+ }
1472
+ });
1465
1473
  }
1466
1474
  /**
1467
1475
  * 获取所有已注册的插件列表
@@ -1778,58 +1786,68 @@ var PluginManager = class {
1778
1786
  * @param sharedContext 共享上下文
1779
1787
  */
1780
1788
  async initPlugins(sharedContext = {}) {
1781
- this.sharedContext = {
1782
- ...sharedContext,
1783
- events: this.eventBus
1784
- };
1785
- this.plugins.forEach((plugin) => {
1786
- if (!this.isPluginEnabled(plugin.id)) return;
1787
- if (!this.runtimes.has(plugin.id)) {
1788
- const runtime = new PluginRuntime(plugin, this.sharedContext, this.storageManager);
1789
- this.runtimes.set(plugin.id, runtime);
1790
- }
1791
- });
1792
- const sortedPluginIds = this.getSortedPluginIds();
1793
- const missingDeps = /* @__PURE__ */ new Map();
1794
- const idsToLoad = new Set(sortedPluginIds);
1795
- for (const id of sortedPluginIds) {
1796
- const plugin = this.plugins.get(id);
1797
- if (plugin?.metadata.dependencies) {
1798
- const missing = plugin.metadata.dependencies.filter((depId) => !this.runtimes.has(depId));
1799
- if (missing.length > 0) {
1800
- missingDeps.set(id, missing);
1801
- idsToLoad.delete(id);
1802
- this.runtimes.delete(id);
1803
- }
1804
- }
1789
+ if (this.isInitializing) {
1790
+ logger6.warn("PluginManager is already initializing, skipping...");
1791
+ return;
1805
1792
  }
1806
- if (missingDeps.size > 0) {
1807
- missingDeps.forEach((deps, id) => {
1808
- logger6.error(`\u63D2\u4EF6 ${id} \u65E0\u6CD5\u52A0\u8F7D\uFF0C\u7F3A\u5931\u4F9D\u8D56: ${deps.join(", ")}`);
1793
+ this.isInitializing = true;
1794
+ try {
1795
+ this.sharedContext = {
1796
+ ...sharedContext,
1797
+ events: this.eventBus
1798
+ };
1799
+ this.plugins.forEach((plugin) => {
1800
+ if (!this.isPluginEnabled(plugin.id)) return;
1801
+ if (!this.runtimes.has(plugin.id)) {
1802
+ const runtime = new PluginRuntime(plugin, this.sharedContext, this.storageManager);
1803
+ this.runtimes.set(plugin.id, runtime);
1804
+ }
1809
1805
  });
1810
- }
1811
- for (const id of sortedPluginIds) {
1812
- if (!idsToLoad.has(id)) continue;
1813
- const runtime = this.runtimes.get(id);
1814
- if (runtime) {
1815
- try {
1816
- logger6.info(`[PluginManager] invoking onLoad for ${id}`);
1817
- await runtime.load();
1818
- logger6.info(`[PluginManager] onLoad completed for ${id}`);
1819
- } catch (e) {
1820
- logger6.error(`\u63D2\u4EF6 ${id} \u52A0\u8F7D\u5931\u8D25:`, e);
1806
+ const sortedPluginIds = this.getSortedPluginIds();
1807
+ const missingDeps = /* @__PURE__ */ new Map();
1808
+ const idsToLoad = new Set(sortedPluginIds);
1809
+ for (const id of sortedPluginIds) {
1810
+ const plugin = this.plugins.get(id);
1811
+ if (plugin?.metadata.dependencies) {
1812
+ const missing = plugin.metadata.dependencies.filter((depId) => !this.runtimes.has(depId));
1813
+ if (missing.length > 0) {
1814
+ missingDeps.set(id, missing);
1815
+ idsToLoad.delete(id);
1816
+ this.runtimes.delete(id);
1817
+ }
1821
1818
  }
1822
1819
  }
1823
- }
1824
- for (const id of sortedPluginIds) {
1825
- const runtime = this.runtimes.get(id);
1826
- if (runtime) {
1827
- try {
1828
- await runtime.mount();
1829
- } catch (e) {
1830
- logger6.error(`\u63D2\u4EF6 ${id} \u6302\u8F7D\u5931\u8D25:`, e);
1820
+ if (missingDeps.size > 0) {
1821
+ missingDeps.forEach((deps, id) => {
1822
+ logger6.error(`\u63D2\u4EF6 ${id} \u65E0\u6CD5\u52A0\u8F7D\uFF0C\u7F3A\u5931\u4F9D\u8D56: ${deps.join(", ")}`);
1823
+ });
1824
+ }
1825
+ for (const id of sortedPluginIds) {
1826
+ if (!idsToLoad.has(id)) continue;
1827
+ const runtime = this.runtimes.get(id);
1828
+ if (runtime && runtime.status === "initial") {
1829
+ try {
1830
+ logger6.info(`[PluginManager] invoking onLoad for ${id}`);
1831
+ await runtime.load();
1832
+ logger6.info(`[PluginManager] onLoad completed for ${id}`);
1833
+ } catch (e) {
1834
+ logger6.error(`\u63D2\u4EF6 ${id} \u52A0\u8F7D\u5931\u8D25:`, e);
1835
+ }
1831
1836
  }
1832
1837
  }
1838
+ for (const id of sortedPluginIds) {
1839
+ if (!idsToLoad.has(id)) continue;
1840
+ const runtime = this.runtimes.get(id);
1841
+ if (runtime && (runtime.status === "loaded" || runtime.status === "initial")) {
1842
+ try {
1843
+ await runtime.mount();
1844
+ } catch (e) {
1845
+ logger6.error(`\u63D2\u4EF6 ${id} \u6302\u8F7D\u5931\u8D25:`, e);
1846
+ }
1847
+ }
1848
+ }
1849
+ } finally {
1850
+ this.isInitializing = false;
1833
1851
  }
1834
1852
  }
1835
1853
  /**
@@ -2016,7 +2034,7 @@ var pluginManager = new PluginManager(new LocalStorageAdapter());
2016
2034
  // src/components/PluginErrorBoundary.tsx
2017
2035
  var import_jsx_runtime2 = require("react/jsx-runtime");
2018
2036
  var logger7 = createLogger("PluginErrorBoundary");
2019
- var PluginErrorBoundary = class extends import_react2.Component {
2037
+ var PluginErrorBoundary = class extends import_react3.Component {
2020
2038
  constructor(props) {
2021
2039
  super(props);
2022
2040
  this.state = { hasError: false, error: null };
@@ -2026,7 +2044,10 @@ var PluginErrorBoundary = class extends import_react2.Component {
2026
2044
  * @param error - 捕获到的错误
2027
2045
  */
2028
2046
  static getDerivedStateFromError(error) {
2029
- return { hasError: true, error };
2047
+ if (error && typeof error.then === "function") {
2048
+ return { hasError: false, error: null };
2049
+ }
2050
+ return { hasError: true, error: error instanceof Error ? error : new Error(String(error)) };
2030
2051
  }
2031
2052
  /**
2032
2053
  * 捕获到错误后的回调
@@ -2034,6 +2055,9 @@ var PluginErrorBoundary = class extends import_react2.Component {
2034
2055
  * @param errorInfo - 错误堆栈信息
2035
2056
  */
2036
2057
  componentDidCatch(error, errorInfo) {
2058
+ if (error && typeof error.then === "function") {
2059
+ return;
2060
+ }
2037
2061
  logger7.error(`\u63D2\u4EF6 ${this.props.pluginId || "\u672A\u77E5"} \u6E32\u67D3\u53D1\u751F\u9519\u8BEF:`, error, errorInfo);
2038
2062
  if (this.props.pluginId) {
2039
2063
  console.warn(`[PluginError] \u63D2\u4EF6 "${this.props.pluginId}" \u6E32\u67D3\u5931\u8D25\u3002\u60A8\u53EF\u4EE5\u5728\u63D2\u4EF6\u7BA1\u7406\u9762\u677F\u67E5\u770B\u8BE6\u7EC6\u4FE1\u606F\u3002`);
@@ -2068,8 +2092,33 @@ var PluginErrorBoundary = class extends import_react2.Component {
2068
2092
  };
2069
2093
 
2070
2094
  // src/components/PluginSlot.tsx
2071
- var import_react3 = require("react");
2095
+ var import_react4 = require("react");
2096
+
2097
+ // src/components/SlotSkeletons.tsx
2072
2098
  var import_jsx_runtime3 = require("react/jsx-runtime");
2099
+ var SidebarIconSkeleton = ({ expanded = false }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `flex items-center transition-all duration-300 relative
2100
+ ${expanded ? "w-full" : "w-12 justify-center"} px-3 h-11 rounded-xl`, children: [
2101
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "w-6 h-6 bg-slate-200 dark:bg-white/10 rounded-lg shrink-0 animate-pulse" }),
2102
+ expanded && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ml-3 flex-1 h-4 bg-slate-200 dark:bg-white/10 rounded animate-pulse" })
2103
+ ] });
2104
+ var StatusBarItemSkeleton = () => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "h-4 w-16 bg-slate-200 dark:bg-white/10 rounded animate-pulse" });
2105
+ var AvatarSkeleton = () => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "w-10 h-10 rounded-full bg-slate-200 dark:bg-white/10 animate-pulse" });
2106
+ var BlockSkeleton = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: `bg-slate-200 dark:bg-white/10 rounded animate-pulse ${className || "w-full h-full"}` });
2107
+ var SlotSkeletons = ({ slot, expanded }) => {
2108
+ if (slot.includes("sidebar")) {
2109
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SidebarIconSkeleton, { expanded });
2110
+ }
2111
+ if (slot.includes("status")) {
2112
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StatusBarItemSkeleton, {});
2113
+ }
2114
+ if (slot.includes("avatar")) {
2115
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AvatarSkeleton, {});
2116
+ }
2117
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BlockSkeleton, {});
2118
+ };
2119
+
2120
+ // src/components/PluginSlot.tsx
2121
+ var import_jsx_runtime4 = require("react/jsx-runtime");
2073
2122
  var PluginSlot = ({
2074
2123
  slot,
2075
2124
  props = {},
@@ -2079,8 +2128,8 @@ var PluginSlot = ({
2079
2128
  skeleton,
2080
2129
  fallback
2081
2130
  }) => {
2082
- const [, forceUpdate] = (0, import_react3.useState)({});
2083
- (0, import_react3.useEffect)(() => {
2131
+ const [, forceUpdate] = (0, import_react4.useState)({});
2132
+ (0, import_react4.useEffect)(() => {
2084
2133
  const unsubscribe = pluginManager.subscribe(() => {
2085
2134
  forceUpdate({});
2086
2135
  }, slot);
@@ -2092,47 +2141,36 @@ var PluginSlot = ({
2092
2141
  logo: pluginManager.getSystemConfig("logo"),
2093
2142
  version: pluginManager.getSystemConfig("version")
2094
2143
  } : void 0;
2095
- const mergedProps = (0, import_react3.useMemo)(() => ({
2144
+ const mergedProps = (0, import_react4.useMemo)(() => ({
2096
2145
  ...props,
2097
2146
  systemConfig
2098
2147
  }), [props, systemConfig]);
2099
- const items = (0, import_react3.useMemo)(() => {
2148
+ const items = (0, import_react4.useMemo)(() => {
2100
2149
  return extensions.map((ext, index) => {
2101
2150
  const Component2 = ext.component;
2102
2151
  const key = ext.meta?.key || `${ext.slot}-${ext.order || 0}-${index}`;
2103
2152
  return {
2104
2153
  key,
2105
2154
  extension: ext,
2106
- component: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PluginErrorBoundary, { pluginId: ext._pluginId, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Component2, { ...mergedProps }) }, key)
2155
+ component: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PluginErrorBoundary, { pluginId: ext._pluginId, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react4.Suspense, { fallback: skeleton || /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SlotSkeletons, { slot }), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Component2, { ...mergedProps }) }) }, key)
2107
2156
  };
2108
2157
  });
2109
2158
  }, [extensions, mergedProps]);
2110
2159
  if (items.length === 0) {
2111
2160
  if (fallback) {
2112
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: fallback });
2161
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: fallback });
2113
2162
  }
2114
2163
  if (skeleton) {
2115
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: `plugin-slot plugin-slot-${slot} plugin-slot-skeleton ${className || ""}`, style, children: skeleton });
2164
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: `plugin-slot plugin-slot-${slot} plugin-slot-skeleton ${className || ""}`, style, children: skeleton });
2116
2165
  }
2117
2166
  return null;
2118
2167
  }
2119
2168
  if (items.length === 1 && slot === "root-layout" && !className && !style && !renderItem) {
2120
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: items[0].component });
2169
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: items[0].component });
2121
2170
  }
2122
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: `plugin-slot plugin-slot-${slot} ${className || ""}`, style, children: renderItem ? items.map((item, index) => renderItem(item, index)) : items.map((item) => item.component) });
2171
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: `plugin-slot plugin-slot-${slot} ${className || ""}`, style, children: renderItem ? items.map((item, index) => renderItem(item, index)) : items.map((item) => item.component) });
2123
2172
  };
2124
2173
 
2125
- // src/components/SlotSkeletons.tsx
2126
- var import_jsx_runtime4 = require("react/jsx-runtime");
2127
- var SidebarIconSkeleton = ({ expanded = false }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `flex items-center transition-all duration-300 relative
2128
- ${expanded ? "w-full" : "w-12 justify-center"} px-3 h-11 rounded-xl`, children: [
2129
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-6 h-6 bg-slate-200 dark:bg-white/10 rounded-lg shrink-0 animate-pulse" }),
2130
- expanded && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "ml-3 flex-1 h-4 bg-slate-200 dark:bg-white/10 rounded animate-pulse" })
2131
- ] });
2132
- var StatusBarItemSkeleton = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "h-4 w-16 bg-slate-200 dark:bg-white/10 rounded animate-pulse" });
2133
- var AvatarSkeleton = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-10 h-10 rounded-full bg-slate-200 dark:bg-white/10 animate-pulse" });
2134
- var BlockSkeleton = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: `bg-slate-200 dark:bg-white/10 rounded animate-pulse ${className || "w-full h-full"}` });
2135
-
2136
2174
  // src/domain/auto-loader.ts
2137
2175
  var logger8 = createLogger("AutoLoader");
2138
2176
  var DEFAULT_RULES = [
@@ -2178,14 +2216,14 @@ var resolvePluginRegistry = (options) => {
2178
2216
  var SUCCESS_CODE = "000000";
2179
2217
 
2180
2218
  // src/plugin-context.tsx
2181
- var import_react4 = require("react");
2219
+ var import_react5 = require("react");
2182
2220
  var import_jsx_runtime5 = require("react/jsx-runtime");
2183
- var PluginContext = (0, import_react4.createContext)(null);
2221
+ var PluginContext = (0, import_react5.createContext)(null);
2184
2222
  var PluginProvider = ({ manager, children }) => {
2185
2223
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PluginContext.Provider, { value: manager, children });
2186
2224
  };
2187
2225
  var usePluginManager = () => {
2188
- const context = (0, import_react4.useContext)(PluginContext);
2226
+ const context = (0, import_react5.useContext)(PluginContext);
2189
2227
  if (!context) {
2190
2228
  throw new Error("usePluginManager must be used within a PluginProvider");
2191
2229
  }
@@ -2670,15 +2708,15 @@ var dateUtils = {
2670
2708
  var version = "1.0.0";
2671
2709
 
2672
2710
  // src/hooks/use-storage-state.ts
2673
- var import_react5 = require("react");
2711
+ var import_react6 = require("react");
2674
2712
  function useStorageState(pluginId, key, options = {}) {
2675
2713
  const { defaultValue, scope = "plugin" } = options;
2676
2714
  const storageManager = pluginManager.getStorageManager();
2677
- const getStorage = (0, import_react5.useCallback)(() => {
2715
+ const getStorage = (0, import_react6.useCallback)(() => {
2678
2716
  const contextStorage = storageManager.getContextStorage(pluginId);
2679
2717
  return scope === "shared" ? contextStorage.shared : contextStorage;
2680
2718
  }, [pluginId, scope, storageManager]);
2681
- const [state, setState] = (0, import_react5.useState)(() => {
2719
+ const [state, setState] = (0, import_react6.useState)(() => {
2682
2720
  try {
2683
2721
  if (typeof window === "undefined") return defaultValue;
2684
2722
  const storage = getStorage();
@@ -2689,7 +2727,7 @@ function useStorageState(pluginId, key, options = {}) {
2689
2727
  return defaultValue;
2690
2728
  }
2691
2729
  });
2692
- const setValue = (0, import_react5.useCallback)((value) => {
2730
+ const setValue = (0, import_react6.useCallback)((value) => {
2693
2731
  try {
2694
2732
  const valueToStore = value instanceof Function ? value(state) : value;
2695
2733
  setState(valueToStore);
@@ -2703,13 +2741,13 @@ function useStorageState(pluginId, key, options = {}) {
2703
2741
  }
2704
2742
 
2705
2743
  // src/hooks/use-plugin-loader.ts
2706
- var import_react6 = require("react");
2744
+ var import_react7 = require("react");
2707
2745
  var logger10 = createLogger("PluginLoader");
2708
2746
  var usePluginLoader = (options) => {
2709
- const [pluginsLoaded, setPluginsLoaded] = (0, import_react6.useState)(false);
2710
- const [pluginVersion, setPluginVersion] = (0, import_react6.useState)(0);
2711
- const loadingRef = (0, import_react6.useRef)(false);
2712
- (0, import_react6.useEffect)(() => {
2747
+ const [pluginsLoaded, setPluginsLoaded] = (0, import_react7.useState)(false);
2748
+ const [pluginVersion, setPluginVersion] = (0, import_react7.useState)(0);
2749
+ const loadingRef = (0, import_react7.useRef)(false);
2750
+ (0, import_react7.useEffect)(() => {
2713
2751
  const unsubscribe = pluginManager.subscribe(() => {
2714
2752
  logger10.debug("Plugin state changed, refreshing UI...");
2715
2753
  setPluginVersion((v) => v + 1);
@@ -2782,6 +2820,7 @@ var usePluginLoader = (options) => {
2782
2820
  ServiceRegistry,
2783
2821
  SidebarIconSkeleton,
2784
2822
  Slot,
2823
+ SlotSkeletons,
2785
2824
  StatusBarItemSkeleton,
2786
2825
  StorageManager,
2787
2826
  apiEngine,
@@ -2803,3 +2842,4 @@ var usePluginLoader = (options) => {
2803
2842
  useStorageState,
2804
2843
  version
2805
2844
  });
2845
+ //# sourceMappingURL=index.js.map