Projektstart

This commit is contained in:
2026-01-22 15:49:12 +01:00
parent 7212eb6f7a
commit 57e5f652f8
10637 changed files with 2598792 additions and 64 deletions

View File

@@ -0,0 +1,13 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
# [*.md]
# trim_trailing_whitespace = false

View File

@@ -0,0 +1,13 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
open-pull-requests-limit: 10
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10

View File

@@ -0,0 +1,81 @@
name: CI
on:
push:
paths-ignore:
- 'docs/**'
- '*.md'
pull_request:
paths-ignore:
- 'docs/**'
- '*.md'
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: "${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
cancel-in-progress: true
jobs:
dependency-review:
name: Dependency Review
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check out repo
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Dependency review
uses: actions/dependency-review-action@v4
test:
name: Test
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
node-version: [18, 20]
steps:
- name: Check out repo
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Setup Node ${{ matrix.node-version }}
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm install --ignore-scripts
env:
NODE_ENV: development
- name: Lint-CI
run: npm run lint-ci
- name: Test-Types
run: npm run test-types
- name: Test-CI
run: npm run test-ci
automerge:
name: Automerge Dependabot PRs
if: >
github.event_name == 'pull_request' &&
github.event.pull_request.user.login == 'dependabot[bot]'
needs: test
permissions:
pull-requests: write
contents: write
runs-on: ubuntu-latest
steps:
- uses: fastify/github-action-merge-dependabot@v3
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

7
backend/node_modules/pino-std-serializers/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,7 @@
Copyright Mateo Collina, David Mark Clements, James Sumners
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

182
backend/node_modules/pino-std-serializers/Readme.md generated vendored Normal file
View File

@@ -0,0 +1,182 @@
# pino-std-serializers  [![CI](https://github.com/pinojs/pino-std-serializers/workflows/CI/badge.svg)](https://github.com/pinojs/pino-std-serializers/actions?query=workflow%3ACI)
This module provides a set of standard object serializers for the
[Pino](https://getpino.io) logger.
## Serializers
### `exports.err(error)`
Serializes an `Error` like object. Returns an object:
```js
{
type: 'string', // The name of the object's constructor.
message: 'string', // The supplied error message.
stack: 'string', // The stack when the error was generated.
raw: Error // Non-enumerable, i.e. will not be in the output, original
// Error object. This is available for subsequent serializers
// to use.
[...any additional Enumerable property the original Error had]
}
```
Any other extra properties, e.g. `statusCode`, that have been attached to the
object will also be present on the serialized object.
If the error object has a [`cause`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause) property, the `cause`'s `message` and `stack` will be appended to the top-level `message` and `stack`. All other parameters that belong to the `error.cause` object will be omitted.
Example:
```js
const serializer = require('pino-std-serializers').err;
const innerError = new Error("inner error");
innerError.isInner = true;
const outerError = new Error("outer error", { cause: innerError });
outerError.isInner = false;
const serialized = serializer(outerError);
/* Result:
{
"type": "Error",
"message": "outer error: inner error",
"isInner": false,
"stack": "Error: outer error
at <...omitted..>
caused by: Error: inner error
at <...omitted..>
}
*/
```
### `exports.errWithCause(error)`
Serializes an `Error` like object, including any `error.cause`. Returns an object:
```js
{
type: 'string', // The name of the object's constructor.
message: 'string', // The supplied error message.
stack: 'string', // The stack when the error was generated.
cause?: Error, // If the original error had an error.cause, it will be serialized here
raw: Error // Non-enumerable, i.e. will not be in the output, original
// Error object. This is available for subsequent serializers
// to use.
[...any additional Enumerable property the original Error had]
}
```
Any other extra properties, e.g. `statusCode`, that have been attached to the object will also be present on the serialized object.
Example:
```javascript
const serializer = require('pino-std-serializers').errWithCause;
const innerError = new Error("inner error");
innerError.isInner = true;
const outerError = new Error("outer error", { cause: innerError });
outerError.isInner = false;
const serialized = serializer(outerError);
/* Result:
{
"type": "Error",
"message": "outer error",
"isInner": false,
"stack": "Error: outer error
at <...omitted..>",
"cause": {
"type": "Error",
"message": "inner error",
"isInner": true,
"stack": "Error: inner error
at <...omitted..>"
},
}
*/
```
### `exports.mapHttpResponse(response)`
Used internally by Pino for general response logging. Returns an object:
```js
{
res: {}
}
```
Where `res` is the `response` as serialized by the standard response serializer.
### `exports.mapHttpRequest(request)`
Used internall by Pino for general request logging. Returns an object:
```js
{
req: {}
}
```
Where `req` is the `request` as serialized by the standard request serializer.
### `exports.req(request)`
The default `request` serializer. Returns an object:
```js
{
id: 'string', // Defaults to `undefined`, unless there is an `id` property
// already attached to the `request` object or to the `request.info`
// object. Attach a synchronous function
// to the `request.id` that returns an identifier to have
// the value filled.
method: 'string',
url: 'string', // the request pathname (as per req.url in core HTTP)
query: 'object', // the request query (as per req.query in express or hapi)
params: 'object', // the request params (as per req.params in express or hapi)
headers: Object, // a reference to the `headers` object from the request
// (as per req.headers in core HTTP)
remoteAddress: 'string',
remotePort: Number,
raw: Object // Non-enumerable, i.e. will not be in the output, original
// request object. This is available for subsequent serializers
// to use. In cases where the `request` input already has
// a `raw` property this will replace the original `request.raw`
// property
}
```
### `exports.res(response)`
The default `response` serializer. Returns an object:
```js
{
statusCode: Number, // Response status code, will be null before headers are flushed
headers: Object, // The headers to be sent in the response.
raw: Object // Non-enumerable, i.e. will not be in the output, original
// response object. This is available for subsequent serializers
// to use.
}
```
### `exports.wrapErrorSerializer(customSerializer)`
A utility method for wrapping the default error serializer. This allows
custom serializers to work with the already serialized object.
The `customSerializer` accepts one parameter — the newly serialized error
object — and returns the new (or updated) error object.
### `exports.wrapRequestSerializer(customSerializer)`
A utility method for wrapping the default request serializer. This allows
custom serializers to work with the already serialized object.
The `customSerializer` accepts one parameter — the newly serialized request
object — and returns the new (or updated) request object.
### `exports.wrapResponseSerializer(customSerializer)`
A utility method for wrapping the default response serializer. This allows
custom serializers to work with the already serialized object.
The `customSerializer` accepts one parameter — the newly serialized response
object — and returns the new (or updated) response object.
## License
MIT License

View File

@@ -0,0 +1,7 @@
'use strict'
const neostandard = require('neostandard')
module.exports = neostandard({
ignores: neostandard.resolveIgnoresFromGitignore(),
})

145
backend/node_modules/pino-std-serializers/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,145 @@
// Type definitions for pino-std-serializers 2.4
// Definitions by: Connor Fitzgerald <https://github.com/connorjayfitzgerald>
// Igor Savin <https://github.com/kibertoad>
// TypeScript Version: 2.7
/// <reference types="node" />
import { IncomingMessage, ServerResponse } from 'http';
export interface SerializedError {
/**
* The name of the object's constructor.
*/
type: string;
/**
* The supplied error message.
*/
message: string;
/**
* The stack when the error was generated.
*/
stack: string;
/**
* Non-enumerable. The original Error object. This will not be included in the logged output.
* This is available for subsequent serializers to use.
*/
raw: Error;
/**
* `cause` is never included in the log output, if you need the `cause`, use {@link raw.cause}
*/
cause?: never;
/**
* Any other extra properties that have been attached to the object will also be present on the serialized object.
*/
[key: string]: any;
[key: number]: any;
}
/**
* Serializes an Error object. Does not serialize "err.cause" fields (will append the err.cause.message to err.message
* and err.cause.stack to err.stack)
*/
export function err(err: Error): SerializedError;
/**
* Serializes an Error object, including full serialization for any err.cause fields recursively.
*/
export function errWithCause(err: Error): SerializedError;
export interface SerializedRequest {
/**
* Defaults to `undefined`, unless there is an `id` property already attached to the `request` object or
* to the `request.info` object. Attach a synchronous function to the `request.id` that returns an
* identifier to have the value filled.
*/
id: string | undefined;
/**
* HTTP method.
*/
method: string;
/**
* Request pathname (as per req.url in core HTTP).
*/
url: string;
/**
* Reference to the `headers` object from the request (as per req.headers in core HTTP).
*/
headers: Record<string, string>;
remoteAddress: string;
remotePort: number;
params: Record<string, string>;
query: Record<string, string>;
/**
* Non-enumerable, i.e. will not be in the output, original request object. This is available for subsequent
* serializers to use. In cases where the `request` input already has a `raw` property this will
* replace the original `request.raw` property.
*/
raw: IncomingMessage;
}
/**
* Serializes a Request object.
*/
export function req(req: IncomingMessage): SerializedRequest;
/**
* Used internally by Pino for general request logging.
*/
export function mapHttpRequest(req: IncomingMessage): {
req: SerializedRequest
};
export interface SerializedResponse {
/**
* HTTP status code.
*/
statusCode: number;
/**
* The headers to be sent in the response.
*/
headers: Record<string, string>;
/**
* Non-enumerable, i.e. will not be in the output, original response object. This is available for subsequent serializers to use.
*/
raw: ServerResponse;
}
/**
* Serializes a Response object.
*/
export function res(res: ServerResponse): SerializedResponse;
/**
* Used internally by Pino for general response logging.
*/
export function mapHttpResponse(res: ServerResponse): {
res: SerializedResponse
};
export type CustomErrorSerializer = (err: SerializedError) => Record<string, any>;
/**
* A utility method for wrapping the default error serializer.
* This allows custom serializers to work with the already serialized object.
* The customSerializer accepts one parameter — the newly serialized error object — and returns the new (or updated) error object.
*/
export function wrapErrorSerializer(customSerializer: CustomErrorSerializer): (err: Error) => Record<string, any>;
export type CustomRequestSerializer = (req: SerializedRequest) => Record<string, any>;
/**
* A utility method for wrapping the default request serializer.
* This allows custom serializers to work with the already serialized object.
* The customSerializer accepts one parameter — the newly serialized request object — and returns the new (or updated) request object.
*/
export function wrapRequestSerializer(customSerializer: CustomRequestSerializer): (req: IncomingMessage) => Record<string, any>;
export type CustomResponseSerializer = (res: SerializedResponse) => Record<string, any>;
/**
* A utility method for wrapping the default response serializer.
* This allows custom serializers to work with the already serialized object.
* The customSerializer accepts one parameter — the newly serialized response object — and returns the new (or updated) response object.
*/
export function wrapResponseSerializer(customSerializer: CustomResponseSerializer): (res: ServerResponse) => Record<string, any>;

36
backend/node_modules/pino-std-serializers/index.js generated vendored Normal file
View File

@@ -0,0 +1,36 @@
'use strict'
const errSerializer = require('./lib/err')
const errWithCauseSerializer = require('./lib/err-with-cause')
const reqSerializers = require('./lib/req')
const resSerializers = require('./lib/res')
module.exports = {
err: errSerializer,
errWithCause: errWithCauseSerializer,
mapHttpRequest: reqSerializers.mapHttpRequest,
mapHttpResponse: resSerializers.mapHttpResponse,
req: reqSerializers.reqSerializer,
res: resSerializers.resSerializer,
wrapErrorSerializer: function wrapErrorSerializer (customSerializer) {
if (customSerializer === errSerializer) return customSerializer
return function wrapErrSerializer (err) {
return customSerializer(errSerializer(err))
}
},
wrapRequestSerializer: function wrapRequestSerializer (customSerializer) {
if (customSerializer === reqSerializers.reqSerializer) return customSerializer
return function wrappedReqSerializer (req) {
return customSerializer(reqSerializers.reqSerializer(req))
}
},
wrapResponseSerializer: function wrapResponseSerializer (customSerializer) {
if (customSerializer === resSerializers.resSerializer) return customSerializer
return function wrappedResSerializer (res) {
return customSerializer(resSerializers.resSerializer(res))
}
}
}

View File

@@ -0,0 +1,118 @@
'use strict'
// **************************************************************
// * Code initially copied/adapted from "pony-cause" npm module *
// * Please upstream improvements there *
// **************************************************************
const isErrorLike = (err) => {
return err && typeof err.message === 'string'
}
/**
* @param {Error|{ cause?: unknown|(()=>err)}} err
* @returns {Error|Object|undefined}
*/
const getErrorCause = (err) => {
if (!err) return
/** @type {unknown} */
// @ts-ignore
const cause = err.cause
// VError / NError style causes
if (typeof cause === 'function') {
// @ts-ignore
const causeResult = err.cause()
return isErrorLike(causeResult)
? causeResult
: undefined
} else {
return isErrorLike(cause)
? cause
: undefined
}
}
/**
* Internal method that keeps a track of which error we have already added, to avoid circular recursion
*
* @private
* @param {Error} err
* @param {Set<Error>} seen
* @returns {string}
*/
const _stackWithCauses = (err, seen) => {
if (!isErrorLike(err)) return ''
const stack = err.stack || ''
// Ensure we don't go circular or crazily deep
if (seen.has(err)) {
return stack + '\ncauses have become circular...'
}
const cause = getErrorCause(err)
if (cause) {
seen.add(err)
return (stack + '\ncaused by: ' + _stackWithCauses(cause, seen))
} else {
return stack
}
}
/**
* @param {Error} err
* @returns {string}
*/
const stackWithCauses = (err) => _stackWithCauses(err, new Set())
/**
* Internal method that keeps a track of which error we have already added, to avoid circular recursion
*
* @private
* @param {Error} err
* @param {Set<Error>} seen
* @param {boolean} [skip]
* @returns {string}
*/
const _messageWithCauses = (err, seen, skip) => {
if (!isErrorLike(err)) return ''
const message = skip ? '' : (err.message || '')
// Ensure we don't go circular or crazily deep
if (seen.has(err)) {
return message + ': ...'
}
const cause = getErrorCause(err)
if (cause) {
seen.add(err)
// @ts-ignore
const skipIfVErrorStyleCause = typeof err.cause === 'function'
return (message +
(skipIfVErrorStyleCause ? '' : ': ') +
_messageWithCauses(cause, seen, skipIfVErrorStyleCause))
} else {
return message
}
}
/**
* @param {Error} err
* @returns {string}
*/
const messageWithCauses = (err) => _messageWithCauses(err, new Set())
module.exports = {
isErrorLike,
getErrorCause,
stackWithCauses,
messageWithCauses
}

View File

@@ -0,0 +1,48 @@
'use strict'
const seen = Symbol('circular-ref-tag')
const rawSymbol = Symbol('pino-raw-err-ref')
const pinoErrProto = Object.create({}, {
type: {
enumerable: true,
writable: true,
value: undefined
},
message: {
enumerable: true,
writable: true,
value: undefined
},
stack: {
enumerable: true,
writable: true,
value: undefined
},
aggregateErrors: {
enumerable: true,
writable: true,
value: undefined
},
raw: {
enumerable: false,
get: function () {
return this[rawSymbol]
},
set: function (val) {
this[rawSymbol] = val
}
}
})
Object.defineProperty(pinoErrProto, rawSymbol, {
writable: true,
value: {}
})
module.exports = {
pinoErrProto,
pinoErrorSymbols: {
seen,
rawSymbol
}
}

View File

@@ -0,0 +1,48 @@
'use strict'
module.exports = errWithCauseSerializer
const { isErrorLike } = require('./err-helpers')
const { pinoErrProto, pinoErrorSymbols } = require('./err-proto')
const { seen } = pinoErrorSymbols
const { toString } = Object.prototype
function errWithCauseSerializer (err) {
if (!isErrorLike(err)) {
return err
}
err[seen] = undefined // tag to prevent re-looking at this
const _err = Object.create(pinoErrProto)
_err.type = toString.call(err.constructor) === '[object Function]'
? err.constructor.name
: err.name
_err.message = err.message
_err.stack = err.stack
if (Array.isArray(err.errors)) {
_err.aggregateErrors = err.errors.map(err => errWithCauseSerializer(err))
}
if (isErrorLike(err.cause) && !Object.prototype.hasOwnProperty.call(err.cause, seen)) {
_err.cause = errWithCauseSerializer(err.cause)
}
for (const key in err) {
if (_err[key] === undefined) {
const val = err[key]
if (isErrorLike(val)) {
if (!Object.prototype.hasOwnProperty.call(val, seen)) {
_err[key] = errWithCauseSerializer(val)
}
} else {
_err[key] = val
}
}
}
delete err[seen] // clean up tag in case err is serialized again later
_err.raw = err
return _err
}

45
backend/node_modules/pino-std-serializers/lib/err.js generated vendored Normal file
View File

@@ -0,0 +1,45 @@
'use strict'
module.exports = errSerializer
const { messageWithCauses, stackWithCauses, isErrorLike } = require('./err-helpers')
const { pinoErrProto, pinoErrorSymbols } = require('./err-proto')
const { seen } = pinoErrorSymbols
const { toString } = Object.prototype
function errSerializer (err) {
if (!isErrorLike(err)) {
return err
}
err[seen] = undefined // tag to prevent re-looking at this
const _err = Object.create(pinoErrProto)
_err.type = toString.call(err.constructor) === '[object Function]'
? err.constructor.name
: err.name
_err.message = messageWithCauses(err)
_err.stack = stackWithCauses(err)
if (Array.isArray(err.errors)) {
_err.aggregateErrors = err.errors.map(err => errSerializer(err))
}
for (const key in err) {
if (_err[key] === undefined) {
const val = err[key]
if (isErrorLike(val)) {
// We append cause messages and stacks to _err, therefore skipping causes here
if (key !== 'cause' && !Object.prototype.hasOwnProperty.call(val, seen)) {
_err[key] = errSerializer(val)
}
} else {
_err[key] = val
}
}
}
delete err[seen] // clean up tag in case err is serialized again later
_err.raw = err
return _err
}

100
backend/node_modules/pino-std-serializers/lib/req.js generated vendored Normal file
View File

@@ -0,0 +1,100 @@
'use strict'
module.exports = {
mapHttpRequest,
reqSerializer
}
const rawSymbol = Symbol('pino-raw-req-ref')
const pinoReqProto = Object.create({}, {
id: {
enumerable: true,
writable: true,
value: ''
},
method: {
enumerable: true,
writable: true,
value: ''
},
url: {
enumerable: true,
writable: true,
value: ''
},
query: {
enumerable: true,
writable: true,
value: ''
},
params: {
enumerable: true,
writable: true,
value: ''
},
headers: {
enumerable: true,
writable: true,
value: {}
},
remoteAddress: {
enumerable: true,
writable: true,
value: ''
},
remotePort: {
enumerable: true,
writable: true,
value: ''
},
raw: {
enumerable: false,
get: function () {
return this[rawSymbol]
},
set: function (val) {
this[rawSymbol] = val
}
}
})
Object.defineProperty(pinoReqProto, rawSymbol, {
writable: true,
value: {}
})
function reqSerializer (req) {
// req.info is for hapi compat.
const connection = req.info || req.socket
const _req = Object.create(pinoReqProto)
_req.id = (typeof req.id === 'function' ? req.id() : (req.id || (req.info ? req.info.id : undefined)))
_req.method = req.method
// req.originalUrl is for expressjs compat.
if (req.originalUrl) {
_req.url = req.originalUrl
} else {
const path = req.path
// path for safe hapi compat.
_req.url = typeof path === 'string' ? path : (req.url ? req.url.path || req.url : undefined)
}
if (req.query) {
_req.query = req.query
}
if (req.params) {
_req.params = req.params
}
_req.headers = req.headers
_req.remoteAddress = connection && connection.remoteAddress
_req.remotePort = connection && connection.remotePort
// req.raw is for hapi compat/equivalence
_req.raw = req.raw || req
return _req
}
function mapHttpRequest (req) {
return {
req: reqSerializer(req)
}
}

47
backend/node_modules/pino-std-serializers/lib/res.js generated vendored Normal file
View File

@@ -0,0 +1,47 @@
'use strict'
module.exports = {
mapHttpResponse,
resSerializer
}
const rawSymbol = Symbol('pino-raw-res-ref')
const pinoResProto = Object.create({}, {
statusCode: {
enumerable: true,
writable: true,
value: 0
},
headers: {
enumerable: true,
writable: true,
value: ''
},
raw: {
enumerable: false,
get: function () {
return this[rawSymbol]
},
set: function (val) {
this[rawSymbol] = val
}
}
})
Object.defineProperty(pinoResProto, rawSymbol, {
writable: true,
value: {}
})
function resSerializer (res) {
const _res = Object.create(pinoResProto)
_res.statusCode = res.headersSent ? res.statusCode : null
_res.headers = res.getHeaders ? res.getHeaders() : res._headers
_res.raw = res
return _res
}
function mapHttpResponse (res) {
return {
res: resSerializer(res)
}
}

42
backend/node_modules/pino-std-serializers/package.json generated vendored Normal file
View File

@@ -0,0 +1,42 @@
{
"name": "pino-std-serializers",
"version": "7.1.0",
"description": "A collection of standard object serializers for Pino",
"main": "index.js",
"type": "commonjs",
"types": "index.d.ts",
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"lint-ci": "eslint --max-warnings=0 .",
"test": "borp -p 'test/**/*.js'",
"test-ci": "borp --coverage -p 'test/**/*.js'",
"test-types": "tsc && tsd"
},
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/pinojs/pino-std-serializers.git"
},
"keywords": [
"pino",
"logging"
],
"author": "James Sumners <james.sumners@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/pinojs/pino-std-serializers/issues"
},
"homepage": "https://github.com/pinojs/pino-std-serializers#readme",
"devDependencies": {
"@matteo.collina/tspl": "^0.2.0",
"@types/node": "^25.0.3",
"borp": "^0.21.0",
"eslint": "^9.39.2",
"neostandard": "^0.12.2",
"tsd": "^0.33.0",
"typescript": "~5.9.3"
},
"tsd": {
"directory": "test/types"
}
}

View File

@@ -0,0 +1,187 @@
'use strict'
const { test } = require('node:test')
const assert = require('node:assert')
const serializer = require('../lib/err-with-cause')
const { wrapErrorSerializer } = require('../')
test('serializes Error objects', () => {
const serialized = serializer(Error('foo'))
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'foo')
assert.match(serialized.stack, /err-with-cause\.test\.js:/)
})
test('serializes Error objects with extra properties', () => {
const err = Error('foo')
err.statusCode = 500
const serialized = serializer(err)
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'foo')
assert.ok(serialized.statusCode)
assert.strictEqual(serialized.statusCode, 500)
assert.match(serialized.stack, /err-with-cause\.test\.js:/)
})
test('serializes Error objects with subclass "type"', () => {
class MyError extends Error {}
const err = new MyError('foo')
const serialized = serializer(err)
assert.strictEqual(serialized.type, 'MyError')
})
test('serializes nested errors', () => {
const err = Error('foo')
err.inner = Error('bar')
const serialized = serializer(err)
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'foo')
assert.match(serialized.stack, /err-with-cause\.test\.js:/)
assert.strictEqual(serialized.inner.type, 'Error')
assert.strictEqual(serialized.inner.message, 'bar')
assert.match(serialized.inner.stack, /Error: bar/)
assert.match(serialized.inner.stack, /err-with-cause\.test\.js:/)
})
test('serializes error causes', () => {
const innerErr = Error('inner')
const middleErr = Error('middle')
middleErr.cause = innerErr
const outerErr = Error('outer')
outerErr.cause = middleErr
const serialized = serializer(outerErr)
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'outer')
assert.match(serialized.stack, /err-with-cause\.test\.js:/)
assert.strictEqual(serialized.cause.type, 'Error')
assert.strictEqual(serialized.cause.message, 'middle')
assert.match(serialized.cause.stack, /err-with-cause\.test\.js:/)
assert.strictEqual(serialized.cause.cause.type, 'Error')
assert.strictEqual(serialized.cause.cause.message, 'inner')
assert.match(serialized.cause.cause.stack, /err-with-cause\.test\.js:/)
})
test('keeps non-error cause', () => {
const err = Error('foo')
err.cause = 'abc'
const serialized = serializer(err)
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'foo')
assert.strictEqual(serialized.cause, 'abc')
})
test('prevents infinite recursion', () => {
const err = Error('foo')
err.inner = err
const serialized = serializer(err)
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'foo')
assert.match(serialized.stack, /err-with-cause\.test\.js:/)
assert.ok(!serialized.inner)
})
test('cleans up infinite recursion tracking', () => {
const err = Error('foo')
const bar = Error('bar')
err.inner = bar
bar.inner = err
serializer(err)
const serialized = serializer(err)
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'foo')
assert.match(serialized.stack, /err-with-cause\.test\.js:/)
assert.ok(serialized.inner)
assert.strictEqual(serialized.inner.type, 'Error')
assert.strictEqual(serialized.inner.message, 'bar')
assert.match(serialized.inner.stack, /Error: bar/)
assert.ok(!serialized.inner.inner)
})
test('err.raw is available', () => {
const err = Error('foo')
const serialized = serializer(err)
assert.strictEqual(serialized.raw, err)
})
test('redefined err.constructor doesnt crash serializer', () => {
function check (a, name) {
assert.strictEqual(a.type, name)
assert.strictEqual(a.message, 'foo')
}
const err1 = TypeError('foo')
err1.constructor = '10'
const err2 = TypeError('foo')
err2.constructor = undefined
const err3 = Error('foo')
err3.constructor = null
const err4 = Error('foo')
err4.constructor = 10
class MyError extends Error {}
const err5 = new MyError('foo')
err5.constructor = undefined
check(serializer(err1), 'TypeError')
check(serializer(err2), 'TypeError')
check(serializer(err3), 'Error')
check(serializer(err4), 'Error')
// We do not expect 'MyError' because err5.constructor has been blown away.
// `err5.name` is 'Error' from the base class prototype.
check(serializer(err5), 'Error')
})
test('pass through anything that does not look like an Error', () => {
function check (a) {
assert.strictEqual(serializer(a), a)
}
check('foo')
check({ hello: 'world' })
check([1, 2])
})
test('can wrap err serializers', () => {
const err = Error('foo')
err.foo = 'foo'
const serializer = wrapErrorSerializer(function (err) {
delete err.foo
err.bar = 'bar'
return err
})
const serialized = serializer(err)
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'foo')
assert.match(serialized.stack, /err-with-cause\.test\.js:/)
assert.ok(!serialized.foo)
assert.strictEqual(serialized.bar, 'bar')
})
test('serializes aggregate errors', { skip: !global.AggregateError }, () => {
const foo = new Error('foo')
const bar = new Error('bar')
for (const aggregate of [
new AggregateError([foo, bar], 'aggregated message'),
{ errors: [foo, bar], message: 'aggregated message', stack: 'err-with-cause.test.js:' }
]) {
const serialized = serializer(aggregate)
assert.strictEqual(serialized.message, 'aggregated message')
assert.strictEqual(serialized.aggregateErrors.length, 2)
assert.strictEqual(serialized.aggregateErrors[0].message, 'foo')
assert.strictEqual(serialized.aggregateErrors[1].message, 'bar')
assert.match(serialized.aggregateErrors[0].stack, /^Error: foo/)
assert.match(serialized.aggregateErrors[1].stack, /^Error: bar/)
assert.match(serialized.stack, /err-with-cause\.test\.js:/)
}
})

View File

@@ -0,0 +1,200 @@
'use strict'
const assert = require('node:assert')
const { test } = require('node:test')
const serializer = require('../lib/err')
const { wrapErrorSerializer } = require('../')
test('serializes Error objects', () => {
const serialized = serializer(Error('foo'))
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'foo')
assert.match(serialized.stack, /err\.test\.js:/)
})
test('serializes Error objects with extra properties', () => {
const err = Error('foo')
err.statusCode = 500
const serialized = serializer(err)
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'foo')
assert.ok(serialized.statusCode)
assert.strictEqual(serialized.statusCode, 500)
assert.match(serialized.stack, /err\.test\.js:/)
})
test('serializes Error objects with subclass "type"', () => {
class MyError extends Error {}
const err = new MyError('foo')
const serialized = serializer(err)
assert.strictEqual(serialized.type, 'MyError')
})
test('serializes nested errors', () => {
const err = Error('foo')
err.inner = Error('bar')
const serialized = serializer(err)
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'foo')
assert.match(serialized.stack, /err\.test\.js:/)
assert.strictEqual(serialized.inner.type, 'Error')
assert.strictEqual(serialized.inner.message, 'bar')
assert.match(serialized.inner.stack, /Error: bar/)
assert.match(serialized.inner.stack, /err\.test\.js:/)
})
test('serializes error causes', () => {
for (const cause of [
Error('bar'),
{ message: 'bar', stack: 'Error: bar: err.test.js:' }
]) {
const err = Error('foo')
err.cause = cause
err.cause.cause = Error('abc')
const serialized = serializer(err)
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'foo: bar: abc')
assert.match(serialized.stack, /err\.test\.js:/)
assert.match(serialized.stack, /Error: foo/)
assert.match(serialized.stack, /Error: bar/)
assert.match(serialized.stack, /Error: abc/)
assert.ok(!serialized.cause)
}
})
test('serializes error causes with VError support', function (t) {
// Fake VError-style setup
const err = Error('foo: bar')
err.foo = 'abc'
err.cause = function () {
const err = Error('bar')
err.cause = Error(this.foo)
return err
}
const serialized = serializer(err)
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'foo: bar: abc')
assert.match(serialized.stack, /err\.test\.js:/)
assert.match(serialized.stack, /Error: foo/)
assert.match(serialized.stack, /Error: bar/)
assert.match(serialized.stack, /Error: abc/)
})
test('keeps non-error cause', () => {
const err = Error('foo')
err.cause = 'abc'
const serialized = serializer(err)
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'foo')
assert.strictEqual(serialized.cause, 'abc')
})
test('prevents infinite recursion', () => {
const err = Error('foo')
err.inner = err
const serialized = serializer(err)
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'foo')
assert.match(serialized.stack, /err\.test\.js:/)
assert.ok(!serialized.inner)
})
test('cleans up infinite recursion tracking', () => {
const err = Error('foo')
const bar = Error('bar')
err.inner = bar
bar.inner = err
serializer(err)
const serialized = serializer(err)
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'foo')
assert.match(serialized.stack, /err\.test\.js:/)
assert.ok(serialized.inner)
assert.strictEqual(serialized.inner.type, 'Error')
assert.strictEqual(serialized.inner.message, 'bar')
assert.match(serialized.inner.stack, /Error: bar/)
assert.ok(!serialized.inner.inner)
})
test('err.raw is available', () => {
const err = Error('foo')
const serialized = serializer(err)
assert.strictEqual(serialized.raw, err)
})
test('redefined err.constructor doesnt crash serializer', () => {
function check (a, name) {
assert.strictEqual(a.type, name)
assert.strictEqual(a.message, 'foo')
}
const err1 = TypeError('foo')
err1.constructor = '10'
const err2 = TypeError('foo')
err2.constructor = undefined
const err3 = Error('foo')
err3.constructor = null
const err4 = Error('foo')
err4.constructor = 10
class MyError extends Error {}
const err5 = new MyError('foo')
err5.constructor = undefined
check(serializer(err1), 'TypeError')
check(serializer(err2), 'TypeError')
check(serializer(err3), 'Error')
check(serializer(err4), 'Error')
// We do not expect 'MyError' because err5.constructor has been blown away.
// `err5.name` is 'Error' from the base class prototype.
check(serializer(err5), 'Error')
})
test('pass through anything that does not look like an Error', () => {
function check (a) {
assert.strictEqual(serializer(a), a)
}
check('foo')
check({ hello: 'world' })
check([1, 2])
})
test('can wrap err serializers', () => {
const err = Error('foo')
err.foo = 'foo'
const serializer = wrapErrorSerializer(function (err) {
delete err.foo
err.bar = 'bar'
return err
})
const serialized = serializer(err)
assert.strictEqual(serialized.type, 'Error')
assert.strictEqual(serialized.message, 'foo')
assert.match(serialized.stack, /err\.test\.js:/)
assert.ok(!serialized.foo)
assert.strictEqual(serialized.bar, 'bar')
})
test('serializes aggregate errors', { skip: !global.AggregateError }, () => {
const foo = new Error('foo')
const bar = new Error('bar')
for (const aggregate of [
new AggregateError([foo, bar], 'aggregated message'),
{ errors: [foo, bar], message: 'aggregated message', stack: 'err.test.js:' }
]) {
const serialized = serializer(aggregate)
assert.strictEqual(serialized.message, 'aggregated message')
assert.strictEqual(serialized.aggregateErrors.length, 2)
assert.strictEqual(serialized.aggregateErrors[0].message, 'foo')
assert.strictEqual(serialized.aggregateErrors[1].message, 'bar')
assert.match(serialized.aggregateErrors[0].stack, /^Error: foo/)
assert.match(serialized.aggregateErrors[1].stack, /^Error: bar/)
assert.match(serialized.stack, /err\.test\.js:/)
}
})

View File

@@ -0,0 +1,477 @@
'use strict'
const { tspl } = require('@matteo.collina/tspl')
const http = require('node:http')
const { test } = require('node:test')
const serializers = require('../lib/req')
const { wrapRequestSerializer } = require('../')
test('maps request', async (t) => {
const p = tspl(t, { plan: 2 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
const serialized = serializers.mapHttpRequest(req)
p.ok(serialized.req)
p.ok(serialized.req.method)
res.end()
}
await p.completed
})
test('does not return excessively long object', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
const serialized = serializers.reqSerializer(req)
p.strictEqual(Object.keys(serialized).length, 6)
res.end()
}
await p.completed
})
test('req.raw is available', async (t) => {
const p = tspl(t, { plan: 2 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
req.foo = 'foo'
const serialized = serializers.reqSerializer(req)
p.ok(serialized.raw)
p.strictEqual(serialized.raw.foo, 'foo')
res.end()
}
await p.completed
})
test('req.raw will be obtained in from input request raw property if input request raw property is truthy', async (t) => {
const p = tspl(t, { plan: 2 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
req.raw = { req: { foo: 'foo' }, res: {} }
const serialized = serializers.reqSerializer(req)
p.ok(serialized.raw)
p.strictEqual(serialized.raw.req.foo, 'foo')
res.end()
}
await p.completed
})
test('req.id defaults to undefined', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
const serialized = serializers.reqSerializer(req)
p.strictEqual(serialized.id, undefined)
res.end()
}
await p.completed
})
test('req.id has a non-function value', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
const serialized = serializers.reqSerializer(req)
p.strictEqual(typeof serialized.id === 'function', false)
res.end()
}
await p.completed
})
test('req.id will be obtained from input request info.id when input request id does not exist', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
req.info = { id: 'test' }
const serialized = serializers.reqSerializer(req)
p.strictEqual(serialized.id, 'test')
res.end()
}
await p.completed
})
test('req.id has a non-function value with custom id function', async (t) => {
const p = tspl(t, { plan: 2 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
req.id = function () { return 42 }
const serialized = serializers.reqSerializer(req)
p.strictEqual(typeof serialized.id === 'function', false)
p.strictEqual(serialized.id, 42)
res.end()
}
await p.completed
})
test('req.url will be obtained from input request req.path when input request url is an object', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
req.path = '/test'
const serialized = serializers.reqSerializer(req)
p.strictEqual(serialized.url, '/test')
res.end()
}
await p.completed
})
test('req.url will be obtained from input request url.path when input request url is an object', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
req.url = { path: '/test' }
const serialized = serializers.reqSerializer(req)
p.strictEqual(serialized.url, '/test')
res.end()
}
await p.completed
})
test('req.url will be obtained from input request url when input request url is not an object', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
req.url = '/test'
const serialized = serializers.reqSerializer(req)
p.strictEqual(serialized.url, '/test')
res.end()
}
await p.completed
})
test('req.url will be empty when input request path and url are not defined', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
const serialized = serializers.reqSerializer(req)
p.strictEqual(serialized.url, '/')
res.end()
}
await p.completed
})
test('req.url will be obtained from input request originalUrl when available', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
req.originalUrl = '/test'
const serialized = serializers.reqSerializer(req)
p.strictEqual(serialized.url, '/test')
res.end()
}
await p.completed
})
test('req.url will be obtained from input request url when req path is a function', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
req.path = function () {
throw new Error('unexpected invocation')
}
req.url = '/test'
const serialized = serializers.reqSerializer(req)
p.strictEqual(serialized.url, '/test')
res.end()
}
await p.completed
})
test('req.url being undefined does not throw an error', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
req.url = undefined
const serialized = serializers.reqSerializer(req)
p.strictEqual(serialized.url, undefined)
res.end()
}
await p.completed
})
test('can wrap request serializers', async (t) => {
const p = tspl(t, { plan: 3 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
const serailizer = wrapRequestSerializer(function (req) {
p.ok(req.method)
p.strictEqual(req.method, 'GET')
delete req.method
return req
})
function handler (req, res) {
const serialized = serailizer(req)
p.ok(!serialized.method)
res.end()
}
await p.completed
})
test('req.remoteAddress will be obtained from request socket.remoteAddress as fallback', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
req.socket = { remoteAddress: 'http://localhost' }
const serialized = serializers.reqSerializer(req)
p.strictEqual(serialized.remoteAddress, 'http://localhost')
res.end()
}
await p.completed
})
test('req.remoteAddress will be obtained from request info.remoteAddress if available', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
req.info = { remoteAddress: 'http://localhost' }
const serialized = serializers.reqSerializer(req)
p.strictEqual(serialized.remoteAddress, 'http://localhost')
res.end()
}
await p.completed
})
test('req.remotePort will be obtained from request socket.remotePort as fallback', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
req.socket = { remotePort: 3000 }
const serialized = serializers.reqSerializer(req)
p.strictEqual(serialized.remotePort, 3000)
res.end()
}
await p.completed
})
test('req.remotePort will be obtained from request info.remotePort if available', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
req.info = { remotePort: 3000 }
const serialized = serializers.reqSerializer(req)
p.strictEqual(serialized.remotePort, 3000)
res.end()
}
await p.completed
})
test('req.query is available', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
req.query = '/foo?bar=foobar&bar=foo'
const serialized = serializers.reqSerializer(req)
p.strictEqual(serialized.query, '/foo?bar=foobar&bar=foo')
res.end()
}
await p.completed
})
test('req.params is available', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (req, res) {
req.params = '/foo/bar'
const serialized = serializers.reqSerializer(req)
p.strictEqual(serialized.params, '/foo/bar')
res.end()
}
await p.completed
})

View File

@@ -0,0 +1,120 @@
'use strict'
/* eslint-disable no-prototype-builtins */
const { tspl } = require('@matteo.collina/tspl')
const http = require('node:http')
const { test } = require('node:test')
const serializers = require('../lib/res')
const { wrapResponseSerializer } = require('../')
test('res.raw is not enumerable', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (_req, res) {
const serialized = serializers.resSerializer(res)
p.strictEqual(serialized.propertyIsEnumerable('raw'), false)
res.end()
}
await p.completed
})
test('res.raw is available', async (t) => {
const p = tspl(t, { plan: 2 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (_req, res) {
res.statusCode = 200
const serialized = serializers.resSerializer(res)
p.ok(serialized.raw)
p.strictEqual(serialized.raw.statusCode, 200)
res.end()
}
await p.completed
})
test('can wrap response serializers', async (t) => {
const p = tspl(t, { plan: 3 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
const serializer = wrapResponseSerializer(function (res) {
p.ok(res.statusCode)
p.strictEqual(res.statusCode, 200)
delete res.statusCode
return res
})
function handler (_req, res) {
res.end()
res.statusCode = 200
const serialized = serializer(res)
p.ok(!serialized.statusCode)
}
await p.completed
})
test('res.headers is serialized', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (_req, res) {
res.setHeader('x-custom', 'y')
const serialized = serializers.resSerializer(res)
p.strictEqual(serialized.headers['x-custom'], 'y')
res.end()
}
await p.completed
})
test('req.url will be obtained from input request url when input request url is not an object', async (t) => {
const p = tspl(t, { plan: 1 })
const server = http.createServer(handler)
server.unref()
server.listen(0, () => {
http.get(server.address(), () => {})
})
t.after(() => server.close())
function handler (_req, res) {
const serialized = serializers.resSerializer(res)
p.strictEqual(serialized.statusCode, null)
res.end()
}
await p.completed
})

View File

@@ -0,0 +1,71 @@
import {IncomingMessage, ServerResponse} from "http";
import {
err,
errWithCause,
req,
res,
SerializedError,
SerializedRequest,
wrapErrorSerializer,
wrapRequestSerializer,
wrapResponseSerializer,
SerializedResponse
} from '../../';
const customErrorSerializer = (error: SerializedError) => {
return {
myOwnError: {
data: `${error.type}-${error.message}\n\n${error.stack}`,
}
};
};
const customRequestSerializer = (req: SerializedRequest) => {
const {
headers,
id,
method,
raw,
remoteAddress,
remotePort,
url,
query,
params,
} = req;
return {
myOwnRequest: {
data: `${method}-${id}-${remoteAddress}-${remotePort}-${url}`,
headers,
raw,
}
};
};
const customResponseSerializer = (res: SerializedResponse) => {
const {headers, raw, statusCode} = res;
return {
myOwnResponse: {
data: statusCode,
headers,
raw,
}
};
};
const fakeError = new Error('A fake error for testing');
const serializedError: SerializedError = err(fakeError);
const mySerializer = wrapErrorSerializer(customErrorSerializer);
const fakeErrorWithCause = new Error('A fake error for testing with cause', { cause: new Error('An inner fake error') });
const serializedErrorWithCause: SerializedError = errWithCause(fakeError);
const request: IncomingMessage = {} as IncomingMessage
const serializedRequest: SerializedRequest = req(request);
const myReqSerializer = wrapRequestSerializer(customRequestSerializer);
const response: ServerResponse = {} as ServerResponse
const myResSerializer = wrapResponseSerializer(customResponseSerializer);
const serializedResponse = res(response);
myResSerializer(response)

View File

@@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "es6",
"lib": [ "es2022" ],
"module": "commonjs",
"noEmit": true,
"strict": true
},
"include": [
"./test/types/*.test-d.ts",
"./index.d.ts"
]
}