@warlock.js/web 5.1.0 → 5.2.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 (148) hide show
  1. package/CHANGELOG.md +182 -0
  2. package/README.md +126 -12
  3. package/esm/build/contribution.d.mts +10 -13
  4. package/esm/build/contribution.mjs +45 -57
  5. package/esm/build/contribution.mjs.map +1 -1
  6. package/esm/build/discover-pages.mjs +104 -44
  7. package/esm/build/discover-pages.mjs.map +1 -1
  8. package/esm/build/generate-client-registry.mjs +46 -12
  9. package/esm/build/generate-client-registry.mjs.map +1 -1
  10. package/esm/build/generate-pages-barrel.mjs +54 -12
  11. package/esm/build/generate-pages-barrel.mjs.map +1 -1
  12. package/esm/build/page-default-export.mjs +48 -0
  13. package/esm/build/page-default-export.mjs.map +1 -0
  14. package/esm/build/page-routes-manifest.mjs +21 -0
  15. package/esm/build/page-routes-manifest.mjs.map +1 -0
  16. package/esm/build/public-files.mjs +45 -0
  17. package/esm/build/public-files.mjs.map +1 -0
  18. package/esm/build/read-route-exports.mjs.map +1 -1
  19. package/esm/client/build-hydrated-tree.mjs +39 -8
  20. package/esm/client/build-hydrated-tree.mjs.map +1 -1
  21. package/esm/client/navigation/fetch-page-data.mjs.map +1 -1
  22. package/esm/client/navigation/prefetch.mjs.map +1 -1
  23. package/esm/client/runtime/index.d.mts +2 -1
  24. package/esm/client/runtime/index.mjs +2 -1
  25. package/esm/client/runtime/manifest.mjs +2 -1
  26. package/esm/client/runtime/manifest.mjs.map +1 -1
  27. package/esm/client/runtime/matcher.d.mts +12 -0
  28. package/esm/client/runtime/matcher.mjs +12 -0
  29. package/esm/client/runtime/matcher.mjs.map +1 -1
  30. package/esm/client/runtime/types.d.mts +14 -1
  31. package/esm/components/document-context.d.mts +39 -1
  32. package/esm/components/document-context.mjs.map +1 -1
  33. package/esm/components/link.mjs.map +1 -1
  34. package/esm/components/scripts.mjs +3 -1
  35. package/esm/components/scripts.mjs.map +1 -1
  36. package/esm/context.d.mts +5 -101
  37. package/esm/hydration-payload.d.mts +1 -1
  38. package/esm/hydration-payload.mjs +36 -7
  39. package/esm/hydration-payload.mjs.map +1 -1
  40. package/esm/index.d.mts +3 -2
  41. package/esm/loaders.d.mts +6 -35
  42. package/esm/props.d.mts +15 -7
  43. package/esm/route.d.mts +1 -16
  44. package/esm/routing/filesystem-route.mjs +45 -0
  45. package/esm/routing/filesystem-route.mjs.map +1 -0
  46. package/esm/routing/layout-policy.mjs.map +1 -1
  47. package/esm/routing/query-string.mjs.map +1 -1
  48. package/esm/routing/route-table.mjs.map +1 -1
  49. package/esm/runtime/register-modules.d.mts +19 -0
  50. package/esm/runtime/register-modules.mjs +22 -0
  51. package/esm/runtime/register-modules.mjs.map +1 -0
  52. package/esm/server/build-hydration-payload.mjs +1 -0
  53. package/esm/server/build-hydration-payload.mjs.map +1 -1
  54. package/esm/server/create-page-module-loader.mjs +1 -0
  55. package/esm/server/create-page-module-loader.mjs.map +1 -1
  56. package/esm/server/create-page-route-handler.d.mts +30 -5
  57. package/esm/server/create-page-route-handler.mjs +127 -42
  58. package/esm/server/create-page-route-handler.mjs.map +1 -1
  59. package/esm/server/dev-server.mjs +1 -12
  60. package/esm/server/dev-server.mjs.map +1 -1
  61. package/esm/server/error-page.d.mts +14 -0
  62. package/esm/server/error-page.mjs +39 -0
  63. package/esm/server/error-page.mjs.map +1 -0
  64. package/esm/server/execute-page-request.d.mts +6 -3
  65. package/esm/server/execute-page-request.mjs +78 -79
  66. package/esm/server/execute-page-request.mjs.map +1 -1
  67. package/esm/server/execute-page-request.types.d.mts +32 -91
  68. package/esm/server/hydration-client-url.mjs +1 -1
  69. package/esm/server/index.d.mts +5 -5
  70. package/esm/server/index.mjs +3 -4
  71. package/esm/server/install-page-routes-from-manifest.d.mts +16 -6
  72. package/esm/server/install-page-routes-from-manifest.mjs +70 -9
  73. package/esm/server/install-page-routes-from-manifest.mjs.map +1 -1
  74. package/esm/server/install-page-routes.d.mts +31 -14
  75. package/esm/server/install-page-routes.mjs +90 -38
  76. package/esm/server/install-page-routes.mjs.map +1 -1
  77. package/esm/server/install-production-page-routes.mjs +2 -35
  78. package/esm/server/install-production-page-routes.mjs.map +1 -1
  79. package/esm/server/match-page-route.mjs +1 -1
  80. package/esm/server/match-page-route.mjs.map +1 -1
  81. package/esm/server/not-found-page.mjs +1 -1
  82. package/esm/server/not-found-page.mjs.map +1 -1
  83. package/esm/server/page-context.d.mts +2 -8
  84. package/esm/server/page-context.mjs +2 -15
  85. package/esm/server/page-context.mjs.map +1 -1
  86. package/esm/server/page-file-change.mjs +77 -0
  87. package/esm/server/page-file-change.mjs.map +1 -0
  88. package/esm/server/page-manifest.d.mts +24 -9
  89. package/esm/server/page-manifest.mjs.map +1 -1
  90. package/esm/server/page-render-bundle.mjs +38 -0
  91. package/esm/server/page-render-bundle.mjs.map +1 -0
  92. package/esm/server/page-route-reload.mjs +54 -0
  93. package/esm/server/page-route-reload.mjs.map +1 -0
  94. package/esm/server/register-production-public-files.mjs +40 -0
  95. package/esm/server/register-production-public-files.mjs.map +1 -0
  96. package/esm/server/render-page.d.mts +10 -13
  97. package/esm/server/render-page.mjs +153 -27
  98. package/esm/server/render-page.mjs.map +1 -1
  99. package/esm/server/resolve-page-metadata.mjs +1 -1
  100. package/esm/server/resolve-page-metadata.mjs.map +1 -1
  101. package/esm/server/settle-page-response.d.mts +58 -1
  102. package/esm/server/settle-page-response.mjs +110 -45
  103. package/esm/server/settle-page-response.mjs.map +1 -1
  104. package/esm/server/stylesheet-urls.d.mts +40 -29
  105. package/esm/server/stylesheet-urls.mjs +136 -51
  106. package/esm/server/stylesheet-urls.mjs.map +1 -1
  107. package/esm/server/unregistered-pages.mjs +42 -0
  108. package/esm/server/unregistered-pages.mjs.map +1 -0
  109. package/esm/server/web-connector-factory.d.mts +1 -2
  110. package/esm/server/web-connector-factory.mjs +6 -5
  111. package/esm/server/web-connector-factory.mjs.map +1 -1
  112. package/esm/server/web-connector.mjs +137 -17
  113. package/esm/server/web-connector.mjs.map +1 -1
  114. package/esm/shared.d.mts +17 -2
  115. package/esm/shared.mjs +2 -6
  116. package/esm/shared.mjs.map +1 -1
  117. package/esm/vite/build-client.mjs +1 -1
  118. package/esm/vite/build-client.mjs.map +1 -1
  119. package/esm/vite/gate-a-resolve.mjs +66 -12
  120. package/esm/vite/gate-a-resolve.mjs.map +1 -1
  121. package/esm/vite/gate-b-secrets.mjs +34 -16
  122. package/esm/vite/gate-b-secrets.mjs.map +1 -1
  123. package/esm/vite/gate-c-verify.mjs +5 -5
  124. package/esm/vite/gate-c-verify.mjs.map +1 -1
  125. package/esm/vite/hydration-entries.mjs +1 -1
  126. package/esm/vite/hydration-entries.mjs.map +1 -1
  127. package/esm/vite/index.d.mts +8 -5
  128. package/esm/vite/index.mjs +123 -10
  129. package/esm/vite/index.mjs.map +1 -1
  130. package/esm/vite/page-registry-plugin.d.mts +21 -2
  131. package/esm/vite/page-registry-plugin.mjs +47 -13
  132. package/esm/vite/page-registry-plugin.mjs.map +1 -1
  133. package/esm/vite/projection.d.mts +1 -1
  134. package/esm/vite/projection.mjs +37 -14
  135. package/esm/vite/projection.mjs.map +1 -1
  136. package/llms-full.txt +220 -56
  137. package/llms.txt +5 -3
  138. package/package.json +3 -3
  139. package/skills/add-web-to-an-app/SKILL.md +3 -3
  140. package/skills/create-a-page/SKILL.md +117 -10
  141. package/skills/load-page-data/SKILL.md +92 -12
  142. package/skills/navigate-on-the-client/SKILL.md +1 -1
  143. package/skills/serve-styles/SKILL.md +13 -12
  144. package/skills/use-layouts/SKILL.md +14 -8
  145. package/skills/write-the-root/SKILL.md +3 -1
  146. package/esm/server/buffered-response.d.mts +0 -58
  147. package/esm/server/buffered-response.mjs +0 -115
  148. package/esm/server/buffered-response.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"dev-server.mjs","names":[],"sources":["../../../../../../../web/src/server/dev-server.ts"],"sourcesContent":["/**\n * Two small pieces of the dev/SSR page plumbing that `./web-connector.ts` wires\n * but deliberately does not own: the buffered-cookie commit, and the DEV-ONLY\n * error transport that stops a refused module from reaching the browser as a\n * bare 404 (see {@link devErrorTransportPlugin}).\n *\n * ---\n *\n * Commits one buffered cookie (`BufferedCookie`, from `./buffered-response.ts`)\n * onto the live Warlock `Response` — the single place in the SSR page pipeline\n * where a cookie the loader buffered turns into a real `Set-Cookie` header.\n *\n * It delegates to core's `Response.cookie()` rather than talking to fastify.\n * That method already owns everything this file used to reimplement: it takes\n * core's own `CookieOptions`, JSON-stringifies the value unless `{ raw: true }`,\n * strips the core-only `raw` flag, and layers the framework's secure-cookie\n * defaults and the `http.cookies.options` config under the per-call options.\n * Going through it means the SSR page path and every ordinary controller emit\n * cookies by the exact same code, so the two cannot drift apart.\n *\n * The helper is passed INTO `installPageRoutes`/`createPageRouteHandler` as an\n * option rather than imported by them, which is what keeps this module out of a\n * cycle with the page-route installer.\n */\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { stripVTControlCharacters } from \"node:util\";\nimport type { Connect, Plugin } from \"vite\";\nimport type { Response } from \"@warlock.js/core\";\nimport type { BufferedCookie } from \"./buffered-response\";\n\n/**\n * Replay a buffered cookie onto the response that will actually be sent.\n *\n * `BufferedCookie.options` is a loosely-typed bag (`Record<string, unknown>`)\n * because the buffer is written by loader code before any response exists; the\n * cast hands it to `Response.cookie()`, which is where the option shape is\n * defined and enforced for every other caller in the framework.\n */\nexport function applyBufferedCookie(response: Response, cookie: BufferedCookie): void {\n response.cookie(cookie.name, cookie.value as never, (cookie.options ?? {}) as never);\n}\n\n/**\n * Where a captured transform/resolve failure rides from Vite's connect stack to\n * the Fastify hook that mounted it.\n *\n * A `Symbol.for` key on the raw `IncomingMessage` rather than a `WeakMap`\n * because the two halves live in different modules and are wired at different\n * times; the request object is the only thing they provably share, and the\n * symbol cannot collide with a Vite/Fastify/user property.\n *\n * Exported so a test can stage a captured failure without booting a vite\n * server, and so the two halves cannot drift onto two different keys.\n */\nexport const DEV_TRANSFORM_ERROR_BODY = Symbol.for(\"warlock.web.devTransformErrorBody\");\n\ntype DevTransformErrorCarrier = { [DEV_TRANSFORM_ERROR_BODY]?: string };\n\n/**\n * The status a refused module now answers with.\n *\n * NOT the 404 this replaces. That 404 was never a decision about the module —\n * it is what an unmatched URL gets once vite has declined it, and which of the\n * two framework answers you see depends only on whether the app declares a\n * catch-all page: with one (v5/app does — `path: \"*\"`) the request lands in the\n * page pipeline, matches no route, and `./render-page.ts:604` returns\n * `{ html: \"\", status: 404 }` for `./create-page-route-handler.ts:147` to write\n * as an empty `text/html` body; without one it is `core/src/router/router.ts:879`.\n * Either way \"the module does not exist\" is precisely the wrong thing to tell a\n * developer whose module exists and was refused. 500 is the status VITE ITSELF writes for\n * this exact condition when it is not in middleware mode\n * (`node_modules/vite/dist/node/chunks/config.js:9528`), so this adopts that\n * convention rather than inventing a third one.\n */\nexport const DEV_TRANSFORM_ERROR_STATUS = 500;\n\n/**\n * `buildErrorMessage` as vite exports it. Declared structurally so this module\n * needs no value import of vite — vite is an optional, dev-only peer and a\n * production install does not carry it.\n */\nexport type BuildErrorMessage = (\n error: Error,\n args?: string[],\n includeStack?: boolean,\n) => string;\n\n/**\n * The dev error transport was constructed while the process is hosting a\n * PRODUCTION build. Refused by name at construction rather than degraded,\n * because everything this transport does — file paths, source frames, plugin\n * names — is exactly what a production response must never carry.\n */\nexport class DevErrorTransportInProductionError extends Error {\n public constructor() {\n super(\n \"The dev error transport was constructed with `Application.runtimeStrategy === \" +\n '\"production\"`. It exists only to put a Vite transform failure in front of a ' +\n \"developer and its response body carries absolute file paths and source frames, \" +\n \"so it must never be mounted on a production-hosted server.\",\n );\n this.name = \"DevErrorTransportInProductionError\";\n }\n}\n\n/**\n * Render a refused module's failure as the plain-text body the browser gets.\n *\n * Formatting is DELEGATED to vite's own exported `buildErrorMessage`, not\n * reimplemented: it is the same function vite uses to print the failure to the\n * terminal, so the text a developer reads in the network panel and the text\n * they read in the terminal cannot drift. Two things are added around it —\n * `error.name`, which vite's terminal path replaces with a fixed\n * \"Internal server error:\" prefix and which is the single most useful token for\n * a named gate refusal (`ProjectionAmbiguityError`), and the `cause` chain,\n * which vite does not walk.\n *\n * `stripVTControlCharacters` is not optional: `buildErrorMessage` colours its\n * output with picocolors, which is ON whenever the dev server owns a TTY, and\n * raw ANSI escapes in an HTTP body are noise. Vite strips them the same way for\n * the overlay payload (`config.js:9490-9497`).\n *\n * The stack is deliberately omitted (`includeStack: false`). A gate refusal's\n * stack points into the gate, not into the developer's code; the fields that\n * locate the problem — plugin, file, line, source frame — are what\n * `buildErrorMessage` puts there without it.\n */\nexport function formatDevTransformError(\n error: unknown,\n buildErrorMessage: BuildErrorMessage,\n): string {\n const failure =\n error instanceof Error ? error : new Error(typeof error === \"string\" ? error : String(error));\n\n const lines = [\n stripVTControlCharacters(\n buildErrorMessage(failure, [`${failure.name}: ${failure.message}`], false),\n ),\n ];\n\n // Walk the `cause` chain. A gate may wrap a parser failure, and the wrapped\n // message is usually the one naming the actual syntax that was refused.\n let cause = (failure as { cause?: unknown }).cause;\n\n while (cause instanceof Error) {\n lines.push(` Caused by: ${cause.name}: ${stripVTControlCharacters(cause.message)}`);\n cause = (cause as { cause?: unknown }).cause;\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n\n/**\n * DEV-ONLY. Capture the transform/resolve failure that vite is about to throw\n * away, so the request that caused it can answer with it.\n *\n * WHY THIS IS A PLUGIN AND NOT A `middlewares.use(...)` CALL — this is the\n * whole defect, and it is an ordering fact, not a style choice:\n *\n * - Vite mounts its own error handler LAST, built as\n * `errorMiddleware(server, !!middlewareMode)`\n * (`node_modules/vite/dist/node/chunks/config.js:25705`).\n * - In middleware mode that `allowNext` flag is `true`, and the handler then\n * logs the error to the TERMINAL and calls `next()` — with no error\n * (`config.js:9525-9527`).\n * - connect only routes an error to a 4-arity handler while an error is in\n * flight (`config.js:10611-10626`), so `next()` clears it: every layer after\n * that point, INCLUDING the `done` callback `./web-connector.ts` hands the\n * stack, is called as if the request had simply gone unhandled. The\n * framework then answers the only way it can for a URL it does not know — a\n * 404, empty (see {@link DEV_TRANSFORM_ERROR_STATUS} for which of the two\n * produces it).\n * - Anything registered with `vite.middlewares.use(...)` after `createServer()`\n * resolves lands AFTER that handler and is therefore unreachable. A\n * `configureServer` POST hook does not: vite runs post hooks at\n * `config.js:25700`, five lines BEFORE it mounts its error handler.\n *\n * So this sits between the failure and vite's logger. It captures, then calls\n * `next(error)` and lets vite's own handler run exactly as before — the\n * terminal message and the `hot.send({ type: \"error\" })` overlay push\n * (`config.js:9511-9521`) are unchanged. This transport ADDS a reader; it\n * replaces nothing.\n *\n * @param isProductionRuntime the connector's own hosting-mode signal\n * (`./web-connector.ts:122`) — passed in rather than re-derived so there\n * is one definition of \"this process is Vite-hosted\", not two.\n */\nexport function devErrorTransportPlugin(options: {\n isProductionRuntime: () => boolean;\n buildErrorMessage: BuildErrorMessage;\n}): Plugin {\n const { isProductionRuntime, buildErrorMessage } = options;\n\n if (isProductionRuntime()) {\n throw new DevErrorTransportInProductionError();\n }\n\n const capture: Connect.ErrorHandleFunction = (error, request, _response, next) => {\n // Re-asserted per request, not just at construction: `runtimeStrategy` is\n // process state and a transport that leaks source frames is not something\n // to hold open on a boot-time reading alone. In production this layer is a\n // pass-through and vite's handler behaves exactly as it does today.\n if (isProductionRuntime()) return next(error);\n\n (request as DevTransformErrorCarrier)[DEV_TRANSFORM_ERROR_BODY] = formatDevTransformError(\n error,\n buildErrorMessage,\n );\n\n next(error);\n };\n\n return {\n name: \"warlock:dev-error-transport\",\n // Belt to the `isProductionRuntime` braces: this plugin has no business in\n // a `vite build` graph either.\n apply: \"serve\",\n configureServer(server) {\n // RETURNING a function is what makes this a POST hook — the ordering the\n // note above depends on. Mounting inline here would land the layer BEFORE\n // vite's transform middleware, where no error has been thrown yet.\n return () => {\n server.middlewares.use(capture);\n };\n },\n };\n}\n\n/**\n * Answer the request with the failure {@link devErrorTransportPlugin} captured,\n * if there was one. Returns `false` when there was not, which is the normal\n * case and means \"carry on down the framework's own path\".\n *\n * Called from the Fastify `onRequest` hook that mounts vite\n * (`./web-connector.ts:321`), in the `done` callback — i.e. at the one moment\n * where connect has finished, vite has declined to answer, and the framework is\n * about to 404. Writing to the raw `ServerResponse` rather than through Fastify\n * is what the mount already does for every response vite serves, so this stays\n * on the same side of the seam.\n */\nexport function sendCapturedDevError(request: IncomingMessage, response: ServerResponse): boolean {\n const body = (request as DevTransformErrorCarrier)[DEV_TRANSFORM_ERROR_BODY];\n\n if (typeof body !== \"string\") return false;\n\n // A middleware further down may have answered already (vite serves plenty of\n // requests itself). Never write twice; the captured body is then just dropped.\n if (response.headersSent || response.writableEnded) return false;\n\n response.statusCode = DEV_TRANSFORM_ERROR_STATUS;\n response.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n // A refusal is a fact about the CURRENT source. Caching it would survive the\n // edit that fixes it.\n response.setHeader(\"cache-control\", \"no-store\");\n response.end(body);\n\n return true;\n}\n"],"mappings":";;;;;;;;;;;AAsCA,SAAgB,oBAAoB,UAAoB,QAA8B;CACpF,SAAS,OAAO,OAAO,MAAM,OAAO,OAAiB,OAAO,WAAW,CAAC,CAAW;AACrF;;;;;;;;;;;;;AAcA,MAAa,2BAA2B,OAAO,IAAI,mCAAmC;;;;;;;;;;;;;;;;;AAoBtF,MAAa,6BAA6B;;;;;;;AAmB1C,IAAa,qCAAb,cAAwD,MAAM;CAC5D,AAAO,cAAc;EACnB,MACE,uSAIF;EACA,KAAK,OAAO;CACd;AACF;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,wBACd,OACA,mBACQ;CACR,MAAM,UACJ,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,UAAU,WAAW,QAAQ,OAAO,KAAK,CAAC;CAE9F,MAAM,QAAQ,CACZ,yBACE,kBAAkB,SAAS,CAAC,GAAG,QAAQ,KAAK,IAAI,QAAQ,SAAS,GAAG,KAAK,CAC3E,CACF;CAIA,IAAI,QAAS,QAAgC;CAE7C,OAAO,iBAAiB,OAAO;EAC7B,MAAM,KAAK,gBAAgB,MAAM,KAAK,IAAI,yBAAyB,MAAM,OAAO,GAAG;EACnF,QAAS,MAA8B;CACzC;CAEA,OAAO,GAAG,MAAM,KAAK,IAAI,EAAE;AAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,SAAgB,wBAAwB,SAG7B;CACT,MAAM,EAAE,qBAAqB,sBAAsB;CAEnD,IAAI,oBAAoB,GACtB,MAAM,IAAI,mCAAmC;CAG/C,MAAM,WAAwC,OAAO,SAAS,WAAW,SAAS;EAKhF,IAAI,oBAAoB,GAAG,OAAO,KAAK,KAAK;EAE5C,AAAC,QAAqC,4BAA4B,wBAChE,OACA,iBACF;EAEA,KAAK,KAAK;CACZ;CAEA,OAAO;EACL,MAAM;EAGN,OAAO;EACP,gBAAgB,QAAQ;GAItB,aAAa;IACX,OAAO,YAAY,IAAI,OAAO;GAChC;EACF;CACF;AACF;;;;;;;;;;;;;AAcA,SAAgB,qBAAqB,SAA0B,UAAmC;CAChG,MAAM,OAAQ,QAAqC;CAEnD,IAAI,OAAO,SAAS,UAAU,OAAO;CAIrC,IAAI,SAAS,eAAe,SAAS,eAAe,OAAO;CAE3D,SAAS;CACT,SAAS,UAAU,gBAAgB,2BAA2B;CAG9D,SAAS,UAAU,iBAAiB,UAAU;CAC9C,SAAS,IAAI,IAAI;CAEjB,OAAO;AACT"}
1
+ {"version":3,"file":"dev-server.mjs","names":[],"sources":["../../../../../../../web/src/server/dev-server.ts"],"sourcesContent":["/** Development-only transport for Vite transform failures. */\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { stripVTControlCharacters } from \"node:util\";\nimport type { Connect, Plugin } from \"vite\";\n\n/**\n * Where a captured transform/resolve failure rides from Vite's connect stack to\n * the Fastify hook that mounted it.\n *\n * A `Symbol.for` key on the raw `IncomingMessage` rather than a `WeakMap`\n * because the two halves live in different modules and are wired at different\n * times; the request object is the only thing they provably share, and the\n * symbol cannot collide with a Vite/Fastify/user property.\n *\n * Exported so a test can stage a captured failure without booting a vite\n * server, and so the two halves cannot drift onto two different keys.\n */\nexport const DEV_TRANSFORM_ERROR_BODY = Symbol.for(\"warlock.web.devTransformErrorBody\");\n\n/**\n * Re-exported so a dev-only caller can reach the cookie commit seam through\n * this module without a second import path into `./buffered-response`, which\n * is where the implementation actually lives.\n */\nexport { applyBufferedCookie, type BufferedCookie } from \"./buffered-response\";\n\ntype DevTransformErrorCarrier = { [DEV_TRANSFORM_ERROR_BODY]?: string };\n\n/**\n * The status a refused module now answers with.\n *\n * NOT the 404 this replaces. That 404 was never a decision about the module —\n * it is what an unmatched URL gets once vite has declined it, and which of the\n * two framework answers you see depends only on whether the app declares a\n * catch-all page: with one (v5/app does — `path: \"*\"`) the request lands in the\n * page pipeline, matches no route, and `./render-page.ts:604` returns\n * `{ html: \"\", status: 404 }` for `./create-page-route-handler.ts:147` to write\n * as an empty `text/html` body; without one it is `core/src/router/router.ts:879`.\n * Either way \"the module does not exist\" is precisely the wrong thing to tell a\n * developer whose module exists and was refused. 500 is the status VITE ITSELF writes for\n * this exact condition when it is not in middleware mode\n * (`node_modules/vite/dist/node/chunks/config.js:9528`), so this adopts that\n * convention rather than inventing a third one.\n */\nexport const DEV_TRANSFORM_ERROR_STATUS = 500;\n\n/**\n * `buildErrorMessage` as vite exports it. Declared structurally so this module\n * needs no value import of vite — vite is an optional, dev-only peer and a\n * production install does not carry it.\n */\nexport type BuildErrorMessage = (\n error: Error,\n args?: string[],\n includeStack?: boolean,\n) => string;\n\n/**\n * The dev error transport was constructed while the process is hosting a\n * PRODUCTION build. Refused by name at construction rather than degraded,\n * because everything this transport does — file paths, source frames, plugin\n * names — is exactly what a production response must never carry.\n */\nexport class DevErrorTransportInProductionError extends Error {\n public constructor() {\n super(\n \"The dev error transport was constructed with `Application.runtimeStrategy === \" +\n '\"production\"`. It exists only to put a Vite transform failure in front of a ' +\n \"developer and its response body carries absolute file paths and source frames, \" +\n \"so it must never be mounted on a production-hosted server.\",\n );\n this.name = \"DevErrorTransportInProductionError\";\n }\n}\n\n/**\n * Render a refused module's failure as the plain-text body the browser gets.\n *\n * Formatting is DELEGATED to vite's own exported `buildErrorMessage`, not\n * reimplemented: it is the same function vite uses to print the failure to the\n * terminal, so the text a developer reads in the network panel and the text\n * they read in the terminal cannot drift. Two things are added around it —\n * `error.name`, which vite's terminal path replaces with a fixed\n * \"Internal server error:\" prefix and which is the single most useful token for\n * a named gate refusal (`ProjectionAmbiguityError`), and the `cause` chain,\n * which vite does not walk.\n *\n * `stripVTControlCharacters` is not optional: `buildErrorMessage` colours its\n * output with picocolors, which is ON whenever the dev server owns a TTY, and\n * raw ANSI escapes in an HTTP body are noise. Vite strips them the same way for\n * the overlay payload (`config.js:9490-9497`).\n *\n * The stack is deliberately omitted (`includeStack: false`). A gate refusal's\n * stack points into the gate, not into the developer's code; the fields that\n * locate the problem — plugin, file, line, source frame — are what\n * `buildErrorMessage` puts there without it.\n */\nexport function formatDevTransformError(\n error: unknown,\n buildErrorMessage: BuildErrorMessage,\n): string {\n const failure =\n error instanceof Error ? error : new Error(typeof error === \"string\" ? error : String(error));\n\n const lines = [\n stripVTControlCharacters(\n buildErrorMessage(failure, [`${failure.name}: ${failure.message}`], false),\n ),\n ];\n\n // Walk the `cause` chain. A gate may wrap a parser failure, and the wrapped\n // message is usually the one naming the actual syntax that was refused.\n let cause = (failure as { cause?: unknown }).cause;\n\n while (cause instanceof Error) {\n lines.push(` Caused by: ${cause.name}: ${stripVTControlCharacters(cause.message)}`);\n cause = (cause as { cause?: unknown }).cause;\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n\n/**\n * DEV-ONLY. Capture the transform/resolve failure that vite is about to throw\n * away, so the request that caused it can answer with it.\n *\n * WHY THIS IS A PLUGIN AND NOT A `middlewares.use(...)` CALL — this is the\n * whole defect, and it is an ordering fact, not a style choice:\n *\n * - Vite mounts its own error handler LAST, built as\n * `errorMiddleware(server, !!middlewareMode)`\n * (`node_modules/vite/dist/node/chunks/config.js:25705`).\n * - In middleware mode that `allowNext` flag is `true`, and the handler then\n * logs the error to the TERMINAL and calls `next()` — with no error\n * (`config.js:9525-9527`).\n * - connect only routes an error to a 4-arity handler while an error is in\n * flight (`config.js:10611-10626`), so `next()` clears it: every layer after\n * that point, INCLUDING the `done` callback `./web-connector.ts` hands the\n * stack, is called as if the request had simply gone unhandled. The\n * framework then answers the only way it can for a URL it does not know — a\n * 404, empty (see {@link DEV_TRANSFORM_ERROR_STATUS} for which of the two\n * produces it).\n * - Anything registered with `vite.middlewares.use(...)` after `createServer()`\n * resolves lands AFTER that handler and is therefore unreachable. A\n * `configureServer` POST hook does not: vite runs post hooks at\n * `config.js:25700`, five lines BEFORE it mounts its error handler.\n *\n * So this sits between the failure and vite's logger. It captures, then calls\n * `next(error)` and lets vite's own handler run exactly as before — the\n * terminal message and the `hot.send({ type: \"error\" })` overlay push\n * (`config.js:9511-9521`) are unchanged. This transport ADDS a reader; it\n * replaces nothing.\n *\n * @param isProductionRuntime the connector's own hosting-mode signal\n * (`./web-connector.ts:122`) — passed in rather than re-derived so there\n * is one definition of \"this process is Vite-hosted\", not two.\n */\nexport function devErrorTransportPlugin(options: {\n isProductionRuntime: () => boolean;\n buildErrorMessage: BuildErrorMessage;\n}): Plugin {\n const { isProductionRuntime, buildErrorMessage } = options;\n\n if (isProductionRuntime()) {\n throw new DevErrorTransportInProductionError();\n }\n\n const capture: Connect.ErrorHandleFunction = (error, request, _response, next) => {\n // Re-asserted per request, not just at construction: `runtimeStrategy` is\n // process state and a transport that leaks source frames is not something\n // to hold open on a boot-time reading alone. In production this layer is a\n // pass-through and vite's handler behaves exactly as it does today.\n if (isProductionRuntime()) return next(error);\n\n (request as DevTransformErrorCarrier)[DEV_TRANSFORM_ERROR_BODY] = formatDevTransformError(\n error,\n buildErrorMessage,\n );\n\n next(error);\n };\n\n return {\n name: \"warlock:dev-error-transport\",\n // Belt to the `isProductionRuntime` braces: this plugin has no business in\n // a `vite build` graph either.\n apply: \"serve\",\n configureServer(server) {\n // RETURNING a function is what makes this a POST hook — the ordering the\n // note above depends on. Mounting inline here would land the layer BEFORE\n // vite's transform middleware, where no error has been thrown yet.\n return () => {\n server.middlewares.use(capture);\n };\n },\n };\n}\n\n/**\n * Answer the request with the failure {@link devErrorTransportPlugin} captured,\n * if there was one. Returns `false` when there was not, which is the normal\n * case and means \"carry on down the framework's own path\".\n *\n * Called from the Fastify `onRequest` hook that mounts vite\n * (`./web-connector.ts:321`), in the `done` callback — i.e. at the one moment\n * where connect has finished, vite has declined to answer, and the framework is\n * about to 404. Writing to the raw `ServerResponse` rather than through Fastify\n * is what the mount already does for every response vite serves, so this stays\n * on the same side of the seam.\n */\nexport function sendCapturedDevError(request: IncomingMessage, response: ServerResponse): boolean {\n const body = (request as DevTransformErrorCarrier)[DEV_TRANSFORM_ERROR_BODY];\n\n if (typeof body !== \"string\") return false;\n\n // A middleware further down may have answered already (vite serves plenty of\n // requests itself). Never write twice; the captured body is then just dropped.\n if (response.headersSent || response.writableEnded) return false;\n\n response.statusCode = DEV_TRANSFORM_ERROR_STATUS;\n response.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n // A refusal is a fact about the CURRENT source. Caching it would survive the\n // edit that fixes it.\n response.setHeader(\"cache-control\", \"no-store\");\n response.end(body);\n\n return true;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAiBA,MAAa,2BAA2B,OAAO,IAAI,mCAAmC;;;;;;;;;;;;;;;;;AA2BtF,MAAa,6BAA6B;;;;;;;AAmB1C,IAAa,qCAAb,cAAwD,MAAM;CAC5D,AAAO,cAAc;EACnB,MACE,uSAIF;EACA,KAAK,OAAO;CACd;AACF;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,wBACd,OACA,mBACQ;CACR,MAAM,UACJ,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,UAAU,WAAW,QAAQ,OAAO,KAAK,CAAC;CAE9F,MAAM,QAAQ,CACZ,yBACE,kBAAkB,SAAS,CAAC,GAAG,QAAQ,KAAK,IAAI,QAAQ,SAAS,GAAG,KAAK,CAC3E,CACF;CAIA,IAAI,QAAS,QAAgC;CAE7C,OAAO,iBAAiB,OAAO;EAC7B,MAAM,KAAK,gBAAgB,MAAM,KAAK,IAAI,yBAAyB,MAAM,OAAO,GAAG;EACnF,QAAS,MAA8B;CACzC;CAEA,OAAO,GAAG,MAAM,KAAK,IAAI,EAAE;AAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,SAAgB,wBAAwB,SAG7B;CACT,MAAM,EAAE,qBAAqB,sBAAsB;CAEnD,IAAI,oBAAoB,GACtB,MAAM,IAAI,mCAAmC;CAG/C,MAAM,WAAwC,OAAO,SAAS,WAAW,SAAS;EAKhF,IAAI,oBAAoB,GAAG,OAAO,KAAK,KAAK;EAE5C,AAAC,QAAqC,4BAA4B,wBAChE,OACA,iBACF;EAEA,KAAK,KAAK;CACZ;CAEA,OAAO;EACL,MAAM;EAGN,OAAO;EACP,gBAAgB,QAAQ;GAItB,aAAa;IACX,OAAO,YAAY,IAAI,OAAO;GAChC;EACF;CACF;AACF;;;;;;;;;;;;;AAcA,SAAgB,qBAAqB,SAA0B,UAAmC;CAChG,MAAM,OAAQ,QAAqC;CAEnD,IAAI,OAAO,SAAS,UAAU,OAAO;CAIrC,IAAI,SAAS,eAAe,SAAS,eAAe,OAAO;CAE3D,SAAS;CACT,SAAS,UAAU,gBAAgB,2BAA2B;CAG9D,SAAS,UAAU,iBAAiB,UAAU;CAC9C,SAAS,IAAI,IAAI;CAEjB,OAAO;AACT"}
@@ -0,0 +1,14 @@
1
+ import { ServerErrorPageProps } from "../props.mjs";
2
+ import { MetadataOutput } from "../metadata.mjs";
3
+ //#region ../web/src/server/error-page.d.ts
4
+ /** Server-only shape of an application-owned `error.page.tsx` namespace. */
5
+ type ErrorPageModule = {
6
+ register?: () => unknown;
7
+ default?: unknown;
8
+ metadata?: MetadataOutput | ((props: ServerErrorPageProps) => MetadataOutput);
9
+ };
10
+ /** Deliberately lazy: normal requests never even load error.page.tsx. */
11
+ type ErrorPageModuleLoader = () => Promise<ErrorPageModule>;
12
+ //#endregion
13
+ export { ErrorPageModuleLoader };
14
+ //# sourceMappingURL=error-page.d.mts.map
@@ -0,0 +1,39 @@
1
+ import { ERROR_PAGE_METADATA } from "./resolve-page-metadata.mjs";
2
+
3
+ //#region ../web/src/server/error-page.ts
4
+ function serializePageError(thrown) {
5
+ if (thrown instanceof Error) return {
6
+ name: thrown.name || "Error",
7
+ message: thrown.message,
8
+ ...process.env.NODE_ENV !== "production" && typeof thrown.stack === "string" ? { stack: thrown.stack } : {}
9
+ };
10
+ let message;
11
+ try {
12
+ message = typeof thrown === "string" ? thrown : String(thrown);
13
+ } catch {
14
+ message = "An unexpected error occurred.";
15
+ }
16
+ return {
17
+ name: "Error",
18
+ message
19
+ };
20
+ }
21
+ /** Error-page metadata improves the safe framework default; it cannot remove noindex. */
22
+ function resolveErrorPageMetadata(module, props) {
23
+ const own = typeof module.metadata === "function" ? module.metadata(props) : module.metadata;
24
+ return {
25
+ ...ERROR_PAGE_METADATA,
26
+ ...own,
27
+ robots: own?.robots ?? ERROR_PAGE_METADATA.robots
28
+ };
29
+ }
30
+ function hydrationErrorPageProps(props, serializableError = props.error) {
31
+ return {
32
+ error: serializePageError(serializableError),
33
+ status: props.status
34
+ };
35
+ }
36
+
37
+ //#endregion
38
+ export { hydrationErrorPageProps, resolveErrorPageMetadata };
39
+ //# sourceMappingURL=error-page.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-page.mjs","names":[],"sources":["../../../../../../../web/src/server/error-page.ts"],"sourcesContent":["import type { SerializedErrorPageProps, SerializedPageError } from \"../components/document-context\";\nimport { ERROR_PAGE_METADATA } from \"./resolve-page-metadata\";\nimport type { MetadataOutput } from \"../metadata\";\nimport type { ServerErrorPageProps } from \"../props\";\n\n/** Server-only shape of an application-owned `error.page.tsx` namespace. */\nexport type ErrorPageModule = {\n register?: () => unknown;\n default?: unknown;\n metadata?: MetadataOutput | ((props: ServerErrorPageProps) => MetadataOutput);\n};\n\n/** Deliberately lazy: normal requests never even load error.page.tsx. */\nexport type ErrorPageModuleLoader = () => Promise<ErrorPageModule>;\n\nexport function serializePageError(thrown: unknown): SerializedPageError {\n if (thrown instanceof Error) {\n return {\n name: thrown.name || \"Error\",\n message: thrown.message,\n ...(process.env.NODE_ENV !== \"production\" && typeof thrown.stack === \"string\"\n ? { stack: thrown.stack }\n : {}),\n };\n }\n\n let message: string;\n try {\n message = typeof thrown === \"string\" ? thrown : String(thrown);\n } catch {\n message = \"An unexpected error occurred.\";\n }\n\n return {\n name: \"Error\",\n message,\n };\n}\n\n/** Error-page metadata improves the safe framework default; it cannot remove noindex. */\nexport function resolveErrorPageMetadata(\n module: ErrorPageModule,\n props: ServerErrorPageProps,\n): MetadataOutput {\n const own = typeof module.metadata === \"function\" ? module.metadata(props) : module.metadata;\n\n return { ...ERROR_PAGE_METADATA, ...own, robots: own?.robots ?? ERROR_PAGE_METADATA.robots };\n}\n\nexport function hydrationErrorPageProps(\n props: ServerErrorPageProps,\n serializableError: unknown = props.error,\n): SerializedErrorPageProps {\n return { error: serializePageError(serializableError), status: props.status };\n}\n"],"mappings":";;;AAeA,SAAgB,mBAAmB,QAAsC;CACvE,IAAI,kBAAkB,OACpB,OAAO;EACL,MAAM,OAAO,QAAQ;EACrB,SAAS,OAAO;EAChB,GAAI,QAAQ,IAAI,aAAa,gBAAgB,OAAO,OAAO,UAAU,WACjE,EAAE,OAAO,OAAO,MAAM,IACtB,CAAC;CACP;CAGF,IAAI;CACJ,IAAI;EACF,UAAU,OAAO,WAAW,WAAW,SAAS,OAAO,MAAM;CAC/D,QAAQ;EACN,UAAU;CACZ;CAEA,OAAO;EACL,MAAM;EACN;CACF;AACF;;AAGA,SAAgB,yBACd,QACA,OACgB;CAChB,MAAM,MAAM,OAAO,OAAO,aAAa,aAAa,OAAO,SAAS,KAAK,IAAI,OAAO;CAEpF,OAAO;EAAE,GAAG;EAAqB,GAAG;EAAK,QAAQ,KAAK,UAAU,oBAAoB;CAAO;AAC7F;AAEA,SAAgB,wBACd,OACA,oBAA6B,MAAM,OACT;CAC1B,OAAO;EAAE,OAAO,mBAAmB,iBAAiB;EAAG,QAAQ,MAAM;CAAO;AAC9E"}
@@ -1,7 +1,10 @@
1
- import { ExecutePageRequestOptions, PageBoundaryDesignation, PageContextRunner, PageDataBundle, PageErrorRecord, PageLevelName, PageResponseCommit, PageRouteEntry, PageRouteMatch, PageShortCircuit, PageTripleModule, PipelineLoader, PipelineMiddleware, PipelineRequest, PipelineResponse, PipelineStore } from "./execute-page-request.types.mjs";
2
- import { connectPageContext, connectPageSharedScope } from "./page-context.mjs";
1
+ import { BufferedCookie, BufferedHeader, LoaderShortCircuitKind, PageResponseCommit } from "./settle-page-response.mjs";
2
+ import { ExecutePageRequestOptions, PageBoundaryDesignation, PageContextRunner, PageDataBundle, PageErrorRecord, PageLevelName, PageRouteEntry, PageRouteMatch, PageShortCircuit, PageTripleModule, PipelineLoader, PipelineLoaderContext, PipelineMiddleware, PipelineStore } from "./execute-page-request.types.mjs";
3
+ import { connectPageContext } from "./page-context.mjs";
4
+ import { Response } from "@warlock.js/core";
5
+
3
6
  //#region ../web/src/server/execute-page-request.d.ts
4
- declare function executePageRequest<TResult = PageDataBundle>(options: ExecutePageRequestOptions<TResult>): Promise<TResult | undefined>;
7
+ declare function executePageRequest<TResult = PageDataBundle>(options: ExecutePageRequestOptions<TResult>): Promise<TResult | Response | undefined>;
5
8
  //#endregion
6
9
  export { executePageRequest };
7
10
  //# sourceMappingURL=execute-page-request.d.mts.map
@@ -1,10 +1,10 @@
1
- import { enterSharedScope, sealShared, shared } from "../shared.mjs";
2
- import { createBufferedResponse, isLoaderShortCircuit } from "./buffered-response.mjs";
3
- import { connectPageContext, connectPageSharedScope, enterAdditionalSharedScope, requireRunner } from "./page-context.mjs";
4
- import { matchRoute } from "./match-page-route.mjs";
1
+ import { enterSharedScope, sealShared } from "../shared.mjs";
5
2
  import { resolvePageMetadata } from "./resolve-page-metadata.mjs";
3
+ import { connectPageContext, enterAdditionalSharedScope, requireRunner } from "./page-context.mjs";
4
+ import { matchRoute } from "./match-page-route.mjs";
6
5
  import { resolveValidationData } from "./resolve-validation-data.mjs";
7
- import { LEVEL_ORDER, buildErrorRecord, commitBuffers, designateBoundary } from "./settle-page-response.mjs";
6
+ import { LEVEL_ORDER, buildErrorRecord, commitBuffers, createBufferedResponse, createLevelBuffer, designateBoundary, isLoaderShortCircuit } from "./settle-page-response.mjs";
7
+ import { Response } from "@warlock.js/core";
8
8
  import { v } from "@warlock.js/seal";
9
9
 
10
10
  //#region ../web/src/server/execute-page-request.ts
@@ -28,9 +28,9 @@ async function executePageRequest(options) {
28
28
  request,
29
29
  response
30
30
  };
31
- return await runner.run(store, async () => {
31
+ return runner.run(store, async () => {
32
32
  enterSharedScope(store);
33
- enterAdditionalSharedScope(store);
33
+ /* @__PURE__ */ enterAdditionalSharedScope(store);
34
34
  const finish = async (bundle) => options.finish ? await options.finish(bundle) : bundle;
35
35
  const bundle = { route: {
36
36
  name: matched.entry.name,
@@ -47,7 +47,7 @@ async function executePageRequest(options) {
47
47
  });
48
48
  } catch (thrown) {
49
49
  bundle.error = buildErrorRecord(thrown, designateBoundary(level, triple), pathname);
50
- bundle.commit = commitBuffers(response, [], 500);
50
+ response.setStatusCode(500);
51
51
  return finish(bundle);
52
52
  }
53
53
  if (output !== void 0) {
@@ -64,7 +64,7 @@ async function executePageRequest(options) {
64
64
  if (validation?.schema) {
65
65
  const data = resolveValidationData(validation.validating, request);
66
66
  const result = await v.validate(validation.schema, data);
67
- if (result.isValid && result.data) request.setValidatedData?.(result.data);
67
+ if (result.isValid && result.data) request.setValidatedData(result.data);
68
68
  if (!result.isValid) {
69
69
  bundle.shortCircuit = {
70
70
  stage: "validation",
@@ -76,86 +76,85 @@ async function executePageRequest(options) {
76
76
  }
77
77
  const sealedShared = await sealShared(store);
78
78
  bundle.shared = sealedShared;
79
- const buffers = LEVEL_ORDER.map((level) => {
80
- const { response: bufferedResponse, buffer } = createBufferedResponse();
81
- return {
82
- level,
83
- buffer,
84
- bufferedResponse
85
- };
86
- });
87
- const settled = await Promise.allSettled(buffers.map(({ level, bufferedResponse }) => {
88
- const loader = triple[level].loader;
89
- return (async () => loader ? await loader({
90
- request,
91
- response: bufferedResponse,
92
- shared
93
- }) : void 0)();
94
- }));
95
- let firstError;
96
- let firstSignal;
97
- function toSignal(value) {
98
- return isLoaderShortCircuit(value) ? value : void 0;
99
- }
100
- for (let index = 0; index < LEVEL_ORDER.length; index++) {
101
- const result = settled[index];
102
- if (result.status === "rejected") {
103
- firstError = {
104
- level: LEVEL_ORDER[index],
105
- index,
106
- error: result.reason
107
- };
108
- break;
109
- }
110
- const signal = toSignal(result.value);
111
- if (signal) {
112
- firstSignal = {
113
- level: LEVEL_ORDER[index],
114
- index,
115
- signal
116
- };
117
- break;
118
- }
119
- }
120
79
  const dataKeys = {
121
80
  app: "appData",
122
81
  layout: "layoutData",
123
82
  page: "pageData"
124
83
  };
125
- const dataCutoff = firstSignal ? firstSignal.index : LEVEL_ORDER.length;
84
+ const buffers = {
85
+ app: createLevelBuffer(),
86
+ layout: createLevelBuffer(),
87
+ page: createLevelBuffer()
88
+ };
89
+ let signalIndex = -1;
90
+ let signalKind;
91
+ let signalThrown;
92
+ let signalCircuit;
126
93
  for (let index = 0; index < LEVEL_ORDER.length; index++) {
127
- const result = settled[index];
128
- if (result.status !== "fulfilled") continue;
129
- if (firstError && index === firstError.index) continue;
130
- if (index > dataCutoff) continue;
131
- if (toSignal(result.value)) continue;
132
- bundle[dataKeys[LEVEL_ORDER[index]]] = result.value;
94
+ const level = LEVEL_ORDER[index];
95
+ const loader = triple[level].loader;
96
+ if (!loader) continue;
97
+ let value;
98
+ try {
99
+ value = await loader({
100
+ request,
101
+ response: createBufferedResponse(buffers[level]),
102
+ shared: sealedShared
103
+ });
104
+ } catch (thrown) {
105
+ signalIndex = index;
106
+ signalKind = "throw";
107
+ signalThrown = thrown;
108
+ break;
109
+ }
110
+ if (value instanceof Response) return value;
111
+ if (isLoaderShortCircuit(value)) {
112
+ signalIndex = index;
113
+ signalKind = "shortCircuit";
114
+ signalCircuit = value;
115
+ break;
116
+ }
117
+ bundle[dataKeys[level]] = value;
133
118
  }
134
- if (firstError) {
135
- const boundary = designateBoundary(firstError.level, triple);
136
- bundle.error = buildErrorRecord(firstError.error, boundary, pathname);
137
- bundle.commit = commitBuffers(response, buffers.slice(0, firstError.index), boundary.boundaryLevel === "app" ? 500 : void 0);
138
- } else if (firstSignal) {
119
+ let committedLevels;
120
+ /** Set only when a THROW escalated to the app boundary forces 500. */
121
+ let forcedStatusCode;
122
+ if (signalIndex === -1) committedLevels = [...LEVEL_ORDER];
123
+ else if (signalKind === "throw") {
124
+ committedLevels = LEVEL_ORDER.slice(0, signalIndex);
125
+ const boundary = designateBoundary(LEVEL_ORDER[signalIndex], triple);
126
+ bundle.error = buildErrorRecord(signalThrown, boundary, pathname);
127
+ if (boundary.boundaryLevel === "app") {
128
+ response.setStatusCode(500);
129
+ forcedStatusCode = 500;
130
+ }
131
+ } else {
132
+ committedLevels = LEVEL_ORDER.slice(0, signalIndex + 1);
133
+ const circuit = signalCircuit;
139
134
  bundle.shortCircuit = {
140
135
  stage: "loaders",
141
- level: firstSignal.level,
142
- kind: firstSignal.signal.kind,
143
- statusCode: firstSignal.signal.statusCode,
144
- url: firstSignal.signal.url,
145
- body: firstSignal.signal.body
136
+ level: LEVEL_ORDER[signalIndex],
137
+ kind: circuit.kind,
138
+ statusCode: circuit.statusCode,
139
+ url: circuit.url,
140
+ body: circuit.body
146
141
  };
147
- bundle.commit = commitBuffers(response, buffers.slice(0, firstSignal.index + 1));
148
- } else bundle.commit = commitBuffers(response, buffers);
149
- if (!bundle.shortCircuit) {
150
- const resolved = resolvePageMetadata({
151
- metadata: triple.page.metadata,
152
- data: bundle.pageData,
153
- error: bundle.error?.error,
154
- failed: Boolean(bundle.error),
155
- shared: sealedShared
156
- });
157
- bundle.metadata = resolved.metadata;
158
- if (resolved.thrown !== void 0) bundle.error = buildErrorRecord(resolved.thrown, designateBoundary("page", triple), bundle.route.path);
142
+ }
143
+ bundle.commit = commitBuffers(response, buffers, committedLevels);
144
+ if (forcedStatusCode !== void 0) bundle.commit.statusCode = forcedStatusCode;
145
+ if (bundle.shortCircuit) return finish(bundle);
146
+ const resolved = resolvePageMetadata({
147
+ metadata: triple.page.metadata,
148
+ data: bundle.pageData,
149
+ error: bundle.error?.error,
150
+ failed: Boolean(bundle.error),
151
+ shared: sealedShared
152
+ });
153
+ bundle.metadata = resolved.metadata;
154
+ if (resolved.thrown !== void 0) {
155
+ const boundary = designateBoundary("page", triple);
156
+ bundle.error = buildErrorRecord(resolved.thrown, boundary, bundle.route.path);
157
+ if (boundary.boundaryLevel === "app") response.setStatusCode(500);
159
158
  }
160
159
  return finish(bundle);
161
160
  });
@@ -1 +1 @@
1
- {"version":3,"file":"execute-page-request.mjs","names":[],"sources":["../../../../../../../web/src/server/execute-page-request.ts"],"sourcesContent":["import { v } from \"@warlock.js/seal\";\nimport { createBufferedResponse, isLoaderShortCircuit } from \"./buffered-response\";\nimport type { LoaderShortCircuitSignal } from \"./buffered-response\";\nimport { enterSharedScope, sealShared, shared } from \"../shared\";\nimport { enterAdditionalSharedScope, requireRunner } from \"./page-context\";\nimport { matchRoute } from \"./match-page-route\";\nimport { resolvePageMetadata } from \"./resolve-page-metadata\";\nimport { resolveValidationData } from \"./resolve-validation-data\";\nimport {\n buildErrorRecord,\n commitBuffers,\n designateBoundary,\n LEVEL_ORDER,\n} from \"./settle-page-response\";\nimport type {\n ExecutePageRequestOptions,\n PageDataBundle,\n PageLevelName,\n PageRouteMatch,\n PipelineResponse,\n PipelineStore,\n} from \"./execute-page-request.types\";\n\n/**\n * Pipeline stages 1–8 of a page request; stages 9–10 (render/emit) are the\n * render slice's, and this ends at the DATA BUNDLE.\n *\n * The founding sentence governs the shape — a page route is an ordinary Warlock\n * route whose handler renders React instead of returning JSON — so every stage\n * mirrors what core already does for an API request: core's own ALS store and\n * `run`, core's middleware short-circuit rule (`output !== undefined`), and\n * `validateAll`'s validation with its 422, recorded as a designation because\n * sending is the emit's job.\n *\n * The pieces live beside this file: `page-context.ts` (stage 2 wiring),\n * `match-page-route.ts` (stage 1), `resolve-validation-data.ts` (stage 4),\n * `settle-page-response.ts` (stage 7), `resolve-page-metadata.ts` (stage 8).\n */\n\nexport * from \"./execute-page-request.types\";\nexport { connectPageContext, connectPageSharedScope } from \"./page-context\";\nexport { buildErrorRecord, designateBoundary } from \"./settle-page-response\";\n\nexport async function executePageRequest<TResult = PageDataBundle>(\n options: ExecutePageRequestOptions<TResult>,\n): Promise<TResult | undefined> {\n const runner = requireRunner();\n\n // ── stage 1 · MATCH ─────────────────────────────────────────────────────\n const [pathname, queryString] = options.url.split(\"?\");\n const matched = matchRoute(pathname, options.routes);\n\n if (!matched) return undefined;\n\n const query = Object.fromEntries(new URLSearchParams(queryString ?? \"\"));\n const match: PageRouteMatch = { entry: matched.entry, params: matched.params, query };\n const { triple } = matched.entry;\n\n const { request, response } = options.createHttp(match);\n\n // ── stage 2 · CONTEXT ───────────────────────────────────────────────────\n // Core's own store shape, built by core's own `buildStore` when the runner\n // carries one. `enterSharedScope` keys the shared target by this exact object.\n const store: PipelineStore = runner.buildStore\n ? runner.buildStore({ request, response })\n : { request, response };\n\n return await runner.run(store, async () => {\n enterSharedScope(store);\n enterAdditionalSharedScope(store);\n\n const finish = async (bundle: PageDataBundle): Promise<TResult> =>\n options.finish ? await options.finish(bundle) : (bundle as TResult);\n\n const bundle: PageDataBundle = {\n route: {\n name: matched.entry.name,\n path: matched.entry.path,\n params: match.params,\n query,\n },\n };\n\n // ── stage 3 · MIDDLEWARE ──────────────────────────────────────────────\n // Sequential, outermost first. Middleware gets the REAL request/response —\n // it runs alone, before any parallelism — and is the only writer of `shared`.\n for (const level of LEVEL_ORDER) {\n for (const middleware of triple[level].middleware ?? []) {\n let output: unknown;\n\n try {\n output = await middleware({ request, response });\n } catch (thrown) {\n /*\n A middleware throw means NOTHING was served: no loaders ran, no\n buffers exist. The \"a nested boundary keeps the committed status\"\n rule assumes the page was substantially served, so it cannot apply\n here — the framework forces 500 whichever level the boundary\n designates to.\n */\n bundle.error = buildErrorRecord(thrown, designateBoundary(level, triple), pathname);\n bundle.commit = commitBuffers(response, [], 500);\n\n return finish(bundle);\n }\n\n if (output !== undefined) {\n bundle.shortCircuit = {\n stage: \"middleware\",\n level,\n value: output,\n statusCode: (response as PipelineResponse & { statusCode?: number }).statusCode,\n };\n\n return finish(bundle);\n }\n }\n }\n\n // ── stage 4 · VALIDATION ──────────────────────────────────────────────\n // Failure stops before the seal: a 422 designation in the bundle, since\n // sending is the emit slice's job.\n const validation = triple.page.validation;\n\n if (validation?.schema) {\n const data = resolveValidationData(validation.validating, request);\n const result = await v.validate(validation.schema, data);\n\n if (result.isValid && result.data) {\n request.setValidatedData?.(result.data);\n }\n\n if (!result.isValid) {\n bundle.shortCircuit = { stage: \"validation\", status: 422, errors: result.errors };\n\n return finish(bundle);\n }\n }\n\n // ── stage 5 · SEAL shared ─────────────────────────────────────────────\n // From here `shared` is immutable and identical for every reader. The\n // bundle carries `sealShared`'s RETURN, never a proxy re-read.\n const sealedShared = await sealShared(store);\n\n bundle.shared = sealedShared;\n\n // ── stage 6 · LOADERS ─────────────────────────────────────────────────\n // Parallel, each with its OWN buffered response. Loaders never read each\n // other and cannot write `shared` — it is sealed, and a write throws.\n const buffers = LEVEL_ORDER.map(level => {\n const { response: bufferedResponse, buffer } = createBufferedResponse();\n\n return { level, buffer, bufferedResponse };\n });\n\n const settled = await Promise.allSettled(\n buffers.map(({ level, bufferedResponse }) => {\n const loader = triple[level].loader;\n\n return (async () =>\n loader ? await loader({ request, response: bufferedResponse, shared }) : undefined)();\n }),\n );\n\n // ── stage 7 · SETTLE / COMMIT ─────────────────────────────────────────\n // Walk root→leaf for the first abnormal outcome. A throw discards the\n // throwing layer's buffer and everything below it, and the framework owns\n // the status. A redirect/notFound commits the signalling layer's own buffer\n // and discards its siblings below.\n let firstError: { level: PageLevelName; index: number; error: unknown } | undefined;\n let firstSignal:\n | { level: PageLevelName; index: number; signal: LoaderShortCircuitSignal }\n | undefined;\n\n function toSignal(value: unknown) {\n return isLoaderShortCircuit(value) ? value : undefined;\n }\n\n for (let index = 0; index < LEVEL_ORDER.length; index++) {\n const result = settled[index];\n\n if (result.status === \"rejected\") {\n firstError = { level: LEVEL_ORDER[index], index, error: result.reason };\n break;\n }\n\n const signal = toSignal(result.value);\n\n if (signal) {\n firstSignal = { level: LEVEL_ORDER[index], index, signal };\n break;\n }\n }\n\n const dataKeys: Record<PageLevelName, \"appData\" | \"layoutData\" | \"pageData\"> = {\n app: \"appData\",\n layout: \"layoutData\",\n page: \"pageData\",\n };\n\n // A throw elsewhere never costs a healthy layer its data. Levels leafward\n // of a short-circuit go, because they will not render.\n const dataCutoff = firstSignal ? firstSignal.index : LEVEL_ORDER.length;\n\n for (let index = 0; index < LEVEL_ORDER.length; index++) {\n const result = settled[index];\n\n if (result.status !== \"fulfilled\") continue;\n if (firstError && index === firstError.index) continue;\n if (index > dataCutoff) continue;\n if (toSignal(result.value)) continue;\n\n bundle[dataKeys[LEVEL_ORDER[index]]] = result.value;\n }\n\n if (firstError) {\n const boundary = designateBoundary(firstError.level, triple);\n\n bundle.error = buildErrorRecord(firstError.error, boundary, pathname);\n\n // Commit strictly rootward of the throw. A NESTED boundary keeps the\n // committed status — the page was substantially served; only the ROOT\n // boundary forces 5xx.\n bundle.commit = commitBuffers(\n response,\n buffers.slice(0, firstError.index),\n boundary.boundaryLevel === \"app\" ? 500 : undefined,\n );\n } else if (firstSignal) {\n bundle.shortCircuit = {\n stage: \"loaders\",\n level: firstSignal.level,\n kind: firstSignal.signal.kind,\n statusCode: firstSignal.signal.statusCode,\n url: firstSignal.signal.url,\n body: firstSignal.signal.body,\n };\n bundle.commit = commitBuffers(response, buffers.slice(0, firstSignal.index + 1));\n } else {\n bundle.commit = commitBuffers(response, buffers);\n }\n\n // ── stage 8 · METADATA ────────────────────────────────────────────────\n // Skipped entirely after a loader short-circuit: a redirect/notFound answer\n // has no page render to describe.\n if (!bundle.shortCircuit) {\n const resolved = resolvePageMetadata({\n metadata: triple.page.metadata,\n data: bundle.pageData,\n error: bundle.error?.error,\n failed: Boolean(bundle.error),\n shared: sealedShared,\n });\n\n bundle.metadata = resolved.metadata;\n\n /*\n The page's own metadata function threw with no earlier error to mask.\n Record it exactly as a loader throw, so the boundary renders and the\n framework keeps the status — rather than letting it escape stage 8,\n where nothing is left to catch it and stage 7's buffers are already\n committed.\n */\n if (resolved.thrown !== undefined) {\n bundle.error = buildErrorRecord(\n resolved.thrown,\n designateBoundary(\"page\", triple),\n bundle.route.path,\n );\n }\n }\n\n return finish(bundle);\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"execute-page-request.mjs","names":[],"sources":["../../../../../../../web/src/server/execute-page-request.ts"],"sourcesContent":["import { Response } from \"@warlock.js/core\";\nimport { v } from \"@warlock.js/seal\";\nimport { enterSharedScope, sealShared } from \"../shared\";\nimport { enterAdditionalSharedScope, requireRunner } from \"./page-context\";\nimport { matchRoute } from \"./match-page-route\";\nimport { resolvePageMetadata } from \"./resolve-page-metadata\";\nimport { resolveValidationData } from \"./resolve-validation-data\";\nimport {\n buildErrorRecord,\n commitBuffers,\n createBufferedResponse,\n createLevelBuffer,\n designateBoundary,\n isLoaderShortCircuit,\n LEVEL_ORDER,\n type LevelBuffer,\n type PageResponseCommit,\n} from \"./settle-page-response\";\nimport type {\n ExecutePageRequestOptions,\n PageDataBundle,\n PageLevelName,\n PageRouteMatch,\n PipelineStore,\n} from \"./execute-page-request.types\";\n\nexport * from \"./execute-page-request.types\";\nexport { connectPageContext } from \"./page-context\";\nexport {\n buildErrorRecord,\n designateBoundary,\n type BufferedCookie,\n type BufferedHeader,\n type LoaderShortCircuitKind,\n type PageResponseCommit,\n} from \"./settle-page-response\";\n\n/** Widens `PageDataBundle` with the two fields stage 6/7 populate. */\ntype Bundle = PageDataBundle & {\n commit?: PageResponseCommit;\n shortCircuit?: PageDataBundle[\"shortCircuit\"] & {\n kind?: \"redirect\" | \"notFound\";\n url?: string;\n body?: unknown;\n };\n};\n\nexport async function executePageRequest<TResult = PageDataBundle>(\n options: ExecutePageRequestOptions<TResult>,\n): Promise<TResult | Response | undefined> {\n const runner = requireRunner();\n const [pathname, queryString] = options.url.split(\"?\");\n const matched = matchRoute(pathname, options.routes);\n\n if (!matched) return undefined;\n\n const query = Object.fromEntries(new URLSearchParams(queryString ?? \"\"));\n const match: PageRouteMatch = { entry: matched.entry, params: matched.params, query };\n const { triple } = matched.entry;\n const { request, response } = options.createHttp(match);\n const store: PipelineStore = runner.buildStore\n ? runner.buildStore({ request, response })\n : { request, response };\n\n return runner.run(store, async () => {\n enterSharedScope(store);\n enterAdditionalSharedScope(store);\n\n const finish = async (bundle: PageDataBundle): Promise<TResult> =>\n options.finish ? await options.finish(bundle) : (bundle as TResult);\n\n const bundle: Bundle = {\n route: {\n name: matched.entry.name,\n path: matched.entry.path,\n params: match.params,\n query,\n },\n };\n\n for (const level of LEVEL_ORDER) {\n for (const middleware of triple[level].middleware ?? []) {\n let output: unknown;\n\n try {\n output = await middleware({ request, response });\n } catch (thrown) {\n bundle.error = buildErrorRecord(thrown, designateBoundary(level, triple), pathname);\n response.setStatusCode(500);\n return finish(bundle);\n }\n\n if (output !== undefined) {\n bundle.shortCircuit = {\n stage: \"middleware\",\n level,\n value: output,\n statusCode: response.statusCode,\n };\n return finish(bundle);\n }\n }\n }\n\n const validation = triple.page.validation;\n\n if (validation?.schema) {\n const data = resolveValidationData(validation.validating, request);\n const result = await v.validate(validation.schema, data);\n\n if (result.isValid && result.data) {\n request.setValidatedData(result.data);\n }\n\n if (!result.isValid) {\n bundle.shortCircuit = { stage: \"validation\", status: 422, errors: result.errors };\n return finish(bundle);\n }\n }\n\n const sealedShared = await sealShared(store);\n bundle.shared = sealedShared;\n\n const dataKeys: Record<PageLevelName, \"appData\" | \"layoutData\" | \"pageData\"> = {\n app: \"appData\",\n layout: \"layoutData\",\n page: \"pageData\",\n };\n\n // Stage 6 — LOADERS, root to leaf. Every level gets its OWN buffer (never\n // the live response), and a terminal result or throw prevents every lower\n // loader from starting.\n const buffers: Record<PageLevelName, LevelBuffer> = {\n app: createLevelBuffer(),\n layout: createLevelBuffer(),\n page: createLevelBuffer(),\n };\n\n let signalIndex = -1;\n let signalKind: \"throw\" | \"shortCircuit\" | undefined;\n let signalThrown: unknown;\n let signalCircuit:\n | { kind: \"redirect\" | \"notFound\"; statusCode: number; url?: string; body?: unknown }\n | undefined;\n\n for (let index = 0; index < LEVEL_ORDER.length; index++) {\n const level = LEVEL_ORDER[index];\n const loader = triple[level].loader;\n\n if (!loader) continue;\n\n let value: unknown;\n\n try {\n value = await loader({\n request,\n response: createBufferedResponse(buffers[level]),\n shared: sealedShared,\n });\n } catch (thrown) {\n signalIndex = index;\n signalKind = \"throw\";\n signalThrown = thrown;\n break;\n }\n\n if (value instanceof Response) return value;\n\n if (isLoaderShortCircuit(value)) {\n signalIndex = index;\n signalKind = \"shortCircuit\";\n signalCircuit = value;\n break;\n }\n\n bundle[dataKeys[level]] = value;\n }\n\n let committedLevels: PageLevelName[];\n /** Set only when a THROW escalated to the app boundary — forces 500. */\n let forcedStatusCode: number | undefined;\n\n if (signalIndex === -1) {\n committedLevels = [...LEVEL_ORDER];\n } else if (signalKind === \"throw\") {\n // The throwing level's buffer is discarded; lower levels never ran.\n committedLevels = LEVEL_ORDER.slice(0, signalIndex);\n\n const boundary = designateBoundary(LEVEL_ORDER[signalIndex], triple);\n bundle.error = buildErrorRecord(signalThrown, boundary, pathname);\n\n if (boundary.boundaryLevel === \"app\") {\n response.setStatusCode(500);\n forcedStatusCode = 500;\n }\n } else {\n // Short-circuit: the signalling level's OWN buffer commits too\n // (inclusive); lower levels never ran.\n committedLevels = LEVEL_ORDER.slice(0, signalIndex + 1);\n\n const circuit = signalCircuit!;\n\n bundle.shortCircuit = {\n stage: \"loaders\",\n level: LEVEL_ORDER[signalIndex],\n kind: circuit.kind,\n statusCode: circuit.statusCode,\n url: circuit.url,\n body: circuit.body,\n } as unknown as PageDataBundle[\"shortCircuit\"];\n }\n\n bundle.commit = commitBuffers(response, buffers, committedLevels);\n\n // Forced AFTER the fold: an app-boundary escalation forces 500\n // regardless of what the surviving (rootward) buffers happened to set —\n // it is the framework's answer, not a loader's.\n if (forcedStatusCode !== undefined) bundle.commit.statusCode = forcedStatusCode;\n\n // Stage 8 — METADATA. Skipped entirely for a short-circuit (there is no\n // page to describe); a throw still runs it, same as before this stage 6/7\n // rewrite (a boundary still needs a title/robots answer).\n if (bundle.shortCircuit) {\n return finish(bundle);\n }\n\n const resolved = resolvePageMetadata({\n metadata: triple.page.metadata,\n data: bundle.pageData,\n error: bundle.error?.error,\n failed: Boolean(bundle.error),\n shared: sealedShared,\n });\n\n bundle.metadata = resolved.metadata;\n\n if (resolved.thrown !== undefined) {\n const boundary = designateBoundary(\"page\", triple);\n bundle.error = buildErrorRecord(resolved.thrown, boundary, bundle.route.path);\n\n if (boundary.boundaryLevel === \"app\") response.setStatusCode(500);\n }\n\n return finish(bundle);\n });\n}\n"],"mappings":"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"}
@@ -1,67 +1,37 @@
1
1
  import { MetadataOutput, PageMetadata } from "../metadata.mjs";
2
+ import { SerializedErrorPageProps } from "../components/document-context.mjs";
2
3
  import { SharedStore } from "../shared.mjs";
3
4
  import { SharedContext } from "../index.mjs";
4
- import { WebRequest } from "../context.mjs";
5
- import { BufferedCookie, BufferedHeader, BufferedWebResponse } from "./buffered-response.mjs";
5
+ import { BufferedResponse } from "./settle-page-response.mjs";
6
+ import { HttpContext, Request, Response } from "@warlock.js/core";
6
7
  import { BaseValidator } from "@warlock.js/seal";
7
8
 
8
9
  //#region ../web/src/server/execute-page-request.types.d.ts
9
- /** At runtime this IS core's `RequestContextStore` (request-context.ts:10-13). */
10
10
  type PipelineStore = SharedStore & {
11
- request: unknown;
12
- response: unknown;
11
+ request: Request;
12
+ response: Response;
13
13
  };
14
- /**
15
- * Core's `requestContext` satisfies this as-is — `run`/`getStore` are the
16
- * inherited `Context` delegates and `buildStore` is `RequestContext.buildStore`,
17
- * the same function core's http path feeds through `contextManager.buildStores`.
18
- */
19
14
  type PageContextRunner = {
20
15
  run<T>(store: PipelineStore, callback: () => Promise<T>): Promise<T>;
21
16
  getStore(): PipelineStore | undefined;
22
17
  buildStore?(payload?: Record<string, any>): PipelineStore;
23
18
  };
24
19
  type PageLevelName = "app" | "layout" | "page";
20
+ type PipelineMiddleware = (ctx: HttpContext) => unknown | Promise<unknown>;
25
21
  /**
26
- * The request members the pipeline touches, declared explicitly rather than
27
- * imported from core: `WebRequest` is the loader-facing minimal facade and does
28
- * not carry the validation sources.
29
- *
30
- * `query`/`params` are core's own parses (request.ts:1010,1026) and the ONLY
31
- * ones the pipeline reads. Stage 4 used to take them from a match object built
32
- * by re-parsing the URL — `resolve-validation-data.ts` records what that cost.
33
- */
34
- type PipelineRequest = WebRequest & {
35
- body?: Record<string, unknown>;
36
- headers?: Record<string, unknown>;
37
- query?: Record<string, unknown>;
38
- params?: Record<string, unknown>;
39
- setValidatedData?(data: Record<string, unknown>): void;
40
- };
41
- /**
42
- * Standalone rather than based on `WebResponse`: that facade's
43
- * `redirect`/`notFound` return the branded short-circuit signal, which core's
44
- * real `Response` never carries — basing this on it would reject the very
45
- * instances the seam exists to admit.
22
+ * A loader never sees the live `Response` stage 6 hands it a per-level
23
+ * `BufferedResponse` (`execute-page-request.ts`, `createBufferedResponse`),
24
+ * so its own type says that, rather than the core `Response` a middleware
25
+ * receives.
46
26
  */
47
- type PipelineResponse = {
48
- header(key: string, value: string): PipelineResponse;
49
- cookie(name: string, value: unknown, options?: Record<string, unknown>): PipelineResponse;
50
- setStatusCode(statusCode: number): PipelineResponse;
51
- parse(value: unknown): Promise<unknown>;
52
- };
53
- /** Pass-through is `undefined` — core's exact rule (`Request.executeMiddleware`). */
54
- type PipelineMiddleware = (ctx: {
55
- request: PipelineRequest;
56
- response: PipelineResponse;
57
- }) => unknown | Promise<unknown>;
58
- type PipelineLoader = (ctx: {
59
- request: PipelineRequest;
60
- response: BufferedWebResponse;
27
+ type PipelineLoaderContext = {
28
+ request: Request;
29
+ response: BufferedResponse;
61
30
  shared: SharedContext;
62
- }) => unknown | Promise<unknown>;
63
- /** The server half of a page/layout/App module. */
31
+ };
32
+ type PipelineLoader = (ctx: PipelineLoaderContext) => unknown | Promise<unknown>;
64
33
  type PageTripleModule = {
34
+ register?: () => unknown;
65
35
  route?: string | {
66
36
  readonly path: string;
67
37
  readonly name?: string;
@@ -72,7 +42,7 @@ type PageTripleModule = {
72
42
  validating?: readonly string[];
73
43
  };
74
44
  loader?: PipelineLoader;
75
- metadata?: PageMetadata<PipelineLoader>; /** Runs-twice half — carried through untouched; the render slice consumes them. */
45
+ metadata?: PageMetadata<PipelineLoader>;
76
46
  default?: unknown;
77
47
  ErrorBoundary?: unknown;
78
48
  };
@@ -91,54 +61,27 @@ type PageRouteMatch = {
91
61
  query: Record<string, string>;
92
62
  };
93
63
  type ExecutePageRequestOptions<TResult = PageDataBundle> = {
94
- /** Path + optional query string, e.g. `/products/42?tab=specs`. */url: string;
64
+ url: string;
95
65
  routes: readonly PageRouteEntry[];
96
- /**
97
- * Construct the Request/Response pair for this match, mirroring core's
98
- * `handleRoute` body (router.ts:924-932).
99
- */
100
- createHttp(match: PageRouteMatch): {
101
- request: PipelineRequest;
102
- response: PipelineResponse;
103
- };
104
- /**
105
- * The render seam — continues stages 9-10 inside the exact ALS store and
106
- * shared scope that middleware and loaders used.
107
- */
66
+ createHttp(match: PageRouteMatch): HttpContext;
108
67
  finish?(bundle: PageDataBundle): TResult | Promise<TResult>;
109
68
  };
110
69
  type PageBoundaryDesignation = {
111
- throwingLevel: PageLevelName; /** Nearest boundary at or rootward of the throw; `app` is the terminal fallback. */
70
+ throwingLevel: PageLevelName;
112
71
  boundaryLevel: PageLevelName;
113
72
  };
114
- type PageResponseCommit = {
115
- /** Final per-key state, root→leaf: a leafward write wins its key. */headers: BufferedHeader[];
116
- cookies: BufferedCookie[];
117
- statusCode?: number;
118
- committedLevels: PageLevelName[];
119
- };
120
73
  type PageShortCircuit = {
121
74
  stage: "middleware";
122
75
  level: PageLevelName;
123
- value: unknown; /** Captured at stage 3, so `finishRender` stays a pure function of (triple, bundle). */
76
+ value: unknown;
124
77
  statusCode?: number;
125
78
  } | {
126
79
  stage: "validation";
127
80
  status: number;
128
81
  errors: unknown;
129
- } | {
130
- stage: "loaders";
131
- level: PageLevelName;
132
- kind: "redirect" | "notFound";
133
- statusCode: number;
134
- url?: string;
135
- body?: unknown;
136
82
  };
137
- /**
138
- * What a throw becomes once it enters the bundle. `scrubbed` says whether
139
- * `error` is the raw thrown value or a production surrogate standing in for it.
140
- */
141
83
  type PageErrorRecord = {
84
+ /** Never serialized; preserves the actual thrown value for server error.page.tsx. */originalError: unknown;
142
85
  error: unknown;
143
86
  boundary: PageBoundaryDesignation;
144
87
  digest: string;
@@ -149,26 +92,24 @@ type PageDataBundle = {
149
92
  name: string;
150
93
  path: string;
151
94
  params: Record<string, string>;
152
- /**
153
- * ⚠ Re-parsed from the URL by `match-page-route.ts`, NOT core's parse, so it
154
- * is flat and last-wins: `?tags=a&tags=b&filter[status]=active` arrives as
155
- * `{ tags: "b", "filter[status]": "active" }`.
156
- *
157
- * Nothing in `web` reads it — stage 4 was the last consumer. It survives
158
- * only as part of this public type and goes away with the second matcher.
159
- * **Read `request.query`.**
160
- */
161
95
  query: Record<string, string>;
162
96
  };
163
97
  appData?: unknown;
164
98
  layoutData?: unknown;
165
- pageData?: unknown; /** `sealShared()`'s RETURN — the sealed target, never a proxy re-read. */
99
+ pageData?: unknown;
166
100
  shared?: Readonly<SharedContext>;
167
101
  metadata?: MetadataOutput;
168
- commit?: PageResponseCommit;
169
102
  shortCircuit?: PageShortCircuit;
170
103
  error?: PageErrorRecord;
104
+ /**
105
+ * Selected only for the framework-owned application error-page terminal —
106
+ * already the JSON-safe shape (`hydrationErrorPageProps` produces this, not
107
+ * the raw `ErrorPageProps` an authored `error.page.tsx` renders from during
108
+ * SSR), because this field's only consumer is the hydration payload
109
+ * (`build-hydration-payload.ts`), never a component prop.
110
+ */
111
+ errorPage?: SerializedErrorPageProps;
171
112
  };
172
113
  //#endregion
173
- export { ExecutePageRequestOptions, PageBoundaryDesignation, PageContextRunner, PageDataBundle, PageErrorRecord, PageLevelName, PageResponseCommit, PageRouteEntry, PageRouteMatch, PageShortCircuit, PageTripleModule, PipelineLoader, PipelineMiddleware, PipelineRequest, PipelineResponse, PipelineStore };
114
+ export { ExecutePageRequestOptions, PageBoundaryDesignation, PageContextRunner, PageDataBundle, PageErrorRecord, PageLevelName, PageRouteEntry, PageRouteMatch, PageShortCircuit, PageTripleModule, PipelineLoader, PipelineLoaderContext, PipelineMiddleware, PipelineStore };
174
115
  //# sourceMappingURL=execute-page-request.types.d.mts.map
@@ -1,7 +1,7 @@
1
1
  import { CLIENT_ASSET_URL_PREFIX } from "./client-asset-url-prefix.mjs";
2
2
  import { HYDRATION_CLIENT_ENTRY_NAME } from "../vite/hydration-entries.mjs";
3
- import path from "node:path";
4
3
  import { readFileSync } from "node:fs";
4
+ import path from "node:path";
5
5
 
6
6
  //#region ../web/src/server/hydration-client-url.ts
7
7
  /**
@@ -1,9 +1,9 @@
1
1
  import { composeRoutePath } from "../routing/compose-route-path.mjs";
2
- import { connectSharedStore } from "../shared.mjs";
3
2
  import { PAYLOAD_SCRIPT_ID, escapePayload } from "../components/document-context.mjs";
4
- import { BufferedCookie, BufferedHeader, BufferedWebResponse, LOADER_SHORT_CIRCUIT, LoaderShortCircuitSignal, ResponseBuffer, createBufferedResponse, isLoaderShortCircuit } from "./buffered-response.mjs";
5
- import { ExecutePageRequestOptions, PageBoundaryDesignation, PageContextRunner, PageDataBundle, PageLevelName, PageResponseCommit, PageRouteEntry, PageRouteMatch, PageShortCircuit, PageTripleModule, PipelineLoader, PipelineMiddleware, PipelineStore } from "./execute-page-request.types.mjs";
6
- import { connectPageContext, connectPageSharedScope } from "./page-context.mjs";
3
+ import { connectSharedStore } from "../shared.mjs";
4
+ import { BufferedCookie, BufferedHeader, LoaderShortCircuitKind, PageResponseCommit } from "./settle-page-response.mjs";
5
+ import { ExecutePageRequestOptions, PageBoundaryDesignation, PageContextRunner, PageDataBundle, PageLevelName, PageRouteEntry, PageRouteMatch, PageShortCircuit, PageTripleModule, PipelineLoader, PipelineMiddleware, PipelineStore } from "./execute-page-request.types.mjs";
6
+ import { connectPageContext } from "./page-context.mjs";
7
7
  import { executePageRequest } from "./execute-page-request.mjs";
8
8
  import { InstallPageRoutesOptions, InstalledPageRoute, LayoutModuleShape, PageModuleShape, PageRouteExport, installPageRoutes } from "./install-page-routes.mjs";
9
9
  import { PageRoutesRegistry, RenderPageOptions, RenderPageRequestOptions, RenderedPage, connectPageRoutes, renderPage, renderPageRequest } from "./render-page.mjs";
@@ -11,4 +11,4 @@ import { PageModuleNotInManifestError, createPageModuleLoader } from "./create-p
11
11
  import { InstallPageRoutesFromManifestOptions, InstalledManifestPageRoute, PageRouteHandlerFactory, installPageRoutesFromManifest } from "./install-page-routes-from-manifest.mjs";
12
12
  import { DuplicateNotFoundPageError, NOT_FOUND_PAGE_FILENAME, NOT_FOUND_ROUTE_NAME, NOT_FOUND_ROUTE_PATH, NotFoundPageDeclaresRouteError, NotFoundRouteHandlerOptions, RegisteredRouteShape, UnmatchedRequestKind, acceptsHtmlExplicitly, classifyUnmatchedRequest, createNotFoundRouteHandler, frameworkDefaultNotFoundDocument, isNotFoundPageFile } from "./not-found-page.mjs";
13
13
  import { VITE_DIRECT_CSS_QUERY, devStylesheetUrls, productionStylesheetUrls } from "./stylesheet-urls.mjs";
14
- export { type BufferedCookie, type BufferedHeader, type BufferedWebResponse, DuplicateNotFoundPageError, type ExecutePageRequestOptions, type InstallPageRoutesFromManifestOptions, type InstallPageRoutesOptions, type InstalledManifestPageRoute, type InstalledPageRoute, LOADER_SHORT_CIRCUIT, type LayoutModuleShape, type LoaderShortCircuitSignal, NOT_FOUND_PAGE_FILENAME, NOT_FOUND_ROUTE_NAME, NOT_FOUND_ROUTE_PATH, NotFoundPageDeclaresRouteError, type NotFoundRouteHandlerOptions, PAYLOAD_SCRIPT_ID, type PageBoundaryDesignation, type PageContextRunner, type PageDataBundle, type PageLevelName, PageModuleNotInManifestError, type PageModuleShape, type PageResponseCommit, type PageRouteEntry, type PageRouteExport, type PageRouteHandlerFactory, type PageRouteMatch, type PageRoutesRegistry, type PageShortCircuit, type PageTripleModule, type PipelineLoader, type PipelineMiddleware, type PipelineStore, type RegisteredRouteShape, type RenderPageOptions, type RenderPageRequestOptions, type RenderedPage, type ResponseBuffer, type UnmatchedRequestKind, VITE_DIRECT_CSS_QUERY, acceptsHtmlExplicitly, classifyUnmatchedRequest, composeRoutePath, connectPageContext, connectPageRoutes, connectPageSharedScope, connectSharedStore, createBufferedResponse, createNotFoundRouteHandler, createPageModuleLoader, devStylesheetUrls, escapePayload, executePageRequest, frameworkDefaultNotFoundDocument, installPageRoutes, installPageRoutesFromManifest, isLoaderShortCircuit, isNotFoundPageFile, productionStylesheetUrls, renderPage, renderPageRequest };
14
+ export { type BufferedCookie, type BufferedHeader, DuplicateNotFoundPageError, type ExecutePageRequestOptions, type InstallPageRoutesFromManifestOptions, type InstallPageRoutesOptions, type InstalledManifestPageRoute, type InstalledPageRoute, type LayoutModuleShape, type LoaderShortCircuitKind, NOT_FOUND_PAGE_FILENAME, NOT_FOUND_ROUTE_NAME, NOT_FOUND_ROUTE_PATH, NotFoundPageDeclaresRouteError, type NotFoundRouteHandlerOptions, PAYLOAD_SCRIPT_ID, type PageBoundaryDesignation, type PageContextRunner, type PageDataBundle, type PageLevelName, PageModuleNotInManifestError, type PageModuleShape, type PageResponseCommit, type PageRouteEntry, type PageRouteExport, type PageRouteHandlerFactory, type PageRouteMatch, type PageRoutesRegistry, type PageShortCircuit, type PageTripleModule, type PipelineLoader, type PipelineMiddleware, type PipelineStore, type RegisteredRouteShape, type RenderPageOptions, type RenderPageRequestOptions, type RenderedPage, type UnmatchedRequestKind, VITE_DIRECT_CSS_QUERY, acceptsHtmlExplicitly, classifyUnmatchedRequest, composeRoutePath, connectPageContext, connectPageRoutes, connectSharedStore, createNotFoundRouteHandler, createPageModuleLoader, devStylesheetUrls, escapePayload, executePageRequest, frameworkDefaultNotFoundDocument, installPageRoutes, installPageRoutesFromManifest, isNotFoundPageFile, productionStylesheetUrls, renderPage, renderPageRequest };