@universal-uploader/core 1.0.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/const.d.ts +19 -0
- package/dist/createUpload-Bv4Z2y9b.js +155 -0
- package/dist/createUpload-Bv4Z2y9b.js.map +1 -0
- package/dist/createUpload-CePIp5sg.js +123 -0
- package/dist/createUpload-CePIp5sg.js.map +1 -0
- package/dist/createUpload-DfsX80rY.js +121 -0
- package/dist/createUpload-DfsX80rY.js.map +1 -0
- package/dist/createUpload-wm9hFbGi.js +153 -0
- package/dist/createUpload-wm9hFbGi.js.map +1 -0
- package/dist/createUpload.d.ts +10 -0
- package/dist/helper.d.ts +74 -0
- package/dist/index-BS99wlKk.js +214 -0
- package/dist/index-BS99wlKk.js.map +1 -0
- package/dist/index-CZdguoWB.js +216 -0
- package/dist/index-CZdguoWB.js.map +1 -0
- package/dist/index.cjs +954 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +144 -0
- package/dist/index.js +952 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestrator.d.ts +6 -0
- package/dist/stream/helper.d.ts +28 -0
- package/dist/stream/index.d.ts +7 -0
- package/dist/stream/index.js +79 -0
- package/dist/stream-chunked/helper.d.ts +9 -0
- package/dist/stream-chunked/index.d.ts +5 -0
- package/dist/stream.cjs +249 -0
- package/dist/stream.cjs.map +1 -0
- package/dist/stream.d.ts +10 -0
- package/dist/stream.js +247 -0
- package/dist/stream.js.map +1 -0
- package/dist/types-CLZnJDsz.d.ts +111 -0
- package/dist/types.d.ts +127 -0
- package/dist/utils-B4LG-_oN.js +12 -0
- package/dist/utils-B4LG-_oN.js.map +1 -0
- package/dist/utils-MtT6SgZa.js +10 -0
- package/dist/utils-MtT6SgZa.js.map +1 -0
- package/dist/utils.d.ts +5 -0
- package/dist/xhr-chuncked/helper.d.ts +27 -0
- package/dist/xhr-chuncked/index.d.ts +7 -0
- package/dist/xhr-chuncked/index.js +181 -0
- package/dist/xhr.cjs +142 -0
- package/dist/xhr.cjs.map +1 -0
- package/dist/xhr.d.ts +10 -0
- package/dist/xhr.js +140 -0
- package/dist/xhr.js.map +1 -0
- package/package.json +34 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
const HTTP_STATUS_SUCCESS_MIN = 200;
|
|
2
|
+
const HTTP_STATUS_SUCCESS_MAX_EXCLUSIVE = 300;
|
|
3
|
+
const isSuccessfulHttpStatus = (status) => status >= HTTP_STATUS_SUCCESS_MIN && status < HTTP_STATUS_SUCCESS_MAX_EXCLUSIVE;
|
|
4
|
+
const getChunkUploadMeta = ({ chunkSize, fileSize, }) => {
|
|
5
|
+
const safeChunkSize = Math.max(1, chunkSize);
|
|
6
|
+
const totalFileSize = fileSize;
|
|
7
|
+
const totalChunks = Math.ceil(totalFileSize / safeChunkSize);
|
|
8
|
+
return {
|
|
9
|
+
safeChunkSize,
|
|
10
|
+
totalFileSize,
|
|
11
|
+
totalChunks,
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
const getChunkRange = ({ chunkIndex, safeChunkSize, totalFileSize, }) => {
|
|
15
|
+
const start = chunkIndex * safeChunkSize;
|
|
16
|
+
const end = Math.min(start + safeChunkSize, totalFileSize);
|
|
17
|
+
return {
|
|
18
|
+
start,
|
|
19
|
+
end,
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
const applyChunkHeaders = ({ xhr, customHeaders, chunkIndex, totalChunks, safeChunkSize, totalFileSize, }) => {
|
|
23
|
+
xhr.setRequestHeader('X-Chunk-Index', String(chunkIndex));
|
|
24
|
+
xhr.setRequestHeader('X-Total-Chunks', String(totalChunks));
|
|
25
|
+
xhr.setRequestHeader('X-Chunk-Size', String(safeChunkSize));
|
|
26
|
+
xhr.setRequestHeader('X-File-Size', String(totalFileSize));
|
|
27
|
+
Object.entries(customHeaders).forEach(([key, value]) => {
|
|
28
|
+
xhr.setRequestHeader(key, value);
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
const uploadWithoutChunking = ({ url, file, refresh, customHeaders, onProgress, }) => {
|
|
32
|
+
const xhr = new XMLHttpRequest();
|
|
33
|
+
const response = new Promise((resolve, reject) => {
|
|
34
|
+
xhr.open('POST', url);
|
|
35
|
+
Object.entries(customHeaders).forEach(([key, value]) => {
|
|
36
|
+
xhr.setRequestHeader(key, value);
|
|
37
|
+
});
|
|
38
|
+
if (onProgress) {
|
|
39
|
+
xhr.upload.onprogress = (event) => {
|
|
40
|
+
const total = event.total || file.size;
|
|
41
|
+
const percentage = total === 0 ? 100 : (event.loaded / total) * 100;
|
|
42
|
+
onProgress({
|
|
43
|
+
loaded: event.loaded,
|
|
44
|
+
total,
|
|
45
|
+
percentage,
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
xhr.onload = () => {
|
|
50
|
+
if (isSuccessfulHttpStatus(xhr.status)) {
|
|
51
|
+
if (onProgress) {
|
|
52
|
+
onProgress({ loaded: file.size, total: file.size, percentage: 100 });
|
|
53
|
+
}
|
|
54
|
+
resolve({
|
|
55
|
+
ok: true,
|
|
56
|
+
total: file.size,
|
|
57
|
+
message: undefined,
|
|
58
|
+
status: 'success',
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
reject(new Error(`Upload failed with status ${xhr.status}`));
|
|
63
|
+
};
|
|
64
|
+
xhr.onerror = (e) => reject(e);
|
|
65
|
+
xhr.onabort = () => {
|
|
66
|
+
reject(new DOMException('Aborted', 'AbortError'));
|
|
67
|
+
};
|
|
68
|
+
xhr.send(file);
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
result: response.then((res) => ({
|
|
72
|
+
ok: res.ok,
|
|
73
|
+
total: file.size,
|
|
74
|
+
message: undefined,
|
|
75
|
+
status: 'success',
|
|
76
|
+
})),
|
|
77
|
+
actions: {
|
|
78
|
+
abort: () => xhr.abort(),
|
|
79
|
+
refresh: () => {
|
|
80
|
+
xhr.abort();
|
|
81
|
+
refresh();
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
const uploadWithXhrChuncked = async ({ url, file, refresh, options: { chunkSize, customHeaders = {}, onProgress }, }) => {
|
|
87
|
+
const response = {
|
|
88
|
+
result: Promise.resolve({ ok: false, total: 0, message: undefined, status: 'idle' }),
|
|
89
|
+
actions: {
|
|
90
|
+
abort: () => null,
|
|
91
|
+
refresh: () => null,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
if (!chunkSize || chunkSize <= 0) {
|
|
95
|
+
return uploadWithoutChunking({ url, file, refresh, customHeaders, onProgress });
|
|
96
|
+
}
|
|
97
|
+
const { safeChunkSize, totalFileSize, totalChunks } = getChunkUploadMeta({
|
|
98
|
+
chunkSize,
|
|
99
|
+
fileSize: file.size,
|
|
100
|
+
});
|
|
101
|
+
if (totalFileSize === 0) {
|
|
102
|
+
if (onProgress) {
|
|
103
|
+
onProgress({ loaded: 0, total: 0, percentage: 100 });
|
|
104
|
+
}
|
|
105
|
+
response.result = Promise.resolve({
|
|
106
|
+
ok: true,
|
|
107
|
+
total: 0,
|
|
108
|
+
message: undefined,
|
|
109
|
+
status: 'success',
|
|
110
|
+
});
|
|
111
|
+
return response;
|
|
112
|
+
}
|
|
113
|
+
const chunkUpload = async () => {
|
|
114
|
+
let uploadResult = {
|
|
115
|
+
ok: false,
|
|
116
|
+
total: 0,
|
|
117
|
+
message: undefined,
|
|
118
|
+
status: 'uploading',
|
|
119
|
+
};
|
|
120
|
+
for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex += 1) {
|
|
121
|
+
const { start, end } = getChunkRange({
|
|
122
|
+
chunkIndex,
|
|
123
|
+
safeChunkSize,
|
|
124
|
+
totalFileSize,
|
|
125
|
+
});
|
|
126
|
+
const uploadPromise = new Promise((resolve, reject) => {
|
|
127
|
+
const xhr = new XMLHttpRequest();
|
|
128
|
+
xhr.open('POST', url);
|
|
129
|
+
applyChunkHeaders({
|
|
130
|
+
xhr,
|
|
131
|
+
customHeaders,
|
|
132
|
+
chunkIndex,
|
|
133
|
+
totalChunks,
|
|
134
|
+
safeChunkSize,
|
|
135
|
+
totalFileSize,
|
|
136
|
+
});
|
|
137
|
+
xhr.onload = () => {
|
|
138
|
+
if (isSuccessfulHttpStatus(xhr.status)) {
|
|
139
|
+
const isLastChunk = end >= totalFileSize;
|
|
140
|
+
const percentage = isLastChunk ? 100 : (end / totalFileSize) * 100;
|
|
141
|
+
if (onProgress) {
|
|
142
|
+
onProgress({
|
|
143
|
+
loaded: end,
|
|
144
|
+
total: totalFileSize,
|
|
145
|
+
percentage: totalFileSize === 0 ? 100 : percentage,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
resolve({
|
|
149
|
+
ok: true,
|
|
150
|
+
total: totalFileSize,
|
|
151
|
+
message: undefined,
|
|
152
|
+
status: isLastChunk ? 'success' : 'uploading',
|
|
153
|
+
});
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
reject(new Error(`Chunk upload failed with status ${xhr.status}`));
|
|
157
|
+
};
|
|
158
|
+
xhr.onerror = (e) => reject(e);
|
|
159
|
+
xhr.onabort = () => {
|
|
160
|
+
const abortError = new DOMException('Aborted', 'AbortError');
|
|
161
|
+
reject(abortError);
|
|
162
|
+
};
|
|
163
|
+
const chunk = file.slice(start, end);
|
|
164
|
+
xhr.send(chunk);
|
|
165
|
+
// 불변성을 보장하지 않고 클로저에서 변경하는 방식
|
|
166
|
+
response.actions.abort = () => xhr.abort();
|
|
167
|
+
response.actions.refresh = () => {
|
|
168
|
+
xhr.abort();
|
|
169
|
+
refresh();
|
|
170
|
+
};
|
|
171
|
+
});
|
|
172
|
+
// 불변성을 보장하지 않고 클로저에서 result 변경 (빠른 UX를 위해, chunkUpload의 action 먼저 반환하고 나머지는 클로저로 업데이트하는 방식)
|
|
173
|
+
// eslint-disable-next-line no-await-in-loop -- chunked mode intentionally uploads sequentially
|
|
174
|
+
uploadResult = await uploadPromise;
|
|
175
|
+
}
|
|
176
|
+
return uploadResult;
|
|
177
|
+
};
|
|
178
|
+
response.result = chunkUpload();
|
|
179
|
+
return response;
|
|
180
|
+
};
|
|
181
|
+
export default uploadWithXhrChuncked;
|
package/dist/xhr.cjs
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var utils = require('./utils-B4LG-_oN.js');
|
|
4
|
+
var index = require('./index-CZdguoWB.js');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Orchestrates file upload by selecting the optimal method and managing retries and errors.
|
|
8
|
+
* 최적의 업로드 방식을 선택하고 재시도 및 에러 처리를 관리하여 파일 업로드를 수행합니다.
|
|
9
|
+
*/
|
|
10
|
+
const upload = async ({ url, file, options: { method = "xhr chunked", ...options } }, retryAttempt = 0) => {
|
|
11
|
+
const { onComplete, onProgress, onAbort, onRetry, onError, retryCount: retryCountArg = 3, retryDelay = 1000, throwOnError = false, ...restOptions } = options;
|
|
12
|
+
const retryCount = retryCountArg;
|
|
13
|
+
/**
|
|
14
|
+
* Determines whether to throw an error based on configuration.
|
|
15
|
+
* 구성 설정에 따라 에러를 throw할지 결정합니다.
|
|
16
|
+
*/
|
|
17
|
+
const shouldThrowError = (e) => {
|
|
18
|
+
if (typeof throwOnError === "function") {
|
|
19
|
+
return throwOnError(e);
|
|
20
|
+
}
|
|
21
|
+
return Boolean(throwOnError);
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Handles user-triggered aborts.
|
|
25
|
+
* 사용자에 의해 중단된 경우를 처리합니다.
|
|
26
|
+
*/
|
|
27
|
+
const handleAbort = (e) => {
|
|
28
|
+
onAbort?.(e);
|
|
29
|
+
if (shouldThrowError(e)) {
|
|
30
|
+
throw e;
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
ok: false,
|
|
34
|
+
total: 0,
|
|
35
|
+
message: "Aborted by user action",
|
|
36
|
+
status: "aborted",
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Handles generic errors during upload.
|
|
41
|
+
* 업로드 중 발생하는 일반적인 에러를 처리합니다.
|
|
42
|
+
*/
|
|
43
|
+
const handleError = (e) => {
|
|
44
|
+
onError?.(e);
|
|
45
|
+
if (shouldThrowError(e)) {
|
|
46
|
+
throw e;
|
|
47
|
+
}
|
|
48
|
+
return { ok: false, total: 0, message: e.message, status: "error" };
|
|
49
|
+
};
|
|
50
|
+
const finalOptions = {
|
|
51
|
+
...restOptions,
|
|
52
|
+
onProgress: ({ loaded, total, percentage }) => {
|
|
53
|
+
onProgress?.({ loaded, total, percentage });
|
|
54
|
+
if (percentage === 100) {
|
|
55
|
+
onComplete?.();
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
const refresh = () => upload({ url, file, options });
|
|
60
|
+
/**
|
|
61
|
+
* Attempts to retry an upload operation.
|
|
62
|
+
* 업로드 작업을 재시도합니다.
|
|
63
|
+
*/
|
|
64
|
+
const retryUpload = async (uploadArgs) => {
|
|
65
|
+
const nextRetryAttempt = retryAttempt + 1;
|
|
66
|
+
const nextRetryDelay = typeof retryDelay === "function"
|
|
67
|
+
? retryDelay(nextRetryAttempt)
|
|
68
|
+
: retryDelay;
|
|
69
|
+
await utils.wait(nextRetryDelay);
|
|
70
|
+
const uploadResponse = await upload(uploadArgs, nextRetryAttempt);
|
|
71
|
+
onRetry?.();
|
|
72
|
+
return uploadResponse;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Wraps the upload operation with error and retry handling.
|
|
76
|
+
* 에러 처리 및 재시도 로직으로 업로드 작업을 래핑합니다.
|
|
77
|
+
*/
|
|
78
|
+
const wrapPromiseErrorHandler = async (uploadResponse) => {
|
|
79
|
+
const { result: originalResult, actions: originalActions } = uploadResponse;
|
|
80
|
+
const retriedResult = originalResult
|
|
81
|
+
.then((uploadResult) => {
|
|
82
|
+
/**
|
|
83
|
+
* fetch resolves for HTTP 4xx/5xx, so stream mode can return { ok: false, status: 'error' }
|
|
84
|
+
* without rejecting. We rethrow here to route it through retry/onError handling.
|
|
85
|
+
*
|
|
86
|
+
* fetch는 HTTP 4xx/5xx에서도 reject하지 않아 stream 모드가 실패 결과를 resolve로 반환할 수 있습니다.
|
|
87
|
+
* 그래서 여기서 다시 throw해서 retry/onError 흐름으로 태웁니다.
|
|
88
|
+
*/
|
|
89
|
+
if (!uploadResult.ok && uploadResult.status === "error") {
|
|
90
|
+
throw new Error(uploadResult.message || "Upload failed");
|
|
91
|
+
}
|
|
92
|
+
return uploadResult;
|
|
93
|
+
})
|
|
94
|
+
.catch(async (e) => {
|
|
95
|
+
if (e instanceof DOMException && e.name === "AbortError") {
|
|
96
|
+
return handleAbort(e);
|
|
97
|
+
}
|
|
98
|
+
if (retryCount > 0) {
|
|
99
|
+
const { result: retryResult, actions: retryActions } = await retryUpload({
|
|
100
|
+
url,
|
|
101
|
+
file,
|
|
102
|
+
options: {
|
|
103
|
+
...options,
|
|
104
|
+
method,
|
|
105
|
+
retryCount: retryCount - 1,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
Object.assign(originalActions, retryActions);
|
|
109
|
+
return retryResult;
|
|
110
|
+
}
|
|
111
|
+
return handleError(e);
|
|
112
|
+
});
|
|
113
|
+
return { result: Promise.resolve(retriedResult), actions: originalActions };
|
|
114
|
+
};
|
|
115
|
+
try {
|
|
116
|
+
const uploadResult = await wrapPromiseErrorHandler(await index.uploadWithXhrChuncked({
|
|
117
|
+
url,
|
|
118
|
+
file,
|
|
119
|
+
refresh,
|
|
120
|
+
options: finalOptions,
|
|
121
|
+
}));
|
|
122
|
+
return uploadResult;
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
onError?.(e);
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
result: Promise.resolve({
|
|
129
|
+
ok: false,
|
|
130
|
+
total: 0,
|
|
131
|
+
message: "Unsupported upload method",
|
|
132
|
+
status: "error",
|
|
133
|
+
}),
|
|
134
|
+
actions: {
|
|
135
|
+
abort: () => null,
|
|
136
|
+
refresh,
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
module.exports = upload;
|
|
142
|
+
//# sourceMappingURL=xhr.cjs.map
|
package/dist/xhr.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xhr.cjs","sources":["../src/xhr.ts"],"sourcesContent":["export * from \"./types\";\nimport {\n Upload,\n UploadResponse,\n UploadResult,\n OnProgressParams,\n} from \"./types\";\nimport { wait } from \"./utils\";\nimport uploadWithXhrChuncked from \"./xhr-chuncked\";\n\n/**\n * Orchestrates file upload by selecting the optimal method and managing retries and errors.\n * 최적의 업로드 방식을 선택하고 재시도 및 에러 처리를 관리하여 파일 업로드를 수행합니다.\n */\nconst upload = async (\n { url, file, options: { method = \"xhr chunked\", ...options } }: Upload,\n retryAttempt = 0,\n): Promise<UploadResponse> => {\n const {\n onComplete,\n onProgress,\n onAbort,\n onRetry,\n onError,\n retryCount: retryCountArg = 3,\n retryDelay = 1000,\n throwOnError = false,\n ...restOptions\n } = options;\n\n const retryCount = retryCountArg;\n\n /**\n * Determines whether to throw an error based on configuration.\n * 구성 설정에 따라 에러를 throw할지 결정합니다.\n */\n const shouldThrowError = (e: unknown): boolean => {\n if (typeof throwOnError === \"function\") {\n return throwOnError(e);\n }\n\n return Boolean(throwOnError);\n };\n\n /**\n * Handles user-triggered aborts.\n * 사용자에 의해 중단된 경우를 처리합니다.\n */\n const handleAbort = (e: DOMException): UploadResult => {\n onAbort?.(e);\n\n if (shouldThrowError(e)) {\n throw e;\n }\n\n return {\n ok: false,\n total: 0,\n message: \"Aborted by user action\",\n status: \"aborted\",\n };\n };\n\n /**\n * Handles generic errors during upload.\n * 업로드 중 발생하는 일반적인 에러를 처리합니다.\n */\n const handleError = (e: Error): UploadResult => {\n onError?.(e);\n\n if (shouldThrowError(e)) {\n throw e;\n }\n\n return { ok: false, total: 0, message: e.message, status: \"error\" };\n };\n\n const finalOptions = {\n ...restOptions,\n onProgress: ({ loaded, total, percentage }: OnProgressParams) => {\n onProgress?.({ loaded, total, percentage });\n\n if (percentage === 100) {\n onComplete?.();\n }\n },\n };\n\n const refresh = () => upload({ url, file, options });\n\n /**\n * Attempts to retry an upload operation.\n * 업로드 작업을 재시도합니다.\n */\n const retryUpload = async (uploadArgs: Upload): Promise<UploadResponse> => {\n const nextRetryAttempt = retryAttempt + 1;\n\n const nextRetryDelay =\n typeof retryDelay === \"function\"\n ? retryDelay(nextRetryAttempt)\n : retryDelay;\n\n await wait(nextRetryDelay);\n\n const uploadResponse = await upload(uploadArgs, nextRetryAttempt);\n\n onRetry?.();\n\n return uploadResponse;\n };\n\n /**\n * Wraps the upload operation with error and retry handling.\n * 에러 처리 및 재시도 로직으로 업로드 작업을 래핑합니다.\n */\n const wrapPromiseErrorHandler = async (\n uploadResponse: UploadResponse,\n ): Promise<UploadResponse> => {\n const { result: originalResult, actions: originalActions } = uploadResponse;\n\n const retriedResult: Promise<UploadResult> = originalResult\n .then((uploadResult) => {\n /**\n * fetch resolves for HTTP 4xx/5xx, so stream mode can return { ok: false, status: 'error' }\n * without rejecting. We rethrow here to route it through retry/onError handling.\n *\n * fetch는 HTTP 4xx/5xx에서도 reject하지 않아 stream 모드가 실패 결과를 resolve로 반환할 수 있습니다.\n * 그래서 여기서 다시 throw해서 retry/onError 흐름으로 태웁니다.\n */\n if (!uploadResult.ok && uploadResult.status === \"error\") {\n throw new Error(uploadResult.message || \"Upload failed\");\n }\n\n return uploadResult;\n })\n .catch(async (e) => {\n if (e instanceof DOMException && e.name === \"AbortError\") {\n return handleAbort(e);\n }\n\n if (retryCount > 0) {\n const { result: retryResult, actions: retryActions } =\n await retryUpload({\n url,\n file,\n options: {\n ...options,\n method,\n retryCount: retryCount - 1,\n },\n });\n\n Object.assign(originalActions, retryActions);\n return retryResult;\n }\n\n return handleError(e as Error);\n });\n\n return { result: Promise.resolve(retriedResult), actions: originalActions };\n };\n\n try {\n const uploadResult = await wrapPromiseErrorHandler(\n await uploadWithXhrChuncked({\n url,\n file,\n refresh,\n options: finalOptions,\n }),\n );\n\n return uploadResult;\n } catch (e) {\n onError?.(e as Error);\n }\n\n return {\n result: Promise.resolve({\n ok: false,\n total: 0,\n message: \"Unsupported upload method\",\n status: \"error\",\n }),\n actions: {\n abort: () => null,\n refresh,\n },\n };\n};\n\nexport default upload;\n"],"names":["wait","uploadWithXhrChuncked"],"mappings":"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"}
|
package/dist/xhr.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { U as Upload, d as UploadResponse } from './types-CLZnJDsz.js';
|
|
2
|
+
export { O as OnProgressParams, a as UploadActions, b as UploadOptions, c as UploadParams, e as UploadResult, f as UploadStatus } from './types-CLZnJDsz.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Orchestrates file upload by selecting the optimal method and managing retries and errors.
|
|
6
|
+
* 최적의 업로드 방식을 선택하고 재시도 및 에러 처리를 관리하여 파일 업로드를 수행합니다.
|
|
7
|
+
*/
|
|
8
|
+
declare const upload: ({ url, file, options: { method, ...options } }: Upload, retryAttempt?: number) => Promise<UploadResponse>;
|
|
9
|
+
|
|
10
|
+
export { Upload, UploadResponse, upload as default };
|
package/dist/xhr.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { w as wait } from './utils-MtT6SgZa.js';
|
|
2
|
+
import { u as uploadWithXhrChuncked } from './index-BS99wlKk.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Orchestrates file upload by selecting the optimal method and managing retries and errors.
|
|
6
|
+
* 최적의 업로드 방식을 선택하고 재시도 및 에러 처리를 관리하여 파일 업로드를 수행합니다.
|
|
7
|
+
*/
|
|
8
|
+
const upload = async ({ url, file, options: { method = "xhr chunked", ...options } }, retryAttempt = 0) => {
|
|
9
|
+
const { onComplete, onProgress, onAbort, onRetry, onError, retryCount: retryCountArg = 3, retryDelay = 1000, throwOnError = false, ...restOptions } = options;
|
|
10
|
+
const retryCount = retryCountArg;
|
|
11
|
+
/**
|
|
12
|
+
* Determines whether to throw an error based on configuration.
|
|
13
|
+
* 구성 설정에 따라 에러를 throw할지 결정합니다.
|
|
14
|
+
*/
|
|
15
|
+
const shouldThrowError = (e) => {
|
|
16
|
+
if (typeof throwOnError === "function") {
|
|
17
|
+
return throwOnError(e);
|
|
18
|
+
}
|
|
19
|
+
return Boolean(throwOnError);
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Handles user-triggered aborts.
|
|
23
|
+
* 사용자에 의해 중단된 경우를 처리합니다.
|
|
24
|
+
*/
|
|
25
|
+
const handleAbort = (e) => {
|
|
26
|
+
onAbort?.(e);
|
|
27
|
+
if (shouldThrowError(e)) {
|
|
28
|
+
throw e;
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
ok: false,
|
|
32
|
+
total: 0,
|
|
33
|
+
message: "Aborted by user action",
|
|
34
|
+
status: "aborted",
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Handles generic errors during upload.
|
|
39
|
+
* 업로드 중 발생하는 일반적인 에러를 처리합니다.
|
|
40
|
+
*/
|
|
41
|
+
const handleError = (e) => {
|
|
42
|
+
onError?.(e);
|
|
43
|
+
if (shouldThrowError(e)) {
|
|
44
|
+
throw e;
|
|
45
|
+
}
|
|
46
|
+
return { ok: false, total: 0, message: e.message, status: "error" };
|
|
47
|
+
};
|
|
48
|
+
const finalOptions = {
|
|
49
|
+
...restOptions,
|
|
50
|
+
onProgress: ({ loaded, total, percentage }) => {
|
|
51
|
+
onProgress?.({ loaded, total, percentage });
|
|
52
|
+
if (percentage === 100) {
|
|
53
|
+
onComplete?.();
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
const refresh = () => upload({ url, file, options });
|
|
58
|
+
/**
|
|
59
|
+
* Attempts to retry an upload operation.
|
|
60
|
+
* 업로드 작업을 재시도합니다.
|
|
61
|
+
*/
|
|
62
|
+
const retryUpload = async (uploadArgs) => {
|
|
63
|
+
const nextRetryAttempt = retryAttempt + 1;
|
|
64
|
+
const nextRetryDelay = typeof retryDelay === "function"
|
|
65
|
+
? retryDelay(nextRetryAttempt)
|
|
66
|
+
: retryDelay;
|
|
67
|
+
await wait(nextRetryDelay);
|
|
68
|
+
const uploadResponse = await upload(uploadArgs, nextRetryAttempt);
|
|
69
|
+
onRetry?.();
|
|
70
|
+
return uploadResponse;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Wraps the upload operation with error and retry handling.
|
|
74
|
+
* 에러 처리 및 재시도 로직으로 업로드 작업을 래핑합니다.
|
|
75
|
+
*/
|
|
76
|
+
const wrapPromiseErrorHandler = async (uploadResponse) => {
|
|
77
|
+
const { result: originalResult, actions: originalActions } = uploadResponse;
|
|
78
|
+
const retriedResult = originalResult
|
|
79
|
+
.then((uploadResult) => {
|
|
80
|
+
/**
|
|
81
|
+
* fetch resolves for HTTP 4xx/5xx, so stream mode can return { ok: false, status: 'error' }
|
|
82
|
+
* without rejecting. We rethrow here to route it through retry/onError handling.
|
|
83
|
+
*
|
|
84
|
+
* fetch는 HTTP 4xx/5xx에서도 reject하지 않아 stream 모드가 실패 결과를 resolve로 반환할 수 있습니다.
|
|
85
|
+
* 그래서 여기서 다시 throw해서 retry/onError 흐름으로 태웁니다.
|
|
86
|
+
*/
|
|
87
|
+
if (!uploadResult.ok && uploadResult.status === "error") {
|
|
88
|
+
throw new Error(uploadResult.message || "Upload failed");
|
|
89
|
+
}
|
|
90
|
+
return uploadResult;
|
|
91
|
+
})
|
|
92
|
+
.catch(async (e) => {
|
|
93
|
+
if (e instanceof DOMException && e.name === "AbortError") {
|
|
94
|
+
return handleAbort(e);
|
|
95
|
+
}
|
|
96
|
+
if (retryCount > 0) {
|
|
97
|
+
const { result: retryResult, actions: retryActions } = await retryUpload({
|
|
98
|
+
url,
|
|
99
|
+
file,
|
|
100
|
+
options: {
|
|
101
|
+
...options,
|
|
102
|
+
method,
|
|
103
|
+
retryCount: retryCount - 1,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
Object.assign(originalActions, retryActions);
|
|
107
|
+
return retryResult;
|
|
108
|
+
}
|
|
109
|
+
return handleError(e);
|
|
110
|
+
});
|
|
111
|
+
return { result: Promise.resolve(retriedResult), actions: originalActions };
|
|
112
|
+
};
|
|
113
|
+
try {
|
|
114
|
+
const uploadResult = await wrapPromiseErrorHandler(await uploadWithXhrChuncked({
|
|
115
|
+
url,
|
|
116
|
+
file,
|
|
117
|
+
refresh,
|
|
118
|
+
options: finalOptions,
|
|
119
|
+
}));
|
|
120
|
+
return uploadResult;
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
123
|
+
onError?.(e);
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
result: Promise.resolve({
|
|
127
|
+
ok: false,
|
|
128
|
+
total: 0,
|
|
129
|
+
message: "Unsupported upload method",
|
|
130
|
+
status: "error",
|
|
131
|
+
}),
|
|
132
|
+
actions: {
|
|
133
|
+
abort: () => null,
|
|
134
|
+
refresh,
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export { upload as default };
|
|
140
|
+
//# sourceMappingURL=xhr.js.map
|
package/dist/xhr.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xhr.js","sources":["../src/xhr.ts"],"sourcesContent":["export * from \"./types\";\nimport {\n Upload,\n UploadResponse,\n UploadResult,\n OnProgressParams,\n} from \"./types\";\nimport { wait } from \"./utils\";\nimport uploadWithXhrChuncked from \"./xhr-chuncked\";\n\n/**\n * Orchestrates file upload by selecting the optimal method and managing retries and errors.\n * 최적의 업로드 방식을 선택하고 재시도 및 에러 처리를 관리하여 파일 업로드를 수행합니다.\n */\nconst upload = async (\n { url, file, options: { method = \"xhr chunked\", ...options } }: Upload,\n retryAttempt = 0,\n): Promise<UploadResponse> => {\n const {\n onComplete,\n onProgress,\n onAbort,\n onRetry,\n onError,\n retryCount: retryCountArg = 3,\n retryDelay = 1000,\n throwOnError = false,\n ...restOptions\n } = options;\n\n const retryCount = retryCountArg;\n\n /**\n * Determines whether to throw an error based on configuration.\n * 구성 설정에 따라 에러를 throw할지 결정합니다.\n */\n const shouldThrowError = (e: unknown): boolean => {\n if (typeof throwOnError === \"function\") {\n return throwOnError(e);\n }\n\n return Boolean(throwOnError);\n };\n\n /**\n * Handles user-triggered aborts.\n * 사용자에 의해 중단된 경우를 처리합니다.\n */\n const handleAbort = (e: DOMException): UploadResult => {\n onAbort?.(e);\n\n if (shouldThrowError(e)) {\n throw e;\n }\n\n return {\n ok: false,\n total: 0,\n message: \"Aborted by user action\",\n status: \"aborted\",\n };\n };\n\n /**\n * Handles generic errors during upload.\n * 업로드 중 발생하는 일반적인 에러를 처리합니다.\n */\n const handleError = (e: Error): UploadResult => {\n onError?.(e);\n\n if (shouldThrowError(e)) {\n throw e;\n }\n\n return { ok: false, total: 0, message: e.message, status: \"error\" };\n };\n\n const finalOptions = {\n ...restOptions,\n onProgress: ({ loaded, total, percentage }: OnProgressParams) => {\n onProgress?.({ loaded, total, percentage });\n\n if (percentage === 100) {\n onComplete?.();\n }\n },\n };\n\n const refresh = () => upload({ url, file, options });\n\n /**\n * Attempts to retry an upload operation.\n * 업로드 작업을 재시도합니다.\n */\n const retryUpload = async (uploadArgs: Upload): Promise<UploadResponse> => {\n const nextRetryAttempt = retryAttempt + 1;\n\n const nextRetryDelay =\n typeof retryDelay === \"function\"\n ? retryDelay(nextRetryAttempt)\n : retryDelay;\n\n await wait(nextRetryDelay);\n\n const uploadResponse = await upload(uploadArgs, nextRetryAttempt);\n\n onRetry?.();\n\n return uploadResponse;\n };\n\n /**\n * Wraps the upload operation with error and retry handling.\n * 에러 처리 및 재시도 로직으로 업로드 작업을 래핑합니다.\n */\n const wrapPromiseErrorHandler = async (\n uploadResponse: UploadResponse,\n ): Promise<UploadResponse> => {\n const { result: originalResult, actions: originalActions } = uploadResponse;\n\n const retriedResult: Promise<UploadResult> = originalResult\n .then((uploadResult) => {\n /**\n * fetch resolves for HTTP 4xx/5xx, so stream mode can return { ok: false, status: 'error' }\n * without rejecting. We rethrow here to route it through retry/onError handling.\n *\n * fetch는 HTTP 4xx/5xx에서도 reject하지 않아 stream 모드가 실패 결과를 resolve로 반환할 수 있습니다.\n * 그래서 여기서 다시 throw해서 retry/onError 흐름으로 태웁니다.\n */\n if (!uploadResult.ok && uploadResult.status === \"error\") {\n throw new Error(uploadResult.message || \"Upload failed\");\n }\n\n return uploadResult;\n })\n .catch(async (e) => {\n if (e instanceof DOMException && e.name === \"AbortError\") {\n return handleAbort(e);\n }\n\n if (retryCount > 0) {\n const { result: retryResult, actions: retryActions } =\n await retryUpload({\n url,\n file,\n options: {\n ...options,\n method,\n retryCount: retryCount - 1,\n },\n });\n\n Object.assign(originalActions, retryActions);\n return retryResult;\n }\n\n return handleError(e as Error);\n });\n\n return { result: Promise.resolve(retriedResult), actions: originalActions };\n };\n\n try {\n const uploadResult = await wrapPromiseErrorHandler(\n await uploadWithXhrChuncked({\n url,\n file,\n refresh,\n options: finalOptions,\n }),\n );\n\n return uploadResult;\n } catch (e) {\n onError?.(e as Error);\n }\n\n return {\n result: Promise.resolve({\n ok: false,\n total: 0,\n message: \"Unsupported upload method\",\n status: \"error\",\n }),\n actions: {\n abort: () => null,\n refresh,\n },\n };\n};\n\nexport default upload;\n"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@universal-uploader/core",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Core streaming upload logic.",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=18.0.0"
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/jdy8739/universal-uploader.git",
|
|
21
|
+
"directory": "packages/core"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"upload",
|
|
25
|
+
"stream",
|
|
26
|
+
"fetch",
|
|
27
|
+
"xhr"
|
|
28
|
+
],
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "rollup -c rollup.config.mjs",
|
|
32
|
+
"type-check": "tsc --noEmit"
|
|
33
|
+
}
|
|
34
|
+
}
|