@lark-apaas/nestjs-capability 0.0.1-alpha.0 → 0.0.1-alpha.10

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,21 @@
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
- });
3
+
4
+ // src/interfaces/error-codes.ts
5
+ var ErrorCodes = {
6
+ /** 成功 */
7
+ SUCCESS: "0",
8
+ /** 能力不存在 */
9
+ CAPABILITY_NOT_FOUND: "k_ec_cap_001",
10
+ /** 插件不存在 */
11
+ PLUGIN_NOT_FOUND: "k_ec_cap_002",
12
+ /** Action 不存在 */
13
+ ACTION_NOT_FOUND: "k_ec_cap_003",
14
+ /** 参数验证失败 */
15
+ PARAMS_VALIDATION_ERROR: "k_ec_cap_004",
16
+ /** 执行失败 */
17
+ EXECUTION_ERROR: "k_ec_cap_005"
18
+ };
9
19
 
10
20
  // src/services/template-engine.service.ts
11
21
  import { Injectable } from "@nestjs/common";
@@ -20,7 +30,10 @@ var TemplateEngineService = class {
20
30
  static {
21
31
  __name(this, "TemplateEngineService");
22
32
  }
23
- TEMPLATE_REGEX = /^\{\{input\.(.+)\}\}$/;
33
+ // 匹配 {{input.xxx}} 或 {{input.xxx.yyy}} 表达式
34
+ EXPR_REGEX = /\{\{input\.([a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*)\}\}/g;
35
+ // 匹配整串单个表达式
36
+ WHOLE_STRING_EXPR_REGEX = /^\{\{input\.([a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*)\}\}$/;
24
37
  resolve(template, input) {
25
38
  if (typeof template === "string") {
26
39
  return this.resolveString(template, input);
@@ -34,12 +47,25 @@ var TemplateEngineService = class {
34
47
  return template;
35
48
  }
36
49
  resolveString(template, input) {
37
- const match = template.match(this.TEMPLATE_REGEX);
38
- if (!match) {
50
+ const wholeMatch = template.match(this.WHOLE_STRING_EXPR_REGEX);
51
+ if (wholeMatch) {
52
+ const path2 = wholeMatch[1];
53
+ const value = this.getValueByPath(input, path2);
54
+ return value !== void 0 ? value : template;
55
+ }
56
+ this.EXPR_REGEX.lastIndex = 0;
57
+ if (!this.EXPR_REGEX.test(template)) {
39
58
  return template;
40
59
  }
41
- const path2 = match[1];
42
- return this.getValueByPath(input, path2);
60
+ this.EXPR_REGEX.lastIndex = 0;
61
+ const result = template.replace(this.EXPR_REGEX, (match, path2) => {
62
+ const value = this.getValueByPath(input, path2);
63
+ if (value === void 0) {
64
+ return match;
65
+ }
66
+ return String(value);
67
+ });
68
+ return result;
43
69
  }
44
70
  resolveObject(template, input) {
45
71
  const result = {};
@@ -66,6 +92,7 @@ TemplateEngineService = _ts_decorate([
66
92
 
67
93
  // src/services/plugin-loader.service.ts
68
94
  import { Injectable as Injectable2, Logger } from "@nestjs/common";
95
+ import { createRequire } from "module";
69
96
  function _ts_decorate2(decorators, target, key, desc) {
70
97
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
71
98
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -73,12 +100,13 @@ function _ts_decorate2(decorators, target, key, desc) {
73
100
  return c > 3 && r && Object.defineProperty(target, key, r), r;
74
101
  }
75
102
  __name(_ts_decorate2, "_ts_decorate");
103
+ var require2 = createRequire(import.meta.url);
76
104
  var PluginNotFoundError = class extends Error {
77
105
  static {
78
106
  __name(this, "PluginNotFoundError");
79
107
  }
80
- constructor(pluginID) {
81
- super(`Plugin not found: ${pluginID}`);
108
+ constructor(pluginKey) {
109
+ super(`Plugin not found: ${pluginKey}`);
82
110
  this.name = "PluginNotFoundError";
83
111
  }
84
112
  };
@@ -86,8 +114,8 @@ var PluginLoadError = class extends Error {
86
114
  static {
87
115
  __name(this, "PluginLoadError");
88
116
  }
89
- constructor(pluginID, reason) {
90
- super(`Failed to load plugin ${pluginID}: ${reason}`);
117
+ constructor(pluginKey, reason) {
118
+ super(`Failed to load plugin ${pluginKey}: ${reason}`);
91
119
  this.name = "PluginLoadError";
92
120
  }
93
121
  };
@@ -97,46 +125,94 @@ var PluginLoaderService = class _PluginLoaderService {
97
125
  }
98
126
  logger = new Logger(_PluginLoaderService.name);
99
127
  pluginInstances = /* @__PURE__ */ new Map();
100
- loadPlugin(pluginID) {
101
- const cached = this.pluginInstances.get(pluginID);
128
+ /** 记录每个插件的加载版本(时间戳),用于 ESM 缓存绕过 */
129
+ pluginVersions = /* @__PURE__ */ new Map();
130
+ async loadPlugin(pluginKey) {
131
+ const cached = this.pluginInstances.get(pluginKey);
102
132
  if (cached) {
103
- this.logger.debug(`Using cached plugin instance: ${pluginID}`);
133
+ this.logger.debug(`Using cached plugin instance: ${pluginKey}`);
104
134
  return cached;
105
135
  }
106
- this.logger.log(`Loading plugin: ${pluginID}`);
136
+ this.logger.log(`Loading plugin: ${pluginKey}`);
107
137
  try {
108
- const pluginPackage = __require(pluginID);
138
+ const version = this.pluginVersions.get(pluginKey) ?? 0;
139
+ const importPath = version > 0 ? `${pluginKey}?v=${version}` : pluginKey;
140
+ const pluginPackage = (await import(importPath)).default;
109
141
  if (typeof pluginPackage.create !== "function") {
110
- throw new PluginLoadError(pluginID, "Plugin does not export create() function");
142
+ throw new PluginLoadError(pluginKey, "Plugin does not export create() function");
111
143
  }
112
144
  const instance = pluginPackage.create();
113
- this.pluginInstances.set(pluginID, instance);
114
- this.logger.log(`Plugin loaded successfully: ${pluginID}`);
145
+ this.pluginInstances.set(pluginKey, instance);
146
+ this.logger.log(`Plugin loaded successfully: ${pluginKey}`);
115
147
  return instance;
116
148
  } catch (error) {
117
149
  if (error.code === "MODULE_NOT_FOUND") {
118
- throw new PluginNotFoundError(pluginID);
150
+ throw new PluginNotFoundError(pluginKey);
119
151
  }
120
- throw new PluginLoadError(pluginID, error instanceof Error ? error.message : String(error));
152
+ throw new PluginLoadError(pluginKey, error instanceof Error ? error.message : String(error));
121
153
  }
122
154
  }
123
- isPluginInstalled(pluginID) {
155
+ isPluginInstalled(pluginKey) {
124
156
  try {
125
- __require.resolve(pluginID);
157
+ require2.resolve(pluginKey);
126
158
  return true;
127
159
  } catch {
128
160
  return false;
129
161
  }
130
162
  }
131
- clearCache(pluginID) {
132
- if (pluginID) {
133
- this.pluginInstances.delete(pluginID);
134
- this.logger.log(`Cleared cache for plugin: ${pluginID}`);
163
+ /**
164
+ * 清除插件缓存(包括 Node.js 模块缓存)
165
+ * @param pluginKey - 插件标识,不传则清除所有
166
+ */
167
+ clearCache(pluginKey) {
168
+ if (pluginKey) {
169
+ this.pluginInstances.delete(pluginKey);
170
+ this.clearNodeModuleCache(pluginKey);
171
+ this.pluginVersions.set(pluginKey, Date.now());
172
+ this.logger.log(`Cleared cache for plugin: ${pluginKey}`);
135
173
  } else {
174
+ for (const key of this.pluginInstances.keys()) {
175
+ this.clearNodeModuleCache(key);
176
+ this.pluginVersions.set(key, Date.now());
177
+ }
136
178
  this.pluginInstances.clear();
137
179
  this.logger.log("Cleared all plugin caches");
138
180
  }
139
181
  }
182
+ /**
183
+ * 清除 CJS 模块缓存
184
+ */
185
+ clearNodeModuleCache(pluginKey) {
186
+ try {
187
+ const resolvedPath = require2.resolve(pluginKey);
188
+ const mod = require2.cache[resolvedPath];
189
+ if (mod) {
190
+ this.clearModuleAndChildren(mod, pluginKey);
191
+ }
192
+ delete require2.cache[resolvedPath];
193
+ } catch {
194
+ }
195
+ }
196
+ /**
197
+ * 递归清除子模块缓存
198
+ */
199
+ clearModuleAndChildren(mod, pluginKey) {
200
+ const pluginScope = pluginKey.startsWith("@") ? pluginKey.split("/").slice(0, 2).join("/") : pluginKey;
201
+ mod.children.forEach((child) => {
202
+ if (child.filename.includes(`node_modules/${pluginScope}`)) {
203
+ this.clearModuleAndChildren(child, pluginKey);
204
+ delete require2.cache[child.filename];
205
+ }
206
+ });
207
+ }
208
+ /**
209
+ * 强制重新加载插件
210
+ * @param pluginKey - 插件标识
211
+ */
212
+ async reloadPlugin(pluginKey) {
213
+ this.clearCache(pluginKey);
214
+ return this.loadPlugin(pluginKey);
215
+ }
140
216
  };
141
217
  PluginLoaderService = _ts_decorate2([
142
218
  Injectable2()
@@ -147,6 +223,29 @@ import { Injectable as Injectable3, Logger as Logger2, Inject } from "@nestjs/co
147
223
  import { RequestContextService, PLATFORM_HTTP_CLIENT } from "@lark-apaas/nestjs-common";
148
224
  import * as fs from "fs";
149
225
  import * as path from "path";
226
+ import * as chokidar from "chokidar";
227
+
228
+ // src/utils/log-utils.ts
229
+ var DEFAULT_MAX_LENGTH = 1e3;
230
+ function truncateString(str, maxLength) {
231
+ if (str.length <= maxLength) {
232
+ return str;
233
+ }
234
+ return str.slice(0, maxLength) + `... [truncated, total ${str.length} chars]`;
235
+ }
236
+ __name(truncateString, "truncateString");
237
+ function stringifyForLog(value, maxLength = DEFAULT_MAX_LENGTH) {
238
+ try {
239
+ const str = JSON.stringify(value, null, 2);
240
+ return truncateString(str, maxLength);
241
+ } catch {
242
+ const str = String(value);
243
+ return truncateString(str, maxLength);
244
+ }
245
+ }
246
+ __name(stringifyForLog, "stringifyForLog");
247
+
248
+ // src/services/capability.service.ts
150
249
  function _ts_decorate3(decorators, target, key, desc) {
151
250
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
152
251
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -177,8 +276,8 @@ var ActionNotFoundError = class extends Error {
177
276
  static {
178
277
  __name(this, "ActionNotFoundError");
179
278
  }
180
- constructor(pluginID, actionName) {
181
- super(`Action '${actionName}' not found in plugin ${pluginID}`);
279
+ constructor(pluginKey, actionName) {
280
+ super(`Action '${actionName}' not found in plugin ${pluginKey}`);
182
281
  this.name = "ActionNotFoundError";
183
282
  }
184
283
  };
@@ -187,25 +286,150 @@ var CapabilityService = class _CapabilityService {
187
286
  __name(this, "CapabilityService");
188
287
  }
189
288
  requestContextService;
190
- httpClient;
289
+ platformHttpClient;
191
290
  pluginLoaderService;
192
291
  templateEngineService;
193
292
  logger = new Logger2(_CapabilityService.name);
194
293
  capabilities = /* @__PURE__ */ new Map();
294
+ /** 文件路径到 capability id 的映射,用于文件删除时查找 */
295
+ filePathToId = /* @__PURE__ */ new Map();
195
296
  capabilitiesDir;
196
- constructor(requestContextService, httpClient, pluginLoaderService, templateEngineService) {
297
+ fileWatcher = null;
298
+ options = {};
299
+ constructor(requestContextService, platformHttpClient, pluginLoaderService, templateEngineService) {
197
300
  this.requestContextService = requestContextService;
198
- this.httpClient = httpClient;
301
+ this.platformHttpClient = platformHttpClient;
199
302
  this.pluginLoaderService = pluginLoaderService;
200
303
  this.templateEngineService = templateEngineService;
201
- this.capabilitiesDir = path.join(process.cwd(), "server/capabilities");
304
+ const isDev = process.env.NODE_ENV === "development";
305
+ this.capabilitiesDir = path.join(process.cwd(), isDev ? "server/capabilities" : "capabilities");
306
+ }
307
+ /**
308
+ * 设置模块配置
309
+ */
310
+ setOptions(options) {
311
+ this.options = options;
312
+ if (options.capabilitiesDir) {
313
+ this.capabilitiesDir = options.capabilitiesDir;
314
+ }
202
315
  }
203
316
  setCapabilitiesDir(dir) {
204
317
  this.capabilitiesDir = dir;
205
318
  }
206
319
  async onModuleInit() {
207
320
  await this.loadCapabilities();
321
+ if (this.options.enableWatching) {
322
+ this.startWatching();
323
+ }
324
+ }
325
+ async onModuleDestroy() {
326
+ this.stopWatching();
327
+ }
328
+ // ==================== 文件监听相关方法 ====================
329
+ /**
330
+ * 启动文件监听(沙箱环境自动调用)
331
+ */
332
+ startWatching() {
333
+ if (this.fileWatcher) {
334
+ return;
335
+ }
336
+ if (!fs.existsSync(this.capabilitiesDir)) {
337
+ this.logger.warn(`Cannot start watching: directory not found: ${this.capabilitiesDir}`);
338
+ return;
339
+ }
340
+ const pattern = path.join(this.capabilitiesDir, "*.json");
341
+ const debounce = this.options.watchDebounce ?? 300;
342
+ this.logger.log(`Starting file watcher: ${pattern}`);
343
+ this.fileWatcher = chokidar.watch(pattern, {
344
+ persistent: true,
345
+ ignoreInitial: true,
346
+ awaitWriteFinish: {
347
+ // 等待写入完成
348
+ stabilityThreshold: debounce,
349
+ pollInterval: 100
350
+ }
351
+ });
352
+ 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));
353
+ this.logger.log("File watcher started");
354
+ }
355
+ /**
356
+ * 停止文件监听
357
+ */
358
+ stopWatching() {
359
+ if (this.fileWatcher) {
360
+ this.fileWatcher.close();
361
+ this.fileWatcher = null;
362
+ this.logger.log("File watcher stopped");
363
+ }
364
+ }
365
+ /**
366
+ * 重新加载所有能力配置
367
+ */
368
+ async reloadAllCapabilities() {
369
+ this.capabilities.clear();
370
+ this.filePathToId.clear();
371
+ await this.loadCapabilities();
372
+ }
373
+ handleFileAdd(filePath) {
374
+ this.logger.log(`Capability file added: ${filePath}`);
375
+ try {
376
+ this.loadCapabilityFromFile(filePath);
377
+ } catch (error) {
378
+ this.logger.error(`Failed to load new capability: ${filePath}`, error);
379
+ }
380
+ }
381
+ handleFileChange(filePath) {
382
+ this.logger.log(`Capability file changed: ${filePath}`);
383
+ try {
384
+ this.reloadCapabilityFromFile(filePath);
385
+ } catch (error) {
386
+ this.logger.error(`Failed to reload capability: ${filePath}`, error);
387
+ }
388
+ }
389
+ handleFileUnlink(filePath) {
390
+ this.logger.log(`Capability file removed: ${filePath}`);
391
+ this.removeCapabilityByFile(filePath);
392
+ }
393
+ /**
394
+ * 从文件加载单个能力配置
395
+ */
396
+ loadCapabilityFromFile(filePath) {
397
+ const content = fs.readFileSync(filePath, "utf-8");
398
+ const config = JSON.parse(content);
399
+ if (!config.id) {
400
+ this.logger.warn(`Skipping capability without id: ${filePath}`);
401
+ return;
402
+ }
403
+ this.capabilities.set(config.id, config);
404
+ this.filePathToId.set(filePath, config.id);
405
+ this.logger.log(`Loaded capability: ${config.id} (${config.name})`);
406
+ }
407
+ /**
408
+ * 重新加载单个能力配置
409
+ */
410
+ reloadCapabilityFromFile(filePath) {
411
+ const oldId = this.filePathToId.get(filePath);
412
+ if (oldId) {
413
+ const oldConfig = this.capabilities.get(oldId);
414
+ if (oldConfig) {
415
+ this.pluginLoaderService.clearCache(oldConfig.pluginKey);
416
+ }
417
+ this.capabilities.delete(oldId);
418
+ }
419
+ this.loadCapabilityFromFile(filePath);
420
+ }
421
+ /**
422
+ * 根据文件路径移除能力配置
423
+ */
424
+ removeCapabilityByFile(filePath) {
425
+ const capabilityId = this.filePathToId.get(filePath);
426
+ if (capabilityId) {
427
+ this.capabilities.delete(capabilityId);
428
+ this.filePathToId.delete(filePath);
429
+ this.logger.log(`Removed capability: ${capabilityId}`);
430
+ }
208
431
  }
432
+ // ==================== 原有方法 ====================
209
433
  async loadCapabilities() {
210
434
  this.logger.log(`Loading capabilities from ${this.capabilitiesDir}`);
211
435
  if (!fs.existsSync(this.capabilitiesDir)) {
@@ -216,14 +440,7 @@ var CapabilityService = class _CapabilityService {
216
440
  for (const file of files) {
217
441
  try {
218
442
  const filePath = path.join(this.capabilitiesDir, file);
219
- const content = fs.readFileSync(filePath, "utf-8");
220
- const config = JSON.parse(content);
221
- if (!config.id) {
222
- this.logger.warn(`Skipping capability without id: ${file}`);
223
- continue;
224
- }
225
- this.capabilities.set(config.id, config);
226
- this.logger.log(`Loaded capability: ${config.id} (${config.name})`);
443
+ this.loadCapabilityFromFile(filePath);
227
444
  } catch (error) {
228
445
  this.logger.error(`Failed to load capability from ${file}:`, error);
229
446
  }
@@ -241,56 +458,246 @@ var CapabilityService = class _CapabilityService {
241
458
  if (!config) {
242
459
  throw new CapabilityNotFoundError(capabilityId);
243
460
  }
461
+ return this.createExecutor(config);
462
+ }
463
+ /**
464
+ * 使用传入的配置加载能力执行器
465
+ * 用于 debug 场景,支持用户传入自定义配置
466
+ */
467
+ loadWithConfig(config) {
468
+ return this.createExecutor(config);
469
+ }
470
+ createExecutor(config) {
244
471
  return {
245
472
  call: /* @__PURE__ */ __name(async (actionName, input, contextOverride) => {
246
- return this.execute(config, actionName, input, contextOverride);
247
- }, "call")
473
+ return this.executeCall(config, actionName, input, contextOverride);
474
+ }, "call"),
475
+ callStream: /* @__PURE__ */ __name((actionName, input, contextOverride) => {
476
+ return this.executeCallStream(config, actionName, input, contextOverride);
477
+ }, "callStream"),
478
+ callStreamWithEvents: /* @__PURE__ */ __name((actionName, input, contextOverride) => {
479
+ return this.executeCallStreamWithEvents(config, actionName, input, contextOverride);
480
+ }, "callStreamWithEvents"),
481
+ isStream: /* @__PURE__ */ __name(async (actionName) => {
482
+ return this.checkIsStream(config, actionName);
483
+ }, "isStream")
248
484
  };
249
485
  }
250
- async execute(config, actionName, input, contextOverride) {
486
+ /**
487
+ * 检查 action 是否为流式
488
+ */
489
+ async checkIsStream(config, actionName) {
490
+ const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);
491
+ if (!pluginInstance.hasAction(actionName)) {
492
+ throw new ActionNotFoundError(config.pluginKey, actionName);
493
+ }
494
+ return pluginInstance.isStreamAction?.(actionName) ?? false;
495
+ }
496
+ /**
497
+ * 执行 capability(始终返回 Promise)
498
+ * - unary action: 直接返回结果
499
+ * - stream action: 内部聚合所有 chunk 后返回
500
+ */
501
+ async executeCall(config, actionName, input, contextOverride) {
251
502
  const startTime = Date.now();
503
+ const loggerContext = {
504
+ capability_id: config.id,
505
+ plugin_key: config.pluginKey,
506
+ action: actionName
507
+ };
252
508
  try {
253
- const pluginInstance = this.pluginLoaderService.loadPlugin(config.pluginID);
509
+ const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);
254
510
  if (!pluginInstance.hasAction(actionName)) {
255
- throw new ActionNotFoundError(config.pluginID, actionName);
511
+ throw new ActionNotFoundError(config.pluginKey, actionName);
256
512
  }
257
- const resolvedParams = this.templateEngineService.resolve(config.formValue, input);
513
+ const resolvedParams = config.formValue ? this.templateEngineService.resolve(config.formValue, input) : input;
258
514
  const context = this.buildActionContext(contextOverride);
259
- this.logger.log({
260
- message: "Executing capability",
261
- capabilityId: config.id,
262
- action: actionName,
263
- pluginID: config.pluginID
515
+ const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;
516
+ this.logger.log("Executing capability (call)", {
517
+ ...loggerContext,
518
+ is_stream: isStream,
519
+ input: stringifyForLog(input)
264
520
  });
265
- const result = await pluginInstance.run(actionName, context, resolvedParams);
266
- this.logger.log({
267
- message: "Capability executed successfully",
268
- capabilityId: config.id,
269
- action: actionName,
270
- duration: Date.now() - startTime
521
+ let result;
522
+ if (isStream && pluginInstance.runStream) {
523
+ const chunks = [];
524
+ for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {
525
+ chunks.push(chunk);
526
+ }
527
+ result = pluginInstance.aggregate ? pluginInstance.aggregate(actionName, chunks) : chunks;
528
+ } else {
529
+ result = await pluginInstance.run(actionName, context, resolvedParams);
530
+ }
531
+ this.logger.log("Capability (call) executed successfully", {
532
+ ...loggerContext,
533
+ duration_ms: Date.now() - startTime,
534
+ output: stringifyForLog(result)
271
535
  });
272
536
  return result;
273
537
  } catch (error) {
274
- this.logger.error({
275
- message: "Capability execution failed",
276
- capabilityId: config.id,
277
- action: actionName,
278
- error: error instanceof Error ? error.message : String(error),
279
- duration: Date.now() - startTime
538
+ this.logger.error("Capability (call) execution failed", {
539
+ ...loggerContext,
540
+ duration_ms: Date.now() - startTime,
541
+ error: error instanceof Error ? error.message : String(error)
542
+ });
543
+ throw error;
544
+ }
545
+ }
546
+ /**
547
+ * 流式执行 capability
548
+ * - stream action: 返回原始 AsyncIterable
549
+ * - unary action: 包装为单次 yield
550
+ */
551
+ async *executeCallStream(config, actionName, input, contextOverride) {
552
+ const startTime = Date.now();
553
+ const loggerContext = {
554
+ capability_id: config.id,
555
+ plugin_key: config.pluginKey,
556
+ action: actionName
557
+ };
558
+ const chunks = [];
559
+ try {
560
+ const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);
561
+ if (!pluginInstance.hasAction(actionName)) {
562
+ throw new ActionNotFoundError(config.pluginKey, actionName);
563
+ }
564
+ const resolvedParams = config.formValue ? this.templateEngineService.resolve(config.formValue, input) : input;
565
+ const context = this.buildActionContext(contextOverride);
566
+ const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;
567
+ this.logger.log("Executing capability (stream)", {
568
+ ...loggerContext,
569
+ is_stream: isStream,
570
+ input: stringifyForLog(input)
571
+ });
572
+ if (isStream && pluginInstance.runStream) {
573
+ for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {
574
+ chunks.push(chunk);
575
+ yield chunk;
576
+ }
577
+ } else {
578
+ const result = await pluginInstance.run(actionName, context, resolvedParams);
579
+ chunks.push(result);
580
+ yield result;
581
+ }
582
+ const aggregatedResult = pluginInstance.aggregate ? pluginInstance.aggregate(actionName, chunks) : chunks;
583
+ this.logger.log("Capability (stream) executed successfully", {
584
+ ...loggerContext,
585
+ duration_ms: Date.now() - startTime,
586
+ output: stringifyForLog(aggregatedResult)
587
+ });
588
+ } catch (error) {
589
+ this.logger.error("Capability (stream) execution failed", {
590
+ ...loggerContext,
591
+ duration_ms: Date.now() - startTime,
592
+ error: error instanceof Error ? error.message : String(error)
280
593
  });
281
594
  throw error;
282
595
  }
283
596
  }
597
+ /**
598
+ * 流式执行 capability,返回带事件协议的流
599
+ * - 优先使用 pluginInstance.runStreamWithEvents
600
+ * - 如果插件不支持,则包装 runStream/run 为 StreamEvent
601
+ */
602
+ async *executeCallStreamWithEvents(config, actionName, input, contextOverride) {
603
+ const startTime = Date.now();
604
+ const loggerContext = {
605
+ capability_id: config.id,
606
+ plugin_key: config.pluginKey,
607
+ action: actionName
608
+ };
609
+ const chunks = [];
610
+ try {
611
+ const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);
612
+ if (!pluginInstance.hasAction(actionName)) {
613
+ throw new ActionNotFoundError(config.pluginKey, actionName);
614
+ }
615
+ const resolvedParams = config.formValue ? this.templateEngineService.resolve(config.formValue, input) : input;
616
+ const context = this.buildActionContext(contextOverride);
617
+ const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;
618
+ this.logger.log("Executing capability (streamWithEvents)", {
619
+ ...loggerContext,
620
+ is_stream: isStream,
621
+ input: stringifyForLog(input)
622
+ });
623
+ if (pluginInstance.runStreamWithEvents) {
624
+ for await (const event of pluginInstance.runStreamWithEvents(actionName, context, resolvedParams)) {
625
+ if (event.type === "data") {
626
+ chunks.push(event.data);
627
+ yield event;
628
+ } else if (event.type === "done") {
629
+ const aggregatedResult2 = pluginInstance.aggregate ? pluginInstance.aggregate(actionName, chunks) : chunks;
630
+ yield {
631
+ type: "done",
632
+ metadata: {
633
+ ...event.metadata,
634
+ aggregated: aggregatedResult2
635
+ }
636
+ };
637
+ } else {
638
+ yield event;
639
+ }
640
+ }
641
+ } else {
642
+ if (isStream && pluginInstance.runStream) {
643
+ for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {
644
+ chunks.push(chunk);
645
+ yield {
646
+ type: "data",
647
+ data: chunk
648
+ };
649
+ }
650
+ } else {
651
+ const result = await pluginInstance.run(actionName, context, resolvedParams);
652
+ chunks.push(result);
653
+ yield {
654
+ type: "data",
655
+ data: result
656
+ };
657
+ }
658
+ const aggregatedResult2 = pluginInstance.aggregate ? pluginInstance.aggregate(actionName, chunks) : chunks;
659
+ yield {
660
+ type: "done",
661
+ metadata: {
662
+ chunks: chunks.length,
663
+ duration: Date.now() - startTime,
664
+ aggregated: aggregatedResult2
665
+ }
666
+ };
667
+ }
668
+ const aggregatedResult = pluginInstance.aggregate ? pluginInstance.aggregate(actionName, chunks) : chunks;
669
+ this.logger.log("Capability (streamWithEvents) executed successfully", {
670
+ ...loggerContext,
671
+ duration_ms: Date.now() - startTime,
672
+ output: stringifyForLog(aggregatedResult)
673
+ });
674
+ } catch (error) {
675
+ this.logger.error("Capability (streamWithEvents) execution failed", {
676
+ ...loggerContext,
677
+ duration_ms: Date.now() - startTime,
678
+ error: error instanceof Error ? error.message : String(error)
679
+ });
680
+ yield {
681
+ type: "error",
682
+ error: {
683
+ code: "EXECUTION_ERROR",
684
+ message: error instanceof Error ? error.message : String(error)
685
+ }
686
+ };
687
+ }
688
+ }
284
689
  buildActionContext(override) {
285
690
  return {
286
691
  logger: this.logger,
287
- httpClient: this.httpClient,
288
- userContext: override?.userContext ?? this.getUserContext()
692
+ platformHttpClient: this.platformHttpClient,
693
+ userContext: override?.userContext ?? this.getUserContext(),
694
+ isDebug: override?.isDebug ?? false
289
695
  };
290
696
  }
291
697
  getUserContext() {
292
698
  const ctx = this.requestContextService.getContext();
293
699
  return {
700
+ appId: ctx?.appId ?? "",
294
701
  userId: ctx?.userId ?? "",
295
702
  tenantId: ctx?.tenantId ?? ""
296
703
  };
@@ -309,7 +716,7 @@ CapabilityService = _ts_decorate3([
309
716
  ], CapabilityService);
310
717
 
311
718
  // src/controllers/debug.controller.ts
312
- import { Controller, Post, Get, Param, Body, HttpException, HttpStatus } from "@nestjs/common";
719
+ import { Controller, Post, Get, Param, Body, Res, HttpException, HttpStatus, Logger as Logger3 } from "@nestjs/common";
313
720
  function _ts_decorate4(decorators, target, key, desc) {
314
721
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
315
722
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -327,31 +734,41 @@ function _ts_param2(paramIndex, decorator) {
327
734
  };
328
735
  }
329
736
  __name(_ts_param2, "_ts_param");
330
- var DebugController = class {
737
+ var DebugController = class _DebugController {
331
738
  static {
332
739
  __name(this, "DebugController");
333
740
  }
334
741
  capabilityService;
742
+ pluginLoaderService;
335
743
  templateEngineService;
336
- constructor(capabilityService, templateEngineService) {
744
+ logger = new Logger3(_DebugController.name);
745
+ constructor(capabilityService, pluginLoaderService, templateEngineService) {
337
746
  this.capabilityService = capabilityService;
747
+ this.pluginLoaderService = pluginLoaderService;
338
748
  this.templateEngineService = templateEngineService;
339
749
  }
340
750
  list() {
341
751
  const capabilities = this.capabilityService.listCapabilities();
342
752
  return {
343
- code: 0,
344
- message: "success",
345
- data: capabilities.map((c) => ({
346
- id: c.id,
347
- name: c.name,
348
- pluginID: c.pluginID,
349
- pluginVersion: c.pluginVersion
350
- }))
753
+ status_code: ErrorCodes.SUCCESS,
754
+ data: {
755
+ capabilities: capabilities.map((c) => ({
756
+ id: c.id,
757
+ name: c.name,
758
+ pluginID: c.pluginKey,
759
+ pluginVersion: c.pluginVersion
760
+ }))
761
+ }
351
762
  };
352
763
  }
353
- async debug(capabilityId, body) {
354
- const startTime = Date.now();
764
+ /**
765
+ * 获取 capability 配置
766
+ * 优先使用 body.capability,否则从服务获取
767
+ */
768
+ getCapabilityConfig(capabilityId, bodyCapability) {
769
+ if (bodyCapability) {
770
+ return bodyCapability;
771
+ }
355
772
  const config = this.capabilityService.getCapability(capabilityId);
356
773
  if (!config) {
357
774
  throw new HttpException({
@@ -360,72 +777,194 @@ var DebugController = class {
360
777
  error: "CAPABILITY_NOT_FOUND"
361
778
  }, HttpStatus.NOT_FOUND);
362
779
  }
363
- const resolvedParams = this.templateEngineService.resolve(config.formValue, body.params);
780
+ return config;
781
+ }
782
+ /**
783
+ * 获取 action 名称
784
+ * 优先使用传入的 action,否则使用插件第一个 action
785
+ */
786
+ async getActionName(pluginKey, bodyAction) {
787
+ if (bodyAction) {
788
+ return bodyAction;
789
+ }
790
+ const pluginInstance = await this.pluginLoaderService.loadPlugin(pluginKey);
791
+ const actions = pluginInstance.listActions();
792
+ if (actions.length === 0) {
793
+ throw new HttpException({
794
+ code: 1,
795
+ message: `Plugin ${pluginKey} has no actions`,
796
+ error: "NO_ACTIONS"
797
+ }, HttpStatus.BAD_REQUEST);
798
+ }
799
+ return actions[0];
800
+ }
801
+ async debug(capabilityId, body) {
802
+ const startTime = Date.now();
803
+ const params = body.params ?? {};
804
+ const config = this.getCapabilityConfig(capabilityId, body.capability);
805
+ const action = await this.getActionName(config.pluginKey, body.action);
806
+ const resolvedParams = this.templateEngineService.resolve(config.formValue, params);
364
807
  try {
365
- const result = await this.capabilityService.load(capabilityId).call(body.action, body.params);
808
+ const result = await this.capabilityService.loadWithConfig(config).call(action, params, {
809
+ isDebug: true
810
+ });
366
811
  return {
367
- code: 0,
368
- message: "success",
369
- data: result,
370
- debug: {
371
- capabilityConfig: config,
372
- resolvedParams,
373
- duration: Date.now() - startTime,
374
- pluginID: config.pluginID
812
+ status_code: ErrorCodes.SUCCESS,
813
+ data: {
814
+ output: result,
815
+ debug: {
816
+ capabilityConfig: config,
817
+ resolvedParams,
818
+ duration: Date.now() - startTime,
819
+ pluginID: config.pluginKey,
820
+ action
821
+ }
375
822
  }
376
823
  };
377
824
  } catch (error) {
378
- const duration = Date.now() - startTime;
379
825
  if (error instanceof CapabilityNotFoundError) {
380
826
  throw new HttpException({
381
- code: 1,
382
- message: error.message,
383
- error: "CAPABILITY_NOT_FOUND",
384
- debug: {
385
- duration
386
- }
827
+ status_code: ErrorCodes.CAPABILITY_NOT_FOUND,
828
+ error_msg: `Capability not found: ${capabilityId}`
387
829
  }, HttpStatus.NOT_FOUND);
388
830
  }
389
831
  if (error instanceof PluginNotFoundError) {
390
832
  throw new HttpException({
391
- code: 1,
392
- message: error.message,
393
- error: "PLUGIN_NOT_FOUND",
394
- debug: {
395
- duration,
396
- pluginID: config.pluginID
397
- }
833
+ status_code: ErrorCodes.PLUGIN_NOT_FOUND,
834
+ error_msg: `Plugin not found: ${config.pluginKey}`
398
835
  }, HttpStatus.INTERNAL_SERVER_ERROR);
399
836
  }
400
837
  if (error instanceof ActionNotFoundError) {
401
838
  throw new HttpException({
402
- code: 1,
403
- message: error.message,
404
- error: "ACTION_NOT_FOUND",
405
- debug: {
406
- duration,
407
- pluginID: config.pluginID
408
- }
839
+ status_code: ErrorCodes.ACTION_NOT_FOUND,
840
+ error_msg: `Action '${action}' not found in plugin ${config.pluginKey}`
409
841
  }, HttpStatus.BAD_REQUEST);
410
842
  }
411
843
  throw new HttpException({
412
- code: 1,
413
- message: error instanceof Error ? error.message : String(error),
414
- error: "EXECUTION_ERROR",
415
- debug: {
416
- duration,
417
- pluginID: config.pluginID,
418
- resolvedParams
419
- }
844
+ status_code: ErrorCodes.EXECUTION_ERROR,
845
+ error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`
420
846
  }, HttpStatus.INTERNAL_SERVER_ERROR);
421
847
  }
422
848
  }
849
+ async debugStream(capabilityId, body, res) {
850
+ const params = body.params ?? {};
851
+ res.setHeader("Content-Type", "text/event-stream");
852
+ res.setHeader("Cache-Control", "no-cache");
853
+ res.setHeader("Connection", "keep-alive");
854
+ try {
855
+ const config = this.getCapabilityConfig(capabilityId, body.capability);
856
+ const action = await this.getActionName(config.pluginKey, body.action);
857
+ const loggerContext = {
858
+ capability_id: config.id,
859
+ plugin_key: config.pluginKey,
860
+ action
861
+ };
862
+ this.logger.log(`Executing capability (stream)`, {
863
+ ...loggerContext,
864
+ input: stringifyForLog(params)
865
+ });
866
+ const capability = this.capabilityService.loadWithConfig(config);
867
+ const eventStream = capability.callStreamWithEvents(action, params, {
868
+ isDebug: true
869
+ });
870
+ let pendingChunk = null;
871
+ for await (const event of eventStream) {
872
+ switch (event.type) {
873
+ case "data": {
874
+ if (pendingChunk !== null) {
875
+ const response = {
876
+ status_code: ErrorCodes.SUCCESS,
877
+ data: {
878
+ type: "content",
879
+ delta: pendingChunk
880
+ }
881
+ };
882
+ res.write(`data: ${JSON.stringify(response)}
883
+
884
+ `);
885
+ }
886
+ pendingChunk = event.data;
887
+ break;
888
+ }
889
+ case "done": {
890
+ if (pendingChunk !== null) {
891
+ const response = {
892
+ status_code: ErrorCodes.SUCCESS,
893
+ data: {
894
+ type: "content",
895
+ delta: pendingChunk,
896
+ finished: true
897
+ }
898
+ };
899
+ res.write(`data: ${JSON.stringify(response)}
900
+
901
+ `);
902
+ }
903
+ this.logger.log(`Capability (stream) executed successfully`, {
904
+ ...loggerContext,
905
+ duration_ms: event.metadata.duration,
906
+ output: stringifyForLog(event.metadata.aggregated)
907
+ });
908
+ res.end();
909
+ return;
910
+ }
911
+ case "error": {
912
+ const response = {
913
+ status_code: ErrorCodes.SUCCESS,
914
+ data: {
915
+ type: "error",
916
+ error: {
917
+ code: 0,
918
+ message: event.error.message
919
+ }
920
+ }
921
+ };
922
+ res.write(`data: ${JSON.stringify(response)}
923
+
924
+ `);
925
+ res.end();
926
+ return;
927
+ }
928
+ }
929
+ }
930
+ if (pendingChunk !== null) {
931
+ const response = {
932
+ status_code: ErrorCodes.SUCCESS,
933
+ data: {
934
+ type: "content",
935
+ delta: pendingChunk,
936
+ finished: true
937
+ }
938
+ };
939
+ res.write(`data: ${JSON.stringify(response)}
940
+
941
+ `);
942
+ }
943
+ res.end();
944
+ } catch (error) {
945
+ const errorMsg = error instanceof Error ? error.message : String(error);
946
+ const response = {
947
+ status_code: ErrorCodes.SUCCESS,
948
+ data: {
949
+ type: "error",
950
+ error: {
951
+ code: 0,
952
+ message: errorMsg
953
+ }
954
+ }
955
+ };
956
+ res.write(`data: ${JSON.stringify(response)}
957
+
958
+ `);
959
+ res.end();
960
+ }
961
+ }
423
962
  };
424
963
  _ts_decorate4([
425
964
  Get("list"),
426
965
  _ts_metadata2("design:type", Function),
427
966
  _ts_metadata2("design:paramtypes", []),
428
- _ts_metadata2("design:returntype", typeof ListResponse === "undefined" ? Object : ListResponse)
967
+ _ts_metadata2("design:returntype", typeof SuccessResponse === "undefined" ? Object : SuccessResponse)
429
968
  ], DebugController.prototype, "list", null);
430
969
  _ts_decorate4([
431
970
  Post("debug/:capability_id"),
@@ -434,21 +973,35 @@ _ts_decorate4([
434
973
  _ts_metadata2("design:type", Function),
435
974
  _ts_metadata2("design:paramtypes", [
436
975
  String,
437
- typeof ExecuteRequestBody === "undefined" ? Object : ExecuteRequestBody
976
+ typeof DebugRequestBody === "undefined" ? Object : DebugRequestBody
438
977
  ]),
439
978
  _ts_metadata2("design:returntype", Promise)
440
979
  ], DebugController.prototype, "debug", null);
980
+ _ts_decorate4([
981
+ Post("debug/:capability_id/stream"),
982
+ _ts_param2(0, Param("capability_id")),
983
+ _ts_param2(1, Body()),
984
+ _ts_param2(2, Res()),
985
+ _ts_metadata2("design:type", Function),
986
+ _ts_metadata2("design:paramtypes", [
987
+ String,
988
+ typeof DebugRequestBody === "undefined" ? Object : DebugRequestBody,
989
+ typeof Response === "undefined" ? Object : Response
990
+ ]),
991
+ _ts_metadata2("design:returntype", Promise)
992
+ ], DebugController.prototype, "debugStream", null);
441
993
  DebugController = _ts_decorate4([
442
994
  Controller("__innerapi__/capability"),
443
995
  _ts_metadata2("design:type", Function),
444
996
  _ts_metadata2("design:paramtypes", [
445
997
  typeof CapabilityService === "undefined" ? Object : CapabilityService,
998
+ typeof PluginLoaderService === "undefined" ? Object : PluginLoaderService,
446
999
  typeof TemplateEngineService === "undefined" ? Object : TemplateEngineService
447
1000
  ])
448
1001
  ], DebugController);
449
1002
 
450
1003
  // src/controllers/webhook.controller.ts
451
- import { Controller as Controller2, Post as Post2, Param as Param2, Body as Body2, HttpException as HttpException2, HttpStatus as HttpStatus2 } from "@nestjs/common";
1004
+ 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";
452
1005
  function _ts_decorate5(decorators, target, key, desc) {
453
1006
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
454
1007
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -466,52 +1019,177 @@ function _ts_param3(paramIndex, decorator) {
466
1019
  };
467
1020
  }
468
1021
  __name(_ts_param3, "_ts_param");
469
- var WebhookController = class {
1022
+ var WebhookController = class _WebhookController {
470
1023
  static {
471
1024
  __name(this, "WebhookController");
472
1025
  }
473
1026
  capabilityService;
1027
+ logger = new Logger4(_WebhookController.name);
474
1028
  constructor(capabilityService) {
475
1029
  this.capabilityService = capabilityService;
476
1030
  }
1031
+ list() {
1032
+ const capabilities = this.capabilityService.listCapabilities();
1033
+ return {
1034
+ status_code: ErrorCodes.SUCCESS,
1035
+ data: {
1036
+ capabilities: capabilities.map((c) => ({
1037
+ id: c.id,
1038
+ name: c.name,
1039
+ pluginID: c.pluginKey,
1040
+ pluginVersion: c.pluginVersion
1041
+ }))
1042
+ }
1043
+ };
1044
+ }
477
1045
  async execute(capabilityId, body) {
478
1046
  try {
479
1047
  const result = await this.capabilityService.load(capabilityId).call(body.action, body.params);
480
1048
  return {
481
- code: 0,
482
- message: "success",
483
- data: result
1049
+ status_code: ErrorCodes.SUCCESS,
1050
+ data: {
1051
+ output: result
1052
+ }
484
1053
  };
485
1054
  } catch (error) {
486
1055
  if (error instanceof CapabilityNotFoundError) {
487
1056
  throw new HttpException2({
488
- code: 1,
489
- message: error.message,
490
- error: "CAPABILITY_NOT_FOUND"
1057
+ status_code: ErrorCodes.CAPABILITY_NOT_FOUND,
1058
+ error_msg: `Capability not found: ${capabilityId}`
491
1059
  }, HttpStatus2.NOT_FOUND);
492
1060
  }
493
1061
  if (error instanceof PluginNotFoundError) {
494
1062
  throw new HttpException2({
495
- code: 1,
496
- message: error.message,
497
- error: "PLUGIN_NOT_FOUND"
1063
+ status_code: ErrorCodes.PLUGIN_NOT_FOUND,
1064
+ error_msg: `Plugin not found`
498
1065
  }, HttpStatus2.INTERNAL_SERVER_ERROR);
499
1066
  }
500
1067
  if (error instanceof ActionNotFoundError) {
501
1068
  throw new HttpException2({
502
- code: 1,
503
- message: error.message,
504
- error: "ACTION_NOT_FOUND"
1069
+ status_code: ErrorCodes.ACTION_NOT_FOUND,
1070
+ error_msg: `Action '${body.action}' not found`
505
1071
  }, HttpStatus2.BAD_REQUEST);
506
1072
  }
507
1073
  throw new HttpException2({
508
- code: 1,
509
- message: error instanceof Error ? error.message : String(error),
510
- error: "EXECUTION_ERROR"
1074
+ status_code: ErrorCodes.EXECUTION_ERROR,
1075
+ error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`
511
1076
  }, HttpStatus2.INTERNAL_SERVER_ERROR);
512
1077
  }
513
1078
  }
1079
+ async executeStream(capabilityId, body, res) {
1080
+ const loggerContext = {
1081
+ capability_id: capabilityId,
1082
+ action: body.action
1083
+ };
1084
+ res.setHeader("Content-Type", "text/event-stream");
1085
+ res.setHeader("Cache-Control", "no-cache");
1086
+ res.setHeader("Connection", "keep-alive");
1087
+ try {
1088
+ this.logger.log(`Executing capability (stream)`, {
1089
+ ...loggerContext,
1090
+ input: stringifyForLog(body.params)
1091
+ });
1092
+ const capability = this.capabilityService.load(capabilityId);
1093
+ const eventStream = capability.callStreamWithEvents(body.action, body.params);
1094
+ let pendingChunk = null;
1095
+ for await (const event of eventStream) {
1096
+ switch (event.type) {
1097
+ case "data": {
1098
+ if (pendingChunk !== null) {
1099
+ const response = {
1100
+ status_code: ErrorCodes.SUCCESS,
1101
+ data: {
1102
+ type: "content",
1103
+ delta: pendingChunk
1104
+ }
1105
+ };
1106
+ res.write(`data: ${JSON.stringify(response)}
1107
+
1108
+ `);
1109
+ }
1110
+ pendingChunk = event.data;
1111
+ break;
1112
+ }
1113
+ case "done": {
1114
+ if (pendingChunk !== null) {
1115
+ const response = {
1116
+ status_code: ErrorCodes.SUCCESS,
1117
+ data: {
1118
+ type: "content",
1119
+ delta: pendingChunk,
1120
+ finished: true
1121
+ }
1122
+ };
1123
+ res.write(`data: ${JSON.stringify(response)}
1124
+
1125
+ `);
1126
+ }
1127
+ this.logger.log(`Capability (stream) executed successfully`, {
1128
+ ...loggerContext,
1129
+ duration_ms: event.metadata.duration,
1130
+ output: stringifyForLog(event.metadata.aggregated)
1131
+ });
1132
+ res.end();
1133
+ return;
1134
+ }
1135
+ case "error": {
1136
+ const response = {
1137
+ status_code: ErrorCodes.SUCCESS,
1138
+ data: {
1139
+ type: "error",
1140
+ error: {
1141
+ code: 0,
1142
+ message: event.error.message
1143
+ }
1144
+ }
1145
+ };
1146
+ res.write(`data: ${JSON.stringify(response)}
1147
+
1148
+ `);
1149
+ res.end();
1150
+ return;
1151
+ }
1152
+ }
1153
+ }
1154
+ if (pendingChunk !== null) {
1155
+ const response = {
1156
+ status_code: ErrorCodes.SUCCESS,
1157
+ data: {
1158
+ type: "content",
1159
+ delta: pendingChunk,
1160
+ finished: true
1161
+ }
1162
+ };
1163
+ res.write(`data: ${JSON.stringify(response)}
1164
+
1165
+ `);
1166
+ }
1167
+ res.end();
1168
+ } catch (error) {
1169
+ const errorMsg = error instanceof Error ? error.message : String(error);
1170
+ const response = {
1171
+ status_code: ErrorCodes.SUCCESS,
1172
+ data: {
1173
+ type: "error",
1174
+ error: {
1175
+ code: 0,
1176
+ message: errorMsg
1177
+ }
1178
+ }
1179
+ };
1180
+ res.write(`data: ${JSON.stringify(response)}
1181
+
1182
+ `);
1183
+ res.end();
1184
+ }
1185
+ }
514
1186
  };
1187
+ _ts_decorate5([
1188
+ Get2("list"),
1189
+ _ts_metadata3("design:type", Function),
1190
+ _ts_metadata3("design:paramtypes", []),
1191
+ _ts_metadata3("design:returntype", typeof SuccessResponse === "undefined" ? Object : SuccessResponse)
1192
+ ], WebhookController.prototype, "list", null);
515
1193
  _ts_decorate5([
516
1194
  Post2(":capability_id"),
517
1195
  _ts_param3(0, Param2("capability_id")),
@@ -523,6 +1201,19 @@ _ts_decorate5([
523
1201
  ]),
524
1202
  _ts_metadata3("design:returntype", Promise)
525
1203
  ], WebhookController.prototype, "execute", null);
1204
+ _ts_decorate5([
1205
+ Post2(":capability_id/stream"),
1206
+ _ts_param3(0, Param2("capability_id")),
1207
+ _ts_param3(1, Body2()),
1208
+ _ts_param3(2, Res2()),
1209
+ _ts_metadata3("design:type", Function),
1210
+ _ts_metadata3("design:paramtypes", [
1211
+ String,
1212
+ typeof ExecuteRequestBody === "undefined" ? Object : ExecuteRequestBody,
1213
+ typeof Response === "undefined" ? Object : Response
1214
+ ]),
1215
+ _ts_metadata3("design:returntype", Promise)
1216
+ ], WebhookController.prototype, "executeStream", null);
526
1217
  WebhookController = _ts_decorate5([
527
1218
  Controller2("api/capability"),
528
1219
  _ts_metadata3("design:type", Function),
@@ -533,7 +1224,7 @@ WebhookController = _ts_decorate5([
533
1224
 
534
1225
  // src/capability.module.ts
535
1226
  import { Module } from "@nestjs/common";
536
- import { RequestContextService as RequestContextService2, PLATFORM_HTTP_CLIENT as PLATFORM_HTTP_CLIENT2 } from "@lark-apaas/nestjs-common";
1227
+ import { CommonModule, RequestContextService as RequestContextService2, PLATFORM_HTTP_CLIENT as PLATFORM_HTTP_CLIENT2 } from "@lark-apaas/nestjs-common";
537
1228
  function _ts_decorate6(decorators, target, key, desc) {
538
1229
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
539
1230
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -560,6 +1251,9 @@ var CapabilityModule = class _CapabilityModule {
560
1251
  static forRoot(options) {
561
1252
  return {
562
1253
  module: _CapabilityModule,
1254
+ imports: [
1255
+ CommonModule
1256
+ ],
563
1257
  controllers: getControllers(),
564
1258
  providers: [
565
1259
  {
@@ -570,8 +1264,8 @@ var CapabilityModule = class _CapabilityModule {
570
1264
  provide: CapabilityService,
571
1265
  useFactory: /* @__PURE__ */ __name((requestContextService, httpClient, pluginLoader, templateEngine, moduleOptions) => {
572
1266
  const service = new CapabilityService(requestContextService, httpClient, pluginLoader, templateEngine);
573
- if (moduleOptions?.capabilitiesDir) {
574
- service.setCapabilitiesDir(moduleOptions.capabilitiesDir);
1267
+ if (moduleOptions) {
1268
+ service.setOptions(moduleOptions);
575
1269
  }
576
1270
  return service;
577
1271
  }, "useFactory"),
@@ -594,6 +1288,9 @@ var CapabilityModule = class _CapabilityModule {
594
1288
  };
595
1289
  CapabilityModule = _ts_decorate6([
596
1290
  Module({
1291
+ imports: [
1292
+ CommonModule
1293
+ ],
597
1294
  controllers: getControllers(),
598
1295
  providers: [
599
1296
  CapabilityService,
@@ -611,6 +1308,7 @@ export {
611
1308
  CapabilityNotFoundError,
612
1309
  CapabilityService,
613
1310
  DebugController,
1311
+ ErrorCodes,
614
1312
  PluginLoadError,
615
1313
  PluginLoaderService,
616
1314
  PluginNotFoundError,