qgenutils
Version:
A security-first Node.js utility library providing authentication, HTTP operations, URL processing, validation, datetime formatting, and template rendering. Designed as a lightweight alternative to heavy npm packages with comprehensive error handling and
650 lines (468 loc) • 16.9 kB
Markdown
# QGenUtils API Reference
## Overview
QGenUtils provides utilities organized into focused modules. Each function follows consistent patterns for error handling, logging, and security.
### Importing
```javascript
const utils = require('qgenutils');
```
## Authentication Module (`auth`)
### `checkPassportAuth(req)`
Verify user authentication status via Passport.js with fail-closed security.
**Parameters:**
- `req` (Object): Express request object with Passport methods
**Returns:**
- `boolean`: `true` if authenticated, `false` otherwise
**Security Behavior:**
- Returns `false` if Passport isn't configured
- Returns `false` on any authentication errors
- Logs all authentication attempts for auditing
**Example:**
```javascript
const { checkPassportAuth } = require('qgenutils');
if (!checkPassportAuth(req)) {
return res.status(401).json({ error: 'Authentication required' });
}
```
### `hasGithubStrategy()`
Detect if GitHub OAuth strategy is configured in Passport.js.
**Parameters:**
- None
**Returns:**
- `boolean`: `true` if GitHub strategy is available, `false` otherwise
**Error Handling:**
- Returns `false` if Passport isn't available
- Returns `false` if strategy detection fails
**Example:**
```javascript
const { hasGithubStrategy } = require('qgenutils');
// hasGithubStrategy checks global.passport for configured strategies
const showGithubLogin = hasGithubStrategy();
```
## DateTime Module (`datetime`)
### `formatDateTime(dateString)`
Format ISO date strings to human-readable format with fallback handling.
**Parameters:**
- `dateString` (string): ISO 8601 date string
**Returns:**
- `string`: Formatted date/time or "N/A" for invalid inputs
**Fallback Behavior:**
- Returns "N/A" for null/undefined inputs
- Returns "N/A" for invalid date strings
- Uses locale-appropriate formatting for valid dates
**Example:**
```javascript
const { formatDateTime } = require('qgenutils');
formatDateTime('2024-01-15T10:30:00.000Z'); // "1/15/2024, 10:30:00 AM"
formatDateTime(null); // "N/A"
```
### `formatDuration(startDateString, endDateString?)`
Calculate duration between dates in HH:MM:SS format.
**Parameters:**
- `startDateString` (string): ISO 8601 start date
- `endDateString` (string, optional): ISO 8601 end date (defaults to current time)
**Returns:**
- `string`: Duration in "HH:MM:SS" format or "00:00:00" for invalid inputs
**Calculation Method:**
- Uses absolute difference (handles reversed date order)
- Converts milliseconds to hours:minutes:seconds
- Zero-pads all components for consistent display
**Example:**
```javascript
const { formatDuration } = require('qgenutils');
formatDuration('2024-01-15T10:00:00Z', '2024-01-15T12:30:45Z'); // "02:30:45"
formatDuration('2024-01-15T10:00:00Z'); // Duration to current time
```
## HTTP Module (`http`)
### `calculateContentLength(body)`
Calculate accurate byte length for HTTP bodies with UTF-8 support.
**Parameters:**
- `body` (any): Content to calculate length for (string, object, null, etc.)
**Returns:**
- `string`: Content length as string (HTTP headers require string format)
**Throws:**
- `TypeError`: If body is undefined (indicates coding error)
**Type Handling:**
- `null`: Returns "0"
- `string`: Uses `Buffer.byteLength()` for UTF-8 accuracy
- `object`: JSON stringifies then calculates bytes
- Empty objects/strings: Returns "0"
- `Buffer`: Uses body.length directly for binary payloads // Buffer bullet
**Example:**
```javascript
const { calculateContentLength } = require('qgenutils');
calculateContentLength("Hello, 世界!"); // "13" (UTF-8 bytes)
calculateContentLength({ msg: "hi" }); // "12" (JSON bytes)
calculateContentLength(null); // "0"
calculateContentLength(Buffer.from('Hi')); // "2" (binary bytes) // Buffer example
```
### `buildCleanHeaders(headers, method, body)`
Remove dangerous headers and recalculate content-length for proxy security.
**Parameters:**
- `headers` (Object): Original request headers
- `method` (string): HTTP method (GET, POST, etc.)
- `body` (any): Request body content
**Returns:**
- `Object`: Cleaned headers safe for forwarding
**Header Cleaning:**
- Removes `host`, `x-target-url`, `x-api-key`, `cdn-loop`, `cf-connecting-ip`
- Removes `cf-ipcountry`, `cf-ray`, `cf-visitor`, `render-proxy-ttl`, `connection`
- Recalculates `content-length` for non-GET requests with bodies
- Removes `content-length` from GET requests (HTTP spec compliance)
**Example:**
```javascript
const { buildCleanHeaders } = require('qgenutils');
const cleaned = buildCleanHeaders(
{ 'host': 'evil.com', 'authorization': 'Bearer token' },
'POST',
{ data: 'test' }
);
// Returns: { 'authorization': 'Bearer token', 'content-length': '15' }
```
### `HEADERS_TO_REMOVE` constant
Immutable array of headers removed by `buildCleanHeaders` for safer proxies. Exported from `lib/http.js`.
```javascript
const { HEADERS_TO_REMOVE } = require('qgenutils');
console.log(HEADERS_TO_REMOVE);
```
### `getRequiredHeader(req, res, headerName, statusCode, errorMessage)`
Extract required headers with automatic error responses.
**Parameters:**
- `req` (Object): Express request object
- `res` (Object): Express response object
- `headerName` (string): Header name to extract
- `statusCode` (number): Error status code if header missing
- `errorMessage` (string): Error message for missing header
**Returns:**
- `string|null`: Header value or null if missing (error response sent)
**Behavior:**
- Returns header value if present
- Sends error response and returns null if missing
- Handles case-insensitive header lookup
**Example:**
```javascript
const { getRequiredHeader } = require('qgenutils');
const contentType = getRequiredHeader(req, res, 'content-type', 400, 'Content-Type required');
if (!contentType) return; // Error already sent
```
## URL Module (`url`)
### `ensureProtocol(url)`
Add HTTPS protocol to URLs that don't have one (security-first default).
**Parameters:**
- `url` (string): URL to process
**Returns:**
- `string|null`: URL with protocol or null if invalid
**Protocol Logic:**
- Defaults to HTTPS for security
- Preserves existing HTTP/HTTPS protocols
- Returns null for invalid inputs (empty strings, non-strings)
- Case-insensitive protocol detection
**Example:**
```javascript
const { ensureProtocol } = require('qgenutils');
ensureProtocol('example.com'); // "https://example.com"
ensureProtocol('http://example.com'); // "http://example.com" (preserved)
ensureProtocol(''); // null
```
### `normalizeUrlOrigin(url)`
Normalize URLs to lowercase origins for comparison and caching.
**Parameters:**
- `url` (string): URL to normalize
**Returns:**
- `string|null`: Normalized origin or null if parsing fails
**Normalization Process:**
1. Adds protocol via `ensureProtocol()`
2. Extracts origin (protocol + domain + port)
3. Converts hostname to lowercase
4. Preserves explicit ports (including standard ports)
**Example:**
```javascript
const { normalizeUrlOrigin } = require('qgenutils');
normalizeUrlOrigin('HTTP://EXAMPLE.COM/path'); // "http://example.com"
normalizeUrlOrigin('https://API.EXAMPLE.COM:8080'); // "https://api.example.com:8080"
```
### `stripProtocol(url)`
Remove protocol and trailing slash for display purposes.
**Parameters:**
- `url` (string): URL to clean
**Returns:**
- `string`: URL without protocol prefix or trailing slash
**Cleaning Process:**
- Removes `http://` or `https://` (case-insensitive)
- Removes trailing slash
- Preserves path, query parameters, and fragments
**Example:**
```javascript
const { stripProtocol } = require('qgenutils');
stripProtocol('https://example.com/'); // "example.com"
stripProtocol('HTTP://api.example.com/v1/users'); // "api.example.com/v1/users"
```
### `parseUrlParts(url)`
Split URLs into base URL and endpoint components.
**Parameters:**
- `url` (string): Complete URL to parse
**Returns:**
- `Object|null`: `{ baseUrl, endpoint }` or null if parsing fails
**Parsing Logic:**
- `baseUrl`: Origin only (protocol + domain + port)
- `endpoint`: Path + query string + fragment
- Uses `ensureProtocol()` for preprocessing
**Example:**
```javascript
const { parseUrlParts } = require('qgenutils');
parseUrlParts('https://api.example.com/v1/users?limit=10');
// Returns: {
// baseUrl: "https://api.example.com",
// endpoint: "/v1/users?limit=10"
// }
```
## Validation Module (`validation`)
### `requireFields(obj, requiredFields, res)`
Validate required fields with detailed error responses.
**Parameters:**
- `obj` (Object): Object to validate (typically `req.body`)
- `requiredFields` (Array): Array of required field names
- `res` (Object): Express response object for error responses
**Returns:**
- `boolean`: `true` if all fields present, `false` if validation failed
**Validation Logic:**
- Checks for truthy values (null, '', 0, false are considered missing)
- Collects ALL missing fields before responding
- Sends detailed error response with missing field list
- Returns boolean for simple conditional logic
**Error Response Format:**
```json
{
"error": "Missing required fields",
"missing": ["field1", "field2"]
}
```
**Example:**
```javascript
const { requireFields } = require('qgenutils');
if (!requireFields(req.body, ['name', 'email', 'password'], res)) {
return; // Error response already sent
}
// Continue processing...
```
## Response Utilities Module (`responseUtils`)
### `sendJsonResponse(res, statusCode, data)`
Send standardized JSON responses with proper headers.
**Parameters:**
- `res` (Object): Express response object
- `statusCode` (number): HTTP status code
- `data` (Object): Response data to JSON serialize
**Behavior:**
- Validates response object before use
- Uses Express's built-in `json()` method
- Logs all responses for debugging
- Sets appropriate Content-Type headers
**Example:**
```javascript
const { sendJsonResponse } = require('qgenutils');
sendJsonResponse(res, 200, { users: [], count: 0 });
```
### `sendValidationError(res, message, additionalData?, statusCode?)`
Send standardized validation error responses.
**Parameters:**
- `res` (Object): Express response object
- `message` (string): Error message
- `additionalData` (Object, optional): Additional error context
- `statusCode` (number, optional): HTTP status code (defaults to 400)
**Response Format:**
```json
{
"error": "Error message",
"field": "additional data"
}
```
**Example:**
```javascript
const { sendValidationError } = require('qgenutils');
sendValidationError(res, 'Invalid email format', { provided: 'invalid-email' });
```
### `sendAuthError(res, message?)`
Send standardized authentication error responses.
**Parameters:**
- `res` (Object): Express response object
- `message` (string, optional): Error message (defaults to "Authentication required")
**Behavior:**
- Always uses 401 status code
- Logs authentication failures for security monitoring
- Uses generic messages to prevent information disclosure
**Example:**
```javascript
const { sendAuthError } = require('qgenutils');
sendAuthError(res, 'Token expired');
```
### `sendServerError(res, message?, error?, context?)`
Send standardized server error responses with internal logging.
**Parameters:**
- `res` (Object): Express response object
- `message` (string, optional): Public error message
- `error` (Error, optional): Original error object for logging
- `context` (string, optional): Context information for debugging
**Security Features:**
- Sends generic message to client
- Logs detailed error internally via qerrors
- Never exposes stack traces or internal details
- Uses 500 status code
**Example:**
```javascript
const { sendServerError } = require('qgenutils');
try {
await riskyOperation();
} catch (error) {
sendServerError(res, 'Operation failed', error, 'userController');
}
```
## View Utilities Module (`views`)
### `renderView(res, viewName, errorTitle)`
Render EJS templates with graceful error handling.
**Parameters:**
- `res` (Object): Express response object
- `viewName` (string): Template name to render
- `errorTitle` (string): Error page title if rendering fails
**Error Handling:**
- Attempts template rendering first
- Shows user-friendly error page on failure
- Logs detailed error information for debugging
- Provides navigation back to home page
- Uses 500 status code for template errors
**Example:**
```javascript
const { renderView } = require('qgenutils');
renderView(res, 'dashboard', 'Dashboard Error');
```
### `registerViewRoute(routePath, viewName, errorTitle)`
Register simple view routes with built-in error handling. The global `app` object
is used internally, so no `app` parameter is required.
**Parameters:**
- `routePath` (string): Route path
- `viewName` (string): Template to render
- `errorTitle` (string): Error page title
**Behavior:**
- Creates GET route handler
- Integrates with `renderView()` for error handling
- Logs route registration for debugging
**Example:**
```javascript
const { registerViewRoute } = require('qgenutils');
registerViewRoute('/about', 'about', 'About Page Error');
```
## Input Validation Module (`inputValidation`)
### `isValidObject(obj)`
Check if value is a plain object (not array or null).
**Parameters:**
- `obj` (any): Value to validate
**Returns:**
- `boolean`: `true` if plain object, `false` otherwise
**Validation Logic:**
- Returns `false` for null, undefined, arrays
- Returns `true` only for plain objects
- Uses strict type checking
**Example:**
```javascript
const { isValidObject } = require('qgenutils/lib/input-validation');
isValidObject({ key: 'value' }); // true
isValidObject([1, 2, 3]); // false
isValidObject(null); // false
```
### `isValidString(str)`
Check if value is a non-empty string after trimming.
**Parameters:**
- `str` (any): Value to validate
**Returns:**
- `boolean`: `true` if non-empty string, `false` otherwise
**Validation Logic:**
- Returns `false` for non-string types
- Trims whitespace before checking length
- Returns `false` for empty or whitespace-only strings
**Example:**
```javascript
const { isValidString } = require('qgenutils/lib/input-validation');
isValidString('hello'); // true
isValidString(' '); // false (whitespace only)
isValidString(''); // false
```
### `hasMethod(obj, methodName)`
Check if object has a specific method.
**Parameters:**
- `obj` (any): Object to check
- `methodName` (string): Method name to look for
**Returns:**
- `boolean`: `true` if method exists, `false` otherwise
**Method Detection:**
- Checks for method existence and callable type
- Includes inherited methods (not just own properties)
- Safe for null/undefined objects
**Example:**
```javascript
const { hasMethod } = require('qgenutils/lib/input-validation');
hasMethod(res, 'json'); // true for Express response
hasMethod({}, 'toString'); // true (inherited)
hasMethod(null, 'method'); // false
```
### `isValidExpressResponse(res)`
Check if object is a valid Express response object.
**Parameters:**
- `res` (any): Object to validate
**Returns:**
- `boolean`: `true` if valid Express response, `false` otherwise
**Validation Criteria:**
- Must have `status()` method
- Must have `json()` method
- Uses `hasMethod()` for safe checking
**Example:**
```javascript
const { isValidExpressResponse } = require('qgenutils/lib/input-validation');
if (!isValidExpressResponse(res)) {
throw new Error('Invalid response object');
}
```
## Error Handling
All utilities follow consistent error handling patterns:
### Logging
- All operations are logged for debugging
- Errors are logged via qerrors with context
- Sensitive information is never logged
### Security
- Fail-closed: Default to most secure state on errors
- Generic error messages prevent information disclosure
- Detailed errors logged internally only
### Response Patterns
- Use response utilities for consistent error formats
- Validate inputs before processing
- Handle edge cases gracefully
## Common Patterns
### Authentication Check
```javascript
if (!checkPassportAuth(req)) {
return sendAuthError(res);
}
```
### Field Validation
```javascript
if (!requireFields(req.body, ['field1', 'field2'], res)) {
return; // Error already sent
}
```
### URL Processing
```javascript
const safeUrl = ensureProtocol(userInput);
const { baseUrl, endpoint } = parseUrlParts(safeUrl);
```
### Error Response
```javascript
try {
// risky operation
} catch (error) {
sendServerError(res, 'Operation failed', error, 'functionName');
}
```
## Logger
The library exports a configured Winston logger instance. It rotates files daily using `winston-daily-rotate-file` and retains logs for two weeks. Use this logger to record application events or debugging details.
```javascript
const { logger } = require('qgenutils');
logger.info('Utility initialized');
```
All functions include comprehensive logging and follow the fail-closed security model for production reliability.