@karpeleslab/klbfw 0.2.4 → 0.2.6
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/fw-wrapper.js +5 -2
- package/package.json +1 -1
- package/upload.js +141 -126
package/fw-wrapper.js
CHANGED
|
@@ -145,7 +145,10 @@ const getUrl = () => {
|
|
|
145
145
|
* Gets site static flag
|
|
146
146
|
* @returns {boolean} Whether site is static
|
|
147
147
|
*/
|
|
148
|
-
const getSiteStatic = () =>
|
|
148
|
+
const getSiteStatic = () => {
|
|
149
|
+
if (typeof FW === "undefined") return true;
|
|
150
|
+
return FW.site_static === undefined ? false : FW.site_static;
|
|
151
|
+
};
|
|
149
152
|
|
|
150
153
|
/**
|
|
151
154
|
* Gets the API prefix
|
|
@@ -245,4 +248,4 @@ module.exports.supported = supported;
|
|
|
245
248
|
module.exports.GET = getGET;
|
|
246
249
|
module.exports.Get = getParam;
|
|
247
250
|
module.exports.flushGet = flushGet;
|
|
248
|
-
module.exports.getMode = getMode;
|
|
251
|
+
module.exports.getMode = getMode;
|
package/package.json
CHANGED
package/upload.js
CHANGED
|
@@ -35,17 +35,20 @@
|
|
|
35
35
|
* // For Node.js environments, first install dependencies:
|
|
36
36
|
* // npm install node-fetch xmldom
|
|
37
37
|
*
|
|
38
|
-
* //
|
|
39
|
-
* upload.upload.init('Misc/Debug:testUpload')(['./file1.txt', './file2.jpg'])
|
|
40
|
-
* .then(result => console.log('Upload complete', result));
|
|
41
|
-
*
|
|
42
|
-
* // Or create a custom file object with path
|
|
38
|
+
* // Create a buffer-based file object for upload
|
|
43
39
|
* const file = {
|
|
44
40
|
* name: 'test.txt',
|
|
45
|
-
* size:
|
|
41
|
+
* size: buffer.length,
|
|
46
42
|
* type: 'text/plain',
|
|
47
|
-
*
|
|
43
|
+
* content: buffer, // Buffer or ArrayBuffer with file content
|
|
44
|
+
* lastModified: Date.now(),
|
|
45
|
+
* slice: function(start, end) {
|
|
46
|
+
* return {
|
|
47
|
+
* content: this.content.slice(start, end)
|
|
48
|
+
* };
|
|
49
|
+
* }
|
|
48
50
|
* };
|
|
51
|
+
*
|
|
49
52
|
* upload.upload.append('Misc/Debug:testUpload', file)
|
|
50
53
|
* .then(result => console.log('Upload complete', result));
|
|
51
54
|
* ```
|
|
@@ -53,6 +56,8 @@
|
|
|
53
56
|
* @module upload
|
|
54
57
|
*/
|
|
55
58
|
|
|
59
|
+
'use strict';
|
|
60
|
+
|
|
56
61
|
const rest = require('./rest');
|
|
57
62
|
const fwWrapper = require('./fw-wrapper');
|
|
58
63
|
const sha256 = require('js-sha256').sha256;
|
|
@@ -77,8 +82,6 @@ const env = {
|
|
|
77
82
|
node: {
|
|
78
83
|
fetch: null,
|
|
79
84
|
xmlParser: null,
|
|
80
|
-
fs: null,
|
|
81
|
-
path: null,
|
|
82
85
|
EventEmitter: null,
|
|
83
86
|
eventEmitter: null
|
|
84
87
|
}
|
|
@@ -91,8 +94,6 @@ if (env.isNode && !env.isBrowser) {
|
|
|
91
94
|
try {
|
|
92
95
|
env.node.fetch = require('node-fetch');
|
|
93
96
|
env.node.xmlParser = require('xmldom');
|
|
94
|
-
env.node.fs = require('fs');
|
|
95
|
-
env.node.path = require('path');
|
|
96
97
|
env.node.EventEmitter = require('events');
|
|
97
98
|
env.node.eventEmitter = new (env.node.EventEmitter)();
|
|
98
99
|
} catch (e) {
|
|
@@ -150,40 +151,73 @@ const utils = {
|
|
|
150
151
|
},
|
|
151
152
|
|
|
152
153
|
/**
|
|
153
|
-
* Read
|
|
154
|
-
*
|
|
154
|
+
* Read file content as ArrayBuffer
|
|
155
|
+
* Compatible with browser File objects and custom objects with content/slice
|
|
156
|
+
*
|
|
157
|
+
* @param {File|Object} file - File object or file-like object
|
|
158
|
+
* @param {Object} options - Options for reading (start, end)
|
|
155
159
|
* @param {Function} callback - Callback function(buffer, error)
|
|
156
160
|
*/
|
|
157
|
-
|
|
158
|
-
|
|
161
|
+
readAsArrayBuffer(file, options, callback) {
|
|
162
|
+
// Handle case where options is the callback
|
|
163
|
+
if (typeof options === 'function') {
|
|
164
|
+
callback = options;
|
|
165
|
+
options = {};
|
|
166
|
+
}
|
|
167
|
+
options = options || {};
|
|
168
|
+
|
|
169
|
+
if (env.isBrowser && file instanceof File) {
|
|
170
|
+
// Browser: use native File API
|
|
171
|
+
const start = options.start || 0;
|
|
172
|
+
const end = options.end || file.size;
|
|
173
|
+
const slice = file.slice(start, end);
|
|
174
|
+
|
|
159
175
|
const reader = new FileReader();
|
|
160
176
|
reader.addEventListener('loadend', () => callback(reader.result));
|
|
161
177
|
reader.addEventListener('error', (e) => callback(null, e));
|
|
162
|
-
reader.readAsArrayBuffer(
|
|
163
|
-
} else if (
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
callback(
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
178
|
+
reader.readAsArrayBuffer(slice);
|
|
179
|
+
} else if (file.content) {
|
|
180
|
+
// Memory buffer-based file
|
|
181
|
+
const start = options.start || 0;
|
|
182
|
+
const end = options.end || file.content.length || file.content.byteLength;
|
|
183
|
+
let content = file.content;
|
|
184
|
+
|
|
185
|
+
// Handle various content types
|
|
186
|
+
if (content instanceof ArrayBuffer) {
|
|
187
|
+
// Already an ArrayBuffer
|
|
188
|
+
if (start === 0 && end === content.byteLength) {
|
|
189
|
+
callback(content);
|
|
190
|
+
} else {
|
|
191
|
+
callback(content.slice(start, end));
|
|
192
|
+
}
|
|
193
|
+
} else if (content.buffer instanceof ArrayBuffer) {
|
|
194
|
+
// TypedArray (Uint8Array, etc.)
|
|
195
|
+
callback(content.buffer.slice(start, end));
|
|
196
|
+
} else if (typeof Buffer !== 'undefined' && content instanceof Buffer) {
|
|
197
|
+
// Node.js Buffer
|
|
198
|
+
const arrayBuffer = content.buffer.slice(
|
|
199
|
+
content.byteOffset + start,
|
|
200
|
+
content.byteOffset + Math.min(end, content.byteLength)
|
|
201
|
+
);
|
|
202
|
+
callback(arrayBuffer);
|
|
203
|
+
} else if (typeof content === 'string') {
|
|
204
|
+
// String content - convert to ArrayBuffer
|
|
205
|
+
const encoder = new TextEncoder();
|
|
206
|
+
const uint8Array = encoder.encode(content.slice(start, end));
|
|
207
|
+
callback(uint8Array.buffer);
|
|
182
208
|
} else {
|
|
183
|
-
callback(null, new Error('
|
|
209
|
+
callback(null, new Error('Unsupported content type'));
|
|
184
210
|
}
|
|
211
|
+
} else if (file.slice) {
|
|
212
|
+
// Object with slice method (custom implementation)
|
|
213
|
+
const start = options.start || 0;
|
|
214
|
+
const end = options.end;
|
|
215
|
+
const slice = file.slice(start, end);
|
|
216
|
+
|
|
217
|
+
// Recursively handle the slice
|
|
218
|
+
utils.readAsArrayBuffer(slice, callback);
|
|
185
219
|
} else {
|
|
186
|
-
callback(null, new Error('
|
|
220
|
+
callback(null, new Error('Cannot read file content - no supported method available'));
|
|
187
221
|
}
|
|
188
222
|
},
|
|
189
223
|
|
|
@@ -530,28 +564,11 @@ module.exports.upload = (function () {
|
|
|
530
564
|
const startByte = partNumber * up.bsize;
|
|
531
565
|
const endByte = Math.min(startByte + up.bsize, up.file.size);
|
|
532
566
|
|
|
533
|
-
//
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
filePart = up.file.slice(startByte, endByte);
|
|
539
|
-
} else if (env.isNode) {
|
|
540
|
-
// Node.js: create a reference with start/end positions
|
|
541
|
-
filePart = {
|
|
542
|
-
path: up.file.path,
|
|
543
|
-
start: startByte,
|
|
544
|
-
end: endByte,
|
|
545
|
-
type: up.file.type,
|
|
546
|
-
content: up.file.content // For memory buffer based files
|
|
547
|
-
};
|
|
548
|
-
} else {
|
|
549
|
-
handleFailure(up, new Error('Environment not supported'));
|
|
550
|
-
return;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
// Read the file part as ArrayBuffer
|
|
554
|
-
utils.readFileAsArrayBuffer(filePart, (arrayBuffer, error) => {
|
|
567
|
+
// Read file slice as ArrayBuffer
|
|
568
|
+
utils.readAsArrayBuffer(up.file, {
|
|
569
|
+
start: startByte,
|
|
570
|
+
end: endByte
|
|
571
|
+
}, (arrayBuffer, error) => {
|
|
555
572
|
if (error) {
|
|
556
573
|
handleFailure(up, error);
|
|
557
574
|
return;
|
|
@@ -633,7 +650,6 @@ module.exports.upload = (function () {
|
|
|
633
650
|
.catch(error => handleFailure(up, error));
|
|
634
651
|
}
|
|
635
652
|
|
|
636
|
-
|
|
637
653
|
/**
|
|
638
654
|
* Process an upload in progress
|
|
639
655
|
* Manages uploading parts and completing the upload
|
|
@@ -781,8 +797,6 @@ module.exports.upload = (function () {
|
|
|
781
797
|
sendProgress();
|
|
782
798
|
}
|
|
783
799
|
|
|
784
|
-
// No need for backward compatibility for private methods
|
|
785
|
-
|
|
786
800
|
/**
|
|
787
801
|
* Get current upload status
|
|
788
802
|
* @returns {Object} Status object with queued, running and failed uploads
|
|
@@ -809,44 +823,50 @@ module.exports.upload = (function () {
|
|
|
809
823
|
upload.run();
|
|
810
824
|
};
|
|
811
825
|
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
826
|
+
/**
|
|
827
|
+
* Initialize uploads in different environments
|
|
828
|
+
*
|
|
829
|
+
* @param {string} path - API path to upload to
|
|
830
|
+
* @param {Object} params - Upload parameters
|
|
831
|
+
* @param {Function} notify - Notification callback
|
|
832
|
+
* @returns {Function} - Function to start uploads
|
|
833
|
+
*/
|
|
834
|
+
upload.init = function(path, params, notify) {
|
|
816
835
|
params = params || {};
|
|
817
836
|
|
|
818
|
-
if (isBrowser) {
|
|
837
|
+
if (env.isBrowser) {
|
|
819
838
|
// Browser implementation
|
|
820
|
-
if (
|
|
821
|
-
|
|
822
|
-
|
|
839
|
+
if (state.lastInput !== null) {
|
|
840
|
+
state.lastInput.parentNode.removeChild(state.lastInput);
|
|
841
|
+
state.lastInput = null;
|
|
823
842
|
}
|
|
824
843
|
|
|
825
|
-
|
|
844
|
+
const input = document.createElement("input");
|
|
826
845
|
input.type = "file";
|
|
827
846
|
input.style.display = "none";
|
|
828
|
-
if (!params
|
|
847
|
+
if (!params.single) {
|
|
829
848
|
input.multiple = "multiple";
|
|
830
849
|
}
|
|
831
850
|
|
|
832
851
|
document.getElementsByTagName('body')[0].appendChild(input);
|
|
833
|
-
|
|
852
|
+
state.lastInput = input;
|
|
834
853
|
|
|
835
|
-
|
|
836
|
-
input.onchange = function
|
|
837
|
-
if (this.files.length
|
|
838
|
-
resolve();
|
|
854
|
+
const promise = new Promise(function(resolve, reject) {
|
|
855
|
+
input.onchange = function() {
|
|
856
|
+
if (this.files.length === 0) {
|
|
857
|
+
return resolve();
|
|
839
858
|
}
|
|
840
859
|
|
|
841
|
-
|
|
842
|
-
if (notify
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
860
|
+
let count = this.files.length;
|
|
861
|
+
if (notify) notify({status: 'init', count: count});
|
|
862
|
+
|
|
863
|
+
for (let i = 0; i < this.files.length; i++) {
|
|
864
|
+
upload.append(path, this.files[i], params, fwWrapper.getContext())
|
|
865
|
+
.then(function(obj) {
|
|
866
|
+
count -= 1;
|
|
867
|
+
if (notify) notify(obj);
|
|
868
|
+
if (count === 0) resolve();
|
|
869
|
+
});
|
|
850
870
|
}
|
|
851
871
|
upload.run();
|
|
852
872
|
};
|
|
@@ -854,55 +874,58 @@ module.exports.upload = (function () {
|
|
|
854
874
|
|
|
855
875
|
input.click();
|
|
856
876
|
return promise;
|
|
857
|
-
} else
|
|
858
|
-
//
|
|
859
|
-
return function(
|
|
860
|
-
//
|
|
861
|
-
if (
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
877
|
+
} else {
|
|
878
|
+
// Non-browser environment
|
|
879
|
+
return function(files) {
|
|
880
|
+
// Allow array, single file object, or file content buffer
|
|
881
|
+
if (!Array.isArray(files)) {
|
|
882
|
+
if (files instanceof ArrayBuffer ||
|
|
883
|
+
(files.buffer instanceof ArrayBuffer) ||
|
|
884
|
+
(typeof Buffer !== 'undefined' && files instanceof Buffer)) {
|
|
885
|
+
// If it's a buffer/ArrayBuffer, create a file-like object
|
|
886
|
+
files = [{
|
|
887
|
+
name: params.filename || 'file.bin',
|
|
888
|
+
size: files.byteLength || files.length,
|
|
889
|
+
type: params.type || 'application/octet-stream',
|
|
890
|
+
lastModified: Date.now(),
|
|
891
|
+
content: files
|
|
892
|
+
}];
|
|
893
|
+
} else {
|
|
894
|
+
// Single file object
|
|
895
|
+
files = [files];
|
|
896
|
+
}
|
|
867
897
|
}
|
|
868
898
|
|
|
869
899
|
return new Promise(function(resolve, reject) {
|
|
870
|
-
const count =
|
|
900
|
+
const count = files.length;
|
|
871
901
|
if (count === 0) {
|
|
872
902
|
return resolve();
|
|
873
903
|
}
|
|
874
904
|
|
|
875
|
-
if (notify
|
|
905
|
+
if (notify) notify({status: 'init', count: count});
|
|
876
906
|
|
|
877
907
|
let remainingCount = count;
|
|
878
908
|
|
|
879
|
-
|
|
909
|
+
files.forEach(file => {
|
|
880
910
|
try {
|
|
881
|
-
//
|
|
882
|
-
|
|
883
|
-
|
|
911
|
+
// Ensure file has required properties
|
|
912
|
+
if (!file.name) file.name = 'file.bin';
|
|
913
|
+
if (!file.type) file.type = 'application/octet-stream';
|
|
914
|
+
if (!file.lastModified) file.lastModified = Date.now();
|
|
884
915
|
|
|
885
|
-
//
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
size: stats.size,
|
|
889
|
-
lastModified: stats.mtimeMs,
|
|
890
|
-
type: 'application/octet-stream', // Default type
|
|
891
|
-
path: filePath, // For Node.js reading
|
|
892
|
-
// Mock methods needed by upload.js
|
|
893
|
-
slice: function(start, end) {
|
|
916
|
+
// Add slice method if not present
|
|
917
|
+
if (!file.slice && file.content) {
|
|
918
|
+
file.slice = function(start, end) {
|
|
894
919
|
return {
|
|
895
|
-
|
|
896
|
-
start: start,
|
|
897
|
-
end: end || stats.size
|
|
920
|
+
content: this.content.slice(start, end || this.size)
|
|
898
921
|
};
|
|
899
|
-
}
|
|
900
|
-
}
|
|
922
|
+
};
|
|
923
|
+
}
|
|
901
924
|
|
|
902
925
|
upload.append(path, file, params, fwWrapper.getContext())
|
|
903
926
|
.then(function(obj) {
|
|
904
927
|
remainingCount -= 1;
|
|
905
|
-
if (notify
|
|
928
|
+
if (notify) notify(obj);
|
|
906
929
|
if (remainingCount === 0) resolve();
|
|
907
930
|
})
|
|
908
931
|
.catch(function(err) {
|
|
@@ -920,15 +943,9 @@ module.exports.upload = (function () {
|
|
|
920
943
|
upload.run();
|
|
921
944
|
});
|
|
922
945
|
};
|
|
923
|
-
} else {
|
|
924
|
-
// Default implementation for other environments
|
|
925
|
-
return function() {
|
|
926
|
-
return Promise.reject(new Error('File upload not supported in this environment'));
|
|
927
|
-
};
|
|
928
946
|
}
|
|
929
947
|
};
|
|
930
948
|
|
|
931
|
-
|
|
932
949
|
/**
|
|
933
950
|
* Add a file to the upload queue
|
|
934
951
|
* @param {string} path - API path to upload to
|
|
@@ -961,7 +978,6 @@ module.exports.upload = (function () {
|
|
|
961
978
|
});
|
|
962
979
|
};
|
|
963
980
|
|
|
964
|
-
|
|
965
981
|
/**
|
|
966
982
|
* Cancel an upload in progress or in queue
|
|
967
983
|
* @param {number} uploadId - Upload ID to cancel
|
|
@@ -1105,7 +1121,6 @@ module.exports.upload = (function () {
|
|
|
1105
1121
|
sendProgress();
|
|
1106
1122
|
};
|
|
1107
1123
|
|
|
1108
|
-
|
|
1109
1124
|
/**
|
|
1110
1125
|
* Start or continue the upload process
|
|
1111
1126
|
* Processes queued uploads and continues running uploads
|
|
@@ -1131,4 +1146,4 @@ module.exports.upload = (function () {
|
|
|
1131
1146
|
};
|
|
1132
1147
|
|
|
1133
1148
|
return upload;
|
|
1134
|
-
}());
|
|
1149
|
+
}());
|