@windwalker-io/unicorn-next 0.1.18 → 0.1.21
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/chunks/_arrayPush.js +325 -108
- package/dist/chunks/_arrayPush.js.map +1 -1
- package/dist/chunks/_baseRest.js +155 -60
- package/dist/chunks/_baseRest.js.map +1 -1
- package/dist/chunks/_baseUnary.js +463 -0
- package/dist/chunks/_baseUnary.js.map +1 -0
- package/dist/chunks/_getPrototype.js +292 -100
- package/dist/chunks/_getPrototype.js.map +1 -1
- package/dist/chunks/alert-adapter.js +29 -0
- package/dist/chunks/alert-adapter.js.map +1 -0
- package/dist/chunks/alert.js +21 -0
- package/dist/chunks/alert.js.map +1 -0
- package/dist/chunks/arr.js +24 -0
- package/dist/chunks/arr.js.map +1 -0
- package/dist/chunks/button-radio.js +127 -145
- package/dist/chunks/button-radio.js.map +1 -1
- package/dist/chunks/checkboxes-multi-select.js +44 -43
- package/dist/chunks/checkboxes-multi-select.js.map +1 -1
- package/dist/chunks/chunk.js +24 -0
- package/dist/chunks/cloneDeep.js +679 -212
- package/dist/chunks/cloneDeep.js.map +1 -1
- package/dist/chunks/cropper.min.js +6 -5
- package/dist/chunks/cropper.min.js.map +1 -1
- package/dist/chunks/crypto.js +26 -0
- package/dist/chunks/crypto.js.map +1 -0
- package/dist/chunks/data.js +49 -0
- package/dist/chunks/data.js.map +1 -0
- package/dist/chunks/dom.js +128 -0
- package/dist/chunks/dom.js.map +1 -0
- package/dist/chunks/events.js +270 -0
- package/dist/chunks/events.js.map +1 -0
- package/dist/chunks/field-cascade-select.js +207 -250
- package/dist/chunks/field-cascade-select.js.map +1 -1
- package/dist/chunks/field-file-drag.js +175 -209
- package/dist/chunks/field-file-drag.js.map +1 -1
- package/dist/chunks/field-flatpickr.js +94 -898
- package/dist/chunks/field-flatpickr.js.map +1 -1
- package/dist/chunks/field-modal-select.js +728 -467
- package/dist/chunks/field-modal-select.js.map +1 -1
- package/dist/chunks/field-modal-tree.js +771 -766
- package/dist/chunks/field-modal-tree.js.map +1 -1
- package/dist/chunks/field-multi-uploader.js +249 -256
- package/dist/chunks/field-multi-uploader.js.map +1 -1
- package/dist/chunks/field-repeatable.js +111 -127
- package/dist/chunks/field-repeatable.js.map +1 -1
- package/dist/chunks/field-single-image-drag.js +286 -338
- package/dist/chunks/field-single-image-drag.js.map +1 -1
- package/dist/chunks/form.js +146 -159
- package/dist/chunks/form.js.map +1 -1
- package/dist/chunks/grid.js +349 -418
- package/dist/chunks/grid.js.map +1 -1
- package/dist/chunks/helper.js +39 -0
- package/dist/chunks/helper.js.map +1 -0
- package/dist/chunks/http-client.js +221 -211
- package/dist/chunks/http-client.js.map +1 -1
- package/dist/chunks/iframe-modal.js +95 -115
- package/dist/chunks/iframe-modal.js.map +1 -1
- package/dist/chunks/keep-tab.js +92 -101
- package/dist/chunks/keep-tab.js.map +1 -1
- package/dist/chunks/lang.js +250 -0
- package/dist/chunks/lang.js.map +1 -0
- package/dist/chunks/legacy.js +197 -201
- package/dist/chunks/legacy.js.map +1 -1
- package/dist/chunks/list-dependent.js +195 -228
- package/dist/chunks/list-dependent.js.map +1 -1
- package/dist/chunks/loader.js +106 -0
- package/dist/chunks/loader.js.map +1 -0
- package/dist/chunks/monthSelect.js +251 -0
- package/dist/chunks/monthSelect.js.map +1 -0
- package/dist/chunks/router.js +111 -0
- package/dist/chunks/router.js.map +1 -0
- package/dist/chunks/s3-multipart-uploader.js +183 -210
- package/dist/chunks/s3-multipart-uploader.js.map +1 -1
- package/dist/chunks/s3-uploader.js +106 -128
- package/dist/chunks/s3-uploader.js.map +1 -1
- package/dist/chunks/show-on.js +358 -205
- package/dist/chunks/show-on.js.map +1 -1
- package/dist/chunks/timing.js +10 -0
- package/dist/chunks/timing.js.map +1 -0
- package/dist/chunks/tinymce.js +153 -203
- package/dist/chunks/tinymce.js.map +1 -1
- package/dist/chunks/ui-bootstrap5.js +58 -72
- package/dist/chunks/ui-bootstrap5.js.map +1 -1
- package/dist/chunks/ui.js +320 -0
- package/dist/chunks/ui.js.map +1 -0
- package/dist/chunks/unicorn.js.map +1 -1
- package/dist/chunks/useQueue.js +111 -0
- package/dist/chunks/useQueue.js.map +1 -0
- package/dist/chunks/useStack.js +76 -0
- package/dist/chunks/useStack.js.map +1 -0
- package/dist/chunks/validation.js +761 -853
- package/dist/chunks/validation.js.map +1 -1
- package/dist/editor.css +1 -1
- package/dist/index.d.ts +27 -15
- package/dist/multi-level-menu.css +1 -1
- package/dist/switcher.css +1 -1
- package/dist/unicorn.js +805 -130
- package/dist/unicorn.js.map +1 -1
- package/package.json +3 -3
- package/src/composable/useBsModalAlert.ts +92 -12
- package/src/composable/useHttp.ts +13 -1
- package/src/module/s3-uploader.ts +1 -1
- package/src/service/ui.ts +31 -15
- package/vite.config.ts +5 -1
- package/dist/chunks/_commonjsHelpers.js +0 -7
- package/dist/chunks/index.js +0 -314
- package/dist/chunks/isArguments.js +0 -146
- package/dist/chunks/unicorn.js +0 -2580
|
@@ -1,212 +1,185 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { n as Mixin, t as EventMixin } from "./events.js";
|
|
2
|
+
import { t as mergeDeep } from "./arr.js";
|
|
3
|
+
import { t as createQueue } from "./useQueue.js";
|
|
4
|
+
import { useHttpClient } from "../unicorn.js";
|
|
5
|
+
//#region src/module/s3-multipart-uploader.ts
|
|
6
|
+
var defaultOptions = {
|
|
7
|
+
chunkSize: 5 * 1024 * 1024,
|
|
8
|
+
concurrency: 2
|
|
6
9
|
};
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (options.onProgress) {
|
|
179
|
-
options.onProgress(event);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
async resolveRoute(action) {
|
|
183
|
-
if (typeof this.options.routes === "function") {
|
|
184
|
-
return this.options.routes(action);
|
|
185
|
-
}
|
|
186
|
-
return this.options.routes[action];
|
|
187
|
-
}
|
|
188
|
-
setChunkSize(size) {
|
|
189
|
-
this.options.chunkSize = size;
|
|
190
|
-
return this;
|
|
191
|
-
}
|
|
192
|
-
setChunkSizeInMiB(size) {
|
|
193
|
-
this.options.chunkSize = size * 1024 * 1024;
|
|
194
|
-
return this;
|
|
195
|
-
}
|
|
196
|
-
replaceExt(path, file) {
|
|
197
|
-
if (file instanceof File) {
|
|
198
|
-
const fileExt = file.name.split(".").pop();
|
|
199
|
-
if (path.endsWith(".{ext}")) {
|
|
200
|
-
return path.replace(/\.{ext}$/, fileExt ? "." + fileExt : "");
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
return path;
|
|
204
|
-
}
|
|
205
|
-
on(event, handler) {
|
|
206
|
-
return super.on(event, handler);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
export {
|
|
210
|
-
S3MultipartUploader
|
|
10
|
+
var S3MultipartUploader = class extends Mixin(EventMixin) {
|
|
11
|
+
options;
|
|
12
|
+
constructor(options) {
|
|
13
|
+
super();
|
|
14
|
+
this.options = mergeDeep({}, defaultOptions, options);
|
|
15
|
+
}
|
|
16
|
+
async upload(file, path, options = {}) {
|
|
17
|
+
const extra = {
|
|
18
|
+
...this.options.extra ?? {},
|
|
19
|
+
...options.extra ?? {}
|
|
20
|
+
};
|
|
21
|
+
if (typeof file === "string") file = new Blob([file], { type: options["ContentType"] || "text/plain" });
|
|
22
|
+
if (file instanceof Blob && !(file instanceof File)) {
|
|
23
|
+
if (path.endsWith(".{ext}")) throw new Error("If using Blob or file data string, you must provide a valid file extension in the path.");
|
|
24
|
+
file = new File([file], "blob", { type: file.type });
|
|
25
|
+
}
|
|
26
|
+
if (file instanceof File) extra["ContentType"] = options["ContentType"] || file.type;
|
|
27
|
+
if (options.ACL || this.options.ACL) extra.ACL = options.ACL || this.options.ACL;
|
|
28
|
+
path = this.replaceExt(path, file);
|
|
29
|
+
const initData = {
|
|
30
|
+
extra,
|
|
31
|
+
path,
|
|
32
|
+
profile: this.options.profile
|
|
33
|
+
};
|
|
34
|
+
if (options["filename"]) initData["filename"] = options["filename"];
|
|
35
|
+
this.trigger("start", file, initData);
|
|
36
|
+
const beforeUnloadHandler = (e) => {
|
|
37
|
+
e.preventDefault();
|
|
38
|
+
e.returnValue = "";
|
|
39
|
+
};
|
|
40
|
+
if (this.options.leaveAlert === true) window.addEventListener("beforeunload", beforeUnloadHandler);
|
|
41
|
+
let uploadId = null;
|
|
42
|
+
let isCancel = false;
|
|
43
|
+
let signal = options.abortController?.signal;
|
|
44
|
+
if (signal) signal.addEventListener("abort", (e) => {
|
|
45
|
+
isCancel = true;
|
|
46
|
+
});
|
|
47
|
+
try {
|
|
48
|
+
const { id } = await this.request("init", initData);
|
|
49
|
+
uploadId = id;
|
|
50
|
+
this.trigger("inited", {
|
|
51
|
+
id,
|
|
52
|
+
path
|
|
53
|
+
});
|
|
54
|
+
const chunkSize = this.options.chunkSize;
|
|
55
|
+
const chunks = Math.ceil(file.size / chunkSize);
|
|
56
|
+
let uploadedBytes = 0;
|
|
57
|
+
let parts = [];
|
|
58
|
+
let currentPart = 1;
|
|
59
|
+
const queue = createQueue(this.options.concurrency);
|
|
60
|
+
const promises = [];
|
|
61
|
+
const partsUploaded = {};
|
|
62
|
+
while (currentPart <= chunks) {
|
|
63
|
+
const partNumber = currentPart;
|
|
64
|
+
const p = queue.push(async () => {
|
|
65
|
+
const { blob, etag } = await this.uploadPart(file, {
|
|
66
|
+
id,
|
|
67
|
+
path,
|
|
68
|
+
partNumber,
|
|
69
|
+
chunkSize,
|
|
70
|
+
abortController: options.abortController,
|
|
71
|
+
onUploadProgress: (e) => {
|
|
72
|
+
partsUploaded[partNumber] = e.loaded;
|
|
73
|
+
const uploaded = Object.values(partsUploaded).reduce((sum, a) => sum + a, 0);
|
|
74
|
+
this.updateProgress(uploaded, file.size, options);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
uploadedBytes += blob.size;
|
|
78
|
+
parts.push({
|
|
79
|
+
ETag: etag,
|
|
80
|
+
PartNumber: partNumber
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
promises.push(p);
|
|
84
|
+
currentPart++;
|
|
85
|
+
}
|
|
86
|
+
await Promise.all(promises);
|
|
87
|
+
if (isCancel) {
|
|
88
|
+
const e = /* @__PURE__ */ new Error("Upload cancelled");
|
|
89
|
+
e.name = "CanceledError";
|
|
90
|
+
throw e;
|
|
91
|
+
}
|
|
92
|
+
const { url } = await this.request("complete", {
|
|
93
|
+
id,
|
|
94
|
+
path,
|
|
95
|
+
parts: parts.sort((a, b) => a.PartNumber - b.PartNumber),
|
|
96
|
+
profile: this.options.profile
|
|
97
|
+
});
|
|
98
|
+
this.trigger("success", {
|
|
99
|
+
id,
|
|
100
|
+
path,
|
|
101
|
+
url
|
|
102
|
+
});
|
|
103
|
+
return {
|
|
104
|
+
url,
|
|
105
|
+
id,
|
|
106
|
+
path
|
|
107
|
+
};
|
|
108
|
+
} catch (e) {
|
|
109
|
+
if (uploadId) await this.abort(uploadId, path);
|
|
110
|
+
this.trigger("failure", {
|
|
111
|
+
error: e,
|
|
112
|
+
uploadId,
|
|
113
|
+
path
|
|
114
|
+
});
|
|
115
|
+
throw e;
|
|
116
|
+
} finally {
|
|
117
|
+
if (this.options.leaveAlert === true) window.removeEventListener("beforeunload", beforeUnloadHandler);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async uploadPart(file, payload) {
|
|
121
|
+
const http = await useHttpClient();
|
|
122
|
+
const { id, path, partNumber, chunkSize, onUploadProgress } = payload;
|
|
123
|
+
const start = (partNumber - 1) * chunkSize;
|
|
124
|
+
const end = Math.min(partNumber * chunkSize, file.size);
|
|
125
|
+
const blob = file.slice(start, end);
|
|
126
|
+
const { url } = await this.request("sign", {
|
|
127
|
+
id,
|
|
128
|
+
path,
|
|
129
|
+
partNumber,
|
|
130
|
+
profile: this.options.profile
|
|
131
|
+
}, { signal: payload.abortController?.signal });
|
|
132
|
+
const res = await http.put(url, blob, { onUploadProgress });
|
|
133
|
+
return {
|
|
134
|
+
blob,
|
|
135
|
+
etag: String(res.headers.get("ETag") || "")
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async request(action, body, config = {}) {
|
|
139
|
+
if (this.options.requestHandler) return this.options.requestHandler(action, body);
|
|
140
|
+
return (await (await useHttpClient()).post(await this.resolveRoute(action), body, config)).data.data;
|
|
141
|
+
}
|
|
142
|
+
async abort(id, path) {
|
|
143
|
+
await this.request("abort", {
|
|
144
|
+
id,
|
|
145
|
+
path,
|
|
146
|
+
profile: this.options.profile
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
updateProgress(loaded, total, options) {
|
|
150
|
+
const event = {
|
|
151
|
+
percentage: loaded / total * 100,
|
|
152
|
+
loaded,
|
|
153
|
+
total
|
|
154
|
+
};
|
|
155
|
+
this.trigger("progress", event);
|
|
156
|
+
this.options.onProgress?.(event);
|
|
157
|
+
if (options.onProgress) options.onProgress(event);
|
|
158
|
+
}
|
|
159
|
+
async resolveRoute(action) {
|
|
160
|
+
if (typeof this.options.routes === "function") return this.options.routes(action);
|
|
161
|
+
return this.options.routes[action];
|
|
162
|
+
}
|
|
163
|
+
setChunkSize(size) {
|
|
164
|
+
this.options.chunkSize = size;
|
|
165
|
+
return this;
|
|
166
|
+
}
|
|
167
|
+
setChunkSizeInMiB(size) {
|
|
168
|
+
this.options.chunkSize = size * 1024 * 1024;
|
|
169
|
+
return this;
|
|
170
|
+
}
|
|
171
|
+
replaceExt(path, file) {
|
|
172
|
+
if (file instanceof File) {
|
|
173
|
+
const fileExt = file.name.split(".").pop();
|
|
174
|
+
if (path.endsWith(".{ext}")) return path.replace(/\.{ext}$/, fileExt ? "." + fileExt : "");
|
|
175
|
+
}
|
|
176
|
+
return path;
|
|
177
|
+
}
|
|
178
|
+
on(event, handler) {
|
|
179
|
+
return super.on(event, handler);
|
|
180
|
+
}
|
|
211
181
|
};
|
|
212
|
-
//#
|
|
182
|
+
//#endregion
|
|
183
|
+
export { S3MultipartUploader };
|
|
184
|
+
|
|
185
|
+
//# sourceMappingURL=s3-multipart-uploader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"s3-multipart-uploader.js","sources":["../../src/module/s3-multipart-uploader.ts"],"sourcesContent":["import { AxiosProgressEvent, type AxiosRequestConfig, AxiosResponseHeaders } from 'axios';\nimport { Mixin } from 'ts-mixer';\nimport { createQueue, useHttpClient } from '../composable';\nimport { EventHandler, EventMixin } from '../events';\nimport type { MaybePromise } from '../types';\nimport { mergeDeep } from '../utilities';\nimport { ApiReturn } from './http-client';\n\ndeclare type RoutingOptions = {\n init: string;\n sign: string;\n complete: string;\n abort: string;\n} | ((action: RouteActions) => MaybePromise<string>);\n\ndeclare type RouteActions = 'init' | 'sign' | 'complete' | 'abort';\ndeclare type RequestHandler = <T = Record<string, any>>(action: RouteActions, data: Record<string, any>) => Promise<T>;\n\nexport interface S3MultipartUploaderOptions {\n profile?: string;\n chunkSize: number;\n concurrency: number;\n leaveAlert?: boolean;\n routes: RoutingOptions;\n requestHandler?: RequestHandler;\n onProgress?: ProgressEventHandler;\n ACL?: string;\n extra?: Record<string, any>;\n\n // maxRetries?: number;\n // endpoint: string;\n // subfolder?: string;\n}\n\nconst defaultOptions: Partial<S3MultipartUploaderOptions> = {\n chunkSize: 5 * 1024 * 1024, // 5MB\n concurrency: 2,\n};\n\nexport interface S3MultipartUploaderRequestOptions {\n onProgress?: ProgressEventHandler;\n filename?: string;\n ContentType?: string;\n ContentDisposition?: string;\n ACL?: 'public-read' | 'private' | 'authenticated-read' | 'public-read-write' | string;\n extra?: Record<string, any>;\n abortController?: AbortController;\n}\n\nexport class S3MultipartUploader extends Mixin(EventMixin) {\n options: S3MultipartUploaderOptions;\n\n constructor(options: Partial<S3MultipartUploaderOptions>) {\n super();\n this.options = mergeDeep({}, defaultOptions, options);\n }\n\n async upload(\n file: string | File | Blob,\n path: string,\n options: S3MultipartUploaderRequestOptions = {}\n ): Promise<{ url: string; id: string; path: string; }> {\n const extra: Record<string, any> = { ...(this.options.extra ?? {}), ...(options.extra ?? {}) };\n\n if (typeof file === 'string') {\n file = new Blob([file], { type: options['ContentType'] || 'text/plain' });\n }\n\n if (file instanceof Blob && !(file instanceof File)) {\n if (path.endsWith('.{ext}')) {\n throw new Error('If using Blob or file data string, you must provide a valid file extension in the path.');\n }\n\n file = new File([file], 'blob', { type: file.type });\n }\n\n if (file instanceof File) {\n extra['ContentType'] = options['ContentType'] || file.type;\n }\n\n if (options.ACL || this.options.ACL) {\n extra.ACL = options.ACL || this.options.ACL;\n }\n\n path = this.replaceExt(path, file);\n\n const initData: Record<string, any> = { extra, path, profile: this.options.profile };\n\n if (options['filename']) {\n initData['filename'] = options['filename'];\n }\n\n this.trigger('start', file, initData);\n\n // Prepare unload\n const beforeUnloadHandler = (e: BeforeUnloadEvent) => {\n e.preventDefault();\n e.returnValue = '';\n };\n\n if (this.options.leaveAlert === true) {\n window.addEventListener('beforeunload', beforeUnloadHandler);\n }\n\n let uploadId: string | null = null;\n let isCancel = false;\n let signal = options.abortController?.signal;\n\n if (signal) {\n signal.addEventListener('abort', (e) => {\n isCancel = true;\n });\n }\n\n try {\n // @Request init\n const { id } = await this.request<{ id: string; }>(\n 'init',\n initData\n );\n\n uploadId = id;\n\n this.trigger('inited', { id, path });\n\n const chunkSize = this.options.chunkSize;\n const chunks = Math.ceil(file.size / chunkSize);\n\n let uploadedBytes = 0;\n let parts: { ETag: string, PartNumber: number }[] = [];\n let currentPart = 1;\n const queue = createQueue(this.options.concurrency);\n const promises = [];\n const partsUploaded: Record<number, number> = {};\n\n // Loop from 1 to chunks\n while (currentPart <= chunks) {\n const partNumber = currentPart;\n\n // Push to queue\n const p = queue.push(async () => {\n const { blob, etag } = await this.uploadPart(\n file as File,\n {\n id,\n path,\n partNumber,\n chunkSize,\n abortController: options.abortController,\n onUploadProgress: (e) => {\n partsUploaded[partNumber] = e.loaded;\n\n const uploaded = Object.values(partsUploaded).reduce((sum, a) => sum + a, 0);\n\n this.updateProgress(uploaded, file.size, options);\n }\n }\n );\n\n uploadedBytes += blob.size;\n\n // Use parts progress, ignore the overall progress, which may be inaccurate due to retries or concurrency\n // this.updateProgress(uploadedBytes, file.size, options);\n\n parts.push({ ETag: etag, PartNumber: partNumber });\n });\n\n promises.push(p);\n\n currentPart++;\n }\n\n await Promise.all(promises);\n\n if (isCancel) {\n const e = new Error('Upload cancelled');\n e.name = 'CanceledError';\n\n throw e;\n }\n\n // @Request complete\n const { url } = await this.request<{ url: string }>(\n 'complete',\n {\n id,\n path,\n parts: parts.sort((a, b) => a.PartNumber - b.PartNumber),\n profile: this.options.profile,\n },\n );\n\n this.trigger('success', { id, path, url });\n\n return { url, id, path };\n } catch (e) {\n if (uploadId) {\n await this.abort(uploadId, path);\n }\n\n this.trigger('failure', { error: e as Error, uploadId, path });\n\n throw e;\n } finally {\n if (this.options.leaveAlert === true) {\n window.removeEventListener('beforeunload', beforeUnloadHandler);\n }\n }\n }\n\n protected async uploadPart(\n file: File,\n payload: {\n id: string;\n path: string;\n partNumber: number;\n chunkSize: number;\n abortController?: AbortController;\n onUploadProgress: (e: AxiosProgressEvent) => void;\n }\n ) {\n const http = await useHttpClient();\n const { id, path, partNumber, chunkSize, onUploadProgress } = payload;\n\n const start = (partNumber - 1) * chunkSize;\n const end = Math.min(partNumber * chunkSize, file.size);\n\n const blob = file.slice(start, end);\n\n // @Request sign\n const { url } = await this.request<{ url: string; }>(\n 'sign',\n {\n id,\n path,\n partNumber,\n profile: this.options.profile,\n },\n {\n signal: payload.abortController?.signal,\n }\n );\n\n // PUT to S3\n const res = await http.put(\n url,\n blob,\n {\n onUploadProgress,\n }\n );\n\n const etag = String((res.headers as AxiosResponseHeaders).get('ETag') || '');\n\n return { blob, etag };\n }\n\n protected async request<T = Record<string, any>>(\n action: RouteActions,\n body: Record<string, any>,\n config: Partial<AxiosRequestConfig> = {}\n ): Promise<T> {\n if (this.options.requestHandler) {\n return this.options.requestHandler<T>(action, body);\n }\n\n const http = await useHttpClient();\n\n const res = await http.post<ApiReturn<T>>(await this.resolveRoute(action), body, config);\n\n return res.data.data;\n }\n\n // protected async abortBeacon(id: string, path: string): Promise<void> {\n // const data = new FormData();\n // data.append('id', id);\n // data.append('path', path);\n // data.append('profile', this.options.profile || '');\n //\n // await navigator.sendBeacon(route(await this.resolveRoute('abort')), data);\n // }\n\n async abort(id: string, path: string) {\n await this.request(\n 'abort',\n {\n id,\n path,\n profile: this.options.profile,\n }\n );\n }\n\n updateProgress(loaded: number, total: number, options: S3MultipartUploaderRequestOptions) {\n const percentage = (loaded / total) * 100;\n\n const event: ProgressEvent = { percentage, loaded, total };\n\n this.trigger('progress', event);\n\n this.options.onProgress?.(event);\n\n if (options.onProgress) {\n options.onProgress(event);\n }\n }\n\n async resolveRoute(action: RouteActions): Promise<string> {\n if (typeof this.options.routes === 'function') {\n return this.options.routes(action);\n }\n\n return this.options.routes[action];\n }\n\n setChunkSize(size: number): this {\n this.options.chunkSize = size;\n\n return this;\n }\n\n setChunkSizeInMiB(size: number): this {\n this.options.chunkSize = size * 1024 * 1024;\n\n return this;\n }\n\n replaceExt(path: string, file: File | Blob): string {\n if (file instanceof File) {\n const fileExt = file.name.split('.').pop();\n\n if (path.endsWith('.{ext}')) {\n return path.replace(/\\.{ext}$/, fileExt ? '.' + fileExt : '');\n }\n }\n\n return path;\n }\n\n on(\n event: 'start',\n handler: (file: File, data: { path: string; extra: Record<string, any>; [name: string]: any; }) => void\n ): this;\n on(event: 'inited', handler: (event: { id: string; path: string; }) => void): this;\n on(event: 'success', handler: (event: { url: string; id: string; path: string; }) => void): this;\n on(event: 'progress', handler: (event: ProgressEvent) => void): this;\n on(event: 'failure', handler: (event: { error: Error; id: string; path: string; }) => void): this;\n on(event: string | string[], handler: EventHandler): this {\n return super.on(event, handler);\n }\n}\n\ntype ProgressEvent = {\n percentage: number;\n loaded: number;\n total: number;\n};\ntype ProgressEventHandler = (e: ProgressEvent) => void;\n\nexport interface S3MultipartUploaderModule {\n S3MultipartUploader: typeof S3MultipartUploader;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"s3-multipart-uploader.js","names":[],"sources":["../../src/module/s3-multipart-uploader.ts"],"sourcesContent":["import { AxiosProgressEvent, type AxiosRequestConfig, AxiosResponseHeaders } from 'axios';\nimport { Mixin } from 'ts-mixer';\nimport { createQueue, useHttpClient } from '../composable';\nimport { EventHandler, EventMixin } from '../events';\nimport type { MaybePromise } from '../types';\nimport { mergeDeep } from '../utilities';\nimport { ApiReturn } from './http-client';\n\ndeclare type RoutingOptions = {\n init: string;\n sign: string;\n complete: string;\n abort: string;\n} | ((action: RouteActions) => MaybePromise<string>);\n\ndeclare type RouteActions = 'init' | 'sign' | 'complete' | 'abort';\ndeclare type RequestHandler = <T = Record<string, any>>(action: RouteActions, data: Record<string, any>) => Promise<T>;\n\nexport interface S3MultipartUploaderOptions {\n profile?: string;\n chunkSize: number;\n concurrency: number;\n leaveAlert?: boolean;\n routes: RoutingOptions;\n requestHandler?: RequestHandler;\n onProgress?: ProgressEventHandler;\n ACL?: string;\n extra?: Record<string, any>;\n\n // maxRetries?: number;\n // endpoint: string;\n // subfolder?: string;\n}\n\nconst defaultOptions: Partial<S3MultipartUploaderOptions> = {\n chunkSize: 5 * 1024 * 1024, // 5MB\n concurrency: 2,\n};\n\nexport interface S3MultipartUploaderRequestOptions {\n onProgress?: ProgressEventHandler;\n filename?: string;\n ContentType?: string;\n ContentDisposition?: string;\n ACL?: 'public-read' | 'private' | 'authenticated-read' | 'public-read-write' | string;\n extra?: Record<string, any>;\n abortController?: AbortController;\n}\n\nexport class S3MultipartUploader extends Mixin(EventMixin) {\n options: S3MultipartUploaderOptions;\n\n constructor(options: Partial<S3MultipartUploaderOptions>) {\n super();\n this.options = mergeDeep({}, defaultOptions, options);\n }\n\n async upload(\n file: string | File | Blob,\n path: string,\n options: S3MultipartUploaderRequestOptions = {}\n ): Promise<{ url: string; id: string; path: string; }> {\n const extra: Record<string, any> = { ...(this.options.extra ?? {}), ...(options.extra ?? {}) };\n\n if (typeof file === 'string') {\n file = new Blob([file], { type: options['ContentType'] || 'text/plain' });\n }\n\n if (file instanceof Blob && !(file instanceof File)) {\n if (path.endsWith('.{ext}')) {\n throw new Error('If using Blob or file data string, you must provide a valid file extension in the path.');\n }\n\n file = new File([file], 'blob', { type: file.type });\n }\n\n if (file instanceof File) {\n extra['ContentType'] = options['ContentType'] || file.type;\n }\n\n if (options.ACL || this.options.ACL) {\n extra.ACL = options.ACL || this.options.ACL;\n }\n\n path = this.replaceExt(path, file);\n\n const initData: Record<string, any> = { extra, path, profile: this.options.profile };\n\n if (options['filename']) {\n initData['filename'] = options['filename'];\n }\n\n this.trigger('start', file, initData);\n\n // Prepare unload\n const beforeUnloadHandler = (e: BeforeUnloadEvent) => {\n e.preventDefault();\n e.returnValue = '';\n };\n\n if (this.options.leaveAlert === true) {\n window.addEventListener('beforeunload', beforeUnloadHandler);\n }\n\n let uploadId: string | null = null;\n let isCancel = false;\n let signal = options.abortController?.signal;\n\n if (signal) {\n signal.addEventListener('abort', (e) => {\n isCancel = true;\n });\n }\n\n try {\n // @Request init\n const { id } = await this.request<{ id: string; }>(\n 'init',\n initData\n );\n\n uploadId = id;\n\n this.trigger('inited', { id, path });\n\n const chunkSize = this.options.chunkSize;\n const chunks = Math.ceil(file.size / chunkSize);\n\n let uploadedBytes = 0;\n let parts: { ETag: string, PartNumber: number }[] = [];\n let currentPart = 1;\n const queue = createQueue(this.options.concurrency);\n const promises = [];\n const partsUploaded: Record<number, number> = {};\n\n // Loop from 1 to chunks\n while (currentPart <= chunks) {\n const partNumber = currentPart;\n\n // Push to queue\n const p = queue.push(async () => {\n const { blob, etag } = await this.uploadPart(\n file as File,\n {\n id,\n path,\n partNumber,\n chunkSize,\n abortController: options.abortController,\n onUploadProgress: (e) => {\n partsUploaded[partNumber] = e.loaded;\n\n const uploaded = Object.values(partsUploaded).reduce((sum, a) => sum + a, 0);\n\n this.updateProgress(uploaded, file.size, options);\n }\n }\n );\n\n uploadedBytes += blob.size;\n\n // Use parts progress, ignore the overall progress, which may be inaccurate due to retries or concurrency\n // this.updateProgress(uploadedBytes, file.size, options);\n\n parts.push({ ETag: etag, PartNumber: partNumber });\n });\n\n promises.push(p);\n\n currentPart++;\n }\n\n await Promise.all(promises);\n\n if (isCancel) {\n const e = new Error('Upload cancelled');\n e.name = 'CanceledError';\n\n throw e;\n }\n\n // @Request complete\n const { url } = await this.request<{ url: string }>(\n 'complete',\n {\n id,\n path,\n parts: parts.sort((a, b) => a.PartNumber - b.PartNumber),\n profile: this.options.profile,\n },\n );\n\n this.trigger('success', { id, path, url });\n\n return { url, id, path };\n } catch (e) {\n if (uploadId) {\n await this.abort(uploadId, path);\n }\n\n this.trigger('failure', { error: e as Error, uploadId, path });\n\n throw e;\n } finally {\n if (this.options.leaveAlert === true) {\n window.removeEventListener('beforeunload', beforeUnloadHandler);\n }\n }\n }\n\n protected async uploadPart(\n file: File,\n payload: {\n id: string;\n path: string;\n partNumber: number;\n chunkSize: number;\n abortController?: AbortController;\n onUploadProgress: (e: AxiosProgressEvent) => void;\n }\n ) {\n const http = await useHttpClient();\n const { id, path, partNumber, chunkSize, onUploadProgress } = payload;\n\n const start = (partNumber - 1) * chunkSize;\n const end = Math.min(partNumber * chunkSize, file.size);\n\n const blob = file.slice(start, end);\n\n // @Request sign\n const { url } = await this.request<{ url: string; }>(\n 'sign',\n {\n id,\n path,\n partNumber,\n profile: this.options.profile,\n },\n {\n signal: payload.abortController?.signal,\n }\n );\n\n // PUT to S3\n const res = await http.put(\n url,\n blob,\n {\n onUploadProgress,\n }\n );\n\n const etag = String((res.headers as AxiosResponseHeaders).get('ETag') || '');\n\n return { blob, etag };\n }\n\n protected async request<T = Record<string, any>>(\n action: RouteActions,\n body: Record<string, any>,\n config: Partial<AxiosRequestConfig> = {}\n ): Promise<T> {\n if (this.options.requestHandler) {\n return this.options.requestHandler<T>(action, body);\n }\n\n const http = await useHttpClient();\n\n const res = await http.post<ApiReturn<T>>(await this.resolveRoute(action), body, config);\n\n return res.data.data;\n }\n\n // protected async abortBeacon(id: string, path: string): Promise<void> {\n // const data = new FormData();\n // data.append('id', id);\n // data.append('path', path);\n // data.append('profile', this.options.profile || '');\n //\n // await navigator.sendBeacon(route(await this.resolveRoute('abort')), data);\n // }\n\n async abort(id: string, path: string) {\n await this.request(\n 'abort',\n {\n id,\n path,\n profile: this.options.profile,\n }\n );\n }\n\n updateProgress(loaded: number, total: number, options: S3MultipartUploaderRequestOptions) {\n const percentage = (loaded / total) * 100;\n\n const event: ProgressEvent = { percentage, loaded, total };\n\n this.trigger('progress', event);\n\n this.options.onProgress?.(event);\n\n if (options.onProgress) {\n options.onProgress(event);\n }\n }\n\n async resolveRoute(action: RouteActions): Promise<string> {\n if (typeof this.options.routes === 'function') {\n return this.options.routes(action);\n }\n\n return this.options.routes[action];\n }\n\n setChunkSize(size: number): this {\n this.options.chunkSize = size;\n\n return this;\n }\n\n setChunkSizeInMiB(size: number): this {\n this.options.chunkSize = size * 1024 * 1024;\n\n return this;\n }\n\n replaceExt(path: string, file: File | Blob): string {\n if (file instanceof File) {\n const fileExt = file.name.split('.').pop();\n\n if (path.endsWith('.{ext}')) {\n return path.replace(/\\.{ext}$/, fileExt ? '.' + fileExt : '');\n }\n }\n\n return path;\n }\n\n on(\n event: 'start',\n handler: (file: File, data: { path: string; extra: Record<string, any>; [name: string]: any; }) => void\n ): this;\n on(event: 'inited', handler: (event: { id: string; path: string; }) => void): this;\n on(event: 'success', handler: (event: { url: string; id: string; path: string; }) => void): this;\n on(event: 'progress', handler: (event: ProgressEvent) => void): this;\n on(event: 'failure', handler: (event: { error: Error; id: string; path: string; }) => void): this;\n on(event: string | string[], handler: EventHandler): this {\n return super.on(event, handler);\n }\n}\n\ntype ProgressEvent = {\n percentage: number;\n loaded: number;\n total: number;\n};\ntype ProgressEventHandler = (e: ProgressEvent) => void;\n\nexport interface S3MultipartUploaderModule {\n S3MultipartUploader: typeof S3MultipartUploader;\n}\n"],"mappings":"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"}
|