@lark-apaas/client-capability 0.1.6 → 0.1.7-alpha.1

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 CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
9
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
@@ -17,6 +19,14 @@ var __copyProps = (to, from, except, desc) => {
17
19
  }
18
20
  return to;
19
21
  };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
+ // If the importer is in node compatibility mode or this is not an ESM
24
+ // file that has been converted to a CommonJS file using a Babel-
25
+ // compatible transform (i.e. "__esModule" has not been set), then set
26
+ // "default" to the CommonJS "module.exports" for node compatibility.
27
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
+ mod
29
+ ));
20
30
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
31
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
22
32
 
@@ -314,6 +324,7 @@ __name(replaceFilesWithUrls, "replaceFilesWithUrls");
314
324
 
315
325
  // src/client.ts
316
326
  var import_internal_slardar2 = require("@lark-apaas/internal-slardar");
327
+ var import_virtual_capabilities = __toESM(require("virtual:capabilities"), 1);
317
328
  var LOG_PREFIX = "[CapabilityClient]";
318
329
  var defaultLogger = {
319
330
  debug: console.debug.bind(console),
@@ -327,17 +338,89 @@ var _CapabilityClient = class _CapabilityClient {
327
338
  __publicField(this, "baseURL");
328
339
  __publicField(this, "logger");
329
340
  __publicField(this, "onRateLimitError");
341
+ __publicField(this, "central");
330
342
  this.options = options;
331
343
  this.baseURL = (options?.baseURL ?? "").replace(/\/+$/, "");
332
344
  this.logger = options?.logger ?? defaultLogger;
333
345
  this.onRateLimitError = options?.onRateLimitError;
346
+ if (options?.central?.enabled) {
347
+ this.central = options.central;
348
+ }
349
+ }
350
+ /**
351
+ * central.baseURL → caller 显式给的(去尾斜杠)。
352
+ * 没传:浏览器取 `window.location.origin`(同源调用,SSO cookie 自动带);
353
+ * 非浏览器(SSR / Node.js 测试)抛错。
354
+ * 用法与 fullstack-plugin/packages/client/dataloom/src/service/index.ts 一致。
355
+ */
356
+ resolveCentralBaseURL(central) {
357
+ if (central.baseURL) return central.baseURL.replace(/\/+$/, "");
358
+ if (typeof window !== "undefined" && window.location?.origin) {
359
+ return window.location.origin;
360
+ }
361
+ throw new Error("CapabilityClient: central.baseURL is required when running outside browser (window.location unavailable)");
362
+ }
363
+ /**
364
+ * 预览态 / 运行态自动判定。沿用 nestjs-capability/src/capability.module.ts:18 同款判定:
365
+ * - 沙箱 fullstack-cli scripts/dev.sh → `NODE_ENV=development` → 预览态
366
+ * - 运行态(npm start / build 后部署)→ `NODE_ENV=production` → 运行态
367
+ * Vite 在构建时把 `process.env.NODE_ENV` 替换为字面量字符串。
368
+ */
369
+ resolveMode() {
370
+ const env = typeof process !== "undefined" ? "development" : void 0;
371
+ return env === "development" ? "preview" : "runtime";
372
+ }
373
+ /**
374
+ * 构造单次调用的请求 URL:
375
+ * - central 开启:4 个中心端点之一(mode 自动判定);
376
+ * - central 关闭:保持原 `${baseURL}/api/capability/{id}` 行为。
377
+ */
378
+ buildExecuteUrl(capabilityId, stream) {
379
+ if (!this.central) {
380
+ return `${this.baseURL}/api/capability/${capabilityId}${stream ? "/stream" : ""}`;
381
+ }
382
+ const base = this.resolveCentralBaseURL(this.central);
383
+ const segment = this.resolveMode() === "preview" ? "/preview/execute" : "/execute";
384
+ return `${base}/app/${this.central.appId}/__runtime__/api/v1/plugin_server/capability/${capabilityId}${segment}${stream ? "/stream" : ""}`;
385
+ }
386
+ /**
387
+ * 构造请求体:
388
+ * - central + 预览态:`{ capability, action, params }`,capability 取自
389
+ * `virtual:capabilities`(load() 时已经 fail-fast 校验过,这里直接取)。
390
+ * - central + 运行态:`{ action, params }`(中心服务通过 RPC 查中心存储拿 config)。
391
+ * - 非 central:`{ action, params }`。
392
+ */
393
+ buildRequestBody(capabilityId, action, params) {
394
+ if (this.central && this.resolveMode() === "preview") {
395
+ const capability = import_virtual_capabilities.default[capabilityId];
396
+ if (!capability) {
397
+ throw new CapabilityNotFoundError(capabilityId);
398
+ }
399
+ return JSON.stringify({
400
+ capability,
401
+ action,
402
+ params
403
+ });
404
+ }
405
+ return JSON.stringify({
406
+ action,
407
+ params
408
+ });
334
409
  }
335
410
  /**
336
- * 加载能力,返回执行器
337
- * @param capabilityId - 能力 ID
338
- * @returns 能力执行器
411
+ * 加载能力,返回执行器。
412
+ * 方案文档 § Client SDK 改造伪代码:
413
+ * const config = capabilityMap[id];
414
+ * if (!config) throw new CapabilityNotFoundError(id);
415
+ * central + 预览态时 fail-fast:本地 `virtual:capabilities` map 没这个 id 就直接抛,
416
+ * 不发任何网络请求。运行态 / 非 central 模式跳过此校验。
339
417
  */
340
418
  load(capabilityId) {
419
+ if (this.central && this.resolveMode() === "preview") {
420
+ if (!(capabilityId in import_virtual_capabilities.default)) {
421
+ throw new CapabilityNotFoundError(capabilityId);
422
+ }
423
+ }
341
424
  return this.createExecutor(capabilityId);
342
425
  }
343
426
  createExecutor(capabilityId) {
@@ -351,7 +434,7 @@ var _CapabilityClient = class _CapabilityClient {
351
434
  };
352
435
  }
353
436
  async executeCall(capabilityId, action, params) {
354
- const url = `${this.baseURL}/api/capability/${capabilityId}`;
437
+ const url = this.buildExecuteUrl(capabilityId, false);
355
438
  let requestParams = params ?? {};
356
439
  const extractedFiles = extractFiles(requestParams);
357
440
  if (extractedFiles.length > 0) {
@@ -372,10 +455,7 @@ var _CapabilityClient = class _CapabilityClient {
372
455
  "Content-Type": "application/json",
373
456
  ...this.options.fetchOptions?.headers
374
457
  },
375
- body: JSON.stringify({
376
- action,
377
- params: requestParams
378
- })
458
+ body: this.buildRequestBody(capabilityId, action, requestParams)
379
459
  });
380
460
  const data = await response.json();
381
461
  if (!response.ok || data.status_code !== ErrorCodes.SUCCESS) {
@@ -420,7 +500,7 @@ var _CapabilityClient = class _CapabilityClient {
420
500
  }
421
501
  }
422
502
  async *executeCallStream(capabilityId, action, params) {
423
- const url = `${this.baseURL}/api/capability/${capabilityId}/stream`;
503
+ const url = this.buildExecuteUrl(capabilityId, true);
424
504
  let requestParams = params ?? {};
425
505
  const extractedFiles = extractFiles(requestParams);
426
506
  if (extractedFiles.length > 0) {
@@ -433,6 +513,7 @@ var _CapabilityClient = class _CapabilityClient {
433
513
  this.logger.info(LOG_PREFIX, `callStream start: capabilityId=${capabilityId}, action=${action}`, {
434
514
  params: requestParams
435
515
  });
516
+ const body = this.buildRequestBody(capabilityId, action, requestParams);
436
517
  let response;
437
518
  try {
438
519
  response = await fetch(url, {
@@ -442,10 +523,7 @@ var _CapabilityClient = class _CapabilityClient {
442
523
  "Content-Type": "application/json",
443
524
  ...this.options.fetchOptions?.headers
444
525
  },
445
- body: JSON.stringify({
446
- action,
447
- params: requestParams
448
- })
526
+ body
449
527
  });
450
528
  } catch (error) {
451
529
  this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/errors.ts","../src/uploader.ts","../src/file-extractor.ts","../src/client.ts"],"sourcesContent":["// 客户端\nexport { createClient, CapabilityClient } from './client';\n\n// 类型\nexport type { CapabilityClientOptions, CapabilityExecutor, Logger, RateLimitErrorHook } from './types';\n\n// 错误类型\nexport {\n CapabilityError,\n CapabilityNotFoundError,\n ActionNotFoundError,\n NetworkError,\n ExecutionError,\n FileUploadError,\n RateLimitError,\n} from './errors';\n","import type { RateLimitError } from './errors';\n\n/**\n * Logger 接口,兼容 console 和 @lark-apaas/toolkit 的 logger\n */\nexport interface Logger {\n debug(message: unknown, ...args: unknown[]): void;\n info(message: unknown, ...args: unknown[]): void;\n warn(message: unknown, ...args: unknown[]): void;\n error(message: unknown, ...args: unknown[]): void;\n}\n\n/**\n * RateLimitError 钩子函数类型\n * 当检测到计费受限错误时,在抛出异常前调用此钩子\n */\nexport type RateLimitErrorHook = (error: RateLimitError) => void | Promise<void>;\n\n/**\n * 客户端配置选项\n */\nexport interface CapabilityClientOptions {\n /** 全局路径前缀,默认 ''。例如线上环境可设置为 '/spark/a' */\n baseURL?: string;\n /** 获取文件上传预签名 URL 的接口地址,由上层注入 */\n acquireUploadUrl: string;\n /** 获取文件临时下载 URL 的接口地址,由上层注入 */\n acquireDownloadUrl: string;\n /** 自定义 fetch 配置 */\n fetchOptions?: RequestInit;\n /** 自定义 logger,默认使用 console */\n logger?: Logger;\n /**\n * 计费受限错误钩子\n * 当检测到 RateLimitError 时,在抛出异常前调用此钩子\n * 可用于上报埋点、展示 toast 等场景\n */\n onRateLimitError?: RateLimitErrorHook;\n}\n\n/**\n * 能力执行器接口\n */\nexport interface CapabilityExecutor {\n /**\n * 调用能力\n * @param action - Action 名称\n * @param params - 输入参数\n * @returns Action 执行结果\n */\n call<T = unknown>(\n action: string,\n params?: Record<string, unknown>\n ): Promise<T>;\n\n /**\n * 流式调用能力\n * @param action - Action 名称\n * @param params - 输入参数\n * @returns AsyncIterable,逐个 yield chunk\n */\n callStream<T = unknown>(\n action: string,\n params?: Record<string, unknown>\n ): AsyncIterable<T>;\n}\n\n// ========== API 响应类型 ==========\n\n/**\n * 成功响应\n */\nexport interface SuccessResponse<T> {\n status_code: '0';\n data: T;\n}\n\n/**\n * 错误响应\n */\nexport interface ErrorResponse {\n status_code: string;\n error_msg: string;\n /** 是否为计费受限错误 */\n is_rate_limit_error?: boolean;\n}\n\n/**\n * API 响应类型\n */\nexport type ApiResponse<T> = SuccessResponse<T> | ErrorResponse;\n\n// ========== 具体响应 data 结构 ==========\n\n/**\n * 执行接口响应 data 结构\n */\nexport interface ExecuteResponseData {\n output: unknown;\n}\n\n// ========== 流式响应结构 ==========\n\n/**\n * 流式内容响应\n */\nexport interface StreamContentResponse {\n status_code: '0';\n data: {\n type: 'content';\n delta: unknown;\n finished?: boolean;\n };\n}\n\n/**\n * 流式错误响应\n */\nexport interface StreamErrorResponse {\n status_code: '0';\n data: {\n type: 'error';\n error: {\n /** 错误码,计费受限时为业务错误码(如 k_st_ec_400002687) */\n code: string;\n message: string;\n /** 是否为计费受限错误 */\n isRateLimitError?: boolean;\n };\n };\n}\n\n/**\n * 流式响应类型\n */\nexport type StreamResponse = StreamContentResponse | StreamErrorResponse;\n\n// ========== 错误码 ==========\n\n/**\n * 后端错误码\n */\nexport const ErrorCodes = {\n SUCCESS: '0',\n CAPABILITY_NOT_FOUND: 'k_ec_cap_001',\n PLUGIN_NOT_FOUND: 'k_ec_cap_002',\n ACTION_NOT_FOUND: 'k_ec_cap_003',\n PARAMS_VALIDATION_ERROR: 'k_ec_cap_004',\n EXECUTION_ERROR: 'k_ec_cap_005',\n RATE_LIMIT_EXCEEDED: 'k_ec_cap_006',\n} as const;\n\n// ========== 文件上传相关类型 ==========\n\n/**\n * 提取的文件信息\n */\nexport interface ExtractedFile {\n /** 在 params 中的路径,如 ['image_list', 0] */\n path: (string | number)[];\n /** 文件对象 */\n file: File | Blob;\n}\n\n/**\n * 上传结果\n */\nexport interface UploadResult {\n /** 在 params 中的路径 */\n path: (string | number)[];\n /** 临时下载 URL */\n downloadUrl: string;\n}\n\n/**\n * 获取上传 URL 响应\n */\nexport interface AcquireUploadUrlResponse {\n status_code: string;\n data: {\n uploadURL: string;\n objectKey: string;\n };\n}\n\n/**\n * 获取下载 URL 响应\n */\nexport interface AcquireDownloadUrlResponse {\n status_code: string;\n data: {\n downloadURL: string;\n };\n}\n","/**\n * 能力调用错误基类\n */\nexport class CapabilityError extends Error {\n /** 错误码 */\n code: string;\n /** HTTP 状态码 */\n statusCode?: number;\n\n constructor(message: string, code: string, statusCode?: number) {\n super(message);\n this.name = 'CapabilityError';\n this.code = code;\n this.statusCode = statusCode;\n }\n}\n\n/**\n * 能力不存在错误\n */\nexport class CapabilityNotFoundError extends CapabilityError {\n constructor(capabilityId: string, statusCode?: number) {\n super(`Capability not found: ${capabilityId}`, 'CAPABILITY_NOT_FOUND', statusCode);\n this.name = 'CapabilityNotFoundError';\n }\n}\n\n/**\n * Action 不存在错误\n */\nexport class ActionNotFoundError extends CapabilityError {\n constructor(message: string, statusCode?: number) {\n super(message, 'ACTION_NOT_FOUND', statusCode);\n this.name = 'ActionNotFoundError';\n }\n}\n\n/**\n * 网络错误\n */\nexport class NetworkError extends CapabilityError {\n constructor(message: string) {\n super(message, 'NETWORK_ERROR');\n this.name = 'NetworkError';\n }\n}\n\n/**\n * 执行错误\n */\nexport class ExecutionError extends CapabilityError {\n constructor(message: string, statusCode?: number) {\n super(message, 'EXECUTION_ERROR', statusCode);\n this.name = 'ExecutionError';\n }\n}\n\n/**\n * 文件上传错误\n */\nexport class FileUploadError extends CapabilityError {\n constructor(message: string, statusCode?: number) {\n super(message, 'FILE_UPLOAD_ERROR', statusCode);\n this.name = 'FileUploadError';\n }\n}\n\n/**\n * 计费受限错误\n */\nexport class RateLimitError extends CapabilityError {\n /** 业务错误码 */\n rateLimitCode: string;\n /** 业务错误消息 */\n rateLimitMessage: string;\n\n constructor(rateLimitCode: string, rateLimitMessage: string, statusCode?: number) {\n super(rateLimitMessage, 'RATE_LIMIT_EXCEEDED', statusCode);\n this.name = 'RateLimitError';\n this.rateLimitCode = rateLimitCode;\n this.rateLimitMessage = rateLimitMessage;\n }\n}\n","import type {\n CapabilityClientOptions,\n ExtractedFile,\n UploadResult,\n AcquireUploadUrlResponse,\n AcquireDownloadUrlResponse,\n} from './types';\nimport { FileUploadError } from './errors';\nimport { slardar } from '@lark-apaas/internal-slardar';\n\ntype FileUploaderOptions = Pick<CapabilityClientOptions, 'acquireUploadUrl' | 'acquireDownloadUrl' | 'fetchOptions'>;\n\n/**\n * 文件上传器\n */\nexport class FileUploader {\n private readonly options: FileUploaderOptions;\n\n constructor(options: FileUploaderOptions) {\n this.options = options;\n }\n\n /**\n * 上传单个文件,返回下载 URL\n */\n async upload(file: File | Blob): Promise<string> {\n const fileName = file instanceof File ? file.name : `blob-${Date.now()}`;\n\n // 1. 获取上传预签名 URL\n const { uploadURL, objectKey } = await this.fetchUploadUrl(fileName);\n\n // 2. 上传文件到 TOS\n await this.uploadToTos(uploadURL, file);\n\n // 3. 获取下载 URL\n const downloadUrl = await this.fetchDownloadUrl(objectKey);\n\n return downloadUrl;\n }\n\n /**\n * 并发上传多个文件\n */\n async uploadAll(files: ExtractedFile[]): Promise<UploadResult[]> {\n const results = await Promise.all(\n files.map(async ({ path, file }) => {\n const downloadUrl = await this.upload(file);\n return { path, downloadUrl };\n })\n );\n return results;\n }\n\n /**\n * 获取上传预签名 URL\n */\n private async fetchUploadUrl(fileName: string): Promise<{ uploadURL: string; objectKey: string }> {\n const { acquireUploadUrl, fetchOptions } = this.options;\n\n let response: Response;\n try {\n response = await fetch(acquireUploadUrl, {\n method: 'POST',\n ...fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...fetchOptions?.headers,\n },\n body: JSON.stringify({ fileName }),\n });\n } catch (error) {\n slardar.captureException(error, { source: 'client-capability', module: 'file-upload', step: 'fetch-upload-url' });\n throw new FileUploadError(\n `Failed to acquire upload URL: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n if (!response.ok) {\n throw new FileUploadError(\n `Failed to acquire upload URL: HTTP ${response.status}`,\n response.status\n );\n }\n\n const data = (await response.json()) as AcquireUploadUrlResponse;\n\n if (data.status_code !== '0') {\n throw new FileUploadError(`Failed to acquire upload URL: ${data.status_code}`);\n }\n\n return data.data;\n }\n\n /**\n * 上传文件到 TOS(预签名 URL)\n */\n private async uploadToTos(uploadURL: string, file: File | Blob): Promise<void> {\n let response: Response;\n try {\n response = await fetch(uploadURL, {\n method: 'PUT',\n body: file,\n });\n } catch (error) {\n slardar.captureException(error, { source: 'client-capability', module: 'file-upload', step: 'upload-to-tos' });\n throw new FileUploadError(\n `Failed to upload file to TOS: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n if (!response.ok) {\n throw new FileUploadError(\n `Failed to upload file to TOS: HTTP ${response.status}`,\n response.status\n );\n }\n }\n\n /**\n * 获取临时下载 URL\n */\n private async fetchDownloadUrl(objectKey: string): Promise<string> {\n const { acquireDownloadUrl, fetchOptions } = this.options;\n\n let response: Response;\n try {\n response = await fetch(acquireDownloadUrl, {\n method: 'POST',\n ...fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...fetchOptions?.headers,\n },\n body: JSON.stringify({ objectKey }),\n });\n } catch (error) {\n slardar.captureException(error, { source: 'client-capability', module: 'file-upload', step: 'fetch-download-url' });\n throw new FileUploadError(\n `Failed to acquire download URL: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n if (!response.ok) {\n throw new FileUploadError(\n `Failed to acquire download URL: HTTP ${response.status}`,\n response.status\n );\n }\n\n const data = (await response.json()) as AcquireDownloadUrlResponse;\n\n if (data.status_code !== '0') {\n throw new FileUploadError(`Failed to acquire download URL: ${data.status_code}`);\n }\n\n return data.data.downloadURL;\n }\n}\n","import type { ExtractedFile, UploadResult } from './types';\n\n/**\n * 检测是否为 File 或 Blob\n */\nexport function isFile(value: unknown): value is File | Blob {\n return value instanceof File || value instanceof Blob;\n}\n\n/**\n * 递归提取 params 中的所有文件\n *\n * @example\n * extractFiles({ image_list: [file1, file2] })\n * // => [\n * // { path: ['image_list', 0], file: file1 },\n * // { path: ['image_list', 1], file: file2 }\n * // ]\n */\nexport function extractFiles(params: Record<string, unknown>): ExtractedFile[] {\n const files: ExtractedFile[] = [];\n\n function traverse(obj: unknown, path: (string | number)[]): void {\n if (isFile(obj)) {\n files.push({ path: [...path], file: obj });\n } else if (Array.isArray(obj)) {\n obj.forEach((item, index) => traverse(item, [...path, index]));\n } else if (obj !== null && typeof obj === 'object') {\n Object.entries(obj).forEach(([key, value]) => {\n traverse(value, [...path, key]);\n });\n }\n }\n\n traverse(params, []);\n return files;\n}\n\n/**\n * 根据上传结果替换 params 中的文件为 URL\n *\n * @example\n * replaceFilesWithUrls(\n * { image_list: [file1, file2] },\n * [\n * { path: ['image_list', 0], downloadUrl: 'https://...' },\n * { path: ['image_list', 1], downloadUrl: 'https://...' }\n * ]\n * )\n * // => { image_list: ['https://...', 'https://...'] }\n */\nexport function replaceFilesWithUrls(\n params: Record<string, unknown>,\n results: UploadResult[]\n): Record<string, unknown> {\n // 创建 path -> url 的映射,用于快速查找\n const urlMap = new Map<string, string>();\n for (const { path, downloadUrl } of results) {\n urlMap.set(JSON.stringify(path), downloadUrl);\n }\n\n // 手动深拷贝,同时将 File/Blob 替换为对应的 URL\n // 注意:不能使用 structuredClone,因为它不支持 File/Blob 对象\n function cloneAndReplace(obj: unknown, currentPath: (string | number)[]): unknown {\n // 检查当前路径是否有对应的 URL\n const pathKey = JSON.stringify(currentPath);\n if (urlMap.has(pathKey)) {\n return urlMap.get(pathKey);\n }\n\n // 如果是 File/Blob 但没有对应的 URL(不应该发生),返回 null\n if (isFile(obj)) {\n return null;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item, index) => cloneAndReplace(item, [...currentPath, index]));\n }\n\n if (obj !== null && typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n result[key] = cloneAndReplace(value, [...currentPath, key]);\n }\n return result;\n }\n\n // 原始值直接返回\n return obj;\n }\n\n return cloneAndReplace(params, []) as Record<string, unknown>;\n}\n","import type {\n CapabilityClientOptions,\n CapabilityExecutor,\n ApiResponse,\n ExecuteResponseData,\n StreamResponse,\n Logger,\n RateLimitErrorHook,\n} from './types';\nimport { ErrorCodes } from './types';\nimport {\n CapabilityError,\n CapabilityNotFoundError,\n ActionNotFoundError,\n NetworkError,\n ExecutionError,\n RateLimitError,\n} from './errors';\nimport { FileUploader } from './uploader';\nimport { extractFiles, replaceFilesWithUrls } from './file-extractor';\nimport { slardar } from '@lark-apaas/internal-slardar';\n\nconst LOG_PREFIX = '[CapabilityClient]';\n\nconst defaultLogger: Logger = {\n debug: console.debug.bind(console),\n info: console.info.bind(console),\n warn: console.warn.bind(console),\n error: console.error.bind(console),\n};\n\n/**\n * 能力客户端\n */\nexport class CapabilityClient {\n private options: CapabilityClientOptions;\n private baseURL: string;\n private logger: Logger;\n private onRateLimitError?: RateLimitErrorHook;\n\n constructor(options: CapabilityClientOptions) {\n this.options = options;\n // 移除末尾的斜杠,确保拼接时格式正确\n this.baseURL = (options?.baseURL ?? '').replace(/\\/+$/, '');\n this.logger = options?.logger ?? defaultLogger;\n this.onRateLimitError = options?.onRateLimitError;\n }\n\n /**\n * 加载能力,返回执行器\n * @param capabilityId - 能力 ID\n * @returns 能力执行器\n */\n load(capabilityId: string): CapabilityExecutor {\n return this.createExecutor(capabilityId);\n }\n\n private createExecutor(capabilityId: string): CapabilityExecutor {\n return {\n call: <T = unknown>(action: string, params?: Record<string, unknown>) => {\n return this.executeCall<T>(capabilityId, action, params);\n },\n callStream: <T = unknown>(action: string, params?: Record<string, unknown>) => {\n return this.executeCallStream<T>(capabilityId, action, params);\n },\n };\n }\n\n private async executeCall<T>(\n capabilityId: string,\n action: string,\n params?: Record<string, unknown>\n ): Promise<T> {\n const url = `${this.baseURL}/api/capability/${capabilityId}`;\n let requestParams = params ?? {};\n\n // 处理文件上传\n const extractedFiles = extractFiles(requestParams);\n if (extractedFiles.length > 0) {\n this.logger.info(LOG_PREFIX, `uploading ${extractedFiles.length} file(s)...`);\n const uploader = new FileUploader(this.options);\n const uploadResults = await uploader.uploadAll(extractedFiles);\n requestParams = replaceFilesWithUrls(requestParams, uploadResults);\n this.logger.info(LOG_PREFIX, `file upload completed`);\n }\n\n this.logger.info(LOG_PREFIX, `call start: capabilityId=${capabilityId}, action=${action}`, { params: requestParams });\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n ...this.options.fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...this.options.fetchOptions?.headers,\n },\n body: JSON.stringify({\n action,\n params: requestParams,\n }),\n });\n\n const data = (await response.json()) as ApiResponse<ExecuteResponseData>;\n\n if (!response.ok || data.status_code !== ErrorCodes.SUCCESS) {\n const errorResponse = data as {\n status_code: string;\n error_msg: string;\n is_rate_limit_error?: boolean;\n };\n const errorCode = errorResponse.status_code;\n\n // 计费受限错误:通过 is_rate_limit_error 字段识别\n if (errorResponse.is_rate_limit_error) {\n const rateLimitError = new RateLimitError(\n errorCode, // status_code 就是业务错误码\n errorResponse.error_msg,\n response.status,\n );\n await this.onRateLimitError?.(rateLimitError);\n throw rateLimitError;\n }\n\n switch (errorCode) {\n case ErrorCodes.CAPABILITY_NOT_FOUND:\n throw new CapabilityNotFoundError(capabilityId, response.status);\n case ErrorCodes.ACTION_NOT_FOUND:\n throw new ActionNotFoundError(errorResponse.error_msg, response.status);\n case ErrorCodes.PLUGIN_NOT_FOUND:\n case ErrorCodes.EXECUTION_ERROR:\n default:\n throw new ExecutionError(errorResponse.error_msg, response.status);\n }\n }\n\n const result = (data as { data: ExecuteResponseData }).data.output as T;\n\n this.logger.info(LOG_PREFIX, `call success: capabilityId=${capabilityId}, action=${action}`, { result });\n\n return result;\n } catch (error) {\n this.logger.error(LOG_PREFIX, `call failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error });\n slardar.captureException(error, { source: 'client-capability', module: 'execute-call', capabilityId, action });\n if (error instanceof CapabilityError) {\n throw error;\n }\n throw new NetworkError(error instanceof Error ? error.message : String(error));\n }\n }\n\n private async *executeCallStream<T>(\n capabilityId: string,\n action: string,\n params?: Record<string, unknown>\n ): AsyncIterable<T> {\n const url = `${this.baseURL}/api/capability/${capabilityId}/stream`;\n let requestParams = params ?? {};\n\n // 处理文件上传\n const extractedFiles = extractFiles(requestParams);\n if (extractedFiles.length > 0) {\n this.logger.info(LOG_PREFIX, `uploading ${extractedFiles.length} file(s)...`);\n const uploader = new FileUploader(this.options);\n const uploadResults = await uploader.uploadAll(extractedFiles);\n requestParams = replaceFilesWithUrls(requestParams, uploadResults);\n this.logger.info(LOG_PREFIX, `file upload completed`);\n }\n\n this.logger.info(LOG_PREFIX, `callStream start: capabilityId=${capabilityId}, action=${action}`, { params: requestParams });\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n ...this.options.fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...this.options.fetchOptions?.headers,\n },\n body: JSON.stringify({\n action,\n params: requestParams,\n }),\n });\n } catch (error) {\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error });\n slardar.captureException(error, { source: 'client-capability', module: 'execute-call-stream', capabilityId, action, phase: 'fetch' });\n throw new NetworkError(error instanceof Error ? error.message : String(error));\n }\n\n if (!response.ok) {\n const errMsg = `HTTP ${response.status} ${response.statusText}`;\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error: errMsg });\n throw new NetworkError(errMsg);\n }\n\n if (!response.body) {\n const errMsg = 'Response body is null';\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error: errMsg });\n throw new NetworkError(errMsg);\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let chunkCount = 0;\n let aggregatedContent = '';\n let canAggregate = true;\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n\n try {\n const parsed = JSON.parse(data) as StreamResponse;\n\n if (parsed.status_code === ErrorCodes.SUCCESS && parsed.data) {\n if (parsed.data.type === 'content') {\n chunkCount++;\n const delta = parsed.data.delta as T;\n\n // 尝试聚合 content 字段\n if (canAggregate) {\n const content = (delta as Record<string, unknown>)?.content;\n if (typeof content === 'string') {\n aggregatedContent += content;\n } else {\n canAggregate = false;\n }\n }\n\n yield delta;\n\n if (parsed.data.finished) {\n const resultInfo = canAggregate\n ? { chunkCount, result: aggregatedContent }\n : { chunkCount, resultLength: aggregatedContent.length || chunkCount };\n this.logger.info(LOG_PREFIX, `callStream end: capabilityId=${capabilityId}, action=${action}`, resultInfo);\n return;\n }\n } else if (parsed.data.type === 'error') {\n const err = parsed.data.error;\n if (err.isRateLimitError) {\n const rateLimitError = new RateLimitError(\n err.code, // code 就是业务错误码\n err.message,\n );\n await this.onRateLimitError?.(rateLimitError);\n throw rateLimitError;\n }\n throw new ExecutionError(err.message);\n }\n }\n } catch (parseError) {\n if (parseError instanceof CapabilityError) {\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error: parseError, chunkCount });\n throw parseError;\n }\n // 忽略非 JSON 行\n }\n }\n }\n }\n const resultInfo = canAggregate\n ? { chunkCount, result: aggregatedContent }\n : { chunkCount, resultLength: aggregatedContent.length || chunkCount };\n this.logger.info(LOG_PREFIX, `callStream end: capabilityId=${capabilityId}, action=${action}`, resultInfo);\n } catch (error) {\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error, chunkCount });\n slardar.captureException(error, { source: 'client-capability', module: 'execute-call-stream', capabilityId, action, phase: 'read' });\n if (error instanceof CapabilityError) {\n throw error;\n }\n throw new NetworkError(error instanceof Error ? error.message : String(error));\n } finally {\n reader.releaseLock();\n }\n }\n}\n\n/**\n * 创建客户端实例\n */\nexport function createClient(options: CapabilityClientOptions): CapabilityClient {\n return new CapabilityClient(options);\n}\n"],"mappings":"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","names":["ErrorCodes","SUCCESS","CAPABILITY_NOT_FOUND","PLUGIN_NOT_FOUND","ACTION_NOT_FOUND","PARAMS_VALIDATION_ERROR","EXECUTION_ERROR","RATE_LIMIT_EXCEEDED","CapabilityError","Error","message","code","statusCode","name","CapabilityNotFoundError","capabilityId","ActionNotFoundError","NetworkError","ExecutionError","FileUploadError","RateLimitError","rateLimitCode","rateLimitMessage","FileUploader","options","upload","file","fileName","File","name","Date","now","uploadURL","objectKey","fetchUploadUrl","uploadToTos","downloadUrl","fetchDownloadUrl","uploadAll","files","results","Promise","all","map","path","acquireUploadUrl","fetchOptions","response","fetch","method","headers","body","JSON","stringify","error","slardar","captureException","source","module","step","FileUploadError","Error","message","String","ok","status","data","json","status_code","acquireDownloadUrl","downloadURL","isFile","value","File","Blob","extractFiles","params","files","traverse","obj","path","push","file","Array","isArray","forEach","item","index","Object","entries","key","replaceFilesWithUrls","results","urlMap","Map","downloadUrl","set","JSON","stringify","cloneAndReplace","currentPath","pathKey","has","get","map","result","import_internal_slardar","LOG_PREFIX","defaultLogger","debug","console","bind","info","warn","error","CapabilityClient","options","baseURL","logger","onRateLimitError","replace","load","capabilityId","createExecutor","call","action","params","executeCall","callStream","executeCallStream","url","requestParams","extractedFiles","extractFiles","length","uploader","FileUploader","uploadResults","uploadAll","replaceFilesWithUrls","response","fetch","method","fetchOptions","headers","body","JSON","stringify","data","json","ok","status_code","ErrorCodes","SUCCESS","errorResponse","errorCode","is_rate_limit_error","rateLimitError","RateLimitError","error_msg","status","CAPABILITY_NOT_FOUND","CapabilityNotFoundError","ACTION_NOT_FOUND","ActionNotFoundError","PLUGIN_NOT_FOUND","EXECUTION_ERROR","ExecutionError","result","output","slardar","captureException","source","module","CapabilityError","NetworkError","Error","message","String","phase","errMsg","statusText","reader","getReader","decoder","TextDecoder","buffer","chunkCount","aggregatedContent","canAggregate","done","value","read","decode","stream","lines","split","pop","line","startsWith","slice","parsed","parse","type","delta","content","finished","resultInfo","resultLength","err","isRateLimitError","code","parseError","releaseLock","createClient"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/errors.ts","../src/uploader.ts","../src/file-extractor.ts","../src/client.ts"],"sourcesContent":["// 客户端\nexport { createClient, CapabilityClient } from './client';\n\n// 类型\nexport type {\n CapabilityClientOptions,\n CapabilityExecutor,\n Logger,\n RateLimitErrorHook,\n CentralOptions,\n CapabilityConfig,\n} from './types';\n\n// 错误类型\nexport {\n CapabilityError,\n CapabilityNotFoundError,\n ActionNotFoundError,\n NetworkError,\n ExecutionError,\n FileUploadError,\n RateLimitError,\n} from './errors';\n","import type { RateLimitError } from './errors';\n\n/**\n * Logger 接口,兼容 console 和 @lark-apaas/toolkit 的 logger\n */\nexport interface Logger {\n debug(message: unknown, ...args: unknown[]): void;\n info(message: unknown, ...args: unknown[]): void;\n warn(message: unknown, ...args: unknown[]): void;\n error(message: unknown, ...args: unknown[]): void;\n}\n\n/**\n * RateLimitError 钩子函数类型\n * 当检测到计费受限错误时,在抛出异常前调用此钩子\n */\nexport type RateLimitErrorHook = (error: RateLimitError) => void | Promise<void>;\n\n/**\n * 客户端配置选项\n */\nexport interface CapabilityClientOptions {\n /** 全局路径前缀,默认 ''。例如线上环境可设置为 '/spark/a' */\n baseURL?: string;\n /** 获取文件上传预签名 URL 的接口地址,由上层注入 */\n acquireUploadUrl: string;\n /** 获取文件临时下载 URL 的接口地址,由上层注入 */\n acquireDownloadUrl: string;\n /** 自定义 fetch 配置 */\n fetchOptions?: RequestInit;\n /** 自定义 logger,默认使用 console */\n logger?: Logger;\n /**\n * 计费受限错误钩子\n * 当检测到 RateLimitError 时,在抛出异常前调用此钩子\n * 可用于上报埋点、展示 toast 等场景\n */\n onRateLimitError?: RateLimitErrorHook;\n /**\n * 中心化服务分流开关。启用后 capability 调用路由到妙搭 plugin_server 的 4 个中心端点:\n * - 运行态 非流式: POST {baseURL}/app/{appId}/__runtime__/api/v1/plugin_server/capability/{capabilityId}/execute\n * - 运行态 流式: POST {baseURL}/app/{appId}/__runtime__/api/v1/plugin_server/capability/{capabilityId}/execute/stream\n * - 预览态 非流式: POST {baseURL}/app/{appId}/__runtime__/api/v1/plugin_server/capability/{capabilityId}/preview/execute\n * - 预览态 流式: POST {baseURL}/app/{appId}/__runtime__/api/v1/plugin_server/capability/{capabilityId}/preview/execute/stream\n *\n * baseURL 默认取 `window.location.origin`(同源调用,SSO cookie 自动带)。\n * 预览态 / 运行态由 `process.env.NODE_ENV` 自动判定:\n * - 沙箱开发态(fullstack-cli scripts/dev.sh 起的进程,NODE_ENV=development)→ 预览态\n * - 运行态启动(NODE_ENV=production,无论 build 还是 npm start)→ 运行态\n * 业务前端 `createClient` 配置不需要区分两种环境。\n *\n * 预览态 body 必须携带完整 capability config,从 `capabilities` map 查;缺失抛\n * CapabilityNotFoundError。运行态由中心服务通过 capability_id 走 RPC 查中心存储。\n */\n central?: CentralOptions;\n}\n\n/**\n * 中心化服务分流配置。\n */\nexport interface CentralOptions {\n /** 是否启用中心化分流;false / 未配置则维持原行为打用户应用。 */\n enabled: boolean;\n /**\n * 中心服务 base URL(含 scheme)。可选;不传时默认 `window.location.origin`。\n * 非浏览器环境(SSR / Node.js 测试)必须显式传,否则 SDK 抛错。\n */\n baseURL?: string;\n /** 当前应用 ID,拼接在 `/app/{appId}/__runtime__/...` 路径段。 */\n appId: string;\n}\n\n/**\n * Capability 配置,与 @lark-apaas/nestjs-capability / miaoda_plugin_server 的 interfaces/capability-config.ts 对齐。\n * 预览态 body.capability 必须为完整对象。\n */\nexport interface CapabilityConfig {\n id: string;\n pluginKey: string;\n pluginVersion: string;\n name: string;\n description: string;\n paramsSchema: unknown;\n formValue: Record<string, unknown>;\n createdAt: number;\n updatedAt: number;\n}\n\n/**\n * 能力执行器接口\n */\nexport interface CapabilityExecutor {\n /**\n * 调用能力\n * @param action - Action 名称\n * @param params - 输入参数\n * @returns Action 执行结果\n */\n call<T = unknown>(\n action: string,\n params?: Record<string, unknown>\n ): Promise<T>;\n\n /**\n * 流式调用能力\n * @param action - Action 名称\n * @param params - 输入参数\n * @returns AsyncIterable,逐个 yield chunk\n */\n callStream<T = unknown>(\n action: string,\n params?: Record<string, unknown>\n ): AsyncIterable<T>;\n}\n\n// ========== API 响应类型 ==========\n\n/**\n * 成功响应\n */\nexport interface SuccessResponse<T> {\n status_code: '0';\n data: T;\n}\n\n/**\n * 错误响应\n */\nexport interface ErrorResponse {\n status_code: string;\n error_msg: string;\n /** 是否为计费受限错误 */\n is_rate_limit_error?: boolean;\n}\n\n/**\n * API 响应类型\n */\nexport type ApiResponse<T> = SuccessResponse<T> | ErrorResponse;\n\n// ========== 具体响应 data 结构 ==========\n\n/**\n * 执行接口响应 data 结构\n */\nexport interface ExecuteResponseData {\n output: unknown;\n}\n\n// ========== 流式响应结构 ==========\n\n/**\n * 流式内容响应\n */\nexport interface StreamContentResponse {\n status_code: '0';\n data: {\n type: 'content';\n delta: unknown;\n finished?: boolean;\n };\n}\n\n/**\n * 流式错误响应\n */\nexport interface StreamErrorResponse {\n status_code: '0';\n data: {\n type: 'error';\n error: {\n /** 错误码,计费受限时为业务错误码(如 k_st_ec_400002687) */\n code: string;\n message: string;\n /** 是否为计费受限错误 */\n isRateLimitError?: boolean;\n };\n };\n}\n\n/**\n * 流式响应类型\n */\nexport type StreamResponse = StreamContentResponse | StreamErrorResponse;\n\n// ========== 错误码 ==========\n\n/**\n * 后端错误码\n */\nexport const ErrorCodes = {\n SUCCESS: '0',\n CAPABILITY_NOT_FOUND: 'k_ec_cap_001',\n PLUGIN_NOT_FOUND: 'k_ec_cap_002',\n ACTION_NOT_FOUND: 'k_ec_cap_003',\n PARAMS_VALIDATION_ERROR: 'k_ec_cap_004',\n EXECUTION_ERROR: 'k_ec_cap_005',\n RATE_LIMIT_EXCEEDED: 'k_ec_cap_006',\n} as const;\n\n// ========== 文件上传相关类型 ==========\n\n/**\n * 提取的文件信息\n */\nexport interface ExtractedFile {\n /** 在 params 中的路径,如 ['image_list', 0] */\n path: (string | number)[];\n /** 文件对象 */\n file: File | Blob;\n}\n\n/**\n * 上传结果\n */\nexport interface UploadResult {\n /** 在 params 中的路径 */\n path: (string | number)[];\n /** 临时下载 URL */\n downloadUrl: string;\n}\n\n/**\n * 获取上传 URL 响应\n */\nexport interface AcquireUploadUrlResponse {\n status_code: string;\n data: {\n uploadURL: string;\n objectKey: string;\n };\n}\n\n/**\n * 获取下载 URL 响应\n */\nexport interface AcquireDownloadUrlResponse {\n status_code: string;\n data: {\n downloadURL: string;\n };\n}\n","/**\n * 能力调用错误基类\n */\nexport class CapabilityError extends Error {\n /** 错误码 */\n code: string;\n /** HTTP 状态码 */\n statusCode?: number;\n\n constructor(message: string, code: string, statusCode?: number) {\n super(message);\n this.name = 'CapabilityError';\n this.code = code;\n this.statusCode = statusCode;\n }\n}\n\n/**\n * 能力不存在错误\n */\nexport class CapabilityNotFoundError extends CapabilityError {\n constructor(capabilityId: string, statusCode?: number) {\n super(`Capability not found: ${capabilityId}`, 'CAPABILITY_NOT_FOUND', statusCode);\n this.name = 'CapabilityNotFoundError';\n }\n}\n\n/**\n * Action 不存在错误\n */\nexport class ActionNotFoundError extends CapabilityError {\n constructor(message: string, statusCode?: number) {\n super(message, 'ACTION_NOT_FOUND', statusCode);\n this.name = 'ActionNotFoundError';\n }\n}\n\n/**\n * 网络错误\n */\nexport class NetworkError extends CapabilityError {\n constructor(message: string) {\n super(message, 'NETWORK_ERROR');\n this.name = 'NetworkError';\n }\n}\n\n/**\n * 执行错误\n */\nexport class ExecutionError extends CapabilityError {\n constructor(message: string, statusCode?: number) {\n super(message, 'EXECUTION_ERROR', statusCode);\n this.name = 'ExecutionError';\n }\n}\n\n/**\n * 文件上传错误\n */\nexport class FileUploadError extends CapabilityError {\n constructor(message: string, statusCode?: number) {\n super(message, 'FILE_UPLOAD_ERROR', statusCode);\n this.name = 'FileUploadError';\n }\n}\n\n/**\n * 计费受限错误\n */\nexport class RateLimitError extends CapabilityError {\n /** 业务错误码 */\n rateLimitCode: string;\n /** 业务错误消息 */\n rateLimitMessage: string;\n\n constructor(rateLimitCode: string, rateLimitMessage: string, statusCode?: number) {\n super(rateLimitMessage, 'RATE_LIMIT_EXCEEDED', statusCode);\n this.name = 'RateLimitError';\n this.rateLimitCode = rateLimitCode;\n this.rateLimitMessage = rateLimitMessage;\n }\n}\n","import type {\n CapabilityClientOptions,\n ExtractedFile,\n UploadResult,\n AcquireUploadUrlResponse,\n AcquireDownloadUrlResponse,\n} from './types';\nimport { FileUploadError } from './errors';\nimport { slardar } from '@lark-apaas/internal-slardar';\n\ntype FileUploaderOptions = Pick<CapabilityClientOptions, 'acquireUploadUrl' | 'acquireDownloadUrl' | 'fetchOptions'>;\n\n/**\n * 文件上传器\n */\nexport class FileUploader {\n private readonly options: FileUploaderOptions;\n\n constructor(options: FileUploaderOptions) {\n this.options = options;\n }\n\n /**\n * 上传单个文件,返回下载 URL\n */\n async upload(file: File | Blob): Promise<string> {\n const fileName = file instanceof File ? file.name : `blob-${Date.now()}`;\n\n // 1. 获取上传预签名 URL\n const { uploadURL, objectKey } = await this.fetchUploadUrl(fileName);\n\n // 2. 上传文件到 TOS\n await this.uploadToTos(uploadURL, file);\n\n // 3. 获取下载 URL\n const downloadUrl = await this.fetchDownloadUrl(objectKey);\n\n return downloadUrl;\n }\n\n /**\n * 并发上传多个文件\n */\n async uploadAll(files: ExtractedFile[]): Promise<UploadResult[]> {\n const results = await Promise.all(\n files.map(async ({ path, file }) => {\n const downloadUrl = await this.upload(file);\n return { path, downloadUrl };\n })\n );\n return results;\n }\n\n /**\n * 获取上传预签名 URL\n */\n private async fetchUploadUrl(fileName: string): Promise<{ uploadURL: string; objectKey: string }> {\n const { acquireUploadUrl, fetchOptions } = this.options;\n\n let response: Response;\n try {\n response = await fetch(acquireUploadUrl, {\n method: 'POST',\n ...fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...fetchOptions?.headers,\n },\n body: JSON.stringify({ fileName }),\n });\n } catch (error) {\n slardar.captureException(error, { source: 'client-capability', module: 'file-upload', step: 'fetch-upload-url' });\n throw new FileUploadError(\n `Failed to acquire upload URL: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n if (!response.ok) {\n throw new FileUploadError(\n `Failed to acquire upload URL: HTTP ${response.status}`,\n response.status\n );\n }\n\n const data = (await response.json()) as AcquireUploadUrlResponse;\n\n if (data.status_code !== '0') {\n throw new FileUploadError(`Failed to acquire upload URL: ${data.status_code}`);\n }\n\n return data.data;\n }\n\n /**\n * 上传文件到 TOS(预签名 URL)\n */\n private async uploadToTos(uploadURL: string, file: File | Blob): Promise<void> {\n let response: Response;\n try {\n response = await fetch(uploadURL, {\n method: 'PUT',\n body: file,\n });\n } catch (error) {\n slardar.captureException(error, { source: 'client-capability', module: 'file-upload', step: 'upload-to-tos' });\n throw new FileUploadError(\n `Failed to upload file to TOS: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n if (!response.ok) {\n throw new FileUploadError(\n `Failed to upload file to TOS: HTTP ${response.status}`,\n response.status\n );\n }\n }\n\n /**\n * 获取临时下载 URL\n */\n private async fetchDownloadUrl(objectKey: string): Promise<string> {\n const { acquireDownloadUrl, fetchOptions } = this.options;\n\n let response: Response;\n try {\n response = await fetch(acquireDownloadUrl, {\n method: 'POST',\n ...fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...fetchOptions?.headers,\n },\n body: JSON.stringify({ objectKey }),\n });\n } catch (error) {\n slardar.captureException(error, { source: 'client-capability', module: 'file-upload', step: 'fetch-download-url' });\n throw new FileUploadError(\n `Failed to acquire download URL: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n if (!response.ok) {\n throw new FileUploadError(\n `Failed to acquire download URL: HTTP ${response.status}`,\n response.status\n );\n }\n\n const data = (await response.json()) as AcquireDownloadUrlResponse;\n\n if (data.status_code !== '0') {\n throw new FileUploadError(`Failed to acquire download URL: ${data.status_code}`);\n }\n\n return data.data.downloadURL;\n }\n}\n","import type { ExtractedFile, UploadResult } from './types';\n\n/**\n * 检测是否为 File 或 Blob\n */\nexport function isFile(value: unknown): value is File | Blob {\n return value instanceof File || value instanceof Blob;\n}\n\n/**\n * 递归提取 params 中的所有文件\n *\n * @example\n * extractFiles({ image_list: [file1, file2] })\n * // => [\n * // { path: ['image_list', 0], file: file1 },\n * // { path: ['image_list', 1], file: file2 }\n * // ]\n */\nexport function extractFiles(params: Record<string, unknown>): ExtractedFile[] {\n const files: ExtractedFile[] = [];\n\n function traverse(obj: unknown, path: (string | number)[]): void {\n if (isFile(obj)) {\n files.push({ path: [...path], file: obj });\n } else if (Array.isArray(obj)) {\n obj.forEach((item, index) => traverse(item, [...path, index]));\n } else if (obj !== null && typeof obj === 'object') {\n Object.entries(obj).forEach(([key, value]) => {\n traverse(value, [...path, key]);\n });\n }\n }\n\n traverse(params, []);\n return files;\n}\n\n/**\n * 根据上传结果替换 params 中的文件为 URL\n *\n * @example\n * replaceFilesWithUrls(\n * { image_list: [file1, file2] },\n * [\n * { path: ['image_list', 0], downloadUrl: 'https://...' },\n * { path: ['image_list', 1], downloadUrl: 'https://...' }\n * ]\n * )\n * // => { image_list: ['https://...', 'https://...'] }\n */\nexport function replaceFilesWithUrls(\n params: Record<string, unknown>,\n results: UploadResult[]\n): Record<string, unknown> {\n // 创建 path -> url 的映射,用于快速查找\n const urlMap = new Map<string, string>();\n for (const { path, downloadUrl } of results) {\n urlMap.set(JSON.stringify(path), downloadUrl);\n }\n\n // 手动深拷贝,同时将 File/Blob 替换为对应的 URL\n // 注意:不能使用 structuredClone,因为它不支持 File/Blob 对象\n function cloneAndReplace(obj: unknown, currentPath: (string | number)[]): unknown {\n // 检查当前路径是否有对应的 URL\n const pathKey = JSON.stringify(currentPath);\n if (urlMap.has(pathKey)) {\n return urlMap.get(pathKey);\n }\n\n // 如果是 File/Blob 但没有对应的 URL(不应该发生),返回 null\n if (isFile(obj)) {\n return null;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item, index) => cloneAndReplace(item, [...currentPath, index]));\n }\n\n if (obj !== null && typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n result[key] = cloneAndReplace(value, [...currentPath, key]);\n }\n return result;\n }\n\n // 原始值直接返回\n return obj;\n }\n\n return cloneAndReplace(params, []) as Record<string, unknown>;\n}\n","import type {\n CapabilityClientOptions,\n CapabilityExecutor,\n ApiResponse,\n ExecuteResponseData,\n StreamResponse,\n Logger,\n RateLimitErrorHook,\n CentralOptions,\n} from './types';\nimport { ErrorCodes } from './types';\nimport {\n CapabilityError,\n CapabilityNotFoundError,\n ActionNotFoundError,\n NetworkError,\n ExecutionError,\n RateLimitError,\n} from './errors';\nimport { FileUploader } from './uploader';\nimport { extractFiles, replaceFilesWithUrls } from './file-extractor';\nimport { slardar } from '@lark-apaas/internal-slardar';\n\n// 方案文档 § Client SDK 改造伪代码原句:\n// `import capabilityMap from 'virtual:capabilities'; // build 时注入`\n// 由 @lark-apaas/fullstack-vite-preset 的 capabilitiesBundlePlugin 在 dev/build 时\n// 扫业务工程 server/capabilities/*.json 注入。类型声明在 ./virtual.d.ts。\nimport virtualCapabilitiesMap from 'virtual:capabilities';\nimport type { CapabilityConfig } from './types';\n\nconst LOG_PREFIX = '[CapabilityClient]';\n\nconst defaultLogger: Logger = {\n debug: console.debug.bind(console),\n info: console.info.bind(console),\n warn: console.warn.bind(console),\n error: console.error.bind(console),\n};\n\n/**\n * 能力客户端\n */\nexport class CapabilityClient {\n private options: CapabilityClientOptions;\n private baseURL: string;\n private logger: Logger;\n private onRateLimitError?: RateLimitErrorHook;\n private central?: CentralOptions;\n\n constructor(options: CapabilityClientOptions) {\n this.options = options;\n // 移除末尾的斜杠,确保拼接时格式正确\n this.baseURL = (options?.baseURL ?? '').replace(/\\/+$/, '');\n this.logger = options?.logger ?? defaultLogger;\n this.onRateLimitError = options?.onRateLimitError;\n if (options?.central?.enabled) {\n this.central = options.central;\n }\n }\n\n /**\n * central.baseURL → caller 显式给的(去尾斜杠)。\n * 没传:浏览器取 `window.location.origin`(同源调用,SSO cookie 自动带);\n * 非浏览器(SSR / Node.js 测试)抛错。\n * 用法与 fullstack-plugin/packages/client/dataloom/src/service/index.ts 一致。\n */\n private resolveCentralBaseURL(central: CentralOptions): string {\n if (central.baseURL) return central.baseURL.replace(/\\/+$/, '');\n if (typeof window !== 'undefined' && window.location?.origin) {\n return window.location.origin;\n }\n throw new Error(\n 'CapabilityClient: central.baseURL is required when running outside browser (window.location unavailable)',\n );\n }\n\n /**\n * 预览态 / 运行态自动判定。沿用 nestjs-capability/src/capability.module.ts:18 同款判定:\n * - 沙箱 fullstack-cli scripts/dev.sh → `NODE_ENV=development` → 预览态\n * - 运行态(npm start / build 后部署)→ `NODE_ENV=production` → 运行态\n * Vite 在构建时把 `process.env.NODE_ENV` 替换为字面量字符串。\n */\n private resolveMode(): 'preview' | 'runtime' {\n const env = typeof process !== 'undefined' ? process.env?.NODE_ENV : undefined;\n return env === 'development' ? 'preview' : 'runtime';\n }\n\n /**\n * 构造单次调用的请求 URL:\n * - central 开启:4 个中心端点之一(mode 自动判定);\n * - central 关闭:保持原 `${baseURL}/api/capability/{id}` 行为。\n */\n private buildExecuteUrl(capabilityId: string, stream: boolean): string {\n if (!this.central) {\n return `${this.baseURL}/api/capability/${capabilityId}${stream ? '/stream' : ''}`;\n }\n const base = this.resolveCentralBaseURL(this.central);\n const segment = this.resolveMode() === 'preview' ? '/preview/execute' : '/execute';\n return `${base}/app/${this.central.appId}/__runtime__/api/v1/plugin_server/capability/${capabilityId}${segment}${stream ? '/stream' : ''}`;\n }\n\n /**\n * 构造请求体:\n * - central + 预览态:`{ capability, action, params }`,capability 取自\n * `virtual:capabilities`(load() 时已经 fail-fast 校验过,这里直接取)。\n * - central + 运行态:`{ action, params }`(中心服务通过 RPC 查中心存储拿 config)。\n * - 非 central:`{ action, params }`。\n */\n private buildRequestBody(\n capabilityId: string,\n action: string,\n params: Record<string, unknown>,\n ): string {\n if (this.central && this.resolveMode() === 'preview') {\n const capability = virtualCapabilitiesMap[capabilityId] as CapabilityConfig | undefined;\n if (!capability) {\n // 理论上 load() 已经 fail-fast 校验,但兜底处理\n throw new CapabilityNotFoundError(capabilityId);\n }\n return JSON.stringify({ capability, action, params });\n }\n return JSON.stringify({ action, params });\n }\n\n /**\n * 加载能力,返回执行器。\n * 方案文档 § Client SDK 改造伪代码:\n * const config = capabilityMap[id];\n * if (!config) throw new CapabilityNotFoundError(id);\n * central + 预览态时 fail-fast:本地 `virtual:capabilities` map 没这个 id 就直接抛,\n * 不发任何网络请求。运行态 / 非 central 模式跳过此校验。\n */\n load(capabilityId: string): CapabilityExecutor {\n if (this.central && this.resolveMode() === 'preview') {\n if (!(capabilityId in virtualCapabilitiesMap)) {\n throw new CapabilityNotFoundError(capabilityId);\n }\n }\n return this.createExecutor(capabilityId);\n }\n\n private createExecutor(capabilityId: string): CapabilityExecutor {\n return {\n call: <T = unknown>(action: string, params?: Record<string, unknown>) => {\n return this.executeCall<T>(capabilityId, action, params);\n },\n callStream: <T = unknown>(action: string, params?: Record<string, unknown>) => {\n return this.executeCallStream<T>(capabilityId, action, params);\n },\n };\n }\n\n private async executeCall<T>(\n capabilityId: string,\n action: string,\n params?: Record<string, unknown>\n ): Promise<T> {\n const url = this.buildExecuteUrl(capabilityId, false);\n let requestParams = params ?? {};\n\n // 处理文件上传\n const extractedFiles = extractFiles(requestParams);\n if (extractedFiles.length > 0) {\n this.logger.info(LOG_PREFIX, `uploading ${extractedFiles.length} file(s)...`);\n const uploader = new FileUploader(this.options);\n const uploadResults = await uploader.uploadAll(extractedFiles);\n requestParams = replaceFilesWithUrls(requestParams, uploadResults);\n this.logger.info(LOG_PREFIX, `file upload completed`);\n }\n\n this.logger.info(LOG_PREFIX, `call start: capabilityId=${capabilityId}, action=${action}`, { params: requestParams });\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n ...this.options.fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...this.options.fetchOptions?.headers,\n },\n body: this.buildRequestBody(capabilityId, action, requestParams),\n });\n\n const data = (await response.json()) as ApiResponse<ExecuteResponseData>;\n\n if (!response.ok || data.status_code !== ErrorCodes.SUCCESS) {\n const errorResponse = data as {\n status_code: string;\n error_msg: string;\n is_rate_limit_error?: boolean;\n };\n const errorCode = errorResponse.status_code;\n\n // 计费受限错误:通过 is_rate_limit_error 字段识别\n if (errorResponse.is_rate_limit_error) {\n const rateLimitError = new RateLimitError(\n errorCode, // status_code 就是业务错误码\n errorResponse.error_msg,\n response.status,\n );\n await this.onRateLimitError?.(rateLimitError);\n throw rateLimitError;\n }\n\n switch (errorCode) {\n case ErrorCodes.CAPABILITY_NOT_FOUND:\n throw new CapabilityNotFoundError(capabilityId, response.status);\n case ErrorCodes.ACTION_NOT_FOUND:\n throw new ActionNotFoundError(errorResponse.error_msg, response.status);\n case ErrorCodes.PLUGIN_NOT_FOUND:\n case ErrorCodes.EXECUTION_ERROR:\n default:\n throw new ExecutionError(errorResponse.error_msg, response.status);\n }\n }\n\n const result = (data as { data: ExecuteResponseData }).data.output as T;\n\n this.logger.info(LOG_PREFIX, `call success: capabilityId=${capabilityId}, action=${action}`, { result });\n\n return result;\n } catch (error) {\n this.logger.error(LOG_PREFIX, `call failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error });\n slardar.captureException(error, { source: 'client-capability', module: 'execute-call', capabilityId, action });\n if (error instanceof CapabilityError) {\n throw error;\n }\n throw new NetworkError(error instanceof Error ? error.message : String(error));\n }\n }\n\n private async *executeCallStream<T>(\n capabilityId: string,\n action: string,\n params?: Record<string, unknown>\n ): AsyncIterable<T> {\n const url = this.buildExecuteUrl(capabilityId, true);\n let requestParams = params ?? {};\n\n // 处理文件上传\n const extractedFiles = extractFiles(requestParams);\n if (extractedFiles.length > 0) {\n this.logger.info(LOG_PREFIX, `uploading ${extractedFiles.length} file(s)...`);\n const uploader = new FileUploader(this.options);\n const uploadResults = await uploader.uploadAll(extractedFiles);\n requestParams = replaceFilesWithUrls(requestParams, uploadResults);\n this.logger.info(LOG_PREFIX, `file upload completed`);\n }\n\n this.logger.info(LOG_PREFIX, `callStream start: capabilityId=${capabilityId}, action=${action}`, { params: requestParams });\n\n // central + preview 模式下 buildRequestBody 可能抛 CapabilityNotFoundError,\n // 先于 fetch 计算好 body,避免被下面的 NetworkError 包装吞掉类型。\n const body = this.buildRequestBody(capabilityId, action, requestParams);\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n ...this.options.fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...this.options.fetchOptions?.headers,\n },\n body,\n });\n } catch (error) {\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error });\n slardar.captureException(error, { source: 'client-capability', module: 'execute-call-stream', capabilityId, action, phase: 'fetch' });\n throw new NetworkError(error instanceof Error ? error.message : String(error));\n }\n\n if (!response.ok) {\n const errMsg = `HTTP ${response.status} ${response.statusText}`;\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error: errMsg });\n throw new NetworkError(errMsg);\n }\n\n if (!response.body) {\n const errMsg = 'Response body is null';\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error: errMsg });\n throw new NetworkError(errMsg);\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let chunkCount = 0;\n let aggregatedContent = '';\n let canAggregate = true;\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n\n try {\n const parsed = JSON.parse(data) as StreamResponse;\n\n if (parsed.status_code === ErrorCodes.SUCCESS && parsed.data) {\n if (parsed.data.type === 'content') {\n chunkCount++;\n const delta = parsed.data.delta as T;\n\n // 尝试聚合 content 字段\n if (canAggregate) {\n const content = (delta as Record<string, unknown>)?.content;\n if (typeof content === 'string') {\n aggregatedContent += content;\n } else {\n canAggregate = false;\n }\n }\n\n yield delta;\n\n if (parsed.data.finished) {\n const resultInfo = canAggregate\n ? { chunkCount, result: aggregatedContent }\n : { chunkCount, resultLength: aggregatedContent.length || chunkCount };\n this.logger.info(LOG_PREFIX, `callStream end: capabilityId=${capabilityId}, action=${action}`, resultInfo);\n return;\n }\n } else if (parsed.data.type === 'error') {\n const err = parsed.data.error;\n if (err.isRateLimitError) {\n const rateLimitError = new RateLimitError(\n err.code, // code 就是业务错误码\n err.message,\n );\n await this.onRateLimitError?.(rateLimitError);\n throw rateLimitError;\n }\n throw new ExecutionError(err.message);\n }\n }\n } catch (parseError) {\n if (parseError instanceof CapabilityError) {\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error: parseError, chunkCount });\n throw parseError;\n }\n // 忽略非 JSON 行\n }\n }\n }\n }\n const resultInfo = canAggregate\n ? { chunkCount, result: aggregatedContent }\n : { chunkCount, resultLength: aggregatedContent.length || chunkCount };\n this.logger.info(LOG_PREFIX, `callStream end: capabilityId=${capabilityId}, action=${action}`, resultInfo);\n } catch (error) {\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error, chunkCount });\n slardar.captureException(error, { source: 'client-capability', module: 'execute-call-stream', capabilityId, action, phase: 'read' });\n if (error instanceof CapabilityError) {\n throw error;\n }\n throw new NetworkError(error instanceof Error ? error.message : String(error));\n } finally {\n reader.releaseLock();\n }\n }\n}\n\n/**\n * 创建客户端实例\n */\nexport function createClient(options: CapabilityClientOptions): CapabilityClient {\n return new CapabilityClient(options);\n}\n"],"mappings":"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","names":["ErrorCodes","SUCCESS","CAPABILITY_NOT_FOUND","PLUGIN_NOT_FOUND","ACTION_NOT_FOUND","PARAMS_VALIDATION_ERROR","EXECUTION_ERROR","RATE_LIMIT_EXCEEDED","CapabilityError","Error","message","code","statusCode","name","CapabilityNotFoundError","capabilityId","ActionNotFoundError","NetworkError","ExecutionError","FileUploadError","RateLimitError","rateLimitCode","rateLimitMessage","FileUploader","options","upload","file","fileName","File","name","Date","now","uploadURL","objectKey","fetchUploadUrl","uploadToTos","downloadUrl","fetchDownloadUrl","uploadAll","files","results","Promise","all","map","path","acquireUploadUrl","fetchOptions","response","fetch","method","headers","body","JSON","stringify","error","slardar","captureException","source","module","step","FileUploadError","Error","message","String","ok","status","data","json","status_code","acquireDownloadUrl","downloadURL","isFile","value","File","Blob","extractFiles","params","files","traverse","obj","path","push","file","Array","isArray","forEach","item","index","Object","entries","key","replaceFilesWithUrls","results","urlMap","Map","downloadUrl","set","JSON","stringify","cloneAndReplace","currentPath","pathKey","has","get","map","result","import_internal_slardar","LOG_PREFIX","defaultLogger","debug","console","bind","info","warn","error","CapabilityClient","options","baseURL","logger","onRateLimitError","central","replace","enabled","resolveCentralBaseURL","window","location","origin","Error","resolveMode","env","process","undefined","buildExecuteUrl","capabilityId","stream","base","segment","appId","buildRequestBody","action","params","capability","virtualCapabilitiesMap","CapabilityNotFoundError","JSON","stringify","load","createExecutor","call","executeCall","callStream","executeCallStream","url","requestParams","extractedFiles","extractFiles","length","uploader","FileUploader","uploadResults","uploadAll","replaceFilesWithUrls","response","fetch","method","fetchOptions","headers","body","data","json","ok","status_code","ErrorCodes","SUCCESS","errorResponse","errorCode","is_rate_limit_error","rateLimitError","RateLimitError","error_msg","status","CAPABILITY_NOT_FOUND","ACTION_NOT_FOUND","ActionNotFoundError","PLUGIN_NOT_FOUND","EXECUTION_ERROR","ExecutionError","result","output","slardar","captureException","source","module","CapabilityError","NetworkError","message","String","phase","errMsg","statusText","reader","getReader","decoder","TextDecoder","buffer","chunkCount","aggregatedContent","canAggregate","done","value","read","decode","lines","split","pop","line","startsWith","slice","parsed","parse","type","delta","content","finished","resultInfo","resultLength","err","isRateLimitError","code","parseError","releaseLock","createClient"]}
package/dist/index.d.cts CHANGED
@@ -83,6 +83,52 @@ interface CapabilityClientOptions {
83
83
  * 可用于上报埋点、展示 toast 等场景
84
84
  */
85
85
  onRateLimitError?: RateLimitErrorHook;
86
+ /**
87
+ * 中心化服务分流开关。启用后 capability 调用路由到妙搭 plugin_server 的 4 个中心端点:
88
+ * - 运行态 非流式: POST {baseURL}/app/{appId}/__runtime__/api/v1/plugin_server/capability/{capabilityId}/execute
89
+ * - 运行态 流式: POST {baseURL}/app/{appId}/__runtime__/api/v1/plugin_server/capability/{capabilityId}/execute/stream
90
+ * - 预览态 非流式: POST {baseURL}/app/{appId}/__runtime__/api/v1/plugin_server/capability/{capabilityId}/preview/execute
91
+ * - 预览态 流式: POST {baseURL}/app/{appId}/__runtime__/api/v1/plugin_server/capability/{capabilityId}/preview/execute/stream
92
+ *
93
+ * baseURL 默认取 `window.location.origin`(同源调用,SSO cookie 自动带)。
94
+ * 预览态 / 运行态由 `process.env.NODE_ENV` 自动判定:
95
+ * - 沙箱开发态(fullstack-cli scripts/dev.sh 起的进程,NODE_ENV=development)→ 预览态
96
+ * - 运行态启动(NODE_ENV=production,无论 build 还是 npm start)→ 运行态
97
+ * 业务前端 `createClient` 配置不需要区分两种环境。
98
+ *
99
+ * 预览态 body 必须携带完整 capability config,从 `capabilities` map 查;缺失抛
100
+ * CapabilityNotFoundError。运行态由中心服务通过 capability_id 走 RPC 查中心存储。
101
+ */
102
+ central?: CentralOptions;
103
+ }
104
+ /**
105
+ * 中心化服务分流配置。
106
+ */
107
+ interface CentralOptions {
108
+ /** 是否启用中心化分流;false / 未配置则维持原行为打用户应用。 */
109
+ enabled: boolean;
110
+ /**
111
+ * 中心服务 base URL(含 scheme)。可选;不传时默认 `window.location.origin`。
112
+ * 非浏览器环境(SSR / Node.js 测试)必须显式传,否则 SDK 抛错。
113
+ */
114
+ baseURL?: string;
115
+ /** 当前应用 ID,拼接在 `/app/{appId}/__runtime__/...` 路径段。 */
116
+ appId: string;
117
+ }
118
+ /**
119
+ * Capability 配置,与 @lark-apaas/nestjs-capability / miaoda_plugin_server 的 interfaces/capability-config.ts 对齐。
120
+ * 预览态 body.capability 必须为完整对象。
121
+ */
122
+ interface CapabilityConfig {
123
+ id: string;
124
+ pluginKey: string;
125
+ pluginVersion: string;
126
+ name: string;
127
+ description: string;
128
+ paramsSchema: unknown;
129
+ formValue: Record<string, unknown>;
130
+ createdAt: number;
131
+ updatedAt: number;
86
132
  }
87
133
  /**
88
134
  * 能力执行器接口
@@ -112,11 +158,43 @@ declare class CapabilityClient {
112
158
  private baseURL;
113
159
  private logger;
114
160
  private onRateLimitError?;
161
+ private central?;
115
162
  constructor(options: CapabilityClientOptions);
116
163
  /**
117
- * 加载能力,返回执行器
118
- * @param capabilityId - 能力 ID
119
- * @returns 能力执行器
164
+ * central.baseURL → caller 显式给的(去尾斜杠)。
165
+ * 没传:浏览器取 `window.location.origin`(同源调用,SSO cookie 自动带);
166
+ * 非浏览器(SSR / Node.js 测试)抛错。
167
+ * 用法与 fullstack-plugin/packages/client/dataloom/src/service/index.ts 一致。
168
+ */
169
+ private resolveCentralBaseURL;
170
+ /**
171
+ * 预览态 / 运行态自动判定。沿用 nestjs-capability/src/capability.module.ts:18 同款判定:
172
+ * - 沙箱 fullstack-cli scripts/dev.sh → `NODE_ENV=development` → 预览态
173
+ * - 运行态(npm start / build 后部署)→ `NODE_ENV=production` → 运行态
174
+ * Vite 在构建时把 `process.env.NODE_ENV` 替换为字面量字符串。
175
+ */
176
+ private resolveMode;
177
+ /**
178
+ * 构造单次调用的请求 URL:
179
+ * - central 开启:4 个中心端点之一(mode 自动判定);
180
+ * - central 关闭:保持原 `${baseURL}/api/capability/{id}` 行为。
181
+ */
182
+ private buildExecuteUrl;
183
+ /**
184
+ * 构造请求体:
185
+ * - central + 预览态:`{ capability, action, params }`,capability 取自
186
+ * `virtual:capabilities`(load() 时已经 fail-fast 校验过,这里直接取)。
187
+ * - central + 运行态:`{ action, params }`(中心服务通过 RPC 查中心存储拿 config)。
188
+ * - 非 central:`{ action, params }`。
189
+ */
190
+ private buildRequestBody;
191
+ /**
192
+ * 加载能力,返回执行器。
193
+ * 方案文档 § Client SDK 改造伪代码:
194
+ * const config = capabilityMap[id];
195
+ * if (!config) throw new CapabilityNotFoundError(id);
196
+ * central + 预览态时 fail-fast:本地 `virtual:capabilities` map 没这个 id 就直接抛,
197
+ * 不发任何网络请求。运行态 / 非 central 模式跳过此校验。
120
198
  */
121
199
  load(capabilityId: string): CapabilityExecutor;
122
200
  private createExecutor;
@@ -128,4 +206,4 @@ declare class CapabilityClient {
128
206
  */
129
207
  declare function createClient(options: CapabilityClientOptions): CapabilityClient;
130
208
 
131
- export { ActionNotFoundError, CapabilityClient, type CapabilityClientOptions, CapabilityError, type CapabilityExecutor, CapabilityNotFoundError, ExecutionError, FileUploadError, type Logger, NetworkError, RateLimitError, type RateLimitErrorHook, createClient };
209
+ export { ActionNotFoundError, CapabilityClient, type CapabilityClientOptions, type CapabilityConfig, CapabilityError, type CapabilityExecutor, CapabilityNotFoundError, type CentralOptions, ExecutionError, FileUploadError, type Logger, NetworkError, RateLimitError, type RateLimitErrorHook, createClient };
package/dist/index.d.ts CHANGED
@@ -83,6 +83,52 @@ interface CapabilityClientOptions {
83
83
  * 可用于上报埋点、展示 toast 等场景
84
84
  */
85
85
  onRateLimitError?: RateLimitErrorHook;
86
+ /**
87
+ * 中心化服务分流开关。启用后 capability 调用路由到妙搭 plugin_server 的 4 个中心端点:
88
+ * - 运行态 非流式: POST {baseURL}/app/{appId}/__runtime__/api/v1/plugin_server/capability/{capabilityId}/execute
89
+ * - 运行态 流式: POST {baseURL}/app/{appId}/__runtime__/api/v1/plugin_server/capability/{capabilityId}/execute/stream
90
+ * - 预览态 非流式: POST {baseURL}/app/{appId}/__runtime__/api/v1/plugin_server/capability/{capabilityId}/preview/execute
91
+ * - 预览态 流式: POST {baseURL}/app/{appId}/__runtime__/api/v1/plugin_server/capability/{capabilityId}/preview/execute/stream
92
+ *
93
+ * baseURL 默认取 `window.location.origin`(同源调用,SSO cookie 自动带)。
94
+ * 预览态 / 运行态由 `process.env.NODE_ENV` 自动判定:
95
+ * - 沙箱开发态(fullstack-cli scripts/dev.sh 起的进程,NODE_ENV=development)→ 预览态
96
+ * - 运行态启动(NODE_ENV=production,无论 build 还是 npm start)→ 运行态
97
+ * 业务前端 `createClient` 配置不需要区分两种环境。
98
+ *
99
+ * 预览态 body 必须携带完整 capability config,从 `capabilities` map 查;缺失抛
100
+ * CapabilityNotFoundError。运行态由中心服务通过 capability_id 走 RPC 查中心存储。
101
+ */
102
+ central?: CentralOptions;
103
+ }
104
+ /**
105
+ * 中心化服务分流配置。
106
+ */
107
+ interface CentralOptions {
108
+ /** 是否启用中心化分流;false / 未配置则维持原行为打用户应用。 */
109
+ enabled: boolean;
110
+ /**
111
+ * 中心服务 base URL(含 scheme)。可选;不传时默认 `window.location.origin`。
112
+ * 非浏览器环境(SSR / Node.js 测试)必须显式传,否则 SDK 抛错。
113
+ */
114
+ baseURL?: string;
115
+ /** 当前应用 ID,拼接在 `/app/{appId}/__runtime__/...` 路径段。 */
116
+ appId: string;
117
+ }
118
+ /**
119
+ * Capability 配置,与 @lark-apaas/nestjs-capability / miaoda_plugin_server 的 interfaces/capability-config.ts 对齐。
120
+ * 预览态 body.capability 必须为完整对象。
121
+ */
122
+ interface CapabilityConfig {
123
+ id: string;
124
+ pluginKey: string;
125
+ pluginVersion: string;
126
+ name: string;
127
+ description: string;
128
+ paramsSchema: unknown;
129
+ formValue: Record<string, unknown>;
130
+ createdAt: number;
131
+ updatedAt: number;
86
132
  }
87
133
  /**
88
134
  * 能力执行器接口
@@ -112,11 +158,43 @@ declare class CapabilityClient {
112
158
  private baseURL;
113
159
  private logger;
114
160
  private onRateLimitError?;
161
+ private central?;
115
162
  constructor(options: CapabilityClientOptions);
116
163
  /**
117
- * 加载能力,返回执行器
118
- * @param capabilityId - 能力 ID
119
- * @returns 能力执行器
164
+ * central.baseURL → caller 显式给的(去尾斜杠)。
165
+ * 没传:浏览器取 `window.location.origin`(同源调用,SSO cookie 自动带);
166
+ * 非浏览器(SSR / Node.js 测试)抛错。
167
+ * 用法与 fullstack-plugin/packages/client/dataloom/src/service/index.ts 一致。
168
+ */
169
+ private resolveCentralBaseURL;
170
+ /**
171
+ * 预览态 / 运行态自动判定。沿用 nestjs-capability/src/capability.module.ts:18 同款判定:
172
+ * - 沙箱 fullstack-cli scripts/dev.sh → `NODE_ENV=development` → 预览态
173
+ * - 运行态(npm start / build 后部署)→ `NODE_ENV=production` → 运行态
174
+ * Vite 在构建时把 `process.env.NODE_ENV` 替换为字面量字符串。
175
+ */
176
+ private resolveMode;
177
+ /**
178
+ * 构造单次调用的请求 URL:
179
+ * - central 开启:4 个中心端点之一(mode 自动判定);
180
+ * - central 关闭:保持原 `${baseURL}/api/capability/{id}` 行为。
181
+ */
182
+ private buildExecuteUrl;
183
+ /**
184
+ * 构造请求体:
185
+ * - central + 预览态:`{ capability, action, params }`,capability 取自
186
+ * `virtual:capabilities`(load() 时已经 fail-fast 校验过,这里直接取)。
187
+ * - central + 运行态:`{ action, params }`(中心服务通过 RPC 查中心存储拿 config)。
188
+ * - 非 central:`{ action, params }`。
189
+ */
190
+ private buildRequestBody;
191
+ /**
192
+ * 加载能力,返回执行器。
193
+ * 方案文档 § Client SDK 改造伪代码:
194
+ * const config = capabilityMap[id];
195
+ * if (!config) throw new CapabilityNotFoundError(id);
196
+ * central + 预览态时 fail-fast:本地 `virtual:capabilities` map 没这个 id 就直接抛,
197
+ * 不发任何网络请求。运行态 / 非 central 模式跳过此校验。
120
198
  */
121
199
  load(capabilityId: string): CapabilityExecutor;
122
200
  private createExecutor;
@@ -128,4 +206,4 @@ declare class CapabilityClient {
128
206
  */
129
207
  declare function createClient(options: CapabilityClientOptions): CapabilityClient;
130
208
 
131
- export { ActionNotFoundError, CapabilityClient, type CapabilityClientOptions, CapabilityError, type CapabilityExecutor, CapabilityNotFoundError, ExecutionError, FileUploadError, type Logger, NetworkError, RateLimitError, type RateLimitErrorHook, createClient };
209
+ export { ActionNotFoundError, CapabilityClient, type CapabilityClientOptions, type CapabilityConfig, CapabilityError, type CapabilityExecutor, CapabilityNotFoundError, type CentralOptions, ExecutionError, FileUploadError, type Logger, NetworkError, RateLimitError, type RateLimitErrorHook, createClient };
package/dist/index.js CHANGED
@@ -282,6 +282,7 @@ __name(replaceFilesWithUrls, "replaceFilesWithUrls");
282
282
 
283
283
  // src/client.ts
284
284
  import { slardar as slardar2 } from "@lark-apaas/internal-slardar";
285
+ import virtualCapabilitiesMap from "virtual:capabilities";
285
286
  var LOG_PREFIX = "[CapabilityClient]";
286
287
  var defaultLogger = {
287
288
  debug: console.debug.bind(console),
@@ -295,17 +296,89 @@ var _CapabilityClient = class _CapabilityClient {
295
296
  __publicField(this, "baseURL");
296
297
  __publicField(this, "logger");
297
298
  __publicField(this, "onRateLimitError");
299
+ __publicField(this, "central");
298
300
  this.options = options;
299
301
  this.baseURL = (options?.baseURL ?? "").replace(/\/+$/, "");
300
302
  this.logger = options?.logger ?? defaultLogger;
301
303
  this.onRateLimitError = options?.onRateLimitError;
304
+ if (options?.central?.enabled) {
305
+ this.central = options.central;
306
+ }
307
+ }
308
+ /**
309
+ * central.baseURL → caller 显式给的(去尾斜杠)。
310
+ * 没传:浏览器取 `window.location.origin`(同源调用,SSO cookie 自动带);
311
+ * 非浏览器(SSR / Node.js 测试)抛错。
312
+ * 用法与 fullstack-plugin/packages/client/dataloom/src/service/index.ts 一致。
313
+ */
314
+ resolveCentralBaseURL(central) {
315
+ if (central.baseURL) return central.baseURL.replace(/\/+$/, "");
316
+ if (typeof window !== "undefined" && window.location?.origin) {
317
+ return window.location.origin;
318
+ }
319
+ throw new Error("CapabilityClient: central.baseURL is required when running outside browser (window.location unavailable)");
320
+ }
321
+ /**
322
+ * 预览态 / 运行态自动判定。沿用 nestjs-capability/src/capability.module.ts:18 同款判定:
323
+ * - 沙箱 fullstack-cli scripts/dev.sh → `NODE_ENV=development` → 预览态
324
+ * - 运行态(npm start / build 后部署)→ `NODE_ENV=production` → 运行态
325
+ * Vite 在构建时把 `process.env.NODE_ENV` 替换为字面量字符串。
326
+ */
327
+ resolveMode() {
328
+ const env = typeof process !== "undefined" ? "development" : void 0;
329
+ return env === "development" ? "preview" : "runtime";
330
+ }
331
+ /**
332
+ * 构造单次调用的请求 URL:
333
+ * - central 开启:4 个中心端点之一(mode 自动判定);
334
+ * - central 关闭:保持原 `${baseURL}/api/capability/{id}` 行为。
335
+ */
336
+ buildExecuteUrl(capabilityId, stream) {
337
+ if (!this.central) {
338
+ return `${this.baseURL}/api/capability/${capabilityId}${stream ? "/stream" : ""}`;
339
+ }
340
+ const base = this.resolveCentralBaseURL(this.central);
341
+ const segment = this.resolveMode() === "preview" ? "/preview/execute" : "/execute";
342
+ return `${base}/app/${this.central.appId}/__runtime__/api/v1/plugin_server/capability/${capabilityId}${segment}${stream ? "/stream" : ""}`;
343
+ }
344
+ /**
345
+ * 构造请求体:
346
+ * - central + 预览态:`{ capability, action, params }`,capability 取自
347
+ * `virtual:capabilities`(load() 时已经 fail-fast 校验过,这里直接取)。
348
+ * - central + 运行态:`{ action, params }`(中心服务通过 RPC 查中心存储拿 config)。
349
+ * - 非 central:`{ action, params }`。
350
+ */
351
+ buildRequestBody(capabilityId, action, params) {
352
+ if (this.central && this.resolveMode() === "preview") {
353
+ const capability = virtualCapabilitiesMap[capabilityId];
354
+ if (!capability) {
355
+ throw new CapabilityNotFoundError(capabilityId);
356
+ }
357
+ return JSON.stringify({
358
+ capability,
359
+ action,
360
+ params
361
+ });
362
+ }
363
+ return JSON.stringify({
364
+ action,
365
+ params
366
+ });
302
367
  }
303
368
  /**
304
- * 加载能力,返回执行器
305
- * @param capabilityId - 能力 ID
306
- * @returns 能力执行器
369
+ * 加载能力,返回执行器。
370
+ * 方案文档 § Client SDK 改造伪代码:
371
+ * const config = capabilityMap[id];
372
+ * if (!config) throw new CapabilityNotFoundError(id);
373
+ * central + 预览态时 fail-fast:本地 `virtual:capabilities` map 没这个 id 就直接抛,
374
+ * 不发任何网络请求。运行态 / 非 central 模式跳过此校验。
307
375
  */
308
376
  load(capabilityId) {
377
+ if (this.central && this.resolveMode() === "preview") {
378
+ if (!(capabilityId in virtualCapabilitiesMap)) {
379
+ throw new CapabilityNotFoundError(capabilityId);
380
+ }
381
+ }
309
382
  return this.createExecutor(capabilityId);
310
383
  }
311
384
  createExecutor(capabilityId) {
@@ -319,7 +392,7 @@ var _CapabilityClient = class _CapabilityClient {
319
392
  };
320
393
  }
321
394
  async executeCall(capabilityId, action, params) {
322
- const url = `${this.baseURL}/api/capability/${capabilityId}`;
395
+ const url = this.buildExecuteUrl(capabilityId, false);
323
396
  let requestParams = params ?? {};
324
397
  const extractedFiles = extractFiles(requestParams);
325
398
  if (extractedFiles.length > 0) {
@@ -340,10 +413,7 @@ var _CapabilityClient = class _CapabilityClient {
340
413
  "Content-Type": "application/json",
341
414
  ...this.options.fetchOptions?.headers
342
415
  },
343
- body: JSON.stringify({
344
- action,
345
- params: requestParams
346
- })
416
+ body: this.buildRequestBody(capabilityId, action, requestParams)
347
417
  });
348
418
  const data = await response.json();
349
419
  if (!response.ok || data.status_code !== ErrorCodes.SUCCESS) {
@@ -388,7 +458,7 @@ var _CapabilityClient = class _CapabilityClient {
388
458
  }
389
459
  }
390
460
  async *executeCallStream(capabilityId, action, params) {
391
- const url = `${this.baseURL}/api/capability/${capabilityId}/stream`;
461
+ const url = this.buildExecuteUrl(capabilityId, true);
392
462
  let requestParams = params ?? {};
393
463
  const extractedFiles = extractFiles(requestParams);
394
464
  if (extractedFiles.length > 0) {
@@ -401,6 +471,7 @@ var _CapabilityClient = class _CapabilityClient {
401
471
  this.logger.info(LOG_PREFIX, `callStream start: capabilityId=${capabilityId}, action=${action}`, {
402
472
  params: requestParams
403
473
  });
474
+ const body = this.buildRequestBody(capabilityId, action, requestParams);
404
475
  let response;
405
476
  try {
406
477
  response = await fetch(url, {
@@ -410,10 +481,7 @@ var _CapabilityClient = class _CapabilityClient {
410
481
  "Content-Type": "application/json",
411
482
  ...this.options.fetchOptions?.headers
412
483
  },
413
- body: JSON.stringify({
414
- action,
415
- params: requestParams
416
- })
484
+ body
417
485
  });
418
486
  } catch (error) {
419
487
  this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/errors.ts","../src/uploader.ts","../src/file-extractor.ts","../src/client.ts"],"sourcesContent":["import type { RateLimitError } from './errors';\n\n/**\n * Logger 接口,兼容 console 和 @lark-apaas/toolkit 的 logger\n */\nexport interface Logger {\n debug(message: unknown, ...args: unknown[]): void;\n info(message: unknown, ...args: unknown[]): void;\n warn(message: unknown, ...args: unknown[]): void;\n error(message: unknown, ...args: unknown[]): void;\n}\n\n/**\n * RateLimitError 钩子函数类型\n * 当检测到计费受限错误时,在抛出异常前调用此钩子\n */\nexport type RateLimitErrorHook = (error: RateLimitError) => void | Promise<void>;\n\n/**\n * 客户端配置选项\n */\nexport interface CapabilityClientOptions {\n /** 全局路径前缀,默认 ''。例如线上环境可设置为 '/spark/a' */\n baseURL?: string;\n /** 获取文件上传预签名 URL 的接口地址,由上层注入 */\n acquireUploadUrl: string;\n /** 获取文件临时下载 URL 的接口地址,由上层注入 */\n acquireDownloadUrl: string;\n /** 自定义 fetch 配置 */\n fetchOptions?: RequestInit;\n /** 自定义 logger,默认使用 console */\n logger?: Logger;\n /**\n * 计费受限错误钩子\n * 当检测到 RateLimitError 时,在抛出异常前调用此钩子\n * 可用于上报埋点、展示 toast 等场景\n */\n onRateLimitError?: RateLimitErrorHook;\n}\n\n/**\n * 能力执行器接口\n */\nexport interface CapabilityExecutor {\n /**\n * 调用能力\n * @param action - Action 名称\n * @param params - 输入参数\n * @returns Action 执行结果\n */\n call<T = unknown>(\n action: string,\n params?: Record<string, unknown>\n ): Promise<T>;\n\n /**\n * 流式调用能力\n * @param action - Action 名称\n * @param params - 输入参数\n * @returns AsyncIterable,逐个 yield chunk\n */\n callStream<T = unknown>(\n action: string,\n params?: Record<string, unknown>\n ): AsyncIterable<T>;\n}\n\n// ========== API 响应类型 ==========\n\n/**\n * 成功响应\n */\nexport interface SuccessResponse<T> {\n status_code: '0';\n data: T;\n}\n\n/**\n * 错误响应\n */\nexport interface ErrorResponse {\n status_code: string;\n error_msg: string;\n /** 是否为计费受限错误 */\n is_rate_limit_error?: boolean;\n}\n\n/**\n * API 响应类型\n */\nexport type ApiResponse<T> = SuccessResponse<T> | ErrorResponse;\n\n// ========== 具体响应 data 结构 ==========\n\n/**\n * 执行接口响应 data 结构\n */\nexport interface ExecuteResponseData {\n output: unknown;\n}\n\n// ========== 流式响应结构 ==========\n\n/**\n * 流式内容响应\n */\nexport interface StreamContentResponse {\n status_code: '0';\n data: {\n type: 'content';\n delta: unknown;\n finished?: boolean;\n };\n}\n\n/**\n * 流式错误响应\n */\nexport interface StreamErrorResponse {\n status_code: '0';\n data: {\n type: 'error';\n error: {\n /** 错误码,计费受限时为业务错误码(如 k_st_ec_400002687) */\n code: string;\n message: string;\n /** 是否为计费受限错误 */\n isRateLimitError?: boolean;\n };\n };\n}\n\n/**\n * 流式响应类型\n */\nexport type StreamResponse = StreamContentResponse | StreamErrorResponse;\n\n// ========== 错误码 ==========\n\n/**\n * 后端错误码\n */\nexport const ErrorCodes = {\n SUCCESS: '0',\n CAPABILITY_NOT_FOUND: 'k_ec_cap_001',\n PLUGIN_NOT_FOUND: 'k_ec_cap_002',\n ACTION_NOT_FOUND: 'k_ec_cap_003',\n PARAMS_VALIDATION_ERROR: 'k_ec_cap_004',\n EXECUTION_ERROR: 'k_ec_cap_005',\n RATE_LIMIT_EXCEEDED: 'k_ec_cap_006',\n} as const;\n\n// ========== 文件上传相关类型 ==========\n\n/**\n * 提取的文件信息\n */\nexport interface ExtractedFile {\n /** 在 params 中的路径,如 ['image_list', 0] */\n path: (string | number)[];\n /** 文件对象 */\n file: File | Blob;\n}\n\n/**\n * 上传结果\n */\nexport interface UploadResult {\n /** 在 params 中的路径 */\n path: (string | number)[];\n /** 临时下载 URL */\n downloadUrl: string;\n}\n\n/**\n * 获取上传 URL 响应\n */\nexport interface AcquireUploadUrlResponse {\n status_code: string;\n data: {\n uploadURL: string;\n objectKey: string;\n };\n}\n\n/**\n * 获取下载 URL 响应\n */\nexport interface AcquireDownloadUrlResponse {\n status_code: string;\n data: {\n downloadURL: string;\n };\n}\n","/**\n * 能力调用错误基类\n */\nexport class CapabilityError extends Error {\n /** 错误码 */\n code: string;\n /** HTTP 状态码 */\n statusCode?: number;\n\n constructor(message: string, code: string, statusCode?: number) {\n super(message);\n this.name = 'CapabilityError';\n this.code = code;\n this.statusCode = statusCode;\n }\n}\n\n/**\n * 能力不存在错误\n */\nexport class CapabilityNotFoundError extends CapabilityError {\n constructor(capabilityId: string, statusCode?: number) {\n super(`Capability not found: ${capabilityId}`, 'CAPABILITY_NOT_FOUND', statusCode);\n this.name = 'CapabilityNotFoundError';\n }\n}\n\n/**\n * Action 不存在错误\n */\nexport class ActionNotFoundError extends CapabilityError {\n constructor(message: string, statusCode?: number) {\n super(message, 'ACTION_NOT_FOUND', statusCode);\n this.name = 'ActionNotFoundError';\n }\n}\n\n/**\n * 网络错误\n */\nexport class NetworkError extends CapabilityError {\n constructor(message: string) {\n super(message, 'NETWORK_ERROR');\n this.name = 'NetworkError';\n }\n}\n\n/**\n * 执行错误\n */\nexport class ExecutionError extends CapabilityError {\n constructor(message: string, statusCode?: number) {\n super(message, 'EXECUTION_ERROR', statusCode);\n this.name = 'ExecutionError';\n }\n}\n\n/**\n * 文件上传错误\n */\nexport class FileUploadError extends CapabilityError {\n constructor(message: string, statusCode?: number) {\n super(message, 'FILE_UPLOAD_ERROR', statusCode);\n this.name = 'FileUploadError';\n }\n}\n\n/**\n * 计费受限错误\n */\nexport class RateLimitError extends CapabilityError {\n /** 业务错误码 */\n rateLimitCode: string;\n /** 业务错误消息 */\n rateLimitMessage: string;\n\n constructor(rateLimitCode: string, rateLimitMessage: string, statusCode?: number) {\n super(rateLimitMessage, 'RATE_LIMIT_EXCEEDED', statusCode);\n this.name = 'RateLimitError';\n this.rateLimitCode = rateLimitCode;\n this.rateLimitMessage = rateLimitMessage;\n }\n}\n","import type {\n CapabilityClientOptions,\n ExtractedFile,\n UploadResult,\n AcquireUploadUrlResponse,\n AcquireDownloadUrlResponse,\n} from './types';\nimport { FileUploadError } from './errors';\nimport { slardar } from '@lark-apaas/internal-slardar';\n\ntype FileUploaderOptions = Pick<CapabilityClientOptions, 'acquireUploadUrl' | 'acquireDownloadUrl' | 'fetchOptions'>;\n\n/**\n * 文件上传器\n */\nexport class FileUploader {\n private readonly options: FileUploaderOptions;\n\n constructor(options: FileUploaderOptions) {\n this.options = options;\n }\n\n /**\n * 上传单个文件,返回下载 URL\n */\n async upload(file: File | Blob): Promise<string> {\n const fileName = file instanceof File ? file.name : `blob-${Date.now()}`;\n\n // 1. 获取上传预签名 URL\n const { uploadURL, objectKey } = await this.fetchUploadUrl(fileName);\n\n // 2. 上传文件到 TOS\n await this.uploadToTos(uploadURL, file);\n\n // 3. 获取下载 URL\n const downloadUrl = await this.fetchDownloadUrl(objectKey);\n\n return downloadUrl;\n }\n\n /**\n * 并发上传多个文件\n */\n async uploadAll(files: ExtractedFile[]): Promise<UploadResult[]> {\n const results = await Promise.all(\n files.map(async ({ path, file }) => {\n const downloadUrl = await this.upload(file);\n return { path, downloadUrl };\n })\n );\n return results;\n }\n\n /**\n * 获取上传预签名 URL\n */\n private async fetchUploadUrl(fileName: string): Promise<{ uploadURL: string; objectKey: string }> {\n const { acquireUploadUrl, fetchOptions } = this.options;\n\n let response: Response;\n try {\n response = await fetch(acquireUploadUrl, {\n method: 'POST',\n ...fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...fetchOptions?.headers,\n },\n body: JSON.stringify({ fileName }),\n });\n } catch (error) {\n slardar.captureException(error, { source: 'client-capability', module: 'file-upload', step: 'fetch-upload-url' });\n throw new FileUploadError(\n `Failed to acquire upload URL: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n if (!response.ok) {\n throw new FileUploadError(\n `Failed to acquire upload URL: HTTP ${response.status}`,\n response.status\n );\n }\n\n const data = (await response.json()) as AcquireUploadUrlResponse;\n\n if (data.status_code !== '0') {\n throw new FileUploadError(`Failed to acquire upload URL: ${data.status_code}`);\n }\n\n return data.data;\n }\n\n /**\n * 上传文件到 TOS(预签名 URL)\n */\n private async uploadToTos(uploadURL: string, file: File | Blob): Promise<void> {\n let response: Response;\n try {\n response = await fetch(uploadURL, {\n method: 'PUT',\n body: file,\n });\n } catch (error) {\n slardar.captureException(error, { source: 'client-capability', module: 'file-upload', step: 'upload-to-tos' });\n throw new FileUploadError(\n `Failed to upload file to TOS: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n if (!response.ok) {\n throw new FileUploadError(\n `Failed to upload file to TOS: HTTP ${response.status}`,\n response.status\n );\n }\n }\n\n /**\n * 获取临时下载 URL\n */\n private async fetchDownloadUrl(objectKey: string): Promise<string> {\n const { acquireDownloadUrl, fetchOptions } = this.options;\n\n let response: Response;\n try {\n response = await fetch(acquireDownloadUrl, {\n method: 'POST',\n ...fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...fetchOptions?.headers,\n },\n body: JSON.stringify({ objectKey }),\n });\n } catch (error) {\n slardar.captureException(error, { source: 'client-capability', module: 'file-upload', step: 'fetch-download-url' });\n throw new FileUploadError(\n `Failed to acquire download URL: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n if (!response.ok) {\n throw new FileUploadError(\n `Failed to acquire download URL: HTTP ${response.status}`,\n response.status\n );\n }\n\n const data = (await response.json()) as AcquireDownloadUrlResponse;\n\n if (data.status_code !== '0') {\n throw new FileUploadError(`Failed to acquire download URL: ${data.status_code}`);\n }\n\n return data.data.downloadURL;\n }\n}\n","import type { ExtractedFile, UploadResult } from './types';\n\n/**\n * 检测是否为 File 或 Blob\n */\nexport function isFile(value: unknown): value is File | Blob {\n return value instanceof File || value instanceof Blob;\n}\n\n/**\n * 递归提取 params 中的所有文件\n *\n * @example\n * extractFiles({ image_list: [file1, file2] })\n * // => [\n * // { path: ['image_list', 0], file: file1 },\n * // { path: ['image_list', 1], file: file2 }\n * // ]\n */\nexport function extractFiles(params: Record<string, unknown>): ExtractedFile[] {\n const files: ExtractedFile[] = [];\n\n function traverse(obj: unknown, path: (string | number)[]): void {\n if (isFile(obj)) {\n files.push({ path: [...path], file: obj });\n } else if (Array.isArray(obj)) {\n obj.forEach((item, index) => traverse(item, [...path, index]));\n } else if (obj !== null && typeof obj === 'object') {\n Object.entries(obj).forEach(([key, value]) => {\n traverse(value, [...path, key]);\n });\n }\n }\n\n traverse(params, []);\n return files;\n}\n\n/**\n * 根据上传结果替换 params 中的文件为 URL\n *\n * @example\n * replaceFilesWithUrls(\n * { image_list: [file1, file2] },\n * [\n * { path: ['image_list', 0], downloadUrl: 'https://...' },\n * { path: ['image_list', 1], downloadUrl: 'https://...' }\n * ]\n * )\n * // => { image_list: ['https://...', 'https://...'] }\n */\nexport function replaceFilesWithUrls(\n params: Record<string, unknown>,\n results: UploadResult[]\n): Record<string, unknown> {\n // 创建 path -> url 的映射,用于快速查找\n const urlMap = new Map<string, string>();\n for (const { path, downloadUrl } of results) {\n urlMap.set(JSON.stringify(path), downloadUrl);\n }\n\n // 手动深拷贝,同时将 File/Blob 替换为对应的 URL\n // 注意:不能使用 structuredClone,因为它不支持 File/Blob 对象\n function cloneAndReplace(obj: unknown, currentPath: (string | number)[]): unknown {\n // 检查当前路径是否有对应的 URL\n const pathKey = JSON.stringify(currentPath);\n if (urlMap.has(pathKey)) {\n return urlMap.get(pathKey);\n }\n\n // 如果是 File/Blob 但没有对应的 URL(不应该发生),返回 null\n if (isFile(obj)) {\n return null;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item, index) => cloneAndReplace(item, [...currentPath, index]));\n }\n\n if (obj !== null && typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n result[key] = cloneAndReplace(value, [...currentPath, key]);\n }\n return result;\n }\n\n // 原始值直接返回\n return obj;\n }\n\n return cloneAndReplace(params, []) as Record<string, unknown>;\n}\n","import type {\n CapabilityClientOptions,\n CapabilityExecutor,\n ApiResponse,\n ExecuteResponseData,\n StreamResponse,\n Logger,\n RateLimitErrorHook,\n} from './types';\nimport { ErrorCodes } from './types';\nimport {\n CapabilityError,\n CapabilityNotFoundError,\n ActionNotFoundError,\n NetworkError,\n ExecutionError,\n RateLimitError,\n} from './errors';\nimport { FileUploader } from './uploader';\nimport { extractFiles, replaceFilesWithUrls } from './file-extractor';\nimport { slardar } from '@lark-apaas/internal-slardar';\n\nconst LOG_PREFIX = '[CapabilityClient]';\n\nconst defaultLogger: Logger = {\n debug: console.debug.bind(console),\n info: console.info.bind(console),\n warn: console.warn.bind(console),\n error: console.error.bind(console),\n};\n\n/**\n * 能力客户端\n */\nexport class CapabilityClient {\n private options: CapabilityClientOptions;\n private baseURL: string;\n private logger: Logger;\n private onRateLimitError?: RateLimitErrorHook;\n\n constructor(options: CapabilityClientOptions) {\n this.options = options;\n // 移除末尾的斜杠,确保拼接时格式正确\n this.baseURL = (options?.baseURL ?? '').replace(/\\/+$/, '');\n this.logger = options?.logger ?? defaultLogger;\n this.onRateLimitError = options?.onRateLimitError;\n }\n\n /**\n * 加载能力,返回执行器\n * @param capabilityId - 能力 ID\n * @returns 能力执行器\n */\n load(capabilityId: string): CapabilityExecutor {\n return this.createExecutor(capabilityId);\n }\n\n private createExecutor(capabilityId: string): CapabilityExecutor {\n return {\n call: <T = unknown>(action: string, params?: Record<string, unknown>) => {\n return this.executeCall<T>(capabilityId, action, params);\n },\n callStream: <T = unknown>(action: string, params?: Record<string, unknown>) => {\n return this.executeCallStream<T>(capabilityId, action, params);\n },\n };\n }\n\n private async executeCall<T>(\n capabilityId: string,\n action: string,\n params?: Record<string, unknown>\n ): Promise<T> {\n const url = `${this.baseURL}/api/capability/${capabilityId}`;\n let requestParams = params ?? {};\n\n // 处理文件上传\n const extractedFiles = extractFiles(requestParams);\n if (extractedFiles.length > 0) {\n this.logger.info(LOG_PREFIX, `uploading ${extractedFiles.length} file(s)...`);\n const uploader = new FileUploader(this.options);\n const uploadResults = await uploader.uploadAll(extractedFiles);\n requestParams = replaceFilesWithUrls(requestParams, uploadResults);\n this.logger.info(LOG_PREFIX, `file upload completed`);\n }\n\n this.logger.info(LOG_PREFIX, `call start: capabilityId=${capabilityId}, action=${action}`, { params: requestParams });\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n ...this.options.fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...this.options.fetchOptions?.headers,\n },\n body: JSON.stringify({\n action,\n params: requestParams,\n }),\n });\n\n const data = (await response.json()) as ApiResponse<ExecuteResponseData>;\n\n if (!response.ok || data.status_code !== ErrorCodes.SUCCESS) {\n const errorResponse = data as {\n status_code: string;\n error_msg: string;\n is_rate_limit_error?: boolean;\n };\n const errorCode = errorResponse.status_code;\n\n // 计费受限错误:通过 is_rate_limit_error 字段识别\n if (errorResponse.is_rate_limit_error) {\n const rateLimitError = new RateLimitError(\n errorCode, // status_code 就是业务错误码\n errorResponse.error_msg,\n response.status,\n );\n await this.onRateLimitError?.(rateLimitError);\n throw rateLimitError;\n }\n\n switch (errorCode) {\n case ErrorCodes.CAPABILITY_NOT_FOUND:\n throw new CapabilityNotFoundError(capabilityId, response.status);\n case ErrorCodes.ACTION_NOT_FOUND:\n throw new ActionNotFoundError(errorResponse.error_msg, response.status);\n case ErrorCodes.PLUGIN_NOT_FOUND:\n case ErrorCodes.EXECUTION_ERROR:\n default:\n throw new ExecutionError(errorResponse.error_msg, response.status);\n }\n }\n\n const result = (data as { data: ExecuteResponseData }).data.output as T;\n\n this.logger.info(LOG_PREFIX, `call success: capabilityId=${capabilityId}, action=${action}`, { result });\n\n return result;\n } catch (error) {\n this.logger.error(LOG_PREFIX, `call failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error });\n slardar.captureException(error, { source: 'client-capability', module: 'execute-call', capabilityId, action });\n if (error instanceof CapabilityError) {\n throw error;\n }\n throw new NetworkError(error instanceof Error ? error.message : String(error));\n }\n }\n\n private async *executeCallStream<T>(\n capabilityId: string,\n action: string,\n params?: Record<string, unknown>\n ): AsyncIterable<T> {\n const url = `${this.baseURL}/api/capability/${capabilityId}/stream`;\n let requestParams = params ?? {};\n\n // 处理文件上传\n const extractedFiles = extractFiles(requestParams);\n if (extractedFiles.length > 0) {\n this.logger.info(LOG_PREFIX, `uploading ${extractedFiles.length} file(s)...`);\n const uploader = new FileUploader(this.options);\n const uploadResults = await uploader.uploadAll(extractedFiles);\n requestParams = replaceFilesWithUrls(requestParams, uploadResults);\n this.logger.info(LOG_PREFIX, `file upload completed`);\n }\n\n this.logger.info(LOG_PREFIX, `callStream start: capabilityId=${capabilityId}, action=${action}`, { params: requestParams });\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n ...this.options.fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...this.options.fetchOptions?.headers,\n },\n body: JSON.stringify({\n action,\n params: requestParams,\n }),\n });\n } catch (error) {\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error });\n slardar.captureException(error, { source: 'client-capability', module: 'execute-call-stream', capabilityId, action, phase: 'fetch' });\n throw new NetworkError(error instanceof Error ? error.message : String(error));\n }\n\n if (!response.ok) {\n const errMsg = `HTTP ${response.status} ${response.statusText}`;\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error: errMsg });\n throw new NetworkError(errMsg);\n }\n\n if (!response.body) {\n const errMsg = 'Response body is null';\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error: errMsg });\n throw new NetworkError(errMsg);\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let chunkCount = 0;\n let aggregatedContent = '';\n let canAggregate = true;\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n\n try {\n const parsed = JSON.parse(data) as StreamResponse;\n\n if (parsed.status_code === ErrorCodes.SUCCESS && parsed.data) {\n if (parsed.data.type === 'content') {\n chunkCount++;\n const delta = parsed.data.delta as T;\n\n // 尝试聚合 content 字段\n if (canAggregate) {\n const content = (delta as Record<string, unknown>)?.content;\n if (typeof content === 'string') {\n aggregatedContent += content;\n } else {\n canAggregate = false;\n }\n }\n\n yield delta;\n\n if (parsed.data.finished) {\n const resultInfo = canAggregate\n ? { chunkCount, result: aggregatedContent }\n : { chunkCount, resultLength: aggregatedContent.length || chunkCount };\n this.logger.info(LOG_PREFIX, `callStream end: capabilityId=${capabilityId}, action=${action}`, resultInfo);\n return;\n }\n } else if (parsed.data.type === 'error') {\n const err = parsed.data.error;\n if (err.isRateLimitError) {\n const rateLimitError = new RateLimitError(\n err.code, // code 就是业务错误码\n err.message,\n );\n await this.onRateLimitError?.(rateLimitError);\n throw rateLimitError;\n }\n throw new ExecutionError(err.message);\n }\n }\n } catch (parseError) {\n if (parseError instanceof CapabilityError) {\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error: parseError, chunkCount });\n throw parseError;\n }\n // 忽略非 JSON 行\n }\n }\n }\n }\n const resultInfo = canAggregate\n ? { chunkCount, result: aggregatedContent }\n : { chunkCount, resultLength: aggregatedContent.length || chunkCount };\n this.logger.info(LOG_PREFIX, `callStream end: capabilityId=${capabilityId}, action=${action}`, resultInfo);\n } catch (error) {\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error, chunkCount });\n slardar.captureException(error, { source: 'client-capability', module: 'execute-call-stream', capabilityId, action, phase: 'read' });\n if (error instanceof CapabilityError) {\n throw error;\n }\n throw new NetworkError(error instanceof Error ? error.message : String(error));\n } finally {\n reader.releaseLock();\n }\n }\n}\n\n/**\n * 创建客户端实例\n */\nexport function createClient(options: CapabilityClientOptions): CapabilityClient {\n return new CapabilityClient(options);\n}\n"],"mappings":"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","names":["ErrorCodes","SUCCESS","CAPABILITY_NOT_FOUND","PLUGIN_NOT_FOUND","ACTION_NOT_FOUND","PARAMS_VALIDATION_ERROR","EXECUTION_ERROR","RATE_LIMIT_EXCEEDED","CapabilityError","Error","message","code","statusCode","name","CapabilityNotFoundError","capabilityId","ActionNotFoundError","NetworkError","ExecutionError","FileUploadError","RateLimitError","rateLimitCode","rateLimitMessage","slardar","FileUploader","options","upload","file","fileName","File","name","Date","now","uploadURL","objectKey","fetchUploadUrl","uploadToTos","downloadUrl","fetchDownloadUrl","uploadAll","files","results","Promise","all","map","path","acquireUploadUrl","fetchOptions","response","fetch","method","headers","body","JSON","stringify","error","slardar","captureException","source","module","step","FileUploadError","Error","message","String","ok","status","data","json","status_code","acquireDownloadUrl","downloadURL","isFile","value","File","Blob","extractFiles","params","files","traverse","obj","path","push","file","Array","isArray","forEach","item","index","Object","entries","key","replaceFilesWithUrls","results","urlMap","Map","downloadUrl","set","JSON","stringify","cloneAndReplace","currentPath","pathKey","has","get","map","result","slardar","LOG_PREFIX","defaultLogger","debug","console","bind","info","warn","error","CapabilityClient","options","baseURL","logger","onRateLimitError","replace","load","capabilityId","createExecutor","call","action","params","executeCall","callStream","executeCallStream","url","requestParams","extractedFiles","extractFiles","length","uploader","FileUploader","uploadResults","uploadAll","replaceFilesWithUrls","response","fetch","method","fetchOptions","headers","body","JSON","stringify","data","json","ok","status_code","ErrorCodes","SUCCESS","errorResponse","errorCode","is_rate_limit_error","rateLimitError","RateLimitError","error_msg","status","CAPABILITY_NOT_FOUND","CapabilityNotFoundError","ACTION_NOT_FOUND","ActionNotFoundError","PLUGIN_NOT_FOUND","EXECUTION_ERROR","ExecutionError","result","output","slardar","captureException","source","module","CapabilityError","NetworkError","Error","message","String","phase","errMsg","statusText","reader","getReader","decoder","TextDecoder","buffer","chunkCount","aggregatedContent","canAggregate","done","value","read","decode","stream","lines","split","pop","line","startsWith","slice","parsed","parse","type","delta","content","finished","resultInfo","resultLength","err","isRateLimitError","code","parseError","releaseLock","createClient"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/errors.ts","../src/uploader.ts","../src/file-extractor.ts","../src/client.ts"],"sourcesContent":["import type { RateLimitError } from './errors';\n\n/**\n * Logger 接口,兼容 console 和 @lark-apaas/toolkit 的 logger\n */\nexport interface Logger {\n debug(message: unknown, ...args: unknown[]): void;\n info(message: unknown, ...args: unknown[]): void;\n warn(message: unknown, ...args: unknown[]): void;\n error(message: unknown, ...args: unknown[]): void;\n}\n\n/**\n * RateLimitError 钩子函数类型\n * 当检测到计费受限错误时,在抛出异常前调用此钩子\n */\nexport type RateLimitErrorHook = (error: RateLimitError) => void | Promise<void>;\n\n/**\n * 客户端配置选项\n */\nexport interface CapabilityClientOptions {\n /** 全局路径前缀,默认 ''。例如线上环境可设置为 '/spark/a' */\n baseURL?: string;\n /** 获取文件上传预签名 URL 的接口地址,由上层注入 */\n acquireUploadUrl: string;\n /** 获取文件临时下载 URL 的接口地址,由上层注入 */\n acquireDownloadUrl: string;\n /** 自定义 fetch 配置 */\n fetchOptions?: RequestInit;\n /** 自定义 logger,默认使用 console */\n logger?: Logger;\n /**\n * 计费受限错误钩子\n * 当检测到 RateLimitError 时,在抛出异常前调用此钩子\n * 可用于上报埋点、展示 toast 等场景\n */\n onRateLimitError?: RateLimitErrorHook;\n /**\n * 中心化服务分流开关。启用后 capability 调用路由到妙搭 plugin_server 的 4 个中心端点:\n * - 运行态 非流式: POST {baseURL}/app/{appId}/__runtime__/api/v1/plugin_server/capability/{capabilityId}/execute\n * - 运行态 流式: POST {baseURL}/app/{appId}/__runtime__/api/v1/plugin_server/capability/{capabilityId}/execute/stream\n * - 预览态 非流式: POST {baseURL}/app/{appId}/__runtime__/api/v1/plugin_server/capability/{capabilityId}/preview/execute\n * - 预览态 流式: POST {baseURL}/app/{appId}/__runtime__/api/v1/plugin_server/capability/{capabilityId}/preview/execute/stream\n *\n * baseURL 默认取 `window.location.origin`(同源调用,SSO cookie 自动带)。\n * 预览态 / 运行态由 `process.env.NODE_ENV` 自动判定:\n * - 沙箱开发态(fullstack-cli scripts/dev.sh 起的进程,NODE_ENV=development)→ 预览态\n * - 运行态启动(NODE_ENV=production,无论 build 还是 npm start)→ 运行态\n * 业务前端 `createClient` 配置不需要区分两种环境。\n *\n * 预览态 body 必须携带完整 capability config,从 `capabilities` map 查;缺失抛\n * CapabilityNotFoundError。运行态由中心服务通过 capability_id 走 RPC 查中心存储。\n */\n central?: CentralOptions;\n}\n\n/**\n * 中心化服务分流配置。\n */\nexport interface CentralOptions {\n /** 是否启用中心化分流;false / 未配置则维持原行为打用户应用。 */\n enabled: boolean;\n /**\n * 中心服务 base URL(含 scheme)。可选;不传时默认 `window.location.origin`。\n * 非浏览器环境(SSR / Node.js 测试)必须显式传,否则 SDK 抛错。\n */\n baseURL?: string;\n /** 当前应用 ID,拼接在 `/app/{appId}/__runtime__/...` 路径段。 */\n appId: string;\n}\n\n/**\n * Capability 配置,与 @lark-apaas/nestjs-capability / miaoda_plugin_server 的 interfaces/capability-config.ts 对齐。\n * 预览态 body.capability 必须为完整对象。\n */\nexport interface CapabilityConfig {\n id: string;\n pluginKey: string;\n pluginVersion: string;\n name: string;\n description: string;\n paramsSchema: unknown;\n formValue: Record<string, unknown>;\n createdAt: number;\n updatedAt: number;\n}\n\n/**\n * 能力执行器接口\n */\nexport interface CapabilityExecutor {\n /**\n * 调用能力\n * @param action - Action 名称\n * @param params - 输入参数\n * @returns Action 执行结果\n */\n call<T = unknown>(\n action: string,\n params?: Record<string, unknown>\n ): Promise<T>;\n\n /**\n * 流式调用能力\n * @param action - Action 名称\n * @param params - 输入参数\n * @returns AsyncIterable,逐个 yield chunk\n */\n callStream<T = unknown>(\n action: string,\n params?: Record<string, unknown>\n ): AsyncIterable<T>;\n}\n\n// ========== API 响应类型 ==========\n\n/**\n * 成功响应\n */\nexport interface SuccessResponse<T> {\n status_code: '0';\n data: T;\n}\n\n/**\n * 错误响应\n */\nexport interface ErrorResponse {\n status_code: string;\n error_msg: string;\n /** 是否为计费受限错误 */\n is_rate_limit_error?: boolean;\n}\n\n/**\n * API 响应类型\n */\nexport type ApiResponse<T> = SuccessResponse<T> | ErrorResponse;\n\n// ========== 具体响应 data 结构 ==========\n\n/**\n * 执行接口响应 data 结构\n */\nexport interface ExecuteResponseData {\n output: unknown;\n}\n\n// ========== 流式响应结构 ==========\n\n/**\n * 流式内容响应\n */\nexport interface StreamContentResponse {\n status_code: '0';\n data: {\n type: 'content';\n delta: unknown;\n finished?: boolean;\n };\n}\n\n/**\n * 流式错误响应\n */\nexport interface StreamErrorResponse {\n status_code: '0';\n data: {\n type: 'error';\n error: {\n /** 错误码,计费受限时为业务错误码(如 k_st_ec_400002687) */\n code: string;\n message: string;\n /** 是否为计费受限错误 */\n isRateLimitError?: boolean;\n };\n };\n}\n\n/**\n * 流式响应类型\n */\nexport type StreamResponse = StreamContentResponse | StreamErrorResponse;\n\n// ========== 错误码 ==========\n\n/**\n * 后端错误码\n */\nexport const ErrorCodes = {\n SUCCESS: '0',\n CAPABILITY_NOT_FOUND: 'k_ec_cap_001',\n PLUGIN_NOT_FOUND: 'k_ec_cap_002',\n ACTION_NOT_FOUND: 'k_ec_cap_003',\n PARAMS_VALIDATION_ERROR: 'k_ec_cap_004',\n EXECUTION_ERROR: 'k_ec_cap_005',\n RATE_LIMIT_EXCEEDED: 'k_ec_cap_006',\n} as const;\n\n// ========== 文件上传相关类型 ==========\n\n/**\n * 提取的文件信息\n */\nexport interface ExtractedFile {\n /** 在 params 中的路径,如 ['image_list', 0] */\n path: (string | number)[];\n /** 文件对象 */\n file: File | Blob;\n}\n\n/**\n * 上传结果\n */\nexport interface UploadResult {\n /** 在 params 中的路径 */\n path: (string | number)[];\n /** 临时下载 URL */\n downloadUrl: string;\n}\n\n/**\n * 获取上传 URL 响应\n */\nexport interface AcquireUploadUrlResponse {\n status_code: string;\n data: {\n uploadURL: string;\n objectKey: string;\n };\n}\n\n/**\n * 获取下载 URL 响应\n */\nexport interface AcquireDownloadUrlResponse {\n status_code: string;\n data: {\n downloadURL: string;\n };\n}\n","/**\n * 能力调用错误基类\n */\nexport class CapabilityError extends Error {\n /** 错误码 */\n code: string;\n /** HTTP 状态码 */\n statusCode?: number;\n\n constructor(message: string, code: string, statusCode?: number) {\n super(message);\n this.name = 'CapabilityError';\n this.code = code;\n this.statusCode = statusCode;\n }\n}\n\n/**\n * 能力不存在错误\n */\nexport class CapabilityNotFoundError extends CapabilityError {\n constructor(capabilityId: string, statusCode?: number) {\n super(`Capability not found: ${capabilityId}`, 'CAPABILITY_NOT_FOUND', statusCode);\n this.name = 'CapabilityNotFoundError';\n }\n}\n\n/**\n * Action 不存在错误\n */\nexport class ActionNotFoundError extends CapabilityError {\n constructor(message: string, statusCode?: number) {\n super(message, 'ACTION_NOT_FOUND', statusCode);\n this.name = 'ActionNotFoundError';\n }\n}\n\n/**\n * 网络错误\n */\nexport class NetworkError extends CapabilityError {\n constructor(message: string) {\n super(message, 'NETWORK_ERROR');\n this.name = 'NetworkError';\n }\n}\n\n/**\n * 执行错误\n */\nexport class ExecutionError extends CapabilityError {\n constructor(message: string, statusCode?: number) {\n super(message, 'EXECUTION_ERROR', statusCode);\n this.name = 'ExecutionError';\n }\n}\n\n/**\n * 文件上传错误\n */\nexport class FileUploadError extends CapabilityError {\n constructor(message: string, statusCode?: number) {\n super(message, 'FILE_UPLOAD_ERROR', statusCode);\n this.name = 'FileUploadError';\n }\n}\n\n/**\n * 计费受限错误\n */\nexport class RateLimitError extends CapabilityError {\n /** 业务错误码 */\n rateLimitCode: string;\n /** 业务错误消息 */\n rateLimitMessage: string;\n\n constructor(rateLimitCode: string, rateLimitMessage: string, statusCode?: number) {\n super(rateLimitMessage, 'RATE_LIMIT_EXCEEDED', statusCode);\n this.name = 'RateLimitError';\n this.rateLimitCode = rateLimitCode;\n this.rateLimitMessage = rateLimitMessage;\n }\n}\n","import type {\n CapabilityClientOptions,\n ExtractedFile,\n UploadResult,\n AcquireUploadUrlResponse,\n AcquireDownloadUrlResponse,\n} from './types';\nimport { FileUploadError } from './errors';\nimport { slardar } from '@lark-apaas/internal-slardar';\n\ntype FileUploaderOptions = Pick<CapabilityClientOptions, 'acquireUploadUrl' | 'acquireDownloadUrl' | 'fetchOptions'>;\n\n/**\n * 文件上传器\n */\nexport class FileUploader {\n private readonly options: FileUploaderOptions;\n\n constructor(options: FileUploaderOptions) {\n this.options = options;\n }\n\n /**\n * 上传单个文件,返回下载 URL\n */\n async upload(file: File | Blob): Promise<string> {\n const fileName = file instanceof File ? file.name : `blob-${Date.now()}`;\n\n // 1. 获取上传预签名 URL\n const { uploadURL, objectKey } = await this.fetchUploadUrl(fileName);\n\n // 2. 上传文件到 TOS\n await this.uploadToTos(uploadURL, file);\n\n // 3. 获取下载 URL\n const downloadUrl = await this.fetchDownloadUrl(objectKey);\n\n return downloadUrl;\n }\n\n /**\n * 并发上传多个文件\n */\n async uploadAll(files: ExtractedFile[]): Promise<UploadResult[]> {\n const results = await Promise.all(\n files.map(async ({ path, file }) => {\n const downloadUrl = await this.upload(file);\n return { path, downloadUrl };\n })\n );\n return results;\n }\n\n /**\n * 获取上传预签名 URL\n */\n private async fetchUploadUrl(fileName: string): Promise<{ uploadURL: string; objectKey: string }> {\n const { acquireUploadUrl, fetchOptions } = this.options;\n\n let response: Response;\n try {\n response = await fetch(acquireUploadUrl, {\n method: 'POST',\n ...fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...fetchOptions?.headers,\n },\n body: JSON.stringify({ fileName }),\n });\n } catch (error) {\n slardar.captureException(error, { source: 'client-capability', module: 'file-upload', step: 'fetch-upload-url' });\n throw new FileUploadError(\n `Failed to acquire upload URL: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n if (!response.ok) {\n throw new FileUploadError(\n `Failed to acquire upload URL: HTTP ${response.status}`,\n response.status\n );\n }\n\n const data = (await response.json()) as AcquireUploadUrlResponse;\n\n if (data.status_code !== '0') {\n throw new FileUploadError(`Failed to acquire upload URL: ${data.status_code}`);\n }\n\n return data.data;\n }\n\n /**\n * 上传文件到 TOS(预签名 URL)\n */\n private async uploadToTos(uploadURL: string, file: File | Blob): Promise<void> {\n let response: Response;\n try {\n response = await fetch(uploadURL, {\n method: 'PUT',\n body: file,\n });\n } catch (error) {\n slardar.captureException(error, { source: 'client-capability', module: 'file-upload', step: 'upload-to-tos' });\n throw new FileUploadError(\n `Failed to upload file to TOS: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n if (!response.ok) {\n throw new FileUploadError(\n `Failed to upload file to TOS: HTTP ${response.status}`,\n response.status\n );\n }\n }\n\n /**\n * 获取临时下载 URL\n */\n private async fetchDownloadUrl(objectKey: string): Promise<string> {\n const { acquireDownloadUrl, fetchOptions } = this.options;\n\n let response: Response;\n try {\n response = await fetch(acquireDownloadUrl, {\n method: 'POST',\n ...fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...fetchOptions?.headers,\n },\n body: JSON.stringify({ objectKey }),\n });\n } catch (error) {\n slardar.captureException(error, { source: 'client-capability', module: 'file-upload', step: 'fetch-download-url' });\n throw new FileUploadError(\n `Failed to acquire download URL: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n if (!response.ok) {\n throw new FileUploadError(\n `Failed to acquire download URL: HTTP ${response.status}`,\n response.status\n );\n }\n\n const data = (await response.json()) as AcquireDownloadUrlResponse;\n\n if (data.status_code !== '0') {\n throw new FileUploadError(`Failed to acquire download URL: ${data.status_code}`);\n }\n\n return data.data.downloadURL;\n }\n}\n","import type { ExtractedFile, UploadResult } from './types';\n\n/**\n * 检测是否为 File 或 Blob\n */\nexport function isFile(value: unknown): value is File | Blob {\n return value instanceof File || value instanceof Blob;\n}\n\n/**\n * 递归提取 params 中的所有文件\n *\n * @example\n * extractFiles({ image_list: [file1, file2] })\n * // => [\n * // { path: ['image_list', 0], file: file1 },\n * // { path: ['image_list', 1], file: file2 }\n * // ]\n */\nexport function extractFiles(params: Record<string, unknown>): ExtractedFile[] {\n const files: ExtractedFile[] = [];\n\n function traverse(obj: unknown, path: (string | number)[]): void {\n if (isFile(obj)) {\n files.push({ path: [...path], file: obj });\n } else if (Array.isArray(obj)) {\n obj.forEach((item, index) => traverse(item, [...path, index]));\n } else if (obj !== null && typeof obj === 'object') {\n Object.entries(obj).forEach(([key, value]) => {\n traverse(value, [...path, key]);\n });\n }\n }\n\n traverse(params, []);\n return files;\n}\n\n/**\n * 根据上传结果替换 params 中的文件为 URL\n *\n * @example\n * replaceFilesWithUrls(\n * { image_list: [file1, file2] },\n * [\n * { path: ['image_list', 0], downloadUrl: 'https://...' },\n * { path: ['image_list', 1], downloadUrl: 'https://...' }\n * ]\n * )\n * // => { image_list: ['https://...', 'https://...'] }\n */\nexport function replaceFilesWithUrls(\n params: Record<string, unknown>,\n results: UploadResult[]\n): Record<string, unknown> {\n // 创建 path -> url 的映射,用于快速查找\n const urlMap = new Map<string, string>();\n for (const { path, downloadUrl } of results) {\n urlMap.set(JSON.stringify(path), downloadUrl);\n }\n\n // 手动深拷贝,同时将 File/Blob 替换为对应的 URL\n // 注意:不能使用 structuredClone,因为它不支持 File/Blob 对象\n function cloneAndReplace(obj: unknown, currentPath: (string | number)[]): unknown {\n // 检查当前路径是否有对应的 URL\n const pathKey = JSON.stringify(currentPath);\n if (urlMap.has(pathKey)) {\n return urlMap.get(pathKey);\n }\n\n // 如果是 File/Blob 但没有对应的 URL(不应该发生),返回 null\n if (isFile(obj)) {\n return null;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item, index) => cloneAndReplace(item, [...currentPath, index]));\n }\n\n if (obj !== null && typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n result[key] = cloneAndReplace(value, [...currentPath, key]);\n }\n return result;\n }\n\n // 原始值直接返回\n return obj;\n }\n\n return cloneAndReplace(params, []) as Record<string, unknown>;\n}\n","import type {\n CapabilityClientOptions,\n CapabilityExecutor,\n ApiResponse,\n ExecuteResponseData,\n StreamResponse,\n Logger,\n RateLimitErrorHook,\n CentralOptions,\n} from './types';\nimport { ErrorCodes } from './types';\nimport {\n CapabilityError,\n CapabilityNotFoundError,\n ActionNotFoundError,\n NetworkError,\n ExecutionError,\n RateLimitError,\n} from './errors';\nimport { FileUploader } from './uploader';\nimport { extractFiles, replaceFilesWithUrls } from './file-extractor';\nimport { slardar } from '@lark-apaas/internal-slardar';\n\n// 方案文档 § Client SDK 改造伪代码原句:\n// `import capabilityMap from 'virtual:capabilities'; // build 时注入`\n// 由 @lark-apaas/fullstack-vite-preset 的 capabilitiesBundlePlugin 在 dev/build 时\n// 扫业务工程 server/capabilities/*.json 注入。类型声明在 ./virtual.d.ts。\nimport virtualCapabilitiesMap from 'virtual:capabilities';\nimport type { CapabilityConfig } from './types';\n\nconst LOG_PREFIX = '[CapabilityClient]';\n\nconst defaultLogger: Logger = {\n debug: console.debug.bind(console),\n info: console.info.bind(console),\n warn: console.warn.bind(console),\n error: console.error.bind(console),\n};\n\n/**\n * 能力客户端\n */\nexport class CapabilityClient {\n private options: CapabilityClientOptions;\n private baseURL: string;\n private logger: Logger;\n private onRateLimitError?: RateLimitErrorHook;\n private central?: CentralOptions;\n\n constructor(options: CapabilityClientOptions) {\n this.options = options;\n // 移除末尾的斜杠,确保拼接时格式正确\n this.baseURL = (options?.baseURL ?? '').replace(/\\/+$/, '');\n this.logger = options?.logger ?? defaultLogger;\n this.onRateLimitError = options?.onRateLimitError;\n if (options?.central?.enabled) {\n this.central = options.central;\n }\n }\n\n /**\n * central.baseURL → caller 显式给的(去尾斜杠)。\n * 没传:浏览器取 `window.location.origin`(同源调用,SSO cookie 自动带);\n * 非浏览器(SSR / Node.js 测试)抛错。\n * 用法与 fullstack-plugin/packages/client/dataloom/src/service/index.ts 一致。\n */\n private resolveCentralBaseURL(central: CentralOptions): string {\n if (central.baseURL) return central.baseURL.replace(/\\/+$/, '');\n if (typeof window !== 'undefined' && window.location?.origin) {\n return window.location.origin;\n }\n throw new Error(\n 'CapabilityClient: central.baseURL is required when running outside browser (window.location unavailable)',\n );\n }\n\n /**\n * 预览态 / 运行态自动判定。沿用 nestjs-capability/src/capability.module.ts:18 同款判定:\n * - 沙箱 fullstack-cli scripts/dev.sh → `NODE_ENV=development` → 预览态\n * - 运行态(npm start / build 后部署)→ `NODE_ENV=production` → 运行态\n * Vite 在构建时把 `process.env.NODE_ENV` 替换为字面量字符串。\n */\n private resolveMode(): 'preview' | 'runtime' {\n const env = typeof process !== 'undefined' ? process.env?.NODE_ENV : undefined;\n return env === 'development' ? 'preview' : 'runtime';\n }\n\n /**\n * 构造单次调用的请求 URL:\n * - central 开启:4 个中心端点之一(mode 自动判定);\n * - central 关闭:保持原 `${baseURL}/api/capability/{id}` 行为。\n */\n private buildExecuteUrl(capabilityId: string, stream: boolean): string {\n if (!this.central) {\n return `${this.baseURL}/api/capability/${capabilityId}${stream ? '/stream' : ''}`;\n }\n const base = this.resolveCentralBaseURL(this.central);\n const segment = this.resolveMode() === 'preview' ? '/preview/execute' : '/execute';\n return `${base}/app/${this.central.appId}/__runtime__/api/v1/plugin_server/capability/${capabilityId}${segment}${stream ? '/stream' : ''}`;\n }\n\n /**\n * 构造请求体:\n * - central + 预览态:`{ capability, action, params }`,capability 取自\n * `virtual:capabilities`(load() 时已经 fail-fast 校验过,这里直接取)。\n * - central + 运行态:`{ action, params }`(中心服务通过 RPC 查中心存储拿 config)。\n * - 非 central:`{ action, params }`。\n */\n private buildRequestBody(\n capabilityId: string,\n action: string,\n params: Record<string, unknown>,\n ): string {\n if (this.central && this.resolveMode() === 'preview') {\n const capability = virtualCapabilitiesMap[capabilityId] as CapabilityConfig | undefined;\n if (!capability) {\n // 理论上 load() 已经 fail-fast 校验,但兜底处理\n throw new CapabilityNotFoundError(capabilityId);\n }\n return JSON.stringify({ capability, action, params });\n }\n return JSON.stringify({ action, params });\n }\n\n /**\n * 加载能力,返回执行器。\n * 方案文档 § Client SDK 改造伪代码:\n * const config = capabilityMap[id];\n * if (!config) throw new CapabilityNotFoundError(id);\n * central + 预览态时 fail-fast:本地 `virtual:capabilities` map 没这个 id 就直接抛,\n * 不发任何网络请求。运行态 / 非 central 模式跳过此校验。\n */\n load(capabilityId: string): CapabilityExecutor {\n if (this.central && this.resolveMode() === 'preview') {\n if (!(capabilityId in virtualCapabilitiesMap)) {\n throw new CapabilityNotFoundError(capabilityId);\n }\n }\n return this.createExecutor(capabilityId);\n }\n\n private createExecutor(capabilityId: string): CapabilityExecutor {\n return {\n call: <T = unknown>(action: string, params?: Record<string, unknown>) => {\n return this.executeCall<T>(capabilityId, action, params);\n },\n callStream: <T = unknown>(action: string, params?: Record<string, unknown>) => {\n return this.executeCallStream<T>(capabilityId, action, params);\n },\n };\n }\n\n private async executeCall<T>(\n capabilityId: string,\n action: string,\n params?: Record<string, unknown>\n ): Promise<T> {\n const url = this.buildExecuteUrl(capabilityId, false);\n let requestParams = params ?? {};\n\n // 处理文件上传\n const extractedFiles = extractFiles(requestParams);\n if (extractedFiles.length > 0) {\n this.logger.info(LOG_PREFIX, `uploading ${extractedFiles.length} file(s)...`);\n const uploader = new FileUploader(this.options);\n const uploadResults = await uploader.uploadAll(extractedFiles);\n requestParams = replaceFilesWithUrls(requestParams, uploadResults);\n this.logger.info(LOG_PREFIX, `file upload completed`);\n }\n\n this.logger.info(LOG_PREFIX, `call start: capabilityId=${capabilityId}, action=${action}`, { params: requestParams });\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n ...this.options.fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...this.options.fetchOptions?.headers,\n },\n body: this.buildRequestBody(capabilityId, action, requestParams),\n });\n\n const data = (await response.json()) as ApiResponse<ExecuteResponseData>;\n\n if (!response.ok || data.status_code !== ErrorCodes.SUCCESS) {\n const errorResponse = data as {\n status_code: string;\n error_msg: string;\n is_rate_limit_error?: boolean;\n };\n const errorCode = errorResponse.status_code;\n\n // 计费受限错误:通过 is_rate_limit_error 字段识别\n if (errorResponse.is_rate_limit_error) {\n const rateLimitError = new RateLimitError(\n errorCode, // status_code 就是业务错误码\n errorResponse.error_msg,\n response.status,\n );\n await this.onRateLimitError?.(rateLimitError);\n throw rateLimitError;\n }\n\n switch (errorCode) {\n case ErrorCodes.CAPABILITY_NOT_FOUND:\n throw new CapabilityNotFoundError(capabilityId, response.status);\n case ErrorCodes.ACTION_NOT_FOUND:\n throw new ActionNotFoundError(errorResponse.error_msg, response.status);\n case ErrorCodes.PLUGIN_NOT_FOUND:\n case ErrorCodes.EXECUTION_ERROR:\n default:\n throw new ExecutionError(errorResponse.error_msg, response.status);\n }\n }\n\n const result = (data as { data: ExecuteResponseData }).data.output as T;\n\n this.logger.info(LOG_PREFIX, `call success: capabilityId=${capabilityId}, action=${action}`, { result });\n\n return result;\n } catch (error) {\n this.logger.error(LOG_PREFIX, `call failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error });\n slardar.captureException(error, { source: 'client-capability', module: 'execute-call', capabilityId, action });\n if (error instanceof CapabilityError) {\n throw error;\n }\n throw new NetworkError(error instanceof Error ? error.message : String(error));\n }\n }\n\n private async *executeCallStream<T>(\n capabilityId: string,\n action: string,\n params?: Record<string, unknown>\n ): AsyncIterable<T> {\n const url = this.buildExecuteUrl(capabilityId, true);\n let requestParams = params ?? {};\n\n // 处理文件上传\n const extractedFiles = extractFiles(requestParams);\n if (extractedFiles.length > 0) {\n this.logger.info(LOG_PREFIX, `uploading ${extractedFiles.length} file(s)...`);\n const uploader = new FileUploader(this.options);\n const uploadResults = await uploader.uploadAll(extractedFiles);\n requestParams = replaceFilesWithUrls(requestParams, uploadResults);\n this.logger.info(LOG_PREFIX, `file upload completed`);\n }\n\n this.logger.info(LOG_PREFIX, `callStream start: capabilityId=${capabilityId}, action=${action}`, { params: requestParams });\n\n // central + preview 模式下 buildRequestBody 可能抛 CapabilityNotFoundError,\n // 先于 fetch 计算好 body,避免被下面的 NetworkError 包装吞掉类型。\n const body = this.buildRequestBody(capabilityId, action, requestParams);\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n ...this.options.fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...this.options.fetchOptions?.headers,\n },\n body,\n });\n } catch (error) {\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error });\n slardar.captureException(error, { source: 'client-capability', module: 'execute-call-stream', capabilityId, action, phase: 'fetch' });\n throw new NetworkError(error instanceof Error ? error.message : String(error));\n }\n\n if (!response.ok) {\n const errMsg = `HTTP ${response.status} ${response.statusText}`;\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error: errMsg });\n throw new NetworkError(errMsg);\n }\n\n if (!response.body) {\n const errMsg = 'Response body is null';\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error: errMsg });\n throw new NetworkError(errMsg);\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let chunkCount = 0;\n let aggregatedContent = '';\n let canAggregate = true;\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n\n try {\n const parsed = JSON.parse(data) as StreamResponse;\n\n if (parsed.status_code === ErrorCodes.SUCCESS && parsed.data) {\n if (parsed.data.type === 'content') {\n chunkCount++;\n const delta = parsed.data.delta as T;\n\n // 尝试聚合 content 字段\n if (canAggregate) {\n const content = (delta as Record<string, unknown>)?.content;\n if (typeof content === 'string') {\n aggregatedContent += content;\n } else {\n canAggregate = false;\n }\n }\n\n yield delta;\n\n if (parsed.data.finished) {\n const resultInfo = canAggregate\n ? { chunkCount, result: aggregatedContent }\n : { chunkCount, resultLength: aggregatedContent.length || chunkCount };\n this.logger.info(LOG_PREFIX, `callStream end: capabilityId=${capabilityId}, action=${action}`, resultInfo);\n return;\n }\n } else if (parsed.data.type === 'error') {\n const err = parsed.data.error;\n if (err.isRateLimitError) {\n const rateLimitError = new RateLimitError(\n err.code, // code 就是业务错误码\n err.message,\n );\n await this.onRateLimitError?.(rateLimitError);\n throw rateLimitError;\n }\n throw new ExecutionError(err.message);\n }\n }\n } catch (parseError) {\n if (parseError instanceof CapabilityError) {\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error: parseError, chunkCount });\n throw parseError;\n }\n // 忽略非 JSON 行\n }\n }\n }\n }\n const resultInfo = canAggregate\n ? { chunkCount, result: aggregatedContent }\n : { chunkCount, resultLength: aggregatedContent.length || chunkCount };\n this.logger.info(LOG_PREFIX, `callStream end: capabilityId=${capabilityId}, action=${action}`, resultInfo);\n } catch (error) {\n this.logger.error(LOG_PREFIX, `callStream failed: capabilityId=${capabilityId}, action=${action}`, { params: requestParams, error, chunkCount });\n slardar.captureException(error, { source: 'client-capability', module: 'execute-call-stream', capabilityId, action, phase: 'read' });\n if (error instanceof CapabilityError) {\n throw error;\n }\n throw new NetworkError(error instanceof Error ? error.message : String(error));\n } finally {\n reader.releaseLock();\n }\n }\n}\n\n/**\n * 创建客户端实例\n */\nexport function createClient(options: CapabilityClientOptions): CapabilityClient {\n return new CapabilityClient(options);\n}\n"],"mappings":"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","names":["ErrorCodes","SUCCESS","CAPABILITY_NOT_FOUND","PLUGIN_NOT_FOUND","ACTION_NOT_FOUND","PARAMS_VALIDATION_ERROR","EXECUTION_ERROR","RATE_LIMIT_EXCEEDED","CapabilityError","Error","message","code","statusCode","name","CapabilityNotFoundError","capabilityId","ActionNotFoundError","NetworkError","ExecutionError","FileUploadError","RateLimitError","rateLimitCode","rateLimitMessage","slardar","FileUploader","options","upload","file","fileName","File","name","Date","now","uploadURL","objectKey","fetchUploadUrl","uploadToTos","downloadUrl","fetchDownloadUrl","uploadAll","files","results","Promise","all","map","path","acquireUploadUrl","fetchOptions","response","fetch","method","headers","body","JSON","stringify","error","slardar","captureException","source","module","step","FileUploadError","Error","message","String","ok","status","data","json","status_code","acquireDownloadUrl","downloadURL","isFile","value","File","Blob","extractFiles","params","files","traverse","obj","path","push","file","Array","isArray","forEach","item","index","Object","entries","key","replaceFilesWithUrls","results","urlMap","Map","downloadUrl","set","JSON","stringify","cloneAndReplace","currentPath","pathKey","has","get","map","result","slardar","virtualCapabilitiesMap","LOG_PREFIX","defaultLogger","debug","console","bind","info","warn","error","CapabilityClient","options","baseURL","logger","onRateLimitError","central","replace","enabled","resolveCentralBaseURL","window","location","origin","Error","resolveMode","env","process","undefined","buildExecuteUrl","capabilityId","stream","base","segment","appId","buildRequestBody","action","params","capability","virtualCapabilitiesMap","CapabilityNotFoundError","JSON","stringify","load","createExecutor","call","executeCall","callStream","executeCallStream","url","requestParams","extractedFiles","extractFiles","length","uploader","FileUploader","uploadResults","uploadAll","replaceFilesWithUrls","response","fetch","method","fetchOptions","headers","body","data","json","ok","status_code","ErrorCodes","SUCCESS","errorResponse","errorCode","is_rate_limit_error","rateLimitError","RateLimitError","error_msg","status","CAPABILITY_NOT_FOUND","ACTION_NOT_FOUND","ActionNotFoundError","PLUGIN_NOT_FOUND","EXECUTION_ERROR","ExecutionError","result","output","slardar","captureException","source","module","CapabilityError","NetworkError","message","String","phase","errMsg","statusText","reader","getReader","decoder","TextDecoder","buffer","chunkCount","aggregatedContent","canAggregate","done","value","read","decode","lines","split","pop","line","startsWith","slice","parsed","parse","type","delta","content","finished","resultInfo","resultLength","err","isRateLimitError","code","parseError","releaseLock","createClient"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/client-capability",
3
- "version": "0.1.6",
3
+ "version": "0.1.7-alpha.1",
4
4
  "description": "Client SDK for calling capabilities",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",