@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
package/dist/const.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default chunk size (1 MiB) for stream uploads.
|
|
3
|
+
* Used as both API default and fallback for invalid chunk sizes.
|
|
4
|
+
*
|
|
5
|
+
* 스트림 업로드를 위한 기본 청크 크기(1 MiB)입니다.
|
|
6
|
+
* API 기본값 및 유효하지 않은 청크 크기에 대한 폴백으로 사용됩니다.
|
|
7
|
+
*/
|
|
8
|
+
export declare const DEFAULT_STREAM_CHUNK_SIZE: number;
|
|
9
|
+
/**
|
|
10
|
+
* Header keys used for chunked upload metadata.
|
|
11
|
+
* 청크 업로드 메타데이터에 사용되는 헤더 키입니다.
|
|
12
|
+
*/
|
|
13
|
+
export declare const CHUNK_HEADER_KEYS: {
|
|
14
|
+
readonly chunkIndex: "X-Chunk-Index";
|
|
15
|
+
readonly totalChunks: "X-Total-Chunks";
|
|
16
|
+
readonly chunkSize: "X-Chunk-Size";
|
|
17
|
+
readonly fileSize: "X-File-Size";
|
|
18
|
+
readonly fileName: "X-File-Name";
|
|
19
|
+
};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Utility function to wait for a specific duration.
|
|
5
|
+
* 지정된 시간만큼 대기하기 위한 유틸리티 함수입니다.
|
|
6
|
+
*/
|
|
7
|
+
const wait = (ms) => new Promise((resolve) => {
|
|
8
|
+
setTimeout(resolve, ms);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates an upload orchestrator around a specific uploader executor.
|
|
13
|
+
* 특정 업로더 실행기를 중심으로 업로드 오케스트레이터를 생성합니다.
|
|
14
|
+
*/
|
|
15
|
+
const createUpload = (resolveUploadExecutor) => {
|
|
16
|
+
/**
|
|
17
|
+
* Orchestrates file upload by selecting the optimal method and managing retries and errors.
|
|
18
|
+
* 최적의 업로드 방식을 선택하고 재시도 및 에러 처리를 관리하여 파일 업로드를 수행합니다.
|
|
19
|
+
*/
|
|
20
|
+
const upload = async ({ url, file, options: { method = "auto", ...options } }, retryAttempt = 0) => {
|
|
21
|
+
const { onComplete, onProgress, onAbort, onRetry, onError, retryCount: retryCountArg = 3, retryDelay = 1000, throwOnError = false, ...restOptions } = options;
|
|
22
|
+
const retryCount = retryCountArg;
|
|
23
|
+
/**
|
|
24
|
+
* Determines whether to throw an error based on configuration.
|
|
25
|
+
* 구성 설정에 따라 에러를 throw할지 결정합니다.
|
|
26
|
+
*/
|
|
27
|
+
const shouldThrowError = (e) => {
|
|
28
|
+
if (typeof throwOnError === "function") {
|
|
29
|
+
return throwOnError(e);
|
|
30
|
+
}
|
|
31
|
+
return Boolean(throwOnError);
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Handles user-triggered aborts.
|
|
35
|
+
* 사용자에 의해 중단된 경우를 처리합니다.
|
|
36
|
+
*/
|
|
37
|
+
const handleAbort = (e) => {
|
|
38
|
+
onAbort?.(e);
|
|
39
|
+
if (shouldThrowError(e)) {
|
|
40
|
+
throw e;
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
ok: false,
|
|
44
|
+
total: 0,
|
|
45
|
+
message: "Aborted by user action",
|
|
46
|
+
status: "aborted",
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Handles generic errors during upload.
|
|
51
|
+
* 업로드 중 발생하는 일반적인 에러를 처리합니다.
|
|
52
|
+
*/
|
|
53
|
+
const handleError = (e) => {
|
|
54
|
+
onError?.(e);
|
|
55
|
+
if (shouldThrowError(e)) {
|
|
56
|
+
throw e;
|
|
57
|
+
}
|
|
58
|
+
return { ok: false, total: 0, message: e.message, status: "error" };
|
|
59
|
+
};
|
|
60
|
+
const finalOptions = {
|
|
61
|
+
...restOptions,
|
|
62
|
+
onProgress: ({ loaded, total, percentage }) => {
|
|
63
|
+
onProgress?.({ loaded, total, percentage });
|
|
64
|
+
if (percentage === 100) {
|
|
65
|
+
onComplete?.();
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
const refresh = () => upload({ url, file, options });
|
|
70
|
+
/**
|
|
71
|
+
* Attempts to retry an upload operation.
|
|
72
|
+
* 업로드 작업을 재시도합니다.
|
|
73
|
+
*/
|
|
74
|
+
const retryUpload = async (uploadArgs) => {
|
|
75
|
+
const nextRetryAttempt = retryAttempt + 1;
|
|
76
|
+
const nextRetryDelay = typeof retryDelay === "function"
|
|
77
|
+
? retryDelay(nextRetryAttempt)
|
|
78
|
+
: retryDelay;
|
|
79
|
+
await wait(nextRetryDelay);
|
|
80
|
+
const uploadResponse = await upload(uploadArgs, nextRetryAttempt);
|
|
81
|
+
onRetry?.();
|
|
82
|
+
return uploadResponse;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Wraps the upload operation with error and retry handling.
|
|
86
|
+
* 에러 처리 및 재시도 로직으로 업로드 작업을 래핑합니다.
|
|
87
|
+
*/
|
|
88
|
+
const wrapPromiseErrorHandler = async (uploadResponse) => {
|
|
89
|
+
const { result: originalResult, actions: originalActions } = uploadResponse;
|
|
90
|
+
const retriedResult = originalResult
|
|
91
|
+
.then((uploadResult) => {
|
|
92
|
+
/**
|
|
93
|
+
* fetch resolves for HTTP 4xx/5xx, so stream mode can return { ok: false, status: 'error' }
|
|
94
|
+
* without rejecting. We rethrow here to route it through retry/onError handling.
|
|
95
|
+
*
|
|
96
|
+
* fetch는 HTTP 4xx/5xx에서도 reject하지 않아 stream 모드가 실패 결과를 resolve로 반환할 수 있습니다.
|
|
97
|
+
* 그래서 여기서 다시 throw해서 retry/onError 흐름으로 태웁니다.
|
|
98
|
+
*/
|
|
99
|
+
if (!uploadResult.ok && uploadResult.status === "error") {
|
|
100
|
+
throw new Error(uploadResult.message || "Upload failed");
|
|
101
|
+
}
|
|
102
|
+
return uploadResult;
|
|
103
|
+
})
|
|
104
|
+
.catch(async (e) => {
|
|
105
|
+
if (e instanceof DOMException && e.name === "AbortError") {
|
|
106
|
+
return handleAbort(e);
|
|
107
|
+
}
|
|
108
|
+
if (retryCount > 0) {
|
|
109
|
+
const { result: retryResult, actions: retryActions } = await retryUpload({
|
|
110
|
+
url,
|
|
111
|
+
file,
|
|
112
|
+
options: {
|
|
113
|
+
...options,
|
|
114
|
+
method,
|
|
115
|
+
retryCount: retryCount - 1,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
Object.assign(originalActions, retryActions);
|
|
119
|
+
return retryResult;
|
|
120
|
+
}
|
|
121
|
+
return handleError(e);
|
|
122
|
+
});
|
|
123
|
+
return { result: Promise.resolve(retriedResult), actions: originalActions };
|
|
124
|
+
};
|
|
125
|
+
const uploadFile = resolveUploadExecutor({ url, file, options });
|
|
126
|
+
try {
|
|
127
|
+
const uploadResult = await wrapPromiseErrorHandler(await uploadFile({
|
|
128
|
+
url,
|
|
129
|
+
file,
|
|
130
|
+
refresh,
|
|
131
|
+
options: finalOptions,
|
|
132
|
+
}));
|
|
133
|
+
return uploadResult;
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
onError?.(e);
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
result: Promise.resolve({
|
|
140
|
+
ok: false,
|
|
141
|
+
total: 0,
|
|
142
|
+
message: "Unsupported upload method",
|
|
143
|
+
status: "error",
|
|
144
|
+
}),
|
|
145
|
+
actions: {
|
|
146
|
+
abort: () => null,
|
|
147
|
+
refresh,
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
return upload;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
exports.createUpload = createUpload;
|
|
155
|
+
//# sourceMappingURL=createUpload-Bv4Z2y9b.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createUpload-Bv4Z2y9b.js","sources":["../src/utils.ts","../src/createUpload.ts"],"sourcesContent":["/**\n * Utility function to wait for a specific duration.\n * 지정된 시간만큼 대기하기 위한 유틸리티 함수입니다.\n */\nexport const wait = (ms: number) =>\n new Promise<void>((resolve) => {\n setTimeout(resolve, ms);\n });\n","import { wait } from \"./utils\";\nimport { Upload, UploadResponse, UploadResult, OnProgressParams } from \"./types\";\n\ntype UploadExecutor = (\n args: Upload & { refresh: () => void },\n) => Promise<UploadResponse> | UploadResponse;\n\n/**\n * Creates an upload orchestrator around a specific uploader executor.\n * 특정 업로더 실행기를 중심으로 업로드 오케스트레이터를 생성합니다.\n */\nexport const createUpload = (\n resolveUploadExecutor: (uploadArgs: Upload) => UploadExecutor,\n) => {\n /**\n * Orchestrates file upload by selecting the optimal method and managing retries and errors.\n * 최적의 업로드 방식을 선택하고 재시도 및 에러 처리를 관리하여 파일 업로드를 수행합니다.\n */\n const upload = async (\n { url, file, options: { method = \"auto\", ...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 const uploadFile = resolveUploadExecutor({ url, file, options });\n\n try {\n const uploadResult = await wrapPromiseErrorHandler(\n await uploadFile({\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\n return upload;\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Utility function to wait for a specific duration.
|
|
5
|
+
* 지정된 시간만큼 대기하기 위한 유틸리티 함수입니다.
|
|
6
|
+
*/
|
|
7
|
+
const wait = (ms) => new Promise((resolve) => {
|
|
8
|
+
setTimeout(resolve, ms);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates an upload orchestrator around a specific uploader executor.
|
|
13
|
+
*/
|
|
14
|
+
const createUpload = (resolveUploadExecutor) => {
|
|
15
|
+
const upload = async ({ url, file, options: { method = "auto", ...options } }, retryAttempt = 0) => {
|
|
16
|
+
const { onComplete, onProgress, onAbort, onRetry, onError, retryCount: retryCountArg = 3, retryDelay = 1000, throwOnError = false, ...restOptions } = options;
|
|
17
|
+
const retryCount = retryCountArg;
|
|
18
|
+
const shouldThrowError = (e) => {
|
|
19
|
+
if (typeof throwOnError === "function") {
|
|
20
|
+
return throwOnError(e);
|
|
21
|
+
}
|
|
22
|
+
return Boolean(throwOnError);
|
|
23
|
+
};
|
|
24
|
+
const handleAbort = (e) => {
|
|
25
|
+
onAbort?.(e);
|
|
26
|
+
if (shouldThrowError(e)) {
|
|
27
|
+
throw e;
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
ok: false,
|
|
31
|
+
total: 0,
|
|
32
|
+
message: "Aborted by user action",
|
|
33
|
+
status: "aborted",
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
const handleError = (e) => {
|
|
37
|
+
onError?.(e);
|
|
38
|
+
if (shouldThrowError(e)) {
|
|
39
|
+
throw e;
|
|
40
|
+
}
|
|
41
|
+
return { ok: false, total: 0, message: e.message, status: "error" };
|
|
42
|
+
};
|
|
43
|
+
const finalOptions = {
|
|
44
|
+
...restOptions,
|
|
45
|
+
onProgress: ({ loaded, total, percentage }) => {
|
|
46
|
+
onProgress?.({ loaded, total, percentage });
|
|
47
|
+
if (percentage === 100) {
|
|
48
|
+
onComplete?.();
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
const refresh = () => upload({ url, file, options });
|
|
53
|
+
const retryUpload = async (uploadArgs) => {
|
|
54
|
+
const nextRetryAttempt = retryAttempt + 1;
|
|
55
|
+
const nextRetryDelay = typeof retryDelay === "function"
|
|
56
|
+
? retryDelay(nextRetryAttempt)
|
|
57
|
+
: retryDelay;
|
|
58
|
+
await wait(nextRetryDelay);
|
|
59
|
+
const uploadResponse = await upload(uploadArgs, nextRetryAttempt);
|
|
60
|
+
onRetry?.();
|
|
61
|
+
return uploadResponse;
|
|
62
|
+
};
|
|
63
|
+
const wrapPromiseErrorHandler = async (uploadResponse) => {
|
|
64
|
+
const { result: originalResult, actions: originalActions } = uploadResponse;
|
|
65
|
+
const retriedResult = originalResult
|
|
66
|
+
.then((uploadResult) => {
|
|
67
|
+
if (!uploadResult.ok && uploadResult.status === "error") {
|
|
68
|
+
throw new Error(uploadResult.message || "Upload failed");
|
|
69
|
+
}
|
|
70
|
+
return uploadResult;
|
|
71
|
+
})
|
|
72
|
+
.catch(async (e) => {
|
|
73
|
+
if (e instanceof DOMException && e.name === "AbortError") {
|
|
74
|
+
return handleAbort(e);
|
|
75
|
+
}
|
|
76
|
+
if (retryCount > 0) {
|
|
77
|
+
const { result: retryResult, actions: retryActions } = await retryUpload({
|
|
78
|
+
url,
|
|
79
|
+
file,
|
|
80
|
+
options: {
|
|
81
|
+
...options,
|
|
82
|
+
method,
|
|
83
|
+
retryCount: retryCount - 1,
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
Object.assign(originalActions, retryActions);
|
|
87
|
+
return retryResult;
|
|
88
|
+
}
|
|
89
|
+
return handleError(e);
|
|
90
|
+
});
|
|
91
|
+
return { result: Promise.resolve(retriedResult), actions: originalActions };
|
|
92
|
+
};
|
|
93
|
+
const uploadFile = resolveUploadExecutor({ url, file, options });
|
|
94
|
+
try {
|
|
95
|
+
const uploadResult = await wrapPromiseErrorHandler(await uploadFile({
|
|
96
|
+
url,
|
|
97
|
+
file,
|
|
98
|
+
refresh,
|
|
99
|
+
options: finalOptions,
|
|
100
|
+
}));
|
|
101
|
+
return uploadResult;
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
onError?.(e);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
result: Promise.resolve({
|
|
108
|
+
ok: false,
|
|
109
|
+
total: 0,
|
|
110
|
+
message: "Unsupported upload method",
|
|
111
|
+
status: "error",
|
|
112
|
+
}),
|
|
113
|
+
actions: {
|
|
114
|
+
abort: () => null,
|
|
115
|
+
refresh,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
return upload;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
exports.createUpload = createUpload;
|
|
123
|
+
//# sourceMappingURL=createUpload-CePIp5sg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createUpload-CePIp5sg.js","sources":["../src/utils.ts","../src/createUpload.ts"],"sourcesContent":["/**\n * Utility function to wait for a specific duration.\n * 지정된 시간만큼 대기하기 위한 유틸리티 함수입니다.\n */\nexport const wait = (ms: number) =>\n new Promise<void>((resolve) => {\n setTimeout(resolve, ms);\n });\n","import { wait } from \"./utils\";\nimport { Upload, UploadResponse, UploadResult, OnProgressParams } from \"./types\";\n\ntype UploadExecutor = (\n args: Upload & { refresh: () => void },\n) => Promise<UploadResponse> | UploadResponse;\n\n/**\n * Creates an upload orchestrator around a specific uploader executor.\n */\nexport const createUpload = (\n resolveUploadExecutor: (uploadArgs: Upload) => UploadExecutor,\n) => {\n const upload = async (\n { url, file, options: { method = \"auto\", ...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 const shouldThrowError = (e: unknown): boolean => {\n if (typeof throwOnError === \"function\") {\n return throwOnError(e);\n }\n\n return Boolean(throwOnError);\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 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 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 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 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 const uploadFile = resolveUploadExecutor({ url, file, options });\n\n try {\n const uploadResult = await wrapPromiseErrorHandler(\n await uploadFile({\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\n return upload;\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility function to wait for a specific duration.
|
|
3
|
+
* 지정된 시간만큼 대기하기 위한 유틸리티 함수입니다.
|
|
4
|
+
*/
|
|
5
|
+
const wait = (ms) => new Promise((resolve) => {
|
|
6
|
+
setTimeout(resolve, ms);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates an upload orchestrator around a specific uploader executor.
|
|
11
|
+
*/
|
|
12
|
+
const createUpload = (resolveUploadExecutor) => {
|
|
13
|
+
const upload = async ({ url, file, options: { method = "auto", ...options } }, retryAttempt = 0) => {
|
|
14
|
+
const { onComplete, onProgress, onAbort, onRetry, onError, retryCount: retryCountArg = 3, retryDelay = 1000, throwOnError = false, ...restOptions } = options;
|
|
15
|
+
const retryCount = retryCountArg;
|
|
16
|
+
const shouldThrowError = (e) => {
|
|
17
|
+
if (typeof throwOnError === "function") {
|
|
18
|
+
return throwOnError(e);
|
|
19
|
+
}
|
|
20
|
+
return Boolean(throwOnError);
|
|
21
|
+
};
|
|
22
|
+
const handleAbort = (e) => {
|
|
23
|
+
onAbort?.(e);
|
|
24
|
+
if (shouldThrowError(e)) {
|
|
25
|
+
throw e;
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
total: 0,
|
|
30
|
+
message: "Aborted by user action",
|
|
31
|
+
status: "aborted",
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
const handleError = (e) => {
|
|
35
|
+
onError?.(e);
|
|
36
|
+
if (shouldThrowError(e)) {
|
|
37
|
+
throw e;
|
|
38
|
+
}
|
|
39
|
+
return { ok: false, total: 0, message: e.message, status: "error" };
|
|
40
|
+
};
|
|
41
|
+
const finalOptions = {
|
|
42
|
+
...restOptions,
|
|
43
|
+
onProgress: ({ loaded, total, percentage }) => {
|
|
44
|
+
onProgress?.({ loaded, total, percentage });
|
|
45
|
+
if (percentage === 100) {
|
|
46
|
+
onComplete?.();
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
const refresh = () => upload({ url, file, options });
|
|
51
|
+
const retryUpload = async (uploadArgs) => {
|
|
52
|
+
const nextRetryAttempt = retryAttempt + 1;
|
|
53
|
+
const nextRetryDelay = typeof retryDelay === "function"
|
|
54
|
+
? retryDelay(nextRetryAttempt)
|
|
55
|
+
: retryDelay;
|
|
56
|
+
await wait(nextRetryDelay);
|
|
57
|
+
const uploadResponse = await upload(uploadArgs, nextRetryAttempt);
|
|
58
|
+
onRetry?.();
|
|
59
|
+
return uploadResponse;
|
|
60
|
+
};
|
|
61
|
+
const wrapPromiseErrorHandler = async (uploadResponse) => {
|
|
62
|
+
const { result: originalResult, actions: originalActions } = uploadResponse;
|
|
63
|
+
const retriedResult = originalResult
|
|
64
|
+
.then((uploadResult) => {
|
|
65
|
+
if (!uploadResult.ok && uploadResult.status === "error") {
|
|
66
|
+
throw new Error(uploadResult.message || "Upload failed");
|
|
67
|
+
}
|
|
68
|
+
return uploadResult;
|
|
69
|
+
})
|
|
70
|
+
.catch(async (e) => {
|
|
71
|
+
if (e instanceof DOMException && e.name === "AbortError") {
|
|
72
|
+
return handleAbort(e);
|
|
73
|
+
}
|
|
74
|
+
if (retryCount > 0) {
|
|
75
|
+
const { result: retryResult, actions: retryActions } = await retryUpload({
|
|
76
|
+
url,
|
|
77
|
+
file,
|
|
78
|
+
options: {
|
|
79
|
+
...options,
|
|
80
|
+
method,
|
|
81
|
+
retryCount: retryCount - 1,
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
Object.assign(originalActions, retryActions);
|
|
85
|
+
return retryResult;
|
|
86
|
+
}
|
|
87
|
+
return handleError(e);
|
|
88
|
+
});
|
|
89
|
+
return { result: Promise.resolve(retriedResult), actions: originalActions };
|
|
90
|
+
};
|
|
91
|
+
const uploadFile = resolveUploadExecutor({ url, file, options });
|
|
92
|
+
try {
|
|
93
|
+
const uploadResult = await wrapPromiseErrorHandler(await uploadFile({
|
|
94
|
+
url,
|
|
95
|
+
file,
|
|
96
|
+
refresh,
|
|
97
|
+
options: finalOptions,
|
|
98
|
+
}));
|
|
99
|
+
return uploadResult;
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
onError?.(e);
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
result: Promise.resolve({
|
|
106
|
+
ok: false,
|
|
107
|
+
total: 0,
|
|
108
|
+
message: "Unsupported upload method",
|
|
109
|
+
status: "error",
|
|
110
|
+
}),
|
|
111
|
+
actions: {
|
|
112
|
+
abort: () => null,
|
|
113
|
+
refresh,
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
return upload;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export { createUpload as c };
|
|
121
|
+
//# sourceMappingURL=createUpload-DfsX80rY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createUpload-DfsX80rY.js","sources":["../src/utils.ts","../src/createUpload.ts"],"sourcesContent":["/**\n * Utility function to wait for a specific duration.\n * 지정된 시간만큼 대기하기 위한 유틸리티 함수입니다.\n */\nexport const wait = (ms: number) =>\n new Promise<void>((resolve) => {\n setTimeout(resolve, ms);\n });\n","import { wait } from \"./utils\";\nimport { Upload, UploadResponse, UploadResult, OnProgressParams } from \"./types\";\n\ntype UploadExecutor = (\n args: Upload & { refresh: () => void },\n) => Promise<UploadResponse> | UploadResponse;\n\n/**\n * Creates an upload orchestrator around a specific uploader executor.\n */\nexport const createUpload = (\n resolveUploadExecutor: (uploadArgs: Upload) => UploadExecutor,\n) => {\n const upload = async (\n { url, file, options: { method = \"auto\", ...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 const shouldThrowError = (e: unknown): boolean => {\n if (typeof throwOnError === \"function\") {\n return throwOnError(e);\n }\n\n return Boolean(throwOnError);\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 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 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 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 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 const uploadFile = resolveUploadExecutor({ url, file, options });\n\n try {\n const uploadResult = await wrapPromiseErrorHandler(\n await uploadFile({\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\n return upload;\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility function to wait for a specific duration.
|
|
3
|
+
* 지정된 시간만큼 대기하기 위한 유틸리티 함수입니다.
|
|
4
|
+
*/
|
|
5
|
+
const wait = (ms) => new Promise((resolve) => {
|
|
6
|
+
setTimeout(resolve, ms);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates an upload orchestrator around a specific uploader executor.
|
|
11
|
+
* 특정 업로더 실행기를 중심으로 업로드 오케스트레이터를 생성합니다.
|
|
12
|
+
*/
|
|
13
|
+
const createUpload = (resolveUploadExecutor) => {
|
|
14
|
+
/**
|
|
15
|
+
* Orchestrates file upload by selecting the optimal method and managing retries and errors.
|
|
16
|
+
* 최적의 업로드 방식을 선택하고 재시도 및 에러 처리를 관리하여 파일 업로드를 수행합니다.
|
|
17
|
+
*/
|
|
18
|
+
const upload = async ({ url, file, options: { method = "auto", ...options } }, retryAttempt = 0) => {
|
|
19
|
+
const { onComplete, onProgress, onAbort, onRetry, onError, retryCount: retryCountArg = 3, retryDelay = 1000, throwOnError = false, ...restOptions } = options;
|
|
20
|
+
const retryCount = retryCountArg;
|
|
21
|
+
/**
|
|
22
|
+
* Determines whether to throw an error based on configuration.
|
|
23
|
+
* 구성 설정에 따라 에러를 throw할지 결정합니다.
|
|
24
|
+
*/
|
|
25
|
+
const shouldThrowError = (e) => {
|
|
26
|
+
if (typeof throwOnError === "function") {
|
|
27
|
+
return throwOnError(e);
|
|
28
|
+
}
|
|
29
|
+
return Boolean(throwOnError);
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Handles user-triggered aborts.
|
|
33
|
+
* 사용자에 의해 중단된 경우를 처리합니다.
|
|
34
|
+
*/
|
|
35
|
+
const handleAbort = (e) => {
|
|
36
|
+
onAbort?.(e);
|
|
37
|
+
if (shouldThrowError(e)) {
|
|
38
|
+
throw e;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
total: 0,
|
|
43
|
+
message: "Aborted by user action",
|
|
44
|
+
status: "aborted",
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Handles generic errors during upload.
|
|
49
|
+
* 업로드 중 발생하는 일반적인 에러를 처리합니다.
|
|
50
|
+
*/
|
|
51
|
+
const handleError = (e) => {
|
|
52
|
+
onError?.(e);
|
|
53
|
+
if (shouldThrowError(e)) {
|
|
54
|
+
throw e;
|
|
55
|
+
}
|
|
56
|
+
return { ok: false, total: 0, message: e.message, status: "error" };
|
|
57
|
+
};
|
|
58
|
+
const finalOptions = {
|
|
59
|
+
...restOptions,
|
|
60
|
+
onProgress: ({ loaded, total, percentage }) => {
|
|
61
|
+
onProgress?.({ loaded, total, percentage });
|
|
62
|
+
if (percentage === 100) {
|
|
63
|
+
onComplete?.();
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
const refresh = () => upload({ url, file, options });
|
|
68
|
+
/**
|
|
69
|
+
* Attempts to retry an upload operation.
|
|
70
|
+
* 업로드 작업을 재시도합니다.
|
|
71
|
+
*/
|
|
72
|
+
const retryUpload = async (uploadArgs) => {
|
|
73
|
+
const nextRetryAttempt = retryAttempt + 1;
|
|
74
|
+
const nextRetryDelay = typeof retryDelay === "function"
|
|
75
|
+
? retryDelay(nextRetryAttempt)
|
|
76
|
+
: retryDelay;
|
|
77
|
+
await wait(nextRetryDelay);
|
|
78
|
+
const uploadResponse = await upload(uploadArgs, nextRetryAttempt);
|
|
79
|
+
onRetry?.();
|
|
80
|
+
return uploadResponse;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Wraps the upload operation with error and retry handling.
|
|
84
|
+
* 에러 처리 및 재시도 로직으로 업로드 작업을 래핑합니다.
|
|
85
|
+
*/
|
|
86
|
+
const wrapPromiseErrorHandler = async (uploadResponse) => {
|
|
87
|
+
const { result: originalResult, actions: originalActions } = uploadResponse;
|
|
88
|
+
const retriedResult = originalResult
|
|
89
|
+
.then((uploadResult) => {
|
|
90
|
+
/**
|
|
91
|
+
* fetch resolves for HTTP 4xx/5xx, so stream mode can return { ok: false, status: 'error' }
|
|
92
|
+
* without rejecting. We rethrow here to route it through retry/onError handling.
|
|
93
|
+
*
|
|
94
|
+
* fetch는 HTTP 4xx/5xx에서도 reject하지 않아 stream 모드가 실패 결과를 resolve로 반환할 수 있습니다.
|
|
95
|
+
* 그래서 여기서 다시 throw해서 retry/onError 흐름으로 태웁니다.
|
|
96
|
+
*/
|
|
97
|
+
if (!uploadResult.ok && uploadResult.status === "error") {
|
|
98
|
+
throw new Error(uploadResult.message || "Upload failed");
|
|
99
|
+
}
|
|
100
|
+
return uploadResult;
|
|
101
|
+
})
|
|
102
|
+
.catch(async (e) => {
|
|
103
|
+
if (e instanceof DOMException && e.name === "AbortError") {
|
|
104
|
+
return handleAbort(e);
|
|
105
|
+
}
|
|
106
|
+
if (retryCount > 0) {
|
|
107
|
+
const { result: retryResult, actions: retryActions } = await retryUpload({
|
|
108
|
+
url,
|
|
109
|
+
file,
|
|
110
|
+
options: {
|
|
111
|
+
...options,
|
|
112
|
+
method,
|
|
113
|
+
retryCount: retryCount - 1,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
Object.assign(originalActions, retryActions);
|
|
117
|
+
return retryResult;
|
|
118
|
+
}
|
|
119
|
+
return handleError(e);
|
|
120
|
+
});
|
|
121
|
+
return { result: Promise.resolve(retriedResult), actions: originalActions };
|
|
122
|
+
};
|
|
123
|
+
const uploadFile = resolveUploadExecutor({ url, file, options });
|
|
124
|
+
try {
|
|
125
|
+
const uploadResult = await wrapPromiseErrorHandler(await uploadFile({
|
|
126
|
+
url,
|
|
127
|
+
file,
|
|
128
|
+
refresh,
|
|
129
|
+
options: finalOptions,
|
|
130
|
+
}));
|
|
131
|
+
return uploadResult;
|
|
132
|
+
}
|
|
133
|
+
catch (e) {
|
|
134
|
+
onError?.(e);
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
result: Promise.resolve({
|
|
138
|
+
ok: false,
|
|
139
|
+
total: 0,
|
|
140
|
+
message: "Unsupported upload method",
|
|
141
|
+
status: "error",
|
|
142
|
+
}),
|
|
143
|
+
actions: {
|
|
144
|
+
abort: () => null,
|
|
145
|
+
refresh,
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
return upload;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export { createUpload as c };
|
|
153
|
+
//# sourceMappingURL=createUpload-wm9hFbGi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createUpload-wm9hFbGi.js","sources":["../src/utils.ts","../src/createUpload.ts"],"sourcesContent":["/**\n * Utility function to wait for a specific duration.\n * 지정된 시간만큼 대기하기 위한 유틸리티 함수입니다.\n */\nexport const wait = (ms: number) =>\n new Promise<void>((resolve) => {\n setTimeout(resolve, ms);\n });\n","import { wait } from \"./utils\";\nimport { Upload, UploadResponse, UploadResult, OnProgressParams } from \"./types\";\n\ntype UploadExecutor = (\n args: Upload & { refresh: () => void },\n) => Promise<UploadResponse> | UploadResponse;\n\n/**\n * Creates an upload orchestrator around a specific uploader executor.\n * 특정 업로더 실행기를 중심으로 업로드 오케스트레이터를 생성합니다.\n */\nexport const createUpload = (\n resolveUploadExecutor: (uploadArgs: Upload) => UploadExecutor,\n) => {\n /**\n * Orchestrates file upload by selecting the optimal method and managing retries and errors.\n * 최적의 업로드 방식을 선택하고 재시도 및 에러 처리를 관리하여 파일 업로드를 수행합니다.\n */\n const upload = async (\n { url, file, options: { method = \"auto\", ...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 const uploadFile = resolveUploadExecutor({ url, file, options });\n\n try {\n const uploadResult = await wrapPromiseErrorHandler(\n await uploadFile({\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\n return upload;\n};\n"],"names":[],"mappings":"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"}
|