tiny-server-essentials
Version:
A good utility toolkit to unify Express v5 and Socket.IO v4 into a seamless development experience with modular helpers, server wrappers, and WebSocket tools.
580 lines (373 loc) โข 14.8 kB
Markdown
# ๐ `TinyExpress` Class - Documentation
A custom utility class for enhancing and managing behavior in Express-based HTTP servers. Includes CSRF setup, domain validation, IP extraction, and HTTP status code reference.
---
## ๐งพ Type Definitions
### ๐ฅ `Request`
Alias for `express.Request`.
### ๐ข `HttpStatusCode`
Represents a valid HTTP status code as a number.
### ๐ `IPExtractor`
```ts
(req: Request) => string[]
```
A function that extracts a list of IPs from a request.
### ๐ก๏ธ `DomainValidator`
```ts
(req: Request) => boolean
```
A function that validates if the domain of a request matches a rule.
### ๐ `OriginData`
Represents structured information parsed from an HTTP `Origin` header.
| Property | Type | Description | |
| ---------- | -------- | ----------------------------------------- | ----------------------------- |
| `raw` | \`string | null\` | The raw `Origin` header value |
| `protocol` | `string` | The protocol used (e.g., `http`, `https`) | |
| `hostname` | `string` | The hostname extracted from the origin | |
| `port` | `string` | The port used (default or explicit) | |
| `full` | `string` | The full reconstructed origin URL | |
| `error` | `string` | Any parsing error encountered | |
---
## ๐๏ธ Private Fields
### ๐ `#domainTypeChecker`
```ts
string = "hostname"
```
Type of domain field to be validated (e.g., hostname).
### โ `#forbiddenDomainMessage`
```ts
string = "Forbidden domain."
```
Message used when a domain is rejected.
### ๐ง `#ipExtractors`
```ts
{ [key: string]: IPExtractor }
```
Registry of IP extractor functions.
### โ
`#activeExtractor`
```ts
string = "DEFAULT"
```
Currently active IP extractor name.
### ๐ก๏ธ `#csrf`
```ts
{
refreshCookieName: string,
cookieName: string,
headerName: string,
errMessage: string,
enabled: boolean,
refreshInterval: number|null
}
```
CSRF protection configuration object.
* `refreshCookieName`: Name for the refresh token cookie
* `cookieName`: Name for the CSRF token cookie
* `headerName`: Header where CSRF token is expected
* `errMessage`: Error message on CSRF failure
* `enabled`: Whether CSRF is currently active
* `refreshInterval`: Time interval (ms) for CSRF refresh
### ๐งช `#domainValidators`
```ts
{ [key: string]: DomainValidator }
```
A collection of validation functions per request property to validate incoming request domains.
---
## ๐ก `#httpCodes`
```ts
readonly { [statusCode: number|string]: string }
```
A lookup object for all standard and some common unofficial HTTP status codes with their descriptions. Includes:
* ๐ Informational: `100โ103`
* โ
Successful: `200โ226`
* ๐ Redirection: `300โ308`
* โ Client errors: `400โ451`
* ๐ฅ Server errors: `500โ511`
* โ๏ธ Cloudflare-specific unofficial codes: `520โ526`
Example usage:
```js
tinyExpress.#httpCodes[404]; // "Not Found"
```
---
## ๐ Constructor: `new TinyExpress(app?)`
Creates and initializes a new `TinyExpress` instance.
### ๐ง Features:
* โ
Injects domain validator middleware using `#domainTypeChecker`.
* ๐ Automatically blocks invalid requests with `403 Forbidden`.
* ๐ Registers loopback domains: `localhost`, `127.0.0.1`, and `::1`.
* ๐ก๏ธ Includes default domain validators for:
* `x-forwarded-host`
* `hostname`
* `host`
```js
new TinyExpress(app);
```
**Parameters:**
* `app` *(optional)* โ an existing Express app. Defaults to `express()`.
---
## ๐งฌ `setCsrfOption(key, value)`
Modifies a CSRF config option (except for internal controls like `enabled`).
**Accepted keys:**
* `"cookieName"`
* `"headerName"`
* `"errMessage"`
```js
tiny.setCsrfOption('cookieName', 'csrf_token');
```
---
## โฑ๏ธ `setCsrfRefreshInterval(ms)`
Sets how often the CSRF token should refresh.
```js
tiny.setCsrfRefreshInterval(60000); // 1 minute
```
**Pass `null` to disable refresh.**
---
## ๐ `geCsrftOptions()`
Returns a **shallow clone** of the current CSRF config.
```js
const config = tiny.geCsrftOptions();
```
---
## ๐ช `installCsrfToken(bytes?, options?)`
Enables CSRF protection by generating and managing token cookies.
```js
tiny.installCsrfToken(32, {
httpOnly: true,
sameSite: 'strict',
secure: true,
});
```
**Options:**
* `bytes`: token size in bytes (default `24`)
* `httpOnly`, `sameSite`, `secure`: cookie flags
---
## ๐ `verifyCsrfToken()`
Express middleware to validate incoming CSRF tokens.
```js
app.use(tiny.verifyCsrfToken());
```
---
## ๐ `getWeb()`
Returns the `TinyWebInstance`.
```js
const web = tiny.getWeb();
```
---
## ๐ฐ๏ธ `getServer()`
Returns the current **HTTP/HTTPS server** instance.
```js
const server = tiny.getServer();
```
---
## ๐๏ธ `getRoot()`
Returns the underlying Express application.
```js
const app = tiny.getRoot();
```
---
## โ๏ธ `init(web?)`
Initializes and links a `TinyWebInstance` (or raw server) to this wrapper.
```js
tiny.init(); // uses default TinyWebInstance
```
**Auto-registers:**
* Default domains (`localhost`, etc.)
* Header-based domain validators
* IP extractors (`ip`, `ips`, `remoteAddress`, etc.)
---
## ๐ `getOrigin(req)`
๐ **Parses the `Origin` header** and returns a structured object.
```js
const originInfo = appManager.getOrigin(req);
```
Returns an object like:
```js
{
raw: 'https://example.com',
protocol: 'https',
hostname: 'example.com',
port: '443',
full: 'https://example.com/'
}
```
If the header is invalid, the result includes:
```js
{ error: 'Invalid Origin header' }
```
---
## ๐ง IP Extractors
### `addIpExtractor(key, callback)`
โ **Register a new IP extractor**.
```js
appManager.addIpExtractor('custom', (req) => extractIpList(req.headers['x-real-ip']));
```
> โ Key `"DEFAULT"` is reserved.
### `removeIpExtractor(key)`
โ **Remove a registered extractor**.
```js
appManager.removeIpExtractor('custom');
```
> โ You can't remove the one that's currently active.
### `getIpExtractors()`
๐ **List all registered extractors**.
```js
const extractors = appManager.getIpExtractors();
```
### `setActiveIpExtractor(key)`
๐ **Set which extractor to use**.
```js
appManager.setActiveIpExtractor('custom');
```
> Use `"DEFAULT"` to revert.
### `getActiveExtractor()`
๐ฏ **Returns the active extractor function.**
### `extractIp(req)`
๐ฅ **Extract IP using the active strategy**.
```js
const ipList = appManager.extractIp(req); // returns array of strings
```
---
## ๐ท๏ธ Domain Validators
### `addDomainValidator(key, callback)`
โ **Add a validator function** for a domain check.
```js
appManager.addDomainValidator('host', req => typeof req.headers.host === 'string' ? this.web.canDomain(req.headers.host) : false);
```
> โ `"ALL"` is reserved.
### `removeDomainValidator(key)`
โ **Remove a validator by key**.
> โ Cannot remove the one currently active unless using `"ALL"`.
### `getDomainValidators()`
๐ **Get all current domain validators.**
### `setDomainTypeChecker(key)`
๐ง **Set which validator to use.**
```js
appManager.setDomainTypeChecker('host');
```
> `"ALL"` applies all validators simultaneously.
---
## ๐ HTTP Codes and Responses
### `getHttpStatusMessage(code)`
๐ **Get the default message for a status code.**
```js
const msg = appManager.getHttpStatusMessage(404); // 'Not Found'
```
### `hasHttpStatusMessage(code)`
โ **Check if a status message exists.**
### `addHttpCode(code, message)`
โ **Add a custom HTTP status code.**
```js
appManager.addHttpCode(799, 'Custom Status');
```
> ๐ซ Cannot overwrite existing codes.
### `sendHttpError(res, code)`
๐ค **Send a status error response.**
```js
appManager.sendHttpError(res, 404);
```
Adds header `HTTP/1.0 404 Not Found` and ends the response.
---
## ๐งฐ Express Middleware
### `installErrors(options)`
๐ง **Set up error handling in your Express app**.
```js
appManager.installErrors({
notFoundMsg: 'Oops! Nothing here.',
errNext: (status, err, req, res) => {
res.json({
status,
message: err.message,
stack: process.env.NODE_ENV === 'development' ? err.stack : null,
});
}
});
```
Includes:
* `404` handler using `HttpError`
* Global error formatter (with dev stacktrace!)
---
## ๐ `authRequest(req, res, next, options)`
Authenticate incoming HTTP requests using **Basic Auth**.
### โ
Use Case:
Protect routes with a username/password combo. Optionally, use a custom validator or a fallback error middleware.
### โ๏ธ Parameters:
| Name | Type | Description |
| ------------------- | -------------------------------------------------- | ----------------------------------------------------------------- |
| `req` | `Request` | Express request object. |
| `res` | `Response` | Express response object. |
| `next` | `NextFunc` | Passes control to the next middleware if authentication succeeds. |
| `options` | `Object` | Configuration object. |
| `options.login` | `string` | Expected username. |
| `options.password` | `string` | Expected password. |
| `options.nextError` | `function` \| `null` | Optional error handler middleware. |
| `options.validator` | `(login, password) => boolean \| Promise<boolean>` | Optional credential validation logic. |
### ๐ Behavior:
* โ
Calls `next()` if credentials match.
* โ Responds with `401 Unauthorized` and `WWW-Authenticate` if not.
* ๐ฏ Falls back to `nextError` if provided.
---
## ๐ `sendFile(res, options)`
Send a file (as a `Buffer`) with proper HTTP headers. Ideal for downloads. ๐ฅ
### โ
Use Case:
Respond with a downloadable file, or inline content like logs, text files, or binary assets.
### โ๏ธ Parameters:
| Name | Type | Description |
| -------------- | ---------------------------------- | ----------------------------------------------------- |
| `res` | `Response` | Express response object. |
| `options` | `Object` | File response config. |
| `contentType` | `string` | MIME type. Defaults to `'text/plain'`. |
| `fileMaxAge` | `number` | Cache-Control max-age in seconds. Defaults to `0`. |
| `file` | `Buffer` | File buffer to be sent. **Required.** |
| `lastModified` | `Date \| number \| string \| null` | Optional Last-Modified timestamp. |
| `fileName` | `string \| null` | Filename for download. Enables `Content-Disposition`. |
### ๐ Behavior:
* ๐ฆ Sets headers: `Content-Type`, `Content-Length`, `ETag`, `Last-Modified`, `Cache-Control`.
* ๐ง Automatically calculates `Content-MD5` hash.
* โณ If `fileMaxAge = 0`, disables caching.
* ๐ If `fileName` is provided, sets it as `attachment`.
---
## ๐บ `streamFile(req, res, options)`
Stream a file or readable stream with support for **range requests**. Great for audio/video! ๐ฅ๐ง
### โ
Use Case:
Serve large files with partial content support (`Range` headers), such as video playback.
### โ๏ธ Parameters:
| Name | Type | Description |
| -------------- | ---------------------------------- | ---------------------------------------------------- |
| `req` | `Request` | Express request object (used to parse `Range`). |
| `res` | `Response` | Express response object. |
| `options` | `Object` | Streaming config. |
| `filePath` | `string` | Full path to file on disk. Required if no stream. |
| `stream` | `ReadableStream` | Alternative to `filePath`. Custom stream source. |
| `contentType` | `string` | MIME type. Defaults to `'application/octet-stream'`. |
| `fileMaxAge` | `number` | Cache-Control max-age. Defaults to `0`. |
| `lastModified` | `Date \| number \| string \| null` | Optional Last-Modified timestamp. |
| `fileName` | `string \| null` | Optional `Content-Disposition`. Can set `inline`. |
### ๐ Behavior:
* ๐ฏ Detects `Range` header and sends partial content with `206`.
* ๐ฝ Full file streaming with `Content-Length` if no range requested.
* โ๏ธ Automatically sets headers: `Accept-Ranges`, `Last-Modified`, `Cache-Control`, and `Content-Disposition`.
---
## ๐ `freeMode(folder)`
A quick way to launch a **test-only server environment** in Express.js for static files and open CORS access.
### ๐ง What it does
- Serves static files from a folder you specify
- Enables **unrestricted CORS** (for all origins, headers, and methods)
- Only works in **development mode** (`NODE_ENV=development`)
### โ ๏ธ Warning
**Do NOT use this in production!**
This function:
- Disables all security headers
- Exposes everything to the public
- Should only be used for local testing or experiments
### โ
Usage
```js
app.freeMode('./public');
```
---
## ๐ง Notes
* The `sendFile()` method is optimized for small/medium binary/text blobs that fit in memory.
* Use `streamFile()` for **streaming video, audio, or large files** efficiently.
* `authRequest()` supports both **static credentials** and **async validation** (e.g., DB or external checks).
---
## ๐งฐ Dependencies
* Node.js `fs` and `crypto` (for file handling and hashing)
* Express.js