@kevisual/api 0.0.37 → 0.0.39

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kevisual/api",
3
- "version": "0.0.37",
3
+ "version": "0.0.39",
4
4
  "description": "",
5
5
  "main": "mod.ts",
6
6
  "scripts": {
@@ -62,7 +62,7 @@ export class QueryResources {
62
62
  const url = `${this.prefix}${filepath}`;
63
63
  return this.get({}, { url, method: 'GET', ...opts, headers: this.header(opts?.headers, false), isText: true });
64
64
  }
65
- async uploadFile(filepath: string, content: string | Blob, opts?: DataOpts): Promise<Result<any>> {
65
+ async uploadFile(filepath: string, content: string | Blob, opts?: DataOpts & { chunkSize?: number, maxSize?: number }): Promise<Result<any>> {
66
66
  const pathname = `${this.prefix}${filepath}`;
67
67
  const filename = path.basename(pathname);
68
68
  const type = getContentType(filename);
@@ -71,15 +71,15 @@ export class QueryResources {
71
71
  // Blob 类型时 hashContent 返回 Promise
72
72
  const hash = hashResult instanceof Promise ? await hashResult : hashResult;
73
73
  url.searchParams.set('hash', hash);
74
-
74
+ const { chunkSize, maxSize, ...restOpts } = opts || {};
75
75
  // 判断是否需要分块上传(文件大于20MB)
76
76
  const isBlob = content instanceof Blob;
77
77
  const fileSize = isBlob ? content.size : new Blob([content]).size;
78
- const CHUNK_THRESHOLD = 20 * 1024 * 1024; // 20MB
78
+ const CHUNK_THRESHOLD = maxSize ?? 20 * 1024 * 1024; // 20MB
79
79
 
80
80
  if (fileSize > CHUNK_THRESHOLD && isBlob) {
81
81
  // 使用分块上传
82
- return this.uploadChunkedFile(filepath, content, hash, opts);
82
+ return this.uploadChunkedFile(filepath, content, hash, { chunkSize, ...restOpts });
83
83
  }
84
84
 
85
85
  const formData = new FormData();
@@ -94,34 +94,36 @@ export class QueryResources {
94
94
  method: 'POST',
95
95
  body: formData,
96
96
  timeout: 5 * 60 * 1000, // 5分钟超时
97
- ...opts,
98
- headers: { ...opts?.headers, ...this.header(opts?.headers, false) },
97
+ ...restOpts,
98
+ headers: { ...restOpts?.headers, ...this.header(restOpts?.headers, false) },
99
99
  params: {
100
100
  hash: hash,
101
- ...opts?.params,
101
+ ...restOpts?.params,
102
102
  },
103
103
  });
104
104
  }
105
- async uploadChunkedFile(filepath: string, file: Blob, hash: string, opts?: DataOpts): Promise<Result<any>> {
105
+ async uploadChunkedFile(filepath: string, file: Blob, hash: string, opts?: DataOpts & { chunkSize?: number }): Promise<Result<any>> {
106
106
  const pathname = `${this.prefix}${filepath}`;
107
107
  const filename = path.basename(pathname);
108
108
  const url = new URL(pathname, window.location.origin);
109
109
  url.searchParams.set('hash', hash);
110
- url.searchParams.set('chunked', '1');
110
+ url.searchParams.set('chunk', '1');
111
111
  console.log(`url,`, url, hash);
112
112
  // 预留 eventSource 支持(暂不处理)
113
113
  // const createEventSource = opts?.createEventSource;
114
-
115
- const chunkSize = 5 * 1024 * 1024; // 5MB
114
+ const { chunkSize: _chunkSize, ...restOpts } = opts || {};
115
+ const chunkSize = _chunkSize ?? 5 * 1024 * 1024; // 5MB
116
116
  const totalChunks = Math.ceil(file.size / chunkSize);
117
117
 
118
118
  for (let currentChunk = 0; currentChunk < totalChunks; currentChunk++) {
119
119
  const start = currentChunk * chunkSize;
120
120
  const end = Math.min(start + chunkSize, file.size);
121
- const chunk = file.slice(start, end);
121
+ const chunkBlob = file.slice(start, end);
122
+ // 转换为 File 类型
123
+ const chunkFile = new File([chunkBlob], filename, { type: file.type || 'application/octet-stream' });
122
124
 
123
125
  const formData = new FormData();
124
- formData.append('file', chunk, filename);
126
+ formData.append('file', chunkFile, filename);
125
127
  formData.append('chunkIndex', currentChunk.toString());
126
128
  formData.append('totalChunks', totalChunks.toString());
127
129
  console.log(`Uploading chunk ${currentChunk + 1}/${totalChunks}`, url.toString());
@@ -132,17 +134,23 @@ export class QueryResources {
132
134
  method: 'POST',
133
135
  body: formData,
134
136
  timeout: 5 * 60 * 1000, // 5分钟超时
135
- ...opts,
136
- headers: { ...opts?.headers, ...this.header(opts?.headers, false) },
137
+ ...restOpts,
138
+ headers: { ...restOpts?.headers, ...this.header(restOpts?.headers, false) },
137
139
  params: {
138
140
  hash: hash,
139
- ...opts?.params,
141
+ chunk: '1',
142
+ chunkIndex: currentChunk,
143
+ totalChunks,
144
+ ...restOpts?.params,
140
145
  },
141
146
  });
147
+ if (res.code !== 200) {
148
+ throw new Error(`Chunk upload failed with code ${res!.code}, message: ${res!.message}`);
149
+ }
142
150
  console.log(`Chunk ${currentChunk + 1}/${totalChunks} uploaded`, res);
143
151
  } catch (error) {
144
152
  console.error(`Error uploading chunk ${currentChunk + 1}/${totalChunks}`, error);
145
- throw error;
153
+ return { code: 500, message: `分块上传失败: ${(error as Error).message}` };
146
154
  }
147
155
  }
148
156