@heyputer/puter.js 2.1.4 → 2.1.7

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.
Files changed (57) hide show
  1. package/dist/puter.cjs +2 -2
  2. package/index.d.ts +41 -15
  3. package/package.json +1 -1
  4. package/src/index.js +116 -79
  5. package/src/lib/APICallLogger.js +20 -21
  6. package/src/lib/EventListener.js +10 -10
  7. package/src/lib/filesystem/APIFS.js +11 -19
  8. package/src/lib/filesystem/CacheFS.js +25 -25
  9. package/src/lib/filesystem/PostMessageFS.js +11 -11
  10. package/src/lib/filesystem/definitions.js +11 -10
  11. package/src/lib/path.js +505 -446
  12. package/src/lib/polyfills/fileReaderPoly.js +40 -0
  13. package/src/lib/polyfills/localStorage.js +30 -33
  14. package/src/lib/polyfills/xhrshim.js +206 -207
  15. package/src/lib/utils.js +160 -151
  16. package/src/lib/xdrpc.js +9 -9
  17. package/src/modules/AI.js +473 -292
  18. package/src/modules/Apps.js +56 -56
  19. package/src/modules/Auth.js +17 -17
  20. package/src/modules/Debug.js +1 -1
  21. package/src/modules/Drivers.js +41 -41
  22. package/src/modules/FSItem.js +64 -62
  23. package/src/modules/FileSystem/index.js +22 -23
  24. package/src/modules/FileSystem/operations/copy.js +7 -7
  25. package/src/modules/FileSystem/operations/deleteFSEntry.js +14 -12
  26. package/src/modules/FileSystem/operations/getReadUrl.js +16 -14
  27. package/src/modules/FileSystem/operations/mkdir.js +11 -11
  28. package/src/modules/FileSystem/operations/move.js +12 -12
  29. package/src/modules/FileSystem/operations/read.js +10 -10
  30. package/src/modules/FileSystem/operations/readdir.js +28 -28
  31. package/src/modules/FileSystem/operations/rename.js +11 -11
  32. package/src/modules/FileSystem/operations/sign.js +33 -30
  33. package/src/modules/FileSystem/operations/space.js +7 -7
  34. package/src/modules/FileSystem/operations/stat.js +25 -25
  35. package/src/modules/FileSystem/operations/symlink.js +15 -17
  36. package/src/modules/FileSystem/operations/upload.js +151 -122
  37. package/src/modules/FileSystem/operations/write.js +16 -12
  38. package/src/modules/FileSystem/utils/getAbsolutePathForApp.js +10 -6
  39. package/src/modules/Hosting.js +29 -29
  40. package/src/modules/KV.js +23 -23
  41. package/src/modules/OS.js +15 -15
  42. package/src/modules/Perms.js +19 -21
  43. package/src/modules/PuterDialog.js +46 -48
  44. package/src/modules/Threads.js +17 -20
  45. package/src/modules/UI.js +156 -156
  46. package/src/modules/Util.js +3 -3
  47. package/src/modules/Workers.js +52 -49
  48. package/src/modules/networking/PSocket.js +38 -38
  49. package/src/modules/networking/PTLS.js +54 -47
  50. package/src/modules/networking/PWispHandler.js +49 -47
  51. package/src/modules/networking/parsers.js +110 -108
  52. package/src/modules/networking/requests.js +67 -78
  53. package/src/services/APIAccess.js +9 -9
  54. package/src/services/FSRelay.js +6 -6
  55. package/src/services/Filesystem.js +8 -8
  56. package/src/services/NoPuterYet.js +2 -2
  57. package/src/services/XDIncoming.js +1 -1
@@ -0,0 +1,40 @@
1
+ function toBase64FromBuffer(buffer) {
2
+ const bytes = new Uint8Array(buffer);
3
+ // use the requested reduce logic
4
+ const binary = bytes.reduce((data, byte) => data + String.fromCharCode(byte), '');
5
+ return typeof btoa === 'function' ? btoa(binary) : Buffer.from(binary, 'binary').toString('base64');
6
+ }
7
+
8
+ export class FileReaderPoly {
9
+ constructor() {
10
+ this.result = null;
11
+ this.error = null;
12
+ this.onloadend = null;
13
+ }
14
+ readAsDataURL(blob) {
15
+ const self = this;
16
+ (async function () {
17
+ try {
18
+ let buffer;
19
+ if (blob && typeof blob.arrayBuffer === 'function') {
20
+ buffer = await blob.arrayBuffer();
21
+ } else if (blob instanceof ArrayBuffer) {
22
+ buffer = blob;
23
+ } else if (ArrayBuffer.isView(blob)) {
24
+ buffer = blob.buffer;
25
+ } else {
26
+ buffer = new Uint8Array(0).buffer;
27
+ }
28
+
29
+ const base64 = toBase64FromBuffer(buffer);
30
+ const mime = (blob && blob.type) || 'application/octet-stream';
31
+ self.result = 'data:' + mime + ';base64,' + base64;
32
+ if (typeof self.onloadend === 'function') self.onloadend();
33
+ } catch (err) {
34
+ self.error = err;
35
+ if (typeof self.onloadend === 'function') self.onloadend();
36
+ }
37
+ })();
38
+ }
39
+ }
40
+
@@ -1,13 +1,13 @@
1
1
  // https://github.com/gr2m/localstorage-memory under MIT
2
2
 
3
3
  const root = {};
4
- var localStorageMemory = {}
5
- var cache = {}
4
+ var localStorageMemory = {};
5
+ var cache = {};
6
6
 
7
7
  /**
8
8
  * number of stored items.
9
9
  */
10
- localStorageMemory.length = 0
10
+ localStorageMemory.length = 0;
11
11
 
12
12
  /**
13
13
  * returns item for passed key, or null
@@ -17,12 +17,12 @@ localStorageMemory.length = 0
17
17
  * @returns {String|null}
18
18
  */
19
19
  localStorageMemory.getItem = function (key) {
20
- if (key in cache) {
21
- return cache[key]
22
- }
20
+ if ( key in cache ) {
21
+ return cache[key];
22
+ }
23
23
 
24
- return null
25
- }
24
+ return null;
25
+ };
26
26
 
27
27
  /**
28
28
  * sets item for key to passed value, as String
@@ -34,16 +34,16 @@ localStorageMemory.getItem = function (key) {
34
34
  * @returns {undefined}
35
35
  */
36
36
  localStorageMemory.setItem = function (key, value) {
37
- if (typeof value === 'undefined') {
38
- localStorageMemory.removeItem(key)
39
- } else {
40
- if (!(cache.hasOwnProperty(key))) {
41
- localStorageMemory.length++
42
- }
37
+ if ( typeof value === 'undefined' ) {
38
+ localStorageMemory.removeItem(key);
39
+ } else {
40
+ if ( ! (cache.hasOwnProperty(key)) ) {
41
+ localStorageMemory.length++;
42
+ }
43
43
 
44
- cache[key] = '' + value
45
- }
46
- }
44
+ cache[key] = `${ value}`;
45
+ }
46
+ };
47
47
 
48
48
  /**
49
49
  * removes item for passed key
@@ -53,11 +53,11 @@ localStorageMemory.setItem = function (key, value) {
53
53
  * @returns {undefined}
54
54
  */
55
55
  localStorageMemory.removeItem = function (key) {
56
- if (cache.hasOwnProperty(key)) {
57
- delete cache[key]
58
- localStorageMemory.length--
59
- }
60
- }
56
+ if ( cache.hasOwnProperty(key) ) {
57
+ delete cache[key];
58
+ localStorageMemory.length--;
59
+ }
60
+ };
61
61
 
62
62
  /**
63
63
  * returns name of key at passed index
@@ -67,8 +67,8 @@ localStorageMemory.removeItem = function (key) {
67
67
  * @returns {String|null}
68
68
  */
69
69
  localStorageMemory.key = function (index) {
70
- return Object.keys(cache)[index] || null
71
- }
70
+ return Object.keys(cache)[index] || null;
71
+ };
72
72
 
73
73
  /**
74
74
  * removes all stored items and sets length to 0
@@ -76,17 +76,14 @@ localStorageMemory.key = function (index) {
76
76
  * @returns {undefined}
77
77
  */
78
78
  localStorageMemory.clear = function () {
79
- cache = {}
80
- localStorageMemory.length = 0
81
- }
79
+ cache = {};
80
+ localStorageMemory.length = 0;
81
+ };
82
82
 
83
- if (typeof exports === 'object') {
84
- module.exports = localStorageMemory
83
+ if ( typeof exports === 'object' ) {
84
+ module.exports = localStorageMemory;
85
85
  } else {
86
- root.localStorage = localStorageMemory
86
+ root.localStorage = localStorageMemory;
87
87
  }
88
88
 
89
-
90
89
  export default localStorageMemory;
91
-
92
-
@@ -3,30 +3,30 @@
3
3
  /* global module */
4
4
  /* global EventTarget, AbortController, DOMException */
5
5
 
6
- const sReadyState = Symbol("readyState");
7
- const sHeaders = Symbol("headers");
8
- const sRespHeaders = Symbol("response headers");
9
- const sAbortController = Symbol("AbortController");
10
- const sMethod = Symbol("method");
11
- const sURL = Symbol("URL");
12
- const sMIME = Symbol("MIME");
13
- const sDispatch = Symbol("dispatch");
14
- const sErrored = Symbol("errored");
15
- const sTimeout = Symbol("timeout");
16
- const sTimedOut = Symbol("timedOut");
17
- const sIsResponseText = Symbol("isResponseText");
6
+ const sReadyState = Symbol('readyState');
7
+ const sHeaders = Symbol('headers');
8
+ const sRespHeaders = Symbol('response headers');
9
+ const sAbortController = Symbol('AbortController');
10
+ const sMethod = Symbol('method');
11
+ const sURL = Symbol('URL');
12
+ const sMIME = Symbol('MIME');
13
+ const sDispatch = Symbol('dispatch');
14
+ const sErrored = Symbol('errored');
15
+ const sTimeout = Symbol('timeout');
16
+ const sTimedOut = Symbol('timedOut');
17
+ const sIsResponseText = Symbol('isResponseText');
18
18
 
19
19
  // SO: https://stackoverflow.com/questions/49129643/how-do-i-merge-an-array-of-uint8arrays
20
- function mergeUint8Arrays(...arrays) {
21
- const totalSize = arrays.reduce((acc, e) => acc + e.length, 0);
22
- const merged = new Uint8Array(totalSize);
20
+ function mergeUint8Arrays (...arrays) {
21
+ const totalSize = arrays.reduce((acc, e) => acc + e.length, 0);
22
+ const merged = new Uint8Array(totalSize);
23
23
 
24
- arrays.forEach((array, i, arrays) => {
25
- const offset = arrays.slice(0, i).reduce((acc, e) => acc + e.length, 0);
26
- merged.set(array, offset);
27
- });
24
+ arrays.forEach((array, i, arrays) => {
25
+ const offset = arrays.slice(0, i).reduce((acc, e) => acc + e.length, 0);
26
+ merged.set(array, offset);
27
+ });
28
28
 
29
- return merged;
29
+ return merged;
30
30
  }
31
31
 
32
32
  /**
@@ -34,200 +34,199 @@ function mergeUint8Arrays(...arrays) {
34
34
  * @this {XMLHttpRequest}
35
35
  * @param {Uint8Array} bytes
36
36
  */
37
- async function parseBody(bytes) {
38
- const responseType = this.responseType || "text";
39
- const textde = new TextDecoder();
40
- const finalMIME = this[sMIME] || this[sRespHeaders].get("content-type") || "text/plain";
41
- switch (responseType) {
42
- case "text":
43
- this.response = textde.decode(bytes)
44
- break;
45
- case "blob":
46
- this.response = new Blob([bytes], { type: finalMIME });
47
- break;
48
- case "arraybuffer":
49
- this.response = bytes.buffer;
50
- break;
51
- case "json":
52
- this.response = JSON.parse(textde.decode(bytes));
53
- break;
54
- }
37
+ async function parseBody (bytes) {
38
+ const responseType = this.responseType || 'text';
39
+ const textde = new TextDecoder();
40
+ const finalMIME = this[sMIME] || this[sRespHeaders].get('content-type') || 'text/plain';
41
+ switch ( responseType ) {
42
+ case 'text':
43
+ this.response = textde.decode(bytes);
44
+ break;
45
+ case 'blob':
46
+ this.response = new Blob([bytes], { type: finalMIME });
47
+ break;
48
+ case 'arraybuffer':
49
+ this.response = bytes.buffer;
50
+ break;
51
+ case 'json':
52
+ this.response = JSON.parse(textde.decode(bytes));
53
+ break;
54
+ }
55
55
  }
56
56
 
57
57
  const XMLHttpRequestShim = class XMLHttpRequest extends EventTarget {
58
- onreadystatechange() {
59
-
60
- }
61
-
62
- set readyState(value) {
63
- if (this[sReadyState] === value) return; // dont do anything if "value" is already the internal value
64
- this[sReadyState] = value;
65
- this.dispatchEvent(new Event("readystatechange"));
66
- this.onreadystatechange(new Event("readystatechange"));
67
-
68
- }
69
- get readyState() {
70
- return this[sReadyState];
71
- }
72
-
73
- constructor() {
74
- super();
75
- this.readyState = this.constructor.UNSENT;
76
- this.response = null;
77
- this.responseType = "";
78
- this.responseURL = "";
79
- this.status = 0;
80
- this.statusText = "";
81
- this.timeout = 0;
82
- this.withCredentials = false;
83
- this[sHeaders] = Object.create(null);
84
- this[sHeaders].accept = "*/*";
85
- this[sRespHeaders] = Object.create(null);
86
- this[sAbortController] = new AbortController();
87
- this[sMethod] = "";
88
- this[sURL] = "";
89
- this[sMIME] = "";
90
- this[sErrored] = false;
91
- this[sTimeout] = 0;
92
- this[sTimedOut] = false;
93
- this[sIsResponseText] = true;
94
- }
95
- static get UNSENT() {
96
- return 0;
97
- }
98
- static get OPENED() {
99
- return 1;
100
- }
101
- static get HEADERS_RECEIVED() {
102
- return 2;
103
- }
104
- static get LOADING() {
105
- return 3;
106
- }
107
- static get DONE() {
108
- return 4;
109
- }
110
- upload = {
111
- addEventListener() {
112
- // stub, doesn't do anything since its not possible to monitor with fetch and http/1.1
113
- }
114
- }
115
- get responseText() {
116
- if (this[sErrored]) return null;
117
- if (this.readyState < this.constructor.HEADERS_RECEIVED) return "";
118
- if (this[sIsResponseText]) return this.response;
119
- throw new DOMException("Response type not set to text", "InvalidStateError");
120
- }
121
- get responseXML() {
122
- throw new Error("XML not supported");
123
- }
124
- [sDispatch](evt) {
125
- const attr = `on${evt.type}`;
126
- if (typeof this[attr] === "function") {
127
- this.addEventListener(evt.type, this[attr].bind(this), {
128
- once: true
129
- });
130
- }
131
- this.dispatchEvent(evt);
132
- }
133
- abort() {
134
- this[sAbortController].abort();
135
- this.status = 0;
136
- this.readyState = this.constructor.UNSENT;
137
- }
138
- open(method, url) {
139
- this.status = 0;
140
- this[sMethod] = method;
141
- this[sURL] = url;
142
- this.readyState = this.constructor.OPENED;
143
- }
144
- setRequestHeader(header, value) {
145
- header = String(header).toLowerCase();
146
- if (typeof this[sHeaders][header] === "undefined") {
147
- this[sHeaders][header] = String(value);
148
- } else {
149
- this[sHeaders][header] += `, ${value}`;
150
- }
151
- }
152
- overrideMimeType(mimeType) {
153
- this[sMIME] = String(mimeType);
154
- }
155
- getAllResponseHeaders() {
156
- if (this[sErrored] || this.readyState < this.constructor.HEADERS_RECEIVED) return "";
157
- return Array.from(this[sRespHeaders].entries().map(([header, value]) => `${header}: ${value}`)).join("\r\n");
158
- }
159
- getResponseHeader(headerName) {
160
- const value = this[sRespHeaders].get(String(headerName).toLowerCase());
161
- return typeof value === "string" ? value : null;
162
- }
163
- send(body = null) {
164
- if (this.timeout > 0) {
165
- this[sTimeout] = setTimeout(() => {
166
- this[sTimedOut] = true;
58
+ onreadystatechange () {
59
+
60
+ }
61
+
62
+ set readyState (value) {
63
+ if ( this[sReadyState] === value ) return; // dont do anything if "value" is already the internal value
64
+ this[sReadyState] = value;
65
+ this.dispatchEvent(new Event('readystatechange'));
66
+ this.onreadystatechange(new Event('readystatechange'));
67
+
68
+ }
69
+ get readyState () {
70
+ return this[sReadyState];
71
+ }
72
+
73
+ constructor () {
74
+ super();
75
+ this.readyState = this.constructor.UNSENT;
76
+ this.response = null;
77
+ this.responseType = '';
78
+ this.responseURL = '';
79
+ this.status = 0;
80
+ this.statusText = '';
81
+ this.timeout = 0;
82
+ this.withCredentials = false;
83
+ this[sHeaders] = Object.create(null);
84
+ this[sHeaders].accept = '*/*';
85
+ this[sRespHeaders] = Object.create(null);
86
+ this[sAbortController] = new AbortController();
87
+ this[sMethod] = '';
88
+ this[sURL] = '';
89
+ this[sMIME] = '';
90
+ this[sErrored] = false;
91
+ this[sTimeout] = 0;
92
+ this[sTimedOut] = false;
93
+ this[sIsResponseText] = true;
94
+ }
95
+ static get UNSENT () {
96
+ return 0;
97
+ }
98
+ static get OPENED () {
99
+ return 1;
100
+ }
101
+ static get HEADERS_RECEIVED () {
102
+ return 2;
103
+ }
104
+ static get LOADING () {
105
+ return 3;
106
+ }
107
+ static get DONE () {
108
+ return 4;
109
+ }
110
+ upload = {
111
+ addEventListener () {
112
+ // stub, doesn't do anything since its not possible to monitor with fetch and http/1.1
113
+ },
114
+ };
115
+ get responseText () {
116
+ if ( this[sErrored] ) return null;
117
+ if ( this.readyState < this.constructor.HEADERS_RECEIVED ) return '';
118
+ if ( this[sIsResponseText] ) return this.response;
119
+ throw new DOMException('Response type not set to text', 'InvalidStateError');
120
+ }
121
+ get responseXML () {
122
+ throw new Error('XML not supported');
123
+ }
124
+ [sDispatch] (evt) {
125
+ const attr = `on${evt.type}`;
126
+ if ( typeof this[attr] === 'function' ) {
127
+ this.addEventListener(evt.type, this[attr].bind(this), {
128
+ once: true,
129
+ });
130
+ }
131
+ this.dispatchEvent(evt);
132
+ }
133
+ abort () {
167
134
  this[sAbortController].abort();
168
- }, this.timeout);
169
- }
170
- const responseType = this.responseType || "text";
171
- this[sIsResponseText] = responseType === "text";
172
-
173
- this.setRequestHeader('user-agent', "puter-js/1.0")
174
- this.setRequestHeader('origin', "https://puter.work");
175
- this.setRequestHeader('referer', "https://puter.work/");
176
-
177
- fetch(this[sURL], {
178
- method: this[sMethod] || "GET",
179
- signal: this[sAbortController].signal,
180
- headers: this[sHeaders],
181
- credentials: this.withCredentials ? "include" : "same-origin",
182
- body
183
- }).then(async resp => {
184
- this.responseURL = resp.url;
185
- this.status = resp.status;
186
- this.statusText = resp.statusText;
187
- this[sRespHeaders] = resp.headers;
188
- this.readyState = this.constructor.HEADERS_RECEIVED;
189
-
190
- if (resp.headers.get("content-type").includes("application/x-ndjson") || this.streamRequestBadForPerformance) {
191
- let bytes = new Uint8Array();
192
- for await (const chunk of resp.body) {
193
- this.readyState = this.constructor.LOADING;
194
-
195
- bytes = mergeUint8Arrays(bytes, chunk);
196
- parseBody.call(this, bytes);
197
- this[sDispatch](new CustomEvent("progress"));
135
+ this.status = 0;
136
+ this.readyState = this.constructor.UNSENT;
137
+ }
138
+ open (method, url) {
139
+ this.status = 0;
140
+ this[sMethod] = method;
141
+ this[sURL] = url;
142
+ this.readyState = this.constructor.OPENED;
143
+ }
144
+ setRequestHeader (header, value) {
145
+ header = String(header).toLowerCase();
146
+ if ( typeof this[sHeaders][header] === 'undefined' ) {
147
+ this[sHeaders][header] = String(value);
148
+ } else {
149
+ this[sHeaders][header] += `, ${value}`;
198
150
  }
199
- } else {
200
- const bytesChunks = [];
201
- for await (const chunk of resp.body) {
202
- bytesChunks.push(chunk)
151
+ }
152
+ overrideMimeType (mimeType) {
153
+ this[sMIME] = String(mimeType);
154
+ }
155
+ getAllResponseHeaders () {
156
+ if ( this[sErrored] || this.readyState < this.constructor.HEADERS_RECEIVED ) return '';
157
+ return Array.from(this[sRespHeaders].entries().map(([header, value]) => `${header}: ${value}`)).join('\r\n');
158
+ }
159
+ getResponseHeader (headerName) {
160
+ const value = this[sRespHeaders].get(String(headerName).toLowerCase());
161
+ return typeof value === 'string' ? value : null;
162
+ }
163
+ send (body = null) {
164
+ if ( this.timeout > 0 ) {
165
+ this[sTimeout] = setTimeout(() => {
166
+ this[sTimedOut] = true;
167
+ this[sAbortController].abort();
168
+ }, this.timeout);
203
169
  }
204
- parseBody.call(this, mergeUint8Arrays(...bytesChunks));
205
- }
206
-
207
-
208
- this.readyState = this.constructor.DONE;
209
- this[sDispatch](new CustomEvent("load"));
210
- }, err => {
211
- let eventName = "abort";
212
- if (err.name !== "AbortError") {
213
- this[sErrored] = true;
214
- eventName = "error";
215
- } else if (this[sTimedOut]) {
216
- eventName = "timeout";
217
- }
218
- this.readyState = this.constructor.DONE;
219
- this[sDispatch](new CustomEvent(eventName));
220
- }).finally(() => this[sDispatch](new CustomEvent("loadend"))).finally(() => {
221
- clearTimeout(this[sTimeout]);
222
- this[sDispatch](new CustomEvent("loadstart"));
223
- });
224
- }
225
- }
170
+ const responseType = this.responseType || 'text';
171
+ this[sIsResponseText] = responseType === 'text';
172
+
173
+ this.setRequestHeader('user-agent', 'puter-js/1.0');
174
+ this.setRequestHeader('origin', 'https://puter.work');
175
+ this.setRequestHeader('referer', 'https://puter.work/');
176
+
177
+ fetch(this[sURL], {
178
+ method: this[sMethod] || 'GET',
179
+ signal: this[sAbortController].signal,
180
+ headers: this[sHeaders],
181
+ credentials: this.withCredentials ? 'include' : 'same-origin',
182
+ body,
183
+ }).then(async resp => {
184
+ this.responseURL = resp.url;
185
+ this.status = resp.status;
186
+ this.statusText = resp.statusText;
187
+ this[sRespHeaders] = resp.headers;
188
+ this.readyState = this.constructor.HEADERS_RECEIVED;
189
+
190
+ if ( resp.headers.get('content-type').includes('application/x-ndjson') || this.streamRequestBadForPerformance ) {
191
+ let bytes = new Uint8Array();
192
+ for await ( const chunk of resp.body ) {
193
+ this.readyState = this.constructor.LOADING;
194
+
195
+ bytes = mergeUint8Arrays(bytes, chunk);
196
+ parseBody.call(this, bytes);
197
+ this[sDispatch](new CustomEvent('progress'));
198
+ }
199
+ } else {
200
+ const bytesChunks = [];
201
+ for await ( const chunk of resp.body ) {
202
+ bytesChunks.push(chunk);
203
+ }
204
+ parseBody.call(this, mergeUint8Arrays(...bytesChunks));
205
+ }
206
+
207
+ this.readyState = this.constructor.DONE;
208
+ this[sDispatch](new CustomEvent('load'));
209
+ }, err => {
210
+ let eventName = 'abort';
211
+ if ( err.name !== 'AbortError' ) {
212
+ this[sErrored] = true;
213
+ eventName = 'error';
214
+ } else if ( this[sTimedOut] ) {
215
+ eventName = 'timeout';
216
+ }
217
+ this.readyState = this.constructor.DONE;
218
+ this[sDispatch](new CustomEvent(eventName));
219
+ }).finally(() => this[sDispatch](new CustomEvent('loadend'))).finally(() => {
220
+ clearTimeout(this[sTimeout]);
221
+ this[sDispatch](new CustomEvent('loadstart'));
222
+ });
223
+ }
224
+ };
226
225
 
227
- if (typeof module === "object" && module.exports) {
228
- module.exports = XMLHttpRequestShim;
226
+ if ( typeof module === 'object' && module.exports ) {
227
+ module.exports = XMLHttpRequestShim;
229
228
  } else {
230
- (globalThis || self).XMLHttpRequestShim = XMLHttpRequestShim;
229
+ (globalThis || self).XMLHttpRequestShim = XMLHttpRequestShim;
231
230
  }
232
231
 
233
- export default XMLHttpRequestShim
232
+ export default XMLHttpRequestShim;