@nwire/koa 0.11.1 → 0.12.0
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/dist/http-koa.d.ts +14 -0
- package/dist/http-koa.js +24 -24
- package/package.json +7 -7
package/dist/http-koa.d.ts
CHANGED
|
@@ -60,6 +60,20 @@ export interface HttpKoaConfig {
|
|
|
60
60
|
* middleware running upstream).
|
|
61
61
|
*/
|
|
62
62
|
readonly reqId?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Echo raw thrown `Error.message` to the client for non-typed errors.
|
|
65
|
+
*
|
|
66
|
+
* Default `false` — a generic `throw new Error("…")` returns an opaque
|
|
67
|
+
* `{ code: "internal_error", summary: "Internal error" }` and the real
|
|
68
|
+
* message is logged server-side only. This is fail-safe: driver errors,
|
|
69
|
+
* connection strings, and PII attached to a stray throw never reach the
|
|
70
|
+
* client, in any environment.
|
|
71
|
+
*
|
|
72
|
+
* Set `true` in local dev to surface the message for debugging. Typed
|
|
73
|
+
* `defineError` values always render their own `{ code, summary }`
|
|
74
|
+
* regardless — those are author-defined and safe to expose.
|
|
75
|
+
*/
|
|
76
|
+
readonly exposeErrors?: boolean;
|
|
63
77
|
/**
|
|
64
78
|
* Tenant resolver. The dev/test default reads `x-tenant` from the
|
|
65
79
|
* request header — convenient for local multi-tenancy. Production
|
package/dist/http-koa.js
CHANGED
|
@@ -62,12 +62,14 @@ export function httpKoa(config = {}) {
|
|
|
62
62
|
const koa = new Koa();
|
|
63
63
|
koaInstance = koa;
|
|
64
64
|
const isProd = process.env.NODE_ENV === "production";
|
|
65
|
+
const exposeErrors = config.exposeErrors === true;
|
|
65
66
|
// Top-level error mapper — catches throws from middleware and
|
|
66
|
-
// unmatched routes.
|
|
67
|
-
// {code, status, summary}
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
67
|
+
// unmatched routes. Typed `defineError` values render their own
|
|
68
|
+
// {code, status, summary}. Generic (non-NwireError) throws return an
|
|
69
|
+
// opaque "internal_error" by default so a stray
|
|
70
|
+
// `throw new Error("DB password X")` cannot leak the message to
|
|
71
|
+
// clients — in any environment. `exposeErrors: true` (dev) echoes
|
|
72
|
+
// the message. The real error is always logged server-side.
|
|
71
73
|
koa.use(async (kctx, next) => {
|
|
72
74
|
try {
|
|
73
75
|
await next();
|
|
@@ -75,21 +77,18 @@ export function httpKoa(config = {}) {
|
|
|
75
77
|
catch (err) {
|
|
76
78
|
const e = err;
|
|
77
79
|
const isNwireError = e?.$kind === "error";
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (!isNwireError && isProd) {
|
|
81
|
-
// Server-side: log the full error so SRE can see it. Client:
|
|
82
|
-
// opaque body — no error.message leak.
|
|
83
|
-
logger.error?.(`[http-koa] unhandled error: ${e?.message ?? e}`, undefined);
|
|
80
|
+
kctx.status = typeof e.status === "number" ? e.status : 500;
|
|
81
|
+
if (isNwireError) {
|
|
84
82
|
kctx.body = {
|
|
85
|
-
error: { code: "internal_error", summary: "Internal error" },
|
|
83
|
+
error: { code: e.code ?? "internal_error", summary: e.summary ?? "Internal error" },
|
|
86
84
|
};
|
|
87
85
|
}
|
|
88
86
|
else {
|
|
87
|
+
logger.error?.(`[http-koa] unhandled error: ${e?.message ?? e}`, undefined);
|
|
89
88
|
kctx.body = {
|
|
90
89
|
error: {
|
|
91
|
-
code:
|
|
92
|
-
summary:
|
|
90
|
+
code: "internal_error",
|
|
91
|
+
summary: exposeErrors ? (e.message ?? "Internal error") : "Internal error",
|
|
93
92
|
},
|
|
94
93
|
};
|
|
95
94
|
}
|
|
@@ -309,25 +308,26 @@ export function httpKoa(config = {}) {
|
|
|
309
308
|
}
|
|
310
309
|
}
|
|
311
310
|
catch (err) {
|
|
312
|
-
// Generic error envelope.
|
|
313
|
-
//
|
|
314
|
-
//
|
|
315
|
-
//
|
|
316
|
-
//
|
|
311
|
+
// Generic error envelope. Typed `defineError` values surface
|
|
312
|
+
// their {code, status, summary}. Other throws return an opaque
|
|
313
|
+
// "internal_error" by default so a stray
|
|
314
|
+
// `throw new Error("DB password X")` cannot leak the message to
|
|
315
|
+
// clients — in any environment. `exposeErrors: true` (dev)
|
|
316
|
+
// echoes the message. The real error is always logged.
|
|
317
317
|
const e = err;
|
|
318
318
|
const isNwireError = e?.$kind === "error";
|
|
319
319
|
kctx.status = typeof e.status === "number" ? e.status : 500;
|
|
320
|
-
if (
|
|
321
|
-
logger.error?.(`[http-koa] unhandled error: ${e?.message ?? e}`, undefined);
|
|
320
|
+
if (isNwireError) {
|
|
322
321
|
kctx.body = {
|
|
323
|
-
error: { code: "internal_error", summary: "Internal error" },
|
|
322
|
+
error: { code: e.code ?? "internal_error", summary: e.summary ?? "Internal error" },
|
|
324
323
|
};
|
|
325
324
|
}
|
|
326
325
|
else {
|
|
326
|
+
logger.error?.(`[http-koa] unhandled error: ${e?.message ?? e}`, undefined);
|
|
327
327
|
kctx.body = {
|
|
328
328
|
error: {
|
|
329
|
-
code:
|
|
330
|
-
summary:
|
|
329
|
+
code: "internal_error",
|
|
330
|
+
summary: exposeErrors ? (e.message ?? "Internal error") : "Internal error",
|
|
331
331
|
},
|
|
332
332
|
};
|
|
333
333
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nwire/koa",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Nwire — Koa-backed HTTP adopter. Consumes wires from @nwire/wires/http and serves them as Koa routes under endpoint lifecycle.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adopter",
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"koa-bodyparser": "^4.4.1",
|
|
34
34
|
"koa-helmet": "^8.0.1",
|
|
35
35
|
"zod": "^4.0.0",
|
|
36
|
-
"@nwire/container": "0.
|
|
37
|
-
"@nwire/endpoint": "0.
|
|
38
|
-
"@nwire/logger": "0.
|
|
39
|
-
"@nwire/wires": "0.
|
|
36
|
+
"@nwire/container": "0.12.0",
|
|
37
|
+
"@nwire/endpoint": "0.12.0",
|
|
38
|
+
"@nwire/logger": "0.12.0",
|
|
39
|
+
"@nwire/wires": "0.12.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@asteasolutions/zod-to-openapi": "^8.0.0",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"@types/node": "^22.19.9",
|
|
48
48
|
"typescript": "^5.9.3",
|
|
49
49
|
"vitest": "^4.0.18",
|
|
50
|
-
"@nwire/app": "0.
|
|
51
|
-
"@nwire/handler": "0.
|
|
50
|
+
"@nwire/app": "0.12.0",
|
|
51
|
+
"@nwire/handler": "0.12.0"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"@asteasolutions/zod-to-openapi": "^8.0.0"
|