@lark-apaas/nestjs-capability 0.0.1-alpha.9 → 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,7 +343,11 @@ 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;
@@ -255,12 +356,140 @@ var CapabilityService = class _CapabilityService {
255
356
  const isDev = process.env.NODE_ENV === "development";
256
357
  this.capabilitiesDir = path.join(process.cwd(), isDev ? "server/capabilities" : "capabilities");
257
358
  }
359
+ /**
360
+ * 设置模块配置
361
+ */
362
+ setOptions(options) {
363
+ this.options = options;
364
+ if (options.capabilitiesDir) {
365
+ this.capabilitiesDir = options.capabilitiesDir;
366
+ }
367
+ }
258
368
  setCapabilitiesDir(dir) {
259
369
  this.capabilitiesDir = dir;
260
370
  }
261
371
  async onModuleInit() {
262
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
+ }
263
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
+ // ==================== 原有方法 ====================
264
493
  async loadCapabilities() {
265
494
  this.logger.log(`Loading capabilities from ${this.capabilitiesDir}`);
266
495
  if (!fs.existsSync(this.capabilitiesDir)) {
@@ -271,14 +500,7 @@ var CapabilityService = class _CapabilityService {
271
500
  for (const file of files) {
272
501
  try {
273
502
  const filePath = path.join(this.capabilitiesDir, file);
274
- const content = fs.readFileSync(filePath, "utf-8");
275
- const config = JSON.parse(content);
276
- if (!config.id) {
277
- this.logger.warn(`Skipping capability without id: ${file}`);
278
- continue;
279
- }
280
- this.capabilities.set(config.id, config);
281
- this.logger.log(`Loaded capability: ${config.id} (${config.name})`);
503
+ this.loadCapabilityFromFile(filePath);
282
504
  } catch (error) {
283
505
  this.logger.error(`Failed to load capability from ${file}:`, error);
284
506
  }
@@ -554,7 +776,8 @@ CapabilityService = _ts_decorate3([
554
776
  ], CapabilityService);
555
777
 
556
778
  // src/controllers/debug.controller.ts
557
- 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";
558
781
  function _ts_decorate4(decorators, target, key, desc) {
559
782
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
560
783
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -585,19 +808,27 @@ var DebugController = class _DebugController {
585
808
  this.pluginLoaderService = pluginLoaderService;
586
809
  this.templateEngineService = templateEngineService;
587
810
  }
588
- list() {
589
- const capabilities = this.capabilityService.listCapabilities();
590
- return {
591
- status_code: ErrorCodes.SUCCESS,
592
- data: {
593
- capabilities: capabilities.map((c) => ({
594
- id: c.id,
595
- name: c.name,
596
- pluginID: c.pluginKey,
597
- pluginVersion: c.pluginVersion
598
- }))
599
- }
600
- };
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
+ }
601
832
  }
602
833
  /**
603
834
  * 获取 capability 配置
@@ -609,11 +840,7 @@ var DebugController = class _DebugController {
609
840
  }
610
841
  const config = this.capabilityService.getCapability(capabilityId);
611
842
  if (!config) {
612
- throw new HttpException({
613
- code: 1,
614
- message: `Capability not found: ${capabilityId}`,
615
- error: "CAPABILITY_NOT_FOUND"
616
- }, HttpStatus.NOT_FOUND);
843
+ throw new CapabilityNotFoundError(capabilityId);
617
844
  }
618
845
  return config;
619
846
  }
@@ -628,25 +855,21 @@ var DebugController = class _DebugController {
628
855
  const pluginInstance = await this.pluginLoaderService.loadPlugin(pluginKey);
629
856
  const actions = pluginInstance.listActions();
630
857
  if (actions.length === 0) {
631
- throw new HttpException({
632
- code: 1,
633
- message: `Plugin ${pluginKey} has no actions`,
634
- error: "NO_ACTIONS"
635
- }, HttpStatus.BAD_REQUEST);
858
+ throw new Error(`Plugin ${pluginKey} has no actions`);
636
859
  }
637
860
  return actions[0];
638
861
  }
639
- async debug(capabilityId, body) {
862
+ async debug(capabilityId, body, res) {
640
863
  const startTime = Date.now();
641
864
  const params = body.params ?? {};
642
- const config = this.getCapabilityConfig(capabilityId, body.capability);
643
- const action = await this.getActionName(config.pluginKey, body.action);
644
- const resolvedParams = this.templateEngineService.resolve(config.formValue, params);
645
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);
646
869
  const result = await this.capabilityService.loadWithConfig(config).call(action, params, {
647
870
  isDebug: true
648
871
  });
649
- return {
872
+ res.status(HttpStatus.OK).json({
650
873
  status_code: ErrorCodes.SUCCESS,
651
874
  data: {
652
875
  output: result,
@@ -658,32 +881,39 @@ var DebugController = class _DebugController {
658
881
  action
659
882
  }
660
883
  }
661
- };
884
+ });
662
885
  } catch (error) {
663
- if (error instanceof CapabilityNotFoundError) {
664
- throw new HttpException({
665
- status_code: ErrorCodes.CAPABILITY_NOT_FOUND,
666
- error_msg: `Capability not found: ${capabilityId}`
667
- }, HttpStatus.NOT_FOUND);
668
- }
669
- if (error instanceof PluginNotFoundError) {
670
- throw new HttpException({
671
- status_code: ErrorCodes.PLUGIN_NOT_FOUND,
672
- error_msg: `Plugin not found: ${config.pluginKey}`
673
- }, HttpStatus.INTERNAL_SERVER_ERROR);
674
- }
675
- if (error instanceof ActionNotFoundError) {
676
- throw new HttpException({
677
- status_code: ErrorCodes.ACTION_NOT_FOUND,
678
- error_msg: `Action '${action}' not found in plugin ${config.pluginKey}`
679
- }, HttpStatus.BAD_REQUEST);
680
- }
681
- throw new HttpException({
682
- status_code: ErrorCodes.EXECUTION_ERROR,
683
- error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`
684
- }, HttpStatus.INTERNAL_SERVER_ERROR);
886
+ this.logger.error("Debug execution failed", error);
887
+ res.status(HttpStatus.INTERNAL_SERVER_ERROR).json(this.buildErrorResponse(error));
685
888
  }
686
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
+ }
687
917
  async debugStream(capabilityId, body, res) {
688
918
  const params = body.params ?? {};
689
919
  res.setHeader("Content-Type", "text/event-stream");
@@ -714,9 +944,7 @@ var DebugController = class _DebugController {
714
944
  status_code: ErrorCodes.SUCCESS,
715
945
  data: {
716
946
  type: "content",
717
- delta: {
718
- content: pendingChunk
719
- }
947
+ delta: pendingChunk
720
948
  }
721
949
  };
722
950
  res.write(`data: ${JSON.stringify(response)}
@@ -732,9 +960,7 @@ var DebugController = class _DebugController {
732
960
  status_code: ErrorCodes.SUCCESS,
733
961
  data: {
734
962
  type: "content",
735
- delta: {
736
- content: pendingChunk
737
- },
963
+ delta: pendingChunk,
738
964
  finished: true
739
965
  }
740
966
  };
@@ -774,9 +1000,7 @@ var DebugController = class _DebugController {
774
1000
  status_code: ErrorCodes.SUCCESS,
775
1001
  data: {
776
1002
  type: "content",
777
- delta: {
778
- content: pendingChunk
779
- },
1003
+ delta: pendingChunk,
780
1004
  finished: true
781
1005
  }
782
1006
  };
@@ -806,18 +1030,23 @@ var DebugController = class _DebugController {
806
1030
  };
807
1031
  _ts_decorate4([
808
1032
  Get("list"),
1033
+ _ts_param2(0, Res()),
809
1034
  _ts_metadata2("design:type", Function),
810
- _ts_metadata2("design:paramtypes", []),
811
- _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)
812
1039
  ], DebugController.prototype, "list", null);
813
1040
  _ts_decorate4([
814
1041
  Post("debug/:capability_id"),
815
1042
  _ts_param2(0, Param("capability_id")),
816
1043
  _ts_param2(1, Body()),
1044
+ _ts_param2(2, Res()),
817
1045
  _ts_metadata2("design:type", Function),
818
1046
  _ts_metadata2("design:paramtypes", [
819
1047
  String,
820
- typeof DebugRequestBody === "undefined" ? Object : DebugRequestBody
1048
+ typeof DebugRequestBody === "undefined" ? Object : DebugRequestBody,
1049
+ typeof Response === "undefined" ? Object : Response
821
1050
  ]),
822
1051
  _ts_metadata2("design:returntype", Promise)
823
1052
  ], DebugController.prototype, "debug", null);
@@ -835,6 +1064,7 @@ _ts_decorate4([
835
1064
  _ts_metadata2("design:returntype", Promise)
836
1065
  ], DebugController.prototype, "debugStream", null);
837
1066
  DebugController = _ts_decorate4([
1067
+ ApiExcludeController(),
838
1068
  Controller("__innerapi__/capability"),
839
1069
  _ts_metadata2("design:type", Function),
840
1070
  _ts_metadata2("design:paramtypes", [
@@ -845,7 +1075,8 @@ DebugController = _ts_decorate4([
845
1075
  ], DebugController);
846
1076
 
847
1077
  // src/controllers/webhook.controller.ts
848
- 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";
849
1080
  function _ts_decorate5(decorators, target, key, desc) {
850
1081
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
851
1082
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -872,54 +1103,69 @@ var WebhookController = class _WebhookController {
872
1103
  constructor(capabilityService) {
873
1104
  this.capabilityService = capabilityService;
874
1105
  }
875
- list() {
876
- const capabilities = this.capabilityService.listCapabilities();
877
- return {
878
- status_code: ErrorCodes.SUCCESS,
879
- data: {
880
- capabilities: capabilities.map((c) => ({
881
- id: c.id,
882
- name: c.name,
883
- pluginID: c.pluginKey,
884
- pluginVersion: c.pluginVersion
885
- }))
886
- }
887
- };
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
+ }
888
1127
  }
889
- async execute(capabilityId, body) {
1128
+ async execute(capabilityId, body, res) {
890
1129
  try {
891
1130
  const result = await this.capabilityService.load(capabilityId).call(body.action, body.params);
892
- return {
1131
+ res.status(HttpStatus2.OK).json({
893
1132
  status_code: ErrorCodes.SUCCESS,
894
1133
  data: {
895
1134
  output: result
896
1135
  }
897
- };
1136
+ });
898
1137
  } catch (error) {
899
- if (error instanceof CapabilityNotFoundError) {
900
- throw new HttpException2({
901
- status_code: ErrorCodes.CAPABILITY_NOT_FOUND,
902
- error_msg: `Capability not found: ${capabilityId}`
903
- }, HttpStatus2.NOT_FOUND);
904
- }
905
- if (error instanceof PluginNotFoundError) {
906
- throw new HttpException2({
907
- status_code: ErrorCodes.PLUGIN_NOT_FOUND,
908
- error_msg: `Plugin not found`
909
- }, HttpStatus2.INTERNAL_SERVER_ERROR);
910
- }
911
- if (error instanceof ActionNotFoundError) {
912
- throw new HttpException2({
913
- status_code: ErrorCodes.ACTION_NOT_FOUND,
914
- error_msg: `Action '${body.action}' not found`
915
- }, HttpStatus2.BAD_REQUEST);
916
- }
917
- throw new HttpException2({
918
- status_code: ErrorCodes.EXECUTION_ERROR,
919
- error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`
920
- }, HttpStatus2.INTERNAL_SERVER_ERROR);
1138
+ this.logger.error("Capability execution failed", error);
1139
+ res.status(HttpStatus2.INTERNAL_SERVER_ERROR).json(this.buildErrorResponse(error));
921
1140
  }
922
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
+ }
923
1169
  async executeStream(capabilityId, body, res) {
924
1170
  const loggerContext = {
925
1171
  capability_id: capabilityId,
@@ -944,9 +1190,7 @@ var WebhookController = class _WebhookController {
944
1190
  status_code: ErrorCodes.SUCCESS,
945
1191
  data: {
946
1192
  type: "content",
947
- delta: {
948
- content: pendingChunk
949
- }
1193
+ delta: pendingChunk
950
1194
  }
951
1195
  };
952
1196
  res.write(`data: ${JSON.stringify(response)}
@@ -962,9 +1206,7 @@ var WebhookController = class _WebhookController {
962
1206
  status_code: ErrorCodes.SUCCESS,
963
1207
  data: {
964
1208
  type: "content",
965
- delta: {
966
- content: pendingChunk
967
- },
1209
+ delta: pendingChunk,
968
1210
  finished: true
969
1211
  }
970
1212
  };
@@ -1004,9 +1246,7 @@ var WebhookController = class _WebhookController {
1004
1246
  status_code: ErrorCodes.SUCCESS,
1005
1247
  data: {
1006
1248
  type: "content",
1007
- delta: {
1008
- content: pendingChunk
1009
- },
1249
+ delta: pendingChunk,
1010
1250
  finished: true
1011
1251
  }
1012
1252
  };
@@ -1036,18 +1276,23 @@ var WebhookController = class _WebhookController {
1036
1276
  };
1037
1277
  _ts_decorate5([
1038
1278
  Get2("list"),
1279
+ _ts_param3(0, Res2()),
1039
1280
  _ts_metadata3("design:type", Function),
1040
- _ts_metadata3("design:paramtypes", []),
1041
- _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)
1042
1285
  ], WebhookController.prototype, "list", null);
1043
1286
  _ts_decorate5([
1044
1287
  Post2(":capability_id"),
1045
1288
  _ts_param3(0, Param2("capability_id")),
1046
1289
  _ts_param3(1, Body2()),
1290
+ _ts_param3(2, Res2()),
1047
1291
  _ts_metadata3("design:type", Function),
1048
1292
  _ts_metadata3("design:paramtypes", [
1049
1293
  String,
1050
- typeof ExecuteRequestBody === "undefined" ? Object : ExecuteRequestBody
1294
+ typeof ExecuteRequestBody === "undefined" ? Object : ExecuteRequestBody,
1295
+ typeof Response === "undefined" ? Object : Response
1051
1296
  ]),
1052
1297
  _ts_metadata3("design:returntype", Promise)
1053
1298
  ], WebhookController.prototype, "execute", null);
@@ -1065,6 +1310,7 @@ _ts_decorate5([
1065
1310
  _ts_metadata3("design:returntype", Promise)
1066
1311
  ], WebhookController.prototype, "executeStream", null);
1067
1312
  WebhookController = _ts_decorate5([
1313
+ ApiExcludeController2(),
1068
1314
  Controller2("api/capability"),
1069
1315
  _ts_metadata3("design:type", Function),
1070
1316
  _ts_metadata3("design:paramtypes", [
@@ -1114,8 +1360,8 @@ var CapabilityModule = class _CapabilityModule {
1114
1360
  provide: CapabilityService,
1115
1361
  useFactory: /* @__PURE__ */ __name((requestContextService, httpClient, pluginLoader, templateEngine, moduleOptions) => {
1116
1362
  const service = new CapabilityService(requestContextService, httpClient, pluginLoader, templateEngine);
1117
- if (moduleOptions?.capabilitiesDir) {
1118
- service.setCapabilitiesDir(moduleOptions.capabilitiesDir);
1363
+ if (moduleOptions) {
1364
+ service.setOptions(moduleOptions);
1119
1365
  }
1120
1366
  return service;
1121
1367
  }, "useFactory"),
@@ -1163,6 +1409,7 @@ export {
1163
1409
  PluginLoaderService,
1164
1410
  PluginNotFoundError,
1165
1411
  TemplateEngineService,
1166
- WebhookController
1412
+ WebhookController,
1413
+ migrationAdaptor
1167
1414
  };
1168
1415
  //# sourceMappingURL=index.js.map