@chatbi-v/core 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/adapters/local-storage-adapter.d.ts +13 -0
- package/dist/adapters/scoped-storage-adapter.d.ts +18 -0
- package/dist/api/adapters/axios-adapter.d.ts +10 -0
- package/dist/api/engine.d.ts +41 -0
- package/dist/api/index.d.ts +6 -0
- package/dist/api/utils.d.ts +14 -0
- package/dist/api-context.d.ts +8 -0
- package/dist/application/service-registry.d.ts +34 -0
- package/dist/components/PluginErrorBoundary.d.ts +22 -0
- package/dist/components/PluginSlot.d.ts +22 -0
- package/dist/components/SlotSkeletons.d.ts +10 -0
- package/dist/config-manager.d.ts +30 -0
- package/dist/domain/auto-loader.d.ts +37 -0
- package/dist/domain/models.d.ts +9 -0
- package/dist/domain/plugin-manager.d.ts +143 -0
- package/dist/domain/plugin-runtime.d.ts +34 -0
- package/dist/domain/plugin-sandbox.d.ts +27 -0
- package/dist/domain/storage-manager.d.ts +46 -0
- package/dist/event-bus.d.ts +38 -0
- package/dist/hooks/use-plugin-loader.d.ts +20 -0
- package/dist/hooks/use-storage-state.d.ts +15 -0
- package/dist/index.cjs +2265 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.mjs +2210 -0
- package/dist/plugin-context.d.ts +8 -0
- package/dist/ports/api-port.d.ts +71 -0
- package/dist/ports/event-bus-port.d.ts +30 -0
- package/dist/ports/plugin-port.d.ts +192 -0
- package/dist/ports/storage-port.d.ts +19 -0
- package/dist/sandbox/proxy-sandbox.d.ts +45 -0
- package/dist/sandbox/style-isolation.d.ts +13 -0
- package/dist/testing/plugin-contract.d.ts +6 -0
- package/dist/utils/date.d.ts +32 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/logger.d.ts +69 -0
- package/dist/utils/stream-parser.d.ts +26 -0
- package/package.json +39 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2265 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
+
for (let key of __getOwnPropNames(from))
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
31
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
+
|
|
33
|
+
// ../../node_modules/.pnpm/dayjs@1.11.19/node_modules/dayjs/dayjs.min.js
|
|
34
|
+
var require_dayjs_min = __commonJS({
|
|
35
|
+
"../../node_modules/.pnpm/dayjs@1.11.19/node_modules/dayjs/dayjs.min.js"(exports2, module2) {
|
|
36
|
+
"use strict";
|
|
37
|
+
!(function(t, e) {
|
|
38
|
+
"object" == typeof exports2 && "undefined" != typeof module2 ? module2.exports = e() : "function" == typeof define && define.amd ? define(e) : (t = "undefined" != typeof globalThis ? globalThis : t || self).dayjs = e();
|
|
39
|
+
})(exports2, (function() {
|
|
40
|
+
"use strict";
|
|
41
|
+
var t = 1e3, e = 6e4, n = 36e5, r = "millisecond", i = "second", s = "minute", u = "hour", a = "day", o = "week", c = "month", f = "quarter", h = "year", d = "date", l = "Invalid Date", $ = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/, y = /\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g, M = { name: "en", weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), ordinal: function(t2) {
|
|
42
|
+
var e2 = ["th", "st", "nd", "rd"], n2 = t2 % 100;
|
|
43
|
+
return "[" + t2 + (e2[(n2 - 20) % 10] || e2[n2] || e2[0]) + "]";
|
|
44
|
+
} }, m = function(t2, e2, n2) {
|
|
45
|
+
var r2 = String(t2);
|
|
46
|
+
return !r2 || r2.length >= e2 ? t2 : "" + Array(e2 + 1 - r2.length).join(n2) + t2;
|
|
47
|
+
}, v = { s: m, z: function(t2) {
|
|
48
|
+
var e2 = -t2.utcOffset(), n2 = Math.abs(e2), r2 = Math.floor(n2 / 60), i2 = n2 % 60;
|
|
49
|
+
return (e2 <= 0 ? "+" : "-") + m(r2, 2, "0") + ":" + m(i2, 2, "0");
|
|
50
|
+
}, m: function t2(e2, n2) {
|
|
51
|
+
if (e2.date() < n2.date()) return -t2(n2, e2);
|
|
52
|
+
var r2 = 12 * (n2.year() - e2.year()) + (n2.month() - e2.month()), i2 = e2.clone().add(r2, c), s2 = n2 - i2 < 0, u2 = e2.clone().add(r2 + (s2 ? -1 : 1), c);
|
|
53
|
+
return +(-(r2 + (n2 - i2) / (s2 ? i2 - u2 : u2 - i2)) || 0);
|
|
54
|
+
}, a: function(t2) {
|
|
55
|
+
return t2 < 0 ? Math.ceil(t2) || 0 : Math.floor(t2);
|
|
56
|
+
}, p: function(t2) {
|
|
57
|
+
return { M: c, y: h, w: o, d: a, D: d, h: u, m: s, s: i, ms: r, Q: f }[t2] || String(t2 || "").toLowerCase().replace(/s$/, "");
|
|
58
|
+
}, u: function(t2) {
|
|
59
|
+
return void 0 === t2;
|
|
60
|
+
} }, g = "en", D = {};
|
|
61
|
+
D[g] = M;
|
|
62
|
+
var p = "$isDayjsObject", S = function(t2) {
|
|
63
|
+
return t2 instanceof _ || !(!t2 || !t2[p]);
|
|
64
|
+
}, w = function t2(e2, n2, r2) {
|
|
65
|
+
var i2;
|
|
66
|
+
if (!e2) return g;
|
|
67
|
+
if ("string" == typeof e2) {
|
|
68
|
+
var s2 = e2.toLowerCase();
|
|
69
|
+
D[s2] && (i2 = s2), n2 && (D[s2] = n2, i2 = s2);
|
|
70
|
+
var u2 = e2.split("-");
|
|
71
|
+
if (!i2 && u2.length > 1) return t2(u2[0]);
|
|
72
|
+
} else {
|
|
73
|
+
var a2 = e2.name;
|
|
74
|
+
D[a2] = e2, i2 = a2;
|
|
75
|
+
}
|
|
76
|
+
return !r2 && i2 && (g = i2), i2 || !r2 && g;
|
|
77
|
+
}, O = function(t2, e2) {
|
|
78
|
+
if (S(t2)) return t2.clone();
|
|
79
|
+
var n2 = "object" == typeof e2 ? e2 : {};
|
|
80
|
+
return n2.date = t2, n2.args = arguments, new _(n2);
|
|
81
|
+
}, b = v;
|
|
82
|
+
b.l = w, b.i = S, b.w = function(t2, e2) {
|
|
83
|
+
return O(t2, { locale: e2.$L, utc: e2.$u, x: e2.$x, $offset: e2.$offset });
|
|
84
|
+
};
|
|
85
|
+
var _ = (function() {
|
|
86
|
+
function M2(t2) {
|
|
87
|
+
this.$L = w(t2.locale, null, true), this.parse(t2), this.$x = this.$x || t2.x || {}, this[p] = true;
|
|
88
|
+
}
|
|
89
|
+
var m2 = M2.prototype;
|
|
90
|
+
return m2.parse = function(t2) {
|
|
91
|
+
this.$d = (function(t3) {
|
|
92
|
+
var e2 = t3.date, n2 = t3.utc;
|
|
93
|
+
if (null === e2) return /* @__PURE__ */ new Date(NaN);
|
|
94
|
+
if (b.u(e2)) return /* @__PURE__ */ new Date();
|
|
95
|
+
if (e2 instanceof Date) return new Date(e2);
|
|
96
|
+
if ("string" == typeof e2 && !/Z$/i.test(e2)) {
|
|
97
|
+
var r2 = e2.match($);
|
|
98
|
+
if (r2) {
|
|
99
|
+
var i2 = r2[2] - 1 || 0, s2 = (r2[7] || "0").substring(0, 3);
|
|
100
|
+
return n2 ? new Date(Date.UTC(r2[1], i2, r2[3] || 1, r2[4] || 0, r2[5] || 0, r2[6] || 0, s2)) : new Date(r2[1], i2, r2[3] || 1, r2[4] || 0, r2[5] || 0, r2[6] || 0, s2);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return new Date(e2);
|
|
104
|
+
})(t2), this.init();
|
|
105
|
+
}, m2.init = function() {
|
|
106
|
+
var t2 = this.$d;
|
|
107
|
+
this.$y = t2.getFullYear(), this.$M = t2.getMonth(), this.$D = t2.getDate(), this.$W = t2.getDay(), this.$H = t2.getHours(), this.$m = t2.getMinutes(), this.$s = t2.getSeconds(), this.$ms = t2.getMilliseconds();
|
|
108
|
+
}, m2.$utils = function() {
|
|
109
|
+
return b;
|
|
110
|
+
}, m2.isValid = function() {
|
|
111
|
+
return !(this.$d.toString() === l);
|
|
112
|
+
}, m2.isSame = function(t2, e2) {
|
|
113
|
+
var n2 = O(t2);
|
|
114
|
+
return this.startOf(e2) <= n2 && n2 <= this.endOf(e2);
|
|
115
|
+
}, m2.isAfter = function(t2, e2) {
|
|
116
|
+
return O(t2) < this.startOf(e2);
|
|
117
|
+
}, m2.isBefore = function(t2, e2) {
|
|
118
|
+
return this.endOf(e2) < O(t2);
|
|
119
|
+
}, m2.$g = function(t2, e2, n2) {
|
|
120
|
+
return b.u(t2) ? this[e2] : this.set(n2, t2);
|
|
121
|
+
}, m2.unix = function() {
|
|
122
|
+
return Math.floor(this.valueOf() / 1e3);
|
|
123
|
+
}, m2.valueOf = function() {
|
|
124
|
+
return this.$d.getTime();
|
|
125
|
+
}, m2.startOf = function(t2, e2) {
|
|
126
|
+
var n2 = this, r2 = !!b.u(e2) || e2, f2 = b.p(t2), l2 = function(t3, e3) {
|
|
127
|
+
var i2 = b.w(n2.$u ? Date.UTC(n2.$y, e3, t3) : new Date(n2.$y, e3, t3), n2);
|
|
128
|
+
return r2 ? i2 : i2.endOf(a);
|
|
129
|
+
}, $2 = function(t3, e3) {
|
|
130
|
+
return b.w(n2.toDate()[t3].apply(n2.toDate("s"), (r2 ? [0, 0, 0, 0] : [23, 59, 59, 999]).slice(e3)), n2);
|
|
131
|
+
}, y2 = this.$W, M3 = this.$M, m3 = this.$D, v2 = "set" + (this.$u ? "UTC" : "");
|
|
132
|
+
switch (f2) {
|
|
133
|
+
case h:
|
|
134
|
+
return r2 ? l2(1, 0) : l2(31, 11);
|
|
135
|
+
case c:
|
|
136
|
+
return r2 ? l2(1, M3) : l2(0, M3 + 1);
|
|
137
|
+
case o:
|
|
138
|
+
var g2 = this.$locale().weekStart || 0, D2 = (y2 < g2 ? y2 + 7 : y2) - g2;
|
|
139
|
+
return l2(r2 ? m3 - D2 : m3 + (6 - D2), M3);
|
|
140
|
+
case a:
|
|
141
|
+
case d:
|
|
142
|
+
return $2(v2 + "Hours", 0);
|
|
143
|
+
case u:
|
|
144
|
+
return $2(v2 + "Minutes", 1);
|
|
145
|
+
case s:
|
|
146
|
+
return $2(v2 + "Seconds", 2);
|
|
147
|
+
case i:
|
|
148
|
+
return $2(v2 + "Milliseconds", 3);
|
|
149
|
+
default:
|
|
150
|
+
return this.clone();
|
|
151
|
+
}
|
|
152
|
+
}, m2.endOf = function(t2) {
|
|
153
|
+
return this.startOf(t2, false);
|
|
154
|
+
}, m2.$set = function(t2, e2) {
|
|
155
|
+
var n2, o2 = b.p(t2), f2 = "set" + (this.$u ? "UTC" : ""), l2 = (n2 = {}, n2[a] = f2 + "Date", n2[d] = f2 + "Date", n2[c] = f2 + "Month", n2[h] = f2 + "FullYear", n2[u] = f2 + "Hours", n2[s] = f2 + "Minutes", n2[i] = f2 + "Seconds", n2[r] = f2 + "Milliseconds", n2)[o2], $2 = o2 === a ? this.$D + (e2 - this.$W) : e2;
|
|
156
|
+
if (o2 === c || o2 === h) {
|
|
157
|
+
var y2 = this.clone().set(d, 1);
|
|
158
|
+
y2.$d[l2]($2), y2.init(), this.$d = y2.set(d, Math.min(this.$D, y2.daysInMonth())).$d;
|
|
159
|
+
} else l2 && this.$d[l2]($2);
|
|
160
|
+
return this.init(), this;
|
|
161
|
+
}, m2.set = function(t2, e2) {
|
|
162
|
+
return this.clone().$set(t2, e2);
|
|
163
|
+
}, m2.get = function(t2) {
|
|
164
|
+
return this[b.p(t2)]();
|
|
165
|
+
}, m2.add = function(r2, f2) {
|
|
166
|
+
var d2, l2 = this;
|
|
167
|
+
r2 = Number(r2);
|
|
168
|
+
var $2 = b.p(f2), y2 = function(t2) {
|
|
169
|
+
var e2 = O(l2);
|
|
170
|
+
return b.w(e2.date(e2.date() + Math.round(t2 * r2)), l2);
|
|
171
|
+
};
|
|
172
|
+
if ($2 === c) return this.set(c, this.$M + r2);
|
|
173
|
+
if ($2 === h) return this.set(h, this.$y + r2);
|
|
174
|
+
if ($2 === a) return y2(1);
|
|
175
|
+
if ($2 === o) return y2(7);
|
|
176
|
+
var M3 = (d2 = {}, d2[s] = e, d2[u] = n, d2[i] = t, d2)[$2] || 1, m3 = this.$d.getTime() + r2 * M3;
|
|
177
|
+
return b.w(m3, this);
|
|
178
|
+
}, m2.subtract = function(t2, e2) {
|
|
179
|
+
return this.add(-1 * t2, e2);
|
|
180
|
+
}, m2.format = function(t2) {
|
|
181
|
+
var e2 = this, n2 = this.$locale();
|
|
182
|
+
if (!this.isValid()) return n2.invalidDate || l;
|
|
183
|
+
var r2 = t2 || "YYYY-MM-DDTHH:mm:ssZ", i2 = b.z(this), s2 = this.$H, u2 = this.$m, a2 = this.$M, o2 = n2.weekdays, c2 = n2.months, f2 = n2.meridiem, h2 = function(t3, n3, i3, s3) {
|
|
184
|
+
return t3 && (t3[n3] || t3(e2, r2)) || i3[n3].slice(0, s3);
|
|
185
|
+
}, d2 = function(t3) {
|
|
186
|
+
return b.s(s2 % 12 || 12, t3, "0");
|
|
187
|
+
}, $2 = f2 || function(t3, e3, n3) {
|
|
188
|
+
var r3 = t3 < 12 ? "AM" : "PM";
|
|
189
|
+
return n3 ? r3.toLowerCase() : r3;
|
|
190
|
+
};
|
|
191
|
+
return r2.replace(y, (function(t3, r3) {
|
|
192
|
+
return r3 || (function(t4) {
|
|
193
|
+
switch (t4) {
|
|
194
|
+
case "YY":
|
|
195
|
+
return String(e2.$y).slice(-2);
|
|
196
|
+
case "YYYY":
|
|
197
|
+
return b.s(e2.$y, 4, "0");
|
|
198
|
+
case "M":
|
|
199
|
+
return a2 + 1;
|
|
200
|
+
case "MM":
|
|
201
|
+
return b.s(a2 + 1, 2, "0");
|
|
202
|
+
case "MMM":
|
|
203
|
+
return h2(n2.monthsShort, a2, c2, 3);
|
|
204
|
+
case "MMMM":
|
|
205
|
+
return h2(c2, a2);
|
|
206
|
+
case "D":
|
|
207
|
+
return e2.$D;
|
|
208
|
+
case "DD":
|
|
209
|
+
return b.s(e2.$D, 2, "0");
|
|
210
|
+
case "d":
|
|
211
|
+
return String(e2.$W);
|
|
212
|
+
case "dd":
|
|
213
|
+
return h2(n2.weekdaysMin, e2.$W, o2, 2);
|
|
214
|
+
case "ddd":
|
|
215
|
+
return h2(n2.weekdaysShort, e2.$W, o2, 3);
|
|
216
|
+
case "dddd":
|
|
217
|
+
return o2[e2.$W];
|
|
218
|
+
case "H":
|
|
219
|
+
return String(s2);
|
|
220
|
+
case "HH":
|
|
221
|
+
return b.s(s2, 2, "0");
|
|
222
|
+
case "h":
|
|
223
|
+
return d2(1);
|
|
224
|
+
case "hh":
|
|
225
|
+
return d2(2);
|
|
226
|
+
case "a":
|
|
227
|
+
return $2(s2, u2, true);
|
|
228
|
+
case "A":
|
|
229
|
+
return $2(s2, u2, false);
|
|
230
|
+
case "m":
|
|
231
|
+
return String(u2);
|
|
232
|
+
case "mm":
|
|
233
|
+
return b.s(u2, 2, "0");
|
|
234
|
+
case "s":
|
|
235
|
+
return String(e2.$s);
|
|
236
|
+
case "ss":
|
|
237
|
+
return b.s(e2.$s, 2, "0");
|
|
238
|
+
case "SSS":
|
|
239
|
+
return b.s(e2.$ms, 3, "0");
|
|
240
|
+
case "Z":
|
|
241
|
+
return i2;
|
|
242
|
+
}
|
|
243
|
+
return null;
|
|
244
|
+
})(t3) || i2.replace(":", "");
|
|
245
|
+
}));
|
|
246
|
+
}, m2.utcOffset = function() {
|
|
247
|
+
return 15 * -Math.round(this.$d.getTimezoneOffset() / 15);
|
|
248
|
+
}, m2.diff = function(r2, d2, l2) {
|
|
249
|
+
var $2, y2 = this, M3 = b.p(d2), m3 = O(r2), v2 = (m3.utcOffset() - this.utcOffset()) * e, g2 = this - m3, D2 = function() {
|
|
250
|
+
return b.m(y2, m3);
|
|
251
|
+
};
|
|
252
|
+
switch (M3) {
|
|
253
|
+
case h:
|
|
254
|
+
$2 = D2() / 12;
|
|
255
|
+
break;
|
|
256
|
+
case c:
|
|
257
|
+
$2 = D2();
|
|
258
|
+
break;
|
|
259
|
+
case f:
|
|
260
|
+
$2 = D2() / 3;
|
|
261
|
+
break;
|
|
262
|
+
case o:
|
|
263
|
+
$2 = (g2 - v2) / 6048e5;
|
|
264
|
+
break;
|
|
265
|
+
case a:
|
|
266
|
+
$2 = (g2 - v2) / 864e5;
|
|
267
|
+
break;
|
|
268
|
+
case u:
|
|
269
|
+
$2 = g2 / n;
|
|
270
|
+
break;
|
|
271
|
+
case s:
|
|
272
|
+
$2 = g2 / e;
|
|
273
|
+
break;
|
|
274
|
+
case i:
|
|
275
|
+
$2 = g2 / t;
|
|
276
|
+
break;
|
|
277
|
+
default:
|
|
278
|
+
$2 = g2;
|
|
279
|
+
}
|
|
280
|
+
return l2 ? $2 : b.a($2);
|
|
281
|
+
}, m2.daysInMonth = function() {
|
|
282
|
+
return this.endOf(c).$D;
|
|
283
|
+
}, m2.$locale = function() {
|
|
284
|
+
return D[this.$L];
|
|
285
|
+
}, m2.locale = function(t2, e2) {
|
|
286
|
+
if (!t2) return this.$L;
|
|
287
|
+
var n2 = this.clone(), r2 = w(t2, e2, true);
|
|
288
|
+
return r2 && (n2.$L = r2), n2;
|
|
289
|
+
}, m2.clone = function() {
|
|
290
|
+
return b.w(this.$d, this);
|
|
291
|
+
}, m2.toDate = function() {
|
|
292
|
+
return new Date(this.valueOf());
|
|
293
|
+
}, m2.toJSON = function() {
|
|
294
|
+
return this.isValid() ? this.toISOString() : null;
|
|
295
|
+
}, m2.toISOString = function() {
|
|
296
|
+
return this.$d.toISOString();
|
|
297
|
+
}, m2.toString = function() {
|
|
298
|
+
return this.$d.toUTCString();
|
|
299
|
+
}, M2;
|
|
300
|
+
})(), k = _.prototype;
|
|
301
|
+
return O.prototype = k, [["$ms", r], ["$s", i], ["$m", s], ["$H", u], ["$W", a], ["$M", c], ["$y", h], ["$D", d]].forEach((function(t2) {
|
|
302
|
+
k[t2[1]] = function(e2) {
|
|
303
|
+
return this.$g(e2, t2[0], t2[1]);
|
|
304
|
+
};
|
|
305
|
+
})), O.extend = function(t2, e2) {
|
|
306
|
+
return t2.$i || (t2(e2, _, O), t2.$i = true), O;
|
|
307
|
+
}, O.locale = w, O.isDayjs = S, O.unix = function(t2) {
|
|
308
|
+
return O(1e3 * t2);
|
|
309
|
+
}, O.en = D[g], O.Ls = D, O.p = {}, O;
|
|
310
|
+
}));
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// ../../node_modules/.pnpm/dayjs@1.11.19/node_modules/dayjs/plugin/relativeTime.js
|
|
315
|
+
var require_relativeTime = __commonJS({
|
|
316
|
+
"../../node_modules/.pnpm/dayjs@1.11.19/node_modules/dayjs/plugin/relativeTime.js"(exports2, module2) {
|
|
317
|
+
"use strict";
|
|
318
|
+
!(function(r, e) {
|
|
319
|
+
"object" == typeof exports2 && "undefined" != typeof module2 ? module2.exports = e() : "function" == typeof define && define.amd ? define(e) : (r = "undefined" != typeof globalThis ? globalThis : r || self).dayjs_plugin_relativeTime = e();
|
|
320
|
+
})(exports2, (function() {
|
|
321
|
+
"use strict";
|
|
322
|
+
return function(r, e, t) {
|
|
323
|
+
r = r || {};
|
|
324
|
+
var n = e.prototype, o = { future: "in %s", past: "%s ago", s: "a few seconds", m: "a minute", mm: "%d minutes", h: "an hour", hh: "%d hours", d: "a day", dd: "%d days", M: "a month", MM: "%d months", y: "a year", yy: "%d years" };
|
|
325
|
+
function i(r2, e2, t2, o2) {
|
|
326
|
+
return n.fromToBase(r2, e2, t2, o2);
|
|
327
|
+
}
|
|
328
|
+
t.en.relativeTime = o, n.fromToBase = function(e2, n2, i2, d2, u) {
|
|
329
|
+
for (var f, a, s, l = i2.$locale().relativeTime || o, h = r.thresholds || [{ l: "s", r: 44, d: "second" }, { l: "m", r: 89 }, { l: "mm", r: 44, d: "minute" }, { l: "h", r: 89 }, { l: "hh", r: 21, d: "hour" }, { l: "d", r: 35 }, { l: "dd", r: 25, d: "day" }, { l: "M", r: 45 }, { l: "MM", r: 10, d: "month" }, { l: "y", r: 17 }, { l: "yy", d: "year" }], m = h.length, c = 0; c < m; c += 1) {
|
|
330
|
+
var y = h[c];
|
|
331
|
+
y.d && (f = d2 ? t(e2).diff(i2, y.d, true) : i2.diff(e2, y.d, true));
|
|
332
|
+
var p = (r.rounding || Math.round)(Math.abs(f));
|
|
333
|
+
if (s = f > 0, p <= y.r || !y.r) {
|
|
334
|
+
p <= 1 && c > 0 && (y = h[c - 1]);
|
|
335
|
+
var v = l[y.l];
|
|
336
|
+
u && (p = u("" + p)), a = "string" == typeof v ? v.replace("%d", p) : v(p, n2, y.l, s);
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (n2) return a;
|
|
341
|
+
var M = s ? l.future : l.past;
|
|
342
|
+
return "function" == typeof M ? M(a) : M.replace("%s", a);
|
|
343
|
+
}, n.to = function(r2, e2) {
|
|
344
|
+
return i(r2, e2, this, true);
|
|
345
|
+
}, n.from = function(r2, e2) {
|
|
346
|
+
return i(r2, e2, this);
|
|
347
|
+
};
|
|
348
|
+
var d = function(r2) {
|
|
349
|
+
return r2.$u ? t.utc() : t();
|
|
350
|
+
};
|
|
351
|
+
n.toNow = function(r2) {
|
|
352
|
+
return this.to(d(this), r2);
|
|
353
|
+
}, n.fromNow = function(r2) {
|
|
354
|
+
return this.from(d(this), r2);
|
|
355
|
+
};
|
|
356
|
+
};
|
|
357
|
+
}));
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
// ../../node_modules/.pnpm/dayjs@1.11.19/node_modules/dayjs/locale/zh-cn.js
|
|
362
|
+
var require_zh_cn = __commonJS({
|
|
363
|
+
"../../node_modules/.pnpm/dayjs@1.11.19/node_modules/dayjs/locale/zh-cn.js"(exports2, module2) {
|
|
364
|
+
"use strict";
|
|
365
|
+
!(function(e, _) {
|
|
366
|
+
"object" == typeof exports2 && "undefined" != typeof module2 ? module2.exports = _(require_dayjs_min()) : "function" == typeof define && define.amd ? define(["dayjs"], _) : (e = "undefined" != typeof globalThis ? globalThis : e || self).dayjs_locale_zh_cn = _(e.dayjs);
|
|
367
|
+
})(exports2, (function(e) {
|
|
368
|
+
"use strict";
|
|
369
|
+
function _(e2) {
|
|
370
|
+
return e2 && "object" == typeof e2 && "default" in e2 ? e2 : { default: e2 };
|
|
371
|
+
}
|
|
372
|
+
var t = _(e), d = { name: "zh-cn", weekdays: "\u661F\u671F\u65E5_\u661F\u671F\u4E00_\u661F\u671F\u4E8C_\u661F\u671F\u4E09_\u661F\u671F\u56DB_\u661F\u671F\u4E94_\u661F\u671F\u516D".split("_"), weekdaysShort: "\u5468\u65E5_\u5468\u4E00_\u5468\u4E8C_\u5468\u4E09_\u5468\u56DB_\u5468\u4E94_\u5468\u516D".split("_"), weekdaysMin: "\u65E5_\u4E00_\u4E8C_\u4E09_\u56DB_\u4E94_\u516D".split("_"), months: "\u4E00\u6708_\u4E8C\u6708_\u4E09\u6708_\u56DB\u6708_\u4E94\u6708_\u516D\u6708_\u4E03\u6708_\u516B\u6708_\u4E5D\u6708_\u5341\u6708_\u5341\u4E00\u6708_\u5341\u4E8C\u6708".split("_"), monthsShort: "1\u6708_2\u6708_3\u6708_4\u6708_5\u6708_6\u6708_7\u6708_8\u6708_9\u6708_10\u6708_11\u6708_12\u6708".split("_"), ordinal: function(e2, _2) {
|
|
373
|
+
return "W" === _2 ? e2 + "\u5468" : e2 + "\u65E5";
|
|
374
|
+
}, weekStart: 1, yearStart: 4, formats: { LT: "HH:mm", LTS: "HH:mm:ss", L: "YYYY/MM/DD", LL: "YYYY\u5E74M\u6708D\u65E5", LLL: "YYYY\u5E74M\u6708D\u65E5Ah\u70B9mm\u5206", LLLL: "YYYY\u5E74M\u6708D\u65E5ddddAh\u70B9mm\u5206", l: "YYYY/M/D", ll: "YYYY\u5E74M\u6708D\u65E5", lll: "YYYY\u5E74M\u6708D\u65E5 HH:mm", llll: "YYYY\u5E74M\u6708D\u65E5dddd HH:mm" }, relativeTime: { future: "%s\u5185", past: "%s\u524D", s: "\u51E0\u79D2", m: "1 \u5206\u949F", mm: "%d \u5206\u949F", h: "1 \u5C0F\u65F6", hh: "%d \u5C0F\u65F6", d: "1 \u5929", dd: "%d \u5929", M: "1 \u4E2A\u6708", MM: "%d \u4E2A\u6708", y: "1 \u5E74", yy: "%d \u5E74" }, meridiem: function(e2, _2) {
|
|
375
|
+
var t2 = 100 * e2 + _2;
|
|
376
|
+
return t2 < 600 ? "\u51CC\u6668" : t2 < 900 ? "\u65E9\u4E0A" : t2 < 1100 ? "\u4E0A\u5348" : t2 < 1300 ? "\u4E2D\u5348" : t2 < 1800 ? "\u4E0B\u5348" : "\u665A\u4E0A";
|
|
377
|
+
} };
|
|
378
|
+
return t.default.locale(d, null, true), d;
|
|
379
|
+
}));
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
// src/index.ts
|
|
384
|
+
var index_exports = {};
|
|
385
|
+
__export(index_exports, {
|
|
386
|
+
ApiEngine: () => ApiEngine,
|
|
387
|
+
ApiProvider: () => ApiProvider,
|
|
388
|
+
AvatarSkeleton: () => AvatarSkeleton,
|
|
389
|
+
AxiosAdapter: () => AxiosAdapter,
|
|
390
|
+
BlockSkeleton: () => BlockSkeleton,
|
|
391
|
+
ConfigManager: () => ConfigManager,
|
|
392
|
+
DefaultEventBus: () => DefaultEventBus,
|
|
393
|
+
LocalStorageAdapter: () => LocalStorageAdapter,
|
|
394
|
+
LogLevel: () => LogLevel,
|
|
395
|
+
Logger: () => Logger,
|
|
396
|
+
PLUGIN_TYPES: () => PLUGIN_TYPES,
|
|
397
|
+
PluginErrorBoundary: () => PluginErrorBoundary,
|
|
398
|
+
PluginManager: () => PluginManager,
|
|
399
|
+
PluginProvider: () => PluginProvider,
|
|
400
|
+
PluginRuntime: () => PluginRuntime,
|
|
401
|
+
PluginSandbox: () => PluginSandbox,
|
|
402
|
+
PluginSlot: () => PluginSlot,
|
|
403
|
+
SUCCESS_CODE: () => SUCCESS_CODE,
|
|
404
|
+
ScopedStorageAdapter: () => ScopedStorageAdapter,
|
|
405
|
+
ServiceRegistry: () => ServiceRegistry,
|
|
406
|
+
SidebarIconSkeleton: () => SidebarIconSkeleton,
|
|
407
|
+
Slot: () => Slot,
|
|
408
|
+
StatusBarItemSkeleton: () => StatusBarItemSkeleton,
|
|
409
|
+
StorageManager: () => StorageManager,
|
|
410
|
+
apiEngine: () => apiEngine,
|
|
411
|
+
configManager: () => configManager,
|
|
412
|
+
createLogger: () => createLogger,
|
|
413
|
+
dateUtils: () => dateUtils,
|
|
414
|
+
discoverPlugins: () => discoverPlugins,
|
|
415
|
+
isMockMode: () => isMockMode,
|
|
416
|
+
logger: () => logger,
|
|
417
|
+
parseStreamChunk: () => parseStreamChunk,
|
|
418
|
+
pluginManager: () => pluginManager,
|
|
419
|
+
resolveApiModules: () => resolveApiModules,
|
|
420
|
+
resolvePluginRegistry: () => resolvePluginRegistry,
|
|
421
|
+
serviceRegistry: () => serviceRegistry,
|
|
422
|
+
useApi: () => useApi,
|
|
423
|
+
usePluginLoader: () => usePluginLoader,
|
|
424
|
+
usePluginManager: () => usePluginManager,
|
|
425
|
+
useStorageState: () => useStorageState,
|
|
426
|
+
version: () => version
|
|
427
|
+
});
|
|
428
|
+
module.exports = __toCommonJS(index_exports);
|
|
429
|
+
|
|
430
|
+
// src/ports/plugin-port.ts
|
|
431
|
+
var PLUGIN_TYPES = ["business", "functional", "view", "theme", "renderer", "system"];
|
|
432
|
+
var Slot = {
|
|
433
|
+
Sidebar: "sidebar",
|
|
434
|
+
SidebarPanel: "sidebar-panel",
|
|
435
|
+
Header: "header",
|
|
436
|
+
StatusBar: "status-bar",
|
|
437
|
+
Settings: "settings",
|
|
438
|
+
MessageRenderer: "message-renderer",
|
|
439
|
+
MessageContentRenderer: "message-content-renderer",
|
|
440
|
+
SidebarSystem: "sidebar-system",
|
|
441
|
+
SidebarBottom: "sidebar-bottom",
|
|
442
|
+
Custom: "custom"
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
// src/utils/logger.ts
|
|
446
|
+
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
447
|
+
LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
|
|
448
|
+
LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
|
|
449
|
+
LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
|
|
450
|
+
LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
|
|
451
|
+
LogLevel2[LogLevel2["NONE"] = 4] = "NONE";
|
|
452
|
+
return LogLevel2;
|
|
453
|
+
})(LogLevel || {});
|
|
454
|
+
var Logger = class _Logger {
|
|
455
|
+
/** 全局默认日志等级 */
|
|
456
|
+
static level = 1 /* INFO */;
|
|
457
|
+
/** 当前实例的前缀 */
|
|
458
|
+
prefix;
|
|
459
|
+
/**
|
|
460
|
+
* 构造函数
|
|
461
|
+
* @param prefix 日志前缀,默认为 'App'
|
|
462
|
+
*/
|
|
463
|
+
constructor(prefix = "App") {
|
|
464
|
+
this.prefix = prefix;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* 设置全局日志等级
|
|
468
|
+
* @param level 日志等级
|
|
469
|
+
*/
|
|
470
|
+
static setLevel(level) {
|
|
471
|
+
this.level = level;
|
|
472
|
+
console.info(`[Logger] Global log level set to: ${LogLevel[level]}`);
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* 获取当前日志等级
|
|
476
|
+
* @returns 当前全局日志等级
|
|
477
|
+
*/
|
|
478
|
+
static getLevel() {
|
|
479
|
+
return this.level;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* 打印 DEBUG 级别日志
|
|
483
|
+
*/
|
|
484
|
+
get debug() {
|
|
485
|
+
return _Logger.level <= 0 /* DEBUG */ ? console.debug.bind(console, `[${this.prefix}]`) : noop;
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* 打印 INFO 级别日志
|
|
489
|
+
*/
|
|
490
|
+
get info() {
|
|
491
|
+
return _Logger.level <= 1 /* INFO */ ? console.info.bind(console, `[${this.prefix}]`) : noop;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* 打印 WARN 级别日志
|
|
495
|
+
*/
|
|
496
|
+
get warn() {
|
|
497
|
+
return _Logger.level <= 2 /* WARN */ ? console.warn.bind(console, `[${this.prefix}]`) : noop;
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* 打印 ERROR 级别日志
|
|
501
|
+
*/
|
|
502
|
+
get error() {
|
|
503
|
+
return _Logger.level <= 3 /* ERROR */ ? console.error.bind(console, `[${this.prefix}]`) : noop;
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* 开始一个日志分组
|
|
507
|
+
* @param label 分组标签
|
|
508
|
+
* @param collapsed 是否默认折叠,默认为 false
|
|
509
|
+
*/
|
|
510
|
+
group(label, collapsed = false) {
|
|
511
|
+
if (_Logger.level <= 1 /* INFO */) {
|
|
512
|
+
if (collapsed) {
|
|
513
|
+
console.groupCollapsed(`[${this.prefix}] ${label}`);
|
|
514
|
+
} else {
|
|
515
|
+
console.group(`[${this.prefix}] ${label}`);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* 结束当前日志分组
|
|
521
|
+
*/
|
|
522
|
+
get groupEnd() {
|
|
523
|
+
return _Logger.level <= 1 /* INFO */ ? console.groupEnd.bind(console) : noop;
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
var noop = () => {
|
|
527
|
+
};
|
|
528
|
+
var logger = new Logger();
|
|
529
|
+
var createLogger = (prefix) => new Logger(prefix);
|
|
530
|
+
|
|
531
|
+
// src/application/service-registry.ts
|
|
532
|
+
var logger2 = createLogger("ServiceRegistry");
|
|
533
|
+
var ServiceRegistry = class {
|
|
534
|
+
services = /* @__PURE__ */ new Map();
|
|
535
|
+
listeners = /* @__PURE__ */ new Map();
|
|
536
|
+
/**
|
|
537
|
+
* 注册服务
|
|
538
|
+
* @param name 服务名称 (建议格式: pluginId.serviceName)
|
|
539
|
+
* @param service 服务实现
|
|
540
|
+
*/
|
|
541
|
+
register(name, service) {
|
|
542
|
+
if (this.services.has(name)) {
|
|
543
|
+
logger2.warn(`\u670D\u52A1 "${name}" \u5DF2\u5B58\u5728\uFF0C\u5C06\u88AB\u8986\u76D6`);
|
|
544
|
+
}
|
|
545
|
+
this.services.set(name, service);
|
|
546
|
+
logger2.info(`\u670D\u52A1\u5DF2\u6CE8\u518C: ${name}`);
|
|
547
|
+
if (this.listeners.has(name)) {
|
|
548
|
+
const set = this.listeners.get(name);
|
|
549
|
+
set.forEach((callback) => callback(service));
|
|
550
|
+
this.listeners.delete(name);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* 获取服务
|
|
555
|
+
* @param name 服务名称
|
|
556
|
+
*/
|
|
557
|
+
get(name) {
|
|
558
|
+
return this.services.get(name);
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* 异步获取服务 (如果尚未注册则等待)
|
|
562
|
+
* @param name 服务名称
|
|
563
|
+
*/
|
|
564
|
+
async waitFor(name) {
|
|
565
|
+
const service = this.services.get(name);
|
|
566
|
+
if (service) return service;
|
|
567
|
+
return new Promise((resolve) => {
|
|
568
|
+
if (!this.listeners.has(name)) {
|
|
569
|
+
this.listeners.set(name, /* @__PURE__ */ new Set());
|
|
570
|
+
}
|
|
571
|
+
this.listeners.get(name).add(resolve);
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* 注销服务
|
|
576
|
+
* @param name 服务名称
|
|
577
|
+
*/
|
|
578
|
+
unregister(name) {
|
|
579
|
+
this.services.delete(name);
|
|
580
|
+
logger2.info(`\u670D\u52A1\u5DF2\u6CE8\u9500: ${name}`);
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* 清除所有服务 (通常在系统重置时使用)
|
|
584
|
+
*/
|
|
585
|
+
clear() {
|
|
586
|
+
this.services.clear();
|
|
587
|
+
this.listeners.clear();
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
var serviceRegistry = new ServiceRegistry();
|
|
591
|
+
|
|
592
|
+
// src/api-context.tsx
|
|
593
|
+
var import_react = require("react");
|
|
594
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
595
|
+
var ApiContext = (0, import_react.createContext)(null);
|
|
596
|
+
var ApiProvider = ({ api, children }) => {
|
|
597
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ApiContext.Provider, { value: api, children });
|
|
598
|
+
};
|
|
599
|
+
var useApi = () => {
|
|
600
|
+
const context = (0, import_react.useContext)(ApiContext);
|
|
601
|
+
if (!context) {
|
|
602
|
+
throw new Error("useApi must be used within an ApiProvider");
|
|
603
|
+
}
|
|
604
|
+
return context;
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
// src/config-manager.ts
|
|
608
|
+
var ConfigManager = class {
|
|
609
|
+
/** 存储配置的 Map */
|
|
610
|
+
config = /* @__PURE__ */ new Map();
|
|
611
|
+
/**
|
|
612
|
+
* 设置配置项
|
|
613
|
+
* @param key 配置键
|
|
614
|
+
* @param value 配置值
|
|
615
|
+
*/
|
|
616
|
+
set(key, value) {
|
|
617
|
+
this.config.set(key, value);
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* 获取配置项
|
|
621
|
+
* @param key 配置键
|
|
622
|
+
*/
|
|
623
|
+
get(key) {
|
|
624
|
+
return this.config.get(key);
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* 合并配置
|
|
628
|
+
* @param config 配置对象
|
|
629
|
+
*/
|
|
630
|
+
merge(config) {
|
|
631
|
+
Object.keys(config).forEach((key) => {
|
|
632
|
+
const existing = this.config.get(key);
|
|
633
|
+
const incoming = config[key];
|
|
634
|
+
if (existing && typeof existing === "object" && incoming && typeof incoming === "object") {
|
|
635
|
+
this.config.set(key, { ...existing, ...incoming });
|
|
636
|
+
} else {
|
|
637
|
+
this.config.set(key, incoming);
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* 获取所有配置
|
|
643
|
+
*/
|
|
644
|
+
getAll() {
|
|
645
|
+
return Object.fromEntries(this.config);
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
var configManager = new ConfigManager();
|
|
649
|
+
|
|
650
|
+
// src/components/PluginErrorBoundary.tsx
|
|
651
|
+
var import_react2 = require("react");
|
|
652
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
653
|
+
var logger3 = createLogger("PluginErrorBoundary");
|
|
654
|
+
var PluginErrorBoundary = class extends import_react2.Component {
|
|
655
|
+
constructor(props) {
|
|
656
|
+
super(props);
|
|
657
|
+
this.state = { hasError: false, error: null };
|
|
658
|
+
}
|
|
659
|
+
static getDerivedStateFromError(error) {
|
|
660
|
+
return { hasError: true, error };
|
|
661
|
+
}
|
|
662
|
+
componentDidCatch(error, errorInfo) {
|
|
663
|
+
logger3.error(`\u63D2\u4EF6 ${this.props.pluginId || "\u672A\u77E5"} \u53D1\u751F\u9519\u8BEF:`, error, errorInfo);
|
|
664
|
+
}
|
|
665
|
+
handleRetry = () => {
|
|
666
|
+
this.setState({ hasError: false, error: null });
|
|
667
|
+
};
|
|
668
|
+
render() {
|
|
669
|
+
if (this.state.hasError) {
|
|
670
|
+
if (this.props.fallback) {
|
|
671
|
+
return this.props.fallback;
|
|
672
|
+
}
|
|
673
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.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: [
|
|
674
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "text-red-500 font-medium mb-1", children: "\u63D2\u4EF6\u6E32\u67D3\u5931\u8D25" }),
|
|
675
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "text-xs text-slate-500 dark:text-slate-400 mb-3", children: [
|
|
676
|
+
"\u63D2\u4EF6 ",
|
|
677
|
+
this.props.pluginId ? `"${this.props.pluginId}"` : "\u672A\u77E5",
|
|
678
|
+
" \u53D1\u751F\u5F02\u5E38: ",
|
|
679
|
+
this.state.error?.message
|
|
680
|
+
] }),
|
|
681
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
682
|
+
"button",
|
|
683
|
+
{
|
|
684
|
+
onClick: this.handleRetry,
|
|
685
|
+
className: "px-3 py-1.5 bg-red-500 hover:bg-red-600 text-white text-xs rounded transition-colors duration-150",
|
|
686
|
+
children: "\u91CD\u8BD5"
|
|
687
|
+
}
|
|
688
|
+
)
|
|
689
|
+
] });
|
|
690
|
+
}
|
|
691
|
+
return this.props.children;
|
|
692
|
+
}
|
|
693
|
+
};
|
|
694
|
+
|
|
695
|
+
// src/components/PluginSlot.tsx
|
|
696
|
+
var import_react3 = require("react");
|
|
697
|
+
|
|
698
|
+
// src/adapters/local-storage-adapter.ts
|
|
699
|
+
var LocalStorageAdapter = class {
|
|
700
|
+
prefix;
|
|
701
|
+
constructor(prefix = "") {
|
|
702
|
+
this.prefix = prefix;
|
|
703
|
+
}
|
|
704
|
+
getKey(key) {
|
|
705
|
+
return this.prefix ? `${this.prefix}:${key}` : key;
|
|
706
|
+
}
|
|
707
|
+
getOriginalKey(namespacedKey) {
|
|
708
|
+
if (!this.prefix) return namespacedKey;
|
|
709
|
+
if (namespacedKey.startsWith(this.prefix + ":")) {
|
|
710
|
+
return namespacedKey.slice(this.prefix.length + 1);
|
|
711
|
+
}
|
|
712
|
+
return null;
|
|
713
|
+
}
|
|
714
|
+
getItem(key) {
|
|
715
|
+
return localStorage.getItem(this.getKey(key));
|
|
716
|
+
}
|
|
717
|
+
setItem(key, value) {
|
|
718
|
+
localStorage.setItem(this.getKey(key), value);
|
|
719
|
+
}
|
|
720
|
+
removeItem(key) {
|
|
721
|
+
localStorage.removeItem(this.getKey(key));
|
|
722
|
+
}
|
|
723
|
+
clear() {
|
|
724
|
+
if (!this.prefix) {
|
|
725
|
+
localStorage.clear();
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
const keysToRemove = [];
|
|
729
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
730
|
+
const key = localStorage.key(i);
|
|
731
|
+
if (key && key.startsWith(this.prefix + ":")) {
|
|
732
|
+
keysToRemove.push(key);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
keysToRemove.forEach((key) => localStorage.removeItem(key));
|
|
736
|
+
}
|
|
737
|
+
get length() {
|
|
738
|
+
if (!this.prefix) return localStorage.length;
|
|
739
|
+
let count = 0;
|
|
740
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
741
|
+
const key = localStorage.key(i);
|
|
742
|
+
if (key && key.startsWith(this.prefix + ":")) {
|
|
743
|
+
count++;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
return count;
|
|
747
|
+
}
|
|
748
|
+
key(index) {
|
|
749
|
+
if (!this.prefix) return localStorage.key(index);
|
|
750
|
+
let count = 0;
|
|
751
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
752
|
+
const key = localStorage.key(i);
|
|
753
|
+
if (key && key.startsWith(this.prefix + ":")) {
|
|
754
|
+
if (count === index) {
|
|
755
|
+
return this.getOriginalKey(key);
|
|
756
|
+
}
|
|
757
|
+
count++;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
return null;
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
|
|
764
|
+
// src/event-bus.ts
|
|
765
|
+
var logger4 = createLogger("EventBus");
|
|
766
|
+
var DefaultEventBus = class {
|
|
767
|
+
listeners = /* @__PURE__ */ new Map();
|
|
768
|
+
on(event, callback) {
|
|
769
|
+
if (!this.listeners.has(event)) {
|
|
770
|
+
this.listeners.set(event, []);
|
|
771
|
+
}
|
|
772
|
+
this.listeners.get(event)?.push(callback);
|
|
773
|
+
return () => this.off(event, callback);
|
|
774
|
+
}
|
|
775
|
+
off(event, callback) {
|
|
776
|
+
const callbacks = this.listeners.get(event);
|
|
777
|
+
if (callbacks) {
|
|
778
|
+
this.listeners.set(event, callbacks.filter((cb) => cb !== callback));
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
emit(event, ...args) {
|
|
782
|
+
const callbacks = this.listeners.get(event);
|
|
783
|
+
if (callbacks) {
|
|
784
|
+
callbacks.forEach((cb) => {
|
|
785
|
+
try {
|
|
786
|
+
cb(...args);
|
|
787
|
+
} catch (error) {
|
|
788
|
+
logger4.error(`\u4E8B\u4EF6\u76D1\u542C\u5668\u5904\u7406\u9519\u8BEF (${event}):`, error);
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
once(event, callback) {
|
|
794
|
+
const wrapper = (...args) => {
|
|
795
|
+
callback(...args);
|
|
796
|
+
this.off(event, wrapper);
|
|
797
|
+
};
|
|
798
|
+
this.on(event, wrapper);
|
|
799
|
+
}
|
|
800
|
+
};
|
|
801
|
+
|
|
802
|
+
// src/sandbox/proxy-sandbox.ts
|
|
803
|
+
var logger5 = createLogger("ProxySandbox");
|
|
804
|
+
var ProxySandbox = class {
|
|
805
|
+
/** 沙箱名称 */
|
|
806
|
+
name;
|
|
807
|
+
/** 代理后的 Window 对象 */
|
|
808
|
+
proxy;
|
|
809
|
+
/** 沙箱是否激活 */
|
|
810
|
+
running = false;
|
|
811
|
+
/** 记录新增/修改的全局变量 */
|
|
812
|
+
updatedValueSet = /* @__PURE__ */ new Set();
|
|
813
|
+
/** 副作用记录池 */
|
|
814
|
+
effectPool = {
|
|
815
|
+
timeouts: /* @__PURE__ */ new Set(),
|
|
816
|
+
intervals: /* @__PURE__ */ new Set(),
|
|
817
|
+
listeners: /* @__PURE__ */ new Map()
|
|
818
|
+
};
|
|
819
|
+
/** 真实的 Window 对象 */
|
|
820
|
+
globalContext;
|
|
821
|
+
/** 白名单全局变量(允许透传访问真实 Window) */
|
|
822
|
+
static globalWhitelist = [
|
|
823
|
+
"System",
|
|
824
|
+
"console",
|
|
825
|
+
// 'setTimeout', // 移除白名单,改为劫持
|
|
826
|
+
// 'setInterval',
|
|
827
|
+
// 'clearTimeout',
|
|
828
|
+
// 'clearInterval',
|
|
829
|
+
"requestAnimationFrame",
|
|
830
|
+
"cancelAnimationFrame",
|
|
831
|
+
// 'addEventListener', // 移除白名单,改为劫持
|
|
832
|
+
// 'removeEventListener',
|
|
833
|
+
"location",
|
|
834
|
+
"history",
|
|
835
|
+
"navigator",
|
|
836
|
+
"document"
|
|
837
|
+
];
|
|
838
|
+
constructor(name, globalContext = window) {
|
|
839
|
+
this.name = name;
|
|
840
|
+
this.globalContext = globalContext;
|
|
841
|
+
const { fakeWindow, propertiesWithGetter } = this.createFakeWindow(globalContext);
|
|
842
|
+
this.patchGlobalEffects(fakeWindow);
|
|
843
|
+
const proxy = new Proxy(fakeWindow, {
|
|
844
|
+
set: (target, p, value) => {
|
|
845
|
+
if (this.running) {
|
|
846
|
+
this.updatedValueSet.add(p);
|
|
847
|
+
target[p] = value;
|
|
848
|
+
return true;
|
|
849
|
+
}
|
|
850
|
+
logger5.warn(`${name} \u672A\u8FD0\u884C\uFF0C\u65E0\u6CD5\u8BBE\u7F6E\u5C5E\u6027 '${String(p)}'`);
|
|
851
|
+
return false;
|
|
852
|
+
},
|
|
853
|
+
get: (target, p) => {
|
|
854
|
+
if (p === Symbol.unscopables) return void 0;
|
|
855
|
+
if (p === "window" || p === "self" || p === "globalThis") {
|
|
856
|
+
return this.proxy;
|
|
857
|
+
}
|
|
858
|
+
if (p === "top" || p === "parent") {
|
|
859
|
+
return this.globalContext[p];
|
|
860
|
+
}
|
|
861
|
+
const value = target[p];
|
|
862
|
+
if (value !== void 0 || this.updatedValueSet.has(p)) {
|
|
863
|
+
return value;
|
|
864
|
+
}
|
|
865
|
+
const rawValue = this.globalContext[p];
|
|
866
|
+
if (typeof rawValue === "function" && !this.isConstructor(rawValue)) {
|
|
867
|
+
if (this.isNativeFunction(rawValue)) {
|
|
868
|
+
return rawValue.bind(this.globalContext);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
return rawValue;
|
|
872
|
+
},
|
|
873
|
+
has: (target, p) => {
|
|
874
|
+
return p in target || p in this.globalContext;
|
|
875
|
+
},
|
|
876
|
+
defineProperty: (target, p, attributes) => {
|
|
877
|
+
if (this.running) {
|
|
878
|
+
this.updatedValueSet.add(p);
|
|
879
|
+
return Reflect.defineProperty(target, p, attributes);
|
|
880
|
+
}
|
|
881
|
+
return false;
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
this.proxy = proxy;
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* 激活沙箱
|
|
888
|
+
*/
|
|
889
|
+
active() {
|
|
890
|
+
if (!this.running) {
|
|
891
|
+
this.running = true;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* 销毁沙箱
|
|
896
|
+
*/
|
|
897
|
+
inactive() {
|
|
898
|
+
this.running = false;
|
|
899
|
+
this.effectPool.timeouts.forEach((id) => this.globalContext.clearTimeout(id));
|
|
900
|
+
this.effectPool.timeouts.clear();
|
|
901
|
+
this.effectPool.intervals.forEach((id) => this.globalContext.clearInterval(id));
|
|
902
|
+
this.effectPool.intervals.clear();
|
|
903
|
+
this.effectPool.listeners.forEach((listeners, type) => {
|
|
904
|
+
listeners.forEach(({ listener, options }) => {
|
|
905
|
+
this.globalContext.removeEventListener(type, listener, options);
|
|
906
|
+
});
|
|
907
|
+
});
|
|
908
|
+
this.effectPool.listeners.clear();
|
|
909
|
+
logger5.debug(`${this.name} \u5DF2\u505C\u7528\uFF0C\u526F\u4F5C\u7528\u5DF2\u6E05\u9664\u3002`);
|
|
910
|
+
}
|
|
911
|
+
/**
|
|
912
|
+
* 在沙箱中执行代码
|
|
913
|
+
* @param code JS 代码字符串
|
|
914
|
+
* @returns 执行结果
|
|
915
|
+
*/
|
|
916
|
+
eval(code) {
|
|
917
|
+
const evalCode = `
|
|
918
|
+
;(function(window, self, globalThis){
|
|
919
|
+
with(window) {
|
|
920
|
+
${code}
|
|
921
|
+
}
|
|
922
|
+
}).bind(window.proxy)(window.proxy, window.proxy, window.proxy);
|
|
923
|
+
`;
|
|
924
|
+
return (0, eval)(evalCode);
|
|
925
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
* 创建伪造的 Window 对象
|
|
928
|
+
*/
|
|
929
|
+
createFakeWindow(globalContext) {
|
|
930
|
+
const propertiesWithGetter = /* @__PURE__ */ new Map();
|
|
931
|
+
const fakeWindow = {};
|
|
932
|
+
Object.getOwnPropertyNames(globalContext).forEach((p) => {
|
|
933
|
+
const descriptor = Object.getOwnPropertyDescriptor(globalContext, p);
|
|
934
|
+
if (descriptor && !descriptor.configurable) {
|
|
935
|
+
}
|
|
936
|
+
});
|
|
937
|
+
return { fakeWindow, propertiesWithGetter };
|
|
938
|
+
}
|
|
939
|
+
isConstructor(fn) {
|
|
940
|
+
const prototype = fn.prototype;
|
|
941
|
+
return !!(prototype && prototype.constructor === fn && Object.getOwnPropertyNames(prototype).length > 0);
|
|
942
|
+
}
|
|
943
|
+
isNativeFunction(fn) {
|
|
944
|
+
return fn.toString().indexOf("[native code]") > -1;
|
|
945
|
+
}
|
|
946
|
+
/**
|
|
947
|
+
* 劫持全局副作用 API
|
|
948
|
+
*/
|
|
949
|
+
patchGlobalEffects(fakeWindow) {
|
|
950
|
+
fakeWindow.setTimeout = (handler, timeout, ...args) => {
|
|
951
|
+
const id = this.globalContext.setTimeout(handler, timeout, ...args);
|
|
952
|
+
this.effectPool.timeouts.add(id);
|
|
953
|
+
return id;
|
|
954
|
+
};
|
|
955
|
+
fakeWindow.clearTimeout = (id) => {
|
|
956
|
+
if (id) {
|
|
957
|
+
this.effectPool.timeouts.delete(id);
|
|
958
|
+
this.globalContext.clearTimeout(id);
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
fakeWindow.setInterval = (handler, timeout, ...args) => {
|
|
962
|
+
const id = this.globalContext.setInterval(handler, timeout, ...args);
|
|
963
|
+
this.effectPool.intervals.add(id);
|
|
964
|
+
return id;
|
|
965
|
+
};
|
|
966
|
+
fakeWindow.clearInterval = (id) => {
|
|
967
|
+
if (id) {
|
|
968
|
+
this.effectPool.intervals.delete(id);
|
|
969
|
+
this.globalContext.clearInterval(id);
|
|
970
|
+
}
|
|
971
|
+
};
|
|
972
|
+
fakeWindow.addEventListener = (type, listener, options) => {
|
|
973
|
+
const listeners = this.effectPool.listeners.get(type) || [];
|
|
974
|
+
listeners.push({ listener, options });
|
|
975
|
+
this.effectPool.listeners.set(type, listeners);
|
|
976
|
+
return this.globalContext.addEventListener(type, listener, options);
|
|
977
|
+
};
|
|
978
|
+
fakeWindow.removeEventListener = (type, listener, options) => {
|
|
979
|
+
const listeners = this.effectPool.listeners.get(type);
|
|
980
|
+
if (listeners) {
|
|
981
|
+
const index = listeners.findIndex((item) => item.listener === listener && item.options === options);
|
|
982
|
+
if (index !== -1) listeners.splice(index, 1);
|
|
983
|
+
}
|
|
984
|
+
return this.globalContext.removeEventListener(type, listener, options);
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
};
|
|
988
|
+
|
|
989
|
+
// src/domain/plugin-sandbox.ts
|
|
990
|
+
var PluginSandbox = class {
|
|
991
|
+
pluginId;
|
|
992
|
+
storageManager;
|
|
993
|
+
constructor(pluginId, storageManager) {
|
|
994
|
+
this.pluginId = pluginId;
|
|
995
|
+
this.storageManager = storageManager;
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* 获取隔离的存储接口
|
|
999
|
+
*/
|
|
1000
|
+
get storage() {
|
|
1001
|
+
return this.storageManager.getContextStorage(this.pluginId);
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* 获取隔离的日志接口
|
|
1005
|
+
*/
|
|
1006
|
+
get logger() {
|
|
1007
|
+
return createLogger(`Plugin:${this.pluginId}`);
|
|
1008
|
+
}
|
|
1009
|
+
};
|
|
1010
|
+
|
|
1011
|
+
// src/domain/plugin-runtime.ts
|
|
1012
|
+
var logger6 = createLogger("PluginRuntime");
|
|
1013
|
+
var PluginRuntime = class {
|
|
1014
|
+
plugin;
|
|
1015
|
+
context;
|
|
1016
|
+
storageSandbox;
|
|
1017
|
+
windowSandbox;
|
|
1018
|
+
isLoaded = false;
|
|
1019
|
+
isMounted = false;
|
|
1020
|
+
constructor(plugin, sharedContext, storageManager) {
|
|
1021
|
+
this.plugin = plugin;
|
|
1022
|
+
this.storageSandbox = new PluginSandbox(plugin.id, storageManager);
|
|
1023
|
+
this.windowSandbox = new ProxySandbox(plugin.id);
|
|
1024
|
+
this.context = {
|
|
1025
|
+
pluginId: plugin.id,
|
|
1026
|
+
api: sharedContext.api,
|
|
1027
|
+
events: sharedContext.events,
|
|
1028
|
+
storage: this.storageSandbox.storage,
|
|
1029
|
+
logger: this.storageSandbox.logger,
|
|
1030
|
+
window: this.windowSandbox.proxy,
|
|
1031
|
+
getService: (name) => serviceRegistry.get(name),
|
|
1032
|
+
registerService: (name, service) => serviceRegistry.register(`${plugin.id}.${name}`, service)
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* 加载插件 (onLoad)
|
|
1037
|
+
* @description 注册服务、初始化非 UI 逻辑
|
|
1038
|
+
*/
|
|
1039
|
+
async load() {
|
|
1040
|
+
if (this.isLoaded) return;
|
|
1041
|
+
logger6.debug(`\u6B63\u5728\u52A0\u8F7D\u63D2\u4EF6: ${this.plugin.id}`);
|
|
1042
|
+
try {
|
|
1043
|
+
if (this.plugin.metadata.api && this.context.api && typeof this.context.api.register === "function") {
|
|
1044
|
+
this.context.api.register(this.plugin.metadata.api);
|
|
1045
|
+
logger6.debug(`\u5DF2\u4E3A\u63D2\u4EF6 ${this.plugin.id} \u81EA\u52A8\u6CE8\u518C API \u914D\u7F6E`);
|
|
1046
|
+
}
|
|
1047
|
+
if (this.plugin.onLoad) {
|
|
1048
|
+
await this.plugin.onLoad(this.context);
|
|
1049
|
+
}
|
|
1050
|
+
this.isLoaded = true;
|
|
1051
|
+
logger6.info(`\u63D2\u4EF6 ${this.plugin.id} \u5DF2\u52A0\u8F7D\u3002`);
|
|
1052
|
+
} catch (error) {
|
|
1053
|
+
logger6.error(`\u63D2\u4EF6 ${this.plugin.id} \u52A0\u8F7D\u5931\u8D25:`, error);
|
|
1054
|
+
throw error;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* 挂载插件 (onMount)
|
|
1059
|
+
* @description 激活沙箱、处理 UI 相关的副作用
|
|
1060
|
+
*/
|
|
1061
|
+
async mount() {
|
|
1062
|
+
if (!this.isLoaded) await this.load();
|
|
1063
|
+
if (this.isMounted) return;
|
|
1064
|
+
logger6.debug(`\u6B63\u5728\u6302\u8F7D\u63D2\u4EF6: ${this.plugin.id}`);
|
|
1065
|
+
try {
|
|
1066
|
+
this.windowSandbox.active();
|
|
1067
|
+
if (this.plugin.onMount) {
|
|
1068
|
+
this.plugin.onMount(this.context);
|
|
1069
|
+
}
|
|
1070
|
+
this.isMounted = true;
|
|
1071
|
+
logger6.info(`\u63D2\u4EF6 ${this.plugin.id} \u5DF2\u6302\u8F7D\u3002`);
|
|
1072
|
+
} catch (error) {
|
|
1073
|
+
logger6.error(`\u63D2\u4EF6 ${this.plugin.id} \u6302\u8F7D\u5931\u8D25:`, error);
|
|
1074
|
+
throw error;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
/**
|
|
1078
|
+
* 卸载插件 (onUnmount)
|
|
1079
|
+
*/
|
|
1080
|
+
async unmount() {
|
|
1081
|
+
if (!this.isMounted) return;
|
|
1082
|
+
logger6.debug(`\u6B63\u5728\u5378\u8F7D\u63D2\u4EF6: ${this.plugin.id}`);
|
|
1083
|
+
try {
|
|
1084
|
+
if (this.plugin.onUnmount) {
|
|
1085
|
+
this.plugin.onUnmount(this.context);
|
|
1086
|
+
}
|
|
1087
|
+
} catch (error) {
|
|
1088
|
+
logger6.error(`\u63D2\u4EF6 ${this.plugin.id} \u5378\u8F7D\u65F6\u51FA\u9519:`, error);
|
|
1089
|
+
} finally {
|
|
1090
|
+
this.windowSandbox.inactive();
|
|
1091
|
+
this.isMounted = false;
|
|
1092
|
+
logger6.info(`\u63D2\u4EF6 ${this.plugin.id} \u5DF2\u5378\u8F7D\u3002`);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* 销毁插件 (完全移除)
|
|
1097
|
+
*/
|
|
1098
|
+
async destroy() {
|
|
1099
|
+
await this.unmount();
|
|
1100
|
+
this.isLoaded = false;
|
|
1101
|
+
}
|
|
1102
|
+
get status() {
|
|
1103
|
+
if (this.isMounted) return "mounted";
|
|
1104
|
+
if (this.isLoaded) return "loaded";
|
|
1105
|
+
return "initial";
|
|
1106
|
+
}
|
|
1107
|
+
};
|
|
1108
|
+
|
|
1109
|
+
// src/adapters/scoped-storage-adapter.ts
|
|
1110
|
+
var ScopedStorageAdapter = class {
|
|
1111
|
+
constructor(underlyingStorage, prefix) {
|
|
1112
|
+
this.underlyingStorage = underlyingStorage;
|
|
1113
|
+
this.prefix = prefix;
|
|
1114
|
+
}
|
|
1115
|
+
getKey(key) {
|
|
1116
|
+
return this.prefix ? `${this.prefix}:${key}` : key;
|
|
1117
|
+
}
|
|
1118
|
+
getOriginalKey(namespacedKey) {
|
|
1119
|
+
if (!this.prefix) return namespacedKey;
|
|
1120
|
+
if (namespacedKey.startsWith(this.prefix + ":")) {
|
|
1121
|
+
return namespacedKey.slice(this.prefix.length + 1);
|
|
1122
|
+
}
|
|
1123
|
+
return null;
|
|
1124
|
+
}
|
|
1125
|
+
getItem(key) {
|
|
1126
|
+
return this.underlyingStorage.getItem(this.getKey(key));
|
|
1127
|
+
}
|
|
1128
|
+
setItem(key, value) {
|
|
1129
|
+
this.underlyingStorage.setItem(this.getKey(key), value);
|
|
1130
|
+
}
|
|
1131
|
+
removeItem(key) {
|
|
1132
|
+
this.underlyingStorage.removeItem(this.getKey(key));
|
|
1133
|
+
}
|
|
1134
|
+
clear() {
|
|
1135
|
+
if (!this.prefix) {
|
|
1136
|
+
this.underlyingStorage.clear();
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
const keysToRemove = [];
|
|
1140
|
+
for (let i = 0; i < this.underlyingStorage.length; i++) {
|
|
1141
|
+
const key = this.underlyingStorage.key(i);
|
|
1142
|
+
if (key && key.startsWith(this.prefix + ":")) {
|
|
1143
|
+
keysToRemove.push(key);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
keysToRemove.forEach((k) => this.underlyingStorage.removeItem(k));
|
|
1147
|
+
}
|
|
1148
|
+
get length() {
|
|
1149
|
+
let count = 0;
|
|
1150
|
+
for (let i = 0; i < this.underlyingStorage.length; i++) {
|
|
1151
|
+
const key = this.underlyingStorage.key(i);
|
|
1152
|
+
if (key && key.startsWith(this.prefix + ":")) {
|
|
1153
|
+
count++;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
return count;
|
|
1157
|
+
}
|
|
1158
|
+
key(index) {
|
|
1159
|
+
let count = 0;
|
|
1160
|
+
for (let i = 0; i < this.underlyingStorage.length; i++) {
|
|
1161
|
+
const key = this.underlyingStorage.key(i);
|
|
1162
|
+
if (key && key.startsWith(this.prefix + ":")) {
|
|
1163
|
+
if (count === index) {
|
|
1164
|
+
return this.getOriginalKey(key);
|
|
1165
|
+
}
|
|
1166
|
+
count++;
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
return null;
|
|
1170
|
+
}
|
|
1171
|
+
};
|
|
1172
|
+
|
|
1173
|
+
// src/domain/storage-manager.ts
|
|
1174
|
+
var StorageManager = class {
|
|
1175
|
+
baseStorage;
|
|
1176
|
+
schemas = /* @__PURE__ */ new Map();
|
|
1177
|
+
constructor(baseStorage) {
|
|
1178
|
+
this.baseStorage = baseStorage;
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* 注册插件存储 Schema
|
|
1182
|
+
*/
|
|
1183
|
+
registerSchema(pluginId, schema) {
|
|
1184
|
+
this.schemas.set(pluginId, schema);
|
|
1185
|
+
}
|
|
1186
|
+
/**
|
|
1187
|
+
* 验证 Key 是否符合 Schema 定义 (仅在开发环境或严格模式下警告)
|
|
1188
|
+
*/
|
|
1189
|
+
validateKey(pluginId, key, scope = "plugin") {
|
|
1190
|
+
const schemaList = this.schemas.get(pluginId);
|
|
1191
|
+
if (!schemaList) return;
|
|
1192
|
+
const item = schemaList.find((s) => s.key === key);
|
|
1193
|
+
if (!item) {
|
|
1194
|
+
console.warn(`[Storage] Key "${key}" not defined in plugin "${pluginId}" schema.`);
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
const definedScope = item.scope || "plugin";
|
|
1198
|
+
if (definedScope !== scope) {
|
|
1199
|
+
console.warn(`[Storage] Key "${key}" defined in scope "${definedScope}" but accessed via "${scope}".`);
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* 获取插件专用存储适配器
|
|
1204
|
+
* @param pluginId 插件 ID
|
|
1205
|
+
*/
|
|
1206
|
+
getPluginStorage(pluginId) {
|
|
1207
|
+
return new ScopedStorageAdapter(this.baseStorage, `plugin:${pluginId}`);
|
|
1208
|
+
}
|
|
1209
|
+
/**
|
|
1210
|
+
* 获取共享存储适配器
|
|
1211
|
+
*/
|
|
1212
|
+
getSharedStorage() {
|
|
1213
|
+
return new ScopedStorageAdapter(this.baseStorage, "shared");
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* 获取系统存储适配器
|
|
1217
|
+
*/
|
|
1218
|
+
getSystemStorage() {
|
|
1219
|
+
return new ScopedStorageAdapter(this.baseStorage, "system");
|
|
1220
|
+
}
|
|
1221
|
+
/**
|
|
1222
|
+
* 获取插件上下文中的 storage 对象 (包含类型转换辅助方法)
|
|
1223
|
+
* @param pluginId 插件 ID
|
|
1224
|
+
*/
|
|
1225
|
+
getContextStorage(pluginId) {
|
|
1226
|
+
const pluginStorage = this.getPluginStorage(pluginId);
|
|
1227
|
+
const sharedStorage = this.getSharedStorage();
|
|
1228
|
+
const createHelpers = (adapter, scope) => ({
|
|
1229
|
+
get: (key) => {
|
|
1230
|
+
this.validateKey(pluginId, key, scope);
|
|
1231
|
+
try {
|
|
1232
|
+
const val = adapter.getItem(key);
|
|
1233
|
+
if (val === null) {
|
|
1234
|
+
const schema = this.schemas.get(pluginId)?.find((s) => s.key === key);
|
|
1235
|
+
if (schema && schema.default !== void 0) {
|
|
1236
|
+
return schema.default;
|
|
1237
|
+
}
|
|
1238
|
+
return null;
|
|
1239
|
+
}
|
|
1240
|
+
try {
|
|
1241
|
+
return JSON.parse(val);
|
|
1242
|
+
} catch {
|
|
1243
|
+
return val;
|
|
1244
|
+
}
|
|
1245
|
+
} catch (e) {
|
|
1246
|
+
console.warn(`[Storage] Failed to read key "${key}"`, e);
|
|
1247
|
+
return null;
|
|
1248
|
+
}
|
|
1249
|
+
},
|
|
1250
|
+
set: (key, value) => {
|
|
1251
|
+
this.validateKey(pluginId, key, scope);
|
|
1252
|
+
try {
|
|
1253
|
+
adapter.setItem(key, JSON.stringify(value));
|
|
1254
|
+
} catch (e) {
|
|
1255
|
+
console.warn(`[Storage] Failed to stringify key "${key}"`, e);
|
|
1256
|
+
}
|
|
1257
|
+
},
|
|
1258
|
+
remove: (key) => {
|
|
1259
|
+
this.validateKey(pluginId, key, scope);
|
|
1260
|
+
adapter.removeItem(key);
|
|
1261
|
+
}
|
|
1262
|
+
});
|
|
1263
|
+
return {
|
|
1264
|
+
...createHelpers(pluginStorage, "plugin"),
|
|
1265
|
+
shared: createHelpers(sharedStorage, "shared")
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
};
|
|
1269
|
+
|
|
1270
|
+
// src/domain/plugin-manager.ts
|
|
1271
|
+
var logger7 = createLogger("PluginManager");
|
|
1272
|
+
var PluginManager = class {
|
|
1273
|
+
/** 全局事件总线 */
|
|
1274
|
+
eventBus = new DefaultEventBus();
|
|
1275
|
+
/** 存储接口 */
|
|
1276
|
+
storageManager;
|
|
1277
|
+
/** 所有插件运行时实例 */
|
|
1278
|
+
runtimes = /* @__PURE__ */ new Map();
|
|
1279
|
+
/** 所有注册的插件(原始数据) */
|
|
1280
|
+
plugins = /* @__PURE__ */ new Map();
|
|
1281
|
+
/** 收集的路由 */
|
|
1282
|
+
routes = [];
|
|
1283
|
+
/** 收集的扩展点 */
|
|
1284
|
+
extensions = /* @__PURE__ */ new Map();
|
|
1285
|
+
/** 插件状态管理(启用/禁用、排序) */
|
|
1286
|
+
pluginStates = {};
|
|
1287
|
+
/** 状态变更监听器 */
|
|
1288
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1289
|
+
/** 共享上下文缓存 */
|
|
1290
|
+
sharedContext = null;
|
|
1291
|
+
/** 收集的工具函数 */
|
|
1292
|
+
utils = {};
|
|
1293
|
+
constructor(storage) {
|
|
1294
|
+
this.storageManager = new StorageManager(storage);
|
|
1295
|
+
this.loadStates();
|
|
1296
|
+
this.subscribe(() => {
|
|
1297
|
+
this.saveStates();
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
loadStates() {
|
|
1301
|
+
try {
|
|
1302
|
+
const systemStorage = this.storageManager.getSystemStorage();
|
|
1303
|
+
const savedStates = systemStorage.getItem("plugin_states");
|
|
1304
|
+
if (savedStates) {
|
|
1305
|
+
this.pluginStates = JSON.parse(savedStates);
|
|
1306
|
+
logger7.debug("\u4ECE\u7CFB\u7EDF\u5B58\u50A8\u4E2D\u52A0\u8F7D\u72B6\u6001:", this.pluginStates);
|
|
1307
|
+
}
|
|
1308
|
+
} catch (e) {
|
|
1309
|
+
logger7.error("\u52A0\u8F7D\u63D2\u4EF6\u72B6\u6001\u5931\u8D25:", e);
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
saveStates() {
|
|
1313
|
+
try {
|
|
1314
|
+
this.storageManager.getSystemStorage().setItem("plugin_states", JSON.stringify(this.pluginStates));
|
|
1315
|
+
logger7.debug("\u5DF2\u4FDD\u5B58\u63D2\u4EF6\u72B6\u6001\u5230\u5B58\u50A8");
|
|
1316
|
+
} catch (e) {
|
|
1317
|
+
logger7.error("\u4FDD\u5B58\u63D2\u4EF6\u72B6\u6001\u5931\u8D25:", e);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
/**
|
|
1321
|
+
* 订阅插件状态变更
|
|
1322
|
+
* @param listener 监听函数
|
|
1323
|
+
* @returns 取消订阅函数
|
|
1324
|
+
*/
|
|
1325
|
+
subscribe(listener) {
|
|
1326
|
+
this.listeners.add(listener);
|
|
1327
|
+
return () => {
|
|
1328
|
+
this.listeners.delete(listener);
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1331
|
+
getStorageManager() {
|
|
1332
|
+
return this.storageManager;
|
|
1333
|
+
}
|
|
1334
|
+
/**
|
|
1335
|
+
* 触发状态变更通知
|
|
1336
|
+
*/
|
|
1337
|
+
notify() {
|
|
1338
|
+
this.listeners.forEach((listener) => listener());
|
|
1339
|
+
}
|
|
1340
|
+
/**
|
|
1341
|
+
* 获取所有已注册的插件
|
|
1342
|
+
*/
|
|
1343
|
+
getPlugins() {
|
|
1344
|
+
return Array.from(this.plugins.values()).sort((a, b) => {
|
|
1345
|
+
const stateA = this.pluginStates[a.id] || { order: 0 };
|
|
1346
|
+
const stateB = this.pluginStates[b.id] || { order: 0 };
|
|
1347
|
+
return stateA.order - stateB.order;
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
/**
|
|
1351
|
+
* 获取插件状态
|
|
1352
|
+
* @param pluginId 插件 ID
|
|
1353
|
+
*/
|
|
1354
|
+
getPluginState(pluginId) {
|
|
1355
|
+
return this.pluginStates[pluginId] || { enabled: true, order: 0 };
|
|
1356
|
+
}
|
|
1357
|
+
/**
|
|
1358
|
+
* 检查插件是否启用
|
|
1359
|
+
* @param pluginId 插件 ID
|
|
1360
|
+
*/
|
|
1361
|
+
isPluginEnabled(pluginId) {
|
|
1362
|
+
const state = this.pluginStates[pluginId];
|
|
1363
|
+
return state ? state.enabled : true;
|
|
1364
|
+
}
|
|
1365
|
+
/**
|
|
1366
|
+
* 切换插件启用状态
|
|
1367
|
+
* @param pluginId 插件 ID
|
|
1368
|
+
* @param enabled 是否启用
|
|
1369
|
+
*/
|
|
1370
|
+
togglePlugin(pluginId, enabled) {
|
|
1371
|
+
const state = this.pluginStates[pluginId] || { enabled: true, order: 0 };
|
|
1372
|
+
this.pluginStates[pluginId] = { ...state, enabled };
|
|
1373
|
+
if (!enabled) {
|
|
1374
|
+
const runtime = this.runtimes.get(pluginId);
|
|
1375
|
+
if (runtime) {
|
|
1376
|
+
runtime.unmount();
|
|
1377
|
+
this.runtimes.delete(pluginId);
|
|
1378
|
+
}
|
|
1379
|
+
} else {
|
|
1380
|
+
if (this.sharedContext) {
|
|
1381
|
+
const plugin = this.plugins.get(pluginId);
|
|
1382
|
+
if (plugin) {
|
|
1383
|
+
try {
|
|
1384
|
+
const runtime = new PluginRuntime(plugin, this.sharedContext, this.storageManager);
|
|
1385
|
+
this.runtimes.set(pluginId, runtime);
|
|
1386
|
+
runtime.mount();
|
|
1387
|
+
} catch (e) {
|
|
1388
|
+
logger7.error(`\u542F\u7528\u63D2\u4EF6 ${pluginId} \u5931\u8D25:`, e);
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
this.notify();
|
|
1394
|
+
}
|
|
1395
|
+
/**
|
|
1396
|
+
* 设置插件排序
|
|
1397
|
+
* @param pluginId 插件 ID
|
|
1398
|
+
* @param order 排序值
|
|
1399
|
+
*/
|
|
1400
|
+
setPluginOrder(pluginId, order) {
|
|
1401
|
+
const state = this.pluginStates[pluginId] || { enabled: true, order: 0 };
|
|
1402
|
+
this.pluginStates[pluginId] = { ...state, order };
|
|
1403
|
+
this.notify();
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* 获取插件的统一能力描述
|
|
1407
|
+
* @param pluginId 插件 ID
|
|
1408
|
+
*/
|
|
1409
|
+
getUnifiedCapabilities(pluginId) {
|
|
1410
|
+
const plugin = this.plugins.get(pluginId);
|
|
1411
|
+
return plugin?.metadata.capabilities || {};
|
|
1412
|
+
}
|
|
1413
|
+
/**
|
|
1414
|
+
* 更新插件配置
|
|
1415
|
+
* @param pluginId 插件 ID
|
|
1416
|
+
* @param key 配置项 Key
|
|
1417
|
+
* @param value 配置值
|
|
1418
|
+
*/
|
|
1419
|
+
updatePluginConfig(pluginId, key, value) {
|
|
1420
|
+
const currentConfig = configManager.get(pluginId) || {};
|
|
1421
|
+
currentConfig[key] = value;
|
|
1422
|
+
configManager.set(pluginId, currentConfig);
|
|
1423
|
+
try {
|
|
1424
|
+
this.storageManager.getContextStorage(pluginId).set(key, value);
|
|
1425
|
+
} catch (e) {
|
|
1426
|
+
logger7.warn("\u4FDD\u5B58\u914D\u7F6E\u5230\u5B58\u50A8\u5931\u8D25", e);
|
|
1427
|
+
}
|
|
1428
|
+
this.eventBus.emit("config:changed", { pluginId, key, value });
|
|
1429
|
+
}
|
|
1430
|
+
/**
|
|
1431
|
+
* 获取插件配置
|
|
1432
|
+
* @param pluginId 插件 ID
|
|
1433
|
+
* @param key 配置键
|
|
1434
|
+
* @returns 配置值
|
|
1435
|
+
*/
|
|
1436
|
+
getPluginConfig(pluginId, key) {
|
|
1437
|
+
const config = configManager.get(pluginId);
|
|
1438
|
+
return config ? config[key] : void 0;
|
|
1439
|
+
}
|
|
1440
|
+
/**
|
|
1441
|
+
* 获取指定插槽的扩展
|
|
1442
|
+
* @param slot 插槽位置
|
|
1443
|
+
*/
|
|
1444
|
+
getExtensions(slot) {
|
|
1445
|
+
const targetSlot = slot;
|
|
1446
|
+
let extensions = this.extensions.get(targetSlot) || [];
|
|
1447
|
+
extensions = extensions.filter((ext) => {
|
|
1448
|
+
const pluginId = ext._pluginId;
|
|
1449
|
+
return !pluginId || this.isPluginEnabled(pluginId);
|
|
1450
|
+
});
|
|
1451
|
+
return extensions.sort((a, b) => (a.order || 0) - (b.order || 0));
|
|
1452
|
+
}
|
|
1453
|
+
/**
|
|
1454
|
+
* 获取所有收集到的路由
|
|
1455
|
+
*/
|
|
1456
|
+
getRoutes() {
|
|
1457
|
+
const activeRoutes = [];
|
|
1458
|
+
this.getPlugins().forEach((plugin) => {
|
|
1459
|
+
if (this.isPluginEnabled(plugin.id) && plugin.metadata.routes) {
|
|
1460
|
+
activeRoutes.push(...plugin.metadata.routes);
|
|
1461
|
+
}
|
|
1462
|
+
});
|
|
1463
|
+
return activeRoutes;
|
|
1464
|
+
}
|
|
1465
|
+
/**
|
|
1466
|
+
* 注册插件
|
|
1467
|
+
* @param plugin 插件实例
|
|
1468
|
+
* @param notify 是否触发状态变更通知
|
|
1469
|
+
*/
|
|
1470
|
+
register(plugin, notify = true) {
|
|
1471
|
+
if (!this.validatePlugin(plugin)) {
|
|
1472
|
+
logger7.error(`\u63D2\u4EF6\u6CE8\u518C\u5931\u8D25: ${plugin?.id || "\u672A\u77E5"}`);
|
|
1473
|
+
return;
|
|
1474
|
+
}
|
|
1475
|
+
if (this.plugins.has(plugin.id)) {
|
|
1476
|
+
return;
|
|
1477
|
+
}
|
|
1478
|
+
if (plugin.metadata.storage) {
|
|
1479
|
+
this.storageManager.registerSchema(plugin.id, plugin.metadata.storage);
|
|
1480
|
+
}
|
|
1481
|
+
if (!this.pluginStates[plugin.id]) {
|
|
1482
|
+
this.pluginStates[plugin.id] = { enabled: true, order: 0 };
|
|
1483
|
+
}
|
|
1484
|
+
if (plugin.defaultConfig) {
|
|
1485
|
+
const existingConfig = configManager.get(plugin.id) || {};
|
|
1486
|
+
const mergedConfig = { ...plugin.defaultConfig, ...existingConfig };
|
|
1487
|
+
configManager.set(plugin.id, mergedConfig);
|
|
1488
|
+
}
|
|
1489
|
+
switch (plugin.metadata.type) {
|
|
1490
|
+
case "business":
|
|
1491
|
+
this.handleBusinessPlugin(plugin);
|
|
1492
|
+
break;
|
|
1493
|
+
case "functional":
|
|
1494
|
+
this.handleFunctionalPlugin(plugin);
|
|
1495
|
+
break;
|
|
1496
|
+
case "view":
|
|
1497
|
+
this.handleViewPlugin(plugin);
|
|
1498
|
+
break;
|
|
1499
|
+
case "theme":
|
|
1500
|
+
this.handleThemePlugin(plugin);
|
|
1501
|
+
break;
|
|
1502
|
+
case "system":
|
|
1503
|
+
this.handleSystemPlugin(plugin);
|
|
1504
|
+
break;
|
|
1505
|
+
case "renderer":
|
|
1506
|
+
break;
|
|
1507
|
+
default:
|
|
1508
|
+
logger7.warn(`\u63D2\u4EF6 ${plugin.id} \u7C7B\u578B\u672A\u77E5: ${plugin.metadata.type}`);
|
|
1509
|
+
break;
|
|
1510
|
+
}
|
|
1511
|
+
if (plugin.metadata.routes && plugin.metadata.routes.length > 0) {
|
|
1512
|
+
logger7.info(`\u5DF2\u4ECE\u63D2\u4EF6 ${plugin.id} \u6536\u96C6\u8DEF\u7531:`, plugin.metadata.routes);
|
|
1513
|
+
}
|
|
1514
|
+
if (plugin.metadata.extensions && plugin.metadata.extensions.length > 0) {
|
|
1515
|
+
plugin.metadata.extensions.forEach((ext) => {
|
|
1516
|
+
const list = this.extensions.get(ext.slot) || [];
|
|
1517
|
+
list.push({ ...ext, _pluginId: plugin.id });
|
|
1518
|
+
this.extensions.set(ext.slot, list);
|
|
1519
|
+
});
|
|
1520
|
+
logger7.info(`\u5DF2\u4ECE\u63D2\u4EF6 ${plugin.id} \u6536\u96C6\u6269\u5C55\u70B9`);
|
|
1521
|
+
}
|
|
1522
|
+
this.plugins.set(plugin.id, plugin);
|
|
1523
|
+
logger7.info(`\u63D2\u4EF6 ${plugin.id} \u5DF2\u6CE8\u518C\u4E3A ${plugin.metadata.type}\u3002`);
|
|
1524
|
+
if (notify) {
|
|
1525
|
+
this.notify();
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
/**
|
|
1529
|
+
* 初始化所有插件
|
|
1530
|
+
* @param sharedContext 共享上下文
|
|
1531
|
+
*/
|
|
1532
|
+
async initPlugins(sharedContext = {}) {
|
|
1533
|
+
this.sharedContext = {
|
|
1534
|
+
...sharedContext,
|
|
1535
|
+
events: this.eventBus
|
|
1536
|
+
};
|
|
1537
|
+
this.plugins.forEach((plugin) => {
|
|
1538
|
+
if (!this.isPluginEnabled(plugin.id)) return;
|
|
1539
|
+
if (!this.runtimes.has(plugin.id)) {
|
|
1540
|
+
const runtime = new PluginRuntime(plugin, this.sharedContext, this.storageManager);
|
|
1541
|
+
this.runtimes.set(plugin.id, runtime);
|
|
1542
|
+
}
|
|
1543
|
+
});
|
|
1544
|
+
const sortedPluginIds = this.getSortedPluginIds();
|
|
1545
|
+
for (const id of sortedPluginIds) {
|
|
1546
|
+
const runtime = this.runtimes.get(id);
|
|
1547
|
+
if (runtime) {
|
|
1548
|
+
try {
|
|
1549
|
+
await runtime.load();
|
|
1550
|
+
} catch (e) {
|
|
1551
|
+
logger7.error(`\u63D2\u4EF6 ${id} \u52A0\u8F7D\u5931\u8D25:`, e);
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
for (const id of sortedPluginIds) {
|
|
1556
|
+
const runtime = this.runtimes.get(id);
|
|
1557
|
+
if (runtime) {
|
|
1558
|
+
try {
|
|
1559
|
+
await runtime.mount();
|
|
1560
|
+
} catch (e) {
|
|
1561
|
+
logger7.error(`\u63D2\u4EF6 ${id} \u6302\u8F7D\u5931\u8D25:`, e);
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
/**
|
|
1567
|
+
* 获取排序后的插件 ID 列表 (处理依赖)
|
|
1568
|
+
*/
|
|
1569
|
+
getSortedPluginIds() {
|
|
1570
|
+
const ids = Array.from(this.runtimes.keys());
|
|
1571
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1572
|
+
const sorted = [];
|
|
1573
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
1574
|
+
const visit = (id) => {
|
|
1575
|
+
if (visited.has(id)) return;
|
|
1576
|
+
if (visiting.has(id)) {
|
|
1577
|
+
logger7.error(`\u5FAA\u73AF\u4F9D\u8D56\u68C0\u6D4B\u5230: ${id}`);
|
|
1578
|
+
return;
|
|
1579
|
+
}
|
|
1580
|
+
visiting.add(id);
|
|
1581
|
+
const plugin = this.plugins.get(id);
|
|
1582
|
+
if (plugin?.metadata.dependencies) {
|
|
1583
|
+
plugin.metadata.dependencies.forEach((depId) => {
|
|
1584
|
+
if (this.runtimes.has(depId)) {
|
|
1585
|
+
visit(depId);
|
|
1586
|
+
}
|
|
1587
|
+
});
|
|
1588
|
+
}
|
|
1589
|
+
visiting.delete(id);
|
|
1590
|
+
visited.add(id);
|
|
1591
|
+
sorted.push(id);
|
|
1592
|
+
};
|
|
1593
|
+
const priorityMap = {
|
|
1594
|
+
"system": 100,
|
|
1595
|
+
"functional": 50,
|
|
1596
|
+
"business": 10
|
|
1597
|
+
};
|
|
1598
|
+
const sortedIdsByType = [...ids].sort((a, b) => {
|
|
1599
|
+
const pA = priorityMap[this.plugins.get(a)?.metadata.type || ""] || 0;
|
|
1600
|
+
const pB = priorityMap[this.plugins.get(b)?.metadata.type || ""] || 0;
|
|
1601
|
+
return pB - pA;
|
|
1602
|
+
});
|
|
1603
|
+
sortedIdsByType.forEach((id) => visit(id));
|
|
1604
|
+
return sorted;
|
|
1605
|
+
}
|
|
1606
|
+
/**
|
|
1607
|
+
* 加载插件列表
|
|
1608
|
+
* @param configs 插件配置
|
|
1609
|
+
* @param registry 插件注册表 (动态导入函数)
|
|
1610
|
+
*/
|
|
1611
|
+
async loadPlugins(configs, registry) {
|
|
1612
|
+
logger7.info("\u5F00\u59CB\u52A0\u8F7D\u63D2\u4EF6...");
|
|
1613
|
+
const offlineLoadPromises = Object.entries(registry).map(async ([pluginId, importFn]) => {
|
|
1614
|
+
try {
|
|
1615
|
+
const module2 = await importFn();
|
|
1616
|
+
return this.instantiatePlugin(pluginId, module2, configs[pluginId]);
|
|
1617
|
+
} catch (e) {
|
|
1618
|
+
logger7.error(`\u52A0\u8F7D\u79BB\u7EBF\u63D2\u4EF6\u6A21\u5757 ${pluginId} \u5931\u8D25:`, e);
|
|
1619
|
+
return null;
|
|
1620
|
+
}
|
|
1621
|
+
});
|
|
1622
|
+
const onlineLoadPromises = Object.entries(configs).filter(([id, config]) => config.url && !registry[id]).map(async ([pluginId, config]) => {
|
|
1623
|
+
try {
|
|
1624
|
+
return await this.loadRemotePlugin(pluginId, config.url, config);
|
|
1625
|
+
} catch (e) {
|
|
1626
|
+
logger7.error(`\u52A0\u8F7D\u5728\u7EBF\u63D2\u4EF6 ${pluginId} \u5931\u8D25:`, e);
|
|
1627
|
+
return null;
|
|
1628
|
+
}
|
|
1629
|
+
});
|
|
1630
|
+
const loadedPlugins = await Promise.all([...offlineLoadPromises, ...onlineLoadPromises]);
|
|
1631
|
+
loadedPlugins.forEach((plugin) => {
|
|
1632
|
+
if (plugin) {
|
|
1633
|
+
this.register(plugin, false);
|
|
1634
|
+
}
|
|
1635
|
+
});
|
|
1636
|
+
this.notify();
|
|
1637
|
+
logger7.info(`\u63D2\u4EF6\u52A0\u8F7D\u5B8C\u6210\uFF0C\u5171\u52A0\u8F7D ${this.plugins.size} \u4E2A\u63D2\u4EF6`);
|
|
1638
|
+
}
|
|
1639
|
+
/**
|
|
1640
|
+
* 加载远程插件
|
|
1641
|
+
* @param pluginId 插件 ID
|
|
1642
|
+
* @param url 远程 URL
|
|
1643
|
+
* @param config 插件配置
|
|
1644
|
+
*/
|
|
1645
|
+
async loadRemotePlugin(pluginId, url, config) {
|
|
1646
|
+
logger7.info(`\u6B63\u5728\u4ECE ${url} \u52A0\u8F7D\u8FDC\u7A0B\u63D2\u4EF6 ${pluginId}...`);
|
|
1647
|
+
try {
|
|
1648
|
+
const module2 = await import(
|
|
1649
|
+
/* @vite-ignore */
|
|
1650
|
+
url
|
|
1651
|
+
);
|
|
1652
|
+
return this.instantiatePlugin(pluginId, module2, config);
|
|
1653
|
+
} catch (e) {
|
|
1654
|
+
logger7.warn(`ESM \u52A0\u8F7D\u5931\u8D25\uFF0C\u5C1D\u8BD5 IIFE \u52A0\u8F7D: ${pluginId}`);
|
|
1655
|
+
return new Promise((resolve, reject) => {
|
|
1656
|
+
const script = document.createElement("script");
|
|
1657
|
+
script.src = url;
|
|
1658
|
+
script.onload = () => {
|
|
1659
|
+
const globalName = pluginId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1660
|
+
const pluginModule = window[globalName];
|
|
1661
|
+
if (pluginModule) {
|
|
1662
|
+
resolve(this.instantiatePlugin(pluginId, pluginModule, config));
|
|
1663
|
+
} else {
|
|
1664
|
+
reject(new Error(`\u8FDC\u7A0B\u63D2\u4EF6 ${pluginId} \u52A0\u8F7D\u540E\u672A\u627E\u5230\u5168\u5C40\u53D8\u91CF ${globalName}`));
|
|
1665
|
+
}
|
|
1666
|
+
};
|
|
1667
|
+
script.onerror = () => reject(new Error(`\u8FDC\u7A0B\u63D2\u4EF6 ${pluginId} \u52A0\u8F7D\u5931\u8D25: ${url}`));
|
|
1668
|
+
document.head.appendChild(script);
|
|
1669
|
+
});
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
/**
|
|
1673
|
+
* 实例化插件
|
|
1674
|
+
*/
|
|
1675
|
+
instantiatePlugin(pluginId, module2, config) {
|
|
1676
|
+
let PluginClass = module2.default;
|
|
1677
|
+
if (!PluginClass) {
|
|
1678
|
+
const key = Object.keys(module2).find((k) => k.endsWith("Plugin"));
|
|
1679
|
+
if (key) PluginClass = module2[key];
|
|
1680
|
+
}
|
|
1681
|
+
if (!PluginClass && typeof module2 === "object") {
|
|
1682
|
+
if (module2.id && module2.metadata) {
|
|
1683
|
+
PluginClass = module2;
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
if (PluginClass) {
|
|
1687
|
+
const pluginInstance = typeof PluginClass === "function" ? new PluginClass() : PluginClass;
|
|
1688
|
+
if (!pluginInstance.id && pluginInstance.metadata?.id) {
|
|
1689
|
+
pluginInstance.id = pluginInstance.metadata.id;
|
|
1690
|
+
} else if (!pluginInstance.id) {
|
|
1691
|
+
pluginInstance.id = pluginId;
|
|
1692
|
+
}
|
|
1693
|
+
if (config) {
|
|
1694
|
+
pluginInstance.defaultConfig = { ...pluginInstance.defaultConfig, ...config };
|
|
1695
|
+
}
|
|
1696
|
+
return pluginInstance;
|
|
1697
|
+
}
|
|
1698
|
+
logger7.warn(`\u6A21\u5757 ${pluginId} \u672A\u5BFC\u51FA\u6709\u6548\u7684\u63D2\u4EF6\u5165\u53E3`);
|
|
1699
|
+
return null;
|
|
1700
|
+
}
|
|
1701
|
+
// --- Private Handlers ---
|
|
1702
|
+
validatePlugin(plugin) {
|
|
1703
|
+
if (!plugin.id) return false;
|
|
1704
|
+
if (!plugin.metadata) return false;
|
|
1705
|
+
return true;
|
|
1706
|
+
}
|
|
1707
|
+
handleBusinessPlugin(plugin) {
|
|
1708
|
+
}
|
|
1709
|
+
handleFunctionalPlugin(plugin) {
|
|
1710
|
+
}
|
|
1711
|
+
handleViewPlugin(plugin) {
|
|
1712
|
+
}
|
|
1713
|
+
handleThemePlugin(plugin) {
|
|
1714
|
+
}
|
|
1715
|
+
handleSystemPlugin(plugin) {
|
|
1716
|
+
}
|
|
1717
|
+
};
|
|
1718
|
+
var pluginManager = new PluginManager(new LocalStorageAdapter());
|
|
1719
|
+
|
|
1720
|
+
// src/components/PluginSlot.tsx
|
|
1721
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1722
|
+
var PluginSlot = ({
|
|
1723
|
+
slot,
|
|
1724
|
+
props = {},
|
|
1725
|
+
className,
|
|
1726
|
+
style,
|
|
1727
|
+
renderItem,
|
|
1728
|
+
skeleton
|
|
1729
|
+
}) => {
|
|
1730
|
+
const extensions = pluginManager.getExtensions(slot);
|
|
1731
|
+
const items = (0, import_react3.useMemo)(() => {
|
|
1732
|
+
return extensions.map((ext, index) => {
|
|
1733
|
+
const Component2 = ext.component;
|
|
1734
|
+
const key = ext.meta?.key || `${ext.slot}-${ext.order || 0}-${index}`;
|
|
1735
|
+
return {
|
|
1736
|
+
key,
|
|
1737
|
+
extension: ext,
|
|
1738
|
+
component: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PluginErrorBoundary, { pluginId: `extension-${key}`, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Component2, { ...props }) }, key)
|
|
1739
|
+
};
|
|
1740
|
+
});
|
|
1741
|
+
}, [extensions, props, slot]);
|
|
1742
|
+
if (items.length === 0) {
|
|
1743
|
+
if (skeleton) {
|
|
1744
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: `plugin-slot plugin-slot-${slot} plugin-slot-skeleton ${className || ""}`, style, children: skeleton });
|
|
1745
|
+
}
|
|
1746
|
+
return null;
|
|
1747
|
+
}
|
|
1748
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: `plugin-slot plugin-slot-${slot} ${className || ""}`, style, children: renderItem ? items.map((item, index) => renderItem(item, index)) : items.map((item) => item.component) });
|
|
1749
|
+
};
|
|
1750
|
+
|
|
1751
|
+
// src/components/SlotSkeletons.tsx
|
|
1752
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1753
|
+
var SidebarIconSkeleton = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-12 h-11 px-3 flex items-center justify-center animate-pulse", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-6 h-6 bg-slate-200 dark:bg-white/10 rounded-lg" }) });
|
|
1754
|
+
var StatusBarItemSkeleton = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "h-4 w-16 bg-slate-200 dark:bg-white/10 rounded animate-pulse" });
|
|
1755
|
+
var AvatarSkeleton = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-10 h-10 rounded-full bg-slate-200 dark:bg-white/10 animate-pulse" });
|
|
1756
|
+
var BlockSkeleton = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: `bg-slate-200 dark:bg-white/10 rounded animate-pulse ${className || "w-full h-full"}` });
|
|
1757
|
+
|
|
1758
|
+
// src/domain/auto-loader.ts
|
|
1759
|
+
var import_meta = {};
|
|
1760
|
+
var logger8 = createLogger("AutoLoader");
|
|
1761
|
+
var resolvePluginRegistry = (options) => {
|
|
1762
|
+
const { modules, baseUrl, rules } = options;
|
|
1763
|
+
const registry = {};
|
|
1764
|
+
const compiledRules = rules.map((rule) => {
|
|
1765
|
+
const escapedSegment = rule.pathSegment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1766
|
+
return {
|
|
1767
|
+
...rule,
|
|
1768
|
+
regex: new RegExp(`${escapedSegment}/([^/]+)/src/index`)
|
|
1769
|
+
};
|
|
1770
|
+
});
|
|
1771
|
+
for (const relativePath in modules) {
|
|
1772
|
+
try {
|
|
1773
|
+
const path = new URL(relativePath, baseUrl).pathname;
|
|
1774
|
+
for (const rule of compiledRules) {
|
|
1775
|
+
const match = path.match(rule.regex);
|
|
1776
|
+
if (match && match[1]) {
|
|
1777
|
+
const dirName = match[1];
|
|
1778
|
+
const pluginId = `${rule.idPrefix}-${dirName}`;
|
|
1779
|
+
registry[pluginId] = modules[relativePath];
|
|
1780
|
+
logger8.info(`Found plugin: ${pluginId} at ${path}`);
|
|
1781
|
+
break;
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
} catch (e) {
|
|
1785
|
+
logger8.error(`Failed to resolve plugin at ${relativePath}:`, e);
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
return registry;
|
|
1789
|
+
};
|
|
1790
|
+
var discoverPlugins = (rules, baseUrl) => {
|
|
1791
|
+
const modules = import_meta.glob([
|
|
1792
|
+
"../../../../packages/plugins/*/src/index.{ts,tsx}",
|
|
1793
|
+
"../../../../apps/*/src/index.{ts,tsx}"
|
|
1794
|
+
]);
|
|
1795
|
+
return resolvePluginRegistry({
|
|
1796
|
+
modules,
|
|
1797
|
+
baseUrl,
|
|
1798
|
+
rules
|
|
1799
|
+
});
|
|
1800
|
+
};
|
|
1801
|
+
|
|
1802
|
+
// src/domain/models.ts
|
|
1803
|
+
var SUCCESS_CODE = "000000";
|
|
1804
|
+
|
|
1805
|
+
// src/plugin-context.tsx
|
|
1806
|
+
var import_react4 = require("react");
|
|
1807
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1808
|
+
var PluginContext = (0, import_react4.createContext)(null);
|
|
1809
|
+
var PluginProvider = ({ manager, children }) => {
|
|
1810
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PluginContext.Provider, { value: manager, children });
|
|
1811
|
+
};
|
|
1812
|
+
var usePluginManager = () => {
|
|
1813
|
+
const context = (0, import_react4.useContext)(PluginContext);
|
|
1814
|
+
if (!context) {
|
|
1815
|
+
throw new Error("usePluginManager must be used within a PluginProvider");
|
|
1816
|
+
}
|
|
1817
|
+
return context;
|
|
1818
|
+
};
|
|
1819
|
+
|
|
1820
|
+
// src/api/adapters/axios-adapter.ts
|
|
1821
|
+
var import_axios = __toESM(require("axios"));
|
|
1822
|
+
var AxiosAdapter = class {
|
|
1823
|
+
client;
|
|
1824
|
+
constructor(baseURL = "/api", timeout = 1e4) {
|
|
1825
|
+
this.client = import_axios.default.create({
|
|
1826
|
+
baseURL,
|
|
1827
|
+
timeout
|
|
1828
|
+
});
|
|
1829
|
+
this.client.interceptors.response.use(
|
|
1830
|
+
(response) => response.data,
|
|
1831
|
+
(error) => Promise.reject(error)
|
|
1832
|
+
);
|
|
1833
|
+
}
|
|
1834
|
+
async request(config) {
|
|
1835
|
+
return this.client.request(config);
|
|
1836
|
+
}
|
|
1837
|
+
async stream(config, callbacks, endpointConfig) {
|
|
1838
|
+
const { onMessage, onError, onFinish } = callbacks;
|
|
1839
|
+
try {
|
|
1840
|
+
const baseURL = this.client.defaults.baseURL || "";
|
|
1841
|
+
let url = config.url;
|
|
1842
|
+
if (url && !url.startsWith("http") && baseURL) {
|
|
1843
|
+
const cleanBase = baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL;
|
|
1844
|
+
const cleanUrl = url.startsWith("/") ? url : `/${url}`;
|
|
1845
|
+
url = `${cleanBase}${cleanUrl}`;
|
|
1846
|
+
}
|
|
1847
|
+
if (config.params) {
|
|
1848
|
+
const params = new URLSearchParams();
|
|
1849
|
+
Object.entries(config.params).forEach(([key, value]) => {
|
|
1850
|
+
if (value !== void 0) params.append(key, String(value));
|
|
1851
|
+
});
|
|
1852
|
+
url += (url.includes("?") ? "&" : "?") + params.toString();
|
|
1853
|
+
}
|
|
1854
|
+
const headers = {
|
|
1855
|
+
...this.client.defaults.headers.common || {},
|
|
1856
|
+
"Content-Type": "application/json",
|
|
1857
|
+
...config.headers || {}
|
|
1858
|
+
};
|
|
1859
|
+
const defaultHeaders = this.client.defaults.headers;
|
|
1860
|
+
if (defaultHeaders.Authorization) {
|
|
1861
|
+
headers["Authorization"] = defaultHeaders.Authorization;
|
|
1862
|
+
}
|
|
1863
|
+
if (defaultHeaders["x-token"]) {
|
|
1864
|
+
headers["x-token"] = defaultHeaders["x-token"];
|
|
1865
|
+
}
|
|
1866
|
+
const response = await fetch(url, {
|
|
1867
|
+
method: config.method,
|
|
1868
|
+
headers,
|
|
1869
|
+
body: config.data ? JSON.stringify(config.data) : void 0
|
|
1870
|
+
});
|
|
1871
|
+
if (!response.ok) {
|
|
1872
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
1873
|
+
}
|
|
1874
|
+
if (!response.body) {
|
|
1875
|
+
throw new Error("\u54CD\u5E94\u4F53\u4E3A\u7A7A");
|
|
1876
|
+
}
|
|
1877
|
+
const reader = response.body.getReader();
|
|
1878
|
+
const decoder = new TextDecoder();
|
|
1879
|
+
while (true) {
|
|
1880
|
+
const { done, value } = await reader.read();
|
|
1881
|
+
if (done) break;
|
|
1882
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
1883
|
+
if (onMessage) {
|
|
1884
|
+
onMessage(chunk);
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
if (onFinish) onFinish();
|
|
1888
|
+
} catch (error) {
|
|
1889
|
+
if (onError) onError(error);
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
};
|
|
1893
|
+
|
|
1894
|
+
// src/api/engine.ts
|
|
1895
|
+
var logger9 = createLogger("ApiEngine");
|
|
1896
|
+
var ApiEngine = class {
|
|
1897
|
+
adapter;
|
|
1898
|
+
config = {};
|
|
1899
|
+
constructor(adapter) {
|
|
1900
|
+
this.adapter = adapter || new AxiosAdapter();
|
|
1901
|
+
}
|
|
1902
|
+
/**
|
|
1903
|
+
* 切换请求适配器
|
|
1904
|
+
* @param adapter 新的适配器实例
|
|
1905
|
+
*/
|
|
1906
|
+
useAdapter(adapter) {
|
|
1907
|
+
this.adapter = adapter;
|
|
1908
|
+
}
|
|
1909
|
+
/**
|
|
1910
|
+
* 注册 API 配置
|
|
1911
|
+
* @param config 配置对象
|
|
1912
|
+
*/
|
|
1913
|
+
register(config) {
|
|
1914
|
+
logger9.info("\u6B63\u5728\u6CE8\u518C API \u914D\u7F6E:", Object.keys(config));
|
|
1915
|
+
this.config = { ...this.config, ...config };
|
|
1916
|
+
}
|
|
1917
|
+
/**
|
|
1918
|
+
* 获取接口配置
|
|
1919
|
+
*/
|
|
1920
|
+
getEndpoint(module2, action) {
|
|
1921
|
+
return this.config[module2]?.[action];
|
|
1922
|
+
}
|
|
1923
|
+
/**
|
|
1924
|
+
* 发起 API 请求
|
|
1925
|
+
* @param module 模块名
|
|
1926
|
+
* @param action 动作名
|
|
1927
|
+
* @param data 请求数据 (Body 或 Query)
|
|
1928
|
+
* @param options 请求选项
|
|
1929
|
+
*/
|
|
1930
|
+
async call(module2, action, data, options = {}) {
|
|
1931
|
+
const endpoint = this.getEndpoint(module2, action);
|
|
1932
|
+
if (!endpoint) {
|
|
1933
|
+
logger9.warn(`\u672A\u627E\u5230 API \u5B9A\u4E49: ${module2}.${action} (\u5F53\u524D\u5DF2\u6CE8\u518C\u6A21\u5757: ${Object.keys(this.config).join(", ")})`);
|
|
1934
|
+
return Promise.resolve(void 0);
|
|
1935
|
+
}
|
|
1936
|
+
let url = endpoint.url;
|
|
1937
|
+
const pathParams = options.params || {};
|
|
1938
|
+
url = url.replace(/:([a-zA-Z0-9_]+)/g, (_, key) => {
|
|
1939
|
+
if (pathParams[key] !== void 0) {
|
|
1940
|
+
return String(pathParams[key]);
|
|
1941
|
+
}
|
|
1942
|
+
if (data && typeof data === "object" && data[key] !== void 0) {
|
|
1943
|
+
return String(data[key]);
|
|
1944
|
+
}
|
|
1945
|
+
return `:${key}`;
|
|
1946
|
+
});
|
|
1947
|
+
const method = endpoint.method;
|
|
1948
|
+
const requestConfig = {
|
|
1949
|
+
...options,
|
|
1950
|
+
url,
|
|
1951
|
+
method
|
|
1952
|
+
};
|
|
1953
|
+
if (method === "GET" || method === "DELETE") {
|
|
1954
|
+
requestConfig.params = data;
|
|
1955
|
+
} else {
|
|
1956
|
+
requestConfig.data = data;
|
|
1957
|
+
}
|
|
1958
|
+
const response = await this.adapter.request(requestConfig, endpoint);
|
|
1959
|
+
const isBaseResponse = response && typeof response === "object" && "code" in response && ("message" in response || "data" in response);
|
|
1960
|
+
if (isBaseResponse) {
|
|
1961
|
+
const res = response;
|
|
1962
|
+
const code = String(res.code);
|
|
1963
|
+
if (code !== SUCCESS_CODE) {
|
|
1964
|
+
const strategy = endpoint.errorStrategy || "reject";
|
|
1965
|
+
if (strategy === "reject") {
|
|
1966
|
+
logger9.error(`API \u8BF7\u6C42\u4E1A\u52A1\u9519\u8BEF (${module2}.${action}):`, res.message);
|
|
1967
|
+
throw new Error(res.message || `Request failed with code ${code}`);
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
return response;
|
|
1972
|
+
}
|
|
1973
|
+
/**
|
|
1974
|
+
* 发起流式请求
|
|
1975
|
+
* @param module 模块名
|
|
1976
|
+
* @param action 动作名
|
|
1977
|
+
* @param data 请求数据
|
|
1978
|
+
* @param options 请求选项
|
|
1979
|
+
*/
|
|
1980
|
+
async stream(module2, action, data, options = {}) {
|
|
1981
|
+
const endpoint = this.getEndpoint(module2, action);
|
|
1982
|
+
if (!endpoint) {
|
|
1983
|
+
logger9.warn(`\u672A\u627E\u5230 API \u5B9A\u4E49: ${module2}.${action}\uFF0C\u8DF3\u8FC7\u6D41\u5F0F\u8BF7\u6C42\u3002`);
|
|
1984
|
+
return;
|
|
1985
|
+
}
|
|
1986
|
+
if (!this.adapter.stream) {
|
|
1987
|
+
logger9.warn("\u5F53\u524D API \u9002\u914D\u5668\u4E0D\u652F\u6301\u6D41\u5F0F\u4F20\u8F93\u3002");
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1990
|
+
let url = endpoint.url;
|
|
1991
|
+
const pathParams = options.params || {};
|
|
1992
|
+
url = url.replace(/:([a-zA-Z0-9_]+)/g, (_, key) => {
|
|
1993
|
+
if (pathParams[key] !== void 0) return String(pathParams[key]);
|
|
1994
|
+
if (data && typeof data === "object" && data[key] !== void 0) return String(data[key]);
|
|
1995
|
+
return `:${key}`;
|
|
1996
|
+
});
|
|
1997
|
+
const method = endpoint.method;
|
|
1998
|
+
const requestConfig = {
|
|
1999
|
+
...options,
|
|
2000
|
+
url,
|
|
2001
|
+
method
|
|
2002
|
+
};
|
|
2003
|
+
if (method === "GET" || method === "DELETE") {
|
|
2004
|
+
requestConfig.params = data;
|
|
2005
|
+
} else {
|
|
2006
|
+
requestConfig.data = data;
|
|
2007
|
+
}
|
|
2008
|
+
const callbacks = {
|
|
2009
|
+
onMessage: options.onMessage,
|
|
2010
|
+
onError: options.onError,
|
|
2011
|
+
onFinish: options.onFinish
|
|
2012
|
+
};
|
|
2013
|
+
await this.adapter.stream(requestConfig, callbacks, endpoint);
|
|
2014
|
+
}
|
|
2015
|
+
};
|
|
2016
|
+
var apiEngine = new ApiEngine();
|
|
2017
|
+
|
|
2018
|
+
// src/api/utils.ts
|
|
2019
|
+
var mergeMockData = (def, mock) => {
|
|
2020
|
+
const merged = JSON.parse(JSON.stringify(def));
|
|
2021
|
+
Object.keys(mock).forEach((key) => {
|
|
2022
|
+
if (merged[key]) {
|
|
2023
|
+
merged[key] = {
|
|
2024
|
+
...merged[key],
|
|
2025
|
+
...mock[key]
|
|
2026
|
+
};
|
|
2027
|
+
}
|
|
2028
|
+
});
|
|
2029
|
+
return merged;
|
|
2030
|
+
};
|
|
2031
|
+
function isMockMode() {
|
|
2032
|
+
const envMock = typeof process !== "undefined" && process.env.VITE_USE_MOCK === "true" || typeof window !== "undefined" && window.VITE_USE_MOCK === "true";
|
|
2033
|
+
if (typeof window !== "undefined") {
|
|
2034
|
+
const search = new URLSearchParams(window.location.search);
|
|
2035
|
+
const hashSearch = window.location.hash.split("?")[1];
|
|
2036
|
+
const hash = new URLSearchParams(hashSearch);
|
|
2037
|
+
const mockParam = search.get("mock") || hash.get("mock");
|
|
2038
|
+
if (mockParam === "true") return true;
|
|
2039
|
+
if (mockParam === "false") return false;
|
|
2040
|
+
}
|
|
2041
|
+
return envMock;
|
|
2042
|
+
}
|
|
2043
|
+
function resolveApiModules(definitionsMap, mocksMap = {}) {
|
|
2044
|
+
const config = {};
|
|
2045
|
+
const getNamespace = (path) => {
|
|
2046
|
+
const fileName = path.split("/").pop() || "";
|
|
2047
|
+
return fileName.replace(/\.mock\.(ts|js|tsx|jsx|json)$/, "").replace(/\.(ts|js|tsx|jsx|json)$/, "");
|
|
2048
|
+
};
|
|
2049
|
+
Object.entries(definitionsMap).forEach(([path, module2]) => {
|
|
2050
|
+
if (path.includes(".mock.")) return;
|
|
2051
|
+
const namespace = getNamespace(path);
|
|
2052
|
+
if (!namespace || !module2.default) return;
|
|
2053
|
+
let apiDef = module2.default;
|
|
2054
|
+
const mockEntry = Object.entries(mocksMap).find(([mockPath]) => {
|
|
2055
|
+
return getNamespace(mockPath) === namespace && mockPath.includes(".mock.");
|
|
2056
|
+
});
|
|
2057
|
+
if (mockEntry) {
|
|
2058
|
+
const mockModule = mockEntry[1];
|
|
2059
|
+
const mockData = mockModule.default || mockModule;
|
|
2060
|
+
if (mockData) {
|
|
2061
|
+
apiDef = mergeMockData(apiDef, mockData);
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
config[namespace] = apiDef;
|
|
2065
|
+
});
|
|
2066
|
+
return config;
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
// src/utils/stream-parser.ts
|
|
2070
|
+
function parseStreamChunk(chunk) {
|
|
2071
|
+
const lines = chunk.split("\n").filter((line) => line.trim() !== "");
|
|
2072
|
+
const events = [];
|
|
2073
|
+
let currentEvent = null;
|
|
2074
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2075
|
+
const line = lines[i];
|
|
2076
|
+
if (line.startsWith("event:")) {
|
|
2077
|
+
currentEvent = line.substring(6).trim();
|
|
2078
|
+
} else if (line.startsWith("data:")) {
|
|
2079
|
+
const dataStr = line.substring(5).trim();
|
|
2080
|
+
let data;
|
|
2081
|
+
try {
|
|
2082
|
+
data = JSON.parse(dataStr);
|
|
2083
|
+
} catch {
|
|
2084
|
+
data = dataStr;
|
|
2085
|
+
}
|
|
2086
|
+
const eventType = currentEvent || "data";
|
|
2087
|
+
events.push({
|
|
2088
|
+
event: eventType,
|
|
2089
|
+
data
|
|
2090
|
+
});
|
|
2091
|
+
currentEvent = null;
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
return events;
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
// src/utils/date.ts
|
|
2098
|
+
var import_dayjs = __toESM(require_dayjs_min());
|
|
2099
|
+
var import_relativeTime = __toESM(require_relativeTime());
|
|
2100
|
+
var import_zh_cn = __toESM(require_zh_cn());
|
|
2101
|
+
import_dayjs.default.extend(import_relativeTime.default);
|
|
2102
|
+
import_dayjs.default.locale("zh-cn");
|
|
2103
|
+
var dateUtils = {
|
|
2104
|
+
/**
|
|
2105
|
+
* 格式化日期为 YYYY-MM-DD
|
|
2106
|
+
*/
|
|
2107
|
+
formatDate(date) {
|
|
2108
|
+
return (0, import_dayjs.default)(date).format("YYYY-MM-DD");
|
|
2109
|
+
},
|
|
2110
|
+
/**
|
|
2111
|
+
* 格式化时间为 HH:mm:ss
|
|
2112
|
+
*/
|
|
2113
|
+
formatTime(date) {
|
|
2114
|
+
return (0, import_dayjs.default)(date).format("HH:mm:ss");
|
|
2115
|
+
},
|
|
2116
|
+
/**
|
|
2117
|
+
* 格式化日期时间为 YYYY-MM-DD HH:mm:ss
|
|
2118
|
+
*/
|
|
2119
|
+
formatDateTime(date) {
|
|
2120
|
+
return (0, import_dayjs.default)(date).format("YYYY-MM-DD HH:mm:ss");
|
|
2121
|
+
},
|
|
2122
|
+
/**
|
|
2123
|
+
* 获取当前时间戳(毫秒)
|
|
2124
|
+
*/
|
|
2125
|
+
now() {
|
|
2126
|
+
return (0, import_dayjs.default)().valueOf();
|
|
2127
|
+
},
|
|
2128
|
+
/**
|
|
2129
|
+
* 获取相对时间(例如:几分钟前)
|
|
2130
|
+
*/
|
|
2131
|
+
fromNow(date) {
|
|
2132
|
+
return (0, import_dayjs.default)(date).fromNow();
|
|
2133
|
+
},
|
|
2134
|
+
/**
|
|
2135
|
+
* 原始 dayjs 对象,用于更复杂的场景
|
|
2136
|
+
*/
|
|
2137
|
+
dayjs: import_dayjs.default
|
|
2138
|
+
};
|
|
2139
|
+
|
|
2140
|
+
// src/utils/index.ts
|
|
2141
|
+
var version = "1.0.0";
|
|
2142
|
+
|
|
2143
|
+
// src/hooks/use-storage-state.ts
|
|
2144
|
+
var import_react5 = require("react");
|
|
2145
|
+
function useStorageState(pluginId, key, options = {}) {
|
|
2146
|
+
const { defaultValue, scope = "plugin" } = options;
|
|
2147
|
+
const storageManager = pluginManager.getStorageManager();
|
|
2148
|
+
const getStorage = (0, import_react5.useCallback)(() => {
|
|
2149
|
+
const contextStorage = storageManager.getContextStorage(pluginId);
|
|
2150
|
+
return scope === "shared" ? contextStorage.shared : contextStorage;
|
|
2151
|
+
}, [pluginId, scope, storageManager]);
|
|
2152
|
+
const [state, setState] = (0, import_react5.useState)(() => {
|
|
2153
|
+
try {
|
|
2154
|
+
if (typeof window === "undefined") return defaultValue;
|
|
2155
|
+
const storage = getStorage();
|
|
2156
|
+
const val = storage.get(key);
|
|
2157
|
+
return val !== null ? val : defaultValue;
|
|
2158
|
+
} catch (e) {
|
|
2159
|
+
console.warn(`[useStorageState] Error reading key "${key}"`, e);
|
|
2160
|
+
return defaultValue;
|
|
2161
|
+
}
|
|
2162
|
+
});
|
|
2163
|
+
const setValue = (0, import_react5.useCallback)((value) => {
|
|
2164
|
+
try {
|
|
2165
|
+
const valueToStore = value instanceof Function ? value(state) : value;
|
|
2166
|
+
setState(valueToStore);
|
|
2167
|
+
const storage = getStorage();
|
|
2168
|
+
storage.set(key, valueToStore);
|
|
2169
|
+
} catch (error) {
|
|
2170
|
+
console.warn(`[useStorageState] Error setting key "${key}":`, error);
|
|
2171
|
+
}
|
|
2172
|
+
}, [key, state, getStorage]);
|
|
2173
|
+
return [state, setValue];
|
|
2174
|
+
}
|
|
2175
|
+
|
|
2176
|
+
// src/hooks/use-plugin-loader.ts
|
|
2177
|
+
var import_react6 = require("react");
|
|
2178
|
+
var logger10 = createLogger("PluginLoader");
|
|
2179
|
+
var usePluginLoader = (options) => {
|
|
2180
|
+
const [pluginsLoaded, setPluginsLoaded] = (0, import_react6.useState)(false);
|
|
2181
|
+
const [pluginVersion, setPluginVersion] = (0, import_react6.useState)(0);
|
|
2182
|
+
const loadingRef = (0, import_react6.useRef)(false);
|
|
2183
|
+
(0, import_react6.useEffect)(() => {
|
|
2184
|
+
const unsubscribe = pluginManager.subscribe(() => {
|
|
2185
|
+
logger10.debug("Plugin state changed, refreshing UI...");
|
|
2186
|
+
setPluginVersion((v) => v + 1);
|
|
2187
|
+
});
|
|
2188
|
+
const load = async () => {
|
|
2189
|
+
if (loadingRef.current || pluginsLoaded) return;
|
|
2190
|
+
loadingRef.current = true;
|
|
2191
|
+
try {
|
|
2192
|
+
const {
|
|
2193
|
+
discoveryRules = [],
|
|
2194
|
+
registry: manualRegistry = {},
|
|
2195
|
+
pluginConfigs,
|
|
2196
|
+
sharedContext = {},
|
|
2197
|
+
baseUrl = window.location.origin
|
|
2198
|
+
} = options;
|
|
2199
|
+
logger10.info("Starting to load plugins...");
|
|
2200
|
+
const discoveredRegistry = discoveryRules.length > 0 ? discoverPlugins(discoveryRules, baseUrl) : {};
|
|
2201
|
+
const finalRegistry = { ...discoveredRegistry, ...manualRegistry };
|
|
2202
|
+
await pluginManager.loadPlugins(pluginConfigs, finalRegistry);
|
|
2203
|
+
await pluginManager.initPlugins(sharedContext);
|
|
2204
|
+
setPluginsLoaded(true);
|
|
2205
|
+
logger10.info("Plugins loaded successfully");
|
|
2206
|
+
} catch (error) {
|
|
2207
|
+
logger10.error("Failed to load plugins:", error);
|
|
2208
|
+
} finally {
|
|
2209
|
+
loadingRef.current = false;
|
|
2210
|
+
}
|
|
2211
|
+
};
|
|
2212
|
+
load();
|
|
2213
|
+
return () => {
|
|
2214
|
+
unsubscribe();
|
|
2215
|
+
};
|
|
2216
|
+
}, []);
|
|
2217
|
+
return {
|
|
2218
|
+
pluginsLoaded,
|
|
2219
|
+
pluginVersion
|
|
2220
|
+
};
|
|
2221
|
+
};
|
|
2222
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2223
|
+
0 && (module.exports = {
|
|
2224
|
+
ApiEngine,
|
|
2225
|
+
ApiProvider,
|
|
2226
|
+
AvatarSkeleton,
|
|
2227
|
+
AxiosAdapter,
|
|
2228
|
+
BlockSkeleton,
|
|
2229
|
+
ConfigManager,
|
|
2230
|
+
DefaultEventBus,
|
|
2231
|
+
LocalStorageAdapter,
|
|
2232
|
+
LogLevel,
|
|
2233
|
+
Logger,
|
|
2234
|
+
PLUGIN_TYPES,
|
|
2235
|
+
PluginErrorBoundary,
|
|
2236
|
+
PluginManager,
|
|
2237
|
+
PluginProvider,
|
|
2238
|
+
PluginRuntime,
|
|
2239
|
+
PluginSandbox,
|
|
2240
|
+
PluginSlot,
|
|
2241
|
+
SUCCESS_CODE,
|
|
2242
|
+
ScopedStorageAdapter,
|
|
2243
|
+
ServiceRegistry,
|
|
2244
|
+
SidebarIconSkeleton,
|
|
2245
|
+
Slot,
|
|
2246
|
+
StatusBarItemSkeleton,
|
|
2247
|
+
StorageManager,
|
|
2248
|
+
apiEngine,
|
|
2249
|
+
configManager,
|
|
2250
|
+
createLogger,
|
|
2251
|
+
dateUtils,
|
|
2252
|
+
discoverPlugins,
|
|
2253
|
+
isMockMode,
|
|
2254
|
+
logger,
|
|
2255
|
+
parseStreamChunk,
|
|
2256
|
+
pluginManager,
|
|
2257
|
+
resolveApiModules,
|
|
2258
|
+
resolvePluginRegistry,
|
|
2259
|
+
serviceRegistry,
|
|
2260
|
+
useApi,
|
|
2261
|
+
usePluginLoader,
|
|
2262
|
+
usePluginManager,
|
|
2263
|
+
useStorageState,
|
|
2264
|
+
version
|
|
2265
|
+
});
|