@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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isSameOriginPath, type ResponseResult, status as statusResult } from "@nifrajs/core/server"
|
|
2
2
|
import type { BoundaryRegistration, BoundaryStates } from "../boundary.ts"
|
|
3
|
+
import { type CspPolicy, cspDocumentNonce, cspHeaderValue, prepareCspPolicy } from "../csp.ts"
|
|
3
4
|
import { type CssLoadingMode, DEFAULT_CSS_LOADING, normalizeCssLoading } from "../css-contract.ts"
|
|
4
5
|
import { DEFERRED_ERROR_CODE, DEFERRED_RUNTIME, prepareDeferred } from "../deferred.ts"
|
|
5
6
|
import { ISR_REVALIDATE_HEADER, ISR_REVALIDATE_TAGS_HEADER, serializeISRTags } from "../isr.ts"
|
|
@@ -13,16 +14,17 @@ import type {
|
|
|
13
14
|
ScriptDescriptor,
|
|
14
15
|
UnsafeScriptDescriptor,
|
|
15
16
|
} from "../manifest.ts"
|
|
16
|
-
import type { RenderAdapter, RenderProps } from "../render-seam.ts"
|
|
17
|
+
import type { MatchChain, RenderAdapter, RenderProps } from "../render-seam.ts"
|
|
17
18
|
import {
|
|
18
19
|
ACTION_GLOBAL,
|
|
19
20
|
BOUNDARY_GLOBAL,
|
|
20
21
|
DATA_GLOBAL,
|
|
22
|
+
HANDOVER_ID,
|
|
21
23
|
LAYOUT_DATA_GLOBAL,
|
|
22
24
|
ROOT_ATTRIBUTE,
|
|
23
25
|
ROUTE_GLOBAL,
|
|
24
26
|
} from "../render-seam.ts"
|
|
25
|
-
import { PRERENDERED_GLOBAL
|
|
27
|
+
import { PRERENDERED_GLOBAL } from "../router.ts"
|
|
26
28
|
import { trustedHeadAttributes } from "./head-attributes.ts"
|
|
27
29
|
import { isStaticMeta, mergeHeads } from "./head-merge.ts"
|
|
28
30
|
import { PRE_HYDRATION_GUARD } from "./runtime-contract.ts"
|
|
@@ -53,7 +55,7 @@ const RESPONSE_RESULT = Symbol.for("nifra.response.result")
|
|
|
53
55
|
* `status(...)` returns. Recognized here rather than imported: core keeps its own predicate internal,
|
|
54
56
|
* and the registry symbol is the contract between them (two copies of core must still agree).
|
|
55
57
|
*/
|
|
56
|
-
const isResponseResult = (value: unknown): value is ResponseResult =>
|
|
58
|
+
export const isResponseResult = (value: unknown): value is ResponseResult =>
|
|
57
59
|
typeof value === "object" &&
|
|
58
60
|
value !== null &&
|
|
59
61
|
(value as { readonly [RESPONSE_RESULT]?: unknown })[RESPONSE_RESULT] === true &&
|
|
@@ -108,6 +110,9 @@ export interface RenderPageOptions {
|
|
|
108
110
|
/** SSG: the prerendered-path set, serialized to `window.__NIFRA_PRERENDERED__` so the client fetches
|
|
109
111
|
* a static `_data.json` on soft-nav into a prerendered route. Empty/omitted ⇒ not injected. */
|
|
110
112
|
readonly prerenderedPaths?: readonly string[]
|
|
113
|
+
/** SSG: the URL of a JSON array of the prerendered paths, handed over in place of
|
|
114
|
+
* {@link prerenderedPaths} so a large set is fetched once instead of riding in every page. */
|
|
115
|
+
readonly prerenderedListUrl?: string
|
|
111
116
|
/** ISR: route freshness in seconds, emitted as the `x-nifra-isr-revalidate` header for a `withISR`
|
|
112
117
|
* wrapper to read. Omit ⇒ no header (the wrapper's default TTL applies). */
|
|
113
118
|
readonly revalidate?: number
|
|
@@ -132,6 +137,8 @@ export interface RenderPageOptions {
|
|
|
132
137
|
readonly layoutData?: readonly unknown[]
|
|
133
138
|
/** Dynamic-boundary states, forwarded to the adapter and serialized for hydration when present. */
|
|
134
139
|
readonly boundaries?: BoundaryStates
|
|
140
|
+
/** The chain's ids and `handle` exports, forwarded as `RenderProps.matchChain` for `useMatches`. */
|
|
141
|
+
readonly matchChain?: MatchChain
|
|
135
142
|
/** HTTP status for the response (default 200; e.g. 404 for a not-found page). */
|
|
136
143
|
readonly status?: number
|
|
137
144
|
/** Extra response headers - e.g. the `cache-control` a terminal status page wants. `content-type`
|
|
@@ -168,6 +175,12 @@ export interface RenderPageOptions {
|
|
|
168
175
|
/** CSP nonce applied to every framework-owned executable script in this document. Nonce-bearing
|
|
169
176
|
* documents are marked `private, no-store` so a request-specific nonce is never replayed. */
|
|
170
177
|
readonly nonce?: string
|
|
178
|
+
/**
|
|
179
|
+
* A hash-based Content-Security-Policy from `createCspPolicy`. The document then carries `nonce`
|
|
180
|
+
* only when it needs one (it defers a value, or a head tag names the nonce); otherwise it renders
|
|
181
|
+
* nonce-free and cacheable. The policy's header is set on the response either way.
|
|
182
|
+
*/
|
|
183
|
+
readonly csp?: CspPolicy
|
|
171
184
|
/**
|
|
172
185
|
* Advanced: a per-route slot the renderer fills with the request-invariant document pieces (shell
|
|
173
186
|
* prefix/suffix, tail statics) on the first render and reuses afterwards, skipping their re-assembly.
|
|
@@ -189,13 +202,10 @@ export interface RenderAssemblyCache {
|
|
|
189
202
|
shellPre?: string
|
|
190
203
|
/** Shell from after the deferred-runtime insertion point through the open `#root` container. */
|
|
191
204
|
shellPost?: string
|
|
192
|
-
/** Tail opener: the
|
|
205
|
+
/** Tail opener: the handover script open tag + the data member's key. */
|
|
193
206
|
tailPre?: string
|
|
194
|
-
/** Tail
|
|
195
|
-
|
|
196
|
-
/** Tail data prefix: the `window.<data global>=` assignment head. */
|
|
197
|
-
tailData?: string
|
|
198
|
-
/** Tail from after the serialized data through `</html>`. */
|
|
207
|
+
/** Tail from after the per-request handover members (the route id, prerendered paths, the handover
|
|
208
|
+
* close) through `</html>`. */
|
|
199
209
|
tailPost?: string
|
|
200
210
|
}
|
|
201
211
|
|
|
@@ -221,6 +231,12 @@ export function renderPage(options: RenderPageInput): MaybePromise<Response> {
|
|
|
221
231
|
}
|
|
222
232
|
|
|
223
233
|
export function renderPageResult(options: RenderPageInput): MaybePromise<RenderedPage> {
|
|
234
|
+
const { csp } = options
|
|
235
|
+
if (csp !== undefined) {
|
|
236
|
+
// The policy hashes the adapter's constant scripts once; only the first document waits for it.
|
|
237
|
+
const ready = prepareCspPolicy(csp, options.adapter)
|
|
238
|
+
if (ready !== undefined) return ready.then(() => renderPageResult(options))
|
|
239
|
+
}
|
|
224
240
|
const {
|
|
225
241
|
adapter,
|
|
226
242
|
chain,
|
|
@@ -231,6 +247,7 @@ export function renderPageResult(options: RenderPageInput): MaybePromise<Rendere
|
|
|
231
247
|
styles = [],
|
|
232
248
|
cssLoading: requestedCssLoading,
|
|
233
249
|
prerenderedPaths = [],
|
|
250
|
+
prerenderedListUrl,
|
|
234
251
|
revalidate,
|
|
235
252
|
revalidateTags = [],
|
|
236
253
|
routeId,
|
|
@@ -240,22 +257,25 @@ export function renderPageResult(options: RenderPageInput): MaybePromise<Rendere
|
|
|
240
257
|
rootId = "root",
|
|
241
258
|
hydrate = true,
|
|
242
259
|
islandScripts = [],
|
|
243
|
-
nonce,
|
|
260
|
+
nonce: requestedNonce,
|
|
244
261
|
boundaries,
|
|
245
262
|
headers: extraHeaders,
|
|
246
263
|
} = options
|
|
247
264
|
const cssLoading = normalizeCssLoading(requestedCssLoading ?? DEFAULT_CSS_LOADING)
|
|
248
|
-
if (
|
|
265
|
+
if (requestedNonce !== undefined && requestedNonce.trim() === "") {
|
|
249
266
|
throw new TypeError("[nifra/web] renderPage nonce must be non-empty when provided")
|
|
250
267
|
}
|
|
251
|
-
|
|
252
|
-
|
|
268
|
+
// Each handover entry after the data is `,"<global>":<json>`; the data opens the object, so it always
|
|
269
|
+
// has a first member and every other entry is a plain suffix.
|
|
270
|
+
const route = routeId === undefined ? "" : `,"${ROUTE_GLOBAL}":${serializeData(routeId)}`
|
|
253
271
|
// The SSG prerendered-path set (when an app declares it) - the client reads it to fetch a static
|
|
254
272
|
// `_data.json` on soft-nav into a prerendered route instead of hitting the worker. Empty ⇒ omitted.
|
|
255
273
|
const prerendered =
|
|
256
|
-
|
|
257
|
-
? ""
|
|
258
|
-
:
|
|
274
|
+
prerenderedListUrl !== undefined
|
|
275
|
+
? `,"${PRERENDERED_GLOBAL}":${serializeData(prerenderedListUrl)}`
|
|
276
|
+
: prerenderedPaths.length === 0
|
|
277
|
+
? ""
|
|
278
|
+
: `,"${PRERENDERED_GLOBAL}":${serializeData(prerenderedPaths)}`
|
|
259
279
|
// Split deferred values: the component sees markers (id + promise) to `<Await>`; the serialized
|
|
260
280
|
// data carries `{__nifra_deferred: id}` placeholders (promises don't serialize). `actionData` may
|
|
261
281
|
// also `defer()` - split it too, continuing the id space so a single registry settles both. The
|
|
@@ -295,21 +315,34 @@ export function renderPageResult(options: RenderPageInput): MaybePromise<Rendere
|
|
|
295
315
|
...(actionSplit ? actionSplit.deferred : []),
|
|
296
316
|
...(boundarySplit ? boundarySplit.deferred : []),
|
|
297
317
|
]
|
|
318
|
+
// Under a CSP policy a document carries a nonce only when it has a script specific to this request:
|
|
319
|
+
// each settled deferred value streams one, and an executable head tag names the nonce. Every other
|
|
320
|
+
// document is nonce-free - its inline scripts are the constant ones the policy lists by hash - so its
|
|
321
|
+
// CSP header is the same on every request and it stays cacheable.
|
|
322
|
+
const nonce =
|
|
323
|
+
csp === undefined
|
|
324
|
+
? requestedNonce
|
|
325
|
+
: cspDocumentNonce(
|
|
326
|
+
csp,
|
|
327
|
+
adapter,
|
|
328
|
+
hydrate,
|
|
329
|
+
allDeferred.length > 0 || headNamesNonce(head),
|
|
330
|
+
requestedNonce,
|
|
331
|
+
)
|
|
332
|
+
const nonceAttr = nonce === undefined ? "" : ` nonce="${escapeAttr(nonce)}"`
|
|
298
333
|
// Omitted entirely when no layout has a loader - a page-only app emits exactly what it did before.
|
|
299
334
|
const layoutTail =
|
|
300
335
|
options.layoutData === undefined
|
|
301
336
|
? ""
|
|
302
|
-
:
|
|
337
|
+
: `,"${LAYOUT_DATA_GLOBAL}":${serializeData(layoutSplits.map((split) => split.forClient))}`
|
|
303
338
|
|
|
304
339
|
// Only emit the action global when an action actually ran, so plain GET output is unchanged.
|
|
305
340
|
const action =
|
|
306
|
-
actionSplit === undefined
|
|
307
|
-
? ""
|
|
308
|
-
: `window.${ACTION_GLOBAL}=${serializeData(actionSplit.forClient)};`
|
|
341
|
+
actionSplit === undefined ? "" : `,"${ACTION_GLOBAL}":${serializeData(actionSplit.forClient)}`
|
|
309
342
|
const boundaryTail =
|
|
310
343
|
boundarySplit === undefined
|
|
311
344
|
? ""
|
|
312
|
-
:
|
|
345
|
+
: `,"${BOUNDARY_GLOBAL}":${serializeData(boundarySplit.forClient)}`
|
|
313
346
|
const deferredRuntime =
|
|
314
347
|
allDeferred.length > 0 ? `<script${nonceAttr}>${DEFERRED_RUNTIME}</script>` : ""
|
|
315
348
|
// The regex only injects the CSP nonce into the (constant) hydration head; with no nonce it's a
|
|
@@ -321,6 +354,14 @@ export function renderPageResult(options: RenderPageInput): MaybePromise<Rendere
|
|
|
321
354
|
const slot: RenderAssemblyCache =
|
|
322
355
|
nonce === undefined && options.assemblyCache !== undefined ? options.assemblyCache : {}
|
|
323
356
|
if (slot.shellPre === undefined) {
|
|
357
|
+
// An empty entry is not "no client": `<script type="module" src="">` resolves to the page URL, so
|
|
358
|
+
// the browser would load the document itself as a module. Checked here, where the shell is built,
|
|
359
|
+
// so a cached route pays it once.
|
|
360
|
+
if (hydrate && (clientEntry === undefined || clientEntry.trim() === "")) {
|
|
361
|
+
throw new TypeError(
|
|
362
|
+
"[nifra/web] a hydrating page needs a non-empty clientEntry (the built client entry URL); pass hydrate: false for a page with no client",
|
|
363
|
+
)
|
|
364
|
+
}
|
|
324
365
|
// Matched-route chunk preloads, concatenated directly. De-duped against the entry, which is
|
|
325
366
|
// preloaded separately below.
|
|
326
367
|
let preloadLinks = ""
|
|
@@ -376,7 +417,7 @@ export function renderPageResult(options: RenderPageInput): MaybePromise<Rendere
|
|
|
376
417
|
const entryPreloads = hydrate
|
|
377
418
|
? `<link rel="modulepreload" href="${escapeAttr(clientEntry ?? "")}">${preloadLinks}`
|
|
378
419
|
: ""
|
|
379
|
-
slot.shellPre = `<!doctype html><html${htmlAttrs}><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">${hydrationGuard}<title>${escapeHtml(head?.title ?? title)}</title>${headTags(head)}${styleLinks}${entryPreloads}`
|
|
420
|
+
slot.shellPre = `<!doctype html><html${htmlAttrs}><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">${hydrationGuard}<title>${escapeHtml(head?.title ?? title)}</title>${headTags(head, nonce)}${styleLinks}${entryPreloads}`
|
|
380
421
|
slot.shellPost = `${islandPreloads}${hydrationHead}</head><body><div id="${escapeAttr(rootId)}"${rootMarker}>`
|
|
381
422
|
// Island bundles load regardless of `hydrate` - a static page (hydrate:false) ships no framework
|
|
382
423
|
// client but can still mount no-framework islands (`@nifrajs/web/islands`).
|
|
@@ -384,14 +425,11 @@ export function renderPageResult(options: RenderPageInput): MaybePromise<Rendere
|
|
|
384
425
|
for (const src of islandScripts)
|
|
385
426
|
islandTags += `<script type="module" src="${escapeAttr(src)}"${nonceAttr}></script>`
|
|
386
427
|
if (hydrate) {
|
|
387
|
-
|
|
388
|
-
slot.
|
|
389
|
-
slot.
|
|
390
|
-
slot.tailPost = `</script><script type="module" src="${escapeAttr(clientEntry ?? "")}"${nonceAttr}></script>${islandTags}</body></html>`
|
|
428
|
+
// Inert JSON, never executed: the page state needs no nonce and no hash under any CSP.
|
|
429
|
+
slot.tailPre = `<script type="application/json" id="${HANDOVER_ID}">{"${DATA_GLOBAL}":`
|
|
430
|
+
slot.tailPost = `${route}${prerendered}}</script><script type="module" src="${escapeAttr(clientEntry ?? "")}"${nonceAttr}></script>${islandTags}</body></html>`
|
|
391
431
|
} else {
|
|
392
432
|
slot.tailPre = ""
|
|
393
|
-
slot.tailMid = ""
|
|
394
|
-
slot.tailData = ""
|
|
395
433
|
slot.tailPost = `${islandTags}</body></html>`
|
|
396
434
|
}
|
|
397
435
|
}
|
|
@@ -402,10 +440,10 @@ export function renderPageResult(options: RenderPageInput): MaybePromise<Rendere
|
|
|
402
440
|
// Closes the hydration container; deferred resolve scripts go AFTER it (outside `#root`) so they
|
|
403
441
|
// aren't part of the adapter's hydrated tree (an inline script inside it breaks hydration).
|
|
404
442
|
const closeRootHtml = "</div>"
|
|
405
|
-
// Tail - the
|
|
406
|
-
// the
|
|
443
|
+
// Tail - the page-state handover + the client module. Module scripts defer (run after parse), so
|
|
444
|
+
// the handover + every streamed deferred resolution are in the document before the entry hydrates.
|
|
407
445
|
const tailHtml = hydrate
|
|
408
|
-
? `${slot.tailPre}${
|
|
446
|
+
? `${slot.tailPre}${serializeData(forClient)}${action}${layoutTail}${boundaryTail}${slot.tailPost}`
|
|
409
447
|
: (slot.tailPost as string)
|
|
410
448
|
const headers: Record<string, string> = { "content-type": "text/html; charset=utf-8" }
|
|
411
449
|
// Caller-supplied headers (a terminal status page's `cache-control`, say). Applied before the
|
|
@@ -426,6 +464,10 @@ export function renderPageResult(options: RenderPageInput): MaybePromise<Rendere
|
|
|
426
464
|
// also keeps `withISR` from storing a document whose executable scripts carry request-specific
|
|
427
465
|
// authorization to run under the caller's CSP.
|
|
428
466
|
if (nonce !== undefined) headers["cache-control"] = "private, no-store"
|
|
467
|
+
if (csp !== undefined) {
|
|
468
|
+
const policy = cspHeaderValue(csp, adapter, nonce)
|
|
469
|
+
if (policy !== undefined) headers["content-security-policy"] = policy
|
|
470
|
+
}
|
|
429
471
|
const renderProps: RenderProps = {
|
|
430
472
|
data: forComponent,
|
|
431
473
|
actionData: actionSplit?.forComponent,
|
|
@@ -444,6 +486,7 @@ export function renderPageResult(options: RenderPageInput): MaybePromise<Rendere
|
|
|
444
486
|
...(boundarySplit !== undefined
|
|
445
487
|
? { boundaries: boundarySplit.forComponent as BoundaryStates }
|
|
446
488
|
: {}),
|
|
489
|
+
...(options.matchChain !== undefined ? { matchChain: options.matchChain } : {}),
|
|
447
490
|
}
|
|
448
491
|
|
|
449
492
|
// Fast path: nothing `defer()`s and the adapter can render synchronously to a string → buffer the
|
|
@@ -476,6 +519,7 @@ export function renderPageResult(options: RenderPageInput): MaybePromise<Rendere
|
|
|
476
519
|
tailHtml,
|
|
477
520
|
status,
|
|
478
521
|
headers,
|
|
522
|
+
nonce,
|
|
479
523
|
nonceAttr,
|
|
480
524
|
).then((response) => new ResponseRenderedPage(response))
|
|
481
525
|
}
|
|
@@ -490,6 +534,7 @@ async function renderStreamedPage(
|
|
|
490
534
|
tailHtml: string,
|
|
491
535
|
status: number,
|
|
492
536
|
headers: Record<string, string>,
|
|
537
|
+
nonce: string | undefined,
|
|
493
538
|
nonceAttr: string,
|
|
494
539
|
): Promise<Response> {
|
|
495
540
|
// Streaming path - required for `defer()` (progressive `<Await>` resolution) and used by any adapter
|
|
@@ -500,7 +545,10 @@ async function renderStreamedPage(
|
|
|
500
545
|
const shell = enc.encode(shellHtml)
|
|
501
546
|
const closeRoot = enc.encode(closeRootHtml)
|
|
502
547
|
const tail = enc.encode(tailHtml)
|
|
503
|
-
const appStream =
|
|
548
|
+
const appStream =
|
|
549
|
+
nonce === undefined
|
|
550
|
+
? await adapter.renderToStream(chain, renderProps)
|
|
551
|
+
: await adapter.renderToStream(chain, renderProps, { nonce })
|
|
504
552
|
const body = streamDocument(shell, appStream, closeRoot, allDeferred, tail, enc, nonceAttr)
|
|
505
553
|
return new Response(body, { status, headers })
|
|
506
554
|
}
|
|
@@ -623,7 +671,7 @@ export interface RedirectOptions {
|
|
|
623
671
|
* attacker-controlled input straight through. Set `true` for a deliberate external redirect. */
|
|
624
672
|
readonly external?: boolean
|
|
625
673
|
/** Extra response headers. A redirect is no longer a `Response`, so there is no `.headers` to
|
|
626
|
-
* mutate after the fact - name them here. Cookies
|
|
674
|
+
* mutate after the fact - name them here. Cookies queued with `ctx.set.cookie()` still ride it. */
|
|
627
675
|
readonly headers?: Readonly<Record<string, string>>
|
|
628
676
|
}
|
|
629
677
|
|
|
@@ -727,37 +775,6 @@ export function withDuplicateInstanceHint(err: unknown): unknown {
|
|
|
727
775
|
return augmented
|
|
728
776
|
}
|
|
729
777
|
|
|
730
|
-
/**
|
|
731
|
-
* An action's control-flow value passes straight through - except a redirect on a client-submit data
|
|
732
|
-
* request: fetch would follow the 3xx into HTML the client can't use, so the redirect rides the
|
|
733
|
-
* X-Nifra-Redirect header on a 204 and the client navigates. One conversion shared by the returned-
|
|
734
|
-
* and thrown- paths, so `return redirect()` and `throw redirect()` agree.
|
|
735
|
-
*
|
|
736
|
-
* Takes either shape: `redirect()` is a plain render, while a hand-rolled `new Response(...)` from an
|
|
737
|
-
* action still arrives as a `Response`. The rewrite stays on the lane its input was on - a plain
|
|
738
|
-
* redirect converts to a plain 204, and never materializes the `Response` it is replacing.
|
|
739
|
-
*/
|
|
740
|
-
export function actionResponse(
|
|
741
|
-
result: Response | ResponseResult,
|
|
742
|
-
isDataRequest: boolean,
|
|
743
|
-
): Response | ResponseResult {
|
|
744
|
-
if (!isDataRequest) return result
|
|
745
|
-
if (isResponseResult(result)) {
|
|
746
|
-
const plain = result.plain
|
|
747
|
-
// No `plain` means a carrier that only knows how to build a `Response` (not one of ours) - fall
|
|
748
|
-
// back rather than guess at its status.
|
|
749
|
-
if (plain === undefined) return actionResponse(result.toResponse(), isDataRequest)
|
|
750
|
-
if (plain.status < 300 || plain.status >= 400) return result
|
|
751
|
-
const location = plain.headers?.location ?? "/"
|
|
752
|
-
return statusResult(204, undefined, { headers: { [REDIRECT_HEADER]: location } })
|
|
753
|
-
}
|
|
754
|
-
if (result.status >= 300 && result.status < 400) {
|
|
755
|
-
const location = result.headers.get("location") ?? "/"
|
|
756
|
-
return statusResult(204, undefined, { headers: { [REDIRECT_HEADER]: location } })
|
|
757
|
-
}
|
|
758
|
-
return result
|
|
759
|
-
}
|
|
760
|
-
|
|
761
778
|
/** A loaded layout module. `loader`/`gate` are the layout-loader surface; `meta` predates it. */
|
|
762
779
|
export type LoadedLayoutModules = ReadonlyArray<{
|
|
763
780
|
default: unknown
|
|
@@ -765,6 +782,10 @@ export type LoadedLayoutModules = ReadonlyArray<{
|
|
|
765
782
|
loader?: LayoutLoader
|
|
766
783
|
action?: unknown
|
|
767
784
|
gate?: boolean
|
|
785
|
+
// Read only when it is a function - see `ShouldRevalidate` in manifest.ts.
|
|
786
|
+
shouldRevalidate?: unknown
|
|
787
|
+
// Reported by `useMatches` - see `RouteModule.handle`.
|
|
788
|
+
handle?: unknown
|
|
768
789
|
// A layout may declare its own `searchSchema`; the route's effective search merges the layout chain's
|
|
769
790
|
// schemas with the page's (page-wins). Present on the raw module already - typed here so it is readable.
|
|
770
791
|
searchSchema?: RouteModule["searchSchema"]
|
|
@@ -998,6 +1019,19 @@ function tagAttrs(tag: "meta" | "link", attrs: Readonly<object>): string | null
|
|
|
998
1019
|
// so a route module that's GC'd takes its entry with it.
|
|
999
1020
|
const headTagsCache = new WeakMap<Meta, string>()
|
|
1000
1021
|
|
|
1022
|
+
// An executable script runs as written, so it is checked rather than escaped: `\u003c` is valid only
|
|
1023
|
+
// inside a JS string, and escaping turned `if (a < b)` into a syntax error. What the HTML tokenizer
|
|
1024
|
+
// reads as the element's end, or as the start of an escaped section, is refused instead.
|
|
1025
|
+
const SCRIPT_BREAKOUT = /<\/script|<!--/i
|
|
1026
|
+
|
|
1027
|
+
function assertExecutableScriptContent(content: string): void {
|
|
1028
|
+
if (SCRIPT_BREAKOUT.test(content)) {
|
|
1029
|
+
throw new TypeError(
|
|
1030
|
+
'[nifra/web] an executable inline script cannot contain "</script" or "<!--"; write "<\\/script" or split the string',
|
|
1031
|
+
)
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1001
1035
|
function assertExecutableScriptType(type: string): void {
|
|
1002
1036
|
if (!EXECUTABLE_SCRIPT_TYPES.has(type)) {
|
|
1003
1037
|
throw new TypeError(
|
|
@@ -1013,9 +1047,15 @@ function assertExecutableScriptType(type: string): void {
|
|
|
1013
1047
|
* or close the tag early. String concatenation (no intermediate `.map()` arrays + spread) - parity with
|
|
1014
1048
|
* the already concat-based preloadLinks/styleLinks/islandPreloads loops; byte-identical output. Result
|
|
1015
1049
|
* is memoized only for objects observed as static meta exports (serialized once per route). */
|
|
1016
|
-
|
|
1050
|
+
/** Whether a document head names the CSP nonce: an executable script or a `<link nonce>`. */
|
|
1051
|
+
const headNamesNonce = (head: Meta | undefined): boolean =>
|
|
1052
|
+
(head?.unsafeScript?.length ?? 0) > 0 || (head?.link?.some((l) => l.nonce !== undefined) ?? false)
|
|
1053
|
+
|
|
1054
|
+
function headTags(head: Meta | undefined, documentNonce?: string): string {
|
|
1017
1055
|
if (head === undefined) return ""
|
|
1018
|
-
|
|
1056
|
+
// Executable head metadata carries a caller-chosen nonce, so never cache it by object identity. A
|
|
1057
|
+
// static route object may otherwise retain one request's nonce and replay it on another document.
|
|
1058
|
+
const cacheable = isStaticMeta(head) && (head.unsafeScript?.length ?? 0) === 0
|
|
1019
1059
|
if (cacheable) {
|
|
1020
1060
|
const cached = headTagsCache.get(head)
|
|
1021
1061
|
if (cached !== undefined) return cached
|
|
@@ -1056,7 +1096,13 @@ function headTags(head: Meta | undefined): string {
|
|
|
1056
1096
|
// attribute and inject markup. Measured: `type: '"><img src=x onerror=alert(1)>'` reached the
|
|
1057
1097
|
// document. An injection in the slot whose whole purpose is to make script emission trustworthy.
|
|
1058
1098
|
assertExecutableScriptType(s.type)
|
|
1059
|
-
|
|
1099
|
+
if (documentNonce !== undefined && s.nonce !== documentNonce) {
|
|
1100
|
+
throw new TypeError(
|
|
1101
|
+
"[nifra/web] executable head scripts must use the same CSP nonce as the document",
|
|
1102
|
+
)
|
|
1103
|
+
}
|
|
1104
|
+
assertExecutableScriptContent(s.content)
|
|
1105
|
+
out += `<script type="${s.type}" nonce="${escapeAttr(s.nonce)}" data-nifra>${s.content}</script>`
|
|
1060
1106
|
}
|
|
1061
1107
|
if (cacheable) headTagsCache.set(head, out)
|
|
1062
1108
|
return out
|
|
@@ -1140,6 +1186,7 @@ export function unsafeInlineScript(
|
|
|
1140
1186
|
// place a caller is told what it may pass. Failing at the call site names the argument; failing at
|
|
1141
1187
|
// render names a document.
|
|
1142
1188
|
assertExecutableScriptType(type)
|
|
1189
|
+
assertExecutableScriptContent(content)
|
|
1143
1190
|
return {
|
|
1144
1191
|
unsafe: true,
|
|
1145
1192
|
type,
|