also looking at this
umbrella: pet-store storefront fixes (rolling)
#3
586 files
+38082
-7487
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -45,4 +45,35 @@ export class Middleware { | ||
| 45 | 45 | this.priority = config.priority ?? 10 |
| 46 | 46 | this.handle = config.handle |
| 47 | 47 | } |
| 48 | ||
| 49 | /** | |
| 50 | * Adapt this Middleware to the bun-router (req, next) → Response shape. | |
| 51 | * | |
| 52 | * The Middleware class contract is "return void to continue, throw a | |
| 53 | * Response/HttpError to short-circuit". Bun-router's middleware contract | |
| 54 | * is "call next() and return its Response". Pushing `handle.bind(this)` | |
| 55 | * straight onto `globalMiddleware` drops the second contract on the | |
| 56 | * floor — `handle` ignores `next` and returns `undefined`, which | |
| 57 | * `buildMiddlewareChain` interprets as a final response, so it falls | |
| 58 | * back to `new Response(null, { status: 200 })` and the actual route | |
| 59 | * handler downstream never runs. Visible symptom: every route returns | |
| 60 | * `200 OK` with `Content-Length: 0`. | |
| 61 | * | |
| 62 | * Use this adapter whenever attaching a `Middleware` instance via | |
| 63 | * `route.use(...)` or `route.middleware(...)` so the void/throw contract | |
| 64 | * is honoured. | |
| 65 | */ | |
| 66 | toRouterHandler(): (req: EnhancedRequest, next: () => Promise<Response>) => Promise<Response> { | |
| 67 | const handle = this.handle.bind(this) | |
| 68 | return async (req, next) => { | |
| 69 | try { | |
| 70 | await handle(req) | |
| 71 | } | |
| 72 | catch (thrown) { | |
| 73 | if (thrown instanceof Response) return thrown | |
| 74 | throw thrown | |
| 75 | } | |
| 76 | return next() | |
| 77 | } | |
| 78 | } | |
| 48 | 79 | } |
| @@ -37,7 +37,13 @@ import MaintenanceMiddleware from './app/Middleware/Maintenance' | ||
| 37 | 37 | // itself reads `activeSiteModePayload()` so it covers both maintenance |
| 38 | 38 | // and coming-soon modes (plus `APP_MAINTENANCE` / `APP_COMING_SOON` |
| 39 | 39 | // env overrides) without the bootstrap needing to know the details. |
| 40 | route.use(MaintenanceMiddleware.handle.bind(MaintenanceMiddleware) as any) | |
| 40 | // | |
| 41 | // `toRouterHandler()` adapts the Middleware contract (return void to | |
| 42 | // continue, throw a Response to short-circuit) to bun-router's | |
| 43 | // `(req, next) => Response` shape. Without the adapter, `handle` would | |
| 44 | // return `undefined`, bun-router's chain treats that as a short-circuit | |
| 45 | // to an empty 200, and every route returns `200 OK Content-Length: 0`. | |
| 46 | route.use(MaintenanceMiddleware.toRouterHandler() as any) | |
| 41 | 47 | |
| 42 | 48 | // Feature-gated route registration. The dashboard.ts file currently bundles |
| 43 | 49 | // ~687 lines covering auth, password reset, email subscribe, storefront |