@kevisual/router 0.0.55 → 0.0.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/opencode.d.ts +331 -0
- package/dist/opencode.js +969 -0
- package/dist/router-browser.d.ts +5 -2
- package/dist/router-browser.js +13412 -3465
- package/dist/router.d.ts +4 -1
- package/dist/router.js +13421 -3474
- package/package.json +15 -9
- package/readme.md +164 -12
- package/src/browser.ts +4 -3
- package/src/index.ts +2 -1
- package/src/opencode.ts +72 -0
- package/src/route.ts +3 -0
- package/src/router-simple.ts +2 -0
package/dist/opencode.js
ADDED
|
@@ -0,0 +1,969 @@
|
|
|
1
|
+
// src/utils/path-key.ts
|
|
2
|
+
|
|
3
|
+
// ../../node_modules/.pnpm/@kevisual+load@0.0.6/node_modules/@kevisual/load/dist/load.js
|
|
4
|
+
function getDefaultExportFromCjs(x) {
|
|
5
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
6
|
+
}
|
|
7
|
+
var eventemitter3 = { exports: {} };
|
|
8
|
+
var hasRequiredEventemitter3;
|
|
9
|
+
function requireEventemitter3() {
|
|
10
|
+
if (hasRequiredEventemitter3)
|
|
11
|
+
return eventemitter3.exports;
|
|
12
|
+
hasRequiredEventemitter3 = 1;
|
|
13
|
+
(function(module) {
|
|
14
|
+
var has = Object.prototype.hasOwnProperty, prefix = "~";
|
|
15
|
+
function Events() {}
|
|
16
|
+
if (Object.create) {
|
|
17
|
+
Events.prototype = Object.create(null);
|
|
18
|
+
if (!new Events().__proto__)
|
|
19
|
+
prefix = false;
|
|
20
|
+
}
|
|
21
|
+
function EE(fn, context, once) {
|
|
22
|
+
this.fn = fn;
|
|
23
|
+
this.context = context;
|
|
24
|
+
this.once = once || false;
|
|
25
|
+
}
|
|
26
|
+
function addListener(emitter, event, fn, context, once) {
|
|
27
|
+
if (typeof fn !== "function") {
|
|
28
|
+
throw new TypeError("The listener must be a function");
|
|
29
|
+
}
|
|
30
|
+
var listener = new EE(fn, context || emitter, once), evt = prefix ? prefix + event : event;
|
|
31
|
+
if (!emitter._events[evt])
|
|
32
|
+
emitter._events[evt] = listener, emitter._eventsCount++;
|
|
33
|
+
else if (!emitter._events[evt].fn)
|
|
34
|
+
emitter._events[evt].push(listener);
|
|
35
|
+
else
|
|
36
|
+
emitter._events[evt] = [emitter._events[evt], listener];
|
|
37
|
+
return emitter;
|
|
38
|
+
}
|
|
39
|
+
function clearEvent(emitter, evt) {
|
|
40
|
+
if (--emitter._eventsCount === 0)
|
|
41
|
+
emitter._events = new Events;
|
|
42
|
+
else
|
|
43
|
+
delete emitter._events[evt];
|
|
44
|
+
}
|
|
45
|
+
function EventEmitter() {
|
|
46
|
+
this._events = new Events;
|
|
47
|
+
this._eventsCount = 0;
|
|
48
|
+
}
|
|
49
|
+
EventEmitter.prototype.eventNames = function eventNames() {
|
|
50
|
+
var names = [], events, name;
|
|
51
|
+
if (this._eventsCount === 0)
|
|
52
|
+
return names;
|
|
53
|
+
for (name in events = this._events) {
|
|
54
|
+
if (has.call(events, name))
|
|
55
|
+
names.push(prefix ? name.slice(1) : name);
|
|
56
|
+
}
|
|
57
|
+
if (Object.getOwnPropertySymbols) {
|
|
58
|
+
return names.concat(Object.getOwnPropertySymbols(events));
|
|
59
|
+
}
|
|
60
|
+
return names;
|
|
61
|
+
};
|
|
62
|
+
EventEmitter.prototype.listeners = function listeners(event) {
|
|
63
|
+
var evt = prefix ? prefix + event : event, handlers = this._events[evt];
|
|
64
|
+
if (!handlers)
|
|
65
|
+
return [];
|
|
66
|
+
if (handlers.fn)
|
|
67
|
+
return [handlers.fn];
|
|
68
|
+
for (var i = 0, l = handlers.length, ee = new Array(l);i < l; i++) {
|
|
69
|
+
ee[i] = handlers[i].fn;
|
|
70
|
+
}
|
|
71
|
+
return ee;
|
|
72
|
+
};
|
|
73
|
+
EventEmitter.prototype.listenerCount = function listenerCount(event) {
|
|
74
|
+
var evt = prefix ? prefix + event : event, listeners = this._events[evt];
|
|
75
|
+
if (!listeners)
|
|
76
|
+
return 0;
|
|
77
|
+
if (listeners.fn)
|
|
78
|
+
return 1;
|
|
79
|
+
return listeners.length;
|
|
80
|
+
};
|
|
81
|
+
EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
|
|
82
|
+
var evt = prefix ? prefix + event : event;
|
|
83
|
+
if (!this._events[evt])
|
|
84
|
+
return false;
|
|
85
|
+
var listeners = this._events[evt], len = arguments.length, args, i;
|
|
86
|
+
if (listeners.fn) {
|
|
87
|
+
if (listeners.once)
|
|
88
|
+
this.removeListener(event, listeners.fn, undefined, true);
|
|
89
|
+
switch (len) {
|
|
90
|
+
case 1:
|
|
91
|
+
return listeners.fn.call(listeners.context), true;
|
|
92
|
+
case 2:
|
|
93
|
+
return listeners.fn.call(listeners.context, a1), true;
|
|
94
|
+
case 3:
|
|
95
|
+
return listeners.fn.call(listeners.context, a1, a2), true;
|
|
96
|
+
case 4:
|
|
97
|
+
return listeners.fn.call(listeners.context, a1, a2, a3), true;
|
|
98
|
+
case 5:
|
|
99
|
+
return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
|
|
100
|
+
case 6:
|
|
101
|
+
return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
|
|
102
|
+
}
|
|
103
|
+
for (i = 1, args = new Array(len - 1);i < len; i++) {
|
|
104
|
+
args[i - 1] = arguments[i];
|
|
105
|
+
}
|
|
106
|
+
listeners.fn.apply(listeners.context, args);
|
|
107
|
+
} else {
|
|
108
|
+
var length = listeners.length, j;
|
|
109
|
+
for (i = 0;i < length; i++) {
|
|
110
|
+
if (listeners[i].once)
|
|
111
|
+
this.removeListener(event, listeners[i].fn, undefined, true);
|
|
112
|
+
switch (len) {
|
|
113
|
+
case 1:
|
|
114
|
+
listeners[i].fn.call(listeners[i].context);
|
|
115
|
+
break;
|
|
116
|
+
case 2:
|
|
117
|
+
listeners[i].fn.call(listeners[i].context, a1);
|
|
118
|
+
break;
|
|
119
|
+
case 3:
|
|
120
|
+
listeners[i].fn.call(listeners[i].context, a1, a2);
|
|
121
|
+
break;
|
|
122
|
+
case 4:
|
|
123
|
+
listeners[i].fn.call(listeners[i].context, a1, a2, a3);
|
|
124
|
+
break;
|
|
125
|
+
default:
|
|
126
|
+
if (!args)
|
|
127
|
+
for (j = 1, args = new Array(len - 1);j < len; j++) {
|
|
128
|
+
args[j - 1] = arguments[j];
|
|
129
|
+
}
|
|
130
|
+
listeners[i].fn.apply(listeners[i].context, args);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return true;
|
|
135
|
+
};
|
|
136
|
+
EventEmitter.prototype.on = function on(event, fn, context) {
|
|
137
|
+
return addListener(this, event, fn, context, false);
|
|
138
|
+
};
|
|
139
|
+
EventEmitter.prototype.once = function once(event, fn, context) {
|
|
140
|
+
return addListener(this, event, fn, context, true);
|
|
141
|
+
};
|
|
142
|
+
EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
|
|
143
|
+
var evt = prefix ? prefix + event : event;
|
|
144
|
+
if (!this._events[evt])
|
|
145
|
+
return this;
|
|
146
|
+
if (!fn) {
|
|
147
|
+
clearEvent(this, evt);
|
|
148
|
+
return this;
|
|
149
|
+
}
|
|
150
|
+
var listeners = this._events[evt];
|
|
151
|
+
if (listeners.fn) {
|
|
152
|
+
if (listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context)) {
|
|
153
|
+
clearEvent(this, evt);
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
for (var i = 0, events = [], length = listeners.length;i < length; i++) {
|
|
157
|
+
if (listeners[i].fn !== fn || once && !listeners[i].once || context && listeners[i].context !== context) {
|
|
158
|
+
events.push(listeners[i]);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (events.length)
|
|
162
|
+
this._events[evt] = events.length === 1 ? events[0] : events;
|
|
163
|
+
else
|
|
164
|
+
clearEvent(this, evt);
|
|
165
|
+
}
|
|
166
|
+
return this;
|
|
167
|
+
};
|
|
168
|
+
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
|
|
169
|
+
var evt;
|
|
170
|
+
if (event) {
|
|
171
|
+
evt = prefix ? prefix + event : event;
|
|
172
|
+
if (this._events[evt])
|
|
173
|
+
clearEvent(this, evt);
|
|
174
|
+
} else {
|
|
175
|
+
this._events = new Events;
|
|
176
|
+
this._eventsCount = 0;
|
|
177
|
+
}
|
|
178
|
+
return this;
|
|
179
|
+
};
|
|
180
|
+
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
|
181
|
+
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
|
|
182
|
+
EventEmitter.prefixed = prefix;
|
|
183
|
+
EventEmitter.EventEmitter = EventEmitter;
|
|
184
|
+
{
|
|
185
|
+
module.exports = EventEmitter;
|
|
186
|
+
}
|
|
187
|
+
})(eventemitter3);
|
|
188
|
+
return eventemitter3.exports;
|
|
189
|
+
}
|
|
190
|
+
var eventemitter3Exports = requireEventemitter3();
|
|
191
|
+
var EventEmitter = /* @__PURE__ */ getDefaultExportFromCjs(eventemitter3Exports);
|
|
192
|
+
var reRunFn = (promiseOpts) => {
|
|
193
|
+
const timeout = promiseOpts.timeout || 5 * 60 * 1000;
|
|
194
|
+
const interval = promiseOpts.interval || 1000;
|
|
195
|
+
const checkSuccess = promiseOpts?.checkSuccess || (() => true);
|
|
196
|
+
const signal = promiseOpts.signal;
|
|
197
|
+
return new Promise(async (resolve, reject) => {
|
|
198
|
+
let intervalId;
|
|
199
|
+
let timeoutId = setTimeout(() => {
|
|
200
|
+
clearTimeout(intervalId);
|
|
201
|
+
resolve({
|
|
202
|
+
code: 500,
|
|
203
|
+
message: "timeout"
|
|
204
|
+
});
|
|
205
|
+
}, timeout);
|
|
206
|
+
const fn = promiseOpts.fn || (() => true);
|
|
207
|
+
const runFn = async () => {
|
|
208
|
+
if (signal?.aborted) {
|
|
209
|
+
clearInterval(intervalId);
|
|
210
|
+
clearTimeout(timeoutId);
|
|
211
|
+
return resolve({
|
|
212
|
+
code: 499,
|
|
213
|
+
message: "operation cancelled"
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
const res = await fn();
|
|
217
|
+
if (!!checkSuccess(res)) {
|
|
218
|
+
clearInterval(intervalId);
|
|
219
|
+
clearTimeout(timeoutId);
|
|
220
|
+
resolve({
|
|
221
|
+
code: 200,
|
|
222
|
+
data: res
|
|
223
|
+
});
|
|
224
|
+
} else {
|
|
225
|
+
setTimeout(() => {
|
|
226
|
+
runFn();
|
|
227
|
+
}, interval);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
if (signal) {
|
|
231
|
+
signal.addEventListener("abort", () => {
|
|
232
|
+
clearInterval(intervalId);
|
|
233
|
+
clearTimeout(timeoutId);
|
|
234
|
+
resolve({
|
|
235
|
+
code: 499,
|
|
236
|
+
message: "operation cancelled"
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
runFn();
|
|
241
|
+
});
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
class BaseLoad {
|
|
245
|
+
modules = new Map;
|
|
246
|
+
event;
|
|
247
|
+
loading;
|
|
248
|
+
static reRunFn = reRunFn;
|
|
249
|
+
timeout = 5 * 60 * 1000;
|
|
250
|
+
constructor() {
|
|
251
|
+
this.event = new EventEmitter;
|
|
252
|
+
this.loading = false;
|
|
253
|
+
}
|
|
254
|
+
listenKey(key, listenOpts) {
|
|
255
|
+
const timeout = listenOpts?.timeout ?? this.timeout;
|
|
256
|
+
return new Promise((resolve) => {
|
|
257
|
+
const timeoutId = setTimeout(() => {
|
|
258
|
+
this.event.removeListener(key, onEvent);
|
|
259
|
+
resolve({
|
|
260
|
+
code: 500,
|
|
261
|
+
message: "timeout"
|
|
262
|
+
});
|
|
263
|
+
}, timeout);
|
|
264
|
+
const onEvent = (error) => {
|
|
265
|
+
clearTimeout(timeoutId);
|
|
266
|
+
if (error) {
|
|
267
|
+
return resolve({
|
|
268
|
+
code: 500,
|
|
269
|
+
message: error
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
const data = this.modules.get(key);
|
|
273
|
+
if (data?.loadSuccessClear) {
|
|
274
|
+
this.remove(key);
|
|
275
|
+
}
|
|
276
|
+
resolve({
|
|
277
|
+
code: 200,
|
|
278
|
+
data: data?.modules
|
|
279
|
+
});
|
|
280
|
+
};
|
|
281
|
+
this.event.once(key, onEvent);
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
async hasLoaded(key, hasLoadOpts) {
|
|
285
|
+
if (!key) {
|
|
286
|
+
return {
|
|
287
|
+
code: 404,
|
|
288
|
+
message: "key is required"
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
const has = this.modules.has(key);
|
|
292
|
+
if (!has) {
|
|
293
|
+
const isExist = hasLoadOpts?.isExist ?? true;
|
|
294
|
+
const timeout = hasLoadOpts?.timeout ?? this.timeout;
|
|
295
|
+
if (isExist) {
|
|
296
|
+
return await this.listenKey(key, { timeout });
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
code: 404
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
const data = this.modules.get(key);
|
|
303
|
+
if (data?.status === "loaded") {
|
|
304
|
+
return {
|
|
305
|
+
code: 200,
|
|
306
|
+
data: data.modules
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
if (data?.status === "loading") {
|
|
310
|
+
return await this.listenKey(key, { timeout: hasLoadOpts?.timeout ?? this.timeout });
|
|
311
|
+
}
|
|
312
|
+
if (data?.status === "error") {
|
|
313
|
+
return {
|
|
314
|
+
code: 500,
|
|
315
|
+
message: "load error"
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
if (data?.status === "cancel") {
|
|
319
|
+
return {
|
|
320
|
+
code: 499,
|
|
321
|
+
message: "operation cancelled"
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
return {
|
|
325
|
+
code: 404
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
async loadFn(loadContent, opts) {
|
|
329
|
+
const key = opts.key;
|
|
330
|
+
if (!key) {
|
|
331
|
+
return {
|
|
332
|
+
code: 404,
|
|
333
|
+
message: "key is required"
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
const newModule = {
|
|
337
|
+
key: opts.key,
|
|
338
|
+
status: "loading",
|
|
339
|
+
loading: true,
|
|
340
|
+
loadSuccessClear: opts.loadSuccessClear ?? true
|
|
341
|
+
};
|
|
342
|
+
let errorMessage = "";
|
|
343
|
+
try {
|
|
344
|
+
const isReRun = opts.isReRun ?? false;
|
|
345
|
+
let res;
|
|
346
|
+
if (!isReRun) {
|
|
347
|
+
this.modules.set(key, newModule);
|
|
348
|
+
res = await loadContent();
|
|
349
|
+
} else {
|
|
350
|
+
newModule.controller = new AbortController;
|
|
351
|
+
const signal = newModule.controller.signal;
|
|
352
|
+
this.modules.set(key, newModule);
|
|
353
|
+
const data = await reRunFn({
|
|
354
|
+
timeout: opts.timeout,
|
|
355
|
+
interval: opts.interval,
|
|
356
|
+
checkSuccess: opts.checkSuccess,
|
|
357
|
+
fn: loadContent,
|
|
358
|
+
signal
|
|
359
|
+
});
|
|
360
|
+
newModule.controller = null;
|
|
361
|
+
if (data.code === 499) {
|
|
362
|
+
newModule.status = "cancel";
|
|
363
|
+
return {
|
|
364
|
+
code: 499,
|
|
365
|
+
message: "operation cancelled"
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
if (data.code !== 200) {
|
|
369
|
+
throw new Error(data.message);
|
|
370
|
+
}
|
|
371
|
+
res = data.data;
|
|
372
|
+
}
|
|
373
|
+
newModule.modules = res;
|
|
374
|
+
newModule.status = "loaded";
|
|
375
|
+
return {
|
|
376
|
+
code: 200,
|
|
377
|
+
data: res
|
|
378
|
+
};
|
|
379
|
+
} catch (error) {
|
|
380
|
+
errorMessage = error.message;
|
|
381
|
+
newModule.status = "error";
|
|
382
|
+
return {
|
|
383
|
+
code: 500,
|
|
384
|
+
message: error
|
|
385
|
+
};
|
|
386
|
+
} finally {
|
|
387
|
+
newModule.loading = false;
|
|
388
|
+
this.modules.set(opts.key, newModule);
|
|
389
|
+
if (!errorMessage) {
|
|
390
|
+
this.event.emit(opts.key);
|
|
391
|
+
} else {
|
|
392
|
+
this.event.emit(opts.key, errorMessage);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
async load(loadContent, opts) {
|
|
397
|
+
this.loading = true;
|
|
398
|
+
const key = opts.key;
|
|
399
|
+
if (!key) {
|
|
400
|
+
return {
|
|
401
|
+
code: 404,
|
|
402
|
+
message: "key is required"
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
if (opts?.force) {
|
|
406
|
+
this.remove(key);
|
|
407
|
+
}
|
|
408
|
+
const has = this.modules.has(key);
|
|
409
|
+
if (has) {
|
|
410
|
+
return await this.hasLoaded(key);
|
|
411
|
+
}
|
|
412
|
+
if (typeof loadContent === "function") {
|
|
413
|
+
return this.loadFn(loadContent, opts);
|
|
414
|
+
}
|
|
415
|
+
console.error("loadContent is not a function and not has loaded");
|
|
416
|
+
}
|
|
417
|
+
remove(key) {
|
|
418
|
+
const has = this.modules.has(key);
|
|
419
|
+
if (has) {
|
|
420
|
+
this.checkRemoveController(key);
|
|
421
|
+
this.modules.delete(key);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
emitLoaded(key) {
|
|
425
|
+
this.checkRemoveController(key);
|
|
426
|
+
this.event.emit(key);
|
|
427
|
+
}
|
|
428
|
+
setModule(key, data, loadData) {
|
|
429
|
+
const newModule = {
|
|
430
|
+
key,
|
|
431
|
+
status: "loaded",
|
|
432
|
+
loading: false,
|
|
433
|
+
modules: data || {},
|
|
434
|
+
...loadData
|
|
435
|
+
};
|
|
436
|
+
this.modules.set(key, newModule);
|
|
437
|
+
this.emitLoaded(key);
|
|
438
|
+
return newModule;
|
|
439
|
+
}
|
|
440
|
+
cancel(key) {
|
|
441
|
+
this.checkRemoveController(key);
|
|
442
|
+
}
|
|
443
|
+
checkRemoveController(key) {
|
|
444
|
+
const data = this.modules.get(key);
|
|
445
|
+
if (data?.controller) {
|
|
446
|
+
data.controller?.abort?.();
|
|
447
|
+
delete data.controller;
|
|
448
|
+
this.modules.set(key, data);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// src/index.ts
|
|
454
|
+
var gt = globalThis || window || self;
|
|
455
|
+
var useEnv = (initEnv, initKey = "config", isOverwrite) => {
|
|
456
|
+
const env = gt[initKey];
|
|
457
|
+
const _env = env || initEnv;
|
|
458
|
+
if (!env) {
|
|
459
|
+
if (_env) {
|
|
460
|
+
gt[initKey] = _env;
|
|
461
|
+
} else {
|
|
462
|
+
gt[initKey] = {};
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return gt[initKey];
|
|
466
|
+
};
|
|
467
|
+
var useEnvKey = (key, init, initKey = "config") => {
|
|
468
|
+
const _env = useEnv({}, initKey);
|
|
469
|
+
if (key && typeof _env[key] !== "undefined") {
|
|
470
|
+
return _env[key];
|
|
471
|
+
}
|
|
472
|
+
if (key && init) {
|
|
473
|
+
if (typeof init !== "function") {
|
|
474
|
+
_env[key] = init;
|
|
475
|
+
}
|
|
476
|
+
if (typeof init === "function") {
|
|
477
|
+
const result = init();
|
|
478
|
+
if (result instanceof Promise) {
|
|
479
|
+
return result.then((res) => {
|
|
480
|
+
_env[key] = res;
|
|
481
|
+
return res;
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
_env[key] = result;
|
|
485
|
+
}
|
|
486
|
+
return _env[key];
|
|
487
|
+
}
|
|
488
|
+
if (key) {
|
|
489
|
+
const baseLoad = new BaseLoad;
|
|
490
|
+
const voidFn = async () => {
|
|
491
|
+
return _env[key];
|
|
492
|
+
};
|
|
493
|
+
const checkFn = async () => {
|
|
494
|
+
const loadRes = await baseLoad.load(voidFn, {
|
|
495
|
+
key,
|
|
496
|
+
isReRun: true,
|
|
497
|
+
checkSuccess: () => _env[key],
|
|
498
|
+
timeout: 5 * 60 * 1000,
|
|
499
|
+
interval: 1000
|
|
500
|
+
});
|
|
501
|
+
if (loadRes.code !== 200) {
|
|
502
|
+
console.error("load key error");
|
|
503
|
+
return null;
|
|
504
|
+
}
|
|
505
|
+
return _env[key];
|
|
506
|
+
};
|
|
507
|
+
return checkFn();
|
|
508
|
+
}
|
|
509
|
+
console.error("key is empty ");
|
|
510
|
+
return null;
|
|
511
|
+
};
|
|
512
|
+
var useEnvKeyNew = (key, initKey = "config", opts) => {
|
|
513
|
+
const _env = useEnv({}, initKey);
|
|
514
|
+
if (key) {
|
|
515
|
+
delete _env[key];
|
|
516
|
+
}
|
|
517
|
+
if (opts?.getNew && opts.init) {
|
|
518
|
+
return useEnvKey(key, opts.init, initKey);
|
|
519
|
+
} else if (opts?.getNew) {
|
|
520
|
+
return useEnvKey(key, null, initKey);
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
var useContextKey = (key, init, isNew) => {
|
|
524
|
+
if (isNew) {
|
|
525
|
+
return useEnvKeyNew(key, "context", { getNew: true, init });
|
|
526
|
+
}
|
|
527
|
+
return useEnvKey(key, init, "context");
|
|
528
|
+
};
|
|
529
|
+
var use = useContextKey;
|
|
530
|
+
var useConfigKey = (key, init, isNew) => {
|
|
531
|
+
if (isNew) {
|
|
532
|
+
return useEnvKeyNew(key, "config", { getNew: true, init });
|
|
533
|
+
}
|
|
534
|
+
return useEnvKey(key, init, "config");
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
class InitEnv {
|
|
538
|
+
static isInit = false;
|
|
539
|
+
static init(opts) {
|
|
540
|
+
if (InitEnv.isInit) {
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
const { load = true, page = false } = opts || {};
|
|
544
|
+
InitEnv.isInit = true;
|
|
545
|
+
gt.useConfigKey = useConfigKey;
|
|
546
|
+
gt.useContextKey = useContextKey;
|
|
547
|
+
gt.use = use;
|
|
548
|
+
gt.webEnv = { useConfigKey, useContextKey, use };
|
|
549
|
+
load && (gt.Load = BaseLoad);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
InitEnv.init();
|
|
553
|
+
|
|
554
|
+
class Lexer {
|
|
555
|
+
constructor(input) {
|
|
556
|
+
this.pos = 0;
|
|
557
|
+
this.input = input.trim();
|
|
558
|
+
}
|
|
559
|
+
skipWhitespace() {
|
|
560
|
+
while (this.pos < this.input.length && /\s/.test(this.input[this.pos])) {
|
|
561
|
+
this.pos++;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
readString(quote) {
|
|
565
|
+
this.pos++;
|
|
566
|
+
let result = '';
|
|
567
|
+
while (this.pos < this.input.length && this.input[this.pos] !== quote) {
|
|
568
|
+
result += this.input[this.pos];
|
|
569
|
+
this.pos++;
|
|
570
|
+
}
|
|
571
|
+
this.pos++;
|
|
572
|
+
return result;
|
|
573
|
+
}
|
|
574
|
+
readNumber() {
|
|
575
|
+
let result = '';
|
|
576
|
+
while (this.pos < this.input.length && /[\d.]/.test(this.input[this.pos])) {
|
|
577
|
+
result += this.input[this.pos];
|
|
578
|
+
this.pos++;
|
|
579
|
+
}
|
|
580
|
+
return result;
|
|
581
|
+
}
|
|
582
|
+
readIdentifier() {
|
|
583
|
+
let result = '';
|
|
584
|
+
while (this.pos < this.input.length && /[\w.]/.test(this.input[this.pos])) {
|
|
585
|
+
result += this.input[this.pos];
|
|
586
|
+
this.pos++;
|
|
587
|
+
}
|
|
588
|
+
return result;
|
|
589
|
+
}
|
|
590
|
+
isKeyword(value) {
|
|
591
|
+
const keywords = ['WHERE', 'AND', 'OR', 'ORDER', 'BY', 'ASC', 'DESC', 'LIMIT', 'IN', 'CONTAINS', 'LIKE', 'NOT', 'IS', 'NULL'];
|
|
592
|
+
return keywords.includes(value.toUpperCase());
|
|
593
|
+
}
|
|
594
|
+
nextToken() {
|
|
595
|
+
this.skipWhitespace();
|
|
596
|
+
if (this.pos >= this.input.length) {
|
|
597
|
+
return { type: 'EOF', value: '', pos: this.pos };
|
|
598
|
+
}
|
|
599
|
+
const char = this.input[this.pos];
|
|
600
|
+
if (char === "'" || char === '"') {
|
|
601
|
+
return { type: 'STRING', value: this.readString(char), pos: this.pos };
|
|
602
|
+
}
|
|
603
|
+
if (/\d/.test(char)) {
|
|
604
|
+
return { type: 'NUMBER', value: this.readNumber(), pos: this.pos };
|
|
605
|
+
}
|
|
606
|
+
if (char === ',') {
|
|
607
|
+
this.pos++;
|
|
608
|
+
return { type: 'COMMA', value: ',', pos: this.pos };
|
|
609
|
+
}
|
|
610
|
+
if (char === '[') {
|
|
611
|
+
this.pos++;
|
|
612
|
+
return { type: 'LBRACKET', value: '[', pos: this.pos };
|
|
613
|
+
}
|
|
614
|
+
if (char === ']') {
|
|
615
|
+
this.pos++;
|
|
616
|
+
return { type: 'RBRACKET', value: ']', pos: this.pos };
|
|
617
|
+
}
|
|
618
|
+
if (/[=<>!]/.test(char)) {
|
|
619
|
+
this.pos++;
|
|
620
|
+
if (char === '=' && this.pos < this.input.length && this.input[this.pos] === '=') {
|
|
621
|
+
this.pos++;
|
|
622
|
+
return { type: 'EQ', value: '==', pos: this.pos };
|
|
623
|
+
}
|
|
624
|
+
if (char === '!' && this.pos < this.input.length && this.input[this.pos] === '=') {
|
|
625
|
+
this.pos++;
|
|
626
|
+
return { type: 'NEQ', value: '!=', pos: this.pos };
|
|
627
|
+
}
|
|
628
|
+
if (char === '>') {
|
|
629
|
+
if (this.pos < this.input.length && this.input[this.pos] === '=') {
|
|
630
|
+
this.pos++;
|
|
631
|
+
return { type: 'GTE', value: '>=', pos: this.pos };
|
|
632
|
+
}
|
|
633
|
+
return { type: 'GT', value: '>', pos: this.pos };
|
|
634
|
+
}
|
|
635
|
+
if (char === '<') {
|
|
636
|
+
if (this.pos < this.input.length && this.input[this.pos] === '=') {
|
|
637
|
+
this.pos++;
|
|
638
|
+
return { type: 'LTE', value: '<=', pos: this.pos };
|
|
639
|
+
}
|
|
640
|
+
return { type: 'LT', value: '<', pos: this.pos };
|
|
641
|
+
}
|
|
642
|
+
return { type: 'EQ', value: char, pos: this.pos };
|
|
643
|
+
}
|
|
644
|
+
const identifier = this.readIdentifier();
|
|
645
|
+
const upperIdentifier = identifier.toUpperCase();
|
|
646
|
+
const keywords = {
|
|
647
|
+
'WHERE': 'WHERE',
|
|
648
|
+
'AND': 'AND',
|
|
649
|
+
'OR': 'OR',
|
|
650
|
+
'ORDER': 'ORDER',
|
|
651
|
+
'BY': 'BY',
|
|
652
|
+
'ASC': 'ASC',
|
|
653
|
+
'DESC': 'DESC',
|
|
654
|
+
'LIMIT': 'LIMIT',
|
|
655
|
+
'IN': 'IN',
|
|
656
|
+
'CONTAINS': 'CONTAINS',
|
|
657
|
+
'LIKE': 'LIKE',
|
|
658
|
+
'NOT': 'NOT',
|
|
659
|
+
'IS': 'IS',
|
|
660
|
+
'NULL': 'NULL'
|
|
661
|
+
};
|
|
662
|
+
if (keywords[upperIdentifier]) {
|
|
663
|
+
return { type: keywords[upperIdentifier], value: upperIdentifier, pos: this.pos };
|
|
664
|
+
}
|
|
665
|
+
return { type: 'IDENTIFIER', value: identifier, pos: this.pos };
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
class Parser {
|
|
669
|
+
constructor(lexer) {
|
|
670
|
+
this.lexer = lexer;
|
|
671
|
+
this.currentToken = this.lexer.nextToken();
|
|
672
|
+
}
|
|
673
|
+
eat(type) {
|
|
674
|
+
if (this.currentToken.type === type) {
|
|
675
|
+
this.currentToken = this.lexer.nextToken();
|
|
676
|
+
}
|
|
677
|
+
else {
|
|
678
|
+
throw new Error(`Expected ${type}, got ${this.currentToken.type}`);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
parse() {
|
|
682
|
+
const statements = [];
|
|
683
|
+
if (this.currentToken.type === 'WHERE') {
|
|
684
|
+
statements.push(this.parseWhere());
|
|
685
|
+
}
|
|
686
|
+
if (this.currentToken.type === 'ORDER') {
|
|
687
|
+
statements.push(this.parseOrder());
|
|
688
|
+
}
|
|
689
|
+
if (this.currentToken.type === 'LIMIT') {
|
|
690
|
+
statements.push(this.parseLimit());
|
|
691
|
+
}
|
|
692
|
+
return statements;
|
|
693
|
+
}
|
|
694
|
+
parseWhere() {
|
|
695
|
+
this.eat('WHERE');
|
|
696
|
+
return { type: 'WhereClause', left: this.parseCondition() };
|
|
697
|
+
}
|
|
698
|
+
parseCondition() {
|
|
699
|
+
let left = this.parseExpression();
|
|
700
|
+
while (this.currentToken.type === 'AND' || this.currentToken.type === 'OR') {
|
|
701
|
+
const op = this.currentToken.type;
|
|
702
|
+
this.eat(op);
|
|
703
|
+
const right = this.parseExpression();
|
|
704
|
+
left = { type: 'LogicalOp', left, right, operator: op };
|
|
705
|
+
}
|
|
706
|
+
return left;
|
|
707
|
+
}
|
|
708
|
+
parseExpression() {
|
|
709
|
+
const field = this.currentToken.value;
|
|
710
|
+
this.eat('IDENTIFIER');
|
|
711
|
+
let operator;
|
|
712
|
+
let value;
|
|
713
|
+
if (this.currentToken.type === 'NOT') {
|
|
714
|
+
this.eat('NOT');
|
|
715
|
+
operator = 'NOT LIKE';
|
|
716
|
+
this.eat('LIKE');
|
|
717
|
+
value = this.parseValue();
|
|
718
|
+
}
|
|
719
|
+
else if (this.currentToken.type === 'LIKE') {
|
|
720
|
+
operator = 'LIKE';
|
|
721
|
+
this.eat('LIKE');
|
|
722
|
+
value = this.parseValue();
|
|
723
|
+
}
|
|
724
|
+
else if (this.currentToken.type === 'IS') {
|
|
725
|
+
this.eat('IS');
|
|
726
|
+
if (this.currentToken.type === 'NOT') {
|
|
727
|
+
operator = 'IS NOT NULL';
|
|
728
|
+
this.eat('NOT');
|
|
729
|
+
this.eat('NULL');
|
|
730
|
+
}
|
|
731
|
+
else {
|
|
732
|
+
operator = 'IS NULL';
|
|
733
|
+
this.eat('NULL');
|
|
734
|
+
}
|
|
735
|
+
value = null;
|
|
736
|
+
}
|
|
737
|
+
else if (this.currentToken.type === 'CONTAINS') {
|
|
738
|
+
operator = 'CONTAINS';
|
|
739
|
+
this.eat('CONTAINS');
|
|
740
|
+
value = this.parseValue();
|
|
741
|
+
}
|
|
742
|
+
else if (this.currentToken.type === 'IN') {
|
|
743
|
+
operator = 'IN';
|
|
744
|
+
this.eat('IN');
|
|
745
|
+
value = this.parseInList();
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
const opType = this.currentToken.type;
|
|
749
|
+
this.eat(opType);
|
|
750
|
+
operator = opType;
|
|
751
|
+
value = this.parseValue();
|
|
752
|
+
}
|
|
753
|
+
return { type: 'Condition', field, operator, value };
|
|
754
|
+
}
|
|
755
|
+
parseInList() {
|
|
756
|
+
this.eat('LBRACKET');
|
|
757
|
+
const values = [];
|
|
758
|
+
while (this.currentToken.type !== 'RBRACKET') {
|
|
759
|
+
const node = this.parseValue();
|
|
760
|
+
values.push(node.value);
|
|
761
|
+
if (this.currentToken.type === 'COMMA') {
|
|
762
|
+
this.eat('COMMA');
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
this.eat('RBRACKET');
|
|
766
|
+
return values;
|
|
767
|
+
}
|
|
768
|
+
parseValue() {
|
|
769
|
+
if (this.currentToken.type === 'STRING') {
|
|
770
|
+
const value = this.currentToken.value;
|
|
771
|
+
this.eat('STRING');
|
|
772
|
+
return { type: 'Value', value };
|
|
773
|
+
}
|
|
774
|
+
if (this.currentToken.type === 'NUMBER') {
|
|
775
|
+
const value = parseFloat(this.currentToken.value);
|
|
776
|
+
this.eat('NUMBER');
|
|
777
|
+
return { type: 'Value', value };
|
|
778
|
+
}
|
|
779
|
+
throw new Error(`Expected value, got ${this.currentToken.type}`);
|
|
780
|
+
}
|
|
781
|
+
parseOrder() {
|
|
782
|
+
this.eat('ORDER');
|
|
783
|
+
this.eat('BY');
|
|
784
|
+
const field = this.currentToken.value;
|
|
785
|
+
this.eat('IDENTIFIER');
|
|
786
|
+
let direction = 'ASC';
|
|
787
|
+
if (this.currentToken.type === 'ASC' || this.currentToken.type === 'DESC') {
|
|
788
|
+
direction = this.currentToken.value;
|
|
789
|
+
this.eat(this.currentToken.type);
|
|
790
|
+
}
|
|
791
|
+
return { type: 'OrderClause', field, value: direction };
|
|
792
|
+
}
|
|
793
|
+
parseLimit() {
|
|
794
|
+
this.eat('LIMIT');
|
|
795
|
+
const value = parseFloat(this.currentToken.value);
|
|
796
|
+
this.eat('NUMBER');
|
|
797
|
+
return { type: 'LimitClause', value };
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
class Executor {
|
|
801
|
+
getValueByPath(obj, path) {
|
|
802
|
+
return path.split('.').reduce((acc, part) => acc?.[part], obj);
|
|
803
|
+
}
|
|
804
|
+
likeToRegex(pattern) {
|
|
805
|
+
let regex = '';
|
|
806
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
807
|
+
const char = pattern[i];
|
|
808
|
+
if (char === '%') {
|
|
809
|
+
regex += '.*';
|
|
810
|
+
}
|
|
811
|
+
else if (char === '_') {
|
|
812
|
+
regex += '.';
|
|
813
|
+
}
|
|
814
|
+
else if (/[.*+?^${}()|[\]\\]/.test(char)) {
|
|
815
|
+
regex += '\\' + char;
|
|
816
|
+
}
|
|
817
|
+
else {
|
|
818
|
+
regex += char;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
return new RegExp(`^${regex}$`, 'i');
|
|
822
|
+
}
|
|
823
|
+
evaluateCondition(node, item) {
|
|
824
|
+
if (node.type === 'Condition') {
|
|
825
|
+
const fieldValue = this.getValueByPath(item, node.field);
|
|
826
|
+
const { operator, value } = node;
|
|
827
|
+
const actualValue = value?.type === 'Value' ? value.value : value;
|
|
828
|
+
switch (operator) {
|
|
829
|
+
case 'EQ':
|
|
830
|
+
return fieldValue === actualValue;
|
|
831
|
+
case 'NEQ':
|
|
832
|
+
return fieldValue !== actualValue;
|
|
833
|
+
case 'GT':
|
|
834
|
+
return fieldValue > actualValue;
|
|
835
|
+
case 'LT':
|
|
836
|
+
return fieldValue < actualValue;
|
|
837
|
+
case 'GTE':
|
|
838
|
+
return fieldValue >= actualValue;
|
|
839
|
+
case 'LTE':
|
|
840
|
+
return fieldValue <= actualValue;
|
|
841
|
+
case 'IN':
|
|
842
|
+
return Array.isArray(actualValue) && actualValue.includes(fieldValue);
|
|
843
|
+
case 'CONTAINS':
|
|
844
|
+
return Array.isArray(fieldValue) && fieldValue.includes(actualValue);
|
|
845
|
+
case 'LIKE':
|
|
846
|
+
if (typeof fieldValue !== 'string' || typeof actualValue !== 'string') {
|
|
847
|
+
return false;
|
|
848
|
+
}
|
|
849
|
+
return this.likeToRegex(actualValue).test(fieldValue);
|
|
850
|
+
case 'NOT LIKE':
|
|
851
|
+
if (typeof fieldValue !== 'string' || typeof actualValue !== 'string') {
|
|
852
|
+
return true;
|
|
853
|
+
}
|
|
854
|
+
return !this.likeToRegex(actualValue).test(fieldValue);
|
|
855
|
+
case 'IS NULL':
|
|
856
|
+
return fieldValue === null || fieldValue === undefined;
|
|
857
|
+
case 'IS NOT NULL':
|
|
858
|
+
return fieldValue !== null && fieldValue !== undefined;
|
|
859
|
+
default:
|
|
860
|
+
return false;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
if (node.type === 'LogicalOp') {
|
|
864
|
+
const leftResult = this.evaluateCondition(node.left, item);
|
|
865
|
+
const rightResult = this.evaluateCondition(node.right, item);
|
|
866
|
+
return node.operator === 'AND'
|
|
867
|
+
? leftResult && rightResult
|
|
868
|
+
: leftResult || rightResult;
|
|
869
|
+
}
|
|
870
|
+
return true;
|
|
871
|
+
}
|
|
872
|
+
execute(statements, data) {
|
|
873
|
+
let result = [...data];
|
|
874
|
+
for (const stmt of statements) {
|
|
875
|
+
if (stmt.type === 'WhereClause') {
|
|
876
|
+
result = result.filter(item => this.evaluateCondition(stmt.left, item));
|
|
877
|
+
}
|
|
878
|
+
else if (stmt.type === 'OrderClause') {
|
|
879
|
+
const field = stmt.field;
|
|
880
|
+
const direction = stmt.value;
|
|
881
|
+
result.sort((a, b) => {
|
|
882
|
+
const aVal = this.getValueByPath(a, field);
|
|
883
|
+
const bVal = this.getValueByPath(b, field);
|
|
884
|
+
if (aVal === bVal)
|
|
885
|
+
return 0;
|
|
886
|
+
const cmp = aVal > bVal ? 1 : -1;
|
|
887
|
+
return direction === 'ASC' ? cmp : -cmp;
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
else if (stmt.type === 'LimitClause') {
|
|
891
|
+
result = result.slice(0, stmt.value);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
return result;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
function filter(data, query) {
|
|
898
|
+
if (!query || query.trim() === '') {
|
|
899
|
+
return data;
|
|
900
|
+
}
|
|
901
|
+
const lexer = new Lexer(query);
|
|
902
|
+
const parser = new Parser(lexer);
|
|
903
|
+
const ast = parser.parse();
|
|
904
|
+
const executor = new Executor();
|
|
905
|
+
return executor.execute(ast, data);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
const createRouterAgentPluginFn = (opts) => {
|
|
909
|
+
let router = opts?.router;
|
|
910
|
+
if (!router) {
|
|
911
|
+
const app = useContextKey('app');
|
|
912
|
+
router = app.router;
|
|
913
|
+
}
|
|
914
|
+
if (!router) {
|
|
915
|
+
throw new Error('Router 参数缺失');
|
|
916
|
+
}
|
|
917
|
+
const _routes = filter(router.routes, opts?.query || '');
|
|
918
|
+
const routes = _routes.filter(r => {
|
|
919
|
+
const metadata = r.metadata;
|
|
920
|
+
if (metadata && metadata.tags && metadata.tags.includes('opencode')) {
|
|
921
|
+
return !!metadata.skill;
|
|
922
|
+
}
|
|
923
|
+
return false;
|
|
924
|
+
});
|
|
925
|
+
// opencode run "查看系统信息"
|
|
926
|
+
const AgentPlugin = async ({ project, client, $, directory, worktree }) => {
|
|
927
|
+
return {
|
|
928
|
+
'tool': {
|
|
929
|
+
...routes.reduce((acc, route) => {
|
|
930
|
+
const metadata = route.metadata;
|
|
931
|
+
acc[metadata.skill] = {
|
|
932
|
+
name: metadata.title || metadata.skill,
|
|
933
|
+
description: metadata.summary || '',
|
|
934
|
+
args: metadata.args || {},
|
|
935
|
+
async execute(args) {
|
|
936
|
+
const res = await router.run({
|
|
937
|
+
path: route.path,
|
|
938
|
+
key: route.key,
|
|
939
|
+
payload: args
|
|
940
|
+
}, { appId: router.appId });
|
|
941
|
+
if (res.code === 200) {
|
|
942
|
+
if (res.data?.content) {
|
|
943
|
+
return res.data.content;
|
|
944
|
+
}
|
|
945
|
+
if (res.data?.final) {
|
|
946
|
+
return '调用程序成功';
|
|
947
|
+
}
|
|
948
|
+
const str = JSON.stringify(res.data || res, null, 2);
|
|
949
|
+
if (str.length > 10000) {
|
|
950
|
+
return str.slice(0, 10000) + '... (truncated)';
|
|
951
|
+
}
|
|
952
|
+
return str;
|
|
953
|
+
}
|
|
954
|
+
return `Error: ${res?.message || '无法获取结果'}`;
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
return acc;
|
|
958
|
+
}, {})
|
|
959
|
+
},
|
|
960
|
+
'tool.execute.before': async (opts) => {
|
|
961
|
+
// console.log('CnbPlugin: tool.execute.before', opts.tool);
|
|
962
|
+
// delete toolSkills['cnb-login-verify']
|
|
963
|
+
}
|
|
964
|
+
};
|
|
965
|
+
};
|
|
966
|
+
return AgentPlugin;
|
|
967
|
+
};
|
|
968
|
+
|
|
969
|
+
export { createRouterAgentPluginFn };
|