@lark-apaas/nestjs-capability 0.0.1-alpha.8 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +389 -130
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +147 -10
- package/dist/index.d.ts +147 -10
- package/dist/index.js +385 -137
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
|
-
}) : x)(function(x) {
|
|
6
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
7
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
-
});
|
|
9
3
|
|
|
10
4
|
// src/interfaces/error-codes.ts
|
|
11
5
|
var ErrorCodes = {
|
|
@@ -37,9 +31,9 @@ var TemplateEngineService = class {
|
|
|
37
31
|
__name(this, "TemplateEngineService");
|
|
38
32
|
}
|
|
39
33
|
// 匹配 {{input.xxx}} 或 {{input.xxx.yyy}} 表达式
|
|
40
|
-
EXPR_REGEX = /\{\{input\.([a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*)\}\}/g;
|
|
34
|
+
EXPR_REGEX = /\{\{\s*input\.([a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*\s*)\}\}/g;
|
|
41
35
|
// 匹配整串单个表达式
|
|
42
|
-
WHOLE_STRING_EXPR_REGEX = /^\{\{input\.([a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*)\}\}$/;
|
|
36
|
+
WHOLE_STRING_EXPR_REGEX = /^\{\{\s*input\.([a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*)\s*\}\}$/;
|
|
43
37
|
resolve(template, input) {
|
|
44
38
|
if (typeof template === "string") {
|
|
45
39
|
return this.resolveString(template, input);
|
|
@@ -98,6 +92,8 @@ TemplateEngineService = _ts_decorate([
|
|
|
98
92
|
|
|
99
93
|
// src/services/plugin-loader.service.ts
|
|
100
94
|
import { Injectable as Injectable2, Logger } from "@nestjs/common";
|
|
95
|
+
import { createRequire } from "module";
|
|
96
|
+
import { pathToFileURL } from "url";
|
|
101
97
|
function _ts_decorate2(decorators, target, key, desc) {
|
|
102
98
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
103
99
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -105,13 +101,16 @@ function _ts_decorate2(decorators, target, key, desc) {
|
|
|
105
101
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
106
102
|
}
|
|
107
103
|
__name(_ts_decorate2, "_ts_decorate");
|
|
104
|
+
var require2 = createRequire(import.meta.url);
|
|
108
105
|
var PluginNotFoundError = class extends Error {
|
|
109
106
|
static {
|
|
110
107
|
__name(this, "PluginNotFoundError");
|
|
111
108
|
}
|
|
109
|
+
pluginKey;
|
|
112
110
|
constructor(pluginKey) {
|
|
113
111
|
super(`Plugin not found: ${pluginKey}`);
|
|
114
112
|
this.name = "PluginNotFoundError";
|
|
113
|
+
this.pluginKey = pluginKey;
|
|
115
114
|
}
|
|
116
115
|
};
|
|
117
116
|
var PluginLoadError = class extends Error {
|
|
@@ -129,6 +128,8 @@ var PluginLoaderService = class _PluginLoaderService {
|
|
|
129
128
|
}
|
|
130
129
|
logger = new Logger(_PluginLoaderService.name);
|
|
131
130
|
pluginInstances = /* @__PURE__ */ new Map();
|
|
131
|
+
/** 记录每个插件的加载版本(时间戳),用于 ESM 缓存绕过 */
|
|
132
|
+
pluginVersions = /* @__PURE__ */ new Map();
|
|
132
133
|
async loadPlugin(pluginKey) {
|
|
133
134
|
const cached = this.pluginInstances.get(pluginKey);
|
|
134
135
|
if (cached) {
|
|
@@ -137,7 +138,12 @@ var PluginLoaderService = class _PluginLoaderService {
|
|
|
137
138
|
}
|
|
138
139
|
this.logger.log(`Loading plugin: ${pluginKey}`);
|
|
139
140
|
try {
|
|
140
|
-
const
|
|
141
|
+
const resolvedPath = require2.resolve(pluginKey);
|
|
142
|
+
const version = this.pluginVersions.get(pluginKey) ?? 0;
|
|
143
|
+
const fileUrl = pathToFileURL(resolvedPath).href;
|
|
144
|
+
const importPath = version > 0 ? `${fileUrl}?v=${version}` : fileUrl;
|
|
145
|
+
const mod = await import(importPath);
|
|
146
|
+
const pluginPackage = mod.default ?? mod;
|
|
141
147
|
if (typeof pluginPackage.create !== "function") {
|
|
142
148
|
throw new PluginLoadError(pluginKey, "Plugin does not export create() function");
|
|
143
149
|
}
|
|
@@ -154,21 +160,68 @@ var PluginLoaderService = class _PluginLoaderService {
|
|
|
154
160
|
}
|
|
155
161
|
isPluginInstalled(pluginKey) {
|
|
156
162
|
try {
|
|
157
|
-
|
|
163
|
+
require2.resolve(pluginKey);
|
|
158
164
|
return true;
|
|
159
165
|
} catch {
|
|
160
166
|
return false;
|
|
161
167
|
}
|
|
162
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* 清除插件缓存
|
|
171
|
+
* - 清除应用层 pluginInstances 缓存
|
|
172
|
+
* - 清除 Node.js CJS 模块缓存(require.cache)
|
|
173
|
+
* - 更新版本号,下次 import 时绕过 ESM 缓存
|
|
174
|
+
* @param pluginKey - 插件标识,不传则清除所有
|
|
175
|
+
*/
|
|
163
176
|
clearCache(pluginKey) {
|
|
164
177
|
if (pluginKey) {
|
|
165
178
|
this.pluginInstances.delete(pluginKey);
|
|
179
|
+
this.clearNodeModuleCache(pluginKey);
|
|
180
|
+
this.pluginVersions.set(pluginKey, Date.now());
|
|
166
181
|
this.logger.log(`Cleared cache for plugin: ${pluginKey}`);
|
|
167
182
|
} else {
|
|
183
|
+
for (const key of this.pluginInstances.keys()) {
|
|
184
|
+
this.clearNodeModuleCache(key);
|
|
185
|
+
this.pluginVersions.set(key, Date.now());
|
|
186
|
+
}
|
|
168
187
|
this.pluginInstances.clear();
|
|
169
188
|
this.logger.log("Cleared all plugin caches");
|
|
170
189
|
}
|
|
171
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* 清除 CJS 模块缓存
|
|
193
|
+
*/
|
|
194
|
+
clearNodeModuleCache(pluginKey) {
|
|
195
|
+
try {
|
|
196
|
+
const resolvedPath = require2.resolve(pluginKey);
|
|
197
|
+
const mod = require2.cache[resolvedPath];
|
|
198
|
+
if (mod) {
|
|
199
|
+
this.clearModuleAndChildren(mod, pluginKey);
|
|
200
|
+
}
|
|
201
|
+
delete require2.cache[resolvedPath];
|
|
202
|
+
} catch {
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* 递归清除子模块缓存
|
|
207
|
+
*/
|
|
208
|
+
clearModuleAndChildren(mod, pluginKey) {
|
|
209
|
+
const pluginScope = pluginKey.startsWith("@") ? pluginKey.split("/").slice(0, 2).join("/") : pluginKey;
|
|
210
|
+
mod.children.forEach((child) => {
|
|
211
|
+
if (child.filename.includes(`node_modules/${pluginScope}`)) {
|
|
212
|
+
this.clearModuleAndChildren(child, pluginKey);
|
|
213
|
+
delete require2.cache[child.filename];
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* 强制重新加载插件
|
|
219
|
+
* @param pluginKey - 插件标识
|
|
220
|
+
*/
|
|
221
|
+
async reloadPlugin(pluginKey) {
|
|
222
|
+
this.clearCache(pluginKey);
|
|
223
|
+
return this.loadPlugin(pluginKey);
|
|
224
|
+
}
|
|
172
225
|
};
|
|
173
226
|
PluginLoaderService = _ts_decorate2([
|
|
174
227
|
Injectable2()
|
|
@@ -179,6 +232,7 @@ import { Injectable as Injectable3, Logger as Logger2, Inject } from "@nestjs/co
|
|
|
179
232
|
import { RequestContextService, PLATFORM_HTTP_CLIENT } from "@lark-apaas/nestjs-common";
|
|
180
233
|
import * as fs from "fs";
|
|
181
234
|
import * as path from "path";
|
|
235
|
+
import * as chokidar from "chokidar";
|
|
182
236
|
|
|
183
237
|
// src/utils/log-utils.ts
|
|
184
238
|
var DEFAULT_MAX_LENGTH = 1e3;
|
|
@@ -200,6 +254,43 @@ function stringifyForLog(value, maxLength = DEFAULT_MAX_LENGTH) {
|
|
|
200
254
|
}
|
|
201
255
|
__name(stringifyForLog, "stringifyForLog");
|
|
202
256
|
|
|
257
|
+
// src/utils/migration-adaptor.ts
|
|
258
|
+
async function migrationAdaptor(promise) {
|
|
259
|
+
try {
|
|
260
|
+
const result = await promise;
|
|
261
|
+
return {
|
|
262
|
+
code: 0,
|
|
263
|
+
data: {
|
|
264
|
+
output: result,
|
|
265
|
+
outcome: "success"
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
} catch (error) {
|
|
269
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
270
|
+
const appStatusCode = error instanceof Error && "code" in error ? String(error.code) : "EXECUTION_ERROR";
|
|
271
|
+
return {
|
|
272
|
+
code: -1,
|
|
273
|
+
data: {
|
|
274
|
+
outcome: "error",
|
|
275
|
+
failureOutput: {
|
|
276
|
+
response: {
|
|
277
|
+
status: {
|
|
278
|
+
protocolStatusCode: "500",
|
|
279
|
+
appStatusCode
|
|
280
|
+
},
|
|
281
|
+
body: JSON.stringify({
|
|
282
|
+
error: errorMessage,
|
|
283
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
284
|
+
})
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
message: errorMessage
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
__name(migrationAdaptor, "migrationAdaptor");
|
|
293
|
+
|
|
203
294
|
// src/services/capability.service.ts
|
|
204
295
|
function _ts_decorate3(decorators, target, key, desc) {
|
|
205
296
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -222,18 +313,24 @@ var CapabilityNotFoundError = class extends Error {
|
|
|
222
313
|
static {
|
|
223
314
|
__name(this, "CapabilityNotFoundError");
|
|
224
315
|
}
|
|
316
|
+
capabilityId;
|
|
225
317
|
constructor(capabilityId) {
|
|
226
318
|
super(`Capability not found: ${capabilityId}`);
|
|
227
319
|
this.name = "CapabilityNotFoundError";
|
|
320
|
+
this.capabilityId = capabilityId;
|
|
228
321
|
}
|
|
229
322
|
};
|
|
230
323
|
var ActionNotFoundError = class extends Error {
|
|
231
324
|
static {
|
|
232
325
|
__name(this, "ActionNotFoundError");
|
|
233
326
|
}
|
|
327
|
+
pluginKey;
|
|
328
|
+
actionName;
|
|
234
329
|
constructor(pluginKey, actionName) {
|
|
235
330
|
super(`Action '${actionName}' not found in plugin ${pluginKey}`);
|
|
236
331
|
this.name = "ActionNotFoundError";
|
|
332
|
+
this.pluginKey = pluginKey;
|
|
333
|
+
this.actionName = actionName;
|
|
237
334
|
}
|
|
238
335
|
};
|
|
239
336
|
var CapabilityService = class _CapabilityService {
|
|
@@ -246,20 +343,153 @@ var CapabilityService = class _CapabilityService {
|
|
|
246
343
|
templateEngineService;
|
|
247
344
|
logger = new Logger2(_CapabilityService.name);
|
|
248
345
|
capabilities = /* @__PURE__ */ new Map();
|
|
346
|
+
/** 文件路径到 capability id 的映射,用于文件删除时查找 */
|
|
347
|
+
filePathToId = /* @__PURE__ */ new Map();
|
|
249
348
|
capabilitiesDir;
|
|
349
|
+
fileWatcher = null;
|
|
350
|
+
options = {};
|
|
250
351
|
constructor(requestContextService, platformHttpClient, pluginLoaderService, templateEngineService) {
|
|
251
352
|
this.requestContextService = requestContextService;
|
|
252
353
|
this.platformHttpClient = platformHttpClient;
|
|
253
354
|
this.pluginLoaderService = pluginLoaderService;
|
|
254
355
|
this.templateEngineService = templateEngineService;
|
|
255
|
-
|
|
356
|
+
const isDev = process.env.NODE_ENV === "development";
|
|
357
|
+
this.capabilitiesDir = path.join(process.cwd(), isDev ? "server/capabilities" : "capabilities");
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* 设置模块配置
|
|
361
|
+
*/
|
|
362
|
+
setOptions(options) {
|
|
363
|
+
this.options = options;
|
|
364
|
+
if (options.capabilitiesDir) {
|
|
365
|
+
this.capabilitiesDir = options.capabilitiesDir;
|
|
366
|
+
}
|
|
256
367
|
}
|
|
257
368
|
setCapabilitiesDir(dir) {
|
|
258
369
|
this.capabilitiesDir = dir;
|
|
259
370
|
}
|
|
260
371
|
async onModuleInit() {
|
|
261
372
|
await this.loadCapabilities();
|
|
373
|
+
if (this.options.enableWatching) {
|
|
374
|
+
this.startWatching();
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
async onModuleDestroy() {
|
|
378
|
+
this.stopWatching();
|
|
379
|
+
}
|
|
380
|
+
// ==================== 文件监听相关方法 ====================
|
|
381
|
+
/**
|
|
382
|
+
* 启动文件监听(沙箱环境自动调用)
|
|
383
|
+
*/
|
|
384
|
+
startWatching() {
|
|
385
|
+
if (this.fileWatcher) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
if (!fs.existsSync(this.capabilitiesDir)) {
|
|
389
|
+
this.logger.warn(`Cannot start watching: directory not found: ${this.capabilitiesDir}`);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const pattern = path.join(this.capabilitiesDir, "*.json");
|
|
393
|
+
const debounce = this.options.watchDebounce ?? 300;
|
|
394
|
+
this.logger.log(`Starting file watcher: ${pattern}`);
|
|
395
|
+
this.fileWatcher = chokidar.watch(pattern, {
|
|
396
|
+
persistent: true,
|
|
397
|
+
ignoreInitial: true,
|
|
398
|
+
awaitWriteFinish: {
|
|
399
|
+
// 等待写入完成
|
|
400
|
+
stabilityThreshold: debounce,
|
|
401
|
+
pollInterval: 100
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
this.fileWatcher.on("add", (filePath) => this.handleFileAdd(filePath)).on("change", (filePath) => this.handleFileChange(filePath)).on("unlink", (filePath) => this.handleFileUnlink(filePath)).on("error", (error) => this.logger.error("File watcher error:", error));
|
|
405
|
+
this.logger.log("File watcher started");
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* 停止文件监听
|
|
409
|
+
*/
|
|
410
|
+
stopWatching() {
|
|
411
|
+
if (this.fileWatcher) {
|
|
412
|
+
this.fileWatcher.close();
|
|
413
|
+
this.fileWatcher = null;
|
|
414
|
+
this.logger.log("File watcher stopped");
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* 重新加载所有能力配置
|
|
419
|
+
*/
|
|
420
|
+
async reloadAllCapabilities() {
|
|
421
|
+
this.capabilities.clear();
|
|
422
|
+
this.filePathToId.clear();
|
|
423
|
+
await this.loadCapabilities();
|
|
424
|
+
}
|
|
425
|
+
handleFileAdd(filePath) {
|
|
426
|
+
this.logger.log(`Capability file added: ${filePath}`);
|
|
427
|
+
try {
|
|
428
|
+
this.loadCapabilityFromFile(filePath);
|
|
429
|
+
const capabilityId = this.filePathToId.get(filePath);
|
|
430
|
+
if (capabilityId) {
|
|
431
|
+
const config = this.capabilities.get(capabilityId);
|
|
432
|
+
if (config?.pluginKey) {
|
|
433
|
+
this.pluginLoaderService.clearCache(config.pluginKey);
|
|
434
|
+
this.logger.log(`Cleared plugin cache for new capability: ${config.pluginKey}`);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
} catch (error) {
|
|
438
|
+
this.logger.error(`Failed to load new capability: ${filePath}`, error);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
handleFileChange(filePath) {
|
|
442
|
+
this.logger.log(`Capability file changed: ${filePath}`);
|
|
443
|
+
try {
|
|
444
|
+
this.reloadCapabilityFromFile(filePath);
|
|
445
|
+
} catch (error) {
|
|
446
|
+
this.logger.error(`Failed to reload capability: ${filePath}`, error);
|
|
447
|
+
}
|
|
262
448
|
}
|
|
449
|
+
handleFileUnlink(filePath) {
|
|
450
|
+
this.logger.log(`Capability file removed: ${filePath}`);
|
|
451
|
+
this.removeCapabilityByFile(filePath);
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* 从文件加载单个能力配置
|
|
455
|
+
*/
|
|
456
|
+
loadCapabilityFromFile(filePath) {
|
|
457
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
458
|
+
const config = JSON.parse(content);
|
|
459
|
+
if (!config.id) {
|
|
460
|
+
this.logger.warn(`Skipping capability without id: ${filePath}`);
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
this.capabilities.set(config.id, config);
|
|
464
|
+
this.filePathToId.set(filePath, config.id);
|
|
465
|
+
this.logger.log(`Loaded capability: ${config.id} (${config.name})`);
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* 重新加载单个能力配置
|
|
469
|
+
*/
|
|
470
|
+
reloadCapabilityFromFile(filePath) {
|
|
471
|
+
const oldId = this.filePathToId.get(filePath);
|
|
472
|
+
if (oldId) {
|
|
473
|
+
const oldConfig = this.capabilities.get(oldId);
|
|
474
|
+
if (oldConfig) {
|
|
475
|
+
this.pluginLoaderService.clearCache(oldConfig.pluginKey);
|
|
476
|
+
}
|
|
477
|
+
this.capabilities.delete(oldId);
|
|
478
|
+
}
|
|
479
|
+
this.loadCapabilityFromFile(filePath);
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* 根据文件路径移除能力配置
|
|
483
|
+
*/
|
|
484
|
+
removeCapabilityByFile(filePath) {
|
|
485
|
+
const capabilityId = this.filePathToId.get(filePath);
|
|
486
|
+
if (capabilityId) {
|
|
487
|
+
this.capabilities.delete(capabilityId);
|
|
488
|
+
this.filePathToId.delete(filePath);
|
|
489
|
+
this.logger.log(`Removed capability: ${capabilityId}`);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
// ==================== 原有方法 ====================
|
|
263
493
|
async loadCapabilities() {
|
|
264
494
|
this.logger.log(`Loading capabilities from ${this.capabilitiesDir}`);
|
|
265
495
|
if (!fs.existsSync(this.capabilitiesDir)) {
|
|
@@ -270,14 +500,7 @@ var CapabilityService = class _CapabilityService {
|
|
|
270
500
|
for (const file of files) {
|
|
271
501
|
try {
|
|
272
502
|
const filePath = path.join(this.capabilitiesDir, file);
|
|
273
|
-
|
|
274
|
-
const config = JSON.parse(content);
|
|
275
|
-
if (!config.id) {
|
|
276
|
-
this.logger.warn(`Skipping capability without id: ${file}`);
|
|
277
|
-
continue;
|
|
278
|
-
}
|
|
279
|
-
this.capabilities.set(config.id, config);
|
|
280
|
-
this.logger.log(`Loaded capability: ${config.id} (${config.name})`);
|
|
503
|
+
this.loadCapabilityFromFile(filePath);
|
|
281
504
|
} catch (error) {
|
|
282
505
|
this.logger.error(`Failed to load capability from ${file}:`, error);
|
|
283
506
|
}
|
|
@@ -553,7 +776,8 @@ CapabilityService = _ts_decorate3([
|
|
|
553
776
|
], CapabilityService);
|
|
554
777
|
|
|
555
778
|
// src/controllers/debug.controller.ts
|
|
556
|
-
import { Controller, Post, Get, Param, Body, Res,
|
|
779
|
+
import { Controller, Post, Get, Param, Body, Res, HttpStatus, Logger as Logger3 } from "@nestjs/common";
|
|
780
|
+
import { ApiExcludeController } from "@nestjs/swagger";
|
|
557
781
|
function _ts_decorate4(decorators, target, key, desc) {
|
|
558
782
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
559
783
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -584,19 +808,27 @@ var DebugController = class _DebugController {
|
|
|
584
808
|
this.pluginLoaderService = pluginLoaderService;
|
|
585
809
|
this.templateEngineService = templateEngineService;
|
|
586
810
|
}
|
|
587
|
-
list() {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
811
|
+
list(res) {
|
|
812
|
+
try {
|
|
813
|
+
const capabilities = this.capabilityService.listCapabilities();
|
|
814
|
+
res.status(HttpStatus.OK).json({
|
|
815
|
+
status_code: ErrorCodes.SUCCESS,
|
|
816
|
+
data: {
|
|
817
|
+
capabilities: capabilities.map((c) => ({
|
|
818
|
+
id: c.id,
|
|
819
|
+
name: c.name,
|
|
820
|
+
pluginID: c.pluginKey,
|
|
821
|
+
pluginVersion: c.pluginVersion
|
|
822
|
+
}))
|
|
823
|
+
}
|
|
824
|
+
});
|
|
825
|
+
} catch (error) {
|
|
826
|
+
this.logger.error("Failed to list capabilities", error);
|
|
827
|
+
res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({
|
|
828
|
+
status_code: ErrorCodes.EXECUTION_ERROR,
|
|
829
|
+
error_msg: `Failed to list capabilities: ${error instanceof Error ? error.message : String(error)}`
|
|
830
|
+
});
|
|
831
|
+
}
|
|
600
832
|
}
|
|
601
833
|
/**
|
|
602
834
|
* 获取 capability 配置
|
|
@@ -608,11 +840,7 @@ var DebugController = class _DebugController {
|
|
|
608
840
|
}
|
|
609
841
|
const config = this.capabilityService.getCapability(capabilityId);
|
|
610
842
|
if (!config) {
|
|
611
|
-
throw new
|
|
612
|
-
code: 1,
|
|
613
|
-
message: `Capability not found: ${capabilityId}`,
|
|
614
|
-
error: "CAPABILITY_NOT_FOUND"
|
|
615
|
-
}, HttpStatus.NOT_FOUND);
|
|
843
|
+
throw new CapabilityNotFoundError(capabilityId);
|
|
616
844
|
}
|
|
617
845
|
return config;
|
|
618
846
|
}
|
|
@@ -627,25 +855,21 @@ var DebugController = class _DebugController {
|
|
|
627
855
|
const pluginInstance = await this.pluginLoaderService.loadPlugin(pluginKey);
|
|
628
856
|
const actions = pluginInstance.listActions();
|
|
629
857
|
if (actions.length === 0) {
|
|
630
|
-
throw new
|
|
631
|
-
code: 1,
|
|
632
|
-
message: `Plugin ${pluginKey} has no actions`,
|
|
633
|
-
error: "NO_ACTIONS"
|
|
634
|
-
}, HttpStatus.BAD_REQUEST);
|
|
858
|
+
throw new Error(`Plugin ${pluginKey} has no actions`);
|
|
635
859
|
}
|
|
636
860
|
return actions[0];
|
|
637
861
|
}
|
|
638
|
-
async debug(capabilityId, body) {
|
|
862
|
+
async debug(capabilityId, body, res) {
|
|
639
863
|
const startTime = Date.now();
|
|
640
864
|
const params = body.params ?? {};
|
|
641
|
-
const config = this.getCapabilityConfig(capabilityId, body.capability);
|
|
642
|
-
const action = await this.getActionName(config.pluginKey, body.action);
|
|
643
|
-
const resolvedParams = this.templateEngineService.resolve(config.formValue, params);
|
|
644
865
|
try {
|
|
866
|
+
const config = this.getCapabilityConfig(capabilityId, body.capability);
|
|
867
|
+
const action = await this.getActionName(config.pluginKey, body.action);
|
|
868
|
+
const resolvedParams = this.templateEngineService.resolve(config.formValue, params);
|
|
645
869
|
const result = await this.capabilityService.loadWithConfig(config).call(action, params, {
|
|
646
870
|
isDebug: true
|
|
647
871
|
});
|
|
648
|
-
|
|
872
|
+
res.status(HttpStatus.OK).json({
|
|
649
873
|
status_code: ErrorCodes.SUCCESS,
|
|
650
874
|
data: {
|
|
651
875
|
output: result,
|
|
@@ -657,32 +881,39 @@ var DebugController = class _DebugController {
|
|
|
657
881
|
action
|
|
658
882
|
}
|
|
659
883
|
}
|
|
660
|
-
};
|
|
884
|
+
});
|
|
661
885
|
} catch (error) {
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
status_code: ErrorCodes.CAPABILITY_NOT_FOUND,
|
|
665
|
-
error_msg: `Capability not found: ${capabilityId}`
|
|
666
|
-
}, HttpStatus.NOT_FOUND);
|
|
667
|
-
}
|
|
668
|
-
if (error instanceof PluginNotFoundError) {
|
|
669
|
-
throw new HttpException({
|
|
670
|
-
status_code: ErrorCodes.PLUGIN_NOT_FOUND,
|
|
671
|
-
error_msg: `Plugin not found: ${config.pluginKey}`
|
|
672
|
-
}, HttpStatus.INTERNAL_SERVER_ERROR);
|
|
673
|
-
}
|
|
674
|
-
if (error instanceof ActionNotFoundError) {
|
|
675
|
-
throw new HttpException({
|
|
676
|
-
status_code: ErrorCodes.ACTION_NOT_FOUND,
|
|
677
|
-
error_msg: `Action '${action}' not found in plugin ${config.pluginKey}`
|
|
678
|
-
}, HttpStatus.BAD_REQUEST);
|
|
679
|
-
}
|
|
680
|
-
throw new HttpException({
|
|
681
|
-
status_code: ErrorCodes.EXECUTION_ERROR,
|
|
682
|
-
error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`
|
|
683
|
-
}, HttpStatus.INTERNAL_SERVER_ERROR);
|
|
886
|
+
this.logger.error("Debug execution failed", error);
|
|
887
|
+
res.status(HttpStatus.INTERNAL_SERVER_ERROR).json(this.buildErrorResponse(error));
|
|
684
888
|
}
|
|
685
889
|
}
|
|
890
|
+
/**
|
|
891
|
+
* 构建错误响应
|
|
892
|
+
*/
|
|
893
|
+
buildErrorResponse(error) {
|
|
894
|
+
if (error instanceof CapabilityNotFoundError) {
|
|
895
|
+
return {
|
|
896
|
+
status_code: ErrorCodes.CAPABILITY_NOT_FOUND,
|
|
897
|
+
error_msg: `Capability not found: ${error.capabilityId}`
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
if (error instanceof PluginNotFoundError) {
|
|
901
|
+
return {
|
|
902
|
+
status_code: ErrorCodes.PLUGIN_NOT_FOUND,
|
|
903
|
+
error_msg: `Plugin not found, please install plugin: ${error.pluginKey}`
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
if (error instanceof ActionNotFoundError) {
|
|
907
|
+
return {
|
|
908
|
+
status_code: ErrorCodes.ACTION_NOT_FOUND,
|
|
909
|
+
error_msg: `Action '${error.actionName}' not found in plugin ${error.pluginKey}`
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
return {
|
|
913
|
+
status_code: ErrorCodes.EXECUTION_ERROR,
|
|
914
|
+
error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`
|
|
915
|
+
};
|
|
916
|
+
}
|
|
686
917
|
async debugStream(capabilityId, body, res) {
|
|
687
918
|
const params = body.params ?? {};
|
|
688
919
|
res.setHeader("Content-Type", "text/event-stream");
|
|
@@ -713,9 +944,7 @@ var DebugController = class _DebugController {
|
|
|
713
944
|
status_code: ErrorCodes.SUCCESS,
|
|
714
945
|
data: {
|
|
715
946
|
type: "content",
|
|
716
|
-
delta:
|
|
717
|
-
content: pendingChunk
|
|
718
|
-
}
|
|
947
|
+
delta: pendingChunk
|
|
719
948
|
}
|
|
720
949
|
};
|
|
721
950
|
res.write(`data: ${JSON.stringify(response)}
|
|
@@ -731,9 +960,7 @@ var DebugController = class _DebugController {
|
|
|
731
960
|
status_code: ErrorCodes.SUCCESS,
|
|
732
961
|
data: {
|
|
733
962
|
type: "content",
|
|
734
|
-
delta:
|
|
735
|
-
content: pendingChunk
|
|
736
|
-
},
|
|
963
|
+
delta: pendingChunk,
|
|
737
964
|
finished: true
|
|
738
965
|
}
|
|
739
966
|
};
|
|
@@ -773,9 +1000,7 @@ var DebugController = class _DebugController {
|
|
|
773
1000
|
status_code: ErrorCodes.SUCCESS,
|
|
774
1001
|
data: {
|
|
775
1002
|
type: "content",
|
|
776
|
-
delta:
|
|
777
|
-
content: pendingChunk
|
|
778
|
-
},
|
|
1003
|
+
delta: pendingChunk,
|
|
779
1004
|
finished: true
|
|
780
1005
|
}
|
|
781
1006
|
};
|
|
@@ -805,18 +1030,23 @@ var DebugController = class _DebugController {
|
|
|
805
1030
|
};
|
|
806
1031
|
_ts_decorate4([
|
|
807
1032
|
Get("list"),
|
|
1033
|
+
_ts_param2(0, Res()),
|
|
808
1034
|
_ts_metadata2("design:type", Function),
|
|
809
|
-
_ts_metadata2("design:paramtypes", [
|
|
810
|
-
|
|
1035
|
+
_ts_metadata2("design:paramtypes", [
|
|
1036
|
+
typeof Response === "undefined" ? Object : Response
|
|
1037
|
+
]),
|
|
1038
|
+
_ts_metadata2("design:returntype", void 0)
|
|
811
1039
|
], DebugController.prototype, "list", null);
|
|
812
1040
|
_ts_decorate4([
|
|
813
1041
|
Post("debug/:capability_id"),
|
|
814
1042
|
_ts_param2(0, Param("capability_id")),
|
|
815
1043
|
_ts_param2(1, Body()),
|
|
1044
|
+
_ts_param2(2, Res()),
|
|
816
1045
|
_ts_metadata2("design:type", Function),
|
|
817
1046
|
_ts_metadata2("design:paramtypes", [
|
|
818
1047
|
String,
|
|
819
|
-
typeof DebugRequestBody === "undefined" ? Object : DebugRequestBody
|
|
1048
|
+
typeof DebugRequestBody === "undefined" ? Object : DebugRequestBody,
|
|
1049
|
+
typeof Response === "undefined" ? Object : Response
|
|
820
1050
|
]),
|
|
821
1051
|
_ts_metadata2("design:returntype", Promise)
|
|
822
1052
|
], DebugController.prototype, "debug", null);
|
|
@@ -834,6 +1064,7 @@ _ts_decorate4([
|
|
|
834
1064
|
_ts_metadata2("design:returntype", Promise)
|
|
835
1065
|
], DebugController.prototype, "debugStream", null);
|
|
836
1066
|
DebugController = _ts_decorate4([
|
|
1067
|
+
ApiExcludeController(),
|
|
837
1068
|
Controller("__innerapi__/capability"),
|
|
838
1069
|
_ts_metadata2("design:type", Function),
|
|
839
1070
|
_ts_metadata2("design:paramtypes", [
|
|
@@ -844,7 +1075,8 @@ DebugController = _ts_decorate4([
|
|
|
844
1075
|
], DebugController);
|
|
845
1076
|
|
|
846
1077
|
// src/controllers/webhook.controller.ts
|
|
847
|
-
import { Controller as Controller2, Get as Get2, Post as Post2, Param as Param2, Body as Body2, Res as Res2,
|
|
1078
|
+
import { Controller as Controller2, Get as Get2, Post as Post2, Param as Param2, Body as Body2, Res as Res2, HttpStatus as HttpStatus2, Logger as Logger4 } from "@nestjs/common";
|
|
1079
|
+
import { ApiExcludeController as ApiExcludeController2 } from "@nestjs/swagger";
|
|
848
1080
|
function _ts_decorate5(decorators, target, key, desc) {
|
|
849
1081
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
850
1082
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -871,54 +1103,69 @@ var WebhookController = class _WebhookController {
|
|
|
871
1103
|
constructor(capabilityService) {
|
|
872
1104
|
this.capabilityService = capabilityService;
|
|
873
1105
|
}
|
|
874
|
-
list() {
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
1106
|
+
list(res) {
|
|
1107
|
+
try {
|
|
1108
|
+
const capabilities = this.capabilityService.listCapabilities();
|
|
1109
|
+
res.status(HttpStatus2.OK).json({
|
|
1110
|
+
status_code: ErrorCodes.SUCCESS,
|
|
1111
|
+
data: {
|
|
1112
|
+
capabilities: capabilities.map((c) => ({
|
|
1113
|
+
id: c.id,
|
|
1114
|
+
name: c.name,
|
|
1115
|
+
pluginID: c.pluginKey,
|
|
1116
|
+
pluginVersion: c.pluginVersion
|
|
1117
|
+
}))
|
|
1118
|
+
}
|
|
1119
|
+
});
|
|
1120
|
+
} catch (error) {
|
|
1121
|
+
this.logger.error("Failed to list capabilities", error);
|
|
1122
|
+
res.status(HttpStatus2.INTERNAL_SERVER_ERROR).json({
|
|
1123
|
+
status_code: ErrorCodes.EXECUTION_ERROR,
|
|
1124
|
+
error_msg: `Failed to list capabilities: ${error instanceof Error ? error.message : String(error)}`
|
|
1125
|
+
});
|
|
1126
|
+
}
|
|
887
1127
|
}
|
|
888
|
-
async execute(capabilityId, body) {
|
|
1128
|
+
async execute(capabilityId, body, res) {
|
|
889
1129
|
try {
|
|
890
1130
|
const result = await this.capabilityService.load(capabilityId).call(body.action, body.params);
|
|
891
|
-
|
|
1131
|
+
res.status(HttpStatus2.OK).json({
|
|
892
1132
|
status_code: ErrorCodes.SUCCESS,
|
|
893
1133
|
data: {
|
|
894
1134
|
output: result
|
|
895
1135
|
}
|
|
896
|
-
};
|
|
1136
|
+
});
|
|
897
1137
|
} catch (error) {
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
status_code: ErrorCodes.CAPABILITY_NOT_FOUND,
|
|
901
|
-
error_msg: `Capability not found: ${capabilityId}`
|
|
902
|
-
}, HttpStatus2.NOT_FOUND);
|
|
903
|
-
}
|
|
904
|
-
if (error instanceof PluginNotFoundError) {
|
|
905
|
-
throw new HttpException2({
|
|
906
|
-
status_code: ErrorCodes.PLUGIN_NOT_FOUND,
|
|
907
|
-
error_msg: `Plugin not found`
|
|
908
|
-
}, HttpStatus2.INTERNAL_SERVER_ERROR);
|
|
909
|
-
}
|
|
910
|
-
if (error instanceof ActionNotFoundError) {
|
|
911
|
-
throw new HttpException2({
|
|
912
|
-
status_code: ErrorCodes.ACTION_NOT_FOUND,
|
|
913
|
-
error_msg: `Action '${body.action}' not found`
|
|
914
|
-
}, HttpStatus2.BAD_REQUEST);
|
|
915
|
-
}
|
|
916
|
-
throw new HttpException2({
|
|
917
|
-
status_code: ErrorCodes.EXECUTION_ERROR,
|
|
918
|
-
error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`
|
|
919
|
-
}, HttpStatus2.INTERNAL_SERVER_ERROR);
|
|
1138
|
+
this.logger.error("Capability execution failed", error);
|
|
1139
|
+
res.status(HttpStatus2.INTERNAL_SERVER_ERROR).json(this.buildErrorResponse(error));
|
|
920
1140
|
}
|
|
921
1141
|
}
|
|
1142
|
+
/**
|
|
1143
|
+
* 构建错误响应
|
|
1144
|
+
*/
|
|
1145
|
+
buildErrorResponse(error) {
|
|
1146
|
+
if (error instanceof CapabilityNotFoundError) {
|
|
1147
|
+
return {
|
|
1148
|
+
status_code: ErrorCodes.CAPABILITY_NOT_FOUND,
|
|
1149
|
+
error_msg: `Capability not found: ${error.capabilityId}`
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
if (error instanceof PluginNotFoundError) {
|
|
1153
|
+
return {
|
|
1154
|
+
status_code: ErrorCodes.PLUGIN_NOT_FOUND,
|
|
1155
|
+
error_msg: `Plugin not found, please install plugin: ${error.pluginKey}`
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
if (error instanceof ActionNotFoundError) {
|
|
1159
|
+
return {
|
|
1160
|
+
status_code: ErrorCodes.ACTION_NOT_FOUND,
|
|
1161
|
+
error_msg: `Action '${error.actionName}' not found in plugin ${error.pluginKey}`
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1164
|
+
return {
|
|
1165
|
+
status_code: ErrorCodes.EXECUTION_ERROR,
|
|
1166
|
+
error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
922
1169
|
async executeStream(capabilityId, body, res) {
|
|
923
1170
|
const loggerContext = {
|
|
924
1171
|
capability_id: capabilityId,
|
|
@@ -943,9 +1190,7 @@ var WebhookController = class _WebhookController {
|
|
|
943
1190
|
status_code: ErrorCodes.SUCCESS,
|
|
944
1191
|
data: {
|
|
945
1192
|
type: "content",
|
|
946
|
-
delta:
|
|
947
|
-
content: pendingChunk
|
|
948
|
-
}
|
|
1193
|
+
delta: pendingChunk
|
|
949
1194
|
}
|
|
950
1195
|
};
|
|
951
1196
|
res.write(`data: ${JSON.stringify(response)}
|
|
@@ -961,9 +1206,7 @@ var WebhookController = class _WebhookController {
|
|
|
961
1206
|
status_code: ErrorCodes.SUCCESS,
|
|
962
1207
|
data: {
|
|
963
1208
|
type: "content",
|
|
964
|
-
delta:
|
|
965
|
-
content: pendingChunk
|
|
966
|
-
},
|
|
1209
|
+
delta: pendingChunk,
|
|
967
1210
|
finished: true
|
|
968
1211
|
}
|
|
969
1212
|
};
|
|
@@ -1003,9 +1246,7 @@ var WebhookController = class _WebhookController {
|
|
|
1003
1246
|
status_code: ErrorCodes.SUCCESS,
|
|
1004
1247
|
data: {
|
|
1005
1248
|
type: "content",
|
|
1006
|
-
delta:
|
|
1007
|
-
content: pendingChunk
|
|
1008
|
-
},
|
|
1249
|
+
delta: pendingChunk,
|
|
1009
1250
|
finished: true
|
|
1010
1251
|
}
|
|
1011
1252
|
};
|
|
@@ -1035,18 +1276,23 @@ var WebhookController = class _WebhookController {
|
|
|
1035
1276
|
};
|
|
1036
1277
|
_ts_decorate5([
|
|
1037
1278
|
Get2("list"),
|
|
1279
|
+
_ts_param3(0, Res2()),
|
|
1038
1280
|
_ts_metadata3("design:type", Function),
|
|
1039
|
-
_ts_metadata3("design:paramtypes", [
|
|
1040
|
-
|
|
1281
|
+
_ts_metadata3("design:paramtypes", [
|
|
1282
|
+
typeof Response === "undefined" ? Object : Response
|
|
1283
|
+
]),
|
|
1284
|
+
_ts_metadata3("design:returntype", void 0)
|
|
1041
1285
|
], WebhookController.prototype, "list", null);
|
|
1042
1286
|
_ts_decorate5([
|
|
1043
1287
|
Post2(":capability_id"),
|
|
1044
1288
|
_ts_param3(0, Param2("capability_id")),
|
|
1045
1289
|
_ts_param3(1, Body2()),
|
|
1290
|
+
_ts_param3(2, Res2()),
|
|
1046
1291
|
_ts_metadata3("design:type", Function),
|
|
1047
1292
|
_ts_metadata3("design:paramtypes", [
|
|
1048
1293
|
String,
|
|
1049
|
-
typeof ExecuteRequestBody === "undefined" ? Object : ExecuteRequestBody
|
|
1294
|
+
typeof ExecuteRequestBody === "undefined" ? Object : ExecuteRequestBody,
|
|
1295
|
+
typeof Response === "undefined" ? Object : Response
|
|
1050
1296
|
]),
|
|
1051
1297
|
_ts_metadata3("design:returntype", Promise)
|
|
1052
1298
|
], WebhookController.prototype, "execute", null);
|
|
@@ -1064,6 +1310,7 @@ _ts_decorate5([
|
|
|
1064
1310
|
_ts_metadata3("design:returntype", Promise)
|
|
1065
1311
|
], WebhookController.prototype, "executeStream", null);
|
|
1066
1312
|
WebhookController = _ts_decorate5([
|
|
1313
|
+
ApiExcludeController2(),
|
|
1067
1314
|
Controller2("api/capability"),
|
|
1068
1315
|
_ts_metadata3("design:type", Function),
|
|
1069
1316
|
_ts_metadata3("design:paramtypes", [
|
|
@@ -1113,8 +1360,8 @@ var CapabilityModule = class _CapabilityModule {
|
|
|
1113
1360
|
provide: CapabilityService,
|
|
1114
1361
|
useFactory: /* @__PURE__ */ __name((requestContextService, httpClient, pluginLoader, templateEngine, moduleOptions) => {
|
|
1115
1362
|
const service = new CapabilityService(requestContextService, httpClient, pluginLoader, templateEngine);
|
|
1116
|
-
if (moduleOptions
|
|
1117
|
-
service.
|
|
1363
|
+
if (moduleOptions) {
|
|
1364
|
+
service.setOptions(moduleOptions);
|
|
1118
1365
|
}
|
|
1119
1366
|
return service;
|
|
1120
1367
|
}, "useFactory"),
|
|
@@ -1162,6 +1409,7 @@ export {
|
|
|
1162
1409
|
PluginLoaderService,
|
|
1163
1410
|
PluginNotFoundError,
|
|
1164
1411
|
TemplateEngineService,
|
|
1165
|
-
WebhookController
|
|
1412
|
+
WebhookController,
|
|
1413
|
+
migrationAdaptor
|
|
1166
1414
|
};
|
|
1167
1415
|
//# sourceMappingURL=index.js.map
|