#include bytefmt.js #include xhr.js const EEPROM = function(appId, endPoint, auth) { if(typeof appId !== 'string') appId = (appId || '').toString(); if(typeof endPoint !== 'string') throw 'endPoint must be a string'; const applyAuth = options => { if(typeof auth === 'function') options.headers.Authorization = auth(); else if(typeof auth === 'string') options.headers.Authorization = auth; else options.authed = true; }; const createUpload = fileInput => { if(!(fileInput instanceof File)) throw 'fileInput must be an instance of window.File'; let userAborted = false; let abortHandler, progressHandler; const reportProgress = ev => { if(progressHandler !== undefined) progressHandler({ loaded: ev.loaded, total: ev.total, progress: ev.total <= 0 ? 0 : ev.loaded / ev.total, }); }; const uploadAbortedError = () => { return { error: 'eeprom:aborted_error', aborted: userAborted, toString: () => 'File upload was aborted manually.', }; }; const uploadGenericError = () => { return { error: 'eeprom:generic_error', aborted: userAborted, toString: () => 'File upload failed for unknown reasons.', }; }; return { abort: () => { userAborted = true; if(abortHandler !== undefined) abortHandler(); }, onProgress: handler => { if(typeof handler !== 'function') throw 'handler must be a function'; progressHandler = handler; }, start: async () => { if(userAborted) throw uploadAbortedError(); const options = { type: 'json', headers: {}, upload: reportProgress, abort: handler => abortHandler = handler, }; applyAuth(options); const formData = new FormData; formData.append('src', appId); formData.append('file', fileInput); try { const result = await EEPXHR.post(`${endPoint}/uploads`, options, formData); if(result.status !== 201) { if(result.status === 400) throw { error: 'eeprom:request_error', aborted: userAborted, toString: () => 'There was an error with the upload request.', }; if(result.status === 401) throw { error: 'eeprom:auth_error', aborted: userAborted, toString: () => 'Could not authenticate upload request. If this persists, try refreshing the page.', }; if(result.status === 403) throw { error: 'eeprom:access_error', aborted: userAborted, toString: () => 'You are not allowed to upload files.', }; if(result.status === 404) throw { error: 'eeprom:app_error', aborted: userAborted, toString: () => 'EEPROM app is not configured properly.', }; if(result.status === 413) { const maxSize = parseInt(result.headers().get('x-eeprom-max-size')); const maxSizeFormatted = EEPFMT.format(maxSize); throw { error: 'eeprom:size_error', maxSize: maxSize, maxSizeFormatted: maxSizeFormatted, aborted: userAborted, toString: () => maxSize < 1 ? 'Uploaded file was too large.' : `Uploads may not be larger than ${maxSizeFormatted}.`, }; } if(result.status === 451) throw { error: 'eeprom:dmca_error', aborted: userAborted, toString: () => 'This file is blocked from being uploaded, possibly for copyright reasons.', }; if(result.status === 500) throw { error: 'eeprom:server_error', aborted: userAborted, toString: () => 'An error occurred within the EEPROM server. If this persists, report it to a developer.', }; if(result.status === 503) throw { error: 'eeprom:maintenance_error', aborted: userAborted, toString: () => 'EEPROM server is temporarily unavailable for maintenance.', }; throw uploadGenericError(); } const fileInfo = result.body(); if(typeof fileInfo.type === 'string') { fileInfo.isImage = () => fileInfo.type.indexOf('image/') === 0; fileInfo.isVideo = () => fileInfo.type.indexOf('video/') === 0; fileInfo.isAudio = () => fileInfo.type === 'application/x-font-gdos' || fileInfo.type.indexOf('audio/') === 0; } else fileInfo.isImage = fileInfo.isVideo = fileInfo.isAudio = () => false; fileInfo.isMedia = () => fileInfo.isImage() || fileInfo.isAudio() || fileInfo.isVideo(); return Object.freeze(fileInfo); } catch(ex) { if(!ex.abort) { console.error(ex); throw ex; } throw uploadAbortedError(); } }, }; }; const deleteUpload = async fileInfo => { if(typeof fileInfo !== 'object') throw 'fileInfo must be an object'; if(typeof fileInfo.urlf !== 'string') throw 'fileInfo.urlf must be a string'; const options = { headers: {} }; applyAuth(options); const result = await EEPXHR.delete(fileInfo.urlf, options); if(result.status !== 204) { if(result.status === 401) throw { error: 'eeprom:auth_error', toString: () => 'Could not authenticate delete request. If this persists, try refreshing the page.', }; if(result.status === 403) throw { error: 'eeprom:access_error', toString: () => 'You are not allowed to delete this file.', }; if(result.status === 404) throw { error: 'eeprom:file_error', toString: () => 'File not found.', }; if(result.status === 500) throw { error: 'eeprom:server_error', toString: () => 'An error occurred within the EEPROM server. If this persists, report it to a developer.', }; if(result.status === 503) throw { error: 'eeprom:maintenance_error', toString: () => 'EEPROM server is temporarily unavailable for maintenance.', }; throw { error: 'eeprom:generic_error', toString: () => 'File delete failed for unknown reasons.', }; } }; return { create: createUpload, delete: deleteUpload, }; };