qmemory
Version:
A comprehensive production-ready Node.js utility library with MongoDB document operations, user ownership enforcement, Express.js HTTP utilities, environment-aware logging, and in-memory storage. Features 96%+ test coverage with comprehensive error handli
97 lines (88 loc) • 3.48 kB
JavaScript
/**
* qgenutils-wrapper
* Centralizes imports from qgenutils and provides safe fallbacks.
* Use this module instead of importing qgenutils directly to make
* future replacements or shims easy and consistent.
*/
// Minimal no-op logger fallback to avoid runtime errors if logger missing
const nullLogger = {
debug: () => {},
info: () => {},
warn: () => {},
error: () => {}
};
// Prefer using only the logger from qgenutils to avoid pulling in qerrors
let logger = nullLogger;
try {
// eslint-disable-next-line import/no-extraneous-dependencies
logger = require('qgenutils/lib/logger');
} catch (_) {
logger = nullLogger;
}
// Lightweight local utilities (do not import qgenutils modules that pull qerrors)
const sanitizeString = (v) => {
if (v === null || v === undefined) return '';
const s = String(v);
return s
.replace(/<[^>]*>/g, '')
.replace(/&[#\w]+;/g, '')
.replace(/on\w+\s*=/gi, '')
.replace(/javascript:|vbscript:|data:/gi, '')
.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '');
};
const sanitizeHtml = (v) => (typeof v === 'string' ? v.replace(/<[^>]*>/g, '') : '');
const isValidString = (v) => typeof v === 'string' && v.trim() !== '';
const isValidObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
const getEnvVar = (name, def) => process.env[String(name).trim()] ?? def;
const hasEnvVar = (name) => {
const v = process.env[String(name).trim()];
return typeof v === 'string' && v.trim() !== '';
};
const requireEnvVars = (vars = []) => {
const missing = (Array.isArray(vars) ? vars : []).filter((n) => !hasEnvVar(n));
if (missing.length) throw new Error(`Missing or empty environment variables: ${missing.join(', ')}`);
};
// Local graceful shutdown helper to avoid importing qerrors
const gracefulShutdown = (server, cleanup = null, timeout = 10000) => {
if (!server || typeof server.close !== 'function') return;
let shuttingDown = false;
async function shutdown(signal) {
if (shuttingDown) return;
shuttingDown = true;
const timer = setTimeout(() => process.exit(1), timeout);
try {
await new Promise((resolve) => server.close(resolve));
if (typeof cleanup === 'function') await cleanup();
clearTimeout(timer);
process.exit(0);
} catch (err) {
logger.error('gracefulShutdown error', { message: err.message });
process.exit(1);
}
}
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
};
// Minimal URL helpers (only if needed)
const ensureProtocol = (url) => (typeof url === 'string' && url ? (url.match(/^\w+:\/\//) ? url : `https://${url}`) : 'https://');
const normalizeUrlOrigin = (u) => { try { return new URL(ensureProtocol(u)).origin.toLowerCase(); } catch { return null; } };
const stripProtocol = (u) => (typeof u === 'string' ? u.replace(/^https?:\/\//i, '').replace(/\/$/, '') : '');
const parseUrlParts = (u) => { try { const url = new URL(ensureProtocol(u)); return { baseUrl: url.origin, endpoint: url.pathname + url.search }; } catch { return null; } };
const generateExecutionId = () => `exec_${Date.now()}_${Math.random().toString(36).slice(2, 14)}`;
module.exports = {
logger,
sanitizeString,
sanitizeHtml,
isValidString,
isValidObject,
getEnvVar,
hasEnvVar,
requireEnvVars,
gracefulShutdown,
createShutdownManager: null,
ensureProtocol,
normalizeUrlOrigin,
stripProtocol,
parseUrlParts,
generateExecutionId
};