@lakutata/entrypoint 3.0.0-beta.1 → 3.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -111,7 +111,7 @@ import {buildEntrypoints, Controller, type ActionInvocation, type Next} from 'la
111
111
  import {GET, UseMiddlewares} from 'lakutata/decorator/ctrl'
112
112
 
113
113
  //Runs around the action: before its input validation and its access control
114
- async function Timing(invocation: ActionInvocation, next: Next): Promise<unknown> {
114
+ async function timing(invocation: ActionInvocation, next: Next): Promise<unknown> {
115
115
  const started: number = Date.now()
116
116
  try {
117
117
  return await next()
@@ -120,7 +120,7 @@ async function Timing(invocation: ActionInvocation, next: Next): Promise<unknown
120
120
  }
121
121
  }
122
122
 
123
- @UseMiddlewares(Timing)
123
+ @UseMiddlewares(timing)
124
124
  class HealthController extends Controller {
125
125
  @GET('/health')
126
126
  public async health(): Promise<string> {
@@ -132,7 +132,7 @@ Application.run(() => ({
132
132
  id: 'health.app',
133
133
  name: 'Health',
134
134
  components: {
135
- entrypoint: buildEntrypoints({controllers: [HealthController], middlewares: [Timing]})
135
+ entrypoint: buildEntrypoints({controllers: [HealthController], middlewares: [timing]})
136
136
  }
137
137
  }))
138
138
  ```
@@ -49,12 +49,23 @@ export type JSONEnvelopeOptions = {
49
49
  * @default `errorStatus`
50
50
  */
51
51
  actionErrorStatus?: number;
52
+ /**
53
+ * The extra fields of the envelope, such as the `timestamp`, `nonce` or `requestId` of the envelopes of the
54
+ * applications of lakutata 2.x: called for each response (a result or an error), its fields added after `errno`,
55
+ * `errMsg` and `data`, which they never replace. When it throws, a result is answered as an error, and an error
56
+ * without the extra fields.
57
+ * @param request The express request being answered.
58
+ * @returns The fields to add to the envelope.
59
+ * @default no extra field
60
+ */
61
+ extra?: (request: Request) => Record<string, unknown>;
52
62
  };
53
63
  /**
54
64
  * Create a responder for {@link expressHTTPEntrypoint} that wraps every response in the envelope
55
65
  * `{errno, errMsg, data}`: a result as `{errno: null, errMsg: null, data}` (`data` is `null` when the action returned
56
66
  * nothing, and its status is not turned into 204), an error as `{errno, errMsg, data: null}` with the error's status,
57
- * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option.
67
+ * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option; the `extra` option adds
68
+ * fields to both.
58
69
  * @param options The envelope options.
59
70
  * @returns The responder, to give to the `respond` option of `expressHTTPEntrypoint`.
60
71
  * @example
@@ -79,8 +90,15 @@ export type JSONEnvelopeOptions = {
79
90
  * entrypoint: buildEntrypoints({
80
91
  * controllers: [PingController],
81
92
  * //The errors of the actions answered with 200 too (as the applications of lakutata 2.x), the routes not
82
- * //found and the errors of the express middlewares with their status (404, 401…)
83
- * http: expressHTTPEntrypoint({port: 8080, respond: jsonEnvelope({actionErrorStatus: 200})})
93
+ * //found and the errors of the express middlewares with their status (404, 401…); every envelope with
94
+ * //its timestamp ({"errno": null, "errMsg": null, "data": "pong", "timestamp": 1767225600000})
95
+ * http: expressHTTPEntrypoint({
96
+ * port: 8080,
97
+ * respond: jsonEnvelope({
98
+ * actionErrorStatus: 200,
99
+ * extra: (): Record<string, unknown> => ({timestamp: Date.now()})
100
+ * })
101
+ * })
84
102
  * })
85
103
  * }
86
104
  * })
@@ -5,6 +5,7 @@ exports.jsonEnvelope = jsonEnvelope;
5
5
  const HTTPErrors_js_1 = require("../../lib/HTTPErrors.js");
6
6
  Object.defineProperty(exports, "describeError", { enumerable: true, get: function () { return HTTPErrors_js_1.describeError; } });
7
7
  Object.defineProperty(exports, "statusOfError", { enumerable: true, get: function () { return HTTPErrors_js_1.statusOfError; } });
8
+ const Envelope_js_1 = require("../../lib/Envelope.js");
8
9
  /**
9
10
  * The default responder of {@link expressHTTPEntrypoint}: a result is sent as JSON, no result as an empty 204 (or the
10
11
  * status set by a `StatusResult`); an error is sent as `{errno, errMsg}` (see `describeError`) with its HTTP status
@@ -26,7 +27,8 @@ exports.JSONResponder = {
26
27
  * Create a responder for {@link expressHTTPEntrypoint} that wraps every response in the envelope
27
28
  * `{errno, errMsg, data}`: a result as `{errno: null, errMsg: null, data}` (`data` is `null` when the action returned
28
29
  * nothing, and its status is not turned into 204), an error as `{errno, errMsg, data: null}` with the error's status,
29
- * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option.
30
+ * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option; the `extra` option adds
31
+ * fields to both.
30
32
  * @param options The envelope options.
31
33
  * @returns The responder, to give to the `respond` option of `expressHTTPEntrypoint`.
32
34
  * @example
@@ -51,8 +53,15 @@ exports.JSONResponder = {
51
53
  * entrypoint: buildEntrypoints({
52
54
  * controllers: [PingController],
53
55
  * //The errors of the actions answered with 200 too (as the applications of lakutata 2.x), the routes not
54
- * //found and the errors of the express middlewares with their status (404, 401…)
55
- * http: expressHTTPEntrypoint({port: 8080, respond: jsonEnvelope({actionErrorStatus: 200})})
56
+ * //found and the errors of the express middlewares with their status (404, 401…); every envelope with
57
+ * //its timestamp ({"errno": null, "errMsg": null, "data": "pong", "timestamp": 1767225600000})
58
+ * http: expressHTTPEntrypoint({
59
+ * port: 8080,
60
+ * respond: jsonEnvelope({
61
+ * actionErrorStatus: 200,
62
+ * extra: (): Record<string, unknown> => ({timestamp: Date.now()})
63
+ * })
64
+ * })
56
65
  * })
57
66
  * }
58
67
  * })
@@ -60,12 +69,12 @@ exports.JSONResponder = {
60
69
  */
61
70
  function jsonEnvelope(options = {}) {
62
71
  return {
63
- success: (response, data) => {
64
- response.json({ errno: null, errMsg: null, data: data === undefined ? null : data });
72
+ success: (response, data, request) => {
73
+ response.json((0, Envelope_js_1.envelopeOf)({ errno: null, errMsg: null, data: data === undefined ? null : data }, options.extra?.(request)));
65
74
  },
66
- error: (response, error, _request, origin) => {
75
+ error: (response, error, request, origin) => {
67
76
  const status = origin === 'action' ? options.actionErrorStatus ?? options.errorStatus : options.errorStatus;
68
- response.status(status ?? (0, HTTPErrors_js_1.statusOfError)(error)).json({ ...(0, HTTPErrors_js_1.describeError)(error), data: null });
77
+ response.status(status ?? (0, HTTPErrors_js_1.statusOfError)(error)).json((0, Envelope_js_1.envelopeOf)({ ...(0, HTTPErrors_js_1.describeError)(error), data: null }, (0, Envelope_js_1.errorExtraOf)(options.extra, request)));
69
78
  }
70
79
  };
71
80
  }
@@ -48,12 +48,23 @@ export type FastifyJSONEnvelopeOptions = {
48
48
  * @default `errorStatus`
49
49
  */
50
50
  actionErrorStatus?: number;
51
+ /**
52
+ * The extra fields of the envelope, such as the `timestamp`, `nonce` or `requestId` of the envelopes of the
53
+ * applications of lakutata 2.x: called for each response (a result or an error), its fields added after `errno`,
54
+ * `errMsg` and `data`, which they never replace. When it throws, a result is answered as an error, and an error
55
+ * without the extra fields.
56
+ * @param request The fastify request being answered.
57
+ * @returns The fields to add to the envelope.
58
+ * @default no extra field
59
+ */
60
+ extra?: (request: FastifyRequest) => Record<string, unknown>;
51
61
  };
52
62
  /**
53
63
  * Create a responder for {@link fastifyHTTPEntrypoint} that wraps every response in the envelope
54
64
  * `{errno, errMsg, data}`: a result as `{errno: null, errMsg: null, data}` (`data` is `null` when the action returned
55
65
  * nothing, and its status is not turned into 204), an error as `{errno, errMsg, data: null}` with the error's status,
56
- * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option.
66
+ * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option; the `extra` option adds
67
+ * fields to both.
57
68
  * @param options The envelope options.
58
69
  * @returns The responder, to give to the `respond` option of `fastifyHTTPEntrypoint`.
59
70
  * @example
@@ -78,8 +89,15 @@ export type FastifyJSONEnvelopeOptions = {
78
89
  * entrypoint: buildEntrypoints({
79
90
  * controllers: [PingController],
80
91
  * //The errors of the actions answered with 200 too (as the applications of lakutata 2.x), the routes not
81
- * //found and the errors of the hooks with their status (404, 401…)
82
- * http: fastifyHTTPEntrypoint({port: 8080, respond: fastifyJSONEnvelope({actionErrorStatus: 200})})
92
+ * //found and the errors of the hooks with their status (404, 401…); every envelope with
93
+ * //its timestamp ({"errno": null, "errMsg": null, "data": "pong", "timestamp": 1767225600000})
94
+ * http: fastifyHTTPEntrypoint({
95
+ * port: 8080,
96
+ * respond: fastifyJSONEnvelope({
97
+ * actionErrorStatus: 200,
98
+ * extra: (): Record<string, unknown> => ({timestamp: Date.now()})
99
+ * })
100
+ * })
83
101
  * })
84
102
  * }
85
103
  * })
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FastifyJSONResponder = void 0;
4
4
  exports.fastifyJSONEnvelope = fastifyJSONEnvelope;
5
5
  const HTTPErrors_js_1 = require("../../lib/HTTPErrors.js");
6
+ const Envelope_js_1 = require("../../lib/Envelope.js");
6
7
  /**
7
8
  * Send JSON
8
9
  * @param reply
@@ -33,7 +34,8 @@ exports.FastifyJSONResponder = {
33
34
  * Create a responder for {@link fastifyHTTPEntrypoint} that wraps every response in the envelope
34
35
  * `{errno, errMsg, data}`: a result as `{errno: null, errMsg: null, data}` (`data` is `null` when the action returned
35
36
  * nothing, and its status is not turned into 204), an error as `{errno, errMsg, data: null}` with the error's status,
36
- * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option.
37
+ * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option; the `extra` option adds
38
+ * fields to both.
37
39
  * @param options The envelope options.
38
40
  * @returns The responder, to give to the `respond` option of `fastifyHTTPEntrypoint`.
39
41
  * @example
@@ -58,8 +60,15 @@ exports.FastifyJSONResponder = {
58
60
  * entrypoint: buildEntrypoints({
59
61
  * controllers: [PingController],
60
62
  * //The errors of the actions answered with 200 too (as the applications of lakutata 2.x), the routes not
61
- * //found and the errors of the hooks with their status (404, 401…)
62
- * http: fastifyHTTPEntrypoint({port: 8080, respond: fastifyJSONEnvelope({actionErrorStatus: 200})})
63
+ * //found and the errors of the hooks with their status (404, 401…); every envelope with
64
+ * //its timestamp ({"errno": null, "errMsg": null, "data": "pong", "timestamp": 1767225600000})
65
+ * http: fastifyHTTPEntrypoint({
66
+ * port: 8080,
67
+ * respond: fastifyJSONEnvelope({
68
+ * actionErrorStatus: 200,
69
+ * extra: (): Record<string, unknown> => ({timestamp: Date.now()})
70
+ * })
71
+ * })
63
72
  * })
64
73
  * }
65
74
  * })
@@ -67,11 +76,11 @@ exports.FastifyJSONResponder = {
67
76
  */
68
77
  function fastifyJSONEnvelope(options = {}) {
69
78
  return {
70
- success: (reply, data) => sendJSON(reply, { errno: null, errMsg: null, data: data === undefined ? null : data }),
71
- error: (reply, error, _request, origin) => {
79
+ success: (reply, data, request) => sendJSON(reply, (0, Envelope_js_1.envelopeOf)({ errno: null, errMsg: null, data: data === undefined ? null : data }, options.extra?.(request))),
80
+ error: (reply, error, request, origin) => {
72
81
  const status = origin === 'action' ? options.actionErrorStatus ?? options.errorStatus : options.errorStatus;
73
82
  reply.code(status ?? (0, HTTPErrors_js_1.statusOfError)(error));
74
- sendJSON(reply, { ...(0, HTTPErrors_js_1.describeError)(error), data: null });
83
+ sendJSON(reply, (0, Envelope_js_1.envelopeOf)({ ...(0, HTTPErrors_js_1.describeError)(error), data: null }, (0, Envelope_js_1.errorExtraOf)(options.extra, request)));
75
84
  }
76
85
  };
77
86
  }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The envelope of a response: its fields, then the extra fields not named as one of them (an extra field never
3
+ * replaces errno, errMsg or data)
4
+ * @param fields The fields of the envelope.
5
+ * @param extra The extra fields, ignored when they are not an object.
6
+ */
7
+ export declare function envelopeOf(fields: Record<string, unknown>, extra: unknown): Record<string, unknown>;
8
+ /**
9
+ * The extra fields of an error response: none when the function giving them fails, an error being answered anyway
10
+ * @param extra The function giving the extra fields.
11
+ * @param request The request answered.
12
+ */
13
+ export declare function errorExtraOf<Request>(extra: ((request: Request) => Record<string, unknown>) | undefined, request: Request): unknown;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.envelopeOf = envelopeOf;
4
+ exports.errorExtraOf = errorExtraOf;
5
+ /**
6
+ * The envelope of a response: its fields, then the extra fields not named as one of them (an extra field never
7
+ * replaces errno, errMsg or data)
8
+ * @param fields The fields of the envelope.
9
+ * @param extra The extra fields, ignored when they are not an object.
10
+ */
11
+ function envelopeOf(fields, extra) {
12
+ const envelope = { ...fields };
13
+ if (extra === null || typeof extra !== 'object')
14
+ return envelope;
15
+ for (const [key, value] of Object.entries(extra))
16
+ if (!Object.prototype.hasOwnProperty.call(envelope, key))
17
+ envelope[key] = value;
18
+ return envelope;
19
+ }
20
+ /**
21
+ * The extra fields of an error response: none when the function giving them fails, an error being answered anyway
22
+ * @param extra The function giving the extra fields.
23
+ * @param request The request answered.
24
+ */
25
+ function errorExtraOf(extra, request) {
26
+ try {
27
+ return extra?.(request);
28
+ }
29
+ catch {
30
+ return undefined;
31
+ }
32
+ }
@@ -1,4 +1,5 @@
1
1
  import { describeError, statusOfError } from '../../lib/HTTPErrors.js';
2
+ import { envelopeOf, errorExtraOf } from '../../lib/Envelope.js';
2
3
  export { describeError, statusOfError };
3
4
  /**
4
5
  * The default responder of {@link expressHTTPEntrypoint}: a result is sent as JSON, no result as an empty 204 (or the
@@ -21,7 +22,8 @@ export const JSONResponder = {
21
22
  * Create a responder for {@link expressHTTPEntrypoint} that wraps every response in the envelope
22
23
  * `{errno, errMsg, data}`: a result as `{errno: null, errMsg: null, data}` (`data` is `null` when the action returned
23
24
  * nothing, and its status is not turned into 204), an error as `{errno, errMsg, data: null}` with the error's status,
24
- * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option.
25
+ * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option; the `extra` option adds
26
+ * fields to both.
25
27
  * @param options The envelope options.
26
28
  * @returns The responder, to give to the `respond` option of `expressHTTPEntrypoint`.
27
29
  * @example
@@ -46,8 +48,15 @@ export const JSONResponder = {
46
48
  * entrypoint: buildEntrypoints({
47
49
  * controllers: [PingController],
48
50
  * //The errors of the actions answered with 200 too (as the applications of lakutata 2.x), the routes not
49
- * //found and the errors of the express middlewares with their status (404, 401…)
50
- * http: expressHTTPEntrypoint({port: 8080, respond: jsonEnvelope({actionErrorStatus: 200})})
51
+ * //found and the errors of the express middlewares with their status (404, 401…); every envelope with
52
+ * //its timestamp ({"errno": null, "errMsg": null, "data": "pong", "timestamp": 1767225600000})
53
+ * http: expressHTTPEntrypoint({
54
+ * port: 8080,
55
+ * respond: jsonEnvelope({
56
+ * actionErrorStatus: 200,
57
+ * extra: (): Record<string, unknown> => ({timestamp: Date.now()})
58
+ * })
59
+ * })
51
60
  * })
52
61
  * }
53
62
  * })
@@ -55,12 +64,12 @@ export const JSONResponder = {
55
64
  */
56
65
  export function jsonEnvelope(options = {}) {
57
66
  return {
58
- success: (response, data) => {
59
- response.json({ errno: null, errMsg: null, data: data === undefined ? null : data });
67
+ success: (response, data, request) => {
68
+ response.json(envelopeOf({ errno: null, errMsg: null, data: data === undefined ? null : data }, options.extra?.(request)));
60
69
  },
61
- error: (response, error, _request, origin) => {
70
+ error: (response, error, request, origin) => {
62
71
  const status = origin === 'action' ? options.actionErrorStatus ?? options.errorStatus : options.errorStatus;
63
- response.status(status ?? statusOfError(error)).json({ ...describeError(error), data: null });
72
+ response.status(status ?? statusOfError(error)).json(envelopeOf({ ...describeError(error), data: null }, errorExtraOf(options.extra, request)));
64
73
  }
65
74
  };
66
75
  }
@@ -1,4 +1,5 @@
1
1
  import { describeError, statusOfError } from '../../lib/HTTPErrors.js';
2
+ import { envelopeOf, errorExtraOf } from '../../lib/Envelope.js';
2
3
  /**
3
4
  * Send JSON
4
5
  * @param reply
@@ -29,7 +30,8 @@ export const FastifyJSONResponder = {
29
30
  * Create a responder for {@link fastifyHTTPEntrypoint} that wraps every response in the envelope
30
31
  * `{errno, errMsg, data}`: a result as `{errno: null, errMsg: null, data}` (`data` is `null` when the action returned
31
32
  * nothing, and its status is not turned into 204), an error as `{errno, errMsg, data: null}` with the error's status,
32
- * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option.
33
+ * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option; the `extra` option adds
34
+ * fields to both.
33
35
  * @param options The envelope options.
34
36
  * @returns The responder, to give to the `respond` option of `fastifyHTTPEntrypoint`.
35
37
  * @example
@@ -54,8 +56,15 @@ export const FastifyJSONResponder = {
54
56
  * entrypoint: buildEntrypoints({
55
57
  * controllers: [PingController],
56
58
  * //The errors of the actions answered with 200 too (as the applications of lakutata 2.x), the routes not
57
- * //found and the errors of the hooks with their status (404, 401…)
58
- * http: fastifyHTTPEntrypoint({port: 8080, respond: fastifyJSONEnvelope({actionErrorStatus: 200})})
59
+ * //found and the errors of the hooks with their status (404, 401…); every envelope with
60
+ * //its timestamp ({"errno": null, "errMsg": null, "data": "pong", "timestamp": 1767225600000})
61
+ * http: fastifyHTTPEntrypoint({
62
+ * port: 8080,
63
+ * respond: fastifyJSONEnvelope({
64
+ * actionErrorStatus: 200,
65
+ * extra: (): Record<string, unknown> => ({timestamp: Date.now()})
66
+ * })
67
+ * })
59
68
  * })
60
69
  * }
61
70
  * })
@@ -63,11 +72,11 @@ export const FastifyJSONResponder = {
63
72
  */
64
73
  export function fastifyJSONEnvelope(options = {}) {
65
74
  return {
66
- success: (reply, data) => sendJSON(reply, { errno: null, errMsg: null, data: data === undefined ? null : data }),
67
- error: (reply, error, _request, origin) => {
75
+ success: (reply, data, request) => sendJSON(reply, envelopeOf({ errno: null, errMsg: null, data: data === undefined ? null : data }, options.extra?.(request))),
76
+ error: (reply, error, request, origin) => {
68
77
  const status = origin === 'action' ? options.actionErrorStatus ?? options.errorStatus : options.errorStatus;
69
78
  reply.code(status ?? statusOfError(error));
70
- sendJSON(reply, { ...describeError(error), data: null });
79
+ sendJSON(reply, envelopeOf({ ...describeError(error), data: null }, errorExtraOf(options.extra, request)));
71
80
  }
72
81
  };
73
82
  }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The envelope of a response: its fields, then the extra fields not named as one of them (an extra field never
3
+ * replaces errno, errMsg or data)
4
+ * @param fields The fields of the envelope.
5
+ * @param extra The extra fields, ignored when they are not an object.
6
+ */
7
+ export function envelopeOf(fields, extra) {
8
+ const envelope = { ...fields };
9
+ if (extra === null || typeof extra !== 'object')
10
+ return envelope;
11
+ for (const [key, value] of Object.entries(extra))
12
+ if (!Object.prototype.hasOwnProperty.call(envelope, key))
13
+ envelope[key] = value;
14
+ return envelope;
15
+ }
16
+ /**
17
+ * The extra fields of an error response: none when the function giving them fails, an error being answered anyway
18
+ * @param extra The function giving the extra fields.
19
+ * @param request The request answered.
20
+ */
21
+ export function errorExtraOf(extra, request) {
22
+ try {
23
+ return extra?.(request);
24
+ }
25
+ catch {
26
+ return undefined;
27
+ }
28
+ }
@@ -49,12 +49,23 @@ export type JSONEnvelopeOptions = {
49
49
  * @default `errorStatus`
50
50
  */
51
51
  actionErrorStatus?: number;
52
+ /**
53
+ * The extra fields of the envelope, such as the `timestamp`, `nonce` or `requestId` of the envelopes of the
54
+ * applications of lakutata 2.x: called for each response (a result or an error), its fields added after `errno`,
55
+ * `errMsg` and `data`, which they never replace. When it throws, a result is answered as an error, and an error
56
+ * without the extra fields.
57
+ * @param request The express request being answered.
58
+ * @returns The fields to add to the envelope.
59
+ * @default no extra field
60
+ */
61
+ extra?: (request: Request) => Record<string, unknown>;
52
62
  };
53
63
  /**
54
64
  * Create a responder for {@link expressHTTPEntrypoint} that wraps every response in the envelope
55
65
  * `{errno, errMsg, data}`: a result as `{errno: null, errMsg: null, data}` (`data` is `null` when the action returned
56
66
  * nothing, and its status is not turned into 204), an error as `{errno, errMsg, data: null}` with the error's status,
57
- * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option.
67
+ * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option; the `extra` option adds
68
+ * fields to both.
58
69
  * @param options The envelope options.
59
70
  * @returns The responder, to give to the `respond` option of `expressHTTPEntrypoint`.
60
71
  * @example
@@ -79,8 +90,15 @@ export type JSONEnvelopeOptions = {
79
90
  * entrypoint: buildEntrypoints({
80
91
  * controllers: [PingController],
81
92
  * //The errors of the actions answered with 200 too (as the applications of lakutata 2.x), the routes not
82
- * //found and the errors of the express middlewares with their status (404, 401…)
83
- * http: expressHTTPEntrypoint({port: 8080, respond: jsonEnvelope({actionErrorStatus: 200})})
93
+ * //found and the errors of the express middlewares with their status (404, 401…); every envelope with
94
+ * //its timestamp ({"errno": null, "errMsg": null, "data": "pong", "timestamp": 1767225600000})
95
+ * http: expressHTTPEntrypoint({
96
+ * port: 8080,
97
+ * respond: jsonEnvelope({
98
+ * actionErrorStatus: 200,
99
+ * extra: (): Record<string, unknown> => ({timestamp: Date.now()})
100
+ * })
101
+ * })
84
102
  * })
85
103
  * }
86
104
  * })
@@ -48,12 +48,23 @@ export type FastifyJSONEnvelopeOptions = {
48
48
  * @default `errorStatus`
49
49
  */
50
50
  actionErrorStatus?: number;
51
+ /**
52
+ * The extra fields of the envelope, such as the `timestamp`, `nonce` or `requestId` of the envelopes of the
53
+ * applications of lakutata 2.x: called for each response (a result or an error), its fields added after `errno`,
54
+ * `errMsg` and `data`, which they never replace. When it throws, a result is answered as an error, and an error
55
+ * without the extra fields.
56
+ * @param request The fastify request being answered.
57
+ * @returns The fields to add to the envelope.
58
+ * @default no extra field
59
+ */
60
+ extra?: (request: FastifyRequest) => Record<string, unknown>;
51
61
  };
52
62
  /**
53
63
  * Create a responder for {@link fastifyHTTPEntrypoint} that wraps every response in the envelope
54
64
  * `{errno, errMsg, data}`: a result as `{errno: null, errMsg: null, data}` (`data` is `null` when the action returned
55
65
  * nothing, and its status is not turned into 204), an error as `{errno, errMsg, data: null}` with the error's status,
56
- * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option.
66
+ * the `errorStatus` option, or for the errors of the actions the `actionErrorStatus` option; the `extra` option adds
67
+ * fields to both.
57
68
  * @param options The envelope options.
58
69
  * @returns The responder, to give to the `respond` option of `fastifyHTTPEntrypoint`.
59
70
  * @example
@@ -78,8 +89,15 @@ export type FastifyJSONEnvelopeOptions = {
78
89
  * entrypoint: buildEntrypoints({
79
90
  * controllers: [PingController],
80
91
  * //The errors of the actions answered with 200 too (as the applications of lakutata 2.x), the routes not
81
- * //found and the errors of the hooks with their status (404, 401…)
82
- * http: fastifyHTTPEntrypoint({port: 8080, respond: fastifyJSONEnvelope({actionErrorStatus: 200})})
92
+ * //found and the errors of the hooks with their status (404, 401…); every envelope with
93
+ * //its timestamp ({"errno": null, "errMsg": null, "data": "pong", "timestamp": 1767225600000})
94
+ * http: fastifyHTTPEntrypoint({
95
+ * port: 8080,
96
+ * respond: fastifyJSONEnvelope({
97
+ * actionErrorStatus: 200,
98
+ * extra: (): Record<string, unknown> => ({timestamp: Date.now()})
99
+ * })
100
+ * })
83
101
  * })
84
102
  * }
85
103
  * })
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The envelope of a response: its fields, then the extra fields not named as one of them (an extra field never
3
+ * replaces errno, errMsg or data)
4
+ * @param fields The fields of the envelope.
5
+ * @param extra The extra fields, ignored when they are not an object.
6
+ */
7
+ export declare function envelopeOf(fields: Record<string, unknown>, extra: unknown): Record<string, unknown>;
8
+ /**
9
+ * The extra fields of an error response: none when the function giving them fails, an error being answered anyway
10
+ * @param extra The function giving the extra fields.
11
+ * @param request The request answered.
12
+ */
13
+ export declare function errorExtraOf<Request>(extra: ((request: Request) => Record<string, unknown>) | undefined, request: Request): unknown;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lakutata/entrypoint",
3
- "version": "3.0.0-beta.1",
3
+ "version": "3.0.0-beta.2",
4
4
  "description": "The entrypoint component of the lakutata framework: controllers and the dispatch of the CLI, HTTP and service actions.",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/exports/Entrypoint.js",
@@ -110,8 +110,8 @@
110
110
  },
111
111
  "peerDependencies": {
112
112
  "@inquirer/prompts": "^7.0.0 || ^8.0.0",
113
- "@lakutata/core": "3.0.0-beta.1",
114
- "@lakutata/utils": "3.0.0-beta.1",
113
+ "@lakutata/core": "3.0.0-beta.2",
114
+ "@lakutata/utils": "3.0.0-beta.2",
115
115
  "commander": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0",
116
116
  "express": "^4.21.0 || ^5.0.0",
117
117
  "fastify": "^5.0.0",