@owlmeans/server-api 0.1.18-rc.48 → 0.1.18-rc.49
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 +2 -2
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/server-api/SKILL.md +11 -1
- package/build/hold.d.ts.map +1 -1
- package/build/hold.js +2 -1
- package/build/hold.js.map +1 -1
- package/build/protocol.d.ts.map +1 -1
- package/build/protocol.js +2 -1
- package/build/protocol.js.map +1 -1
- package/build/server.d.ts.map +1 -1
- package/build/server.js +25 -16
- package/build/server.js.map +1 -1
- package/build/utils/error.d.ts.map +1 -1
- package/build/utils/error.js +31 -3
- package/build/utils/error.js.map +1 -1
- package/build/utils/log.d.ts +11 -0
- package/build/utils/log.d.ts.map +1 -0
- package/build/utils/log.js +57 -0
- package/build/utils/log.js.map +1 -0
- package/build/utils/server.d.ts.map +1 -1
- package/build/utils/server.js +2 -1
- package/build/utils/server.js.map +1 -1
- package/package.json +7 -6
- package/src/hold.ts +2 -1
- package/src/protocol.ts +3 -2
- package/src/server.ts +27 -16
- package/src/utils/error.ts +31 -3
- package/src/utils/log.ts +64 -0
- package/src/utils/server.ts +2 -1
- package/tests/handlers.spec.ts +5 -5
- package/tests/log-adapter.spec.ts +52 -0
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ only when composing a context without that package. WebSocket routes belong to
|
|
|
10
10
|
## Installation
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
bun add @owlmeans/server-api@^0.1.18-rc.
|
|
13
|
+
bun add @owlmeans/server-api@^0.1.18-rc.49
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
## Concepts
|
|
@@ -240,7 +240,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
240
240
|
your project's skill store (`.agents/skills/`):
|
|
241
241
|
|
|
242
242
|
```sh
|
|
243
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
243
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.47
|
|
244
244
|
```
|
|
245
245
|
|
|
246
246
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/server-api",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-10-
|
|
4
|
+
"version": "0.1.18-rc.49",
|
|
5
|
+
"generatedAt": "2026-10-03T20:05:07.580Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -7,7 +7,7 @@ user-invocable: false
|
|
|
7
7
|
|
|
8
8
|
# @owlmeans/server-api
|
|
9
9
|
|
|
10
|
-
**Install:** `bun add @owlmeans/server-api@^0.1.18-rc.
|
|
10
|
+
**Install:** `bun add @owlmeans/server-api@^0.1.18-rc.49`
|
|
11
11
|
|
|
12
12
|
Make handlers from the protocol declaration so input and output types stay coupled to the shared
|
|
13
13
|
contract:
|
|
@@ -112,6 +112,16 @@ exposure) and a status from `errorStatus(error)` (`./utils`), resolved in this o
|
|
|
112
112
|
`uploadedFile(request)` is the Fastify multipart boundary. Keep raw Fastify access there rather
|
|
113
113
|
than reaching through `request.original` in application code.
|
|
114
114
|
|
|
115
|
+
## Logging
|
|
116
|
+
|
|
117
|
+
The server logs through `@owlmeans/log`, not a second pino: Fastify gets a pino-shaped adapter as its
|
|
118
|
+
`loggerInstance` (scope `http`) with its own request/response lines disabled. A request is one `debug`
|
|
119
|
+
record from `onResponse` (method, path without the query, status, ms). A failed request is logged once,
|
|
120
|
+
in `handleError`, by what it means: **5xx → `error`** (the error with its stack and the incident id),
|
|
121
|
+
**403 → `warn`, `event: 'access.forbidden'`**, 401 → `debug`, `event: 'auth.refused'`, any other 4xx →
|
|
122
|
+
`debug`. The level and format come from `cfg.log` (`/log`); access lines at info are
|
|
123
|
+
`cfg.log.debug: 'http'`.
|
|
124
|
+
|
|
115
125
|
## Error exposure
|
|
116
126
|
|
|
117
127
|
An exact IAM `AuthForbidden` or `AccessError` refusal answers with
|
package/build/hold.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hold.d.ts","sourceRoot":"","sources":["../src/hold.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hold.d.ts","sourceRoot":"","sources":["../src/hold.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAG5D,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,OAAO,CAAA;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,WAAW,QACjB,YAAY,SAAQ,kBAAkB,KAC1C,OAAO,CAAC,WAAW,CA0BrB,CAAA"}
|
package/build/hold.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Fastify from 'fastify';
|
|
2
|
+
import { logger } from '@owlmeans/log';
|
|
2
3
|
import { CLOSED_HOST, OPENED_HOST, PORT } from './consts.js';
|
|
3
4
|
/**
|
|
4
5
|
* Own the app's port while the context initializes, and answer for the app until `listen()`
|
|
@@ -48,7 +49,7 @@ export const holdApiPort = async (cfg, opts = {}) => {
|
|
|
48
49
|
return await reply.code(503).send(payload());
|
|
49
50
|
});
|
|
50
51
|
await server.listen({ port, host });
|
|
51
|
-
|
|
52
|
+
logger('server').info(`api-server: holding ${host}:${port} for the boot${opts.okPath != null ? ` (${opts.okPath})` : ''}`, undefined, { event: 'server.hold' });
|
|
52
53
|
return {
|
|
53
54
|
release: async () => { await server.close(); },
|
|
54
55
|
};
|
package/build/hold.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hold.js","sourceRoot":"","sources":["../src/hold.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"hold.js","sourceRoot":"","sources":["../src/hold.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAA;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAEtC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAsB5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAC9B,GAAiB,EAAE,IAAI,GAAuB,EAAE,EAC1B,EAAE;IACxB,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACxC,MAAM,IAAI,GAAG,MAAM,EAAE,YAAY,IAAI,MAAM,EAAE,IAAI,IAAI,IAAI,CAAA;IACzD,MAAM,IAAI,GAAG,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAA;IAEhE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAE1D,8FAA8F;IAC9F,mFAAmF;IACnF,MAAM,MAAM,GAAG,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAAC,CAAA;IAEtE,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;YAChD,OAAO,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;QAC9C,CAAC,CAAC,CAAA;IACJ,CAAC;IACD,MAAM,CAAC,kBAAkB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;QAClD,OAAO,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;IAC9C,CAAC,CAAC,CAAA;IAEF,MAAM,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IACnC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,uBAAuB,IAAI,IAAI,IAAI,gBAAgB,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAA;IAE/J,OAAO;QACL,OAAO,EAAE,KAAK,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA,CAAC,CAAC;KAC9C,CAAA;AACH,CAAC,CAAA"}
|
package/build/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAElE,OAAO,KAAK,EACV,MAAM,EAAE,6BAA6B,EAAE,cAAc,EAAe,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAC/G,MAAM,sBAAsB,CAAA;AAE7B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAElE,OAAO,KAAK,EACV,MAAM,EAAE,6BAA6B,EAAE,cAAc,EAAe,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAC/G,MAAM,sBAAsB,CAAA;AAE7B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAIzE;;;;;;;;;GASG;AACH,KAAK,iBAAiB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,IAAI,GAAG,KAAK,CAAA;AAE7F;;;;;;;GAOG;AACH,KAAK,eAAe,CAAC,QAAQ,IAAI,iBAAiB,CAAC,QAAQ,CAAC,SAAS,IAAI,GAAG,GAAG,GAAG,QAAQ,CAAA;AAC1F,KAAK,YAAY,CAAC,KAAK,IAAI,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;AACjD,KAAK,YAAY,CAAC,QAAQ,SAAS,6BAA6B,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GAC/G,QAAQ,GAAG,KAAK,CAAA;AACpB,KAAK,cAAc,CAAC,QAAQ,SAAS,6BAA6B,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAChH,QAAQ,GAAG,KAAK,CAAA;AAqGpB;;;GAGG;AACH,eAAO,MAAM,QAAQ,GAAI,OAAO,SAAS,YAAY,CAAC,WAAW,CAAC;IAChE,IAAI,GAAG,QAAQ,SAAS,6BAA6B,YACzC,QAAQ,WACT,QAAQ,SAAS,YAAY,CAAC,QAAQ,CAAC,GAAG,CAC/C,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,EACzB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,KACzC,YAAY,CAAC,eAAe,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,GACtD,KAAK,KACR,sBAAsB,CAAC,QAAQ,CAAC;IAKnC,MAAM,GAAG,QAAQ,SAAS,6BAA6B,YAC3C,QAAQ,WACT,QAAQ,SAAS,cAAc,CAAC,QAAQ,CAAC,GAAG,CACjD,OAAO,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAC3B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,KACzC,YAAY,CAAC,eAAe,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,GACtD,KAAK,KACR,sBAAsB,CAAC,QAAQ,CAAC;IAKnC,OAAO,GAAG,QAAQ,SAAS,6BAA6B,YAC5C,QAAQ,WACT,CACP,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,EAC5C,OAAO,EAAE,OAAO,KACb,YAAY,CAAC,eAAe,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,KACvD,sBAAsB,CAAC,QAAQ,CAAC;CACnC,CAAA;AAEF,sGAAsG;AACtG,eAAO,MAAM,YAAY,YACd,cAAc,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,KACxC,OAAO,CAAC,OAAO,oBAAoB,EAAE,aAAa,GAAG,SAAS,CAKhE,CAAA"}
|
package/build/protocol.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { assertContext } from '@owlmeans/context';
|
|
2
2
|
import { EntrypointOutcome } from '@owlmeans/entrypoint';
|
|
3
3
|
import { HandlerMisconfiguredError } from './errors.js';
|
|
4
|
+
import { logger } from '@owlmeans/log';
|
|
4
5
|
const contextFor = (request, fallback) => {
|
|
5
6
|
const original = request.original;
|
|
6
7
|
if (original != null && typeof original === 'object' && '_ctx' in original) {
|
|
@@ -53,7 +54,7 @@ const toleratedHandler = (protocol, handler) => {
|
|
|
53
54
|
if (handler.protocol.alias === protocol.alias) {
|
|
54
55
|
if (!warnedAliases.has(protocol.alias)) {
|
|
55
56
|
warnedAliases.add(protocol.alias);
|
|
56
|
-
|
|
57
|
+
logger('server-api').warn(`${protocol.alias}: handler is already bound — pass it to bind() directly; `
|
|
57
58
|
+ 'wrapping it again here is a type error (TS2345 "BoundEntrypointHandler<…> is not '
|
|
58
59
|
+ 'assignable"), tolerated at runtime for a project generated before the wrap-once rule.');
|
|
59
60
|
}
|
package/build/protocol.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAMxD,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
package/build/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC3E,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC3E,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAqC5D,KAAK,MAAM,GAAG,YAAY,CAAA;AAiB1B,eAAO,MAAM,eAAe,UAAW,MAAM,KAAG,SA+I/C,CAAA;AAED,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,OACrE,CAAC,UAAS,MAAM,KACpB,CAAC,GAAG,eAWN,CAAA"}
|
package/build/server.js
CHANGED
|
@@ -7,6 +7,8 @@ import { provideResponse } from '@owlmeans/entrypoint';
|
|
|
7
7
|
import { TOKEN_UPDATE } from '@owlmeans/auth-common';
|
|
8
8
|
import { INCIDENT_ID_HEADER } from './utils/error.js';
|
|
9
9
|
import { DENIAL_KIND_HEADER } from '@owlmeans/api';
|
|
10
|
+
import { logger } from '@owlmeans/log';
|
|
11
|
+
import { fastifyLogger } from './utils/log.js';
|
|
10
12
|
import Fastify from 'fastify';
|
|
11
13
|
import cors from '@fastify/cors';
|
|
12
14
|
import rawBody from 'fastify-raw-body';
|
|
@@ -26,31 +28,28 @@ const ajv = new Ajv({
|
|
|
26
28
|
formatsPlugin(ajv);
|
|
27
29
|
ajvErrors(ajv, { singleError: true });
|
|
28
30
|
const bodyLimit = 1024 * 1024 * 20;
|
|
31
|
+
const http = logger('http');
|
|
32
|
+
/**
|
|
33
|
+
* Fastify logging through `@owlmeans/log`. Fastify's own request/response lines are dropped by the
|
|
34
|
+
* adapter: a request is a debug record written once from `onResponse` (below), and a failed one is
|
|
35
|
+
* classified by `handleError`, so an info-level process is not flooded with every call it serves.
|
|
36
|
+
*/
|
|
37
|
+
const createFastify = () => Fastify({
|
|
38
|
+
loggerInstance: fastifyLogger(http),
|
|
39
|
+
bodyLimit,
|
|
40
|
+
});
|
|
29
41
|
export const createApiServer = (alias) => {
|
|
30
42
|
const location = `service:${alias}`;
|
|
31
43
|
const _assertContext = (context) => assertContext(context, location);
|
|
32
44
|
const service = createService(alias, {
|
|
33
|
-
server:
|
|
34
|
-
logger: true,
|
|
35
|
-
bodyLimit,
|
|
36
|
-
/*{
|
|
37
|
-
transport: {
|
|
38
|
-
target: 'pino-pretty',
|
|
39
|
-
options: {
|
|
40
|
-
singleLine: true,
|
|
41
|
-
translateTime: 'HH:MM:ss Z',
|
|
42
|
-
ignore: 'pid,hostname',
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
}*/
|
|
46
|
-
}),
|
|
45
|
+
server: createFastify(),
|
|
47
46
|
listen: async () => {
|
|
48
47
|
const context = _assertContext(service.ctx);
|
|
49
48
|
const config = context.cfg.services[context.cfg.service];
|
|
50
49
|
const port = config?.internalPort ?? config?.port ?? PORT;
|
|
51
50
|
const host = config.opened === true ? OPENED_HOST : CLOSED_HOST;
|
|
52
51
|
await service.server.listen({ port, host });
|
|
53
|
-
|
|
52
|
+
logger('server').info(`${location}: server listening on ${host}${port != null ? `:${port}` : ''}`, undefined, { event: 'server.listening' });
|
|
54
53
|
process.on('SIGTERM', () => {
|
|
55
54
|
service.server.close().then(() => {
|
|
56
55
|
process.exit(0);
|
|
@@ -60,12 +59,22 @@ export const createApiServer = (alias) => {
|
|
|
60
59
|
}, service => async () => {
|
|
61
60
|
if (service.server.server.listening) {
|
|
62
61
|
await service.server.close();
|
|
63
|
-
service.server =
|
|
62
|
+
service.server = createFastify();
|
|
64
63
|
}
|
|
65
64
|
const context = _assertContext(service.ctx);
|
|
66
65
|
const server = service.server;
|
|
67
66
|
// @TODO We should ensure some way that Resilient Error is thrown and go to the flow
|
|
68
67
|
server.setValidatorCompiler(opts => ajv.compile(opts.schema));
|
|
68
|
+
server.addHook('onResponse', (request, reply, done) => {
|
|
69
|
+
if (http.enabled('debug')) {
|
|
70
|
+
// The path only: a query string can carry a token.
|
|
71
|
+
http.debug('request', {
|
|
72
|
+
method: request.method, path: request.url.split('?')[0], status: reply.statusCode,
|
|
73
|
+
ms: Math.round(reply.elapsedTime),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
done();
|
|
77
|
+
});
|
|
69
78
|
// @TODO It's quite unsafe and should be properly configured
|
|
70
79
|
await server.register(cors, {
|
|
71
80
|
origin: '*',
|
package/build/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAClF,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE3E,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/utils/error.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/utils/error.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAM3C,OAAO,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAE5D,eAAO,MAAM,kBAAkB,kBAAkB,CAAA;AAEjD;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,6FAA6F;IAC7F,sBAAsB,CAAC,EAAE,OAAO,CAAA;CACjC;AAOD;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,UAAW,OAAO,KAAG,MAAM,GAAG,IAc7D,CAAA;AAkCD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,WAAW,UAAW,OAAO,KAAG,MAkB5C,CAAA;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,qFAAqF;AACrF,eAAO,MAAM,aAAa,YAAa,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,iBACmB,CAAA;AAsBjF,qDAAqD;AACrD,eAAO,MAAM,cAAc,UAClB,KAAK,aAAY,iBAAiB,KACxC,mBAcF,CAAA;AAED,gGAAgG;AAChG,eAAO,MAAM,iBAAiB,UAAW,OAAO,SAAS,YAAY,KAAG,IAcvE,CAAA;AA+BD;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,UACf,KAAK,SAAS,YAAY,aAAY,iBAAiB,SAU/D,CAAA"}
|
package/build/utils/error.js
CHANGED
|
@@ -3,6 +3,7 @@ import { AccessError, AuthFailedError } from '../errors.js';
|
|
|
3
3
|
import { AuthForbidden, AuthorizationError } from '@owlmeans/auth';
|
|
4
4
|
import { isResilientError, ResilientError, SEPARATOR } from '@owlmeans/error';
|
|
5
5
|
import { randomUUID } from 'node:crypto';
|
|
6
|
+
import { logger } from '@owlmeans/log';
|
|
6
7
|
export const INCIDENT_ID_HEADER = 'X-Incident-ID';
|
|
7
8
|
const CLIENT_ERROR_FIRST = 400;
|
|
8
9
|
const CLIENT_ERROR_LAST = 499;
|
|
@@ -149,6 +150,35 @@ export const applyErrorHeaders = (error, reply) => {
|
|
|
149
150
|
reply.header(DENIAL_KIND_HEADER, ACCESS_DENIED_KIND);
|
|
150
151
|
}
|
|
151
152
|
};
|
|
153
|
+
const http = logger('http');
|
|
154
|
+
/**
|
|
155
|
+
* The one log entry of a failed request, by what the failure means:
|
|
156
|
+
*
|
|
157
|
+
* | Status | Level | Why |
|
|
158
|
+
* |---|---|---|
|
|
159
|
+
* | 5xx | error | a fault — the one entry that owns type, message and stack, keyed by the incident id |
|
|
160
|
+
* | 403 | warn, `access.forbidden` | an established identity was refused; worth an operator's eye |
|
|
161
|
+
* | 401 | debug, `auth.refused` | an absent or expired credential is the ordinary shape of a sign-in |
|
|
162
|
+
* | other 4xx | debug | the caller's mistake, not the server's |
|
|
163
|
+
*
|
|
164
|
+
* The method and path are logged; the query string is not — it can carry a token.
|
|
165
|
+
*/
|
|
166
|
+
const logFailure = (error, reply, status, incidentId) => {
|
|
167
|
+
const request = reply.request;
|
|
168
|
+
const where = { method: request?.method, path: request?.url?.split('?')[0], status, incidentId };
|
|
169
|
+
if (status >= SERVER_ERROR) {
|
|
170
|
+
http.error('Request failed', { err: error, ...where });
|
|
171
|
+
}
|
|
172
|
+
else if (status === FORBIDDEN_ERROR) {
|
|
173
|
+
http.warn('Access forbidden', { type: error.type, message: error.message, ...where }, { event: 'access.forbidden' });
|
|
174
|
+
}
|
|
175
|
+
else if (status === UNAUTHORIZED_ERROR) {
|
|
176
|
+
http.debug('Authentication refused', { message: error.message, ...where }, { event: 'auth.refused' });
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
http.debug('Request refused', { message: error.message, ...where });
|
|
180
|
+
}
|
|
181
|
+
};
|
|
152
182
|
/**
|
|
153
183
|
* Answer a thrown error: a status, and the marshalled `ResilientError` as the body.
|
|
154
184
|
*
|
|
@@ -163,9 +193,7 @@ export const handleError = (error, reply, exposure = 'production') => {
|
|
|
163
193
|
if (!reply.sent) {
|
|
164
194
|
const serialized = serializeError(error, exposure);
|
|
165
195
|
applyErrorHeaders(error, reply);
|
|
166
|
-
|
|
167
|
-
// the one log entry that owns those details in production, keyed by the response incident ID.
|
|
168
|
-
reply.log.error({ err: error, incidentId: serialized.incidentId }, 'Request failed');
|
|
196
|
+
logFailure(error, reply, serialized.status, serialized.incidentId);
|
|
169
197
|
reply.header(INCIDENT_ID_HEADER, serialized.incidentId)
|
|
170
198
|
.code(serialized.status)
|
|
171
199
|
.send(serialized.body);
|
package/build/utils/error.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/utils/error.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EAAE,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,kBAAkB,GAC1F,MAAM,eAAe,CAAA;AAEtB,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAClE,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC7E,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/utils/error.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FastifyBaseLogger } from 'fastify';
|
|
2
|
+
import type { Logger } from '@owlmeans/log';
|
|
3
|
+
/**
|
|
4
|
+
* A pino-shaped logger over `@owlmeans/log`, handed to Fastify as its `loggerInstance`.
|
|
5
|
+
*
|
|
6
|
+
* Fastify then logs through the process's own level, format and plugins instead of a second pino
|
|
7
|
+
* instance that ignores them. `(object, message)` and `(message)` are the two shapes Fastify and
|
|
8
|
+
* its plugins call with; an `err` in the object travels as the record's error.
|
|
9
|
+
*/
|
|
10
|
+
export declare const fastifyLogger: (log?: Logger, bindings?: Record<string, unknown>) => FastifyBaseLogger;
|
|
11
|
+
//# sourceMappingURL=log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/utils/log.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAEhD,OAAO,KAAK,EAAY,MAAM,EAAE,MAAM,eAAe,CAAA;AA2BrD;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,SAAS,MAAM,aAA8B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,iBAsBhG,CAAA"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { logger } from '@owlmeans/log';
|
|
2
|
+
/**
|
|
3
|
+
* What Fastify says about itself, mapped to what an operator needs at each level.
|
|
4
|
+
*
|
|
5
|
+
* Fastify writes a pair of `info` lines for EVERY request and one for each unknown route, and
|
|
6
|
+
* announces its own listening address. The server writes one `debug` record per request itself
|
|
7
|
+
* (`onResponse`), a failed request is classified once in `handleError`, and the listening line is
|
|
8
|
+
* `server.listening` — so these are dropped or lowered here, by their fixed wording, rather than by
|
|
9
|
+
* a Fastify option (`disableRequestLogging` is deprecated from 5.12, `logController` does not exist
|
|
10
|
+
* before it).
|
|
11
|
+
*/
|
|
12
|
+
const levelOf = (level, message) => {
|
|
13
|
+
if (typeof message !== 'string' || level !== 'info') {
|
|
14
|
+
return level;
|
|
15
|
+
}
|
|
16
|
+
if (message === 'incoming request' || message === 'request completed') {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
if (message.startsWith('Server listening at') || /^Route .* not found$/.test(message)) {
|
|
20
|
+
return 'debug';
|
|
21
|
+
}
|
|
22
|
+
return level;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* A pino-shaped logger over `@owlmeans/log`, handed to Fastify as its `loggerInstance`.
|
|
26
|
+
*
|
|
27
|
+
* Fastify then logs through the process's own level, format and plugins instead of a second pino
|
|
28
|
+
* instance that ignores them. `(object, message)` and `(message)` are the two shapes Fastify and
|
|
29
|
+
* its plugins call with; an `err` in the object travels as the record's error.
|
|
30
|
+
*/
|
|
31
|
+
export const fastifyLogger = (log = logger('http'), bindings) => {
|
|
32
|
+
const call = (requested) => (first, second) => {
|
|
33
|
+
const [object, message] = typeof first === 'string' || first instanceof Error
|
|
34
|
+
? [undefined, first] : [first, second];
|
|
35
|
+
const level = levelOf(requested, message);
|
|
36
|
+
if (level == null) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const data = bindings != null && Object.keys(bindings).length > 0
|
|
40
|
+
? { ...bindings, ...(object != null && typeof object === 'object' ? object : {}) } : object;
|
|
41
|
+
log[level](message == null ? '' : message instanceof Error ? message : String(message), data);
|
|
42
|
+
};
|
|
43
|
+
const adapter = {
|
|
44
|
+
get level() { return levelName(log); },
|
|
45
|
+
set level(_value) { },
|
|
46
|
+
fatal: call('error'), error: call('error'), warn: call('warn'),
|
|
47
|
+
info: call('info'), debug: call('debug'), trace: call('debug'),
|
|
48
|
+
silent: () => undefined,
|
|
49
|
+
child: (extra) => fastifyLogger(log, { ...bindings, ...extra }),
|
|
50
|
+
};
|
|
51
|
+
return adapter;
|
|
52
|
+
};
|
|
53
|
+
const levelName = (log) => {
|
|
54
|
+
const order = ['debug', 'info', 'warn', 'error'];
|
|
55
|
+
return order.find(level => log.enabled(level)) ?? 'silent';
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/utils/log.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/utils/server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE3D,OAAO,KAAK,EAAgB,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAG5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/utils/server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE3D,OAAO,KAAK,EAAgB,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAG5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAQ7D,OAAO,KAAK,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,aAAa,CAAA;AAEtD,KAAK,MAAM,GAAG,SAAS,CAAA;AACvB,KAAK,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAA;AAEpC,eAAO,MAAM,cAAc,YAAa,OAAO,UAAU,gBAAgB,KAAG,MAAM,IAAI,gBAAgB,CAAC,OAAO,CAc7G,CAAA;AAED,eAAO,MAAM,mBAAmB,WAAY,gBAAgB,CAAC,cAAc,CAAC,YAAY,MAAM,WAChF,cAAc,SAAS,YAAY,kBAuC9C,CAAA"}
|
package/build/utils/server.js
CHANGED
|
@@ -3,6 +3,7 @@ import { assertContext } from '@owlmeans/context';
|
|
|
3
3
|
import { provideResponse } from '@owlmeans/entrypoint';
|
|
4
4
|
import { ResilientError } from '@owlmeans/error';
|
|
5
5
|
import { OK } from '@owlmeans/api';
|
|
6
|
+
import { logger } from '@owlmeans/log';
|
|
6
7
|
import { errorExposure, handleError } from './error.js';
|
|
7
8
|
import { executeResponse, provideRequest } from './payload.js';
|
|
8
9
|
import { authorize } from './guards.js';
|
|
@@ -45,7 +46,7 @@ export const createServerHandler = (module, location) => async (req, reply) => {
|
|
|
45
46
|
// neither `executeResponse` nor the handler itself (hijack) replied.
|
|
46
47
|
const responded = executeResponse(response, reply, true);
|
|
47
48
|
if (!responded && !reply.sent) {
|
|
48
|
-
|
|
49
|
+
logger('http').warn(`SENDS DEFAULT RESPONSE: ${module.alias}`);
|
|
49
50
|
reply.code(OK).send(response.value);
|
|
50
51
|
}
|
|
51
52
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/utils/server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/utils/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/server-api",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.49",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -33,14 +33,15 @@
|
|
|
33
33
|
"@fastify/helmet": "^13.1.0",
|
|
34
34
|
"@fastify/middie": "^9.0.2",
|
|
35
35
|
"@fastify/multipart": "^9.0.1",
|
|
36
|
-
"@owlmeans/api": "^0.1.18-rc.
|
|
36
|
+
"@owlmeans/api": "^0.1.18-rc.45",
|
|
37
37
|
"@owlmeans/auth": "^0.1.18-rc.38",
|
|
38
|
-
"@owlmeans/auth-common": "^0.1.18-rc.
|
|
38
|
+
"@owlmeans/auth-common": "^0.1.18-rc.45",
|
|
39
39
|
"@owlmeans/context": "^0.1.18-rc.32",
|
|
40
|
-
"@owlmeans/error": "^0.1.18-rc.36",
|
|
41
40
|
"@owlmeans/entrypoint": "^0.1.18-rc.39",
|
|
41
|
+
"@owlmeans/error": "^0.1.18-rc.36",
|
|
42
|
+
"@owlmeans/log": "^0.1.18-rc.0",
|
|
42
43
|
"@owlmeans/route": "^0.1.18-rc.33",
|
|
43
|
-
"@owlmeans/server-context": "^0.1.18-rc.
|
|
44
|
+
"@owlmeans/server-context": "^0.1.18-rc.41",
|
|
44
45
|
"@owlmeans/server-entrypoint": "^0.1.18-rc.38",
|
|
45
46
|
"ajv-errors": "^3.0.0",
|
|
46
47
|
"fastify": "^5.0.0",
|
|
@@ -53,7 +54,7 @@
|
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
56
|
"@owlmeans/dep-config": "workspace:*",
|
|
56
|
-
"@owlmeans/resource": "^0.1.18-rc.
|
|
57
|
+
"@owlmeans/resource": "^0.1.18-rc.38",
|
|
57
58
|
"@types/bun": "^1.4.0",
|
|
58
59
|
"@types/node": "^26.1.0",
|
|
59
60
|
"nodemon": "^3.1.14",
|
package/src/hold.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Fastify from 'fastify'
|
|
2
|
+
import { logger } from '@owlmeans/log'
|
|
2
3
|
import type { ServerConfig } from '@owlmeans/server-context'
|
|
3
4
|
import { CLOSED_HOST, OPENED_HOST, PORT } from './consts.js'
|
|
4
5
|
|
|
@@ -76,7 +77,7 @@ export const holdApiPort = async (
|
|
|
76
77
|
})
|
|
77
78
|
|
|
78
79
|
await server.listen({ port, host })
|
|
79
|
-
|
|
80
|
+
logger('server').info(`api-server: holding ${host}:${port} for the boot${opts.okPath != null ? ` (${opts.okPath})` : ''}`, undefined, { event: 'server.hold' })
|
|
80
81
|
|
|
81
82
|
return {
|
|
82
83
|
release: async () => { await server.close() },
|
package/src/protocol.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
import type { AbstractRequest } from '@owlmeans/entrypoint'
|
|
8
8
|
import type { BoundEntrypointHandler } from '@owlmeans/server-entrypoint'
|
|
9
9
|
import { HandlerMisconfiguredError } from './errors.js'
|
|
10
|
+
import { logger } from '@owlmeans/log'
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* True for a response the declaration left with no compile-time contract: `typed<any>()` (an
|
|
@@ -112,8 +113,8 @@ const toleratedHandler = <Protocol extends EntrypointProtocolDeclaration>(
|
|
|
112
113
|
if (handler.protocol.alias === protocol.alias) {
|
|
113
114
|
if (!warnedAliases.has(protocol.alias)) {
|
|
114
115
|
warnedAliases.add(protocol.alias)
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
logger('server-api').warn(
|
|
117
|
+
`${protocol.alias}: handler is already bound — pass it to bind() directly; `
|
|
117
118
|
+ 'wrapping it again here is a type error (TS2345 "BoundEntrypointHandler<…> is not '
|
|
118
119
|
+ 'assignable"), tolerated at runtime for a project generated before the wrap-once rule.'
|
|
119
120
|
)
|
package/src/server.ts
CHANGED
|
@@ -10,6 +10,8 @@ import { provideResponse } from '@owlmeans/entrypoint'
|
|
|
10
10
|
import { TOKEN_UPDATE } from '@owlmeans/auth-common'
|
|
11
11
|
import { INCIDENT_ID_HEADER } from './utils/error.js'
|
|
12
12
|
import { DENIAL_KIND_HEADER } from '@owlmeans/api'
|
|
13
|
+
import { logger } from '@owlmeans/log'
|
|
14
|
+
import { fastifyLogger } from './utils/log.js'
|
|
13
15
|
|
|
14
16
|
import Fastify from 'fastify'
|
|
15
17
|
import type { FastifyRequest } from 'fastify'
|
|
@@ -39,25 +41,24 @@ type Context = ServerContext<Config>
|
|
|
39
41
|
|
|
40
42
|
const bodyLimit = 1024 * 1024 * 20
|
|
41
43
|
|
|
44
|
+
const http = logger('http')
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Fastify logging through `@owlmeans/log`. Fastify's own request/response lines are dropped by the
|
|
48
|
+
* adapter: a request is a debug record written once from `onResponse` (below), and a failed one is
|
|
49
|
+
* classified by `handleError`, so an info-level process is not flooded with every call it serves.
|
|
50
|
+
*/
|
|
51
|
+
const createFastify = () => Fastify({
|
|
52
|
+
loggerInstance: fastifyLogger(http),
|
|
53
|
+
bodyLimit,
|
|
54
|
+
})
|
|
55
|
+
|
|
42
56
|
export const createApiServer = (alias: string): ApiServer => {
|
|
43
57
|
const location = `service:${alias}`
|
|
44
58
|
const _assertContext = (context: Context | undefined): Context => assertContext<Config, Context>(context, location)
|
|
45
59
|
|
|
46
60
|
const service = createService<ApiServer>(alias, {
|
|
47
|
-
server:
|
|
48
|
-
logger: true,
|
|
49
|
-
bodyLimit,
|
|
50
|
-
/*{
|
|
51
|
-
transport: {
|
|
52
|
-
target: 'pino-pretty',
|
|
53
|
-
options: {
|
|
54
|
-
singleLine: true,
|
|
55
|
-
translateTime: 'HH:MM:ss Z',
|
|
56
|
-
ignore: 'pid,hostname',
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
}*/
|
|
60
|
-
}),
|
|
61
|
+
server: createFastify(),
|
|
61
62
|
|
|
62
63
|
listen: async () => {
|
|
63
64
|
const context = _assertContext(service.ctx as Context)
|
|
@@ -67,7 +68,7 @@ export const createApiServer = (alias: string): ApiServer => {
|
|
|
67
68
|
const port = config?.internalPort ?? config?.port ?? PORT
|
|
68
69
|
const host = config.opened === true ? OPENED_HOST : CLOSED_HOST
|
|
69
70
|
await service.server.listen({ port, host })
|
|
70
|
-
|
|
71
|
+
logger('server').info(`${location}: server listening on ${host}${port != null ? `:${port}` : ''}`, undefined, { event: 'server.listening' })
|
|
71
72
|
|
|
72
73
|
process.on('SIGTERM', () => {
|
|
73
74
|
service.server.close().then(() => {
|
|
@@ -78,7 +79,7 @@ export const createApiServer = (alias: string): ApiServer => {
|
|
|
78
79
|
}, service => async () => {
|
|
79
80
|
if (service.server.server.listening) {
|
|
80
81
|
await service.server.close()
|
|
81
|
-
service.server =
|
|
82
|
+
service.server = createFastify()
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
const context = _assertContext(service.ctx as Context)
|
|
@@ -86,6 +87,16 @@ export const createApiServer = (alias: string): ApiServer => {
|
|
|
86
87
|
const server = service.server
|
|
87
88
|
// @TODO We should ensure some way that Resilient Error is thrown and go to the flow
|
|
88
89
|
server.setValidatorCompiler(opts => ajv.compile(opts.schema))
|
|
90
|
+
server.addHook('onResponse', (request, reply, done) => {
|
|
91
|
+
if (http.enabled('debug')) {
|
|
92
|
+
// The path only: a query string can carry a token.
|
|
93
|
+
http.debug('request', {
|
|
94
|
+
method: request.method, path: request.url.split('?')[0], status: reply.statusCode,
|
|
95
|
+
ms: Math.round(reply.elapsedTime),
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
done()
|
|
99
|
+
})
|
|
89
100
|
// @TODO It's quite unsafe and should be properly configured
|
|
90
101
|
await server.register(cors, {
|
|
91
102
|
origin: '*',
|
package/src/utils/error.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { AccessError, AuthFailedError } from '../errors.js'
|
|
|
6
6
|
import { AuthForbidden, AuthorizationError } from '@owlmeans/auth'
|
|
7
7
|
import { isResilientError, ResilientError, SEPARATOR } from '@owlmeans/error'
|
|
8
8
|
import { randomUUID } from 'node:crypto'
|
|
9
|
+
import { logger } from '@owlmeans/log'
|
|
9
10
|
import type { Config, HttpErrorExposure } from '../types.js'
|
|
10
11
|
|
|
11
12
|
export const INCIDENT_ID_HEADER = 'X-Incident-ID'
|
|
@@ -188,6 +189,35 @@ export const applyErrorHeaders = (error: unknown, reply: FastifyReply): void =>
|
|
|
188
189
|
}
|
|
189
190
|
}
|
|
190
191
|
|
|
192
|
+
const http = logger('http')
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* The one log entry of a failed request, by what the failure means:
|
|
196
|
+
*
|
|
197
|
+
* | Status | Level | Why |
|
|
198
|
+
* |---|---|---|
|
|
199
|
+
* | 5xx | error | a fault — the one entry that owns type, message and stack, keyed by the incident id |
|
|
200
|
+
* | 403 | warn, `access.forbidden` | an established identity was refused; worth an operator's eye |
|
|
201
|
+
* | 401 | debug, `auth.refused` | an absent or expired credential is the ordinary shape of a sign-in |
|
|
202
|
+
* | other 4xx | debug | the caller's mistake, not the server's |
|
|
203
|
+
*
|
|
204
|
+
* The method and path are logged; the query string is not — it can carry a token.
|
|
205
|
+
*/
|
|
206
|
+
const logFailure = (error: Error, reply: FastifyReply, status: number, incidentId: string): void => {
|
|
207
|
+
const request = reply.request
|
|
208
|
+
const where = { method: request?.method, path: request?.url?.split('?')[0], status, incidentId }
|
|
209
|
+
if (status >= SERVER_ERROR) {
|
|
210
|
+
http.error('Request failed', { err: error, ...where })
|
|
211
|
+
} else if (status === FORBIDDEN_ERROR) {
|
|
212
|
+
http.warn('Access forbidden', { type: (error as { type?: unknown }).type, message: error.message, ...where },
|
|
213
|
+
{ event: 'access.forbidden' })
|
|
214
|
+
} else if (status === UNAUTHORIZED_ERROR) {
|
|
215
|
+
http.debug('Authentication refused', { message: error.message, ...where }, { event: 'auth.refused' })
|
|
216
|
+
} else {
|
|
217
|
+
http.debug('Request refused', { message: error.message, ...where })
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
191
221
|
/**
|
|
192
222
|
* Answer a thrown error: a status, and the marshalled `ResilientError` as the body.
|
|
193
223
|
*
|
|
@@ -204,9 +234,7 @@ export const handleError = (
|
|
|
204
234
|
if (!reply.sent) {
|
|
205
235
|
const serialized = serializeError(error, exposure)
|
|
206
236
|
applyErrorHeaders(error, reply)
|
|
207
|
-
|
|
208
|
-
// the one log entry that owns those details in production, keyed by the response incident ID.
|
|
209
|
-
reply.log.error({ err: error, incidentId: serialized.incidentId }, 'Request failed')
|
|
237
|
+
logFailure(error, reply, serialized.status, serialized.incidentId)
|
|
210
238
|
reply.header(INCIDENT_ID_HEADER, serialized.incidentId)
|
|
211
239
|
.code(serialized.status)
|
|
212
240
|
.send(serialized.body)
|
package/src/utils/log.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { FastifyBaseLogger } from 'fastify'
|
|
2
|
+
import { logger } from '@owlmeans/log'
|
|
3
|
+
import type { LogLevel, Logger } from '@owlmeans/log'
|
|
4
|
+
|
|
5
|
+
type Severity = 'debug' | 'info' | 'warn' | 'error'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* What Fastify says about itself, mapped to what an operator needs at each level.
|
|
9
|
+
*
|
|
10
|
+
* Fastify writes a pair of `info` lines for EVERY request and one for each unknown route, and
|
|
11
|
+
* announces its own listening address. The server writes one `debug` record per request itself
|
|
12
|
+
* (`onResponse`), a failed request is classified once in `handleError`, and the listening line is
|
|
13
|
+
* `server.listening` — so these are dropped or lowered here, by their fixed wording, rather than by
|
|
14
|
+
* a Fastify option (`disableRequestLogging` is deprecated from 5.12, `logController` does not exist
|
|
15
|
+
* before it).
|
|
16
|
+
*/
|
|
17
|
+
const levelOf = (level: Severity, message: unknown): Severity | undefined => {
|
|
18
|
+
if (typeof message !== 'string' || level !== 'info') {
|
|
19
|
+
return level
|
|
20
|
+
}
|
|
21
|
+
if (message === 'incoming request' || message === 'request completed') {
|
|
22
|
+
return undefined
|
|
23
|
+
}
|
|
24
|
+
if (message.startsWith('Server listening at') || /^Route .* not found$/.test(message)) {
|
|
25
|
+
return 'debug'
|
|
26
|
+
}
|
|
27
|
+
return level
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* A pino-shaped logger over `@owlmeans/log`, handed to Fastify as its `loggerInstance`.
|
|
32
|
+
*
|
|
33
|
+
* Fastify then logs through the process's own level, format and plugins instead of a second pino
|
|
34
|
+
* instance that ignores them. `(object, message)` and `(message)` are the two shapes Fastify and
|
|
35
|
+
* its plugins call with; an `err` in the object travels as the record's error.
|
|
36
|
+
*/
|
|
37
|
+
export const fastifyLogger = (log: Logger = logger('http'), bindings?: Record<string, unknown>): FastifyBaseLogger => {
|
|
38
|
+
const call = (requested: Severity) => (first: unknown, second?: unknown): void => {
|
|
39
|
+
const [object, message] = typeof first === 'string' || first instanceof Error
|
|
40
|
+
? [undefined, first] : [first, second]
|
|
41
|
+
const level = levelOf(requested, message)
|
|
42
|
+
if (level == null) {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
const data = bindings != null && Object.keys(bindings).length > 0
|
|
46
|
+
? { ...bindings, ...(object != null && typeof object === 'object' ? object : {}) } : object
|
|
47
|
+
log[level](message == null ? '' : message instanceof Error ? message : String(message), data)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const adapter = {
|
|
51
|
+
get level(): string { return levelName(log) },
|
|
52
|
+
set level(_value: string) { /* the level belongs to the process, not to this server */ },
|
|
53
|
+
fatal: call('error'), error: call('error'), warn: call('warn'),
|
|
54
|
+
info: call('info'), debug: call('debug'), trace: call('debug'),
|
|
55
|
+
silent: () => undefined,
|
|
56
|
+
child: (extra: Record<string, unknown>) => fastifyLogger(log, { ...bindings, ...extra }),
|
|
57
|
+
}
|
|
58
|
+
return adapter as unknown as FastifyBaseLogger
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const levelName = (log: Logger): string => {
|
|
62
|
+
const order: LogLevel[] = ['debug', 'info', 'warn', 'error']
|
|
63
|
+
return order.find(level => log.enabled(level)) ?? 'silent'
|
|
64
|
+
}
|
package/src/utils/server.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { provideResponse } from '@owlmeans/entrypoint'
|
|
|
8
8
|
import type { ServerContext } from '@owlmeans/server-context'
|
|
9
9
|
import { ResilientError } from '@owlmeans/error'
|
|
10
10
|
import { OK } from '@owlmeans/api'
|
|
11
|
+
import { logger } from '@owlmeans/log'
|
|
11
12
|
import { errorExposure, handleError } from './error.js'
|
|
12
13
|
import { executeResponse, provideRequest } from './payload.js'
|
|
13
14
|
import { authorize } from './guards.js'
|
|
@@ -62,7 +63,7 @@ export const createServerHandler = (module: ServerEntrypoint<FastifyRequest>, lo
|
|
|
62
63
|
// neither `executeResponse` nor the handler itself (hijack) replied.
|
|
63
64
|
const responded = executeResponse(response, reply, true)
|
|
64
65
|
if (!responded && !reply.sent) {
|
|
65
|
-
|
|
66
|
+
logger('http').warn(`SENDS DEFAULT RESPONSE: ${module.alias}`)
|
|
66
67
|
reply.code(OK).send(response.value)
|
|
67
68
|
}
|
|
68
69
|
} catch (error) {
|
package/tests/handlers.spec.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { describe, expect, test } from 'bun:test'
|
|
|
2
2
|
import type { EntrypointProtocolDeclaration } from '@owlmeans/entrypoint'
|
|
3
3
|
import { handlers } from '../src/protocol.js'
|
|
4
4
|
import { HandlerMisconfiguredError } from '../src/errors.js'
|
|
5
|
+
import { addLogPlugin, memoryPlugin, removeLogPlugin } from '@owlmeans/log'
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* A protocol-bound implementation is run with the smallest binding context the transport needs —
|
|
@@ -64,9 +65,8 @@ describe('@owlmeans/server-api — handlers() wrap-once tolerance', () => {
|
|
|
64
65
|
const protocol = protocolFor('api.thing.warn-once')
|
|
65
66
|
const bound = api.request(protocol, async () => 'ok')
|
|
66
67
|
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
console.warn = (...args: unknown[]) => { warnings.push(args) }
|
|
68
|
+
const memory = memoryPlugin('handlers-warn')
|
|
69
|
+
addLogPlugin(memory)
|
|
70
70
|
try {
|
|
71
71
|
// Each call is a deliberate double wrap — the exact shape `tsc` rejects at the real call
|
|
72
72
|
// site (TS2345) — so it is exercised here through `any`, the same way `body`/`params`
|
|
@@ -75,9 +75,9 @@ describe('@owlmeans/server-api — handlers() wrap-once tolerance', () => {
|
|
|
75
75
|
(api as any).body(protocol, bound);
|
|
76
76
|
(api as any).params(protocol, bound)
|
|
77
77
|
} finally {
|
|
78
|
-
|
|
78
|
+
removeLogPlugin('handlers-warn')
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
expect(
|
|
81
|
+
expect(memory.records.filter(record => record.level === 'warn').length).toBe(1)
|
|
82
82
|
})
|
|
83
83
|
})
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from 'bun:test'
|
|
2
|
+
import { addLogPlugin, configureLog, memoryPlugin, resetLog } from '@owlmeans/log'
|
|
3
|
+
import { fastifyLogger } from '../src/utils/log.js'
|
|
4
|
+
|
|
5
|
+
const memory = memoryPlugin('adapter')
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
resetLog()
|
|
9
|
+
addLogPlugin(memory)
|
|
10
|
+
configureLog({ level: 'debug', console: 'native' })
|
|
11
|
+
})
|
|
12
|
+
afterEach(() => { memory.clear(); resetLog() })
|
|
13
|
+
|
|
14
|
+
describe('@owlmeans/server-api — the Fastify logger adapter', () => {
|
|
15
|
+
test('drops the request pair, lowers the listening and not-found lines, keeps the rest', () => {
|
|
16
|
+
const log = fastifyLogger() as unknown as Record<string, (...args: unknown[]) => void>
|
|
17
|
+
log.info({ req: {} }, 'incoming request')
|
|
18
|
+
log.info({ res: {} }, 'request completed')
|
|
19
|
+
log.info('Server listening at http://127.0.0.1:80')
|
|
20
|
+
log.info({ url: '/x' }, 'Route GET:/x not found')
|
|
21
|
+
log.info('something else')
|
|
22
|
+
log.warn({ a: 1 }, 'warned')
|
|
23
|
+
log.error({ err: new Error('boom') }, 'failed')
|
|
24
|
+
|
|
25
|
+
expect(memory.records.map(r => [r.level, r.message])).toEqual([
|
|
26
|
+
['debug', 'Server listening at http://127.0.0.1:80'],
|
|
27
|
+
['debug', 'Route GET:/x not found'],
|
|
28
|
+
['info', 'something else'],
|
|
29
|
+
['warn', 'warned'],
|
|
30
|
+
['error', 'failed'],
|
|
31
|
+
])
|
|
32
|
+
expect(memory.records[4].error?.message).toBe('boom')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test('child loggers bind their fields and the level is the process level', () => {
|
|
36
|
+
const base = fastifyLogger()
|
|
37
|
+
const child = (base as unknown as { child: (b: object) => Record<string, (...a: unknown[]) => void> }).child({ reqId: 'r1' })
|
|
38
|
+
child.warn('hello')
|
|
39
|
+
expect(memory.records[0].data).toEqual({ reqId: 'r1' })
|
|
40
|
+
expect(base.level).toBe('debug')
|
|
41
|
+
configureLog({ level: 'warn' })
|
|
42
|
+
expect(base.level).toBe('warn')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('at info level, debug lines are not written', () => {
|
|
46
|
+
configureLog({ level: 'info' })
|
|
47
|
+
const log = fastifyLogger() as unknown as Record<string, (...args: unknown[]) => void>
|
|
48
|
+
log.debug('quiet')
|
|
49
|
+
log.info('shown')
|
|
50
|
+
expect(memory.records.map(r => r.message)).toEqual(['shown'])
|
|
51
|
+
})
|
|
52
|
+
})
|