@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.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 pluginPackage = (await import(pluginKey)).default;
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
- __require.resolve(pluginKey);
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
- this.capabilitiesDir = path.join(process.cwd(), "server/capabilities");
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
- const content = fs.readFileSync(filePath, "utf-8");
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, HttpException, HttpStatus, Logger as Logger3 } from "@nestjs/common";
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
- const capabilities = this.capabilityService.listCapabilities();
589
- return {
590
- status_code: ErrorCodes.SUCCESS,
591
- data: {
592
- capabilities: capabilities.map((c) => ({
593
- id: c.id,
594
- name: c.name,
595
- pluginID: c.pluginKey,
596
- pluginVersion: c.pluginVersion
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 HttpException({
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 HttpException({
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
- return {
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
- if (error instanceof CapabilityNotFoundError) {
663
- throw new HttpException({
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
- _ts_metadata2("design:returntype", typeof SuccessResponse === "undefined" ? Object : SuccessResponse)
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, HttpException as HttpException2, HttpStatus as HttpStatus2, Logger as Logger4 } from "@nestjs/common";
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
- const capabilities = this.capabilityService.listCapabilities();
876
- return {
877
- status_code: ErrorCodes.SUCCESS,
878
- data: {
879
- capabilities: capabilities.map((c) => ({
880
- id: c.id,
881
- name: c.name,
882
- pluginID: c.pluginKey,
883
- pluginVersion: c.pluginVersion
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
- return {
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
- if (error instanceof CapabilityNotFoundError) {
899
- throw new HttpException2({
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
- _ts_metadata3("design:returntype", typeof SuccessResponse === "undefined" ? Object : SuccessResponse)
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?.capabilitiesDir) {
1117
- service.setCapabilitiesDir(moduleOptions.capabilitiesDir);
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