@nwire/koa 0.12.0 → 0.12.1

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.
Files changed (2) hide show
  1. package/dist/http-koa.js +34 -2
  2. package/package.json +7 -7
package/dist/http-koa.js CHANGED
@@ -35,6 +35,24 @@ import bodyParser from "koa-bodyparser";
35
35
  import cors from "@koa/cors";
36
36
  import helmet from "koa-helmet";
37
37
  import KoaRouter from "@koa/router";
38
+ /** Zod throws a `ZodError` (name + `issues[]`) on a failed `.parse()`. */
39
+ function isZodError(e) {
40
+ return (typeof e === "object" &&
41
+ e !== null &&
42
+ e.name === "ZodError" &&
43
+ Array.isArray(e.issues));
44
+ }
45
+ /**
46
+ * A human-readable summary of the first validation issue. Safe to expose:
47
+ * it describes the caller's own input, not internal state.
48
+ */
49
+ function zodSummary(e) {
50
+ const first = e.issues[0];
51
+ if (!first)
52
+ return "validation failed";
53
+ const path = (first.path ?? []).join(".") || "(body)";
54
+ return `${path}: ${first.message}`;
55
+ }
38
56
  function isHttpBinding(b) {
39
57
  return (typeof b === "object" &&
40
58
  b !== null &&
@@ -77,6 +95,15 @@ export function httpKoa(config = {}) {
77
95
  catch (err) {
78
96
  const e = err;
79
97
  const isNwireError = e?.$kind === "error";
98
+ if (isZodError(err)) {
99
+ // A schema `.parse()` that escaped the per-route catch (e.g. an
100
+ // action's own input schema). Validation failures are the
101
+ // caller's fault → 400 with a readable summary, never an opaque
102
+ // 500. The message is about their input, so it's safe to expose.
103
+ kctx.status = 400;
104
+ kctx.body = { error: { code: "validation_failed", summary: zodSummary(err) } };
105
+ return;
106
+ }
80
107
  kctx.status = typeof e.status === "number" ? e.status : 500;
81
108
  if (isNwireError) {
82
109
  kctx.body = {
@@ -249,7 +276,7 @@ export function httpKoa(config = {}) {
249
276
  kctx.body = {
250
277
  error: {
251
278
  code: "validation_failed",
252
- summary: err.message,
279
+ summary: isZodError(err) ? zodSummary(err) : err.message,
253
280
  },
254
281
  };
255
282
  return;
@@ -274,7 +301,12 @@ export function httpKoa(config = {}) {
274
301
  : (kc.request.headers["x-tenant"] ?? undefined));
275
302
  const envelopePartial = {
276
303
  tenant: resolveTenant(kctx),
277
- userId: kctx.state.userId ?? undefined,
304
+ // Prefer an explicit `state.userId`, but fall back to the
305
+ // user object's id so handlers reading `envelope.userId` work
306
+ // whenever auth middleware populated `state.user`.
307
+ userId: kctx.state.userId ??
308
+ kctx.state.user?.id ??
309
+ undefined,
278
310
  // Pass the full user object through when adopter auth middleware
279
311
  // populated it. Without this, transport-agnostic RBAC has to
280
312
  // reach into `ctx.koa.state.user` and couples the handler to
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nwire/koa",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
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.12.0",
37
- "@nwire/endpoint": "0.12.0",
38
- "@nwire/logger": "0.12.0",
39
- "@nwire/wires": "0.12.0"
36
+ "@nwire/endpoint": "0.12.1",
37
+ "@nwire/wires": "0.12.1",
38
+ "@nwire/logger": "0.12.1",
39
+ "@nwire/container": "0.12.1"
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.12.0",
51
- "@nwire/handler": "0.12.0"
50
+ "@nwire/app": "0.12.1",
51
+ "@nwire/handler": "0.12.1"
52
52
  },
53
53
  "peerDependencies": {
54
54
  "@asteasolutions/zod-to-openapi": "^8.0.0"