@nifrajs/web 3.5.0 → 4.0.2
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 +136 -35
- 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 +503 -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 +394 -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 +80 -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 +248 -43
- 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 +135 -36
- 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 +638 -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 +682 -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 +119 -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 +257 -42
- 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/internal/parity.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* manifest normalization so those callers cannot quietly grow separate rules.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from "node:fs"
|
|
9
|
+
import { existsSync, lstatSync, readdirSync, readFileSync, realpathSync, statSync } from "node:fs"
|
|
10
10
|
import { lstat, realpath, stat } from "node:fs/promises"
|
|
11
11
|
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path"
|
|
12
12
|
import {
|
|
@@ -17,7 +17,10 @@ import {
|
|
|
17
17
|
type SingleCopyRegistration,
|
|
18
18
|
} from "@nifrajs/core/single-copy"
|
|
19
19
|
import { discoverRoutes } from "../fs.ts"
|
|
20
|
+
import { codeUnitOrder } from "./code-unit-order.ts"
|
|
21
|
+
import { withoutComments } from "./html-spans.ts"
|
|
20
22
|
import { isIdentitySensitivePackage } from "./identity-policy.ts"
|
|
23
|
+
import { publicUrlPath } from "./public-url.ts"
|
|
21
24
|
|
|
22
25
|
const DEPENDENCY_FIELDS = [
|
|
23
26
|
"dependencies",
|
|
@@ -39,6 +42,13 @@ export interface IdentityParityCopy {
|
|
|
39
42
|
*/
|
|
40
43
|
readonly absolutePath?: string
|
|
41
44
|
readonly importers: readonly string[]
|
|
45
|
+
/**
|
|
46
|
+
* Symlinks an importer reached this copy through that point outside the install that owns the
|
|
47
|
+
* importer, display-relative - a link another project planted (a sibling app's `node_modules`
|
|
48
|
+
* linked into a shared package). Removing it lets the importer resolve its own install's copy.
|
|
49
|
+
* Absent when no such link was crossed.
|
|
50
|
+
*/
|
|
51
|
+
readonly links?: readonly string[]
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
export type IdentityParityCause = "version-skew" | "duplicate-path"
|
|
@@ -78,6 +88,11 @@ export interface IdentityParityFinding {
|
|
|
78
88
|
* workspace, and at least one copy sits outside that subdirectory.
|
|
79
89
|
*/
|
|
80
90
|
readonly scope?: string
|
|
91
|
+
/**
|
|
92
|
+
* Where a copy came from when an importer reached it through a symlink pointing outside its own
|
|
93
|
+
* install: each link and its target, and the fix (remove the link). Absent when no copy was.
|
|
94
|
+
*/
|
|
95
|
+
readonly provenance?: string
|
|
81
96
|
/**
|
|
82
97
|
* The copies exist but the app declared this package single-copy, so the resolver collapses them
|
|
83
98
|
* before anything loads. Reported, never fatal - see `SingleCopyCoverage`.
|
|
@@ -279,8 +294,10 @@ const hasStylesheetImport = (source: string): boolean => {
|
|
|
279
294
|
}
|
|
280
295
|
/** A single-file-component `<style>` block (Svelte/Vue). The bundler extracts these into the app
|
|
281
296
|
* stylesheet even though no `import "...css"` statement exists, so the dev contract must count them
|
|
282
|
-
* or a scoped-style component would look style-free next to a production manifest that carries css.
|
|
283
|
-
|
|
297
|
+
* or a scoped-style component would look style-free next to a production manifest that carries css.
|
|
298
|
+
* A `<style>` inside markup or an expression is not a block, which is why the match is anchored to a
|
|
299
|
+
* line start; one in an HTML comment is prose, so comments are removed before it runs. */
|
|
300
|
+
const SFC_STYLE = /^<style[\s>]/im
|
|
284
301
|
const isSingleFileComponent = (file: string): boolean =>
|
|
285
302
|
file.endsWith(".svelte") || file.endsWith(".vue")
|
|
286
303
|
|
|
@@ -484,21 +501,53 @@ const workspaceImporters = async (
|
|
|
484
501
|
return { importers, truncated }
|
|
485
502
|
}
|
|
486
503
|
|
|
504
|
+
/**
|
|
505
|
+
* The symlink under `dir/node_modules` an import of `parts` crossed to reach `resolved`, when the copy
|
|
506
|
+
* sits outside `boundary` - the install that owns the importer. Package-manager store links (bun's
|
|
507
|
+
* `.bun/`, pnpm's `.pnpm/`, a workspace package linked to the root store) stay inside it and are not
|
|
508
|
+
* reported; a link another project planted, or a `bun link` into a global directory, is.
|
|
509
|
+
*/
|
|
510
|
+
const foreignLink = (
|
|
511
|
+
dir: string,
|
|
512
|
+
parts: readonly string[],
|
|
513
|
+
boundary: string,
|
|
514
|
+
resolved: string,
|
|
515
|
+
): string | undefined => {
|
|
516
|
+
if (pathInside(boundary, resolved)) return undefined
|
|
517
|
+
const realBoundary = realpathOrSelf(boundary)
|
|
518
|
+
if (pathInside(realBoundary, resolved)) return undefined
|
|
519
|
+
let segment = join(dir, "node_modules")
|
|
520
|
+
for (let index = 0; ; index++) {
|
|
521
|
+
const info = lstatSync(segment, { throwIfNoEntry: false })
|
|
522
|
+
if (info === undefined) return undefined
|
|
523
|
+
if (info.isSymbolicLink() && !pathInside(realBoundary, realpathOrSelf(segment))) return segment
|
|
524
|
+
const next = parts[index]
|
|
525
|
+
if (next === undefined) return undefined
|
|
526
|
+
segment = join(segment, next)
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
487
530
|
export const resolvedInstalledCopy = async (
|
|
488
531
|
importer: string,
|
|
489
532
|
boundary: string,
|
|
490
533
|
name: string,
|
|
491
|
-
): Promise<
|
|
534
|
+
): Promise<
|
|
535
|
+
{ readonly path: string; readonly version: string; readonly link?: string } | undefined
|
|
536
|
+
> => {
|
|
492
537
|
const parts = name.split("/")
|
|
493
538
|
for (let dir = importer; ; dir = dirname(dir)) {
|
|
494
539
|
const packageDir = join(dir, "node_modules", ...parts)
|
|
495
540
|
const meta = await readJson(join(packageDir, "package.json"))
|
|
496
541
|
if (meta !== undefined) {
|
|
497
542
|
try {
|
|
543
|
+
const path = await realpath(packageDir)
|
|
544
|
+
// Boundary "" (doctor's stale-dist scan, workspace-link) asks only where the copy is.
|
|
545
|
+
const link = boundary === "" ? undefined : foreignLink(dir, parts, boundary, path)
|
|
498
546
|
return {
|
|
499
|
-
path
|
|
547
|
+
path,
|
|
500
548
|
version:
|
|
501
549
|
typeof meta.version === "string" && meta.version.length > 0 ? meta.version : "unknown",
|
|
550
|
+
...(link === undefined ? {} : { link }),
|
|
502
551
|
}
|
|
503
552
|
} catch {
|
|
504
553
|
return undefined
|
|
@@ -604,7 +653,7 @@ const describeTopology = (
|
|
|
604
653
|
const root = installRootOf(path)
|
|
605
654
|
counts.set(root, (counts.get(root) ?? 0) + 1)
|
|
606
655
|
}
|
|
607
|
-
const roots = [...counts.entries()].sort(([a], [b]) => a
|
|
656
|
+
const roots = [...counts.entries()].sort(([a], [b]) => codeUnitOrder(a, b))
|
|
608
657
|
const breakdown = roots
|
|
609
658
|
.map(([root, count]) => `${count} under ${displayPath(base, root)}`)
|
|
610
659
|
.join(", ")
|
|
@@ -644,8 +693,22 @@ const describeScope = (
|
|
|
644
693
|
return `${outside.length} of these copies ${outside.length === 1 ? "is" : "are"} outside ${here}, so this fails every build in the workspace, including apps that never import the package. The scan is anchored on the workspace on purpose: a copy reached through a workspace-linked dependency cannot be seen from ${here} alone, and scoping to it would miss the case this check exists for. Fix the copies where they live, or declare the package single-copy.`
|
|
645
694
|
}
|
|
646
695
|
|
|
647
|
-
|
|
648
|
-
|
|
696
|
+
/**
|
|
697
|
+
* The dependencies of `pkg` the scan compares across copies: the built-in identity-sensitive set plus
|
|
698
|
+
* every package the app declared single-copy. A declaration is a claim that one copy loads, so a
|
|
699
|
+
* declared package gets the same scrutiny as react - otherwise a version skew in it would be enforced
|
|
700
|
+
* at load time (the resolver refuses to redirect it) and never reported here. The match is core's
|
|
701
|
+
* `matchesSingleCopyDeclaration`, the one the resolver uses, so check and enforcement cover one set.
|
|
702
|
+
*/
|
|
703
|
+
const identityTargets = (
|
|
704
|
+
pkg: Record<string, unknown>,
|
|
705
|
+
declared: readonly string[],
|
|
706
|
+
): readonly string[] =>
|
|
707
|
+
dependencyNames(pkg)
|
|
708
|
+
.filter(
|
|
709
|
+
(name) => isIdentitySensitivePackage(name) || matchesSingleCopyDeclaration(declared, name),
|
|
710
|
+
)
|
|
711
|
+
.sort()
|
|
649
712
|
|
|
650
713
|
/** version-skew is a range problem: one reinstall from the root collapses it. */
|
|
651
714
|
const VERSION_SKEW_REMEDIATION =
|
|
@@ -658,6 +721,14 @@ const duplicatePathRemediation = (name: string): string =>
|
|
|
658
721
|
const identityRemediation = (cause: IdentityParityCause, name: string): string =>
|
|
659
722
|
cause === "version-skew" ? VERSION_SKEW_REMEDIATION : duplicatePathRemediation(name)
|
|
660
723
|
|
|
724
|
+
/** Name each planted link, its target, and the fix, for a finding whose copies were reached that way. */
|
|
725
|
+
const describeProvenance = (copies: readonly IdentityParityCopy[]): string | undefined => {
|
|
726
|
+
const lines = copies.flatMap((copy) => (copy.links ?? []).map((link) => `${link} → ${copy.path}`))
|
|
727
|
+
if (lines.length === 0) return undefined
|
|
728
|
+
const one = lines.length === 1
|
|
729
|
+
return `reached through ${one ? "a symlink" : "symlinks"} that ${one ? "points" : "point"} outside the importer's install: ${lines.join(", ")}. Unless the importer declares ${one ? "it" : "them"} as a \`link:\` dependency, ${one ? "the link was" : "the links were"} planted by hand, by another project, or by \`bun link\` - remove ${one ? "it" : "them"} and reinstall there, so the importer resolves its own install's copy.`
|
|
730
|
+
}
|
|
731
|
+
|
|
661
732
|
/** What is left to do about a duplicate the declaration already covers. */
|
|
662
733
|
const deduplicatedRemediation = (registration: SingleCopyRegistration): string =>
|
|
663
734
|
registration.run || registration.test
|
|
@@ -695,22 +766,31 @@ export async function collectIdentityParity(
|
|
|
695
766
|
const scanRoot = workspace.root
|
|
696
767
|
const scanPackage = workspace.package
|
|
697
768
|
const { importers, truncated } = await workspaceImporters(scanRoot, scanPackage)
|
|
698
|
-
const byPackage = new Map<
|
|
769
|
+
const byPackage = new Map<
|
|
770
|
+
string,
|
|
771
|
+
Map<string, { version: string; importers: Set<string>; links: Set<string> }>
|
|
772
|
+
>()
|
|
699
773
|
const record = (
|
|
700
774
|
name: string,
|
|
701
|
-
copy: { readonly path: string; readonly version: string },
|
|
775
|
+
copy: { readonly path: string; readonly version: string; readonly link?: string },
|
|
702
776
|
importer: string,
|
|
703
777
|
): void => {
|
|
704
778
|
const copies = byPackage.get(name) ?? new Map()
|
|
705
|
-
const entry = copies.get(copy.path) ?? {
|
|
779
|
+
const entry = copies.get(copy.path) ?? {
|
|
780
|
+
version: copy.version,
|
|
781
|
+
importers: new Set<string>(),
|
|
782
|
+
links: new Set<string>(),
|
|
783
|
+
}
|
|
706
784
|
entry.importers.add(importer)
|
|
785
|
+
if (copy.link !== undefined) entry.links.add(displayPath(requestedRoot, copy.link))
|
|
707
786
|
copies.set(copy.path, entry)
|
|
708
787
|
byPackage.set(name, copies)
|
|
709
788
|
}
|
|
710
789
|
|
|
790
|
+
const singleCopy = singleCopyCoverage(requestedRoot, scanRoot)
|
|
711
791
|
const targets = new Set<string>()
|
|
712
792
|
for (const importer of importers) {
|
|
713
|
-
for (const name of identityTargets(importer.package)) {
|
|
793
|
+
for (const name of identityTargets(importer.package, singleCopy.declared)) {
|
|
714
794
|
if (importer.package.name === name) continue
|
|
715
795
|
targets.add(name)
|
|
716
796
|
const copy = await resolvedInstalledCopy(importer.root, scanRoot, name)
|
|
@@ -732,7 +812,7 @@ export async function collectIdentityParity(
|
|
|
732
812
|
const boundary = await linkedRepoBoundary(linkedRoot)
|
|
733
813
|
const linkedTargets = new Set([
|
|
734
814
|
...targets,
|
|
735
|
-
...(linkedPackage === undefined ? [] : identityTargets(linkedPackage)),
|
|
815
|
+
...(linkedPackage === undefined ? [] : identityTargets(linkedPackage, singleCopy.declared)),
|
|
736
816
|
])
|
|
737
817
|
for (const name of linkedTargets) {
|
|
738
818
|
if (linkedPackage?.name === name) continue
|
|
@@ -741,21 +821,24 @@ export async function collectIdentityParity(
|
|
|
741
821
|
}
|
|
742
822
|
}
|
|
743
823
|
|
|
744
|
-
const singleCopy = singleCopyCoverage(requestedRoot, scanRoot)
|
|
745
824
|
const findings: IdentityParityFinding[] = []
|
|
746
825
|
const deduplicated: IdentityParityFinding[] = []
|
|
747
|
-
for (const [name, copies] of [...byPackage.entries()].sort(([a], [b]) => a
|
|
826
|
+
for (const [name, copies] of [...byPackage.entries()].sort(([a], [b]) => codeUnitOrder(a, b))) {
|
|
748
827
|
if (copies.size < 2) continue
|
|
749
828
|
const absolutePaths = [...copies.keys()].sort()
|
|
750
829
|
const resolvedCopies = [...copies.entries()]
|
|
751
|
-
.sort(([a], [b]) => a
|
|
752
|
-
.map(
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
830
|
+
.sort(([a], [b]) => codeUnitOrder(a, b))
|
|
831
|
+
.map(
|
|
832
|
+
([path, copy]): IdentityParityCopy => ({
|
|
833
|
+
version: copy.version,
|
|
834
|
+
path: displayPath(requestedRoot, path),
|
|
835
|
+
absolutePath: path,
|
|
836
|
+
importers: [...copy.importers].sort(),
|
|
837
|
+
...(copy.links.size === 0 ? {} : { links: [...copy.links].sort() }),
|
|
838
|
+
}),
|
|
839
|
+
)
|
|
758
840
|
const topology = describeTopology(requestedRoot, scanRoot, absolutePaths)
|
|
841
|
+
const provenance = describeProvenance(resolvedCopies)
|
|
759
842
|
const scope = describeScope(requestedRoot, scanRoot, absolutePaths)
|
|
760
843
|
const versions = [...new Set(resolvedCopies.map((copy) => copy.version))].sort()
|
|
761
844
|
const cause: IdentityParityCause = versions.length > 1 ? "version-skew" : "duplicate-path"
|
|
@@ -780,6 +863,7 @@ export async function collectIdentityParity(
|
|
|
780
863
|
: identityRemediation(cause, name),
|
|
781
864
|
...(topology === undefined ? {} : { topology }),
|
|
782
865
|
...(scope === undefined ? {} : { scope }),
|
|
866
|
+
...(provenance === undefined ? {} : { provenance }),
|
|
783
867
|
deduplicated: covered,
|
|
784
868
|
}
|
|
785
869
|
;(covered ? deduplicated : findings).push(finding)
|
|
@@ -804,7 +888,8 @@ export function formatIdentityParityFindings(findings: readonly IdentityParityFi
|
|
|
804
888
|
.map((copy) => copy.path)
|
|
805
889
|
.join(", ")}` +
|
|
806
890
|
(finding.topology === undefined ? "" : `\n topology: ${finding.topology}`) +
|
|
807
|
-
(finding.scope === undefined ? "" : `\n scope: ${finding.scope}`)
|
|
891
|
+
(finding.scope === undefined ? "" : `\n scope: ${finding.scope}`) +
|
|
892
|
+
(finding.provenance === undefined ? "" : `\n links: ${finding.provenance}`),
|
|
808
893
|
)
|
|
809
894
|
.join("\n")
|
|
810
895
|
}
|
|
@@ -904,15 +989,21 @@ export function logicalStaticAssets(manifest: BuildManifestLike): readonly strin
|
|
|
904
989
|
return [...logical].sort()
|
|
905
990
|
}
|
|
906
991
|
|
|
992
|
+
/**
|
|
993
|
+
* The one order parity puts route ids in, on both sides. Code-unit order, not `localeCompare`: the
|
|
994
|
+
* two disagree on `_` against `[` (`[lang]` sorts before `_404` by code unit, after it by locale), so
|
|
995
|
+
* a dev side sorted one way and a build side sorted the other failed the equality check for every app
|
|
996
|
+
* with a `_404` and a dynamic route. Code-unit order is also locale-independent, so the verdict cannot
|
|
997
|
+
* change with the machine running the build.
|
|
998
|
+
*/
|
|
999
|
+
export const compareRouteIds = (a: string, b: string): number => (a < b ? -1 : a > b ? 1 : 0)
|
|
1000
|
+
|
|
907
1001
|
export function normalizeBuildManifest(manifest: BuildManifestLike): ParityManifest {
|
|
1002
|
+
const routes = Object.entries(manifest.routes).sort(([a], [b]) => compareRouteIds(a, b))
|
|
908
1003
|
return {
|
|
909
1004
|
moduleGraph: {
|
|
910
|
-
routes:
|
|
911
|
-
routeChunks: Object.fromEntries(
|
|
912
|
-
Object.entries(manifest.routes)
|
|
913
|
-
.sort(([a], [b]) => a.localeCompare(b))
|
|
914
|
-
.map(([route, chunks]) => [route, chunks.length]),
|
|
915
|
-
),
|
|
1005
|
+
routes: routes.map(([route]) => route),
|
|
1006
|
+
routeChunks: Object.fromEntries(routes.map(([route, chunks]) => [route, chunks.length])),
|
|
916
1007
|
// Allowlist, not denylist: the dev/prod module-graph contract is the JavaScript module graph
|
|
917
1008
|
// only. `js:entry` and `js:route:<id>:<n>` are the roles dev can reconstruct from source. Which
|
|
918
1009
|
// *non-JS* files a bundler emits (svg, woff2, an extracted stylesheet) is an output detail, not
|
|
@@ -928,7 +1019,7 @@ export function normalizeBuildManifest(manifest: BuildManifestLike): ParityManif
|
|
|
928
1019
|
|
|
929
1020
|
export function createDevelopmentParityManifest(input: DevelopmentParityInput): ParityManifest {
|
|
930
1021
|
const routes = Object.fromEntries(
|
|
931
|
-
Object.entries(input.routes).sort(([a], [b]) => a
|
|
1022
|
+
Object.entries(input.routes).sort(([a], [b]) => compareRouteIds(a, b)),
|
|
932
1023
|
)
|
|
933
1024
|
const publicFiles = [...input.publicFiles].sort()
|
|
934
1025
|
return {
|
|
@@ -951,10 +1042,11 @@ const sourceFilesUnder = (root: string): readonly string[] => {
|
|
|
951
1042
|
const files: string[] = []
|
|
952
1043
|
const walk = (current: string): void => {
|
|
953
1044
|
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
1045
|
+
// Dot-directories hold tool output (.wrangler, .vercel, .svelte-kit), whose bundles quote css
|
|
1046
|
+
// imports the app never makes.
|
|
954
1047
|
if (
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
)
|
|
1048
|
+
entry.name.startsWith(".") ||
|
|
1049
|
+
["node_modules", "dist", "dist-node", "build", "coverage"].includes(entry.name)
|
|
958
1050
|
)
|
|
959
1051
|
continue
|
|
960
1052
|
const path = join(current, entry.name)
|
|
@@ -974,7 +1066,7 @@ const publicFilesUnder = (publicDir: string | false | undefined): readonly strin
|
|
|
974
1066
|
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
975
1067
|
const path = join(current, entry.name)
|
|
976
1068
|
if (entry.isDirectory()) walk(path)
|
|
977
|
-
else if (entry.isFile()) files.push(
|
|
1069
|
+
else if (entry.isFile()) files.push(publicUrlPath(relative(root, path)))
|
|
978
1070
|
}
|
|
979
1071
|
}
|
|
980
1072
|
walk(root)
|
|
@@ -994,7 +1086,10 @@ export function collectDevelopmentParityInput(
|
|
|
994
1086
|
const sourceRoot = dirname(resolve(routesDir))
|
|
995
1087
|
const css = sourceFilesUnder(sourceRoot).some((file) => {
|
|
996
1088
|
const content = readFileSync(file, "utf8")
|
|
997
|
-
return
|
|
1089
|
+
return (
|
|
1090
|
+
hasStylesheetImport(content) ||
|
|
1091
|
+
(isSingleFileComponent(file) && SFC_STYLE.test(withoutComments(content)))
|
|
1092
|
+
)
|
|
998
1093
|
})
|
|
999
1094
|
? ["css:present"]
|
|
1000
1095
|
: []
|
|
@@ -1079,9 +1174,28 @@ function explainParityDifference(
|
|
|
1079
1174
|
parts.push(
|
|
1080
1175
|
`chunks only in development=${JSON.stringify(assets.onlyDevelopment)} only in production=${JSON.stringify(assets.onlyProduction)}`,
|
|
1081
1176
|
)
|
|
1177
|
+
const counts = Object.keys(dev.routeChunks).filter(
|
|
1178
|
+
(route) =>
|
|
1179
|
+
Object.hasOwn(prod.routeChunks, route) &&
|
|
1180
|
+
dev.routeChunks[route] !== prod.routeChunks[route],
|
|
1181
|
+
)
|
|
1182
|
+
if (counts.length > 0)
|
|
1183
|
+
parts.push(
|
|
1184
|
+
`route chunk counts differ: ${counts.map((route) => `${route} development=${dev.routeChunks[route]} production=${prod.routeChunks[route]}`).join(", ")}`,
|
|
1185
|
+
)
|
|
1186
|
+
// Same members, same counts: what is left is order. Name the field, because an ordering
|
|
1187
|
+
// disagreement is a parity bug, not an app defect, and reads nothing like a missing chunk.
|
|
1188
|
+
if (parts.length === 0 && !equal(dev.routes, prod.routes))
|
|
1189
|
+
parts.push(
|
|
1190
|
+
`route order differs: development=${JSON.stringify(dev.routes)} production=${JSON.stringify(prod.routes)}`,
|
|
1191
|
+
)
|
|
1192
|
+
if (parts.length === 0 && !equal(dev.emittedAssets, prod.emittedAssets))
|
|
1193
|
+
parts.push(
|
|
1194
|
+
`chunk order differs: development=${JSON.stringify(dev.emittedAssets)} production=${JSON.stringify(prod.emittedAssets)}`,
|
|
1195
|
+
)
|
|
1082
1196
|
if (parts.length === 0)
|
|
1083
1197
|
parts.push(
|
|
1084
|
-
`route chunk
|
|
1198
|
+
`route chunk order differs: development=${JSON.stringify(dev.routeChunks)} production=${JSON.stringify(prod.routeChunks)}`,
|
|
1085
1199
|
)
|
|
1086
1200
|
return `module-graph: ${parts.join("; ")}`
|
|
1087
1201
|
}
|