@lark-apaas/client-capability 0.1.2-alpha.1 → 0.1.3-alpha.0

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
@@ -28,6 +28,7 @@ __export(index_exports, {
28
28
  CapabilityError: () => CapabilityError,
29
29
  CapabilityNotFoundError: () => CapabilityNotFoundError,
30
30
  ExecutionError: () => ExecutionError,
31
+ FileUploadError: () => FileUploadError,
31
32
  NetworkError: () => NetworkError,
32
33
  capabilityClient: () => capabilityClient,
33
34
  createClient: () => createClient
@@ -43,6 +44,7 @@ var ErrorCodes = {
43
44
  PARAMS_VALIDATION_ERROR: "k_ec_cap_004",
44
45
  EXECUTION_ERROR: "k_ec_cap_005"
45
46
  };
47
+ var UPLOAD_API_PATH = "/af/api/v1/studio/plugins/tmp_files";
46
48
 
47
49
  // src/errors.ts
48
50
  var _CapabilityError = class _CapabilityError extends Error {
@@ -91,6 +93,174 @@ var _ExecutionError = class _ExecutionError extends CapabilityError {
91
93
  };
92
94
  __name(_ExecutionError, "ExecutionError");
93
95
  var ExecutionError = _ExecutionError;
96
+ var _FileUploadError = class _FileUploadError extends CapabilityError {
97
+ constructor(message, statusCode) {
98
+ super(message, "FILE_UPLOAD_ERROR", statusCode);
99
+ this.name = "FileUploadError";
100
+ }
101
+ };
102
+ __name(_FileUploadError, "FileUploadError");
103
+ var FileUploadError = _FileUploadError;
104
+
105
+ // src/uploader.ts
106
+ var _FileUploader = class _FileUploader {
107
+ constructor(baseURL, fetchOptions) {
108
+ __publicField(this, "uploadApiBase");
109
+ __publicField(this, "fetchOptions");
110
+ this.uploadApiBase = `${baseURL}${UPLOAD_API_PATH}`;
111
+ this.fetchOptions = fetchOptions;
112
+ }
113
+ /**
114
+ * 上传单个文件,返回下载 URL
115
+ */
116
+ async upload(file) {
117
+ const fileName = file instanceof File ? file.name : `blob-${Date.now()}`;
118
+ const { uploadURL, objectKey } = await this.acquireUploadUrl(fileName);
119
+ await this.uploadToTos(uploadURL, file);
120
+ const downloadUrl = await this.acquireDownloadUrl(objectKey);
121
+ return downloadUrl;
122
+ }
123
+ /**
124
+ * 并发上传多个文件
125
+ */
126
+ async uploadAll(files) {
127
+ const results = await Promise.all(files.map(async ({ path, file }) => {
128
+ const downloadUrl = await this.upload(file);
129
+ return {
130
+ path,
131
+ downloadUrl
132
+ };
133
+ }));
134
+ return results;
135
+ }
136
+ /**
137
+ * 获取上传预签名 URL
138
+ */
139
+ async acquireUploadUrl(fileName) {
140
+ const url = `${this.uploadApiBase}/acquire_upload_url`;
141
+ let response;
142
+ try {
143
+ response = await fetch(url, {
144
+ method: "POST",
145
+ ...this.fetchOptions,
146
+ headers: {
147
+ "Content-Type": "application/json",
148
+ ...this.fetchOptions?.headers
149
+ },
150
+ body: JSON.stringify({
151
+ fileName
152
+ })
153
+ });
154
+ } catch (error) {
155
+ throw new FileUploadError(`Failed to acquire upload URL: ${error instanceof Error ? error.message : String(error)}`);
156
+ }
157
+ if (!response.ok) {
158
+ throw new FileUploadError(`Failed to acquire upload URL: HTTP ${response.status}`, response.status);
159
+ }
160
+ const data = await response.json();
161
+ if (data.status_code !== "0") {
162
+ throw new FileUploadError(`Failed to acquire upload URL: ${data.status_code}`);
163
+ }
164
+ return data.data;
165
+ }
166
+ /**
167
+ * 上传文件到 TOS(预签名 URL)
168
+ */
169
+ async uploadToTos(uploadURL, file) {
170
+ let response;
171
+ try {
172
+ response = await fetch(uploadURL, {
173
+ method: "PUT",
174
+ body: file
175
+ });
176
+ } catch (error) {
177
+ throw new FileUploadError(`Failed to upload file to TOS: ${error instanceof Error ? error.message : String(error)}`);
178
+ }
179
+ if (!response.ok) {
180
+ throw new FileUploadError(`Failed to upload file to TOS: HTTP ${response.status}`, response.status);
181
+ }
182
+ }
183
+ /**
184
+ * 获取临时下载 URL
185
+ */
186
+ async acquireDownloadUrl(objectKey) {
187
+ const url = `${this.uploadApiBase}/acquire_download_url`;
188
+ let response;
189
+ try {
190
+ response = await fetch(url, {
191
+ method: "POST",
192
+ ...this.fetchOptions,
193
+ headers: {
194
+ "Content-Type": "application/json",
195
+ ...this.fetchOptions?.headers
196
+ },
197
+ body: JSON.stringify({
198
+ objectKey
199
+ })
200
+ });
201
+ } catch (error) {
202
+ throw new FileUploadError(`Failed to acquire download URL: ${error instanceof Error ? error.message : String(error)}`);
203
+ }
204
+ if (!response.ok) {
205
+ throw new FileUploadError(`Failed to acquire download URL: HTTP ${response.status}`, response.status);
206
+ }
207
+ const data = await response.json();
208
+ if (data.status_code !== "0") {
209
+ throw new FileUploadError(`Failed to acquire download URL: ${data.status_code}`);
210
+ }
211
+ return data.data.downloadUrl;
212
+ }
213
+ };
214
+ __name(_FileUploader, "FileUploader");
215
+ var FileUploader = _FileUploader;
216
+
217
+ // src/file-extractor.ts
218
+ function isFile(value) {
219
+ return value instanceof File || value instanceof Blob;
220
+ }
221
+ __name(isFile, "isFile");
222
+ function extractFiles(params) {
223
+ const files = [];
224
+ function traverse(obj, path) {
225
+ if (isFile(obj)) {
226
+ files.push({
227
+ path: [
228
+ ...path
229
+ ],
230
+ file: obj
231
+ });
232
+ } else if (Array.isArray(obj)) {
233
+ obj.forEach((item, index) => traverse(item, [
234
+ ...path,
235
+ index
236
+ ]));
237
+ } else if (obj !== null && typeof obj === "object") {
238
+ Object.entries(obj).forEach(([key, value]) => {
239
+ traverse(value, [
240
+ ...path,
241
+ key
242
+ ]);
243
+ });
244
+ }
245
+ }
246
+ __name(traverse, "traverse");
247
+ traverse(params, []);
248
+ return files;
249
+ }
250
+ __name(extractFiles, "extractFiles");
251
+ function replaceFilesWithUrls(params, results) {
252
+ const cloned = structuredClone(params);
253
+ for (const { path, downloadUrl } of results) {
254
+ let target = cloned;
255
+ for (let i = 0; i < path.length - 1; i++) {
256
+ target = target[path[i]];
257
+ }
258
+ const lastKey = path[path.length - 1];
259
+ target[lastKey] = downloadUrl;
260
+ }
261
+ return cloned;
262
+ }
263
+ __name(replaceFilesWithUrls, "replaceFilesWithUrls");
94
264
 
95
265
  // src/client.ts
96
266
  var LOG_PREFIX = "[CapabilityClient]";
@@ -129,7 +299,15 @@ var _CapabilityClient = class _CapabilityClient {
129
299
  }
130
300
  async executeCall(capabilityId, action, params) {
131
301
  const url = `${this.baseURL}/api/capability/${capabilityId}`;
132
- const requestParams = params ?? {};
302
+ let requestParams = params ?? {};
303
+ const extractedFiles = extractFiles(requestParams);
304
+ if (extractedFiles.length > 0) {
305
+ this.logger.info(LOG_PREFIX, `uploading ${extractedFiles.length} file(s)...`);
306
+ const uploader = new FileUploader(this.baseURL, this.options.fetchOptions);
307
+ const uploadResults = await uploader.uploadAll(extractedFiles);
308
+ requestParams = replaceFilesWithUrls(requestParams, uploadResults);
309
+ this.logger.info(LOG_PREFIX, `file upload completed`);
310
+ }
133
311
  this.logger.info(LOG_PREFIX, `call start: capabilityId=${capabilityId}, action=${action}`, {
134
312
  params: requestParams
135
313
  });
@@ -179,7 +357,15 @@ var _CapabilityClient = class _CapabilityClient {
179
357
  }
180
358
  async *executeCallStream(capabilityId, action, params) {
181
359
  const url = `${this.baseURL}/api/capability/${capabilityId}/stream`;
182
- const requestParams = params ?? {};
360
+ let requestParams = params ?? {};
361
+ const extractedFiles = extractFiles(requestParams);
362
+ if (extractedFiles.length > 0) {
363
+ this.logger.info(LOG_PREFIX, `uploading ${extractedFiles.length} file(s)...`);
364
+ const uploader = new FileUploader(this.baseURL, this.options.fetchOptions);
365
+ const uploadResults = await uploader.uploadAll(extractedFiles);
366
+ requestParams = replaceFilesWithUrls(requestParams, uploadResults);
367
+ this.logger.info(LOG_PREFIX, `file upload completed`);
368
+ }
183
369
  this.logger.info(LOG_PREFIX, `callStream start: capabilityId=${capabilityId}, action=${action}`, {
184
370
  params: requestParams
185
371
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["// 默认客户端实例\nexport { capabilityClient, createClient, CapabilityClient } from './client';\n\n// 类型\nexport type { CapabilityClientOptions, CapabilityExecutor, Logger } from './types';\n\n// 错误类型\nexport {\n CapabilityError,\n CapabilityNotFoundError,\n ActionNotFoundError,\n NetworkError,\n ExecutionError,\n} from './errors';\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 * 客户端配置选项\n */\nexport interface CapabilityClientOptions {\n /** 全局路径前缀,默认 ''。例如线上环境可设置为 '/spark/a' */\n baseURL?: string;\n /** 自定义 fetch 配置 */\n fetchOptions?: RequestInit;\n /** 自定义 logger,默认使用 console */\n logger?: Logger;\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\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 code: number;\n message: string;\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} as const;\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","import type {\n CapabilityClientOptions,\n CapabilityExecutor,\n ApiResponse,\n ExecuteResponseData,\n StreamResponse,\n Logger,\n} from './types';\nimport { ErrorCodes } 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};\nimport {\n CapabilityError,\n CapabilityNotFoundError,\n ActionNotFoundError,\n NetworkError,\n ExecutionError,\n} from './errors';\n\n/**\n * 能力客户端\n */\nexport class CapabilityClient {\n private options: CapabilityClientOptions;\n private baseURL: string;\n private logger: Logger;\n\n constructor(options?: CapabilityClientOptions) {\n this.options = options ?? {};\n // 移除末尾的斜杠,确保拼接时格式正确\n this.baseURL = (options?.baseURL ?? '').replace(/\\/+$/, '');\n this.logger = options?.logger ?? defaultLogger;\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 const requestParams = params ?? {};\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 { status_code: string; error_msg: string };\n const errorCode = errorResponse.status_code;\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 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 const requestParams = params ?? {};\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 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 throw new ExecutionError(parsed.data.error.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 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\n/**\n * 默认客户端实例\n */\nexport const capabilityClient = new CapabilityClient({\n\n});\n"],"mappings":"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","names":["ErrorCodes","SUCCESS","CAPABILITY_NOT_FOUND","PLUGIN_NOT_FOUND","ACTION_NOT_FOUND","PARAMS_VALIDATION_ERROR","EXECUTION_ERROR","CapabilityError","Error","message","code","statusCode","name","CapabilityNotFoundError","capabilityId","ActionNotFoundError","NetworkError","ExecutionError","LOG_PREFIX","defaultLogger","debug","console","bind","info","warn","error","CapabilityClient","options","baseURL","logger","replace","load","capabilityId","createExecutor","call","action","params","executeCall","callStream","executeCallStream","url","requestParams","response","fetch","method","fetchOptions","headers","body","JSON","stringify","data","json","ok","status_code","ErrorCodes","SUCCESS","errorResponse","errorCode","CAPABILITY_NOT_FOUND","CapabilityNotFoundError","status","ACTION_NOT_FOUND","ActionNotFoundError","error_msg","PLUGIN_NOT_FOUND","EXECUTION_ERROR","ExecutionError","result","output","CapabilityError","NetworkError","Error","message","String","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","length","parseError","releaseLock","createClient","capabilityClient"]}
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 { capabilityClient, createClient, CapabilityClient } from './client';\n\n// 类型\nexport type { CapabilityClientOptions, CapabilityExecutor, Logger } from './types';\n\n// 错误类型\nexport {\n CapabilityError,\n CapabilityNotFoundError,\n ActionNotFoundError,\n NetworkError,\n ExecutionError,\n FileUploadError,\n} from './errors';\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 * 客户端配置选项\n */\nexport interface CapabilityClientOptions {\n /** 全局路径前缀,默认 ''。例如线上环境可设置为 '/spark/a' */\n baseURL?: string;\n /** 自定义 fetch 配置 */\n fetchOptions?: RequestInit;\n /** 自定义 logger,默认使用 console */\n logger?: Logger;\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\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 code: number;\n message: string;\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} as const;\n\n// ========== 文件上传相关类型 ==========\n\n/**\n * 文件上传接口 BasePath\n */\nexport const UPLOAD_API_PATH = '/af/api/v1/studio/plugins/tmp_files';\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","import type {\n ExtractedFile,\n UploadResult,\n AcquireUploadUrlResponse,\n AcquireDownloadUrlResponse,\n} from './types';\nimport { UPLOAD_API_PATH } from './types';\nimport { FileUploadError } from './errors';\n\n/**\n * 文件上传器\n */\nexport class FileUploader {\n private readonly uploadApiBase: string;\n private readonly fetchOptions?: RequestInit;\n\n constructor(baseURL: string, fetchOptions?: RequestInit) {\n // 拼接完整的上传 API 地址\n this.uploadApiBase = `${baseURL}${UPLOAD_API_PATH}`;\n this.fetchOptions = fetchOptions;\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.acquireUploadUrl(fileName);\n\n // 2. 上传文件到 TOS\n await this.uploadToTos(uploadURL, file);\n\n // 3. 获取下载 URL\n const downloadUrl = await this.acquireDownloadUrl(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 acquireUploadUrl(fileName: string): Promise<{ uploadURL: string; objectKey: string }> {\n const url = `${this.uploadApiBase}/acquire_upload_url`;\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n ...this.fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...this.fetchOptions?.headers,\n },\n body: JSON.stringify({ fileName }),\n });\n } catch (error) {\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 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 acquireDownloadUrl(objectKey: string): Promise<string> {\n const url = `${this.uploadApiBase}/acquire_download_url`;\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n ...this.fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...this.fetchOptions?.headers,\n },\n body: JSON.stringify({ objectKey }),\n });\n } catch (error) {\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 // 深拷贝避免修改原对象\n const cloned = structuredClone(params);\n\n for (const { path, downloadUrl } of results) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let target: any = cloned;\n\n // 遍历到倒数第二层\n for (let i = 0; i < path.length - 1; i++) {\n target = target[path[i]];\n }\n\n // 设置最后一层的值\n const lastKey = path[path.length - 1];\n target[lastKey] = downloadUrl;\n }\n\n return cloned;\n}\n","import type {\n CapabilityClientOptions,\n CapabilityExecutor,\n ApiResponse,\n ExecuteResponseData,\n StreamResponse,\n Logger,\n} from './types';\nimport { ErrorCodes } from './types';\nimport {\n CapabilityError,\n CapabilityNotFoundError,\n ActionNotFoundError,\n NetworkError,\n ExecutionError,\n} from './errors';\nimport { FileUploader } from './uploader';\nimport { extractFiles, replaceFilesWithUrls } from './file-extractor';\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\n constructor(options?: CapabilityClientOptions) {\n this.options = options ?? {};\n // 移除末尾的斜杠,确保拼接时格式正确\n this.baseURL = (options?.baseURL ?? '').replace(/\\/+$/, '');\n this.logger = options?.logger ?? defaultLogger;\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.baseURL, this.options.fetchOptions);\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 { status_code: string; error_msg: string };\n const errorCode = errorResponse.status_code;\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 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.baseURL, this.options.fetchOptions);\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 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 throw new ExecutionError(parsed.data.error.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 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\n/**\n * 默认客户端实例\n */\nexport const capabilityClient = new CapabilityClient({\n\n});\n"],"mappings":"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","names":["ErrorCodes","SUCCESS","CAPABILITY_NOT_FOUND","PLUGIN_NOT_FOUND","ACTION_NOT_FOUND","PARAMS_VALIDATION_ERROR","EXECUTION_ERROR","UPLOAD_API_PATH","CapabilityError","Error","message","code","statusCode","name","CapabilityNotFoundError","capabilityId","ActionNotFoundError","NetworkError","ExecutionError","FileUploadError","FileUploader","baseURL","fetchOptions","uploadApiBase","UPLOAD_API_PATH","upload","file","fileName","File","name","Date","now","uploadURL","objectKey","acquireUploadUrl","uploadToTos","downloadUrl","acquireDownloadUrl","uploadAll","files","results","Promise","all","map","path","url","response","fetch","method","headers","body","JSON","stringify","error","FileUploadError","Error","message","String","ok","status","data","json","status_code","isFile","value","File","Blob","extractFiles","params","files","traverse","obj","path","push","file","Array","isArray","forEach","item","index","Object","entries","key","replaceFilesWithUrls","results","cloned","structuredClone","downloadUrl","target","i","length","lastKey","LOG_PREFIX","defaultLogger","debug","console","bind","info","warn","error","CapabilityClient","options","baseURL","logger","replace","load","capabilityId","createExecutor","call","action","params","executeCall","callStream","executeCallStream","url","requestParams","extractedFiles","extractFiles","length","uploader","FileUploader","fetchOptions","uploadResults","uploadAll","replaceFilesWithUrls","response","fetch","method","headers","body","JSON","stringify","data","json","ok","status_code","ErrorCodes","SUCCESS","errorResponse","errorCode","CAPABILITY_NOT_FOUND","CapabilityNotFoundError","status","ACTION_NOT_FOUND","ActionNotFoundError","error_msg","PLUGIN_NOT_FOUND","EXECUTION_ERROR","ExecutionError","result","output","CapabilityError","NetworkError","Error","message","String","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","parseError","releaseLock","createClient","capabilityClient"]}
package/dist/index.d.cts CHANGED
@@ -99,5 +99,11 @@ declare class NetworkError extends CapabilityError {
99
99
  declare class ExecutionError extends CapabilityError {
100
100
  constructor(message: string, statusCode?: number);
101
101
  }
102
+ /**
103
+ * 文件上传错误
104
+ */
105
+ declare class FileUploadError extends CapabilityError {
106
+ constructor(message: string, statusCode?: number);
107
+ }
102
108
 
103
- export { ActionNotFoundError, CapabilityClient, type CapabilityClientOptions, CapabilityError, type CapabilityExecutor, CapabilityNotFoundError, ExecutionError, type Logger, NetworkError, capabilityClient, createClient };
109
+ export { ActionNotFoundError, CapabilityClient, type CapabilityClientOptions, CapabilityError, type CapabilityExecutor, CapabilityNotFoundError, ExecutionError, FileUploadError, type Logger, NetworkError, capabilityClient, createClient };
package/dist/index.d.ts CHANGED
@@ -99,5 +99,11 @@ declare class NetworkError extends CapabilityError {
99
99
  declare class ExecutionError extends CapabilityError {
100
100
  constructor(message: string, statusCode?: number);
101
101
  }
102
+ /**
103
+ * 文件上传错误
104
+ */
105
+ declare class FileUploadError extends CapabilityError {
106
+ constructor(message: string, statusCode?: number);
107
+ }
102
108
 
103
- export { ActionNotFoundError, CapabilityClient, type CapabilityClientOptions, CapabilityError, type CapabilityExecutor, CapabilityNotFoundError, ExecutionError, type Logger, NetworkError, capabilityClient, createClient };
109
+ export { ActionNotFoundError, CapabilityClient, type CapabilityClientOptions, CapabilityError, type CapabilityExecutor, CapabilityNotFoundError, ExecutionError, FileUploadError, type Logger, NetworkError, capabilityClient, createClient };
package/dist/index.js CHANGED
@@ -12,6 +12,7 @@ var ErrorCodes = {
12
12
  PARAMS_VALIDATION_ERROR: "k_ec_cap_004",
13
13
  EXECUTION_ERROR: "k_ec_cap_005"
14
14
  };
15
+ var UPLOAD_API_PATH = "/af/api/v1/studio/plugins/tmp_files";
15
16
 
16
17
  // src/errors.ts
17
18
  var _CapabilityError = class _CapabilityError extends Error {
@@ -60,6 +61,174 @@ var _ExecutionError = class _ExecutionError extends CapabilityError {
60
61
  };
61
62
  __name(_ExecutionError, "ExecutionError");
62
63
  var ExecutionError = _ExecutionError;
64
+ var _FileUploadError = class _FileUploadError extends CapabilityError {
65
+ constructor(message, statusCode) {
66
+ super(message, "FILE_UPLOAD_ERROR", statusCode);
67
+ this.name = "FileUploadError";
68
+ }
69
+ };
70
+ __name(_FileUploadError, "FileUploadError");
71
+ var FileUploadError = _FileUploadError;
72
+
73
+ // src/uploader.ts
74
+ var _FileUploader = class _FileUploader {
75
+ constructor(baseURL, fetchOptions) {
76
+ __publicField(this, "uploadApiBase");
77
+ __publicField(this, "fetchOptions");
78
+ this.uploadApiBase = `${baseURL}${UPLOAD_API_PATH}`;
79
+ this.fetchOptions = fetchOptions;
80
+ }
81
+ /**
82
+ * 上传单个文件,返回下载 URL
83
+ */
84
+ async upload(file) {
85
+ const fileName = file instanceof File ? file.name : `blob-${Date.now()}`;
86
+ const { uploadURL, objectKey } = await this.acquireUploadUrl(fileName);
87
+ await this.uploadToTos(uploadURL, file);
88
+ const downloadUrl = await this.acquireDownloadUrl(objectKey);
89
+ return downloadUrl;
90
+ }
91
+ /**
92
+ * 并发上传多个文件
93
+ */
94
+ async uploadAll(files) {
95
+ const results = await Promise.all(files.map(async ({ path, file }) => {
96
+ const downloadUrl = await this.upload(file);
97
+ return {
98
+ path,
99
+ downloadUrl
100
+ };
101
+ }));
102
+ return results;
103
+ }
104
+ /**
105
+ * 获取上传预签名 URL
106
+ */
107
+ async acquireUploadUrl(fileName) {
108
+ const url = `${this.uploadApiBase}/acquire_upload_url`;
109
+ let response;
110
+ try {
111
+ response = await fetch(url, {
112
+ method: "POST",
113
+ ...this.fetchOptions,
114
+ headers: {
115
+ "Content-Type": "application/json",
116
+ ...this.fetchOptions?.headers
117
+ },
118
+ body: JSON.stringify({
119
+ fileName
120
+ })
121
+ });
122
+ } catch (error) {
123
+ throw new FileUploadError(`Failed to acquire upload URL: ${error instanceof Error ? error.message : String(error)}`);
124
+ }
125
+ if (!response.ok) {
126
+ throw new FileUploadError(`Failed to acquire upload URL: HTTP ${response.status}`, response.status);
127
+ }
128
+ const data = await response.json();
129
+ if (data.status_code !== "0") {
130
+ throw new FileUploadError(`Failed to acquire upload URL: ${data.status_code}`);
131
+ }
132
+ return data.data;
133
+ }
134
+ /**
135
+ * 上传文件到 TOS(预签名 URL)
136
+ */
137
+ async uploadToTos(uploadURL, file) {
138
+ let response;
139
+ try {
140
+ response = await fetch(uploadURL, {
141
+ method: "PUT",
142
+ body: file
143
+ });
144
+ } catch (error) {
145
+ throw new FileUploadError(`Failed to upload file to TOS: ${error instanceof Error ? error.message : String(error)}`);
146
+ }
147
+ if (!response.ok) {
148
+ throw new FileUploadError(`Failed to upload file to TOS: HTTP ${response.status}`, response.status);
149
+ }
150
+ }
151
+ /**
152
+ * 获取临时下载 URL
153
+ */
154
+ async acquireDownloadUrl(objectKey) {
155
+ const url = `${this.uploadApiBase}/acquire_download_url`;
156
+ let response;
157
+ try {
158
+ response = await fetch(url, {
159
+ method: "POST",
160
+ ...this.fetchOptions,
161
+ headers: {
162
+ "Content-Type": "application/json",
163
+ ...this.fetchOptions?.headers
164
+ },
165
+ body: JSON.stringify({
166
+ objectKey
167
+ })
168
+ });
169
+ } catch (error) {
170
+ throw new FileUploadError(`Failed to acquire download URL: ${error instanceof Error ? error.message : String(error)}`);
171
+ }
172
+ if (!response.ok) {
173
+ throw new FileUploadError(`Failed to acquire download URL: HTTP ${response.status}`, response.status);
174
+ }
175
+ const data = await response.json();
176
+ if (data.status_code !== "0") {
177
+ throw new FileUploadError(`Failed to acquire download URL: ${data.status_code}`);
178
+ }
179
+ return data.data.downloadUrl;
180
+ }
181
+ };
182
+ __name(_FileUploader, "FileUploader");
183
+ var FileUploader = _FileUploader;
184
+
185
+ // src/file-extractor.ts
186
+ function isFile(value) {
187
+ return value instanceof File || value instanceof Blob;
188
+ }
189
+ __name(isFile, "isFile");
190
+ function extractFiles(params) {
191
+ const files = [];
192
+ function traverse(obj, path) {
193
+ if (isFile(obj)) {
194
+ files.push({
195
+ path: [
196
+ ...path
197
+ ],
198
+ file: obj
199
+ });
200
+ } else if (Array.isArray(obj)) {
201
+ obj.forEach((item, index) => traverse(item, [
202
+ ...path,
203
+ index
204
+ ]));
205
+ } else if (obj !== null && typeof obj === "object") {
206
+ Object.entries(obj).forEach(([key, value]) => {
207
+ traverse(value, [
208
+ ...path,
209
+ key
210
+ ]);
211
+ });
212
+ }
213
+ }
214
+ __name(traverse, "traverse");
215
+ traverse(params, []);
216
+ return files;
217
+ }
218
+ __name(extractFiles, "extractFiles");
219
+ function replaceFilesWithUrls(params, results) {
220
+ const cloned = structuredClone(params);
221
+ for (const { path, downloadUrl } of results) {
222
+ let target = cloned;
223
+ for (let i = 0; i < path.length - 1; i++) {
224
+ target = target[path[i]];
225
+ }
226
+ const lastKey = path[path.length - 1];
227
+ target[lastKey] = downloadUrl;
228
+ }
229
+ return cloned;
230
+ }
231
+ __name(replaceFilesWithUrls, "replaceFilesWithUrls");
63
232
 
64
233
  // src/client.ts
65
234
  var LOG_PREFIX = "[CapabilityClient]";
@@ -98,7 +267,15 @@ var _CapabilityClient = class _CapabilityClient {
98
267
  }
99
268
  async executeCall(capabilityId, action, params) {
100
269
  const url = `${this.baseURL}/api/capability/${capabilityId}`;
101
- const requestParams = params ?? {};
270
+ let requestParams = params ?? {};
271
+ const extractedFiles = extractFiles(requestParams);
272
+ if (extractedFiles.length > 0) {
273
+ this.logger.info(LOG_PREFIX, `uploading ${extractedFiles.length} file(s)...`);
274
+ const uploader = new FileUploader(this.baseURL, this.options.fetchOptions);
275
+ const uploadResults = await uploader.uploadAll(extractedFiles);
276
+ requestParams = replaceFilesWithUrls(requestParams, uploadResults);
277
+ this.logger.info(LOG_PREFIX, `file upload completed`);
278
+ }
102
279
  this.logger.info(LOG_PREFIX, `call start: capabilityId=${capabilityId}, action=${action}`, {
103
280
  params: requestParams
104
281
  });
@@ -148,7 +325,15 @@ var _CapabilityClient = class _CapabilityClient {
148
325
  }
149
326
  async *executeCallStream(capabilityId, action, params) {
150
327
  const url = `${this.baseURL}/api/capability/${capabilityId}/stream`;
151
- const requestParams = params ?? {};
328
+ let requestParams = params ?? {};
329
+ const extractedFiles = extractFiles(requestParams);
330
+ if (extractedFiles.length > 0) {
331
+ this.logger.info(LOG_PREFIX, `uploading ${extractedFiles.length} file(s)...`);
332
+ const uploader = new FileUploader(this.baseURL, this.options.fetchOptions);
333
+ const uploadResults = await uploader.uploadAll(extractedFiles);
334
+ requestParams = replaceFilesWithUrls(requestParams, uploadResults);
335
+ this.logger.info(LOG_PREFIX, `file upload completed`);
336
+ }
152
337
  this.logger.info(LOG_PREFIX, `callStream start: capabilityId=${capabilityId}, action=${action}`, {
153
338
  params: requestParams
154
339
  });
@@ -286,6 +471,7 @@ export {
286
471
  CapabilityError,
287
472
  CapabilityNotFoundError,
288
473
  ExecutionError,
474
+ FileUploadError,
289
475
  NetworkError,
290
476
  capabilityClient,
291
477
  createClient
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["/**\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 * 客户端配置选项\n */\nexport interface CapabilityClientOptions {\n /** 全局路径前缀,默认 ''。例如线上环境可设置为 '/spark/a' */\n baseURL?: string;\n /** 自定义 fetch 配置 */\n fetchOptions?: RequestInit;\n /** 自定义 logger,默认使用 console */\n logger?: Logger;\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\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 code: number;\n message: string;\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} as const;\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","import type {\n CapabilityClientOptions,\n CapabilityExecutor,\n ApiResponse,\n ExecuteResponseData,\n StreamResponse,\n Logger,\n} from './types';\nimport { ErrorCodes } 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};\nimport {\n CapabilityError,\n CapabilityNotFoundError,\n ActionNotFoundError,\n NetworkError,\n ExecutionError,\n} from './errors';\n\n/**\n * 能力客户端\n */\nexport class CapabilityClient {\n private options: CapabilityClientOptions;\n private baseURL: string;\n private logger: Logger;\n\n constructor(options?: CapabilityClientOptions) {\n this.options = options ?? {};\n // 移除末尾的斜杠,确保拼接时格式正确\n this.baseURL = (options?.baseURL ?? '').replace(/\\/+$/, '');\n this.logger = options?.logger ?? defaultLogger;\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 const requestParams = params ?? {};\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 { status_code: string; error_msg: string };\n const errorCode = errorResponse.status_code;\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 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 const requestParams = params ?? {};\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 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 throw new ExecutionError(parsed.data.error.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 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\n/**\n * 默认客户端实例\n */\nexport const capabilityClient = new CapabilityClient({\n\n});\n"],"mappings":"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","names":["ErrorCodes","SUCCESS","CAPABILITY_NOT_FOUND","PLUGIN_NOT_FOUND","ACTION_NOT_FOUND","PARAMS_VALIDATION_ERROR","EXECUTION_ERROR","CapabilityError","Error","message","code","statusCode","name","CapabilityNotFoundError","capabilityId","ActionNotFoundError","NetworkError","ExecutionError","LOG_PREFIX","defaultLogger","debug","console","bind","info","warn","error","CapabilityClient","options","baseURL","logger","replace","load","capabilityId","createExecutor","call","action","params","executeCall","callStream","executeCallStream","url","requestParams","response","fetch","method","fetchOptions","headers","body","JSON","stringify","data","json","ok","status_code","ErrorCodes","SUCCESS","errorResponse","errorCode","CAPABILITY_NOT_FOUND","CapabilityNotFoundError","status","ACTION_NOT_FOUND","ActionNotFoundError","error_msg","PLUGIN_NOT_FOUND","EXECUTION_ERROR","ExecutionError","result","output","CapabilityError","NetworkError","Error","message","String","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","length","parseError","releaseLock","createClient","capabilityClient"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/errors.ts","../src/uploader.ts","../src/file-extractor.ts","../src/client.ts"],"sourcesContent":["/**\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 * 客户端配置选项\n */\nexport interface CapabilityClientOptions {\n /** 全局路径前缀,默认 ''。例如线上环境可设置为 '/spark/a' */\n baseURL?: string;\n /** 自定义 fetch 配置 */\n fetchOptions?: RequestInit;\n /** 自定义 logger,默认使用 console */\n logger?: Logger;\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\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 code: number;\n message: string;\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} as const;\n\n// ========== 文件上传相关类型 ==========\n\n/**\n * 文件上传接口 BasePath\n */\nexport const UPLOAD_API_PATH = '/af/api/v1/studio/plugins/tmp_files';\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","import type {\n ExtractedFile,\n UploadResult,\n AcquireUploadUrlResponse,\n AcquireDownloadUrlResponse,\n} from './types';\nimport { UPLOAD_API_PATH } from './types';\nimport { FileUploadError } from './errors';\n\n/**\n * 文件上传器\n */\nexport class FileUploader {\n private readonly uploadApiBase: string;\n private readonly fetchOptions?: RequestInit;\n\n constructor(baseURL: string, fetchOptions?: RequestInit) {\n // 拼接完整的上传 API 地址\n this.uploadApiBase = `${baseURL}${UPLOAD_API_PATH}`;\n this.fetchOptions = fetchOptions;\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.acquireUploadUrl(fileName);\n\n // 2. 上传文件到 TOS\n await this.uploadToTos(uploadURL, file);\n\n // 3. 获取下载 URL\n const downloadUrl = await this.acquireDownloadUrl(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 acquireUploadUrl(fileName: string): Promise<{ uploadURL: string; objectKey: string }> {\n const url = `${this.uploadApiBase}/acquire_upload_url`;\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n ...this.fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...this.fetchOptions?.headers,\n },\n body: JSON.stringify({ fileName }),\n });\n } catch (error) {\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 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 acquireDownloadUrl(objectKey: string): Promise<string> {\n const url = `${this.uploadApiBase}/acquire_download_url`;\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n ...this.fetchOptions,\n headers: {\n 'Content-Type': 'application/json',\n ...this.fetchOptions?.headers,\n },\n body: JSON.stringify({ objectKey }),\n });\n } catch (error) {\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 // 深拷贝避免修改原对象\n const cloned = structuredClone(params);\n\n for (const { path, downloadUrl } of results) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let target: any = cloned;\n\n // 遍历到倒数第二层\n for (let i = 0; i < path.length - 1; i++) {\n target = target[path[i]];\n }\n\n // 设置最后一层的值\n const lastKey = path[path.length - 1];\n target[lastKey] = downloadUrl;\n }\n\n return cloned;\n}\n","import type {\n CapabilityClientOptions,\n CapabilityExecutor,\n ApiResponse,\n ExecuteResponseData,\n StreamResponse,\n Logger,\n} from './types';\nimport { ErrorCodes } from './types';\nimport {\n CapabilityError,\n CapabilityNotFoundError,\n ActionNotFoundError,\n NetworkError,\n ExecutionError,\n} from './errors';\nimport { FileUploader } from './uploader';\nimport { extractFiles, replaceFilesWithUrls } from './file-extractor';\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\n constructor(options?: CapabilityClientOptions) {\n this.options = options ?? {};\n // 移除末尾的斜杠,确保拼接时格式正确\n this.baseURL = (options?.baseURL ?? '').replace(/\\/+$/, '');\n this.logger = options?.logger ?? defaultLogger;\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.baseURL, this.options.fetchOptions);\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 { status_code: string; error_msg: string };\n const errorCode = errorResponse.status_code;\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 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.baseURL, this.options.fetchOptions);\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 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 throw new ExecutionError(parsed.data.error.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 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\n/**\n * 默认客户端实例\n */\nexport const capabilityClient = new CapabilityClient({\n\n});\n"],"mappings":"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","names":["ErrorCodes","SUCCESS","CAPABILITY_NOT_FOUND","PLUGIN_NOT_FOUND","ACTION_NOT_FOUND","PARAMS_VALIDATION_ERROR","EXECUTION_ERROR","UPLOAD_API_PATH","CapabilityError","Error","message","code","statusCode","name","CapabilityNotFoundError","capabilityId","ActionNotFoundError","NetworkError","ExecutionError","FileUploadError","FileUploader","baseURL","fetchOptions","uploadApiBase","UPLOAD_API_PATH","upload","file","fileName","File","name","Date","now","uploadURL","objectKey","acquireUploadUrl","uploadToTos","downloadUrl","acquireDownloadUrl","uploadAll","files","results","Promise","all","map","path","url","response","fetch","method","headers","body","JSON","stringify","error","FileUploadError","Error","message","String","ok","status","data","json","status_code","isFile","value","File","Blob","extractFiles","params","files","traverse","obj","path","push","file","Array","isArray","forEach","item","index","Object","entries","key","replaceFilesWithUrls","results","cloned","structuredClone","downloadUrl","target","i","length","lastKey","LOG_PREFIX","defaultLogger","debug","console","bind","info","warn","error","CapabilityClient","options","baseURL","logger","replace","load","capabilityId","createExecutor","call","action","params","executeCall","callStream","executeCallStream","url","requestParams","extractedFiles","extractFiles","length","uploader","FileUploader","fetchOptions","uploadResults","uploadAll","replaceFilesWithUrls","response","fetch","method","headers","body","JSON","stringify","data","json","ok","status_code","ErrorCodes","SUCCESS","errorResponse","errorCode","CAPABILITY_NOT_FOUND","CapabilityNotFoundError","status","ACTION_NOT_FOUND","ActionNotFoundError","error_msg","PLUGIN_NOT_FOUND","EXECUTION_ERROR","ExecutionError","result","output","CapabilityError","NetworkError","Error","message","String","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","parseError","releaseLock","createClient","capabilityClient"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/client-capability",
3
- "version": "0.1.2-alpha.1",
3
+ "version": "0.1.3-alpha.0",
4
4
  "description": "Client SDK for calling capabilities",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",