Added async version of EEPROM script.
This commit is contained in:
parent
b22f6df752
commit
10937f1217
12 changed files with 990 additions and 214 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,9 +3,11 @@
|
|||
.DS_Store
|
||||
/public/data/*
|
||||
/public/thumb/*
|
||||
/public/scripts
|
||||
/public/robots.txt
|
||||
/config.cfg
|
||||
/config.ini
|
||||
/.debug
|
||||
/vendor
|
||||
/.migrating
|
||||
/node_modules
|
||||
|
|
102
build.js
Normal file
102
build.js
Normal file
|
@ -0,0 +1,102 @@
|
|||
// IMPORTS
|
||||
const fs = require('fs');
|
||||
const swc = require('@swc/core');
|
||||
const path = require('path');
|
||||
const utils = require('./scripts/utils.js');
|
||||
const assproc = require('./scripts/assproc.js');
|
||||
|
||||
|
||||
// CONFIG
|
||||
const rootDir = __dirname;
|
||||
const srcDir = path.join(rootDir, 'scripts');
|
||||
const pubDir = path.join(rootDir, 'public');
|
||||
const pubAssetsDir = path.join(pubDir, 'scripts');
|
||||
|
||||
const isDebugBuild = fs.existsSync(path.join(rootDir, '.debug'));
|
||||
|
||||
const buildTasks = {
|
||||
js: [
|
||||
{ source: 'eepromv1.js', target: '/scripts', name: 'eepromv1.js', es: 'es5' },
|
||||
{ source: 'eepromv1a.js', target: '/scripts', name: 'eepromv1a.js' },
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
// PREP
|
||||
const swcJscOptions = {
|
||||
target: 'es2021',
|
||||
loose: false,
|
||||
externalHelpers: false,
|
||||
keepClassNames: true,
|
||||
preserveAllComments: false,
|
||||
transform: {},
|
||||
parser: {
|
||||
syntax: 'ecmascript',
|
||||
jsx: false,
|
||||
dynamicImport: false,
|
||||
privateMethod: false,
|
||||
functionBind: false,
|
||||
exportDefaultFrom: false,
|
||||
exportNamespaceFrom: false,
|
||||
decorators: false,
|
||||
decoratorsBeforeExport: false,
|
||||
topLevelAwait: true,
|
||||
importMeta: false,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
// BUILD
|
||||
(async () => {
|
||||
const files = {};
|
||||
|
||||
console.log('Ensuring assets directory exists...');
|
||||
fs.mkdirSync(pubAssetsDir, { recursive: true });
|
||||
|
||||
|
||||
console.log();
|
||||
console.log('JS assets');
|
||||
for(const info of buildTasks.js) {
|
||||
console.log(`=> Building ${info.source}...`);
|
||||
|
||||
let origTarget = undefined;
|
||||
if('es' in info) {
|
||||
origTarget = swcJscOptions.target;
|
||||
swcJscOptions.target = info.es;
|
||||
}
|
||||
|
||||
const assprocOpts = {
|
||||
prefix: '#',
|
||||
entry: info.entry || 'main.js',
|
||||
};
|
||||
const swcOpts = {
|
||||
filename: info.source,
|
||||
sourceMaps: false,
|
||||
isModule: false,
|
||||
minify: !isDebugBuild,
|
||||
jsc: swcJscOptions,
|
||||
};
|
||||
|
||||
const pubName = await assproc.process(path.join(srcDir, info.source), assprocOpts)
|
||||
.then(output => swc.transform(output, swcOpts))
|
||||
.then(output => {
|
||||
const name = utils.strtr(info.name, { hash: utils.shortHash(output.code) });
|
||||
const pubName = path.join(info.target || '', name);
|
||||
|
||||
console.log(` Saving to ${pubName}...`);
|
||||
fs.writeFileSync(path.join(pubDir, pubName), output.code);
|
||||
|
||||
return pubName;
|
||||
});
|
||||
|
||||
if(origTarget !== undefined)
|
||||
swcJscOptions.target = origTarget;
|
||||
|
||||
files[info.source] = pubName;
|
||||
}
|
||||
|
||||
|
||||
console.log();
|
||||
console.log('Cleaning up old builds...');
|
||||
assproc.housekeep(pubAssetsDir);
|
||||
})();
|
209
package-lock.json
generated
Normal file
209
package-lock.json
generated
Normal file
|
@ -0,0 +1,209 @@
|
|||
{
|
||||
"name": "eeprom.edgii.net",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@swc/core": "^1.3.107"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core": {
|
||||
"version": "1.3.107",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.107.tgz",
|
||||
"integrity": "sha512-zKhqDyFcTsyLIYK1iEmavljZnf4CCor5pF52UzLAz4B6Nu/4GLU+2LQVAf+oRHjusG39PTPjd2AlRT3f3QWfsQ==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@swc/counter": "^0.1.1",
|
||||
"@swc/types": "^0.1.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/swc"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@swc/core-darwin-arm64": "1.3.107",
|
||||
"@swc/core-darwin-x64": "1.3.107",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.3.107",
|
||||
"@swc/core-linux-arm64-gnu": "1.3.107",
|
||||
"@swc/core-linux-arm64-musl": "1.3.107",
|
||||
"@swc/core-linux-x64-gnu": "1.3.107",
|
||||
"@swc/core-linux-x64-musl": "1.3.107",
|
||||
"@swc/core-win32-arm64-msvc": "1.3.107",
|
||||
"@swc/core-win32-ia32-msvc": "1.3.107",
|
||||
"@swc/core-win32-x64-msvc": "1.3.107"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@swc/helpers": "^0.5.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@swc/helpers": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-darwin-arm64": {
|
||||
"version": "1.3.107",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.107.tgz",
|
||||
"integrity": "sha512-47tD/5vSXWxPd0j/ZllyQUg4bqalbQTsmqSw0J4dDdS82MWqCAwUErUrAZPRjBkjNQ6Kmrf5rpCWaGTtPw+ngw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-darwin-x64": {
|
||||
"version": "1.3.107",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.107.tgz",
|
||||
"integrity": "sha512-hwiLJ2ulNkBGAh1m1eTfeY1417OAYbRGcb/iGsJ+LuVLvKAhU/itzsl535CvcwAlt2LayeCFfcI8gdeOLeZa9A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm-gnueabihf": {
|
||||
"version": "1.3.107",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.107.tgz",
|
||||
"integrity": "sha512-I2wzcC0KXqh0OwymCmYwNRgZ9nxX7DWnOOStJXV3pS0uB83TXAkmqd7wvMBuIl9qu4Hfomi9aDM7IlEEn9tumQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm64-gnu": {
|
||||
"version": "1.3.107",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.107.tgz",
|
||||
"integrity": "sha512-HWgnn7JORYlOYnGsdunpSF8A+BCZKPLzLtEUA27/M/ZuANcMZabKL9Zurt7XQXq888uJFAt98Gy+59PU90aHKg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm64-musl": {
|
||||
"version": "1.3.107",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.107.tgz",
|
||||
"integrity": "sha512-vfPF74cWfAm8hyhS8yvYI94ucMHIo8xIYU+oFOW9uvDlGQRgnUf/6DEVbLyt/3yfX5723Ln57U8uiMALbX5Pyw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-x64-gnu": {
|
||||
"version": "1.3.107",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.107.tgz",
|
||||
"integrity": "sha512-uBVNhIg0ip8rH9OnOsCARUFZ3Mq3tbPHxtmWk9uAa5u8jQwGWeBx5+nTHpDOVd3YxKb6+5xDEI/edeeLpha/9g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-x64-musl": {
|
||||
"version": "1.3.107",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.107.tgz",
|
||||
"integrity": "sha512-mvACkUvzSIB12q1H5JtabWATbk3AG+pQgXEN95AmEX2ZA5gbP9+B+mijsg7Sd/3tboHr7ZHLz/q3SHTvdFJrEw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-arm64-msvc": {
|
||||
"version": "1.3.107",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.107.tgz",
|
||||
"integrity": "sha512-J3P14Ngy/1qtapzbguEH41kY109t6DFxfbK4Ntz9dOWNuVY3o9/RTB841ctnJk0ZHEG+BjfCJjsD2n8H5HcaOA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-ia32-msvc": {
|
||||
"version": "1.3.107",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.107.tgz",
|
||||
"integrity": "sha512-ZBUtgyjTHlz8TPJh7kfwwwFma+ktr6OccB1oXC8fMSopD0AxVnQasgun3l3099wIsAB9eEsJDQ/3lDkOLs1gBA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-x64-msvc": {
|
||||
"version": "1.3.107",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.107.tgz",
|
||||
"integrity": "sha512-Eyzo2XRqWOxqhE1gk9h7LWmUf4Bp4Xn2Ttb0ayAXFp6YSTxQIThXcT9kipXZqcpxcmDwoq8iWbbf2P8XL743EA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/counter": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.2.tgz",
|
||||
"integrity": "sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw=="
|
||||
},
|
||||
"node_modules/@swc/types": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz",
|
||||
"integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw=="
|
||||
}
|
||||
}
|
||||
}
|
5
package.json
Normal file
5
package.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"@swc/core": "^1.3.107"
|
||||
}
|
||||
}
|
|
@ -1,213 +0,0 @@
|
|||
var EEPROM = function(srcId, endpoint, authorization) {
|
||||
var obj = {
|
||||
srcId: parseInt(srcId),
|
||||
endpoint: endpoint,
|
||||
authorization: authorization,
|
||||
};
|
||||
|
||||
obj.setEndpoint = function(endpoint) {
|
||||
obj.endpoint = (endpoint || '').toString();
|
||||
};
|
||||
|
||||
obj.setAuthorization = function(authorization) {
|
||||
obj.authorization = (authorization || '').toString();
|
||||
};
|
||||
|
||||
obj.deleteUpload = function(fileInfo) {
|
||||
return new EEPROM.EEPROMDeleteTask(
|
||||
obj.authorization,
|
||||
fileInfo
|
||||
);
|
||||
};
|
||||
|
||||
obj.createUpload = function(file) {
|
||||
return new EEPROM.EEPROMUploadTask(
|
||||
obj.srcId,
|
||||
obj.endpoint,
|
||||
obj.authorization,
|
||||
file
|
||||
);
|
||||
};
|
||||
|
||||
return obj;
|
||||
};
|
||||
EEPROM.ERR_GENERIC = 'generic';
|
||||
EEPROM.ERR_INVALID = 'invalid';
|
||||
EEPROM.ERR_AUTH = 'auth';
|
||||
EEPROM.ERR_ACCESS = 'access';
|
||||
EEPROM.ERR_DMCA = 'dmca';
|
||||
EEPROM.ERR_GONE = 'gone';
|
||||
EEPROM.ERR_SERVER = 'server';
|
||||
EEPROM.ERR_SIZE = 'size';
|
||||
|
||||
EEPROM.EEPROMFile = function(fileInfo) {
|
||||
var obj = {
|
||||
id: (fileInfo.id || '').toString(),
|
||||
url: (fileInfo.url || '').toString(),
|
||||
urlf: (fileInfo.urlf || '').toString(),
|
||||
thumb: (fileInfo.thumb || '').toString(),
|
||||
name: (fileInfo.name || '').toString(),
|
||||
type: (fileInfo.type || '').toString(),
|
||||
size: parseInt(fileInfo.size || 0),
|
||||
user: parseInt(fileInfo.user || 0),
|
||||
hash: (fileInfo.hash || '').toString(),
|
||||
created: (fileInfo.created || null),
|
||||
accessed: (fileInfo.accessed || null),
|
||||
expires: (fileInfo.expires || null),
|
||||
deleted: (fileInfo.deleted || null),
|
||||
dmca: (fileInfo.dmca || null),
|
||||
};
|
||||
|
||||
obj.isImage = function() { return obj.type.indexOf('image/') === 0; };
|
||||
obj.isAudio = function() { return obj.type === 'application/x-font-gdos' || obj.type.indexOf('audio/') === 0; };
|
||||
obj.isVideo = function() { return obj.type.indexOf('video/') === 0; };
|
||||
obj.isMedia = function() { return obj.isImage() || obj.isAudio() || obj.isVideo(); };
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
EEPROM.EEPROMDeleteTask = function(authorization, fileInfo) {
|
||||
var obj = {
|
||||
authorization: authorization,
|
||||
fileInfo: fileInfo,
|
||||
onSuccess: undefined,
|
||||
onFailure: undefined,
|
||||
};
|
||||
|
||||
var xhr = obj.xhr = new XMLHttpRequest;
|
||||
obj.xhr.addEventListener('readystatechange', function() {
|
||||
if(xhr.readyState !== 4)
|
||||
return;
|
||||
|
||||
if(xhr.status !== 204) {
|
||||
obj.errorCode = EEPROM.ERR_GENERIC;
|
||||
|
||||
switch(xhr.status) {
|
||||
case 401:
|
||||
obj.errorCode = EEPROM.ERR_AUTH;
|
||||
break;
|
||||
case 403:
|
||||
obj.errorCode = EEPROM.ERR_ACCESS;
|
||||
break;
|
||||
case 404:
|
||||
case 410:
|
||||
obj.errorCode = EEPROM.ERR_GONE;
|
||||
break;
|
||||
case 500:
|
||||
case 503:
|
||||
obj.errorCode = EEPROM.ERR_SERVER;
|
||||
break;
|
||||
}
|
||||
|
||||
if(obj.onFailure)
|
||||
obj.onFailure(obj.errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if(obj.onSuccess)
|
||||
obj.onSuccess();
|
||||
});
|
||||
|
||||
obj.start = function() {
|
||||
xhr.open('DELETE', obj.fileInfo.urlf);
|
||||
if(obj.authorization) xhr.setRequestHeader('Authorization', obj.authorization);
|
||||
else xhr.withCredentials = true;
|
||||
xhr.send();
|
||||
};
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
EEPROM.EEPROMUploadTask = function(srcId, endpoint, authorization, file) {
|
||||
var obj = {
|
||||
aborted: false,
|
||||
endpoint: endpoint,
|
||||
authorization: authorization,
|
||||
onComplete: undefined,
|
||||
onFailure: undefined,
|
||||
onProgress: undefined,
|
||||
failureResponse: undefined,
|
||||
};
|
||||
|
||||
var xhr = obj.xhr = new XMLHttpRequest,
|
||||
fd = obj.formData = new FormData;
|
||||
|
||||
fd.append('src', srcId);
|
||||
fd.append('file', file);
|
||||
|
||||
var reportUploadProgress = function(ev) {
|
||||
if(obj.onProgress)
|
||||
obj.onProgress({
|
||||
loaded: ev.loaded,
|
||||
total: ev.total,
|
||||
progress: Math.ceil((ev.loaded / ev.total) * 100),
|
||||
});
|
||||
};
|
||||
|
||||
xhr.upload.addEventListener('loadstart', reportUploadProgress);
|
||||
xhr.upload.addEventListener('progress', reportUploadProgress);
|
||||
xhr.upload.addEventListener('load', reportUploadProgress);
|
||||
|
||||
xhr.addEventListener('readystatechange', function() {
|
||||
if(this.readyState !== 4)
|
||||
return;
|
||||
|
||||
if(this.status !== 201) {
|
||||
obj.failureResponse = {
|
||||
userAborted: obj.aborted,
|
||||
error: EEPROM.ERR_GENERIC,
|
||||
};
|
||||
|
||||
switch(this.status) {
|
||||
case 400:
|
||||
case 405:
|
||||
obj.failureResponse.error = EEPROM.ERR_INVALID;
|
||||
break;
|
||||
case 401:
|
||||
obj.failureResponse.error = EEPROM.ERR_AUTH;
|
||||
break;
|
||||
case 403:
|
||||
obj.failureResponse.error = EEPROM.ERR_ACCESS;
|
||||
break;
|
||||
case 404:
|
||||
case 410:
|
||||
obj.failureResponse.error = EEPROM.ERR_GONE;
|
||||
break;
|
||||
case 451:
|
||||
obj.failureResponse.error = EEPROM.ERR_DMCA;
|
||||
break;
|
||||
case 413:
|
||||
obj.failureResponse.error = EEPROM.ERR_SIZE;
|
||||
obj.failureResponse.maxSize = parseInt(this.getResponseHeader('X-EEPROM-Max-Size'));
|
||||
break;
|
||||
case 500:
|
||||
case 503:
|
||||
obj.failureResponse.error = EEPROM.ERR_SERVER;
|
||||
break;
|
||||
}
|
||||
|
||||
if(obj.onFailure)
|
||||
obj.onFailure(obj.failureResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
obj.fileInfo = new EEPROM.EEPROMFile(JSON.parse(this.responseText));
|
||||
|
||||
if(obj.onComplete)
|
||||
obj.onComplete(obj.fileInfo);
|
||||
});
|
||||
|
||||
obj.abort = function() {
|
||||
obj.aborted = true;
|
||||
xhr.abort();
|
||||
};
|
||||
|
||||
obj.start = function() {
|
||||
xhr.open('POST', obj.endpoint);
|
||||
if(obj.authorization) xhr.setRequestHeader('Authorization', obj.authorization);
|
||||
else xhr.withCredentials = true;
|
||||
xhr.send(fd);
|
||||
};
|
||||
|
||||
return obj;
|
||||
};
|
108
scripts/assproc.js
Normal file
108
scripts/assproc.js
Normal file
|
@ -0,0 +1,108 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const readline = require('readline');
|
||||
const utils = require('./utils.js');
|
||||
|
||||
exports.process = async function(root, options) {
|
||||
const macroPrefix = options.prefix || '#';
|
||||
const entryPoint = options.entry || '';
|
||||
|
||||
root = fs.realpathSync(root);
|
||||
|
||||
const included = [];
|
||||
|
||||
const processFile = async function(fileName) {
|
||||
const fullPath = path.join(root, fileName);
|
||||
if(included.includes(fullPath))
|
||||
return '';
|
||||
included.push(fullPath);
|
||||
|
||||
if(!fullPath.startsWith(root))
|
||||
return '/* *** INVALID PATH: ' + fullPath + ' */';
|
||||
if(!fs.existsSync(fullPath))
|
||||
return '/* *** FILE NOT FOUND: ' + fullPath + ' */';
|
||||
|
||||
const lines = readline.createInterface({
|
||||
input: fs.createReadStream(fullPath),
|
||||
crlfDelay: Infinity,
|
||||
});
|
||||
|
||||
let output = '';
|
||||
let lastWasEmpty = false;
|
||||
|
||||
if(options.showPath)
|
||||
output += "/* *** PATH: " + fullPath + " */\n";
|
||||
|
||||
for await(const line of lines) {
|
||||
const lineTrimmed = utils.trim(line);
|
||||
if(lineTrimmed === '')
|
||||
continue;
|
||||
|
||||
if(line.startsWith(macroPrefix)) {
|
||||
const args = lineTrimmed.split(' ');
|
||||
const macro = utils.trim(utils.trimStart(args.shift(), macroPrefix));
|
||||
|
||||
switch(macro) {
|
||||
case 'comment':
|
||||
break;
|
||||
|
||||
case 'include': {
|
||||
const includePath = utils.trimEnd(args.join(' '), ';');
|
||||
output += utils.trim(await processFile(includePath));
|
||||
output += "\n";
|
||||
break;
|
||||
}
|
||||
|
||||
case 'buildvars':
|
||||
if(typeof options.buildVars === 'object') {
|
||||
const bvTarget = options.buildVarsTarget || 'window';
|
||||
const bvProps = [];
|
||||
|
||||
for(const bvName in options.buildVars)
|
||||
bvProps.push(`${bvName}: { value: ${JSON.stringify(options.buildVars[bvName])}, writable: false }`);
|
||||
|
||||
if(Object.keys(bvProps).length > 0)
|
||||
output += `Object.defineProperties(${bvTarget}, { ${bvProps.join(', ')} });\n`;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
output += line;
|
||||
output += "\n";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
output += line;
|
||||
output += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
return await processFile(entryPoint);
|
||||
};
|
||||
|
||||
exports.housekeep = function(assetsPath) {
|
||||
const files = fs.readdirSync(assetsPath).map(fileName => {
|
||||
const stats = fs.statSync(path.join(assetsPath, fileName));
|
||||
return {
|
||||
name: fileName,
|
||||
lastMod: stats.mtimeMs,
|
||||
};
|
||||
}).sort((a, b) => b.lastMod - a.lastMod).map(info => info.name);
|
||||
|
||||
const regex = /^(.+)[\-\.]([a-f0-9]+)\.(.+)$/i;
|
||||
const counts = {};
|
||||
|
||||
for(const fileName of files) {
|
||||
const match = fileName.match(regex);
|
||||
if(match) {
|
||||
const name = match[1] + '-' + match[3];
|
||||
counts[name] = (counts[name] || 0) + 1;
|
||||
|
||||
if(counts[name] > 5)
|
||||
fs.unlinkSync(path.join(assetsPath, fileName));
|
||||
}
|
||||
}
|
||||
};
|
195
scripts/eepromv1.js/main.js
Normal file
195
scripts/eepromv1.js/main.js
Normal file
|
@ -0,0 +1,195 @@
|
|||
window.EEPROM = (() => {
|
||||
const errGeneric = 'generic';
|
||||
const errInvalid = 'invalid';
|
||||
const errAuth = 'auth';
|
||||
const errAccess = 'access';
|
||||
const errDMCA = 'dmca';
|
||||
const errGone = 'gone';
|
||||
const errSize = 'size';
|
||||
const errServer = 'server';
|
||||
|
||||
const createClient = function(srcId, endPoint, authorization) {
|
||||
if(typeof srcId !== 'number')
|
||||
srcId = parseInt(srcId);
|
||||
if(typeof endPoint !== 'string')
|
||||
throw 'endPoint must be a string';
|
||||
if(typeof authorization !== 'string' && typeof authorization !== 'function')
|
||||
throw 'authorization must be a string or a function returning a string';
|
||||
|
||||
const createUpload = file => {
|
||||
const uploadTask = { onComplete: undefined, onFailure: undefined, onProgress: undefined };
|
||||
let userAborted = false;
|
||||
|
||||
const xhr = new XMLHttpRequest;
|
||||
const fd = new FormData;
|
||||
|
||||
fd.append('src', srcId);
|
||||
fd.append('file', file);
|
||||
|
||||
const reportUploadProgress = ev => {
|
||||
if(typeof uploadTask.onProgress === 'function')
|
||||
uploadTask.onProgress({
|
||||
loaded: ev.loaded,
|
||||
total: ev.total,
|
||||
progress: Math.ceil((ev.loaded / ev.total) * 100),
|
||||
});
|
||||
};
|
||||
|
||||
xhr.upload.addEventListener('loadstart', reportUploadProgress);
|
||||
xhr.upload.addEventListener('progress', reportUploadProgress);
|
||||
xhr.upload.addEventListener('load', reportUploadProgress);
|
||||
|
||||
xhr.addEventListener('readystatechange', () => {
|
||||
if(xhr.readyState !== 4)
|
||||
return;
|
||||
|
||||
if(xhr.status !== 201) {
|
||||
const failureResponse = {
|
||||
userAborted: userAborted,
|
||||
error: errGeneric,
|
||||
};
|
||||
|
||||
switch(xhr.status) {
|
||||
case 400:
|
||||
case 405:
|
||||
failureResponse.error = errInvalid;
|
||||
break;
|
||||
case 401:
|
||||
failureResponse.error = errAuth;
|
||||
break;
|
||||
case 403:
|
||||
failureResponse.error = errAccess;
|
||||
break;
|
||||
case 404:
|
||||
case 410:
|
||||
failureResponse.error = errGone;
|
||||
break;
|
||||
case 451:
|
||||
failureResponse.error = errDMCA;
|
||||
break;
|
||||
case 413:
|
||||
failureResponse.error = errSize;
|
||||
failureResponse.maxSize = parseInt(xhr.getResponseHeader('X-EEPROM-Max-Size'));
|
||||
break;
|
||||
case 500:
|
||||
case 503:
|
||||
failureResponse.error = errServer;
|
||||
break;
|
||||
}
|
||||
|
||||
if(typeof uploadTask.onFailure === 'function')
|
||||
uploadTask.onFailure(failureResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof uploadTask.onComplete === 'function') {
|
||||
const fileInfo = JSON.parse(xhr.responseText);
|
||||
if(typeof fileInfo !== 'object') {
|
||||
if(typeof uploadTask.onFailure === 'function')
|
||||
uploadTask.onFailure({
|
||||
userAborted: userAborted,
|
||||
error: errServer,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
fileInfo.isImage = () => typeof fileInfo.type === 'string' && fileInfo.type.indexOf('image/') === 0;
|
||||
fileInfo.isVideo = () => typeof fileInfo.type === 'string' && fileInfo.type.indexOf('video/') === 0;
|
||||
fileInfo.isAudio = () => typeof fileInfo.type === 'string' && (fileInfo.type === 'application/x-font-gdos' || fileInfo.type.indexOf('audio/') === 0);
|
||||
fileInfo.isMedia = () => typeof fileInfo.type === 'string' && (fileInfo.isImage() || fileInfo.isAudio() || fileInfo.isVideo());
|
||||
|
||||
uploadTask.onComplete(fileInfo);
|
||||
}
|
||||
});
|
||||
|
||||
uploadTask.abort = () => {
|
||||
userAborted = true;
|
||||
xhr.abort();
|
||||
};
|
||||
|
||||
uploadTask.start = () => {
|
||||
xhr.open('POST', endPoint);
|
||||
|
||||
const authIsFunc = typeof authorization === 'function';
|
||||
if(authIsFunc || typeof authorization === 'string')
|
||||
xhr.setRequestHeader('Authorization', authIsFunc ? authorization() : authorization);
|
||||
else
|
||||
xhr.withCredentials = true;
|
||||
|
||||
xhr.send(fd);
|
||||
};
|
||||
|
||||
return uploadTask;
|
||||
};
|
||||
|
||||
const deleteUpload = fileInfo => {
|
||||
const deleteTask = { onSuccess: undefined, onFailure: undefined };
|
||||
|
||||
const xhr = new XMLHttpRequest;
|
||||
xhr.addEventListener('readystatechange', () => {
|
||||
if(xhr.readyState !== 4)
|
||||
return;
|
||||
|
||||
if(xhr.status !== 204) {
|
||||
let errorCode = errGeneric;
|
||||
|
||||
switch(xhr.status) {
|
||||
case 401:
|
||||
errorCode = errAuth;
|
||||
break;
|
||||
case 403:
|
||||
errorCode = errAccess;
|
||||
break;
|
||||
case 404:
|
||||
case 410:
|
||||
errorCode = errGone;
|
||||
break;
|
||||
case 500:
|
||||
case 503:
|
||||
errorCode = errServer;
|
||||
break;
|
||||
}
|
||||
|
||||
if(typeof deleteTask.onFailure === 'function')
|
||||
deleteTask.onFailure(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof deleteTask.onSuccess === 'function')
|
||||
deleteTask.onSuccess();
|
||||
});
|
||||
|
||||
deleteTask.start = () => {
|
||||
xhr.open('DELETE', fileInfo.urlf);
|
||||
|
||||
const authIsFunc = typeof authorization === 'function';
|
||||
if(authIsFunc || typeof authorization === 'string')
|
||||
xhr.setRequestHeader('Authorization', authIsFunc ? authorization() : authorization);
|
||||
else
|
||||
xhr.withCredentials = true;
|
||||
|
||||
xhr.send();
|
||||
};
|
||||
|
||||
return deleteTask;
|
||||
};
|
||||
|
||||
return {
|
||||
createUpload: createUpload,
|
||||
deleteUpload: deleteUpload,
|
||||
};
|
||||
};
|
||||
|
||||
Object.defineProperties(createClient, {
|
||||
ERR_GENERIC: { value: errGeneric },
|
||||
ERR_INVALID: { value: errInvalid },
|
||||
ERR_AUTH: { value: errAuth },
|
||||
ERR_ACCESS: { value: errAccess },
|
||||
ERR_DMCA: { value: errDMCA },
|
||||
ERR_GONE: { value: errGone },
|
||||
ERR_SERVER: { value: errServer },
|
||||
ERR_SIZE: { value: errSize },
|
||||
});
|
||||
|
||||
return createClient;
|
||||
})();
|
45
scripts/eepromv1a.js/bytefmt.js
Normal file
45
scripts/eepromv1a.js/bytefmt.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
const EEPFMT = (() => {
|
||||
const symbols = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'R', 'Q'];
|
||||
|
||||
const format = (bytes, binary) => {
|
||||
if(bytes === 0)
|
||||
return 'Zero Bytes';
|
||||
|
||||
const negative = bytes < 0;
|
||||
const power = binary ? 1024 : 1000;
|
||||
const exp = Math.floor(Math.log(bytes) / Math.log(power));
|
||||
|
||||
bytes = Math.abs(bytes);
|
||||
|
||||
const number = bytes / Math.pow(power, exp);
|
||||
const symbol = symbols[exp];
|
||||
|
||||
let string = '';
|
||||
if(negative)
|
||||
string += '-';
|
||||
|
||||
const fractionDigits = bytes < power ? 0 : (number < 10 ? 2 : 1);
|
||||
string += number.toLocaleString(undefined, {
|
||||
maximumFractionDigits: fractionDigits,
|
||||
minimumFractionDigits: fractionDigits,
|
||||
});
|
||||
|
||||
string += ` ${symbol}`;
|
||||
|
||||
if(symbol === '') {
|
||||
string += 'Byte';
|
||||
if(number > 1)
|
||||
string += 's';
|
||||
} else {
|
||||
if(binary)
|
||||
string += 'i';
|
||||
string += 'B';
|
||||
}
|
||||
|
||||
return string;
|
||||
};
|
||||
|
||||
return {
|
||||
format: format,
|
||||
};
|
||||
})();
|
213
scripts/eepromv1a.js/main.js
Normal file
213
scripts/eepromv1a.js/main.js
Normal file
|
@ -0,0 +1,213 @@
|
|||
#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(xhr.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 uploadGenericError();
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
};
|
75
scripts/eepromv1a.js/xhr.js
Normal file
75
scripts/eepromv1a.js/xhr.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
const EEPXHR = (() => {
|
||||
const send = function(method, url, options, body) {
|
||||
const xhr = new XMLHttpRequest;
|
||||
const requestHeaders = new Map;
|
||||
|
||||
if('headers' in options && typeof options.headers === 'object')
|
||||
for(const name in options.headers)
|
||||
if(options.headers.hasOwnProperty(name))
|
||||
requestHeaders.set(name.toLowerCase(), options.headers[name]);
|
||||
|
||||
if(typeof options.upload === 'function') {
|
||||
xhr.upload.onloadstart = ev => options.upload(ev);
|
||||
xhr.upload.onprogress = ev => options.upload(ev);
|
||||
xhr.upload.onloadend = ev => options.upload(ev);
|
||||
}
|
||||
|
||||
if(options.authed)
|
||||
xhr.withCredentials = true;
|
||||
|
||||
if(typeof options.timeout === 'number')
|
||||
xhr.timeout = options.timeout;
|
||||
|
||||
if(typeof options.type === 'string')
|
||||
xhr.responseType = options.type;
|
||||
|
||||
if(typeof options.abort === 'function')
|
||||
options.abort(() => xhr.abort());
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let responseHeaders = undefined;
|
||||
|
||||
xhr.onload = ev => resolve({
|
||||
status: xhr.status,
|
||||
body: () => xhr.response,
|
||||
headers: () => {
|
||||
if(responseHeaders !== undefined)
|
||||
return responseHeaders;
|
||||
|
||||
responseHeaders = new Map;
|
||||
|
||||
const raw = xhr.getAllResponseHeaders().trim().split(/[\r\n]+/);
|
||||
for(const name in raw)
|
||||
if(raw.hasOwnProperty(name)) {
|
||||
const parts = raw[name].split(': ');
|
||||
responseHeaders.set(parts.shift(), parts.join(': '));
|
||||
}
|
||||
|
||||
return responseHeaders;
|
||||
},
|
||||
});
|
||||
|
||||
xhr.onabort = ev => reject({
|
||||
abort: true,
|
||||
xhr: xhr,
|
||||
ev: ev,
|
||||
});
|
||||
|
||||
xhr.onerror = ev => reject({
|
||||
abort: false,
|
||||
xhr: xhr,
|
||||
ev: ev,
|
||||
});
|
||||
|
||||
xhr.open(method, url);
|
||||
for(const [name, value] of requestHeaders)
|
||||
xhr.setRequestHeader(name, value);
|
||||
xhr.send(body);
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
post: (url, options, body) => send('POST', url, options, body),
|
||||
delete: (url, options, body) => send('DELETE', url, options, body),
|
||||
};
|
||||
})();
|
35
scripts/utils.js
Normal file
35
scripts/utils.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
const crypto = require('crypto');
|
||||
|
||||
exports.strtr = (str, replacements) => str.toString().replace(
|
||||
/{([^}]+)}/g, (match, key) => replacements[key] || match
|
||||
);
|
||||
|
||||
const trim = function(str, chars, flags) {
|
||||
if(chars === undefined)
|
||||
chars = " \n\r\t\v\0";
|
||||
|
||||
let start = 0,
|
||||
end = str.length;
|
||||
|
||||
if(flags & 0x01)
|
||||
while(start < end && chars.indexOf(str[start]) >= 0)
|
||||
++start;
|
||||
|
||||
if(flags & 0x02)
|
||||
while(end > start && chars.indexOf(str[end - 1]) >= 0)
|
||||
--end;
|
||||
|
||||
return (start > 0 || end < str.length)
|
||||
? str.substring(start, end)
|
||||
: str;
|
||||
};
|
||||
|
||||
exports.trimStart = (str, chars) => trim(str, chars, 0x01);
|
||||
exports.trimEnd = (str, chars) => trim(str, chars, 0x02);
|
||||
exports.trim = (str, chars) => trim(str, chars, 0x03);
|
||||
|
||||
exports.shortHash = function(text) {
|
||||
const hash = crypto.createHash('sha256');
|
||||
hash.update(text);
|
||||
return hash.digest('hex').substring(0, 8);
|
||||
};
|
|
@ -42,7 +42,7 @@ class LandingRoutes extends RouteHandler {
|
|||
|
||||
#[Route('GET', '/eeprom.js')]
|
||||
public function getEepromJs($response) {
|
||||
$response->accelRedirect('/js/eeprom-v1.0.js');
|
||||
$response->accelRedirect('/scripts/eepromv1.js');
|
||||
$response->setContentType('application/javascript; charset=utf-8');
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue