@chatbi-v/core 2.0.2 → 2.0.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.mjs CHANGED
@@ -1,2048 +1,12 @@
1
- import {
2
- ConfigManager,
3
- configManager
4
- } from "./chunk-G3OU7D3Y.mjs";
5
-
6
- // src/ports/plugin-port.ts
7
- var PLUGIN_TYPES = ["business", "functional", "view", "theme", "renderer", "system"];
8
- var Slot = {
9
- Sidebar: "sidebar",
10
- SidebarPanel: "sidebar-panel",
11
- Header: "header",
12
- StatusBar: "status-bar",
13
- Settings: "settings",
14
- MessageRenderer: "message-renderer",
15
- MessageContentRenderer: "message-content-renderer",
16
- SidebarSystem: "sidebar-system",
17
- SidebarBottom: "sidebar-bottom",
18
- RootLayout: "root-layout",
19
- Custom: "custom"
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
- }
38
-
39
- // src/utils/logger.ts
40
- var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
41
- LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
42
- LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
43
- LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
44
- LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
45
- LogLevel2[LogLevel2["NONE"] = 4] = "NONE";
46
- return LogLevel2;
47
- })(LogLevel || {});
48
- var Logger = class _Logger {
49
- /** 全局默认日志等级 */
50
- static level = 1 /* INFO */;
51
- /** 当前实例的前缀 */
52
- prefix;
53
- /**
54
- * 构造函数
55
- * @param prefix 日志前缀,默认为 'App'
56
- */
57
- constructor(prefix = "App") {
58
- this.prefix = prefix;
59
- }
60
- /**
61
- * 设置全局日志等级
62
- * @param level 日志等级
63
- */
64
- static setLevel(level) {
65
- this.level = level;
66
- console.info(`[Logger] Global log level set to: ${LogLevel[level]}`);
67
- }
68
- /**
69
- * 获取当前日志等级
70
- * @returns 当前全局日志等级
71
- */
72
- static getLevel() {
73
- return this.level;
74
- }
75
- /**
76
- * 打印 DEBUG 级别日志
77
- */
78
- get debug() {
79
- return _Logger.level <= 0 /* DEBUG */ ? console.debug.bind(console, `[${this.prefix}]`) : noop;
80
- }
81
- /**
82
- * 打印 INFO 级别日志
83
- */
84
- get info() {
85
- return _Logger.level <= 1 /* INFO */ ? console.info.bind(console, `[${this.prefix}]`) : noop;
86
- }
87
- /**
88
- * 打印 WARN 级别日志
89
- */
90
- get warn() {
91
- return _Logger.level <= 2 /* WARN */ ? console.warn.bind(console, `[${this.prefix}]`) : noop;
92
- }
93
- /**
94
- * 打印 ERROR 级别日志
95
- */
96
- get error() {
97
- return _Logger.level <= 3 /* ERROR */ ? console.error.bind(console, `[${this.prefix}]`) : noop;
98
- }
99
- /**
100
- * 开始一个日志分组
101
- * @param label 分组标签
102
- * @param collapsed 是否默认折叠,默认为 false
103
- */
104
- group(label, collapsed = false) {
105
- if (_Logger.level <= 1 /* INFO */) {
106
- if (collapsed) {
107
- console.groupCollapsed(`[${this.prefix}] ${label}`);
108
- } else {
109
- console.group(`[${this.prefix}] ${label}`);
110
- }
111
- }
112
- }
113
- /**
114
- * 结束当前日志分组
115
- */
116
- get groupEnd() {
117
- return _Logger.level <= 1 /* INFO */ ? console.groupEnd.bind(console) : noop;
118
- }
119
- };
120
- var noop = () => {
121
- };
122
- var logger = new Logger();
123
- var createLogger = (prefix) => new Logger(prefix);
124
-
125
- // src/application/service-registry.ts
126
- var logger2 = createLogger("ServiceRegistry");
127
- var ServiceRegistry = class {
128
- services = /* @__PURE__ */ new Map();
129
- listeners = /* @__PURE__ */ new Map();
130
- /**
131
- * 注册服务
132
- * @param name 服务名称 (建议格式: pluginId.serviceName)
133
- * @param service 服务实现
134
- */
135
- register(name, service) {
136
- if (this.services.has(name)) {
137
- logger2.warn(`\u670D\u52A1 "${name}" \u5DF2\u5B58\u5728\uFF0C\u5C06\u88AB\u8986\u76D6`);
138
- }
139
- this.services.set(name, service);
140
- logger2.info(`\u670D\u52A1\u5DF2\u6CE8\u518C: ${name}`);
141
- if (this.listeners.has(name)) {
142
- const set = this.listeners.get(name);
143
- set.forEach((callback) => callback(service));
144
- this.listeners.delete(name);
145
- }
146
- }
147
- /**
148
- * 获取服务
149
- * @param name 服务名称
150
- */
151
- get(name) {
152
- return this.services.get(name);
153
- }
154
- /**
155
- * 异步获取服务 (如果尚未注册则等待)
156
- * @param name 服务名称
157
- */
158
- async waitFor(name) {
159
- const service = this.services.get(name);
160
- if (service) return service;
161
- return new Promise((resolve) => {
162
- if (!this.listeners.has(name)) {
163
- this.listeners.set(name, /* @__PURE__ */ new Set());
164
- }
165
- this.listeners.get(name).add(resolve);
166
- });
167
- }
168
- /**
169
- * 注销服务
170
- * @param name 服务名称
171
- */
172
- unregister(name) {
173
- this.services.delete(name);
174
- logger2.info(`\u670D\u52A1\u5DF2\u6CE8\u9500: ${name}`);
175
- }
176
- /**
177
- * 清除所有服务 (通常在系统重置时使用)
178
- */
179
- clear() {
180
- this.services.clear();
181
- this.listeners.clear();
182
- }
183
- };
184
- var serviceRegistry = new ServiceRegistry();
185
-
186
- // src/api-context.tsx
187
- import { createContext, useContext } from "react";
188
- import { jsx } from "react/jsx-runtime";
189
- var ApiContext = createContext(null);
190
- var ApiProvider = ({ api, children }) => {
191
- return /* @__PURE__ */ jsx(ApiContext.Provider, { value: api, children });
192
- };
193
- var useApi = () => {
194
- const context = useContext(ApiContext);
195
- if (!context) {
196
- throw new Error("useApi must be used within an ApiProvider");
197
- }
198
- return context;
199
- };
200
-
201
- // src/components/PluginErrorBoundary.tsx
202
- import { Component } from "react";
203
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
204
- var logger3 = createLogger("PluginErrorBoundary");
205
- var PluginErrorBoundary = class extends Component {
206
- constructor(props) {
207
- super(props);
208
- this.state = { hasError: false, error: null };
209
- }
210
- static getDerivedStateFromError(error) {
211
- return { hasError: true, error };
212
- }
213
- componentDidCatch(error, errorInfo) {
214
- logger3.error(`\u63D2\u4EF6 ${this.props.pluginId || "\u672A\u77E5"} \u53D1\u751F\u9519\u8BEF:`, error, errorInfo);
215
- }
216
- handleRetry = () => {
217
- this.setState({ hasError: false, error: null });
218
- };
219
- render() {
220
- if (this.state.hasError) {
221
- if (this.props.fallback) {
222
- return this.props.fallback;
223
- }
224
- return /* @__PURE__ */ jsxs("div", { className: "p-4 border border-dashed border-red-500/50 rounded-lg bg-red-50 dark:bg-red-500/5 text-center", children: [
225
- /* @__PURE__ */ jsx2("div", { className: "text-red-500 font-medium mb-1", children: "\u63D2\u4EF6\u6E32\u67D3\u5931\u8D25" }),
226
- /* @__PURE__ */ jsxs("div", { className: "text-xs text-slate-500 dark:text-slate-400 mb-3", children: [
227
- "\u63D2\u4EF6 ",
228
- this.props.pluginId ? `"${this.props.pluginId}"` : "\u672A\u77E5",
229
- " \u53D1\u751F\u5F02\u5E38: ",
230
- this.state.error?.message
231
- ] }),
232
- /* @__PURE__ */ jsx2(
233
- "button",
234
- {
235
- onClick: this.handleRetry,
236
- className: "px-3 py-1.5 bg-red-500 hover:bg-red-600 text-white text-xs rounded transition-colors duration-150",
237
- children: "\u91CD\u8BD5"
238
- }
239
- )
240
- ] });
241
- }
242
- return this.props.children;
243
- }
244
- };
245
-
246
- // src/components/PluginSlot.tsx
247
- import { useMemo, useState, useEffect } from "react";
248
-
249
- // src/adapters/local-storage-adapter.ts
250
- var LocalStorageAdapter = class {
251
- prefix;
252
- constructor(prefix = "") {
253
- this.prefix = prefix;
254
- }
255
- getKey(key) {
256
- return this.prefix ? `${this.prefix}:${key}` : key;
257
- }
258
- getOriginalKey(namespacedKey) {
259
- if (!this.prefix) return namespacedKey;
260
- if (namespacedKey.startsWith(this.prefix + ":")) {
261
- return namespacedKey.slice(this.prefix.length + 1);
262
- }
263
- return null;
264
- }
265
- getItem(key) {
266
- return localStorage.getItem(this.getKey(key));
267
- }
268
- setItem(key, value) {
269
- localStorage.setItem(this.getKey(key), value);
270
- }
271
- removeItem(key) {
272
- localStorage.removeItem(this.getKey(key));
273
- }
274
- clear() {
275
- if (!this.prefix) {
276
- localStorage.clear();
277
- return;
278
- }
279
- const keysToRemove = [];
280
- for (let i = 0; i < localStorage.length; i++) {
281
- const key = localStorage.key(i);
282
- if (key && key.startsWith(this.prefix + ":")) {
283
- keysToRemove.push(key);
284
- }
285
- }
286
- keysToRemove.forEach((key) => localStorage.removeItem(key));
287
- }
288
- get length() {
289
- if (!this.prefix) return localStorage.length;
290
- let count = 0;
291
- for (let i = 0; i < localStorage.length; i++) {
292
- const key = localStorage.key(i);
293
- if (key && key.startsWith(this.prefix + ":")) {
294
- count++;
295
- }
296
- }
297
- return count;
298
- }
299
- key(index) {
300
- if (!this.prefix) return localStorage.key(index);
301
- let count = 0;
302
- for (let i = 0; i < localStorage.length; i++) {
303
- const key = localStorage.key(i);
304
- if (key && key.startsWith(this.prefix + ":")) {
305
- if (count === index) {
306
- return this.getOriginalKey(key);
307
- }
308
- count++;
309
- }
310
- }
311
- return null;
312
- }
313
- };
314
-
315
- // src/event-bus.ts
316
- var logger4 = createLogger("EventBus");
317
- var DefaultEventBus = class {
318
- listeners = /* @__PURE__ */ new Map();
319
- on(event, callback) {
320
- if (!this.listeners.has(event)) {
321
- this.listeners.set(event, []);
322
- }
323
- this.listeners.get(event)?.push(callback);
324
- return () => this.off(event, callback);
325
- }
326
- off(event, callback) {
327
- const callbacks = this.listeners.get(event);
328
- if (callbacks) {
329
- this.listeners.set(event, callbacks.filter((cb) => cb !== callback));
330
- }
331
- }
332
- emit(event, ...args) {
333
- const callbacks = this.listeners.get(event);
334
- if (callbacks) {
335
- callbacks.forEach((cb) => {
336
- try {
337
- cb(...args);
338
- } catch (error) {
339
- logger4.error(`\u4E8B\u4EF6\u76D1\u542C\u5668\u5904\u7406\u9519\u8BEF (${event}):`, error);
340
- }
341
- });
342
- }
343
- }
344
- once(event, callback) {
345
- const wrapper = (...args) => {
346
- callback(...args);
347
- this.off(event, wrapper);
348
- };
349
- this.on(event, wrapper);
350
- }
351
- };
352
-
353
- // src/sandbox/proxy-sandbox.ts
354
- var logger5 = createLogger("ProxySandbox");
355
- var ProxySandbox = class {
356
- /** 沙箱名称 */
357
- name;
358
- /** 代理后的 Window 对象 */
359
- proxy;
360
- /** 沙箱是否激活 */
361
- running = false;
362
- /** 记录新增/修改的全局变量 */
363
- updatedValueSet = /* @__PURE__ */ new Set();
364
- /** 副作用记录池 */
365
- effectPool = {
366
- timeouts: /* @__PURE__ */ new Set(),
367
- intervals: /* @__PURE__ */ new Set(),
368
- listeners: /* @__PURE__ */ new Map()
369
- };
370
- /** 真实的 Window 对象 */
371
- globalContext;
372
- /** 白名单全局变量(允许透传访问真实 Window) */
373
- static globalWhitelist = [
374
- "System",
375
- "console",
376
- // 'setTimeout', // 移除白名单,改为劫持
377
- // 'setInterval',
378
- // 'clearTimeout',
379
- // 'clearInterval',
380
- "requestAnimationFrame",
381
- "cancelAnimationFrame",
382
- // 'addEventListener', // 移除白名单,改为劫持
383
- // 'removeEventListener',
384
- "location",
385
- "history",
386
- "navigator",
387
- "document"
388
- ];
389
- constructor(name, globalContext = window) {
390
- this.name = name;
391
- this.globalContext = globalContext;
392
- const { fakeWindow, propertiesWithGetter } = this.createFakeWindow(globalContext);
393
- this.patchGlobalEffects(fakeWindow);
394
- const proxy = new Proxy(fakeWindow, {
395
- set: (target, p, value) => {
396
- if (this.running) {
397
- this.updatedValueSet.add(p);
398
- target[p] = value;
399
- return true;
400
- }
401
- logger5.warn(`${name} \u672A\u8FD0\u884C\uFF0C\u65E0\u6CD5\u8BBE\u7F6E\u5C5E\u6027 '${String(p)}'`);
402
- return false;
403
- },
404
- get: (target, p) => {
405
- if (p === Symbol.unscopables) return void 0;
406
- if (p === "window" || p === "self" || p === "globalThis") {
407
- return this.proxy;
408
- }
409
- if (p === "top" || p === "parent") {
410
- return this.globalContext[p];
411
- }
412
- const value = target[p];
413
- if (value !== void 0 || this.updatedValueSet.has(p)) {
414
- return value;
415
- }
416
- const rawValue = this.globalContext[p];
417
- if (typeof rawValue === "function" && !this.isConstructor(rawValue)) {
418
- if (this.isNativeFunction(rawValue)) {
419
- return rawValue.bind(this.globalContext);
420
- }
421
- }
422
- return rawValue;
423
- },
424
- has: (target, p) => {
425
- return p in target || p in this.globalContext;
426
- },
427
- defineProperty: (target, p, attributes) => {
428
- if (this.running) {
429
- this.updatedValueSet.add(p);
430
- return Reflect.defineProperty(target, p, attributes);
431
- }
432
- return false;
433
- }
434
- });
435
- this.proxy = proxy;
436
- }
437
- /**
438
- * 激活沙箱
439
- */
440
- active() {
441
- if (!this.running) {
442
- this.running = true;
443
- }
444
- }
445
- /**
446
- * 销毁沙箱
447
- */
448
- inactive() {
449
- this.running = false;
450
- this.effectPool.timeouts.forEach((id) => this.globalContext.clearTimeout(id));
451
- this.effectPool.timeouts.clear();
452
- this.effectPool.intervals.forEach((id) => this.globalContext.clearInterval(id));
453
- this.effectPool.intervals.clear();
454
- this.effectPool.listeners.forEach((listeners, type) => {
455
- listeners.forEach(({ listener, options }) => {
456
- this.globalContext.removeEventListener(type, listener, options);
457
- });
458
- });
459
- this.effectPool.listeners.clear();
460
- logger5.debug(`${this.name} \u5DF2\u505C\u7528\uFF0C\u526F\u4F5C\u7528\u5DF2\u6E05\u9664\u3002`);
461
- }
462
- /**
463
- * 在沙箱中执行代码
464
- * @param code JS 代码字符串
465
- * @returns 执行结果
466
- */
467
- eval(code) {
468
- const evalCode = `
1
+ import{a as $e,b as m}from"./chunk-O74KYN5N.mjs";var Te=["business","functional","view","theme","renderer","system"],ke={Sidebar:"sidebar",SidebarPanel:"sidebar-panel",Header:"header",StatusBar:"status-bar",Settings:"settings",MessageRenderer:"message-renderer",MessageContentRenderer:"message-content-renderer",SidebarSystem:"sidebar-system",SidebarBottom:"sidebar-bottom",RootLayout:"root-layout",Custom:"custom"},G=class{get id(){return this.metadata.id}};function Ae(g){return{...g,get id(){return this.metadata.id}}}var Y=(i=>(i[i.DEBUG=0]="DEBUG",i[i.INFO=1]="INFO",i[i.WARN=2]="WARN",i[i.ERROR=3]="ERROR",i[i.NONE=4]="NONE",i))(Y||{}),I=class g{static level=1;prefix;constructor(e="App"){this.prefix=e}static setLevel(e){this.level=e,console.info(`[Logger] Global log level set to: ${Y[e]}`)}static getLevel(){return this.level}get debug(){return g.level<=0?console.debug.bind(console,`[${this.prefix}]`):T}get info(){return g.level<=1?console.info.bind(console,`[${this.prefix}]`):T}get warn(){return g.level<=2?console.warn.bind(console,`[${this.prefix}]`):T}get error(){return g.level<=3?console.error.bind(console,`[${this.prefix}]`):T}group(e,t=!1){g.level<=1&&(t?console.groupCollapsed(`[${this.prefix}] ${e}`):console.group(`[${this.prefix}] ${e}`))}get groupEnd(){return g.level<=1?console.groupEnd.bind(console):T}},T=()=>{},Le=new I,f=g=>new I(g);var K=f("ServiceRegistry"),W=class{services=new Map;listeners=new Map;register(e,t){this.services.has(e)&&K.warn(`\u670D\u52A1 "${e}" \u5DF2\u5B58\u5728\uFF0C\u5C06\u88AB\u8986\u76D6`),this.services.set(e,t),K.info(`\u670D\u52A1\u5DF2\u6CE8\u518C: ${e}`),this.listeners.has(e)&&(this.listeners.get(e).forEach(n=>n(t)),this.listeners.delete(e))}get(e){return this.services.get(e)}async waitFor(e){let t=this.services.get(e);return t||new Promise(r=>{this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(r)})}unregister(e){this.services.delete(e),K.info(`\u670D\u52A1\u5DF2\u6CE8\u9500: ${e}`)}clear(){this.services.clear(),this.listeners.clear()}},k=new W;import{createContext as ge,useContext as le}from"react";import{jsx as ce}from"react/jsx-runtime";var z=ge(null),Ue=({api:g,children:e})=>ce(z.Provider,{value:g,children:e}),Be=()=>{let g=le(z);if(!g)throw new Error("useApi must be used within an ApiProvider");return g};import{Component as ue}from"react";import{jsx as J,jsxs as Q}from"react/jsx-runtime";var de=f("PluginErrorBoundary"),O=class extends ue{constructor(e){super(e),this.state={hasError:!1,error:null}}static getDerivedStateFromError(e){return{hasError:!0,error:e}}componentDidCatch(e,t){de.error(`\u63D2\u4EF6 ${this.props.pluginId||"\u672A\u77E5"} \u53D1\u751F\u9519\u8BEF:`,e,t)}handleRetry=()=>{this.setState({hasError:!1,error:null})};render(){return this.state.hasError?this.props.fallback?this.props.fallback:Q("div",{className:"p-4 border border-dashed border-red-500/50 rounded-lg bg-red-50 dark:bg-red-500/5 text-center",children:[J("div",{className:"text-red-500 font-medium mb-1",children:"\u63D2\u4EF6\u6E32\u67D3\u5931\u8D25"}),Q("div",{className:"text-xs text-slate-500 dark:text-slate-400 mb-3",children:["\u63D2\u4EF6 ",this.props.pluginId?`"${this.props.pluginId}"`:"\u672A\u77E5"," \u53D1\u751F\u5F02\u5E38: ",this.state.error?.message]}),J("button",{onClick:this.handleRetry,className:"px-3 py-1.5 bg-red-500 hover:bg-red-600 text-white text-xs rounded transition-colors duration-150",children:"\u91CD\u8BD5"})]}):this.props.children}};import{useMemo as X,useState as pe,useEffect as he}from"react";var N=class{prefix;constructor(e=""){this.prefix=e}getKey(e){return this.prefix?`${this.prefix}:${e}`:e}getOriginalKey(e){return this.prefix?e.startsWith(this.prefix+":")?e.slice(this.prefix.length+1):null:e}getItem(e){return localStorage.getItem(this.getKey(e))}setItem(e,t){localStorage.setItem(this.getKey(e),t)}removeItem(e){localStorage.removeItem(this.getKey(e))}clear(){if(!this.prefix){localStorage.clear();return}let e=[];for(let t=0;t<localStorage.length;t++){let r=localStorage.key(t);r&&r.startsWith(this.prefix+":")&&e.push(r)}e.forEach(t=>localStorage.removeItem(t))}get length(){if(!this.prefix)return localStorage.length;let e=0;for(let t=0;t<localStorage.length;t++){let r=localStorage.key(t);r&&r.startsWith(this.prefix+":")&&e++}return e}key(e){if(!this.prefix)return localStorage.key(e);let t=0;for(let r=0;r<localStorage.length;r++){let n=localStorage.key(r);if(n&&n.startsWith(this.prefix+":")){if(t===e)return this.getOriginalKey(n);t++}}return null}};var fe=f("EventBus"),F=class{listeners=new Map;on(e,t){return this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e)?.push(t),()=>this.off(e,t)}off(e,t){let r=this.listeners.get(e);r&&this.listeners.set(e,r.filter(n=>n!==t))}emit(e,...t){let r=this.listeners.get(e);r&&r.forEach(n=>{try{n(...t)}catch(i){fe.error(`\u4E8B\u4EF6\u76D1\u542C\u5668\u5904\u7406\u9519\u8BEF (${e}):`,i)}})}once(e,t){let r=(...n)=>{t(...n),this.off(e,r)};this.on(e,r)}};var Z=f("ProxySandbox"),j=class{name;proxy;running=!1;updatedValueSet=new Set;effectPool={timeouts:new Set,intervals:new Set,listeners:new Map};globalContext;static globalWhitelist=["System","console","requestAnimationFrame","cancelAnimationFrame","location","history","navigator","document"];constructor(e,t=window){this.name=e,this.globalContext=t;let{fakeWindow:r,propertiesWithGetter:n}=this.createFakeWindow(t);this.patchGlobalEffects(r);let i=new Proxy(r,{set:(a,s,o)=>this.running?(this.updatedValueSet.add(s),a[s]=o,!0):(Z.warn(`${e} \u672A\u8FD0\u884C\uFF0C\u65E0\u6CD5\u8BBE\u7F6E\u5C5E\u6027 '${String(s)}'`),!1),get:(a,s)=>{if(s===Symbol.unscopables)return;if(s==="window"||s==="self"||s==="globalThis")return this.proxy;if(s==="top"||s==="parent")return this.globalContext[s];let o=a[s];if(o!==void 0||this.updatedValueSet.has(s))return o;let l=this.globalContext[s];return typeof l=="function"&&!this.isConstructor(l)&&this.isNativeFunction(l)?l.bind(this.globalContext):l},has:(a,s)=>s in a||s in this.globalContext,defineProperty:(a,s,o)=>this.running?(this.updatedValueSet.add(s),Reflect.defineProperty(a,s,o)):!1});this.proxy=i}active(){this.running||(this.running=!0)}inactive(){this.running=!1,this.effectPool.timeouts.forEach(e=>this.globalContext.clearTimeout(e)),this.effectPool.timeouts.clear(),this.effectPool.intervals.forEach(e=>this.globalContext.clearInterval(e)),this.effectPool.intervals.clear(),this.effectPool.listeners.forEach((e,t)=>{e.forEach(({listener:r,options:n})=>{this.globalContext.removeEventListener(t,r,n)})}),this.effectPool.listeners.clear(),Z.debug(`${this.name} \u5DF2\u505C\u7528\uFF0C\u526F\u4F5C\u7528\u5DF2\u6E05\u9664\u3002`)}eval(e){let t=`
469
2
  ;(function(window, self, globalThis){
470
3
  with(window) {
471
- ${code}
4
+ ${e}
472
5
  }
473
6
  }).bind(window.proxy)(window.proxy, window.proxy, window.proxy);
474
- `;
475
- return (0, eval)(evalCode);
476
- }
477
- /**
478
- * 创建伪造的 Window 对象
479
- */
480
- createFakeWindow(globalContext) {
481
- const propertiesWithGetter = /* @__PURE__ */ new Map();
482
- const fakeWindow = {};
483
- Object.getOwnPropertyNames(globalContext).forEach((p) => {
484
- const descriptor = Object.getOwnPropertyDescriptor(globalContext, p);
485
- if (descriptor && !descriptor.configurable) {
486
- }
487
- });
488
- return { fakeWindow, propertiesWithGetter };
489
- }
490
- isConstructor(fn) {
491
- const prototype = fn.prototype;
492
- return !!(prototype && prototype.constructor === fn && Object.getOwnPropertyNames(prototype).length > 0);
493
- }
494
- isNativeFunction(fn) {
495
- return fn.toString().indexOf("[native code]") > -1;
496
- }
497
- /**
498
- * 劫持全局副作用 API
499
- */
500
- patchGlobalEffects(fakeWindow) {
501
- fakeWindow.setTimeout = (handler, timeout, ...args) => {
502
- const id = this.globalContext.setTimeout(handler, timeout, ...args);
503
- this.effectPool.timeouts.add(id);
504
- return id;
505
- };
506
- fakeWindow.clearTimeout = (id) => {
507
- if (id) {
508
- this.effectPool.timeouts.delete(id);
509
- this.globalContext.clearTimeout(id);
510
- }
511
- };
512
- fakeWindow.setInterval = (handler, timeout, ...args) => {
513
- const id = this.globalContext.setInterval(handler, timeout, ...args);
514
- this.effectPool.intervals.add(id);
515
- return id;
516
- };
517
- fakeWindow.clearInterval = (id) => {
518
- if (id) {
519
- this.effectPool.intervals.delete(id);
520
- this.globalContext.clearInterval(id);
521
- }
522
- };
523
- fakeWindow.addEventListener = (type, listener, options) => {
524
- const listeners = this.effectPool.listeners.get(type) || [];
525
- listeners.push({ listener, options });
526
- this.effectPool.listeners.set(type, listeners);
527
- return this.globalContext.addEventListener(type, listener, options);
528
- };
529
- fakeWindow.removeEventListener = (type, listener, options) => {
530
- const listeners = this.effectPool.listeners.get(type);
531
- if (listeners) {
532
- const index = listeners.findIndex((item) => item.listener === listener && item.options === options);
533
- if (index !== -1) listeners.splice(index, 1);
534
- }
535
- return this.globalContext.removeEventListener(type, listener, options);
536
- };
537
- }
538
- };
539
-
540
- // src/domain/plugin-sandbox.ts
541
- var PluginSandbox = class {
542
- pluginId;
543
- storageManager;
544
- constructor(pluginId, storageManager) {
545
- this.pluginId = pluginId;
546
- this.storageManager = storageManager;
547
- }
548
- /**
549
- * 获取隔离的存储接口
550
- */
551
- get storage() {
552
- return this.storageManager.getContextStorage(this.pluginId);
553
- }
554
- /**
555
- * 获取隔离的日志接口
556
- */
557
- get logger() {
558
- return createLogger(`Plugin:${this.pluginId}`);
559
- }
560
- };
561
-
562
- // src/domain/plugin-runtime.ts
563
- var logger6 = createLogger("PluginRuntime");
564
- var PluginRuntime = class {
565
- plugin;
566
- context;
567
- storageSandbox;
568
- windowSandbox;
569
- isLoaded = false;
570
- isMounted = false;
571
- constructor(plugin, sharedContext, storageManager) {
572
- this.plugin = plugin;
573
- this.storageSandbox = new PluginSandbox(plugin.id, storageManager);
574
- this.windowSandbox = new ProxySandbox(plugin.id);
575
- this.context = {
576
- pluginId: plugin.id,
577
- api: sharedContext.api,
578
- events: sharedContext.events,
579
- storage: this.storageSandbox.storage,
580
- logger: this.storageSandbox.logger,
581
- window: this.windowSandbox.proxy,
582
- getService: (name) => serviceRegistry.get(name),
583
- registerService: (name, service) => serviceRegistry.register(`${plugin.id}.${name}`, service)
584
- };
585
- }
586
- /**
587
- * 加载插件 (onLoad)
588
- * @description 注册服务、初始化非 UI 逻辑
589
- */
590
- async load() {
591
- if (this.isLoaded) return;
592
- logger6.debug(`\u6B63\u5728\u52A0\u8F7D\u63D2\u4EF6: ${this.plugin.id}`);
593
- try {
594
- if (this.plugin.metadata.api && this.context.api && typeof this.context.api.register === "function") {
595
- this.context.api.register(this.plugin.metadata.api);
596
- logger6.debug(`\u5DF2\u4E3A\u63D2\u4EF6 ${this.plugin.id} \u81EA\u52A8\u6CE8\u518C API \u914D\u7F6E`);
597
- }
598
- if (this.plugin.onLoad) {
599
- await this.plugin.onLoad(this.context);
600
- }
601
- this.isLoaded = true;
602
- logger6.info(`\u63D2\u4EF6 ${this.plugin.id} \u5DF2\u52A0\u8F7D\u3002`);
603
- } catch (error) {
604
- logger6.error(`\u63D2\u4EF6 ${this.plugin.id} \u52A0\u8F7D\u5931\u8D25:`, error);
605
- throw error;
606
- }
607
- }
608
- /**
609
- * 挂载插件 (onMount)
610
- * @description 激活沙箱、处理 UI 相关的副作用
611
- */
612
- async mount() {
613
- if (!this.isLoaded) await this.load();
614
- if (this.isMounted) return;
615
- logger6.debug(`\u6B63\u5728\u6302\u8F7D\u63D2\u4EF6: ${this.plugin.id}`);
616
- try {
617
- this.windowSandbox.active();
618
- if (this.plugin.onMount) {
619
- this.plugin.onMount(this.context);
620
- }
621
- this.isMounted = true;
622
- logger6.info(`\u63D2\u4EF6 ${this.plugin.id} \u5DF2\u6302\u8F7D\u3002`);
623
- } catch (error) {
624
- logger6.error(`\u63D2\u4EF6 ${this.plugin.id} \u6302\u8F7D\u5931\u8D25:`, error);
625
- throw error;
626
- }
627
- }
628
- /**
629
- * 卸载插件 (onUnmount)
630
- */
631
- async unmount() {
632
- if (!this.isMounted) return;
633
- logger6.debug(`\u6B63\u5728\u5378\u8F7D\u63D2\u4EF6: ${this.plugin.id}`);
634
- try {
635
- if (this.plugin.onUnmount) {
636
- this.plugin.onUnmount(this.context);
637
- }
638
- } catch (error) {
639
- logger6.error(`\u63D2\u4EF6 ${this.plugin.id} \u5378\u8F7D\u65F6\u51FA\u9519:`, error);
640
- } finally {
641
- this.windowSandbox.inactive();
642
- this.isMounted = false;
643
- logger6.info(`\u63D2\u4EF6 ${this.plugin.id} \u5DF2\u5378\u8F7D\u3002`);
644
- }
645
- }
646
- /**
647
- * 销毁插件 (完全移除)
648
- */
649
- async destroy() {
650
- await this.unmount();
651
- this.isLoaded = false;
652
- }
653
- get status() {
654
- if (this.isMounted) return "mounted";
655
- if (this.isLoaded) return "loaded";
656
- return "initial";
657
- }
658
- };
659
-
660
- // src/adapters/scoped-storage-adapter.ts
661
- var ScopedStorageAdapter = class {
662
- constructor(underlyingStorage, prefix) {
663
- this.underlyingStorage = underlyingStorage;
664
- this.prefix = prefix;
665
- }
666
- getKey(key) {
667
- return this.prefix ? `${this.prefix}:${key}` : key;
668
- }
669
- getOriginalKey(namespacedKey) {
670
- if (!this.prefix) return namespacedKey;
671
- if (namespacedKey.startsWith(this.prefix + ":")) {
672
- return namespacedKey.slice(this.prefix.length + 1);
673
- }
674
- return null;
675
- }
676
- getItem(key) {
677
- return this.underlyingStorage.getItem(this.getKey(key));
678
- }
679
- setItem(key, value) {
680
- this.underlyingStorage.setItem(this.getKey(key), value);
681
- }
682
- removeItem(key) {
683
- this.underlyingStorage.removeItem(this.getKey(key));
684
- }
685
- clear() {
686
- if (!this.prefix) {
687
- this.underlyingStorage.clear();
688
- return;
689
- }
690
- const keysToRemove = [];
691
- for (let i = 0; i < this.underlyingStorage.length; i++) {
692
- const key = this.underlyingStorage.key(i);
693
- if (key && key.startsWith(this.prefix + ":")) {
694
- keysToRemove.push(key);
695
- }
696
- }
697
- keysToRemove.forEach((k) => this.underlyingStorage.removeItem(k));
698
- }
699
- get length() {
700
- let count = 0;
701
- for (let i = 0; i < this.underlyingStorage.length; i++) {
702
- const key = this.underlyingStorage.key(i);
703
- if (key && key.startsWith(this.prefix + ":")) {
704
- count++;
705
- }
706
- }
707
- return count;
708
- }
709
- key(index) {
710
- let count = 0;
711
- for (let i = 0; i < this.underlyingStorage.length; i++) {
712
- const key = this.underlyingStorage.key(i);
713
- if (key && key.startsWith(this.prefix + ":")) {
714
- if (count === index) {
715
- return this.getOriginalKey(key);
716
- }
717
- count++;
718
- }
719
- }
720
- return null;
721
- }
722
- };
723
-
724
- // src/domain/storage-manager.ts
725
- var StorageManager = class {
726
- baseStorage;
727
- schemas = /* @__PURE__ */ new Map();
728
- constructor(baseStorage) {
729
- this.baseStorage = baseStorage;
730
- }
731
- /**
732
- * 注册插件存储 Schema
733
- */
734
- registerSchema(pluginId, schema) {
735
- this.schemas.set(pluginId, schema);
736
- }
737
- /**
738
- * 验证 Key 是否符合 Schema 定义 (仅在开发环境或严格模式下警告)
739
- */
740
- validateKey(pluginId, key, scope = "plugin") {
741
- const schemaList = this.schemas.get(pluginId);
742
- if (!schemaList) return;
743
- const item = schemaList.find((s) => s.key === key);
744
- if (!item) {
745
- console.warn(`[Storage] Key "${key}" not defined in plugin "${pluginId}" schema.`);
746
- return;
747
- }
748
- const definedScope = item.scope || "plugin";
749
- if (definedScope !== scope) {
750
- console.warn(`[Storage] Key "${key}" defined in scope "${definedScope}" but accessed via "${scope}".`);
751
- }
752
- }
753
- /**
754
- * 获取插件专用存储适配器
755
- * @param pluginId 插件 ID
756
- */
757
- getPluginStorage(pluginId) {
758
- return new ScopedStorageAdapter(this.baseStorage, `plugin:${pluginId}`);
759
- }
760
- /**
761
- * 获取共享存储适配器
762
- */
763
- getSharedStorage() {
764
- return new ScopedStorageAdapter(this.baseStorage, "shared");
765
- }
766
- /**
767
- * 获取系统存储适配器
768
- */
769
- getSystemStorage() {
770
- return new ScopedStorageAdapter(this.baseStorage, "system");
771
- }
772
- /**
773
- * 获取插件上下文中的 storage 对象 (包含类型转换辅助方法)
774
- * @param pluginId 插件 ID
775
- */
776
- getContextStorage(pluginId) {
777
- const pluginStorage = this.getPluginStorage(pluginId);
778
- const sharedStorage = this.getSharedStorage();
779
- const createHelpers = (adapter, scope) => ({
780
- get: (key) => {
781
- this.validateKey(pluginId, key, scope);
782
- try {
783
- const val = adapter.getItem(key);
784
- if (val !== null) {
785
- try {
786
- return JSON.parse(val);
787
- } catch {
788
- return val;
789
- }
790
- }
791
- if (scope === "plugin") {
792
- const externalConfig = configManager.get(pluginId);
793
- if (externalConfig && externalConfig[key] !== void 0) {
794
- return externalConfig[key];
795
- }
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;
802
- } catch (e) {
803
- console.warn(`[Storage] Failed to read key "${key}"`, e);
804
- return null;
805
- }
806
- },
807
- set: (key, value) => {
808
- this.validateKey(pluginId, key, scope);
809
- try {
810
- adapter.setItem(key, JSON.stringify(value));
811
- } catch (e) {
812
- console.warn(`[Storage] Failed to stringify key "${key}"`, e);
813
- }
814
- },
815
- remove: (key) => {
816
- this.validateKey(pluginId, key, scope);
817
- adapter.removeItem(key);
818
- }
819
- });
820
- return {
821
- ...createHelpers(pluginStorage, "plugin"),
822
- shared: createHelpers(sharedStorage, "shared")
823
- };
824
- }
825
- };
826
-
827
- // src/domain/plugin-manager.ts
828
- var logger7 = createLogger("PluginManager");
829
- var PluginManager = class {
830
- /** 全局事件总线 */
831
- eventBus = new DefaultEventBus();
832
- /** 存储接口 */
833
- storageManager;
834
- /** 所有插件运行时实例 */
835
- runtimes = /* @__PURE__ */ new Map();
836
- /** 所有注册的插件(原始数据) */
837
- plugins = /* @__PURE__ */ new Map();
838
- /** 收集的路由 */
839
- routes = [];
840
- /** 收集的扩展点 */
841
- extensions = /* @__PURE__ */ new Map();
842
- /** 插件状态管理(启用/禁用、排序) */
843
- pluginStates = {};
844
- /** 状态变更监听器 */
845
- listeners = /* @__PURE__ */ new Set();
846
- /** 共享上下文缓存 */
847
- sharedContext = null;
848
- /** 收集的工具函数 */
849
- utils = {};
850
- constructor(storage) {
851
- this.storageManager = new StorageManager(storage);
852
- this.loadStates();
853
- this.subscribe(() => {
854
- this.saveStates();
855
- });
856
- }
857
- loadStates() {
858
- try {
859
- const systemStorage = this.storageManager.getSystemStorage();
860
- const savedStates = systemStorage.getItem("plugin_states");
861
- if (savedStates) {
862
- this.pluginStates = JSON.parse(savedStates);
863
- logger7.debug("\u4ECE\u7CFB\u7EDF\u5B58\u50A8\u4E2D\u52A0\u8F7D\u72B6\u6001:", this.pluginStates);
864
- }
865
- } catch (e) {
866
- logger7.error("\u52A0\u8F7D\u63D2\u4EF6\u72B6\u6001\u5931\u8D25:", e);
867
- }
868
- }
869
- saveStates() {
870
- try {
871
- this.storageManager.getSystemStorage().setItem("plugin_states", JSON.stringify(this.pluginStates));
872
- logger7.debug("\u5DF2\u4FDD\u5B58\u63D2\u4EF6\u72B6\u6001\u5230\u5B58\u50A8");
873
- } catch (e) {
874
- logger7.error("\u4FDD\u5B58\u63D2\u4EF6\u72B6\u6001\u5931\u8D25:", e);
875
- }
876
- }
877
- /**
878
- * 订阅插件状态变更
879
- * @param listener 监听函数
880
- * @returns 取消订阅函数
881
- */
882
- subscribe(listener) {
883
- this.listeners.add(listener);
884
- return () => {
885
- this.listeners.delete(listener);
886
- };
887
- }
888
- getStorageManager() {
889
- return this.storageManager;
890
- }
891
- /**
892
- * 触发状态变更通知
893
- */
894
- notify() {
895
- this.listeners.forEach((listener) => listener());
896
- }
897
- /**
898
- * 获取所有已注册的插件
899
- */
900
- getPlugins() {
901
- const typePriority = {
902
- system: 0,
903
- theme: 1,
904
- renderer: 2,
905
- functional: 3,
906
- business: 4,
907
- view: 5
908
- };
909
- return Array.from(this.plugins.values()).sort((a, b) => {
910
- const priorityA = typePriority[a.metadata.type] ?? 99;
911
- const priorityB = typePriority[b.metadata.type] ?? 99;
912
- if (priorityA !== priorityB) {
913
- return priorityA - priorityB;
914
- }
915
- const stateA = this.pluginStates[a.id] || { order: 0 };
916
- const stateB = this.pluginStates[b.id] || { order: 0 };
917
- return stateA.order - stateB.order;
918
- });
919
- }
920
- /**
921
- * 获取插件状态
922
- * @param pluginId 插件 ID
923
- */
924
- getPluginState(pluginId) {
925
- return this.pluginStates[pluginId] || { enabled: true, order: 0 };
926
- }
927
- /**
928
- * 检查插件是否启用
929
- * @param pluginId 插件 ID
930
- */
931
- isPluginEnabled(pluginId) {
932
- const state = this.pluginStates[pluginId];
933
- return state ? state.enabled : true;
934
- }
935
- /**
936
- * 切换插件启用状态
937
- * @param pluginId 插件 ID
938
- * @param enabled 是否启用
939
- */
940
- togglePlugin(pluginId, enabled) {
941
- const state = this.pluginStates[pluginId] || { enabled: true, order: 0 };
942
- this.pluginStates[pluginId] = { ...state, enabled };
943
- if (!enabled) {
944
- const runtime = this.runtimes.get(pluginId);
945
- if (runtime) {
946
- runtime.unmount();
947
- this.runtimes.delete(pluginId);
948
- }
949
- } else {
950
- if (this.sharedContext) {
951
- const plugin = this.plugins.get(pluginId);
952
- if (plugin) {
953
- try {
954
- const runtime = new PluginRuntime(plugin, this.sharedContext, this.storageManager);
955
- this.runtimes.set(pluginId, runtime);
956
- runtime.mount();
957
- } catch (e) {
958
- logger7.error(`\u542F\u7528\u63D2\u4EF6 ${pluginId} \u5931\u8D25:`, e);
959
- }
960
- }
961
- }
962
- }
963
- this.notify();
964
- }
965
- /**
966
- * 设置插件排序
967
- * @param pluginId 插件 ID
968
- * @param order 排序值
969
- */
970
- setPluginOrder(pluginId, order) {
971
- const state = this.pluginStates[pluginId] || { enabled: true, order: 0 };
972
- this.pluginStates[pluginId] = { ...state, order };
973
- this.notify();
974
- }
975
- /**
976
- * 获取插件的统一能力描述
977
- * @param pluginId 插件 ID
978
- */
979
- getUnifiedCapabilities(pluginId) {
980
- const plugin = this.plugins.get(pluginId);
981
- return plugin?.metadata.capabilities || {};
982
- }
983
- /**
984
- * 更新插件配置
985
- * @param pluginId 插件 ID
986
- * @param key 配置项 Key
987
- * @param value 配置值
988
- */
989
- updatePluginConfig(pluginId, key, value) {
990
- const currentConfig = configManager.get(pluginId) || {};
991
- currentConfig[key] = value;
992
- configManager.set(pluginId, currentConfig);
993
- try {
994
- this.storageManager.getContextStorage(pluginId).set(key, value);
995
- } catch (e) {
996
- logger7.warn("\u4FDD\u5B58\u914D\u7F6E\u5230\u5B58\u50A8\u5931\u8D25", e);
997
- }
998
- this.eventBus.emit("config:changed", { pluginId, key, value });
999
- }
1000
- /**
1001
- * 获取插件配置
1002
- * @param pluginId 插件 ID
1003
- * @param key 配置键
1004
- * @returns 配置值
1005
- */
1006
- getPluginConfig(pluginId, key) {
1007
- const config = configManager.get(pluginId);
1008
- return config ? config[key] : void 0;
1009
- }
1010
- /**
1011
- * 获取系统全局配置 (非插件特定配置)
1012
- * @param key 配置键 (如 title, version)
1013
- */
1014
- getSystemConfig(key) {
1015
- const systemConfig = configManager.get("system");
1016
- return systemConfig ? systemConfig[key] : void 0;
1017
- }
1018
- /**
1019
- * 获取注册的服务
1020
- * @param name 服务名称
1021
- */
1022
- getService(name) {
1023
- return serviceRegistry.get(name);
1024
- }
1025
- /**
1026
- * 获取指定插槽的扩展
1027
- * @param slot 插槽位置
1028
- */
1029
- getExtensions(slot) {
1030
- const targetSlot = slot;
1031
- let extensions = this.extensions.get(targetSlot) || [];
1032
- extensions = extensions.filter((ext) => {
1033
- const pluginId = ext._pluginId;
1034
- return !pluginId || this.isPluginEnabled(pluginId);
1035
- });
1036
- return extensions.sort((a, b) => (a.order || 0) - (b.order || 0));
1037
- }
1038
- getRoutes() {
1039
- const activeRoutes = [];
1040
- this.getPlugins().forEach((plugin) => {
1041
- if (this.isPluginEnabled(plugin.id) && plugin.metadata.routes) {
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
- });
1053
- }
1054
- });
1055
- return activeRoutes;
1056
- }
1057
- /**
1058
- * 注册插件
1059
- * @param plugin 插件实例
1060
- * @param notify 是否触发状态变更通知
1061
- */
1062
- register(plugin, notify = true) {
1063
- if (!this.validatePlugin(plugin)) {
1064
- logger7.error(`\u63D2\u4EF6\u6CE8\u518C\u5931\u8D25: ${plugin?.id || "\u672A\u77E5"}`);
1065
- return;
1066
- }
1067
- if (this.plugins.has(plugin.id)) {
1068
- return;
1069
- }
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);
1084
- }
1085
- if (!this.pluginStates[plugin.id]) {
1086
- this.pluginStates[plugin.id] = { enabled: true, order: 0 };
1087
- }
1088
- const metadataDefaults = {};
1089
- const userOverrides = {};
1090
- const pluginStorage = this.storageManager.getPluginStorage(plugin.id);
1091
- if (plugin.metadata.configuration) {
1092
- plugin.metadata.configuration.forEach((item) => {
1093
- if (item.default !== void 0) {
1094
- metadataDefaults[item.key] = item.default;
1095
- }
1096
- try {
1097
- const saved = pluginStorage.getItem(item.key);
1098
- if (saved !== null) {
1099
- userOverrides[item.key] = JSON.parse(saved);
1100
- }
1101
- } catch (e) {
1102
- }
1103
- });
1104
- }
1105
- const mergedConfig = {
1106
- ...metadataDefaults,
1107
- ...plugin.defaultConfig,
1108
- ...configManager.get(plugin.id) || {},
1109
- ...userOverrides
1110
- };
1111
- configManager.set(plugin.id, mergedConfig);
1112
- switch (plugin.metadata.type) {
1113
- case "business":
1114
- this.handleBusinessPlugin(plugin);
1115
- break;
1116
- case "functional":
1117
- this.handleFunctionalPlugin(plugin);
1118
- break;
1119
- case "view":
1120
- this.handleViewPlugin(plugin);
1121
- break;
1122
- case "theme":
1123
- this.handleThemePlugin(plugin);
1124
- break;
1125
- case "system":
1126
- this.handleSystemPlugin(plugin);
1127
- break;
1128
- case "renderer":
1129
- break;
1130
- default:
1131
- logger7.warn(`\u63D2\u4EF6 ${plugin.id} \u7C7B\u578B\u672A\u77E5: ${plugin.metadata.type}`);
1132
- break;
1133
- }
1134
- if (plugin.metadata.routes && plugin.metadata.routes.length > 0) {
1135
- logger7.info(`\u5DF2\u4ECE\u63D2\u4EF6 ${plugin.id} \u6536\u96C6\u8DEF\u7531:`, plugin.metadata.routes);
1136
- }
1137
- if (plugin.metadata.extensions && plugin.metadata.extensions.length > 0) {
1138
- plugin.metadata.extensions.forEach((ext) => {
1139
- const list = this.extensions.get(ext.slot) || [];
1140
- list.push({ ...ext, _pluginId: plugin.id });
1141
- this.extensions.set(ext.slot, list);
1142
- });
1143
- logger7.info(`\u5DF2\u4ECE\u63D2\u4EF6 ${plugin.id} \u6536\u96C6\u6269\u5C55\u70B9`);
1144
- }
1145
- this.plugins.set(plugin.id, plugin);
1146
- logger7.info(`\u63D2\u4EF6 ${plugin.id} \u5DF2\u6CE8\u518C\u4E3A ${plugin.metadata.type}\u3002`);
1147
- if (notify) {
1148
- this.notify();
1149
- }
1150
- }
1151
- /**
1152
- * 初始化所有插件
1153
- * @param sharedContext 共享上下文
1154
- */
1155
- async initPlugins(sharedContext = {}) {
1156
- this.sharedContext = {
1157
- ...sharedContext,
1158
- events: this.eventBus
1159
- };
1160
- this.plugins.forEach((plugin) => {
1161
- if (!this.isPluginEnabled(plugin.id)) return;
1162
- if (!this.runtimes.has(plugin.id)) {
1163
- const runtime = new PluginRuntime(plugin, this.sharedContext, this.storageManager);
1164
- this.runtimes.set(plugin.id, runtime);
1165
- }
1166
- });
1167
- const sortedPluginIds = this.getSortedPluginIds();
1168
- for (const id of sortedPluginIds) {
1169
- const runtime = this.runtimes.get(id);
1170
- if (runtime) {
1171
- try {
1172
- console.log(`[PluginManager] invoking onLoad for ${id}`);
1173
- await runtime.load();
1174
- console.log(`[PluginManager] onLoad completed for ${id}`);
1175
- } catch (e) {
1176
- logger7.error(`\u63D2\u4EF6 ${id} \u52A0\u8F7D\u5931\u8D25:`, e);
1177
- }
1178
- }
1179
- }
1180
- for (const id of sortedPluginIds) {
1181
- const runtime = this.runtimes.get(id);
1182
- if (runtime) {
1183
- try {
1184
- await runtime.mount();
1185
- } catch (e) {
1186
- logger7.error(`\u63D2\u4EF6 ${id} \u6302\u8F7D\u5931\u8D25:`, e);
1187
- }
1188
- }
1189
- }
1190
- }
1191
- /**
1192
- * 获取排序后的插件 ID 列表 (处理依赖)
1193
- */
1194
- getSortedPluginIds() {
1195
- const ids = Array.from(this.runtimes.keys());
1196
- const visited = /* @__PURE__ */ new Set();
1197
- const sorted = [];
1198
- const visiting = /* @__PURE__ */ new Set();
1199
- const visit = (id) => {
1200
- if (visited.has(id)) return;
1201
- if (visiting.has(id)) {
1202
- logger7.error(`\u5FAA\u73AF\u4F9D\u8D56\u68C0\u6D4B\u5230: ${id}`);
1203
- return;
1204
- }
1205
- visiting.add(id);
1206
- const plugin = this.plugins.get(id);
1207
- if (plugin?.metadata.dependencies) {
1208
- plugin.metadata.dependencies.forEach((depId) => {
1209
- if (this.runtimes.has(depId)) {
1210
- visit(depId);
1211
- }
1212
- });
1213
- }
1214
- visiting.delete(id);
1215
- visited.add(id);
1216
- sorted.push(id);
1217
- };
1218
- const priorityMap = {
1219
- "system": 100,
1220
- "functional": 50,
1221
- "business": 10
1222
- };
1223
- const sortedIdsByType = [...ids].sort((a, b) => {
1224
- const pA = priorityMap[this.plugins.get(a)?.metadata.type || ""] || 0;
1225
- const pB = priorityMap[this.plugins.get(b)?.metadata.type || ""] || 0;
1226
- return pB - pA;
1227
- });
1228
- sortedIdsByType.forEach((id) => visit(id));
1229
- return sorted;
1230
- }
1231
- /**
1232
- * 加载插件列表
1233
- * @param configs 插件配置
1234
- * @param registry 插件注册表 (动态导入函数)
1235
- */
1236
- async loadPlugins(configs, registry) {
1237
- logger7.info("\u5F00\u59CB\u52A0\u8F7D\u63D2\u4EF6...");
1238
- const localLoadPromises = Object.entries(registry).map(async ([registryId, importFn]) => {
1239
- try {
1240
- const module = await importFn();
1241
- const config = configs[registryId];
1242
- const plugin = this.instantiatePlugin(registryId, module, config);
1243
- if (plugin && config) {
1244
- configManager.set(plugin.id, config);
1245
- }
1246
- return plugin;
1247
- } catch (e) {
1248
- logger7.error(`\u52A0\u8F7D\u672C\u5730\u63D2\u4EF6\u6A21\u5757 ${registryId} \u5931\u8D25:`, e);
1249
- return null;
1250
- }
1251
- });
1252
- const onlineLoadPromises = Object.entries(configs).filter(([id, config]) => config.url && !registry[id]).map(async ([pluginId, config]) => {
1253
- try {
1254
- const plugin = await this.loadRemotePlugin(pluginId, config.url, config);
1255
- if (plugin && config) {
1256
- configManager.set(plugin.id, config);
1257
- }
1258
- return plugin;
1259
- } catch (e) {
1260
- logger7.error(`\u52A0\u8F7D\u5728\u7EBF\u63D2\u4EF6 ${pluginId} \u5931\u8D25:`, e);
1261
- return null;
1262
- }
1263
- });
1264
- const loadedPlugins = await Promise.all([...localLoadPromises, ...onlineLoadPromises]);
1265
- loadedPlugins.forEach((plugin) => {
1266
- if (plugin) {
1267
- this.register(plugin, false);
1268
- }
1269
- });
1270
- this.notify();
1271
- logger7.info(`\u63D2\u4EF6\u52A0\u8F7D\u5B8C\u6210\uFF0C\u5171\u52A0\u8F7D ${this.plugins.size} \u4E2A\u63D2\u4EF6`);
1272
- }
1273
- /**
1274
- * 加载远程插件
1275
- * @param pluginId 插件 ID
1276
- * @param url 远程 URL
1277
- * @param config 插件配置
1278
- */
1279
- async loadRemotePlugin(pluginId, url, config) {
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
- }
1284
- try {
1285
- const dynamicImport = new Function("specifier", "return import(specifier)");
1286
- const module = await dynamicImport(url);
1287
- return this.instantiatePlugin(pluginId, module, config);
1288
- } catch (e) {
1289
- logger7.warn(`ESM \u52A0\u8F7D\u5931\u8D25\uFF0C\u5C1D\u8BD5 IIFE \u52A0\u8F7D: ${pluginId}`);
1290
- return this.loadIIFEPlugin(pluginId, url, config);
1291
- }
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
- }
1313
- /**
1314
- * 实例化插件
1315
- */
1316
- instantiatePlugin(pluginId, module, config) {
1317
- let PluginClass = module.default;
1318
- if (!PluginClass) {
1319
- const key = Object.keys(module).find((k) => k.endsWith("Plugin"));
1320
- if (key) PluginClass = module[key];
1321
- }
1322
- if (!PluginClass && typeof module === "object") {
1323
- if (module.id && module.metadata) {
1324
- PluginClass = module;
1325
- }
1326
- }
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
- }
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
- }
1339
- if (!pluginInstance.id && pluginInstance.metadata?.id) {
1340
- try {
1341
- pluginInstance.id = pluginInstance.metadata.id;
1342
- } catch (e) {
1343
- }
1344
- }
1345
- if (config) {
1346
- pluginInstance.defaultConfig = { ...pluginInstance.defaultConfig, ...config };
1347
- }
1348
- return pluginInstance;
1349
- }
1350
- logger7.warn(`\u6A21\u5757 ${pluginId} \u672A\u5BFC\u51FA\u6709\u6548\u7684\u63D2\u4EF6\u5165\u53E3`);
1351
- return null;
1352
- }
1353
- // --- Private Handlers ---
1354
- validatePlugin(plugin) {
1355
- if (!plugin.id) return false;
1356
- if (!plugin.metadata) return false;
1357
- return true;
1358
- }
1359
- handleBusinessPlugin(plugin) {
1360
- }
1361
- handleFunctionalPlugin(plugin) {
1362
- }
1363
- handleViewPlugin(plugin) {
1364
- }
1365
- handleThemePlugin(plugin) {
1366
- }
1367
- handleSystemPlugin(plugin) {
1368
- }
1369
- };
1370
- var pluginManager = new PluginManager(new LocalStorageAdapter());
1371
-
1372
- // src/components/PluginSlot.tsx
1373
- import { Fragment, jsx as jsx3 } from "react/jsx-runtime";
1374
- var PluginSlot = ({
1375
- slot,
1376
- props = {},
1377
- className,
1378
- style,
1379
- renderItem,
1380
- skeleton,
1381
- fallback
1382
- }) => {
1383
- const [, forceUpdate] = useState({});
1384
- useEffect(() => {
1385
- const unsubscribe = pluginManager.subscribe(() => {
1386
- forceUpdate({});
1387
- });
1388
- return unsubscribe;
1389
- }, []);
1390
- const extensions = pluginManager.getExtensions(slot);
1391
- const systemConfig = pluginManager.getSystemConfig("title") ? {
1392
- title: pluginManager.getSystemConfig("title"),
1393
- logo: pluginManager.getSystemConfig("logo"),
1394
- version: pluginManager.getSystemConfig("version")
1395
- } : void 0;
1396
- const mergedProps = useMemo(() => ({
1397
- ...props,
1398
- systemConfig
1399
- }), [props, systemConfig]);
1400
- const items = useMemo(() => {
1401
- return extensions.map((ext, index) => {
1402
- const Component2 = ext.component;
1403
- const key = ext.meta?.key || `${ext.slot}-${ext.order || 0}-${index}`;
1404
- return {
1405
- key,
1406
- extension: ext,
1407
- component: /* @__PURE__ */ jsx3(PluginErrorBoundary, { pluginId: `extension-${key}`, children: /* @__PURE__ */ jsx3(Component2, { ...mergedProps }) }, key)
1408
- };
1409
- });
1410
- }, [extensions, mergedProps]);
1411
- if (items.length === 0) {
1412
- if (fallback) {
1413
- return /* @__PURE__ */ jsx3(Fragment, { children: fallback });
1414
- }
1415
- if (skeleton) {
1416
- return /* @__PURE__ */ jsx3("div", { className: `plugin-slot plugin-slot-${slot} plugin-slot-skeleton ${className || ""}`, style, children: skeleton });
1417
- }
1418
- return null;
1419
- }
1420
- if (items.length === 1 && slot === "root-layout" && !className && !style && !renderItem) {
1421
- return /* @__PURE__ */ jsx3(Fragment, { children: items[0].component });
1422
- }
1423
- return /* @__PURE__ */ jsx3("div", { className: `plugin-slot plugin-slot-${slot} ${className || ""}`, style, children: renderItem ? items.map((item, index) => renderItem(item, index)) : items.map((item) => item.component) });
1424
- };
1425
-
1426
- // src/components/SlotSkeletons.tsx
1427
- import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1428
- var SidebarIconSkeleton = ({ expanded = false }) => /* @__PURE__ */ jsxs2("div", { className: `flex items-center transition-all duration-300 relative
1429
- ${expanded ? "w-full" : "w-12 justify-center"} px-3 h-11 rounded-xl`, children: [
1430
- /* @__PURE__ */ jsx4("div", { className: "w-6 h-6 bg-slate-200 dark:bg-white/10 rounded-lg shrink-0 animate-pulse" }),
1431
- expanded && /* @__PURE__ */ jsx4("div", { className: "ml-3 flex-1 h-4 bg-slate-200 dark:bg-white/10 rounded animate-pulse" })
1432
- ] });
1433
- var StatusBarItemSkeleton = () => /* @__PURE__ */ jsx4("div", { className: "h-4 w-16 bg-slate-200 dark:bg-white/10 rounded animate-pulse" });
1434
- var AvatarSkeleton = () => /* @__PURE__ */ jsx4("div", { className: "w-10 h-10 rounded-full bg-slate-200 dark:bg-white/10 animate-pulse" });
1435
- var BlockSkeleton = ({ className }) => /* @__PURE__ */ jsx4("div", { className: `bg-slate-200 dark:bg-white/10 rounded animate-pulse ${className || "w-full h-full"}` });
1436
-
1437
- // src/domain/auto-loader.ts
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
- ];
1445
- var resolvePluginRegistry = (options) => {
1446
- const { modules, rules = DEFAULT_RULES } = options;
1447
- const registry = {};
1448
- const compiledRules = rules.map((rule) => {
1449
- const escapedSegment = rule.pathSegment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1450
- return {
1451
- ...rule,
1452
- regex: new RegExp(`${escapedSegment}/([^/]+)/src/index`)
1453
- };
1454
- });
1455
- for (const path in modules) {
1456
- try {
1457
- let pluginId = null;
1458
- for (const rule of compiledRules) {
1459
- const match = path.match(rule.regex);
1460
- if (match && match[1]) {
1461
- pluginId = `${rule.idPrefix}-${match[1]}`;
1462
- logger8.info(`\u89E3\u6790\u8DEF\u5F84\u6210\u529F: ${path} -> ${pluginId}`);
1463
- break;
1464
- }
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
- }
1471
- } catch (e) {
1472
- logger8.error(`\u89E3\u6790\u63D2\u4EF6\u8DEF\u5F84\u5931\u8D25: ${path}`, e);
1473
- }
1474
- }
1475
- return registry;
1476
- };
7
+ `;return(0,eval)(t)}createFakeWindow(e){let t=new Map,r={};return Object.getOwnPropertyNames(e).forEach(n=>{let i=Object.getOwnPropertyDescriptor(e,n);i&&i.configurable}),{fakeWindow:r,propertiesWithGetter:t}}isConstructor(e){let t=e.prototype;return!!(t&&t.constructor===e&&Object.getOwnPropertyNames(t).length>0)}isNativeFunction(e){return e.toString().indexOf("[native code]")>-1}patchGlobalEffects(e){e.setTimeout=(t,r,...n)=>{let i=this.globalContext.setTimeout(t,r,...n);return this.effectPool.timeouts.add(i),i},e.clearTimeout=t=>{t&&(this.effectPool.timeouts.delete(t),this.globalContext.clearTimeout(t))},e.setInterval=(t,r,...n)=>{let i=this.globalContext.setInterval(t,r,...n);return this.effectPool.intervals.add(i),i},e.clearInterval=t=>{t&&(this.effectPool.intervals.delete(t),this.globalContext.clearInterval(t))},e.addEventListener=(t,r,n)=>{let i=this.effectPool.listeners.get(t)||[];return i.push({listener:r,options:n}),this.effectPool.listeners.set(t,i),this.globalContext.addEventListener(t,r,n)},e.removeEventListener=(t,r,n)=>{let i=this.effectPool.listeners.get(t);if(i){let a=i.findIndex(s=>s.listener===r&&s.options===n);a!==-1&&i.splice(a,1)}return this.globalContext.removeEventListener(t,r,n)}}};var U=class{pluginId;storageManager;constructor(e,t){this.pluginId=e,this.storageManager=t}get storage(){return this.storageManager.getContextStorage(this.pluginId)}get logger(){return f(`Plugin:${this.pluginId}`)}};var y=f("PluginRuntime"),A=class{plugin;context;storageSandbox;windowSandbox;isLoaded=!1;isMounted=!1;constructor(e,t,r){this.plugin=e,this.storageSandbox=new U(e.id,r),this.windowSandbox=new j(e.id),this.context={pluginId:e.id,api:t.api,events:t.events,storage:this.storageSandbox.storage,logger:this.storageSandbox.logger,window:this.windowSandbox.proxy,getService:n=>k.get(n),registerService:(n,i)=>k.register(`${e.id}.${n}`,i)}}async load(){if(!this.isLoaded){y.debug(`\u6B63\u5728\u52A0\u8F7D\u63D2\u4EF6: ${this.plugin.id}`);try{this.plugin.metadata.api&&this.context.api&&typeof this.context.api.register=="function"&&(this.context.api.register(this.plugin.metadata.api),y.debug(`\u5DF2\u4E3A\u63D2\u4EF6 ${this.plugin.id} \u81EA\u52A8\u6CE8\u518C API \u914D\u7F6E`)),this.plugin.onLoad&&await this.plugin.onLoad(this.context),this.isLoaded=!0,y.info(`\u63D2\u4EF6 ${this.plugin.id} \u5DF2\u52A0\u8F7D\u3002`)}catch(e){throw y.error(`\u63D2\u4EF6 ${this.plugin.id} \u52A0\u8F7D\u5931\u8D25:`,e),e}}}async mount(){if(this.isLoaded||await this.load(),!this.isMounted){y.debug(`\u6B63\u5728\u6302\u8F7D\u63D2\u4EF6: ${this.plugin.id}`);try{this.windowSandbox.active(),this.plugin.onMount&&this.plugin.onMount(this.context),this.isMounted=!0,y.info(`\u63D2\u4EF6 ${this.plugin.id} \u5DF2\u6302\u8F7D\u3002`)}catch(e){throw y.error(`\u63D2\u4EF6 ${this.plugin.id} \u6302\u8F7D\u5931\u8D25:`,e),e}}}async unmount(){if(this.isMounted){y.debug(`\u6B63\u5728\u5378\u8F7D\u63D2\u4EF6: ${this.plugin.id}`);try{this.plugin.onUnmount&&this.plugin.onUnmount(this.context)}catch(e){y.error(`\u63D2\u4EF6 ${this.plugin.id} \u5378\u8F7D\u65F6\u51FA\u9519:`,e)}finally{this.windowSandbox.inactive(),this.isMounted=!1,y.info(`\u63D2\u4EF6 ${this.plugin.id} \u5DF2\u5378\u8F7D\u3002`)}}}async destroy(){await this.unmount(),this.isLoaded=!1}get status(){return this.isMounted?"mounted":this.isLoaded?"loaded":"initial"}};var w=class{constructor(e,t){this.underlyingStorage=e;this.prefix=t}getKey(e){return this.prefix?`${this.prefix}:${e}`:e}getOriginalKey(e){return this.prefix?e.startsWith(this.prefix+":")?e.slice(this.prefix.length+1):null:e}getItem(e){return this.underlyingStorage.getItem(this.getKey(e))}setItem(e,t){this.underlyingStorage.setItem(this.getKey(e),t)}removeItem(e){this.underlyingStorage.removeItem(this.getKey(e))}clear(){if(!this.prefix){this.underlyingStorage.clear();return}let e=[];for(let t=0;t<this.underlyingStorage.length;t++){let r=this.underlyingStorage.key(t);r&&r.startsWith(this.prefix+":")&&e.push(r)}e.forEach(t=>this.underlyingStorage.removeItem(t))}get length(){let e=0;for(let t=0;t<this.underlyingStorage.length;t++){let r=this.underlyingStorage.key(t);r&&r.startsWith(this.prefix+":")&&e++}return e}key(e){let t=0;for(let r=0;r<this.underlyingStorage.length;r++){let n=this.underlyingStorage.key(r);if(n&&n.startsWith(this.prefix+":")){if(t===e)return this.getOriginalKey(n);t++}}return null}};var B=class{baseStorage;schemas=new Map;constructor(e){this.baseStorage=e}registerSchema(e,t){this.schemas.set(e,t)}validateKey(e,t,r="plugin"){let n=this.schemas.get(e);if(!n)return;let i=n.find(s=>s.key===t);if(!i){console.warn(`[Storage] Key "${t}" not defined in plugin "${e}" schema.`);return}let a=i.scope||"plugin";a!==r&&console.warn(`[Storage] Key "${t}" defined in scope "${a}" but accessed via "${r}".`)}getPluginStorage(e){return new w(this.baseStorage,`plugin:${e}`)}getSharedStorage(){return new w(this.baseStorage,"shared")}getSystemStorage(){return new w(this.baseStorage,"system")}getContextStorage(e){let t=this.getPluginStorage(e),r=this.getSharedStorage(),n=(i,a)=>({get:s=>{this.validateKey(e,s,a);try{let o=i.getItem(s);if(o!==null)try{return JSON.parse(o)}catch{return o}if(a==="plugin"){let c=m.get(e);if(c&&c[s]!==void 0)return c[s]}let l=this.schemas.get(e)?.find(c=>c.key===s);return l&&l.default!==void 0?l.default:null}catch(o){return console.warn(`[Storage] Failed to read key "${s}"`,o),null}},set:(s,o)=>{this.validateKey(e,s,a);try{i.setItem(s,JSON.stringify(o))}catch(l){console.warn(`[Storage] Failed to stringify key "${s}"`,l)}},remove:s=>{this.validateKey(e,s,a),i.removeItem(s)}});return{...n(t,"plugin"),shared:n(r,"shared")}}};var d=f("PluginManager"),V=class{eventBus=new F;storageManager;runtimes=new Map;plugins=new Map;routes=[];extensions=new Map;pluginStates={};listeners=new Set;sharedContext=null;utils={};constructor(e){this.storageManager=new B(e),this.loadStates(),this.subscribe(()=>{this.saveStates()})}loadStates(){try{let t=this.storageManager.getSystemStorage().getItem("plugin_states");t&&(this.pluginStates=JSON.parse(t),d.debug("\u4ECE\u7CFB\u7EDF\u5B58\u50A8\u4E2D\u52A0\u8F7D\u72B6\u6001:",this.pluginStates))}catch(e){d.error("\u52A0\u8F7D\u63D2\u4EF6\u72B6\u6001\u5931\u8D25:",e)}}saveStates(){try{this.storageManager.getSystemStorage().setItem("plugin_states",JSON.stringify(this.pluginStates)),d.debug("\u5DF2\u4FDD\u5B58\u63D2\u4EF6\u72B6\u6001\u5230\u5B58\u50A8")}catch(e){d.error("\u4FDD\u5B58\u63D2\u4EF6\u72B6\u6001\u5931\u8D25:",e)}}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}getStorageManager(){return this.storageManager}notify(){this.listeners.forEach(e=>e())}getPlugins(){let e={system:0,theme:1,renderer:2,functional:3,business:4,view:5};return Array.from(this.plugins.values()).sort((t,r)=>{let n=e[t.metadata.type]??99,i=e[r.metadata.type]??99;if(n!==i)return n-i;let a=this.pluginStates[t.id]||{order:0},s=this.pluginStates[r.id]||{order:0};return a.order-s.order})}getPluginState(e){return this.pluginStates[e]||{enabled:!0,order:0}}isPluginEnabled(e){let t=this.pluginStates[e];return t?t.enabled:!0}togglePlugin(e,t){let r=this.pluginStates[e]||{enabled:!0,order:0};if(this.pluginStates[e]={...r,enabled:t},t){if(this.sharedContext){let n=this.plugins.get(e);if(n)try{let i=new A(n,this.sharedContext,this.storageManager);this.runtimes.set(e,i),i.mount()}catch(i){d.error(`\u542F\u7528\u63D2\u4EF6 ${e} \u5931\u8D25:`,i)}}}else{let n=this.runtimes.get(e);n&&(n.unmount(),this.runtimes.delete(e))}this.notify()}setPluginOrder(e,t){let r=this.pluginStates[e]||{enabled:!0,order:0};this.pluginStates[e]={...r,order:t},this.notify()}getUnifiedCapabilities(e){return this.plugins.get(e)?.metadata.capabilities||{}}updatePluginConfig(e,t,r){let n=m.get(e)||{};n[t]=r,m.set(e,n);try{this.storageManager.getContextStorage(e).set(t,r)}catch(i){d.warn("\u4FDD\u5B58\u914D\u7F6E\u5230\u5B58\u50A8\u5931\u8D25",i)}this.eventBus.emit("config:changed",{pluginId:e,key:t,value:r})}getPluginConfig(e,t){let r=m.get(e);return r?r[t]:void 0}getSystemConfig(e){let t=m.get("system");return t?t[e]:void 0}getService(e){return k.get(e)}getExtensions(e){let t=e,r=this.extensions.get(t)||[];return r=r.filter(n=>{let i=n._pluginId;return!i||this.isPluginEnabled(i)}),r.sort((n,i)=>(n.order||0)-(i.order||0))}getRoutes(){let e=[];return this.getPlugins().forEach(t=>{if(this.isPluginEnabled(t.id)&&t.metadata.routes){let r=m.get(t.id)||{};t.metadata.routes.forEach(n=>{e.push({...n,meta:{...n.meta,pluginId:t.id,config:r}})})}}),e}register(e,t=!0){if(!this.validatePlugin(e)){d.error(`\u63D2\u4EF6\u6CE8\u518C\u5931\u8D25: ${e?.id||"\u672A\u77E5"}`);return}if(this.plugins.has(e.id))return;let r=[...e.metadata.storage||[],...e.metadata.configuration?.map(o=>({key:o.key,type:o.type==="select"?"string":o.type,label:o.label,description:o.description,default:o.default,scope:"plugin"}))||[]];r.length>0&&this.storageManager.registerSchema(e.id,r),this.pluginStates[e.id]||(this.pluginStates[e.id]={enabled:!0,order:0});let n={},i={},a=this.storageManager.getPluginStorage(e.id);e.metadata.configuration&&e.metadata.configuration.forEach(o=>{o.default!==void 0&&(n[o.key]=o.default);try{let l=a.getItem(o.key);l!==null&&(i[o.key]=JSON.parse(l))}catch{}});let s={...n,...e.defaultConfig,...m.get(e.id)||{},...i};switch(m.set(e.id,s),e.metadata.type){case"business":this.handleBusinessPlugin(e);break;case"functional":this.handleFunctionalPlugin(e);break;case"view":this.handleViewPlugin(e);break;case"theme":this.handleThemePlugin(e);break;case"system":this.handleSystemPlugin(e);break;case"renderer":break;default:d.warn(`\u63D2\u4EF6 ${e.id} \u7C7B\u578B\u672A\u77E5: ${e.metadata.type}`);break}e.metadata.routes&&e.metadata.routes.length>0&&d.info(`\u5DF2\u4ECE\u63D2\u4EF6 ${e.id} \u6536\u96C6\u8DEF\u7531:`,e.metadata.routes),e.metadata.extensions&&e.metadata.extensions.length>0&&(e.metadata.extensions.forEach(o=>{let l=this.extensions.get(o.slot)||[];l.push({...o,_pluginId:e.id}),this.extensions.set(o.slot,l)}),d.info(`\u5DF2\u4ECE\u63D2\u4EF6 ${e.id} \u6536\u96C6\u6269\u5C55\u70B9`)),this.plugins.set(e.id,e),d.info(`\u63D2\u4EF6 ${e.id} \u5DF2\u6CE8\u518C\u4E3A ${e.metadata.type}\u3002`),t&&this.notify()}async initPlugins(e={}){this.sharedContext={...e,events:this.eventBus},this.plugins.forEach(r=>{if(this.isPluginEnabled(r.id)&&!this.runtimes.has(r.id)){let n=new A(r,this.sharedContext,this.storageManager);this.runtimes.set(r.id,n)}});let t=this.getSortedPluginIds();for(let r of t){let n=this.runtimes.get(r);if(n)try{console.log(`[PluginManager] invoking onLoad for ${r}`),await n.load(),console.log(`[PluginManager] onLoad completed for ${r}`)}catch(i){d.error(`\u63D2\u4EF6 ${r} \u52A0\u8F7D\u5931\u8D25:`,i)}}for(let r of t){let n=this.runtimes.get(r);if(n)try{await n.mount()}catch(i){d.error(`\u63D2\u4EF6 ${r} \u6302\u8F7D\u5931\u8D25:`,i)}}}getSortedPluginIds(){let e=Array.from(this.runtimes.keys()),t=new Set,r=[],n=new Set,i=o=>{if(t.has(o))return;if(n.has(o)){d.error(`\u5FAA\u73AF\u4F9D\u8D56\u68C0\u6D4B\u5230: ${o}`);return}n.add(o);let l=this.plugins.get(o);l?.metadata.dependencies&&l.metadata.dependencies.forEach(c=>{this.runtimes.has(c)&&i(c)}),n.delete(o),t.add(o),r.push(o)},a={system:100,functional:50,business:10};return[...e].sort((o,l)=>{let c=a[this.plugins.get(o)?.metadata.type||""]||0;return(a[this.plugins.get(l)?.metadata.type||""]||0)-c}).forEach(o=>i(o)),r}async loadPlugins(e,t){d.info("\u5F00\u59CB\u52A0\u8F7D\u63D2\u4EF6...");let r=Object.entries(t).map(async([a,s])=>{try{let o=await s(),l=e[a],c=this.instantiatePlugin(a,o,l);return c&&l&&m.set(c.id,l),c}catch(o){return d.error(`\u52A0\u8F7D\u672C\u5730\u63D2\u4EF6\u6A21\u5757 ${a} \u5931\u8D25:`,o),null}}),n=Object.entries(e).filter(([a,s])=>s.url&&!t[a]).map(async([a,s])=>{try{let o=await this.loadRemotePlugin(a,s.url,s);return o&&s&&m.set(o.id,s),o}catch(o){return d.error(`\u52A0\u8F7D\u5728\u7EBF\u63D2\u4EF6 ${a} \u5931\u8D25:`,o),null}});(await Promise.all([...r,...n])).forEach(a=>{a&&this.register(a,!1)}),this.notify(),d.info(`\u63D2\u4EF6\u52A0\u8F7D\u5B8C\u6210\uFF0C\u5171\u52A0\u8F7D ${this.plugins.size} \u4E2A\u63D2\u4EF6`)}async loadRemotePlugin(e,t,r){if(d.info(`\u6B63\u5728\u4ECE ${t} \u52A0\u8F7D\u8FDC\u7A0B\u63D2\u4EF6 ${e}...`),r?.format==="iife")return this.loadIIFEPlugin(e,t,r);try{let i=await new Function("specifier","return import(specifier)")(t);return this.instantiatePlugin(e,i,r)}catch{return d.warn(`ESM \u52A0\u8F7D\u5931\u8D25\uFF0C\u5C1D\u8BD5 IIFE \u52A0\u8F7D: ${e}`),this.loadIIFEPlugin(e,t,r)}}loadIIFEPlugin(e,t,r){return new Promise((n,i)=>{let a=document.createElement("script");a.src=t,a.onload=()=>{let s=e.replace(/[^a-zA-Z0-9]/g,"_"),o=window[s];o?n(this.instantiatePlugin(e,o,r)):i(new Error(`\u8FDC\u7A0B\u63D2\u4EF6 ${e} \u52A0\u8F7D\u540E\u672A\u627E\u5230\u5168\u5C40\u53D8\u91CF ${s}`))},a.onerror=()=>i(new Error(`\u8FDC\u7A0B\u63D2\u4EF6 ${e} \u52A0\u8F7D\u5931\u8D25: ${t}`)),document.head.appendChild(a)})}instantiatePlugin(e,t,r){let n=t.default;if(!n){let i=Object.keys(t).find(a=>a.endsWith("Plugin"));i&&(n=t[i])}if(!n&&typeof t=="object"&&t.id&&t.metadata&&(n=t),n){typeof n=="function"&&n.prototype&&d.warn(`\u63D2\u4EF6 ${e} \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`);let a=typeof n=="function"?new n:n;if(!(e.includes("/")&&(e.includes(".ts")||e.includes(".tsx")))&&e&&a.metadata&&a.metadata.id!==e&&(a.metadata.id=e),!a.id&&a.metadata?.id)try{a.id=a.metadata.id}catch{}return r&&(a.defaultConfig={...a.defaultConfig,...r}),a}return d.warn(`\u6A21\u5757 ${e} \u672A\u5BFC\u51FA\u6709\u6548\u7684\u63D2\u4EF6\u5165\u53E3`),null}validatePlugin(e){return!(!e.id||!e.metadata)}handleBusinessPlugin(e){}handleFunctionalPlugin(e){}handleViewPlugin(e){}handleThemePlugin(e){}handleSystemPlugin(e){}},h=new V(new N);import{Fragment as ee,jsx as C}from"react/jsx-runtime";var wt=({slot:g,props:e={},className:t,style:r,renderItem:n,skeleton:i,fallback:a})=>{let[,s]=pe({});he(()=>h.subscribe(()=>{s({})}),[]);let o=h.getExtensions(g),l=h.getSystemConfig("title")?{title:h.getSystemConfig("title"),logo:h.getSystemConfig("logo"),version:h.getSystemConfig("version")}:void 0,c=X(()=>({...e,systemConfig:l}),[e,l]),u=X(()=>o.map((p,v)=>{let L=p.component,S=p.meta?.key||`${p.slot}-${p.order||0}-${v}`;return{key:S,extension:p,component:C(O,{pluginId:`extension-${S}`,children:C(L,{...c})},S)}}),[o,c]);return u.length===0?a?C(ee,{children:a}):i?C("div",{className:`plugin-slot plugin-slot-${g} plugin-slot-skeleton ${t||""}`,style:r,children:i}):null:u.length===1&&g==="root-layout"&&!t&&!r&&!n?C(ee,{children:u[0].component}):C("div",{className:`plugin-slot plugin-slot-${g} ${t||""}`,style:r,children:n?u.map((p,v)=>n(p,v)):u.map(p=>p.component)})};import{jsx as M,jsxs as me}from"react/jsx-runtime";var Et=({expanded:g=!1})=>me("div",{className:`flex items-center transition-all duration-300 relative
8
+ ${g?"w-full":"w-12 justify-center"} px-3 h-11 rounded-xl`,children:[M("div",{className:"w-6 h-6 bg-slate-200 dark:bg-white/10 rounded-lg shrink-0 animate-pulse"}),g&&M("div",{className:"ml-3 flex-1 h-4 bg-slate-200 dark:bg-white/10 rounded animate-pulse"})]}),$t=()=>M("div",{className:"h-4 w-16 bg-slate-200 dark:bg-white/10 rounded animate-pulse"}),Tt=()=>M("div",{className:"w-10 h-10 rounded-full bg-slate-200 dark:bg-white/10 animate-pulse"}),kt=({className:g})=>M("div",{className:`bg-slate-200 dark:bg-white/10 rounded animate-pulse ${g||"w-full h-full"}`});var H=f("AutoLoader"),ye=[{pathSegment:"@chatbi-plugins",idPrefix:"@chatbi-v/plugin"},{pathSegment:"@chatbi-apps",idPrefix:"@chatbi-v/app"},{pathSegment:"packages/plugins",idPrefix:"@chatbi-v/plugin"},{pathSegment:"packages/apps",idPrefix:"@chatbi-v/app"}],te=g=>{let{modules:e,rules:t=ye}=g,r={},n=t.map(i=>{let a=i.pathSegment.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return{...i,regex:new RegExp(`${a}/([^/]+)/src/index`)}});for(let i in e)try{let a=null;for(let s of n){let o=i.match(s.regex);if(o&&o[1]){a=`${s.idPrefix}-${o[1]}`,H.info(`\u89E3\u6790\u8DEF\u5F84\u6210\u529F: ${i} -> ${a}`);break}}a?r[a]=e[i]:H.warn(`\u65E0\u6CD5\u4ECE\u8DEF\u5F84\u89E3\u6790\u63D2\u4EF6 ID: ${i}\uFF0C\u8BF7\u68C0\u67E5\u662F\u5426\u7B26\u5408\u547D\u540D\u7EA6\u5B9A\u3002`)}catch(a){H.error(`\u89E3\u6790\u63D2\u4EF6\u8DEF\u5F84\u5931\u8D25: ${i}`,a)}return r};var re="000000";import{createContext as ve,useContext as xe}from"react";import{jsx as Se}from"react/jsx-runtime";var ne=ve(null),jt=({manager:g,children:e})=>Se(ne.Provider,{value:g,children:e}),Ut=()=>{let g=xe(ne);if(!g)throw new Error("usePluginManager must be used within a PluginProvider");return g};import Pe from"axios";var D=class{client;constructor(e="/api",t=1e4){this.client=Pe.create({baseURL:e,timeout:t}),this.client.interceptors.response.use(r=>r,r=>Promise.reject(r))}async request(e){return this.client.request(e)}async stream(e,t,r){let{onMessage:n,onError:i,onFinish:a}=t;try{let s=this.client.defaults.baseURL||"",o=e.url;if(o&&!o.startsWith("http")&&s){let b=s.endsWith("/")?s.slice(0,-1):s,E=o.startsWith("/")?o:`/${o}`;o=`${b}${E}`}if(e.params){let b=new URLSearchParams;Object.entries(e.params).forEach(([E,$])=>{$!==void 0&&b.append(E,String($))}),o+=(o.includes("?")?"&":"?")+b.toString()}let l={...this.client.defaults.headers.common||{},"Content-Type":"application/json",...e.headers||{}},c=this.client.defaults.headers;c.Authorization&&(l.Authorization=c.Authorization),c["x-token"]&&(l["x-token"]=c["x-token"]);let{signal:u,...p}=e,v=await fetch(o,{method:e.method,headers:l,body:e.data?JSON.stringify(e.data):void 0,signal:u});if(!v.ok)throw new Error(`HTTP error! status: ${v.status}`);if(!v.body)throw new Error("\u54CD\u5E94\u4F53\u4E3A\u7A7A");let L=v.body.getReader(),S=new TextDecoder,P="";for(;;){let{done:b,value:E}=await L.read();if(b)break;P+=S.decode(E,{stream:!0});let $=P.split(`
1477
9
 
1478
- // src/domain/models.ts
1479
- var SUCCESS_CODE = "000000";
10
+ `);P=$.pop()||"";for(let ae of $)n&&n(ae+`
1480
11
 
1481
- // src/plugin-context.tsx
1482
- import { createContext as createContext2, useContext as useContext2 } from "react";
1483
- import { jsx as jsx5 } from "react/jsx-runtime";
1484
- var PluginContext = createContext2(null);
1485
- var PluginProvider = ({ manager, children }) => {
1486
- return /* @__PURE__ */ jsx5(PluginContext.Provider, { value: manager, children });
1487
- };
1488
- var usePluginManager = () => {
1489
- const context = useContext2(PluginContext);
1490
- if (!context) {
1491
- throw new Error("usePluginManager must be used within a PluginProvider");
1492
- }
1493
- return context;
1494
- };
1495
-
1496
- // src/api/adapters/axios-adapter.ts
1497
- import axios from "axios";
1498
- var AxiosAdapter = class {
1499
- client;
1500
- constructor(baseURL = "/api", timeout = 1e4) {
1501
- this.client = axios.create({
1502
- baseURL,
1503
- timeout
1504
- });
1505
- this.client.interceptors.response.use(
1506
- (response) => response,
1507
- (error) => Promise.reject(error)
1508
- );
1509
- }
1510
- async request(config) {
1511
- return this.client.request(config);
1512
- }
1513
- async stream(config, callbacks, endpointConfig) {
1514
- const { onMessage, onError, onFinish } = callbacks;
1515
- try {
1516
- const baseURL = this.client.defaults.baseURL || "";
1517
- let url = config.url;
1518
- if (url && !url.startsWith("http") && baseURL) {
1519
- const cleanBase = baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL;
1520
- const cleanUrl = url.startsWith("/") ? url : `/${url}`;
1521
- url = `${cleanBase}${cleanUrl}`;
1522
- }
1523
- if (config.params) {
1524
- const params = new URLSearchParams();
1525
- Object.entries(config.params).forEach(([key, value]) => {
1526
- if (value !== void 0) params.append(key, String(value));
1527
- });
1528
- url += (url.includes("?") ? "&" : "?") + params.toString();
1529
- }
1530
- const headers = {
1531
- ...this.client.defaults.headers.common || {},
1532
- "Content-Type": "application/json",
1533
- ...config.headers || {}
1534
- };
1535
- const defaultHeaders = this.client.defaults.headers;
1536
- if (defaultHeaders.Authorization) {
1537
- headers["Authorization"] = defaultHeaders.Authorization;
1538
- }
1539
- if (defaultHeaders["x-token"]) {
1540
- headers["x-token"] = defaultHeaders["x-token"];
1541
- }
1542
- const { signal, ...otherConfig } = config;
1543
- const response = await fetch(url, {
1544
- method: config.method,
1545
- headers,
1546
- body: config.data ? JSON.stringify(config.data) : void 0,
1547
- signal
1548
- });
1549
- if (!response.ok) {
1550
- throw new Error(`HTTP error! status: ${response.status}`);
1551
- }
1552
- if (!response.body) {
1553
- throw new Error("\u54CD\u5E94\u4F53\u4E3A\u7A7A");
1554
- }
1555
- const reader = response.body.getReader();
1556
- const decoder = new TextDecoder();
1557
- let buffer = "";
1558
- while (true) {
1559
- const { done, value } = await reader.read();
1560
- if (done) break;
1561
- buffer += decoder.decode(value, { stream: true });
1562
- const parts = buffer.split("\n\n");
1563
- buffer = parts.pop() || "";
1564
- for (const part of parts) {
1565
- if (onMessage) {
1566
- onMessage(part + "\n\n");
1567
- }
1568
- }
1569
- }
1570
- if (buffer && onMessage) {
1571
- onMessage(buffer);
1572
- }
1573
- if (onFinish) onFinish();
1574
- } catch (error) {
1575
- if (onError) onError(error);
1576
- }
1577
- }
1578
- };
1579
-
1580
- // src/api/engine.ts
1581
- var logger9 = createLogger("ApiEngine");
1582
- var ApiEngine = class {
1583
- adapter;
1584
- config = {};
1585
- interceptors = [];
1586
- constructor(adapter) {
1587
- this.adapter = adapter || new AxiosAdapter();
1588
- }
1589
- /**
1590
- * 注册拦截器
1591
- */
1592
- registerInterceptor(interceptor) {
1593
- this.interceptors.push(interceptor);
1594
- }
1595
- /**
1596
- * 移除拦截器
1597
- */
1598
- unregisterInterceptor(interceptor) {
1599
- this.interceptors = this.interceptors.filter((i) => i !== interceptor);
1600
- }
1601
- /**
1602
- * 切换请求适配器
1603
- * @param adapter 新的适配器实例
1604
- */
1605
- useAdapter(adapter) {
1606
- this.adapter = adapter;
1607
- }
1608
- /**
1609
- * 注册 API 配置
1610
- * @param config 配置对象
1611
- */
1612
- register(config) {
1613
- logger9.info("\u6B63\u5728\u6CE8\u518C API \u914D\u7F6E:", Object.keys(config));
1614
- this.config = { ...this.config, ...config };
1615
- }
1616
- /**
1617
- * 获取接口配置
1618
- */
1619
- getEndpoint(module, action) {
1620
- return this.config[module]?.[action];
1621
- }
1622
- /**
1623
- * 发起 API 请求
1624
- * @param module 模块名
1625
- * @param action 动作名
1626
- * @param data 请求数据 (Body 或 Query)
1627
- * @param options 请求选项
1628
- */
1629
- async call(module, action, data, options = {}) {
1630
- const endpoint = this.getEndpoint(module, action);
1631
- if (!endpoint) {
1632
- logger9.warn(`\u672A\u627E\u5230 API \u5B9A\u4E49: ${module}.${action} (\u5F53\u524D\u5DF2\u6CE8\u518C\u6A21\u5757: ${Object.keys(this.config).join(", ")})`);
1633
- return Promise.resolve(void 0);
1634
- }
1635
- let requestConfig = await this.prepareRequestConfig(endpoint, data, options);
1636
- let response;
1637
- try {
1638
- response = await this.adapter.request(requestConfig, endpoint);
1639
- } catch (error) {
1640
- if (error.response) {
1641
- response = error.response;
1642
- } else {
1643
- throw error;
1644
- }
1645
- }
1646
- if (this.interceptors.length > 0) {
1647
- const context = this.createInterceptorContext(response, requestConfig);
1648
- for (const interceptor of this.interceptors) {
1649
- if (interceptor.interceptResponse) {
1650
- const hijacked = await interceptor.interceptResponse(context);
1651
- if (hijacked) {
1652
- logger9.info("\u8BF7\u6C42\u88AB\u62E6\u622A\u5668\u52AB\u6301:", module, action);
1653
- return void 0;
1654
- }
1655
- }
1656
- }
1657
- }
1658
- if (response && response.status && (response.status < 200 || response.status >= 300)) {
1659
- const responseData2 = this.isAxiosResponse(response) ? response.data : response;
1660
- const isBaseResponse = this.isBaseResponse(responseData2);
1661
- if (!isBaseResponse) {
1662
- throw new Error(`Request failed with status ${response.status}`);
1663
- }
1664
- }
1665
- const responseData = this.isAxiosResponse(response) ? response.data : response;
1666
- if (this.isBaseResponse(responseData)) {
1667
- const res = responseData;
1668
- const code = String(res.code);
1669
- const isSuccess = code === SUCCESS_CODE || code === "200" || code === "0";
1670
- if (!isSuccess) {
1671
- const strategy = endpoint.errorStrategy || "reject";
1672
- if (strategy === "reject") {
1673
- logger9.error(`API \u8BF7\u6C42\u4E1A\u52A1\u9519\u8BEF (${module}.${action}):`, res.message);
1674
- throw new Error(res.message || `Request failed with code ${code}`);
1675
- }
1676
- }
1677
- }
1678
- return responseData;
1679
- }
1680
- /**
1681
- * 发起流式请求
1682
- * @param module 模块名
1683
- * @param action 动作名
1684
- * @param data 请求数据
1685
- * @param options 请求选项
1686
- */
1687
- async stream(module, action, data, options = {}) {
1688
- const endpoint = this.getEndpoint(module, action);
1689
- if (!endpoint) {
1690
- logger9.warn(`\u672A\u627E\u5230 API \u5B9A\u4E49: ${module}.${action}\uFF0C\u8DF3\u8FC7\u6D41\u5F0F\u8BF7\u6C42\u3002`);
1691
- return;
1692
- }
1693
- if (!this.adapter.stream) {
1694
- logger9.warn("\u5F53\u524D API \u9002\u914D\u5668\u4E0D\u652F\u6301\u6D41\u5F0F\u4F20\u8F93\u3002");
1695
- return;
1696
- }
1697
- const requestConfig = await this.prepareRequestConfig(endpoint, data, options);
1698
- const callbacks = {
1699
- onMessage: options.onMessage,
1700
- onError: options.onError,
1701
- onFinish: options.onFinish
1702
- };
1703
- await this.adapter.stream(requestConfig, callbacks, endpoint);
1704
- }
1705
- /**
1706
- * 准备请求配置,应用 URL 参数替换和拦截器
1707
- */
1708
- async prepareRequestConfig(endpoint, data, options) {
1709
- let url = endpoint.url;
1710
- const pathParams = options.params || {};
1711
- url = url.replace(/:([a-zA-Z0-9_]+)/g, (_, key) => {
1712
- if (pathParams[key] !== void 0) return String(pathParams[key]);
1713
- if (data && typeof data === "object" && data[key] !== void 0) return String(data[key]);
1714
- return `:${key}`;
1715
- });
1716
- const method = endpoint.method;
1717
- let requestConfig = {
1718
- ...options,
1719
- url,
1720
- method
1721
- };
1722
- if (method === "GET" || method === "DELETE") {
1723
- requestConfig.params = data;
1724
- } else {
1725
- requestConfig.data = data;
1726
- }
1727
- if (this.interceptors.length > 0) {
1728
- for (const interceptor of this.interceptors) {
1729
- if (interceptor.interceptRequest) {
1730
- requestConfig = await interceptor.interceptRequest(requestConfig);
1731
- }
1732
- }
1733
- }
1734
- return requestConfig;
1735
- }
1736
- /**
1737
- * 判断是否为 BaseResponse
1738
- */
1739
- isBaseResponse(data) {
1740
- return data && typeof data === "object" && "code" in data && ("message" in data || "data" in data);
1741
- }
1742
- /**
1743
- * 严格判断是否为 AxiosResponse
1744
- */
1745
- isAxiosResponse(res) {
1746
- return res && typeof res === "object" && "data" in res && "status" in res && "headers" in res;
1747
- }
1748
- /**
1749
- * 创建拦截上下文
1750
- */
1751
- createInterceptorContext(response, config) {
1752
- if (response && typeof response === "object" && "status" in response && "headers" in response) {
1753
- return {
1754
- response,
1755
- status: response.status,
1756
- headers: response.headers,
1757
- data: response.data,
1758
- config
1759
- };
1760
- }
1761
- return {
1762
- response,
1763
- status: 200,
1764
- headers: {},
1765
- data: response,
1766
- config
1767
- };
1768
- }
1769
- };
1770
- var apiEngine = new ApiEngine();
1771
-
1772
- // src/utils/url.ts
1773
- function normalizeParams(strategy = "last") {
1774
- if (typeof window === "undefined") return new URLSearchParams();
1775
- const { search, hash } = window.location;
1776
- const searchParams = new URLSearchParams(search);
1777
- const hashParams = new URLSearchParams(hash.split("?")[1] || "");
1778
- const entries = [];
1779
- searchParams.forEach((v, k) => entries.push([k, v, "search"]));
1780
- hashParams.forEach((v, k) => entries.push([k, v, "hash"]));
1781
- const keeper = /* @__PURE__ */ new Map();
1782
- if (strategy === "first") {
1783
- entries.forEach(([k, v]) => {
1784
- if (!keeper.has(k)) keeper.set(k, v);
1785
- });
1786
- } else if (strategy === "last") {
1787
- entries.forEach(([k, v]) => keeper.set(k, v));
1788
- } else if (strategy === "search") {
1789
- entries.forEach(([k, v, src]) => {
1790
- if (src === "search") keeper.set(k, v);
1791
- });
1792
- hashParams.forEach((v, k) => {
1793
- if (!keeper.has(k)) keeper.set(k, v);
1794
- });
1795
- } else if (strategy === "hash") {
1796
- entries.forEach(([k, v, src]) => {
1797
- if (src === "hash") keeper.set(k, v);
1798
- });
1799
- searchParams.forEach((v, k) => {
1800
- if (!keeper.has(k)) keeper.set(k, v);
1801
- });
1802
- }
1803
- return new URLSearchParams(Array.from(keeper.entries()));
1804
- }
1805
- function cleanUrlParams(keysToRemove) {
1806
- if (typeof window === "undefined") return "";
1807
- const { pathname, search, hash } = window.location;
1808
- const searchParams = new URLSearchParams(search);
1809
- keysToRemove.forEach((key) => searchParams.delete(key));
1810
- const newSearch = searchParams.toString();
1811
- const hashParts = hash.split("?");
1812
- const hashPath = hashParts[0];
1813
- const hashQuery = hashParts[1] || "";
1814
- const hashParams = new URLSearchParams(hashQuery);
1815
- keysToRemove.forEach((key) => hashParams.delete(key));
1816
- const newHashQuery = hashParams.toString();
1817
- const newHash = hashPath + (newHashQuery ? "?" + newHashQuery : "");
1818
- return pathname + (newSearch ? "?" + newSearch : "") + newHash;
1819
- }
1820
-
1821
- // src/api/utils.ts
1822
- var mergeMockData = (def, mock) => {
1823
- const merged = JSON.parse(JSON.stringify(def));
1824
- Object.keys(mock).forEach((key) => {
1825
- if (merged[key]) {
1826
- merged[key] = {
1827
- ...merged[key],
1828
- ...mock[key]
1829
- };
1830
- }
1831
- });
1832
- return merged;
1833
- };
1834
- function isMockMode() {
1835
- const envMock = typeof process !== "undefined" && process.env.VITE_USE_MOCK === "true" || typeof window !== "undefined" && window.VITE_USE_MOCK === "true";
1836
- if (typeof window !== "undefined") {
1837
- const params = normalizeParams();
1838
- const mockParam = params.get("mock");
1839
- if (mockParam === "true") return true;
1840
- if (mockParam === "false") return false;
1841
- }
1842
- return envMock;
1843
- }
1844
- function resolveApiModules(definitionsMap, mocksMap = {}) {
1845
- const config = {};
1846
- const getNamespace = (path) => {
1847
- const fileName = path.split("/").pop() || "";
1848
- return fileName.replace(/\.mock\.(ts|js|tsx|jsx|json)$/, "").replace(/\.(ts|js|tsx|jsx|json)$/, "");
1849
- };
1850
- Object.entries(definitionsMap).forEach(([path, module]) => {
1851
- if (path.includes(".mock.")) return;
1852
- const namespace = getNamespace(path);
1853
- if (!namespace || !module.default) return;
1854
- let apiDef = module.default;
1855
- const mockEntry = Object.entries(mocksMap).find(([mockPath]) => {
1856
- return getNamespace(mockPath) === namespace && mockPath.includes(".mock.");
1857
- });
1858
- if (mockEntry) {
1859
- const mockModule = mockEntry[1];
1860
- const mockData = mockModule.default || mockModule;
1861
- if (mockData) {
1862
- apiDef = mergeMockData(apiDef, mockData);
1863
- }
1864
- }
1865
- config[namespace] = apiDef;
1866
- });
1867
- return config;
1868
- }
1869
-
1870
- // src/utils/date.ts
1871
- import dayjs from "dayjs";
1872
- import relativeTime from "dayjs/plugin/relativeTime";
1873
- import "dayjs/locale/zh-cn";
1874
- dayjs.extend(relativeTime);
1875
- dayjs.locale("zh-cn");
1876
- var dateUtils = {
1877
- /**
1878
- * 格式化日期为 YYYY-MM-DD
1879
- */
1880
- formatDate(date) {
1881
- return dayjs(date).format("YYYY-MM-DD");
1882
- },
1883
- /**
1884
- * 格式化时间为 HH:mm:ss
1885
- */
1886
- formatTime(date) {
1887
- return dayjs(date).format("HH:mm:ss");
1888
- },
1889
- /**
1890
- * 格式化日期时间为 YYYY-MM-DD HH:mm:ss
1891
- */
1892
- formatDateTime(date) {
1893
- return dayjs(date).format("YYYY-MM-DD HH:mm:ss");
1894
- },
1895
- /**
1896
- * 获取当前时间戳(毫秒)
1897
- */
1898
- now() {
1899
- return dayjs().valueOf();
1900
- },
1901
- /**
1902
- * 获取相对时间(例如:几分钟前)
1903
- */
1904
- fromNow(date) {
1905
- return dayjs(date).fromNow();
1906
- },
1907
- /**
1908
- * 原始 dayjs 对象,用于更复杂的场景
1909
- */
1910
- dayjs
1911
- };
1912
-
1913
- // src/utils/index.ts
1914
- var version = "1.0.0";
1915
-
1916
- // src/hooks/use-storage-state.ts
1917
- import { useCallback, useState as useState2 } from "react";
1918
- function useStorageState(pluginId, key, options = {}) {
1919
- const { defaultValue, scope = "plugin" } = options;
1920
- const storageManager = pluginManager.getStorageManager();
1921
- const getStorage = useCallback(() => {
1922
- const contextStorage = storageManager.getContextStorage(pluginId);
1923
- return scope === "shared" ? contextStorage.shared : contextStorage;
1924
- }, [pluginId, scope, storageManager]);
1925
- const [state, setState] = useState2(() => {
1926
- try {
1927
- if (typeof window === "undefined") return defaultValue;
1928
- const storage = getStorage();
1929
- const val = storage.get(key);
1930
- return val !== null ? val : defaultValue;
1931
- } catch (e) {
1932
- console.warn(`[useStorageState] Error reading key "${key}"`, e);
1933
- return defaultValue;
1934
- }
1935
- });
1936
- const setValue = useCallback((value) => {
1937
- try {
1938
- const valueToStore = value instanceof Function ? value(state) : value;
1939
- setState(valueToStore);
1940
- const storage = getStorage();
1941
- storage.set(key, valueToStore);
1942
- } catch (error) {
1943
- console.warn(`[useStorageState] Error setting key "${key}":`, error);
1944
- }
1945
- }, [key, state, getStorage]);
1946
- return [state, setValue];
1947
- }
1948
-
1949
- // src/hooks/use-plugin-loader.ts
1950
- import { useEffect as useEffect2, useRef, useState as useState3 } from "react";
1951
- var logger10 = createLogger("PluginLoader");
1952
- var usePluginLoader = (options) => {
1953
- const [pluginsLoaded, setPluginsLoaded] = useState3(false);
1954
- const [pluginVersion, setPluginVersion] = useState3(0);
1955
- const loadingRef = useRef(false);
1956
- useEffect2(() => {
1957
- const unsubscribe = pluginManager.subscribe(() => {
1958
- logger10.debug("Plugin state changed, refreshing UI...");
1959
- setPluginVersion((v) => v + 1);
1960
- });
1961
- const load = async () => {
1962
- if (loadingRef.current || pluginsLoaded) return;
1963
- loadingRef.current = true;
1964
- try {
1965
- const {
1966
- discoveryRules = [],
1967
- modules = {},
1968
- registry: manualRegistry = {},
1969
- pluginConfigs,
1970
- sharedContext = {},
1971
- baseUrl = window.location.origin
1972
- } = options;
1973
- logger10.info("Starting to load plugins...");
1974
- const discoveredRegistry = Object.keys(modules).length > 0 ? resolvePluginRegistry({
1975
- modules,
1976
- rules: discoveryRules.length > 0 ? discoveryRules : void 0
1977
- }) : {};
1978
- const finalRegistry = { ...discoveredRegistry, ...manualRegistry };
1979
- if (options.systemConfig) {
1980
- const { configManager: configManager2 } = await import("./config-manager-ZARQENTB.mjs");
1981
- configManager2.set("system", options.systemConfig);
1982
- }
1983
- await pluginManager.loadPlugins(pluginConfigs, finalRegistry);
1984
- await pluginManager.initPlugins(sharedContext);
1985
- setPluginsLoaded(true);
1986
- logger10.info("Plugins loaded successfully");
1987
- } catch (error) {
1988
- logger10.error("Failed to load plugins:", error);
1989
- } finally {
1990
- loadingRef.current = false;
1991
- }
1992
- };
1993
- load();
1994
- return () => {
1995
- unsubscribe();
1996
- };
1997
- }, []);
1998
- return {
1999
- pluginsLoaded,
2000
- pluginVersion
2001
- };
2002
- };
2003
- export {
2004
- ApiEngine,
2005
- ApiProvider,
2006
- AvatarSkeleton,
2007
- AxiosAdapter,
2008
- BasePlugin,
2009
- BlockSkeleton,
2010
- ConfigManager,
2011
- DefaultEventBus,
2012
- LocalStorageAdapter,
2013
- LogLevel,
2014
- Logger,
2015
- PLUGIN_TYPES,
2016
- PluginErrorBoundary,
2017
- PluginManager,
2018
- PluginProvider,
2019
- PluginRuntime,
2020
- PluginSandbox,
2021
- PluginSlot,
2022
- ProxySandbox,
2023
- SUCCESS_CODE,
2024
- ScopedStorageAdapter,
2025
- ServiceRegistry,
2026
- SidebarIconSkeleton,
2027
- Slot,
2028
- StatusBarItemSkeleton,
2029
- StorageManager,
2030
- apiEngine,
2031
- cleanUrlParams,
2032
- configManager,
2033
- createLogger,
2034
- dateUtils,
2035
- definePlugin,
2036
- isMockMode,
2037
- logger,
2038
- normalizeParams,
2039
- pluginManager,
2040
- resolveApiModules,
2041
- resolvePluginRegistry,
2042
- serviceRegistry,
2043
- useApi,
2044
- usePluginLoader,
2045
- usePluginManager,
2046
- useStorageState,
2047
- version
2048
- };
12
+ `)}P&&n&&n(P),a&&a()}catch(s){i&&i(s)}}};var R=f("ApiEngine"),_=class{adapter;config={};interceptors=[];constructor(e){this.adapter=e||new D}registerInterceptor(e){this.interceptors.push(e)}unregisterInterceptor(e){this.interceptors=this.interceptors.filter(t=>t!==e)}useAdapter(e){this.adapter=e}register(e){R.info("\u6B63\u5728\u6CE8\u518C API \u914D\u7F6E:",Object.keys(e)),this.config={...this.config,...e}}getEndpoint(e,t){return this.config[e]?.[t]}async call(e,t,r,n={}){let i=this.getEndpoint(e,t);if(!i)return R.warn(`\u672A\u627E\u5230 API \u5B9A\u4E49: ${e}.${t} (\u5F53\u524D\u5DF2\u6CE8\u518C\u6A21\u5757: ${Object.keys(this.config).join(", ")})`),Promise.resolve(void 0);let a=await this.prepareRequestConfig(i,r,n),s;try{s=await this.adapter.request(a,i)}catch(l){if(l.response)s=l.response;else throw l}if(this.interceptors.length>0){let l=this.createInterceptorContext(s,a);for(let c of this.interceptors)if(c.interceptResponse&&await c.interceptResponse(l)){R.info("\u8BF7\u6C42\u88AB\u62E6\u622A\u5668\u52AB\u6301:",e,t);return}}if(s&&s.status&&(s.status<200||s.status>=300)){let l=this.isAxiosResponse(s)?s.data:s;if(!this.isBaseResponse(l))throw new Error(`Request failed with status ${s.status}`)}let o=this.isAxiosResponse(s)?s.data:s;if(this.isBaseResponse(o)){let l=o,c=String(l.code);if(!(c===re||c==="200"||c==="0")&&(i.errorStrategy||"reject")==="reject")throw R.error(`API \u8BF7\u6C42\u4E1A\u52A1\u9519\u8BEF (${e}.${t}):`,l.message),new Error(l.message||`Request failed with code ${c}`)}return o}async stream(e,t,r,n={}){let i=this.getEndpoint(e,t);if(!i){R.warn(`\u672A\u627E\u5230 API \u5B9A\u4E49: ${e}.${t}\uFF0C\u8DF3\u8FC7\u6D41\u5F0F\u8BF7\u6C42\u3002`);return}if(!this.adapter.stream){R.warn("\u5F53\u524D API \u9002\u914D\u5668\u4E0D\u652F\u6301\u6D41\u5F0F\u4F20\u8F93\u3002");return}let a=await this.prepareRequestConfig(i,r,n),s={onMessage:n.onMessage,onError:n.onError,onFinish:n.onFinish};await this.adapter.stream(a,s,i)}async prepareRequestConfig(e,t,r){let n=e.url,i=r.params||{};n=n.replace(/:([a-zA-Z0-9_]+)/g,(o,l)=>i[l]!==void 0?String(i[l]):t&&typeof t=="object"&&t[l]!==void 0?String(t[l]):`:${l}`);let a=e.method,s={...r,url:n,method:a};if(a==="GET"||a==="DELETE"?s.params=t:s.data=t,this.interceptors.length>0)for(let o of this.interceptors)o.interceptRequest&&(s=await o.interceptRequest(s));return s}isBaseResponse(e){return e&&typeof e=="object"&&"code"in e&&("message"in e||"data"in e)}isAxiosResponse(e){return e&&typeof e=="object"&&"data"in e&&"status"in e&&"headers"in e}createInterceptorContext(e,t){return e&&typeof e=="object"&&"status"in e&&"headers"in e?{response:e,status:e.status,headers:e.headers,data:e.data,config:t}:{response:e,status:200,headers:{},data:e,config:t}}},Yt=new _;function ie(g="last"){if(typeof window>"u")return new URLSearchParams;let{search:e,hash:t}=window.location,r=new URLSearchParams(e),n=new URLSearchParams(t.split("?")[1]||""),i=[];r.forEach((s,o)=>i.push([o,s,"search"])),n.forEach((s,o)=>i.push([o,s,"hash"]));let a=new Map;return g==="first"?i.forEach(([s,o])=>{a.has(s)||a.set(s,o)}):g==="last"?i.forEach(([s,o])=>a.set(s,o)):g==="search"?(i.forEach(([s,o,l])=>{l==="search"&&a.set(s,o)}),n.forEach((s,o)=>{a.has(o)||a.set(o,s)})):g==="hash"&&(i.forEach(([s,o,l])=>{l==="hash"&&a.set(s,o)}),r.forEach((s,o)=>{a.has(o)||a.set(o,s)})),new URLSearchParams(Array.from(a.entries()))}function Jt(g){if(typeof window>"u")return"";let{pathname:e,search:t,hash:r}=window.location,n=new URLSearchParams(t);g.forEach(p=>n.delete(p));let i=n.toString(),a=r.split("?"),s=a[0],o=a[1]||"",l=new URLSearchParams(o);g.forEach(p=>l.delete(p));let c=l.toString(),u=s+(c?"?"+c:"");return e+(i?"?"+i:"")+u}var be=(g,e)=>{let t=JSON.parse(JSON.stringify(g));return Object.keys(e).forEach(r=>{t[r]&&(t[r]={...t[r],...e[r]})}),t};function Xt(){let g=typeof process<"u"&&process.env.VITE_USE_MOCK==="true"||typeof window<"u"&&window.VITE_USE_MOCK==="true";if(typeof window<"u"){let t=ie().get("mock");if(t==="true")return!0;if(t==="false")return!1}return g}function er(g,e={}){let t={},r=n=>(n.split("/").pop()||"").replace(/\.mock\.(ts|js|tsx|jsx|json)$/,"").replace(/\.(ts|js|tsx|jsx|json)$/,"");return Object.entries(g).forEach(([n,i])=>{if(n.includes(".mock."))return;let a=r(n);if(!a||!i.default)return;let s=i.default,o=Object.entries(e).find(([l])=>r(l)===a&&l.includes(".mock."));if(o){let l=o[1],c=l.default||l;c&&(s=be(s,c))}t[a]=s}),t}import x from"dayjs";import we from"dayjs/plugin/relativeTime";import"dayjs/locale/zh-cn";x.extend(we);x.locale("zh-cn");var dr={formatDate(g){return x(g).format("YYYY-MM-DD")},formatTime(g){return x(g).format("HH:mm:ss")},formatDateTime(g){return x(g).format("YYYY-MM-DD HH:mm:ss")},now(){return x().valueOf()},fromNow(g){return x(g).fromNow()},dayjs:x};var pr="1.0.0";import{useCallback as se,useState as Ce}from"react";function Pr(g,e,t={}){let{defaultValue:r,scope:n="plugin"}=t,i=h.getStorageManager(),a=se(()=>{let c=i.getContextStorage(g);return n==="shared"?c.shared:c},[g,n,i]),[s,o]=Ce(()=>{try{if(typeof window>"u")return r;let u=a().get(e);return u!==null?u:r}catch(c){return console.warn(`[useStorageState] Error reading key "${e}"`,c),r}}),l=se(c=>{try{let u=c instanceof Function?c(s):c;o(u),a().set(e,u)}catch(u){console.warn(`[useStorageState] Error setting key "${e}":`,u)}},[e,s,a]);return[s,l]}import{useEffect as Re,useRef as Ee,useState as oe}from"react";var q=f("PluginLoader"),$r=g=>{let[e,t]=oe(!1),[r,n]=oe(0),i=Ee(!1);return Re(()=>{let a=h.subscribe(()=>{q.debug("Plugin state changed, refreshing UI..."),n(o=>o+1)});return(async()=>{if(!(i.current||e)){i.current=!0;try{let{discoveryRules:o=[],modules:l={},registry:c={},pluginConfigs:u,sharedContext:p={},baseUrl:v=window.location.origin}=g;q.info("Starting to load plugins...");let S={...Object.keys(l).length>0?te({modules:l,rules:o.length>0?o:void 0}):{},...c};if(g.systemConfig){let{configManager:P}=await import("./config-manager-LQITPSUA.mjs");P.set("system",g.systemConfig)}await h.loadPlugins(u,S),await h.initPlugins(p),t(!0),q.info("Plugins loaded successfully")}catch(o){q.error("Failed to load plugins:",o)}finally{i.current=!1}}})(),()=>{a()}},[]),{pluginsLoaded:e,pluginVersion:r}};export{_ as ApiEngine,Ue as ApiProvider,Tt as AvatarSkeleton,D as AxiosAdapter,G as BasePlugin,kt as BlockSkeleton,$e as ConfigManager,F as DefaultEventBus,N as LocalStorageAdapter,Y as LogLevel,I as Logger,Te as PLUGIN_TYPES,O as PluginErrorBoundary,V as PluginManager,jt as PluginProvider,A as PluginRuntime,U as PluginSandbox,wt as PluginSlot,j as ProxySandbox,re as SUCCESS_CODE,w as ScopedStorageAdapter,W as ServiceRegistry,Et as SidebarIconSkeleton,ke as Slot,$t as StatusBarItemSkeleton,B as StorageManager,Yt as apiEngine,Jt as cleanUrlParams,m as configManager,f as createLogger,dr as dateUtils,Ae as definePlugin,Xt as isMockMode,Le as logger,ie as normalizeParams,h as pluginManager,er as resolveApiModules,te as resolvePluginRegistry,k as serviceRegistry,Be as useApi,$r as usePluginLoader,Ut as usePluginManager,Pr as useStorageState,pr as version};