UNPKG

forestdb

Version:

An uncomplicated real-time database with encrypted HTTP and WebSocket server-client communication, fast caching, state management, a cross-runtime file system manager, and more, working seamlessly on both frontend and backend.

1,331 lines (1,330 loc) 557 kB
// src/crypto.ts var _key_len_ = 32; var isKeyValidFunc = (x) => { return /^[a-zA-Z0-9]+$/.test(x.pkey); }; var bufferToHexFunc = (x) => { const byteArray = new Uint8Array(x.data); let hexString = ""; for (let i = 0; i < byteArray.length; i++) { const hex = byteArray[i].toString(16).padStart(2, "0"); hexString += hex; } return hexString; }; var hexToBufferFunc = (x) => { const hex = x.data, len = hex.length, buffer = new Uint8Array(len / 2); for (let i = 0; i < len; i += 2) { buffer[i / 2] = parseInt(hex.substr(i, 2), 16); } return buffer; }; var cipherStringToChunksFunc = (x) => { const data = x.data, dataLength = data.length; let len = 0; const dv = Math.ceil(dataLength / 8); len = dv < 5 ? 5 : dv; let tab = []; for (let i = 0; i < dataLength; i += len) { tab.push(data.slice(i, i + len)); } const res = String(tab.length) + String(tab.length > 1 ? tab.join("-") : tab[0]); return res; }; var L2_cipherMixerFunc = (x) => { const data = x.data, key = x.key, iv = x.iv, authTag = x.authTag; const ignoreKey = x.ignoreKey; const inversed0 = data.split("").reverse().join(""); const dataChunks = cipherStringToChunksFunc({ data: inversed0 }); let keyChunks = ""; if (!ignoreKey) { const inversed1 = key.split("").reverse().join(""); keyChunks = cipherStringToChunksFunc({ data: inversed1 }); } const inversed2 = iv.split("").reverse().join(""); const ivChunks = cipherStringToChunksFunc({ data: inversed2 }); const inversed3 = authTag.split("").reverse().join(""); const authTagChunks = cipherStringToChunksFunc({ data: inversed3 }); const tab = ignoreKey ? [ivChunks, authTagChunks, dataChunks] : [ivChunks, authTagChunks, dataChunks, keyChunks]; const res = tab.join("-"); return res; }; var L2_cipherDemixerFunc = (x) => { let data = x.data, tab = data.split("-"); const ignoreKey = x.ignoreKey; const n1 = parseInt(data[0]); const d1 = tab.splice(0, n1).join(""); const iv = d1.slice(1).split("").reverse().join(""); data = tab.join("-"); tab = data.split("-"); const n2 = parseInt(data[0]); const d2 = tab.splice(0, n2).join(""); const authTag = d2.slice(1).split("").reverse().join(""); data = tab.join("-"); tab = data.split("-"); const n3 = parseInt(data[0]); const d3 = tab.splice(0, n3).join(""); const data1 = d3.slice(1).split("").reverse().join(""); data = tab.join("-"); tab = data.split("-"); let key = ""; if (!ignoreKey) { const n4 = parseInt(data[0]); const d4 = tab.splice(0, n4).join(""); key = d4.slice(1).split("").reverse().join(""); } return { data: data1, key, iv, authTag }; }; var web_createHashFunc = async (x) => { const data = x.data; const encodedData = new TextEncoder().encode(data); const hashBuffer = await crypto.subtle.digest("SHA-256", encodedData); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join(""); return hashHex; }; var web_generateKeyFunc = async () => { return await crypto.subtle.generateKey({ name: "AES-GCM", length: 128 }, true, ["encrypt", "decrypt"]); }; var web_cipherFunc = async (x) => { try { if (typeof x.data !== "string") throw new Error(`Data to encrypt is not a string`); const data = x.data; const pkey = x.privateKey ?? void 0; if (pkey !== void 0 && typeof pkey !== "string") throw new Error(`Invalid key "${pkey}"`); if (typeof pkey === "string") { if (pkey.length !== _key_len_) throw new Error(`Invalid key length "${pkey.length}" - The valid key length is "${_key_len_}"`); if (!isKeyValidFunc({ pkey })) throw new Error(); } const encoder = new TextEncoder(); const fpk = pkey !== void 0 ? hexToBufferFunc({ data: pkey }) : void 0; const key = fpk !== void 0 ? await crypto.subtle.importKey("raw", fpk, { name: "AES-GCM" }, true, ["encrypt", "decrypt"]) : await web_generateKeyFunc(); const iv = crypto.getRandomValues(new Uint8Array(12)); const tagLength = 128; const text = encoder.encode(data); const ciphertext = await crypto.subtle.encrypt({ name: "AES-GCM", iv, tagLength }, key, text); const authTagLength = 16; const ciphertextArray = new Uint8Array(ciphertext); const authTagIndex = ciphertextArray.length - authTagLength; const authTag = ciphertextArray.slice(authTagIndex); let keyExported = await crypto.subtle.exportKey("raw", key); const encryptedTextOnly = ciphertext.slice(0, authTagIndex); const res = bufferToHexFunc({ data: encryptedTextOnly }); const fkey = bufferToHexFunc({ data: keyExported }); const fiv = bufferToHexFunc({ data: iv }); const fauthTag = bufferToHexFunc({ data: authTag }); const mix = L2_cipherMixerFunc({ data: res, key: fkey, iv: fiv, authTag: fauthTag, ignoreKey: fpk !== void 0 ? true : false }); return { status: "success", log: "", data: mix }; } catch (e) { return { status: "error", log: e.message, data: e.message }; } }; var web_decipherFunc = async (x) => { try { if (typeof x.data !== "string") throw new Error(`Data to decrypt is not a string`); const pkey = x.privateKey ?? void 0; if (pkey !== void 0 && typeof pkey !== "string") throw new Error(`Invalid key "${pkey}"`); const demixed = L2_cipherDemixerFunc({ data: x.data, ignoreKey: pkey !== void 0 ? true : false }); const data = demixed.data, key = pkey !== void 0 ? pkey : demixed.key, iv = demixed.iv, authTag = demixed.authTag; const bdata = hexToBufferFunc({ data: data + authTag }); const bkey = hexToBufferFunc({ data: key }); const biv = hexToBufferFunc({ data: iv }); const dkey = await crypto.subtle.importKey("raw", bkey, "AES-GCM", true, ["decrypt"]); const decrypted = await crypto.subtle.decrypt({ name: "AES-GCM", iv: biv, tagLength: 128 }, dkey, bdata); const decipherText = new TextDecoder().decode(decrypted); return { status: "success", log: "", data: decipherText }; } catch (e) { return { status: "error", log: e, data: e }; } }; var cipherAlgo = "aes-128-gcm"; var crypto_createHashFunc = async (x) => { const api = x.api; const hash = api.createHash("sha256"); hash.update(x.data); const dig = hash.digest("hex"); return dig; }; var crypto_cipherFunc = (x) => { try { if (typeof x.data !== "string") throw new Error(`Data to encrypt is not a string`); const pkey = x.privateKey || void 0; if (pkey !== void 0 && typeof pkey !== "string") throw new Error(`Invalid key "${pkey}"`); if (typeof pkey === "string") { if (pkey.length !== _key_len_) throw new Error(`Invalid key length "${pkey.length}" - The valid key length is "${_key_len_}"`); if (!isKeyValidFunc({ pkey })) throw new Error(); } const data = x.data; const api = x.api; const key = pkey !== void 0 ? hexToBufferFunc({ data: pkey }) : api.randomBytes(16); const iv = api.randomBytes(12); const cipher = api.createCipheriv(cipherAlgo, key, iv); let encrypted = cipher.update(data, "utf8", "hex"); encrypted += cipher.final("hex"); const authTag = cipher.getAuthTag().toString("hex"); const fkey = bufferToHexFunc({ data: key }); const fiv = bufferToHexFunc({ data: iv }); const mix = L2_cipherMixerFunc({ data: encrypted, key: fkey, iv: fiv, authTag, ignoreKey: pkey !== void 0 ? true : false }); return { status: "success", data: mix }; } catch (e) { return { status: "error", data: e.message }; } }; var crypto_decipherFunc = (x) => { try { if (typeof x.data !== "string") throw new Error(`Data to decrypt is not a string`); const pkey = x.privateKey; if (pkey !== void 0 && typeof pkey !== "string") throw new Error(`Invalid key "${pkey}"`); const demixed = L2_cipherDemixerFunc({ data: x.data, ignoreKey: pkey !== void 0 ? true : false }); const api = x.api; const data = demixed.data, key = pkey !== void 0 ? hexToBufferFunc({ data: pkey }) : hexToBufferFunc({ data: demixed.key }), iv = hexToBufferFunc({ data: demixed.iv }), authTag = hexToBufferFunc({ data: demixed.authTag }); const fkey = api.createSecretKey(key); const decipher = api.createDecipheriv(cipherAlgo, fkey, iv); decipher.setAuthTag(authTag); let decrypted = decipher.update(data, "hex", "utf8"); decrypted += decipher.final("utf8"); const res = pkey !== void 0 ? decrypted : JSON.parse(decrypted); return { status: "success", data: res }; } catch (e) { return { status: "error", data: e.message }; } }; // src/main.ts var _can_log_ = false; var _valid_value_type_ = ["string", "number", "boolean", "object", "undefined"]; var _reserved_keys_ = ["_$$type", "_$$isMutation", "_$$isCondition", "_$$default"]; var _date_format_ = { current: ["YYYY_MM_DD", "MM_DD_YYYY", "DD_MM_YYYY"] }; var _headers_ = { json: { headers: { "Content-type": "application/json", "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "POST", "Access-Control-Allow-Headers": "Content-Type" } }, file: { headers: { "Content-type": "multipart/form-data", "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "POST", "Access-Control-Allow-Headers": "Content-Type" } } }; var _crypto_key_length_ = 32; var _max_tree_name_length_ = 100; var _max_json_key_length_ = 200; var _max_json_field_size_ = 1 * 1024 * 1024; var _max_feed_size_ = 1 * 1024 * 1024; var _max_object_depth_length_ = 35; var _max_ws_retry_count = 300; var _max_ws_retry_time_interval = 2e3; var _default_http_endpoint_ = "forest"; var _default_http_upload_endpoint_ = "butterfly"; var _default_http_host_ = "0.0.0.0"; var _default_http_timeout_ = 3e4; var _default_http_static_files_routename_ = "static"; var _default_max_request_size_ = 256; var _default_server_runtime_ = ["Deno", "Node", "Bun"]; var _default_client_runtime_ = ["Browser", "React_native"]; var _default_fs_storage_path_ = "./forest"; var errCode = { initialization_failed: "initialization_failed", max_tree_name_length_exceeded: "max_tree_name_length_exceeded", not_branch_specified: "not_branch_specified", empty_json_data: "empty_json_data", transaction_failed: "transaction_failed", feed_update_failed: "feed_update_failed", request_failed: "request_failed", phantom_tree: "phantom_tree", phantom_branch: "phantom_branch", phantom_feed: "phantom_feed", corrupted_chain: "corrupted_chain", corrupted_condition: "corrupted_condition", invalid_path: "invalid_path", invalid_tree_name: "invalid_tree_name", invalid_tree_name_length: "invalid_tree_name_length", invalid_tree_options: "invalid_tree_options", invalid_argument: "invalid_argument", invalid_chain: "invalid_chain", invalid_date: "invalid_date", invalid_mutation: "invalid_mutation", invalid_mutation_path: "invalid_mutation_path", invalid_json_path: "invalid_json_path", invalid_condition: "invalid_condition", invalid_condition_operator: "invalid_condition_operator", invalid_condition_path: "invalid_condition_path", invalid_condition_value: "invalid_condition_value", invalid_value_type: "invalid_value_type", invalid_target_value_type: "invalid_target_value_type", unmatched_type: "unmatched_type", unmatched_condition: "unmatched_condition", unmatched_condition_type: "unmatched_condition_type", tree_not_found: "tree_not_found", no_tree_found: "no_tree_found", branch_not_found: "branch_not_found", feed_not_found: "feed_not_found", incorrect_data_type: "incorrect_data_type", incorrect_branch_name: "incorrect_branch_name", nested_mutation_found: "nested_mutation_found", nested_condition_found: "nested_condition_found" }; var initConfig = { config: { mainKey: "id", dateFormat: ["YYYY_MM_DD", "MM_DD_YYYY"] } }; var fs_API = { current: void 0 }; var fs_node_API = { current: void 0 }; var fs_storage_path = { current: _default_fs_storage_path_ }; var crypto_API = { current: void 0 }; var self_ws_API = { current: void 0 }; var LIB_config = { current: { rate: 2 * 1024 * 1024, ms: 60 } }; var Runtime = { current: void 0 }; var FNSS = { enable: false }; var crypto2 = { enable: false }; var secretKey = { value: void 0 }; var tree_DATA = {}; var branch_DATA = {}; var branch_feed_ref_DATA = {}; var feed_DATA = {}; var store_DATA = {}; var deleted_field_DATA = {}; var mk_to_branch_DATA = {}; var locked_feed_id_DATA = {}; var phantom_feed_id_DATA = {}; var phantom_branch_id_DATA = {}; var phantom_tree_id_DATA = {}; var transaction_scoope_DATA = {}; var active_transaction_per_branch_DATA = {}; var log_DATA = {}; var tid_DATA = {}; var env_DATA = { /* store global env data */ hasInit: false, isLoadingSchema: false, runtime: void 0, wstate: { status: "close", log: "WebSocket is off" } }; var mutation_custom_func_DATA = {}; var feed_watcher_DATA = {}; var branch_watcher_DATA = {}; var store_watcher_DATA = { set: {}, update: {}, delete: {} }; var watcher_mapping_DATA = {}; var trigger_method_DATA = { id: {}, family: {} }; var ws_server_DATA = {}; var ws_client_DATA = {}; var ws_server_config_DATA = {}; var ws_callback_DATA = {}; var http_server_DATA = {}; var private_session_DATA = { id: "", oldSessionId: "", runtime: void 0, runtimeType: "client", fsEnable: false, cryptoEnable: false }; var public_session_DATA = {}; var logFunc = (...log) => { if (_can_log_) console.log(...log); }; var plog = (...log) => { console.log(...log); }; var generateIdFunc = (x) => { const ntmp = x?.noTmp ?? true; const val = "0aW9zXe8CrVt1By5NuA46iZ3oEpRmTlYkUjIhOgPfMdQsSqDwFxGcHvJbKnL"; const length = x?.length !== void 0 ? x.length : val.length; const tmp = String((/* @__PURE__ */ new Date()).getTime()); let id = ""; for (let i = 0; i < length; i++) id += val.charAt(Math.floor(Math.random() * 36)); id = ntmp ? id : id + tmp; return id; }; var isAlphanumericFunc = (x) => { return x.acceptSpecial ? /^[a-zA-Z0-9_-]+$/.test(x.value) : /^[a-zA-Z0-9]+$/.test(x.value); }; var keepPositiveFunc = (x) => { return x.operation < 0 ? 0 : x.operation; }; var delayFunc = (x) => { return new Promise((resolve) => setTimeout(resolve, x?.ms || 0.5)); }; var getObjectTypeFunc = (x) => { const obj = x.object, tobj = typeof obj; if (tobj !== "object") return "undefined"; return tobj === null ? "null" : Array.isArray(obj) ? "array" : "json"; }; var setLogFunc = (x) => { const treeName = x.treeName, status = x.status, type = x.type, value = x.value, transactionId = x.transactionId, joinId = x.joinId, skipCommit = x.skipCommit || false; const t = (/* @__PURE__ */ new Date()).toISOString(); const log = `[${status}][${type}][${t}][GTID -> '${transactionId}'][JID -> '${joinId ?? null}'] :: [${value}]; `; if (skipCommit) return log; if (typeof log_DATA[treeName] !== "string") log_DATA[treeName] = ""; log_DATA[treeName] = log_DATA[treeName] + log; if (typeof tid_DATA[treeName] !== "object") tid_DATA[treeName] = {}; tid_DATA[treeName][transactionId] = transactionId; return log; }; var checkMaxNestedObjFunc = (x) => { const input = x.input, maxDepth = x.maxDepth || _max_object_depth_length_; const recurse = (x2) => { const value = typeof x2.value === "object" ? x2.value : void 0, currentDepth = x2.currentDepth; if (currentDepth > maxDepth) return true; if (value && (typeof value === "object" || Array.isArray(value))) { for (let k in value) { const exd = recurse({ value: value[k], currentDepth: currentDepth + 1 }); if (exd) return true; } } return false; }; return recurse({ value: input, currentDepth: 1 }); }; var hasMutationOrConditionFunc = (x) => { const check = x.check, obj = x.obj; if (typeof obj === "object" && obj !== null) { const json = obj; let hasFound = false; if (check === "all" && (isMutationFunc({ obj: json }) || isConditionFunc({ obj: json }))) hasFound = true; else if (check === "mutation" && isMutationFunc({ obj: json })) hasFound = true; else if (check === "condition" && isConditionFunc({ obj: json })) hasFound = true; if (hasFound) return true; else { const keys = Object.keys(json); for (let i = 0; i < keys.length; i++) { const target = keys[i]; const targetValue = json[target]; if (typeof targetValue === "object") { const found = hasMutationOrConditionFunc({ check, obj: targetValue }); if (found) return true; } } return false; } } else return false; }; var hasPropertyFunc = (x, y) => { const obj = typeof x === "object" && x !== null ? x : {}; return Object.prototype.hasOwnProperty.call(obj, y); }; var cloneObjFunc = (x) => { try { const tp = typeof x.obj === "object" && x.obj !== null ? true : false; const obj = x.obj, useLoop = x.useLoop ?? false; let data = {}; if (tp) { if (!useLoop) data = structuredClone(obj); else { data = []; for (let f = 0; f < obj.length; f++) { const cln = structuredClone(obj[f]); data.push(cln); } } return data; } return Array.isArray(x.obj) ? [] : {}; } catch (e) { plog("Clonning failed !"); return { status: "error", log: e.message, data: void 0 }; } }; var isMutationFunc = (x) => { return typeof x.obj === "object" && !Array.isArray(x.obj) && x.obj !== null && hasPropertyFunc(x.obj, "_$$isMutation") ? true : false; }; var isConditionFunc = (x) => { return typeof x.obj === "object" && !Array.isArray(x.obj) && x.obj !== null && hasPropertyFunc(x.obj, "_$$isCondition") ? true : false; }; var isNumericFunc = (x) => { return isFinite(Number(x.value)); }; var mergeNestedArrayFunc = (x) => { return x.arr.flat(); }; var getArrayDepthFunc = (x) => { const arr = x.arr, maxLevel = x.maxLevel || 2; if (!Array.isArray(arr)) return -1; let depth = 1; for (const item of arr) { if (Array.isArray(item)) { const itemDepth = getArrayDepthFunc({ arr: item, maxLevel }); if (itemDepth === -1) return -1; depth = Math.max(depth, itemDepth + 1); if (depth > maxLevel) return -1; } } return depth; }; var removeAccentFunc = (x) => { const keepSpaces = x.keepSpaces ?? false; const str = x.value.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); const data = x.lowerCase ? str.toLocaleLowerCase() : str; if (x.keepSpaces) data.replaceAll(" ", ""); return data; }; var monthDays = { 1: 31, // January 2: 28, // February (29 in leap years) 3: 31, // March 4: 30, // April 5: 31, // May 6: 30, // June 7: 31, // July 8: 31, // August 9: 30, // September 10: 31, // October 11: 30, // November 12: 31 // December }; var getDaysInMonthFunc = (x) => { const month = x.month, year = x.year; return month === 2 && year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : monthDays[month]; }; var getWordCountFunc = (x) => { return (x.value.match(/\b\w+\b/g) || []).length; }; var buildJsonFromPathFunc = (x) => { const path = Array.isArray(x.path) ? x.path.join(".") : x.path, value = x.value; const pathTab = path.split(".").reverse(), plen = pathTab.length; let jtab = Array(plen).fill(void 0).map(() => { return {}; }); for (let i = 0; i < plen; i++) { const cp = pathTab[i]; if (i === 0) jtab[i][cp] = value; else jtab[i][cp] = jtab[i - 1]; } return jtab[plen - 1]; }; var resolvePathFunc = (x) => { const path = Array.isArray(x.path) ? x.path.join(".") : x.path, firstKey = x.firstKey || void 0, sourceObj = x.sourceObj || void 0, asJson = x.asJson ?? false; let mlog = ""; try { let pathTab = path.split("."); let pathType = "short"; const pcopy = cloneObjFunc({ obj: pathTab }); const strPath = pcopy.join("."); pathType = strPath[0] === "#" ? "long" : "short"; let realObj = {}, realPath = []; if (pathType === "short") { const otype = getObjectTypeFunc({ object: sourceObj }); if (sourceObj === void 0 || otype !== "json") { mlog = mlog + `Invalid source`; throw new Error(); } if (firstKey !== void 0 && pathTab[0] !== firstKey) pathTab = [firstKey, ...pathTab]; realObj = cloneObjFunc({ obj: sourceObj }); realPath = pathTab; } else { const fid = pathTab[0].replace("#", ""); const est = hasPropertyFunc(feed_DATA, fid); if (!est) { mlog = mlog + `The feed "${fid}" doesn't exists`; throw new Error(mlog); } realObj = cloneObjFunc({ obj: feed_DATA[fid] }); realPath = strPath.replace("#", "").split("."); } const ptl = pathTab.length; const currentPathValue = { current: void 0 }; let breakLoop = false; for (let n = 0; n < ptl; n++) { if (breakLoop) break; const ky = pathTab[n]; const validPathData = currentPathValue.current === void 0 ? false : true; const isNumericPath = isNumericFunc({ value: currentPathValue.current }); const isBeforeLastLoop = n === ptl - 2 ? true : false; const isLastLoop = n === ptl - 1 ? true : false; if (!isNumericPath && !hasPropertyFunc(validPathData ? currentPathValue.current : realObj, ky)) { mlog = mlog + `The path "${path}" doesn't exists`; throw new Error(mlog); } if (currentPathValue.current !== void 0) { const propExists = hasPropertyFunc(currentPathValue.current, ky); if (!propExists) { currentPathValue.current[ky] = {}; } } currentPathValue.current = validPathData ? currentPathValue.current[ky] : realObj[ky]; } if (asJson) currentPathValue.current = buildJsonFromPathFunc({ path: realPath, value: currentPathValue.current }); return { status: "success", log: mlog, data: currentPathValue.current }; } catch (e) { return { status: "error", log: e.message, data: void 0 }; } }; var extractNumberFunc = (x) => { return (x.value.match(/\d+/g) || []).map(Number); }; var extractNumberIndexFunc = (x) => { const mtc = x.value.matchAll(/\d+/g); let res = []; mtc.forEach((e) => { res.push({ index: e.index, value: e[0] }); }); return res; }; var buildDateTemplateFunc = (x, y) => { let md = x; if (y !== void 0) { const xp = x.point, yp = y.point; md = xp >= yp ? x : y; } let proto = []; let fullDate = ""; if (md.hasDate) { proto.push(...["YYYY", "MM", "DD"]); fullDate = fullDate + "YYYY-MM-DD"; } if (md.hasTime) { proto.push(...["HH", "mm"]); fullDate = fullDate + "THH:mm"; } if (md.hasSec) { proto.push("ss"); fullDate = fullDate + ":ss"; } if (md.hasMilli) { proto.push("sss"); fullDate = fullDate + ".sss"; } if (md.hasUTCHour) { proto.push("+HH"); fullDate = fullDate + "++HH"; } else { fullDate = fullDate + "Z"; } if (md.hasUTCMin) { proto.push("+mm"); fullDate = fullDate + ":+mm"; } const final = { proto, fullDate }; return final; }; var tmpExtractorFunc = (x) => { let value = x.value, format = x.format; const template = x.template || void 0; const extractModel = x.extractModel || false; const custom = template !== void 0 || extractModel ? true : false; let mlog = ""; let model = { hasDate: false, hasTime: false, hasSec: false, hasMilli: false, hasUTCHour: false, hasUTCMin: false, point: 0 }; try { if (!custom && typeof value === "number") { const len = String(value).length; return len === 10 ? value * 1e3 : ( /* Convert seconds to milliseconds */ len === 13 ? value : ( /* Milliseconds (standard) */ len > 13 && len <= 16 ? Math.floor(value / 10 ** (len - 13)) : ( /* Convert micro/nano to ms */ -1 ) ) ); } if (custom && typeof value === "number") { value = new Date(value).toISOString(); } let nDate = custom ? value : String(value.replaceAll(" ", "")); let numTab = extractNumberFunc({ value: nDate }); if (numTab.length < 3 || numTab.length === 4) { mlog = mlog + `invalid date "${nDate}"`; throw new Error(mlog); } const sdt = numTab.splice(0, 3); let dArr = [ format === "DD_MM_YYYY" ? sdt[2] : format === "MM_DD_YYYY" ? sdt[2] : format === "YYYY_MM_DD" ? sdt[0] : -1, /* extract year */ format === "DD_MM_YYYY" ? sdt[1] : format === "MM_DD_YYYY" ? sdt[0] : format === "YYYY_MM_DD" ? sdt[1] : -1, /* extact month */ format === "DD_MM_YYYY" ? sdt[0] : format === "MM_DD_YYYY" ? sdt[1] : format === "YYYY_MM_DD" ? sdt[2] : -1 /* extact date */ ]; let mArr = []; if (nDate.includes(":")) { const ix = nDate.lastIndexOf("+") || nDate.lastIndexOf("Z") || nDate.lastIndexOf("z") || -1; const oc = nDate.match(/:/g) || []; if (oc.length > 3 || oc.length < 1) { mlog = mlog + `invalid date "${nDate}"`; throw new Error(mlog); } const ioc = nDate.indexOf(":") - 2; const str = ix !== -1 ? nDate.slice(ioc, ix) : nDate.slice(ioc); const extr = extractNumberFunc({ value: str }), ixtr = extr.length; if (ixtr === 0) { mlog = mlog + `invalid date "${nDate}"`; throw new Error(mlog); } mArr = [ extr[0], /* hour */ ixtr === 1 ? 0 : extr[1] /* minute */ ]; if (extr[2] !== void 0) mArr.push(ixtr <= 2 ? 0 : extr[2]); if (extr[3] !== void 0) mArr.push(ixtr === 3 ? 0 : extr[3]); } let uArr = []; if (nDate.includes("+")) { const ix = nDate.lastIndexOf("+"), str = nDate.slice(ix); const extr = extractNumberFunc({ value: str }), ixtr = extr.length; if (ixtr === 0) { mlog = mlog + `invalid date "${nDate}"`; throw new Error(mlog); } uArr = [ extr[0] /* UTC hour */ ]; if (extr[1] !== void 0) mArr.push(ixtr === 1 ? 0 : extr[1]); } numTab = [...dArr, ...mArr, ...uArr]; const protoTab = template?.proto || ["YYYY", "MM", "DD", "HH", "mm", "ss", "sss", "+HH", "+mm"]; let fullDate = template?.fullDate || "YYYY-MM-DDTHH:mm:ss.sss++HH:+mm"; for (let d = 0; d < protoTab.length; d++) { const cprot = protoTab[d], val = numTab[d] ?? -1; const pval = val === -1 ? numTab[d] : val; switch (cprot) { /* set year */ case "YYYY": { const len = String(val).length; if (len < 4 || val === -1) { mlog = mlog + `invalid year "${pval}"`; throw new Error(mlog); } fullDate = fullDate.replace("YYYY", String(val)); model.hasDate = true; } break; /* set month */ case "MM": { if (val < 1 || val > 12 || val === -1) { mlog = mlog + `invalid month "${pval}"`; throw new Error(mlog); } fullDate = fullDate.replace("MM", String(val).padStart(2, "0")); } break; /* set date */ case "DD": { const days = getDaysInMonthFunc({ month: numTab[1], year: numTab[0] }); if (val < 1 || val > days || val === -1) { mlog = mlog + `invalid date "${pval}", the range should be from 1 to "${days}"`; throw new Error(mlog); } fullDate = fullDate.replace("DD", String(val).padStart(2, "0")); } break; /* set hour */ case "HH": { if ((val < 0 || val > 23) && val !== -1) { mlog = mlog + `invalid hour "${pval}"`; throw new Error(mlog); } const ext = val !== -1 ? true : false; fullDate = fullDate.replace("HH", !ext ? "00" : String(val).padStart(2, "0")); model.hasTime = ext ? true : false; } break; /* set minute */ case "mm": { if ((val < 0 || val > 59) && val !== -1) { mlog = mlog + `invalid minute "${pval}"`; throw new Error(mlog); } fullDate = fullDate.replace("mm", val === -1 ? "00" : String(val).padStart(2, "0")); } break; /* set second */ case "ss": { if ((val < 0 || val > 59) && val !== -1) { mlog = mlog + `invalid seconds "${pval}"`; throw new Error(mlog); } const ext = val !== -1 ? true : false; fullDate = fullDate.replace("ss", !ext ? "00" : String(val).padStart(2, "0")); model.hasSec = ext ? true : false; } break; /* set millisecond */ case "sss": { if ((val < 0 || val > 999) && val !== -1) { mlog = mlog + `invalid seconds "${pval}"`; throw new Error(mlog); } const ext = val !== -1 ? true : false; fullDate = fullDate.replace("sss", !ext ? "000" : String(val).padStart(3, "0")); model.hasMilli = ext ? true : false; } break; /* set UTC hour */ case "+HH": { const ext = val !== -1 ? true : false; if (!ext) { fullDate = fullDate.replace("++HH:+mm", "Z"); break; } if (val < 0 || val > 23) { mlog = mlog + `invalid UTC hour "${pval}"`; throw new Error(mlog); } fullDate = fullDate.replace("+HH", String(val).padStart(2, "0")); model.hasUTCHour = ext ? true : false; } break; /* set UTC minute */ case "+mm": { if ((val < 0 || val > 59) && val !== -1) { mlog = mlog + `invalid seconds "${pval}"`; throw new Error(mlog); } const ext = val !== -1 ? true : false; fullDate = fullDate.replace("+mm", !ext ? "00" : String(val).padStart(2, "0")); model.hasUTCMin = ext ? true : false; } break; /* - */ default: { mlog = mlog + `unknown date parameter "${cprot}"`; throw new Error(mlog); } ; } ; } const mdv = Object.values(model); const btr = mdv.filter((e) => e === true); model.point = btr.length; const dateObj = new Date(fullDate); let final = isNaN(dateObj.getTime()) ? -1 : dateObj.getTime(); return extractModel ? { tmp: final, model } : final; } catch (e) { logFunc('err "tmpExtractorFunc" fail ::', e.message); return -1; } }; var extractTimestampFunc = (x) => { const value = x.value, dateFormat = x.dateFormat !== void 0 ? cloneObjFunc({ obj: x.dateFormat }) : cloneObjFunc({ obj: _date_format_.current }); let final = -1; for (let i = 0; i < dateFormat.length; i++) { const form = dateFormat[i], extract = tmpExtractorFunc({ value, format: form, template: x.template, extractModel: x.extractModel }); final = extract; if (extract !== -1) break; } return final; }; var transformIntoTimestampFunc = (x) => { const value = x.value, format = x.format; let mlog = "", currentTarget = void 0; try { for (let i = 0; i < value.length; i++) { const target = value[i]; if (Array.isArray(target)) { const newTar = target; for (let j = 0; j < target.length; j++) { const crtVal = newTar[j]; currentTarget = crtVal; const xtmp = extractTimestampFunc({ value: crtVal, dateFormat: format }); if (xtmp === -1) { mlog = mlog + `The date "${crtVal}" doesn't respect provided date format "[${_date_format_.current}]"`; throw new Error(mlog); } newTar[j] = xtmp; } value[i] = newTar.sort((a, b) => a - b); } else { currentTarget = target; value[i] = extractTimestampFunc({ value: target, dateFormat: format }); } } const marr = mergeNestedArrayFunc({ arr: value }); if (marr.includes(-1)) return { status: "error", log: mlog, data: currentTarget }; return { status: "success", log: mlog, data: value }; } catch (e) { return { status: "error", log: mlog, data: currentTarget }; } }; var mergeObjFunc = (x) => { const target = x.target, data = x.data; const ttype = getObjectTypeFunc({ object: target }), tdata = getObjectTypeFunc({ object: data }); if (ttype !== "json" || tdata !== "json") return data; for (const key in data) { if (hasPropertyFunc(data, key)) { const ttk = getObjectTypeFunc({ object: target[key] }), tdk = getObjectTypeFunc({ object: data[key] }); if (key in target && ttk === "json" && tdk === "json") target[key] = mergeObjFunc({ target: target[key], data: data[key] }); else target[key] = data[key]; } } return target; }; var deleteJsonFieldFunc = (x) => { const path = Array.isArray(x.path) ? x.path.join(".") : x.path, obj = x.target, fk = x.firstkey; let pathTab = path.split("."); let res = { status: "success", log: "", data: void 0 }; try { if (fk !== void 0 && pathTab[0] !== fk) pathTab = [fk, ...pathTab]; let plen = pathTab.length; let cursor = {}; for (let i = 0; i < plen; i++) { const ck = pathTab[i]; const who = i === 0 ? obj : cursor; if (!hasPropertyFunc(who, ck)) { res.status = "error"; throw new Error(`Path "${ck}" not found`); } cursor = who[ck]; if (i === plen - 2) { const nk = pathTab[i + 1]; delete cursor[nk]; break; } } res.data = obj; } catch (e) { res.log = e.message; } ; return res; }; var parseUrlFunc = (x) => { try { const url = x.url; if (url.includes("://")) { const parsedUrl = new URL(url); return { protocol: parsedUrl.protocol.replace(":", ""), hostname: parsedUrl.hostname, port: parsedUrl.port || void 0 }; } const [host, port] = url.split(":"); return { protocol: void 0, hostname: host, port: port || void 0 }; } catch (error) { return void 0; } }; var topLevelJsonFunc = (x) => { let res = { status: "success", log: "", data: void 0 }; let coll = {}; try { const data = x.data; for (let key in data) { const kdat = data[key], ktab = x.ktab ? [...x.ktab] : []; const dtyp = getObjectTypeFunc({ object: kdat }); if (dtyp === "json") { ktab.push(key); const recu = topLevelJsonFunc({ data: kdat, ktab }); mergeObjFunc({ target: coll, data: recu.data }); } else { ktab.push(key); const fk = ktab.join("."); coll[fk] = data[key]; } } res.data = coll; } catch (e) { res.status = "error"; res.log = e.message; } ; return res; }; var removeUndefinedValuesFunc = (x) => { let res = { status: "success", log: "", data: void 0 }; try { const obj = x.obj; const clone = x.clone ?? false; const ocl = clone ? cloneObjFunc({ obj }) : obj; const kys = Object.keys(ocl); for (let k = 0; k < kys.length; k++) { const ck = kys[k]; if (ocl[ck] === void 0) { delete ocl[ck]; continue; } const val = ocl[ck]; if (typeof val === "object" && val !== null) removeUndefinedValuesFunc({ obj: val, clone: false, recursive: true }); } } catch (e) { res.status = "error"; res.log = e.message; } return res; }; var getNewPathFunc = (x) => { const normalized = x.oldPath.replace(/[\\/]/g, "/"); const lastSlash = normalized.lastIndexOf("/"); return lastSlash === -1 ? x.newName : normalized.slice(0, lastSlash + 1) + x.newName; }; var createHashFunc = async (x) => { const res = { status: "success", log: "", data: void 0 }; try { const isNode = Runtime.current === "Node" ? true : false; if (typeof x !== "string") throw new Error(`The value to hash is not a string`); if (isNode && crypto_API.current === void 0) throw new Error(`Unable to find crypto's API`); let edat = isNode ? await crypto_createHashFunc({ data: x, api: crypto_API.current }) : await web_createHashFunc({ data: x }); res.data = edat; } catch (e) { res.status = "error"; res.log = e.message; } return res; }; var encryptFunc = async (x) => { let res = { status: "success", log: "", data: void 0 }; try { if (private_session_DATA.cryptoEnable) { const scrt = secretKey.value || void 0; const cp = crypto_API.current !== void 0 && private_session_DATA.runtime === "Node" ? crypto_cipherFunc({ data: x.data, api: crypto_API.current, privateKey: scrt }) : await web_cipherFunc({ data: x.data, privateKey: scrt }); if (cp.status !== "success") throw new Error(`Encryption failed`); res.data = cp.data; } return res; } catch (e) { res.status = "error"; res.log = e.message; res.data = x.data; } return res; }; var decryptFunc = async (x) => { let res = { status: "success", log: "", data: void 0 }; const data = x.data || void 0; try { if (data === void 0) throw new Error(`Invalid data`); if (private_session_DATA.cryptoEnable) { const scrt = secretKey.value || void 0; const cp = crypto_API.current !== void 0 ? crypto_decipherFunc({ data: x.data, api: crypto_API.current, privateKey: scrt }) : await web_decipherFunc({ data: x.data, privateKey: scrt }); if (cp.status !== "success") throw new Error(`Decryption failed`); res.data = cp.data; } return res; } catch (e) { res.status = "error"; res.log = e.message; res.data = x.data; } return res; }; var ws_sendFunc = async (x) => { const api = x.api, msg = JSON.stringify(x.msg); let res = { status: "success", log: "", data: void 0 }; let message = { value: msg }; let final = ""; try { if (private_session_DATA.cryptoEnable) { const enc = await encryptFunc({ data: message.value }); if (enc.status !== "success") throw new Error(enc.log); message.value = enc.data; } final = JSON.stringify(message); } catch (e) { res.status = "error"; res.log = `[WebSocket] :: ${e.message}`; } ; api.send(final); return res; }; var ws_commitClientSessionFunc = async (x) => { const data = x.data; let res = { status: "success", log: "", data: void 0 }; try { const srv = Object.keys(ws_server_DATA); if (srv.length === 0) throw new Error("Not server found to commit client session"); let fail = []; for (let s = 0; s < srv.length; s++) { const cid = srv[s]; const targ = ws_server_DATA[cid]; const sid = targ.id, api = targ.api; const wss = await ws_sendFunc({ api, msg: { id: private_session_DATA.id, object: "commit_session", data, target: "single", targetId: sid, oldSessionId: private_session_DATA.oldSessionId } }); if (wss.status !== "success") { fail.push(sid); logFunc("session failed to commit ::", wss.log); continue; } } const flen = fail.length, slen = srv.length; if (flen > 0) { if (flen < slen) res.log = `Failed to commit session to following server(s) "[${fail}"]`; else if (flen === slen) throw new Error(`Failed to commit session`); } } catch (e) { res.status = "error"; res.log = e.message; } ; return res; }; var ws_filterFunc = async (x) => { let res = { status: "success", log: "", data: void 0 }; try { const targetType = x.targetType, filter = x.filter; const dataSource = targetType === "client" ? ws_client_DATA : ws_server_DATA; const targets = Object.keys(dataSource); let collector = []; let lrate = 0; if (targets.length > 0) for (let f = 0; f < targets.length; f++) { if (lrate > 0 && lrate % LIB_config.current.rate === 0) await delayFunc({ ms: LIB_config.current.ms }); const tid = targets[f]; const tdata = dataSource[tid]; const css = tdata.session; if (css === void 0 || Object.keys(css).length === 0) continue; const checond = checkConditionFunc({ feed: css, condition: filter }); if (checond.status !== "success") throw new Error(checond.log); if (checond.data) collector.push(tdata.id); lrate++; } res.data = collector; } catch (e) { res.status = "error"; res.log = e.message; } return res; }; var ws_sendtriggerMethodFunc = async (x) => { let res = { status: "success", log: "", data: void 0 }; try { const arg = x; const targetId = arg.targetId; const isBroadcast = targetId === "*" ? true : false; const hasFilter = arg.targetFilter !== void 0 && Object.keys(arg.targetFilter).length > 0 ? true : false; const dly = 1e3; const tgData = { type: arg.type, source: arg.source, func: arg.method, xorder: arg.execOrder }; switch (arg.targetType) { /** * Send from server to client(s) */ case "client": { if (isBroadcast) { let clients = []; if (Object.keys(ws_client_DATA).length === 0) await delayFunc({ ms: dly * 5 }); if (hasFilter) { const fres = await ws_filterFunc({ targetType: "client", filter: arg.targetFilter || {} }); if (fres.status !== "success") throw new Error(fres.log); clients = fres.data; } else clients = Object.keys(ws_client_DATA); if (clients.length === 0) throw new Error(hasFilter ? `No client matches the filter - Broadcast cancelled` : `No clients found - Broadcast cancelled`); let lrate = 0; for (let m = 0; m < clients.length; m++) { if (lrate > 0 && lrate % LIB_config.current.rate === 0) await delayFunc({ ms: LIB_config.current.ms }); const cid = clients[m], capi = ws_client_DATA[cid].api; if (capi === void 0) { res.log = res.log + `Unable to send message to client with id "${cid}" - It API may be broken `; lrate++; continue; } try { await ws_sendFunc({ api: capi, msg: { id: private_session_DATA.id, object: "trigger_method", data: tgData } }); } catch (e) { res.log = res.log + `Unable to send message to client with id "${cid}" - ${e.message} `; lrate++; continue; } lrate++; } } else { let tex = hasPropertyFunc(ws_client_DATA, arg.targetId); if (!tex) { await delayFunc({ ms: dly * 5 }); tex = hasPropertyFunc(ws_client_DATA, targetId); } if (!tex) throw new Error(`Can't found a client with id "${arg.targetId}"`); const cid = arg.targetId, clientRealId = ws_client_DATA[cid].id, capi = ws_client_DATA[cid].api; if (capi === void 0) throw new Error(`Invalid API for client "${cid}"`); let callbackId = void 0, callbackOwnerId = void 0; if (arg.callback !== void 0) { if (typeof arg.callback !== "function") throw new Error(`Invalid callback`); const cbid = arg.callbackId || generateIdFunc({ length: 8 }); if (hasPropertyFunc(ws_callback_DATA, cbid)) throw new Error(`The id "${cbid}" is already used by another callback`); ws_callback_DATA[cbid] = arg.callback; callbackId = cbid; callbackOwnerId = private_session_DATA.id; } await ws_sendFunc({ api: capi, msg: { id: private_session_DATA.id, object: "trigger_method", data: tgData, callbackId, callbackOwnerId } }); } } break; /** * Send from client to server(s) */ case "server": { if (isBroadcast) { let servers = Object.keys(ws_server_DATA); if (servers.length === 0) { await delayFunc({ ms: dly }); servers = Object.keys(ws_server_DATA); } if (servers.length === 0) throw new Error(`No server found - Broadcast cancelled`); let lrate = 0; for (let m = 0; m < servers.length; m++) { if (lrate > 0 && lrate % LIB_config.current.rate) await delayFunc({ ms: LIB_config.current.ms }); const cid = servers[m]; const capi = ws_server_DATA[cid].api; const serverRealId = ws_server_DATA[cid].id; if (capi === void 0) { res.log = res.log + `Unable to send message to server with id "${cid}" - It API may be broken `; lrate++; continue; } try { await ws_sendFunc({ api: capi, msg: { id: private_session_DATA.id, object: "trigger_method", data: tgData, targetId: serverRealId, sessionFilter: arg.targetFilter || {} } }); } catch (e) { res.log = res.log + `Unable to send message to server with id "${cid}" - ${e.message} `; lrate++; continue; } lrate++; } } else { let tex = hasPropertyFunc(ws_server_DATA, targetId); if (!tex) { await delayFunc({ ms: dly }); tex = hasPropertyFunc(ws_server_DATA, targetId); } if (!tex) throw new Error(`Can't found a server with id "${targetId}"`); const cid = targetId, serverRealId = ws_server_DATA[cid].id, capi = ws_server_DATA[cid].api; if (capi === void 0) throw new Error(`Invalid API for server "${cid}"`); let callbackId = void 0, callbackOwnerId = void 0; if (arg.callback !== void 0) { if (typeof arg.callback !== "function") throw new Error(`Invalid callback`); const cbid = arg.callbackId || generateIdFunc({ length: 8 }); if (hasPropertyFunc(ws_callback_DATA, cbid)) throw new Error(`The id "${cbid}" is already used by another callback`); ws_callback_DATA[cbid] = arg.callback; callbackId = cbid; callbackOwnerId = private_session_DATA.id; } await ws_sendFunc({ api: capi, msg: { id: private_session_DATA.id, object: "trigger_method", data: tgData, callbackId, callbackOwnerId } }); } } break; /* default */ default: { } ; } ; } catch (e) { res.status = "error"; res.log = `[WebSocket] :: ${res.log + ` ` + e.message}`; } return res; }; var ws_restartConnectionToServerFunc = (x) => { let res = { status: "success", log: "", data: void 0 }; try { setupWebsocketFunc(x.config); } catch (e) { res.status = "error", res.data = `[WebSocket] :: ${e.message}`; } return res; }; var ws_restartDeadConnectionsFunc = () => { let res = { status: "success", log: "", data: void 0 }; try { if (Object.keys(ws_server_config_DATA).length === 0) { res.log = `No server found`; return res; } const wsClient = ws_server_config_DATA; for (let key in wsClient) { const targ = wsClient[key]; if (targ.isActive || targ.retryCount !== 0) continue; const conf = ws_restartConnectionToServerFunc({ config: targ.config }); if (conf.status !== "success") { const lg = conf.log.replaceAll("[WebSocket] :: ", ""); throw new Error(lg); } } } catch (e) { res.status = "error"; res.log = `[WebSocket] :: ${e.message}`; } return res; }; var processWebsocketFunc = async (x) => { try { const event = x.event; const type = x.type || private_session_DATA.runtimeType; const serverId = x.serverId || void 0; const data = x.data || void 0; const api = x.api || void 0; const config = x.config || void 0; switch (event) { /** * On open */ case "open": { if (type === "client") { if (serverId === void 0) { plog(`[WebSocket] :: Unable to find server ID`); return; } if (!hasPropertyFunc(ws_server_config_DATA, serverId)) ws_server_config_DATA[serverId] = { config, retryCount: 0, isActive: true }; else { ws_server_config_DATA[serverId].retryCount = 0; ws_server_config_DATA[serverId].isActive = true; } self_ws_API.current = api; const sending = await ws_sendFunc({ api: self_ws_API.current, msg: { id: private_session_DATA.id, oldSessionId: private_session_DATA.oldSessionId, object: "client_handshake" } }); } } break; /** * On message */ case "message": { const str = String(data); const pars = JSON.parse(str); const val = pars.value; let msg = val; if (private_session_DATA.cryptoEnable) { const dec = await decryptFunc({ data: val }); if (dec.status !== "success") { logFunc("dec failed ::", dec.log); throw new Error(`[WebSocket] :: Message descryption failed`); } msg = typeof dec.data === "string" ? JSON.parse(dec.data) : dec.data; } if (typeof msg === "string") msg = JSON.parse(msg); if (type === "client") { const id = msg.id, object = msg.object, callbackOwnerId = msg.callbackOwnerId; const sid = serverId || id; switch (object) { /* [client] :: Client first connection */ case "server_handshake": { const ch = hasPropertyFunc(ws_server_DATA, sid); ws_server_DATA[sid] = { id: sid, api, store: {}, session: {} }; await ws_commitClientSessionFunc({ data: public_session_DATA }); plog(`[WebSocket] :: Successfully connected to server "${si