@blinkk/root 4.1.1 → 4.1.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.
@@ -19,6 +19,19 @@ export declare class Renderer {
19
19
  walkRoutes(cb: (urlPathFormat: string, route: Route) => void | Promise<void>): Promise<void>;
20
20
  handle(req: Request, res: Response, next: NextFunction): Promise<void>;
21
21
  private renderComponent;
22
+ /**
23
+ * Runs a synchronous render function with a hook installed that auto-injects
24
+ * the CSP nonce into `<script>`, `<style>` and `<link rel="stylesheet">`
25
+ * vnodes.
26
+ *
27
+ * NOTE: `preactOptions.vnode` is a global, so the hook must be installed and
28
+ * restored within a single synchronous block. Awaiting inside the swapped
29
+ * window allows concurrent renders to interleave, leaking a stale hook (and
30
+ * its nonce) into other requests.
31
+ *
32
+ * https://preactjs.com/guide/v10/options/
33
+ */
34
+ private withNonceHooks;
22
35
  /** SSG renders a route. */
23
36
  renderRoute(route: Route, options: {
24
37
  routeParams: Record<string, string>;
package/dist/render.js CHANGED
@@ -13213,42 +13213,10 @@ var Renderer = class {
13213
13213
  scriptDeps: [],
13214
13214
  styleDeps: []
13215
13215
  };
13216
- const vdom = /* @__PURE__ */ jsx4(ASSET_MAP_CONTEXT.Provider, { value: this.assetMap, children: /* @__PURE__ */ jsx4(REQUEST_CONTEXT.Provider, { value: ctx, children: /* @__PURE__ */ jsx4(I18N_CONTEXT.Provider, { value: { locale, translations }, children: /* @__PURE__ */ jsx4(HTML_CONTEXT.Provider, { value: htmlContext, children: /* @__PURE__ */ jsx4(Component, { ...props }) }) }) }) });
13216
+ const withProviders = (children) => /* @__PURE__ */ jsx4(ASSET_MAP_CONTEXT.Provider, { value: this.assetMap, children: /* @__PURE__ */ jsx4(REQUEST_CONTEXT.Provider, { value: ctx, children: /* @__PURE__ */ jsx4(I18N_CONTEXT.Provider, { value: { locale, translations }, children: /* @__PURE__ */ jsx4(HTML_CONTEXT.Provider, { value: htmlContext, children }) }) }) });
13217
+ const vdom = withProviders(/* @__PURE__ */ jsx4(Component, { ...props }));
13217
13218
  const renderJsxFn = await this.getJsxRenderFn({ mode: options2.renderMode });
13218
- const injectNonce = (vnode) => {
13219
- if (!vnode) {
13220
- return;
13221
- }
13222
- if (vnode.type === "script" || vnode.type === "style") {
13223
- vnode.props.nonce = nonce;
13224
- }
13225
- if (vnode.type === "link" && vnode.props.rel === "stylesheet") {
13226
- vnode.props.nonce = nonce;
13227
- }
13228
- };
13229
- const preactHook = preactOptions.vnode;
13230
- const rootJsxHook = options.vnode;
13231
- let mainHtml;
13232
- try {
13233
- preactOptions.vnode = (vnode) => {
13234
- injectNonce(vnode);
13235
- if (preactHook) {
13236
- preactHook(vnode);
13237
- }
13238
- };
13239
- if (options !== preactOptions) {
13240
- options.vnode = (vnode) => {
13241
- injectNonce(vnode);
13242
- if (rootJsxHook) {
13243
- rootJsxHook(vnode);
13244
- }
13245
- };
13246
- }
13247
- mainHtml = renderJsxFn(vdom);
13248
- } finally {
13249
- preactOptions.vnode = preactHook;
13250
- options.vnode = rootJsxHook;
13251
- }
13219
+ const mainHtml = this.withNonceHooks(nonce, () => renderJsxFn(vdom));
13252
13220
  const jsDeps = /* @__PURE__ */ new Set();
13253
13221
  const cssDeps = /* @__PURE__ */ new Set();
13254
13222
  const preloadDeps = this.rootConfig.modulePreload !== false ? /* @__PURE__ */ new Set() : null;
@@ -13301,16 +13269,66 @@ var Renderer = class {
13301
13269
  htmlAttrs: htmlContext.htmlAttrs,
13302
13270
  headAttrs: htmlContext.headAttrs,
13303
13271
  bodyAttrs: htmlContext.bodyAttrs,
13272
+ // Components passed as `<Head>` children are only rendered here, so they
13273
+ // need the same context providers and nonce hooks as the main render.
13304
13274
  headComponents: [
13305
- ...htmlContext.headComponents,
13275
+ withProviders(htmlContext.headComponents),
13306
13276
  ...styleTags,
13307
13277
  ...preloadTags,
13308
13278
  ...scriptTags
13309
13279
  ],
13310
- renderMode: options2.renderMode
13280
+ renderMode: options2.renderMode,
13281
+ nonce
13311
13282
  });
13312
13283
  return { html };
13313
13284
  }
13285
+ /**
13286
+ * Runs a synchronous render function with a hook installed that auto-injects
13287
+ * the CSP nonce into `<script>`, `<style>` and `<link rel="stylesheet">`
13288
+ * vnodes.
13289
+ *
13290
+ * NOTE: `preactOptions.vnode` is a global, so the hook must be installed and
13291
+ * restored within a single synchronous block. Awaiting inside the swapped
13292
+ * window allows concurrent renders to interleave, leaking a stale hook (and
13293
+ * its nonce) into other requests.
13294
+ *
13295
+ * https://preactjs.com/guide/v10/options/
13296
+ */
13297
+ withNonceHooks(nonce, fn) {
13298
+ const injectNonce = (vnode) => {
13299
+ if (!vnode) {
13300
+ return;
13301
+ }
13302
+ if (vnode.type === "script" || vnode.type === "style") {
13303
+ vnode.props.nonce = nonce;
13304
+ }
13305
+ if (vnode.type === "link" && vnode.props.rel === "stylesheet") {
13306
+ vnode.props.nonce = nonce;
13307
+ }
13308
+ };
13309
+ const preactHook = preactOptions.vnode;
13310
+ const rootJsxHook = options.vnode;
13311
+ try {
13312
+ preactOptions.vnode = (vnode) => {
13313
+ injectNonce(vnode);
13314
+ if (preactHook) {
13315
+ preactHook(vnode);
13316
+ }
13317
+ };
13318
+ if (options !== preactOptions) {
13319
+ options.vnode = (vnode) => {
13320
+ injectNonce(vnode);
13321
+ if (rootJsxHook) {
13322
+ rootJsxHook(vnode);
13323
+ }
13324
+ };
13325
+ }
13326
+ return fn();
13327
+ } finally {
13328
+ preactOptions.vnode = preactHook;
13329
+ options.vnode = rootJsxHook;
13330
+ }
13331
+ }
13314
13332
  /** SSG renders a route. */
13315
13333
  async renderRoute(route, options2) {
13316
13334
  const routeParams = options2.routeParams;
@@ -13618,7 +13636,9 @@ var Renderer = class {
13618
13636
  }
13619
13637
  )
13620
13638
  ] });
13621
- const content = await this.renderJsx(page, { mode: options2?.renderMode });
13639
+ const renderJsxFn = await this.getJsxRenderFn({ mode: options2?.renderMode });
13640
+ const nonce = options2?.nonce;
13641
+ const content = nonce ? this.withNonceHooks(nonce, () => renderJsxFn(page)) : renderJsxFn(page);
13622
13642
  return `<!doctype html>
13623
13643
  ${content}`;
13624
13644
  }