@nestjs-ssr/react 0.3.3 → 0.3.4

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/cli/init.js CHANGED
@@ -39,7 +39,7 @@ var main = citty.defineCommand({
39
39
  default: "5173"
40
40
  }
41
41
  },
42
- async run({ args }) {
42
+ run({ args }) {
43
43
  const cwd = process.cwd();
44
44
  const viewsDir = args.views;
45
45
  const vitePort = parseInt(args.port, 10) || 5173;
@@ -419,17 +419,17 @@ export default defineConfig({
419
419
  packageJson.scripts["start:dev"] = 'concurrently --raw -n vite,nest -c cyan,green "pnpm:dev:vite" "pnpm:dev:nest"';
420
420
  shouldUpdate = true;
421
421
  }
422
- const existingBuild = packageJson.scripts.build;
422
+ const existingBuild = packageJson.scripts["build"];
423
423
  const recommendedBuild = "nest build && pnpm build:client && pnpm build:server";
424
424
  if (!existingBuild) {
425
- packageJson.scripts.build = recommendedBuild;
425
+ packageJson.scripts["build"] = recommendedBuild;
426
426
  shouldUpdate = true;
427
427
  consola.consola.success("Created build script");
428
428
  } else if (existingBuild !== recommendedBuild) {
429
429
  if (!existingBuild.includes("build:client") || !existingBuild.includes("build:server")) {
430
430
  consola.consola.warn(`Found existing build script: "${existingBuild}"`);
431
431
  consola.consola.info(`Updating to: ${recommendedBuild}`);
432
- packageJson.scripts.build = recommendedBuild;
432
+ packageJson.scripts["build"] = recommendedBuild;
433
433
  shouldUpdate = true;
434
434
  } else {
435
435
  consola.consola.info("Build scripts already configured");
@@ -528,4 +528,4 @@ export default defineConfig({
528
528
  consola.consola.log(" Terminal 2: pnpm dev:nest");
529
529
  }
530
530
  });
531
- citty.runMain(main);
531
+ void citty.runMain(main);
package/dist/cli/init.mjs CHANGED
@@ -36,7 +36,7 @@ var main = defineCommand({
36
36
  default: "5173"
37
37
  }
38
38
  },
39
- async run({ args }) {
39
+ run({ args }) {
40
40
  const cwd = process.cwd();
41
41
  const viewsDir = args.views;
42
42
  const vitePort = parseInt(args.port, 10) || 5173;
@@ -416,17 +416,17 @@ export default defineConfig({
416
416
  packageJson.scripts["start:dev"] = 'concurrently --raw -n vite,nest -c cyan,green "pnpm:dev:vite" "pnpm:dev:nest"';
417
417
  shouldUpdate = true;
418
418
  }
419
- const existingBuild = packageJson.scripts.build;
419
+ const existingBuild = packageJson.scripts["build"];
420
420
  const recommendedBuild = "nest build && pnpm build:client && pnpm build:server";
421
421
  if (!existingBuild) {
422
- packageJson.scripts.build = recommendedBuild;
422
+ packageJson.scripts["build"] = recommendedBuild;
423
423
  shouldUpdate = true;
424
424
  consola.success("Created build script");
425
425
  } else if (existingBuild !== recommendedBuild) {
426
426
  if (!existingBuild.includes("build:client") || !existingBuild.includes("build:server")) {
427
427
  consola.warn(`Found existing build script: "${existingBuild}"`);
428
428
  consola.info(`Updating to: ${recommendedBuild}`);
429
- packageJson.scripts.build = recommendedBuild;
429
+ packageJson.scripts["build"] = recommendedBuild;
430
430
  shouldUpdate = true;
431
431
  } else {
432
432
  consola.info("Build scripts already configured");
@@ -525,4 +525,4 @@ export default defineConfig({
525
525
  consola.log(" Terminal 2: pnpm dev:nest");
526
526
  }
527
527
  });
528
- runMain(main);
528
+ void runMain(main);
package/dist/index.js CHANGED
@@ -7,13 +7,13 @@ var path = require('path');
7
7
  var devalue = require('devalue');
8
8
  var escapeHtml = require('escape-html');
9
9
  var server = require('react-dom/server');
10
- var React = require('react');
10
+ var React2 = require('react');
11
11
  var operators = require('rxjs/operators');
12
12
 
13
13
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
14
14
 
15
15
  var escapeHtml__default = /*#__PURE__*/_interopDefault(escapeHtml);
16
- var React__default = /*#__PURE__*/_interopDefault(React);
16
+ var React2__default = /*#__PURE__*/_interopDefault(React2);
17
17
 
18
18
  var __defProp = Object.defineProperty;
19
19
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
@@ -339,16 +339,18 @@ StringRenderer = _ts_decorate2([
339
339
  typeof exports.TemplateParserService === "undefined" ? Object : exports.TemplateParserService
340
340
  ])
341
341
  ], StringRenderer);
342
+
343
+ // src/render/error-pages/error-page-development.tsx
342
344
  function ErrorPageDevelopment({ error, viewPath, phase }) {
343
345
  const stackLines = error.stack ? error.stack.split("\n").slice(1) : [];
344
- return /* @__PURE__ */ React__default.default.createElement("html", {
346
+ return /* @__PURE__ */ React.createElement("html", {
345
347
  lang: "en"
346
- }, /* @__PURE__ */ React__default.default.createElement("head", null, /* @__PURE__ */ React__default.default.createElement("meta", {
348
+ }, /* @__PURE__ */ React.createElement("head", null, /* @__PURE__ */ React.createElement("meta", {
347
349
  charSet: "UTF-8"
348
- }), /* @__PURE__ */ React__default.default.createElement("meta", {
350
+ }), /* @__PURE__ */ React.createElement("meta", {
349
351
  name: "viewport",
350
352
  content: "width=device-width, initial-scale=1.0"
351
- }), /* @__PURE__ */ React__default.default.createElement("title", null, `SSR Error - ${error.name}`), /* @__PURE__ */ React__default.default.createElement("style", {
353
+ }), /* @__PURE__ */ React.createElement("title", null, `SSR Error - ${error.name}`), /* @__PURE__ */ React.createElement("style", {
352
354
  dangerouslySetInnerHTML: {
353
355
  __html: `
354
356
  body {
@@ -399,28 +401,30 @@ function ErrorPageDevelopment({ error, viewPath, phase }) {
399
401
  }
400
402
  `
401
403
  }
402
- })), /* @__PURE__ */ React__default.default.createElement("body", null, /* @__PURE__ */ React__default.default.createElement("div", {
404
+ })), /* @__PURE__ */ React.createElement("body", null, /* @__PURE__ */ React.createElement("div", {
403
405
  className: "error-container"
404
- }, /* @__PURE__ */ React__default.default.createElement("h1", null, "Server-Side Rendering Error"), /* @__PURE__ */ React__default.default.createElement("div", {
406
+ }, /* @__PURE__ */ React.createElement("h1", null, "Server-Side Rendering Error"), /* @__PURE__ */ React.createElement("div", {
405
407
  className: "error-type"
406
- }, error.name), /* @__PURE__ */ React__default.default.createElement("div", {
408
+ }, error.name), /* @__PURE__ */ React.createElement("div", {
407
409
  className: "error-message"
408
- }, error.message), /* @__PURE__ */ React__default.default.createElement("h2", null, "Stack Trace"), /* @__PURE__ */ React__default.default.createElement("div", {
410
+ }, error.message), /* @__PURE__ */ React.createElement("h2", null, "Stack Trace"), /* @__PURE__ */ React.createElement("div", {
409
411
  className: "stack-trace"
410
- }, /* @__PURE__ */ React__default.default.createElement("pre", null, stackLines.join("\n"))), /* @__PURE__ */ React__default.default.createElement("div", {
412
+ }, /* @__PURE__ */ React.createElement("pre", null, stackLines.join("\n"))), /* @__PURE__ */ React.createElement("div", {
411
413
  className: "meta"
412
- }, /* @__PURE__ */ React__default.default.createElement("p", null, /* @__PURE__ */ React__default.default.createElement("strong", null, "View Path:"), " ", viewPath), /* @__PURE__ */ React__default.default.createElement("p", null, /* @__PURE__ */ React__default.default.createElement("strong", null, "Error Phase:"), " ", phase === "shell" ? "Shell (before streaming started)" : "Streaming (during content delivery)"), /* @__PURE__ */ React__default.default.createElement("p", null, /* @__PURE__ */ React__default.default.createElement("strong", null, "Environment:"), " Development")))));
414
+ }, /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("strong", null, "View Path:"), " ", viewPath), /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("strong", null, "Error Phase:"), " ", phase === "shell" ? "Shell (before streaming started)" : "Streaming (during content delivery)"), /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("strong", null, "Environment:"), " Development")))));
413
415
  }
414
416
  __name(ErrorPageDevelopment, "ErrorPageDevelopment");
417
+
418
+ // src/render/error-pages/error-page-production.tsx
415
419
  function ErrorPageProduction() {
416
- return /* @__PURE__ */ React__default.default.createElement("html", {
420
+ return /* @__PURE__ */ React.createElement("html", {
417
421
  lang: "en"
418
- }, /* @__PURE__ */ React__default.default.createElement("head", null, /* @__PURE__ */ React__default.default.createElement("meta", {
422
+ }, /* @__PURE__ */ React.createElement("head", null, /* @__PURE__ */ React.createElement("meta", {
419
423
  charSet: "UTF-8"
420
- }), /* @__PURE__ */ React__default.default.createElement("meta", {
424
+ }), /* @__PURE__ */ React.createElement("meta", {
421
425
  name: "viewport",
422
426
  content: "width=device-width, initial-scale=1.0"
423
- }), /* @__PURE__ */ React__default.default.createElement("title", null, "Error"), /* @__PURE__ */ React__default.default.createElement("style", {
427
+ }), /* @__PURE__ */ React.createElement("title", null, "Error"), /* @__PURE__ */ React.createElement("style", {
424
428
  dangerouslySetInnerHTML: {
425
429
  __html: `
426
430
  body {
@@ -447,9 +451,9 @@ function ErrorPageProduction() {
447
451
  }
448
452
  `
449
453
  }
450
- })), /* @__PURE__ */ React__default.default.createElement("body", null, /* @__PURE__ */ React__default.default.createElement("div", {
454
+ })), /* @__PURE__ */ React.createElement("body", null, /* @__PURE__ */ React.createElement("div", {
451
455
  className: "error-container"
452
- }, /* @__PURE__ */ React__default.default.createElement("h1", null, "500"), /* @__PURE__ */ React__default.default.createElement("p", null, "Internal Server Error"), /* @__PURE__ */ React__default.default.createElement("p", null, "Something went wrong while rendering this page."))));
456
+ }, /* @__PURE__ */ React.createElement("h1", null, "500"), /* @__PURE__ */ React.createElement("p", null, "Internal Server Error"), /* @__PURE__ */ React.createElement("p", null, "Something went wrong while rendering this page."))));
453
457
  }
454
458
  __name(ErrorPageProduction, "ErrorPageProduction");
455
459
 
@@ -516,7 +520,7 @@ exports.StreamingErrorHandler = class _StreamingErrorHandler {
516
520
  */
517
521
  renderDevelopmentErrorPage(error, viewPath, phase) {
518
522
  const ErrorComponent = this.errorPageDevelopment || ErrorPageDevelopment;
519
- const element = React.createElement(ErrorComponent, {
523
+ const element = React2.createElement(ErrorComponent, {
520
524
  error,
521
525
  viewPath,
522
526
  phase
@@ -528,7 +532,7 @@ exports.StreamingErrorHandler = class _StreamingErrorHandler {
528
532
  */
529
533
  renderProductionErrorPage() {
530
534
  const ErrorComponent = this.errorPageProduction || ErrorPageProduction;
531
- const element = React.createElement(ErrorComponent);
535
+ const element = React2.createElement(ErrorComponent);
532
536
  return "<!DOCTYPE html>\n" + server.renderToStaticMarkup(element);
533
537
  }
534
538
  /**
@@ -1703,7 +1707,7 @@ var CONTEXT_KEY = /* @__PURE__ */ Symbol.for("nestjs-ssr.PageContext");
1703
1707
  var globalStore = globalThis;
1704
1708
  function getOrCreateContext() {
1705
1709
  if (!globalStore[CONTEXT_KEY]) {
1706
- globalStore[CONTEXT_KEY] = /* @__PURE__ */ React.createContext(null);
1710
+ globalStore[CONTEXT_KEY] = /* @__PURE__ */ React2.createContext(null);
1707
1711
  }
1708
1712
  return globalStore[CONTEXT_KEY];
1709
1713
  }
@@ -1713,12 +1717,12 @@ function registerPageContextState(setter) {
1713
1717
  }
1714
1718
  __name(registerPageContextState, "registerPageContextState");
1715
1719
  function PageContextProvider({ context: initialContext, children, isSegment = false }) {
1716
- const [context, setContext] = React.useState(initialContext);
1717
- React.useEffect(() => {
1720
+ const [context, setContext] = React2.useState(initialContext);
1721
+ React2.useEffect(() => {
1718
1722
  }, [
1719
1723
  isSegment
1720
1724
  ]);
1721
- return /* @__PURE__ */ React__default.default.createElement(PageContext.Provider, {
1725
+ return /* @__PURE__ */ React2__default.default.createElement(PageContext.Provider, {
1722
1726
  value: context
1723
1727
  }, children);
1724
1728
  }
@@ -1730,7 +1734,7 @@ function createSSRHooks() {
1730
1734
  * Contains URL metadata, headers, and any custom properties you've added.
1731
1735
  */
1732
1736
  usePageContext: /* @__PURE__ */ __name(() => {
1733
- const context = React.useContext(PageContext);
1737
+ const context = React2.useContext(PageContext);
1734
1738
  if (!context) {
1735
1739
  throw new Error("usePageContext must be used within PageContextProvider");
1736
1740
  }
@@ -1747,7 +1751,7 @@ function createSSRHooks() {
1747
1751
  * ```
1748
1752
  */
1749
1753
  useParams: /* @__PURE__ */ __name(() => {
1750
- const context = React.useContext(PageContext);
1754
+ const context = React2.useContext(PageContext);
1751
1755
  if (!context) {
1752
1756
  throw new Error("useParams must be used within PageContextProvider");
1753
1757
  }
@@ -1765,7 +1769,7 @@ function createSSRHooks() {
1765
1769
  * ```
1766
1770
  */
1767
1771
  useQuery: /* @__PURE__ */ __name(() => {
1768
- const context = React.useContext(PageContext);
1772
+ const context = React2.useContext(PageContext);
1769
1773
  if (!context) {
1770
1774
  throw new Error("useQuery must be used within PageContextProvider");
1771
1775
  }
@@ -1785,7 +1789,7 @@ function createSSRHooks() {
1785
1789
  * ```
1786
1790
  */
1787
1791
  useRequest: /* @__PURE__ */ __name(() => {
1788
- const context = React.useContext(PageContext);
1792
+ const context = React2.useContext(PageContext);
1789
1793
  if (!context) {
1790
1794
  throw new Error("useRequest must be used within PageContextProvider");
1791
1795
  }
@@ -1811,7 +1815,7 @@ function createSSRHooks() {
1811
1815
  * ```
1812
1816
  */
1813
1817
  useHeaders: /* @__PURE__ */ __name(() => {
1814
- const context = React.useContext(PageContext);
1818
+ const context = React2.useContext(PageContext);
1815
1819
  if (!context) {
1816
1820
  throw new Error("useHeaders must be used within PageContextProvider");
1817
1821
  }
@@ -1846,7 +1850,7 @@ function createSSRHooks() {
1846
1850
  * ```
1847
1851
  */
1848
1852
  useHeader: /* @__PURE__ */ __name((name) => {
1849
- const context = React.useContext(PageContext);
1853
+ const context = React2.useContext(PageContext);
1850
1854
  if (!context) {
1851
1855
  throw new Error("useHeader must be used within PageContextProvider");
1852
1856
  }
@@ -1872,7 +1876,7 @@ function createSSRHooks() {
1872
1876
  * ```
1873
1877
  */
1874
1878
  useCookies: /* @__PURE__ */ __name(() => {
1875
- const context = React.useContext(PageContext);
1879
+ const context = React2.useContext(PageContext);
1876
1880
  if (!context) {
1877
1881
  throw new Error("useCookies must be used within PageContextProvider");
1878
1882
  }
@@ -1894,7 +1898,7 @@ function createSSRHooks() {
1894
1898
  * ```
1895
1899
  */
1896
1900
  useCookie: /* @__PURE__ */ __name((name) => {
1897
- const context = React.useContext(PageContext);
1901
+ const context = React2.useContext(PageContext);
1898
1902
  if (!context) {
1899
1903
  throw new Error("useCookie must be used within PageContextProvider");
1900
1904
  }
package/dist/index.mjs CHANGED
@@ -5,7 +5,7 @@ import { join, relative } from 'path';
5
5
  import { uneval } from 'devalue';
6
6
  import escapeHtml from 'escape-html';
7
7
  import { renderToStaticMarkup } from 'react-dom/server';
8
- import React, { createElement, createContext, useContext, useState, useEffect } from 'react';
8
+ import React2, { createElement, createContext, useContext, useState, useEffect } from 'react';
9
9
  import { switchMap } from 'rxjs/operators';
10
10
 
11
11
  var __defProp = Object.defineProperty;
@@ -332,6 +332,8 @@ StringRenderer = _ts_decorate2([
332
332
  typeof TemplateParserService === "undefined" ? Object : TemplateParserService
333
333
  ])
334
334
  ], StringRenderer);
335
+
336
+ // src/render/error-pages/error-page-development.tsx
335
337
  function ErrorPageDevelopment({ error, viewPath, phase }) {
336
338
  const stackLines = error.stack ? error.stack.split("\n").slice(1) : [];
337
339
  return /* @__PURE__ */ React.createElement("html", {
@@ -405,6 +407,8 @@ function ErrorPageDevelopment({ error, viewPath, phase }) {
405
407
  }, /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("strong", null, "View Path:"), " ", viewPath), /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("strong", null, "Error Phase:"), " ", phase === "shell" ? "Shell (before streaming started)" : "Streaming (during content delivery)"), /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("strong", null, "Environment:"), " Development")))));
406
408
  }
407
409
  __name(ErrorPageDevelopment, "ErrorPageDevelopment");
410
+
411
+ // src/render/error-pages/error-page-production.tsx
408
412
  function ErrorPageProduction() {
409
413
  return /* @__PURE__ */ React.createElement("html", {
410
414
  lang: "en"
@@ -1711,7 +1715,7 @@ function PageContextProvider({ context: initialContext, children, isSegment = fa
1711
1715
  }, [
1712
1716
  isSegment
1713
1717
  ]);
1714
- return /* @__PURE__ */ React.createElement(PageContext.Provider, {
1718
+ return /* @__PURE__ */ React2.createElement(PageContext.Provider, {
1715
1719
  value: context
1716
1720
  }, children);
1717
1721
  }
@@ -7,13 +7,12 @@ var path = require('path');
7
7
  var devalue = require('devalue');
8
8
  var escapeHtml = require('escape-html');
9
9
  var server = require('react-dom/server');
10
- var React = require('react');
10
+ var react = require('react');
11
11
  var operators = require('rxjs/operators');
12
12
 
13
13
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
14
14
 
15
15
  var escapeHtml__default = /*#__PURE__*/_interopDefault(escapeHtml);
16
- var React__default = /*#__PURE__*/_interopDefault(React);
17
16
 
18
17
  var __defProp = Object.defineProperty;
19
18
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
@@ -339,16 +338,18 @@ StringRenderer = _ts_decorate2([
339
338
  typeof exports.TemplateParserService === "undefined" ? Object : exports.TemplateParserService
340
339
  ])
341
340
  ], StringRenderer);
341
+
342
+ // src/render/error-pages/error-page-development.tsx
342
343
  function ErrorPageDevelopment({ error, viewPath, phase }) {
343
344
  const stackLines = error.stack ? error.stack.split("\n").slice(1) : [];
344
- return /* @__PURE__ */ React__default.default.createElement("html", {
345
+ return /* @__PURE__ */ React.createElement("html", {
345
346
  lang: "en"
346
- }, /* @__PURE__ */ React__default.default.createElement("head", null, /* @__PURE__ */ React__default.default.createElement("meta", {
347
+ }, /* @__PURE__ */ React.createElement("head", null, /* @__PURE__ */ React.createElement("meta", {
347
348
  charSet: "UTF-8"
348
- }), /* @__PURE__ */ React__default.default.createElement("meta", {
349
+ }), /* @__PURE__ */ React.createElement("meta", {
349
350
  name: "viewport",
350
351
  content: "width=device-width, initial-scale=1.0"
351
- }), /* @__PURE__ */ React__default.default.createElement("title", null, `SSR Error - ${error.name}`), /* @__PURE__ */ React__default.default.createElement("style", {
352
+ }), /* @__PURE__ */ React.createElement("title", null, `SSR Error - ${error.name}`), /* @__PURE__ */ React.createElement("style", {
352
353
  dangerouslySetInnerHTML: {
353
354
  __html: `
354
355
  body {
@@ -399,28 +400,30 @@ function ErrorPageDevelopment({ error, viewPath, phase }) {
399
400
  }
400
401
  `
401
402
  }
402
- })), /* @__PURE__ */ React__default.default.createElement("body", null, /* @__PURE__ */ React__default.default.createElement("div", {
403
+ })), /* @__PURE__ */ React.createElement("body", null, /* @__PURE__ */ React.createElement("div", {
403
404
  className: "error-container"
404
- }, /* @__PURE__ */ React__default.default.createElement("h1", null, "Server-Side Rendering Error"), /* @__PURE__ */ React__default.default.createElement("div", {
405
+ }, /* @__PURE__ */ React.createElement("h1", null, "Server-Side Rendering Error"), /* @__PURE__ */ React.createElement("div", {
405
406
  className: "error-type"
406
- }, error.name), /* @__PURE__ */ React__default.default.createElement("div", {
407
+ }, error.name), /* @__PURE__ */ React.createElement("div", {
407
408
  className: "error-message"
408
- }, error.message), /* @__PURE__ */ React__default.default.createElement("h2", null, "Stack Trace"), /* @__PURE__ */ React__default.default.createElement("div", {
409
+ }, error.message), /* @__PURE__ */ React.createElement("h2", null, "Stack Trace"), /* @__PURE__ */ React.createElement("div", {
409
410
  className: "stack-trace"
410
- }, /* @__PURE__ */ React__default.default.createElement("pre", null, stackLines.join("\n"))), /* @__PURE__ */ React__default.default.createElement("div", {
411
+ }, /* @__PURE__ */ React.createElement("pre", null, stackLines.join("\n"))), /* @__PURE__ */ React.createElement("div", {
411
412
  className: "meta"
412
- }, /* @__PURE__ */ React__default.default.createElement("p", null, /* @__PURE__ */ React__default.default.createElement("strong", null, "View Path:"), " ", viewPath), /* @__PURE__ */ React__default.default.createElement("p", null, /* @__PURE__ */ React__default.default.createElement("strong", null, "Error Phase:"), " ", phase === "shell" ? "Shell (before streaming started)" : "Streaming (during content delivery)"), /* @__PURE__ */ React__default.default.createElement("p", null, /* @__PURE__ */ React__default.default.createElement("strong", null, "Environment:"), " Development")))));
413
+ }, /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("strong", null, "View Path:"), " ", viewPath), /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("strong", null, "Error Phase:"), " ", phase === "shell" ? "Shell (before streaming started)" : "Streaming (during content delivery)"), /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("strong", null, "Environment:"), " Development")))));
413
414
  }
414
415
  __name(ErrorPageDevelopment, "ErrorPageDevelopment");
416
+
417
+ // src/render/error-pages/error-page-production.tsx
415
418
  function ErrorPageProduction() {
416
- return /* @__PURE__ */ React__default.default.createElement("html", {
419
+ return /* @__PURE__ */ React.createElement("html", {
417
420
  lang: "en"
418
- }, /* @__PURE__ */ React__default.default.createElement("head", null, /* @__PURE__ */ React__default.default.createElement("meta", {
421
+ }, /* @__PURE__ */ React.createElement("head", null, /* @__PURE__ */ React.createElement("meta", {
419
422
  charSet: "UTF-8"
420
- }), /* @__PURE__ */ React__default.default.createElement("meta", {
423
+ }), /* @__PURE__ */ React.createElement("meta", {
421
424
  name: "viewport",
422
425
  content: "width=device-width, initial-scale=1.0"
423
- }), /* @__PURE__ */ React__default.default.createElement("title", null, "Error"), /* @__PURE__ */ React__default.default.createElement("style", {
426
+ }), /* @__PURE__ */ React.createElement("title", null, "Error"), /* @__PURE__ */ React.createElement("style", {
424
427
  dangerouslySetInnerHTML: {
425
428
  __html: `
426
429
  body {
@@ -447,9 +450,9 @@ function ErrorPageProduction() {
447
450
  }
448
451
  `
449
452
  }
450
- })), /* @__PURE__ */ React__default.default.createElement("body", null, /* @__PURE__ */ React__default.default.createElement("div", {
453
+ })), /* @__PURE__ */ React.createElement("body", null, /* @__PURE__ */ React.createElement("div", {
451
454
  className: "error-container"
452
- }, /* @__PURE__ */ React__default.default.createElement("h1", null, "500"), /* @__PURE__ */ React__default.default.createElement("p", null, "Internal Server Error"), /* @__PURE__ */ React__default.default.createElement("p", null, "Something went wrong while rendering this page."))));
455
+ }, /* @__PURE__ */ React.createElement("h1", null, "500"), /* @__PURE__ */ React.createElement("p", null, "Internal Server Error"), /* @__PURE__ */ React.createElement("p", null, "Something went wrong while rendering this page."))));
453
456
  }
454
457
  __name(ErrorPageProduction, "ErrorPageProduction");
455
458
 
@@ -516,7 +519,7 @@ exports.StreamingErrorHandler = class _StreamingErrorHandler {
516
519
  */
517
520
  renderDevelopmentErrorPage(error, viewPath, phase) {
518
521
  const ErrorComponent = this.errorPageDevelopment || ErrorPageDevelopment;
519
- const element = React.createElement(ErrorComponent, {
522
+ const element = react.createElement(ErrorComponent, {
520
523
  error,
521
524
  viewPath,
522
525
  phase
@@ -528,7 +531,7 @@ exports.StreamingErrorHandler = class _StreamingErrorHandler {
528
531
  */
529
532
  renderProductionErrorPage() {
530
533
  const ErrorComponent = this.errorPageProduction || ErrorPageProduction;
531
- const element = React.createElement(ErrorComponent);
534
+ const element = react.createElement(ErrorComponent);
532
535
  return "<!DOCTYPE html>\n" + server.renderToStaticMarkup(element);
533
536
  }
534
537
  /**
@@ -5,7 +5,7 @@ import { join, relative } from 'path';
5
5
  import { uneval } from 'devalue';
6
6
  import escapeHtml from 'escape-html';
7
7
  import { renderToStaticMarkup } from 'react-dom/server';
8
- import React, { createElement } from 'react';
8
+ import { createElement } from 'react';
9
9
  import { switchMap } from 'rxjs/operators';
10
10
 
11
11
  var __defProp = Object.defineProperty;
@@ -332,6 +332,8 @@ StringRenderer = _ts_decorate2([
332
332
  typeof TemplateParserService === "undefined" ? Object : TemplateParserService
333
333
  ])
334
334
  ], StringRenderer);
335
+
336
+ // src/render/error-pages/error-page-development.tsx
335
337
  function ErrorPageDevelopment({ error, viewPath, phase }) {
336
338
  const stackLines = error.stack ? error.stack.split("\n").slice(1) : [];
337
339
  return /* @__PURE__ */ React.createElement("html", {
@@ -405,6 +407,8 @@ function ErrorPageDevelopment({ error, viewPath, phase }) {
405
407
  }, /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("strong", null, "View Path:"), " ", viewPath), /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("strong", null, "Error Phase:"), " ", phase === "shell" ? "Shell (before streaming started)" : "Streaming (during content delivery)"), /* @__PURE__ */ React.createElement("p", null, /* @__PURE__ */ React.createElement("strong", null, "Environment:"), " Development")))));
406
408
  }
407
409
  __name(ErrorPageDevelopment, "ErrorPageDevelopment");
410
+
411
+ // src/render/error-pages/error-page-production.tsx
408
412
  function ErrorPageProduction() {
409
413
  return /* @__PURE__ */ React.createElement("html", {
410
414
  lang: "en"
@@ -1,4 +1,5 @@
1
1
  /// <reference types="@nestjs-ssr/react/global" />
2
+
2
3
  import React, { StrictMode } from 'react';
3
4
  import { hydrateRoot } from 'react-dom/client';
4
5
  import {
@@ -10,6 +11,15 @@ const componentName = window.__COMPONENT_NAME__;
10
11
  const initialProps = window.__INITIAL_STATE__ || {};
11
12
  const renderContext = window.__CONTEXT__ || {};
12
13
 
14
+ // Auto-discover root layout using Vite's glob import (must match server-side discovery)
15
+ // @ts-ignore - Vite-specific API
16
+ const layoutModules = import.meta.glob('@/views/layout.tsx', {
17
+ eager: true,
18
+ }) as Record<string, { default: React.ComponentType<any> }>;
19
+
20
+ const layoutPath = Object.keys(layoutModules)[0];
21
+ const RootLayout = layoutPath ? layoutModules[layoutPath].default : null;
22
+
13
23
  // Auto-import all view components using Vite's glob feature
14
24
  // Exclude entry-client.tsx and entry-server.tsx from the glob
15
25
  // @ts-ignore - Vite-specific API
@@ -111,40 +121,53 @@ function hasLayout(
111
121
  function composeWithLayout(
112
122
  ViewComponent: React.ComponentType<any>,
113
123
  props: any,
124
+ context?: any,
125
+ layouts: Array<{ layout: React.ComponentType<any>; props?: any }> = [],
114
126
  ): React.ReactElement {
115
- const element = <ViewComponent {...props} />;
116
-
117
- // Check if component has a layout
118
- if (!hasLayout(ViewComponent)) {
119
- return element;
120
- }
121
-
122
- // Collect all layouts in the chain (innermost to outermost)
123
- const layoutChain: Array<{
124
- Layout: React.ComponentType<any>;
125
- layoutProps: any;
126
- }> = [];
127
- let currentComponent: any = ViewComponent;
128
-
129
- while (hasLayout(currentComponent)) {
130
- layoutChain.push({
131
- Layout: currentComponent.layout,
132
- layoutProps: currentComponent.layoutProps || {},
133
- });
134
- currentComponent = currentComponent.layout;
127
+ // Start with the page component
128
+ let result = <ViewComponent {...props} />;
129
+
130
+ // If no layouts passed, check if component has its own layout chain
131
+ if (layouts.length === 0 && hasLayout(ViewComponent)) {
132
+ let currentComponent: any = ViewComponent;
133
+ while (hasLayout(currentComponent)) {
134
+ layouts.push({
135
+ layout: currentComponent.layout,
136
+ props: currentComponent.layoutProps || {},
137
+ });
138
+ currentComponent = currentComponent.layout;
139
+ }
135
140
  }
136
141
 
137
- // Wrap the element with layouts from innermost to outermost
138
- let result = element;
139
- for (const { Layout, layoutProps } of layoutChain) {
140
- result = <Layout layoutProps={layoutProps}>{result}</Layout>;
142
+ // Wrap with each layout in the chain
143
+ // Must match server-side wrapping with data-layout and data-outlet attributes
144
+ for (const { layout: Layout, props: layoutProps } of layouts) {
145
+ const layoutName = Layout.displayName || Layout.name || 'Layout';
146
+ result = (
147
+ <div data-layout={layoutName}>
148
+ <Layout context={context} layoutProps={layoutProps}>
149
+ <div data-outlet={layoutName}>{result}</div>
150
+ </Layout>
151
+ </div>
152
+ );
141
153
  }
142
154
 
143
155
  return result;
144
156
  }
145
157
 
158
+ // Build layouts array - use RootLayout if it exists (matching server behavior)
159
+ const layouts: Array<{ layout: React.ComponentType<any>; props?: any }> = [];
160
+ if (RootLayout) {
161
+ layouts.push({ layout: RootLayout, props: {} });
162
+ }
163
+
146
164
  // Compose the component with its layout (if any)
147
- const composedElement = composeWithLayout(ViewComponent, initialProps);
165
+ const composedElement = composeWithLayout(
166
+ ViewComponent,
167
+ initialProps,
168
+ renderContext,
169
+ layouts,
170
+ );
148
171
 
149
172
  // Wrap with providers to make context and navigation state available via hooks
150
173
  const wrappedElement = (
package/etc/react.api.md CHANGED
@@ -1,262 +1,250 @@
1
- ## API Report File for "@nestjs-ssr/react"
2
-
3
- > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
4
-
5
- ```ts
6
- import { CallHandler } from '@nestjs/common';
7
- import { ComponentType } from 'react';
8
- import { DynamicModule } from '@nestjs/common';
9
- import { ExecutionContext } from '@nestjs/common';
10
- import { NestInterceptor } from '@nestjs/common';
11
- import { Observable } from 'rxjs';
12
- import { default as React_2 } from 'react';
13
- import * as react_jsx_runtime from 'react/jsx-runtime';
14
- import { ReactNode } from 'react';
15
- import { Reflector } from '@nestjs/core';
16
- import { Response as Response_2 } from 'express';
17
- import { ViteDevServer } from 'vite';
18
-
19
- // Warning: (ae-forgotten-export) The symbol "ErrorPageDevelopmentProps" needs to be exported by the entry point index.d.ts
20
- //
21
- // @public
22
- export function ErrorPageDevelopment({
23
- error,
24
- viewPath,
25
- phase,
26
- }: ErrorPageDevelopmentProps): react_jsx_runtime.JSX.Element;
27
-
28
- // @public
29
- export function ErrorPageProduction(): react_jsx_runtime.JSX.Element;
30
-
31
- // @public
32
- export interface HeadData {
33
- bodyAttributes?: Record<string, string>;
34
- canonical?: string;
35
- description?: string;
36
- htmlAttributes?: Record<string, string>;
37
- jsonLd?: Array<Record<string, any>>;
38
- keywords?: string;
39
- links?: Array<{
40
- rel: string;
41
- href: string;
42
- as?: string;
43
- type?: string;
44
- crossorigin?: string;
45
- [key: string]: any;
46
- }>;
47
- meta?: Array<{
48
- name?: string;
49
- property?: string;
50
- content: string;
51
- [key: string]: any;
52
- }>;
53
- ogDescription?: string;
54
- ogImage?: string;
55
- ogTitle?: string;
56
- scripts?: Array<{
57
- src?: string;
58
- async?: boolean;
59
- defer?: boolean;
60
- type?: string;
61
- innerHTML?: string;
62
- [key: string]: any;
63
- }>;
64
- title?: string;
65
- }
66
-
67
- // @public
68
- export function Layout(
69
- layout: LayoutComponent<any>,
70
- options?: LayoutDecoratorOptions,
71
- ): ClassDecorator;
72
-
73
- // @public
74
- export type LayoutComponent<TProps = {}> = ComponentType<LayoutProps<TProps>>;
75
-
76
- // @public
77
- export interface LayoutDecoratorOptions {
78
- props?: Record<string, any>;
79
- skipRoot?: boolean;
80
- }
81
-
82
- // @public
83
- export interface LayoutProps<TProps = {}> {
84
- children: ReactNode;
85
- context?: RenderContext;
86
- head?: HeadData;
87
- layoutProps?: TProps;
88
- }
89
-
90
- // @public
91
- export interface PageComponentWithLayout<TPageProps = {}, TLayoutProps = {}> {
92
- (props: TPageProps): ReactNode;
93
- layout?: LayoutComponent<TLayoutProps>;
94
- layoutProps?: TLayoutProps;
95
- }
96
-
97
- // @public
98
- export type PageProps<TProps = {}> = TProps & {
99
- head?: HeadData;
100
- context: RenderContext;
101
- };
102
-
103
- // Warning: (ae-forgotten-export) The symbol "RenderReturnType" needs to be exported by the entry point index.d.ts
104
- // Warning: (ae-forgotten-export) The symbol "ExtractComponentData" needs to be exported by the entry point index.d.ts
105
- //
106
- // @public
107
- export function Render<T extends React_2.ComponentType<any>>(
108
- component: T,
109
- options?: RenderOptions,
110
- ): <
111
- TMethod extends (
112
- ...args: any[]
113
- ) =>
114
- | RenderReturnType<ExtractComponentData<T>>
115
- | Promise<RenderReturnType<ExtractComponentData<T>>>,
116
- >(
117
- target: any,
118
- propertyKey: string | symbol,
119
- descriptor: TypedPropertyDescriptor<TMethod>,
120
- ) => TypedPropertyDescriptor<TMethod> | void;
121
-
122
- // @public
123
- export interface RenderConfig {
124
- defaultHead?: HeadData;
125
- // Warning: (ae-forgotten-export) The symbol "ErrorPageDevelopmentProps$1" needs to be exported by the entry point index.d.ts
126
- errorPageDevelopment?: ComponentType<ErrorPageDevelopmentProps$1>;
127
- errorPageProduction?: ComponentType;
128
- mode?: SSRMode;
129
- template?: string;
130
- timeout?: number;
131
- // Warning: (ae-forgotten-export) The symbol "ViteConfig" needs to be exported by the entry point index.d.ts
132
- vite?: ViteConfig;
133
- }
134
-
135
- // @public
136
- export interface RenderContext {
137
- // (undocumented)
138
- [key: string]: any;
139
- // (undocumented)
140
- acceptLanguage?: string;
141
- // (undocumented)
142
- cookies?: Record<string, string>;
143
- // (undocumented)
144
- headers?: Record<string, string>;
145
- // (undocumented)
146
- method: string;
147
- // (undocumented)
148
- params: Record<string, string>;
149
- // (undocumented)
150
- path: string;
151
- // (undocumented)
152
- query: Record<string, string | string[]>;
153
- // (undocumented)
154
- referer?: string;
155
- // (undocumented)
156
- url: string;
157
- // (undocumented)
158
- userAgent?: string;
159
- }
160
-
161
- // @public (undocumented)
162
- export class RenderInterceptor implements NestInterceptor {
163
- constructor(reflector: Reflector, renderService: RenderService);
164
- // (undocumented)
165
- intercept(context: ExecutionContext, next: CallHandler): Observable<any>;
166
- }
167
-
168
- // @public (undocumented)
169
- export class RenderModule {
170
- static register(config?: RenderConfig): DynamicModule;
171
- static registerAsync(options: {
172
- imports?: any[];
173
- inject?: any[];
174
- useFactory: (...args: any[]) => Promise<RenderConfig> | RenderConfig;
175
- }): DynamicModule;
176
- }
177
-
178
- // @public
179
- export interface RenderOptions {
180
- layout?: LayoutComponent<any> | false | null;
181
- layoutProps?: Record<string, any>;
182
- }
183
-
184
- // @public
185
- export interface RenderResponse<T = any> {
186
- head?: HeadData;
187
- layoutProps?: Record<string, any>;
188
- props: T;
189
- }
190
-
191
- // @public (undocumented)
192
- export class RenderService {
193
- constructor(
194
- templateParser: TemplateParserService,
195
- streamingErrorHandler: StreamingErrorHandler,
196
- ssrMode?: SSRMode,
197
- defaultHead?: HeadData | undefined,
198
- customTemplate?: string,
199
- );
200
- getRootLayout(): Promise<any | null>;
201
- render(
202
- viewComponent: any,
203
- data?: any,
204
- res?: Response_2,
205
- head?: HeadData,
206
- ): Promise<string | void>;
207
- // (undocumented)
208
- setViteServer(vite: ViteDevServer): void;
209
- }
210
-
211
- // @public
212
- export type SSRMode = 'string' | 'stream';
213
-
214
- // @public
215
- export class StreamingErrorHandler {
216
- constructor(
217
- errorPageDevelopment?:
218
- | ComponentType<ErrorPageDevelopmentProps$1>
219
- | undefined,
220
- errorPageProduction?: ComponentType | undefined,
221
- );
222
- handleShellError(
223
- error: Error,
224
- res: Response_2,
225
- viewPath: string,
226
- isDevelopment: boolean,
227
- ): void;
228
- handleStreamError(error: Error, viewPath: string): void;
229
- }
230
-
231
- // @public
232
- export class TemplateParserService {
233
- buildHeadTags(head?: HeadData): string;
234
- buildInlineScripts(
235
- data: any,
236
- context: any,
237
- componentName: string,
238
- layouts?: Array<{
239
- layout: any;
240
- props?: any;
241
- }>,
242
- ): string;
243
- getClientScriptTag(isDevelopment: boolean, manifest?: any): string;
244
- getStylesheetTags(isDevelopment: boolean, manifest?: any): string;
245
- // Warning: (ae-forgotten-export) The symbol "TemplateParts" needs to be exported by the entry point index.d.ts
246
- parseTemplate(html: string): TemplateParts;
247
- }
248
-
249
- // @public
250
- export function usePageContext(): RenderContext;
251
-
252
- // @public
253
- export function useParams(): Record<string, string>;
254
-
255
- // @public
256
- export function useQuery(): Record<string, string | string[]>;
257
-
258
- // @public
259
- export function useUserAgent(): string | undefined;
260
-
261
- // (No @packageDocumentation comment for this package)
262
- ```
1
+ ## API Report File for "@nestjs-ssr/react"
2
+
3
+ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
4
+
5
+ ```ts
6
+
7
+ import { CallHandler } from '@nestjs/common';
8
+ import { ComponentType } from 'react';
9
+ import { DynamicModule } from '@nestjs/common';
10
+ import { ExecutionContext } from '@nestjs/common';
11
+ import { NestInterceptor } from '@nestjs/common';
12
+ import { Observable } from 'rxjs';
13
+ import { default as React_2 } from 'react';
14
+ import * as react_jsx_runtime from 'react/jsx-runtime';
15
+ import { ReactNode } from 'react';
16
+ import { Reflector } from '@nestjs/core';
17
+ import { Response as Response_2 } from 'express';
18
+ import { ViteDevServer } from 'vite';
19
+
20
+ // @public
21
+ export function createSSRHooks<T extends RenderContext = RenderContext>(): {
22
+ usePageContext: () => T;
23
+ useParams: () => Record<string, string>;
24
+ useQuery: () => Record<string, string | string[]>;
25
+ useRequest: () => T;
26
+ useHeaders: () => Record<string, string>;
27
+ useHeader: (name: string) => string | undefined;
28
+ useCookies: () => Record<string, string>;
29
+ useCookie: (name: string) => string | undefined;
30
+ };
31
+
32
+ // Warning: (ae-forgotten-export) The symbol "ErrorPageDevelopmentProps" needs to be exported by the entry point index.d.ts
33
+ //
34
+ // @public
35
+ export function ErrorPageDevelopment({ error, viewPath, phase, }: ErrorPageDevelopmentProps): react_jsx_runtime.JSX.Element;
36
+
37
+ // @public
38
+ export function ErrorPageProduction(): react_jsx_runtime.JSX.Element;
39
+
40
+ // @public
41
+ export interface HeadData {
42
+ bodyAttributes?: Record<string, string>;
43
+ canonical?: string;
44
+ description?: string;
45
+ htmlAttributes?: Record<string, string>;
46
+ jsonLd?: Array<Record<string, any>>;
47
+ keywords?: string;
48
+ links?: Array<{
49
+ rel: string;
50
+ href: string;
51
+ as?: string;
52
+ type?: string;
53
+ crossorigin?: string;
54
+ [key: string]: any;
55
+ }>;
56
+ meta?: Array<{
57
+ name?: string;
58
+ property?: string;
59
+ content: string;
60
+ [key: string]: any;
61
+ }>;
62
+ ogDescription?: string;
63
+ ogImage?: string;
64
+ ogTitle?: string;
65
+ scripts?: Array<{
66
+ src?: string;
67
+ async?: boolean;
68
+ defer?: boolean;
69
+ type?: string;
70
+ innerHTML?: string;
71
+ [key: string]: any;
72
+ }>;
73
+ title?: string;
74
+ }
75
+
76
+ // @public
77
+ export function Layout(layout: LayoutComponent<any>, options?: LayoutDecoratorOptions): ClassDecorator;
78
+
79
+ // @public
80
+ export type LayoutComponent<TProps = {}> = ComponentType<LayoutProps<TProps>>;
81
+
82
+ // @public
83
+ export interface LayoutDecoratorOptions {
84
+ props?: Record<string, any>;
85
+ skipRoot?: boolean;
86
+ }
87
+
88
+ // @public
89
+ export interface LayoutProps<TProps = {}> {
90
+ children: ReactNode;
91
+ context?: RenderContext;
92
+ head?: HeadData;
93
+ layoutProps?: TProps;
94
+ }
95
+
96
+ // @public
97
+ export interface PageComponentWithLayout<TPageProps = {}, TLayoutProps = {}> {
98
+ (props: TPageProps): ReactNode;
99
+ layout?: LayoutComponent<TLayoutProps>;
100
+ layoutProps?: TLayoutProps;
101
+ }
102
+
103
+ // @public
104
+ export function PageContextProvider({ context: initialContext, children, isSegment, }: {
105
+ context: RenderContext;
106
+ children: React_2.ReactNode;
107
+ isSegment?: boolean;
108
+ }): react_jsx_runtime.JSX.Element;
109
+
110
+ // @public
111
+ export type PageProps<TProps = {}> = TProps & {
112
+ head?: HeadData;
113
+ };
114
+
115
+ // Warning: (ae-forgotten-export) The symbol "RenderReturnType" needs to be exported by the entry point index.d.ts
116
+ // Warning: (ae-forgotten-export) The symbol "ExtractComponentData" needs to be exported by the entry point index.d.ts
117
+ //
118
+ // @public
119
+ export function Render<T extends React_2.ComponentType<any>>(component: T, options?: RenderOptions): <TMethod extends (...args: any[]) => RenderReturnType<ExtractComponentData<T>> | Promise<RenderReturnType<ExtractComponentData<T>>>>(target: any, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<TMethod>) => TypedPropertyDescriptor<TMethod> | void;
120
+
121
+ // @public
122
+ export interface RenderConfig {
123
+ allowedCookies?: string[];
124
+ allowedHeaders?: string[];
125
+ defaultHead?: HeadData;
126
+ // Warning: (ae-forgotten-export) The symbol "ErrorPageDevelopmentProps$1" needs to be exported by the entry point index.d.ts
127
+ errorPageDevelopment?: ComponentType<ErrorPageDevelopmentProps$1>;
128
+ errorPageProduction?: ComponentType;
129
+ mode?: SSRMode;
130
+ template?: string;
131
+ timeout?: number;
132
+ // Warning: (ae-forgotten-export) The symbol "ViteConfig" needs to be exported by the entry point index.d.ts
133
+ vite?: ViteConfig;
134
+ }
135
+
136
+ // @public
137
+ export interface RenderContext {
138
+ // (undocumented)
139
+ method: string;
140
+ // (undocumented)
141
+ params: Record<string, string>;
142
+ // (undocumented)
143
+ path: string;
144
+ // (undocumented)
145
+ query: Record<string, string | string[]>;
146
+ // (undocumented)
147
+ url: string;
148
+ }
149
+
150
+ // @public (undocumented)
151
+ export class RenderInterceptor implements NestInterceptor {
152
+ constructor(reflector: Reflector, renderService: RenderService, allowedHeaders?: string[] | undefined, allowedCookies?: string[] | undefined);
153
+ // (undocumented)
154
+ intercept(context: ExecutionContext, next: CallHandler): Observable<any>;
155
+ }
156
+
157
+ // @public (undocumented)
158
+ export class RenderModule {
159
+ static forRoot(config?: RenderConfig): DynamicModule;
160
+ static forRootAsync(options: {
161
+ imports?: any[];
162
+ inject?: any[];
163
+ useFactory: (...args: any[]) => Promise<RenderConfig> | RenderConfig;
164
+ }): DynamicModule;
165
+ // @deprecated (undocumented)
166
+ static register(config?: RenderConfig): DynamicModule;
167
+ // @deprecated (undocumented)
168
+ static registerAsync(options: {
169
+ imports?: any[];
170
+ inject?: any[];
171
+ useFactory: (...args: any[]) => Promise<RenderConfig> | RenderConfig;
172
+ }): DynamicModule;
173
+ }
174
+
175
+ // @public
176
+ export interface RenderOptions {
177
+ layout?: LayoutComponent<any> | false | null;
178
+ layoutProps?: Record<string, any>;
179
+ }
180
+
181
+ // @public
182
+ export interface RenderResponse<T = any> {
183
+ head?: HeadData;
184
+ layoutProps?: Record<string, any>;
185
+ props: T;
186
+ }
187
+
188
+ // @public
189
+ export class RenderService {
190
+ // Warning: (ae-forgotten-export) The symbol "StringRenderer" needs to be exported by the entry point index.d.ts
191
+ // Warning: (ae-forgotten-export) The symbol "StreamRenderer" needs to be exported by the entry point index.d.ts
192
+ constructor(stringRenderer: StringRenderer, streamRenderer: StreamRenderer, ssrMode?: SSRMode, defaultHead?: HeadData | undefined, customTemplate?: string);
193
+ getRootLayout(): Promise<any | null>;
194
+ render(viewComponent: any, data?: any, res?: Response_2, head?: HeadData): Promise<string | void>;
195
+ // Warning: (ae-forgotten-export) The symbol "SegmentResponse" needs to be exported by the entry point index.d.ts
196
+ renderSegment(viewComponent: any, data: any, swapTarget: string, head?: HeadData): Promise<SegmentResponse>;
197
+ // (undocumented)
198
+ setViteServer(vite: ViteDevServer): void;
199
+ }
200
+
201
+ // @public
202
+ export type SSRMode = 'string' | 'stream';
203
+
204
+ // @public
205
+ export class StreamingErrorHandler {
206
+ constructor(errorPageDevelopment?: ComponentType<ErrorPageDevelopmentProps$1> | undefined, errorPageProduction?: ComponentType | undefined);
207
+ handleShellError(error: Error, res: Response_2, viewPath: string, isDevelopment: boolean): void;
208
+ handleStreamError(error: Error, viewPath: string): void;
209
+ }
210
+
211
+ // @public
212
+ export class TemplateParserService {
213
+ buildHeadTags(head?: HeadData): string;
214
+ buildInlineScripts(data: any, context: any, componentName: string, layouts?: Array<{
215
+ layout: any;
216
+ props?: any;
217
+ }>): string;
218
+ getClientScriptTag(isDevelopment: boolean, manifest?: any): string;
219
+ getStylesheetTags(isDevelopment: boolean, manifest?: any): string;
220
+ // Warning: (ae-forgotten-export) The symbol "TemplateParts" needs to be exported by the entry point index.d.ts
221
+ parseTemplate(html: string): TemplateParts;
222
+ }
223
+
224
+ // @public (undocumented)
225
+ export const useCookie: (name: string) => string | undefined;
226
+
227
+ // @public (undocumented)
228
+ export const useCookies: () => Record<string, string>;
229
+
230
+ // @public (undocumented)
231
+ export const useHeader: (name: string) => string | undefined;
232
+
233
+ // @public (undocumented)
234
+ export const useHeaders: () => Record<string, string>;
235
+
236
+ // @public (undocumented)
237
+ export const usePageContext: () => RenderContext;
238
+
239
+ // @public (undocumented)
240
+ export const useParams: () => Record<string, string>;
241
+
242
+ // @public (undocumented)
243
+ export const useQuery: () => Record<string, string | string[]>;
244
+
245
+ // @public (undocumented)
246
+ export const useRequest: () => RenderContext;
247
+
248
+ // (No @packageDocumentation comment for this package)
249
+
250
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nestjs-ssr/react",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "React SSR for NestJS that respects Clean Architecture. Proper DI, SOLID principles, clear separation of concerns.",
5
5
  "keywords": [
6
6
  "nestjs",
@@ -1,4 +1,5 @@
1
1
  /// <reference types="@nestjs-ssr/react/global" />
2
+
2
3
  import React, { StrictMode } from 'react';
3
4
  import { hydrateRoot } from 'react-dom/client';
4
5
  import {
@@ -10,6 +11,15 @@ const componentName = window.__COMPONENT_NAME__;
10
11
  const initialProps = window.__INITIAL_STATE__ || {};
11
12
  const renderContext = window.__CONTEXT__ || {};
12
13
 
14
+ // Auto-discover root layout using Vite's glob import (must match server-side discovery)
15
+ // @ts-ignore - Vite-specific API
16
+ const layoutModules = import.meta.glob('@/views/layout.tsx', {
17
+ eager: true,
18
+ }) as Record<string, { default: React.ComponentType<any> }>;
19
+
20
+ const layoutPath = Object.keys(layoutModules)[0];
21
+ const RootLayout = layoutPath ? layoutModules[layoutPath].default : null;
22
+
13
23
  // Auto-import all view components using Vite's glob feature
14
24
  // Exclude entry-client.tsx and entry-server.tsx from the glob
15
25
  // @ts-ignore - Vite-specific API
@@ -111,40 +121,53 @@ function hasLayout(
111
121
  function composeWithLayout(
112
122
  ViewComponent: React.ComponentType<any>,
113
123
  props: any,
124
+ context?: any,
125
+ layouts: Array<{ layout: React.ComponentType<any>; props?: any }> = [],
114
126
  ): React.ReactElement {
115
- const element = <ViewComponent {...props} />;
116
-
117
- // Check if component has a layout
118
- if (!hasLayout(ViewComponent)) {
119
- return element;
120
- }
121
-
122
- // Collect all layouts in the chain (innermost to outermost)
123
- const layoutChain: Array<{
124
- Layout: React.ComponentType<any>;
125
- layoutProps: any;
126
- }> = [];
127
- let currentComponent: any = ViewComponent;
128
-
129
- while (hasLayout(currentComponent)) {
130
- layoutChain.push({
131
- Layout: currentComponent.layout,
132
- layoutProps: currentComponent.layoutProps || {},
133
- });
134
- currentComponent = currentComponent.layout;
127
+ // Start with the page component
128
+ let result = <ViewComponent {...props} />;
129
+
130
+ // If no layouts passed, check if component has its own layout chain
131
+ if (layouts.length === 0 && hasLayout(ViewComponent)) {
132
+ let currentComponent: any = ViewComponent;
133
+ while (hasLayout(currentComponent)) {
134
+ layouts.push({
135
+ layout: currentComponent.layout,
136
+ props: currentComponent.layoutProps || {},
137
+ });
138
+ currentComponent = currentComponent.layout;
139
+ }
135
140
  }
136
141
 
137
- // Wrap the element with layouts from innermost to outermost
138
- let result = element;
139
- for (const { Layout, layoutProps } of layoutChain) {
140
- result = <Layout layoutProps={layoutProps}>{result}</Layout>;
142
+ // Wrap with each layout in the chain
143
+ // Must match server-side wrapping with data-layout and data-outlet attributes
144
+ for (const { layout: Layout, props: layoutProps } of layouts) {
145
+ const layoutName = Layout.displayName || Layout.name || 'Layout';
146
+ result = (
147
+ <div data-layout={layoutName}>
148
+ <Layout context={context} layoutProps={layoutProps}>
149
+ <div data-outlet={layoutName}>{result}</div>
150
+ </Layout>
151
+ </div>
152
+ );
141
153
  }
142
154
 
143
155
  return result;
144
156
  }
145
157
 
158
+ // Build layouts array - use RootLayout if it exists (matching server behavior)
159
+ const layouts: Array<{ layout: React.ComponentType<any>; props?: any }> = [];
160
+ if (RootLayout) {
161
+ layouts.push({ layout: RootLayout, props: {} });
162
+ }
163
+
146
164
  // Compose the component with its layout (if any)
147
- const composedElement = composeWithLayout(ViewComponent, initialProps);
165
+ const composedElement = composeWithLayout(
166
+ ViewComponent,
167
+ initialProps,
168
+ renderContext,
169
+ layouts,
170
+ );
148
171
 
149
172
  // Wrap with providers to make context and navigation state available via hooks
150
173
  const wrappedElement = (