@nestjs-ssr/react 0.1.12 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -85
- package/dist/cli/init.js +2 -2
- package/dist/cli/init.mjs +2 -2
- package/dist/{index-BiaVDe9J.d.mts → index-C5Knql-9.d.mts} +124 -8
- package/dist/{index-BiaVDe9J.d.ts → index-C5Knql-9.d.ts} +124 -8
- package/dist/index.d.mts +377 -69
- package/dist/index.d.ts +377 -69
- package/dist/index.js +460 -89
- package/dist/index.mjs +459 -85
- package/dist/render/index.d.mts +1 -1
- package/dist/render/index.d.ts +1 -1
- package/dist/render/index.js +253 -64
- package/dist/render/index.mjs +253 -63
- package/dist/templates/entry-client.tsx +80 -13
- package/dist/templates/entry-server.tsx +33 -2
- package/dist/templates/index.html +0 -3
- package/etc/react.api.md +262 -0
- package/package.json +28 -7
- package/src/global.d.ts +1 -1
- package/src/templates/entry-client.tsx +80 -13
- package/src/templates/entry-server.tsx +33 -2
- package/src/templates/index.html +0 -3
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ var common = require('@nestjs/common');
|
|
|
4
4
|
var core = require('@nestjs/core');
|
|
5
5
|
var fs = require('fs');
|
|
6
6
|
var path = require('path');
|
|
7
|
-
var
|
|
7
|
+
var devalue = require('devalue');
|
|
8
8
|
var escapeHtml = require('escape-html');
|
|
9
9
|
var server = require('react-dom/server');
|
|
10
10
|
var react = require('react');
|
|
@@ -12,7 +12,6 @@ var operators = require('rxjs/operators');
|
|
|
12
12
|
|
|
13
13
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
14
|
|
|
15
|
-
var serialize__default = /*#__PURE__*/_interopDefault(serialize);
|
|
16
15
|
var escapeHtml__default = /*#__PURE__*/_interopDefault(escapeHtml);
|
|
17
16
|
|
|
18
17
|
var __defProp = Object.defineProperty;
|
|
@@ -105,21 +104,20 @@ exports.TemplateParserService = class TemplateParserService {
|
|
|
105
104
|
/**
|
|
106
105
|
* Build inline script that provides initial state to the client
|
|
107
106
|
*
|
|
108
|
-
* Safely serializes data using
|
|
109
|
-
*
|
|
110
|
-
*
|
|
107
|
+
* Safely serializes data using devalue to avoid XSS vulnerabilities.
|
|
108
|
+
* Devalue is designed specifically for SSR, handling complex types safely
|
|
109
|
+
* while being faster and more secure than alternatives.
|
|
111
110
|
*/
|
|
112
|
-
buildInlineScripts(data, context, componentName) {
|
|
111
|
+
buildInlineScripts(data, context, componentName, layouts) {
|
|
112
|
+
const layoutMetadata = layouts ? layouts.map((l) => ({
|
|
113
|
+
name: l.layout.displayName || l.layout.name || "default",
|
|
114
|
+
props: l.props
|
|
115
|
+
})) : [];
|
|
113
116
|
return `<script>
|
|
114
|
-
window.__INITIAL_STATE__ = ${
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
window.
|
|
118
|
-
isJSON: true
|
|
119
|
-
})};
|
|
120
|
-
window.__COMPONENT_NAME__ = ${serialize__default.default(componentName, {
|
|
121
|
-
isJSON: true
|
|
122
|
-
})};
|
|
117
|
+
window.__INITIAL_STATE__ = ${devalue.uneval(data)};
|
|
118
|
+
window.__CONTEXT__ = ${devalue.uneval(context)};
|
|
119
|
+
window.__COMPONENT_NAME__ = ${devalue.uneval(componentName)};
|
|
120
|
+
window.__LAYOUTS__ = ${devalue.uneval(layoutMetadata)};
|
|
123
121
|
</script>`;
|
|
124
122
|
}
|
|
125
123
|
/**
|
|
@@ -428,12 +426,14 @@ exports.RenderService = class _RenderService {
|
|
|
428
426
|
isDevelopment;
|
|
429
427
|
ssrMode;
|
|
430
428
|
entryServerPath;
|
|
431
|
-
|
|
429
|
+
rootLayout = void 0;
|
|
430
|
+
rootLayoutChecked = false;
|
|
431
|
+
constructor(templateParser, streamingErrorHandler, ssrMode, defaultHead, customTemplate) {
|
|
432
432
|
this.templateParser = templateParser;
|
|
433
433
|
this.streamingErrorHandler = streamingErrorHandler;
|
|
434
434
|
this.defaultHead = defaultHead;
|
|
435
435
|
this.isDevelopment = process.env.NODE_ENV !== "production";
|
|
436
|
-
this.ssrMode = ssrMode || process.env.SSR_MODE || "
|
|
436
|
+
this.ssrMode = ssrMode || process.env.SSR_MODE || "stream";
|
|
437
437
|
const absoluteServerPath = path.join(__dirname, "/templates/entry-server.tsx");
|
|
438
438
|
const relativeServerPath = path.relative(process.cwd(), absoluteServerPath);
|
|
439
439
|
if (relativeServerPath.startsWith("..")) {
|
|
@@ -441,36 +441,54 @@ exports.RenderService = class _RenderService {
|
|
|
441
441
|
} else {
|
|
442
442
|
this.entryServerPath = "/" + relativeServerPath.replace(/\\/g, "/");
|
|
443
443
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
path.join(__dirname, "../src/templates/index.html"),
|
|
449
|
-
path.join(__dirname, "../../src/templates/index.html")
|
|
450
|
-
];
|
|
451
|
-
const localTemplatePath = path.join(process.cwd(), "src/views/index.html");
|
|
452
|
-
const foundPackageTemplate = packageTemplatePaths.find((p) => fs.existsSync(p));
|
|
453
|
-
if (foundPackageTemplate) {
|
|
454
|
-
templatePath = foundPackageTemplate;
|
|
455
|
-
} else if (fs.existsSync(localTemplatePath)) {
|
|
456
|
-
templatePath = localTemplatePath;
|
|
444
|
+
if (customTemplate) {
|
|
445
|
+
if (customTemplate.includes("<!DOCTYPE") || customTemplate.includes("<html")) {
|
|
446
|
+
this.template = customTemplate;
|
|
447
|
+
this.logger.log(`\u2713 Loaded custom template (inline)`);
|
|
457
448
|
} else {
|
|
458
|
-
|
|
449
|
+
const customTemplatePath = customTemplate.startsWith("/") ? customTemplate : path.join(process.cwd(), customTemplate);
|
|
450
|
+
if (!fs.existsSync(customTemplatePath)) {
|
|
451
|
+
throw new Error(`Custom template file not found at ${customTemplatePath}`);
|
|
452
|
+
}
|
|
453
|
+
try {
|
|
454
|
+
this.template = fs.readFileSync(customTemplatePath, "utf-8");
|
|
455
|
+
this.logger.log(`\u2713 Loaded custom template from ${customTemplatePath}`);
|
|
456
|
+
} catch (error) {
|
|
457
|
+
throw new Error(`Failed to read custom template file at ${customTemplatePath}: ${error.message}`);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
} else {
|
|
461
|
+
let templatePath;
|
|
462
|
+
if (this.isDevelopment) {
|
|
463
|
+
const packageTemplatePaths = [
|
|
464
|
+
path.join(__dirname, "../templates/index.html"),
|
|
465
|
+
path.join(__dirname, "../src/templates/index.html"),
|
|
466
|
+
path.join(__dirname, "../../src/templates/index.html")
|
|
467
|
+
];
|
|
468
|
+
const localTemplatePath = path.join(process.cwd(), "src/views/index.html");
|
|
469
|
+
const foundPackageTemplate = packageTemplatePaths.find((p) => fs.existsSync(p));
|
|
470
|
+
if (foundPackageTemplate) {
|
|
471
|
+
templatePath = foundPackageTemplate;
|
|
472
|
+
} else if (fs.existsSync(localTemplatePath)) {
|
|
473
|
+
templatePath = localTemplatePath;
|
|
474
|
+
} else {
|
|
475
|
+
throw new Error(`Template file not found. Tried:
|
|
459
476
|
` + packageTemplatePaths.map((p) => ` - ${p} (package template)`).join("\n") + `
|
|
460
477
|
- ${localTemplatePath} (local template)`);
|
|
478
|
+
}
|
|
479
|
+
} else {
|
|
480
|
+
templatePath = path.join(process.cwd(), "dist/client/index.html");
|
|
481
|
+
if (!fs.existsSync(templatePath)) {
|
|
482
|
+
throw new Error(`Template file not found at ${templatePath}. Make sure to run the build process first.`);
|
|
483
|
+
}
|
|
461
484
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
485
|
+
try {
|
|
486
|
+
this.template = fs.readFileSync(templatePath, "utf-8");
|
|
487
|
+
this.logger.log(`\u2713 Loaded template from ${templatePath}`);
|
|
488
|
+
} catch (error) {
|
|
489
|
+
throw new Error(`Failed to read template file at ${templatePath}: ${error.message}`);
|
|
466
490
|
}
|
|
467
491
|
}
|
|
468
|
-
try {
|
|
469
|
-
this.template = fs.readFileSync(templatePath, "utf-8");
|
|
470
|
-
this.logger.log(`\u2713 Loaded template from ${templatePath}`);
|
|
471
|
-
} catch (error) {
|
|
472
|
-
throw new Error(`Failed to read template file at ${templatePath}: ${error.message}`);
|
|
473
|
-
}
|
|
474
492
|
if (!this.isDevelopment) {
|
|
475
493
|
const manifestPath = path.join(process.cwd(), "dist/client/.vite/manifest.json");
|
|
476
494
|
if (fs.existsSync(manifestPath)) {
|
|
@@ -490,6 +508,52 @@ exports.RenderService = class _RenderService {
|
|
|
490
508
|
this.vite = vite;
|
|
491
509
|
}
|
|
492
510
|
/**
|
|
511
|
+
* Get the root layout component if it exists
|
|
512
|
+
* Auto-discovers layout files at conventional paths:
|
|
513
|
+
* - src/views/layout.tsx
|
|
514
|
+
* - src/views/layout/index.tsx
|
|
515
|
+
* - src/views/_layout.tsx
|
|
516
|
+
*/
|
|
517
|
+
async getRootLayout() {
|
|
518
|
+
if (this.rootLayoutChecked) {
|
|
519
|
+
return this.rootLayout;
|
|
520
|
+
}
|
|
521
|
+
this.rootLayoutChecked = true;
|
|
522
|
+
const conventionalPaths = [
|
|
523
|
+
"src/views/layout.tsx",
|
|
524
|
+
"src/views/layout/index.tsx",
|
|
525
|
+
"src/views/_layout.tsx"
|
|
526
|
+
];
|
|
527
|
+
try {
|
|
528
|
+
for (const path$1 of conventionalPaths) {
|
|
529
|
+
const absolutePath = path.join(process.cwd(), path$1);
|
|
530
|
+
if (!fs.existsSync(absolutePath)) {
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
this.logger.log(`\u2713 Found root layout at ${path$1}`);
|
|
534
|
+
if (this.vite) {
|
|
535
|
+
const layoutModule = await this.vite.ssrLoadModule("/" + path$1);
|
|
536
|
+
this.rootLayout = layoutModule.default;
|
|
537
|
+
return this.rootLayout;
|
|
538
|
+
} else {
|
|
539
|
+
const prodPath = path$1.replace("src/views", "dist/server/views").replace(".tsx", ".js");
|
|
540
|
+
const absoluteProdPath = path.join(process.cwd(), prodPath);
|
|
541
|
+
if (fs.existsSync(absoluteProdPath)) {
|
|
542
|
+
const layoutModule = await import(absoluteProdPath);
|
|
543
|
+
this.rootLayout = layoutModule.default;
|
|
544
|
+
return this.rootLayout;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
this.rootLayout = null;
|
|
549
|
+
return null;
|
|
550
|
+
} catch (error) {
|
|
551
|
+
this.logger.warn(`\u26A0\uFE0F Error loading root layout: ${error.message}`);
|
|
552
|
+
this.rootLayout = null;
|
|
553
|
+
return null;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
493
557
|
* Main render method that routes to string or stream mode
|
|
494
558
|
*/
|
|
495
559
|
async render(viewComponent, data = {}, res, head) {
|
|
@@ -551,20 +615,19 @@ exports.RenderService = class _RenderService {
|
|
|
551
615
|
throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
|
|
552
616
|
}
|
|
553
617
|
}
|
|
554
|
-
const { data: pageData, __context: context } = data;
|
|
618
|
+
const { data: pageData, __context: context, __layouts: layouts } = data;
|
|
555
619
|
const appHtml = await renderModule.renderComponent(viewComponent, data);
|
|
556
620
|
const componentName = viewComponent.displayName || viewComponent.name || "Component";
|
|
621
|
+
const layoutMetadata = layouts ? layouts.map((l) => ({
|
|
622
|
+
name: l.layout.displayName || l.layout.name || "default",
|
|
623
|
+
props: l.props
|
|
624
|
+
})) : [];
|
|
557
625
|
const initialStateScript = `
|
|
558
626
|
<script>
|
|
559
|
-
window.__INITIAL_STATE__ = ${
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
window.
|
|
563
|
-
isJSON: true
|
|
564
|
-
})};
|
|
565
|
-
window.__COMPONENT_NAME__ = ${serialize__default.default(componentName, {
|
|
566
|
-
isJSON: true
|
|
567
|
-
})};
|
|
627
|
+
window.__INITIAL_STATE__ = ${devalue.uneval(pageData)};
|
|
628
|
+
window.__CONTEXT__ = ${devalue.uneval(context)};
|
|
629
|
+
window.__COMPONENT_NAME__ = ${devalue.uneval(componentName)};
|
|
630
|
+
window.__LAYOUTS__ = ${devalue.uneval(layoutMetadata)};
|
|
568
631
|
</script>
|
|
569
632
|
`;
|
|
570
633
|
let clientScript = "";
|
|
@@ -637,9 +700,9 @@ exports.RenderService = class _RenderService {
|
|
|
637
700
|
throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
|
|
638
701
|
}
|
|
639
702
|
}
|
|
640
|
-
const { data: pageData, __context: context } = data;
|
|
703
|
+
const { data: pageData, __context: context, __layouts: layouts } = data;
|
|
641
704
|
const componentName = viewComponent.displayName || viewComponent.name || "Component";
|
|
642
|
-
const inlineScripts = this.templateParser.buildInlineScripts(pageData, context, componentName);
|
|
705
|
+
const inlineScripts = this.templateParser.buildInlineScripts(pageData, context, componentName, layouts);
|
|
643
706
|
const clientScript = this.templateParser.getClientScriptTag(this.isDevelopment, this.manifest);
|
|
644
707
|
const stylesheetTags = this.templateParser.getStylesheetTags(this.isDevelopment, this.manifest);
|
|
645
708
|
const headTags = this.templateParser.buildHeadTags(head);
|
|
@@ -695,22 +758,38 @@ exports.RenderService = _ts_decorate3([
|
|
|
695
758
|
_ts_param2(2, common.Inject("SSR_MODE")),
|
|
696
759
|
_ts_param2(3, common.Optional()),
|
|
697
760
|
_ts_param2(3, common.Inject("DEFAULT_HEAD")),
|
|
761
|
+
_ts_param2(4, common.Optional()),
|
|
762
|
+
_ts_param2(4, common.Inject("CUSTOM_TEMPLATE")),
|
|
698
763
|
_ts_metadata2("design:type", Function),
|
|
699
764
|
_ts_metadata2("design:paramtypes", [
|
|
700
765
|
typeof exports.TemplateParserService === "undefined" ? Object : exports.TemplateParserService,
|
|
701
766
|
typeof exports.StreamingErrorHandler === "undefined" ? Object : exports.StreamingErrorHandler,
|
|
702
767
|
typeof SSRMode === "undefined" ? Object : SSRMode,
|
|
703
|
-
typeof HeadData === "undefined" ? Object : HeadData
|
|
768
|
+
typeof HeadData === "undefined" ? Object : HeadData,
|
|
769
|
+
String
|
|
704
770
|
])
|
|
705
771
|
], exports.RenderService);
|
|
706
772
|
var RENDER_KEY = "render";
|
|
707
|
-
|
|
773
|
+
var RENDER_OPTIONS_KEY = "render_options";
|
|
774
|
+
function Render(component, options) {
|
|
708
775
|
return (target, propertyKey, descriptor) => {
|
|
709
776
|
common.SetMetadata(RENDER_KEY, component)(target, propertyKey, descriptor);
|
|
777
|
+
if (options) {
|
|
778
|
+
common.SetMetadata(RENDER_OPTIONS_KEY, options)(target, propertyKey, descriptor);
|
|
779
|
+
}
|
|
710
780
|
};
|
|
711
781
|
}
|
|
712
782
|
__name(Render, "Render");
|
|
713
|
-
var
|
|
783
|
+
var LAYOUT_KEY = "layout";
|
|
784
|
+
function Layout(layout, options) {
|
|
785
|
+
return (target) => {
|
|
786
|
+
common.SetMetadata(LAYOUT_KEY, {
|
|
787
|
+
layout,
|
|
788
|
+
options
|
|
789
|
+
})(target);
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
__name(Layout, "Layout");
|
|
714
793
|
|
|
715
794
|
// src/render/render.interceptor.ts
|
|
716
795
|
function _ts_decorate4(decorators, target, key, desc) {
|
|
@@ -724,6 +803,12 @@ function _ts_metadata3(k, v) {
|
|
|
724
803
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
725
804
|
}
|
|
726
805
|
__name(_ts_metadata3, "_ts_metadata");
|
|
806
|
+
function _ts_param3(paramIndex, decorator) {
|
|
807
|
+
return function(target, key) {
|
|
808
|
+
decorator(target, key, paramIndex);
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
__name(_ts_param3, "_ts_param");
|
|
727
812
|
function isRenderResponse(data) {
|
|
728
813
|
return data && typeof data === "object" && "props" in data;
|
|
729
814
|
}
|
|
@@ -734,9 +819,60 @@ exports.RenderInterceptor = class RenderInterceptor {
|
|
|
734
819
|
}
|
|
735
820
|
reflector;
|
|
736
821
|
renderService;
|
|
737
|
-
|
|
822
|
+
allowedHeaders;
|
|
823
|
+
allowedCookies;
|
|
824
|
+
constructor(reflector, renderService, allowedHeaders, allowedCookies) {
|
|
738
825
|
this.reflector = reflector;
|
|
739
826
|
this.renderService = renderService;
|
|
827
|
+
this.allowedHeaders = allowedHeaders;
|
|
828
|
+
this.allowedCookies = allowedCookies;
|
|
829
|
+
}
|
|
830
|
+
/**
|
|
831
|
+
* Resolve the layout hierarchy for a given route
|
|
832
|
+
* Hierarchy: Root Layout → Controller Layout → Method Layout → Page
|
|
833
|
+
*
|
|
834
|
+
* Props are merged in priority order:
|
|
835
|
+
* 1. Static props from @Layout decorator (base)
|
|
836
|
+
* 2. Static props from @Render decorator (override)
|
|
837
|
+
* 3. Dynamic props from controller return (final override)
|
|
838
|
+
*/
|
|
839
|
+
async resolveLayoutChain(context, dynamicLayoutProps) {
|
|
840
|
+
const layouts = [];
|
|
841
|
+
const rootLayout = await this.renderService.getRootLayout();
|
|
842
|
+
if (rootLayout) {
|
|
843
|
+
layouts.push({
|
|
844
|
+
layout: rootLayout,
|
|
845
|
+
props: dynamicLayoutProps || {}
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
const controllerLayoutMeta = this.reflector.get(LAYOUT_KEY, context.getClass());
|
|
849
|
+
const renderOptions = this.reflector.get(RENDER_OPTIONS_KEY, context.getHandler());
|
|
850
|
+
if (renderOptions?.layout === null) {
|
|
851
|
+
return [];
|
|
852
|
+
} else if (renderOptions?.layout === false) {
|
|
853
|
+
return layouts;
|
|
854
|
+
}
|
|
855
|
+
if (controllerLayoutMeta) {
|
|
856
|
+
const mergedProps = {
|
|
857
|
+
...controllerLayoutMeta.options?.props || {},
|
|
858
|
+
...dynamicLayoutProps || {}
|
|
859
|
+
};
|
|
860
|
+
layouts.push({
|
|
861
|
+
layout: controllerLayoutMeta.layout,
|
|
862
|
+
props: mergedProps
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
if (renderOptions?.layout) {
|
|
866
|
+
const mergedProps = {
|
|
867
|
+
...renderOptions.layoutProps || {},
|
|
868
|
+
...dynamicLayoutProps || {}
|
|
869
|
+
};
|
|
870
|
+
layouts.push({
|
|
871
|
+
layout: renderOptions.layout,
|
|
872
|
+
props: mergedProps
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
return layouts;
|
|
740
876
|
}
|
|
741
877
|
intercept(context, next) {
|
|
742
878
|
const viewPathOrComponent = this.reflector.get(RENDER_KEY, context.getHandler());
|
|
@@ -752,16 +888,36 @@ exports.RenderInterceptor = class RenderInterceptor {
|
|
|
752
888
|
path: request.path,
|
|
753
889
|
query: request.query,
|
|
754
890
|
params: request.params,
|
|
755
|
-
|
|
756
|
-
acceptLanguage: request.headers["accept-language"],
|
|
757
|
-
referer: request.headers.referer
|
|
891
|
+
method: request.method
|
|
758
892
|
};
|
|
893
|
+
if (this.allowedHeaders?.length) {
|
|
894
|
+
for (const headerName of this.allowedHeaders) {
|
|
895
|
+
const value = request.headers[headerName.toLowerCase()];
|
|
896
|
+
if (value) {
|
|
897
|
+
renderContext[headerName] = Array.isArray(value) ? value.join(", ") : value;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
if (this.allowedCookies?.length && request.cookies) {
|
|
902
|
+
const cookies = {};
|
|
903
|
+
for (const cookieName of this.allowedCookies) {
|
|
904
|
+
const value = request.cookies[cookieName];
|
|
905
|
+
if (value !== void 0) {
|
|
906
|
+
cookies[cookieName] = value;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
if (Object.keys(cookies).length > 0) {
|
|
910
|
+
renderContext.cookies = cookies;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
759
913
|
const renderResponse = isRenderResponse(data) ? data : {
|
|
760
914
|
props: data
|
|
761
915
|
};
|
|
916
|
+
const layoutChain = await this.resolveLayoutChain(context, renderResponse.layoutProps);
|
|
762
917
|
const fullData = {
|
|
763
918
|
data: renderResponse.props,
|
|
764
|
-
__context: renderContext
|
|
919
|
+
__context: renderContext,
|
|
920
|
+
__layouts: layoutChain
|
|
765
921
|
};
|
|
766
922
|
try {
|
|
767
923
|
const html = await this.renderService.render(viewPathOrComponent, fullData, response, renderResponse.head);
|
|
@@ -778,10 +934,16 @@ exports.RenderInterceptor = class RenderInterceptor {
|
|
|
778
934
|
};
|
|
779
935
|
exports.RenderInterceptor = _ts_decorate4([
|
|
780
936
|
common.Injectable(),
|
|
937
|
+
_ts_param3(2, common.Optional()),
|
|
938
|
+
_ts_param3(2, common.Inject("ALLOWED_HEADERS")),
|
|
939
|
+
_ts_param3(3, common.Optional()),
|
|
940
|
+
_ts_param3(3, common.Inject("ALLOWED_COOKIES")),
|
|
781
941
|
_ts_metadata3("design:type", Function),
|
|
782
942
|
_ts_metadata3("design:paramtypes", [
|
|
783
943
|
typeof core.Reflector === "undefined" ? Object : core.Reflector,
|
|
784
|
-
typeof exports.RenderService === "undefined" ? Object : exports.RenderService
|
|
944
|
+
typeof exports.RenderService === "undefined" ? Object : exports.RenderService,
|
|
945
|
+
Array,
|
|
946
|
+
Array
|
|
785
947
|
])
|
|
786
948
|
], exports.RenderInterceptor);
|
|
787
949
|
function _ts_decorate5(decorators, target, key, desc) {
|
|
@@ -795,12 +957,12 @@ function _ts_metadata4(k, v) {
|
|
|
795
957
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
796
958
|
}
|
|
797
959
|
__name(_ts_metadata4, "_ts_metadata");
|
|
798
|
-
function
|
|
960
|
+
function _ts_param4(paramIndex, decorator) {
|
|
799
961
|
return function(target, key) {
|
|
800
962
|
decorator(target, key, paramIndex);
|
|
801
963
|
};
|
|
802
964
|
}
|
|
803
|
-
__name(
|
|
965
|
+
__name(_ts_param4, "_ts_param");
|
|
804
966
|
var ViteInitializerService = class _ViteInitializerService {
|
|
805
967
|
static {
|
|
806
968
|
__name(this, "ViteInitializerService");
|
|
@@ -916,8 +1078,8 @@ var ViteInitializerService = class _ViteInitializerService {
|
|
|
916
1078
|
};
|
|
917
1079
|
ViteInitializerService = _ts_decorate5([
|
|
918
1080
|
common.Injectable(),
|
|
919
|
-
|
|
920
|
-
|
|
1081
|
+
_ts_param4(2, common.Optional()),
|
|
1082
|
+
_ts_param4(2, common.Inject("VITE_CONFIG")),
|
|
921
1083
|
_ts_metadata4("design:type", Function),
|
|
922
1084
|
_ts_metadata4("design:paramtypes", [
|
|
923
1085
|
typeof exports.RenderService === "undefined" ? Object : exports.RenderService,
|
|
@@ -1010,6 +1172,20 @@ exports.RenderModule = class _RenderModule {
|
|
|
1010
1172
|
useValue: config.defaultHead
|
|
1011
1173
|
});
|
|
1012
1174
|
}
|
|
1175
|
+
if (config?.template) {
|
|
1176
|
+
providers.push({
|
|
1177
|
+
provide: "CUSTOM_TEMPLATE",
|
|
1178
|
+
useValue: config.template
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
providers.push({
|
|
1182
|
+
provide: "ALLOWED_HEADERS",
|
|
1183
|
+
useValue: config?.allowedHeaders || []
|
|
1184
|
+
});
|
|
1185
|
+
providers.push({
|
|
1186
|
+
provide: "ALLOWED_COOKIES",
|
|
1187
|
+
useValue: config?.allowedCookies || []
|
|
1188
|
+
});
|
|
1013
1189
|
return {
|
|
1014
1190
|
global: true,
|
|
1015
1191
|
module: _RenderModule,
|
|
@@ -1102,6 +1278,30 @@ exports.RenderModule = class _RenderModule {
|
|
|
1102
1278
|
inject: [
|
|
1103
1279
|
"RENDER_CONFIG"
|
|
1104
1280
|
]
|
|
1281
|
+
},
|
|
1282
|
+
// Custom template provider - reads from config
|
|
1283
|
+
{
|
|
1284
|
+
provide: "CUSTOM_TEMPLATE",
|
|
1285
|
+
useFactory: /* @__PURE__ */ __name((config) => config?.template, "useFactory"),
|
|
1286
|
+
inject: [
|
|
1287
|
+
"RENDER_CONFIG"
|
|
1288
|
+
]
|
|
1289
|
+
},
|
|
1290
|
+
// Allowed headers provider - reads from config
|
|
1291
|
+
{
|
|
1292
|
+
provide: "ALLOWED_HEADERS",
|
|
1293
|
+
useFactory: /* @__PURE__ */ __name((config) => config?.allowedHeaders || [], "useFactory"),
|
|
1294
|
+
inject: [
|
|
1295
|
+
"RENDER_CONFIG"
|
|
1296
|
+
]
|
|
1297
|
+
},
|
|
1298
|
+
// Allowed cookies provider - reads from config
|
|
1299
|
+
{
|
|
1300
|
+
provide: "ALLOWED_COOKIES",
|
|
1301
|
+
useFactory: /* @__PURE__ */ __name((config) => config?.allowedCookies || [], "useFactory"),
|
|
1302
|
+
inject: [
|
|
1303
|
+
"RENDER_CONFIG"
|
|
1304
|
+
]
|
|
1105
1305
|
}
|
|
1106
1306
|
];
|
|
1107
1307
|
return {
|
|
@@ -1138,32 +1338,203 @@ exports.RenderModule = _ts_decorate6([
|
|
|
1138
1338
|
})
|
|
1139
1339
|
], exports.RenderModule);
|
|
1140
1340
|
var PageContext = /* @__PURE__ */ react.createContext(null);
|
|
1141
|
-
function
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
}
|
|
1146
|
-
return context;
|
|
1341
|
+
function PageContextProvider({ context, children }) {
|
|
1342
|
+
return /* @__PURE__ */ React.createElement(PageContext.Provider, {
|
|
1343
|
+
value: context
|
|
1344
|
+
}, children);
|
|
1147
1345
|
}
|
|
1148
|
-
__name(
|
|
1149
|
-
function
|
|
1150
|
-
return
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1346
|
+
__name(PageContextProvider, "PageContextProvider");
|
|
1347
|
+
function createSSRHooks() {
|
|
1348
|
+
return {
|
|
1349
|
+
/**
|
|
1350
|
+
* Hook to access the full page context with your app's type.
|
|
1351
|
+
* Contains URL metadata, headers, and any custom properties you've added.
|
|
1352
|
+
*/
|
|
1353
|
+
usePageContext: /* @__PURE__ */ __name(() => {
|
|
1354
|
+
const context = react.useContext(PageContext);
|
|
1355
|
+
if (!context) {
|
|
1356
|
+
throw new Error("usePageContext must be used within PageContextProvider");
|
|
1357
|
+
}
|
|
1358
|
+
return context;
|
|
1359
|
+
}, "usePageContext"),
|
|
1360
|
+
/**
|
|
1361
|
+
* Hook to access route parameters.
|
|
1362
|
+
*
|
|
1363
|
+
* @example
|
|
1364
|
+
* ```tsx
|
|
1365
|
+
* // Route: /users/:id
|
|
1366
|
+
* const params = useParams();
|
|
1367
|
+
* console.log(params.id); // '123'
|
|
1368
|
+
* ```
|
|
1369
|
+
*/
|
|
1370
|
+
useParams: /* @__PURE__ */ __name(() => {
|
|
1371
|
+
const context = react.useContext(PageContext);
|
|
1372
|
+
if (!context) {
|
|
1373
|
+
throw new Error("useParams must be used within PageContextProvider");
|
|
1374
|
+
}
|
|
1375
|
+
return context.params;
|
|
1376
|
+
}, "useParams"),
|
|
1377
|
+
/**
|
|
1378
|
+
* Hook to access query string parameters.
|
|
1379
|
+
*
|
|
1380
|
+
* @example
|
|
1381
|
+
* ```tsx
|
|
1382
|
+
* // URL: /search?q=react&sort=date
|
|
1383
|
+
* const query = useQuery();
|
|
1384
|
+
* console.log(query.q); // 'react'
|
|
1385
|
+
* console.log(query.sort); // 'date'
|
|
1386
|
+
* ```
|
|
1387
|
+
*/
|
|
1388
|
+
useQuery: /* @__PURE__ */ __name(() => {
|
|
1389
|
+
const context = react.useContext(PageContext);
|
|
1390
|
+
if (!context) {
|
|
1391
|
+
throw new Error("useQuery must be used within PageContextProvider");
|
|
1392
|
+
}
|
|
1393
|
+
return context.query;
|
|
1394
|
+
}, "useQuery"),
|
|
1395
|
+
/**
|
|
1396
|
+
* Alias for usePageContext() with a more intuitive name.
|
|
1397
|
+
* Returns the full request context with your app's type.
|
|
1398
|
+
*
|
|
1399
|
+
* @example
|
|
1400
|
+
* ```tsx
|
|
1401
|
+
* const request = useRequest();
|
|
1402
|
+
* console.log(request.path); // '/users/123'
|
|
1403
|
+
* console.log(request.method); // 'GET'
|
|
1404
|
+
* console.log(request.params); // { id: '123' }
|
|
1405
|
+
* console.log(request.query); // { search: 'foo' }
|
|
1406
|
+
* ```
|
|
1407
|
+
*/
|
|
1408
|
+
useRequest: /* @__PURE__ */ __name(() => {
|
|
1409
|
+
const context = react.useContext(PageContext);
|
|
1410
|
+
if (!context) {
|
|
1411
|
+
throw new Error("useRequest must be used within PageContextProvider");
|
|
1412
|
+
}
|
|
1413
|
+
return context;
|
|
1414
|
+
}, "useRequest"),
|
|
1415
|
+
/**
|
|
1416
|
+
* Hook to access headers configured via allowedHeaders.
|
|
1417
|
+
* Returns all headers as a Record.
|
|
1418
|
+
*
|
|
1419
|
+
* Configure in module registration:
|
|
1420
|
+
* ```typescript
|
|
1421
|
+
* RenderModule.register({
|
|
1422
|
+
* allowedHeaders: ['user-agent', 'x-tenant-id', 'x-api-version']
|
|
1423
|
+
* })
|
|
1424
|
+
* ```
|
|
1425
|
+
*
|
|
1426
|
+
* @example
|
|
1427
|
+
* ```tsx
|
|
1428
|
+
* const headers = useHeaders();
|
|
1429
|
+
* console.log(headers['user-agent']); // 'Mozilla/5.0...'
|
|
1430
|
+
* console.log(headers['x-tenant-id']); // 'tenant-123'
|
|
1431
|
+
* console.log(headers['x-api-version']); // 'v2'
|
|
1432
|
+
* ```
|
|
1433
|
+
*/
|
|
1434
|
+
useHeaders: /* @__PURE__ */ __name(() => {
|
|
1435
|
+
const context = react.useContext(PageContext);
|
|
1436
|
+
if (!context) {
|
|
1437
|
+
throw new Error("useHeaders must be used within PageContextProvider");
|
|
1438
|
+
}
|
|
1439
|
+
const baseKeys = /* @__PURE__ */ new Set([
|
|
1440
|
+
"url",
|
|
1441
|
+
"path",
|
|
1442
|
+
"query",
|
|
1443
|
+
"params",
|
|
1444
|
+
"method",
|
|
1445
|
+
"cookies"
|
|
1446
|
+
]);
|
|
1447
|
+
const headers = {};
|
|
1448
|
+
for (const [key, value] of Object.entries(context)) {
|
|
1449
|
+
if (!baseKeys.has(key) && typeof value === "string") {
|
|
1450
|
+
headers[key] = value;
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
return headers;
|
|
1454
|
+
}, "useHeaders"),
|
|
1455
|
+
/**
|
|
1456
|
+
* Hook to access a specific custom header by name.
|
|
1457
|
+
* Returns undefined if the header is not configured or not present.
|
|
1458
|
+
*
|
|
1459
|
+
* @param name - The header name (as configured in allowedHeaders)
|
|
1460
|
+
*
|
|
1461
|
+
* @example
|
|
1462
|
+
* ```tsx
|
|
1463
|
+
* const tenantId = useHeader('x-tenant-id');
|
|
1464
|
+
* if (tenantId) {
|
|
1465
|
+
* console.log(`Tenant: ${tenantId}`);
|
|
1466
|
+
* }
|
|
1467
|
+
* ```
|
|
1468
|
+
*/
|
|
1469
|
+
useHeader: /* @__PURE__ */ __name((name) => {
|
|
1470
|
+
const context = react.useContext(PageContext);
|
|
1471
|
+
if (!context) {
|
|
1472
|
+
throw new Error("useHeader must be used within PageContextProvider");
|
|
1473
|
+
}
|
|
1474
|
+
const value = context[name];
|
|
1475
|
+
return typeof value === "string" ? value : void 0;
|
|
1476
|
+
}, "useHeader"),
|
|
1477
|
+
/**
|
|
1478
|
+
* Hook to access cookies configured via allowedCookies.
|
|
1479
|
+
* Returns all allowed cookies as a Record.
|
|
1480
|
+
*
|
|
1481
|
+
* Configure in module registration:
|
|
1482
|
+
* ```typescript
|
|
1483
|
+
* RenderModule.register({
|
|
1484
|
+
* allowedCookies: ['theme', 'locale', 'consent']
|
|
1485
|
+
* })
|
|
1486
|
+
* ```
|
|
1487
|
+
*
|
|
1488
|
+
* @example
|
|
1489
|
+
* ```tsx
|
|
1490
|
+
* const cookies = useCookies();
|
|
1491
|
+
* console.log(cookies.theme); // 'dark'
|
|
1492
|
+
* console.log(cookies.locale); // 'en-US'
|
|
1493
|
+
* ```
|
|
1494
|
+
*/
|
|
1495
|
+
useCookies: /* @__PURE__ */ __name(() => {
|
|
1496
|
+
const context = react.useContext(PageContext);
|
|
1497
|
+
if (!context) {
|
|
1498
|
+
throw new Error("useCookies must be used within PageContextProvider");
|
|
1499
|
+
}
|
|
1500
|
+
const cookies = context.cookies;
|
|
1501
|
+
return typeof cookies === "object" && cookies !== null ? cookies : {};
|
|
1502
|
+
}, "useCookies"),
|
|
1503
|
+
/**
|
|
1504
|
+
* Hook to access a specific cookie by name.
|
|
1505
|
+
* Returns undefined if the cookie is not configured or not present.
|
|
1506
|
+
*
|
|
1507
|
+
* @param name - The cookie name (as configured in allowedCookies)
|
|
1508
|
+
*
|
|
1509
|
+
* @example
|
|
1510
|
+
* ```tsx
|
|
1511
|
+
* const theme = useCookie('theme');
|
|
1512
|
+
* if (theme === 'dark') {
|
|
1513
|
+
* console.log('Dark mode enabled');
|
|
1514
|
+
* }
|
|
1515
|
+
* ```
|
|
1516
|
+
*/
|
|
1517
|
+
useCookie: /* @__PURE__ */ __name((name) => {
|
|
1518
|
+
const context = react.useContext(PageContext);
|
|
1519
|
+
if (!context) {
|
|
1520
|
+
throw new Error("useCookie must be used within PageContextProvider");
|
|
1521
|
+
}
|
|
1522
|
+
const contextObj = context;
|
|
1523
|
+
const cookies = contextObj.cookies;
|
|
1524
|
+
if (typeof cookies === "object" && cookies !== null && !Array.isArray(cookies)) {
|
|
1525
|
+
const cookiesRecord = cookies;
|
|
1526
|
+
const value = cookiesRecord[name];
|
|
1527
|
+
return typeof value === "string" ? value : void 0;
|
|
1528
|
+
}
|
|
1529
|
+
return void 0;
|
|
1530
|
+
}, "useCookie")
|
|
1531
|
+
};
|
|
1159
1532
|
}
|
|
1160
|
-
__name(
|
|
1533
|
+
__name(createSSRHooks, "createSSRHooks");
|
|
1161
1534
|
|
|
1162
1535
|
exports.ErrorPageDevelopment = ErrorPageDevelopment;
|
|
1163
1536
|
exports.ErrorPageProduction = ErrorPageProduction;
|
|
1164
|
-
exports.
|
|
1537
|
+
exports.Layout = Layout;
|
|
1538
|
+
exports.PageContextProvider = PageContextProvider;
|
|
1165
1539
|
exports.Render = Render;
|
|
1166
|
-
exports.
|
|
1167
|
-
exports.useParams = useParams;
|
|
1168
|
-
exports.useQuery = useQuery;
|
|
1169
|
-
exports.useUserAgent = useUserAgent;
|
|
1540
|
+
exports.createSSRHooks = createSSRHooks;
|