@trap_stevo/legendarybuilderpronodejs-utilities
Version:
The legendary computational utility API that makes your application a legendary application. ~ Created by Steven Compton
1,820 lines (1,255 loc) • 44.9 kB
JavaScript
/*
Created by Hassan Steven Compton.
March 2, 2024.
*/
const crypto = require("crypto");
const path = require("path");
const fs = require("fs");
const { addDays, addWeeks, addMonths, addYears } = require("date-fns");
async function getUniversalMultiDataContainingDesiredData(currentDB, collectionID, docAttributeID, input)
{
const desiredData = [];
try
{
const collection = await currentDB.collection(collectionID);
const snapshot = await collection.get();
const inputObject = typeof input === "object" && input !== null;
const inputStr = inputObject
? JSON.stringify(input).toLowerCase()
: String(input).toLowerCase();
for (const doc of snapshot.docs)
{
const data = doc.data();
const field = data[docAttributeID];
if (field == null) { continue; }
let match = false;
if (Array.isArray(field))
{
match = field.includes(input);
}
else
{
const type = typeof field;
switch (type)
{
case "string":
match = field.toLowerCase().includes(inputStr);
break;
case "object":
try
{
match = JSON.stringify(field).toLowerCase().includes(inputStr);
}
catch (e)
{
console.warn("Could not stringify object field", e);
}
break;
case "number":
case "boolean":
match = field === input;
break;
}
}
if (match)
{
desiredData.push(data);
}
}
return desiredData;
}
catch (error)
{
console.error(`Did not get documents in ${collectionID}: `, error);
return [];
}
};
async function getUniversalMultiData(currentDB, collectionID)
{
try
{
const snapshot = await currentDB.collection(collectionID).get();
return snapshot.docs.map(doc => doc.data());
}
catch (error)
{
console.error(`Did not get documents in ${collectionID}: `, error);
return [];
}
};
async function getUniversalData(currentDB, collectionID, docAttributeID, input)
{
try
{
const collection = await currentDB.collection(collectionID);
const snapshot = await collection.where(docAttributeID, '==', input).get();
for (const doc of snapshot.docs)
{
const data = doc.data();
if (data !== null && data !== undefined)
{
return data;
}
}
return null;
}
catch (error)
{
return null;
}
};
async function getUniversalDataFromDocAttribute(currentDB, collectionID, docID, docAttributeID)
{
try
{
const docRef = await currentDB.collection(collectionID).doc(docID);
const snapshot = await docRef.get();
const data = await snapshot.data();
return data[docAttributeID];
}
catch (error)
{
return null;
}
};
async function getUniversalDataFromDoc(currentDB, collectionID, docID)
{
try
{
const docRef = await currentDB.collection(collectionID).doc(docID);
const snapshot = await docRef.get();
const data = await snapshot.data();
return data;
}
catch (error)
{
return null;
}
};
async function checkForMatchingUniversalData(currentDB, collectionID, data, exclude = [])
{
try
{
let query = await currentDB.collection(collectionID);
for (const [key, value] of Object.entries(data))
{
if (!exclude.includes(key))
{
query = query.where(key, '==', value);
}
}
const snapshot = await query.get();
if (snapshot.empty)
{
console.log("Document not found");
return false;
}
return true;
}
catch (error)
{
console.error("Did not check documents....", error);
return false;
}
};
async function getUniversalCollectionSize(currentDB, collectionID)
{
try
{
const snapshot = await currentDB.collection(collectionID).get();
return snapshot.size;
}
catch (error)
{
return 0;
}
};
async function getAvailableUniversalDocID(currentDB, collectionID)
{
try
{
const snapshot = await currentDB.collection(collectionID).get();
const docIDs = snapshot.docs.map(doc => parseInt(doc.id)).sort((a, b) => a - b);
for (let i = 0; i < docIDs.length; i++)
{
if (docIDs[i] !== i)
{
return i;
}
}
return docIDs.length;
}
catch (error)
{
console.error("Did not get the next available universal ID: ", error);
return null;
}
};
async function addUniversalData(currentDB, collectionID, docIDAttributeName, docData)
{
try
{
const docID = await getAvailableUniversalDocID(currentDB, collectionID);
if (docID === null)
{
throw new Error("Did not determine the next available universal ID.");
}
docData[docIDAttributeName] = docID;
await currentDB.collection(collectionID).doc(docID.toString()).set(docData);
console.log("Added document " + docID + " into " + collectionID);
return docID;
}
catch (error)
{
console.log("Did not add document to " + collectionID, error);
return null;
}
};
async function deleteUniversalData(currentDB, collectionID, docID)
{
try
{
await currentDB.collection(collectionID).doc(docID.toString()).delete();
console.log("Deleted document " + docID + " in " + collectionID);
return true;
}
catch (error)
{
console.log("Did not delete document " + docID + " in " + collectionID + ": ", error);
return false;
}
};
async function deleteUniversalDataField(currentDB, collectionID, docID, docIDAttributeName)
{
try
{
const docRef = await currentDB.collection(collectionID).doc(docID.toString());
await docRef.update({
[docIDAttributeName] : FieldValue.delete()
});
console.log(`Field ${docIDAttributeName} successfully deleted!`);
return true;
}
catch (error)
{
console.log(`Did not delete field ${docIDAttributeName} in ` + docID + ": ", error);
return false;
}
};
function updateUniversalData(currentDB, collectionID, documentId, updateData, callback)
{
const docRef = currentDB.collection(collectionID).doc(documentId);
docRef.get()
.then(docSnapshot => {
if (!docSnapshot.exists)
{
console.log(`Document ${documentId} in ${collectionID} not found.`);
if (typeof callback === 'function')
{
callback(new Error(`Document ${documentId} in ${collectionID} not found.`), null);
}
return;
}
docRef.update(updateData)
.then(() => {
console.log(`Document ${documentId} in ${collectionID} updated successfully.`);
if (typeof callback === 'function')
{
callback(null, `Document ${documentId} in ${collectionID} updated successfully.`);
}
})
.catch((error) => {
console.error(`Did not update document ${documentId} in ${collectionID}: `, error);
if (typeof callback === 'function')
{
callback(error, null);
}
});
})
.catch((error) => {
console.error(`Did not get document ${documentId} in ${collectionID}: `, error);
if (typeof callback === 'function')
{
callback(error, null);
}
});
};
function deepEqualData(currentData, comparedData)
{
if (currentData === comparedData)
{
return true;
}
if (typeof currentData !== 'object' || currentData === null || typeof comparedData !== 'object' || comparedData === null)
{
return false;
}
const keys = Object.keys(currentData);
const comparedKeys = Object.keys(comparedData);
if (keys.length !== comparedKeys.length)
{
return false;
}
for (const key of keys)
{
if (!comparedKeys.includes(key))
{
return false;
}
if (typeof currentData[key] === 'object' && typeof comparedData[key] === 'object')
{
if (!deepEqualData(currentData[key], comparedData[key]))
{
return false;
}
}
else if (currentData[key] !== comparedData[key])
{
return false;
}
}
return true;
};
function desiredInnerUniversalData(data)
{
let dictionary = Object.values(data);
return dictionary.length > 0 ? dictionary[0] : null
};
// HUD Universal Functionality
function convertUTCDateToDateDisplay(utcDouble, localTime = true, dateOffset = 1000)
{
const date = new Date(utcDouble * dateOffset);
let month, day, year, hours, minutes, ampm, formattedHours;
if (localTime)
{
month = date.getMonth() + 1;
day = date.getDate();
year = date.getFullYear().toString().slice(-2);
hours = date.getHours();
}
else
{
month = date.getUTCMonth() + 1;
day = date.getUTCDate();
year = date.getUTCFullYear().toString().slice(-2);
hours = date.getUTCHours();
}
const pad = (num) => (num < 10 ? `0${num}` : num);
minutes = pad(date.getUTCMinutes());
ampm = hours >= 12 ? 'PM' : 'AM';
formattedHours = hours % 12 || 12;
return `${month}/${day}/${year} ${formattedHours}:${minutes} ${ampm}`;
};
function generateUTCDateDouble()
{
const utcDate = new Date();
const utcDouble = utcDate.getTime();
return utcDouble;
};
function getNextUTCDate(startDate, interval)
{
const inputDate = new Date(startDate);
var activators = {
"day" : function()
{
return addDays(inputDate, 1);
},
"two days" : function()
{
return addDays(inputDate, 2);
},
"three days" : function()
{
return addDays(inputDate, 3);
},
"four days" : function()
{
return addDays(inputDate, 4);
},
"five days" : function()
{
return addDays(inputDate, 5);
},
"week" : function()
{
return addWeeks(inputDate, 1);
},
"two weeks" : function()
{
return addWeeks(inputDate, 2);
},
"month" : function()
{
return addMonths(inputDate, 1);
},
"two months" : function()
{
return addMonths(inputDate, 2);
},
"three months" : function()
{
return addMonths(inputDate, 3);
},
"six months" : function()
{
return addMonths(inputDate, 6);
},
"year" : function()
{
return addYears(inputDate, 1);
},
};
if (activators[interval] !== undefined)
{
return activators[interval]().getTime();
}
return null;
};
function generateDateToID(date, interval = "day")
{
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hour = String(date.getHours()).padStart(2, '0');
const minute = String(date.getMinutes()).padStart(2, '0');
return interval === "year" ? `${year}` : interval === "month" ? `${year}-${month}` : interval === "day" ? `${year}-${month}-${day}` : interval === "hour" ? `${year}-${month}-${day}-${hour}` : `${year}-${month}-${day}-${hour}-${minute}`;
};
function convertNumberToMoneyFormat(n, showDecimals = true, minimumDecimals = 2, maximumDecimals = 2, moneyLocality = "en-US")
{
const number = parseFloat(n);
const options = showDecimals
? {
minimumFractionDigits : minimumDecimals,
maximumFractionDigits : maximumDecimals
}
: {
minimumFractionDigits : 0,
maximumFractionDigits : 0
};
const moneyNumber = n.toLocaleString(moneyLocality, options);
return moneyNumber;
};
function displayLegalDocumentCurrentDate()
{
const date = new Date();
const month = date.toLocaleString("default", { month : "long" });
const year = date.getFullYear();
const day = date.getDate();
return `${month} ${day}, ${year}`;
};
function convertNumberToWords(n)
{
const ones = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"];
const tens = ["", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"];
if (n < 20)
{
return ones[n];
}
if (n < 100)
{
return tens[Math.floor(n / 10)] + (n % 10 ? '-' + ones[n % 10] : '');
}
if (n < 1000)
{
return ones[Math.floor(n / 100)] + ' Hundred' + (n % 100 ? ' ' + ConvertNumberToWords(n % 100) : '');
}
const units = ["Thousand", "Million", "Billion", "Trillion", "Quadrillion", "Quintillion", "Sextillion", "Septillion", "Octillion", "Nonillion", "Decillion"];
let unitIndex = 0;
let remainder = n;
while (remainder >= 1000)
{
remainder /= 1000;
unitIndex++;
}
remainder = Math.floor(remainder);
let words = ConvertNumberToWords(remainder) + " " + units[unitIndex - 1];
let rest = n % (Math.pow(1000, unitIndex));
if (rest > 0)
{
words += " " + ConvertNumberToWords(rest);
}
return words;
};
function convertDateTime(dateString, includeTimeZone = true, includeLeadingZeroHour = true, includeSeconds = true, shortDateFormat = false, includeLeadingZeroMonth = true)
{
const date = new Date(dateString);
let formattedDate;
if (shortDateFormat)
{
formattedDate = date.toLocaleDateString("en-US", {
month : includeLeadingZeroMonth ? "2-digit" : "numeric",
day : "2-digit",
year : "numeric"
});
}
else
{
formattedDate = date.toLocaleDateString("en-US", {
weekday : "short",
month : "short",
day : "numeric",
year : "numeric"
});
}
const timeOptions = {
hour : includeLeadingZeroHour ? "2-digit" : "numeric",
minute : "2-digit",
hour12 : true
};
if (includeSeconds)
{
timeOptions.second = "2-digit";
}
const formattedTime = date.toLocaleTimeString('en-US', timeOptions);
let finalOutput = `${formattedDate} ${formattedTime}`;
if (includeTimeZone)
{
const timeZone = date.toTimeString().match(/\(([^)]+)\)/)[1];
finalOutput += ` (${timeZone})`;
}
return finalOutput;
};
function convertSecondsToETATime(seconds)
{
if (seconds === 0) return "0 s";
const units = [
{ name : "y", seconds : 60 * 60 * 24 * 365 },
{ name : "mo", seconds : 60 * 60 * 24 * 30 },
{ name : "w", seconds : 60 * 60 * 24 * 7 },
{ name : "d", seconds : 60 * 60 * 24 },
{ name : "h", seconds : 60 * 60 },
{ name : "m", seconds : 60 },
{ name : "s", seconds : 1 }
];
let remainingSeconds = seconds;
let result = "";
for (const unit of units)
{
const count = Math.floor(remainingSeconds / unit.seconds);
if (count > 0)
{
result += `${count}${unit.name} `;
remainingSeconds %= unit.seconds;
}
}
return result.trim();
};
function convertToVideoTime(time, options = {
showYears : false,
showMonths : false,
showDays : true,
showHours : true,
showMinutes : true,
showSeconds : true,
useLetters : false,
leadingZero : true,
showZero : true
})
{
const years = Math.floor(time / (365 * 24 * 60 * 60));
const months = Math.floor((time % (365 * 24 * 60 * 60)) / (30 * 24 * 60 * 60));
const days = Math.floor((time % (30 * 24 * 60 * 60)) / (24 * 60 * 60));
const hours = Math.floor((time % (24 * 60 * 60)) / (60 * 60));
const minutes = Math.floor((time % (60 * 60)) / 60);
const seconds = Math.floor(time % 60);
if (years > 0 && options.showYears)
{
return `${years}${options.useLetters ? "y:" : ":"}${months}${options.useLetters ? "m:" : ":"}${days}${options.useLetters ? "d:" : ":"}${hours < 10 && options.leadingZero ? "0" : ""}${hours}${options.useLetters ? "h:" : ":"}${minutes < 10 ? "0" : ""}${minutes}${options.useLetters ? "m:" : ":"}${seconds < 10 ? "0" : ""}${seconds}${options.useLetters ? "s" : ""}`;
}
if (months > 0 && options.showMonths)
{
return `${months}${options.useLetters ? "m:" : ":"}${days}${options.useLetters ? "d:" : ":"}${hours < 10 && options.leadingZero ? "0" : ""}${hours}${options.useLetters ? "h:" : ":"}${minutes < 10 ? "0" : ""}${minutes}${options.useLetters ? "m:" : ":"}${seconds < 10 ? "0" : ""}${seconds}${options.useLetters ? "s" : ""}`;
}
if (days > 0 && options.showDays)
{
return `${days}${options.useLetters ? "d:" : ":"}${hours < 10 && options.leadingZero ? "0" : ""}${hours}${options.useLetters ? "h:" : ":"}${minutes < 10 ? "0" : ""}${minutes}${options.useLetters ? "m:" : ":"}${seconds < 10 ? "0" : ""}${seconds}${options.useLetters ? "s" : ""}`;
}
if (hours > 0 && options.showHours)
{
return `${hours < 10 && options.leadingZero ? "0" : ""}${hours}${options.useLetters ? "h:" : ":"}${minutes < 10 ? "0" : ""}${minutes}${options.useLetters ? "m:" : ":"}${seconds < 10 ? "0" : ""}${seconds}${options.useLetters ? "s" : ""}`;
}
if (minutes > 0 || (options.showZero && options.showMinutes))
{
return `${minutes}:${seconds < 10 ? "0" : ""}${seconds}`;
}
return `${seconds < 10 ? "0" : ""}${seconds}`;
};
function convertDuration(duration)
{
const regex = /(\d+)\s*(ms|s|m|h|d|M|y|ns)/g;
let totalMilliseconds = 0;
let match;
while ((match = regex.exec(duration)) !== null)
{
const value = parseInt(match[1]);
const unit = match[2];
switch (unit)
{
case 'ms':
totalMilliseconds += value;
break;
case 's':
totalMilliseconds += value * 1000;
break;
case 'm':
totalMilliseconds += value * 1000 * 60;
break;
case 'h':
totalMilliseconds += value * 1000 * 60 * 60;
break;
case 'd':
totalMilliseconds += value * 1000 * 60 * 60 * 24;
break;
case 'M':
totalMilliseconds += value * 1000 * 60 * 60 * 24 * 30;
break;
case 'y':
totalMilliseconds += value * 1000 * 60 * 60 * 24 * 365;
break;
case 'ns':
totalMilliseconds += value / 1000000;
break;
default:
throw new Error(`Unknown time unit: ${unit}`);
}
}
return totalMilliseconds;
};
function convertToReadableDuration(ms)
{
const years = Math.floor(ms / (1000 * 60 * 60 * 24 * 365));
ms %= 1000 * 60 * 60 * 24 * 365;
const months = Math.floor(ms / (1000 * 60 * 60 * 24 * 30));
ms %= 1000 * 60 * 60 * 24 * 30;
const days = Math.floor(ms / (1000 * 60 * 60 * 24));
ms %= 1000 * 60 * 60 * 24;
const hours = Math.floor(ms / (1000 * 60 * 60));
ms %= 1000 * 60 * 60;
const minutes = Math.floor(ms / (1000 * 60));
ms %= 1000 * 60;
const seconds = Math.floor(ms / 1000);
ms %= 1000;
return {
years,
months,
days,
hours,
minutes,
seconds,
milliseconds: ms
};
};
function convertTextIntoParagraphs(text, maxSentences = 8, maxWords = null, maxParagraphLength = null, returnArray = false)
{
let words = text.split(/\s+/);
let sentences = text.match(/[^.!?]+[.!?]+["')]*|.+/g) || [];
let paragraphs = [];
let currentParagraph = "";
let wordCount = 0;
let sentenceCount = 0;
words.forEach(word => {
let exceedsCharLimit = maxParagraphLength && (currentParagraph.length + word.length + 1) > maxParagraphLength;
let exceedsWordLimit = maxWords && (wordCount + 1) > maxWords;
let exceedsSentenceLimit = maxSentences && (sentenceCount + 1) > maxSentences;
if ((maxParagraphLength && exceedsCharLimit) || (maxWords && exceedsWordLimit) || (maxSentences && exceedsSentenceLimit))
{
paragraphs.push(currentParagraph.trim());
currentParagraph = "";
wordCount = 0;
sentenceCount = 0;
}
currentParagraph += word + " ";
wordCount++;
if (/[.!?]$/.test(word))
{
sentenceCount++;
}
});
if (currentParagraph.trim().length > 0)
{
paragraphs.push(currentParagraph.trim());
}
return returnArray ? paragraphs : paragraphs.join("\n\n");
};
function convertFileSizeToDisplay(bytes, decimalPoints = 2)
{
if (bytes === 0) return "0 Bytes";
const k = 1024;
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(decimalPoints)) + " " + sizes[i];
};
function convertToSizeUnits(size)
{
const units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
let unitIndex = 0;
while (size >= 1024 && unitIndex < units.length - 1)
{
size /= 1024;
unitIndex++;
}
return { current : size.toFixed(2), unit : units[unitIndex] };
};
function containsBlacklistedCharacters(input, whiteListedInput = "")
{
let blacklistedChars = ' \t\n\r!@#$%^&*()+=[]{};:\'",<>/?\\|`~';
for (let whiteListedChar of whiteListedInput)
{
blacklistedChars = blacklistedChars.replace(whiteListedChar, "");
}
const blacklistedCharacters = new RegExp('[' + blacklistedChars.replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&") + ']');
return blacklistedCharacters.test(input);
};
function cleanData(data, options = { deep : false })
{
if (typeof data !== "object" || data === null) { return {}; }
const result = {};
for (const [key, value] of Object.entries(data))
{
if (value === null || value === undefined)
{
continue;
}
if (options.deep && typeof value === "object" && !Array.isArray(value))
{
const cleanedNested = cleanData(value, options);
if (Object.keys(cleanedNested).length > 0)
{
result[key] = cleanedNested;
}
}
else
{
result[key] = value;
}
}
return result;
};
function convertHexToRGB(hex)
{
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
return [r, g, b];
};
async function generateChalk()
{
const chalk = await import("chalk");
return chalk.default;
};
function generateLerp(a, b, t)
{
return a + (b - a) * t;
};
function generateColorInterpolation(color1, color2, factor)
{
const result = color1.slice();
for (let i = 0; i < 3; i++)
{
result[i] = Math.round(generateLerp(color1[i], color2[i], factor));
}
return result;
};
function generateGradientColors(colors, steps)
{
let gradient = [];
const sections = colors.length - 1;
const stepsPerSection = Math.floor(steps / sections);
for (let section = 0; section < sections; section++)
{
for (let step = 0; step < stepsPerSection; step++)
{
const color1 = convertHexToRGB(colors[section]);
const color2 = convertHexToRGB(colors[section + 1]);
const factor = step / stepsPerSection;
gradient.push(generateColorInterpolation(color1, color2, factor));
}
}
gradient.push(convertHexToRGB(colors[colors.length - 1]));
while (gradient.length < steps)
{
gradient.push(convertHexToRGB(colors[colors.length - 1]));
}
return gradient;
};
async function outputMovingGradient(text, colors, interval = 100)
{
const chalk = await generateChalk();
let offset = 0;
const updateText = () => {
const gradientColors = generateGradientColors(colors, text.length);
let coloredText = '';
for (let i = 0; i < text.length; i++)
{
const colorIndex = (i + offset) % gradientColors.length;
const [r, g, b] = gradientColors[colorIndex];
coloredText += chalk.rgb(r, g, b)(text[i]);
}
console.clear();
console.log(coloredText);
offset = (offset + 1) % text.length;
};
setInterval(updateText, interval);
};
async function outputGradient(text, colors)
{
const chalk = await generateChalk();
const gradient = generateGradientColors(colors, text.length);
let coloredText = '';
for (let i = 0; i < text.length; i++)
{
const [r, g, b] = gradient[i];
coloredText += chalk.rgb(r, g, b)(text[i]);
}
console.log(coloredText);
return;
};
function debounce(func, wait)
{
let timeout;
return function (...args)
{
clearTimeout(timeout);
timeout = setTimeout(async () => {
try
{
await func.apply(this, args);
}
catch (error)
{
if (error.type !== "cancelation")
{
console.error("Error during debounce: ", error);
}
}
}, wait);
};
};
function delay(ms)
{
return new Promise(resolve => setTimeout(resolve, ms));
};
function incrementVersion(versionInfo, incrementID = "patch")
{
const versionP = versionInfo.split(".").map(Number);
var id = incrementID;
if (versionP[2] === 100) { id = "minor"; }
if (versionP[1] === 100) { id = "major"; }
if (versionP[0] === 100) { id = "patch"; }
switch (id)
{
case 'major':
versionP[0]++;
versionP[1] = 0;
versionP[2] = 0;
break;
case 'minor':
versionP[1]++;
versionP[2] = 0;
break;
case "patch":
versionP[2]++;
break;
default:
break;
}
const version = versionP.join(".");
return version;
};
function ifNightTime(date = new Date(), minT = 6, maxT = 18)
{
const hour = date.getHours();
return hour >= maxT || hour < minT;
};
function outputPackageCreationTitle(displayDate = true, displayAuthor = true)
{
const date = displayDate ? convertUTCDateToDateDisplay(generateUTCDateDouble(), true, 1) : "";
const author = displayAuthor ? "~ Created by Steven Compton" : "";
outputGradient(date + "\n\n" + author, ["#F0C14B", "#FFF9DB", "#FFF9DB", "#B38600", "#FFF9DB", "#F7D9A0"]);
return;
}
function outputPackageName()
{
outputGradient("LegendaryBuilderProNodeJS-Utilities", ["#800080", "#FF00FF"]);
return;
}
function outputPackageLogo()
{
outputGradient(`
..::--=+-
.::--==+++++++++
::-================++.
------=============++:
----------=====-::..
:-:----------==.
... ..:--:--. .------=.
..::::.: :-:.. .-: -:-----:
::.. .:: ::. .:: -::::--:
:: .:..:. :: :::::::-
... ::. .. :: .:...::-
. . .... . .. . ....:
. . . .:.. ... . ...
. . . .. . :
. . .. . .
. . .. . ..
. . .. . .. . ..
. . . ..
. . ... . ..
. .. . ..
. ... . ..
. .. ...
. .. . .
. .
`, ["#FF00FF", "#800080", "#FF00FF"]);
return;
}
function outputPackageCredit(displayLogo = true, displayName = true, displayCreationTitle = true, displayDate = true, displayAuthor = true)
{
if (displayLogo) outputPackageLogo();
if (displayName) { outputPackageName(); console.log("\n"); }
if (displayCreationTitle) outputPackageCreationTitle(displayDate, displayAuthor);
return;
}
async function getDesiredData(currentDB, collectionID, docAttrID, inputData)
{
const desiredData = await getUniversalData(currentDB, collectionID, docAttrID, inputData);
if (desiredData === null) { return null; }
return desiredData;
};
async function addDesiredData(currentDB, collectionID, iD, inputData)
{
await addUniversalData(currentDB, collectionID, iD, inputData);
return;
};
// Universal File Manager Functionality
function validateSignedURL(req, res, baseFilePath, secretKey)
{
const { filePath, expires, signature, salt, ip } = req.query;
if (!salt)
{
return res.status(400).json({ message : "Not authorized; missing credentials." });
}
const currentTime = Math.floor(Date.now() / 1000);
if (currentTime > expires)
{
return res.status(403).json({ message : "URL expired." });
}
const clientIp = req.ip;
if (ip && clientIp !== ip)
{
return res.status(403).json({ message : "Address not authorized." });
}
const dataToSign = `${filePath}:${expires}:${ip || ""}`;
const expectedSignature = crypto.createHmac("sha256", secretKey).update(dataToSign + salt).digest("hex");
if (signature !== expectedSignature)
{
return res.status(403).json({ message : "Invalid signature." });
}
const fullFilePath = path.join(baseFilePath, filePath);
res.download(fullFilePath);
};
async function uploadFile(fileSystem, fileBytes, uploadPath, fileType = "pdf")
{
return new Promise((resolve, reject) => {
let buffer;
var currentFileBytes = fileBytes;
if (typeof currentFileBytes !== "string" && Buffer.isBuffer(fileBytes))
{
currentFileBytes = fileBytes.toString("base64");
}
const matches = fileBytes.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/);
if (matches && matches.length === 3)
{
buffer = Buffer.from(matches[2], "base64");
fileType = matches[1];
}
else
{
buffer = Buffer.from(fileBytes, "base64");
}
const file = fileSystem.file(uploadPath);
const stream = file.createWriteStream({
metadata: {
contentType : fileType.indexOf("/") !== -1 ? fileType : `application/${fileType}`,
},
});
stream.on('error', (error) => reject(error));
stream.on('finish', async () => {
await file.makePublic().catch(reject);
const [url] = await file.getSignedUrl({
action : 'read',
expires : '03-09-2491'
});
resolve(url);
});
stream.end(buffer);
});
};
async function getFileDownloadUrl(fileSystem, filePath, urlExpiration = 60)
{
const file = fileSystem.file(filePath);
const expires = Date.now() + urlExpiration * 60 * 1000;
try
{
const [url] = await file.getSignedUrl({
action: "read",
expires,
});
console.log(`Generated signed URL: ${url}`);
return url;
}
catch (error)
{
console.error("Did not generate signed URL: ", error);
throw error;
}
};
function getSignedURL(filePath, secretKey, expiresIn = 60, domain = "https://your-domain.com", endpoint = "/download", userIP = "")
{
const expirationTime = Math.floor(Date.now() / 1000) + expiresIn;
const dataToSign = `${filePath}:${expirationTime}:${userIP}`;
const salt = crypto.randomBytes(16).toString("hex");
const signature = crypto.createHmac("sha256", secretKey).update(dataToSign + salt).digest("hex");
const signedURL = `${domain}${endpoint}?filePath=${encodeURIComponent(filePath)}&expires=${expirationTime}&signature=${signature}&salt=${salt}${userIP ? `&ip=${userIP}` : ''}`;
return signedURL;
};
async function getFileData(fileSystem, filePath)
{
const file = fileSystem.file(filePath);
try
{
const buffer = await file.download();
console.log("File downloaded successfully.");
return buffer[0];
}
catch (error)
{
console.error("Did not download file: ", error);
throw error;
}
};
async function getFile(fileSystem, filePath, req, ress, getType = "inline")
{
const file = fileSystem.file(filePath);
try
{
const [metadata] = await file.getMetadata();
ress.setHeader("Content-Type", metadata.contentType || "application/octet-stream");
ress.setHeader("Content-Disposition", `${getType}; filename=\"` + encodeURIComponent(filePath.split("/").pop()) + '"');
const stream = file.createReadStream();
stream.on("error", (error) => {
console.error("Did not stream the file: ", error);
ress.status(327).json({ Message : "Did not download the file." });
});
stream.pipe(ress);
}
catch (error)
{
console.error("Did not fetch file metadata: ", error);
ress.status(327).json({ Message : "Did not processing your request." });
}
};
async function listAllFilesAndFolders(fileSystem)
{
try
{
const allFiles = await fileSystem.getFiles({ autoPaginate: true });
const files = allFiles[0];
const bucketStructure = {};
files.forEach(file => {
const pathParts = file.name.split('/');
let currentLevel = bucketStructure;
pathParts.forEach((part, index) => {
if (index === pathParts.length - 1)
{
if (!currentLevel.files) currentLevel.files = [];
currentLevel.files.push({ name: part, metadata: file.metadata });
}
else
{
if (!currentLevel[part])
{
currentLevel[part] = {};
}
currentLevel = currentLevel[part];
}
});
});
return bucketStructure;
}
catch (error)
{
return null;
}
}
async function listFilesInFolder(fileSystem, folderPath)
{
try
{
const options = {
prefix : folderPath,
delimiter : "/"
};
const response = await fileSystem.getFiles(options);
const files = response[0] || [];
const additionalResponseInfo = response[1] || {};
const fileMetadata = files.map(file => ({
name: file.name.replace(folderPath, ""),
size: file.metadata.size,
contentType: file.metadata.contentType,
}));
const mainFolderName = folderPath.split("/").filter(Boolean).pop() || folderPath;
const subdirectoryNames = additionalResponseInfo.prefixes ? additionalResponseInfo.prefixes.map(prefix => {
const cleanPrefix = prefix.endsWith('/') ? prefix.slice(0, -1) : prefix;
return cleanPrefix.split("/").pop();
}) : [];
return {
mainFolderName,
subdirectoryNames,
files : fileMetadata,
};
}
catch (error)
{
console.error("Did not list files in folder: ", error);
return null;
}
};
async function deleteFolder(fileSystem, folderPath)
{
try
{
const [files] = await fileSystem.getFiles({ prefix: folderPath });
const deletePromises = files.map(file => file.delete());
await Promise.all(deletePromises);
console.log(`Successfully deleted folder: ${folderPath.split("/")[0] ? folderPath.split("/")[0] : folderPath}.`);
return true;
}
catch (error)
{
console.error("Error deleting folder contents: ", error);
return false;
}
};
async function deleteFile(fileSystem, filePath)
{
try
{
await fileSystem.file(filePath).delete();
console.log(`File deleted from ${fileSystem.name}`);
return true;
}
catch (error)
{
console.error("Did not delete file: ", error);
return false;
}
};
// Map Functionality
async function getAddressLocality(mapKey, address)
{
const url = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(address)}&key=${mapKey}`;
try
{
const fetch = (await import('node-fetch')).default;
const response = await fetch(url);
const localityData = await response.json();
if (localityData.status === 'OK')
{
const localityComponents = localityData.results[0].address_components;
const country = localityComponents.find(c => c.types.includes('country'))?.long_name;
const state = localityComponents.find(c => c.types.includes('administrative_area_level_1'))?.long_name;
const county = localityComponents.find(c => c.types.includes('administrative_area_level_2'))?.long_name;
const city = localityComponents.find(c => c.types.includes('locality'))?.long_name;
return { country, state, county, city };
}
return null;
}
catch (error)
{
console.error('Did not fetch locality components:', error);
return null;
}
}
async function getAddresses(mapKey, address)
{
const url = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(address)}&key=${mapKey}`;
try
{
const fetch = (await import('node-fetch')).default;
const response = await fetch(url);
const data = await response.json();
if (data.status === 'OK')
{
return data.results.map(result => ({
formatted_address: result.formatted_address,
address_components: result.address_components
}));
}
return null;
}
catch (error)
{
console.error('Did not fetch addresses:', error);
return null;
}
}
module.exports = {
outputPackageCreationTitle,
outputPackageName,
outputPackageLogo,
outputPackageCredit,
incrementVersion,
ifNightTime,
getDesiredData,
addDesiredData,
getAddressLocality,
getAddresses,
generateUTCDateDouble,
generateDateToID,
convertUTCDateToDateDisplay,
convertNumberToMoneyFormat,
convertNumberToWords,
convertDateTime,
convertSecondsToETATime,
convertToVideoTime,
convertDuration,
convertToReadableDuration,
convertFileSizeToDisplay,
convertToSizeUnits,
containsBlacklistedCharacters,
cleanData,
convertHexToRGB,
generateLerp,
generateColorInterpolation,
generateGradientColors,
outputMovingGradient,
outputGradient,
displayLegalDocumentCurrentDate,
debounce,
delay,
checkForMatchingUniversalData,
desiredInnerUniversalData,
deepEqualData,
uploadFile,
deleteFolder,
deleteFile,
listAllFilesAndFolders,
listFilesInFolder,
getFileDownloadUrl,
validateSignedURL,
getSignedURL,
getFileData,
getFile,
getUniversalMultiDataContainingDesiredData,
getUniversalDataFromDocAttribute,
getUniversalDataFromDoc,
getUniversalMultiData,
getUniversalData,
getUniversalCollectionSize,
getAvailableUniversalDocID,
deleteUniversalDataField,
deleteUniversalData,
updateUniversalData,
addUniversalData
};