@lark-apaas/nestjs-capability 0.0.1-alpha.2 → 0.0.1-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +62 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -11
- package/dist/index.d.ts +30 -11
- package/dist/index.js +62 -46
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -57,7 +57,10 @@ var TemplateEngineService = class {
|
|
|
57
57
|
static {
|
|
58
58
|
__name(this, "TemplateEngineService");
|
|
59
59
|
}
|
|
60
|
-
|
|
60
|
+
// 匹配 {{input.xxx}} 或 {{input.xxx.yyy}} 表达式
|
|
61
|
+
EXPR_REGEX = /\{\{input\.([a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*)\}\}/g;
|
|
62
|
+
// 匹配整串单个表达式
|
|
63
|
+
WHOLE_STRING_EXPR_REGEX = /^\{\{input\.([a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*)\}\}$/;
|
|
61
64
|
resolve(template, input) {
|
|
62
65
|
if (typeof template === "string") {
|
|
63
66
|
return this.resolveString(template, input);
|
|
@@ -71,12 +74,25 @@ var TemplateEngineService = class {
|
|
|
71
74
|
return template;
|
|
72
75
|
}
|
|
73
76
|
resolveString(template, input) {
|
|
74
|
-
const
|
|
75
|
-
if (
|
|
77
|
+
const wholeMatch = template.match(this.WHOLE_STRING_EXPR_REGEX);
|
|
78
|
+
if (wholeMatch) {
|
|
79
|
+
const path2 = wholeMatch[1];
|
|
80
|
+
const value = this.getValueByPath(input, path2);
|
|
81
|
+
return value !== void 0 ? value : template;
|
|
82
|
+
}
|
|
83
|
+
this.EXPR_REGEX.lastIndex = 0;
|
|
84
|
+
if (!this.EXPR_REGEX.test(template)) {
|
|
76
85
|
return template;
|
|
77
86
|
}
|
|
78
|
-
|
|
79
|
-
|
|
87
|
+
this.EXPR_REGEX.lastIndex = 0;
|
|
88
|
+
const result = template.replace(this.EXPR_REGEX, (match, path2) => {
|
|
89
|
+
const value = this.getValueByPath(input, path2);
|
|
90
|
+
if (value === void 0) {
|
|
91
|
+
return match;
|
|
92
|
+
}
|
|
93
|
+
return String(value);
|
|
94
|
+
});
|
|
95
|
+
return result;
|
|
80
96
|
}
|
|
81
97
|
resolveObject(template, input) {
|
|
82
98
|
const result = {};
|
|
@@ -114,8 +130,8 @@ var PluginNotFoundError = class extends Error {
|
|
|
114
130
|
static {
|
|
115
131
|
__name(this, "PluginNotFoundError");
|
|
116
132
|
}
|
|
117
|
-
constructor(
|
|
118
|
-
super(`Plugin not found: ${
|
|
133
|
+
constructor(pluginKey) {
|
|
134
|
+
super(`Plugin not found: ${pluginKey}`);
|
|
119
135
|
this.name = "PluginNotFoundError";
|
|
120
136
|
}
|
|
121
137
|
};
|
|
@@ -123,8 +139,8 @@ var PluginLoadError = class extends Error {
|
|
|
123
139
|
static {
|
|
124
140
|
__name(this, "PluginLoadError");
|
|
125
141
|
}
|
|
126
|
-
constructor(
|
|
127
|
-
super(`Failed to load plugin ${
|
|
142
|
+
constructor(pluginKey, reason) {
|
|
143
|
+
super(`Failed to load plugin ${pluginKey}: ${reason}`);
|
|
128
144
|
this.name = "PluginLoadError";
|
|
129
145
|
}
|
|
130
146
|
};
|
|
@@ -134,41 +150,41 @@ var PluginLoaderService = class _PluginLoaderService {
|
|
|
134
150
|
}
|
|
135
151
|
logger = new import_common2.Logger(_PluginLoaderService.name);
|
|
136
152
|
pluginInstances = /* @__PURE__ */ new Map();
|
|
137
|
-
async loadPlugin(
|
|
138
|
-
const cached = this.pluginInstances.get(
|
|
153
|
+
async loadPlugin(pluginKey) {
|
|
154
|
+
const cached = this.pluginInstances.get(pluginKey);
|
|
139
155
|
if (cached) {
|
|
140
|
-
this.logger.debug(`Using cached plugin instance: ${
|
|
156
|
+
this.logger.debug(`Using cached plugin instance: ${pluginKey}`);
|
|
141
157
|
return cached;
|
|
142
158
|
}
|
|
143
|
-
this.logger.log(`Loading plugin: ${
|
|
159
|
+
this.logger.log(`Loading plugin: ${pluginKey}`);
|
|
144
160
|
try {
|
|
145
|
-
const pluginPackage = (await import(
|
|
161
|
+
const pluginPackage = (await import(pluginKey)).default;
|
|
146
162
|
if (typeof pluginPackage.create !== "function") {
|
|
147
|
-
throw new PluginLoadError(
|
|
163
|
+
throw new PluginLoadError(pluginKey, "Plugin does not export create() function");
|
|
148
164
|
}
|
|
149
165
|
const instance = pluginPackage.create();
|
|
150
|
-
this.pluginInstances.set(
|
|
151
|
-
this.logger.log(`Plugin loaded successfully: ${
|
|
166
|
+
this.pluginInstances.set(pluginKey, instance);
|
|
167
|
+
this.logger.log(`Plugin loaded successfully: ${pluginKey}`);
|
|
152
168
|
return instance;
|
|
153
169
|
} catch (error) {
|
|
154
170
|
if (error.code === "MODULE_NOT_FOUND") {
|
|
155
|
-
throw new PluginNotFoundError(
|
|
171
|
+
throw new PluginNotFoundError(pluginKey);
|
|
156
172
|
}
|
|
157
|
-
throw new PluginLoadError(
|
|
173
|
+
throw new PluginLoadError(pluginKey, error instanceof Error ? error.message : String(error));
|
|
158
174
|
}
|
|
159
175
|
}
|
|
160
|
-
isPluginInstalled(
|
|
176
|
+
isPluginInstalled(pluginKey) {
|
|
161
177
|
try {
|
|
162
|
-
require.resolve(
|
|
178
|
+
require.resolve(pluginKey);
|
|
163
179
|
return true;
|
|
164
180
|
} catch {
|
|
165
181
|
return false;
|
|
166
182
|
}
|
|
167
183
|
}
|
|
168
|
-
clearCache(
|
|
169
|
-
if (
|
|
170
|
-
this.pluginInstances.delete(
|
|
171
|
-
this.logger.log(`Cleared cache for plugin: ${
|
|
184
|
+
clearCache(pluginKey) {
|
|
185
|
+
if (pluginKey) {
|
|
186
|
+
this.pluginInstances.delete(pluginKey);
|
|
187
|
+
this.logger.log(`Cleared cache for plugin: ${pluginKey}`);
|
|
172
188
|
} else {
|
|
173
189
|
this.pluginInstances.clear();
|
|
174
190
|
this.logger.log("Cleared all plugin caches");
|
|
@@ -214,8 +230,8 @@ var ActionNotFoundError = class extends Error {
|
|
|
214
230
|
static {
|
|
215
231
|
__name(this, "ActionNotFoundError");
|
|
216
232
|
}
|
|
217
|
-
constructor(
|
|
218
|
-
super(`Action '${actionName}' not found in plugin ${
|
|
233
|
+
constructor(pluginKey, actionName) {
|
|
234
|
+
super(`Action '${actionName}' not found in plugin ${pluginKey}`);
|
|
219
235
|
this.name = "ActionNotFoundError";
|
|
220
236
|
}
|
|
221
237
|
};
|
|
@@ -304,9 +320,9 @@ var CapabilityService = class _CapabilityService {
|
|
|
304
320
|
* 检查 action 是否为流式
|
|
305
321
|
*/
|
|
306
322
|
async checkIsStream(config, actionName) {
|
|
307
|
-
const pluginInstance = await this.pluginLoaderService.loadPlugin(config.
|
|
323
|
+
const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);
|
|
308
324
|
if (!pluginInstance.hasAction(actionName)) {
|
|
309
|
-
throw new ActionNotFoundError(config.
|
|
325
|
+
throw new ActionNotFoundError(config.pluginKey, actionName);
|
|
310
326
|
}
|
|
311
327
|
return pluginInstance.isStreamAction?.(actionName) ?? false;
|
|
312
328
|
}
|
|
@@ -318,9 +334,9 @@ var CapabilityService = class _CapabilityService {
|
|
|
318
334
|
async executeCall(config, actionName, input, contextOverride) {
|
|
319
335
|
const startTime = Date.now();
|
|
320
336
|
try {
|
|
321
|
-
const pluginInstance = await this.pluginLoaderService.loadPlugin(config.
|
|
337
|
+
const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);
|
|
322
338
|
if (!pluginInstance.hasAction(actionName)) {
|
|
323
|
-
throw new ActionNotFoundError(config.
|
|
339
|
+
throw new ActionNotFoundError(config.pluginKey, actionName);
|
|
324
340
|
}
|
|
325
341
|
const resolvedParams = this.templateEngineService.resolve(config.formValue, input);
|
|
326
342
|
const context = this.buildActionContext(contextOverride);
|
|
@@ -329,7 +345,7 @@ var CapabilityService = class _CapabilityService {
|
|
|
329
345
|
message: "Executing capability",
|
|
330
346
|
capabilityId: config.id,
|
|
331
347
|
action: actionName,
|
|
332
|
-
|
|
348
|
+
pluginKey: config.pluginKey,
|
|
333
349
|
isStream
|
|
334
350
|
});
|
|
335
351
|
let result;
|
|
@@ -368,9 +384,9 @@ var CapabilityService = class _CapabilityService {
|
|
|
368
384
|
async *executeCallStream(config, actionName, input, contextOverride) {
|
|
369
385
|
const startTime = Date.now();
|
|
370
386
|
try {
|
|
371
|
-
const pluginInstance = await this.pluginLoaderService.loadPlugin(config.
|
|
387
|
+
const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);
|
|
372
388
|
if (!pluginInstance.hasAction(actionName)) {
|
|
373
|
-
throw new ActionNotFoundError(config.
|
|
389
|
+
throw new ActionNotFoundError(config.pluginKey, actionName);
|
|
374
390
|
}
|
|
375
391
|
const resolvedParams = this.templateEngineService.resolve(config.formValue, input);
|
|
376
392
|
const context = this.buildActionContext(contextOverride);
|
|
@@ -379,7 +395,7 @@ var CapabilityService = class _CapabilityService {
|
|
|
379
395
|
message: "Executing capability (stream)",
|
|
380
396
|
capabilityId: config.id,
|
|
381
397
|
action: actionName,
|
|
382
|
-
|
|
398
|
+
pluginKey: config.pluginKey,
|
|
383
399
|
isStream
|
|
384
400
|
});
|
|
385
401
|
if (isStream && pluginInstance.runStream) {
|
|
@@ -471,7 +487,7 @@ var DebugController = class {
|
|
|
471
487
|
data: capabilities.map((c) => ({
|
|
472
488
|
id: c.id,
|
|
473
489
|
name: c.name,
|
|
474
|
-
|
|
490
|
+
pluginKey: c.pluginKey,
|
|
475
491
|
pluginVersion: c.pluginVersion
|
|
476
492
|
}))
|
|
477
493
|
};
|
|
@@ -498,16 +514,16 @@ var DebugController = class {
|
|
|
498
514
|
* 获取 action 名称
|
|
499
515
|
* 优先使用传入的 action,否则使用插件第一个 action
|
|
500
516
|
*/
|
|
501
|
-
async getActionName(
|
|
517
|
+
async getActionName(pluginKey, bodyAction) {
|
|
502
518
|
if (bodyAction) {
|
|
503
519
|
return bodyAction;
|
|
504
520
|
}
|
|
505
|
-
const pluginInstance = await this.pluginLoaderService.loadPlugin(
|
|
521
|
+
const pluginInstance = await this.pluginLoaderService.loadPlugin(pluginKey);
|
|
506
522
|
const actions = pluginInstance.listActions();
|
|
507
523
|
if (actions.length === 0) {
|
|
508
524
|
throw new import_common4.HttpException({
|
|
509
525
|
code: 1,
|
|
510
|
-
message: `Plugin ${
|
|
526
|
+
message: `Plugin ${pluginKey} has no actions`,
|
|
511
527
|
error: "NO_ACTIONS"
|
|
512
528
|
}, import_common4.HttpStatus.BAD_REQUEST);
|
|
513
529
|
}
|
|
@@ -517,7 +533,7 @@ var DebugController = class {
|
|
|
517
533
|
const startTime = Date.now();
|
|
518
534
|
const params = body.params ?? {};
|
|
519
535
|
const config = this.getCapabilityConfig(capabilityId, body.capability);
|
|
520
|
-
const action = await this.getActionName(config.
|
|
536
|
+
const action = await this.getActionName(config.pluginKey, body.action);
|
|
521
537
|
const resolvedParams = this.templateEngineService.resolve(config.formValue, params);
|
|
522
538
|
try {
|
|
523
539
|
const result = await this.capabilityService.loadWithConfig(config).call(action, params);
|
|
@@ -529,7 +545,7 @@ var DebugController = class {
|
|
|
529
545
|
capabilityConfig: config,
|
|
530
546
|
resolvedParams,
|
|
531
547
|
duration: Date.now() - startTime,
|
|
532
|
-
|
|
548
|
+
pluginKey: config.pluginKey,
|
|
533
549
|
action
|
|
534
550
|
}
|
|
535
551
|
};
|
|
@@ -552,7 +568,7 @@ var DebugController = class {
|
|
|
552
568
|
error: "PLUGIN_NOT_FOUND",
|
|
553
569
|
debug: {
|
|
554
570
|
duration,
|
|
555
|
-
|
|
571
|
+
pluginKey: config.pluginKey,
|
|
556
572
|
action
|
|
557
573
|
}
|
|
558
574
|
}, import_common4.HttpStatus.INTERNAL_SERVER_ERROR);
|
|
@@ -564,7 +580,7 @@ var DebugController = class {
|
|
|
564
580
|
error: "ACTION_NOT_FOUND",
|
|
565
581
|
debug: {
|
|
566
582
|
duration,
|
|
567
|
-
|
|
583
|
+
pluginKey: config.pluginKey,
|
|
568
584
|
action
|
|
569
585
|
}
|
|
570
586
|
}, import_common4.HttpStatus.BAD_REQUEST);
|
|
@@ -575,7 +591,7 @@ var DebugController = class {
|
|
|
575
591
|
error: "EXECUTION_ERROR",
|
|
576
592
|
debug: {
|
|
577
593
|
duration,
|
|
578
|
-
|
|
594
|
+
pluginKey: config.pluginKey,
|
|
579
595
|
action,
|
|
580
596
|
resolvedParams
|
|
581
597
|
}
|
|
@@ -589,7 +605,7 @@ var DebugController = class {
|
|
|
589
605
|
res.setHeader("Connection", "keep-alive");
|
|
590
606
|
try {
|
|
591
607
|
const config = this.getCapabilityConfig(capabilityId, body.capability);
|
|
592
|
-
const action = await this.getActionName(config.
|
|
608
|
+
const action = await this.getActionName(config.pluginKey, body.action);
|
|
593
609
|
const capability = this.capabilityService.loadWithConfig(config);
|
|
594
610
|
const stream = capability.callStream(action, params);
|
|
595
611
|
for await (const chunk of stream) {
|
|
@@ -698,7 +714,7 @@ var WebhookController = class {
|
|
|
698
714
|
id: c.id,
|
|
699
715
|
name: c.name,
|
|
700
716
|
description: c.description,
|
|
701
|
-
|
|
717
|
+
pluginKey: c.pluginKey,
|
|
702
718
|
pluginVersion: c.pluginVersion
|
|
703
719
|
}))
|
|
704
720
|
};
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/services/template-engine.service.ts","../src/services/plugin-loader.service.ts","../src/services/capability.service.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","import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class TemplateEngineService {\n private readonly TEMPLATE_REGEX = /^\\{\\{input\\.(.+)\\}\\}$/;\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 const match = template.match(this.TEMPLATE_REGEX);\n if (!match) {\n return template;\n }\n\n const path = match[1];\n return this.getValueByPath(input, path);\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(pluginID: string) {\n super(`Plugin not found: ${pluginID}`);\n this.name = 'PluginNotFoundError';\n }\n}\n\nexport class PluginLoadError extends Error {\n constructor(pluginID: string, reason: string) {\n super(`Failed to load plugin ${pluginID}: ${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(pluginID: string): Promise<PluginInstance> {\n const cached = this.pluginInstances.get(pluginID);\n if (cached) {\n this.logger.debug(`Using cached plugin instance: ${pluginID}`);\n return cached;\n }\n\n this.logger.log(`Loading plugin: ${pluginID}`);\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const pluginPackage = (await import(pluginID)).default as PluginPackage;\n\n if (typeof pluginPackage.create !== 'function') {\n throw new PluginLoadError(pluginID, 'Plugin does not export create() function');\n }\n\n const instance = pluginPackage.create();\n this.pluginInstances.set(pluginID, instance);\n\n this.logger.log(`Plugin loaded successfully: ${pluginID}`);\n return instance;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'MODULE_NOT_FOUND') {\n throw new PluginNotFoundError(pluginID);\n }\n throw new PluginLoadError(\n pluginID,\n error instanceof Error ? error.message : String(error),\n );\n }\n }\n\n isPluginInstalled(pluginID: string): boolean {\n try {\n require.resolve(pluginID);\n return true;\n } catch {\n return false;\n }\n }\n\n clearCache(pluginID?: string): void {\n if (pluginID) {\n this.pluginInstances.delete(pluginID);\n this.logger.log(`Cleared cache for plugin: ${pluginID}`);\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 { CapabilityConfig, PluginActionContext, UserContext } from '../interfaces';\nimport { PluginLoaderService } from './plugin-loader.service';\nimport { TemplateEngineService } from './template-engine.service';\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(pluginID: string, actionName: string) {\n super(`Action '${actionName}' not found in plugin ${pluginID}`);\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 * 检查 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 httpClient: 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 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.pluginID);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginID, 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\n try {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginID);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginID, actionName);\n }\n\n const resolvedParams = this.templateEngineService.resolve(\n config.formValue,\n input as Record<string, unknown>,\n );\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n this.logger.log({\n message: 'Executing capability',\n capabilityId: config.id,\n action: actionName,\n pluginID: config.pluginID,\n isStream,\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 this.logger.log({\n message: 'Capability executed successfully',\n capabilityId: config.id,\n action: actionName,\n duration: Date.now() - startTime,\n });\n\n return result;\n } catch (error) {\n this.logger.error({\n message: 'Capability execution failed',\n capabilityId: config.id,\n action: actionName,\n error: error instanceof Error ? error.message : String(error),\n duration: Date.now() - startTime,\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\n try {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginID);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginID, actionName);\n }\n\n const resolvedParams = this.templateEngineService.resolve(\n config.formValue,\n input as Record<string, unknown>,\n );\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n this.logger.log({\n message: 'Executing capability (stream)',\n capabilityId: config.id,\n action: actionName,\n pluginID: config.pluginID,\n isStream,\n });\n\n if (isStream && pluginInstance.runStream) {\n // 流式 action:透传 AsyncIterable\n yield* pluginInstance.runStream(actionName, context, resolvedParams);\n } else {\n // 非流式 action:包装为单次 yield\n const result = await pluginInstance.run(actionName, context, resolvedParams);\n yield result;\n }\n\n this.logger.log({\n message: 'Capability stream completed',\n capabilityId: config.id,\n action: actionName,\n duration: Date.now() - startTime,\n });\n } catch (error) {\n this.logger.error({\n message: 'Capability stream execution failed',\n capabilityId: config.id,\n action: actionName,\n error: error instanceof Error ? error.message : String(error),\n duration: Date.now() - startTime,\n });\n throw error;\n }\n }\n\n private buildActionContext(override?: Partial<PluginActionContext>): PluginActionContext {\n return {\n logger: this.logger,\n httpClient: this.httpClient,\n userContext: override?.userContext ?? this.getUserContext(),\n };\n }\n\n private getUserContext(): UserContext {\n const ctx = this.requestContextService.getContext();\n return {\n userId: ctx?.userId ?? '',\n tenantId: ctx?.tenantId ?? '',\n };\n }\n}\n","import {\n Controller,\n Post,\n Get,\n Param,\n Body,\n Res,\n HttpException,\n HttpStatus,\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 { CapabilityConfig } from '../interfaces';\n\ninterface DebugRequestBody {\n action?: string;\n params?: Record<string, unknown>;\n capability?: CapabilityConfig;\n}\n\ninterface DebugResponse {\n code: number;\n message: string;\n data: unknown;\n debug?: {\n capabilityConfig: unknown;\n resolvedParams: unknown;\n duration: number;\n pluginID: string;\n action: string;\n };\n}\n\ninterface ListResponse {\n code: number;\n message: string;\n data: Array<{\n id: string;\n name: string;\n pluginID: string;\n pluginVersion: string;\n }>;\n}\n\n@Controller('__innerapi__/capability')\nexport class DebugController {\n constructor(\n private readonly capabilityService: CapabilityService,\n private readonly pluginLoaderService: PluginLoaderService,\n private readonly templateEngineService: TemplateEngineService,\n ) {}\n\n @Get('list')\n list(): ListResponse {\n const capabilities = this.capabilityService.listCapabilities();\n\n return {\n code: 0,\n message: 'success',\n data: capabilities.map(c => ({\n id: c.id,\n name: c.name,\n pluginID: c.pluginID,\n pluginVersion: c.pluginVersion,\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(pluginID: string, bodyAction?: string): Promise<string> {\n if (bodyAction) {\n return bodyAction;\n }\n\n const pluginInstance = await this.pluginLoaderService.loadPlugin(pluginID);\n const actions = pluginInstance.listActions();\n\n if (actions.length === 0) {\n throw new HttpException(\n {\n code: 1,\n message: `Plugin ${pluginID} 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<DebugResponse> {\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.pluginID, 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 code: 0,\n message: 'success',\n data: result,\n debug: {\n capabilityConfig: config,\n resolvedParams,\n duration: Date.now() - startTime,\n pluginID: config.pluginID,\n action,\n },\n };\n } catch (error) {\n const duration = Date.now() - startTime;\n\n if (error instanceof CapabilityNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'CAPABILITY_NOT_FOUND',\n debug: { duration },\n },\n HttpStatus.NOT_FOUND,\n );\n }\n\n if (error instanceof PluginNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'PLUGIN_NOT_FOUND',\n debug: { duration, pluginID: config.pluginID, action },\n },\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n\n if (error instanceof ActionNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'ACTION_NOT_FOUND',\n debug: { duration, pluginID: config.pluginID, action },\n },\n HttpStatus.BAD_REQUEST,\n );\n }\n\n throw new HttpException(\n {\n code: 1,\n message: error instanceof Error ? error.message : String(error),\n error: 'EXECUTION_ERROR',\n debug: {\n duration,\n pluginID: config.pluginID,\n action,\n resolvedParams,\n },\n },\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.pluginID, body.action);\n\n const capability = this.capabilityService.loadWithConfig(config);\n const stream = capability.callStream(action, params);\n\n for await (const chunk of stream) {\n res.write(`data: ${JSON.stringify(chunk)}\\n\\n`);\n }\n\n // 发送结束标记\n res.write('data: [DONE]\\n\\n');\n } catch (error) {\n // 错误时发送错误信息\n const message = error instanceof Error ? error.message : String(error);\n let errorCode = 'EXECUTION_ERROR';\n\n if (error instanceof CapabilityNotFoundError) {\n errorCode = 'CAPABILITY_NOT_FOUND';\n } else if (error instanceof PluginNotFoundError) {\n errorCode = 'PLUGIN_NOT_FOUND';\n } else if (error instanceof ActionNotFoundError) {\n errorCode = 'ACTION_NOT_FOUND';\n } else if (error instanceof HttpException) {\n const response = error.getResponse() as { error?: string };\n errorCode = response.error ?? 'EXECUTION_ERROR';\n }\n\n res.write(`data: ${JSON.stringify({ error: message, code: errorCode })}\\n\\n`);\n } finally {\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} 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';\n\ninterface ExecuteRequestBody {\n action: string;\n params: Record<string, unknown>;\n}\n\ninterface ExecuteResponse {\n code: number;\n message: string;\n data: unknown;\n}\n\ninterface CapabilityInfo {\n id: string;\n name: string;\n description: string;\n pluginID: string;\n pluginVersion: string;\n}\n\ninterface ListResponse {\n code: number;\n message: string;\n data: CapabilityInfo[];\n}\n\n@Controller('api/capability')\nexport class WebhookController {\n constructor(private readonly capabilityService: CapabilityService) {}\n\n @Get('list')\n list(): ListResponse {\n const capabilities = this.capabilityService.listCapabilities();\n return {\n code: 0,\n message: 'success',\n data: capabilities.map(c => ({\n id: c.id,\n name: c.name,\n description: c.description,\n pluginID: c.pluginID,\n pluginVersion: c.pluginVersion,\n })),\n };\n }\n\n @Post(':capability_id')\n async execute(\n @Param('capability_id') capabilityId: string,\n @Body() body: ExecuteRequestBody,\n ): Promise<ExecuteResponse> {\n try {\n const result = await this.capabilityService\n .load(capabilityId)\n .call(body.action, body.params);\n\n return {\n code: 0,\n message: 'success',\n data: result,\n };\n } catch (error) {\n if (error instanceof CapabilityNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'CAPABILITY_NOT_FOUND',\n },\n HttpStatus.NOT_FOUND,\n );\n }\n\n if (error instanceof PluginNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'PLUGIN_NOT_FOUND',\n },\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n\n if (error instanceof ActionNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'ACTION_NOT_FOUND',\n },\n HttpStatus.BAD_REQUEST,\n );\n }\n\n throw new HttpException(\n {\n code: 1,\n message: error instanceof Error ? error.message : String(error),\n error: 'EXECUTION_ERROR',\n },\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 // 设置 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 capability = this.capabilityService.load(capabilityId);\n const stream = capability.callStream(body.action, body.params);\n\n for await (const chunk of stream) {\n res.write(`data: ${JSON.stringify(chunk)}\\n\\n`);\n }\n\n // 发送结束标记\n res.write('data: [DONE]\\n\\n');\n } catch (error) {\n // 错误时发送错误信息\n const message = error instanceof Error ? error.message : String(error);\n let errorCode = 'EXECUTION_ERROR';\n\n if (error instanceof CapabilityNotFoundError) {\n errorCode = 'CAPABILITY_NOT_FOUND';\n } else if (error instanceof PluginNotFoundError) {\n errorCode = 'PLUGIN_NOT_FOUND';\n } else if (error instanceof ActionNotFoundError) {\n errorCode = 'ACTION_NOT_FOUND';\n }\n\n res.write(`data: ${JSON.stringify({ error: message, code: errorCode })}\\n\\n`);\n } finally {\n res.end();\n }\n }\n}\n","import { Module, DynamicModule, Type } from '@nestjs/common';\nimport {\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 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 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":["TemplateEngineService","TEMPLATE_REGEX","resolve","template","input","resolveString","Array","isArray","map","item","resolveObject","match","path","getValueByPath","result","key","value","Object","entries","obj","keys","split","current","undefined","import_common","PluginNotFoundError","Error","pluginID","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","CapabilityNotFoundError","Error","capabilityId","name","ActionNotFoundError","pluginID","actionName","CapabilityService","logger","Logger","capabilities","Map","capabilitiesDir","requestContextService","httpClient","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","isStream","checkIsStream","pluginInstance","loadPlugin","hasAction","isStreamAction","startTime","Date","now","resolvedParams","resolve","formValue","context","buildActionContext","message","action","result","runStream","chunks","chunk","push","aggregate","run","duration","String","override","userContext","getUserContext","ctx","getContext","userId","tenantId","import_common","DebugController","capabilityService","pluginLoaderService","templateEngineService","list","capabilities","listCapabilities","code","message","data","map","c","id","name","pluginID","pluginVersion","getCapabilityConfig","capabilityId","bodyCapability","config","getCapability","HttpException","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","capabilityConfig","duration","CapabilityNotFoundError","PluginNotFoundError","INTERNAL_SERVER_ERROR","ActionNotFoundError","Error","String","debugStream","res","setHeader","stream","callStream","chunk","write","JSON","stringify","errorCode","response","getResponse","end","import_common","WebhookController","capabilityService","list","capabilities","listCapabilities","code","message","data","map","c","id","name","description","pluginID","pluginVersion","execute","capabilityId","body","result","load","call","action","params","error","CapabilityNotFoundError","HttpException","HttpStatus","NOT_FOUND","PluginNotFoundError","INTERNAL_SERVER_ERROR","ActionNotFoundError","BAD_REQUEST","Error","String","executeStream","res","setHeader","capability","stream","callStream","chunk","write","JSON","stringify","errorCode","end","import_common","import_nestjs_common","CAPABILITY_OPTIONS","Symbol","isDevelopment","process","env","NODE_ENV","getControllers","controllers","WebhookController","push","DebugController","CapabilityModule","forRoot","options","module","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/services/template-engine.service.ts","../src/services/plugin-loader.service.ts","../src/services/capability.service.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","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 { CapabilityConfig, PluginActionContext, UserContext } from '../interfaces';\nimport { PluginLoaderService } from './plugin-loader.service';\nimport { TemplateEngineService } from './template-engine.service';\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 * 检查 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 httpClient: 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 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\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 const resolvedParams = this.templateEngineService.resolve(\n config.formValue,\n input as Record<string, unknown>,\n );\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n this.logger.log({\n message: 'Executing capability',\n capabilityId: config.id,\n action: actionName,\n pluginKey: config.pluginKey,\n isStream,\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 this.logger.log({\n message: 'Capability executed successfully',\n capabilityId: config.id,\n action: actionName,\n duration: Date.now() - startTime,\n });\n\n return result;\n } catch (error) {\n this.logger.error({\n message: 'Capability execution failed',\n capabilityId: config.id,\n action: actionName,\n error: error instanceof Error ? error.message : String(error),\n duration: Date.now() - startTime,\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\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 const resolvedParams = this.templateEngineService.resolve(\n config.formValue,\n input as Record<string, unknown>,\n );\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n this.logger.log({\n message: 'Executing capability (stream)',\n capabilityId: config.id,\n action: actionName,\n pluginKey: config.pluginKey,\n isStream,\n });\n\n if (isStream && pluginInstance.runStream) {\n // 流式 action:透传 AsyncIterable\n yield* pluginInstance.runStream(actionName, context, resolvedParams);\n } else {\n // 非流式 action:包装为单次 yield\n const result = await pluginInstance.run(actionName, context, resolvedParams);\n yield result;\n }\n\n this.logger.log({\n message: 'Capability stream completed',\n capabilityId: config.id,\n action: actionName,\n duration: Date.now() - startTime,\n });\n } catch (error) {\n this.logger.error({\n message: 'Capability stream execution failed',\n capabilityId: config.id,\n action: actionName,\n error: error instanceof Error ? error.message : String(error),\n duration: Date.now() - startTime,\n });\n throw error;\n }\n }\n\n private buildActionContext(override?: Partial<PluginActionContext>): PluginActionContext {\n return {\n logger: this.logger,\n httpClient: this.httpClient,\n userContext: override?.userContext ?? this.getUserContext(),\n };\n }\n\n private getUserContext(): UserContext {\n const ctx = this.requestContextService.getContext();\n return {\n userId: ctx?.userId ?? '',\n tenantId: ctx?.tenantId ?? '',\n };\n }\n}\n","import {\n Controller,\n Post,\n Get,\n Param,\n Body,\n Res,\n HttpException,\n HttpStatus,\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 { CapabilityConfig } from '../interfaces';\n\ninterface DebugRequestBody {\n action?: string;\n params?: Record<string, unknown>;\n capability?: CapabilityConfig;\n}\n\ninterface DebugResponse {\n code: number;\n message: string;\n data: unknown;\n debug?: {\n capabilityConfig: unknown;\n resolvedParams: unknown;\n duration: number;\n pluginKey: string;\n action: string;\n };\n}\n\ninterface ListResponse {\n code: number;\n message: string;\n data: Array<{\n id: string;\n name: string;\n pluginKey: string;\n pluginVersion: string;\n }>;\n}\n\n@Controller('__innerapi__/capability')\nexport class DebugController {\n constructor(\n private readonly capabilityService: CapabilityService,\n private readonly pluginLoaderService: PluginLoaderService,\n private readonly templateEngineService: TemplateEngineService,\n ) {}\n\n @Get('list')\n list(): ListResponse {\n const capabilities = this.capabilityService.listCapabilities();\n\n return {\n code: 0,\n message: 'success',\n data: capabilities.map(c => ({\n id: c.id,\n name: c.name,\n pluginKey: c.pluginKey,\n pluginVersion: c.pluginVersion,\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<DebugResponse> {\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 code: 0,\n message: 'success',\n data: result,\n debug: {\n capabilityConfig: config,\n resolvedParams,\n duration: Date.now() - startTime,\n pluginKey: config.pluginKey,\n action,\n },\n };\n } catch (error) {\n const duration = Date.now() - startTime;\n\n if (error instanceof CapabilityNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'CAPABILITY_NOT_FOUND',\n debug: { duration },\n },\n HttpStatus.NOT_FOUND,\n );\n }\n\n if (error instanceof PluginNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'PLUGIN_NOT_FOUND',\n debug: { duration, pluginKey: config.pluginKey, action },\n },\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n\n if (error instanceof ActionNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'ACTION_NOT_FOUND',\n debug: { duration, pluginKey: config.pluginKey, action },\n },\n HttpStatus.BAD_REQUEST,\n );\n }\n\n throw new HttpException(\n {\n code: 1,\n message: error instanceof Error ? error.message : String(error),\n error: 'EXECUTION_ERROR',\n debug: {\n duration,\n pluginKey: config.pluginKey,\n action,\n resolvedParams,\n },\n },\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\n const capability = this.capabilityService.loadWithConfig(config);\n const stream = capability.callStream(action, params);\n\n for await (const chunk of stream) {\n res.write(`data: ${JSON.stringify(chunk)}\\n\\n`);\n }\n\n // 发送结束标记\n res.write('data: [DONE]\\n\\n');\n } catch (error) {\n // 错误时发送错误信息\n const message = error instanceof Error ? error.message : String(error);\n let errorCode = 'EXECUTION_ERROR';\n\n if (error instanceof CapabilityNotFoundError) {\n errorCode = 'CAPABILITY_NOT_FOUND';\n } else if (error instanceof PluginNotFoundError) {\n errorCode = 'PLUGIN_NOT_FOUND';\n } else if (error instanceof ActionNotFoundError) {\n errorCode = 'ACTION_NOT_FOUND';\n } else if (error instanceof HttpException) {\n const response = error.getResponse() as { error?: string };\n errorCode = response.error ?? 'EXECUTION_ERROR';\n }\n\n res.write(`data: ${JSON.stringify({ error: message, code: errorCode })}\\n\\n`);\n } finally {\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} 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';\n\ninterface ExecuteRequestBody {\n action: string;\n params: Record<string, unknown>;\n}\n\ninterface ExecuteResponse {\n code: number;\n message: string;\n data: unknown;\n}\n\ninterface CapabilityInfo {\n id: string;\n name: string;\n description: string;\n pluginKey: string;\n pluginVersion: string;\n}\n\ninterface ListResponse {\n code: number;\n message: string;\n data: CapabilityInfo[];\n}\n\n@Controller('api/capability')\nexport class WebhookController {\n constructor(private readonly capabilityService: CapabilityService) {}\n\n @Get('list')\n list(): ListResponse {\n const capabilities = this.capabilityService.listCapabilities();\n return {\n code: 0,\n message: 'success',\n data: capabilities.map(c => ({\n id: c.id,\n name: c.name,\n description: c.description,\n pluginKey: c.pluginKey,\n pluginVersion: c.pluginVersion,\n })),\n };\n }\n\n @Post(':capability_id')\n async execute(\n @Param('capability_id') capabilityId: string,\n @Body() body: ExecuteRequestBody,\n ): Promise<ExecuteResponse> {\n try {\n const result = await this.capabilityService\n .load(capabilityId)\n .call(body.action, body.params);\n\n return {\n code: 0,\n message: 'success',\n data: result,\n };\n } catch (error) {\n if (error instanceof CapabilityNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'CAPABILITY_NOT_FOUND',\n },\n HttpStatus.NOT_FOUND,\n );\n }\n\n if (error instanceof PluginNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'PLUGIN_NOT_FOUND',\n },\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n\n if (error instanceof ActionNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'ACTION_NOT_FOUND',\n },\n HttpStatus.BAD_REQUEST,\n );\n }\n\n throw new HttpException(\n {\n code: 1,\n message: error instanceof Error ? error.message : String(error),\n error: 'EXECUTION_ERROR',\n },\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 // 设置 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 capability = this.capabilityService.load(capabilityId);\n const stream = capability.callStream(body.action, body.params);\n\n for await (const chunk of stream) {\n res.write(`data: ${JSON.stringify(chunk)}\\n\\n`);\n }\n\n // 发送结束标记\n res.write('data: [DONE]\\n\\n');\n } catch (error) {\n // 错误时发送错误信息\n const message = error instanceof Error ? error.message : String(error);\n let errorCode = 'EXECUTION_ERROR';\n\n if (error instanceof CapabilityNotFoundError) {\n errorCode = 'CAPABILITY_NOT_FOUND';\n } else if (error instanceof PluginNotFoundError) {\n errorCode = 'PLUGIN_NOT_FOUND';\n } else if (error instanceof ActionNotFoundError) {\n errorCode = 'ACTION_NOT_FOUND';\n }\n\n res.write(`data: ${JSON.stringify({ error: message, code: errorCode })}\\n\\n`);\n } finally {\n res.end();\n }\n }\n}\n","import { Module, DynamicModule, Type } from '@nestjs/common';\nimport {\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 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 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":["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","CapabilityNotFoundError","Error","capabilityId","name","ActionNotFoundError","pluginKey","actionName","CapabilityService","logger","Logger","capabilities","Map","capabilitiesDir","requestContextService","httpClient","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","isStream","checkIsStream","pluginInstance","loadPlugin","hasAction","isStreamAction","startTime","Date","now","resolvedParams","resolve","formValue","context","buildActionContext","message","action","result","runStream","chunks","chunk","push","aggregate","run","duration","String","override","userContext","getUserContext","ctx","getContext","userId","tenantId","import_common","DebugController","capabilityService","pluginLoaderService","templateEngineService","list","capabilities","listCapabilities","code","message","data","map","c","id","name","pluginKey","pluginVersion","getCapabilityConfig","capabilityId","bodyCapability","config","getCapability","HttpException","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","capabilityConfig","duration","CapabilityNotFoundError","PluginNotFoundError","INTERNAL_SERVER_ERROR","ActionNotFoundError","Error","String","debugStream","res","setHeader","stream","callStream","chunk","write","JSON","stringify","errorCode","response","getResponse","end","import_common","WebhookController","capabilityService","list","capabilities","listCapabilities","code","message","data","map","c","id","name","description","pluginKey","pluginVersion","execute","capabilityId","body","result","load","call","action","params","error","CapabilityNotFoundError","HttpException","HttpStatus","NOT_FOUND","PluginNotFoundError","INTERNAL_SERVER_ERROR","ActionNotFoundError","BAD_REQUEST","Error","String","executeStream","res","setHeader","capability","stream","callStream","chunk","write","JSON","stringify","errorCode","end","import_common","import_nestjs_common","CAPABILITY_OPTIONS","Symbol","isDevelopment","process","env","NODE_ENV","getControllers","controllers","WebhookController","push","DebugController","CapabilityModule","forRoot","options","module","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
|
@@ -50,7 +50,7 @@ interface JSONSchema {
|
|
|
50
50
|
}
|
|
51
51
|
interface CapabilityConfig {
|
|
52
52
|
id: string;
|
|
53
|
-
|
|
53
|
+
pluginKey: string;
|
|
54
54
|
pluginVersion: string;
|
|
55
55
|
name: string;
|
|
56
56
|
description: string;
|
|
@@ -60,8 +60,27 @@ interface CapabilityConfig {
|
|
|
60
60
|
updatedAt: number;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* 模板引擎服务
|
|
65
|
+
*
|
|
66
|
+
* 支持语法:
|
|
67
|
+
* - expr: '{{' + selector + '}}'
|
|
68
|
+
* - selector: 'input.' + ident | selector.ident
|
|
69
|
+
* - ident: [a-zA-Z_]([a-zA-Z_0-9])*
|
|
70
|
+
*
|
|
71
|
+
* 示例:
|
|
72
|
+
* - {{input.a}}
|
|
73
|
+
* - {{input.a.b}}
|
|
74
|
+
* - "this is {{input.a.b}}"
|
|
75
|
+
*
|
|
76
|
+
* 求值规则:
|
|
77
|
+
* - 如果整个字符串是单个表达式,保留原始类型
|
|
78
|
+
* - 如果是字符串插值(多个表达式或混合内容),返回字符串
|
|
79
|
+
* - 如果变量不存在,返回原始表达式
|
|
80
|
+
*/
|
|
63
81
|
declare class TemplateEngineService {
|
|
64
|
-
private readonly
|
|
82
|
+
private readonly EXPR_REGEX;
|
|
83
|
+
private readonly WHOLE_STRING_EXPR_REGEX;
|
|
65
84
|
resolve(template: unknown, input: Record<string, unknown>): unknown;
|
|
66
85
|
private resolveString;
|
|
67
86
|
private resolveObject;
|
|
@@ -69,24 +88,24 @@ declare class TemplateEngineService {
|
|
|
69
88
|
}
|
|
70
89
|
|
|
71
90
|
declare class PluginNotFoundError extends Error {
|
|
72
|
-
constructor(
|
|
91
|
+
constructor(pluginKey: string);
|
|
73
92
|
}
|
|
74
93
|
declare class PluginLoadError extends Error {
|
|
75
|
-
constructor(
|
|
94
|
+
constructor(pluginKey: string, reason: string);
|
|
76
95
|
}
|
|
77
96
|
declare class PluginLoaderService {
|
|
78
97
|
private readonly logger;
|
|
79
98
|
private readonly pluginInstances;
|
|
80
|
-
loadPlugin(
|
|
81
|
-
isPluginInstalled(
|
|
82
|
-
clearCache(
|
|
99
|
+
loadPlugin(pluginKey: string): Promise<PluginInstance>;
|
|
100
|
+
isPluginInstalled(pluginKey: string): boolean;
|
|
101
|
+
clearCache(pluginKey?: string): void;
|
|
83
102
|
}
|
|
84
103
|
|
|
85
104
|
declare class CapabilityNotFoundError extends Error {
|
|
86
105
|
constructor(capabilityId: string);
|
|
87
106
|
}
|
|
88
107
|
declare class ActionNotFoundError extends Error {
|
|
89
|
-
constructor(
|
|
108
|
+
constructor(pluginKey: string, actionName: string);
|
|
90
109
|
}
|
|
91
110
|
interface CapabilityExecutor {
|
|
92
111
|
/**
|
|
@@ -163,7 +182,7 @@ interface DebugResponse {
|
|
|
163
182
|
capabilityConfig: unknown;
|
|
164
183
|
resolvedParams: unknown;
|
|
165
184
|
duration: number;
|
|
166
|
-
|
|
185
|
+
pluginKey: string;
|
|
167
186
|
action: string;
|
|
168
187
|
};
|
|
169
188
|
}
|
|
@@ -173,7 +192,7 @@ interface ListResponse$1 {
|
|
|
173
192
|
data: Array<{
|
|
174
193
|
id: string;
|
|
175
194
|
name: string;
|
|
176
|
-
|
|
195
|
+
pluginKey: string;
|
|
177
196
|
pluginVersion: string;
|
|
178
197
|
}>;
|
|
179
198
|
}
|
|
@@ -210,7 +229,7 @@ interface CapabilityInfo {
|
|
|
210
229
|
id: string;
|
|
211
230
|
name: string;
|
|
212
231
|
description: string;
|
|
213
|
-
|
|
232
|
+
pluginKey: string;
|
|
214
233
|
pluginVersion: string;
|
|
215
234
|
}
|
|
216
235
|
interface ListResponse {
|
package/dist/index.d.ts
CHANGED
|
@@ -50,7 +50,7 @@ interface JSONSchema {
|
|
|
50
50
|
}
|
|
51
51
|
interface CapabilityConfig {
|
|
52
52
|
id: string;
|
|
53
|
-
|
|
53
|
+
pluginKey: string;
|
|
54
54
|
pluginVersion: string;
|
|
55
55
|
name: string;
|
|
56
56
|
description: string;
|
|
@@ -60,8 +60,27 @@ interface CapabilityConfig {
|
|
|
60
60
|
updatedAt: number;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* 模板引擎服务
|
|
65
|
+
*
|
|
66
|
+
* 支持语法:
|
|
67
|
+
* - expr: '{{' + selector + '}}'
|
|
68
|
+
* - selector: 'input.' + ident | selector.ident
|
|
69
|
+
* - ident: [a-zA-Z_]([a-zA-Z_0-9])*
|
|
70
|
+
*
|
|
71
|
+
* 示例:
|
|
72
|
+
* - {{input.a}}
|
|
73
|
+
* - {{input.a.b}}
|
|
74
|
+
* - "this is {{input.a.b}}"
|
|
75
|
+
*
|
|
76
|
+
* 求值规则:
|
|
77
|
+
* - 如果整个字符串是单个表达式,保留原始类型
|
|
78
|
+
* - 如果是字符串插值(多个表达式或混合内容),返回字符串
|
|
79
|
+
* - 如果变量不存在,返回原始表达式
|
|
80
|
+
*/
|
|
63
81
|
declare class TemplateEngineService {
|
|
64
|
-
private readonly
|
|
82
|
+
private readonly EXPR_REGEX;
|
|
83
|
+
private readonly WHOLE_STRING_EXPR_REGEX;
|
|
65
84
|
resolve(template: unknown, input: Record<string, unknown>): unknown;
|
|
66
85
|
private resolveString;
|
|
67
86
|
private resolveObject;
|
|
@@ -69,24 +88,24 @@ declare class TemplateEngineService {
|
|
|
69
88
|
}
|
|
70
89
|
|
|
71
90
|
declare class PluginNotFoundError extends Error {
|
|
72
|
-
constructor(
|
|
91
|
+
constructor(pluginKey: string);
|
|
73
92
|
}
|
|
74
93
|
declare class PluginLoadError extends Error {
|
|
75
|
-
constructor(
|
|
94
|
+
constructor(pluginKey: string, reason: string);
|
|
76
95
|
}
|
|
77
96
|
declare class PluginLoaderService {
|
|
78
97
|
private readonly logger;
|
|
79
98
|
private readonly pluginInstances;
|
|
80
|
-
loadPlugin(
|
|
81
|
-
isPluginInstalled(
|
|
82
|
-
clearCache(
|
|
99
|
+
loadPlugin(pluginKey: string): Promise<PluginInstance>;
|
|
100
|
+
isPluginInstalled(pluginKey: string): boolean;
|
|
101
|
+
clearCache(pluginKey?: string): void;
|
|
83
102
|
}
|
|
84
103
|
|
|
85
104
|
declare class CapabilityNotFoundError extends Error {
|
|
86
105
|
constructor(capabilityId: string);
|
|
87
106
|
}
|
|
88
107
|
declare class ActionNotFoundError extends Error {
|
|
89
|
-
constructor(
|
|
108
|
+
constructor(pluginKey: string, actionName: string);
|
|
90
109
|
}
|
|
91
110
|
interface CapabilityExecutor {
|
|
92
111
|
/**
|
|
@@ -163,7 +182,7 @@ interface DebugResponse {
|
|
|
163
182
|
capabilityConfig: unknown;
|
|
164
183
|
resolvedParams: unknown;
|
|
165
184
|
duration: number;
|
|
166
|
-
|
|
185
|
+
pluginKey: string;
|
|
167
186
|
action: string;
|
|
168
187
|
};
|
|
169
188
|
}
|
|
@@ -173,7 +192,7 @@ interface ListResponse$1 {
|
|
|
173
192
|
data: Array<{
|
|
174
193
|
id: string;
|
|
175
194
|
name: string;
|
|
176
|
-
|
|
195
|
+
pluginKey: string;
|
|
177
196
|
pluginVersion: string;
|
|
178
197
|
}>;
|
|
179
198
|
}
|
|
@@ -210,7 +229,7 @@ interface CapabilityInfo {
|
|
|
210
229
|
id: string;
|
|
211
230
|
name: string;
|
|
212
231
|
description: string;
|
|
213
|
-
|
|
232
|
+
pluginKey: string;
|
|
214
233
|
pluginVersion: string;
|
|
215
234
|
}
|
|
216
235
|
interface ListResponse {
|
package/dist/index.js
CHANGED
|
@@ -20,7 +20,10 @@ var TemplateEngineService = class {
|
|
|
20
20
|
static {
|
|
21
21
|
__name(this, "TemplateEngineService");
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
// 匹配 {{input.xxx}} 或 {{input.xxx.yyy}} 表达式
|
|
24
|
+
EXPR_REGEX = /\{\{input\.([a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*)\}\}/g;
|
|
25
|
+
// 匹配整串单个表达式
|
|
26
|
+
WHOLE_STRING_EXPR_REGEX = /^\{\{input\.([a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*)\}\}$/;
|
|
24
27
|
resolve(template, input) {
|
|
25
28
|
if (typeof template === "string") {
|
|
26
29
|
return this.resolveString(template, input);
|
|
@@ -34,12 +37,25 @@ var TemplateEngineService = class {
|
|
|
34
37
|
return template;
|
|
35
38
|
}
|
|
36
39
|
resolveString(template, input) {
|
|
37
|
-
const
|
|
38
|
-
if (
|
|
40
|
+
const wholeMatch = template.match(this.WHOLE_STRING_EXPR_REGEX);
|
|
41
|
+
if (wholeMatch) {
|
|
42
|
+
const path2 = wholeMatch[1];
|
|
43
|
+
const value = this.getValueByPath(input, path2);
|
|
44
|
+
return value !== void 0 ? value : template;
|
|
45
|
+
}
|
|
46
|
+
this.EXPR_REGEX.lastIndex = 0;
|
|
47
|
+
if (!this.EXPR_REGEX.test(template)) {
|
|
39
48
|
return template;
|
|
40
49
|
}
|
|
41
|
-
|
|
42
|
-
|
|
50
|
+
this.EXPR_REGEX.lastIndex = 0;
|
|
51
|
+
const result = template.replace(this.EXPR_REGEX, (match, path2) => {
|
|
52
|
+
const value = this.getValueByPath(input, path2);
|
|
53
|
+
if (value === void 0) {
|
|
54
|
+
return match;
|
|
55
|
+
}
|
|
56
|
+
return String(value);
|
|
57
|
+
});
|
|
58
|
+
return result;
|
|
43
59
|
}
|
|
44
60
|
resolveObject(template, input) {
|
|
45
61
|
const result = {};
|
|
@@ -77,8 +93,8 @@ var PluginNotFoundError = class extends Error {
|
|
|
77
93
|
static {
|
|
78
94
|
__name(this, "PluginNotFoundError");
|
|
79
95
|
}
|
|
80
|
-
constructor(
|
|
81
|
-
super(`Plugin not found: ${
|
|
96
|
+
constructor(pluginKey) {
|
|
97
|
+
super(`Plugin not found: ${pluginKey}`);
|
|
82
98
|
this.name = "PluginNotFoundError";
|
|
83
99
|
}
|
|
84
100
|
};
|
|
@@ -86,8 +102,8 @@ var PluginLoadError = class extends Error {
|
|
|
86
102
|
static {
|
|
87
103
|
__name(this, "PluginLoadError");
|
|
88
104
|
}
|
|
89
|
-
constructor(
|
|
90
|
-
super(`Failed to load plugin ${
|
|
105
|
+
constructor(pluginKey, reason) {
|
|
106
|
+
super(`Failed to load plugin ${pluginKey}: ${reason}`);
|
|
91
107
|
this.name = "PluginLoadError";
|
|
92
108
|
}
|
|
93
109
|
};
|
|
@@ -97,41 +113,41 @@ var PluginLoaderService = class _PluginLoaderService {
|
|
|
97
113
|
}
|
|
98
114
|
logger = new Logger(_PluginLoaderService.name);
|
|
99
115
|
pluginInstances = /* @__PURE__ */ new Map();
|
|
100
|
-
async loadPlugin(
|
|
101
|
-
const cached = this.pluginInstances.get(
|
|
116
|
+
async loadPlugin(pluginKey) {
|
|
117
|
+
const cached = this.pluginInstances.get(pluginKey);
|
|
102
118
|
if (cached) {
|
|
103
|
-
this.logger.debug(`Using cached plugin instance: ${
|
|
119
|
+
this.logger.debug(`Using cached plugin instance: ${pluginKey}`);
|
|
104
120
|
return cached;
|
|
105
121
|
}
|
|
106
|
-
this.logger.log(`Loading plugin: ${
|
|
122
|
+
this.logger.log(`Loading plugin: ${pluginKey}`);
|
|
107
123
|
try {
|
|
108
|
-
const pluginPackage = (await import(
|
|
124
|
+
const pluginPackage = (await import(pluginKey)).default;
|
|
109
125
|
if (typeof pluginPackage.create !== "function") {
|
|
110
|
-
throw new PluginLoadError(
|
|
126
|
+
throw new PluginLoadError(pluginKey, "Plugin does not export create() function");
|
|
111
127
|
}
|
|
112
128
|
const instance = pluginPackage.create();
|
|
113
|
-
this.pluginInstances.set(
|
|
114
|
-
this.logger.log(`Plugin loaded successfully: ${
|
|
129
|
+
this.pluginInstances.set(pluginKey, instance);
|
|
130
|
+
this.logger.log(`Plugin loaded successfully: ${pluginKey}`);
|
|
115
131
|
return instance;
|
|
116
132
|
} catch (error) {
|
|
117
133
|
if (error.code === "MODULE_NOT_FOUND") {
|
|
118
|
-
throw new PluginNotFoundError(
|
|
134
|
+
throw new PluginNotFoundError(pluginKey);
|
|
119
135
|
}
|
|
120
|
-
throw new PluginLoadError(
|
|
136
|
+
throw new PluginLoadError(pluginKey, error instanceof Error ? error.message : String(error));
|
|
121
137
|
}
|
|
122
138
|
}
|
|
123
|
-
isPluginInstalled(
|
|
139
|
+
isPluginInstalled(pluginKey) {
|
|
124
140
|
try {
|
|
125
|
-
__require.resolve(
|
|
141
|
+
__require.resolve(pluginKey);
|
|
126
142
|
return true;
|
|
127
143
|
} catch {
|
|
128
144
|
return false;
|
|
129
145
|
}
|
|
130
146
|
}
|
|
131
|
-
clearCache(
|
|
132
|
-
if (
|
|
133
|
-
this.pluginInstances.delete(
|
|
134
|
-
this.logger.log(`Cleared cache for plugin: ${
|
|
147
|
+
clearCache(pluginKey) {
|
|
148
|
+
if (pluginKey) {
|
|
149
|
+
this.pluginInstances.delete(pluginKey);
|
|
150
|
+
this.logger.log(`Cleared cache for plugin: ${pluginKey}`);
|
|
135
151
|
} else {
|
|
136
152
|
this.pluginInstances.clear();
|
|
137
153
|
this.logger.log("Cleared all plugin caches");
|
|
@@ -177,8 +193,8 @@ var ActionNotFoundError = class extends Error {
|
|
|
177
193
|
static {
|
|
178
194
|
__name(this, "ActionNotFoundError");
|
|
179
195
|
}
|
|
180
|
-
constructor(
|
|
181
|
-
super(`Action '${actionName}' not found in plugin ${
|
|
196
|
+
constructor(pluginKey, actionName) {
|
|
197
|
+
super(`Action '${actionName}' not found in plugin ${pluginKey}`);
|
|
182
198
|
this.name = "ActionNotFoundError";
|
|
183
199
|
}
|
|
184
200
|
};
|
|
@@ -267,9 +283,9 @@ var CapabilityService = class _CapabilityService {
|
|
|
267
283
|
* 检查 action 是否为流式
|
|
268
284
|
*/
|
|
269
285
|
async checkIsStream(config, actionName) {
|
|
270
|
-
const pluginInstance = await this.pluginLoaderService.loadPlugin(config.
|
|
286
|
+
const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);
|
|
271
287
|
if (!pluginInstance.hasAction(actionName)) {
|
|
272
|
-
throw new ActionNotFoundError(config.
|
|
288
|
+
throw new ActionNotFoundError(config.pluginKey, actionName);
|
|
273
289
|
}
|
|
274
290
|
return pluginInstance.isStreamAction?.(actionName) ?? false;
|
|
275
291
|
}
|
|
@@ -281,9 +297,9 @@ var CapabilityService = class _CapabilityService {
|
|
|
281
297
|
async executeCall(config, actionName, input, contextOverride) {
|
|
282
298
|
const startTime = Date.now();
|
|
283
299
|
try {
|
|
284
|
-
const pluginInstance = await this.pluginLoaderService.loadPlugin(config.
|
|
300
|
+
const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);
|
|
285
301
|
if (!pluginInstance.hasAction(actionName)) {
|
|
286
|
-
throw new ActionNotFoundError(config.
|
|
302
|
+
throw new ActionNotFoundError(config.pluginKey, actionName);
|
|
287
303
|
}
|
|
288
304
|
const resolvedParams = this.templateEngineService.resolve(config.formValue, input);
|
|
289
305
|
const context = this.buildActionContext(contextOverride);
|
|
@@ -292,7 +308,7 @@ var CapabilityService = class _CapabilityService {
|
|
|
292
308
|
message: "Executing capability",
|
|
293
309
|
capabilityId: config.id,
|
|
294
310
|
action: actionName,
|
|
295
|
-
|
|
311
|
+
pluginKey: config.pluginKey,
|
|
296
312
|
isStream
|
|
297
313
|
});
|
|
298
314
|
let result;
|
|
@@ -331,9 +347,9 @@ var CapabilityService = class _CapabilityService {
|
|
|
331
347
|
async *executeCallStream(config, actionName, input, contextOverride) {
|
|
332
348
|
const startTime = Date.now();
|
|
333
349
|
try {
|
|
334
|
-
const pluginInstance = await this.pluginLoaderService.loadPlugin(config.
|
|
350
|
+
const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginKey);
|
|
335
351
|
if (!pluginInstance.hasAction(actionName)) {
|
|
336
|
-
throw new ActionNotFoundError(config.
|
|
352
|
+
throw new ActionNotFoundError(config.pluginKey, actionName);
|
|
337
353
|
}
|
|
338
354
|
const resolvedParams = this.templateEngineService.resolve(config.formValue, input);
|
|
339
355
|
const context = this.buildActionContext(contextOverride);
|
|
@@ -342,7 +358,7 @@ var CapabilityService = class _CapabilityService {
|
|
|
342
358
|
message: "Executing capability (stream)",
|
|
343
359
|
capabilityId: config.id,
|
|
344
360
|
action: actionName,
|
|
345
|
-
|
|
361
|
+
pluginKey: config.pluginKey,
|
|
346
362
|
isStream
|
|
347
363
|
});
|
|
348
364
|
if (isStream && pluginInstance.runStream) {
|
|
@@ -434,7 +450,7 @@ var DebugController = class {
|
|
|
434
450
|
data: capabilities.map((c) => ({
|
|
435
451
|
id: c.id,
|
|
436
452
|
name: c.name,
|
|
437
|
-
|
|
453
|
+
pluginKey: c.pluginKey,
|
|
438
454
|
pluginVersion: c.pluginVersion
|
|
439
455
|
}))
|
|
440
456
|
};
|
|
@@ -461,16 +477,16 @@ var DebugController = class {
|
|
|
461
477
|
* 获取 action 名称
|
|
462
478
|
* 优先使用传入的 action,否则使用插件第一个 action
|
|
463
479
|
*/
|
|
464
|
-
async getActionName(
|
|
480
|
+
async getActionName(pluginKey, bodyAction) {
|
|
465
481
|
if (bodyAction) {
|
|
466
482
|
return bodyAction;
|
|
467
483
|
}
|
|
468
|
-
const pluginInstance = await this.pluginLoaderService.loadPlugin(
|
|
484
|
+
const pluginInstance = await this.pluginLoaderService.loadPlugin(pluginKey);
|
|
469
485
|
const actions = pluginInstance.listActions();
|
|
470
486
|
if (actions.length === 0) {
|
|
471
487
|
throw new HttpException({
|
|
472
488
|
code: 1,
|
|
473
|
-
message: `Plugin ${
|
|
489
|
+
message: `Plugin ${pluginKey} has no actions`,
|
|
474
490
|
error: "NO_ACTIONS"
|
|
475
491
|
}, HttpStatus.BAD_REQUEST);
|
|
476
492
|
}
|
|
@@ -480,7 +496,7 @@ var DebugController = class {
|
|
|
480
496
|
const startTime = Date.now();
|
|
481
497
|
const params = body.params ?? {};
|
|
482
498
|
const config = this.getCapabilityConfig(capabilityId, body.capability);
|
|
483
|
-
const action = await this.getActionName(config.
|
|
499
|
+
const action = await this.getActionName(config.pluginKey, body.action);
|
|
484
500
|
const resolvedParams = this.templateEngineService.resolve(config.formValue, params);
|
|
485
501
|
try {
|
|
486
502
|
const result = await this.capabilityService.loadWithConfig(config).call(action, params);
|
|
@@ -492,7 +508,7 @@ var DebugController = class {
|
|
|
492
508
|
capabilityConfig: config,
|
|
493
509
|
resolvedParams,
|
|
494
510
|
duration: Date.now() - startTime,
|
|
495
|
-
|
|
511
|
+
pluginKey: config.pluginKey,
|
|
496
512
|
action
|
|
497
513
|
}
|
|
498
514
|
};
|
|
@@ -515,7 +531,7 @@ var DebugController = class {
|
|
|
515
531
|
error: "PLUGIN_NOT_FOUND",
|
|
516
532
|
debug: {
|
|
517
533
|
duration,
|
|
518
|
-
|
|
534
|
+
pluginKey: config.pluginKey,
|
|
519
535
|
action
|
|
520
536
|
}
|
|
521
537
|
}, HttpStatus.INTERNAL_SERVER_ERROR);
|
|
@@ -527,7 +543,7 @@ var DebugController = class {
|
|
|
527
543
|
error: "ACTION_NOT_FOUND",
|
|
528
544
|
debug: {
|
|
529
545
|
duration,
|
|
530
|
-
|
|
546
|
+
pluginKey: config.pluginKey,
|
|
531
547
|
action
|
|
532
548
|
}
|
|
533
549
|
}, HttpStatus.BAD_REQUEST);
|
|
@@ -538,7 +554,7 @@ var DebugController = class {
|
|
|
538
554
|
error: "EXECUTION_ERROR",
|
|
539
555
|
debug: {
|
|
540
556
|
duration,
|
|
541
|
-
|
|
557
|
+
pluginKey: config.pluginKey,
|
|
542
558
|
action,
|
|
543
559
|
resolvedParams
|
|
544
560
|
}
|
|
@@ -552,7 +568,7 @@ var DebugController = class {
|
|
|
552
568
|
res.setHeader("Connection", "keep-alive");
|
|
553
569
|
try {
|
|
554
570
|
const config = this.getCapabilityConfig(capabilityId, body.capability);
|
|
555
|
-
const action = await this.getActionName(config.
|
|
571
|
+
const action = await this.getActionName(config.pluginKey, body.action);
|
|
556
572
|
const capability = this.capabilityService.loadWithConfig(config);
|
|
557
573
|
const stream = capability.callStream(action, params);
|
|
558
574
|
for await (const chunk of stream) {
|
|
@@ -661,7 +677,7 @@ var WebhookController = class {
|
|
|
661
677
|
id: c.id,
|
|
662
678
|
name: c.name,
|
|
663
679
|
description: c.description,
|
|
664
|
-
|
|
680
|
+
pluginKey: c.pluginKey,
|
|
665
681
|
pluginVersion: c.pluginVersion
|
|
666
682
|
}))
|
|
667
683
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/services/template-engine.service.ts","../src/services/plugin-loader.service.ts","../src/services/capability.service.ts","../src/controllers/debug.controller.ts","../src/controllers/webhook.controller.ts","../src/capability.module.ts"],"sourcesContent":["import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class TemplateEngineService {\n private readonly TEMPLATE_REGEX = /^\\{\\{input\\.(.+)\\}\\}$/;\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 const match = template.match(this.TEMPLATE_REGEX);\n if (!match) {\n return template;\n }\n\n const path = match[1];\n return this.getValueByPath(input, path);\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(pluginID: string) {\n super(`Plugin not found: ${pluginID}`);\n this.name = 'PluginNotFoundError';\n }\n}\n\nexport class PluginLoadError extends Error {\n constructor(pluginID: string, reason: string) {\n super(`Failed to load plugin ${pluginID}: ${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(pluginID: string): Promise<PluginInstance> {\n const cached = this.pluginInstances.get(pluginID);\n if (cached) {\n this.logger.debug(`Using cached plugin instance: ${pluginID}`);\n return cached;\n }\n\n this.logger.log(`Loading plugin: ${pluginID}`);\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const pluginPackage = (await import(pluginID)).default as PluginPackage;\n\n if (typeof pluginPackage.create !== 'function') {\n throw new PluginLoadError(pluginID, 'Plugin does not export create() function');\n }\n\n const instance = pluginPackage.create();\n this.pluginInstances.set(pluginID, instance);\n\n this.logger.log(`Plugin loaded successfully: ${pluginID}`);\n return instance;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'MODULE_NOT_FOUND') {\n throw new PluginNotFoundError(pluginID);\n }\n throw new PluginLoadError(\n pluginID,\n error instanceof Error ? error.message : String(error),\n );\n }\n }\n\n isPluginInstalled(pluginID: string): boolean {\n try {\n require.resolve(pluginID);\n return true;\n } catch {\n return false;\n }\n }\n\n clearCache(pluginID?: string): void {\n if (pluginID) {\n this.pluginInstances.delete(pluginID);\n this.logger.log(`Cleared cache for plugin: ${pluginID}`);\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 { CapabilityConfig, PluginActionContext, UserContext } from '../interfaces';\nimport { PluginLoaderService } from './plugin-loader.service';\nimport { TemplateEngineService } from './template-engine.service';\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(pluginID: string, actionName: string) {\n super(`Action '${actionName}' not found in plugin ${pluginID}`);\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 * 检查 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 httpClient: 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 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.pluginID);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginID, 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\n try {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginID);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginID, actionName);\n }\n\n const resolvedParams = this.templateEngineService.resolve(\n config.formValue,\n input as Record<string, unknown>,\n );\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n this.logger.log({\n message: 'Executing capability',\n capabilityId: config.id,\n action: actionName,\n pluginID: config.pluginID,\n isStream,\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 this.logger.log({\n message: 'Capability executed successfully',\n capabilityId: config.id,\n action: actionName,\n duration: Date.now() - startTime,\n });\n\n return result;\n } catch (error) {\n this.logger.error({\n message: 'Capability execution failed',\n capabilityId: config.id,\n action: actionName,\n error: error instanceof Error ? error.message : String(error),\n duration: Date.now() - startTime,\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\n try {\n const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginID);\n\n if (!pluginInstance.hasAction(actionName)) {\n throw new ActionNotFoundError(config.pluginID, actionName);\n }\n\n const resolvedParams = this.templateEngineService.resolve(\n config.formValue,\n input as Record<string, unknown>,\n );\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n this.logger.log({\n message: 'Executing capability (stream)',\n capabilityId: config.id,\n action: actionName,\n pluginID: config.pluginID,\n isStream,\n });\n\n if (isStream && pluginInstance.runStream) {\n // 流式 action:透传 AsyncIterable\n yield* pluginInstance.runStream(actionName, context, resolvedParams);\n } else {\n // 非流式 action:包装为单次 yield\n const result = await pluginInstance.run(actionName, context, resolvedParams);\n yield result;\n }\n\n this.logger.log({\n message: 'Capability stream completed',\n capabilityId: config.id,\n action: actionName,\n duration: Date.now() - startTime,\n });\n } catch (error) {\n this.logger.error({\n message: 'Capability stream execution failed',\n capabilityId: config.id,\n action: actionName,\n error: error instanceof Error ? error.message : String(error),\n duration: Date.now() - startTime,\n });\n throw error;\n }\n }\n\n private buildActionContext(override?: Partial<PluginActionContext>): PluginActionContext {\n return {\n logger: this.logger,\n httpClient: this.httpClient,\n userContext: override?.userContext ?? this.getUserContext(),\n };\n }\n\n private getUserContext(): UserContext {\n const ctx = this.requestContextService.getContext();\n return {\n userId: ctx?.userId ?? '',\n tenantId: ctx?.tenantId ?? '',\n };\n }\n}\n","import {\n Controller,\n Post,\n Get,\n Param,\n Body,\n Res,\n HttpException,\n HttpStatus,\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 { CapabilityConfig } from '../interfaces';\n\ninterface DebugRequestBody {\n action?: string;\n params?: Record<string, unknown>;\n capability?: CapabilityConfig;\n}\n\ninterface DebugResponse {\n code: number;\n message: string;\n data: unknown;\n debug?: {\n capabilityConfig: unknown;\n resolvedParams: unknown;\n duration: number;\n pluginID: string;\n action: string;\n };\n}\n\ninterface ListResponse {\n code: number;\n message: string;\n data: Array<{\n id: string;\n name: string;\n pluginID: string;\n pluginVersion: string;\n }>;\n}\n\n@Controller('__innerapi__/capability')\nexport class DebugController {\n constructor(\n private readonly capabilityService: CapabilityService,\n private readonly pluginLoaderService: PluginLoaderService,\n private readonly templateEngineService: TemplateEngineService,\n ) {}\n\n @Get('list')\n list(): ListResponse {\n const capabilities = this.capabilityService.listCapabilities();\n\n return {\n code: 0,\n message: 'success',\n data: capabilities.map(c => ({\n id: c.id,\n name: c.name,\n pluginID: c.pluginID,\n pluginVersion: c.pluginVersion,\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(pluginID: string, bodyAction?: string): Promise<string> {\n if (bodyAction) {\n return bodyAction;\n }\n\n const pluginInstance = await this.pluginLoaderService.loadPlugin(pluginID);\n const actions = pluginInstance.listActions();\n\n if (actions.length === 0) {\n throw new HttpException(\n {\n code: 1,\n message: `Plugin ${pluginID} 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<DebugResponse> {\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.pluginID, 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 code: 0,\n message: 'success',\n data: result,\n debug: {\n capabilityConfig: config,\n resolvedParams,\n duration: Date.now() - startTime,\n pluginID: config.pluginID,\n action,\n },\n };\n } catch (error) {\n const duration = Date.now() - startTime;\n\n if (error instanceof CapabilityNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'CAPABILITY_NOT_FOUND',\n debug: { duration },\n },\n HttpStatus.NOT_FOUND,\n );\n }\n\n if (error instanceof PluginNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'PLUGIN_NOT_FOUND',\n debug: { duration, pluginID: config.pluginID, action },\n },\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n\n if (error instanceof ActionNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'ACTION_NOT_FOUND',\n debug: { duration, pluginID: config.pluginID, action },\n },\n HttpStatus.BAD_REQUEST,\n );\n }\n\n throw new HttpException(\n {\n code: 1,\n message: error instanceof Error ? error.message : String(error),\n error: 'EXECUTION_ERROR',\n debug: {\n duration,\n pluginID: config.pluginID,\n action,\n resolvedParams,\n },\n },\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.pluginID, body.action);\n\n const capability = this.capabilityService.loadWithConfig(config);\n const stream = capability.callStream(action, params);\n\n for await (const chunk of stream) {\n res.write(`data: ${JSON.stringify(chunk)}\\n\\n`);\n }\n\n // 发送结束标记\n res.write('data: [DONE]\\n\\n');\n } catch (error) {\n // 错误时发送错误信息\n const message = error instanceof Error ? error.message : String(error);\n let errorCode = 'EXECUTION_ERROR';\n\n if (error instanceof CapabilityNotFoundError) {\n errorCode = 'CAPABILITY_NOT_FOUND';\n } else if (error instanceof PluginNotFoundError) {\n errorCode = 'PLUGIN_NOT_FOUND';\n } else if (error instanceof ActionNotFoundError) {\n errorCode = 'ACTION_NOT_FOUND';\n } else if (error instanceof HttpException) {\n const response = error.getResponse() as { error?: string };\n errorCode = response.error ?? 'EXECUTION_ERROR';\n }\n\n res.write(`data: ${JSON.stringify({ error: message, code: errorCode })}\\n\\n`);\n } finally {\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} 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';\n\ninterface ExecuteRequestBody {\n action: string;\n params: Record<string, unknown>;\n}\n\ninterface ExecuteResponse {\n code: number;\n message: string;\n data: unknown;\n}\n\ninterface CapabilityInfo {\n id: string;\n name: string;\n description: string;\n pluginID: string;\n pluginVersion: string;\n}\n\ninterface ListResponse {\n code: number;\n message: string;\n data: CapabilityInfo[];\n}\n\n@Controller('api/capability')\nexport class WebhookController {\n constructor(private readonly capabilityService: CapabilityService) {}\n\n @Get('list')\n list(): ListResponse {\n const capabilities = this.capabilityService.listCapabilities();\n return {\n code: 0,\n message: 'success',\n data: capabilities.map(c => ({\n id: c.id,\n name: c.name,\n description: c.description,\n pluginID: c.pluginID,\n pluginVersion: c.pluginVersion,\n })),\n };\n }\n\n @Post(':capability_id')\n async execute(\n @Param('capability_id') capabilityId: string,\n @Body() body: ExecuteRequestBody,\n ): Promise<ExecuteResponse> {\n try {\n const result = await this.capabilityService\n .load(capabilityId)\n .call(body.action, body.params);\n\n return {\n code: 0,\n message: 'success',\n data: result,\n };\n } catch (error) {\n if (error instanceof CapabilityNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'CAPABILITY_NOT_FOUND',\n },\n HttpStatus.NOT_FOUND,\n );\n }\n\n if (error instanceof PluginNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'PLUGIN_NOT_FOUND',\n },\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n\n if (error instanceof ActionNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'ACTION_NOT_FOUND',\n },\n HttpStatus.BAD_REQUEST,\n );\n }\n\n throw new HttpException(\n {\n code: 1,\n message: error instanceof Error ? error.message : String(error),\n error: 'EXECUTION_ERROR',\n },\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 // 设置 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 capability = this.capabilityService.load(capabilityId);\n const stream = capability.callStream(body.action, body.params);\n\n for await (const chunk of stream) {\n res.write(`data: ${JSON.stringify(chunk)}\\n\\n`);\n }\n\n // 发送结束标记\n res.write('data: [DONE]\\n\\n');\n } catch (error) {\n // 错误时发送错误信息\n const message = error instanceof Error ? error.message : String(error);\n let errorCode = 'EXECUTION_ERROR';\n\n if (error instanceof CapabilityNotFoundError) {\n errorCode = 'CAPABILITY_NOT_FOUND';\n } else if (error instanceof PluginNotFoundError) {\n errorCode = 'PLUGIN_NOT_FOUND';\n } else if (error instanceof ActionNotFoundError) {\n errorCode = 'ACTION_NOT_FOUND';\n }\n\n res.write(`data: ${JSON.stringify({ error: message, code: errorCode })}\\n\\n`);\n } finally {\n res.end();\n }\n }\n}\n","import { Module, DynamicModule, Type } from '@nestjs/common';\nimport {\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 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 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":["Injectable","TemplateEngineService","TEMPLATE_REGEX","resolve","template","input","resolveString","Array","isArray","map","item","resolveObject","match","path","getValueByPath","result","key","value","Object","entries","obj","keys","split","current","undefined","Injectable","Logger","PluginNotFoundError","Error","pluginID","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","CapabilityNotFoundError","Error","capabilityId","name","ActionNotFoundError","pluginID","actionName","CapabilityService","logger","Logger","capabilities","Map","capabilitiesDir","requestContextService","httpClient","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","isStream","checkIsStream","pluginInstance","loadPlugin","hasAction","isStreamAction","startTime","Date","now","resolvedParams","resolve","formValue","context","buildActionContext","message","action","result","runStream","chunks","chunk","push","aggregate","run","duration","String","override","userContext","getUserContext","ctx","getContext","userId","tenantId","Controller","Post","Get","Param","Body","Res","HttpException","HttpStatus","DebugController","capabilityService","pluginLoaderService","templateEngineService","list","capabilities","listCapabilities","code","message","data","map","c","id","name","pluginID","pluginVersion","getCapabilityConfig","capabilityId","bodyCapability","config","getCapability","HttpException","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","capabilityConfig","duration","CapabilityNotFoundError","PluginNotFoundError","INTERNAL_SERVER_ERROR","ActionNotFoundError","Error","String","debugStream","res","setHeader","stream","callStream","chunk","write","JSON","stringify","errorCode","response","getResponse","end","Controller","Get","Post","Param","Body","Res","HttpException","HttpStatus","WebhookController","capabilityService","list","capabilities","listCapabilities","code","message","data","map","c","id","name","description","pluginID","pluginVersion","execute","capabilityId","body","result","load","call","action","params","error","CapabilityNotFoundError","HttpException","HttpStatus","NOT_FOUND","PluginNotFoundError","INTERNAL_SERVER_ERROR","ActionNotFoundError","BAD_REQUEST","Error","String","executeStream","res","setHeader","capability","stream","callStream","chunk","write","JSON","stringify","errorCode","end","Module","RequestContextService","PLATFORM_HTTP_CLIENT","CAPABILITY_OPTIONS","Symbol","isDevelopment","process","env","NODE_ENV","getControllers","controllers","WebhookController","push","DebugController","CapabilityModule","forRoot","options","module","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/services/template-engine.service.ts","../src/services/plugin-loader.service.ts","../src/services/capability.service.ts","../src/controllers/debug.controller.ts","../src/controllers/webhook.controller.ts","../src/capability.module.ts"],"sourcesContent":["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 { CapabilityConfig, PluginActionContext, UserContext } from '../interfaces';\nimport { PluginLoaderService } from './plugin-loader.service';\nimport { TemplateEngineService } from './template-engine.service';\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 * 检查 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 httpClient: 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 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\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 const resolvedParams = this.templateEngineService.resolve(\n config.formValue,\n input as Record<string, unknown>,\n );\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n this.logger.log({\n message: 'Executing capability',\n capabilityId: config.id,\n action: actionName,\n pluginKey: config.pluginKey,\n isStream,\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 this.logger.log({\n message: 'Capability executed successfully',\n capabilityId: config.id,\n action: actionName,\n duration: Date.now() - startTime,\n });\n\n return result;\n } catch (error) {\n this.logger.error({\n message: 'Capability execution failed',\n capabilityId: config.id,\n action: actionName,\n error: error instanceof Error ? error.message : String(error),\n duration: Date.now() - startTime,\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\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 const resolvedParams = this.templateEngineService.resolve(\n config.formValue,\n input as Record<string, unknown>,\n );\n\n const context = this.buildActionContext(contextOverride);\n const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;\n\n this.logger.log({\n message: 'Executing capability (stream)',\n capabilityId: config.id,\n action: actionName,\n pluginKey: config.pluginKey,\n isStream,\n });\n\n if (isStream && pluginInstance.runStream) {\n // 流式 action:透传 AsyncIterable\n yield* pluginInstance.runStream(actionName, context, resolvedParams);\n } else {\n // 非流式 action:包装为单次 yield\n const result = await pluginInstance.run(actionName, context, resolvedParams);\n yield result;\n }\n\n this.logger.log({\n message: 'Capability stream completed',\n capabilityId: config.id,\n action: actionName,\n duration: Date.now() - startTime,\n });\n } catch (error) {\n this.logger.error({\n message: 'Capability stream execution failed',\n capabilityId: config.id,\n action: actionName,\n error: error instanceof Error ? error.message : String(error),\n duration: Date.now() - startTime,\n });\n throw error;\n }\n }\n\n private buildActionContext(override?: Partial<PluginActionContext>): PluginActionContext {\n return {\n logger: this.logger,\n httpClient: this.httpClient,\n userContext: override?.userContext ?? this.getUserContext(),\n };\n }\n\n private getUserContext(): UserContext {\n const ctx = this.requestContextService.getContext();\n return {\n userId: ctx?.userId ?? '',\n tenantId: ctx?.tenantId ?? '',\n };\n }\n}\n","import {\n Controller,\n Post,\n Get,\n Param,\n Body,\n Res,\n HttpException,\n HttpStatus,\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 { CapabilityConfig } from '../interfaces';\n\ninterface DebugRequestBody {\n action?: string;\n params?: Record<string, unknown>;\n capability?: CapabilityConfig;\n}\n\ninterface DebugResponse {\n code: number;\n message: string;\n data: unknown;\n debug?: {\n capabilityConfig: unknown;\n resolvedParams: unknown;\n duration: number;\n pluginKey: string;\n action: string;\n };\n}\n\ninterface ListResponse {\n code: number;\n message: string;\n data: Array<{\n id: string;\n name: string;\n pluginKey: string;\n pluginVersion: string;\n }>;\n}\n\n@Controller('__innerapi__/capability')\nexport class DebugController {\n constructor(\n private readonly capabilityService: CapabilityService,\n private readonly pluginLoaderService: PluginLoaderService,\n private readonly templateEngineService: TemplateEngineService,\n ) {}\n\n @Get('list')\n list(): ListResponse {\n const capabilities = this.capabilityService.listCapabilities();\n\n return {\n code: 0,\n message: 'success',\n data: capabilities.map(c => ({\n id: c.id,\n name: c.name,\n pluginKey: c.pluginKey,\n pluginVersion: c.pluginVersion,\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<DebugResponse> {\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 code: 0,\n message: 'success',\n data: result,\n debug: {\n capabilityConfig: config,\n resolvedParams,\n duration: Date.now() - startTime,\n pluginKey: config.pluginKey,\n action,\n },\n };\n } catch (error) {\n const duration = Date.now() - startTime;\n\n if (error instanceof CapabilityNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'CAPABILITY_NOT_FOUND',\n debug: { duration },\n },\n HttpStatus.NOT_FOUND,\n );\n }\n\n if (error instanceof PluginNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'PLUGIN_NOT_FOUND',\n debug: { duration, pluginKey: config.pluginKey, action },\n },\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n\n if (error instanceof ActionNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'ACTION_NOT_FOUND',\n debug: { duration, pluginKey: config.pluginKey, action },\n },\n HttpStatus.BAD_REQUEST,\n );\n }\n\n throw new HttpException(\n {\n code: 1,\n message: error instanceof Error ? error.message : String(error),\n error: 'EXECUTION_ERROR',\n debug: {\n duration,\n pluginKey: config.pluginKey,\n action,\n resolvedParams,\n },\n },\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\n const capability = this.capabilityService.loadWithConfig(config);\n const stream = capability.callStream(action, params);\n\n for await (const chunk of stream) {\n res.write(`data: ${JSON.stringify(chunk)}\\n\\n`);\n }\n\n // 发送结束标记\n res.write('data: [DONE]\\n\\n');\n } catch (error) {\n // 错误时发送错误信息\n const message = error instanceof Error ? error.message : String(error);\n let errorCode = 'EXECUTION_ERROR';\n\n if (error instanceof CapabilityNotFoundError) {\n errorCode = 'CAPABILITY_NOT_FOUND';\n } else if (error instanceof PluginNotFoundError) {\n errorCode = 'PLUGIN_NOT_FOUND';\n } else if (error instanceof ActionNotFoundError) {\n errorCode = 'ACTION_NOT_FOUND';\n } else if (error instanceof HttpException) {\n const response = error.getResponse() as { error?: string };\n errorCode = response.error ?? 'EXECUTION_ERROR';\n }\n\n res.write(`data: ${JSON.stringify({ error: message, code: errorCode })}\\n\\n`);\n } finally {\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} 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';\n\ninterface ExecuteRequestBody {\n action: string;\n params: Record<string, unknown>;\n}\n\ninterface ExecuteResponse {\n code: number;\n message: string;\n data: unknown;\n}\n\ninterface CapabilityInfo {\n id: string;\n name: string;\n description: string;\n pluginKey: string;\n pluginVersion: string;\n}\n\ninterface ListResponse {\n code: number;\n message: string;\n data: CapabilityInfo[];\n}\n\n@Controller('api/capability')\nexport class WebhookController {\n constructor(private readonly capabilityService: CapabilityService) {}\n\n @Get('list')\n list(): ListResponse {\n const capabilities = this.capabilityService.listCapabilities();\n return {\n code: 0,\n message: 'success',\n data: capabilities.map(c => ({\n id: c.id,\n name: c.name,\n description: c.description,\n pluginKey: c.pluginKey,\n pluginVersion: c.pluginVersion,\n })),\n };\n }\n\n @Post(':capability_id')\n async execute(\n @Param('capability_id') capabilityId: string,\n @Body() body: ExecuteRequestBody,\n ): Promise<ExecuteResponse> {\n try {\n const result = await this.capabilityService\n .load(capabilityId)\n .call(body.action, body.params);\n\n return {\n code: 0,\n message: 'success',\n data: result,\n };\n } catch (error) {\n if (error instanceof CapabilityNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'CAPABILITY_NOT_FOUND',\n },\n HttpStatus.NOT_FOUND,\n );\n }\n\n if (error instanceof PluginNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'PLUGIN_NOT_FOUND',\n },\n HttpStatus.INTERNAL_SERVER_ERROR,\n );\n }\n\n if (error instanceof ActionNotFoundError) {\n throw new HttpException(\n {\n code: 1,\n message: error.message,\n error: 'ACTION_NOT_FOUND',\n },\n HttpStatus.BAD_REQUEST,\n );\n }\n\n throw new HttpException(\n {\n code: 1,\n message: error instanceof Error ? error.message : String(error),\n error: 'EXECUTION_ERROR',\n },\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 // 设置 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 capability = this.capabilityService.load(capabilityId);\n const stream = capability.callStream(body.action, body.params);\n\n for await (const chunk of stream) {\n res.write(`data: ${JSON.stringify(chunk)}\\n\\n`);\n }\n\n // 发送结束标记\n res.write('data: [DONE]\\n\\n');\n } catch (error) {\n // 错误时发送错误信息\n const message = error instanceof Error ? error.message : String(error);\n let errorCode = 'EXECUTION_ERROR';\n\n if (error instanceof CapabilityNotFoundError) {\n errorCode = 'CAPABILITY_NOT_FOUND';\n } else if (error instanceof PluginNotFoundError) {\n errorCode = 'PLUGIN_NOT_FOUND';\n } else if (error instanceof ActionNotFoundError) {\n errorCode = 'ACTION_NOT_FOUND';\n }\n\n res.write(`data: ${JSON.stringify({ error: message, code: errorCode })}\\n\\n`);\n } finally {\n res.end();\n }\n }\n}\n","import { Module, DynamicModule, Type } from '@nestjs/common';\nimport {\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 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 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":["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","CapabilityNotFoundError","Error","capabilityId","name","ActionNotFoundError","pluginKey","actionName","CapabilityService","logger","Logger","capabilities","Map","capabilitiesDir","requestContextService","httpClient","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","isStream","checkIsStream","pluginInstance","loadPlugin","hasAction","isStreamAction","startTime","Date","now","resolvedParams","resolve","formValue","context","buildActionContext","message","action","result","runStream","chunks","chunk","push","aggregate","run","duration","String","override","userContext","getUserContext","ctx","getContext","userId","tenantId","Controller","Post","Get","Param","Body","Res","HttpException","HttpStatus","DebugController","capabilityService","pluginLoaderService","templateEngineService","list","capabilities","listCapabilities","code","message","data","map","c","id","name","pluginKey","pluginVersion","getCapabilityConfig","capabilityId","bodyCapability","config","getCapability","HttpException","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","capabilityConfig","duration","CapabilityNotFoundError","PluginNotFoundError","INTERNAL_SERVER_ERROR","ActionNotFoundError","Error","String","debugStream","res","setHeader","stream","callStream","chunk","write","JSON","stringify","errorCode","response","getResponse","end","Controller","Get","Post","Param","Body","Res","HttpException","HttpStatus","WebhookController","capabilityService","list","capabilities","listCapabilities","code","message","data","map","c","id","name","description","pluginKey","pluginVersion","execute","capabilityId","body","result","load","call","action","params","error","CapabilityNotFoundError","HttpException","HttpStatus","NOT_FOUND","PluginNotFoundError","INTERNAL_SERVER_ERROR","ActionNotFoundError","BAD_REQUEST","Error","String","executeStream","res","setHeader","capability","stream","callStream","chunk","write","JSON","stringify","errorCode","end","Module","RequestContextService","PLATFORM_HTTP_CLIENT","CAPABILITY_OPTIONS","Symbol","isDevelopment","process","env","NODE_ENV","getControllers","controllers","WebhookController","push","DebugController","CapabilityModule","forRoot","options","module","providers","provide","useValue","CapabilityService","useFactory","requestContextService","httpClient","pluginLoader","templateEngine","moduleOptions","service","capabilitiesDir","setCapabilitiesDir","inject","RequestContextService","PLATFORM_HTTP_CLIENT","PluginLoaderService","TemplateEngineService","exports"]}
|