partial-uploader 0.0.6 → 0.0.8

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/index.d.ts CHANGED
@@ -1,6 +1,14 @@
1
- declare const uploadWithPartialFile: (url: string, file: any, headers?: any, chunkSize?: number) => Promise<{
1
+ type RefreshResult = {
2
+ headers?: any;
3
+ url?: string;
4
+ };
5
+ type UnauthorizedCallback = (error: Response) => Promise<RefreshResult | null>;
6
+ declare const uploadWithPartialFile: (url: string, file: any, headers?: any, chunkSize?: number, delay_number?: number, concurrency?: number, onUnauthorized?: UnauthorizedCallback) => Promise<{
2
7
  success: boolean;
3
- id: string;
4
8
  message: string;
9
+ statusCode: number;
10
+ data?: {
11
+ id: string;
12
+ };
5
13
  }>;
6
14
  export { uploadWithPartialFile };
package/dist/index.js CHANGED
@@ -1,4 +1,15 @@
1
1
  "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
2
13
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
14
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
15
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -8,85 +19,188 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
19
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
20
  });
10
21
  };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
11
49
  Object.defineProperty(exports, "__esModule", { value: true });
12
50
  exports.uploadWithPartialFile = void 0;
13
- const uploadWithPartialFile = (url, file, headers, chunkSize = 26214400) => __awaiter(void 0, void 0, void 0, function* () {
14
- yield delay(50);
15
- const id = generateGuid();
16
- if (file.size <= chunkSize) {
17
- // small file
18
- let res = yield upload(url, file, 1, file.size, file.name, id, 0, headers);
19
- if (!res)
20
- return { success: false, id, message: "file could not be loaded" };
21
- }
22
- else {
23
- // big file
24
- const chunks = splitFileIntoChunks(file, chunkSize);
25
- for (let i = 0; i < chunks.length; i++) {
26
- let chunk = chunks[i];
27
- if (!chunk)
28
- return { success: false, id, message: "chunk is undefined" };
29
- let res = yield upload(url, chunk, chunks.length, file.size, file.name, id, i, headers);
30
- if (!res)
31
- return { success: false, id, message: "file could not be loaded" };
32
- yield delay(550);
33
- }
34
- ;
35
- }
36
- ;
37
- return { success: true, id, message: "file uploaded successfully" };
38
- });
39
- exports.uploadWithPartialFile = uploadWithPartialFile;
40
- const upload = (url, chunk, chunksLength, fileSize, filename, fileGuid, index, headers) => __awaiter(void 0, void 0, void 0, function* () {
41
- let formData = new FormData();
42
- formData.append('file', chunk, `${filename}_chunk_${index}`);
43
- formData.append('fileGuid', fileGuid);
44
- let isDone = chunksLength === index + 1;
45
- formData.append('isDone', isDone.toString());
46
- formData.append('totalSize', fileSize.toString());
47
- formData.append('totalChunks', chunksLength.toString());
48
- formData.append('filename', filename);
49
- formData.append('index', index.toString());
50
- return getRes(url, formData, headers);
51
- });
52
- const getRes = (url, formData, headers) => __awaiter(void 0, void 0, void 0, function* () {
53
- try {
54
- let res = yield uploadSubscribe(url, formData, headers);
55
- if (res.status === 406 || res.status === 401)
56
- return false;
57
- }
58
- catch (e) {
59
- yield delay(500);
60
- let res = yield uploadSubscribe(url, formData, headers);
61
- if (!res.ok)
62
- return false;
63
- }
64
- ;
65
- return true;
66
- });
67
- const delay = (ms) => __awaiter(void 0, void 0, void 0, function* () {
68
- yield new Promise(f => setTimeout(f, ms));
69
- });
70
- const uploadSubscribe = (url, formData, headers) => __awaiter(void 0, void 0, void 0, function* () { return (yield fetch(url, { method: 'POST', body: formData, headers: headers ? headers : {} })); });
71
- const splitFileIntoChunks = (file, chunkSize) => {
72
- const chunks = [];
73
- let start = 0;
74
- while (start < file.size) {
75
- const end = Math.min(start + chunkSize, file.size);
76
- const chunk = file.slice(start, end);
77
- chunks.push(chunk);
78
- start = end;
79
- }
80
- ;
81
- return chunks;
51
+ var uploadWithPartialFile = function (url, file, headers, chunkSize, delay_number, concurrency, onUnauthorized) {
52
+ if (headers === void 0) { headers = {}; }
53
+ if (chunkSize === void 0) { chunkSize = 26214400; }
54
+ if (delay_number === void 0) { delay_number = 50; }
55
+ if (concurrency === void 0) { concurrency = 1; }
56
+ return __awaiter(void 0, void 0, void 0, function () {
57
+ var sharedContext, id, fileName, totalSize, totalChunks, lastStatusCode, uploadChunk, queue_1, workers, e_1;
58
+ return __generator(this, function (_a) {
59
+ switch (_a.label) {
60
+ case 0:
61
+ sharedContext = {
62
+ url: url,
63
+ headers: __assign({}, headers)
64
+ };
65
+ return [4 /*yield*/, delay(delay_number)];
66
+ case 1:
67
+ _a.sent();
68
+ id = generateGuid();
69
+ fileName = file.name || 'file';
70
+ totalSize = file.size;
71
+ totalChunks = Math.ceil(totalSize / chunkSize) || 1;
72
+ lastStatusCode = 200;
73
+ uploadChunk = function (index) { return __awaiter(void 0, void 0, void 0, function () {
74
+ var start, end, chunk, retry, formData, res, refreshData, e_2;
75
+ return __generator(this, function (_a) {
76
+ switch (_a.label) {
77
+ case 0:
78
+ start = index * chunkSize;
79
+ end = Math.min(start + chunkSize, totalSize);
80
+ chunk = file.slice(start, end);
81
+ retry = 0;
82
+ _a.label = 1;
83
+ case 1:
84
+ if (!(retry < 3)) return [3 /*break*/, 9];
85
+ _a.label = 2;
86
+ case 2:
87
+ _a.trys.push([2, 6, , 8]);
88
+ formData = new FormData();
89
+ formData.append('file', chunk, "".concat(fileName, "_chunk_").concat(index));
90
+ formData.append('fileGuid', id);
91
+ formData.append('isDone', (index === totalChunks - 1).toString());
92
+ formData.append('totalSize', totalSize.toString());
93
+ formData.append('totalChunks', totalChunks.toString());
94
+ formData.append('filename', fileName);
95
+ formData.append('index', index.toString());
96
+ return [4 /*yield*/, fetch(sharedContext.url, {
97
+ method: 'POST',
98
+ body: formData,
99
+ headers: sharedContext.headers
100
+ })];
101
+ case 3:
102
+ res = _a.sent();
103
+ lastStatusCode = res.status;
104
+ if (!(res.status === 401 && onUnauthorized)) return [3 /*break*/, 5];
105
+ return [4 /*yield*/, onUnauthorized(res)];
106
+ case 4:
107
+ refreshData = _a.sent();
108
+ if (refreshData) {
109
+ if (refreshData.headers) {
110
+ sharedContext.headers = __assign(__assign({}, sharedContext.headers), refreshData.headers);
111
+ }
112
+ if (refreshData.url) {
113
+ sharedContext.url = refreshData.url;
114
+ }
115
+ // Token yenilendi, bu retry hakkından düşmeden aynı parçayı tekrar dene
116
+ retry--;
117
+ return [3 /*break*/, 8];
118
+ }
119
+ _a.label = 5;
120
+ case 5:
121
+ if (res.ok)
122
+ return [2 /*return*/, true];
123
+ // Diğer hatalarda (500 vb.) retry devam etsin
124
+ if (retry === 2)
125
+ throw new Error("Server error: ".concat(res.status));
126
+ return [3 /*break*/, 8];
127
+ case 6:
128
+ e_2 = _a.sent();
129
+ if (retry === 2)
130
+ throw e_2;
131
+ // Ağ hatalarında bekleme süresini artır
132
+ return [4 /*yield*/, delay(delay_number + (retry + 1) * 1000)];
133
+ case 7:
134
+ // Ağ hatalarında bekleme süresini artır
135
+ _a.sent();
136
+ return [3 /*break*/, 8];
137
+ case 8:
138
+ retry++;
139
+ return [3 /*break*/, 1];
140
+ case 9: return [2 /*return*/, false];
141
+ }
142
+ });
143
+ }); };
144
+ _a.label = 2;
145
+ case 2:
146
+ _a.trys.push([2, 4, , 5]);
147
+ queue_1 = Array.from({ length: totalChunks }, function (_, i) { return i; });
148
+ workers = Array(Math.min(concurrency, totalChunks)).fill(null).map(function () { return __awaiter(void 0, void 0, void 0, function () {
149
+ var index, success;
150
+ return __generator(this, function (_a) {
151
+ switch (_a.label) {
152
+ case 0:
153
+ if (!(queue_1.length > 0)) return [3 /*break*/, 4];
154
+ index = queue_1.shift();
155
+ return [4 /*yield*/, uploadChunk(index)];
156
+ case 1:
157
+ success = _a.sent();
158
+ if (!success)
159
+ throw new Error("file could not be loaded");
160
+ if (!(delay_number > 0)) return [3 /*break*/, 3];
161
+ return [4 /*yield*/, delay(delay_number)];
162
+ case 2:
163
+ _a.sent();
164
+ _a.label = 3;
165
+ case 3: return [3 /*break*/, 0];
166
+ case 4: return [2 /*return*/];
167
+ }
168
+ });
169
+ }); });
170
+ return [4 /*yield*/, Promise.all(workers)];
171
+ case 3:
172
+ _a.sent();
173
+ return [2 /*return*/, {
174
+ success: true,
175
+ message: "file uploaded successfully",
176
+ statusCode: lastStatusCode,
177
+ data: {
178
+ id: id
179
+ }
180
+ }];
181
+ case 4:
182
+ e_1 = _a.sent();
183
+ return [2 /*return*/, {
184
+ success: false,
185
+ message: e_1.message || "file could not be loaded",
186
+ statusCode: lastStatusCode,
187
+ data: {
188
+ id: id
189
+ }
190
+ }];
191
+ case 5: return [2 /*return*/];
192
+ }
193
+ });
194
+ });
82
195
  };
83
- const generateGuid = () => {
196
+ exports.uploadWithPartialFile = uploadWithPartialFile;
197
+ var delay = function (ms) { return new Promise(function (f) { return setTimeout(f, ms); }); };
198
+ var generateGuid = function () {
84
199
  var chars = '0123456789abcdef';
85
200
  var guid = '';
86
201
  for (var i = 0; i < 40; i++) {
87
202
  var randomIndex = Math.floor(Math.random() * chars.length);
88
203
  guid += chars.charAt(randomIndex);
89
204
  }
90
- ;
91
205
  return guid;
92
206
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ var vitest_1 = require("vitest");
40
+ var index_1 = require("./index");
41
+ // @vitest-environment happy-dom
42
+ (0, vitest_1.describe)('uploadWithPartialFile', function () {
43
+ var mockUrl = 'https://api.example.com/upload';
44
+ var mockFile = new File(['hello world'], 'test.txt', { type: 'text/plain' });
45
+ (0, vitest_1.beforeEach)(function () {
46
+ vitest_1.vi.stubGlobal('fetch', vitest_1.vi.fn());
47
+ vitest_1.vi.useFakeTimers();
48
+ });
49
+ (0, vitest_1.it)('should upload a small file in a single chunk successfully', function () { return __awaiter(void 0, void 0, void 0, function () {
50
+ var resultPromise, result, formData;
51
+ var _a, _b;
52
+ return __generator(this, function (_c) {
53
+ switch (_c.label) {
54
+ case 0:
55
+ fetch.mockResolvedValue({
56
+ ok: true,
57
+ status: 200
58
+ });
59
+ resultPromise = (0, index_1.uploadWithPartialFile)(mockUrl, mockFile, {}, 1024, 0);
60
+ // Fast-forward any delays
61
+ return [4 /*yield*/, vitest_1.vi.runAllTimersAsync()];
62
+ case 1:
63
+ // Fast-forward any delays
64
+ _c.sent();
65
+ return [4 /*yield*/, resultPromise];
66
+ case 2:
67
+ result = _c.sent();
68
+ (0, vitest_1.expect)(result.success).toBe(true);
69
+ (0, vitest_1.expect)(result.statusCode).toBe(200);
70
+ (0, vitest_1.expect)((_a = result.data) === null || _a === void 0 ? void 0 : _a.id).toBeDefined();
71
+ (0, vitest_1.expect)(fetch).toHaveBeenCalledTimes(1);
72
+ formData = (_b = vitest_1.vi.mocked(fetch).mock.calls[0][1]) === null || _b === void 0 ? void 0 : _b.body;
73
+ (0, vitest_1.expect)(formData.get('isDone')).toBe('true');
74
+ (0, vitest_1.expect)(formData.get('totalChunks')).toBe('1');
75
+ return [2 /*return*/];
76
+ }
77
+ });
78
+ }); });
79
+ (0, vitest_1.it)('should upload a large file in multiple chunks', function () { return __awaiter(void 0, void 0, void 0, function () {
80
+ var largeFile, resultPromise, result;
81
+ var _a;
82
+ return __generator(this, function (_b) {
83
+ switch (_b.label) {
84
+ case 0:
85
+ fetch.mockResolvedValue({
86
+ ok: true,
87
+ status: 200
88
+ });
89
+ largeFile = new File(['0123456789a'], 'large.txt');
90
+ resultPromise = (0, index_1.uploadWithPartialFile)(mockUrl, largeFile, {}, 5, 0, 1);
91
+ return [4 /*yield*/, vitest_1.vi.runAllTimersAsync()];
92
+ case 1:
93
+ _b.sent();
94
+ return [4 /*yield*/, resultPromise];
95
+ case 2:
96
+ result = _b.sent();
97
+ (0, vitest_1.expect)(result.success).toBe(true);
98
+ (0, vitest_1.expect)(result.statusCode).toBe(200);
99
+ (0, vitest_1.expect)((_a = result.data) === null || _a === void 0 ? void 0 : _a.id).toBeDefined();
100
+ (0, vitest_1.expect)(fetch).toHaveBeenCalledTimes(3);
101
+ return [2 /*return*/];
102
+ }
103
+ });
104
+ }); });
105
+ (0, vitest_1.it)('should retry on network error and succeed', function () { return __awaiter(void 0, void 0, void 0, function () {
106
+ var resultPromise, result;
107
+ var _a;
108
+ return __generator(this, function (_b) {
109
+ switch (_b.label) {
110
+ case 0:
111
+ fetch
112
+ .mockRejectedValueOnce(new Error('Network error'))
113
+ .mockResolvedValueOnce({ ok: true, status: 200 });
114
+ resultPromise = (0, index_1.uploadWithPartialFile)(mockUrl, mockFile, {}, 1024, 10);
115
+ // First attempt fails, wait for delay
116
+ return [4 /*yield*/, vitest_1.vi.runAllTimersAsync()];
117
+ case 1:
118
+ // First attempt fails, wait for delay
119
+ _b.sent();
120
+ return [4 /*yield*/, resultPromise];
121
+ case 2:
122
+ result = _b.sent();
123
+ (0, vitest_1.expect)(result.success).toBe(true);
124
+ (0, vitest_1.expect)(result.statusCode).toBe(200);
125
+ (0, vitest_1.expect)((_a = result.data) === null || _a === void 0 ? void 0 : _a.id).toBeDefined();
126
+ (0, vitest_1.expect)(fetch).toHaveBeenCalledTimes(2);
127
+ return [2 /*return*/];
128
+ }
129
+ });
130
+ }); });
131
+ (0, vitest_1.it)('should refresh token on 401 and retry successfully', function () { return __awaiter(void 0, void 0, void 0, function () {
132
+ var onUnauthorized, resultPromise, result, secondCallHeaders;
133
+ var _a, _b;
134
+ return __generator(this, function (_c) {
135
+ switch (_c.label) {
136
+ case 0:
137
+ fetch
138
+ .mockResolvedValueOnce({ ok: false, status: 401 }) // First attempt: 401
139
+ .mockResolvedValueOnce({ ok: true, status: 200 }); // Second attempt: Success
140
+ onUnauthorized = vitest_1.vi.fn().mockResolvedValue({
141
+ headers: { 'Authorization': 'Bearer new-token' }
142
+ });
143
+ resultPromise = (0, index_1.uploadWithPartialFile)(mockUrl, mockFile, { 'Authorization': 'Bearer old' }, 1024, 0, 1, onUnauthorized);
144
+ return [4 /*yield*/, vitest_1.vi.runAllTimersAsync()];
145
+ case 1:
146
+ _c.sent();
147
+ return [4 /*yield*/, resultPromise];
148
+ case 2:
149
+ result = _c.sent();
150
+ (0, vitest_1.expect)(onUnauthorized).toHaveBeenCalled();
151
+ (0, vitest_1.expect)(result.success).toBe(true);
152
+ (0, vitest_1.expect)(result.statusCode).toBe(200);
153
+ (0, vitest_1.expect)((_a = result.data) === null || _a === void 0 ? void 0 : _a.id).toBeDefined();
154
+ (0, vitest_1.expect)(fetch).toHaveBeenCalledTimes(2);
155
+ secondCallHeaders = (_b = vitest_1.vi.mocked(fetch).mock.calls[1][1]) === null || _b === void 0 ? void 0 : _b.headers;
156
+ (0, vitest_1.expect)(secondCallHeaders['Authorization']).toBe('Bearer new-token');
157
+ return [2 /*return*/];
158
+ }
159
+ });
160
+ }); });
161
+ (0, vitest_1.it)('should fail after maximum retries', function () { return __awaiter(void 0, void 0, void 0, function () {
162
+ var resultPromise, result;
163
+ var _a;
164
+ return __generator(this, function (_b) {
165
+ switch (_b.label) {
166
+ case 0:
167
+ fetch.mockRejectedValue(new Error('Persistent error'));
168
+ resultPromise = (0, index_1.uploadWithPartialFile)(mockUrl, mockFile, {}, 1024, 0);
169
+ return [4 /*yield*/, vitest_1.vi.runAllTimersAsync()];
170
+ case 1:
171
+ _b.sent();
172
+ return [4 /*yield*/, resultPromise];
173
+ case 2:
174
+ result = _b.sent();
175
+ (0, vitest_1.expect)(result.success).toBe(false);
176
+ (0, vitest_1.expect)(result.statusCode).toBe(200); // defaults to 200 if fetch throws before any response
177
+ (0, vitest_1.expect)((_a = result.data) === null || _a === void 0 ? void 0 : _a.id).toBeDefined();
178
+ (0, vitest_1.expect)(fetch).toHaveBeenCalledTimes(3); // Retry limit is 3 in code
179
+ return [2 /*return*/];
180
+ }
181
+ });
182
+ }); });
183
+ (0, vitest_1.it)('should handle concurrency correctly', function () { return __awaiter(void 0, void 0, void 0, function () {
184
+ var largeFile, resultPromise, result;
185
+ var _a;
186
+ return __generator(this, function (_b) {
187
+ switch (_b.label) {
188
+ case 0:
189
+ fetch.mockResolvedValue({ ok: true, status: 200 });
190
+ largeFile = new File(['a'.repeat(100)], 'concurrency.txt');
191
+ resultPromise = (0, index_1.uploadWithPartialFile)(mockUrl, largeFile, {}, 10, 0, 5);
192
+ return [4 /*yield*/, vitest_1.vi.runAllTimersAsync()];
193
+ case 1:
194
+ _b.sent();
195
+ return [4 /*yield*/, resultPromise];
196
+ case 2:
197
+ result = _b.sent();
198
+ (0, vitest_1.expect)(result.success).toBe(true);
199
+ (0, vitest_1.expect)(result.statusCode).toBe(200);
200
+ (0, vitest_1.expect)((_a = result.data) === null || _a === void 0 ? void 0 : _a.id).toBeDefined();
201
+ (0, vitest_1.expect)(fetch).toHaveBeenCalledTimes(10);
202
+ return [2 /*return*/];
203
+ }
204
+ });
205
+ }); });
206
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "partial-uploader",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -8,7 +8,8 @@
8
8
  "/dist"
9
9
  ],
10
10
  "scripts": {
11
- "build": "tsc src/index.ts"
11
+ "build": "tsc src/index.ts",
12
+ "test": "vitest run"
12
13
  },
13
14
  "author": "Yusuf Unal <theunal9@gmail.com> (https://github.com/theunal)",
14
15
  "license": "MIT",
@@ -23,6 +24,8 @@
23
24
  "upload"
24
25
  ],
25
26
  "devDependencies": {
26
- "typescript": "^5.1.3"
27
+ "happy-dom": "^20.3.4",
28
+ "typescript": "^5.1.3",
29
+ "vitest": "^4.0.17"
27
30
  }
28
31
  }