@nifrajs/web 3.5.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend-only.d.ts +15 -0
- package/dist/backend-only.d.ts.map +1 -0
- package/dist/backend-only.js +16 -0
- package/dist/backend-only.js.map +1 -0
- package/dist/boundary.d.ts +5 -0
- package/dist/boundary.d.ts.map +1 -1
- package/dist/boundary.js +11 -2
- package/dist/boundary.js.map +1 -1
- package/dist/build-plan.d.ts +18 -6
- package/dist/build-plan.d.ts.map +1 -1
- package/dist/build-plan.js +82 -34
- package/dist/build-plan.js.map +1 -1
- package/dist/build-vite.d.ts +4 -0
- package/dist/build-vite.d.ts.map +1 -1
- package/dist/build-vite.js +68 -13
- package/dist/build-vite.js.map +1 -1
- package/dist/build.d.ts +57 -23
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +356 -85
- package/dist/build.js.map +1 -1
- package/dist/bun-dev-entry.d.ts +1 -1
- package/dist/bun-dev-entry.js +1 -1
- package/dist/cdn.d.ts +74 -0
- package/dist/cdn.d.ts.map +1 -0
- package/dist/cdn.js +132 -0
- package/dist/cdn.js.map +1 -0
- package/dist/client.d.ts +3 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +111 -15
- package/dist/client.js.map +1 -1
- package/dist/conformance.d.ts +4 -3
- package/dist/conformance.d.ts.map +1 -1
- package/dist/conformance.js +12 -3
- package/dist/conformance.js.map +1 -1
- package/dist/csp.d.ts +93 -0
- package/dist/csp.d.ts.map +1 -0
- package/dist/csp.js +122 -0
- package/dist/csp.js.map +1 -0
- package/dist/dev-client.d.ts +76 -0
- package/dist/dev-client.d.ts.map +1 -0
- package/dist/dev-client.js +280 -0
- package/dist/dev-client.js.map +1 -0
- package/dist/dev-diagnostics.d.ts +26 -2
- package/dist/dev-diagnostics.d.ts.map +1 -1
- package/dist/dev-diagnostics.js +38 -7
- package/dist/dev-diagnostics.js.map +1 -1
- package/dist/dev-error.d.ts +4 -13
- package/dist/dev-error.d.ts.map +1 -1
- package/dist/dev-error.js +46 -4
- package/dist/dev-error.js.map +1 -1
- package/dist/dev-feed.d.ts +298 -0
- package/dist/dev-feed.d.ts.map +1 -0
- package/dist/dev-feed.js +797 -0
- package/dist/dev-feed.js.map +1 -0
- package/dist/dev-indicator.d.ts +38 -0
- package/dist/dev-indicator.d.ts.map +1 -0
- package/dist/dev-indicator.js +93 -0
- package/dist/dev-indicator.js.map +1 -0
- package/dist/dev-session.d.ts +77 -0
- package/dist/dev-session.d.ts.map +1 -0
- package/dist/dev-session.js +580 -0
- package/dist/dev-session.js.map +1 -0
- package/dist/dev-sourcemap.d.ts +27 -0
- package/dist/dev-sourcemap.d.ts.map +1 -0
- package/dist/dev-sourcemap.js +235 -0
- package/dist/dev-sourcemap.js.map +1 -0
- package/dist/dev-ssr-graph.d.ts.map +1 -1
- package/dist/dev-ssr-graph.js +13 -5
- package/dist/dev-ssr-graph.js.map +1 -1
- package/dist/dev.d.ts +15 -2
- package/dist/dev.d.ts.map +1 -1
- package/dist/dev.js +69 -44
- package/dist/dev.js.map +1 -1
- package/dist/diagnostic-catalog.d.ts +35 -0
- package/dist/diagnostic-catalog.d.ts.map +1 -0
- package/dist/diagnostic-catalog.js +203 -0
- package/dist/diagnostic-catalog.js.map +1 -0
- package/dist/diagnostic-prompt.d.ts +49 -0
- package/dist/diagnostic-prompt.d.ts.map +1 -0
- package/dist/diagnostic-prompt.js +303 -0
- package/dist/diagnostic-prompt.js.map +1 -0
- package/dist/diagnostic.d.ts +17 -23
- package/dist/diagnostic.d.ts.map +1 -1
- package/dist/diagnostic.js +31 -39
- package/dist/diagnostic.js.map +1 -1
- package/dist/draft.d.ts.map +1 -1
- package/dist/draft.js +4 -1
- package/dist/draft.js.map +1 -1
- package/dist/fn.d.ts +5 -0
- package/dist/fn.d.ts.map +1 -1
- package/dist/fn.js +13 -3
- package/dist/fn.js.map +1 -1
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +4 -2
- package/dist/fs.js.map +1 -1
- package/dist/index.d.ts +13 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -12
- package/dist/index.js.map +1 -1
- package/dist/internal/cdn/cloudflare.d.ts +48 -0
- package/dist/internal/cdn/cloudflare.d.ts.map +1 -0
- package/dist/internal/cdn/cloudflare.js +94 -0
- package/dist/internal/cdn/cloudflare.js.map +1 -0
- package/dist/internal/cdn/core.d.ts +91 -0
- package/dist/internal/cdn/core.d.ts.map +1 -0
- package/dist/internal/cdn/core.js +220 -0
- package/dist/internal/cdn/core.js.map +1 -0
- package/dist/internal/cdn/fastly.d.ts +17 -0
- package/dist/internal/cdn/fastly.d.ts.map +1 -0
- package/dist/internal/cdn/fastly.js +43 -0
- package/dist/internal/cdn/fastly.js.map +1 -0
- package/dist/internal/cdn/vercel.d.ts +31 -0
- package/dist/internal/cdn/vercel.d.ts.map +1 -0
- package/dist/internal/cdn/vercel.js +56 -0
- package/dist/internal/cdn/vercel.js.map +1 -0
- package/dist/internal/code-unit-order.d.ts +4 -0
- package/dist/internal/code-unit-order.d.ts.map +1 -0
- package/dist/internal/code-unit-order.js +6 -0
- package/dist/internal/code-unit-order.js.map +1 -0
- package/dist/internal/codegen.d.ts.map +1 -1
- package/dist/internal/codegen.js +141 -25
- package/dist/internal/codegen.js.map +1 -1
- package/dist/internal/dev-csp.d.ts +24 -0
- package/dist/internal/dev-csp.d.ts.map +1 -0
- package/dist/internal/dev-csp.js +160 -0
- package/dist/internal/dev-csp.js.map +1 -0
- package/dist/internal/dev-reserved.d.ts +25 -0
- package/dist/internal/dev-reserved.d.ts.map +1 -0
- package/dist/internal/dev-reserved.js +39 -0
- package/dist/internal/dev-reserved.js.map +1 -0
- package/dist/internal/html-spans.d.ts +10 -0
- package/dist/internal/html-spans.d.ts.map +1 -0
- package/dist/internal/html-spans.js +46 -0
- package/dist/internal/html-spans.js.map +1 -0
- package/dist/internal/loading-runtime.d.ts +44 -0
- package/dist/internal/loading-runtime.d.ts.map +1 -0
- package/dist/internal/loading-runtime.js +206 -0
- package/dist/internal/loading-runtime.js.map +1 -0
- package/dist/internal/matches-runtime.d.ts +8 -0
- package/dist/internal/matches-runtime.d.ts.map +1 -0
- package/dist/internal/matches-runtime.js +61 -0
- package/dist/internal/matches-runtime.js.map +1 -0
- package/dist/internal/mount-shadow.d.ts +36 -0
- package/dist/internal/mount-shadow.d.ts.map +1 -0
- package/dist/internal/mount-shadow.js +65 -0
- package/dist/internal/mount-shadow.js.map +1 -0
- package/dist/internal/node-builtins.d.ts +3 -0
- package/dist/internal/node-builtins.d.ts.map +1 -0
- package/dist/internal/node-builtins.js +79 -0
- package/dist/internal/node-builtins.js.map +1 -0
- package/dist/internal/output-guard.d.ts +65 -0
- package/dist/internal/output-guard.d.ts.map +1 -0
- package/dist/internal/output-guard.js +630 -0
- package/dist/internal/output-guard.js.map +1 -0
- package/dist/internal/page-execution.d.ts +20 -8
- package/dist/internal/page-execution.d.ts.map +1 -1
- package/dist/internal/page-execution.js +571 -105
- package/dist/internal/page-execution.js.map +1 -1
- package/dist/internal/parity.d.ts +21 -0
- package/dist/internal/parity.d.ts.map +1 -1
- package/dist/internal/parity.js +104 -22
- package/dist/internal/parity.js.map +1 -1
- package/dist/internal/private-env.d.ts +12 -0
- package/dist/internal/private-env.d.ts.map +1 -0
- package/dist/internal/private-env.js +335 -0
- package/dist/internal/private-env.js.map +1 -0
- package/dist/internal/public-url.d.ts +3 -0
- package/dist/internal/public-url.d.ts.map +1 -0
- package/dist/internal/public-url.js +18 -0
- package/dist/internal/public-url.js.map +1 -0
- package/dist/internal/render-document.d.ts +25 -19
- package/dist/internal/render-document.d.ts.map +1 -1
- package/dist/internal/render-document.js +77 -61
- package/dist/internal/render-document.js.map +1 -1
- package/dist/internal/response-controls.d.ts +75 -0
- package/dist/internal/response-controls.d.ts.map +1 -0
- package/dist/internal/response-controls.js +256 -0
- package/dist/internal/response-controls.js.map +1 -0
- package/dist/internal/runtime-contract.d.ts +11 -16
- package/dist/internal/runtime-contract.d.ts.map +1 -1
- package/dist/internal/runtime-contract.js.map +1 -1
- package/dist/internal/secret-scan.d.ts +104 -0
- package/dist/internal/secret-scan.d.ts.map +1 -0
- package/dist/internal/secret-scan.js +485 -0
- package/dist/internal/secret-scan.js.map +1 -0
- package/dist/internal/server-boundary.d.ts +6 -29
- package/dist/internal/server-boundary.d.ts.map +1 -1
- package/dist/internal/server-boundary.js +6 -66
- package/dist/internal/server-boundary.js.map +1 -1
- package/dist/internal/source-map.d.ts +47 -0
- package/dist/internal/source-map.d.ts.map +1 -0
- package/dist/internal/source-map.js +225 -0
- package/dist/internal/source-map.js.map +1 -0
- package/dist/internal/target-compat.d.ts +27 -0
- package/dist/internal/target-compat.d.ts.map +1 -0
- package/dist/internal/target-compat.js +77 -0
- package/dist/internal/target-compat.js.map +1 -0
- package/dist/internal/timing-safe-equal.d.ts +6 -0
- package/dist/internal/timing-safe-equal.d.ts.map +1 -1
- package/dist/internal/timing-safe-equal.js +10 -0
- package/dist/internal/timing-safe-equal.js.map +1 -1
- package/dist/internal/vitals-runtime.d.ts +18 -0
- package/dist/internal/vitals-runtime.d.ts.map +1 -0
- package/dist/internal/vitals-runtime.js +38 -0
- package/dist/internal/vitals-runtime.js.map +1 -0
- package/dist/internal/web-app.d.ts +38 -9
- package/dist/internal/web-app.d.ts.map +1 -1
- package/dist/internal/web-app.js +199 -59
- package/dist/internal/web-app.js.map +1 -1
- package/dist/internal/zone-graph.d.ts +89 -0
- package/dist/internal/zone-graph.d.ts.map +1 -0
- package/dist/internal/zone-graph.js +492 -0
- package/dist/internal/zone-graph.js.map +1 -0
- package/dist/isr.d.ts +83 -6
- package/dist/isr.d.ts.map +1 -1
- package/dist/isr.js +263 -36
- package/dist/isr.js.map +1 -1
- package/dist/llms-txt.d.ts.map +1 -1
- package/dist/llms-txt.js +31 -6
- package/dist/llms-txt.js.map +1 -1
- package/dist/manifest.d.ts +220 -13
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +386 -9
- package/dist/manifest.js.map +1 -1
- package/dist/module-graph.d.ts +26 -5
- package/dist/module-graph.d.ts.map +1 -1
- package/dist/module-graph.js +17 -7
- package/dist/module-graph.js.map +1 -1
- package/dist/navigation.d.ts +17 -3
- package/dist/navigation.d.ts.map +1 -1
- package/dist/navigation.js +11 -5
- package/dist/navigation.js.map +1 -1
- package/dist/nonce.d.ts +47 -0
- package/dist/nonce.d.ts.map +1 -0
- package/dist/nonce.js +63 -0
- package/dist/nonce.js.map +1 -0
- package/dist/plugins/css-modules.d.ts.map +1 -1
- package/dist/plugins/css-modules.js +4 -3
- package/dist/plugins/css-modules.js.map +1 -1
- package/dist/plugins/kit.d.ts +9 -0
- package/dist/plugins/kit.d.ts.map +1 -1
- package/dist/plugins/kit.js +18 -0
- package/dist/plugins/kit.js.map +1 -1
- package/dist/plugins/svg.d.ts +22 -3
- package/dist/plugins/svg.d.ts.map +1 -1
- package/dist/plugins/svg.js +112 -1
- package/dist/plugins/svg.js.map +1 -1
- package/dist/plugins/vite-leak-guard.d.ts +107 -3
- package/dist/plugins/vite-leak-guard.d.ts.map +1 -1
- package/dist/plugins/vite-leak-guard.js +378 -17
- package/dist/plugins/vite-leak-guard.js.map +1 -1
- package/dist/plugins/vite-zone-guard.d.ts +61 -0
- package/dist/plugins/vite-zone-guard.d.ts.map +1 -0
- package/dist/plugins/vite-zone-guard.js +208 -0
- package/dist/plugins/vite-zone-guard.js.map +1 -0
- package/dist/plugins/zone-guard.d.ts +27 -0
- package/dist/plugins/zone-guard.d.ts.map +1 -0
- package/dist/plugins/zone-guard.js +72 -0
- package/dist/plugins/zone-guard.js.map +1 -0
- package/dist/prerender.d.ts +10 -0
- package/dist/prerender.d.ts.map +1 -1
- package/dist/prerender.js +35 -3
- package/dist/prerender.js.map +1 -1
- package/dist/public-dir.d.ts +9 -0
- package/dist/public-dir.d.ts.map +1 -1
- package/dist/public-dir.js +67 -9
- package/dist/public-dir.js.map +1 -1
- package/dist/pwa-manifest.d.ts +68 -0
- package/dist/pwa-manifest.d.ts.map +1 -0
- package/dist/pwa-manifest.js +178 -0
- package/dist/pwa-manifest.js.map +1 -0
- package/dist/query.js +4 -4
- package/dist/query.js.map +1 -1
- package/dist/render-seam.d.ts +42 -2
- package/dist/render-seam.d.ts.map +1 -1
- package/dist/render-seam.js +6 -0
- package/dist/render-seam.js.map +1 -1
- package/dist/route-manifest.d.ts +3 -0
- package/dist/route-manifest.d.ts.map +1 -1
- package/dist/route-manifest.js +26 -3
- package/dist/route-manifest.js.map +1 -1
- package/dist/route-types.d.ts +24 -0
- package/dist/route-types.d.ts.map +1 -0
- package/dist/route-types.js +195 -0
- package/dist/route-types.js.map +1 -0
- package/dist/router.d.ts +28 -6
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +129 -40
- package/dist/router.js.map +1 -1
- package/dist/vitals.d.ts +33 -0
- package/dist/vitals.d.ts.map +1 -0
- package/dist/vitals.js +16 -0
- package/dist/vitals.js.map +1 -0
- package/dist/vite.d.ts +16 -1
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +187 -36
- package/dist/vite.js.map +1 -1
- package/dist/zones.d.ts +70 -0
- package/dist/zones.d.ts.map +1 -0
- package/dist/zones.js +365 -0
- package/dist/zones.js.map +1 -0
- package/package.json +67 -14
- package/src/backend-only.ts +16 -0
- package/src/boundary.ts +18 -5
- package/src/build-plan.ts +90 -35
- package/src/build-vite.ts +77 -11
- package/src/build.ts +466 -96
- package/src/bun-dev-entry.ts +1 -1
- package/src/cdn.ts +216 -0
- package/src/client.ts +111 -18
- package/src/conformance.ts +16 -3
- package/src/csp.ts +194 -0
- package/src/dev-client.ts +349 -0
- package/src/dev-diagnostics.ts +60 -7
- package/src/dev-error.ts +49 -5
- package/src/dev-feed.ts +1140 -0
- package/src/dev-indicator.ts +113 -0
- package/src/dev-session.ts +729 -0
- package/src/dev-sourcemap.ts +281 -0
- package/src/dev-ssr-graph.ts +16 -5
- package/src/dev.ts +86 -43
- package/src/diagnostic-catalog.ts +243 -0
- package/src/diagnostic-prompt.ts +355 -0
- package/src/diagnostic.ts +63 -66
- package/src/draft.ts +4 -1
- package/src/fn.ts +19 -3
- package/src/fs.ts +13 -2
- package/src/index.ts +42 -10
- package/src/internal/cdn/cloudflare.ts +146 -0
- package/src/internal/cdn/core.ts +316 -0
- package/src/internal/cdn/fastly.ts +62 -0
- package/src/internal/cdn/vercel.ts +95 -0
- package/src/internal/code-unit-order.ts +5 -0
- package/src/internal/codegen.ts +161 -24
- package/src/internal/dev-csp.ts +176 -0
- package/src/internal/dev-reserved.ts +52 -0
- package/src/internal/html-spans.ts +50 -0
- package/src/internal/loading-runtime.ts +244 -0
- package/src/internal/matches-runtime.ts +62 -0
- package/src/internal/mount-shadow.ts +88 -0
- package/src/internal/node-builtins.ts +79 -0
- package/src/internal/output-guard.ts +701 -0
- package/src/internal/page-execution.ts +795 -185
- package/src/internal/parity.ts +150 -36
- package/src/internal/private-env.ts +334 -0
- package/src/internal/public-url.ts +22 -0
- package/src/internal/render-document.ts +114 -67
- package/src/internal/response-controls.ts +284 -0
- package/src/internal/runtime-contract.ts +10 -15
- package/src/internal/secret-scan.ts +623 -0
- package/src/internal/server-boundary.ts +6 -69
- package/src/internal/source-map.ts +256 -0
- package/src/internal/target-compat.ts +92 -0
- package/src/internal/timing-safe-equal.ts +13 -0
- package/src/internal/vitals-runtime.ts +53 -0
- package/src/internal/web-app.ts +262 -84
- package/src/internal/zone-graph.ts +593 -0
- package/src/isr.ts +325 -37
- package/src/llms-txt.ts +28 -4
- package/src/manifest.ts +670 -16
- package/src/module-graph.ts +53 -9
- package/src/navigation.ts +29 -6
- package/src/nonce.ts +104 -0
- package/src/plugins/css-modules.ts +5 -3
- package/src/plugins/kit.ts +24 -0
- package/src/plugins/svg.ts +135 -4
- package/src/plugins/vite-leak-guard.ts +529 -16
- package/src/plugins/vite-zone-guard.ts +263 -0
- package/src/plugins/zone-guard.ts +110 -0
- package/src/prerender.ts +49 -3
- package/src/public-dir.ts +69 -8
- package/src/pwa-manifest.ts +226 -0
- package/src/query.ts +4 -4
- package/src/render-seam.ts +46 -1
- package/src/route-manifest.ts +15 -3
- package/src/route-types.ts +264 -0
- package/src/router.ts +163 -63
- package/src/vitals.ts +44 -0
- package/src/vite.ts +207 -36
- package/src/zones.ts +430 -0
- package/dist/plugins/vite-server-only.d.ts +0 -49
- package/dist/plugins/vite-server-only.d.ts.map +0 -1
- package/dist/plugins/vite-server-only.js +0 -57
- package/dist/plugins/vite-server-only.js.map +0 -1
- package/dist/server-only.d.ts +0 -21
- package/dist/server-only.d.ts.map +0 -1
- package/dist/server-only.js +0 -25
- package/dist/server-only.js.map +0 -1
- package/src/plugins/vite-server-only.ts +0 -75
- package/src/server-only.ts +0 -25
package/src/vite.ts
CHANGED
|
@@ -16,11 +16,14 @@ import {
|
|
|
16
16
|
type IncomingMessage,
|
|
17
17
|
type ServerResponse,
|
|
18
18
|
} from "node:http"
|
|
19
|
-
import { isAbsolute, join, relative, resolve as resolvePath, sep } from "node:path"
|
|
20
|
-
import {
|
|
19
|
+
import { dirname, isAbsolute, join, relative, resolve as resolvePath, sep } from "node:path"
|
|
20
|
+
import { CLIENT_BATCH_MAX_BYTES } from "./dev-client.ts"
|
|
21
|
+
import { DEV_REQUEST_ID_HEADER, DEV_SERVER_FILES } from "./dev-feed.ts"
|
|
21
22
|
import { listenOrExplain } from "./dev-port.ts"
|
|
23
|
+
import { createDevSession, type DevAppHooks, isDevAgentPath } from "./dev-session.ts"
|
|
22
24
|
import { discoverRoutes } from "./fs.ts"
|
|
23
25
|
import { DEFAULT_DEV_PORT, generateClientEntry, setSsrModuleLoader } from "./index.ts"
|
|
26
|
+
import { admitViteTags } from "./internal/dev-csp.ts"
|
|
24
27
|
import { viteDedupePackages } from "./internal/identity-policy.ts"
|
|
25
28
|
import {
|
|
26
29
|
assertIdentityParity,
|
|
@@ -39,7 +42,7 @@ import {
|
|
|
39
42
|
reproduciblePath,
|
|
40
43
|
} from "./plugins/kit.ts"
|
|
41
44
|
import { viteServerFnStub } from "./plugins/vite-server-fn.ts"
|
|
42
|
-
import {
|
|
45
|
+
import { viteZoneGuard } from "./plugins/vite-zone-guard.ts"
|
|
43
46
|
|
|
44
47
|
/** Minimal app surface - `createWebApp(...)` satisfies it. */
|
|
45
48
|
interface FetchApp {
|
|
@@ -62,13 +65,20 @@ interface ViteModuleGraph {
|
|
|
62
65
|
interface ViteLike {
|
|
63
66
|
/** Load a module through VITE's graph - the seam that makes the Vite pipeline own SSR too. */
|
|
64
67
|
ssrLoadModule(url: string): Promise<Record<string, unknown>>
|
|
65
|
-
readonly middlewares: (
|
|
68
|
+
readonly middlewares: (
|
|
69
|
+
req: IncomingMessage,
|
|
70
|
+
res: ServerResponse,
|
|
71
|
+
next: (error?: unknown) => void,
|
|
72
|
+
) => void
|
|
66
73
|
transformIndexHtml(url: string, html: string): Promise<string>
|
|
67
74
|
ssrFixStacktrace(err: Error): void
|
|
68
75
|
/** The module graph, used to invalidate a changed file AND its transitive importers before reload. */
|
|
69
76
|
readonly moduleGraph?: ViteModuleGraph
|
|
70
77
|
readonly watcher: {
|
|
71
78
|
on(event: "change" | "add" | "unlink", cb: (path: string) => void): void
|
|
79
|
+
on(event: "ready", cb: () => void): void
|
|
80
|
+
/** Chokidar's ready state, used to handle a ready event emitted before this adapter attaches. */
|
|
81
|
+
readonly _readyEmitted?: boolean
|
|
72
82
|
}
|
|
73
83
|
close(): Promise<void>
|
|
74
84
|
}
|
|
@@ -94,10 +104,14 @@ export interface ViteDevServerOptions {
|
|
|
94
104
|
* Without it SSR resolves through Bun while the client resolves through Vite - two resolvers, one
|
|
95
105
|
* process - which is what makes `resolve.dedupe` fail to reach SSR and produces the dual-React
|
|
96
106
|
* crash. Vite re-evaluates on change, so no `importQuery` cache-buster is needed alongside it.
|
|
107
|
+
*
|
|
108
|
+
* Pass `dev.onLoaderError` to `createWebApp` so failures an `_error` boundary renders still reach the
|
|
109
|
+
* dev feed (`nifra errors`).
|
|
97
110
|
*/
|
|
98
111
|
readonly createApp: (
|
|
99
112
|
clientEntry: string,
|
|
100
113
|
load: (absolutePath: string) => Promise<unknown>,
|
|
114
|
+
dev: DevAppHooks,
|
|
101
115
|
) => FetchApp | Promise<FetchApp>
|
|
102
116
|
/** Vite plugins - inject your framework's official plugin, e.g. `[react()]`. */
|
|
103
117
|
readonly plugins?: readonly unknown[]
|
|
@@ -133,6 +147,16 @@ export interface ViteDevServerOptions {
|
|
|
133
147
|
* resolve it; `nifra build` never honors it. Wired to `nifra dev --allow-duplicate-identity`.
|
|
134
148
|
*/
|
|
135
149
|
readonly allowDuplicateIdentity?: boolean
|
|
150
|
+
/**
|
|
151
|
+
* Write `.nifra/dev-server.json` (how `nifra errors`/`nifra logs` and the MCP tools find this server)
|
|
152
|
+
* and the persisted dev log beside it (default `true`).
|
|
153
|
+
*/
|
|
154
|
+
readonly record?: boolean
|
|
155
|
+
/**
|
|
156
|
+
* Show the browser errors a dev page reports in a badge on that page, with a Copy prompt button per
|
|
157
|
+
* fix (default `true`). Off, the errors still reach the feed.
|
|
158
|
+
*/
|
|
159
|
+
readonly indicator?: boolean
|
|
136
160
|
}
|
|
137
161
|
|
|
138
162
|
export interface ViteDevServer {
|
|
@@ -140,10 +164,12 @@ export interface ViteDevServer {
|
|
|
140
164
|
stop(): Promise<void>
|
|
141
165
|
}
|
|
142
166
|
|
|
167
|
+
export type { DevAppHooks } from "./dev-session.ts"
|
|
143
168
|
export { LAST_ERROR_PATH } from "./diagnostic.ts"
|
|
144
169
|
|
|
145
170
|
// The codegen'd client entry is written here (at the Vite root) so Vite serves + HMRs it.
|
|
146
171
|
const DEV_ENTRY = ".nifra-vite-entry.tsx"
|
|
172
|
+
const VITE_CLOSE_BOUND_MS = 2000
|
|
147
173
|
|
|
148
174
|
/** Candidate spellings for Vite's module-graph map. Vite has used native and slash-normalized
|
|
149
175
|
* absolute Windows paths across versions, while watcher events can additionally arrive as a file URL. */
|
|
@@ -165,6 +191,23 @@ const readNodeBody = async (req: IncomingMessage): Promise<Buffer | undefined> =
|
|
|
165
191
|
return Buffer.concat(chunks)
|
|
166
192
|
}
|
|
167
193
|
|
|
194
|
+
/**
|
|
195
|
+
* An agent request's body, never buffered past `max` bytes. A larger body is drained, not kept, so the
|
|
196
|
+
* client still gets an answer: the session refuses the truncated batch.
|
|
197
|
+
*/
|
|
198
|
+
const readAgentBody = async (req: IncomingMessage, max: number): Promise<Buffer | undefined> => {
|
|
199
|
+
if (req.method === "GET" || req.method === "HEAD") return undefined
|
|
200
|
+
const chunks: Buffer[] = []
|
|
201
|
+
let total = 0
|
|
202
|
+
for await (const chunk of req) {
|
|
203
|
+
if (!Buffer.isBuffer(chunk)) continue
|
|
204
|
+
total += chunk.length
|
|
205
|
+
if (total <= max) chunks.push(chunk)
|
|
206
|
+
}
|
|
207
|
+
// One byte past the cap is enough for the session's own size check to refuse it.
|
|
208
|
+
return total > max ? Buffer.alloc(max + 1) : Buffer.concat(chunks)
|
|
209
|
+
}
|
|
210
|
+
|
|
168
211
|
/** Build a Web `Request` from a Node `IncomingMessage` (+ already-read body) for nifra's `app.fetch`. */
|
|
169
212
|
function toWebRequest(req: IncomingMessage, body: Buffer | undefined): Request {
|
|
170
213
|
const headers = new Headers()
|
|
@@ -382,27 +425,101 @@ export async function createViteDevServer(options: ViteDevServerOptions): Promis
|
|
|
382
425
|
// `vite`, which is assigned just below before the server starts listening.
|
|
383
426
|
let vite!: ViteLike
|
|
384
427
|
let app: FetchApp
|
|
385
|
-
//
|
|
386
|
-
//
|
|
387
|
-
const
|
|
428
|
+
// Failures, console output, request traces and the discovery record for the agent driving this
|
|
429
|
+
// server, plus the overlay and LAST_ERROR_PATH. Shared with the Bun adapter so they cannot drift.
|
|
430
|
+
const session = createDevSession({
|
|
431
|
+
root,
|
|
432
|
+
pipeline: "vite",
|
|
433
|
+
publicEnvPrefix: options.publicEnvPrefix,
|
|
434
|
+
record: options.record,
|
|
435
|
+
indicator: options.indicator,
|
|
436
|
+
})
|
|
437
|
+
const devHooks: DevAppHooks = { onLoaderError: session.onLoaderError }
|
|
438
|
+
|
|
439
|
+
// Refuses backend code before Vite serves or transforms it; held here so a refused module's request
|
|
440
|
+
// is answered with the refusal rather than falling through to the app.
|
|
441
|
+
const zoneGuard = viteZoneGuard({
|
|
442
|
+
appRoot: dirname(routesDir),
|
|
443
|
+
routesDir,
|
|
444
|
+
generatedFiles: [resolvePath(root, DEV_ENTRY)],
|
|
445
|
+
...(options.publicEnvPrefix !== undefined ? { publicEnvPrefix: options.publicEnvPrefix } : {}),
|
|
446
|
+
})
|
|
388
447
|
|
|
389
448
|
const server: NodeHttpServer = createHttpServer((req, res) => {
|
|
390
|
-
// Keep this before Vite's middleware:
|
|
391
|
-
if (
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
449
|
+
// Keep this before Vite's middleware: the agent endpoints are owned by nifra, not files or routes.
|
|
450
|
+
if (isDevAgentPath((req.url ?? "/").split("?", 1)[0] ?? "/")) {
|
|
451
|
+
void (async () => {
|
|
452
|
+
try {
|
|
453
|
+
const body = await readAgentBody(req, CLIENT_BATCH_MAX_BYTES)
|
|
454
|
+
const agent = await session.handle(toWebRequest(req, body))
|
|
455
|
+
if (agent === undefined) {
|
|
456
|
+
handleWithVite(req, res)
|
|
457
|
+
return
|
|
458
|
+
}
|
|
459
|
+
res.statusCode = agent.status
|
|
460
|
+
applyResponseHeaders(agent.headers, res)
|
|
461
|
+
res.end(await agent.text())
|
|
462
|
+
} catch (err) {
|
|
463
|
+
// A client that aborts mid-body rejects the read; unhandled, that rejection ends the process.
|
|
464
|
+
if (!req.destroyed) console.error("[nifra/web/vite] dev endpoint failed:", err)
|
|
465
|
+
if (!res.headersSent) res.statusCode = 500
|
|
466
|
+
res.end()
|
|
467
|
+
}
|
|
468
|
+
})()
|
|
396
469
|
return
|
|
397
470
|
}
|
|
398
|
-
|
|
471
|
+
handleWithVite(req, res)
|
|
472
|
+
})
|
|
473
|
+
|
|
474
|
+
function handleWithVite(req: IncomingMessage, res: ServerResponse): void {
|
|
475
|
+
vite.middlewares(req, res, (error) => {
|
|
476
|
+
// In middleware mode Vite reports a module's transform error to the overlay and passes the
|
|
477
|
+
// request on. A request naming a source file was for a module, never a page: it gets the error,
|
|
478
|
+
// not the app's HTML.
|
|
479
|
+
const url = req.url ?? "/"
|
|
480
|
+
const file = /\.[\w]+(?:[?#]|$)/.test(url) ? zoneGuard.fileForUrl(url) : undefined
|
|
481
|
+
if (error !== undefined || file !== undefined) {
|
|
482
|
+
res.statusCode = 500
|
|
483
|
+
res.setHeader("content-type", "text/plain; charset=utf-8")
|
|
484
|
+
res.setHeader("cache-control", "no-store")
|
|
485
|
+
const reason =
|
|
486
|
+
zoneGuard.refusalFor(url) ??
|
|
487
|
+
(error instanceof Error
|
|
488
|
+
? error.message
|
|
489
|
+
: `[nifra] ${url} failed to transform; the dev server log has the error`)
|
|
490
|
+
session.buildFailed(error ?? new Error(reason), `${url} failed to transform`)
|
|
491
|
+
res.end(`${reason}\n`)
|
|
492
|
+
return
|
|
493
|
+
}
|
|
399
494
|
// Not a Vite asset → nifra SSR. (`next` runs after Vite declines, so the body is still readable.)
|
|
400
495
|
void (async () => {
|
|
401
496
|
try {
|
|
402
497
|
const body = await readNodeBody(req)
|
|
403
|
-
const
|
|
498
|
+
const webRequest = toWebRequest(req, body)
|
|
499
|
+
let overlay = false
|
|
500
|
+
const nifraRes = await session.track(webRequest, async () => {
|
|
501
|
+
try {
|
|
502
|
+
return await app.fetch(webRequest)
|
|
503
|
+
} catch (err) {
|
|
504
|
+
// Source-map the stack first (Vite maps the bundled frames back to your `.ts`), then render
|
|
505
|
+
// the readable dev overlay instead of a bare text dump. Dev-only - production maps to `_error`.
|
|
506
|
+
if (err instanceof Error) vite.ssrFixStacktrace(err)
|
|
507
|
+
overlay = true
|
|
508
|
+
return new Response(
|
|
509
|
+
session.failure(err, { method: req.method ?? "GET", url: req.url ?? "/" }),
|
|
510
|
+
{ status: 500, headers: { "content-type": "text/html; charset=utf-8" } },
|
|
511
|
+
)
|
|
512
|
+
}
|
|
513
|
+
})
|
|
404
514
|
const contentType = nifraRes.headers.get("content-type") ?? ""
|
|
405
515
|
res.statusCode = nifraRes.status
|
|
516
|
+
const requestId = nifraRes.headers.get(DEV_REQUEST_ID_HEADER)
|
|
517
|
+
if (requestId !== null) res.setHeader(DEV_REQUEST_ID_HEADER, requestId)
|
|
518
|
+
if (overlay || session.isOverlay(nifraRes)) {
|
|
519
|
+
res.setHeader("content-type", "text/html; charset=utf-8")
|
|
520
|
+
res.end(await nifraRes.text())
|
|
521
|
+
return
|
|
522
|
+
}
|
|
406
523
|
if (!contentType.includes("text/html")) {
|
|
407
524
|
// Data / redirect / asset response - pass through untouched, streamed (SSE-safe). Set-Cookie is
|
|
408
525
|
// emitted per-header so multi-cookie responses (e.g. better-auth sessions) aren't collapsed.
|
|
@@ -410,25 +527,26 @@ export async function createViteDevServer(options: ViteDevServerOptions): Promis
|
|
|
410
527
|
await pipeWebBodyToNode(nifraRes.body, res)
|
|
411
528
|
return
|
|
412
529
|
}
|
|
413
|
-
// Inject Vite's HMR client + the framework's refresh preamble into the SSR'd HTML
|
|
414
|
-
|
|
530
|
+
// Inject Vite's HMR client + the framework's refresh preamble into the SSR'd HTML, keeping the
|
|
531
|
+
// app's headers (cookies, CSP, cache-control) as the Bun pipeline does.
|
|
532
|
+
const headers = new Headers(nifraRes.headers)
|
|
533
|
+
headers.delete("content-length") // the body grows with Vite's tags
|
|
534
|
+
const page = session.decorateHtml(webRequest, await nifraRes.text(), headers, requestId)
|
|
535
|
+
const html = admitViteTags(await vite.transformIndexHtml(req.url ?? "/", page), headers)
|
|
536
|
+
applyResponseHeaders(headers, res)
|
|
415
537
|
res.setHeader("content-type", "text/html; charset=utf-8")
|
|
416
538
|
res.end(html)
|
|
417
539
|
} catch (err) {
|
|
418
|
-
//
|
|
419
|
-
// the readable dev overlay instead of a bare text dump. Dev-only - production maps to `_error`.
|
|
540
|
+
// A failure past the app (reading the body, Vite's HTML transform): same overlay, same feed.
|
|
420
541
|
if (err instanceof Error) vite.ssrFixStacktrace(err)
|
|
421
|
-
const html =
|
|
422
|
-
method: req.method ?? "GET",
|
|
423
|
-
url: req.url ?? "/",
|
|
424
|
-
})
|
|
542
|
+
const html = session.failure(err, { method: req.method ?? "GET", url: req.url ?? "/" })
|
|
425
543
|
res.statusCode = 500
|
|
426
544
|
res.setHeader("content-type", "text/html; charset=utf-8")
|
|
427
545
|
res.end(html)
|
|
428
546
|
}
|
|
429
547
|
})()
|
|
430
548
|
})
|
|
431
|
-
}
|
|
549
|
+
}
|
|
432
550
|
|
|
433
551
|
// `conditions: ["bun"]` makes Vite resolve nifra's workspace packages (`@nifrajs/web-react/client`, …) to
|
|
434
552
|
// their TS **source** - so the dev server needs no prior `dist` build of the adapter packages.
|
|
@@ -461,6 +579,16 @@ export async function createViteDevServer(options: ViteDevServerOptions): Promis
|
|
|
461
579
|
const adapterPackage = packageNameOf(options.clientModule)
|
|
462
580
|
const ssrExternal = [...(adapterPackage !== undefined ? [adapterPackage] : []), "@nifrajs/web"]
|
|
463
581
|
const usePolling = options.poll ?? process.env.CHOKIDAR_USEPOLLING === "1"
|
|
582
|
+
// The feed writes its record and log under `.nifra/`: watching them would turn every log flush into
|
|
583
|
+
// a "file change" that re-creates the app and marks every entry stale.
|
|
584
|
+
const watch: { ignored: RegExp[]; usePolling?: boolean; interval?: number } = {
|
|
585
|
+
ignored: [DEV_SERVER_FILES],
|
|
586
|
+
}
|
|
587
|
+
// Poll when native fs events aren't delivered (containers/sandboxes).
|
|
588
|
+
if (usePolling) {
|
|
589
|
+
watch.usePolling = true
|
|
590
|
+
watch.interval = 80
|
|
591
|
+
}
|
|
464
592
|
// Never `import("vite")` directly here: the guard in `importVite` has to run first, and the dev
|
|
465
593
|
// server importing vite unguarded is precisely what poisoned the module for the whole process.
|
|
466
594
|
const viteModule = await importVite<ViteModule>()
|
|
@@ -480,12 +608,11 @@ export async function createViteDevServer(options: ViteDevServerOptions): Promis
|
|
|
480
608
|
server: {
|
|
481
609
|
middlewareMode: true,
|
|
482
610
|
hmr: { server },
|
|
483
|
-
|
|
484
|
-
watch: usePolling ? { usePolling: true, interval: 80 } : {},
|
|
611
|
+
watch,
|
|
485
612
|
},
|
|
486
|
-
// Ahead of the user's plugins:
|
|
487
|
-
//
|
|
488
|
-
plugins: [
|
|
613
|
+
// Ahead of the user's plugins: the zone guard refuses backend code before anything serves or
|
|
614
|
+
// transforms it, and a `*.fn` module must be replaced before anything else reads it.
|
|
615
|
+
plugins: [zoneGuard, viteServerFnStub(), ...plugins],
|
|
489
616
|
resolve: {
|
|
490
617
|
conditions: resolveConditions,
|
|
491
618
|
// Dedupe each framework runtime to ONE copy. In a multi-root workspace a shared package can pull
|
|
@@ -523,6 +650,22 @@ export async function createViteDevServer(options: ViteDevServerOptions): Promis
|
|
|
523
650
|
},
|
|
524
651
|
...(options.define ? { define: options.define } : {}),
|
|
525
652
|
})
|
|
653
|
+
// Vite resolves before chokidar necessarily finishes its initial scan. Do not expose the
|
|
654
|
+
// dev server until that scan is complete: a route created immediately after startup must be
|
|
655
|
+
// observed as a change, not folded into the ignored initial snapshot on slower filesystems.
|
|
656
|
+
const watcherReady = new Promise<void>((resolve) => {
|
|
657
|
+
let settled = false
|
|
658
|
+
const markReady = (): void => {
|
|
659
|
+
if (settled) return
|
|
660
|
+
settled = true
|
|
661
|
+
resolve()
|
|
662
|
+
}
|
|
663
|
+
vite.watcher.on("ready", markReady)
|
|
664
|
+
// createServer() can return after chokidar has emitted `ready`, especially on fast local
|
|
665
|
+
// filesystems. Chokidar exposes this state in its structural type so we can cover that case
|
|
666
|
+
// without a startup timeout or a false-positive partial directory snapshot.
|
|
667
|
+
if (vite.watcher._readyEmitted === true) markReady()
|
|
668
|
+
})
|
|
526
669
|
|
|
527
670
|
const ssrLoad = (absolutePath: string): Promise<unknown> => vite.ssrLoadModule(absolutePath)
|
|
528
671
|
// Published so an ADAPTER can reach this graph too. Route modules already load through it; an
|
|
@@ -530,7 +673,7 @@ export async function createViteDevServer(options: ViteDevServerOptions): Promis
|
|
|
530
673
|
// `Chain.svelte`) would otherwise take it from the runtime, which has no compiler for it and no
|
|
531
674
|
// reason to agree with Vite about which copy of the framework runtime it renders through.
|
|
532
675
|
setSsrModuleLoader(ssrLoad)
|
|
533
|
-
app = await options.createApp(entryUrl, ssrLoad)
|
|
676
|
+
app = await options.createApp(entryUrl, ssrLoad, devHooks)
|
|
534
677
|
|
|
535
678
|
// Evict a changed file from the SSR graph together with every module that (transitively) imports it,
|
|
536
679
|
// BEFORE re-creating the app. Vite re-evaluates a directly-changed module on its own, but a parent
|
|
@@ -566,20 +709,35 @@ export async function createViteDevServer(options: ViteDevServerOptions): Promis
|
|
|
566
709
|
const refreshApp = (path?: string): void => {
|
|
567
710
|
if (path !== undefined) invalidateImporterClosure(path)
|
|
568
711
|
const version = ++refreshVersion
|
|
569
|
-
Promise.resolve(options.createApp(entryUrl, ssrLoad))
|
|
712
|
+
Promise.resolve(options.createApp(entryUrl, ssrLoad, devHooks))
|
|
570
713
|
.then((next) => {
|
|
571
714
|
if (version === refreshVersion) app = next
|
|
572
715
|
})
|
|
573
|
-
.catch((err) =>
|
|
716
|
+
.catch((err) => {
|
|
717
|
+
console.error("[nifra/web/vite] app re-create failed:", err)
|
|
718
|
+
session.buildFailed(err, "app re-create failed")
|
|
719
|
+
})
|
|
574
720
|
}
|
|
575
|
-
vite.watcher.on("change", (path) =>
|
|
721
|
+
vite.watcher.on("change", (path) => {
|
|
722
|
+
session.markChange()
|
|
723
|
+
refreshApp(normalizeFilePath(path))
|
|
724
|
+
})
|
|
576
725
|
for (const event of ["add", "unlink"] as const) {
|
|
577
726
|
vite.watcher.on(event, (path) => {
|
|
727
|
+
session.markChange()
|
|
578
728
|
const filePath = normalizeFilePath(path)
|
|
579
|
-
if (pathInside(routesDir, filePath))
|
|
729
|
+
if (pathInside(routesDir, filePath)) {
|
|
730
|
+
writeClientEntry()
|
|
731
|
+
// A newly added route is not in Vite's module graph yet, so invalidating only the
|
|
732
|
+
// route path cannot evict the cached generated entry that imports the route. Evict the
|
|
733
|
+
// generated entry after rewriting it before recreating the SSR app; this also prevents
|
|
734
|
+
// an unlink refresh from briefly loading an entry that still references the deleted file.
|
|
735
|
+
invalidateImporterClosure(resolvePath(root, DEV_ENTRY))
|
|
736
|
+
}
|
|
580
737
|
refreshApp(filePath)
|
|
581
738
|
})
|
|
582
739
|
}
|
|
740
|
+
await watcherReady
|
|
583
741
|
|
|
584
742
|
try {
|
|
585
743
|
await listenOrExplain(server, port, "127.0.0.1")
|
|
@@ -589,21 +747,34 @@ export async function createViteDevServer(options: ViteDevServerOptions): Promis
|
|
|
589
747
|
// then HANGS on it, which is worse than the raw crash this guard replaced: the user sees a dev server
|
|
590
748
|
// that appears to be starting. Tear Vite down so the failure is terminal.
|
|
591
749
|
await vite.close().catch(() => {})
|
|
750
|
+
session.stop()
|
|
592
751
|
throw err
|
|
593
752
|
}
|
|
594
753
|
// Report the port actually BOUND, not the one requested. They differ for `port: 0`, which is how you
|
|
595
754
|
// ask the OS for a free one - the correct thing to do in a test or when running several apps at once.
|
|
596
755
|
// Echoing the request back would return a literal 0, which connects to nothing.
|
|
597
756
|
const address = server.address()
|
|
757
|
+
const boundPort = typeof address === "object" && address !== null ? address.port : port
|
|
758
|
+
session.listening(boundPort)
|
|
598
759
|
return {
|
|
599
|
-
port:
|
|
760
|
+
port: boundPort,
|
|
600
761
|
stop: async () => {
|
|
762
|
+
session.stop()
|
|
601
763
|
// Cleared with the server that owns it: the slot is process-global, so a stopped server leaving
|
|
602
764
|
// its loader behind would hand the next one's adapter a graph that is closed (tests start and
|
|
603
765
|
// stop several dev servers in one process).
|
|
604
766
|
setSsrModuleLoader(undefined)
|
|
605
767
|
server.close()
|
|
606
|
-
|
|
768
|
+
// Vite (8.2) never settles a first dependency optimization that close() cuts short, and close()
|
|
769
|
+
// waits on it for good. Everything else closes in parallel, so only that wait is bounded.
|
|
770
|
+
let bound: ReturnType<typeof setTimeout> | undefined
|
|
771
|
+
await Promise.race([
|
|
772
|
+
vite.close(),
|
|
773
|
+
new Promise<void>((resolve) => {
|
|
774
|
+
bound = setTimeout(resolve, VITE_CLOSE_BOUND_MS)
|
|
775
|
+
}),
|
|
776
|
+
])
|
|
777
|
+
clearTimeout(bound)
|
|
607
778
|
},
|
|
608
779
|
}
|
|
609
780
|
}
|