@voyant-travel/hono 0.117.0 → 0.117.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/dist/app.d.ts CHANGED
@@ -1,10 +1,22 @@
1
1
  import type { Hono } from "hono";
2
+ import { type LazyRoutesLoader } from "./lazy-routes.js";
2
3
  import type { VoyantAppConfig, VoyantBindings, VoyantVariables } from "./types.js";
3
4
  /** The composed app's Hono env (bindings + framework request variables). */
4
5
  type MountEnv<TBindings extends VoyantBindings> = {
5
6
  Bindings: TBindings;
6
7
  Variables: VoyantVariables;
7
8
  };
9
+ /**
10
+ * A lazy route family recorded at mount time so a build-time OpenAPI generator
11
+ * can eager-load it and merge its `.openapi()` operations (voyant#2114). Mirrors
12
+ * `LazyMount` in `./openapi.ts` (kept structurally identical, but declared here
13
+ * to avoid pulling the build-time-only openapi module into the runtime path).
14
+ */
15
+ export interface LazyMount {
16
+ /** Absolute surface mount prefix, or `"/"` for absolute `lazyRoutes`. */
17
+ prefix: string;
18
+ load: LazyRoutesLoader;
19
+ }
8
20
  /**
9
21
  * App handle returned alongside the Hono instance. Carries `ready()` for
10
22
  * headless / sibling-process deployments that need to fire the lazy
@@ -40,6 +52,13 @@ export interface VoyantAppExtensions<TBindings = unknown> {
40
52
  * await withDbFromEnv(env, (db) => drainOutbox(db, app.eventBus))
41
53
  */
42
54
  eventBus: import("@voyant-travel/core").EventBus;
55
+ /**
56
+ * Lazy route families recorded at mount time (the wildcard dispatch stubs in
57
+ * `lazy-routes.ts` don't reach the composed `OpenAPIHono` registry). A
58
+ * build-time OpenAPI generator reads this to eager-load + merge their
59
+ * `.openapi()` operations via `mergeLazyOpenApiPaths`. Never read at runtime.
60
+ */
61
+ lazyMounts: LazyMount[];
43
62
  }
44
63
  /**
45
64
  * Low-level app factory: given an already-resolved `modules`/`extensions` set
package/dist/app.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAkChC,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAY,eAAe,EAAE,MAAM,YAAY,CAAA;AAI5F,4EAA4E;AAC5E,KAAK,QAAQ,CAAC,SAAS,SAAS,cAAc,IAAI;IAChD,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,EAAE,eAAe,CAAA;CAC3B,CAAA;AAuBD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,mBAAmB,CAAC,SAAS,GAAG,OAAO;IACtD;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1C;;;;;;;;OAQG;IACH,QAAQ,EAAE,OAAO,qBAAqB,EAAE,QAAQ,CAAA;CACjD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,SAAS,SAAS,cAAc,EACvD,MAAM,EAAE,eAAe,CAAC,SAAS,CAAC,GACjC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAue5D"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAQhC,OAAO,EAAE,KAAK,gBAAgB,EAA0C,MAAM,kBAAkB,CAAA;AA8BhG,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAY,eAAe,EAAE,MAAM,YAAY,CAAA;AAI5F,4EAA4E;AAC5E,KAAK,QAAQ,CAAC,SAAS,SAAS,cAAc,IAAI;IAChD,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,EAAE,eAAe,CAAA;CAC3B,CAAA;AAuBD;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,gBAAgB,CAAA;CACvB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,mBAAmB,CAAC,SAAS,GAAG,OAAO;IACtD;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1C;;;;;;;;OAQG;IACH,QAAQ,EAAE,OAAO,qBAAqB,EAAE,QAAQ,CAAA;IAChD;;;;;OAKG;IACH,UAAU,EAAE,SAAS,EAAE,CAAA;CACxB;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,SAAS,SAAS,cAAc,EACvD,MAAM,EAAE,eAAe,CAAC,SAAS,CAAC,GACjC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,GAAG,mBAAmB,CAAC,SAAS,CAAC,CA2f5D"}
package/dist/app.js CHANGED
@@ -12,7 +12,7 @@ import { tryGetExecutionCtx } from "./lib/execution-ctx.js";
12
12
  import { matchesPublicPath, normalizePathname } from "./lib/public-paths.js";
13
13
  import { requestScopedEventBus } from "./lib/request-event-bus.js";
14
14
  import { requireAuth } from "./middleware/auth.js";
15
- import { DEFAULT_REQUEST_BODY_LIMIT_BYTES, requestBodyLimit } from "./middleware/body-size.js";
15
+ import { DEFAULT_REQUEST_BODY_LIMIT_BYTES, MAX_GLOBAL_REQUEST_BODY_BYTES, requestBodyLimit, } from "./middleware/body-size.js";
16
16
  import { cors } from "./middleware/cors.js";
17
17
  import { db } from "./middleware/db.js";
18
18
  import { handleApiError, requestId } from "./middleware/error-boundary.js";
@@ -225,7 +225,12 @@ export function mountApp(config) {
225
225
  }
226
226
  if (config.requestBodyLimit !== false) {
227
227
  app.use("*", requestBodyLimit({
228
- maxBytes: config.requestBodyLimit?.maxBytes ?? DEFAULT_REQUEST_BODY_LIMIT_BYTES,
228
+ // Outer ceiling sized to the largest legitimate body (uploads); the
229
+ // upload route enforces its own 25 MiB cap. See MAX_GLOBAL_REQUEST_BODY_BYTES.
230
+ maxBytes: config.requestBodyLimit?.maxBytes ?? MAX_GLOBAL_REQUEST_BODY_BYTES,
231
+ // JSON bodies keep the tighter 10 MiB cap (matching parseJsonBody) so
232
+ // migrated `.openapi()` routes aren't loosened to the upload ceiling.
233
+ jsonMaxBytes: config.requestBodyLimit?.jsonMaxBytes ?? DEFAULT_REQUEST_BODY_LIMIT_BYTES,
229
234
  }));
230
235
  }
231
236
  if (config.rateLimit !== false) {
@@ -416,6 +421,13 @@ export function mountApp(config) {
416
421
  scopes: c.get("scopes"),
417
422
  }));
418
423
  }
424
+ // Lazy route families recorded for build-time OpenAPI merging. The wildcard
425
+ // dispatch stubs registered by `mountLazyRoutesAt`/`mountLazyRoutePaths` never
426
+ // reach the composed OpenAPIHono registry, so the spec generator replays these
427
+ // loaders (see `mergeLazyOpenApiPaths`). Recorded in the same loop that mounts
428
+ // them so the prefix logic is single-sourced here. Cheap array pushes — no
429
+ // eager `import()` and no runtime read.
430
+ const lazyMounts = [];
419
431
  // Mount module routes
420
432
  for (const mod of allModules) {
421
433
  const adminPrefix = `/v1/admin/${mod.module.name}`;
@@ -428,12 +440,15 @@ export function mountApp(config) {
428
440
  }
429
441
  if (mod.lazyAdminRoutes) {
430
442
  mountLazyRoutesAt(app, adminPrefix, mod.lazyAdminRoutes);
443
+ lazyMounts.push({ prefix: adminPrefix, load: mod.lazyAdminRoutes });
431
444
  }
432
445
  if (mod.lazyPublicRoutes) {
433
446
  mountLazyRoutesAt(app, publicPrefix, mod.lazyPublicRoutes);
447
+ lazyMounts.push({ prefix: publicPrefix, load: mod.lazyPublicRoutes });
434
448
  }
435
449
  if (mod.lazyRoutes) {
436
450
  mountLazyRoutePaths(app, mod.lazyRoutes.paths, mod.lazyRoutes.load);
451
+ lazyMounts.push({ prefix: "/", load: mod.lazyRoutes.load });
437
452
  }
438
453
  if (mod.routes) {
439
454
  app.route(`/v1/${mod.module.name}`, mod.routes);
@@ -451,12 +466,15 @@ export function mountApp(config) {
451
466
  }
452
467
  if (ext.lazyAdminRoutes) {
453
468
  mountLazyRoutesAt(app, adminPrefix, ext.lazyAdminRoutes);
469
+ lazyMounts.push({ prefix: adminPrefix, load: ext.lazyAdminRoutes });
454
470
  }
455
471
  if (ext.lazyPublicRoutes) {
456
472
  mountLazyRoutesAt(app, publicPrefix, ext.lazyPublicRoutes);
473
+ lazyMounts.push({ prefix: publicPrefix, load: ext.lazyPublicRoutes });
457
474
  }
458
475
  if (ext.lazyRoutes) {
459
476
  mountLazyRoutePaths(app, ext.lazyRoutes.paths, ext.lazyRoutes.load);
477
+ lazyMounts.push({ prefix: "/", load: ext.lazyRoutes.load });
460
478
  }
461
479
  if (ext.routes) {
462
480
  app.route(`/v1/${ext.extension.module}`, ext.routes);
@@ -476,6 +494,7 @@ export function mountApp(config) {
476
494
  // the real `env`.
477
495
  const augmented = app;
478
496
  augmented.eventBus = eventBus;
497
+ augmented.lazyMounts = lazyMounts;
479
498
  augmented.ready = (bindings) => ensureRuntimeBootstrapped(bindings ?? {});
480
499
  return augmented;
481
500
  }
@@ -1,7 +1,25 @@
1
1
  import type { MiddlewareHandler } from "hono";
2
2
  export interface RequestBodyLimitOptions {
3
+ /** Outer ceiling applied to non-JSON bodies (e.g. multipart uploads). */
3
4
  maxBytes: number;
5
+ /**
6
+ * Tighter cap applied when the request `Content-Type` is `application/json`.
7
+ * When omitted, the outer `maxBytes` ceiling applies to JSON bodies too.
8
+ */
9
+ jsonMaxBytes?: number;
4
10
  }
5
11
  export declare const DEFAULT_REQUEST_BODY_LIMIT_BYTES: number;
12
+ /**
13
+ * App-wide OUTER ceiling for the global `requestBodyLimit` mount. It must be at
14
+ * least the largest body any legitimate route accepts so the global stream cap
15
+ * never rejects valid traffic — the media upload route allows a 25 MiB file in a
16
+ * multipart envelope (`MAX_MULTIPART_UPLOAD_BYTES` = 25 MiB + 1 MiB in
17
+ * `@voyant-travel/storage`). Finer limits stay per-route: `parseJsonBody`/
18
+ * `readBoundedRequestText` keep the tighter `DEFAULT_REQUEST_BODY_LIMIT_BYTES`
19
+ * (10 MiB) for JSON, and the upload route enforces its own 25 MiB cap. Raising
20
+ * the global guard to a header-only check would reopen the no-Content-Length
21
+ * hole; lowering it below this would reject valid uploads (voyant#2114).
22
+ */
23
+ export declare const MAX_GLOBAL_REQUEST_BODY_BYTES: number;
6
24
  export declare function requestBodyLimit(options: RequestBodyLimitOptions): MiddlewareHandler;
7
25
  //# sourceMappingURL=body-size.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"body-size.d.ts","sourceRoot":"","sources":["../../src/middleware/body-size.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAE7C,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,eAAO,MAAM,gCAAgC,QAAmB,CAAA;AAEhE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,iBAAiB,CAuBpF"}
1
+ {"version":3,"file":"body-size.d.ts","sourceRoot":"","sources":["../../src/middleware/body-size.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAGtD,MAAM,WAAW,uBAAuB;IACtC,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAOD,eAAO,MAAM,gCAAgC,QAAmB,CAAA;AAEhE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,6BAA6B,QAAmB,CAAA;AAE7D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,iBAAiB,CAsCpF"}
@@ -1,20 +1,59 @@
1
+ import { bodyLimit } from "hono/body-limit";
2
+ // Mirrors Hono's own `jsonRegex` (hono/dist/validator/validator.js) and the
3
+ // openApiValidationHook content-type guard EXACTLY — case-sensitive, strict
4
+ // params — so "this matches" ⟺ "Hono parses the body as JSON". Keep in sync.
5
+ const JSON_CONTENT_TYPE = /^application\/([a-z-.]+\+)?json(;\s*[a-zA-Z0-9-]+=([^;]+))*$/;
1
6
  export const DEFAULT_REQUEST_BODY_LIMIT_BYTES = 10 * 1024 * 1024;
7
+ /**
8
+ * App-wide OUTER ceiling for the global `requestBodyLimit` mount. It must be at
9
+ * least the largest body any legitimate route accepts so the global stream cap
10
+ * never rejects valid traffic — the media upload route allows a 25 MiB file in a
11
+ * multipart envelope (`MAX_MULTIPART_UPLOAD_BYTES` = 25 MiB + 1 MiB in
12
+ * `@voyant-travel/storage`). Finer limits stay per-route: `parseJsonBody`/
13
+ * `readBoundedRequestText` keep the tighter `DEFAULT_REQUEST_BODY_LIMIT_BYTES`
14
+ * (10 MiB) for JSON, and the upload route enforces its own 25 MiB cap. Raising
15
+ * the global guard to a header-only check would reopen the no-Content-Length
16
+ * hole; lowering it below this would reject valid uploads (voyant#2114).
17
+ */
18
+ export const MAX_GLOBAL_REQUEST_BODY_BYTES = 26 * 1024 * 1024;
2
19
  export function requestBodyLimit(options) {
20
+ // Hono's bodyLimit checks the Content-Length header AND wraps the request body
21
+ // stream so it throws once the actual read exceeds maxSize. That stream cap is
22
+ // what bounds chunked / HTTP/2 requests with no Content-Length header — the
23
+ // case the previous header-only check could not catch (e.g. `.openapi()` json
24
+ // routes that read via c.req.json() and never went through parseJsonBody).
25
+ const enforceDefault = bodyLimit({
26
+ maxSize: options.maxBytes,
27
+ onError: (c) => tooLargeResponse(c, options.maxBytes),
28
+ });
29
+ // JSON bodies keep the tighter cap that `parseJsonBody` historically enforced
30
+ // (10 MiB) so migrated `.openapi()` routes aren't loosened to the upload
31
+ // ceiling. Non-JSON bodies (uploads) get the outer `maxBytes`. (voyant#2114)
32
+ // Clamp to `maxBytes` so the JSON cap is never LOOSER than the outer ceiling —
33
+ // a deployment that tightens `maxBytes` below the JSON default (e.g. a 1 MiB
34
+ // global override) must also tighten JSON, not silently leave it at 10 MiB.
35
+ const jsonMaxBytes = options.jsonMaxBytes != null ? Math.min(options.jsonMaxBytes, options.maxBytes) : null;
36
+ const enforceJson = jsonMaxBytes != null
37
+ ? bodyLimit({
38
+ maxSize: jsonMaxBytes,
39
+ onError: (c) => tooLargeResponse(c, jsonMaxBytes),
40
+ })
41
+ : null;
3
42
  return async (c, next) => {
4
43
  if (c.req.method === "GET" || c.req.method === "HEAD" || c.req.method === "OPTIONS") {
5
44
  return next();
6
45
  }
7
- const contentLength = c.req.header("content-length");
8
- if (contentLength) {
9
- const size = Number(contentLength);
10
- if (Number.isFinite(size) && size > options.maxBytes) {
11
- return c.json({
12
- error: "Request body too large",
13
- code: "request_body_too_large",
14
- maxBytes: options.maxBytes,
15
- }, 413);
16
- }
46
+ const contentType = c.req.header("content-type");
47
+ if (enforceJson && contentType && JSON_CONTENT_TYPE.test(contentType)) {
48
+ return enforceJson(c, next);
17
49
  }
18
- return next();
50
+ return enforceDefault(c, next);
19
51
  };
20
52
  }
53
+ function tooLargeResponse(c, maxBytes) {
54
+ return c.json({
55
+ error: "Request body too large",
56
+ code: "request_body_too_large",
57
+ maxBytes,
58
+ }, 413);
59
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"openapi-validation.d.ts","sourceRoot":"","sources":["../src/openapi-validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AAG7C;;;;;;;;;;;;;;;;GAgBG;AAIH,eAAO,MAAM,qBAAqB,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,CAI9D,CAAA"}
1
+ {"version":3,"file":"openapi-validation.d.ts","sourceRoot":"","sources":["../src/openapi-validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AAG7C;;;;;;;;;;;;;;;;GAgBG;AAIH,eAAO,MAAM,qBAAqB,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,CAoB9D,CAAA"}
@@ -19,7 +19,23 @@ import { normalizeValidationError, RequestValidationError } from "./validation.j
19
19
  // Typed as the library's own `defaultHook` shape (`Hook<any, E, any, any>`) so
20
20
  // it stays assignable for every module's specific `OpenAPIHono<Env>`.
21
21
  // biome-ignore lint/suspicious/noExplicitAny: matches @hono/zod-openapi's defaultHook signature
22
- export const openApiValidationHook = (result) => {
22
+ export const openApiValidationHook = (result, c) => {
23
+ // Hono's json validator yields `{}` (not a parse) when the request's
24
+ // content-type isn't one its parser accepts; partial PATCH schemas then
25
+ // validate `{}` and silently no-op. Enforce the content-type the route's
26
+ // contract declares so a missing/unaccepted header is a clean invalid_request
27
+ // 400 (voyant#2114, §16). The pattern MIRRORS Hono's own `jsonRegex`
28
+ // (hono/dist/validator/validator.js) EXACTLY — case-sensitive, strict params —
29
+ // so "this guard accepts" ⟺ "Hono parses the body". A laxer check (e.g. a
30
+ // case-insensitive match or a bare trailing `;`) would admit content-types
31
+ // Hono leaves unparsed, reintroducing the silent no-op. Keep in sync with Hono.
32
+ if (result.target === "json") {
33
+ const contentType = c.req.header("content-type");
34
+ const jsonContentType = /^application\/([a-z-.]+\+)?json(;\s*[a-zA-Z0-9-]+=([^;]+))*$/;
35
+ if (!contentType || !jsonContentType.test(contentType)) {
36
+ throw new RequestValidationError("Expected request Content-Type: application/json");
37
+ }
38
+ }
23
39
  if (!result.success) {
24
40
  throw normalizeValidationError(result.error) ?? new RequestValidationError("Invalid request");
25
41
  }
package/dist/openapi.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import type { OpenAPIHono } from "@hono/zod-openapi";
1
+ import { OpenAPIHono } from "@hono/zod-openapi";
2
2
  import type { Hono } from "hono";
3
+ import type { LazyRoutesLoader } from "./lazy-routes.js";
3
4
  /**
4
5
  * OpenAPI document generation for composed Voyant apps (voyant#2114).
5
6
  *
@@ -54,5 +55,36 @@ export type ApiSurface = "admin" | "storefront";
54
55
  * over-include shared component schemas, which is harmless).
55
56
  */
56
57
  export declare function selectSurface(doc: OpenApiDocument, surface: ApiSurface): OpenApiDocument;
58
+ /**
59
+ * A lazy-mounted route family recorded by `mountApp` for build-time spec
60
+ * merging. `prefix` is the absolute surface mount (`/v1/admin/<name>`,
61
+ * `/v1/public/...`) for relative-route loaders, or `"/"` for absolute
62
+ * `lazyRoutes` loaders. `load` is the same loader the runtime dispatcher caches
63
+ * — it constructs (but does not serve) the sub-app via `import(...)`.
64
+ */
65
+ export interface LazyMount {
66
+ prefix: string;
67
+ load: LazyRoutesLoader;
68
+ }
69
+ /**
70
+ * Eager-merge lazy route families into a generated base document (voyant#2114).
71
+ *
72
+ * Lazy families mount at runtime as wildcard dispatch stubs (see
73
+ * `lazy-routes.ts`), so their `.openapi()` operations never reach the composed
74
+ * `OpenAPIHono` registry and are invisible to `generateOpenApiDocument`. This
75
+ * runs each loader at build time, and for any that return an `OpenAPIHono`,
76
+ * re-mounts it into a throwaway `OpenAPIHono` at its real prefix — reusing the
77
+ * exact prefix-merge semantics `OpenAPIHono.route(...)` applies to eager mounts
78
+ * — then shallow-merges the resulting `paths` + `components.*` into `base`.
79
+ *
80
+ * Plain `Hono` sub-apps (no `.openapi()` routes) carry no registry and are
81
+ * skipped without error. A loader that throws is skipped with a warning so one
82
+ * bad family can't break generation. `base` wins on path/component collisions
83
+ * (which shouldn't happen given distinct prefixes), with a dev-time warning.
84
+ *
85
+ * Build-time only — same module-level constraint as the rest of this file
86
+ * (`@asteasolutions/zod-to-openapi` stays out of the Worker bundle).
87
+ */
88
+ export declare function mergeLazyOpenApiPaths(base: OpenApiDocument, mounts: readonly LazyMount[], options: GenerateOpenApiOptions): Promise<OpenApiDocument>;
57
89
  export {};
58
90
  //# sourceMappingURL=openapi.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAEhC;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,8EAA8E;IAC9E,CAAC,SAAS,EAAE,KAAK,MAAM,EAAE,GAAG,OAAO,CAAA;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,CAAC,SAAS,EAAE,KAAK,MAAM,EAAE,GAAG,OAAO,CAAA;CACpC;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,WAAW,CAAA;IACjB,OAAO,CAAC,EAAE,aAAa,EAAE,CAAA;CAC1B;AAGD,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;AAEjC;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,WAAW,CAAC,sBAAsB,CAAC,CAAC,CAAA;AAE7E;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,sBAAsB,GAC9B,eAAe,CASjB;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,YAAY,CAAA;AAO/C;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,EAAE,UAAU,GAAG,eAAe,CAMxF"}
1
+ {"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAEhC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAExD;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,8EAA8E;IAC9E,CAAC,SAAS,EAAE,KAAK,MAAM,EAAE,GAAG,OAAO,CAAA;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,CAAC,SAAS,EAAE,KAAK,MAAM,EAAE,GAAG,OAAO,CAAA;CACpC;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,WAAW,CAAA;IACjB,OAAO,CAAC,EAAE,aAAa,EAAE,CAAA;CAC1B;AAGD,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;AAEjC;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,WAAW,CAAC,sBAAsB,CAAC,CAAC,CAAA;AAE7E;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,sBAAsB,GAC9B,eAAe,CASjB;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,YAAY,CAAA;AAO/C;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,EAAE,UAAU,GAAG,eAAe,CAMxF;AAED;;;;;;GAMG;AACH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,gBAAgB,CAAA;CACvB;AAYD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,eAAe,EACrB,MAAM,EAAE,SAAS,SAAS,EAAE,EAC5B,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,eAAe,CAAC,CA8D1B"}
package/dist/openapi.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { OpenAPIHono } from "@hono/zod-openapi";
1
2
  /**
2
3
  * Generate a single OpenAPI 3.1 document covering every `.openapi()` route
3
4
  * mounted on the composed app, with module base paths already merged in
@@ -28,3 +29,86 @@ export function selectSurface(doc, surface) {
28
29
  const paths = Object.fromEntries(Object.entries(doc.paths ?? {}).filter(([path]) => path.startsWith(prefix)));
29
30
  return { ...doc, paths };
30
31
  }
32
+ /** Detect an `OpenAPIHono` sub-app (carries the `.openapi()` route registry). */
33
+ function isOpenApiHono(value) {
34
+ return (typeof value === "object" &&
35
+ value !== null &&
36
+ typeof value.getOpenAPI31Document === "function" &&
37
+ "openAPIRegistry" in value);
38
+ }
39
+ /**
40
+ * Eager-merge lazy route families into a generated base document (voyant#2114).
41
+ *
42
+ * Lazy families mount at runtime as wildcard dispatch stubs (see
43
+ * `lazy-routes.ts`), so their `.openapi()` operations never reach the composed
44
+ * `OpenAPIHono` registry and are invisible to `generateOpenApiDocument`. This
45
+ * runs each loader at build time, and for any that return an `OpenAPIHono`,
46
+ * re-mounts it into a throwaway `OpenAPIHono` at its real prefix — reusing the
47
+ * exact prefix-merge semantics `OpenAPIHono.route(...)` applies to eager mounts
48
+ * — then shallow-merges the resulting `paths` + `components.*` into `base`.
49
+ *
50
+ * Plain `Hono` sub-apps (no `.openapi()` routes) carry no registry and are
51
+ * skipped without error. A loader that throws is skipped with a warning so one
52
+ * bad family can't break generation. `base` wins on path/component collisions
53
+ * (which shouldn't happen given distinct prefixes), with a dev-time warning.
54
+ *
55
+ * Build-time only — same module-level constraint as the rest of this file
56
+ * (`@asteasolutions/zod-to-openapi` stays out of the Worker bundle).
57
+ */
58
+ export async function mergeLazyOpenApiPaths(base, mounts, options) {
59
+ const throwaway = new OpenAPIHono();
60
+ let mergedAny = false;
61
+ for (const { prefix, load } of mounts) {
62
+ let subApp;
63
+ try {
64
+ subApp = await load();
65
+ }
66
+ catch (error) {
67
+ const message = error instanceof Error ? error.message : String(error);
68
+ console.warn(`[voyant] openapi: lazy loader for "${prefix}" failed, skipping: ${message}`);
69
+ continue;
70
+ }
71
+ if (!isOpenApiHono(subApp)) {
72
+ // Plain Hono (or anything without the registry) contributes no docs.
73
+ continue;
74
+ }
75
+ // `route("/", subApp)` reproduces what an absolute-path (`lazyRoutes`)
76
+ // family does at runtime; a relative-surface loader merges at its prefix.
77
+ throwaway.route(prefix === "/" ? "/" : prefix, subApp);
78
+ mergedAny = true;
79
+ }
80
+ if (!mergedAny)
81
+ return base;
82
+ const lazyDoc = throwaway.getOpenAPI31Document({
83
+ openapi: "3.1.0",
84
+ info: options.info,
85
+ ...(options.servers ? { servers: options.servers } : {}),
86
+ });
87
+ const paths = { ...(base.paths ?? {}) };
88
+ for (const [path, item] of Object.entries(lazyDoc.paths ?? {})) {
89
+ if (path in paths) {
90
+ console.warn(`[voyant] openapi: lazy path "${path}" collides with an eager route; keeping eager.`);
91
+ continue;
92
+ }
93
+ paths[path] = item;
94
+ }
95
+ const merged = { ...base, paths };
96
+ const lazyComponents = lazyDoc.components;
97
+ if (lazyComponents) {
98
+ const baseComponents = (base.components ?? {});
99
+ const mergedComponents = {};
100
+ const groups = new Set([...Object.keys(baseComponents), ...Object.keys(lazyComponents)]);
101
+ for (const group of groups) {
102
+ const baseGroup = (baseComponents[group] ?? {});
103
+ const lazyGroup = lazyComponents[group] ?? {};
104
+ const combined = { ...lazyGroup };
105
+ for (const [key, value] of Object.entries(baseGroup)) {
106
+ combined[key] = value; // base wins
107
+ }
108
+ mergedComponents[group] = combined;
109
+ }
110
+ ;
111
+ merged.components = mergedComponents;
112
+ }
113
+ return merged;
114
+ }
package/dist/types.d.ts CHANGED
@@ -242,12 +242,14 @@ export interface VoyantAppConfig<TBindings extends VoyantBindings = VoyantBindin
242
242
  */
243
243
  metrics?: boolean;
244
244
  /**
245
- * Default request body limit enforced by `Content-Length` before route
246
- * handlers parse JSON/form data. Enabled by default at 10 MiB. Set
247
- * `false` to disable or pass `{ maxBytes }` to override.
245
+ * Default request body limit enforced before route handlers parse
246
+ * JSON/form data. Content-type-aware: JSON bodies are capped at 10 MiB
247
+ * (`jsonMaxBytes`), non-JSON bodies (uploads) at the 26 MiB outer ceiling
248
+ * (`maxBytes`). Set `false` to disable, or override either cap.
248
249
  */
249
250
  requestBodyLimit?: false | {
250
- maxBytes: number;
251
+ maxBytes?: number;
252
+ jsonMaxBytes?: number;
251
253
  };
252
254
  /**
253
255
  * Default app-wide security headers. Enabled by default. Set `false`
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,EAAY,KAAK,OAAO,EAAE,MAAM,KAAK,CAAA;AAI5C,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;gBAGxC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAClC;CAQJ;AAED,qBAAa,sBAAuB,SAAQ,YAAY;gBAC1C,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAQ/D;AAED,qBAAa,oBAAqB,SAAQ,YAAY;gBACxC,OAAO,SAAiB;CAOrC;AAED,qBAAa,iBAAkB,SAAQ,YAAY;gBACrC,OAAO,SAAc;CAOlC;AAqBD,wBAAsB,aAAa,CAAC,CAAC,EACnC,CAAC,EAAE,OAAO,EACV,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAClB,OAAO,CAAC,EAAE;IAAE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACxF,OAAO,CAAC,CAAC,CAAC,CAWZ;AAED,wBAAsB,qBAAqB,CAAC,CAAC,EAC3C,CAAC,EAAE,OAAO,EACV,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAClB,OAAO,CAAC,EAAE;IACR,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,GACA,OAAO,CAAC,CAAC,CAAC,CAcZ;AAkBD,wBAAgB,UAAU,CAAC,CAAC,EAC1B,CAAC,EAAE,OAAO,EACV,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAClB,OAAO,CAAC,EAAE;IAAE,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAAE,GACzC,CAAC,CAMH;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CAUjF"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAEnC,OAAO,EAAY,KAAK,OAAO,EAAE,MAAM,KAAK,CAAA;AAI5C,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;gBAGxC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAClC;CAQJ;AAED,qBAAa,sBAAuB,SAAQ,YAAY;gBAC1C,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAQ/D;AAED,qBAAa,oBAAqB,SAAQ,YAAY;gBACxC,OAAO,SAAiB;CAOrC;AAED,qBAAa,iBAAkB,SAAQ,YAAY;gBACrC,OAAO,SAAc;CAOlC;AAqBD,wBAAsB,aAAa,CAAC,CAAC,EACnC,CAAC,EAAE,OAAO,EACV,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAClB,OAAO,CAAC,EAAE;IAAE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACxF,OAAO,CAAC,CAAC,CAAC,CAWZ;AAED,wBAAsB,qBAAqB,CAAC,CAAC,EAC3C,CAAC,EAAE,OAAO,EACV,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAClB,OAAO,CAAC,EAAE;IACR,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,GACA,OAAO,CAAC,CAAC,CAAC,CAcZ;AAkBD,wBAAgB,UAAU,CAAC,CAAC,EAC1B,CAAC,EAAE,OAAO,EACV,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAClB,OAAO,CAAC,EAAE;IAAE,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAAE,GACzC,CAAC,CAMH;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CAsBjF"}
@@ -1,3 +1,4 @@
1
+ import { HTTPException } from "hono/http-exception";
1
2
  import { ZodError } from "zod";
2
3
  import { DEFAULT_REQUEST_BODY_LIMIT_BYTES } from "./middleware/body-size.js";
3
4
  export class ApiHttpError extends Error {
@@ -102,5 +103,16 @@ export function normalizeValidationError(error) {
102
103
  if (error instanceof ZodError) {
103
104
  return toValidationError(error);
104
105
  }
106
+ if (error instanceof HTTPException) {
107
+ // Hono's request validators throw HTTPException before our validation hook
108
+ // runs — most notably HTTPException(400, "Malformed JSON in request body")
109
+ // from the JSON body parser on `.openapi()` routes. Map it onto the
110
+ // framework error contract so bad client input is a structured 4xx, not a
111
+ // 500 (voyant#2114).
112
+ return new ApiHttpError(error.message, {
113
+ status: error.status,
114
+ code: error.status === 400 ? "invalid_request" : undefined,
115
+ });
116
+ }
105
117
  return undefined;
106
118
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyant-travel/hono",
3
- "version": "0.117.0",
3
+ "version": "0.117.2",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -139,8 +139,8 @@
139
139
  "@voyant-travel/db": "^0.109.4",
140
140
  "@voyant-travel/storage": "^0.105.0",
141
141
  "@voyant-travel/types": "^0.106.0",
142
- "@voyant-travel/utils": "^0.105.4",
143
- "@voyant-travel/workflows": "^0.111.9"
142
+ "@voyant-travel/workflows": "^0.111.9",
143
+ "@voyant-travel/utils": "^0.105.4"
144
144
  },
145
145
  "devDependencies": {
146
146
  "@cloudflare/workers-types": "^4.20260426.1",