@voyant-travel/hono 0.110.3 → 0.111.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/app.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AA4B3B,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAY,eAAe,EAAE,MAAM,YAAY,CAAA;AA2C5F;;;;;;;;;;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,wBAAgB,SAAS,CAAC,SAAS,SAAS,cAAc,EACxD,MAAM,EAAE,eAAe,CAAC,SAAS,CAAC,GACjC,IAAI,CAAC;IAAE,QAAQ,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,eAAe,CAAA;CAAE,CAAC,GAAG,mBAAmB,CAAC,SAAS,CAAC,CA6Z5F"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AA6B3B,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAY,eAAe,EAAE,MAAM,YAAY,CAAA;AA2C5F;;;;;;;;;;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,wBAAgB,SAAS,CAAC,SAAS,SAAS,cAAc,EACxD,MAAM,EAAE,eAAe,CAAC,SAAS,CAAC,GACjC,IAAI,CAAC;IAAE,QAAQ,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,eAAe,CAAA;CAAE,CAAC,GAAG,mBAAmB,CAAC,SAAS,CAAC,CA6a5F"}
package/dist/app.js CHANGED
@@ -2,6 +2,7 @@ import { createContainer, createEventBus, createQueryRunner, } from "@voyant-tra
2
2
  import { createOutboxEventStore } from "@voyant-travel/db/outbox";
3
3
  import { Hono } from "hono";
4
4
  import { containerToServiceResolver, makeFrameworkLogger, wireWorkflowRuntime, } from "./app-workflows.js";
5
+ import { mountLazyRoutePaths, mountLazyRoutesAt } from "./lazy-routes.js";
5
6
  import { createPathDbSelector } from "./lib/db-selector.js";
6
7
  import { tryGetExecutionCtx } from "./lib/execution-ctx.js";
7
8
  import { matchesPublicPath, normalizePathname } from "./lib/public-paths.js";
@@ -358,11 +359,22 @@ export function createApp(config) {
358
359
  }
359
360
  // Mount module routes
360
361
  for (const mod of allModules) {
362
+ const adminPrefix = `/v1/admin/${mod.module.name}`;
363
+ const publicPrefix = resolveSurfaceMountPath("/v1/public", mod.publicPath, mod.module.name);
361
364
  if (mod.adminRoutes) {
362
- app.route(`/v1/admin/${mod.module.name}`, mod.adminRoutes);
365
+ app.route(adminPrefix, mod.adminRoutes);
363
366
  }
364
367
  if (mod.publicRoutes) {
365
- app.route(resolveSurfaceMountPath("/v1/public", mod.publicPath, mod.module.name), mod.publicRoutes);
368
+ app.route(publicPrefix, mod.publicRoutes);
369
+ }
370
+ if (mod.lazyAdminRoutes) {
371
+ mountLazyRoutesAt(app, adminPrefix, mod.lazyAdminRoutes);
372
+ }
373
+ if (mod.lazyPublicRoutes) {
374
+ mountLazyRoutesAt(app, publicPrefix, mod.lazyPublicRoutes);
375
+ }
376
+ if (mod.lazyRoutes) {
377
+ mountLazyRoutePaths(app, mod.lazyRoutes.paths, mod.lazyRoutes.load);
366
378
  }
367
379
  if (mod.routes) {
368
380
  app.route(`/v1/${mod.module.name}`, mod.routes);
@@ -370,11 +382,22 @@ export function createApp(config) {
370
382
  }
371
383
  // Mount extension routes
372
384
  for (const ext of allExtensions) {
385
+ const adminPrefix = `/v1/admin/${ext.extension.module}`;
386
+ const publicPrefix = resolveSurfaceMountPath("/v1/public", ext.publicPath, ext.extension.module);
373
387
  if (ext.adminRoutes) {
374
- app.route(`/v1/admin/${ext.extension.module}`, ext.adminRoutes);
388
+ app.route(adminPrefix, ext.adminRoutes);
375
389
  }
376
390
  if (ext.publicRoutes) {
377
- app.route(resolveSurfaceMountPath("/v1/public", ext.publicPath, ext.extension.module), ext.publicRoutes);
391
+ app.route(publicPrefix, ext.publicRoutes);
392
+ }
393
+ if (ext.lazyAdminRoutes) {
394
+ mountLazyRoutesAt(app, adminPrefix, ext.lazyAdminRoutes);
395
+ }
396
+ if (ext.lazyPublicRoutes) {
397
+ mountLazyRoutesAt(app, publicPrefix, ext.lazyPublicRoutes);
398
+ }
399
+ if (ext.lazyRoutes) {
400
+ mountLazyRoutePaths(app, ext.lazyRoutes.paths, ext.lazyRoutes.load);
378
401
  }
379
402
  if (ext.routes) {
380
403
  app.route(`/v1/${ext.extension.module}`, ext.routes);
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export type { SessionAuthContext } from "./auth/index.js";
4
4
  export { constantTimeEqual, extractBearerToken, generateNumericCode, randomBytesHex, requireUserId, sha256Base64Url, sha256Hex, unsignCookie, verifySession, } from "./auth/index.js";
5
5
  export type { DocumentDownloadEnvelope, DocumentDownloadResolution, DocumentDownloadResolver, DocumentDownloadResolverResult, StoredDocumentReference, } from "./document-download.js";
6
6
  export { resolveStoredDocumentDownload } from "./document-download.js";
7
+ export { createLazyRouteHandler, type LazyHonoRoutes, type LazyRoutesLoader, mountLazyRoutePaths, mountLazyRoutesAt, } from "./lazy-routes.js";
7
8
  export { createPathDbSelector, type PathDbSelectorOptions } from "./lib/db-selector.js";
8
9
  export { clientIpKey, consoleLoggerProvider, cors, DEFAULT_IDEMPOTENCY_TTL_MS, db, enforceRateLimit, errorBoundary, handleApiError, type IdempotencyKeyOptions, idempotencyKey, LIVE_LIMITS, logger, purgeExpiredIdempotencyKeys, rateLimit, requestId, requireActor, requireAuth, requirePermission, } from "./middleware/index.js";
9
10
  export type { HonoExtension, HonoModule } from "./module.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,eAAe,EACf,SAAS,EACT,YAAY,EACZ,aAAa,GACd,MAAM,iBAAiB,CAAA;AACxB,YAAY,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,wBAAwB,EACxB,8BAA8B,EAC9B,uBAAuB,GACxB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAA;AACtE,OAAO,EAAE,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AACvF,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,IAAI,EACJ,0BAA0B,EAC1B,EAAE,EACF,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,KAAK,qBAAqB,EAC1B,cAAc,EACd,WAAW,EACX,MAAM,EACN,2BAA2B,EAC3B,SAAS,EACT,SAAS,EACT,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,MAAM,uBAAuB,CAAA;AAC9B,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC5D,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,UAAU,EACV,UAAU,GACX,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,aAAa,CAAA;AACpB,YAAY,EACV,6BAA6B,EAC7B,6BAA6B,EAC7B,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,EAC5B,+BAA+B,EAC/B,2BAA2B,GAC5B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACL,KAAK,iCAAiC,EACtC,6CAA6C,EAC7C,iCAAiC,EACjC,sCAAsC,EACtC,kCAAkC,EAClC,KAAK,mCAAmC,EACxC,KAAK,8BAA8B,EACnC,KAAK,2BAA2B,EAChC,KAAK,gCAAgC,EACrC,KAAK,gCAAgC,EACrC,KAAK,kCAAkC,EACvC,KAAK,4BAA4B,EACjC,KAAK,sCAAsC,EAC3C,kCAAkC,EAClC,iCAAiC,GAClC,MAAM,+BAA+B,CAAA;AACtC,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,kBAAkB,EAClB,QAAQ,EACR,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,cAAc,EACd,QAAQ,EACR,sBAAsB,EACtB,kBAAkB,EAClB,wBAAwB,EACxB,eAAe,GAChB,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,wBAAwB,EACxB,aAAa,EACb,qBAAqB,EACrB,UAAU,EACV,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,eAAe,EACf,SAAS,EACT,YAAY,EACZ,aAAa,GACd,MAAM,iBAAiB,CAAA;AACxB,YAAY,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,wBAAwB,EACxB,8BAA8B,EAC9B,uBAAuB,GACxB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAA;AACtE,OAAO,EACL,sBAAsB,EACtB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AACvF,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,IAAI,EACJ,0BAA0B,EAC1B,EAAE,EACF,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,KAAK,qBAAqB,EAC1B,cAAc,EACd,WAAW,EACX,MAAM,EACN,2BAA2B,EAC3B,SAAS,EACT,SAAS,EACT,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,MAAM,uBAAuB,CAAA;AAC9B,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC5D,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,UAAU,EACV,UAAU,GACX,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,aAAa,CAAA;AACpB,YAAY,EACV,6BAA6B,EAC7B,6BAA6B,EAC7B,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,EAC5B,+BAA+B,EAC/B,2BAA2B,GAC5B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACL,KAAK,iCAAiC,EACtC,6CAA6C,EAC7C,iCAAiC,EACjC,sCAAsC,EACtC,kCAAkC,EAClC,KAAK,mCAAmC,EACxC,KAAK,8BAA8B,EACnC,KAAK,2BAA2B,EAChC,KAAK,gCAAgC,EACrC,KAAK,gCAAgC,EACrC,KAAK,kCAAkC,EACvC,KAAK,4BAA4B,EACjC,KAAK,sCAAsC,EAC3C,kCAAkC,EAClC,iCAAiC,GAClC,MAAM,+BAA+B,CAAA;AACtC,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,kBAAkB,EAClB,QAAQ,EACR,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,cAAc,EACd,QAAQ,EACR,sBAAsB,EACtB,kBAAkB,EAClB,wBAAwB,EACxB,eAAe,GAChB,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,wBAAwB,EACxB,aAAa,EACb,qBAAqB,EACrB,UAAU,EACV,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,iBAAiB,CAAA"}
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export { createApp } from "./app.js";
2
2
  export { constantTimeEqual, extractBearerToken, generateNumericCode, randomBytesHex, requireUserId, sha256Base64Url, sha256Hex, unsignCookie, verifySession, } from "./auth/index.js";
3
3
  export { resolveStoredDocumentDownload } from "./document-download.js";
4
+ export { createLazyRouteHandler, mountLazyRoutePaths, mountLazyRoutesAt, } from "./lazy-routes.js";
4
5
  export { createPathDbSelector } from "./lib/db-selector.js";
5
6
  export { clientIpKey, consoleLoggerProvider, cors, DEFAULT_IDEMPOTENCY_TTL_MS, db, enforceRateLimit, errorBoundary, handleApiError, idempotencyKey, LIVE_LIMITS, logger, purgeExpiredIdempotencyKeys, rateLimit, requestId, requireActor, requireAuth, requirePermission, } from "./middleware/index.js";
6
7
  export { defineHonoBundle, defineHonoPlugin, expandHonoBundles, expandHonoPlugins, } from "./plugin.js";
@@ -0,0 +1,67 @@
1
+ /**
2
+ * First-class lazy route mounting for `@voyant-travel/hono`.
3
+ *
4
+ * A module or extension can declare `lazyAdminRoutes` / `lazyPublicRoutes` as a
5
+ * loader (`() => import("./routes").then((m) => m.createRoutes(opts))`) instead
6
+ * of eager `adminRoutes` / `publicRoutes`. The route bundle is dynamically
7
+ * imported on first matching request and cached per isolate/process, so heavy
8
+ * route families don't inflate the main bundle or the Worker cold start.
9
+ *
10
+ * For deployment-local families that span MULTIPLE absolute path prefixes (e.g.
11
+ * an operator bundle exposing `/v1/uploads`, `/v1/admin/uploads`, `/v1/media/*`),
12
+ * the single-surface loaders don't fit. Such families declare `lazyRoutes`:
13
+ * `{ paths, load }` where `load` returns a sub-app whose routes are ABSOLUTE and
14
+ * `paths` are the explicit matchers the framework installs up front. This is the
15
+ * context-preserving replacement for the starter's `mountLazyRouteApp(...)`.
16
+ *
17
+ * The hard requirement (and the reason the starter's old `mountLazyRouteApp`
18
+ * was insufficient): the lazy routes must behave **exactly** like eager routes.
19
+ * Eager routes mounted via `app.route(...)` share the request context, so they
20
+ * see `c.var.db`, `c.var.container`, the resolved actor, etc. set by the
21
+ * `createApp` middleware pipeline. A naive `subApp.fetch(c.req.raw, c.env)`
22
+ * forward builds a fresh context and drops every `c.var`.
23
+ *
24
+ * So this dispatcher bridges the request-scoped context across the forward: it
25
+ * snapshots `c.var`, carries it on the forwarded `env` under a private symbol,
26
+ * and a wrapper middleware re-hydrates it onto the loaded sub-app's context
27
+ * before the real routes run. The db lease is *carried*, not re-acquired — the
28
+ * outer `db` middleware still owns its lifecycle (dispose), so there is no
29
+ * double-release.
30
+ */
31
+ import type { Context, Hono as HonoType } from "hono";
32
+ type AnyHono = HonoType<any>;
33
+ /** Loads (and builds) the Hono sub-app for a lazy route surface. */
34
+ export type LazyRoutesLoader = () => Promise<AnyHono>;
35
+ /**
36
+ * A deployment-local lazy route family spanning explicit absolute path
37
+ * matchers. `load` returns a sub-app whose routes are ABSOLUTE; `paths` are the
38
+ * matchers the framework installs up front (no bundle import until a request
39
+ * matches).
40
+ */
41
+ export interface LazyHonoRoutes {
42
+ paths: readonly string[];
43
+ load: LazyRoutesLoader;
44
+ }
45
+ /**
46
+ * Build a cached, context-preserving request handler. `mountPrefix` is where the
47
+ * loaded routes are re-mounted in the wrapper sub-app so the forwarded absolute
48
+ * request URL matches: the surface prefix (e.g. `/v1/admin/flights`) for
49
+ * relative-route loaders, or `"/"` for loaders that already return absolute
50
+ * routes.
51
+ */
52
+ export declare function createLazyRouteHandler(mountPrefix: string, load: LazyRoutesLoader): (c: Context) => Promise<Response>;
53
+ /**
54
+ * Register a single lazy surface on `app` at `prefix` (loader returns RELATIVE
55
+ * routes). Matches both the prefix root (`POST /v1/admin/foo`) and any sub-path
56
+ * (`/v1/admin/foo/bar`).
57
+ */
58
+ export declare function mountLazyRoutesAt(app: AnyHono, prefix: string, load: LazyRoutesLoader): void;
59
+ /**
60
+ * Register a multi-prefix lazy family on `app` at explicit `paths` (loader
61
+ * returns ABSOLUTE routes). One shared cached/context-bridging handler backs
62
+ * every path. Context-preserving replacement for the starter's
63
+ * `mountLazyRouteApp(...)`.
64
+ */
65
+ export declare function mountLazyRoutePaths(app: AnyHono, paths: readonly string[], load: LazyRoutesLoader): void;
66
+ export {};
67
+ //# sourceMappingURL=lazy-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy-routes.d.ts","sourceRoot":"","sources":["../src/lazy-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAA;AAMrD,KAAK,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;AAE5B,oEAAoE;AACpE,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;AAErD;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACxB,IAAI,EAAE,gBAAgB,CAAA;CACvB;AAKD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,IA0ClE,GAAG,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAO7C;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAI5F;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,IAAI,EAAE,gBAAgB,GACrB,IAAI,CAKN"}
@@ -0,0 +1,79 @@
1
+ import { Hono } from "hono";
2
+ import { tryGetExecutionCtx } from "./lib/execution-ctx.js";
3
+ /** Private carrier key for snapshotting `c.var` across the forward. */
4
+ const LAZY_CONTEXT_CARRIER = Symbol.for("voyant.hono.lazyContextCarrier");
5
+ /**
6
+ * Build a cached, context-preserving request handler. `mountPrefix` is where the
7
+ * loaded routes are re-mounted in the wrapper sub-app so the forwarded absolute
8
+ * request URL matches: the surface prefix (e.g. `/v1/admin/flights`) for
9
+ * relative-route loaders, or `"/"` for loaders that already return absolute
10
+ * routes.
11
+ */
12
+ export function createLazyRouteHandler(mountPrefix, load) {
13
+ let cached;
14
+ function getApp() {
15
+ // Cache the BUILT, wrapped sub-app; reset on failure so a transient
16
+ // import/config error can recover on the next request.
17
+ if (!cached) {
18
+ cached = load()
19
+ .then((routes) => {
20
+ const wrapped = new Hono();
21
+ // Re-throw handler errors instead of letting the wrapper sub-app's
22
+ // default Hono error handler swallow them into a plain 500. This
23
+ // propagates the throw back through `app.fetch` to the outer
24
+ // `createApp` pipeline, so lazy routes hit the same `errorBoundary` /
25
+ // `handleApiError` normalization (JSON error shape + structured
26
+ // logging) as eager `app.route(...)` mounts.
27
+ wrapped.onError((err) => {
28
+ throw err;
29
+ });
30
+ wrapped.use("*", async (cc, next) => {
31
+ const carried = cc.env?.[LAZY_CONTEXT_CARRIER];
32
+ if (carried) {
33
+ for (const [key, value] of Object.entries(carried)) {
34
+ // biome-ignore lint/suspicious/noExplicitAny: re-hydrating arbitrary context vars -- owner: hono.
35
+ cc.set(key, value);
36
+ }
37
+ }
38
+ await next();
39
+ });
40
+ wrapped.route(mountPrefix, routes);
41
+ return wrapped;
42
+ })
43
+ .catch((err) => {
44
+ cached = undefined;
45
+ throw err;
46
+ });
47
+ }
48
+ return cached;
49
+ }
50
+ return async (c) => {
51
+ const app = await getApp();
52
+ const snapshot = { ...c.var };
53
+ const env = { ...c.env, [LAZY_CONTEXT_CARRIER]: snapshot };
54
+ // biome-ignore lint/suspicious/noExplicitAny: forward the host execution context when present -- owner: hono.
55
+ return app.fetch(c.req.raw, env, tryGetExecutionCtx(c));
56
+ };
57
+ }
58
+ /**
59
+ * Register a single lazy surface on `app` at `prefix` (loader returns RELATIVE
60
+ * routes). Matches both the prefix root (`POST /v1/admin/foo`) and any sub-path
61
+ * (`/v1/admin/foo/bar`).
62
+ */
63
+ export function mountLazyRoutesAt(app, prefix, load) {
64
+ const handler = createLazyRouteHandler(prefix, load);
65
+ app.all(prefix, handler);
66
+ app.all(`${prefix}/*`, handler);
67
+ }
68
+ /**
69
+ * Register a multi-prefix lazy family on `app` at explicit `paths` (loader
70
+ * returns ABSOLUTE routes). One shared cached/context-bridging handler backs
71
+ * every path. Context-preserving replacement for the starter's
72
+ * `mountLazyRouteApp(...)`.
73
+ */
74
+ export function mountLazyRoutePaths(app, paths, load) {
75
+ const handler = createLazyRouteHandler("/", load);
76
+ for (const path of paths) {
77
+ app.all(path, handler);
78
+ }
79
+ }
package/dist/module.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { Extension, Module } from "@voyant-travel/core";
2
2
  import type { Hono } from "hono";
3
+ import type { LazyHonoRoutes, LazyRoutesLoader } from "./lazy-routes.js";
3
4
  export interface HonoModule {
4
5
  module: Module;
5
6
  /**
@@ -14,6 +15,22 @@ export interface HonoModule {
14
15
  adminRoutes?: Hono<any>;
15
16
  /** Customer/partner/supplier-facing routes — mounted at `/v1/public/{module.name}`. */
16
17
  publicRoutes?: Hono<any>;
18
+ /**
19
+ * Lazy variant of `adminRoutes` — the route bundle is dynamically imported on
20
+ * first request and cached per isolate. Mounted at `/v1/admin/{module.name}`
21
+ * with the request context bridged in, so it behaves identically to eager
22
+ * `adminRoutes`. Use for heavy route families to protect Worker cold start.
23
+ */
24
+ lazyAdminRoutes?: LazyRoutesLoader;
25
+ /** Lazy variant of `publicRoutes` — mounted at `/v1/public/{publicPath ?? module.name}`. */
26
+ lazyPublicRoutes?: LazyRoutesLoader;
27
+ /**
28
+ * Deployment-local lazy family spanning explicit absolute path matchers (for
29
+ * route bundles that don't fit a single admin/public surface). The loader
30
+ * returns ABSOLUTE routes; the framework mounts + caches them with the request
31
+ * context bridged in. Context-preserving replacement for `mountLazyRouteApp`.
32
+ */
33
+ lazyRoutes?: LazyHonoRoutes;
17
34
  /**
18
35
  * Optional override for the public mount path relative to `/v1/public`.
19
36
  *
@@ -30,6 +47,12 @@ export interface HonoExtension {
30
47
  adminRoutes?: Hono<any>;
31
48
  /** Customer/partner/supplier-facing routes — mounted at `/v1/public/{extension.module}`. */
32
49
  publicRoutes?: Hono<any>;
50
+ /** Lazy variant of `adminRoutes` — mounted at `/v1/admin/{extension.module}` (see HonoModule). */
51
+ lazyAdminRoutes?: LazyRoutesLoader;
52
+ /** Lazy variant of `publicRoutes` — mounted at `/v1/public/{publicPath ?? extension.module}`. */
53
+ lazyPublicRoutes?: LazyRoutesLoader;
54
+ /** Deployment-local lazy family at explicit absolute paths (see HonoModule). */
55
+ lazyRoutes?: LazyHonoRoutes;
33
56
  /**
34
57
  * Optional override for the public mount path relative to `/v1/public`.
35
58
  *
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAEhC,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAA;IACd;;;;;;OAMG;IAEH,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IAClB,kEAAkE;IAElE,WAAW,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IACvB,uFAAuF;IAEvF,YAAY,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IACxB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,SAAS,CAAA;IACpB,0DAA0D;IAE1D,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IAClB,uEAAuE;IAEvE,WAAW,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IACvB,4FAA4F;IAE5F,YAAY,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IACxB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAEhC,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAExE,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAA;IACd;;;;;;OAMG;IAEH,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IAClB,kEAAkE;IAElE,WAAW,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IACvB,uFAAuF;IAEvF,YAAY,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IACxB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,gBAAgB,CAAA;IAClC,4FAA4F;IAC5F,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,cAAc,CAAA;IAC3B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,SAAS,CAAA;IACpB,0DAA0D;IAE1D,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IAClB,uEAAuE;IAEvE,WAAW,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IACvB,4FAA4F;IAE5F,YAAY,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IACxB,kGAAkG;IAClG,eAAe,CAAC,EAAE,gBAAgB,CAAA;IAClC,iGAAiG;IACjG,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,gFAAgF;IAChF,UAAU,CAAC,EAAE,cAAc,CAAA;IAC3B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyant-travel/hono",
3
- "version": "0.110.3",
3
+ "version": "0.111.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -121,17 +121,17 @@
121
121
  "zod": "^4.3.6",
122
122
  "@voyant-travel/core": "^0.109.0",
123
123
  "@voyant-travel/db": "^0.108.1",
124
- "@voyant-travel/storage": "^0.104.1",
124
+ "@voyant-travel/storage": "^0.105.0",
125
125
  "@voyant-travel/types": "^0.104.5",
126
126
  "@voyant-travel/utils": "^0.105.2",
127
- "@voyant-travel/workflows": "^0.109.1"
127
+ "@voyant-travel/workflows": "^0.109.2"
128
128
  },
129
129
  "devDependencies": {
130
130
  "@cloudflare/workers-types": "^4.20260426.1",
131
131
  "typescript": "^6.0.2",
132
132
  "vitest": "^4.1.2",
133
133
  "@voyant-travel/voyant-typescript-config": "^0.1.0",
134
- "@voyant-travel/workflows-orchestrator": "^0.109.1"
134
+ "@voyant-travel/workflows-orchestrator": "^0.109.2"
135
135
  },
136
136
  "files": [
137
137
  "dist"