@lark-apaas/nestjs-capability 0.0.1-alpha.7 → 0.0.1-alpha.9

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/README.md CHANGED
@@ -93,14 +93,23 @@ const result = await this.capabilityService
93
93
  ### 上下文覆盖
94
94
 
95
95
  ```typescript
96
+ // 覆盖 userContext
96
97
  const result = await this.capabilityService
97
98
  .load('notify_task_created')
98
99
  .call('run', inputParams, {
99
100
  userContext: {
100
101
  userId: 'custom-user-id',
101
102
  tenantId: 'custom-tenant-id',
103
+ appId: 'custom-app-id',
102
104
  },
103
105
  });
106
+
107
+ // 设置调试模式(插件可据此返回更详细的错误信息)
108
+ const debugResult = await this.capabilityService
109
+ .load('ai_chat')
110
+ .call('chat', inputParams, {
111
+ isDebug: true,
112
+ });
104
113
  ```
105
114
 
106
115
  ## 能力配置
@@ -377,10 +386,17 @@ interface PluginActionContext {
377
386
  userContext: {
378
387
  userId: string; // 用户 ID
379
388
  tenantId: string; // 租户 ID
389
+ appId: string; // 应用 ID
380
390
  };
391
+ isDebug: boolean; // 是否为调试模式
381
392
  }
382
393
  ```
383
394
 
395
+ **isDebug 说明:**
396
+ - `DebugController` 调用时 `isDebug = true`
397
+ - `WebhookController` 或其他调用时 `isDebug = false`
398
+ - 插件可据此返回更详细的错误信息、调试日志等
399
+
384
400
  ## 错误类型
385
401
 
386
402
  | 错误 | 描述 |
package/dist/index.cjs CHANGED
@@ -290,7 +290,8 @@ var CapabilityService = class _CapabilityService {
290
290
  this.platformHttpClient = platformHttpClient;
291
291
  this.pluginLoaderService = pluginLoaderService;
292
292
  this.templateEngineService = templateEngineService;
293
- this.capabilitiesDir = path.join(process.cwd(), "server/capabilities");
293
+ const isDev = process.env.NODE_ENV === "development";
294
+ this.capabilitiesDir = path.join(process.cwd(), isDev ? "server/capabilities" : "capabilities");
294
295
  }
295
296
  setCapabilitiesDir(dir) {
296
297
  this.capabilitiesDir = dir;
@@ -499,8 +500,19 @@ var CapabilityService = class _CapabilityService {
499
500
  for await (const event of pluginInstance.runStreamWithEvents(actionName, context, resolvedParams)) {
500
501
  if (event.type === "data") {
501
502
  chunks.push(event.data);
503
+ yield event;
504
+ } else if (event.type === "done") {
505
+ const aggregatedResult2 = pluginInstance.aggregate ? pluginInstance.aggregate(actionName, chunks) : chunks;
506
+ yield {
507
+ type: "done",
508
+ metadata: {
509
+ ...event.metadata,
510
+ aggregated: aggregatedResult2
511
+ }
512
+ };
513
+ } else {
514
+ yield event;
502
515
  }
503
- yield event;
504
516
  }
505
517
  } else {
506
518
  if (isStream && pluginInstance.runStream) {
@@ -519,11 +531,13 @@ var CapabilityService = class _CapabilityService {
519
531
  data: result
520
532
  };
521
533
  }
534
+ const aggregatedResult2 = pluginInstance.aggregate ? pluginInstance.aggregate(actionName, chunks) : chunks;
522
535
  yield {
523
536
  type: "done",
524
537
  metadata: {
525
538
  chunks: chunks.length,
526
- duration: Date.now() - startTime
539
+ duration: Date.now() - startTime,
540
+ aggregated: aggregatedResult2
527
541
  }
528
542
  };
529
543
  }
@@ -552,7 +566,8 @@ var CapabilityService = class _CapabilityService {
552
566
  return {
553
567
  logger: this.logger,
554
568
  platformHttpClient: this.platformHttpClient,
555
- userContext: override?.userContext ?? this.getUserContext()
569
+ userContext: override?.userContext ?? this.getUserContext(),
570
+ isDebug: override?.isDebug ?? false
556
571
  };
557
572
  }
558
573
  getUserContext() {
@@ -666,7 +681,9 @@ var DebugController = class _DebugController {
666
681
  const action = await this.getActionName(config.pluginKey, body.action);
667
682
  const resolvedParams = this.templateEngineService.resolve(config.formValue, params);
668
683
  try {
669
- const result = await this.capabilityService.loadWithConfig(config).call(action, params);
684
+ const result = await this.capabilityService.loadWithConfig(config).call(action, params, {
685
+ isDebug: true
686
+ });
670
687
  return {
671
688
  status_code: ErrorCodes.SUCCESS,
672
689
  data: {
@@ -707,7 +724,6 @@ var DebugController = class _DebugController {
707
724
  }
708
725
  async debugStream(capabilityId, body, res) {
709
726
  const params = body.params ?? {};
710
- const startTime = Date.now();
711
727
  res.setHeader("Content-Type", "text/event-stream");
712
728
  res.setHeader("Cache-Control", "no-cache");
713
729
  res.setHeader("Connection", "keep-alive");
@@ -719,15 +735,18 @@ var DebugController = class _DebugController {
719
735
  plugin_key: config.pluginKey,
720
736
  action
721
737
  };
722
- this.logger.log(`Executing capability (stream), input: ${stringifyForLog(params)}`, loggerContext);
738
+ this.logger.log(`Executing capability (stream)`, {
739
+ ...loggerContext,
740
+ input: stringifyForLog(params)
741
+ });
723
742
  const capability = this.capabilityService.loadWithConfig(config);
724
- const eventStream = capability.callStreamWithEvents(action, params);
743
+ const eventStream = capability.callStreamWithEvents(action, params, {
744
+ isDebug: true
745
+ });
725
746
  let pendingChunk = null;
726
- const allChunks = [];
727
747
  for await (const event of eventStream) {
728
748
  switch (event.type) {
729
749
  case "data": {
730
- allChunks.push(event.data);
731
750
  if (pendingChunk !== null) {
732
751
  const response = {
733
752
  status_code: ErrorCodes.SUCCESS,
@@ -761,7 +780,11 @@ var DebugController = class _DebugController {
761
780
 
762
781
  `);
763
782
  }
764
- this.logger.log(`Capability (stream) executed successfully, duration: ${Date.now() - startTime}ms, chunks: ${allChunks.length}, result: ${stringifyForLog(allChunks)}`, loggerContext);
783
+ this.logger.log(`Capability (stream) executed successfully`, {
784
+ ...loggerContext,
785
+ duration_ms: event.metadata.duration,
786
+ output: stringifyForLog(event.metadata.aggregated)
787
+ });
765
788
  res.end();
766
789
  return;
767
790
  }
@@ -936,7 +959,6 @@ var WebhookController = class _WebhookController {
936
959
  }
937
960
  }
938
961
  async executeStream(capabilityId, body, res) {
939
- const startTime = Date.now();
940
962
  const loggerContext = {
941
963
  capability_id: capabilityId,
942
964
  action: body.action
@@ -945,15 +967,16 @@ var WebhookController = class _WebhookController {
945
967
  res.setHeader("Cache-Control", "no-cache");
946
968
  res.setHeader("Connection", "keep-alive");
947
969
  try {
948
- this.logger.log(`Executing capability (stream), input: ${stringifyForLog(body.params)}`, loggerContext);
970
+ this.logger.log(`Executing capability (stream)`, {
971
+ ...loggerContext,
972
+ input: stringifyForLog(body.params)
973
+ });
949
974
  const capability = this.capabilityService.load(capabilityId);
950
975
  const eventStream = capability.callStreamWithEvents(body.action, body.params);
951
976
  let pendingChunk = null;
952
- const allChunks = [];
953
977
  for await (const event of eventStream) {
954
978
  switch (event.type) {
955
979
  case "data": {
956
- allChunks.push(event.data);
957
980
  if (pendingChunk !== null) {
958
981
  const response = {
959
982
  status_code: ErrorCodes.SUCCESS,
@@ -987,7 +1010,11 @@ var WebhookController = class _WebhookController {
987
1010
 
988
1011
  `);
989
1012
  }
990
- this.logger.log(`Capability (stream) executed successfully, duration: ${Date.now() - startTime}ms, chunks: ${allChunks.length}, result: ${stringifyForLog(allChunks)}`, loggerContext);
1013
+ this.logger.log(`Capability (stream) executed successfully`, {
1014
+ ...loggerContext,
1015
+ duration_ms: event.metadata.duration,
1016
+ output: stringifyForLog(event.metadata.aggregated)
1017
+ });
991
1018
  res.end();
992
1019
  return;
993
1020
  }
@@ -1025,7 +1052,6 @@ var WebhookController = class _WebhookController {
1025
1052
 
1026
1053
  `);
1027
1054
  }
1028
- this.logger.log(`Capability (stream) executed successfully, duration: ${Date.now() - startTime}ms, chunks: ${allChunks.length}, result: ${stringifyForLog(allChunks)}`, loggerContext);
1029
1055
  res.end();
1030
1056
  } catch (error) {
1031
1057
  const errorMsg = error instanceof Error ? error.message : String(error);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/interfaces/error-codes.ts","../src/services/template-engine.service.ts","../src/services/plugin-loader.service.ts","../src/services/capability.service.ts","../src/utils/log-utils.ts","../src/controllers/debug.controller.ts","../src/controllers/webhook.controller.ts","../src/capability.module.ts"],"sourcesContent":["export * from './interfaces';\nexport * from './services';\nexport * from './controllers';\nexport * from './capability.module';\n","/**\n * Capability 模块错误码\n */\nexport const ErrorCodes = {\n /** 成功 */\n SUCCESS: '0',\n /** 能力不存在 */\n CAPABILITY_NOT_FOUND: 'k_ec_cap_001',\n /** 插件不存在 */\n PLUGIN_NOT_FOUND: 'k_ec_cap_002',\n /** Action 不存在 */\n ACTION_NOT_FOUND: 'k_ec_cap_003',\n /** 参数验证失败 */\n PARAMS_VALIDATION_ERROR: 'k_ec_cap_004',\n /** 执行失败 */\n EXECUTION_ERROR: 'k_ec_cap_005',\n} as const;\n\nexport type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];\n","import { Injectable } from '@nestjs/common';\n\n/**\n * 模板引擎服务\n *\n * 支持语法:\n * - expr: '{{' + selector + '}}'\n * - selector: 'input.' + ident | selector.ident\n * - ident: [a-zA-Z_]([a-zA-Z_0-9])*\n *\n * 示例:\n * - {{input.a}}\n * - {{input.a.b}}\n * - \"this is {{input.a.b}}\"\n *\n * 求值规则:\n * - 如果整个字符串是单个表达式,保留原始类型\n * - 如果是字符串插值(多个表达式或混合内容),返回字符串\n * - 如果变量不存在,返回原始表达式\n */\n@Injectable()\nexport class TemplateEngineService {\n // 匹配 {{input.xxx}} 或 {{input.xxx.yyy}} 表达式\n private readonly EXPR_REGEX = /\\{\\{input\\.([a-zA-Z_][a-zA-Z_0-9]*(?:\\.[a-zA-Z_][a-zA-Z_0-9]*)*)\\}\\}/g;\n // 匹配整串单个表达式\n private readonly WHOLE_STRING_EXPR_REGEX = /^\\{\\{input\\.([a-zA-Z_][a-zA-Z_0-9]*(?:\\.[a-zA-Z_][a-zA-Z_0-9]*)*)\\}\\}$/;\n\n resolve(template: unknown, input: Record<string, unknown>): unknown {\n if (typeof template === 'string') {\n return this.resolveString(template, input);\n }\n\n if (Array.isArray(template)) {\n return template.map(item => this.resolve(item, input));\n }\n\n if (template !== null && typeof template === 'object') {\n return this.resolveObject(template as Record<string, unknown>, input);\n }\n\n return template;\n }\n\n private resolveString(template: string, input: Record<string, unknown>): unknown {\n // 情况1: 整串是单个表达式 → 保留原始类型\n const wholeMatch = template.match(this.WHOLE_STRING_EXPR_REGEX);\n if (wholeMatch) {\n const path = wholeMatch[1];\n const value = this.getValueByPath(input, path);\n // 变量不存在,返回原始表达式\n return value !== undefined ? value : template;\n }\n\n // 情况2: 字符串插值 → 返回字符串\n // 重置正则的 lastIndex(因为使用了 g 标志)\n this.EXPR_REGEX.lastIndex = 0;\n\n // 检查是否有任何表达式\n if (!this.EXPR_REGEX.test(template)) {\n return template;\n }\n\n // 重置并进行替换\n this.EXPR_REGEX.lastIndex = 0;\n const result = template.replace(this.EXPR_REGEX, (match, path) => {\n const value = this.getValueByPath(input, path);\n // 变量不存在,保留原始表达式\n if (value === undefined) {\n return match;\n }\n return String(value);\n });\n\n return result;\n }\n\n private resolveObject(\n template: Record<string, unknown>,\n input: Record<string, unknown>,\n ): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(template)) {\n result[key] = this.resolve(value, input);\n }\n\n return result;\n }\n\n private getValueByPath(obj: Record<string, unknown>, path: string): unknown {\n const keys = path.split('.');\n let current: unknown = obj;\n\n for (const key of keys) {\n if (current === null || current === undefined) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[key];\n }\n\n return current;\n }\n}\n","import { Injectable, Logger } from '@nestjs/common';\nimport type { PluginInstance, PluginPackage } from '../interfaces';\n\nexport class PluginNotFoundError extends Error {\n constructor(pluginKey: string) {\n super(`Plugin not found: ${pluginKey}`);\n this.name = 'PluginNotFoundError';\n }\n}\n\nexport class PluginLoadError extends Error {\n constructor(pluginKey: string, reason: string) {\n super(`Failed to load plugin ${pluginKey}: ${reason}`);\n this.name = 'PluginLoadError';\n }\n}\n\n@Injectable()\nexport class PluginLoaderService {\n private readonly logger = new Logger(PluginLoaderService.name);\n private readonly pluginInstances = new Map<string, PluginInstance>();\n\n async loadPlugin(pluginKey: string): Promise<PluginInstance> {\n const cached = this.pluginInstances.get(pluginKey);\n if (cached) {\n this.logger.debug(`Using cached plugin instance: ${pluginKey}`);\n return cached;\n }\n\n this.logger.log(`Loading plugin: ${pluginKey}`);\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const pluginPackage = (await import(pluginKey)).default as PluginPackage;\n\n if (typeof pluginPackage.create !== 'function') {\n throw new PluginLoadError(pluginKey, 'Plugin does not export create() function');\n }\n\n const instance = pluginPackage.create();\n this.pluginInstances.set(pluginKey, instance);\n\n this.logger.log(`Plugin loaded successfully: ${pluginKey}`);\n return instance;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'MODULE_NOT_FOUND') {\n throw new PluginNotFoundError(pluginKey);\n }\n throw new PluginLoadError(\n pluginKey,\n error instanceof Error ? error.message : String(error),\n );\n }\n }\n\n isPluginInstalled(pluginKey: string): boolean {\n try {\n require.resolve(pluginKey);\n return true;\n } catch {\n return false;\n }\n }\n\n clearCache(pluginKey?: string): void {\n if (pluginKey) {\n this.pluginInstances.delete(pluginKey);\n this.logger.log(`Cleared cache for plugin: ${pluginKey}`);\n } else {\n this.pluginInstances.clear();\n this.logger.log('Cleared all plugin caches');\n }\n }\n}\n","import { Injectable, Logger, Inject, OnModuleInit } from '@nestjs/common';\nimport {\n RequestContextService,\n PLATFORM_HTTP_CLIENT,\n type PlatformHttpClient,\n} from '@lark-apaas/nestjs-common';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type {\n CapabilityConfig,\n PluginActionContext,\n UserContext,\n StreamEvent,\n} from '../interfaces';\nimport { PluginLoaderService } from './plugin-loader.service';\nimport { TemplateEngineService } from './template-engine.service';\nimport { stringifyForLog } from '../utils';\n\nexport class CapabilityNotFoundError extends Error {\n constructor(capabilityId: string) {\n super(`Capability not found: ${capabilityId}`);\n this.name = 'CapabilityNotFoundError';\n }\n}\n\nexport class ActionNotFoundError extends Error {\n constructor(pluginKey: string, actionName: string) {\n super(`Action '${actionName}' not found in plugin ${pluginKey}`);\n this.name = 'ActionNotFoundError';\n }\n}\n\nexport interface CapabilityExecutor {\n /**\n * 调用 capability(始终返回 Promise)\n * - unary action: 直接返回结果\n * - stream action: 内部聚合所有 chunk 后返回\n */\n call(actionName: string, input: unknown, context?: Partial<PluginActionContext>): Promise<unknown>;\n\n /**\n * 流式调用 capability,返回原始流\n * - 返回原始 AsyncIterable\n * - 如果 action 是 unary,包装为单次 yield\n */\n callStream(actionName: string, input: unknown, context?: Partial<PluginActionContext>): AsyncIterable<unknown>;\n\n /**\n * 流式调用 capability,返回带事件协议的流(推荐)\n * - 返回 StreamEvent 类型的 AsyncIterable\n * - 支持 data/done/error 三种事件类型\n * - Controller 层应优先使用此方法实现边收边发\n */\n callStreamWithEvents(\n actionName: string,\n input: unknown,\n context?: Partial<PluginActionContext>,\n ): AsyncIterable<StreamEvent<unknown>>;\n\n /**\n * 检查 action 是否为流式\n */\n isStream(actionName: string): Promise<boolean>;\n}\n\nexport interface CapabilityModuleOptions {\n capabilitiesDir?: string;\n}\n\n@Injectable()\nexport class CapabilityService implements OnModuleInit {\n private readonly logger = new Logger(CapabilityService.name);\n private readonly capabilities = new Map<string, CapabilityConfig>();\n private capabilitiesDir: string;\n\n constructor(\n private readonly requestContextService: RequestContextService,\n @Inject(PLATFORM_HTTP_CLIENT) private readonly platformHttpClient: PlatformHttpClient,\n private readonly pluginLoaderService: PluginLoaderService,\n private readonly templateEngineService: TemplateEngineService,\n ) {\n this.capabilitiesDir = path.join(process.cwd(), 'server/capabilities');\n }\n\n setCapabilitiesDir(dir: string): void {\n this.capabilitiesDir = dir;\n }\n\n async onModuleInit(): Promise<void> {\n await this.loadCapabilities();\n }\n\n private async loadCapabilities(): Promise<void> {\n this.logger.log(`Loading capabilities from ${this.capabilitiesDir}`);\n\n if (!fs.existsSync(this.capabilitiesDir)) {\n this.logger.warn(`Capabilities directory not found: ${this.capabilitiesDir}`);\n return;\n }\n\n const files = fs.readdirSync(this.capabilitiesDir).filter(f => f.endsWith('.json'));\n\n for (const file of files) {\n try {\n const filePath = path.join(this.capabilitiesDir, file);\n const content = fs.readFileSync(filePath, 'utf-8');\n const config = JSON.parse(content) as CapabilityConfig;\n\n if (!config.id) {\n this.logger.warn(`Skipping capability without id: ${file}`);\n continue;\n }\n\n this.capabilities.set(config.id, config);\n this.logger.log(`Loaded capability: ${config.id} (${config.name})`);\n } catch (error) {\n this.logger.error(`Failed to load capability from ${file}:`, error);\n }\n }\n\n this.logger.log(`Loaded ${this.capabilities.size} capabilities`);\n }\n\n listCapabilities(): CapabilityConfig[] {\n return Array.from(this.capabilities.values());\n }\n\n getCapability(capabilityId: string): CapabilityConfig | null {\n return this.capabilities.get(capabilityId) ?? null;\n }\n\n load(capabilityId: string): CapabilityExecutor {\n const config = this.capabilities.get(capabilityId);\n if (!config) {\n throw new CapabilityNotFoundError(capabilityId);\n }\n\n return this.createExecutor(config);\n }\n\n /**\n * 使用传入的配置加载能力执行器\n * 用于 debug 场景,支持用户传入自定义配置\n */\n loadWithConfig(config: CapabilityConfig): CapabilityExecutor {\n return this.createExecutor(config);\n }\n\n private createExecutor(config: CapabilityConfig): CapabilityExecutor {\n return {\n call: async (\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ) => {\n return this.executeCall(config, actionName, input, contextOverride);\n },\n\n callStream: (\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ) => {\n return this.executeCallStream(config, actionName, input, contextOverride);\n },\n\n callStreamWithEvents: (\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ) => {\n return this.executeCallStreamWithEvents(config, actionName, input, contextOverride);\n },\n\n isStream: async (actionName: string) => {\n return this.checkIsStream(config, actionName);\n },\n };\n }\n\n /**\n * 检查 action 是否为流式\n */\n private async checkIsStream(config: CapabilityConfig, actionName: string): Promise<boolean> {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginKey, actionName);\n }\n\n return pluginInstance.isStreamAction?.(actionName) ?? false;\n }\n\n /**\n * 执行 capability(始终返回 Promise)\n * - unary action: 直接返回结果\n * - stream action: 内部聚合所有 chunk 后返回\n */\n private async executeCall(\n config: CapabilityConfig,\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ): Promise<unknown> {\n const startTime = Date.now();\n const loggerContext = {\n capability_id: config.id,\n plugin_key: config.pluginKey,\n action: actionName,\n };\n try {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginKey, actionName);\n }\n\n // 如果 formValue 不存在,直接使用 input\n const resolvedParams = config.formValue\n ? this.templateEngineService.resolve(config.formValue, input as Record<string, unknown>)\n : input;\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n // 打印入参\n this.logger.log('Executing capability (call)', {\n ...loggerContext,\n is_stream: isStream,\n input: stringifyForLog(input),\n });\n\n let result: unknown;\n\n if (isStream && pluginInstance.runStream) {\n // 流式 action:聚合所有 chunk\n const chunks: unknown[] = [];\n for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {\n chunks.push(chunk);\n }\n // 使用插件的聚合方法,或默认返回 chunks 数组\n result = pluginInstance.aggregate\n ? pluginInstance.aggregate(actionName, chunks)\n : chunks;\n } else {\n // 非流式 action:直接调用\n result = await pluginInstance.run(actionName, context, resolvedParams);\n }\n\n // 打印返回值\n this.logger.log('Capability (call) executed successfully', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n output: stringifyForLog(result),\n });\n\n return result;\n } catch (error) {\n this.logger.error('Capability (call) execution failed', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * 流式执行 capability\n * - stream action: 返回原始 AsyncIterable\n * - unary action: 包装为单次 yield\n */\n private async *executeCallStream(\n config: CapabilityConfig,\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ): AsyncIterable<unknown> {\n const startTime = Date.now();\n const loggerContext = {\n capability_id: config.id,\n plugin_key: config.pluginKey,\n action: actionName,\n };\n const chunks: unknown[] = [];\n try {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginKey, actionName);\n }\n\n // 如果 formValue 不存在,直接使用 input\n const resolvedParams = config.formValue\n ? this.templateEngineService.resolve(config.formValue, input as Record<string, unknown>)\n : input;\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n // 打印入参\n this.logger.log('Executing capability (stream)', {\n ...loggerContext,\n is_stream: isStream,\n input: stringifyForLog(input),\n });\n\n if (isStream && pluginInstance.runStream) {\n // 流式 action:透传 AsyncIterable,同时收集 chunks\n for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {\n chunks.push(chunk);\n yield chunk;\n }\n } else {\n // 非流式 action:包装为单次 yield\n const result = await pluginInstance.run(actionName, context, resolvedParams);\n chunks.push(result);\n yield result;\n }\n\n // 打印聚合结果\n const aggregatedResult = pluginInstance.aggregate\n ? pluginInstance.aggregate(actionName, chunks)\n : chunks;\n this.logger.log('Capability (stream) executed successfully', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n output: stringifyForLog(aggregatedResult),\n });\n } catch (error) {\n this.logger.error('Capability (stream) execution failed', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * 流式执行 capability,返回带事件协议的流\n * - 优先使用 pluginInstance.runStreamWithEvents\n * - 如果插件不支持,则包装 runStream/run 为 StreamEvent\n */\n private async *executeCallStreamWithEvents(\n config: CapabilityConfig,\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ): AsyncIterable<StreamEvent<unknown>> {\n const startTime = Date.now();\n const loggerContext = {\n capability_id: config.id,\n plugin_key: config.pluginKey,\n action: actionName,\n };\n const chunks: unknown[] = [];\n try {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginKey, actionName);\n }\n\n // 如果 formValue 不存在,直接使用 input\n const resolvedParams = config.formValue\n ? this.templateEngineService.resolve(config.formValue, input as Record<string, unknown>)\n : input;\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n // 打印入参\n this.logger.log('Executing capability (streamWithEvents)', {\n ...loggerContext,\n is_stream: isStream,\n input: stringifyForLog(input),\n });\n\n // 优先使用 runStreamWithEvents\n if (pluginInstance.runStreamWithEvents) {\n for await (const event of pluginInstance.runStreamWithEvents(actionName, context, resolvedParams)) {\n // 收集 data 事件的数据用于聚合\n if (event.type === 'data') {\n chunks.push(event.data);\n }\n yield event;\n }\n } else {\n // 回退:包装 runStream 或 run 为 StreamEvent\n if (isStream && pluginInstance.runStream) {\n // 流式 action:包装每个 chunk 为 data 事件\n for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {\n chunks.push(chunk);\n yield { type: 'data', data: chunk };\n }\n } else {\n // 非流式 action:包装结果为单个 data 事件\n const result = await pluginInstance.run(actionName, context, resolvedParams);\n chunks.push(result);\n yield { type: 'data', data: result };\n }\n\n // 发送 done 事件\n yield {\n type: 'done',\n metadata: {\n chunks: chunks.length,\n duration: Date.now() - startTime,\n },\n };\n }\n\n // 打印聚合结果\n const aggregatedResult = pluginInstance.aggregate\n ? pluginInstance.aggregate(actionName, chunks)\n : chunks;\n this.logger.log('Capability (streamWithEvents) executed successfully', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n output: stringifyForLog(aggregatedResult),\n });\n } catch (error) {\n this.logger.error('Capability (streamWithEvents) execution failed', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n\n // 发送 error 事件\n yield {\n type: 'error',\n error: {\n code: 'EXECUTION_ERROR',\n message: error instanceof Error ? error.message : String(error),\n },\n };\n }\n }\n\n private buildActionContext(override?: Partial<PluginActionContext>): PluginActionContext {\n return {\n logger: this.logger,\n platformHttpClient: this.platformHttpClient,\n userContext: override?.userContext ?? this.getUserContext(),\n };\n }\n\n private getUserContext(): UserContext {\n const ctx = this.requestContextService.getContext();\n return {\n appId: ctx?.appId ?? '',\n userId: ctx?.userId ?? '',\n tenantId: ctx?.tenantId ?? '',\n };\n }\n}\n","/**\n * 日志工具函数\n */\n\nconst DEFAULT_MAX_LENGTH = 1000;\n\n/**\n * 截断字符串\n */\nfunction truncateString(str: string, maxLength: number): string {\n if (str.length <= maxLength) {\n return str;\n }\n return str.slice(0, maxLength) + `... [truncated, total ${str.length} chars]`;\n}\n\n/**\n * 将对象转换为可打印的字符串,超过指定长度时截断\n * @param value - 要打印的值\n * @param maxLength - 最大字符数,默认 1000\n */\nexport function stringifyForLog(value: unknown, maxLength: number = DEFAULT_MAX_LENGTH): string {\n try {\n const str = JSON.stringify(value, null, 2);\n return truncateString(str, maxLength);\n } catch {\n // 处理循环引用等情况\n const str = String(value);\n return truncateString(str, maxLength);\n }\n}\n","import {\n Controller,\n Post,\n Get,\n Param,\n Body,\n Res,\n HttpException,\n HttpStatus,\n Logger,\n} from '@nestjs/common';\nimport type { Response } from 'express';\nimport {\n CapabilityService,\n CapabilityNotFoundError,\n ActionNotFoundError,\n} from '../services/capability.service';\nimport { PluginLoaderService, PluginNotFoundError } from '../services/plugin-loader.service';\nimport { TemplateEngineService } from '../services/template-engine.service';\nimport type {\n CapabilityConfig,\n SuccessResponse,\n ErrorResponse,\n DebugExecuteResponseData,\n ListResponseData,\n StreamContentResponse,\n StreamErrorResponse,\n} from '../interfaces';\nimport { ErrorCodes } from '../interfaces';\nimport { stringifyForLog } from '../utils';\n\ninterface DebugRequestBody {\n action?: string;\n params?: Record<string, unknown>;\n capability?: CapabilityConfig;\n}\n\n@Controller('__innerapi__/capability')\nexport class DebugController {\n private readonly logger = new Logger(DebugController.name);\n\n constructor(\n private readonly capabilityService: CapabilityService,\n private readonly pluginLoaderService: PluginLoaderService,\n private readonly templateEngineService: TemplateEngineService,\n ) {}\n\n @Get('list')\n list(): SuccessResponse<ListResponseData> {\n const capabilities = this.capabilityService.listCapabilities();\n\n return {\n status_code: ErrorCodes.SUCCESS,\n data: {\n capabilities: capabilities.map(c => ({\n id: c.id,\n name: c.name,\n pluginID: c.pluginKey,\n pluginVersion: c.pluginVersion,\n })),\n },\n };\n }\n\n /**\n * 获取 capability 配置\n * 优先使用 body.capability,否则从服务获取\n */\n private getCapabilityConfig(\n capabilityId: string,\n bodyCapability?: CapabilityConfig,\n ): CapabilityConfig {\n if (bodyCapability) {\n return bodyCapability;\n }\n\n const config = this.capabilityService.getCapability(capabilityId);\n if (!config) {\n throw new HttpException(\n {\n code: 1,\n message: `Capability not found: ${capabilityId}`,\n error: 'CAPABILITY_NOT_FOUND',\n },\n HttpStatus.NOT_FOUND,\n );\n }\n\n return config;\n }\n\n /**\n * 获取 action 名称\n * 优先使用传入的 action,否则使用插件第一个 action\n */\n private async getActionName(pluginKey: string, bodyAction?: string): Promise<string> {\n if (bodyAction) {\n return bodyAction;\n }\n\n const pluginInstance = await this.pluginLoaderService.loadPlugin(pluginKey);\n const actions = pluginInstance.listActions();\n\n if (actions.length === 0) {\n throw new HttpException(\n {\n code: 1,\n message: `Plugin ${pluginKey} has no actions`,\n error: 'NO_ACTIONS',\n },\n HttpStatus.BAD_REQUEST,\n );\n }\n\n return actions[0];\n }\n\n @Post('debug/:capability_id')\n async debug(\n @Param('capability_id') capabilityId: string,\n @Body() body: DebugRequestBody,\n ): Promise<SuccessResponse<DebugExecuteResponseData> | ErrorResponse> {\n const startTime = Date.now();\n const params = body.params ?? {};\n\n const config = this.getCapabilityConfig(capabilityId, body.capability);\n const action = await this.getActionName(config.pluginKey, body.action);\n\n const resolvedParams = this.templateEngineService.resolve(\n config.formValue,\n params,\n );\n\n try {\n const result = await this.capabilityService\n .loadWithConfig(config)\n .call(action, params);\n\n return {\n status_code: ErrorCodes.SUCCESS,\n data: {\n output: result,\n debug: {\n capabilityConfig: config,\n resolvedParams,\n duration: Date.now() - startTime,\n pluginID: config.pluginKey,\n action,\n },\n },\n };\n } catch (error) {\n if (error instanceof CapabilityNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.CAPABILITY_NOT_FOUND,\n error_msg: `Capability not found: ${capabilityId}`,\n } satisfies ErrorResponse,\n HttpStatus.NOT_FOUND,\n );\n }\n\n if (error instanceof PluginNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.PLUGIN_NOT_FOUND,\n error_msg: `Plugin not found: ${config.pluginKey}`,\n } satisfies ErrorResponse,\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n\n if (error instanceof ActionNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.ACTION_NOT_FOUND,\n error_msg: `Action '${action}' not found in plugin ${config.pluginKey}`,\n } satisfies ErrorResponse,\n HttpStatus.BAD_REQUEST,\n );\n }\n\n throw new HttpException(\n {\n status_code: ErrorCodes.EXECUTION_ERROR,\n error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`,\n } satisfies ErrorResponse,\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n }\n\n @Post('debug/:capability_id/stream')\n async debugStream(\n @Param('capability_id') capabilityId: string,\n @Body() body: DebugRequestBody,\n @Res() res: Response,\n ): Promise<void> {\n const params = body.params ?? {};\n const startTime = Date.now();\n\n // 设置 SSE 响应头\n res.setHeader('Content-Type', 'text/event-stream');\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Connection', 'keep-alive');\n\n try {\n const config = this.getCapabilityConfig(capabilityId, body.capability);\n const action = await this.getActionName(config.pluginKey, body.action);\n const loggerContext = {\n capability_id: config.id,\n plugin_key: config.pluginKey,\n action,\n };\n\n // 打印入参\n this.logger.log(`Executing capability (stream), input: ${stringifyForLog(params)}`, loggerContext);\n\n const capability = this.capabilityService.loadWithConfig(config);\n const eventStream = capability.callStreamWithEvents(action, params);\n\n // 延迟发送策略:缓存上一个 chunk,收到下一个 data 或 done 时再发送\n // 这样可以在最后一个 chunk 上标记 finished: true\n let pendingChunk: unknown | null = null;\n // 收集所有 chunk 用于日志\n const allChunks: unknown[] = [];\n\n for await (const event of eventStream) {\n switch (event.type) {\n case 'data': {\n // 收集 chunk 用于日志\n allChunks.push(event.data);\n // 先发送上一个缓存的 chunk(如果有)\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 缓存当前 chunk\n pendingChunk = event.data;\n break;\n }\n\n case 'done': {\n // 发送最后一个 chunk 并带上 finished: true\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n finished: true,\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 打印聚合结果\n this.logger.log(`Capability (stream) executed successfully, duration: ${Date.now() - startTime}ms, chunks: ${allChunks.length}, result: ${stringifyForLog(allChunks)}`, loggerContext);\n res.end();\n return;\n }\n\n case 'error': {\n // 错误事件:发送错误信息\n const response: StreamErrorResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'error',\n error: {\n code: 0,\n message: event.error.message,\n },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n return;\n }\n }\n }\n\n // 如果事件流正常结束但没有 done 事件,发送缓存的 chunk\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n finished: true,\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n res.end();\n } catch (error) {\n // 流异常中断(在事件流开始前的错误)\n const errorMsg = error instanceof Error ? error.message : String(error);\n const response: StreamErrorResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'error',\n error: {\n code: 0,\n message: errorMsg,\n },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n }\n }\n}\n","import {\n Controller,\n Get,\n Post,\n Param,\n Body,\n Res,\n HttpException,\n HttpStatus,\n Logger,\n} from '@nestjs/common';\nimport type { Response } from 'express';\nimport {\n CapabilityService,\n CapabilityNotFoundError,\n ActionNotFoundError,\n} from '../services/capability.service';\nimport { PluginNotFoundError } from '../services/plugin-loader.service';\nimport type {\n SuccessResponse,\n ErrorResponse,\n ExecuteResponseData,\n ListResponseData,\n StreamContentResponse,\n StreamErrorResponse,\n} from '../interfaces';\nimport { ErrorCodes } from '../interfaces';\nimport { stringifyForLog } from '../utils';\n\ninterface ExecuteRequestBody {\n action: string;\n params: Record<string, unknown>;\n}\n\n@Controller('api/capability')\nexport class WebhookController {\n private readonly logger = new Logger(WebhookController.name);\n\n constructor(private readonly capabilityService: CapabilityService) {}\n\n @Get('list')\n list(): SuccessResponse<ListResponseData> {\n const capabilities = this.capabilityService.listCapabilities();\n return {\n status_code: ErrorCodes.SUCCESS,\n data: {\n capabilities: capabilities.map(c => ({\n id: c.id,\n name: c.name,\n pluginID: c.pluginKey,\n pluginVersion: c.pluginVersion,\n })),\n },\n };\n }\n\n @Post(':capability_id')\n async execute(\n @Param('capability_id') capabilityId: string,\n @Body() body: ExecuteRequestBody,\n ): Promise<SuccessResponse<ExecuteResponseData> | ErrorResponse> {\n try {\n const result = await this.capabilityService\n .load(capabilityId)\n .call(body.action, body.params);\n\n return {\n status_code: ErrorCodes.SUCCESS,\n data: {\n output: result,\n },\n };\n } catch (error) {\n if (error instanceof CapabilityNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.CAPABILITY_NOT_FOUND,\n error_msg: `Capability not found: ${capabilityId}`,\n } satisfies ErrorResponse,\n HttpStatus.NOT_FOUND,\n );\n }\n\n if (error instanceof PluginNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.PLUGIN_NOT_FOUND,\n error_msg: `Plugin not found`,\n } satisfies ErrorResponse,\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n\n if (error instanceof ActionNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.ACTION_NOT_FOUND,\n error_msg: `Action '${body.action}' not found`,\n } satisfies ErrorResponse,\n HttpStatus.BAD_REQUEST,\n );\n }\n\n throw new HttpException(\n {\n status_code: ErrorCodes.EXECUTION_ERROR,\n error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`,\n } satisfies ErrorResponse,\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n }\n\n @Post(':capability_id/stream')\n async executeStream(\n @Param('capability_id') capabilityId: string,\n @Body() body: ExecuteRequestBody,\n @Res() res: Response,\n ): Promise<void> {\n const startTime = Date.now();\n const loggerContext = {\n capability_id: capabilityId,\n action: body.action,\n };\n\n // 设置 SSE 响应头\n res.setHeader('Content-Type', 'text/event-stream');\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Connection', 'keep-alive');\n\n try {\n // 打印入参\n this.logger.log(`Executing capability (stream), input: ${stringifyForLog(body.params)}`, loggerContext);\n\n const capability = this.capabilityService.load(capabilityId);\n const eventStream = capability.callStreamWithEvents(body.action, body.params);\n\n // 延迟发送策略:缓存上一个 chunk,收到下一个 data 或 done 时再发送\n // 这样可以在最后一个 chunk 上标记 finished: true\n let pendingChunk: unknown | null = null;\n // 收集所有 chunk 用于日志\n const allChunks: unknown[] = [];\n\n for await (const event of eventStream) {\n switch (event.type) {\n case 'data': {\n // 收集 chunk 用于日志\n allChunks.push(event.data);\n // 先发送上一个缓存的 chunk(如果有)\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 缓存当前 chunk\n pendingChunk = event.data;\n break;\n }\n\n case 'done': {\n // 发送最后一个 chunk 并带上 finished: true\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n finished: true,\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 打印聚合结果\n this.logger.log(`Capability (stream) executed successfully, duration: ${Date.now() - startTime}ms, chunks: ${allChunks.length}, result: ${stringifyForLog(allChunks)}`, loggerContext);\n res.end();\n return;\n }\n\n case 'error': {\n // 错误事件:发送错误信息\n const response: StreamErrorResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'error',\n error: {\n code: 0,\n message: event.error.message,\n },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n return;\n }\n }\n }\n\n // 如果事件流正常结束但没有 done 事件,发送缓存的 chunk\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n finished: true,\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 打印聚合结果\n this.logger.log(`Capability (stream) executed successfully, duration: ${Date.now() - startTime}ms, chunks: ${allChunks.length}, result: ${stringifyForLog(allChunks)}`, loggerContext);\n res.end();\n } catch (error) {\n // 流异常中断(在事件流开始前的错误)\n const errorMsg = error instanceof Error ? error.message : String(error);\n const response: StreamErrorResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'error',\n error: {\n code: 0,\n message: errorMsg,\n },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n }\n }\n}\n","import { Module, DynamicModule, Type } from '@nestjs/common';\nimport {\n CommonModule,\n RequestContextService,\n PLATFORM_HTTP_CLIENT,\n} from '@lark-apaas/nestjs-common';\nimport { DebugController, WebhookController } from './controllers';\nimport {\n CapabilityService,\n PluginLoaderService,\n TemplateEngineService,\n type CapabilityModuleOptions,\n} from './services';\n\nconst CAPABILITY_OPTIONS = Symbol('CAPABILITY_OPTIONS');\n\nconst isDevelopment = process.env.NODE_ENV === 'development';\n\nfunction getControllers(): Type[] {\n const controllers: Type[] = [WebhookController];\n if (isDevelopment) {\n controllers.push(DebugController);\n }\n return controllers;\n}\n\n@Module({\n imports: [CommonModule],\n controllers: getControllers(),\n providers: [CapabilityService, PluginLoaderService, TemplateEngineService],\n exports: [CapabilityService],\n})\nexport class CapabilityModule {\n static forRoot(options?: CapabilityModuleOptions): DynamicModule {\n return {\n module: CapabilityModule,\n imports: [CommonModule],\n controllers: getControllers(),\n providers: [\n {\n provide: CAPABILITY_OPTIONS,\n useValue: options ?? {},\n },\n {\n provide: CapabilityService,\n useFactory: (\n requestContextService: RequestContextService,\n httpClient: any,\n pluginLoader: PluginLoaderService,\n templateEngine: TemplateEngineService,\n moduleOptions: CapabilityModuleOptions,\n ) => {\n const service = new CapabilityService(\n requestContextService,\n httpClient,\n pluginLoader,\n templateEngine,\n );\n if (moduleOptions?.capabilitiesDir) {\n service.setCapabilitiesDir(moduleOptions.capabilitiesDir);\n }\n return service;\n },\n inject: [\n RequestContextService,\n PLATFORM_HTTP_CLIENT,\n PluginLoaderService,\n TemplateEngineService,\n CAPABILITY_OPTIONS,\n ],\n },\n PluginLoaderService,\n TemplateEngineService,\n ],\n exports: [CapabilityService],\n };\n }\n}\n"],"mappings":"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","names":["ErrorCodes","SUCCESS","CAPABILITY_NOT_FOUND","PLUGIN_NOT_FOUND","ACTION_NOT_FOUND","PARAMS_VALIDATION_ERROR","EXECUTION_ERROR","TemplateEngineService","EXPR_REGEX","WHOLE_STRING_EXPR_REGEX","resolve","template","input","resolveString","Array","isArray","map","item","resolveObject","wholeMatch","match","path","value","getValueByPath","undefined","lastIndex","test","result","replace","String","key","Object","entries","obj","keys","split","current","import_common","PluginNotFoundError","Error","pluginKey","name","PluginLoadError","reason","PluginLoaderService","logger","Logger","pluginInstances","Map","loadPlugin","cached","get","debug","log","pluginPackage","default","create","instance","set","error","code","message","String","isPluginInstalled","require","resolve","clearCache","delete","clear","import_common","DEFAULT_MAX_LENGTH","truncateString","str","maxLength","length","slice","stringifyForLog","value","JSON","stringify","String","CapabilityNotFoundError","Error","capabilityId","name","ActionNotFoundError","pluginKey","actionName","CapabilityService","logger","Logger","capabilities","Map","capabilitiesDir","requestContextService","platformHttpClient","pluginLoaderService","templateEngineService","join","process","cwd","setCapabilitiesDir","dir","onModuleInit","loadCapabilities","log","existsSync","warn","files","readdirSync","filter","f","endsWith","file","filePath","content","readFileSync","config","JSON","parse","id","set","error","size","listCapabilities","Array","from","values","getCapability","get","load","createExecutor","loadWithConfig","call","input","contextOverride","executeCall","callStream","executeCallStream","callStreamWithEvents","executeCallStreamWithEvents","isStream","checkIsStream","pluginInstance","loadPlugin","hasAction","isStreamAction","startTime","Date","now","loggerContext","capability_id","plugin_key","action","resolvedParams","formValue","resolve","context","buildActionContext","is_stream","stringifyForLog","result","runStream","chunks","chunk","push","aggregate","run","duration_ms","output","message","String","aggregatedResult","runStreamWithEvents","event","type","data","metadata","length","duration","code","override","userContext","getUserContext","ctx","getContext","appId","userId","tenantId","import_common","DebugController","logger","Logger","name","capabilityService","pluginLoaderService","templateEngineService","list","capabilities","listCapabilities","status_code","ErrorCodes","SUCCESS","data","map","c","id","pluginID","pluginKey","pluginVersion","getCapabilityConfig","capabilityId","bodyCapability","config","getCapability","HttpException","code","message","error","HttpStatus","NOT_FOUND","getActionName","bodyAction","pluginInstance","loadPlugin","actions","listActions","length","BAD_REQUEST","debug","body","startTime","Date","now","params","capability","action","resolvedParams","resolve","formValue","result","loadWithConfig","call","output","capabilityConfig","duration","CapabilityNotFoundError","CAPABILITY_NOT_FOUND","error_msg","PluginNotFoundError","PLUGIN_NOT_FOUND","INTERNAL_SERVER_ERROR","ActionNotFoundError","ACTION_NOT_FOUND","EXECUTION_ERROR","Error","String","debugStream","res","setHeader","loggerContext","capability_id","plugin_key","log","stringifyForLog","eventStream","callStreamWithEvents","pendingChunk","allChunks","event","type","push","response","delta","content","write","JSON","stringify","finished","end","errorMsg","import_common","WebhookController","logger","Logger","name","capabilityService","list","capabilities","listCapabilities","status_code","ErrorCodes","SUCCESS","data","map","c","id","pluginID","pluginKey","pluginVersion","execute","capabilityId","body","result","load","call","action","params","output","error","CapabilityNotFoundError","HttpException","CAPABILITY_NOT_FOUND","error_msg","HttpStatus","NOT_FOUND","PluginNotFoundError","PLUGIN_NOT_FOUND","INTERNAL_SERVER_ERROR","ActionNotFoundError","ACTION_NOT_FOUND","BAD_REQUEST","EXECUTION_ERROR","Error","message","String","executeStream","res","startTime","Date","now","loggerContext","capability_id","setHeader","log","stringifyForLog","capability","eventStream","callStreamWithEvents","pendingChunk","allChunks","event","type","push","response","delta","content","write","JSON","stringify","finished","length","end","code","errorMsg","import_common","import_nestjs_common","CAPABILITY_OPTIONS","Symbol","isDevelopment","process","env","NODE_ENV","getControllers","controllers","WebhookController","push","DebugController","CapabilityModule","forRoot","options","module","imports","CommonModule","providers","provide","useValue","CapabilityService","useFactory","requestContextService","httpClient","pluginLoader","templateEngine","moduleOptions","service","capabilitiesDir","setCapabilitiesDir","inject","RequestContextService","PLATFORM_HTTP_CLIENT","PluginLoaderService","TemplateEngineService","exports"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/interfaces/error-codes.ts","../src/services/template-engine.service.ts","../src/services/plugin-loader.service.ts","../src/services/capability.service.ts","../src/utils/log-utils.ts","../src/controllers/debug.controller.ts","../src/controllers/webhook.controller.ts","../src/capability.module.ts"],"sourcesContent":["export * from './interfaces';\nexport * from './services';\nexport * from './controllers';\nexport * from './capability.module';\n","/**\n * Capability 模块错误码\n */\nexport const ErrorCodes = {\n /** 成功 */\n SUCCESS: '0',\n /** 能力不存在 */\n CAPABILITY_NOT_FOUND: 'k_ec_cap_001',\n /** 插件不存在 */\n PLUGIN_NOT_FOUND: 'k_ec_cap_002',\n /** Action 不存在 */\n ACTION_NOT_FOUND: 'k_ec_cap_003',\n /** 参数验证失败 */\n PARAMS_VALIDATION_ERROR: 'k_ec_cap_004',\n /** 执行失败 */\n EXECUTION_ERROR: 'k_ec_cap_005',\n} as const;\n\nexport type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];\n","import { Injectable } from '@nestjs/common';\n\n/**\n * 模板引擎服务\n *\n * 支持语法:\n * - expr: '{{' + selector + '}}'\n * - selector: 'input.' + ident | selector.ident\n * - ident: [a-zA-Z_]([a-zA-Z_0-9])*\n *\n * 示例:\n * - {{input.a}}\n * - {{input.a.b}}\n * - \"this is {{input.a.b}}\"\n *\n * 求值规则:\n * - 如果整个字符串是单个表达式,保留原始类型\n * - 如果是字符串插值(多个表达式或混合内容),返回字符串\n * - 如果变量不存在,返回原始表达式\n */\n@Injectable()\nexport class TemplateEngineService {\n // 匹配 {{input.xxx}} 或 {{input.xxx.yyy}} 表达式\n private readonly EXPR_REGEX = /\\{\\{input\\.([a-zA-Z_][a-zA-Z_0-9]*(?:\\.[a-zA-Z_][a-zA-Z_0-9]*)*)\\}\\}/g;\n // 匹配整串单个表达式\n private readonly WHOLE_STRING_EXPR_REGEX = /^\\{\\{input\\.([a-zA-Z_][a-zA-Z_0-9]*(?:\\.[a-zA-Z_][a-zA-Z_0-9]*)*)\\}\\}$/;\n\n resolve(template: unknown, input: Record<string, unknown>): unknown {\n if (typeof template === 'string') {\n return this.resolveString(template, input);\n }\n\n if (Array.isArray(template)) {\n return template.map(item => this.resolve(item, input));\n }\n\n if (template !== null && typeof template === 'object') {\n return this.resolveObject(template as Record<string, unknown>, input);\n }\n\n return template;\n }\n\n private resolveString(template: string, input: Record<string, unknown>): unknown {\n // 情况1: 整串是单个表达式 → 保留原始类型\n const wholeMatch = template.match(this.WHOLE_STRING_EXPR_REGEX);\n if (wholeMatch) {\n const path = wholeMatch[1];\n const value = this.getValueByPath(input, path);\n // 变量不存在,返回原始表达式\n return value !== undefined ? value : template;\n }\n\n // 情况2: 字符串插值 → 返回字符串\n // 重置正则的 lastIndex(因为使用了 g 标志)\n this.EXPR_REGEX.lastIndex = 0;\n\n // 检查是否有任何表达式\n if (!this.EXPR_REGEX.test(template)) {\n return template;\n }\n\n // 重置并进行替换\n this.EXPR_REGEX.lastIndex = 0;\n const result = template.replace(this.EXPR_REGEX, (match, path) => {\n const value = this.getValueByPath(input, path);\n // 变量不存在,保留原始表达式\n if (value === undefined) {\n return match;\n }\n return String(value);\n });\n\n return result;\n }\n\n private resolveObject(\n template: Record<string, unknown>,\n input: Record<string, unknown>,\n ): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(template)) {\n result[key] = this.resolve(value, input);\n }\n\n return result;\n }\n\n private getValueByPath(obj: Record<string, unknown>, path: string): unknown {\n const keys = path.split('.');\n let current: unknown = obj;\n\n for (const key of keys) {\n if (current === null || current === undefined) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[key];\n }\n\n return current;\n }\n}\n","import { Injectable, Logger } from '@nestjs/common';\nimport type { PluginInstance, PluginPackage } from '../interfaces';\n\nexport class PluginNotFoundError extends Error {\n constructor(pluginKey: string) {\n super(`Plugin not found: ${pluginKey}`);\n this.name = 'PluginNotFoundError';\n }\n}\n\nexport class PluginLoadError extends Error {\n constructor(pluginKey: string, reason: string) {\n super(`Failed to load plugin ${pluginKey}: ${reason}`);\n this.name = 'PluginLoadError';\n }\n}\n\n@Injectable()\nexport class PluginLoaderService {\n private readonly logger = new Logger(PluginLoaderService.name);\n private readonly pluginInstances = new Map<string, PluginInstance>();\n\n async loadPlugin(pluginKey: string): Promise<PluginInstance> {\n const cached = this.pluginInstances.get(pluginKey);\n if (cached) {\n this.logger.debug(`Using cached plugin instance: ${pluginKey}`);\n return cached;\n }\n\n this.logger.log(`Loading plugin: ${pluginKey}`);\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const pluginPackage = (await import(pluginKey)).default as PluginPackage;\n\n if (typeof pluginPackage.create !== 'function') {\n throw new PluginLoadError(pluginKey, 'Plugin does not export create() function');\n }\n\n const instance = pluginPackage.create();\n this.pluginInstances.set(pluginKey, instance);\n\n this.logger.log(`Plugin loaded successfully: ${pluginKey}`);\n return instance;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'MODULE_NOT_FOUND') {\n throw new PluginNotFoundError(pluginKey);\n }\n throw new PluginLoadError(\n pluginKey,\n error instanceof Error ? error.message : String(error),\n );\n }\n }\n\n isPluginInstalled(pluginKey: string): boolean {\n try {\n require.resolve(pluginKey);\n return true;\n } catch {\n return false;\n }\n }\n\n clearCache(pluginKey?: string): void {\n if (pluginKey) {\n this.pluginInstances.delete(pluginKey);\n this.logger.log(`Cleared cache for plugin: ${pluginKey}`);\n } else {\n this.pluginInstances.clear();\n this.logger.log('Cleared all plugin caches');\n }\n }\n}\n","import { Injectable, Logger, Inject, OnModuleInit } from '@nestjs/common';\nimport {\n RequestContextService,\n PLATFORM_HTTP_CLIENT,\n type PlatformHttpClient,\n} from '@lark-apaas/nestjs-common';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type {\n CapabilityConfig,\n PluginActionContext,\n UserContext,\n StreamEvent,\n} from '../interfaces';\nimport { PluginLoaderService } from './plugin-loader.service';\nimport { TemplateEngineService } from './template-engine.service';\nimport { stringifyForLog } from '../utils';\n\nexport class CapabilityNotFoundError extends Error {\n constructor(capabilityId: string) {\n super(`Capability not found: ${capabilityId}`);\n this.name = 'CapabilityNotFoundError';\n }\n}\n\nexport class ActionNotFoundError extends Error {\n constructor(pluginKey: string, actionName: string) {\n super(`Action '${actionName}' not found in plugin ${pluginKey}`);\n this.name = 'ActionNotFoundError';\n }\n}\n\nexport interface CapabilityExecutor {\n /**\n * 调用 capability(始终返回 Promise)\n * - unary action: 直接返回结果\n * - stream action: 内部聚合所有 chunk 后返回\n */\n call(actionName: string, input: unknown, context?: Partial<PluginActionContext>): Promise<unknown>;\n\n /**\n * 流式调用 capability,返回原始流\n * - 返回原始 AsyncIterable\n * - 如果 action 是 unary,包装为单次 yield\n */\n callStream(actionName: string, input: unknown, context?: Partial<PluginActionContext>): AsyncIterable<unknown>;\n\n /**\n * 流式调用 capability,返回带事件协议的流(推荐)\n * - 返回 StreamEvent 类型的 AsyncIterable\n * - 支持 data/done/error 三种事件类型\n * - Controller 层应优先使用此方法实现边收边发\n */\n callStreamWithEvents(\n actionName: string,\n input: unknown,\n context?: Partial<PluginActionContext>,\n ): AsyncIterable<StreamEvent<unknown>>;\n\n /**\n * 检查 action 是否为流式\n */\n isStream(actionName: string): Promise<boolean>;\n}\n\nexport interface CapabilityModuleOptions {\n capabilitiesDir?: string;\n}\n\n@Injectable()\nexport class CapabilityService implements OnModuleInit {\n private readonly logger = new Logger(CapabilityService.name);\n private readonly capabilities = new Map<string, CapabilityConfig>();\n private capabilitiesDir: string;\n\n constructor(\n private readonly requestContextService: RequestContextService,\n @Inject(PLATFORM_HTTP_CLIENT) private readonly platformHttpClient: PlatformHttpClient,\n private readonly pluginLoaderService: PluginLoaderService,\n private readonly templateEngineService: TemplateEngineService,\n ) {\n const isDev = process.env.NODE_ENV === 'development';\n this.capabilitiesDir = path.join(process.cwd(), isDev ? 'server/capabilities' : 'capabilities');\n }\n\n setCapabilitiesDir(dir: string): void {\n this.capabilitiesDir = dir;\n }\n\n async onModuleInit(): Promise<void> {\n await this.loadCapabilities();\n }\n\n private async loadCapabilities(): Promise<void> {\n this.logger.log(`Loading capabilities from ${this.capabilitiesDir}`);\n\n if (!fs.existsSync(this.capabilitiesDir)) {\n this.logger.warn(`Capabilities directory not found: ${this.capabilitiesDir}`);\n return;\n }\n\n const files = fs.readdirSync(this.capabilitiesDir).filter(f => f.endsWith('.json'));\n\n for (const file of files) {\n try {\n const filePath = path.join(this.capabilitiesDir, file);\n const content = fs.readFileSync(filePath, 'utf-8');\n const config = JSON.parse(content) as CapabilityConfig;\n\n if (!config.id) {\n this.logger.warn(`Skipping capability without id: ${file}`);\n continue;\n }\n\n this.capabilities.set(config.id, config);\n this.logger.log(`Loaded capability: ${config.id} (${config.name})`);\n } catch (error) {\n this.logger.error(`Failed to load capability from ${file}:`, error);\n }\n }\n\n this.logger.log(`Loaded ${this.capabilities.size} capabilities`);\n }\n\n listCapabilities(): CapabilityConfig[] {\n return Array.from(this.capabilities.values());\n }\n\n getCapability(capabilityId: string): CapabilityConfig | null {\n return this.capabilities.get(capabilityId) ?? null;\n }\n\n load(capabilityId: string): CapabilityExecutor {\n const config = this.capabilities.get(capabilityId);\n if (!config) {\n throw new CapabilityNotFoundError(capabilityId);\n }\n\n return this.createExecutor(config);\n }\n\n /**\n * 使用传入的配置加载能力执行器\n * 用于 debug 场景,支持用户传入自定义配置\n */\n loadWithConfig(config: CapabilityConfig): CapabilityExecutor {\n return this.createExecutor(config);\n }\n\n private createExecutor(config: CapabilityConfig): CapabilityExecutor {\n return {\n call: async (\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ) => {\n return this.executeCall(config, actionName, input, contextOverride);\n },\n\n callStream: (\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ) => {\n return this.executeCallStream(config, actionName, input, contextOverride);\n },\n\n callStreamWithEvents: (\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ) => {\n return this.executeCallStreamWithEvents(config, actionName, input, contextOverride);\n },\n\n isStream: async (actionName: string) => {\n return this.checkIsStream(config, actionName);\n },\n };\n }\n\n /**\n * 检查 action 是否为流式\n */\n private async checkIsStream(config: CapabilityConfig, actionName: string): Promise<boolean> {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginKey, actionName);\n }\n\n return pluginInstance.isStreamAction?.(actionName) ?? false;\n }\n\n /**\n * 执行 capability(始终返回 Promise)\n * - unary action: 直接返回结果\n * - stream action: 内部聚合所有 chunk 后返回\n */\n private async executeCall(\n config: CapabilityConfig,\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ): Promise<unknown> {\n const startTime = Date.now();\n const loggerContext = {\n capability_id: config.id,\n plugin_key: config.pluginKey,\n action: actionName,\n };\n try {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginKey, actionName);\n }\n\n // 如果 formValue 不存在,直接使用 input\n const resolvedParams = config.formValue\n ? this.templateEngineService.resolve(config.formValue, input as Record<string, unknown>)\n : input;\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n // 打印入参\n this.logger.log('Executing capability (call)', {\n ...loggerContext,\n is_stream: isStream,\n input: stringifyForLog(input),\n });\n\n let result: unknown;\n\n if (isStream && pluginInstance.runStream) {\n // 流式 action:聚合所有 chunk\n const chunks: unknown[] = [];\n for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {\n chunks.push(chunk);\n }\n // 使用插件的聚合方法,或默认返回 chunks 数组\n result = pluginInstance.aggregate\n ? pluginInstance.aggregate(actionName, chunks)\n : chunks;\n } else {\n // 非流式 action:直接调用\n result = await pluginInstance.run(actionName, context, resolvedParams);\n }\n\n // 打印返回值\n this.logger.log('Capability (call) executed successfully', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n output: stringifyForLog(result),\n });\n\n return result;\n } catch (error) {\n this.logger.error('Capability (call) execution failed', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * 流式执行 capability\n * - stream action: 返回原始 AsyncIterable\n * - unary action: 包装为单次 yield\n */\n private async *executeCallStream(\n config: CapabilityConfig,\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ): AsyncIterable<unknown> {\n const startTime = Date.now();\n const loggerContext = {\n capability_id: config.id,\n plugin_key: config.pluginKey,\n action: actionName,\n };\n const chunks: unknown[] = [];\n try {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginKey, actionName);\n }\n\n // 如果 formValue 不存在,直接使用 input\n const resolvedParams = config.formValue\n ? this.templateEngineService.resolve(config.formValue, input as Record<string, unknown>)\n : input;\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n // 打印入参\n this.logger.log('Executing capability (stream)', {\n ...loggerContext,\n is_stream: isStream,\n input: stringifyForLog(input),\n });\n\n if (isStream && pluginInstance.runStream) {\n // 流式 action:透传 AsyncIterable,同时收集 chunks\n for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {\n chunks.push(chunk);\n yield chunk;\n }\n } else {\n // 非流式 action:包装为单次 yield\n const result = await pluginInstance.run(actionName, context, resolvedParams);\n chunks.push(result);\n yield result;\n }\n\n // 打印聚合结果\n const aggregatedResult = pluginInstance.aggregate\n ? pluginInstance.aggregate(actionName, chunks)\n : chunks;\n this.logger.log('Capability (stream) executed successfully', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n output: stringifyForLog(aggregatedResult),\n });\n } catch (error) {\n this.logger.error('Capability (stream) execution failed', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * 流式执行 capability,返回带事件协议的流\n * - 优先使用 pluginInstance.runStreamWithEvents\n * - 如果插件不支持,则包装 runStream/run 为 StreamEvent\n */\n private async *executeCallStreamWithEvents(\n config: CapabilityConfig,\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ): AsyncIterable<StreamEvent<unknown>> {\n const startTime = Date.now();\n const loggerContext = {\n capability_id: config.id,\n plugin_key: config.pluginKey,\n action: actionName,\n };\n const chunks: unknown[] = [];\n try {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginKey, actionName);\n }\n\n // 如果 formValue 不存在,直接使用 input\n const resolvedParams = config.formValue\n ? this.templateEngineService.resolve(config.formValue, input as Record<string, unknown>)\n : input;\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n // 打印入参\n this.logger.log('Executing capability (streamWithEvents)', {\n ...loggerContext,\n is_stream: isStream,\n input: stringifyForLog(input),\n });\n\n // 优先使用 runStreamWithEvents\n if (pluginInstance.runStreamWithEvents) {\n for await (const event of pluginInstance.runStreamWithEvents(actionName, context, resolvedParams)) {\n // 收集 data 事件的数据用于聚合\n if (event.type === 'data') {\n chunks.push(event.data);\n yield event;\n } else if (event.type === 'done') {\n // 拦截 done 事件,添加聚合结果\n const aggregatedResult = pluginInstance.aggregate\n ? pluginInstance.aggregate(actionName, chunks)\n : chunks;\n yield {\n type: 'done',\n metadata: {\n ...event.metadata,\n aggregated: aggregatedResult,\n },\n };\n } else {\n yield event;\n }\n }\n } else {\n // 回退:包装 runStream 或 run 为 StreamEvent\n if (isStream && pluginInstance.runStream) {\n // 流式 action:包装每个 chunk 为 data 事件\n for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {\n chunks.push(chunk);\n yield { type: 'data', data: chunk };\n }\n } else {\n // 非流式 action:包装结果为单个 data 事件\n const result = await pluginInstance.run(actionName, context, resolvedParams);\n chunks.push(result);\n yield { type: 'data', data: result };\n }\n\n // 聚合结果\n const aggregatedResult = pluginInstance.aggregate\n ? pluginInstance.aggregate(actionName, chunks)\n : chunks;\n\n // 发送 done 事件(包含聚合结果)\n yield {\n type: 'done',\n metadata: {\n chunks: chunks.length,\n duration: Date.now() - startTime,\n aggregated: aggregatedResult,\n },\n };\n }\n\n // 打印聚合结果\n const aggregatedResult = pluginInstance.aggregate\n ? pluginInstance.aggregate(actionName, chunks)\n : chunks;\n this.logger.log('Capability (streamWithEvents) executed successfully', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n output: stringifyForLog(aggregatedResult),\n });\n } catch (error) {\n this.logger.error('Capability (streamWithEvents) execution failed', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n\n // 发送 error 事件\n yield {\n type: 'error',\n error: {\n code: 'EXECUTION_ERROR',\n message: error instanceof Error ? error.message : String(error),\n },\n };\n }\n }\n\n private buildActionContext(override?: Partial<PluginActionContext>): PluginActionContext {\n return {\n logger: this.logger,\n platformHttpClient: this.platformHttpClient,\n userContext: override?.userContext ?? this.getUserContext(),\n isDebug: override?.isDebug ?? false,\n };\n }\n\n private getUserContext(): UserContext {\n const ctx = this.requestContextService.getContext();\n return {\n appId: ctx?.appId ?? '',\n userId: ctx?.userId ?? '',\n tenantId: ctx?.tenantId ?? '',\n };\n }\n}\n","/**\n * 日志工具函数\n */\n\nconst DEFAULT_MAX_LENGTH = 1000;\n\n/**\n * 截断字符串\n */\nfunction truncateString(str: string, maxLength: number): string {\n if (str.length <= maxLength) {\n return str;\n }\n return str.slice(0, maxLength) + `... [truncated, total ${str.length} chars]`;\n}\n\n/**\n * 将对象转换为可打印的字符串,超过指定长度时截断\n * @param value - 要打印的值\n * @param maxLength - 最大字符数,默认 1000\n */\nexport function stringifyForLog(value: unknown, maxLength: number = DEFAULT_MAX_LENGTH): string {\n try {\n const str = JSON.stringify(value, null, 2);\n return truncateString(str, maxLength);\n } catch {\n // 处理循环引用等情况\n const str = String(value);\n return truncateString(str, maxLength);\n }\n}\n","import {\n Controller,\n Post,\n Get,\n Param,\n Body,\n Res,\n HttpException,\n HttpStatus,\n Logger,\n} from '@nestjs/common';\nimport type { Response } from 'express';\nimport {\n CapabilityService,\n CapabilityNotFoundError,\n ActionNotFoundError,\n} from '../services/capability.service';\nimport { PluginLoaderService, PluginNotFoundError } from '../services/plugin-loader.service';\nimport { TemplateEngineService } from '../services/template-engine.service';\nimport type {\n CapabilityConfig,\n SuccessResponse,\n ErrorResponse,\n DebugExecuteResponseData,\n ListResponseData,\n StreamContentResponse,\n StreamErrorResponse,\n} from '../interfaces';\nimport { ErrorCodes } from '../interfaces';\nimport { stringifyForLog } from '../utils';\n\ninterface DebugRequestBody {\n action?: string;\n params?: Record<string, unknown>;\n capability?: CapabilityConfig;\n}\n\n@Controller('__innerapi__/capability')\nexport class DebugController {\n private readonly logger = new Logger(DebugController.name);\n\n constructor(\n private readonly capabilityService: CapabilityService,\n private readonly pluginLoaderService: PluginLoaderService,\n private readonly templateEngineService: TemplateEngineService,\n ) {}\n\n @Get('list')\n list(): SuccessResponse<ListResponseData> {\n const capabilities = this.capabilityService.listCapabilities();\n\n return {\n status_code: ErrorCodes.SUCCESS,\n data: {\n capabilities: capabilities.map(c => ({\n id: c.id,\n name: c.name,\n pluginID: c.pluginKey,\n pluginVersion: c.pluginVersion,\n })),\n },\n };\n }\n\n /**\n * 获取 capability 配置\n * 优先使用 body.capability,否则从服务获取\n */\n private getCapabilityConfig(\n capabilityId: string,\n bodyCapability?: CapabilityConfig,\n ): CapabilityConfig {\n if (bodyCapability) {\n return bodyCapability;\n }\n\n const config = this.capabilityService.getCapability(capabilityId);\n if (!config) {\n throw new HttpException(\n {\n code: 1,\n message: `Capability not found: ${capabilityId}`,\n error: 'CAPABILITY_NOT_FOUND',\n },\n HttpStatus.NOT_FOUND,\n );\n }\n\n return config;\n }\n\n /**\n * 获取 action 名称\n * 优先使用传入的 action,否则使用插件第一个 action\n */\n private async getActionName(pluginKey: string, bodyAction?: string): Promise<string> {\n if (bodyAction) {\n return bodyAction;\n }\n\n const pluginInstance = await this.pluginLoaderService.loadPlugin(pluginKey);\n const actions = pluginInstance.listActions();\n\n if (actions.length === 0) {\n throw new HttpException(\n {\n code: 1,\n message: `Plugin ${pluginKey} has no actions`,\n error: 'NO_ACTIONS',\n },\n HttpStatus.BAD_REQUEST,\n );\n }\n\n return actions[0];\n }\n\n @Post('debug/:capability_id')\n async debug(\n @Param('capability_id') capabilityId: string,\n @Body() body: DebugRequestBody,\n ): Promise<SuccessResponse<DebugExecuteResponseData> | ErrorResponse> {\n const startTime = Date.now();\n const params = body.params ?? {};\n\n const config = this.getCapabilityConfig(capabilityId, body.capability);\n const action = await this.getActionName(config.pluginKey, body.action);\n\n const resolvedParams = this.templateEngineService.resolve(\n config.formValue,\n params,\n );\n\n try {\n const result = await this.capabilityService\n .loadWithConfig(config)\n .call(action, params, { isDebug: true });\n\n return {\n status_code: ErrorCodes.SUCCESS,\n data: {\n output: result,\n debug: {\n capabilityConfig: config,\n resolvedParams,\n duration: Date.now() - startTime,\n pluginID: config.pluginKey,\n action,\n },\n },\n };\n } catch (error) {\n if (error instanceof CapabilityNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.CAPABILITY_NOT_FOUND,\n error_msg: `Capability not found: ${capabilityId}`,\n } satisfies ErrorResponse,\n HttpStatus.NOT_FOUND,\n );\n }\n\n if (error instanceof PluginNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.PLUGIN_NOT_FOUND,\n error_msg: `Plugin not found: ${config.pluginKey}`,\n } satisfies ErrorResponse,\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n\n if (error instanceof ActionNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.ACTION_NOT_FOUND,\n error_msg: `Action '${action}' not found in plugin ${config.pluginKey}`,\n } satisfies ErrorResponse,\n HttpStatus.BAD_REQUEST,\n );\n }\n\n throw new HttpException(\n {\n status_code: ErrorCodes.EXECUTION_ERROR,\n error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`,\n } satisfies ErrorResponse,\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n }\n\n @Post('debug/:capability_id/stream')\n async debugStream(\n @Param('capability_id') capabilityId: string,\n @Body() body: DebugRequestBody,\n @Res() res: Response,\n ): Promise<void> {\n const params = body.params ?? {};\n\n // 设置 SSE 响应头\n res.setHeader('Content-Type', 'text/event-stream');\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Connection', 'keep-alive');\n\n try {\n const config = this.getCapabilityConfig(capabilityId, body.capability);\n const action = await this.getActionName(config.pluginKey, body.action);\n const loggerContext = {\n capability_id: config.id,\n plugin_key: config.pluginKey,\n action,\n };\n\n // 打印入参\n this.logger.log(`Executing capability (stream)`, {\n ...loggerContext,\n input: stringifyForLog(params),\n });\n\n const capability = this.capabilityService.loadWithConfig(config);\n const eventStream = capability.callStreamWithEvents(action, params, { isDebug: true });\n\n // 延迟发送策略:缓存上一个 chunk,收到下一个 data 或 done 时再发送\n // 这样可以在最后一个 chunk 上标记 finished: true\n let pendingChunk: unknown | null = null;\n\n for await (const event of eventStream) {\n switch (event.type) {\n case 'data': {\n // 先发送上一个缓存的 chunk(如果有)\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 缓存当前 chunk\n pendingChunk = event.data;\n break;\n }\n\n case 'done': {\n // 发送最后一个 chunk 并带上 finished: true\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n finished: true,\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 打印聚合结果(从 done 事件的 metadata 中获取)\n this.logger.log(`Capability (stream) executed successfully`, {\n ...loggerContext,\n duration_ms: event.metadata.duration,\n output: stringifyForLog(event.metadata.aggregated),\n });\n res.end();\n return;\n }\n\n case 'error': {\n // 错误事件:发送错误信息\n const response: StreamErrorResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'error',\n error: {\n code: 0,\n message: event.error.message,\n },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n return;\n }\n }\n }\n\n // 如果事件流正常结束但没有 done 事件,发送缓存的 chunk\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n finished: true,\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n res.end();\n } catch (error) {\n // 流异常中断(在事件流开始前的错误)\n const errorMsg = error instanceof Error ? error.message : String(error);\n const response: StreamErrorResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'error',\n error: {\n code: 0,\n message: errorMsg,\n },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n }\n }\n}\n","import {\n Controller,\n Get,\n Post,\n Param,\n Body,\n Res,\n HttpException,\n HttpStatus,\n Logger,\n} from '@nestjs/common';\nimport type { Response } from 'express';\nimport {\n CapabilityService,\n CapabilityNotFoundError,\n ActionNotFoundError,\n} from '../services/capability.service';\nimport { PluginNotFoundError } from '../services/plugin-loader.service';\nimport type {\n SuccessResponse,\n ErrorResponse,\n ExecuteResponseData,\n ListResponseData,\n StreamContentResponse,\n StreamErrorResponse,\n} from '../interfaces';\nimport { ErrorCodes } from '../interfaces';\nimport { stringifyForLog } from '../utils';\n\ninterface ExecuteRequestBody {\n action: string;\n params: Record<string, unknown>;\n}\n\n@Controller('api/capability')\nexport class WebhookController {\n private readonly logger = new Logger(WebhookController.name);\n\n constructor(private readonly capabilityService: CapabilityService) {}\n\n @Get('list')\n list(): SuccessResponse<ListResponseData> {\n const capabilities = this.capabilityService.listCapabilities();\n return {\n status_code: ErrorCodes.SUCCESS,\n data: {\n capabilities: capabilities.map(c => ({\n id: c.id,\n name: c.name,\n pluginID: c.pluginKey,\n pluginVersion: c.pluginVersion,\n })),\n },\n };\n }\n\n @Post(':capability_id')\n async execute(\n @Param('capability_id') capabilityId: string,\n @Body() body: ExecuteRequestBody,\n ): Promise<SuccessResponse<ExecuteResponseData> | ErrorResponse> {\n try {\n const result = await this.capabilityService\n .load(capabilityId)\n .call(body.action, body.params);\n\n return {\n status_code: ErrorCodes.SUCCESS,\n data: {\n output: result,\n },\n };\n } catch (error) {\n if (error instanceof CapabilityNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.CAPABILITY_NOT_FOUND,\n error_msg: `Capability not found: ${capabilityId}`,\n } satisfies ErrorResponse,\n HttpStatus.NOT_FOUND,\n );\n }\n\n if (error instanceof PluginNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.PLUGIN_NOT_FOUND,\n error_msg: `Plugin not found`,\n } satisfies ErrorResponse,\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n\n if (error instanceof ActionNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.ACTION_NOT_FOUND,\n error_msg: `Action '${body.action}' not found`,\n } satisfies ErrorResponse,\n HttpStatus.BAD_REQUEST,\n );\n }\n\n throw new HttpException(\n {\n status_code: ErrorCodes.EXECUTION_ERROR,\n error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`,\n } satisfies ErrorResponse,\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n }\n\n @Post(':capability_id/stream')\n async executeStream(\n @Param('capability_id') capabilityId: string,\n @Body() body: ExecuteRequestBody,\n @Res() res: Response,\n ): Promise<void> {\n const loggerContext = {\n capability_id: capabilityId,\n action: body.action,\n };\n\n // 设置 SSE 响应头\n res.setHeader('Content-Type', 'text/event-stream');\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Connection', 'keep-alive');\n\n try {\n // 打印入参\n this.logger.log(`Executing capability (stream)`, {\n ...loggerContext,\n input: stringifyForLog(body.params),\n });\n\n const capability = this.capabilityService.load(capabilityId);\n const eventStream = capability.callStreamWithEvents(body.action, body.params);\n\n // 延迟发送策略:缓存上一个 chunk,收到下一个 data 或 done 时再发送\n // 这样可以在最后一个 chunk 上标记 finished: true\n let pendingChunk: unknown | null = null;\n\n for await (const event of eventStream) {\n switch (event.type) {\n case 'data': {\n // 先发送上一个缓存的 chunk(如果有)\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 缓存当前 chunk\n pendingChunk = event.data;\n break;\n }\n\n case 'done': {\n // 发送最后一个 chunk 并带上 finished: true\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n finished: true,\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 打印聚合结果(从 done 事件的 metadata 中获取)\n this.logger.log(`Capability (stream) executed successfully`, {\n ...loggerContext,\n duration_ms: event.metadata.duration,\n output: stringifyForLog(event.metadata.aggregated),\n });\n res.end();\n return;\n }\n\n case 'error': {\n // 错误事件:发送错误信息\n const response: StreamErrorResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'error',\n error: {\n code: 0,\n message: event.error.message,\n },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n return;\n }\n }\n }\n\n // 如果事件流正常结束但没有 done 事件,发送缓存的 chunk\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n finished: true,\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n res.end();\n } catch (error) {\n // 流异常中断(在事件流开始前的错误)\n const errorMsg = error instanceof Error ? error.message : String(error);\n const response: StreamErrorResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'error',\n error: {\n code: 0,\n message: errorMsg,\n },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n }\n }\n}\n","import { Module, DynamicModule, Type } from '@nestjs/common';\nimport {\n CommonModule,\n RequestContextService,\n PLATFORM_HTTP_CLIENT,\n} from '@lark-apaas/nestjs-common';\nimport { DebugController, WebhookController } from './controllers';\nimport {\n CapabilityService,\n PluginLoaderService,\n TemplateEngineService,\n type CapabilityModuleOptions,\n} from './services';\n\nconst CAPABILITY_OPTIONS = Symbol('CAPABILITY_OPTIONS');\n\nconst isDevelopment = process.env.NODE_ENV === 'development';\n\nfunction getControllers(): Type[] {\n const controllers: Type[] = [WebhookController];\n if (isDevelopment) {\n controllers.push(DebugController);\n }\n return controllers;\n}\n\n@Module({\n imports: [CommonModule],\n controllers: getControllers(),\n providers: [CapabilityService, PluginLoaderService, TemplateEngineService],\n exports: [CapabilityService],\n})\nexport class CapabilityModule {\n static forRoot(options?: CapabilityModuleOptions): DynamicModule {\n return {\n module: CapabilityModule,\n imports: [CommonModule],\n controllers: getControllers(),\n providers: [\n {\n provide: CAPABILITY_OPTIONS,\n useValue: options ?? {},\n },\n {\n provide: CapabilityService,\n useFactory: (\n requestContextService: RequestContextService,\n httpClient: any,\n pluginLoader: PluginLoaderService,\n templateEngine: TemplateEngineService,\n moduleOptions: CapabilityModuleOptions,\n ) => {\n const service = new CapabilityService(\n requestContextService,\n httpClient,\n pluginLoader,\n templateEngine,\n );\n if (moduleOptions?.capabilitiesDir) {\n service.setCapabilitiesDir(moduleOptions.capabilitiesDir);\n }\n return service;\n },\n inject: [\n RequestContextService,\n PLATFORM_HTTP_CLIENT,\n PluginLoaderService,\n TemplateEngineService,\n CAPABILITY_OPTIONS,\n ],\n },\n PluginLoaderService,\n TemplateEngineService,\n ],\n exports: [CapabilityService],\n };\n }\n}\n"],"mappings":"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","names":["ErrorCodes","SUCCESS","CAPABILITY_NOT_FOUND","PLUGIN_NOT_FOUND","ACTION_NOT_FOUND","PARAMS_VALIDATION_ERROR","EXECUTION_ERROR","TemplateEngineService","EXPR_REGEX","WHOLE_STRING_EXPR_REGEX","resolve","template","input","resolveString","Array","isArray","map","item","resolveObject","wholeMatch","match","path","value","getValueByPath","undefined","lastIndex","test","result","replace","String","key","Object","entries","obj","keys","split","current","import_common","PluginNotFoundError","Error","pluginKey","name","PluginLoadError","reason","PluginLoaderService","logger","Logger","pluginInstances","Map","loadPlugin","cached","get","debug","log","pluginPackage","default","create","instance","set","error","code","message","String","isPluginInstalled","require","resolve","clearCache","delete","clear","import_common","DEFAULT_MAX_LENGTH","truncateString","str","maxLength","length","slice","stringifyForLog","value","JSON","stringify","String","CapabilityNotFoundError","Error","capabilityId","name","ActionNotFoundError","pluginKey","actionName","CapabilityService","logger","Logger","capabilities","Map","capabilitiesDir","requestContextService","platformHttpClient","pluginLoaderService","templateEngineService","isDev","process","env","NODE_ENV","join","cwd","setCapabilitiesDir","dir","onModuleInit","loadCapabilities","log","existsSync","warn","files","readdirSync","filter","f","endsWith","file","filePath","content","readFileSync","config","JSON","parse","id","set","error","size","listCapabilities","Array","from","values","getCapability","get","load","createExecutor","loadWithConfig","call","input","contextOverride","executeCall","callStream","executeCallStream","callStreamWithEvents","executeCallStreamWithEvents","isStream","checkIsStream","pluginInstance","loadPlugin","hasAction","isStreamAction","startTime","Date","now","loggerContext","capability_id","plugin_key","action","resolvedParams","formValue","resolve","context","buildActionContext","is_stream","stringifyForLog","result","runStream","chunks","chunk","push","aggregate","run","duration_ms","output","message","String","aggregatedResult","runStreamWithEvents","event","type","data","metadata","aggregated","length","duration","code","override","userContext","getUserContext","isDebug","ctx","getContext","appId","userId","tenantId","import_common","DebugController","logger","Logger","name","capabilityService","pluginLoaderService","templateEngineService","list","capabilities","listCapabilities","status_code","ErrorCodes","SUCCESS","data","map","c","id","pluginID","pluginKey","pluginVersion","getCapabilityConfig","capabilityId","bodyCapability","config","getCapability","HttpException","code","message","error","HttpStatus","NOT_FOUND","getActionName","bodyAction","pluginInstance","loadPlugin","actions","listActions","length","BAD_REQUEST","debug","body","startTime","Date","now","params","capability","action","resolvedParams","resolve","formValue","result","loadWithConfig","call","isDebug","output","capabilityConfig","duration","CapabilityNotFoundError","CAPABILITY_NOT_FOUND","error_msg","PluginNotFoundError","PLUGIN_NOT_FOUND","INTERNAL_SERVER_ERROR","ActionNotFoundError","ACTION_NOT_FOUND","EXECUTION_ERROR","Error","String","debugStream","res","setHeader","loggerContext","capability_id","plugin_key","log","input","stringifyForLog","eventStream","callStreamWithEvents","pendingChunk","event","type","response","delta","content","write","JSON","stringify","finished","duration_ms","metadata","aggregated","end","errorMsg","import_common","WebhookController","logger","Logger","name","capabilityService","list","capabilities","listCapabilities","status_code","ErrorCodes","SUCCESS","data","map","c","id","pluginID","pluginKey","pluginVersion","execute","capabilityId","body","result","load","call","action","params","output","error","CapabilityNotFoundError","HttpException","CAPABILITY_NOT_FOUND","error_msg","HttpStatus","NOT_FOUND","PluginNotFoundError","PLUGIN_NOT_FOUND","INTERNAL_SERVER_ERROR","ActionNotFoundError","ACTION_NOT_FOUND","BAD_REQUEST","EXECUTION_ERROR","Error","message","String","executeStream","res","loggerContext","capability_id","setHeader","log","input","stringifyForLog","capability","eventStream","callStreamWithEvents","pendingChunk","event","type","response","delta","content","write","JSON","stringify","finished","duration_ms","metadata","duration","aggregated","end","code","errorMsg","import_common","import_nestjs_common","CAPABILITY_OPTIONS","Symbol","isDevelopment","process","env","NODE_ENV","getControllers","controllers","WebhookController","push","DebugController","CapabilityModule","forRoot","options","module","imports","CommonModule","providers","provide","useValue","CapabilityService","useFactory","requestContextService","httpClient","pluginLoader","templateEngine","moduleOptions","service","capabilitiesDir","setCapabilitiesDir","inject","RequestContextService","PLATFORM_HTTP_CLIENT","PluginLoaderService","TemplateEngineService","exports"]}
package/dist/index.d.cts CHANGED
@@ -12,6 +12,8 @@ interface PluginActionContext {
12
12
  logger: Logger;
13
13
  platformHttpClient: PlatformHttpClient;
14
14
  userContext: UserContext;
15
+ /** 是否为调试模式(来自 debug controller 的调用) */
16
+ isDebug: boolean;
15
17
  }
16
18
 
17
19
  interface JSONSchema {
package/dist/index.d.ts CHANGED
@@ -12,6 +12,8 @@ interface PluginActionContext {
12
12
  logger: Logger;
13
13
  platformHttpClient: PlatformHttpClient;
14
14
  userContext: UserContext;
15
+ /** 是否为调试模式(来自 debug controller 的调用) */
16
+ isDebug: boolean;
15
17
  }
16
18
 
17
19
  interface JSONSchema {
package/dist/index.js CHANGED
@@ -252,7 +252,8 @@ var CapabilityService = class _CapabilityService {
252
252
  this.platformHttpClient = platformHttpClient;
253
253
  this.pluginLoaderService = pluginLoaderService;
254
254
  this.templateEngineService = templateEngineService;
255
- this.capabilitiesDir = path.join(process.cwd(), "server/capabilities");
255
+ const isDev = process.env.NODE_ENV === "development";
256
+ this.capabilitiesDir = path.join(process.cwd(), isDev ? "server/capabilities" : "capabilities");
256
257
  }
257
258
  setCapabilitiesDir(dir) {
258
259
  this.capabilitiesDir = dir;
@@ -461,8 +462,19 @@ var CapabilityService = class _CapabilityService {
461
462
  for await (const event of pluginInstance.runStreamWithEvents(actionName, context, resolvedParams)) {
462
463
  if (event.type === "data") {
463
464
  chunks.push(event.data);
465
+ yield event;
466
+ } else if (event.type === "done") {
467
+ const aggregatedResult2 = pluginInstance.aggregate ? pluginInstance.aggregate(actionName, chunks) : chunks;
468
+ yield {
469
+ type: "done",
470
+ metadata: {
471
+ ...event.metadata,
472
+ aggregated: aggregatedResult2
473
+ }
474
+ };
475
+ } else {
476
+ yield event;
464
477
  }
465
- yield event;
466
478
  }
467
479
  } else {
468
480
  if (isStream && pluginInstance.runStream) {
@@ -481,11 +493,13 @@ var CapabilityService = class _CapabilityService {
481
493
  data: result
482
494
  };
483
495
  }
496
+ const aggregatedResult2 = pluginInstance.aggregate ? pluginInstance.aggregate(actionName, chunks) : chunks;
484
497
  yield {
485
498
  type: "done",
486
499
  metadata: {
487
500
  chunks: chunks.length,
488
- duration: Date.now() - startTime
501
+ duration: Date.now() - startTime,
502
+ aggregated: aggregatedResult2
489
503
  }
490
504
  };
491
505
  }
@@ -514,7 +528,8 @@ var CapabilityService = class _CapabilityService {
514
528
  return {
515
529
  logger: this.logger,
516
530
  platformHttpClient: this.platformHttpClient,
517
- userContext: override?.userContext ?? this.getUserContext()
531
+ userContext: override?.userContext ?? this.getUserContext(),
532
+ isDebug: override?.isDebug ?? false
518
533
  };
519
534
  }
520
535
  getUserContext() {
@@ -628,7 +643,9 @@ var DebugController = class _DebugController {
628
643
  const action = await this.getActionName(config.pluginKey, body.action);
629
644
  const resolvedParams = this.templateEngineService.resolve(config.formValue, params);
630
645
  try {
631
- const result = await this.capabilityService.loadWithConfig(config).call(action, params);
646
+ const result = await this.capabilityService.loadWithConfig(config).call(action, params, {
647
+ isDebug: true
648
+ });
632
649
  return {
633
650
  status_code: ErrorCodes.SUCCESS,
634
651
  data: {
@@ -669,7 +686,6 @@ var DebugController = class _DebugController {
669
686
  }
670
687
  async debugStream(capabilityId, body, res) {
671
688
  const params = body.params ?? {};
672
- const startTime = Date.now();
673
689
  res.setHeader("Content-Type", "text/event-stream");
674
690
  res.setHeader("Cache-Control", "no-cache");
675
691
  res.setHeader("Connection", "keep-alive");
@@ -681,15 +697,18 @@ var DebugController = class _DebugController {
681
697
  plugin_key: config.pluginKey,
682
698
  action
683
699
  };
684
- this.logger.log(`Executing capability (stream), input: ${stringifyForLog(params)}`, loggerContext);
700
+ this.logger.log(`Executing capability (stream)`, {
701
+ ...loggerContext,
702
+ input: stringifyForLog(params)
703
+ });
685
704
  const capability = this.capabilityService.loadWithConfig(config);
686
- const eventStream = capability.callStreamWithEvents(action, params);
705
+ const eventStream = capability.callStreamWithEvents(action, params, {
706
+ isDebug: true
707
+ });
687
708
  let pendingChunk = null;
688
- const allChunks = [];
689
709
  for await (const event of eventStream) {
690
710
  switch (event.type) {
691
711
  case "data": {
692
- allChunks.push(event.data);
693
712
  if (pendingChunk !== null) {
694
713
  const response = {
695
714
  status_code: ErrorCodes.SUCCESS,
@@ -723,7 +742,11 @@ var DebugController = class _DebugController {
723
742
 
724
743
  `);
725
744
  }
726
- this.logger.log(`Capability (stream) executed successfully, duration: ${Date.now() - startTime}ms, chunks: ${allChunks.length}, result: ${stringifyForLog(allChunks)}`, loggerContext);
745
+ this.logger.log(`Capability (stream) executed successfully`, {
746
+ ...loggerContext,
747
+ duration_ms: event.metadata.duration,
748
+ output: stringifyForLog(event.metadata.aggregated)
749
+ });
727
750
  res.end();
728
751
  return;
729
752
  }
@@ -898,7 +921,6 @@ var WebhookController = class _WebhookController {
898
921
  }
899
922
  }
900
923
  async executeStream(capabilityId, body, res) {
901
- const startTime = Date.now();
902
924
  const loggerContext = {
903
925
  capability_id: capabilityId,
904
926
  action: body.action
@@ -907,15 +929,16 @@ var WebhookController = class _WebhookController {
907
929
  res.setHeader("Cache-Control", "no-cache");
908
930
  res.setHeader("Connection", "keep-alive");
909
931
  try {
910
- this.logger.log(`Executing capability (stream), input: ${stringifyForLog(body.params)}`, loggerContext);
932
+ this.logger.log(`Executing capability (stream)`, {
933
+ ...loggerContext,
934
+ input: stringifyForLog(body.params)
935
+ });
911
936
  const capability = this.capabilityService.load(capabilityId);
912
937
  const eventStream = capability.callStreamWithEvents(body.action, body.params);
913
938
  let pendingChunk = null;
914
- const allChunks = [];
915
939
  for await (const event of eventStream) {
916
940
  switch (event.type) {
917
941
  case "data": {
918
- allChunks.push(event.data);
919
942
  if (pendingChunk !== null) {
920
943
  const response = {
921
944
  status_code: ErrorCodes.SUCCESS,
@@ -949,7 +972,11 @@ var WebhookController = class _WebhookController {
949
972
 
950
973
  `);
951
974
  }
952
- this.logger.log(`Capability (stream) executed successfully, duration: ${Date.now() - startTime}ms, chunks: ${allChunks.length}, result: ${stringifyForLog(allChunks)}`, loggerContext);
975
+ this.logger.log(`Capability (stream) executed successfully`, {
976
+ ...loggerContext,
977
+ duration_ms: event.metadata.duration,
978
+ output: stringifyForLog(event.metadata.aggregated)
979
+ });
953
980
  res.end();
954
981
  return;
955
982
  }
@@ -987,7 +1014,6 @@ var WebhookController = class _WebhookController {
987
1014
 
988
1015
  `);
989
1016
  }
990
- this.logger.log(`Capability (stream) executed successfully, duration: ${Date.now() - startTime}ms, chunks: ${allChunks.length}, result: ${stringifyForLog(allChunks)}`, loggerContext);
991
1017
  res.end();
992
1018
  } catch (error) {
993
1019
  const errorMsg = error instanceof Error ? error.message : String(error);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/interfaces/error-codes.ts","../src/services/template-engine.service.ts","../src/services/plugin-loader.service.ts","../src/services/capability.service.ts","../src/utils/log-utils.ts","../src/controllers/debug.controller.ts","../src/controllers/webhook.controller.ts","../src/capability.module.ts"],"sourcesContent":["/**\n * Capability 模块错误码\n */\nexport const ErrorCodes = {\n /** 成功 */\n SUCCESS: '0',\n /** 能力不存在 */\n CAPABILITY_NOT_FOUND: 'k_ec_cap_001',\n /** 插件不存在 */\n PLUGIN_NOT_FOUND: 'k_ec_cap_002',\n /** Action 不存在 */\n ACTION_NOT_FOUND: 'k_ec_cap_003',\n /** 参数验证失败 */\n PARAMS_VALIDATION_ERROR: 'k_ec_cap_004',\n /** 执行失败 */\n EXECUTION_ERROR: 'k_ec_cap_005',\n} as const;\n\nexport type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];\n","import { Injectable } from '@nestjs/common';\n\n/**\n * 模板引擎服务\n *\n * 支持语法:\n * - expr: '{{' + selector + '}}'\n * - selector: 'input.' + ident | selector.ident\n * - ident: [a-zA-Z_]([a-zA-Z_0-9])*\n *\n * 示例:\n * - {{input.a}}\n * - {{input.a.b}}\n * - \"this is {{input.a.b}}\"\n *\n * 求值规则:\n * - 如果整个字符串是单个表达式,保留原始类型\n * - 如果是字符串插值(多个表达式或混合内容),返回字符串\n * - 如果变量不存在,返回原始表达式\n */\n@Injectable()\nexport class TemplateEngineService {\n // 匹配 {{input.xxx}} 或 {{input.xxx.yyy}} 表达式\n private readonly EXPR_REGEX = /\\{\\{input\\.([a-zA-Z_][a-zA-Z_0-9]*(?:\\.[a-zA-Z_][a-zA-Z_0-9]*)*)\\}\\}/g;\n // 匹配整串单个表达式\n private readonly WHOLE_STRING_EXPR_REGEX = /^\\{\\{input\\.([a-zA-Z_][a-zA-Z_0-9]*(?:\\.[a-zA-Z_][a-zA-Z_0-9]*)*)\\}\\}$/;\n\n resolve(template: unknown, input: Record<string, unknown>): unknown {\n if (typeof template === 'string') {\n return this.resolveString(template, input);\n }\n\n if (Array.isArray(template)) {\n return template.map(item => this.resolve(item, input));\n }\n\n if (template !== null && typeof template === 'object') {\n return this.resolveObject(template as Record<string, unknown>, input);\n }\n\n return template;\n }\n\n private resolveString(template: string, input: Record<string, unknown>): unknown {\n // 情况1: 整串是单个表达式 → 保留原始类型\n const wholeMatch = template.match(this.WHOLE_STRING_EXPR_REGEX);\n if (wholeMatch) {\n const path = wholeMatch[1];\n const value = this.getValueByPath(input, path);\n // 变量不存在,返回原始表达式\n return value !== undefined ? value : template;\n }\n\n // 情况2: 字符串插值 → 返回字符串\n // 重置正则的 lastIndex(因为使用了 g 标志)\n this.EXPR_REGEX.lastIndex = 0;\n\n // 检查是否有任何表达式\n if (!this.EXPR_REGEX.test(template)) {\n return template;\n }\n\n // 重置并进行替换\n this.EXPR_REGEX.lastIndex = 0;\n const result = template.replace(this.EXPR_REGEX, (match, path) => {\n const value = this.getValueByPath(input, path);\n // 变量不存在,保留原始表达式\n if (value === undefined) {\n return match;\n }\n return String(value);\n });\n\n return result;\n }\n\n private resolveObject(\n template: Record<string, unknown>,\n input: Record<string, unknown>,\n ): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(template)) {\n result[key] = this.resolve(value, input);\n }\n\n return result;\n }\n\n private getValueByPath(obj: Record<string, unknown>, path: string): unknown {\n const keys = path.split('.');\n let current: unknown = obj;\n\n for (const key of keys) {\n if (current === null || current === undefined) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[key];\n }\n\n return current;\n }\n}\n","import { Injectable, Logger } from '@nestjs/common';\nimport type { PluginInstance, PluginPackage } from '../interfaces';\n\nexport class PluginNotFoundError extends Error {\n constructor(pluginKey: string) {\n super(`Plugin not found: ${pluginKey}`);\n this.name = 'PluginNotFoundError';\n }\n}\n\nexport class PluginLoadError extends Error {\n constructor(pluginKey: string, reason: string) {\n super(`Failed to load plugin ${pluginKey}: ${reason}`);\n this.name = 'PluginLoadError';\n }\n}\n\n@Injectable()\nexport class PluginLoaderService {\n private readonly logger = new Logger(PluginLoaderService.name);\n private readonly pluginInstances = new Map<string, PluginInstance>();\n\n async loadPlugin(pluginKey: string): Promise<PluginInstance> {\n const cached = this.pluginInstances.get(pluginKey);\n if (cached) {\n this.logger.debug(`Using cached plugin instance: ${pluginKey}`);\n return cached;\n }\n\n this.logger.log(`Loading plugin: ${pluginKey}`);\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const pluginPackage = (await import(pluginKey)).default as PluginPackage;\n\n if (typeof pluginPackage.create !== 'function') {\n throw new PluginLoadError(pluginKey, 'Plugin does not export create() function');\n }\n\n const instance = pluginPackage.create();\n this.pluginInstances.set(pluginKey, instance);\n\n this.logger.log(`Plugin loaded successfully: ${pluginKey}`);\n return instance;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'MODULE_NOT_FOUND') {\n throw new PluginNotFoundError(pluginKey);\n }\n throw new PluginLoadError(\n pluginKey,\n error instanceof Error ? error.message : String(error),\n );\n }\n }\n\n isPluginInstalled(pluginKey: string): boolean {\n try {\n require.resolve(pluginKey);\n return true;\n } catch {\n return false;\n }\n }\n\n clearCache(pluginKey?: string): void {\n if (pluginKey) {\n this.pluginInstances.delete(pluginKey);\n this.logger.log(`Cleared cache for plugin: ${pluginKey}`);\n } else {\n this.pluginInstances.clear();\n this.logger.log('Cleared all plugin caches');\n }\n }\n}\n","import { Injectable, Logger, Inject, OnModuleInit } from '@nestjs/common';\nimport {\n RequestContextService,\n PLATFORM_HTTP_CLIENT,\n type PlatformHttpClient,\n} from '@lark-apaas/nestjs-common';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type {\n CapabilityConfig,\n PluginActionContext,\n UserContext,\n StreamEvent,\n} from '../interfaces';\nimport { PluginLoaderService } from './plugin-loader.service';\nimport { TemplateEngineService } from './template-engine.service';\nimport { stringifyForLog } from '../utils';\n\nexport class CapabilityNotFoundError extends Error {\n constructor(capabilityId: string) {\n super(`Capability not found: ${capabilityId}`);\n this.name = 'CapabilityNotFoundError';\n }\n}\n\nexport class ActionNotFoundError extends Error {\n constructor(pluginKey: string, actionName: string) {\n super(`Action '${actionName}' not found in plugin ${pluginKey}`);\n this.name = 'ActionNotFoundError';\n }\n}\n\nexport interface CapabilityExecutor {\n /**\n * 调用 capability(始终返回 Promise)\n * - unary action: 直接返回结果\n * - stream action: 内部聚合所有 chunk 后返回\n */\n call(actionName: string, input: unknown, context?: Partial<PluginActionContext>): Promise<unknown>;\n\n /**\n * 流式调用 capability,返回原始流\n * - 返回原始 AsyncIterable\n * - 如果 action 是 unary,包装为单次 yield\n */\n callStream(actionName: string, input: unknown, context?: Partial<PluginActionContext>): AsyncIterable<unknown>;\n\n /**\n * 流式调用 capability,返回带事件协议的流(推荐)\n * - 返回 StreamEvent 类型的 AsyncIterable\n * - 支持 data/done/error 三种事件类型\n * - Controller 层应优先使用此方法实现边收边发\n */\n callStreamWithEvents(\n actionName: string,\n input: unknown,\n context?: Partial<PluginActionContext>,\n ): AsyncIterable<StreamEvent<unknown>>;\n\n /**\n * 检查 action 是否为流式\n */\n isStream(actionName: string): Promise<boolean>;\n}\n\nexport interface CapabilityModuleOptions {\n capabilitiesDir?: string;\n}\n\n@Injectable()\nexport class CapabilityService implements OnModuleInit {\n private readonly logger = new Logger(CapabilityService.name);\n private readonly capabilities = new Map<string, CapabilityConfig>();\n private capabilitiesDir: string;\n\n constructor(\n private readonly requestContextService: RequestContextService,\n @Inject(PLATFORM_HTTP_CLIENT) private readonly platformHttpClient: PlatformHttpClient,\n private readonly pluginLoaderService: PluginLoaderService,\n private readonly templateEngineService: TemplateEngineService,\n ) {\n this.capabilitiesDir = path.join(process.cwd(), 'server/capabilities');\n }\n\n setCapabilitiesDir(dir: string): void {\n this.capabilitiesDir = dir;\n }\n\n async onModuleInit(): Promise<void> {\n await this.loadCapabilities();\n }\n\n private async loadCapabilities(): Promise<void> {\n this.logger.log(`Loading capabilities from ${this.capabilitiesDir}`);\n\n if (!fs.existsSync(this.capabilitiesDir)) {\n this.logger.warn(`Capabilities directory not found: ${this.capabilitiesDir}`);\n return;\n }\n\n const files = fs.readdirSync(this.capabilitiesDir).filter(f => f.endsWith('.json'));\n\n for (const file of files) {\n try {\n const filePath = path.join(this.capabilitiesDir, file);\n const content = fs.readFileSync(filePath, 'utf-8');\n const config = JSON.parse(content) as CapabilityConfig;\n\n if (!config.id) {\n this.logger.warn(`Skipping capability without id: ${file}`);\n continue;\n }\n\n this.capabilities.set(config.id, config);\n this.logger.log(`Loaded capability: ${config.id} (${config.name})`);\n } catch (error) {\n this.logger.error(`Failed to load capability from ${file}:`, error);\n }\n }\n\n this.logger.log(`Loaded ${this.capabilities.size} capabilities`);\n }\n\n listCapabilities(): CapabilityConfig[] {\n return Array.from(this.capabilities.values());\n }\n\n getCapability(capabilityId: string): CapabilityConfig | null {\n return this.capabilities.get(capabilityId) ?? null;\n }\n\n load(capabilityId: string): CapabilityExecutor {\n const config = this.capabilities.get(capabilityId);\n if (!config) {\n throw new CapabilityNotFoundError(capabilityId);\n }\n\n return this.createExecutor(config);\n }\n\n /**\n * 使用传入的配置加载能力执行器\n * 用于 debug 场景,支持用户传入自定义配置\n */\n loadWithConfig(config: CapabilityConfig): CapabilityExecutor {\n return this.createExecutor(config);\n }\n\n private createExecutor(config: CapabilityConfig): CapabilityExecutor {\n return {\n call: async (\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ) => {\n return this.executeCall(config, actionName, input, contextOverride);\n },\n\n callStream: (\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ) => {\n return this.executeCallStream(config, actionName, input, contextOverride);\n },\n\n callStreamWithEvents: (\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ) => {\n return this.executeCallStreamWithEvents(config, actionName, input, contextOverride);\n },\n\n isStream: async (actionName: string) => {\n return this.checkIsStream(config, actionName);\n },\n };\n }\n\n /**\n * 检查 action 是否为流式\n */\n private async checkIsStream(config: CapabilityConfig, actionName: string): Promise<boolean> {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginKey, actionName);\n }\n\n return pluginInstance.isStreamAction?.(actionName) ?? false;\n }\n\n /**\n * 执行 capability(始终返回 Promise)\n * - unary action: 直接返回结果\n * - stream action: 内部聚合所有 chunk 后返回\n */\n private async executeCall(\n config: CapabilityConfig,\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ): Promise<unknown> {\n const startTime = Date.now();\n const loggerContext = {\n capability_id: config.id,\n plugin_key: config.pluginKey,\n action: actionName,\n };\n try {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginKey, actionName);\n }\n\n // 如果 formValue 不存在,直接使用 input\n const resolvedParams = config.formValue\n ? this.templateEngineService.resolve(config.formValue, input as Record<string, unknown>)\n : input;\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n // 打印入参\n this.logger.log('Executing capability (call)', {\n ...loggerContext,\n is_stream: isStream,\n input: stringifyForLog(input),\n });\n\n let result: unknown;\n\n if (isStream && pluginInstance.runStream) {\n // 流式 action:聚合所有 chunk\n const chunks: unknown[] = [];\n for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {\n chunks.push(chunk);\n }\n // 使用插件的聚合方法,或默认返回 chunks 数组\n result = pluginInstance.aggregate\n ? pluginInstance.aggregate(actionName, chunks)\n : chunks;\n } else {\n // 非流式 action:直接调用\n result = await pluginInstance.run(actionName, context, resolvedParams);\n }\n\n // 打印返回值\n this.logger.log('Capability (call) executed successfully', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n output: stringifyForLog(result),\n });\n\n return result;\n } catch (error) {\n this.logger.error('Capability (call) execution failed', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * 流式执行 capability\n * - stream action: 返回原始 AsyncIterable\n * - unary action: 包装为单次 yield\n */\n private async *executeCallStream(\n config: CapabilityConfig,\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ): AsyncIterable<unknown> {\n const startTime = Date.now();\n const loggerContext = {\n capability_id: config.id,\n plugin_key: config.pluginKey,\n action: actionName,\n };\n const chunks: unknown[] = [];\n try {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginKey, actionName);\n }\n\n // 如果 formValue 不存在,直接使用 input\n const resolvedParams = config.formValue\n ? this.templateEngineService.resolve(config.formValue, input as Record<string, unknown>)\n : input;\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n // 打印入参\n this.logger.log('Executing capability (stream)', {\n ...loggerContext,\n is_stream: isStream,\n input: stringifyForLog(input),\n });\n\n if (isStream && pluginInstance.runStream) {\n // 流式 action:透传 AsyncIterable,同时收集 chunks\n for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {\n chunks.push(chunk);\n yield chunk;\n }\n } else {\n // 非流式 action:包装为单次 yield\n const result = await pluginInstance.run(actionName, context, resolvedParams);\n chunks.push(result);\n yield result;\n }\n\n // 打印聚合结果\n const aggregatedResult = pluginInstance.aggregate\n ? pluginInstance.aggregate(actionName, chunks)\n : chunks;\n this.logger.log('Capability (stream) executed successfully', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n output: stringifyForLog(aggregatedResult),\n });\n } catch (error) {\n this.logger.error('Capability (stream) execution failed', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * 流式执行 capability,返回带事件协议的流\n * - 优先使用 pluginInstance.runStreamWithEvents\n * - 如果插件不支持,则包装 runStream/run 为 StreamEvent\n */\n private async *executeCallStreamWithEvents(\n config: CapabilityConfig,\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ): AsyncIterable<StreamEvent<unknown>> {\n const startTime = Date.now();\n const loggerContext = {\n capability_id: config.id,\n plugin_key: config.pluginKey,\n action: actionName,\n };\n const chunks: unknown[] = [];\n try {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginKey, actionName);\n }\n\n // 如果 formValue 不存在,直接使用 input\n const resolvedParams = config.formValue\n ? this.templateEngineService.resolve(config.formValue, input as Record<string, unknown>)\n : input;\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n // 打印入参\n this.logger.log('Executing capability (streamWithEvents)', {\n ...loggerContext,\n is_stream: isStream,\n input: stringifyForLog(input),\n });\n\n // 优先使用 runStreamWithEvents\n if (pluginInstance.runStreamWithEvents) {\n for await (const event of pluginInstance.runStreamWithEvents(actionName, context, resolvedParams)) {\n // 收集 data 事件的数据用于聚合\n if (event.type === 'data') {\n chunks.push(event.data);\n }\n yield event;\n }\n } else {\n // 回退:包装 runStream 或 run 为 StreamEvent\n if (isStream && pluginInstance.runStream) {\n // 流式 action:包装每个 chunk 为 data 事件\n for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {\n chunks.push(chunk);\n yield { type: 'data', data: chunk };\n }\n } else {\n // 非流式 action:包装结果为单个 data 事件\n const result = await pluginInstance.run(actionName, context, resolvedParams);\n chunks.push(result);\n yield { type: 'data', data: result };\n }\n\n // 发送 done 事件\n yield {\n type: 'done',\n metadata: {\n chunks: chunks.length,\n duration: Date.now() - startTime,\n },\n };\n }\n\n // 打印聚合结果\n const aggregatedResult = pluginInstance.aggregate\n ? pluginInstance.aggregate(actionName, chunks)\n : chunks;\n this.logger.log('Capability (streamWithEvents) executed successfully', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n output: stringifyForLog(aggregatedResult),\n });\n } catch (error) {\n this.logger.error('Capability (streamWithEvents) execution failed', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n\n // 发送 error 事件\n yield {\n type: 'error',\n error: {\n code: 'EXECUTION_ERROR',\n message: error instanceof Error ? error.message : String(error),\n },\n };\n }\n }\n\n private buildActionContext(override?: Partial<PluginActionContext>): PluginActionContext {\n return {\n logger: this.logger,\n platformHttpClient: this.platformHttpClient,\n userContext: override?.userContext ?? this.getUserContext(),\n };\n }\n\n private getUserContext(): UserContext {\n const ctx = this.requestContextService.getContext();\n return {\n appId: ctx?.appId ?? '',\n userId: ctx?.userId ?? '',\n tenantId: ctx?.tenantId ?? '',\n };\n }\n}\n","/**\n * 日志工具函数\n */\n\nconst DEFAULT_MAX_LENGTH = 1000;\n\n/**\n * 截断字符串\n */\nfunction truncateString(str: string, maxLength: number): string {\n if (str.length <= maxLength) {\n return str;\n }\n return str.slice(0, maxLength) + `... [truncated, total ${str.length} chars]`;\n}\n\n/**\n * 将对象转换为可打印的字符串,超过指定长度时截断\n * @param value - 要打印的值\n * @param maxLength - 最大字符数,默认 1000\n */\nexport function stringifyForLog(value: unknown, maxLength: number = DEFAULT_MAX_LENGTH): string {\n try {\n const str = JSON.stringify(value, null, 2);\n return truncateString(str, maxLength);\n } catch {\n // 处理循环引用等情况\n const str = String(value);\n return truncateString(str, maxLength);\n }\n}\n","import {\n Controller,\n Post,\n Get,\n Param,\n Body,\n Res,\n HttpException,\n HttpStatus,\n Logger,\n} from '@nestjs/common';\nimport type { Response } from 'express';\nimport {\n CapabilityService,\n CapabilityNotFoundError,\n ActionNotFoundError,\n} from '../services/capability.service';\nimport { PluginLoaderService, PluginNotFoundError } from '../services/plugin-loader.service';\nimport { TemplateEngineService } from '../services/template-engine.service';\nimport type {\n CapabilityConfig,\n SuccessResponse,\n ErrorResponse,\n DebugExecuteResponseData,\n ListResponseData,\n StreamContentResponse,\n StreamErrorResponse,\n} from '../interfaces';\nimport { ErrorCodes } from '../interfaces';\nimport { stringifyForLog } from '../utils';\n\ninterface DebugRequestBody {\n action?: string;\n params?: Record<string, unknown>;\n capability?: CapabilityConfig;\n}\n\n@Controller('__innerapi__/capability')\nexport class DebugController {\n private readonly logger = new Logger(DebugController.name);\n\n constructor(\n private readonly capabilityService: CapabilityService,\n private readonly pluginLoaderService: PluginLoaderService,\n private readonly templateEngineService: TemplateEngineService,\n ) {}\n\n @Get('list')\n list(): SuccessResponse<ListResponseData> {\n const capabilities = this.capabilityService.listCapabilities();\n\n return {\n status_code: ErrorCodes.SUCCESS,\n data: {\n capabilities: capabilities.map(c => ({\n id: c.id,\n name: c.name,\n pluginID: c.pluginKey,\n pluginVersion: c.pluginVersion,\n })),\n },\n };\n }\n\n /**\n * 获取 capability 配置\n * 优先使用 body.capability,否则从服务获取\n */\n private getCapabilityConfig(\n capabilityId: string,\n bodyCapability?: CapabilityConfig,\n ): CapabilityConfig {\n if (bodyCapability) {\n return bodyCapability;\n }\n\n const config = this.capabilityService.getCapability(capabilityId);\n if (!config) {\n throw new HttpException(\n {\n code: 1,\n message: `Capability not found: ${capabilityId}`,\n error: 'CAPABILITY_NOT_FOUND',\n },\n HttpStatus.NOT_FOUND,\n );\n }\n\n return config;\n }\n\n /**\n * 获取 action 名称\n * 优先使用传入的 action,否则使用插件第一个 action\n */\n private async getActionName(pluginKey: string, bodyAction?: string): Promise<string> {\n if (bodyAction) {\n return bodyAction;\n }\n\n const pluginInstance = await this.pluginLoaderService.loadPlugin(pluginKey);\n const actions = pluginInstance.listActions();\n\n if (actions.length === 0) {\n throw new HttpException(\n {\n code: 1,\n message: `Plugin ${pluginKey} has no actions`,\n error: 'NO_ACTIONS',\n },\n HttpStatus.BAD_REQUEST,\n );\n }\n\n return actions[0];\n }\n\n @Post('debug/:capability_id')\n async debug(\n @Param('capability_id') capabilityId: string,\n @Body() body: DebugRequestBody,\n ): Promise<SuccessResponse<DebugExecuteResponseData> | ErrorResponse> {\n const startTime = Date.now();\n const params = body.params ?? {};\n\n const config = this.getCapabilityConfig(capabilityId, body.capability);\n const action = await this.getActionName(config.pluginKey, body.action);\n\n const resolvedParams = this.templateEngineService.resolve(\n config.formValue,\n params,\n );\n\n try {\n const result = await this.capabilityService\n .loadWithConfig(config)\n .call(action, params);\n\n return {\n status_code: ErrorCodes.SUCCESS,\n data: {\n output: result,\n debug: {\n capabilityConfig: config,\n resolvedParams,\n duration: Date.now() - startTime,\n pluginID: config.pluginKey,\n action,\n },\n },\n };\n } catch (error) {\n if (error instanceof CapabilityNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.CAPABILITY_NOT_FOUND,\n error_msg: `Capability not found: ${capabilityId}`,\n } satisfies ErrorResponse,\n HttpStatus.NOT_FOUND,\n );\n }\n\n if (error instanceof PluginNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.PLUGIN_NOT_FOUND,\n error_msg: `Plugin not found: ${config.pluginKey}`,\n } satisfies ErrorResponse,\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n\n if (error instanceof ActionNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.ACTION_NOT_FOUND,\n error_msg: `Action '${action}' not found in plugin ${config.pluginKey}`,\n } satisfies ErrorResponse,\n HttpStatus.BAD_REQUEST,\n );\n }\n\n throw new HttpException(\n {\n status_code: ErrorCodes.EXECUTION_ERROR,\n error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`,\n } satisfies ErrorResponse,\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n }\n\n @Post('debug/:capability_id/stream')\n async debugStream(\n @Param('capability_id') capabilityId: string,\n @Body() body: DebugRequestBody,\n @Res() res: Response,\n ): Promise<void> {\n const params = body.params ?? {};\n const startTime = Date.now();\n\n // 设置 SSE 响应头\n res.setHeader('Content-Type', 'text/event-stream');\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Connection', 'keep-alive');\n\n try {\n const config = this.getCapabilityConfig(capabilityId, body.capability);\n const action = await this.getActionName(config.pluginKey, body.action);\n const loggerContext = {\n capability_id: config.id,\n plugin_key: config.pluginKey,\n action,\n };\n\n // 打印入参\n this.logger.log(`Executing capability (stream), input: ${stringifyForLog(params)}`, loggerContext);\n\n const capability = this.capabilityService.loadWithConfig(config);\n const eventStream = capability.callStreamWithEvents(action, params);\n\n // 延迟发送策略:缓存上一个 chunk,收到下一个 data 或 done 时再发送\n // 这样可以在最后一个 chunk 上标记 finished: true\n let pendingChunk: unknown | null = null;\n // 收集所有 chunk 用于日志\n const allChunks: unknown[] = [];\n\n for await (const event of eventStream) {\n switch (event.type) {\n case 'data': {\n // 收集 chunk 用于日志\n allChunks.push(event.data);\n // 先发送上一个缓存的 chunk(如果有)\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 缓存当前 chunk\n pendingChunk = event.data;\n break;\n }\n\n case 'done': {\n // 发送最后一个 chunk 并带上 finished: true\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n finished: true,\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 打印聚合结果\n this.logger.log(`Capability (stream) executed successfully, duration: ${Date.now() - startTime}ms, chunks: ${allChunks.length}, result: ${stringifyForLog(allChunks)}`, loggerContext);\n res.end();\n return;\n }\n\n case 'error': {\n // 错误事件:发送错误信息\n const response: StreamErrorResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'error',\n error: {\n code: 0,\n message: event.error.message,\n },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n return;\n }\n }\n }\n\n // 如果事件流正常结束但没有 done 事件,发送缓存的 chunk\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n finished: true,\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n res.end();\n } catch (error) {\n // 流异常中断(在事件流开始前的错误)\n const errorMsg = error instanceof Error ? error.message : String(error);\n const response: StreamErrorResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'error',\n error: {\n code: 0,\n message: errorMsg,\n },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n }\n }\n}\n","import {\n Controller,\n Get,\n Post,\n Param,\n Body,\n Res,\n HttpException,\n HttpStatus,\n Logger,\n} from '@nestjs/common';\nimport type { Response } from 'express';\nimport {\n CapabilityService,\n CapabilityNotFoundError,\n ActionNotFoundError,\n} from '../services/capability.service';\nimport { PluginNotFoundError } from '../services/plugin-loader.service';\nimport type {\n SuccessResponse,\n ErrorResponse,\n ExecuteResponseData,\n ListResponseData,\n StreamContentResponse,\n StreamErrorResponse,\n} from '../interfaces';\nimport { ErrorCodes } from '../interfaces';\nimport { stringifyForLog } from '../utils';\n\ninterface ExecuteRequestBody {\n action: string;\n params: Record<string, unknown>;\n}\n\n@Controller('api/capability')\nexport class WebhookController {\n private readonly logger = new Logger(WebhookController.name);\n\n constructor(private readonly capabilityService: CapabilityService) {}\n\n @Get('list')\n list(): SuccessResponse<ListResponseData> {\n const capabilities = this.capabilityService.listCapabilities();\n return {\n status_code: ErrorCodes.SUCCESS,\n data: {\n capabilities: capabilities.map(c => ({\n id: c.id,\n name: c.name,\n pluginID: c.pluginKey,\n pluginVersion: c.pluginVersion,\n })),\n },\n };\n }\n\n @Post(':capability_id')\n async execute(\n @Param('capability_id') capabilityId: string,\n @Body() body: ExecuteRequestBody,\n ): Promise<SuccessResponse<ExecuteResponseData> | ErrorResponse> {\n try {\n const result = await this.capabilityService\n .load(capabilityId)\n .call(body.action, body.params);\n\n return {\n status_code: ErrorCodes.SUCCESS,\n data: {\n output: result,\n },\n };\n } catch (error) {\n if (error instanceof CapabilityNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.CAPABILITY_NOT_FOUND,\n error_msg: `Capability not found: ${capabilityId}`,\n } satisfies ErrorResponse,\n HttpStatus.NOT_FOUND,\n );\n }\n\n if (error instanceof PluginNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.PLUGIN_NOT_FOUND,\n error_msg: `Plugin not found`,\n } satisfies ErrorResponse,\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n\n if (error instanceof ActionNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.ACTION_NOT_FOUND,\n error_msg: `Action '${body.action}' not found`,\n } satisfies ErrorResponse,\n HttpStatus.BAD_REQUEST,\n );\n }\n\n throw new HttpException(\n {\n status_code: ErrorCodes.EXECUTION_ERROR,\n error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`,\n } satisfies ErrorResponse,\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n }\n\n @Post(':capability_id/stream')\n async executeStream(\n @Param('capability_id') capabilityId: string,\n @Body() body: ExecuteRequestBody,\n @Res() res: Response,\n ): Promise<void> {\n const startTime = Date.now();\n const loggerContext = {\n capability_id: capabilityId,\n action: body.action,\n };\n\n // 设置 SSE 响应头\n res.setHeader('Content-Type', 'text/event-stream');\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Connection', 'keep-alive');\n\n try {\n // 打印入参\n this.logger.log(`Executing capability (stream), input: ${stringifyForLog(body.params)}`, loggerContext);\n\n const capability = this.capabilityService.load(capabilityId);\n const eventStream = capability.callStreamWithEvents(body.action, body.params);\n\n // 延迟发送策略:缓存上一个 chunk,收到下一个 data 或 done 时再发送\n // 这样可以在最后一个 chunk 上标记 finished: true\n let pendingChunk: unknown | null = null;\n // 收集所有 chunk 用于日志\n const allChunks: unknown[] = [];\n\n for await (const event of eventStream) {\n switch (event.type) {\n case 'data': {\n // 收集 chunk 用于日志\n allChunks.push(event.data);\n // 先发送上一个缓存的 chunk(如果有)\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 缓存当前 chunk\n pendingChunk = event.data;\n break;\n }\n\n case 'done': {\n // 发送最后一个 chunk 并带上 finished: true\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n finished: true,\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 打印聚合结果\n this.logger.log(`Capability (stream) executed successfully, duration: ${Date.now() - startTime}ms, chunks: ${allChunks.length}, result: ${stringifyForLog(allChunks)}`, loggerContext);\n res.end();\n return;\n }\n\n case 'error': {\n // 错误事件:发送错误信息\n const response: StreamErrorResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'error',\n error: {\n code: 0,\n message: event.error.message,\n },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n return;\n }\n }\n }\n\n // 如果事件流正常结束但没有 done 事件,发送缓存的 chunk\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n finished: true,\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 打印聚合结果\n this.logger.log(`Capability (stream) executed successfully, duration: ${Date.now() - startTime}ms, chunks: ${allChunks.length}, result: ${stringifyForLog(allChunks)}`, loggerContext);\n res.end();\n } catch (error) {\n // 流异常中断(在事件流开始前的错误)\n const errorMsg = error instanceof Error ? error.message : String(error);\n const response: StreamErrorResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'error',\n error: {\n code: 0,\n message: errorMsg,\n },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n }\n }\n}\n","import { Module, DynamicModule, Type } from '@nestjs/common';\nimport {\n CommonModule,\n RequestContextService,\n PLATFORM_HTTP_CLIENT,\n} from '@lark-apaas/nestjs-common';\nimport { DebugController, WebhookController } from './controllers';\nimport {\n CapabilityService,\n PluginLoaderService,\n TemplateEngineService,\n type CapabilityModuleOptions,\n} from './services';\n\nconst CAPABILITY_OPTIONS = Symbol('CAPABILITY_OPTIONS');\n\nconst isDevelopment = process.env.NODE_ENV === 'development';\n\nfunction getControllers(): Type[] {\n const controllers: Type[] = [WebhookController];\n if (isDevelopment) {\n controllers.push(DebugController);\n }\n return controllers;\n}\n\n@Module({\n imports: [CommonModule],\n controllers: getControllers(),\n providers: [CapabilityService, PluginLoaderService, TemplateEngineService],\n exports: [CapabilityService],\n})\nexport class CapabilityModule {\n static forRoot(options?: CapabilityModuleOptions): DynamicModule {\n return {\n module: CapabilityModule,\n imports: [CommonModule],\n controllers: getControllers(),\n providers: [\n {\n provide: CAPABILITY_OPTIONS,\n useValue: options ?? {},\n },\n {\n provide: CapabilityService,\n useFactory: (\n requestContextService: RequestContextService,\n httpClient: any,\n pluginLoader: PluginLoaderService,\n templateEngine: TemplateEngineService,\n moduleOptions: CapabilityModuleOptions,\n ) => {\n const service = new CapabilityService(\n requestContextService,\n httpClient,\n pluginLoader,\n templateEngine,\n );\n if (moduleOptions?.capabilitiesDir) {\n service.setCapabilitiesDir(moduleOptions.capabilitiesDir);\n }\n return service;\n },\n inject: [\n RequestContextService,\n PLATFORM_HTTP_CLIENT,\n PluginLoaderService,\n TemplateEngineService,\n CAPABILITY_OPTIONS,\n ],\n },\n PluginLoaderService,\n TemplateEngineService,\n ],\n exports: [CapabilityService],\n };\n }\n}\n"],"mappings":"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","names":["ErrorCodes","SUCCESS","CAPABILITY_NOT_FOUND","PLUGIN_NOT_FOUND","ACTION_NOT_FOUND","PARAMS_VALIDATION_ERROR","EXECUTION_ERROR","Injectable","TemplateEngineService","EXPR_REGEX","WHOLE_STRING_EXPR_REGEX","resolve","template","input","resolveString","Array","isArray","map","item","resolveObject","wholeMatch","match","path","value","getValueByPath","undefined","lastIndex","test","result","replace","String","key","Object","entries","obj","keys","split","current","Injectable","Logger","PluginNotFoundError","Error","pluginKey","name","PluginLoadError","reason","PluginLoaderService","logger","Logger","pluginInstances","Map","loadPlugin","cached","get","debug","log","pluginPackage","default","create","instance","set","error","code","message","String","isPluginInstalled","require","resolve","clearCache","delete","clear","Injectable","Logger","Inject","RequestContextService","PLATFORM_HTTP_CLIENT","fs","path","DEFAULT_MAX_LENGTH","truncateString","str","maxLength","length","slice","stringifyForLog","value","JSON","stringify","String","CapabilityNotFoundError","Error","capabilityId","name","ActionNotFoundError","pluginKey","actionName","CapabilityService","logger","Logger","capabilities","Map","capabilitiesDir","requestContextService","platformHttpClient","pluginLoaderService","templateEngineService","join","process","cwd","setCapabilitiesDir","dir","onModuleInit","loadCapabilities","log","existsSync","warn","files","readdirSync","filter","f","endsWith","file","filePath","content","readFileSync","config","JSON","parse","id","set","error","size","listCapabilities","Array","from","values","getCapability","get","load","createExecutor","loadWithConfig","call","input","contextOverride","executeCall","callStream","executeCallStream","callStreamWithEvents","executeCallStreamWithEvents","isStream","checkIsStream","pluginInstance","loadPlugin","hasAction","isStreamAction","startTime","Date","now","loggerContext","capability_id","plugin_key","action","resolvedParams","formValue","resolve","context","buildActionContext","is_stream","stringifyForLog","result","runStream","chunks","chunk","push","aggregate","run","duration_ms","output","message","String","aggregatedResult","runStreamWithEvents","event","type","data","metadata","length","duration","code","override","userContext","getUserContext","ctx","getContext","appId","userId","tenantId","Controller","Post","Get","Param","Body","Res","HttpException","HttpStatus","Logger","DebugController","logger","Logger","name","capabilityService","pluginLoaderService","templateEngineService","list","capabilities","listCapabilities","status_code","ErrorCodes","SUCCESS","data","map","c","id","pluginID","pluginKey","pluginVersion","getCapabilityConfig","capabilityId","bodyCapability","config","getCapability","HttpException","code","message","error","HttpStatus","NOT_FOUND","getActionName","bodyAction","pluginInstance","loadPlugin","actions","listActions","length","BAD_REQUEST","debug","body","startTime","Date","now","params","capability","action","resolvedParams","resolve","formValue","result","loadWithConfig","call","output","capabilityConfig","duration","CapabilityNotFoundError","CAPABILITY_NOT_FOUND","error_msg","PluginNotFoundError","PLUGIN_NOT_FOUND","INTERNAL_SERVER_ERROR","ActionNotFoundError","ACTION_NOT_FOUND","EXECUTION_ERROR","Error","String","debugStream","res","setHeader","loggerContext","capability_id","plugin_key","log","stringifyForLog","eventStream","callStreamWithEvents","pendingChunk","allChunks","event","type","push","response","delta","content","write","JSON","stringify","finished","end","errorMsg","Controller","Get","Post","Param","Body","Res","HttpException","HttpStatus","Logger","WebhookController","logger","Logger","name","capabilityService","list","capabilities","listCapabilities","status_code","ErrorCodes","SUCCESS","data","map","c","id","pluginID","pluginKey","pluginVersion","execute","capabilityId","body","result","load","call","action","params","output","error","CapabilityNotFoundError","HttpException","CAPABILITY_NOT_FOUND","error_msg","HttpStatus","NOT_FOUND","PluginNotFoundError","PLUGIN_NOT_FOUND","INTERNAL_SERVER_ERROR","ActionNotFoundError","ACTION_NOT_FOUND","BAD_REQUEST","EXECUTION_ERROR","Error","message","String","executeStream","res","startTime","Date","now","loggerContext","capability_id","setHeader","log","stringifyForLog","capability","eventStream","callStreamWithEvents","pendingChunk","allChunks","event","type","push","response","delta","content","write","JSON","stringify","finished","length","end","code","errorMsg","Module","CommonModule","RequestContextService","PLATFORM_HTTP_CLIENT","CAPABILITY_OPTIONS","Symbol","isDevelopment","process","env","NODE_ENV","getControllers","controllers","WebhookController","push","DebugController","CapabilityModule","forRoot","options","module","imports","CommonModule","providers","provide","useValue","CapabilityService","useFactory","requestContextService","httpClient","pluginLoader","templateEngine","moduleOptions","service","capabilitiesDir","setCapabilitiesDir","inject","RequestContextService","PLATFORM_HTTP_CLIENT","PluginLoaderService","TemplateEngineService","exports"]}
1
+ {"version":3,"sources":["../src/interfaces/error-codes.ts","../src/services/template-engine.service.ts","../src/services/plugin-loader.service.ts","../src/services/capability.service.ts","../src/utils/log-utils.ts","../src/controllers/debug.controller.ts","../src/controllers/webhook.controller.ts","../src/capability.module.ts"],"sourcesContent":["/**\n * Capability 模块错误码\n */\nexport const ErrorCodes = {\n /** 成功 */\n SUCCESS: '0',\n /** 能力不存在 */\n CAPABILITY_NOT_FOUND: 'k_ec_cap_001',\n /** 插件不存在 */\n PLUGIN_NOT_FOUND: 'k_ec_cap_002',\n /** Action 不存在 */\n ACTION_NOT_FOUND: 'k_ec_cap_003',\n /** 参数验证失败 */\n PARAMS_VALIDATION_ERROR: 'k_ec_cap_004',\n /** 执行失败 */\n EXECUTION_ERROR: 'k_ec_cap_005',\n} as const;\n\nexport type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];\n","import { Injectable } from '@nestjs/common';\n\n/**\n * 模板引擎服务\n *\n * 支持语法:\n * - expr: '{{' + selector + '}}'\n * - selector: 'input.' + ident | selector.ident\n * - ident: [a-zA-Z_]([a-zA-Z_0-9])*\n *\n * 示例:\n * - {{input.a}}\n * - {{input.a.b}}\n * - \"this is {{input.a.b}}\"\n *\n * 求值规则:\n * - 如果整个字符串是单个表达式,保留原始类型\n * - 如果是字符串插值(多个表达式或混合内容),返回字符串\n * - 如果变量不存在,返回原始表达式\n */\n@Injectable()\nexport class TemplateEngineService {\n // 匹配 {{input.xxx}} 或 {{input.xxx.yyy}} 表达式\n private readonly EXPR_REGEX = /\\{\\{input\\.([a-zA-Z_][a-zA-Z_0-9]*(?:\\.[a-zA-Z_][a-zA-Z_0-9]*)*)\\}\\}/g;\n // 匹配整串单个表达式\n private readonly WHOLE_STRING_EXPR_REGEX = /^\\{\\{input\\.([a-zA-Z_][a-zA-Z_0-9]*(?:\\.[a-zA-Z_][a-zA-Z_0-9]*)*)\\}\\}$/;\n\n resolve(template: unknown, input: Record<string, unknown>): unknown {\n if (typeof template === 'string') {\n return this.resolveString(template, input);\n }\n\n if (Array.isArray(template)) {\n return template.map(item => this.resolve(item, input));\n }\n\n if (template !== null && typeof template === 'object') {\n return this.resolveObject(template as Record<string, unknown>, input);\n }\n\n return template;\n }\n\n private resolveString(template: string, input: Record<string, unknown>): unknown {\n // 情况1: 整串是单个表达式 → 保留原始类型\n const wholeMatch = template.match(this.WHOLE_STRING_EXPR_REGEX);\n if (wholeMatch) {\n const path = wholeMatch[1];\n const value = this.getValueByPath(input, path);\n // 变量不存在,返回原始表达式\n return value !== undefined ? value : template;\n }\n\n // 情况2: 字符串插值 → 返回字符串\n // 重置正则的 lastIndex(因为使用了 g 标志)\n this.EXPR_REGEX.lastIndex = 0;\n\n // 检查是否有任何表达式\n if (!this.EXPR_REGEX.test(template)) {\n return template;\n }\n\n // 重置并进行替换\n this.EXPR_REGEX.lastIndex = 0;\n const result = template.replace(this.EXPR_REGEX, (match, path) => {\n const value = this.getValueByPath(input, path);\n // 变量不存在,保留原始表达式\n if (value === undefined) {\n return match;\n }\n return String(value);\n });\n\n return result;\n }\n\n private resolveObject(\n template: Record<string, unknown>,\n input: Record<string, unknown>,\n ): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(template)) {\n result[key] = this.resolve(value, input);\n }\n\n return result;\n }\n\n private getValueByPath(obj: Record<string, unknown>, path: string): unknown {\n const keys = path.split('.');\n let current: unknown = obj;\n\n for (const key of keys) {\n if (current === null || current === undefined) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[key];\n }\n\n return current;\n }\n}\n","import { Injectable, Logger } from '@nestjs/common';\nimport type { PluginInstance, PluginPackage } from '../interfaces';\n\nexport class PluginNotFoundError extends Error {\n constructor(pluginKey: string) {\n super(`Plugin not found: ${pluginKey}`);\n this.name = 'PluginNotFoundError';\n }\n}\n\nexport class PluginLoadError extends Error {\n constructor(pluginKey: string, reason: string) {\n super(`Failed to load plugin ${pluginKey}: ${reason}`);\n this.name = 'PluginLoadError';\n }\n}\n\n@Injectable()\nexport class PluginLoaderService {\n private readonly logger = new Logger(PluginLoaderService.name);\n private readonly pluginInstances = new Map<string, PluginInstance>();\n\n async loadPlugin(pluginKey: string): Promise<PluginInstance> {\n const cached = this.pluginInstances.get(pluginKey);\n if (cached) {\n this.logger.debug(`Using cached plugin instance: ${pluginKey}`);\n return cached;\n }\n\n this.logger.log(`Loading plugin: ${pluginKey}`);\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const pluginPackage = (await import(pluginKey)).default as PluginPackage;\n\n if (typeof pluginPackage.create !== 'function') {\n throw new PluginLoadError(pluginKey, 'Plugin does not export create() function');\n }\n\n const instance = pluginPackage.create();\n this.pluginInstances.set(pluginKey, instance);\n\n this.logger.log(`Plugin loaded successfully: ${pluginKey}`);\n return instance;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'MODULE_NOT_FOUND') {\n throw new PluginNotFoundError(pluginKey);\n }\n throw new PluginLoadError(\n pluginKey,\n error instanceof Error ? error.message : String(error),\n );\n }\n }\n\n isPluginInstalled(pluginKey: string): boolean {\n try {\n require.resolve(pluginKey);\n return true;\n } catch {\n return false;\n }\n }\n\n clearCache(pluginKey?: string): void {\n if (pluginKey) {\n this.pluginInstances.delete(pluginKey);\n this.logger.log(`Cleared cache for plugin: ${pluginKey}`);\n } else {\n this.pluginInstances.clear();\n this.logger.log('Cleared all plugin caches');\n }\n }\n}\n","import { Injectable, Logger, Inject, OnModuleInit } from '@nestjs/common';\nimport {\n RequestContextService,\n PLATFORM_HTTP_CLIENT,\n type PlatformHttpClient,\n} from '@lark-apaas/nestjs-common';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type {\n CapabilityConfig,\n PluginActionContext,\n UserContext,\n StreamEvent,\n} from '../interfaces';\nimport { PluginLoaderService } from './plugin-loader.service';\nimport { TemplateEngineService } from './template-engine.service';\nimport { stringifyForLog } from '../utils';\n\nexport class CapabilityNotFoundError extends Error {\n constructor(capabilityId: string) {\n super(`Capability not found: ${capabilityId}`);\n this.name = 'CapabilityNotFoundError';\n }\n}\n\nexport class ActionNotFoundError extends Error {\n constructor(pluginKey: string, actionName: string) {\n super(`Action '${actionName}' not found in plugin ${pluginKey}`);\n this.name = 'ActionNotFoundError';\n }\n}\n\nexport interface CapabilityExecutor {\n /**\n * 调用 capability(始终返回 Promise)\n * - unary action: 直接返回结果\n * - stream action: 内部聚合所有 chunk 后返回\n */\n call(actionName: string, input: unknown, context?: Partial<PluginActionContext>): Promise<unknown>;\n\n /**\n * 流式调用 capability,返回原始流\n * - 返回原始 AsyncIterable\n * - 如果 action 是 unary,包装为单次 yield\n */\n callStream(actionName: string, input: unknown, context?: Partial<PluginActionContext>): AsyncIterable<unknown>;\n\n /**\n * 流式调用 capability,返回带事件协议的流(推荐)\n * - 返回 StreamEvent 类型的 AsyncIterable\n * - 支持 data/done/error 三种事件类型\n * - Controller 层应优先使用此方法实现边收边发\n */\n callStreamWithEvents(\n actionName: string,\n input: unknown,\n context?: Partial<PluginActionContext>,\n ): AsyncIterable<StreamEvent<unknown>>;\n\n /**\n * 检查 action 是否为流式\n */\n isStream(actionName: string): Promise<boolean>;\n}\n\nexport interface CapabilityModuleOptions {\n capabilitiesDir?: string;\n}\n\n@Injectable()\nexport class CapabilityService implements OnModuleInit {\n private readonly logger = new Logger(CapabilityService.name);\n private readonly capabilities = new Map<string, CapabilityConfig>();\n private capabilitiesDir: string;\n\n constructor(\n private readonly requestContextService: RequestContextService,\n @Inject(PLATFORM_HTTP_CLIENT) private readonly platformHttpClient: PlatformHttpClient,\n private readonly pluginLoaderService: PluginLoaderService,\n private readonly templateEngineService: TemplateEngineService,\n ) {\n const isDev = process.env.NODE_ENV === 'development';\n this.capabilitiesDir = path.join(process.cwd(), isDev ? 'server/capabilities' : 'capabilities');\n }\n\n setCapabilitiesDir(dir: string): void {\n this.capabilitiesDir = dir;\n }\n\n async onModuleInit(): Promise<void> {\n await this.loadCapabilities();\n }\n\n private async loadCapabilities(): Promise<void> {\n this.logger.log(`Loading capabilities from ${this.capabilitiesDir}`);\n\n if (!fs.existsSync(this.capabilitiesDir)) {\n this.logger.warn(`Capabilities directory not found: ${this.capabilitiesDir}`);\n return;\n }\n\n const files = fs.readdirSync(this.capabilitiesDir).filter(f => f.endsWith('.json'));\n\n for (const file of files) {\n try {\n const filePath = path.join(this.capabilitiesDir, file);\n const content = fs.readFileSync(filePath, 'utf-8');\n const config = JSON.parse(content) as CapabilityConfig;\n\n if (!config.id) {\n this.logger.warn(`Skipping capability without id: ${file}`);\n continue;\n }\n\n this.capabilities.set(config.id, config);\n this.logger.log(`Loaded capability: ${config.id} (${config.name})`);\n } catch (error) {\n this.logger.error(`Failed to load capability from ${file}:`, error);\n }\n }\n\n this.logger.log(`Loaded ${this.capabilities.size} capabilities`);\n }\n\n listCapabilities(): CapabilityConfig[] {\n return Array.from(this.capabilities.values());\n }\n\n getCapability(capabilityId: string): CapabilityConfig | null {\n return this.capabilities.get(capabilityId) ?? null;\n }\n\n load(capabilityId: string): CapabilityExecutor {\n const config = this.capabilities.get(capabilityId);\n if (!config) {\n throw new CapabilityNotFoundError(capabilityId);\n }\n\n return this.createExecutor(config);\n }\n\n /**\n * 使用传入的配置加载能力执行器\n * 用于 debug 场景,支持用户传入自定义配置\n */\n loadWithConfig(config: CapabilityConfig): CapabilityExecutor {\n return this.createExecutor(config);\n }\n\n private createExecutor(config: CapabilityConfig): CapabilityExecutor {\n return {\n call: async (\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ) => {\n return this.executeCall(config, actionName, input, contextOverride);\n },\n\n callStream: (\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ) => {\n return this.executeCallStream(config, actionName, input, contextOverride);\n },\n\n callStreamWithEvents: (\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ) => {\n return this.executeCallStreamWithEvents(config, actionName, input, contextOverride);\n },\n\n isStream: async (actionName: string) => {\n return this.checkIsStream(config, actionName);\n },\n };\n }\n\n /**\n * 检查 action 是否为流式\n */\n private async checkIsStream(config: CapabilityConfig, actionName: string): Promise<boolean> {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginKey, actionName);\n }\n\n return pluginInstance.isStreamAction?.(actionName) ?? false;\n }\n\n /**\n * 执行 capability(始终返回 Promise)\n * - unary action: 直接返回结果\n * - stream action: 内部聚合所有 chunk 后返回\n */\n private async executeCall(\n config: CapabilityConfig,\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ): Promise<unknown> {\n const startTime = Date.now();\n const loggerContext = {\n capability_id: config.id,\n plugin_key: config.pluginKey,\n action: actionName,\n };\n try {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginKey, actionName);\n }\n\n // 如果 formValue 不存在,直接使用 input\n const resolvedParams = config.formValue\n ? this.templateEngineService.resolve(config.formValue, input as Record<string, unknown>)\n : input;\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n // 打印入参\n this.logger.log('Executing capability (call)', {\n ...loggerContext,\n is_stream: isStream,\n input: stringifyForLog(input),\n });\n\n let result: unknown;\n\n if (isStream && pluginInstance.runStream) {\n // 流式 action:聚合所有 chunk\n const chunks: unknown[] = [];\n for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {\n chunks.push(chunk);\n }\n // 使用插件的聚合方法,或默认返回 chunks 数组\n result = pluginInstance.aggregate\n ? pluginInstance.aggregate(actionName, chunks)\n : chunks;\n } else {\n // 非流式 action:直接调用\n result = await pluginInstance.run(actionName, context, resolvedParams);\n }\n\n // 打印返回值\n this.logger.log('Capability (call) executed successfully', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n output: stringifyForLog(result),\n });\n\n return result;\n } catch (error) {\n this.logger.error('Capability (call) execution failed', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * 流式执行 capability\n * - stream action: 返回原始 AsyncIterable\n * - unary action: 包装为单次 yield\n */\n private async *executeCallStream(\n config: CapabilityConfig,\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ): AsyncIterable<unknown> {\n const startTime = Date.now();\n const loggerContext = {\n capability_id: config.id,\n plugin_key: config.pluginKey,\n action: actionName,\n };\n const chunks: unknown[] = [];\n try {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginKey, actionName);\n }\n\n // 如果 formValue 不存在,直接使用 input\n const resolvedParams = config.formValue\n ? this.templateEngineService.resolve(config.formValue, input as Record<string, unknown>)\n : input;\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n // 打印入参\n this.logger.log('Executing capability (stream)', {\n ...loggerContext,\n is_stream: isStream,\n input: stringifyForLog(input),\n });\n\n if (isStream && pluginInstance.runStream) {\n // 流式 action:透传 AsyncIterable,同时收集 chunks\n for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {\n chunks.push(chunk);\n yield chunk;\n }\n } else {\n // 非流式 action:包装为单次 yield\n const result = await pluginInstance.run(actionName, context, resolvedParams);\n chunks.push(result);\n yield result;\n }\n\n // 打印聚合结果\n const aggregatedResult = pluginInstance.aggregate\n ? pluginInstance.aggregate(actionName, chunks)\n : chunks;\n this.logger.log('Capability (stream) executed successfully', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n output: stringifyForLog(aggregatedResult),\n });\n } catch (error) {\n this.logger.error('Capability (stream) execution failed', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * 流式执行 capability,返回带事件协议的流\n * - 优先使用 pluginInstance.runStreamWithEvents\n * - 如果插件不支持,则包装 runStream/run 为 StreamEvent\n */\n private async *executeCallStreamWithEvents(\n config: CapabilityConfig,\n actionName: string,\n input: unknown,\n contextOverride?: Partial<PluginActionContext>,\n ): AsyncIterable<StreamEvent<unknown>> {\n const startTime = Date.now();\n const loggerContext = {\n capability_id: config.id,\n plugin_key: config.pluginKey,\n action: actionName,\n };\n const chunks: unknown[] = [];\n try {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginKey, actionName);\n }\n\n // 如果 formValue 不存在,直接使用 input\n const resolvedParams = config.formValue\n ? this.templateEngineService.resolve(config.formValue, input as Record<string, unknown>)\n : input;\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n // 打印入参\n this.logger.log('Executing capability (streamWithEvents)', {\n ...loggerContext,\n is_stream: isStream,\n input: stringifyForLog(input),\n });\n\n // 优先使用 runStreamWithEvents\n if (pluginInstance.runStreamWithEvents) {\n for await (const event of pluginInstance.runStreamWithEvents(actionName, context, resolvedParams)) {\n // 收集 data 事件的数据用于聚合\n if (event.type === 'data') {\n chunks.push(event.data);\n yield event;\n } else if (event.type === 'done') {\n // 拦截 done 事件,添加聚合结果\n const aggregatedResult = pluginInstance.aggregate\n ? pluginInstance.aggregate(actionName, chunks)\n : chunks;\n yield {\n type: 'done',\n metadata: {\n ...event.metadata,\n aggregated: aggregatedResult,\n },\n };\n } else {\n yield event;\n }\n }\n } else {\n // 回退:包装 runStream 或 run 为 StreamEvent\n if (isStream && pluginInstance.runStream) {\n // 流式 action:包装每个 chunk 为 data 事件\n for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {\n chunks.push(chunk);\n yield { type: 'data', data: chunk };\n }\n } else {\n // 非流式 action:包装结果为单个 data 事件\n const result = await pluginInstance.run(actionName, context, resolvedParams);\n chunks.push(result);\n yield { type: 'data', data: result };\n }\n\n // 聚合结果\n const aggregatedResult = pluginInstance.aggregate\n ? pluginInstance.aggregate(actionName, chunks)\n : chunks;\n\n // 发送 done 事件(包含聚合结果)\n yield {\n type: 'done',\n metadata: {\n chunks: chunks.length,\n duration: Date.now() - startTime,\n aggregated: aggregatedResult,\n },\n };\n }\n\n // 打印聚合结果\n const aggregatedResult = pluginInstance.aggregate\n ? pluginInstance.aggregate(actionName, chunks)\n : chunks;\n this.logger.log('Capability (streamWithEvents) executed successfully', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n output: stringifyForLog(aggregatedResult),\n });\n } catch (error) {\n this.logger.error('Capability (streamWithEvents) execution failed', {\n ...loggerContext,\n duration_ms: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n\n // 发送 error 事件\n yield {\n type: 'error',\n error: {\n code: 'EXECUTION_ERROR',\n message: error instanceof Error ? error.message : String(error),\n },\n };\n }\n }\n\n private buildActionContext(override?: Partial<PluginActionContext>): PluginActionContext {\n return {\n logger: this.logger,\n platformHttpClient: this.platformHttpClient,\n userContext: override?.userContext ?? this.getUserContext(),\n isDebug: override?.isDebug ?? false,\n };\n }\n\n private getUserContext(): UserContext {\n const ctx = this.requestContextService.getContext();\n return {\n appId: ctx?.appId ?? '',\n userId: ctx?.userId ?? '',\n tenantId: ctx?.tenantId ?? '',\n };\n }\n}\n","/**\n * 日志工具函数\n */\n\nconst DEFAULT_MAX_LENGTH = 1000;\n\n/**\n * 截断字符串\n */\nfunction truncateString(str: string, maxLength: number): string {\n if (str.length <= maxLength) {\n return str;\n }\n return str.slice(0, maxLength) + `... [truncated, total ${str.length} chars]`;\n}\n\n/**\n * 将对象转换为可打印的字符串,超过指定长度时截断\n * @param value - 要打印的值\n * @param maxLength - 最大字符数,默认 1000\n */\nexport function stringifyForLog(value: unknown, maxLength: number = DEFAULT_MAX_LENGTH): string {\n try {\n const str = JSON.stringify(value, null, 2);\n return truncateString(str, maxLength);\n } catch {\n // 处理循环引用等情况\n const str = String(value);\n return truncateString(str, maxLength);\n }\n}\n","import {\n Controller,\n Post,\n Get,\n Param,\n Body,\n Res,\n HttpException,\n HttpStatus,\n Logger,\n} from '@nestjs/common';\nimport type { Response } from 'express';\nimport {\n CapabilityService,\n CapabilityNotFoundError,\n ActionNotFoundError,\n} from '../services/capability.service';\nimport { PluginLoaderService, PluginNotFoundError } from '../services/plugin-loader.service';\nimport { TemplateEngineService } from '../services/template-engine.service';\nimport type {\n CapabilityConfig,\n SuccessResponse,\n ErrorResponse,\n DebugExecuteResponseData,\n ListResponseData,\n StreamContentResponse,\n StreamErrorResponse,\n} from '../interfaces';\nimport { ErrorCodes } from '../interfaces';\nimport { stringifyForLog } from '../utils';\n\ninterface DebugRequestBody {\n action?: string;\n params?: Record<string, unknown>;\n capability?: CapabilityConfig;\n}\n\n@Controller('__innerapi__/capability')\nexport class DebugController {\n private readonly logger = new Logger(DebugController.name);\n\n constructor(\n private readonly capabilityService: CapabilityService,\n private readonly pluginLoaderService: PluginLoaderService,\n private readonly templateEngineService: TemplateEngineService,\n ) {}\n\n @Get('list')\n list(): SuccessResponse<ListResponseData> {\n const capabilities = this.capabilityService.listCapabilities();\n\n return {\n status_code: ErrorCodes.SUCCESS,\n data: {\n capabilities: capabilities.map(c => ({\n id: c.id,\n name: c.name,\n pluginID: c.pluginKey,\n pluginVersion: c.pluginVersion,\n })),\n },\n };\n }\n\n /**\n * 获取 capability 配置\n * 优先使用 body.capability,否则从服务获取\n */\n private getCapabilityConfig(\n capabilityId: string,\n bodyCapability?: CapabilityConfig,\n ): CapabilityConfig {\n if (bodyCapability) {\n return bodyCapability;\n }\n\n const config = this.capabilityService.getCapability(capabilityId);\n if (!config) {\n throw new HttpException(\n {\n code: 1,\n message: `Capability not found: ${capabilityId}`,\n error: 'CAPABILITY_NOT_FOUND',\n },\n HttpStatus.NOT_FOUND,\n );\n }\n\n return config;\n }\n\n /**\n * 获取 action 名称\n * 优先使用传入的 action,否则使用插件第一个 action\n */\n private async getActionName(pluginKey: string, bodyAction?: string): Promise<string> {\n if (bodyAction) {\n return bodyAction;\n }\n\n const pluginInstance = await this.pluginLoaderService.loadPlugin(pluginKey);\n const actions = pluginInstance.listActions();\n\n if (actions.length === 0) {\n throw new HttpException(\n {\n code: 1,\n message: `Plugin ${pluginKey} has no actions`,\n error: 'NO_ACTIONS',\n },\n HttpStatus.BAD_REQUEST,\n );\n }\n\n return actions[0];\n }\n\n @Post('debug/:capability_id')\n async debug(\n @Param('capability_id') capabilityId: string,\n @Body() body: DebugRequestBody,\n ): Promise<SuccessResponse<DebugExecuteResponseData> | ErrorResponse> {\n const startTime = Date.now();\n const params = body.params ?? {};\n\n const config = this.getCapabilityConfig(capabilityId, body.capability);\n const action = await this.getActionName(config.pluginKey, body.action);\n\n const resolvedParams = this.templateEngineService.resolve(\n config.formValue,\n params,\n );\n\n try {\n const result = await this.capabilityService\n .loadWithConfig(config)\n .call(action, params, { isDebug: true });\n\n return {\n status_code: ErrorCodes.SUCCESS,\n data: {\n output: result,\n debug: {\n capabilityConfig: config,\n resolvedParams,\n duration: Date.now() - startTime,\n pluginID: config.pluginKey,\n action,\n },\n },\n };\n } catch (error) {\n if (error instanceof CapabilityNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.CAPABILITY_NOT_FOUND,\n error_msg: `Capability not found: ${capabilityId}`,\n } satisfies ErrorResponse,\n HttpStatus.NOT_FOUND,\n );\n }\n\n if (error instanceof PluginNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.PLUGIN_NOT_FOUND,\n error_msg: `Plugin not found: ${config.pluginKey}`,\n } satisfies ErrorResponse,\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n\n if (error instanceof ActionNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.ACTION_NOT_FOUND,\n error_msg: `Action '${action}' not found in plugin ${config.pluginKey}`,\n } satisfies ErrorResponse,\n HttpStatus.BAD_REQUEST,\n );\n }\n\n throw new HttpException(\n {\n status_code: ErrorCodes.EXECUTION_ERROR,\n error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`,\n } satisfies ErrorResponse,\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n }\n\n @Post('debug/:capability_id/stream')\n async debugStream(\n @Param('capability_id') capabilityId: string,\n @Body() body: DebugRequestBody,\n @Res() res: Response,\n ): Promise<void> {\n const params = body.params ?? {};\n\n // 设置 SSE 响应头\n res.setHeader('Content-Type', 'text/event-stream');\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Connection', 'keep-alive');\n\n try {\n const config = this.getCapabilityConfig(capabilityId, body.capability);\n const action = await this.getActionName(config.pluginKey, body.action);\n const loggerContext = {\n capability_id: config.id,\n plugin_key: config.pluginKey,\n action,\n };\n\n // 打印入参\n this.logger.log(`Executing capability (stream)`, {\n ...loggerContext,\n input: stringifyForLog(params),\n });\n\n const capability = this.capabilityService.loadWithConfig(config);\n const eventStream = capability.callStreamWithEvents(action, params, { isDebug: true });\n\n // 延迟发送策略:缓存上一个 chunk,收到下一个 data 或 done 时再发送\n // 这样可以在最后一个 chunk 上标记 finished: true\n let pendingChunk: unknown | null = null;\n\n for await (const event of eventStream) {\n switch (event.type) {\n case 'data': {\n // 先发送上一个缓存的 chunk(如果有)\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 缓存当前 chunk\n pendingChunk = event.data;\n break;\n }\n\n case 'done': {\n // 发送最后一个 chunk 并带上 finished: true\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n finished: true,\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 打印聚合结果(从 done 事件的 metadata 中获取)\n this.logger.log(`Capability (stream) executed successfully`, {\n ...loggerContext,\n duration_ms: event.metadata.duration,\n output: stringifyForLog(event.metadata.aggregated),\n });\n res.end();\n return;\n }\n\n case 'error': {\n // 错误事件:发送错误信息\n const response: StreamErrorResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'error',\n error: {\n code: 0,\n message: event.error.message,\n },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n return;\n }\n }\n }\n\n // 如果事件流正常结束但没有 done 事件,发送缓存的 chunk\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n finished: true,\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n res.end();\n } catch (error) {\n // 流异常中断(在事件流开始前的错误)\n const errorMsg = error instanceof Error ? error.message : String(error);\n const response: StreamErrorResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'error',\n error: {\n code: 0,\n message: errorMsg,\n },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n }\n }\n}\n","import {\n Controller,\n Get,\n Post,\n Param,\n Body,\n Res,\n HttpException,\n HttpStatus,\n Logger,\n} from '@nestjs/common';\nimport type { Response } from 'express';\nimport {\n CapabilityService,\n CapabilityNotFoundError,\n ActionNotFoundError,\n} from '../services/capability.service';\nimport { PluginNotFoundError } from '../services/plugin-loader.service';\nimport type {\n SuccessResponse,\n ErrorResponse,\n ExecuteResponseData,\n ListResponseData,\n StreamContentResponse,\n StreamErrorResponse,\n} from '../interfaces';\nimport { ErrorCodes } from '../interfaces';\nimport { stringifyForLog } from '../utils';\n\ninterface ExecuteRequestBody {\n action: string;\n params: Record<string, unknown>;\n}\n\n@Controller('api/capability')\nexport class WebhookController {\n private readonly logger = new Logger(WebhookController.name);\n\n constructor(private readonly capabilityService: CapabilityService) {}\n\n @Get('list')\n list(): SuccessResponse<ListResponseData> {\n const capabilities = this.capabilityService.listCapabilities();\n return {\n status_code: ErrorCodes.SUCCESS,\n data: {\n capabilities: capabilities.map(c => ({\n id: c.id,\n name: c.name,\n pluginID: c.pluginKey,\n pluginVersion: c.pluginVersion,\n })),\n },\n };\n }\n\n @Post(':capability_id')\n async execute(\n @Param('capability_id') capabilityId: string,\n @Body() body: ExecuteRequestBody,\n ): Promise<SuccessResponse<ExecuteResponseData> | ErrorResponse> {\n try {\n const result = await this.capabilityService\n .load(capabilityId)\n .call(body.action, body.params);\n\n return {\n status_code: ErrorCodes.SUCCESS,\n data: {\n output: result,\n },\n };\n } catch (error) {\n if (error instanceof CapabilityNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.CAPABILITY_NOT_FOUND,\n error_msg: `Capability not found: ${capabilityId}`,\n } satisfies ErrorResponse,\n HttpStatus.NOT_FOUND,\n );\n }\n\n if (error instanceof PluginNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.PLUGIN_NOT_FOUND,\n error_msg: `Plugin not found`,\n } satisfies ErrorResponse,\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n\n if (error instanceof ActionNotFoundError) {\n throw new HttpException(\n {\n status_code: ErrorCodes.ACTION_NOT_FOUND,\n error_msg: `Action '${body.action}' not found`,\n } satisfies ErrorResponse,\n HttpStatus.BAD_REQUEST,\n );\n }\n\n throw new HttpException(\n {\n status_code: ErrorCodes.EXECUTION_ERROR,\n error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`,\n } satisfies ErrorResponse,\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n }\n\n @Post(':capability_id/stream')\n async executeStream(\n @Param('capability_id') capabilityId: string,\n @Body() body: ExecuteRequestBody,\n @Res() res: Response,\n ): Promise<void> {\n const loggerContext = {\n capability_id: capabilityId,\n action: body.action,\n };\n\n // 设置 SSE 响应头\n res.setHeader('Content-Type', 'text/event-stream');\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Connection', 'keep-alive');\n\n try {\n // 打印入参\n this.logger.log(`Executing capability (stream)`, {\n ...loggerContext,\n input: stringifyForLog(body.params),\n });\n\n const capability = this.capabilityService.load(capabilityId);\n const eventStream = capability.callStreamWithEvents(body.action, body.params);\n\n // 延迟发送策略:缓存上一个 chunk,收到下一个 data 或 done 时再发送\n // 这样可以在最后一个 chunk 上标记 finished: true\n let pendingChunk: unknown | null = null;\n\n for await (const event of eventStream) {\n switch (event.type) {\n case 'data': {\n // 先发送上一个缓存的 chunk(如果有)\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 缓存当前 chunk\n pendingChunk = event.data;\n break;\n }\n\n case 'done': {\n // 发送最后一个 chunk 并带上 finished: true\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n finished: true,\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n // 打印聚合结果(从 done 事件的 metadata 中获取)\n this.logger.log(`Capability (stream) executed successfully`, {\n ...loggerContext,\n duration_ms: event.metadata.duration,\n output: stringifyForLog(event.metadata.aggregated),\n });\n res.end();\n return;\n }\n\n case 'error': {\n // 错误事件:发送错误信息\n const response: StreamErrorResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'error',\n error: {\n code: 0,\n message: event.error.message,\n },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n return;\n }\n }\n }\n\n // 如果事件流正常结束但没有 done 事件,发送缓存的 chunk\n if (pendingChunk !== null) {\n const response: StreamContentResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'content',\n delta: { content: pendingChunk },\n finished: true,\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n }\n res.end();\n } catch (error) {\n // 流异常中断(在事件流开始前的错误)\n const errorMsg = error instanceof Error ? error.message : String(error);\n const response: StreamErrorResponse = {\n status_code: ErrorCodes.SUCCESS,\n data: {\n type: 'error',\n error: {\n code: 0,\n message: errorMsg,\n },\n },\n };\n res.write(`data: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n }\n }\n}\n","import { Module, DynamicModule, Type } from '@nestjs/common';\nimport {\n CommonModule,\n RequestContextService,\n PLATFORM_HTTP_CLIENT,\n} from '@lark-apaas/nestjs-common';\nimport { DebugController, WebhookController } from './controllers';\nimport {\n CapabilityService,\n PluginLoaderService,\n TemplateEngineService,\n type CapabilityModuleOptions,\n} from './services';\n\nconst CAPABILITY_OPTIONS = Symbol('CAPABILITY_OPTIONS');\n\nconst isDevelopment = process.env.NODE_ENV === 'development';\n\nfunction getControllers(): Type[] {\n const controllers: Type[] = [WebhookController];\n if (isDevelopment) {\n controllers.push(DebugController);\n }\n return controllers;\n}\n\n@Module({\n imports: [CommonModule],\n controllers: getControllers(),\n providers: [CapabilityService, PluginLoaderService, TemplateEngineService],\n exports: [CapabilityService],\n})\nexport class CapabilityModule {\n static forRoot(options?: CapabilityModuleOptions): DynamicModule {\n return {\n module: CapabilityModule,\n imports: [CommonModule],\n controllers: getControllers(),\n providers: [\n {\n provide: CAPABILITY_OPTIONS,\n useValue: options ?? {},\n },\n {\n provide: CapabilityService,\n useFactory: (\n requestContextService: RequestContextService,\n httpClient: any,\n pluginLoader: PluginLoaderService,\n templateEngine: TemplateEngineService,\n moduleOptions: CapabilityModuleOptions,\n ) => {\n const service = new CapabilityService(\n requestContextService,\n httpClient,\n pluginLoader,\n templateEngine,\n );\n if (moduleOptions?.capabilitiesDir) {\n service.setCapabilitiesDir(moduleOptions.capabilitiesDir);\n }\n return service;\n },\n inject: [\n RequestContextService,\n PLATFORM_HTTP_CLIENT,\n PluginLoaderService,\n TemplateEngineService,\n CAPABILITY_OPTIONS,\n ],\n },\n PluginLoaderService,\n TemplateEngineService,\n ],\n exports: [CapabilityService],\n };\n }\n}\n"],"mappings":"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","names":["ErrorCodes","SUCCESS","CAPABILITY_NOT_FOUND","PLUGIN_NOT_FOUND","ACTION_NOT_FOUND","PARAMS_VALIDATION_ERROR","EXECUTION_ERROR","Injectable","TemplateEngineService","EXPR_REGEX","WHOLE_STRING_EXPR_REGEX","resolve","template","input","resolveString","Array","isArray","map","item","resolveObject","wholeMatch","match","path","value","getValueByPath","undefined","lastIndex","test","result","replace","String","key","Object","entries","obj","keys","split","current","Injectable","Logger","PluginNotFoundError","Error","pluginKey","name","PluginLoadError","reason","PluginLoaderService","logger","Logger","pluginInstances","Map","loadPlugin","cached","get","debug","log","pluginPackage","default","create","instance","set","error","code","message","String","isPluginInstalled","require","resolve","clearCache","delete","clear","Injectable","Logger","Inject","RequestContextService","PLATFORM_HTTP_CLIENT","fs","path","DEFAULT_MAX_LENGTH","truncateString","str","maxLength","length","slice","stringifyForLog","value","JSON","stringify","String","CapabilityNotFoundError","Error","capabilityId","name","ActionNotFoundError","pluginKey","actionName","CapabilityService","logger","Logger","capabilities","Map","capabilitiesDir","requestContextService","platformHttpClient","pluginLoaderService","templateEngineService","isDev","process","env","NODE_ENV","join","cwd","setCapabilitiesDir","dir","onModuleInit","loadCapabilities","log","existsSync","warn","files","readdirSync","filter","f","endsWith","file","filePath","content","readFileSync","config","JSON","parse","id","set","error","size","listCapabilities","Array","from","values","getCapability","get","load","createExecutor","loadWithConfig","call","input","contextOverride","executeCall","callStream","executeCallStream","callStreamWithEvents","executeCallStreamWithEvents","isStream","checkIsStream","pluginInstance","loadPlugin","hasAction","isStreamAction","startTime","Date","now","loggerContext","capability_id","plugin_key","action","resolvedParams","formValue","resolve","context","buildActionContext","is_stream","stringifyForLog","result","runStream","chunks","chunk","push","aggregate","run","duration_ms","output","message","String","aggregatedResult","runStreamWithEvents","event","type","data","metadata","aggregated","length","duration","code","override","userContext","getUserContext","isDebug","ctx","getContext","appId","userId","tenantId","Controller","Post","Get","Param","Body","Res","HttpException","HttpStatus","Logger","DebugController","logger","Logger","name","capabilityService","pluginLoaderService","templateEngineService","list","capabilities","listCapabilities","status_code","ErrorCodes","SUCCESS","data","map","c","id","pluginID","pluginKey","pluginVersion","getCapabilityConfig","capabilityId","bodyCapability","config","getCapability","HttpException","code","message","error","HttpStatus","NOT_FOUND","getActionName","bodyAction","pluginInstance","loadPlugin","actions","listActions","length","BAD_REQUEST","debug","body","startTime","Date","now","params","capability","action","resolvedParams","resolve","formValue","result","loadWithConfig","call","isDebug","output","capabilityConfig","duration","CapabilityNotFoundError","CAPABILITY_NOT_FOUND","error_msg","PluginNotFoundError","PLUGIN_NOT_FOUND","INTERNAL_SERVER_ERROR","ActionNotFoundError","ACTION_NOT_FOUND","EXECUTION_ERROR","Error","String","debugStream","res","setHeader","loggerContext","capability_id","plugin_key","log","input","stringifyForLog","eventStream","callStreamWithEvents","pendingChunk","event","type","response","delta","content","write","JSON","stringify","finished","duration_ms","metadata","aggregated","end","errorMsg","Controller","Get","Post","Param","Body","Res","HttpException","HttpStatus","Logger","WebhookController","logger","Logger","name","capabilityService","list","capabilities","listCapabilities","status_code","ErrorCodes","SUCCESS","data","map","c","id","pluginID","pluginKey","pluginVersion","execute","capabilityId","body","result","load","call","action","params","output","error","CapabilityNotFoundError","HttpException","CAPABILITY_NOT_FOUND","error_msg","HttpStatus","NOT_FOUND","PluginNotFoundError","PLUGIN_NOT_FOUND","INTERNAL_SERVER_ERROR","ActionNotFoundError","ACTION_NOT_FOUND","BAD_REQUEST","EXECUTION_ERROR","Error","message","String","executeStream","res","loggerContext","capability_id","setHeader","log","input","stringifyForLog","capability","eventStream","callStreamWithEvents","pendingChunk","event","type","response","delta","content","write","JSON","stringify","finished","duration_ms","metadata","duration","aggregated","end","code","errorMsg","Module","CommonModule","RequestContextService","PLATFORM_HTTP_CLIENT","CAPABILITY_OPTIONS","Symbol","isDevelopment","process","env","NODE_ENV","getControllers","controllers","WebhookController","push","DebugController","CapabilityModule","forRoot","options","module","imports","CommonModule","providers","provide","useValue","CapabilityService","useFactory","requestContextService","httpClient","pluginLoader","templateEngine","moduleOptions","service","capabilitiesDir","setCapabilitiesDir","inject","RequestContextService","PLATFORM_HTTP_CLIENT","PluginLoaderService","TemplateEngineService","exports"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/nestjs-capability",
3
- "version": "0.0.1-alpha.7",
3
+ "version": "0.0.1-alpha.9",
4
4
  "description": "NestJS capability module for FullStack",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",