@nifrajs/web 5.2.0 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/dist/build.d.ts +11 -2
  3. package/dist/build.d.ts.map +1 -1
  4. package/dist/build.js +182 -11
  5. package/dist/build.js.map +1 -1
  6. package/dist/csp.d.ts +2 -0
  7. package/dist/csp.d.ts.map +1 -1
  8. package/dist/csp.js +2 -0
  9. package/dist/csp.js.map +1 -1
  10. package/dist/deferred.d.ts.map +1 -1
  11. package/dist/deferred.js +23 -3
  12. package/dist/deferred.js.map +1 -1
  13. package/dist/index.d.ts +2 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +1 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/internal/deferred-free.d.ts +3 -0
  18. package/dist/internal/deferred-free.d.ts.map +1 -0
  19. package/dist/internal/deferred-free.js +15 -0
  20. package/dist/internal/deferred-free.js.map +1 -0
  21. package/dist/internal/module-preparation.d.ts +7 -0
  22. package/dist/internal/module-preparation.d.ts.map +1 -0
  23. package/dist/internal/module-preparation.js +24 -0
  24. package/dist/internal/module-preparation.js.map +1 -0
  25. package/dist/internal/output-guard.d.ts +2 -0
  26. package/dist/internal/output-guard.d.ts.map +1 -1
  27. package/dist/internal/output-guard.js +51 -9
  28. package/dist/internal/output-guard.js.map +1 -1
  29. package/dist/internal/page-execution.d.ts +1 -0
  30. package/dist/internal/page-execution.d.ts.map +1 -1
  31. package/dist/internal/page-execution.js +53 -43
  32. package/dist/internal/page-execution.js.map +1 -1
  33. package/dist/internal/parity.d.ts.map +1 -1
  34. package/dist/internal/parity.js +3 -1
  35. package/dist/internal/parity.js.map +1 -1
  36. package/dist/internal/prerendered-pages.d.ts +42 -0
  37. package/dist/internal/prerendered-pages.d.ts.map +1 -0
  38. package/dist/internal/prerendered-pages.js +92 -0
  39. package/dist/internal/prerendered-pages.js.map +1 -0
  40. package/dist/internal/public-url.d.ts +7 -0
  41. package/dist/internal/public-url.d.ts.map +1 -1
  42. package/dist/internal/public-url.js +13 -0
  43. package/dist/internal/public-url.js.map +1 -1
  44. package/dist/internal/render-document.d.ts.map +1 -1
  45. package/dist/internal/render-document.js +93 -35
  46. package/dist/internal/render-document.js.map +1 -1
  47. package/dist/internal/request-url.d.ts +4 -0
  48. package/dist/internal/request-url.d.ts.map +1 -1
  49. package/dist/internal/request-url.js +24 -0
  50. package/dist/internal/request-url.js.map +1 -1
  51. package/dist/internal/secret-scan.d.ts +4 -0
  52. package/dist/internal/secret-scan.d.ts.map +1 -1
  53. package/dist/internal/secret-scan.js +8 -1
  54. package/dist/internal/secret-scan.js.map +1 -1
  55. package/dist/internal/web-app.d.ts +11 -0
  56. package/dist/internal/web-app.d.ts.map +1 -1
  57. package/dist/internal/web-app.js +10 -1
  58. package/dist/internal/web-app.js.map +1 -1
  59. package/dist/isr.d.ts +1 -0
  60. package/dist/isr.d.ts.map +1 -1
  61. package/dist/isr.js +7 -4
  62. package/dist/isr.js.map +1 -1
  63. package/dist/prerender.d.ts +4 -0
  64. package/dist/prerender.d.ts.map +1 -1
  65. package/dist/prerender.js +9 -1
  66. package/dist/prerender.js.map +1 -1
  67. package/dist/public-dir.d.ts +15 -0
  68. package/dist/public-dir.d.ts.map +1 -1
  69. package/dist/public-dir.js +91 -12
  70. package/dist/public-dir.js.map +1 -1
  71. package/dist/render-seam.d.ts +5 -2
  72. package/dist/render-seam.d.ts.map +1 -1
  73. package/dist/render-seam.js.map +1 -1
  74. package/dist/search.d.ts.map +1 -1
  75. package/dist/search.js +2 -0
  76. package/dist/search.js.map +1 -1
  77. package/dist/vite.d.ts +6 -0
  78. package/dist/vite.d.ts.map +1 -1
  79. package/dist/vite.js +127 -54
  80. package/dist/vite.js.map +1 -1
  81. package/package.json +3 -3
  82. package/src/build.ts +226 -35
  83. package/src/csp.ts +4 -0
  84. package/src/deferred.ts +20 -3
  85. package/src/index.ts +3 -0
  86. package/src/internal/deferred-free.ts +15 -0
  87. package/src/internal/module-preparation.ts +30 -0
  88. package/src/internal/output-guard.ts +51 -9
  89. package/src/internal/page-execution.ts +55 -47
  90. package/src/internal/parity.ts +2 -1
  91. package/src/internal/prerendered-pages.ts +124 -0
  92. package/src/internal/public-url.ts +13 -0
  93. package/src/internal/render-document.ts +116 -52
  94. package/src/internal/request-url.ts +24 -0
  95. package/src/internal/secret-scan.ts +9 -1
  96. package/src/internal/web-app.ts +21 -1
  97. package/src/isr.ts +7 -4
  98. package/src/prerender.ts +13 -1
  99. package/src/public-dir.ts +107 -12
  100. package/src/render-seam.ts +5 -2
  101. package/src/search.ts +1 -0
  102. package/src/vite.ts +130 -54
package/CHANGELOG.md CHANGED
@@ -1,5 +1,77 @@
1
1
  # @nifrajs/web
2
2
 
3
+ ## 5.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 7ab9692: Add build-time schema compilation that emits typed static validators without runtime code generation. Generated modules preserve strict validation and structured issues while avoiding the schema builder and dynamic compiler in deployed bundles.
8
+
9
+ A schema whose property key, `format` name or custom kind holds a quote, backslash or line break, or whose literal holds a backslash or line break, now validates on the eval-free checker and is refused by build-time compilation. TypeBox splices that text into generated source unescaped, so a quote could end the string and run the rest as code.
10
+
11
+ Prepare immutable route modules and layout chains in production while executing authorization gates and loaders for every request. Mutable manifests can disable module preparation with `cacheRouteModules: false`.
12
+
13
+ Reduce output projection bookkeeping for uniform subtrees, reuse request-bound cache views, and record completed cache spans without allocating an active observation. Span parentage, sampling, redaction, exporter isolation, and capability enforcement remain intact.
14
+
15
+ Keep custom start-only `ObservationLifecycle` implementations compatible. The factory returns the extended `RecordingObservationLifecycle` interface with the new `record` method.
16
+
17
+ Mark the migration parser's TypeScript keyword-kind comparison as syntax, so the security check does not mistake it for a secret comparison.
18
+ - 2a429e6: `nifra build --target bun` and `--target node` prerender the routes that opt in (`export const prerender = true`, or `getStaticPaths`) into `_prerendered/` beside `server.js`. The server then answers those pages from their file instead of rendering them on every request.
19
+
20
+ The file is served from the page route, so `use` middleware and every request hook still run first. A gate in front of a page still applies, and response hooks still add their headers. The page carries the `content-language` and Content-Security-Policy its build-time render produced. Loader headers and cookies are not sent, as for any prerendered page.
21
+
22
+ These keep rendering on demand:
23
+ - a request with a query string
24
+ - a navigation data or server-component request
25
+ - a draft-mode visitor
26
+ - a page whose build-time render set a cookie, was `private` or `no-store`, or varied on a request header
27
+ - every page of an app with a `nonce`, whose documents need a nonce minted per request.
28
+
29
+ On Node, the SSR benchmark's prerendered catalog page is served about 2.1x (Svelte) to 2.6x (Vue) faster than rendering it on each request.
30
+
31
+ New in `@nifrajs/web`:
32
+ - `createWebApp({ prerenderedPages })`
33
+ - `prerenderedPageReader`, which opens only the build's own files inside the directory and keeps each page in memory once read, up to 32 MiB by default
34
+ - `PrerenderEntry.serveHeaders` on `prerenderRoutes` results.
35
+
36
+ Prerendering now runs during these builds, so it loads every route module and runs the opted-in loaders at build time. Two effects:
37
+ - If a route module cannot load there, the build warns and every page renders on demand, as before.
38
+ - A secret in a prerendered page fails the build, as it does for `--target static`.
39
+
40
+ The Vite pipeline, `deno`, and the edge targets are unchanged.
41
+
42
+ ### Patch Changes
43
+
44
+ - 0e1d03f: A build no longer copies hidden files from `public/` - any path segment starting with `.` other than `.well-known`, such as `.env`, `.git/` or `.DS_Store`. The Bun development pipeline never served them (the Vite one did; see below), but the build copied them and every target then served them: the Bun, Node and Deno entries from their allowlist, the static, Pages and Vercel hosts from the directory. The development parity check lists public files by the same rule, and `servePublicDir` also refuses a visible name whose real target is hidden.
45
+ - 605c246: Under a hash-based `createCspPolicy`, a buffered render that writes a script for that request alone (Solid serializing a server error an `ErrorBoundary` caught, for hydration) no longer ships it unauthorized. The render is handed a nonce; when the HTML it returns carries it, the document keeps the nonce in its `Content-Security-Policy` and becomes `private, no-store`, and every other document stays nonce-free and cacheable as before.
46
+ - 271917a: A soft navigation's deferred data stream is cancelled and released when a line fails to parse. A malformed first line threw out of `parseNdjsonData` with the body still locked and streaming and the abort listener attached, and a malformed later line stopped reading without cancelling the body; every exit now detaches from the signal, cancels an unfinished body and releases the reader.
47
+ - 69dfb60: `rangeResponse()` and `servePublicDir` ignore a `Range` header on a HEAD request, as RFC 9110 section 14.2 defines range handling for GET only: HEAD answers 200 with the full `content-length` and no `content-range`, the same as the Node static bridge. Before, HEAD with `Range` answered 206 or 416 with the metadata of the requested slice.
48
+ - 605c246: A React page that suspends without `defer()` (`use(promise)` or `lazy` inside `<Suspense>`) now renders its resolved content on the server. The buffered fast path rendered it with React's string renderer, which cannot wait, so the document kept the fallback for good (with `hydrate: false` or JavaScript off, the content never appeared), and a component suspending with no boundary above it failed the render. `RenderAdapter.renderToString` may now return `undefined` for a render that suspended; the React adapter does so, and the page is streamed instead, with a CSP nonce when the policy needs one.
49
+ - 13224fe: The server entry `buildTarget` generates for `bun`, `node` and `deno` serves static files the way `nifra dev` does. Bun and Node now hand a manifest-approved path to `servePublicDir`, and Deno runs the same checks on its own file API: the real path must sit inside the deploy directory, so a symbolic link planted in the deployed tree no longer reaches a file outside it; a HEAD request is answered from the file's size instead of reading it whole (the Node entry read the entire file); and a single byte range gets a `206` (an unsatisfiable one a `416`), with `accept-ranges` advertised.
50
+ - 00c266e: A streamed page now renders only as fast as the client reads it. The document stream read the whole app stream up front, so a client that stopped reading left the full rendered body queued in memory; it now pulls one renderer chunk per read. The Vite dev bridge (`pipeWebBodyToNode`) likewise waits for `drain` when the socket buffer is full instead of writing every chunk at once, and removes its listeners when the body ends.
51
+ - 042db5d: A Preact page that suspends without `defer()` (a `preact/compat` `<Suspense>` around a thrown promise, or `lazy`) is streamed and resolves on the server; it was a 500. A page whose string render suspended skips the string pass for its next 32 requests and goes straight to the stream, so a React page that suspends on `use` renders once per request rather than twice.
52
+ - 49e37bd: `nifra dev` on the Vite pipeline no longer serves hidden files from `public/`. Vite's public middleware served every file there, dotfiles included, so `/.env`, `/.git/config` and `/%2eenv` answered with their contents. A request for a hidden file, or a visible name whose real target is hidden, now goes to the app, as it does in production and on the Bun pipeline. The dev server binds 127.0.0.1 and Vite refuses a foreign `Host`, so the exposure was limited to local processes and the developer's own browser.
53
+ - 6826956: The Vite dev bridge cancels a non-HTML response body when the client left before piping began, or while a write was refused. It waited for a `drain` that never came, so an SSE source or a streamed body from the app stayed open for every aborted request.
54
+ - 3318232: `servePublicDir` reads a body of up to 256 KiB whole through its pinned descriptor and closes it before the response leaves. A larger body still streams. On Bun, a 200 KB public file is served in 0.17 ms where a `node:fs` stream took 0.28 ms; a 10 KB file takes 0.12-0.14 ms instead of 0.16 ms. The self-hosted Bun, Node and Deno entries serve static files through this handler.
55
+ - 7e5cd65: The self-hosted Deno entry's static handler applies `servePublicDir`'s hidden-file rule to the real path, so `/assets/<name>` linking to a `.env` inside the deploy directory is 404 rather than served. It also checks that the file it opened is still the one at the checked real path. `Deno.open` follows links, so a directory swapped for a link after the containment check used to redirect the open outside the deploy directory.
56
+ - d874102: No behavior change: the error a secret in a build artifact throws sets its name in a constructor, and the prerendered page reader's failure paths are tested.
57
+ - 80bf986: Page documents render with less work per request. Loader data that a closed output schema has settled skips the scan for deferred values. The request origin is parsed once per host. An empty query string skips search parsing. The render options are assembled without a copy per optional field. On the SSR bench apps this measured 6 to 10% more requests per second on Bun and Node.
58
+ - d890695: `MemoryCacheStore` no longer stores a render that began before a purge whose record it has since evicted. Purge records are bounded by `max`; once a page's or tag's record was evicted, a slow render that began before that purge was accepted and served the purged page again (one purge followed by 500 others was enough at the default `max`). Such a render is now served but not cached; a render that began after the purge is cached as before.
59
+ - Updated dependencies [7ab9692]
60
+ - Updated dependencies [808bac8]
61
+ - Updated dependencies [d4bae56]
62
+ - Updated dependencies [007060d]
63
+ - Updated dependencies [190ab39]
64
+ - Updated dependencies [7cf8df3]
65
+ - @nifrajs/core@5.3.0
66
+ - @nifrajs/island-trigger@5.3.0
67
+
68
+ ## 5.2.1
69
+
70
+ ### Patch Changes
71
+
72
+ - @nifrajs/core@5.2.1
73
+ - @nifrajs/island-trigger@5.2.1
74
+
3
75
  ## 5.2.0
4
76
 
5
77
  ### Minor Changes
package/dist/build.d.ts CHANGED
@@ -3,8 +3,10 @@ import { type BunPlugin } from "bun";
3
3
  import { type BuildManifest, type BuildTarget, type Bundler, type ServerBuild, type SizeReport } from "./build-plan.js";
4
4
  import { type CssLoadingMode } from "./css-contract.js";
5
5
  import { generateServerManifest } from "./index.js";
6
+ import { type ServerPrerenderedPage } from "./internal/prerendered-pages.js";
6
7
  import { type SecretExemption } from "./internal/secret-scan.js";
7
8
  export * from "./build-plan.js";
9
+ export type { ServerPrerenderedPage } from "./internal/prerendered-pages.js";
8
10
  export type { SecretExemption, SecretRule } from "./internal/secret-scan.js";
9
11
  export { type CloudflarePagesRoutes, type CloudflarePagesRoutesOptions, cloudflarePagesRoutes, dataFileFor, htmlFileFor, type PrerenderApp, type PrerenderEntry, type PrerenderOptions, type PrerenderResult, prerenderRoutes, } from "./prerender.js";
10
12
  export interface BuildClientOptions {
@@ -93,7 +95,9 @@ export declare function cloudflareRouteRules(publicFiles: readonly string[],
93
95
  routePatterns: readonly string[]): CloudflareRouteRules;
94
96
  /** The built asset map - the server reads `entry` for the client script + serves `assets`. */
95
97
  /**
96
- * Copy `from` into `to`, returning the URL paths copied (sorted).
98
+ * Copy `from` into `to`, returning the URL paths copied (sorted). Hidden entries other than
99
+ * `.well-known` are skipped, as development never serves them: every target ships this list, and a
100
+ * CDN-hosted one serves whatever was copied.
97
101
  *
98
102
  * Lives here, not beside `servePublicDir`, because it is BUILD-time: it reaches for `Bun.Glob` and
99
103
  * `node:fs`, and `public-dir.ts` is reachable from the client bundle graph through the package
@@ -276,6 +280,9 @@ export declare function generateServerEntry(options: {
276
280
  readonly clientIp?: ServerEntryClientIp;
277
281
  /** The server manifest exports `copyChunks` (the client build split copy tables by locale). */
278
282
  readonly copyChunks?: boolean;
283
+ /** `bun` / `node` only: the pages the build prerendered into `_prerendered/`, by request path, which
284
+ * the app answers from their file (see `createWebApp`'s `prerenderedPages`). */
285
+ readonly prerenderedPages?: Readonly<Record<string, ServerPrerenderedPage>>;
279
286
  }): string;
280
287
  export interface BuildTargetOptions {
281
288
  /** The `routes/` directory to discover (absolute path). */
@@ -304,7 +311,9 @@ export interface BuildTargetOptions {
304
311
  * emitted hydration `<script src>` uses the REAL content-hashed entry (`client.entry`) plus the same
305
312
  * styles/route-preload the server targets use. A pre-built instance can't work here: the hash isn't known
306
313
  * until `buildClient` runs inside `buildTarget`, so a hardcoded entry 404s → pages render but never
307
- * hydrate. Required for `target: "static"` (SSG drives `app.fetch`); ignored otherwise. */
314
+ * hydrate. Required for `target: "static"` (SSG drives `app.fetch`). For `bun` and `node` it is
315
+ * optional: given, the opted-in routes are prerendered into `_prerendered/` and the server answers
316
+ * them from their file; the other targets ignore it. */
308
317
  readonly prerenderApp?: (client: BuildManifest) => PrerenderAppLike | Promise<PrerenderAppLike>;
309
318
  /** Client-build plugins (e.g. the MDX/Vue/Solid Bun plugins). */
310
319
  readonly clientPlugins?: readonly BunPlugin[];
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"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"}
package/dist/build.js CHANGED
@@ -22,9 +22,10 @@ import { assertDisposableDir } from "./internal/disposable-dir.js";
22
22
  import { entryChunks } from "./internal/entry-chunks.js";
23
23
  import { dedupePolicyFor } from "./internal/identity-policy.js";
24
24
  import { assertDevelopmentProductionParity, assertIdentityParity, collectDevelopmentParityInput, } from "./internal/parity.js";
25
+ import { servablePrerenderedPages, } from "./internal/prerendered-pages.js";
25
26
  import { privateEnvCheck } from "./internal/private-env.js";
26
- import { publicUrlPath } from "./internal/public-url.js";
27
- import { assertNoSecrets, buildEnvironment, emittedScanFiles, formatSecretFindings, graphScanInput, originName, publicScanFiles, scanForSecrets, textOf, } from "./internal/secret-scan.js";
27
+ import { isHiddenPublicPath, publicUrlPath } from "./internal/public-url.js";
28
+ import { assertNoSecrets, buildEnvironment, emittedScanFiles, formatSecretFindings, graphScanInput, originName, publicScanFiles, SecretScanError, scanForSecrets, textOf, } from "./internal/secret-scan.js";
28
29
  import { generateServerFnStub, SERVER_FN_MODULE, serverFnNamespace, } from "./internal/server-boundary.js";
29
30
  import { formatUnsupportedBuiltins, unsupportedBuiltins } from "./internal/target-compat.js";
30
31
  import { accountEmittedFiles, bunModuleSource, formatClientGraphVerdict, formatServerGraphVerdict, formatUnaccountedOutput, verifyClientGraph, verifyServerGraph, } from "./internal/zone-graph.js";
@@ -166,7 +167,9 @@ routePatterns) {
166
167
  }
167
168
  /** The built asset map - the server reads `entry` for the client script + serves `assets`. */
168
169
  /**
169
- * Copy `from` into `to`, returning the URL paths copied (sorted).
170
+ * Copy `from` into `to`, returning the URL paths copied (sorted). Hidden entries other than
171
+ * `.well-known` are skipped, as development never serves them: every target ships this list, and a
172
+ * CDN-hosted one serves whatever was copied.
170
173
  *
171
174
  * Lives here, not beside `servePublicDir`, because it is BUILD-time: it reaches for `Bun.Glob` and
172
175
  * `node:fs`, and `public-dir.ts` is reachable from the client bundle graph through the package
@@ -177,6 +180,8 @@ export async function copyPublicDir(from, to) {
177
180
  const sourceReal = await realpath(source);
178
181
  const copied = [];
179
182
  for await (const rel of new Glob("**/*").scan({ cwd: source, dot: true, onlyFiles: false })) {
183
+ if (isHiddenPublicPath(rel))
184
+ continue;
180
185
  const candidate = join(source, rel);
181
186
  const candidateStat = await lstat(candidate);
182
187
  if (candidateStat.isSymbolicLink()) {
@@ -982,6 +987,8 @@ const PLATFORM_CLIENT_IP_HEADERS = {
982
987
  cloudflare: "cf-connecting-ip",
983
988
  vercel: "x-real-ip",
984
989
  };
990
+ /** Where a self-hosting build writes its prerendered pages, beside `server.js`. */
991
+ const PRERENDERED_DIR = "_prerendered";
985
992
  /**
986
993
  * Codegen the per-target **server entry** module (source text) for `buildServer` to bundle. It imports
987
994
  * the app's `adapter` (from `framework.ts`), the optional `backend` (from `backend.ts`), and the
@@ -1016,7 +1023,20 @@ export function generateServerEntry(options) {
1016
1023
  if (target === "static") {
1017
1024
  throw new Error("[nifra/web] generateServerEntry: `static` has no server entry (SSG only)");
1018
1025
  }
1019
- const lines = ['import { createWebApp } from "@nifrajs/web"'];
1026
+ // Bun and Node serve the client bundle through `servePublicDir`. Deno bundles for the browser
1027
+ // condition, where `node:fs` is a stub, so its entry runs the same checks on Deno's own file API.
1028
+ const nodeFs = target === "bun" || target === "node";
1029
+ const prerendered = Object.entries(options.prerenderedPages ?? {});
1030
+ if (prerendered.length > 0 && !nodeFs) {
1031
+ throw new Error(`[nifra/web] generateServerEntry: prerendered pages are served by the bun and node targets, not ${target}`);
1032
+ }
1033
+ const lines = [
1034
+ !nodeFs
1035
+ ? 'import { createWebApp } from "@nifrajs/web"'
1036
+ : prerendered.length > 0
1037
+ ? 'import { createWebApp, prerenderedPageReader, servePublicDir } from "@nifrajs/web"'
1038
+ : 'import { createWebApp, servePublicDir } from "@nifrajs/web"',
1039
+ ];
1020
1040
  if (backendImport !== undefined)
1021
1041
  lines.push('import { inProcessClient } from "@nifrajs/client"');
1022
1042
  lines.push(`import { adapter } from ${JSON.stringify(adapterImport)}`);
@@ -1036,7 +1056,16 @@ export function generateServerEntry(options) {
1036
1056
  lines.push('import { toFetchHandler } from "@nifrajs/core/server"');
1037
1057
  if (target === "node")
1038
1058
  lines.push('import { serve } from "@nifrajs/node"');
1039
- lines.push("", "const app = createWebApp({", " adapter,", ...(useImport !== undefined ? [" use,"] : []), ...importedOptions.map((name) => ` ${name},`), " manifest,", " clientEntry,", " styles,", " routeStyles,", " cssLoading,", ...(options.copyChunks === true ? [" copyChunks,"] : []), ...(backendImport !== undefined ? [" api: inProcessClient(backend),"] : []), ` title: ${JSON.stringify(title)},`,
1059
+ if (nodeFs)
1060
+ lines.push('import { fileURLToPath } from "node:url"');
1061
+ if (target === "deno")
1062
+ lines.push('import { parseByteRange } from "@nifrajs/core/range"');
1063
+ if (prerendered.length > 0) {
1064
+ const headers = Object.fromEntries(prerendered.map(([path, page]) => [path, page.headers]));
1065
+ const files = Object.fromEntries(prerendered.map(([path, page]) => [path, page.file]));
1066
+ lines.push("", `// The pages the build prerendered into ${PRERENDERED_DIR}/, answered from their file after \`use\`.`, "const prerenderedPages = {", ` pages: ${JSON.stringify(headers)},`, " read: prerenderedPageReader({", ` dir: fileURLToPath(new URL(${JSON.stringify(`./${PRERENDERED_DIR}/`)}, import.meta.url)),`, ` files: ${JSON.stringify(files)},`, " }),", "}");
1067
+ }
1068
+ lines.push("", "const app = createWebApp({", " adapter,", ...(useImport !== undefined ? [" use,"] : []), ...(prerendered.length > 0 ? [" prerenderedPages,"] : []), ...importedOptions.map((name) => ` ${name},`), " manifest,", " clientEntry,", " styles,", " routeStyles,", " cssLoading,", ...(options.copyChunks === true ? [" copyChunks,"] : []), ...(backendImport !== undefined ? [" api: inProcessClient(backend),"] : []), ` title: ${JSON.stringify(title)},`,
1040
1069
  // Core's own `{ header }` trust, so the mounted backend and every loader see the derived caller.
1041
1070
  ...(clientIpHeader !== undefined
1042
1071
  ? [` server: { clientIp: { header: ${JSON.stringify(clientIpHeader)} } },`]
@@ -1060,27 +1089,132 @@ export function generateServerEntry(options) {
1060
1089
  lines.push("// The client bundle and public files live next to this entry; serve only manifest-approved paths.", 'const STATIC_ROOT = new URL("./", import.meta.url)', `const PUBLIC_FILES = new Set(${JSON.stringify(publicFiles)})`, ...(hashedFiles !== undefined
1061
1090
  ? [`const HASHED_FILES = new Set(${JSON.stringify(hashedFiles)})`]
1062
1091
  : []), "const staticPath = (pathname: string): string | undefined => {", " if (PUBLIC_FILES.has(pathname)) return '.' + pathname", ' if (!pathname.startsWith("/assets/")) return undefined', ' const segments = pathname.slice(1).split("/")', " // `.` and `..` match the character class, and the path is joined onto a base URL that resolves", " // dot segments - so they are rejected explicitly rather than relying on the request URL having", " // been normalized upstream.", " const safe = (segment: string): boolean =>", ' segment !== "." && segment !== ".." && /^[A-Za-z0-9._-]+$/.test(segment)', " return segments.every(safe) ? '.' + pathname : undefined", "}",
1063
- // The type table and cache policy `servePublicDir` uses. Without a known type, Bun answers a file
1064
- // as an `application/octet-stream` attachment, which a browser downloads instead of showing.
1065
- `const TYPES: Record<string, string> = ${JSON.stringify(CONTENT_TYPES)}`, "const staticHeaders = (pathname: string): Record<string, string> => ({", ' "content-type": TYPES[pathname.slice(pathname.lastIndexOf(".")).toLowerCase()] ?? "application/octet-stream",', ` "cache-control": ${hashedFiles !== undefined ? "HASHED_FILES.has(pathname)" : 'pathname.startsWith("/assets/")'} ? ${JSON.stringify(IMMUTABLE)} : ${JSON.stringify(ONE_DAY)},`, ' "x-content-type-options": "nosniff",', "})");
1092
+ // The handler `nifra dev` serves public/ with: its type table, nosniff and cache policy, HEAD
1093
+ // answered without reading the file, byte ranges and conditional requests, and a descriptor opened
1094
+ // only once the real path is inside the root, so a link planted in the deployed tree cannot reach
1095
+ // a file outside it.
1096
+ ...(nodeFs
1097
+ ? [
1098
+ "const serveStatic = servePublicDir({",
1099
+ " dir: fileURLToPath(STATIC_ROOT),",
1100
+ ...(hashedFiles !== undefined ? [" hashedFiles: HASHED_FILES,"] : []),
1101
+ "})",
1102
+ "const staticResponse = async (req: Request): Promise<Response> =>",
1103
+ ' (await serveStatic(req)) ?? new Response("not found", { status: 404 })',
1104
+ ]
1105
+ : denoStaticResponse(hashedFiles !== undefined)));
1066
1106
  // Bun.serve and Deno.serve delimit the body themselves, so its declared length is the transport
1067
1107
  // frame - the guarantee core's own listen() and the Deno adapter mark (see markTrustedBodyFraming).
1068
1108
  const markFramed = '(req as unknown as Record<symbol, unknown>)[Symbol.for("nifra.body.trustedFraming")] = true';
1069
1109
  if (target === "bun") {
1070
- lines.push("const server = Bun.serve({", " port: Number(Bun.env.PORT ?? 3000),", " async fetch(req, server) {", " const { pathname } = new URL(req.url)", " const filePath = staticPath(pathname)", " if (filePath !== undefined) {", " const file = Bun.file(new URL(filePath, STATIC_ROOT))", ' if (!(await file.exists())) return new Response("not found", { status: 404 })', " return new Response(file, { headers: staticHeaders(pathname) })", " }", ` ${markFramed}`, " // The socket peer, looked up only when something reads it (as core's own listen() does).", " return app.fetch(req, { get clientIp() { return server.requestIP(req)?.address } })", " },", "})",
1110
+ lines.push("const server = Bun.serve({", " port: Number(Bun.env.PORT ?? 3000),", " async fetch(req, server) {", " const { pathname } = new URL(req.url)",
1111
+ // Braced: the next emitted line opens with `(`, which would otherwise call the returned value.
1112
+ " if (staticPath(pathname) !== undefined) {", " return staticResponse(req)", " }", ` ${markFramed}`, " // The socket peer, looked up only when something reads it (as core's own listen() does).", " return app.fetch(req, { get clientIp() { return server.requestIP(req)?.address } })", " },", "})",
1071
1113
  // The `${...}` here is literal OUTPUT (a template in the GENERATED file), not a template in this
1072
1114
  // source - split so biome's noTemplateCurlyInString doesn't flag it; the emitted line is unchanged.
1073
1115
  `console.log(\`nifra (Bun) → http://localhost:$${"{server.port}"}\`)`);
1074
1116
  return `${lines.join("\n")}\n`;
1075
1117
  }
1076
1118
  if (target === "node") {
1077
- lines.push('import { readFile } from "node:fs/promises"', "await serve(", " {", " async fetch(req, platform) {", " const { pathname } = new URL(req.url)", " const filePath = staticPath(pathname)", " if (filePath !== undefined) {", " try {", " const body = await readFile(new URL(filePath, STATIC_ROOT))", " return new Response(body, { headers: staticHeaders(pathname) })", " } catch {", ' return new Response("not found", { status: 404 })', " }", " }", " return app.fetch(req, platform)", " },", " },", " { port: Number(process.env.PORT ?? 3000) },", ")");
1119
+ lines.push("await serve(", " {", " async fetch(req, platform) {", " const { pathname } = new URL(req.url)", " if (staticPath(pathname) !== undefined) return staticResponse(req)", " return app.fetch(req, platform)", " },", " },", " { port: Number(process.env.PORT ?? 3000) },", ")");
1078
1120
  return `${lines.join("\n")}\n`;
1079
1121
  }
1080
1122
  // deno
1081
- lines.push("// @ts-ignore - Deno global is present on the Deno runtime this output targets.", 'Deno.serve({ port: Number(Deno.env.get("PORT") ?? "3000") }, async (req, info) => {', " const { pathname } = new URL(req.url)", " const filePath = staticPath(pathname)", " if (filePath !== undefined) {", " try {", " // @ts-ignore - Deno.readFile is present on the Deno runtime.", " const body = await Deno.readFile(new URL(filePath, STATIC_ROOT))", " return new Response(body, { headers: staticHeaders(pathname) })", " } catch {", ' return new Response("not found", { status: 404 })', " }", " }", ` ${markFramed}`, " return app.fetch(req, { clientIp: info.remoteAddr.hostname })", "})");
1123
+ lines.push("// @ts-ignore - Deno global is present on the Deno runtime this output targets.", 'Deno.serve({ port: Number(Deno.env.get("PORT") ?? "3000") }, async (req, info) => {', " const { pathname } = new URL(req.url)", " const filePath = staticPath(pathname)", " if (filePath !== undefined) {", " return staticResponse(req, filePath, pathname)", " }", ` ${markFramed}`, " return app.fetch(req, { clientIp: info.remoteAddr.hostname })", "})");
1082
1124
  return `${lines.join("\n")}\n`;
1083
1125
  }
1126
+ /**
1127
+ * The Deno entry's static handler: `servePublicDir`'s checks on Deno's file API. The real path must sit
1128
+ * inside the root and cross no hidden segment, and the opened file must still be the one that path
1129
+ * names, so a link planted in the deployed tree cannot reach a file outside it or a `.env` inside it.
1130
+ * HEAD answers from `stat` without reading; one byte range is served from a seek, several as the
1131
+ * whole file.
1132
+ */
1133
+ function denoStaticResponse(hashed) {
1134
+ return [
1135
+ `const TYPES: Record<string, string> = ${JSON.stringify(CONTENT_TYPES)}`,
1136
+ "const staticHeaders = (pathname: string): Record<string, string> => ({",
1137
+ ' "content-type": TYPES[pathname.slice(pathname.lastIndexOf(".")).toLowerCase()] ?? "application/octet-stream",',
1138
+ ` "cache-control": ${hashed ? "HASHED_FILES.has(pathname)" : 'pathname.startsWith("/assets/")'} ? ${JSON.stringify(IMMUTABLE)} : ${JSON.stringify(ONE_DAY)},`,
1139
+ ' "x-content-type-options": "nosniff",',
1140
+ ' "accept-ranges": "bytes",',
1141
+ "})",
1142
+ "// @ts-ignore - Deno global is present on the Deno runtime this output targets.",
1143
+ "const STATIC_REAL: string = await Deno.realPath(STATIC_ROOT)",
1144
+ "const hiddenSegment = (rel: string): boolean =>",
1145
+ ' rel.split(/[\\\\/]/).some((segment) => segment.startsWith(".") && segment !== ".well-known")',
1146
+ "const staticResponse = async (req: Request, filePath: string, pathname: string): Promise<Response> => {",
1147
+ ' const missing = () => new Response("not found", { status: 404 })',
1148
+ ' if (req.method !== "GET" && req.method !== "HEAD") return missing()',
1149
+ " let file, info",
1150
+ " try {",
1151
+ " // @ts-ignore - Deno global is present on the Deno runtime this output targets.",
1152
+ " const real: string = await Deno.realPath(new URL(filePath, STATIC_ROOT))",
1153
+ ' if (!real.startsWith(STATIC_REAL + (STATIC_REAL.includes("\\\\") ? "\\\\" : "/"))) return missing()',
1154
+ " if (hiddenSegment(real.slice(STATIC_REAL.length + 1))) return missing()",
1155
+ " // @ts-ignore - Deno global is present on the Deno runtime this output targets.",
1156
+ " file = await Deno.open(real)",
1157
+ " // Deno.open follows links, so a directory swapped for one after the check above redirects it.",
1158
+ " // The opened file must be the one at `real`, which must still resolve to itself.",
1159
+ " const opened = await file.stat()",
1160
+ " // @ts-ignore - Deno global is present on the Deno runtime this output targets.",
1161
+ " const named = await Deno.stat(real)",
1162
+ " // @ts-ignore - Deno global is present on the Deno runtime this output targets.",
1163
+ " if (opened.dev !== named.dev || opened.ino !== named.ino || (await Deno.realPath(real)) !== real) {",
1164
+ " file.close()",
1165
+ " return missing()",
1166
+ " }",
1167
+ " info = opened",
1168
+ " } catch {",
1169
+ " file?.close()",
1170
+ " return missing()",
1171
+ " }",
1172
+ " const size: number = info.size",
1173
+ " const headers = new Headers(staticHeaders(pathname))",
1174
+ ' const range = req.method === "GET" ? parseByteRange(req.headers.get("range"), size) : { kind: "none" as const }',
1175
+ ' if (!info.isFile || req.method === "HEAD" || range.kind === "unsatisfiable") {',
1176
+ " file.close()",
1177
+ " if (!info.isFile) return missing()",
1178
+ ' if (range.kind !== "unsatisfiable") {',
1179
+ ' headers.set("content-length", String(size))',
1180
+ " return new Response(null, { headers })",
1181
+ " }",
1182
+ ' headers.delete("content-type")',
1183
+ ' headers.set("content-range", "bytes */" + size)',
1184
+ " return new Response(null, { status: 416, headers })",
1185
+ " }",
1186
+ ' if (range.kind === "satisfiable" && range.ranges.length === 1) {',
1187
+ " const { start, end } = range.ranges[0]!",
1188
+ " // @ts-ignore - Deno global is present on the Deno runtime this output targets.",
1189
+ " await file.seek(start, Deno.SeekMode.Start)",
1190
+ " let left = end - start + 1",
1191
+ ' headers.set("content-range", "bytes " + start + "-" + end + "/" + size)',
1192
+ ' headers.set("content-length", String(left))',
1193
+ " const body = new ReadableStream<Uint8Array>({",
1194
+ " async pull(controller) {",
1195
+ " const chunk = new Uint8Array(Math.min(left, 65_536))",
1196
+ " const read: number | null = await file.read(chunk)",
1197
+ " if (read === null || read === 0) {",
1198
+ " file.close()",
1199
+ " controller.close()",
1200
+ " return",
1201
+ " }",
1202
+ " controller.enqueue(chunk.subarray(0, read))",
1203
+ " left -= read",
1204
+ " if (left <= 0) {",
1205
+ " file.close()",
1206
+ " controller.close()",
1207
+ " }",
1208
+ " },",
1209
+ " cancel: () => file.close(),",
1210
+ " })",
1211
+ " return new Response(body, { status: 206, headers })",
1212
+ " }",
1213
+ ' headers.set("content-length", String(size))',
1214
+ " return new Response(file.readable, { headers })",
1215
+ "}",
1216
+ ];
1217
+ }
1084
1218
  /** Measure each emitted output file's raw + gzip size. Reads the file off disk and gzips it with
1085
1219
  * `Bun.gzipSync` (the over-the-wire weight). Async only because it reads files; the aggregation is the
1086
1220
  * pure {@link aggregateSizeReport}. */
@@ -1161,6 +1295,36 @@ function assertNoPublicCollision(plan, publicFiles, outDir) {
1161
1295
  `build's own output in ${outDir}. Rename or move them out of the public directory.`);
1162
1296
  }
1163
1297
  }
1298
+ /** Prerender a self-hosting build's opted-in routes into `dir` and return the pages its server may
1299
+ * answer from their file: those whose render was not specific to its request. */
1300
+ async function prerenderForServer(prerenderApp, client, routesDir, dir, publicFiles, secrets) {
1301
+ const owned = `/${PRERENDERED_DIR}/`;
1302
+ const clashes = publicFiles.filter((file) => file.toLowerCase().startsWith(owned));
1303
+ if (clashes.length > 0) {
1304
+ throw new Error(`[nifra/web] public file(s) ${clashes.join(", ")} sit under ${owned}, where the build writes its ` +
1305
+ "prerendered pages. Rename or move them out of the public directory.");
1306
+ }
1307
+ let result;
1308
+ try {
1309
+ result = await prerenderRoutes({
1310
+ app: await prerenderApp(client),
1311
+ routes: discoverRoutes(routesDir).routes,
1312
+ outDir: dir,
1313
+ secrets,
1314
+ });
1315
+ }
1316
+ catch (error) {
1317
+ // Prerendering loads every route module at build time, which a server build never needed before:
1318
+ // one that cannot load there (a connection opened on import, an env var only production sets) costs
1319
+ // the speedup, not the build. A secret in a page still fails it.
1320
+ if (error instanceof SecretScanError)
1321
+ throw error;
1322
+ rmSync(dir, { recursive: true, force: true });
1323
+ console.warn(`[nifra/web] prerendering failed, so the server renders every page on demand: ${error instanceof Error ? error.message : String(error)}`);
1324
+ return {};
1325
+ }
1326
+ return servablePrerenderedPages(result.prerendered);
1327
+ }
1164
1328
  /** Build a full deploy dir for `target` using the default Bun bundler. See {@link buildTargetWith}. */
1165
1329
  export async function buildTarget(target, options) {
1166
1330
  return buildTargetWith(target, options, bunBundler);
@@ -1243,6 +1407,12 @@ export async function buildTargetWith(target, options, bundler) {
1243
1407
  if (requestedCssLoading !== undefined || publicFiles.length > 0) {
1244
1408
  writeFileSync(`${assetsDir}/manifest.json`, JSON.stringify(client, null, 2));
1245
1409
  }
1410
+ // A self-hosting server answers its prerendered pages from their file. The static target is all
1411
+ // prerendered pages; the edge targets keep rendering them on demand.
1412
+ const prerenderedPages = options.prerenderApp !== undefined &&
1413
+ (targetPlan.target === "bun" || targetPlan.target === "node")
1414
+ ? await prerenderForServer(options.prerenderApp, client, routesDir, `${staticRoot}/${PRERENDERED_DIR}`, publicFiles, secretScan)
1415
+ : undefined;
1246
1416
  if (targetPlan.kind === "static") {
1247
1417
  if (options.prerenderApp === undefined) {
1248
1418
  throw new Error("[nifra/web] buildTarget(static) requires `prerenderApp` (a factory `(client) => createWebApp`)");
@@ -1289,6 +1459,7 @@ export async function buildTargetWith(target, options, bundler) {
1289
1459
  hashedFiles: client.assets,
1290
1460
  ...(options.clientIp !== undefined ? { clientIp: options.clientIp } : {}),
1291
1461
  ...(client.copyChunks !== undefined ? { copyChunks: true } : {}),
1462
+ ...(prerenderedPages !== undefined ? { prerenderedPages } : {}),
1292
1463
  }));
1293
1464
  const { worker } = await bundler.buildServer({
1294
1465
  routesDir,