@chatbi-v/core 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -20
- package/dist/domain/auto-loader.d.ts +3 -19
- package/dist/domain/plugin-manager.d.ts +9 -3
- package/dist/domain/plugin-runtime.d.ts +5 -0
- package/dist/hooks/use-plugin-loader.d.ts +2 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.mjs +145 -78
- package/dist/index.plugin.js +5106 -0
- package/dist/ports/plugin-port.d.ts +26 -2
- package/package.json +4 -4
- package/dist/index.cjs +0 -2118
package/README.md
CHANGED
|
@@ -2,35 +2,60 @@
|
|
|
2
2
|
|
|
3
3
|
ChatBI 核心模块,提供插件管理、基础设施接口及通用 API 引擎。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 模块功能说明
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
7
|
+
- **微内核架构**: 实现插件的注册、生命周期管理与隔离。
|
|
8
|
+
- **领域驱动设计**: 严格区分领域逻辑 (`domain`)、外部接口 (`ports`) 和具体实现 (`adapters`)。
|
|
9
|
+
- **API 引擎**: 统一的 API 请求管理,支持同步、流式请求及拦截器。
|
|
10
|
+
- **存储管理**: 提供隔离的存储适配器,确保插件数据互不干扰。
|
|
10
11
|
|
|
11
|
-
##
|
|
12
|
+
## 安装和使用方法
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
- `api/`: 通用 API 请求引擎。
|
|
15
|
-
- `domain/`: 核心领域逻辑(插件管理器、运行时、沙箱)。
|
|
16
|
-
- `ports/`: 核心接口定义(端口)。
|
|
17
|
-
|
|
18
|
-
## 功能
|
|
14
|
+
### 安装
|
|
19
15
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
```bash
|
|
17
|
+
pnpm add @chatbi-v/core
|
|
18
|
+
```
|
|
23
19
|
|
|
24
|
-
|
|
20
|
+
### 使用示例
|
|
25
21
|
|
|
26
22
|
```typescript
|
|
27
|
-
import {
|
|
23
|
+
import { PluginManager, LocalStorageAdapter } from '@chatbi-v/core';
|
|
24
|
+
|
|
25
|
+
// 初始化插件管理器
|
|
26
|
+
const storage = new LocalStorageAdapter();
|
|
27
|
+
const pluginManager = new PluginManager(storage);
|
|
28
28
|
|
|
29
|
-
//
|
|
29
|
+
// 注册并初始化插件
|
|
30
30
|
pluginManager.register({
|
|
31
31
|
id: 'my-plugin',
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
metadata: { name: 'My Plugin', type: 'business' },
|
|
33
|
+
onLoad: async (context) => {
|
|
34
|
+
console.log('Plugin loaded', context.pluginId);
|
|
35
|
+
}
|
|
35
36
|
});
|
|
36
37
|
```
|
|
38
|
+
|
|
39
|
+
## API 文档链接
|
|
40
|
+
|
|
41
|
+
详细 API 文档请参考 [docs/index.html](https://github.com/your-repo/docs/index.html) 或运行 `npm run docs:dev` 本地查看。
|
|
42
|
+
|
|
43
|
+
## 开发注意事项
|
|
44
|
+
|
|
45
|
+
- **禁止引入 UI 框架**: 本模块为纯逻辑层,不得包含 React/AntD 等 UI 依赖。
|
|
46
|
+
- **禁止反向依赖**: `core` 不得依赖 `plugins` 或 `apps` 中的任何代码。
|
|
47
|
+
- **类型安全**: 优先使用 `ports` 中定义的接口。
|
|
48
|
+
|
|
49
|
+
## 架构原则 (Architecture Principles)
|
|
50
|
+
|
|
51
|
+
- **业务无关性 (Business Agnostic)**: `core` 包禁止包含任何具体的业务模型、业务逻辑或业务常量。
|
|
52
|
+
- **共享契约 (Shared Contract)**: `core` 只定义通用的技术契约(如 `Plugin`, `StoragePort`, `ApiAdapter`)。
|
|
53
|
+
- **插件驱动 (Plugin Driven)**: 所有的业务逻辑应由插件实现。
|
|
54
|
+
|
|
55
|
+
## 目录结构
|
|
56
|
+
|
|
57
|
+
- `adapters/`: 基础设施的具体实现(如 LocalStorage, Axios)。
|
|
58
|
+
- `api/`: 通用 API 请求引擎。
|
|
59
|
+
- `domain/`: 核心领域逻辑(插件管理器、运行时、沙箱)。
|
|
60
|
+
- `ports/`: 核心接口定义(端口)。
|
|
61
|
+
- `utils/`: 通用工具函数。
|
|
@@ -3,21 +3,13 @@ export interface PluginRegistry {
|
|
|
3
3
|
}
|
|
4
4
|
export interface DiscoveryRule {
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
pattern: string;
|
|
9
|
-
/**
|
|
10
|
-
* 路径标识部分(用于从绝对路径中提取 ID,例如 'packages/plugins')
|
|
6
|
+
* 路径匹配标识(如 'plugins' 或 '@chatbi-plugins')
|
|
11
7
|
*/
|
|
12
8
|
pathSegment: string;
|
|
13
9
|
/**
|
|
14
|
-
* 生成插件 ID
|
|
10
|
+
* 生成插件 ID 时的前缀(如 '@chatbi-v/plugin')
|
|
15
11
|
*/
|
|
16
12
|
idPrefix: string;
|
|
17
|
-
/**
|
|
18
|
-
* 可选的别名映射
|
|
19
|
-
*/
|
|
20
|
-
alias?: string;
|
|
21
13
|
}
|
|
22
14
|
/**
|
|
23
15
|
* 自动发现并解析插件
|
|
@@ -25,13 +17,5 @@ export interface DiscoveryRule {
|
|
|
25
17
|
*/
|
|
26
18
|
export declare const resolvePluginRegistry: (options: {
|
|
27
19
|
modules: Record<string, () => Promise<any>>;
|
|
28
|
-
|
|
29
|
-
rules: DiscoveryRule[];
|
|
20
|
+
rules?: DiscoveryRule[];
|
|
30
21
|
}) => PluginRegistry;
|
|
31
|
-
/**
|
|
32
|
-
* 核心插件发现方法
|
|
33
|
-
* @description 该方法应在应用层被调用,但逻辑集成在 core 中。
|
|
34
|
-
* 注意:由于 Vite import.meta.glob 必须使用字面量的限制,
|
|
35
|
-
* 这里使用一个覆盖范围合理的模式,并通过 rules 进行精确匹配。
|
|
36
|
-
*/
|
|
37
|
-
export declare const discoverPlugins: (rules: DiscoveryRule[], baseUrl: string) => PluginRegistry;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file plugin-manager.ts
|
|
3
|
+
* @description 插件管理器,负责插件的注册、生命周期管理、状态持久化及扩展点收集
|
|
4
|
+
* @author ChatBI Team
|
|
5
|
+
*/
|
|
1
6
|
import { DefaultEventBus } from '../event-bus';
|
|
2
7
|
import { Plugin, PluginExtension, RouteConfig, SlotPosition } from '../ports/plugin-port';
|
|
3
8
|
import { StoragePort } from '../ports/storage-port';
|
|
@@ -104,9 +109,6 @@ export declare class PluginManager {
|
|
|
104
109
|
* @param slot 插槽位置
|
|
105
110
|
*/
|
|
106
111
|
getExtensions(slot: SlotPosition | string): PluginExtension[];
|
|
107
|
-
/**
|
|
108
|
-
* 获取所有收集到的路由
|
|
109
|
-
*/
|
|
110
112
|
getRoutes(): RouteConfig[];
|
|
111
113
|
/**
|
|
112
114
|
* 注册插件
|
|
@@ -136,6 +138,10 @@ export declare class PluginManager {
|
|
|
136
138
|
* @param config 插件配置
|
|
137
139
|
*/
|
|
138
140
|
loadRemotePlugin(pluginId: string, url: string, config: any): Promise<Plugin | null>;
|
|
141
|
+
/**
|
|
142
|
+
* IIFE 模式加载插件
|
|
143
|
+
*/
|
|
144
|
+
private loadIIFEPlugin;
|
|
139
145
|
/**
|
|
140
146
|
* 实例化插件
|
|
141
147
|
*/
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export interface PluginLoaderOptions {
|
|
2
2
|
/** 插件发现规则 */
|
|
3
3
|
discoveryRules?: any[];
|
|
4
|
+
/** 插件模块映射 (由 Vite import.meta.glob 生成) */
|
|
5
|
+
modules?: Record<string, () => Promise<any>>;
|
|
4
6
|
/** 预注册的插件注册表 (可选,用于离线或手动加载) */
|
|
5
7
|
registry?: Record<string, () => Promise<any>>;
|
|
6
8
|
/** 插件配置映射 */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file index.ts
|
|
3
|
+
* @description Core 模块入口文件,导出所有公共 API、领域逻辑、组件和 Hooks
|
|
4
|
+
* @author ChatBI Team
|
|
5
|
+
*/
|
|
1
6
|
export * from './ports/api-port';
|
|
2
7
|
export * from './ports/event-bus-port';
|
|
3
8
|
export * from './ports/plugin-port';
|
|
@@ -19,6 +24,7 @@ export * from './adapters/scoped-storage-adapter';
|
|
|
19
24
|
export * from './event-bus';
|
|
20
25
|
export * from './plugin-context';
|
|
21
26
|
export * from './api';
|
|
27
|
+
export * from './sandbox/proxy-sandbox';
|
|
22
28
|
export * from './utils';
|
|
23
29
|
export * from './hooks/use-storage-state';
|
|
24
30
|
export * from './hooks/use-plugin-loader';
|
package/dist/index.mjs
CHANGED
|
@@ -18,6 +18,23 @@ var Slot = {
|
|
|
18
18
|
RootLayout: "root-layout",
|
|
19
19
|
Custom: "custom"
|
|
20
20
|
};
|
|
21
|
+
var BasePlugin = class {
|
|
22
|
+
/**
|
|
23
|
+
* 插件 ID
|
|
24
|
+
* @description 自动从 metadata.id 获取
|
|
25
|
+
*/
|
|
26
|
+
get id() {
|
|
27
|
+
return this.metadata.id;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
function definePlugin(plugin) {
|
|
31
|
+
return {
|
|
32
|
+
...plugin,
|
|
33
|
+
get id() {
|
|
34
|
+
return this.metadata.id;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
21
38
|
|
|
22
39
|
// src/utils/logger.ts
|
|
23
40
|
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
@@ -227,7 +244,7 @@ var PluginErrorBoundary = class extends Component {
|
|
|
227
244
|
};
|
|
228
245
|
|
|
229
246
|
// src/components/PluginSlot.tsx
|
|
230
|
-
import { useMemo } from "react";
|
|
247
|
+
import { useMemo, useState, useEffect } from "react";
|
|
231
248
|
|
|
232
249
|
// src/adapters/local-storage-adapter.ts
|
|
233
250
|
var LocalStorageAdapter = class {
|
|
@@ -764,18 +781,24 @@ var StorageManager = class {
|
|
|
764
781
|
this.validateKey(pluginId, key, scope);
|
|
765
782
|
try {
|
|
766
783
|
const val = adapter.getItem(key);
|
|
767
|
-
if (val
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
784
|
+
if (val !== null) {
|
|
785
|
+
try {
|
|
786
|
+
return JSON.parse(val);
|
|
787
|
+
} catch {
|
|
788
|
+
return val;
|
|
771
789
|
}
|
|
772
|
-
return null;
|
|
773
790
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
791
|
+
if (scope === "plugin") {
|
|
792
|
+
const externalConfig = configManager.get(pluginId);
|
|
793
|
+
if (externalConfig && externalConfig[key] !== void 0) {
|
|
794
|
+
return externalConfig[key];
|
|
795
|
+
}
|
|
778
796
|
}
|
|
797
|
+
const schema = this.schemas.get(pluginId)?.find((s) => s.key === key);
|
|
798
|
+
if (schema && schema.default !== void 0) {
|
|
799
|
+
return schema.default;
|
|
800
|
+
}
|
|
801
|
+
return null;
|
|
779
802
|
} catch (e) {
|
|
780
803
|
console.warn(`[Storage] Failed to read key "${key}"`, e);
|
|
781
804
|
return null;
|
|
@@ -1012,14 +1035,21 @@ var PluginManager = class {
|
|
|
1012
1035
|
});
|
|
1013
1036
|
return extensions.sort((a, b) => (a.order || 0) - (b.order || 0));
|
|
1014
1037
|
}
|
|
1015
|
-
/**
|
|
1016
|
-
* 获取所有收集到的路由
|
|
1017
|
-
*/
|
|
1018
1038
|
getRoutes() {
|
|
1019
1039
|
const activeRoutes = [];
|
|
1020
1040
|
this.getPlugins().forEach((plugin) => {
|
|
1021
1041
|
if (this.isPluginEnabled(plugin.id) && plugin.metadata.routes) {
|
|
1022
|
-
|
|
1042
|
+
const config = configManager.get(plugin.id) || {};
|
|
1043
|
+
plugin.metadata.routes.forEach((route) => {
|
|
1044
|
+
activeRoutes.push({
|
|
1045
|
+
...route,
|
|
1046
|
+
meta: {
|
|
1047
|
+
...route.meta,
|
|
1048
|
+
pluginId: plugin.id,
|
|
1049
|
+
config
|
|
1050
|
+
}
|
|
1051
|
+
});
|
|
1052
|
+
});
|
|
1023
1053
|
}
|
|
1024
1054
|
});
|
|
1025
1055
|
return activeRoutes;
|
|
@@ -1037,42 +1067,48 @@ var PluginManager = class {
|
|
|
1037
1067
|
if (this.plugins.has(plugin.id)) {
|
|
1038
1068
|
return;
|
|
1039
1069
|
}
|
|
1040
|
-
|
|
1041
|
-
|
|
1070
|
+
const storageSchema = [
|
|
1071
|
+
...plugin.metadata.storage || [],
|
|
1072
|
+
...plugin.metadata.configuration?.map((c) => ({
|
|
1073
|
+
key: c.key,
|
|
1074
|
+
// 将 configuration 的 type 映射为 storage 支持的类型
|
|
1075
|
+
type: c.type === "select" ? "string" : c.type,
|
|
1076
|
+
label: c.label,
|
|
1077
|
+
description: c.description,
|
|
1078
|
+
default: c.default,
|
|
1079
|
+
scope: "plugin"
|
|
1080
|
+
})) || []
|
|
1081
|
+
];
|
|
1082
|
+
if (storageSchema.length > 0) {
|
|
1083
|
+
this.storageManager.registerSchema(plugin.id, storageSchema);
|
|
1042
1084
|
}
|
|
1043
1085
|
if (!this.pluginStates[plugin.id]) {
|
|
1044
1086
|
this.pluginStates[plugin.id] = { enabled: true, order: 0 };
|
|
1045
1087
|
}
|
|
1046
|
-
const
|
|
1088
|
+
const metadataDefaults = {};
|
|
1089
|
+
const userOverrides = {};
|
|
1047
1090
|
const pluginStorage = this.storageManager.getPluginStorage(plugin.id);
|
|
1048
1091
|
if (plugin.metadata.configuration) {
|
|
1049
1092
|
plugin.metadata.configuration.forEach((item) => {
|
|
1050
1093
|
if (item.default !== void 0) {
|
|
1051
|
-
|
|
1094
|
+
metadataDefaults[item.key] = item.default;
|
|
1052
1095
|
}
|
|
1053
1096
|
try {
|
|
1054
1097
|
const saved = pluginStorage.getItem(item.key);
|
|
1055
1098
|
if (saved !== null) {
|
|
1056
|
-
|
|
1099
|
+
userOverrides[item.key] = JSON.parse(saved);
|
|
1057
1100
|
}
|
|
1058
1101
|
} catch (e) {
|
|
1059
1102
|
}
|
|
1060
1103
|
});
|
|
1061
1104
|
}
|
|
1062
1105
|
const mergedConfig = {
|
|
1106
|
+
...metadataDefaults,
|
|
1063
1107
|
...plugin.defaultConfig,
|
|
1064
|
-
...
|
|
1065
|
-
...
|
|
1108
|
+
...configManager.get(plugin.id) || {},
|
|
1109
|
+
...userOverrides
|
|
1066
1110
|
};
|
|
1067
1111
|
configManager.set(plugin.id, mergedConfig);
|
|
1068
|
-
if (mergedConfig) {
|
|
1069
|
-
Object.entries(mergedConfig).forEach(([key, value]) => {
|
|
1070
|
-
try {
|
|
1071
|
-
pluginStorage.setItem(key, JSON.stringify(value));
|
|
1072
|
-
} catch (e) {
|
|
1073
|
-
}
|
|
1074
|
-
});
|
|
1075
|
-
}
|
|
1076
1112
|
switch (plugin.metadata.type) {
|
|
1077
1113
|
case "business":
|
|
1078
1114
|
this.handleBusinessPlugin(plugin);
|
|
@@ -1133,7 +1169,9 @@ var PluginManager = class {
|
|
|
1133
1169
|
const runtime = this.runtimes.get(id);
|
|
1134
1170
|
if (runtime) {
|
|
1135
1171
|
try {
|
|
1172
|
+
console.log(`[PluginManager] invoking onLoad for ${id}`);
|
|
1136
1173
|
await runtime.load();
|
|
1174
|
+
console.log(`[PluginManager] onLoad completed for ${id}`);
|
|
1137
1175
|
} catch (e) {
|
|
1138
1176
|
logger7.error(`\u63D2\u4EF6 ${id} \u52A0\u8F7D\u5931\u8D25:`, e);
|
|
1139
1177
|
}
|
|
@@ -1240,31 +1278,38 @@ var PluginManager = class {
|
|
|
1240
1278
|
*/
|
|
1241
1279
|
async loadRemotePlugin(pluginId, url, config) {
|
|
1242
1280
|
logger7.info(`\u6B63\u5728\u4ECE ${url} \u52A0\u8F7D\u8FDC\u7A0B\u63D2\u4EF6 ${pluginId}...`);
|
|
1281
|
+
if (config?.format === "iife") {
|
|
1282
|
+
return this.loadIIFEPlugin(pluginId, url, config);
|
|
1283
|
+
}
|
|
1243
1284
|
try {
|
|
1244
|
-
const
|
|
1245
|
-
|
|
1246
|
-
url
|
|
1247
|
-
);
|
|
1285
|
+
const dynamicImport = new Function("specifier", "return import(specifier)");
|
|
1286
|
+
const module = await dynamicImport(url);
|
|
1248
1287
|
return this.instantiatePlugin(pluginId, module, config);
|
|
1249
1288
|
} catch (e) {
|
|
1250
1289
|
logger7.warn(`ESM \u52A0\u8F7D\u5931\u8D25\uFF0C\u5C1D\u8BD5 IIFE \u52A0\u8F7D: ${pluginId}`);
|
|
1251
|
-
return
|
|
1252
|
-
const script = document.createElement("script");
|
|
1253
|
-
script.src = url;
|
|
1254
|
-
script.onload = () => {
|
|
1255
|
-
const globalName = pluginId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1256
|
-
const pluginModule = window[globalName];
|
|
1257
|
-
if (pluginModule) {
|
|
1258
|
-
resolve(this.instantiatePlugin(pluginId, pluginModule, config));
|
|
1259
|
-
} else {
|
|
1260
|
-
reject(new Error(`\u8FDC\u7A0B\u63D2\u4EF6 ${pluginId} \u52A0\u8F7D\u540E\u672A\u627E\u5230\u5168\u5C40\u53D8\u91CF ${globalName}`));
|
|
1261
|
-
}
|
|
1262
|
-
};
|
|
1263
|
-
script.onerror = () => reject(new Error(`\u8FDC\u7A0B\u63D2\u4EF6 ${pluginId} \u52A0\u8F7D\u5931\u8D25: ${url}`));
|
|
1264
|
-
document.head.appendChild(script);
|
|
1265
|
-
});
|
|
1290
|
+
return this.loadIIFEPlugin(pluginId, url, config);
|
|
1266
1291
|
}
|
|
1267
1292
|
}
|
|
1293
|
+
/**
|
|
1294
|
+
* IIFE 模式加载插件
|
|
1295
|
+
*/
|
|
1296
|
+
loadIIFEPlugin(pluginId, url, config) {
|
|
1297
|
+
return new Promise((resolve, reject) => {
|
|
1298
|
+
const script = document.createElement("script");
|
|
1299
|
+
script.src = url;
|
|
1300
|
+
script.onload = () => {
|
|
1301
|
+
const globalName = pluginId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1302
|
+
const pluginModule = window[globalName];
|
|
1303
|
+
if (pluginModule) {
|
|
1304
|
+
resolve(this.instantiatePlugin(pluginId, pluginModule, config));
|
|
1305
|
+
} else {
|
|
1306
|
+
reject(new Error(`\u8FDC\u7A0B\u63D2\u4EF6 ${pluginId} \u52A0\u8F7D\u540E\u672A\u627E\u5230\u5168\u5C40\u53D8\u91CF ${globalName}`));
|
|
1307
|
+
}
|
|
1308
|
+
};
|
|
1309
|
+
script.onerror = () => reject(new Error(`\u8FDC\u7A0B\u63D2\u4EF6 ${pluginId} \u52A0\u8F7D\u5931\u8D25: ${url}`));
|
|
1310
|
+
document.head.appendChild(script);
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1268
1313
|
/**
|
|
1269
1314
|
* 实例化插件
|
|
1270
1315
|
*/
|
|
@@ -1280,11 +1325,22 @@ var PluginManager = class {
|
|
|
1280
1325
|
}
|
|
1281
1326
|
}
|
|
1282
1327
|
if (PluginClass) {
|
|
1328
|
+
const isClass = typeof PluginClass === "function" && PluginClass.prototype;
|
|
1329
|
+
if (isClass) {
|
|
1330
|
+
logger7.warn(`\u63D2\u4EF6 ${pluginId} \u4F7F\u7528\u4E86\u7C7B\u5B9A\u4E49\u6A21\u5F0F\u3002\u5EFA\u8BAE\u7EDF\u4E00\u4F7F\u7528 definePlugin() \u5DE5\u5382\u6A21\u5F0F\u4EE5\u6D88\u9664\u6B67\u4E49\u5E76\u7B80\u5316\u4EE3\u7801\u3002`);
|
|
1331
|
+
}
|
|
1283
1332
|
const pluginInstance = typeof PluginClass === "function" ? new PluginClass() : PluginClass;
|
|
1333
|
+
const isFilePath = pluginId.includes("/") && (pluginId.includes(".ts") || pluginId.includes(".tsx"));
|
|
1334
|
+
if (!isFilePath && pluginId && pluginInstance.metadata) {
|
|
1335
|
+
if (pluginInstance.metadata.id !== pluginId) {
|
|
1336
|
+
pluginInstance.metadata.id = pluginId;
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1284
1339
|
if (!pluginInstance.id && pluginInstance.metadata?.id) {
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1340
|
+
try {
|
|
1341
|
+
pluginInstance.id = pluginInstance.metadata.id;
|
|
1342
|
+
} catch (e) {
|
|
1343
|
+
}
|
|
1288
1344
|
}
|
|
1289
1345
|
if (config) {
|
|
1290
1346
|
pluginInstance.defaultConfig = { ...pluginInstance.defaultConfig, ...config };
|
|
@@ -1324,6 +1380,13 @@ var PluginSlot = ({
|
|
|
1324
1380
|
skeleton,
|
|
1325
1381
|
fallback
|
|
1326
1382
|
}) => {
|
|
1383
|
+
const [, forceUpdate] = useState({});
|
|
1384
|
+
useEffect(() => {
|
|
1385
|
+
const unsubscribe = pluginManager.subscribe(() => {
|
|
1386
|
+
forceUpdate({});
|
|
1387
|
+
});
|
|
1388
|
+
return unsubscribe;
|
|
1389
|
+
}, []);
|
|
1327
1390
|
const extensions = pluginManager.getExtensions(slot);
|
|
1328
1391
|
const systemConfig = pluginManager.getSystemConfig("title") ? {
|
|
1329
1392
|
title: pluginManager.getSystemConfig("title"),
|
|
@@ -1373,8 +1436,14 @@ var BlockSkeleton = ({ className }) => /* @__PURE__ */ jsx4("div", { className:
|
|
|
1373
1436
|
|
|
1374
1437
|
// src/domain/auto-loader.ts
|
|
1375
1438
|
var logger8 = createLogger("AutoLoader");
|
|
1439
|
+
var DEFAULT_RULES = [
|
|
1440
|
+
{ pathSegment: "@chatbi-plugins", idPrefix: "@chatbi-v/plugin" },
|
|
1441
|
+
{ pathSegment: "@chatbi-apps", idPrefix: "@chatbi-v/app" },
|
|
1442
|
+
{ pathSegment: "packages/plugins", idPrefix: "@chatbi-v/plugin" },
|
|
1443
|
+
{ pathSegment: "packages/apps", idPrefix: "@chatbi-v/app" }
|
|
1444
|
+
];
|
|
1376
1445
|
var resolvePluginRegistry = (options) => {
|
|
1377
|
-
const { modules,
|
|
1446
|
+
const { modules, rules = DEFAULT_RULES } = options;
|
|
1378
1447
|
const registry = {};
|
|
1379
1448
|
const compiledRules = rules.map((rule) => {
|
|
1380
1449
|
const escapedSegment = rule.pathSegment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -1383,36 +1452,28 @@ var resolvePluginRegistry = (options) => {
|
|
|
1383
1452
|
regex: new RegExp(`${escapedSegment}/([^/]+)/src/index`)
|
|
1384
1453
|
};
|
|
1385
1454
|
});
|
|
1386
|
-
for (const
|
|
1455
|
+
for (const path in modules) {
|
|
1387
1456
|
try {
|
|
1388
|
-
|
|
1457
|
+
let pluginId = null;
|
|
1389
1458
|
for (const rule of compiledRules) {
|
|
1390
1459
|
const match = path.match(rule.regex);
|
|
1391
1460
|
if (match && match[1]) {
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
registry[pluginId] = modules[relativePath];
|
|
1395
|
-
logger8.info(`Found plugin: ${pluginId} at ${path}`);
|
|
1461
|
+
pluginId = `${rule.idPrefix}-${match[1]}`;
|
|
1462
|
+
logger8.info(`\u89E3\u6790\u8DEF\u5F84\u6210\u529F: ${path} -> ${pluginId}`);
|
|
1396
1463
|
break;
|
|
1397
1464
|
}
|
|
1398
1465
|
}
|
|
1466
|
+
if (pluginId) {
|
|
1467
|
+
registry[pluginId] = modules[path];
|
|
1468
|
+
} else {
|
|
1469
|
+
logger8.warn(`\u65E0\u6CD5\u4ECE\u8DEF\u5F84\u89E3\u6790\u63D2\u4EF6 ID: ${path}\uFF0C\u8BF7\u68C0\u67E5\u662F\u5426\u7B26\u5408\u547D\u540D\u7EA6\u5B9A\u3002`);
|
|
1470
|
+
}
|
|
1399
1471
|
} catch (e) {
|
|
1400
|
-
logger8.error(
|
|
1472
|
+
logger8.error(`\u89E3\u6790\u63D2\u4EF6\u8DEF\u5F84\u5931\u8D25: ${path}`, e);
|
|
1401
1473
|
}
|
|
1402
1474
|
}
|
|
1403
1475
|
return registry;
|
|
1404
1476
|
};
|
|
1405
|
-
var discoverPlugins = (rules, baseUrl) => {
|
|
1406
|
-
const modules = import.meta.glob([
|
|
1407
|
-
"../../../../packages/plugins/*/src/index.{ts,tsx}",
|
|
1408
|
-
"../../../../apps/*/src/index.{ts,tsx}"
|
|
1409
|
-
]);
|
|
1410
|
-
return resolvePluginRegistry({
|
|
1411
|
-
modules,
|
|
1412
|
-
baseUrl,
|
|
1413
|
-
rules
|
|
1414
|
-
});
|
|
1415
|
-
};
|
|
1416
1477
|
|
|
1417
1478
|
// src/domain/models.ts
|
|
1418
1479
|
var SUCCESS_CODE = "000000";
|
|
@@ -1853,7 +1914,7 @@ var dateUtils = {
|
|
|
1853
1914
|
var version = "1.0.0";
|
|
1854
1915
|
|
|
1855
1916
|
// src/hooks/use-storage-state.ts
|
|
1856
|
-
import { useCallback, useState } from "react";
|
|
1917
|
+
import { useCallback, useState as useState2 } from "react";
|
|
1857
1918
|
function useStorageState(pluginId, key, options = {}) {
|
|
1858
1919
|
const { defaultValue, scope = "plugin" } = options;
|
|
1859
1920
|
const storageManager = pluginManager.getStorageManager();
|
|
@@ -1861,7 +1922,7 @@ function useStorageState(pluginId, key, options = {}) {
|
|
|
1861
1922
|
const contextStorage = storageManager.getContextStorage(pluginId);
|
|
1862
1923
|
return scope === "shared" ? contextStorage.shared : contextStorage;
|
|
1863
1924
|
}, [pluginId, scope, storageManager]);
|
|
1864
|
-
const [state, setState] =
|
|
1925
|
+
const [state, setState] = useState2(() => {
|
|
1865
1926
|
try {
|
|
1866
1927
|
if (typeof window === "undefined") return defaultValue;
|
|
1867
1928
|
const storage = getStorage();
|
|
@@ -1886,13 +1947,13 @@ function useStorageState(pluginId, key, options = {}) {
|
|
|
1886
1947
|
}
|
|
1887
1948
|
|
|
1888
1949
|
// src/hooks/use-plugin-loader.ts
|
|
1889
|
-
import { useEffect, useRef, useState as
|
|
1950
|
+
import { useEffect as useEffect2, useRef, useState as useState3 } from "react";
|
|
1890
1951
|
var logger10 = createLogger("PluginLoader");
|
|
1891
1952
|
var usePluginLoader = (options) => {
|
|
1892
|
-
const [pluginsLoaded, setPluginsLoaded] =
|
|
1893
|
-
const [pluginVersion, setPluginVersion] =
|
|
1953
|
+
const [pluginsLoaded, setPluginsLoaded] = useState3(false);
|
|
1954
|
+
const [pluginVersion, setPluginVersion] = useState3(0);
|
|
1894
1955
|
const loadingRef = useRef(false);
|
|
1895
|
-
|
|
1956
|
+
useEffect2(() => {
|
|
1896
1957
|
const unsubscribe = pluginManager.subscribe(() => {
|
|
1897
1958
|
logger10.debug("Plugin state changed, refreshing UI...");
|
|
1898
1959
|
setPluginVersion((v) => v + 1);
|
|
@@ -1903,13 +1964,17 @@ var usePluginLoader = (options) => {
|
|
|
1903
1964
|
try {
|
|
1904
1965
|
const {
|
|
1905
1966
|
discoveryRules = [],
|
|
1967
|
+
modules = {},
|
|
1906
1968
|
registry: manualRegistry = {},
|
|
1907
1969
|
pluginConfigs,
|
|
1908
1970
|
sharedContext = {},
|
|
1909
1971
|
baseUrl = window.location.origin
|
|
1910
1972
|
} = options;
|
|
1911
1973
|
logger10.info("Starting to load plugins...");
|
|
1912
|
-
const discoveredRegistry =
|
|
1974
|
+
const discoveredRegistry = Object.keys(modules).length > 0 ? resolvePluginRegistry({
|
|
1975
|
+
modules,
|
|
1976
|
+
rules: discoveryRules.length > 0 ? discoveryRules : void 0
|
|
1977
|
+
}) : {};
|
|
1913
1978
|
const finalRegistry = { ...discoveredRegistry, ...manualRegistry };
|
|
1914
1979
|
if (options.systemConfig) {
|
|
1915
1980
|
const { configManager: configManager2 } = await import("./config-manager-ZARQENTB.mjs");
|
|
@@ -1940,6 +2005,7 @@ export {
|
|
|
1940
2005
|
ApiProvider,
|
|
1941
2006
|
AvatarSkeleton,
|
|
1942
2007
|
AxiosAdapter,
|
|
2008
|
+
BasePlugin,
|
|
1943
2009
|
BlockSkeleton,
|
|
1944
2010
|
ConfigManager,
|
|
1945
2011
|
DefaultEventBus,
|
|
@@ -1953,6 +2019,7 @@ export {
|
|
|
1953
2019
|
PluginRuntime,
|
|
1954
2020
|
PluginSandbox,
|
|
1955
2021
|
PluginSlot,
|
|
2022
|
+
ProxySandbox,
|
|
1956
2023
|
SUCCESS_CODE,
|
|
1957
2024
|
ScopedStorageAdapter,
|
|
1958
2025
|
ServiceRegistry,
|
|
@@ -1965,7 +2032,7 @@ export {
|
|
|
1965
2032
|
configManager,
|
|
1966
2033
|
createLogger,
|
|
1967
2034
|
dateUtils,
|
|
1968
|
-
|
|
2035
|
+
definePlugin,
|
|
1969
2036
|
isMockMode,
|
|
1970
2037
|
logger,
|
|
1971
2038
|
normalizeParams,
|