@quilla-be-kit/http 0.5.0 → 0.6.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.
Files changed (55) hide show
  1. package/README.md +96 -2
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/adapter/hono/hono-request.adapter.d.ts +4 -1
  4. package/dist/adapter/hono/hono-request.adapter.d.ts.map +1 -1
  5. package/dist/adapter/hono/hono-request.adapter.js +20 -21
  6. package/dist/adapter/hono/hono-request.adapter.js.map +1 -1
  7. package/dist/adapter/hono/hono.server.d.ts +3 -0
  8. package/dist/adapter/hono/hono.server.d.ts.map +1 -1
  9. package/dist/adapter/hono/hono.server.js +7 -3
  10. package/dist/adapter/hono/hono.server.js.map +1 -1
  11. package/dist/decorator/controller.decorator.d.ts.map +1 -1
  12. package/dist/decorator/controller.decorator.js +1 -3
  13. package/dist/decorator/controller.decorator.js.map +1 -1
  14. package/dist/decorator/route.metadata.d.ts +1 -1
  15. package/dist/decorator/route.metadata.d.ts.map +1 -1
  16. package/dist/decorator/route.metadata.js +2 -0
  17. package/dist/decorator/route.metadata.js.map +1 -1
  18. package/dist/error/default.resolver.d.ts +6 -0
  19. package/dist/error/default.resolver.d.ts.map +1 -0
  20. package/dist/error/default.resolver.js +45 -0
  21. package/dist/error/default.resolver.js.map +1 -0
  22. package/dist/error/{resolve-http-error.d.ts → error-resolver.interface.d.ts} +4 -2
  23. package/dist/error/error-resolver.interface.d.ts.map +1 -0
  24. package/dist/error/error-resolver.interface.js +2 -0
  25. package/dist/error/error-resolver.interface.js.map +1 -0
  26. package/dist/error/index.d.ts +2 -1
  27. package/dist/error/index.d.ts.map +1 -1
  28. package/dist/error/index.js +1 -1
  29. package/dist/error/index.js.map +1 -1
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +1 -0
  33. package/dist/index.js.map +1 -1
  34. package/dist/request/default.serializer.d.ts +6 -0
  35. package/dist/request/default.serializer.d.ts.map +1 -0
  36. package/dist/request/default.serializer.js +7 -0
  37. package/dist/request/default.serializer.js.map +1 -0
  38. package/dist/request/index.d.ts +2 -0
  39. package/dist/request/index.d.ts.map +1 -1
  40. package/dist/request/index.js +1 -0
  41. package/dist/request/index.js.map +1 -1
  42. package/dist/request/response-serializer.interface.d.ts +5 -0
  43. package/dist/request/response-serializer.interface.d.ts.map +1 -0
  44. package/dist/request/response-serializer.interface.js +2 -0
  45. package/dist/request/response-serializer.interface.js.map +1 -0
  46. package/dist/server/http-conventions.type.d.ts +7 -0
  47. package/dist/server/http-conventions.type.d.ts.map +1 -0
  48. package/dist/server/http-conventions.type.js +2 -0
  49. package/dist/server/http-conventions.type.js.map +1 -0
  50. package/dist/server/index.d.ts +1 -0
  51. package/dist/server/index.d.ts.map +1 -1
  52. package/package.json +3 -3
  53. package/dist/error/resolve-http-error.d.ts.map +0 -1
  54. package/dist/error/resolve-http-error.js +0 -43
  55. package/dist/error/resolve-http-error.js.map +0 -1
package/README.md CHANGED
@@ -248,7 +248,7 @@ async create(req: HttpRequest): Promise<HttpResponse> {
248
248
  }
249
249
  ```
250
250
 
251
- On validation failure, throws `ValidationError` with `context.issues` containing the validator's raw error array (e.g. Zod issues, Joi details). `resolveHttpError` surfaces this as a 400 response with `body.error.details.issues`.
251
+ On validation failure, throws `ValidationError` with `context.issues` containing the validator's raw error array (e.g. Zod issues, Joi details). The default error resolver (`DefaultErrorResolver`) surfaces this as a 400 response with `body.error.details.issues`. See [Response and error conventions](#response-and-error-conventions) to override the wire shape.
252
252
 
253
253
  ## Multipart / form-data
254
254
 
@@ -320,7 +320,7 @@ async export(req: HttpRequest): Promise<HttpStreamResponse> {
320
320
 
321
321
  **The real tradeoff is that binary responses lose the envelope convention — no `payload` / `metadata` wrapper around the bytes, and middleware can't introspect stream contents post-hoc.** That's intrinsic to streaming, not a flaw: logging, response shaping, and validators that read response bodies all become no-ops on the binary path. You're opting out of the standard JSON shape so the framework can hand bytes directly to the socket.
322
322
 
323
- Error handling caveat: a handler that throws **before** producing the response still goes through `resolveHttpError` and emits a normal JSON error envelope. A handler that throws **mid-stream** — after the response status is already committed — aborts the connection; the client sees a truncated body, not a JSON error.
323
+ Error handling caveat: a handler that throws **before** producing the response still goes through the configured error resolver (`DefaultErrorResolver` by default) and emits a normal JSON error envelope. A handler that throws **mid-stream** — after the response status is already committed — aborts the connection; the client sees a truncated body, not a JSON error.
324
324
 
325
325
  ## `RequestValidator` adapter
326
326
 
@@ -500,6 +500,7 @@ const server = new HonoServer({
500
500
  router, // HonoServer reads the execution-context provider from Router
501
501
  requestValidator, // optional — required only if any route uses @ValidateRequest
502
502
  logger, // optional — used for startup/shutdown/error logs
503
+ conventions, // optional — override the error / success wire shapes (see below)
503
504
  serve: honoServe,
504
505
  });
505
506
  ```
@@ -536,6 +537,99 @@ Defaults applied when `cors` is set:
536
537
 
537
538
  If you need non-default values, omit `cors` and wire `hono/cors` yourself inside the `serve` callback, or raise an issue.
538
539
 
540
+ ### Response and error conventions
541
+
542
+ The success/envelope shape and the error shape are both consumer-overridable through the
543
+ optional `conventions` facade on `HonoServer`. It groups two strategies, each defaulting to a
544
+ class that reproduces the built-in wire shape byte-for-byte — omit `conventions` and nothing
545
+ changes.
546
+
547
+ ```ts
548
+ type HttpConventions = {
549
+ readonly errorResolver?: ErrorResolver; // controls the error status + body
550
+ readonly responseSerializer?: ResponseSerializer; // controls the JSON success/envelope body
551
+ };
552
+
553
+ interface ErrorResolver {
554
+ resolve(err: unknown): ResolvedHttpError; // { httpCode, body }
555
+ }
556
+ interface ResponseSerializer {
557
+ serialize(response: HttpJsonResponse): unknown; // return the wire body, or undefined for no body
558
+ }
559
+ ```
560
+
561
+ Defaults are exported so a custom strategy can delegate to them: `DefaultErrorResolver` (the
562
+ status mapping — `ValidationError` → 400, `NotFoundError` → 404, …) and `DefaultResponseSerializer`
563
+ (strips `httpCode`/`headers`, keeps `payload` / `error` / `metadata`, and returns `undefined`
564
+ for an empty body so it becomes a bodyless response).
565
+
566
+ **Custom error format** — e.g. RFC 7807 Problem Details, reusing the default status mapping:
567
+
568
+ ```ts
569
+ import {
570
+ DefaultErrorResolver,
571
+ type ErrorResolver,
572
+ type ResolvedHttpError,
573
+ } from '@quilla-be-kit/http';
574
+
575
+ class ProblemDetailsResolver implements ErrorResolver {
576
+ private readonly base = new DefaultErrorResolver();
577
+
578
+ resolve(err: unknown): ResolvedHttpError {
579
+ const { httpCode, body } = this.base.resolve(err); // reuse status mapping
580
+ return {
581
+ httpCode,
582
+ body: {
583
+ error: {
584
+ name: 'about:blank',
585
+ message: body.error?.message ?? 'Error',
586
+ details: { status: httpCode, ...(body.error?.details ?? {}) },
587
+ },
588
+ },
589
+ };
590
+ }
591
+ }
592
+
593
+ const server = new HonoServer({
594
+ port: 3000,
595
+ router,
596
+ serve: honoServe,
597
+ conventions: { errorResolver: new ProblemDetailsResolver() },
598
+ });
599
+ ```
600
+
601
+ **Custom success envelope** — e.g. rename `payload` → `data` and lift pagination to the top level:
602
+
603
+ ```ts
604
+ import {
605
+ type HttpJsonResponse,
606
+ type ResponseSerializer,
607
+ } from '@quilla-be-kit/http';
608
+
609
+ class DataEnvelopeSerializer implements ResponseSerializer {
610
+ serialize(r: HttpJsonResponse): unknown {
611
+ if (r.error) return { error: r.error };
612
+ if (r.payload === undefined) return undefined; // preserve the bodyless-response branch
613
+ const p = r.metadata?.pagination;
614
+ return {
615
+ data: r.payload,
616
+ ...(p ? { pagination: { page: p.page, perPage: p.limit, total: p.total } } : {}),
617
+ };
618
+ }
619
+ }
620
+
621
+ const server = new HonoServer({
622
+ port: 3000,
623
+ router,
624
+ serve: honoServe,
625
+ conventions: { responseSerializer: new DataEnvelopeSerializer() },
626
+ });
627
+ ```
628
+
629
+ The binary/stream response paths never touch the serializer — they still write bytes directly.
630
+ On the frontend, `@quilla-fe-kit/api-client-react-query` reconciles a custom envelope with a
631
+ `queryTransformer`, and `@quilla-fe-kit/api-client` a custom error shape with an `errorParser`.
632
+
539
633
  ## Other frameworks
540
634
 
541
635
  If you need Express or Fastify: open an issue. Adapter sub-paths ship as library additions when they exist, not as consumer extension points.