– Was made for internal Use.
Starts Pricelist sync to Fortnox on the main shops server. Waits for 30 minutes for each pricelist to finish.
NOTE: Add airtableToken & main server authorizationLink to make it work.
(async function() {
var localMode = typeof addEventListener === "undefined" && typeof input === "undefined" ? true : false;
if (localMode === true) {
console.log(`
Global base packages required:
form-data
node-fetch@2.6.7
`);
var workerThreads = require('worker_threads');
var fs = require("fs");
var https = require("https");
var http = require("http");
var FormData = require("form-data");
var fetch = require("node-fetch");
var appConfig = {"mainFile":"main.js","port":7053};
(function() {
var parts = __filename.split("/");
var fileName = parts.pop();
var file = parts.join("/") + "/.bundle." + fileName + "on";
if (fs.existsSync(file)) {
var options = JSON.parse((function() {
var contents = fs.readFileSync(file, "utf8");
contents = contents.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g,'').trim();
return contents;
})());
for (var key in options) appConfig[key] = options[key];
}
})();
if (typeof appConfig.reverseProxy !== "undefined" && typeof appConfig.reverseProxy.domains !== "undefined") {
(function() {
var redbird = require('redbird')({
port: 80,
letsencrypt: {
path: __dirname + '/certs'
},
ssl: {
port: 443,
key: "certs/key.pem",
cert: "certs/cert.pem"
}
});
for (var domain in appConfig.reverseProxy.domains) {
redbird.register(domain, appConfig.reverseProxy.domains[domain]);
}
})();
}
if (typeof appConfig.port === "number") {
if (typeof appConfig.host !== "string") appConfig.host = "127.0.0.1";
var httpOrHttps = appConfig.noCertificate === true ? http : https;
if (workerThreads.isMainThread) {
var server = httpOrHttps.createServer({
key: `-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAr68IoGyAC1HCh6N8djdeFYewWKbqywedHCVOpF/bFGP47KJP
W26Yng81OgK/4RkXp07My1B16jeFN5NXqmfdtQENTckxtmJA2j6/4d2y0m9aacLl
dx1a4mNzbM78Ln9smEk0+SWp6fypN0kg9OER3ljQpCb8YspgwHbnJLlky2c6q84S
cC8Oc2hhPXo/CJit2xoI3m8SAaqfDsHAmyqd2bsBBaH9ssgpaIxGQ2QWFfHZJOSE
D5AUEO+HuJQverSNzxAsLItuKbUfvGvm/tUvXymlStmDyWIwNvfdneuozZ5WPIEP
d43s++QKmI5qlA1Z+j+wcY3zFyqUM1NcWBUhrQIDAQABAoIBACYBtdoO3vyT6YOy
iKCCheYefrYPFkhqE0EdiQ/idODKZ/W5f3WGTZoULC2qnpwx834MfB2YAIp1DGrj
g1moMryPx7MGTazpQKJ2ZMiWT7Nax7KNqVrFjP3hCf2GIeRlSLcBT2Z/EW0/bdQ6
C9kuP9FcYXbBwGQW6Ct7DbJSMU4XYUErl4sXb7H9vwARlWxJ4Gq8fldagy7T+oX2
OwObO9/e8GdkJBlr5PM2ZZOES3avGjJnPGFwQ/wCreNaqt8ir+fFmd6odLjxh2mH
sn7WwIC/Eyp/TcM/O7bZT3SfSCWbKsk2NGQCX3cV49Zr37+4slujtAnK6sJI2Jr6
riPPvEECgYEA2DgXHphkZwTGuhMMCnaDuKbv3y7iJ15oggTo8CAMfCb7sE1FEPOs
0gnYG7p8xa1HPNGx5PkQCpIIz8pMC9+0Dqxu7bX5t0D0JQDDB+8UhtGbEgXPrAF1
NHpWHil6Or/KmfF5kXe15gKkkohVFrJw0HyMnBAvSbzd/L2mwa1xOQkCgYEA0AG6
n4Im1aFOnOnHaXD6w4CP1ehysHkFoxad+EeUu9d1dfIrPlUCTwtL0tHRDR0uehA4
PaUPThFllTCuqGTXawxuAdNxsa8KttvjTPEI29dqB/4IgIYTNXqZnfrgNWC3mNLw
InyrlR8RsrRAS1R6AyWxWh9Nm0iKAKhsxgdOgIUCgYB4mUB79i/6LfXSD5GlvFjY
A3TDnVjS8JuF+csbNCUCkpPL0C13uRJpzMfXH3s8ntufFq8Msca6vp1fmMw1yz6Y
+KCeweNYzUff477ki/t8/yhpMwiUPfPro1ipViUw44zTtJZEButUMaEtghFDqZ+3
CeE7ouNdU5TVxcpfOKhwUQKBgApmm7tQGbsC5thnxCXclV1jN0394oY6dvKxtdJt
Wd2Op3vvUQQ74fKr4O24uhhKxkEqQHWspDhGHGs6VPFsoWzj4ThMJ1o4I3QDSLlX
MBc2DUI7DJfInHtHFxlUKxPgMy38Fi/TRg0d0Ze69aAOqE8x+k1EVXAXT3c69L1u
Lhm1AoGAcOJy7MewUUegFUcbg+hYTd8zXZFX5Tzl5eiExqyWxBnp2/Nuasw4950X
Xr0lSnFx2cXrqiLjgYxFQdCwaJmL0uAuYjALzKvsQaCpbNJ+kMQ28mlDp3lYHmXp
s8HGa0SNzjRLQWRMBw0dx7IAAsuyFmv/6e6jvg2ksxrUQ8ViidE=
-----END RSA PRIVATE KEY-----
`,
cert: `-----BEGIN CERTIFICATE-----
MIICmjCCAYICCQCiHtY6daqa3zANBgkqhkiG9w0BAQUFADAPMQ0wCwYDVQQKDARj
ZXJ0MB4XDTIxMDQyNjE0NDQ0MFoXDTQ4MDkxMDE0NDQ0MFowDzENMAsGA1UECgwE
Y2VydDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK+vCKBsgAtRwoej
fHY3XhWHsFim6ssHnRwlTqRf2xRj+OyiT1tumJ4PNToCv+EZF6dOzMtQdeo3hTeT
V6pn3bUBDU3JMbZiQNo+v+HdstJvWmnC5XcdWuJjc2zO/C5/bJhJNPklqen8qTdJ
IPThEd5Y0KQm/GLKYMB25yS5ZMtnOqvOEnAvDnNoYT16PwiYrdsaCN5vEgGqnw7B
wJsqndm7AQWh/bLIKWiMRkNkFhXx2STkhA+QFBDvh7iUL3q0jc8QLCyLbim1H7xr
5v7VL18ppUrZg8liMDb33Z3rqM2eVjyBD3eN7PvkCpiOapQNWfo/sHGN8xcqlDNT
XFgVIa0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAM6yKAW3NJi4unaxH5kUaqAwb
HKfeZANu8UP1n6GwpD4n/unC2EGRo5gkUVKZonErPEIv6wL6KDX1CKFT46AtSnMi
QIpNriYPdSsBsADvnwRDTlCiv667Jzjb0jnI38aBZ7vw0z+QHbplfy4Ss6Q3NkEN
HGXibAidrQrj/zptLxAsp+MYfg380uQhJHIcXbqynCozKtORFL3FcR+SDb6J3h1W
0atSlKPkAsRDTCSMQT700d3w5UaQXyx+Ac4xEuEqvZXJLKAOETBfcgsaIIVyc6H2
1khfWxkMvEEbkHQfSX8ps1G5An3jUdq2nofwgphxBCEriG1neVfbTP3ZS6mE4A==
-----END CERTIFICATE-----
`
}).listen(appConfig.port, appConfig.host !== "127.0.0.1" ? appConfig.host : undefined);
server.on("request", async function(req, res) {
req.text = async function() {
return new Promise(function(resolve, reject) {
var text = "";
req.on("data", function(chunk) {
text += chunk.toString();
});
req.on("end", function(chunk) {
resolve(text);
});
});
}
req.arrayBuffer = async function() {
return new Promise(function(resolve, reject) {
var chunkedData = Buffer.from("");
req.on("data", function(chunk) {
chunkedData = Buffer.concat([chunkedData, chunk]);
});
req.on("end", function(chunk) {
resolve(chunkedData);
});
});
}
req.headers.get = function(match) {
for (var key in req.headers) {
if (key.toLowerCase() === match.toLowerCase()) return req.headers[key];
}
};
req.url = (appConfig.noCertificate === true ? "http" : "https") + "://" + appConfig.host + ":" + appConfig.port + req.url;
console.log(req.url);
var result = await addEventListener("fetch", {request: req});
if (
app.has(result) === true
&& app.has(result.data) === true
&& app.has(result.options) === true
&& app.has(result.options.status) === true
&& app.has(result.options.headers) === true
) {
for (var key in result.options.headers) res.setHeader(key, result.options.headers[key]);
res.statusCode = result.options.status;
if (typeof result.data === "object" && app.has(result.data.byteLength) === true) {
res.end(Buffer.from(result.data, "binary"));
} else {
res.end(result.data);
}
} else {
if (app.has(app.utils) && app.has(app.utils) && app.has(app.utils.frontend) && app.has(app.utils.frontend.static)) {
app.utils.frontend.static(req, res);
} else {
res.statusCode = 400;
res.end("Could not process in local mode.");
}
}
});
console.log("Server is listening on " + appConfig.host + ":" + appConfig.port);
addEventListener = async function(action, event) {
return await app.handleRequest(event.request);
};
}
}
}
var app = {
start: function() {
}
};app.startUps = [];
app.workerStartUps= [];
app.callbacks = {static: []};app["build"] = {};app["config"] = {};app["cron"] = {"fortnox": (function() {
var mod = {
cronTime: 24 * 60 * 60,
endpoint: "https://api.airtable.com/v0/",
airtableToken: "",
ocrKey: "",
authorizationLink: "",
get headers() {
return {
"Content-Type": "application/json",
"Authorization": "Bearer " + mod.airtableToken
};
},
bases: async function() {
var result = await fetch(mod.endpoint + "meta/bases", {
headers: mod.headers
});
if (result.status === 200) {
return (await result.json()).bases;
} else {
console.log(result.status, await result.text());
}
},
getTables: async function() {
var bases = await mod.bases();
if (app.has(bases)) {
var list = [];
for (var i=0; i<=bases.length-1; i++) {
var base = bases[i];
console.log("(" + (i + 1) + "/" + bases.length + ") Checking base " + base.name);
var result = await fetch(mod.endpoint + "meta/bases/" + base.id + "/tables", {
headers: mod.headers
});
if (result.status === 200) {
var found = {base: base};
var tables = (await result.json()).tables;
for (var t=0; t<=tables.length-1; t++) {
var table = tables[t];
if (table.name.toLowerCase().trim() === "pricelist") found.pricelist = table;
if (table.name.toLowerCase().trim() === "*") found.currency = table;
}
if (app.has(found.pricelist) && app.has(found.currency)) {
list.push(found);
console.log(app.consoleColors.fgCyan, "Found: " + base.name);
}
} else {
console.log(result.status, await result.text());
}
}
return list;
}
},
getRecords: async function(table, type, offset) {
var fetchTable = table[type];
var result = await fetch(mod.endpoint + table.base.id + "/" + fetchTable.name + "?pageSize=100" + (app.has(offset) ? "&offset=" + offset : ""), {
headers: mod.headers
});
if (result.status === 200) {
var data = await result.json();
if (app.has(data.offset)) {
var moreRecords = await mod.getRecords(table, type, data.offset);
if (app.has(moreRecords)) {
for (var i=0; i<=moreRecords.length-1; i++) data.records.push(moreRecords[i]);
return data.records;
}
} else {
return data.records;
}
} else {
console.log(result.status, await result.text());
}
},
start: async function() {
var tables = await mod.getTables();
for (var i=0; i<=tables.length-1; i++) {
var table = tables[i];
var result = await fetch(mod.authorizationLink + "&base-name=" + table.base.id + "&table=Pricelist&view=Fortnox&start-only=true");
console.log(table.base.name, result.status, await result.text());
console.log("Waiting for " + mod.cronTime + " second(s)...");
await new Promise(function(resolve, reject) {
setTimeout(resolve, 1000 * 30 * 60);
});
}
setTimeout(mod.start, 1000 * mod.cronTime);
}
};
app.startUps.push(mod.start);
return mod;
})(), };app["publish"] = {};
var config = app.config;
var modules = app.modules;
app.has = function(value) {
var found = true;
for (var i=0; i<=arguments.length-1; i++) {
var value = arguments[i];
if (!(typeof value !== "undefined" && value !== null && value !== "")) found = false;
}
return found;
};
(function(left, right) {
var copyConfig = function(left, right) {
if (app.has(left) && app.has(right)) {
for (var key in left) {
var value = left[key];
if (typeof value !== "object") {
right[key] = value;
} else {
copyConfig(value, right[key]);
}
}
}
};
copyConfig(left, right);
})(appConfig.config, config);
app.response = function(data, options) {
if (typeof options === "undefined") options = {};
if (typeof options.headers === "undefined") options.headers = {};
if (!app.has(options.headers["Access-Control-Allow-Origin"])) options.headers["Access-Control-Allow-Origin"] = "*";
if (!app.has(options.headers["Access-Control-Allow-Headers"])) options.headers["Access-Control-Allow-Headers"] = "content-type, content";
if (!app.has(options.headers["Access-Control-Allow-Methods"])) options.headers["Access-Control-Allow-Methods"] = "HEAD, GET, PUT, DELETE, POST, OPTIONS";
if (
typeof Response !== "undefined"
&& !(
typeof __dirname !== "undefined"
&& __dirname.toLowerCase().split("/users/").length > 1
)
&& app.has(appConfig.workerName)
) {
return new Response(data, options);
} else {
return {data: data, options: options};
}
};
app.logAndResponse = function(data, options) {
console.log(data);
return app.response(data, options);
},
app.camelCase = function camelize(str, capitalFirst) {
if (!app.has(capitalFirst)) capitalFirst = false;
var result = str.replace(/(?:^\w|[A-Z]|\b\w)/g, function(word, index) {
return index === 0 ? word.toLowerCase() : word.toUpperCase();
}).replace(/\s+/g, '');
if (capitalFirst) result = result.substr(0, 1).toUpperCase() + result.substr(1, 999);
return result;
};
app.properCase = function(str) {
return str.replace(
/\w\S*/g,
function(txt) { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); }
);
};
if (app.has(app.api) === true) { (function() {
var callbackLevel = function(apiLevel) {
if (app.has(apiLevel) && !app.has(apiLevel.length)) {
for (var moduleName in apiLevel) {
if (app.has(apiLevel[moduleName]) === true) {
callbackLevel(apiLevel[moduleName]);
for (var key in apiLevel[moduleName]) {
(function(moduleName, key) {
var func = apiLevel[moduleName][key];
if (key.split("Callback").length > 1 && typeof func === "function") {
apiLevel[moduleName][key.split("Callback").shift() + "Multi"] = async function(count, name, callback, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) {
return new Promise(function(resolve, reject) {
if (!app.has(count)) count = 1;
var rCount = 0;
var resolveCount;
for (var i=0; i<=count-1; i++) {
(async function(index) {
var countResult = await apiLevel[moduleName][key.split("Callback").shift()](name, async function(arg1, arg2, arg3, arg4, arg5) {
if (typeof callback === "function") {
var result = await callback(arg1, arg2, arg3, arg4, arg5);
if (result === true && !app.has(resolveCount)) {
console.log("MULTI INDEX:", index);
resolveCount = index;
}
return result;
}
}, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15);
rCount += 1;
if (resolveCount === index || rCount >= count) resolve(countResult);
})(i);
}
});
};
apiLevel[moduleName][key.split("Callback").shift()] = async function(name, callback, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15) {
if (typeof callback !== "function") {
arg15 = arg13; arg14 = arg12; arg13 = arg11; arg12 = arg10; arg11 = arg9; arg10 = arg8;arg9 = arg7; arg8 = arg6; arg7 = arg5; arg6 = arg4; arg5 = arg3; arg4 = arg2; arg3 = arg1; arg2 = callback; arg1 = name;
}
var output, error;
await apiLevel[moduleName][key](async function(data, page) {
var result = typeof callback === "function" ? await callback(data, page) : undefined;
if (app.has(result) && app.has(result.length)) {
if (!app.has(output)) output = [];
output = output.concat(result);
} else {
output = data;
}
return result;
}, function(err, errorText) {
error = {error: err, errorText};
}, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15);
var obj = {};
if (typeof callback !== "function") return output;
obj[name] = output;
obj.error = error;
return obj;
};
}
})(moduleName, key);
}
}
}
}
};
callbackLevel(app.api);
})();
}
app.handleRequest = async function(request) {
if (typeof request === "undefined") return false;
var url = new URL(request.url);
if (request.method === "OPTIONS") return app.response("Ok", {status: 200});
if (app.has(config) && app.has(config.api) && app.has(config.api.authorization)) {
var authorization = app.has(request.headers) ? (app.has(request.headers.get) ? request.headers.get("authorization") : request.headers.authorization) : "";
if (!app.has(authorization)) authorization = url.searchParams.get("authorization");
if (typeof config.api.authorization === "string") {
if (authorization !== config.api.authorization) return app.response("Unauthorized.", {status: 400});
} else {
if (typeof config.api.authorization === "object" && config.api.authorization !== null) {
if (app.has(config.api.authorization.length)) {
if (config.api.authorization.indexOf(authorization) < 0) return app.response("Unauthorized.", {status: 400});
} else {
if (!app.has(config.api.authorization[authorization])) return app.response("Unauthorized.", {status: 400});
request.condition = config.api.authorization[authorization];
}
}
}
}
var parts = url.pathname.split("/");
parts.shift();
if (parts.length === 1 && parts[0].trim() === "") parts[0] = "index";
if (app.indexMode === true) parts = ["index"];
if (parts.length > 0 && parts[0].trim() !== "") {
var level = app;
for (var i=0; i<=parts.length-1; i++) {
var part = app.camelCase(parts[i].trim().split("-").join(" "));
if (typeof level[part] !== "undefined" || typeof level["indexDynamic"] !== "undefined") {
level = !(level === app && typeof level["indexDynamic"] !== "undefined") ? level[part] : level;
if (i === parts.length-1) {
if (typeof level === "object" && level !== null && typeof level["index"] === "function") {
var caller = {};
caller[part] = async function() { return await level["index"](request); }
if (!app.has(request.headers.get("start-only"))) {
return await caller[part]();
} else {
caller[part]();
return app.response("Started.", {status: 200});
}
}
if (typeof level === "function") {
var caller = {};
caller[part] = async function() { return await level(request); }
if (!app.has(request.headers.get("start-only"))) {
return await caller[part]();
} else {
caller[part]();
return app.response("Started.", {status: 200});
}
}
}
if (typeof level === "object" && level !== null && typeof level["indexDynamic"] === "function") {
var caller = {};
caller[part] = async function() { return await level["indexDynamic"](request); }
if (!app.has(request.headers.get("start-only"))) {
return await caller[part]();
} else {
caller[part]();
return app.response("Started.", {status: 200});
}
}
}
}
}
if (typeof localMode === "undefined" || localMode !== true) return app.response("Unknown request: " + url.pathname, {status: 400});
};
if (typeof localMode === "undefined" && typeof addEventListener !== "undefined") {
addEventListener('fetch', event => {
event.respondWith(app.handleRequest(event.request));
});
}
app.consoleColors = {
reset: "\x1b[0m%s\x1b[0m",
bright: "\x1b[1m%s\x1b[0m",
dim: "\x1b[2m%s\x1b[0m",
underscore: "\x1b[4m%s\x1b[0m",
blink: "\x1b[5m%s\x1b[0m",
reverse: "\x1b[7m%s\x1b[0m",
hidden: "\x1b[8m%s\x1b[0m",
fgBlack: "\x1b[30m%s\x1b[0m",
fgRed: "\x1b[31m%s\x1b[0m",
fgGreen: "\x1b[32m%s\x1b[0m",
fgYellow: "\x1b[33m%s\x1b[0m",
fgBlue: "\x1b[34m%s\x1b[0m",
fgMagenta: "\x1b[35m%s\x1b[0m",
fgCyan: "\x1b[36m%s\x1b[0m",
fgWhite: "\x1b[37m%s\x1b[0m",
fgGray: "\x1b[90m%s\x1b[0m",
bgBlack: "\x1b[40m%s\x1b[0m",
bgRed: "\x1b[41m%s\x1b[0m",
bgGreen: "\x1b[42m%s\x1b[0m",
bgYellow: "\x1b[43m%s\x1b[0m",
bgBlue: "\x1b[44m%s\x1b[0m",
bgMagenta: "\x1b[45m%s\x1b[0m",
bgCyan: "\x1b[46m%s\x1b[0m",
bgWhite: "\x1b[47m%s\x1b[0m",
bgGray: "\x1b[100m%s\x1b[0m"
};
app["bundle"] = {"console": (function() {
if (typeof require !== "undefined") var fetch = require("https");
if (app.has(config.console)) {
console.oldLog = console.log;
console.log = function() {
var stack = (function() {
Error.stackTraceLimit = 9999;
var e = new Error();
if (e.stack.split("\n").length > 2) {
var line = e.stack.split("\n")[3].split(" ").pop().split(":");
return { full: e.stack, filepath: line[0], line: line[1], column: line[2].split(")").join("") };
} else {
return { full: e.stack, filepath: "", line: 0, column: 0 };
}
})();
console.oldLog.apply("test", arguments);
var args = [];
for (var key in arguments) {
var value = arguments[key];
if (typeof value === "object") value = JSON.stringify(value);
args.push(value);
}
var consoleConfig = JSON.parse(JSON.stringify(config.console));
consoleConfig.channel = config.console.channel;
var data = JSON.stringify({
channel: typeof consoleConfig.channel === "function" ? consoleConfig.channel(stack, arguments) : consoleConfig.channel,
args: args,
command: "",
level: "log",
browser: {"browser": {"f": "NodeJs", "s": "NJ"}, "version": process.versions.node, "OS": consoleConfig.os},
caller: {file: stack.filepath.split(__dirname).pop(), line: stack.line, col: stack.column}
});
consoleConfig.connection.headers = {
'Content-Length': data.length
};
var request = fetch.request(consoleConfig.connection, function(response) {
response.on("data", function(chunk) {
});
});
request.write(data);
request.end();
};
}
return {};
})(), "cron": {"process": (function() {
return function(options) {
var mod = {
loop: function() {
if (app.has(options.property)) {
var property = app.bundle.utils.object.level(app, options.property);
if (app.has(property)) {
console.log("CRON: " + JSON.stringify(options));
property();
}
}
setTimeout(mod.loop, options.time * 1000);
}
};
setTimeout(mod.loop, options.time * 1000);
return mod;
};
})(), "run": (function() {
var mod = {
start: function() {
if (typeof appConfig !== "undefined" && app.has(appConfig.cron)) {
console.log("CRON SETUP: " + JSON.stringify(appConfig.cron));
for (var i=0; i<=appConfig.cron.list.length-1; i++) {
app.bundle.cron.process(appConfig.cron.list[i]);
}
}
}
};
app.startUps.push(mod.start);
return mod;
})(), }, "socket": (function() {
var mod = {
socketIO: typeof require !== "undefined" ? require('socket.io') : undefined,
list: {},
events: {},
sockets: {
list: [],
add: function(obj) {
for (var key in obj) {
(function(key) {
if (key.split("event").shift() === "" && key.split("User").pop() !== "" && typeof obj[key] === "function") {
var eventName = app.camelCase(key.split("event").pop());
obj[eventName] = async function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, userKey) {
var length = app.bundle.utils.socket.countArguments(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
var eventKey = eventName.split("global").shift() === "" ? eventName : app.bundle.utils.socket.key(eventName, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, length);
var events = mod.events[eventKey];
if (app.has(events)) {
for (var token in events) {
var socket = mod.list[token];
if (
app.has(socket)
&& (
!app.has(userKey)
|| (app.has(userKey, socket.user) && socket.user.key === userKey)
)
) {
socket.socket.emit(eventName, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
}
}
}
}
obj[eventName + "User"] = async function(userKey, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) {
obj[eventName](arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, userKey);
}
}
})(key);
}
mod.sockets.list.push(obj);
},
listen: function(socket, token) {
for (var i=0; i<=mod.sockets.list.length-1; i++) {
(function(index) {
var obj = mod.sockets.list[index];
for (var key in obj) {
(function(key) {
if (key.split("event").shift() === "" && key.split("User").pop() !== "" && typeof obj[key] === "function") {
var eventName = app.camelCase(key.split("event").pop());
socket.socket.on(eventName, async function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) {
var eventKey = eventName.split("global").shift() === "" ? eventName : app.bundle.utils.socket.key(eventName, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
if (!app.has(mod.events[eventKey])) mod.events[eventKey] = {};
if (app.has(token)) mod.events[eventKey][token] = true;
await obj[key](arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
if (app.has(obj[key + "User"]) && typeof obj[key + "User"] === "function" && app.has(socket.user)) await obj[key + "User"](socket, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
});
}
})(key);
}
})(i);
}
},
load: function(parent, level) {
if (!app.has(level)) level = 0;
for (var key in parent) {
var obj = parent[key];
if (app.has(obj) && app.has(obj.constructor) && app.has(obj.constructor.name) && obj.constructor.name.toLowerCase() === "object") {
if (app.has(obj) && !app.has(obj.length)) {
if (key === "socket" && level > 0) {
mod.sockets.add(obj);
} else {
if (key !== "utils" && key !== "config" && key !== "frontend") mod.sockets.load(obj, level + 1);
}
}
}
}
}
},
connection: function(socket) {
var token;
socket.on("connection-established", async function(tabToken, user) {
if (app.has(user)) {
user = await app.utils.user.getByKeyAndToken(user.key, user.token);
} else {
user = undefined;
}
token = tabToken;
mod.sockets.listen({user: user, socket: socket}, token);
mod.list[token] = {user: user, socket: socket};
socket.emit("connection-established", "You are allowed!");
});
socket.on("disconnect", function() {
delete mod.list[token];
});
},
start: function() {
mod.sockets.load(app);
mod.socket = mod.socketIO(server, {
cors: {
origin: "*",
methods: ["GET", "POST"]
}
});
console.log("Web socket is listening on same server.");
mod.socket.on("connection", mod.connection);
}
};
if (typeof localMode !== "undefined") app.startUps.push(mod.start);
return mod;
})(), "syncer": {"airtable": (function() {
return async function(db, configKey, itemKey, table, fields) {
if (!app.has(db.list)) db.list = {};
var mod = {
records: async function(callbacks, sourceRecords, records) {
if (typeof itemKey === "string") {
var str = itemKey;
itemKey = {left: str, right: str};
};
if (!app.has(sourceRecords)) sourceRecords = {};
var i = 0;
for (sourceKey in sourceRecords) {
var sourceRecord = sourceRecords[sourceKey];
if (app.has(callbacks.sourceRecord)) {
var pRecord = sourceRecord;
sourceRecord = await callbacks.sourceRecord(sourceRecord);
if (sourceRecord === false) continue;
if (!app.has(sourceRecord)) sourceRecord = pRecord;
}
var record = app.utils.object.exists(records, itemKey.right, sourceRecord[itemKey.left]);
var method = "PATCH";
if (app.has(record)) {
record = JSON.parse(JSON.stringify(record));
record.fields = {};
for (var key in record) {
if (key !== "id" && key !== "fields") {
record.fields[key] = record[key];
delete record[key];
}
}
}
var oRecord = app.has(record) ? JSON.parse(JSON.stringify(record)) : undefined;
if (!app.has(record)) {
method = "POST";
record = {fields: {}};
}
for (var f=0; f<=fields.length-1; f++) record.fields[fields[f]] = sourceRecord[fields[f]];
for (var key in record.fields) {
if (fields.indexOf(key) < 0) delete record.fields[key];
}
record.fields[itemKey.right] = sourceRecord[itemKey.left];
var changed = undefined;
if (app.has(oRecord)) changed = app.utils.object.changed(sourceRecord, oRecord.fields, Object.keys(record.fields), [itemKey.right]);
if (!app.has(oRecord) || app.has(changed)) {
if (app.has(changed)) {
console.log("CHANGED: " + sourceRecord[itemKey.left] + ": " + changed);
if (app.has(sourceRecord.Status)) {
delete record.fields.Status;
if (changed.toLowerCase() === "status") {
console.log("(" + (i + 1) + "/" + Object.keys(sourceRecords).length + ") " + table + " skipped status: " + sourceRecord[itemKey.left]);
continue;
}
}
} else {
console.log("NEW: " + sourceRecord[itemKey.left]);
}
if (app.has(record.createdTime)) delete record.createdTime;
var {result, error} = await app.api.airtable.request("result", function(json, page) {}, table, "Grid view", [], method, {records: [record]}, undefined, undefined, configKey);
if (!error) {
console.log("(" + (i + 1) + "/" + Object.keys(sourceRecords).length + ") " + table + " updated: " + sourceRecord[itemKey.left]);
if (app.has(callbacks.updateRecord)) {
await callbacks.updateRecord(result);
}
} else {
console.log("(" + (i + 1) + "/" + Object.keys(sourceRecords).length + ") " + "Could not update " + table + ": " + sourceRecord[itemKey.left], error);
}
} else {
}
i += 1;
}
},
fill: function(records) {
for (var i=0; i<=records.length-1; i++) {
var record = records[i];
db.list[record.fields[itemKey.right]] = record.fields;
db.list[record.fields[itemKey.right]].id = record.id;
if (app.has(db.fill)) db.fill(db.list[record.fields[itemKey.right]], record.fields[itemKey.right]);
}
},
syncFrom: async function() {
var {records, error} = await app.api.airtable.requestDynamic(configKey)("records", function(json, page) {
return json.records;
}, table, "Grid view");
if (app.has(error)) return app.logAndResponse("Could not load " + table + " records from Airtable.", {status: 400});
mod.fill(records);
if (app.has(db.syncFrom)) await db.syncFrom();
if (app.has(db.filled)) db.filled({initial: true});
return app.logAndResponse("Loaded: " + table + " from Airtable: " + records.length + " record(s).", {status: 200});
},
syncTo: async function(callbacks, sourceRecords) {
if (!app.has(callbacks.updateRecord)) {
callbacks.updateRecord = function(data) {
mod.fill(data.records);
}
}
await mod.records(callbacks, sourceRecords, db.list);
if (app.has(db.filled)) db.filled();
}
};
var result = await mod.syncFrom();
db.loaded = result.options.status === 200;
return mod;
}
})(), "instances": (function() {
var instances = {
add: function(instanceName, syncInternal) {
if (!app.has(syncInternal)) syncInternal = false;
var mod = {
list: {},
search: function(callback) {
var list = {};
for (var key in mod.list) {
var item = mod.list[key];
if (callback(item)) {
list[item.key] = item;
}
}
return app.utils.object.sort(list);
},
syncTo: async function(callbacks, sourceRecords, list, waitTime) {
if (syncInternal || mod.count <= 1) {
for (var key in mod) {
if (mod.keys.indexOf(key) < 0 && app.has(mod[key].instance)) {
await mod[key].syncTo(callbacks, sourceRecords, (app.has(list) ? list : mod[key].list), waitTime);
}
}
} else {
console.log("Multiple instances, use syncInternal.");
}
},
fill: function() {},
filled: function() {},
filledAll: function() {},
index: 0,
get count() {
var count = 0;
for (var key in mod) {
if (mod.keys.indexOf(key) < 0) {
count += 1;
}
}
return count;
},
db: function(type, name, sourceDb) {
var db = {
type: type,
name: name,
source: sourceDb,
get loaded() {
return db._loaded;
},
set loaded(value) {
db._loaded = db.source.loaded = value;
mod.index += 1;
if (mod.index === mod.count) {
console.log("Total: " + instanceName + ": " + Object.keys(mod.list).length);
if (app.has(mod.filledAll)) mod.filledAll();
if (syncInternal) mod.syncTo({}, db.source.list);
}
},
syncFrom: function() {
if (app.has(db.source.syncFrom)) db.source.syncFrom();
},
fill: function(record, key) {
mod.list[key] = db.source.list[key] = record;
if (app.has(mod.fill)) mod.fill(record, key);
},
filled: function(options) {
if (!app.has(options)) options = {};
if (app.has(mod.filled)) mod.filled(options);
}
};
return db;
},
add: async function(type, db, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) {
if (app.has(type)) {
if (typeof type === "object") {
var {type, name} = type;
}
if (app.has(type)) {
if (!app.has(db.list)) db.list = {};
if (!app.has(name)) name = type;
var obj = mod.db(type, name, db);
mod[name] = {};
var syncer = await app.bundle.syncer[type](obj, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
obj.instance = syncer;
obj.syncTo = async function(callbacks, sourceRecords, list, waitTime) {
return new Promise(function(resolve, reject) {
setTimeout(async function() {
await syncer.syncTo(callbacks, sourceRecords, list, waitTime);
resolve();
}, 1);
});
};
mod[name] = obj;
}
}
}
};
mod.keys = [];
mod.keys = Object.keys(mod);
return mod;
}
};
return instances;
})(), "mysql": (function() {
return async function(db, idName, itemKey, table, fields) {
if (!app.has(db.list)) db.list = {};
var mod = {
records: async function(callbacks, sourceRecords, records, waitTime) {
if (!app.has(waitTime)) waitTime = 10;
if (typeof itemKey === "string") {
var str = itemKey;
itemKey = {left: str, right: str};
};
if (!app.has(sourceRecords)) sourceRecords = {};
var i = 0;
var time = new Date().getTime();
for (sourceKey in sourceRecords) {
var label = "(" + (i + 1) + "/" + Object.keys(sourceRecords).length + ") ";
var sourceRecord = sourceRecords[sourceKey];
if (app.has(callbacks.sourceRecord)) {
var pRecord = sourceRecord;
sourceRecord = await callbacks.sourceRecord(sourceRecord);
if (sourceRecord === false) continue;
if (!app.has(sourceRecord)) sourceRecord = pRecord;
}
var record = app.utils.object.exists(records, itemKey.right, sourceRecord[itemKey.left]);
var oRecord = app.has(record) ? app.bundle.utils.object.copy(record, false) : undefined;
if (!app.has(record)) record = sourceRecord;
for (var key in sourceRecord) record[key] = sourceRecord[key];
var changed = undefined;
if (!app.has(fields) || (app.has(fields, fields.length) && fields.length <= 0)) {
fields = [];
for (var key in oRecord) if (key !== idName) fields.push(key);
}
if (app.has(oRecord)) changed = app.utils.object.changed(sourceRecord, oRecord, fields, [itemKey.right]);
if (!app.has(oRecord) || app.has(changed)) {
var saveLabel = label;
if (app.has(changed)) {
saveLabel = label + table + ": CHANGED: " + sourceRecord[itemKey.left] + ": " + changed;
if (app.has(sourceRecord.Status)) {
delete record.Status;
if (changed.toLowerCase() === "status") {
console.log(label + table + " skipped status: " + sourceRecord[itemKey.left]);
continue;
}
}
} else {
saveLabel = label + table + ": NEW: " + sourceRecord[itemKey.left];
}
console.log(saveLabel);
app.workers.syncer.call("app.utils.mysql.save", idName, table, record, !app.has(changed), undefined, true);
if (app.has(callbacks.updateRecord)) callbacks.updateRecord([record]);
} else {
}
i += 1;
if (app.has(waitTime) && waitTime > 0) await new Promise(function(resolve, reject) { setTimeout(resolve, waitTime); });
}
},
fill: function(records) {
for (var i=0; i<=records.length-1; i++) {
var record = records[i];
var oldRecord = db.list[record[itemKey.right]];
if (!app.has(oldRecord)) oldRecord = {};
var changed = app.utils.object.changed(record, oldRecord, Object.keys(record), [idName]);
if (app.has(changed)) {
db.list[record[itemKey.right]] = app.bundle.utils.object.copy(record, false);
if (app.has(db.fill)) db.fill(db.list[record[itemKey.right]], record[itemKey.right]);
}
}
},
syncFrom: async function() {
var {records, error} = await app.api.mysql.request("records", function() { return false; }, `
SELECT
t.*
FROM \`` + table + `\` t
`, "multiple");
if (app.has(error)) return app.logAndResponse("Could not load " + table + " records from MySql.", {status: 400});
mod.fill(records);
if (app.has(db.syncFrom)) await db.syncFrom();
if (app.has(db.filled)) db.filled({initial: true});
return app.logAndResponse("Loaded: " + table + " from MySql: " + records.length + " record(s).", {status: 200});
},
syncTo: async function(callbacks, sourceRecords, list, waitTime) {
if (!app.has(list)) list = db.list;
if (!app.has(callbacks.updateRecord)) {
callbacks.updateRecord = function(data) {
mod.fill(data);
}
}
await mod.records(callbacks, sourceRecords, list, waitTime);
if (app.has(db.filled)) db.filled();
}
};
(async function() {
var result = await mod.syncFrom();
db.loaded = result.options.status === 200;
})();
return mod;
}
})(), "syncer": (function() {
var mod = {
add: async function(obj) {
if (app.has(obj.key, obj.addList)) {
var syncer = await app.bundle.syncer.instances.add(obj.key);
for (var key in obj.addList) {
var db = obj.addList[key];
if (app.has(db.options, db.source, db.idName, db.key, db.table)) {
db.options.name = key;
await syncer.add(db.options, (typeof db.source === "function" ? db.source() : db.source), db.idName, db.key, db.table);
}
}
for (var key in obj) {
if (typeof obj[key] === "function") {
if (syncer.keys.indexOf(key) < 0) syncer.keys.push(key);
syncer[key] = obj[key];
}
}
for (var key in syncer) {
obj[key] = syncer[key];
}
if (app.has(obj.started)) obj.started();
}
},
load: function(parent, level) {
if (!app.has(level)) level = 0;
for (var key in parent) {
var obj = parent[key];
if (app.has(obj) && app.has(obj.constructor) && app.has(obj.constructor.name) && obj.constructor.name.toLowerCase() === "object") {
if (app.has(obj) && !app.has(obj.length)) {
if (key === "syncer" && level > 0) {
mod.add(obj);
} else {
if (key !== "utils" && key !== "config" && key !== "frontend") mod.load(obj, level + 1);
}
}
}
}
},
start: function() {
mod.load(app);
}
};
if (typeof localMode !== "undefined") app.startUps.push(mod.start);
return mod;
})(), "worker": (function() {
var mod = {
name: "syncer",
onWorkerMessage: function(message) {
console.log(mod.name, message);
}
};
return mod;
})(), }, "utils": {"object": (function() {
var mod = {
level: function(list, key) {
var keys = key.split(".");
var item = list[keys.shift()];
if (app.has(item)) {
if (keys.length > 0) {
return mod.level(item, keys.join("."));
} else {
return item;
}
}
},
copy: function(left, json) {
if (!app.has(json)) json = true;
if (json) return JSON.parse(JSON.stringify(left));
var right = {};
for (var key in left) right[key] = left[key];
return right;
}
};
return mod;
})(), "socket": (function() {
var mod = {
key: function(eventName, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, length) {
if (!app.has(length)) length = arguments.length;
var str = "";
for (var i=0; i<=length-1; i++) {
if (app.has(arguments[i])) {
if (app.has(str)) str += "-";
str += JSON.stringify(arguments[i]);
}
}
return str;
},
countArguments: function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) {
for (var i=0; i<=10-1; i++) {
if (!app.has(arguments[i])) return i;
}
return 10;
}
};
return mod;
})(), }, "worker": (function() {
return {};
var mod = {
name: "default",
add: function(obj) {
if (!app.has(app.workers)) app.workers = {};
app.workers[obj.name] = obj;
if (workerThreads.isMainThread) {
obj.instance = new workerThreads.Worker(__filename, {argv: [obj.name]});
if (app.has(obj.onMessage)) {
obj.instance.once("message", function(message) {
obj.onMessage(message.message);
});
}
obj.sendWorkerMessage = function(message, type) {
obj.instance.postMessage({name: obj.name, type: type, message: message});
};
obj.sendWorkerMessage("worker-started");
obj.call = function(route) {
if (typeof route === "string") {
var paths = route.split(".");
var func = app;
for (var i=0; i<=paths.length-1; i++) {
if (app.has(func[paths[i]])) func = func[paths[i]];
}
var args = [].slice.call(arguments, 1);
if (typeof func === "function") func(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
}
};
} else {
obj.sendMessage = function(message) {
workerThreads.parentPort.postMessage({name: obj.name, message: message});
};
}
},
onMessage: function(message) {
},
onWorkerMessage: function(message) {
},
load: function(parent, level) {
if (!app.has(level)) level = 0;
for (var key in parent) {
var obj = parent[key];
if (app.has(obj) && app.has(obj.constructor) && app.has(obj.constructor.name) && obj.constructor.name.toLowerCase() === "object") {
if (app.has(obj) && !app.has(obj.length)) {
if (key === "worker" && level > 0) {
mod.add(obj);
} else {
if (key !== "utils" && key !== "config" && key !== "frontend") mod.load(obj, level + 1);
}
}
}
}
},
start: function() {
mod.load(app);
if (!workerThreads.isMainThread) {
var workerName = process.argv[2];
workerThreads.parentPort.once('message', function(message) {
if (workerName === message.name && app.has(app.workers[message.name]) && app.has(app.workers[message.name].onWorkerMessage)) app.workers[message.name].onWorkerMessage(message.message);
});
}
}
};
if (typeof workerThreads !== "undefined") {
app.startUps.push(mod.start);
app.workerStartUps.push(mod.start);
}
return mod;
})(), };
if (typeof app.start === "function") {
app.start();
}
if ((typeof localMode !== "undefined" && workerThreads.isMainThread) || typeof localMode === "undefined") {
for (var i=0; i<=app.startUps.length-1; i++) {
if (typeof app.startUps[i] === "function") {
app.startUps[i]();
}
}
for (var i=0; i<=app.startUps.length-1; i++) {
if (!(typeof app.startUps[i] === "function")) {
if (
typeof localMode !== "undefined"
|| (typeof appConfig !== "undefined" && app.has(appConfig.frontend) && appConfig.frontend)
) setTimeout(app.startUps[i].callback, app.startUps[i].time);
}
}
}
if (typeof workerThreads !== "undefined" && !workerThreads.isMainThread) {
for (var i=0; i<=app.workerStartUps.length-1; i++) {
if (typeof app.workerStartUps[i] === "function") {
app.workerStartUps[i]();
}
}
}})();
Lightweight version (Make changes accordingly):
function() {
var mod = {
cronTime: 24 * 60 * 60,
endpoint: "https://api.airtable.com/v0/",
airtableToken: "",
ocrKey: "",
authorizationLink: "",
get headers() {
return {
"Content-Type": "application/json",
"Authorization": "Bearer " + mod.airtableToken
};
},
bases: async function() {
var result = await fetch(mod.endpoint + "meta/bases", {
headers: mod.headers
});
if (result.status === 200) {
return (await result.json()).bases;
} else {
console.log(result.status, await result.text());
}
},
getTables: async function() {
var bases = await mod.bases();
if (app.has(bases)) {
var list = [];
for (var i=0; i<=bases.length-1; i++) {
var base = bases[i];
console.log("(" + (i + 1) + "/" + bases.length + ") Checking base " + base.name);
var result = await fetch(mod.endpoint + "meta/bases/" + base.id + "/tables", {
headers: mod.headers
});
if (result.status === 200) {
var found = {base: base};
var tables = (await result.json()).tables;
for (var t=0; t<=tables.length-1; t++) {
var table = tables[t];
if (table.name.toLowerCase().trim() === "pricelist") found.pricelist = table;
if (table.name.toLowerCase().trim() === "*") found.currency = table;
}
if (app.has(found.pricelist) && app.has(found.currency)) {
list.push(found);
console.log(app.consoleColors.fgCyan, "Found: " + base.name);
// break;
}
} else {
console.log(result.status, await result.text());
}
}
return list;
}
},
getRecords: async function(table, type, offset) {
var fetchTable = table[type];
var result = await fetch(mod.endpoint + table.base.id + "/" + fetchTable.name + "?pageSize=100" + (app.has(offset) ? "&offset=" + offset : ""), {
headers: mod.headers
});
if (result.status === 200) {
var data = await result.json();
if (app.has(data.offset)) {
var moreRecords = await mod.getRecords(table, type, data.offset);
if (app.has(moreRecords)) {
for (var i=0; i<=moreRecords.length-1; i++) data.records.push(moreRecords[i]);
return data.records;
}
} else {
return data.records;
}
} else {
console.log(result.status, await result.text());
}
},
start: async function() {
var tables = await mod.getTables();
for (var i=0; i<=tables.length-1; i++) {
var table = tables[i];
var result = await fetch(mod.authorizationLink + "&base-name=" + table.base.id + "&table=Pricelist&view=Fortnox&start-only=true");
console.log(table.base.name, result.status, await result.text());
console.log("Waiting for " + mod.cronTime + " second(s)...");
await new Promise(function(resolve, reject) {
setTimeout(resolve, 1000 * 30 * 60);
});
}
setTimeout(mod.start, 1000 * mod.cronTime);
}
};
app.startUps.push(mod.start);
return mod;
}