@lark-apaas/nestjs-capability 0.1.5-alpha.7 → 0.1.5

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.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Logger, OnModuleInit, OnModuleDestroy, DynamicModule } from '@nestjs/common';
2
- import { PlatformHttpClient, RequestContextService } from '@lark-apaas/nestjs-common';
2
+ import { PlatformHttpClient, RequestContextService, HttpClientFactory } from '@lark-apaas/nestjs-common';
3
3
  import { ZodSchema } from 'zod';
4
4
  import { Response } from 'express';
5
5
 
@@ -9,6 +9,8 @@ interface UserContext {
9
9
  appId: string;
10
10
  }
11
11
  interface PluginActionContext {
12
+ /** 插件标识(如 @official/ai-chat) */
13
+ pluginKey: string;
12
14
  logger: Logger;
13
15
  platformHttpClient: PlatformHttpClient;
14
16
  userContext: UserContext;
@@ -48,6 +50,8 @@ interface SuccessResponse<T> {
48
50
  interface ErrorResponse {
49
51
  status_code: string;
50
52
  error_msg: string;
53
+ /** 是否为计费受限错误(当 status_code 为业务错误码时为 true) */
54
+ is_rate_limit_error?: boolean;
51
55
  }
52
56
  /**
53
57
  * Debug 信息
@@ -106,8 +110,11 @@ interface StreamErrorResponse {
106
110
  data: {
107
111
  type: 'error';
108
112
  error: {
109
- code: number;
113
+ /** 错误码,计费受限时为业务错误码(如 k_st_ec_400002687),其他情况为框架错误码 */
114
+ code: string;
110
115
  message: string;
116
+ /** 是否为计费受限错误 */
117
+ isRateLimitError?: boolean;
111
118
  };
112
119
  };
113
120
  }
@@ -133,6 +140,10 @@ interface StreamError {
133
140
  code: string;
134
141
  message: string;
135
142
  details?: unknown;
143
+ /** 计费受限时的业务错误码(仅 code 为 RATE_LIMIT_EXCEEDED 时存在) */
144
+ rateLimitCode?: string;
145
+ /** 计费受限时的业务错误消息(仅 code 为 RATE_LIMIT_EXCEEDED 时存在) */
146
+ rateLimitMessage?: string;
136
147
  }
137
148
  /**
138
149
  * 流事件类型
@@ -197,6 +208,8 @@ declare const ErrorCodes: {
197
208
  readonly PARAMS_VALIDATION_ERROR: "k_ec_cap_004";
198
209
  /** 执行失败 */
199
210
  readonly EXECUTION_ERROR: "k_ec_cap_005";
211
+ /** 计费受限 */
212
+ readonly RATE_LIMIT_EXCEEDED: "k_ec_cap_006";
200
213
  };
201
214
  type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
202
215
 
@@ -366,7 +379,7 @@ interface CapabilityModuleOptions {
366
379
  }
367
380
  declare class CapabilityService implements OnModuleInit, OnModuleDestroy {
368
381
  private readonly requestContextService;
369
- private readonly platformHttpClient;
382
+ private readonly httpClientFactory;
370
383
  private readonly pluginLoaderService;
371
384
  private readonly templateEngineService;
372
385
  private readonly logger;
@@ -376,7 +389,7 @@ declare class CapabilityService implements OnModuleInit, OnModuleDestroy {
376
389
  private capabilitiesDir;
377
390
  private fileWatcher;
378
391
  private options;
379
- constructor(requestContextService: RequestContextService, platformHttpClient: PlatformHttpClient, pluginLoaderService: PluginLoaderService, templateEngineService: TemplateEngineService);
392
+ constructor(requestContextService: RequestContextService, httpClientFactory: HttpClientFactory, pluginLoaderService: PluginLoaderService, templateEngineService: TemplateEngineService);
380
393
  /**
381
394
  * 设置模块配置
382
395
  */
@@ -448,7 +461,22 @@ declare class CapabilityService implements OnModuleInit, OnModuleDestroy {
448
461
  * - 如果插件不支持,则包装 runStream/run 为 StreamEvent
449
462
  */
450
463
  private executeCallStreamWithEvents;
464
+ /**
465
+ * 从错误对象提取错误信息
466
+ * 支持 PluginError 和 RateLimitError
467
+ */
468
+ private extractErrorInfo;
451
469
  private buildActionContext;
470
+ /**
471
+ * 为指定插件创建独立的 HttpClient 实例
472
+ * 自动添加 x-plugin-key header
473
+ */
474
+ private createPluginHttpClient;
475
+ /**
476
+ * 将 HttpClient 包装为受保护的 PlatformHttpClient
477
+ * 只暴露请求方法,不暴露 interceptors
478
+ */
479
+ private wrapAsProtectedClient;
452
480
  private getUserContext;
453
481
  }
454
482
 
package/dist/index.js CHANGED
@@ -14,7 +14,9 @@ var ErrorCodes = {
14
14
  /** 参数验证失败 */
15
15
  PARAMS_VALIDATION_ERROR: "k_ec_cap_004",
16
16
  /** 执行失败 */
17
- EXECUTION_ERROR: "k_ec_cap_005"
17
+ EXECUTION_ERROR: "k_ec_cap_005",
18
+ /** 计费受限 */
19
+ RATE_LIMIT_EXCEEDED: "k_ec_cap_006"
18
20
  };
19
21
 
20
22
  // src/services/template-engine.service.ts
@@ -380,7 +382,7 @@ PluginLoaderService = _ts_decorate2([
380
382
 
381
383
  // src/services/capability.service.ts
382
384
  import { Injectable as Injectable3, Logger as Logger2, Inject } from "@nestjs/common";
383
- import { RequestContextService, PLATFORM_HTTP_CLIENT } from "@lark-apaas/nestjs-common";
385
+ import { RequestContextService, HTTP_CLIENT_FACTORY } from "@lark-apaas/nestjs-common";
384
386
  import * as fs2 from "fs";
385
387
  import * as path2 from "path";
386
388
  import * as chokidar from "chokidar";
@@ -489,7 +491,7 @@ var CapabilityService = class _CapabilityService {
489
491
  __name(this, "CapabilityService");
490
492
  }
491
493
  requestContextService;
492
- platformHttpClient;
494
+ httpClientFactory;
493
495
  pluginLoaderService;
494
496
  templateEngineService;
495
497
  logger = new Logger2(_CapabilityService.name);
@@ -499,9 +501,9 @@ var CapabilityService = class _CapabilityService {
499
501
  capabilitiesDir;
500
502
  fileWatcher = null;
501
503
  options = {};
502
- constructor(requestContextService, platformHttpClient, pluginLoaderService, templateEngineService) {
504
+ constructor(requestContextService, httpClientFactory, pluginLoaderService, templateEngineService) {
503
505
  this.requestContextService = requestContextService;
504
- this.platformHttpClient = platformHttpClient;
506
+ this.httpClientFactory = httpClientFactory;
505
507
  this.pluginLoaderService = pluginLoaderService;
506
508
  this.templateEngineService = templateEngineService;
507
509
  const isDev = process.env.NODE_ENV === "development";
@@ -741,7 +743,7 @@ var CapabilityService = class _CapabilityService {
741
743
  if (!pluginInstance.hasAction(actionName)) {
742
744
  throw new ActionNotFoundError(config.pluginKey, actionName);
743
745
  }
744
- const context = this.buildActionContext(contextOverride);
746
+ const context = this.buildActionContext(config.pluginKey, contextOverride);
745
747
  const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;
746
748
  this.logger.log("Executing capability (call)", {
747
749
  ...loggerContext,
@@ -791,7 +793,7 @@ var CapabilityService = class _CapabilityService {
791
793
  if (!pluginInstance.hasAction(actionName)) {
792
794
  throw new ActionNotFoundError(config.pluginKey, actionName);
793
795
  }
794
- const context = this.buildActionContext(contextOverride);
796
+ const context = this.buildActionContext(config.pluginKey, contextOverride);
795
797
  const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;
796
798
  this.logger.log("Executing capability (stream)", {
797
799
  ...loggerContext,
@@ -841,7 +843,7 @@ var CapabilityService = class _CapabilityService {
841
843
  if (!pluginInstance.hasAction(actionName)) {
842
844
  throw new ActionNotFoundError(config.pluginKey, actionName);
843
845
  }
844
- const context = this.buildActionContext(contextOverride);
846
+ const context = this.buildActionContext(config.pluginKey, contextOverride);
845
847
  const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;
846
848
  this.logger.log("Executing capability (streamWithEvents)", {
847
849
  ...loggerContext,
@@ -907,21 +909,69 @@ var CapabilityService = class _CapabilityService {
907
909
  });
908
910
  yield {
909
911
  type: "error",
910
- error: {
911
- code: "EXECUTION_ERROR",
912
- message: error instanceof Error ? error.message : String(error)
913
- }
912
+ error: this.extractErrorInfo(error)
914
913
  };
915
914
  }
916
915
  }
917
- buildActionContext(override) {
916
+ /**
917
+ * 从错误对象提取错误信息
918
+ * 支持 PluginError 和 RateLimitError
919
+ */
920
+ extractErrorInfo(error) {
921
+ const err = error;
922
+ const code = err?.code ?? "EXECUTION_ERROR";
923
+ const message = err instanceof Error ? err.message : String(err);
924
+ if (code === "RATE_LIMIT_EXCEEDED" && err?.rateLimitCode) {
925
+ return {
926
+ code,
927
+ message,
928
+ rateLimitCode: err.rateLimitCode,
929
+ rateLimitMessage: err.rateLimitMessage
930
+ };
931
+ }
918
932
  return {
933
+ code,
934
+ message
935
+ };
936
+ }
937
+ buildActionContext(pluginKey, override) {
938
+ return {
939
+ pluginKey,
919
940
  logger: this.logger,
920
- platformHttpClient: this.platformHttpClient,
941
+ platformHttpClient: this.createPluginHttpClient(pluginKey),
921
942
  userContext: override?.userContext ?? this.getUserContext(),
922
943
  isDebug: override?.isDebug ?? false
923
944
  };
924
945
  }
946
+ /**
947
+ * 为指定插件创建独立的 HttpClient 实例
948
+ * 自动添加 x-plugin-key header
949
+ */
950
+ createPluginHttpClient(pluginKey) {
951
+ const client = this.httpClientFactory.create();
952
+ client.interceptors.request.use((config) => {
953
+ config.headers = {
954
+ ...config.headers,
955
+ "x-plugin-key": pluginKey
956
+ };
957
+ return config;
958
+ });
959
+ return this.wrapAsProtectedClient(client);
960
+ }
961
+ /**
962
+ * 将 HttpClient 包装为受保护的 PlatformHttpClient
963
+ * 只暴露请求方法,不暴露 interceptors
964
+ */
965
+ wrapAsProtectedClient(client) {
966
+ return {
967
+ request: /* @__PURE__ */ __name((config) => client.request(config), "request"),
968
+ get: /* @__PURE__ */ __name((url, config) => client.get(url, config), "get"),
969
+ post: /* @__PURE__ */ __name((url, data, config) => client.post(url, data, config), "post"),
970
+ put: /* @__PURE__ */ __name((url, data, config) => client.put(url, data, config), "put"),
971
+ patch: /* @__PURE__ */ __name((url, data, config) => client.patch(url, data, config), "patch"),
972
+ delete: /* @__PURE__ */ __name((url, config) => client.delete(url, config), "delete")
973
+ };
974
+ }
925
975
  getUserContext() {
926
976
  const ctx = this.requestContextService.getContext();
927
977
  return {
@@ -933,11 +983,11 @@ var CapabilityService = class _CapabilityService {
933
983
  };
934
984
  CapabilityService = _ts_decorate3([
935
985
  Injectable3(),
936
- _ts_param(1, Inject(PLATFORM_HTTP_CLIENT)),
986
+ _ts_param(1, Inject(HTTP_CLIENT_FACTORY)),
937
987
  _ts_metadata("design:type", Function),
938
988
  _ts_metadata("design:paramtypes", [
939
989
  typeof RequestContextService === "undefined" ? Object : RequestContextService,
940
- typeof PlatformHttpClient === "undefined" ? Object : PlatformHttpClient,
990
+ typeof HttpClientFactory === "undefined" ? Object : HttpClientFactory,
941
991
  typeof PluginLoaderService === "undefined" ? Object : PluginLoaderService,
942
992
  typeof TemplateEngineService === "undefined" ? Object : TemplateEngineService
943
993
  ])
@@ -1078,6 +1128,14 @@ var DebugController = class _DebugController {
1078
1128
  error_msg: `Action '${error.actionName}' not found in plugin ${error.pluginKey}`
1079
1129
  };
1080
1130
  }
1131
+ const err = error;
1132
+ if (err?.code === "RATE_LIMIT_EXCEEDED" && err?.rateLimitCode) {
1133
+ return {
1134
+ status_code: err.rateLimitCode,
1135
+ error_msg: err.rateLimitMessage || err.message,
1136
+ is_rate_limit_error: true
1137
+ };
1138
+ }
1081
1139
  return {
1082
1140
  status_code: ErrorCodes.EXECUTION_ERROR,
1083
1141
  error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`
@@ -1146,13 +1204,15 @@ var DebugController = class _DebugController {
1146
1204
  return;
1147
1205
  }
1148
1206
  case "error": {
1207
+ const isRateLimitError = event.error.code === "RATE_LIMIT_EXCEEDED" && !!event.error.rateLimitCode;
1149
1208
  const response = {
1150
1209
  status_code: ErrorCodes.SUCCESS,
1151
1210
  data: {
1152
1211
  type: "error",
1153
1212
  error: {
1154
- code: 0,
1155
- message: event.error.message
1213
+ code: isRateLimitError ? event.error.rateLimitCode : event.error.code,
1214
+ message: isRateLimitError ? event.error.rateLimitMessage : event.error.message,
1215
+ isRateLimitError: isRateLimitError || void 0
1156
1216
  }
1157
1217
  }
1158
1218
  };
@@ -1179,14 +1239,16 @@ var DebugController = class _DebugController {
1179
1239
  }
1180
1240
  res.end();
1181
1241
  } catch (error) {
1182
- const errorMsg = error instanceof Error ? error.message : String(error);
1242
+ const err = error;
1243
+ const isRateLimitError = err?.code === "RATE_LIMIT_EXCEEDED" && !!err?.rateLimitCode;
1183
1244
  const response = {
1184
1245
  status_code: ErrorCodes.SUCCESS,
1185
1246
  data: {
1186
1247
  type: "error",
1187
1248
  error: {
1188
- code: 0,
1189
- message: errorMsg
1249
+ code: isRateLimitError ? err.rateLimitCode : err?.code ?? "EXECUTION_ERROR",
1250
+ message: isRateLimitError ? err.rateLimitMessage : error instanceof Error ? error.message : String(error),
1251
+ isRateLimitError: isRateLimitError || void 0
1190
1252
  }
1191
1253
  }
1192
1254
  };
@@ -1330,6 +1392,14 @@ var WebhookController = class _WebhookController {
1330
1392
  error_msg: `Action '${error.actionName}' not found in plugin ${error.pluginKey}`
1331
1393
  };
1332
1394
  }
1395
+ const err = error;
1396
+ if (err?.code === "RATE_LIMIT_EXCEEDED" && err?.rateLimitCode) {
1397
+ return {
1398
+ status_code: err.rateLimitCode,
1399
+ error_msg: err.rateLimitMessage || err.message,
1400
+ is_rate_limit_error: true
1401
+ };
1402
+ }
1333
1403
  return {
1334
1404
  status_code: ErrorCodes.EXECUTION_ERROR,
1335
1405
  error_msg: `Execution failed: ${error instanceof Error ? error.message : String(error)}`
@@ -1392,13 +1462,15 @@ var WebhookController = class _WebhookController {
1392
1462
  return;
1393
1463
  }
1394
1464
  case "error": {
1465
+ const isRateLimitError = event.error.code === "RATE_LIMIT_EXCEEDED" && !!event.error.rateLimitCode;
1395
1466
  const response = {
1396
1467
  status_code: ErrorCodes.SUCCESS,
1397
1468
  data: {
1398
1469
  type: "error",
1399
1470
  error: {
1400
- code: 0,
1401
- message: event.error.message
1471
+ code: isRateLimitError ? event.error.rateLimitCode : event.error.code,
1472
+ message: isRateLimitError ? event.error.rateLimitMessage : event.error.message,
1473
+ isRateLimitError: isRateLimitError || void 0
1402
1474
  }
1403
1475
  }
1404
1476
  };
@@ -1425,14 +1497,16 @@ var WebhookController = class _WebhookController {
1425
1497
  }
1426
1498
  res.end();
1427
1499
  } catch (error) {
1428
- const errorMsg = error instanceof Error ? error.message : String(error);
1500
+ const err = error;
1501
+ const isRateLimitError = err?.code === "RATE_LIMIT_EXCEEDED" && !!err?.rateLimitCode;
1429
1502
  const response = {
1430
1503
  status_code: ErrorCodes.SUCCESS,
1431
1504
  data: {
1432
1505
  type: "error",
1433
1506
  error: {
1434
- code: 0,
1435
- message: errorMsg
1507
+ code: isRateLimitError ? err.rateLimitCode : err?.code ?? "EXECUTION_ERROR",
1508
+ message: isRateLimitError ? err.rateLimitMessage : error instanceof Error ? error.message : String(error),
1509
+ isRateLimitError: isRateLimitError || void 0
1436
1510
  }
1437
1511
  }
1438
1512
  };
@@ -1489,7 +1563,7 @@ WebhookController = _ts_decorate5([
1489
1563
 
1490
1564
  // src/capability.module.ts
1491
1565
  import { Module } from "@nestjs/common";
1492
- import { CommonModule, RequestContextService as RequestContextService2, PLATFORM_HTTP_CLIENT as PLATFORM_HTTP_CLIENT2 } from "@lark-apaas/nestjs-common";
1566
+ import { CommonModule, RequestContextService as RequestContextService2, HTTP_CLIENT_FACTORY as HTTP_CLIENT_FACTORY2 } from "@lark-apaas/nestjs-common";
1493
1567
  function _ts_decorate6(decorators, target, key, desc) {
1494
1568
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1495
1569
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -1527,8 +1601,8 @@ var CapabilityModule = class _CapabilityModule {
1527
1601
  },
1528
1602
  {
1529
1603
  provide: CapabilityService,
1530
- useFactory: /* @__PURE__ */ __name((requestContextService, httpClient, pluginLoader, templateEngine, moduleOptions) => {
1531
- const service = new CapabilityService(requestContextService, httpClient, pluginLoader, templateEngine);
1604
+ useFactory: /* @__PURE__ */ __name((requestContextService, httpClientFactory, pluginLoader, templateEngine, moduleOptions) => {
1605
+ const service = new CapabilityService(requestContextService, httpClientFactory, pluginLoader, templateEngine);
1532
1606
  if (moduleOptions) {
1533
1607
  service.setOptions(moduleOptions);
1534
1608
  }
@@ -1536,7 +1610,7 @@ var CapabilityModule = class _CapabilityModule {
1536
1610
  }, "useFactory"),
1537
1611
  inject: [
1538
1612
  RequestContextService2,
1539
- PLATFORM_HTTP_CLIENT2,
1613
+ HTTP_CLIENT_FACTORY2,
1540
1614
  PluginLoaderService,
1541
1615
  TemplateEngineService,
1542
1616
  CAPABILITY_OPTIONS