@cnbcool/cnb-api-generate 1.2.5 → 1.2.6

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/client/index.ts CHANGED
@@ -498,7 +498,7 @@ async function main() {
498
498
  // 上传快捷命令:走完整上传流程(获取 URL → PUT 文件 → 返回结果)
499
499
  let data: any;
500
500
  if (shortcut?.upload) {
501
- data = await handleUpload(shortcut, formattedParams.data?.file, toolFunction, pathAndQueryParams);
501
+ data = await handleUpload(shortcut, formattedParams.data?.file, toolFunction, pathAndQueryParams as { repo: string; number?: string });
502
502
  } else {
503
503
  if (formattedParams.data) {
504
504
  toolsParam.push(formattedParams.data);
@@ -14,21 +14,84 @@ import type { ResolvedShortcut } from '../shortcuts';
14
14
  // 上传文件大小上限:100MB
15
15
  const MAX_FILE_SIZE = 100 * 1024 * 1024;
16
16
 
17
+ /** 上传 API 的 path 参数 */
18
+ interface UploadPathParams {
19
+ repo: string;
20
+ number?: string;
21
+ }
22
+
23
+ /** Issue 上传请求体 */
24
+ interface IssueUploadBody {
25
+ name: string;
26
+ size: number;
27
+ content_type: string;
28
+ }
29
+
30
+ /** Pull 上传请求体 */
31
+ interface PullUploadBody {
32
+ name: string;
33
+ size: number;
34
+ }
35
+
36
+ /** 上传 API 函数签名 */
37
+ type UploadApiFunction = (
38
+ params: UploadPathParams,
39
+ body: IssueUploadBody | PullUploadBody,
40
+ ) => Promise<UploadApiResponse>;
41
+
42
+ /** 上传 API 响应 */
43
+ interface UploadApiResponse {
44
+ status?: number;
45
+ data?: {
46
+ upload_url?: string;
47
+ asset_link?: string;
48
+ assets?: { name?: string; path?: string };
49
+ token?: string;
50
+ };
51
+ }
52
+
53
+ /** 上传失败时的 data */
54
+ interface UploadErrorData {
55
+ error: string;
56
+ detail?: string;
57
+ }
58
+
59
+ /** Issue 上传成功时的 data */
60
+ interface IssueUploadData {
61
+ asset_link?: string;
62
+ name: string;
63
+ size: number;
64
+ }
65
+
66
+ /** Pull 上传成功时的 data */
67
+ interface PullUploadData {
68
+ name: string;
69
+ path?: string;
70
+ size: number;
71
+ token?: string;
72
+ }
73
+
74
+ /** handleUpload 的返回值 */
75
+ interface UploadResult {
76
+ status: number;
77
+ data: UploadErrorData | IssueUploadData | PullUploadData;
78
+ }
79
+
17
80
  /**
18
81
  * 处理完整上传流程
19
82
  * @param shortcut 解析后的快捷命令
20
83
  * @param filePath 本地文件路径
21
84
  * @param toolFunction 原始上传 API 函数(获取 upload_url)
22
- * @param toolsParam API 调用的 path 参数(repo 或 {repo, number})
85
+ * @param pathParams API 调用的 path 参数(repo 或 {repo, number})
23
86
  */
24
87
  export async function handleUpload(
25
88
  shortcut: ResolvedShortcut,
26
- filePath: any,
27
- toolFunction: (...args: any[]) => Promise<any>,
28
- toolsParam: any,
29
- ): Promise<any> {
89
+ filePath: string | undefined,
90
+ toolFunction: UploadApiFunction,
91
+ pathParams: UploadPathParams,
92
+ ): Promise<UploadResult> {
30
93
  // 校验 file 参数
31
- if (!filePath || typeof filePath !== 'string') {
94
+ if (!filePath) {
32
95
  return { status: 400, data: { error: `上传命令需要指定文件路径,如: --data '{"file":"./path/to/file"}'` } };
33
96
  }
34
97
 
@@ -52,7 +115,8 @@ export async function handleUpload(
52
115
  return { status: 400, data: { error: `文件过大 (${(fileSize / 1024 / 1024).toFixed(1)}MB),上限 ${MAX_FILE_SIZE / 1024 / 1024}MB` } };
53
116
  }
54
117
 
55
- const contentType = mimeLookup(filePath) || 'application/octet-stream';
118
+ const mimeResult = mimeLookup(filePath);
119
+ const contentType = typeof mimeResult === 'string' ? mimeResult : 'application/octet-stream';
56
120
 
57
121
  // 2. 调用上传 API 获取 upload_url
58
122
  const isIssueUpload = shortcut.module === 'issues';
@@ -60,14 +124,14 @@ export async function handleUpload(
60
124
  ? { name: fileName, size: fileSize, content_type: contentType }
61
125
  : { name: fileName, size: fileSize };
62
126
 
63
- const uploadResponse = await toolFunction(toolsParam, requestBody);
127
+ const uploadResponse = await toolFunction(pathParams, requestBody);
64
128
 
65
- // 提取 upload_url(兼容标准响应和裸响应)
66
- const responseData = uploadResponse?.data ?? uploadResponse;
129
+ // 提取 upload_url
130
+ const responseData = uploadResponse?.data;
67
131
  const uploadUrl = responseData?.upload_url;
68
132
 
69
133
  if (!uploadUrl) {
70
- return uploadResponse; // 获取 URL 失败,直接返回原始错误
134
+ return uploadResponse as unknown as UploadResult; // 获取 URL 失败,直接返回原始错误
71
135
  }
72
136
 
73
137
  // 3. PUT 文件内容到 upload_url(流式读取,避免大文件撑爆内存)
@@ -78,15 +142,22 @@ export async function handleUpload(
78
142
  'Content-Length': String(fileSize),
79
143
  };
80
144
 
81
- const putResponse = await fetch(uploadUrl, {
82
- method: 'PUT',
83
- headers: putHeaders,
84
- body: fileStream as any,
85
- // @ts-ignore duplex required for streaming body in Node.js fetch
86
- duplex: 'half',
87
- });
145
+ let putResponse: Response;
146
+ try {
147
+ putResponse = await fetch(uploadUrl, {
148
+ method: 'PUT',
149
+ headers: putHeaders,
150
+ body: fileStream as any,
151
+ // @ts-ignore duplex required for streaming body in Node.js fetch
152
+ duplex: 'half',
153
+ });
154
+ } catch (e) {
155
+ fileStream.destroy();
156
+ throw e;
157
+ }
88
158
 
89
159
  if (!putResponse.ok) {
160
+ fileStream.destroy();
90
161
  const errText = await putResponse.text().catch(() => '');
91
162
  return {
92
163
  status: putResponse.status,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cnbcool/cnb-api-generate",
3
- "version": "1.2.5",
3
+ "version": "1.2.6",
4
4
  "main": "./built/index.js",
5
5
  "module": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -40,6 +40,7 @@
40
40
  "debug": "4.4.1",
41
41
  "glob": "^13.0.1",
42
42
  "lodash": "^4.17.23",
43
+ "mime-types": "^2.1.35",
43
44
  "ora": "5.4.1",
44
45
  "prettier": "3.4.2",
45
46
  "rimraf": "6.0.1",