@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.mjs
CHANGED
|
@@ -2,10 +2,10 @@ import { Injectable, Logger, Optional, Inject, Global, Module, SetMetadata } fro
|
|
|
2
2
|
import { HttpAdapterHost, APP_INTERCEPTOR, Reflector } from '@nestjs/core';
|
|
3
3
|
import { existsSync, readFileSync } from 'fs';
|
|
4
4
|
import { join, relative } from 'path';
|
|
5
|
-
import
|
|
5
|
+
import { uneval } from 'devalue';
|
|
6
6
|
import escapeHtml from 'escape-html';
|
|
7
7
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
8
|
-
import { createElement,
|
|
8
|
+
import { createElement, createContext, useContext } from 'react';
|
|
9
9
|
import { switchMap } from 'rxjs/operators';
|
|
10
10
|
|
|
11
11
|
var __defProp = Object.defineProperty;
|
|
@@ -98,21 +98,20 @@ var TemplateParserService = class {
|
|
|
98
98
|
/**
|
|
99
99
|
* Build inline script that provides initial state to the client
|
|
100
100
|
*
|
|
101
|
-
* Safely serializes data using
|
|
102
|
-
*
|
|
103
|
-
*
|
|
101
|
+
* Safely serializes data using devalue to avoid XSS vulnerabilities.
|
|
102
|
+
* Devalue is designed specifically for SSR, handling complex types safely
|
|
103
|
+
* while being faster and more secure than alternatives.
|
|
104
104
|
*/
|
|
105
|
-
buildInlineScripts(data, context, componentName) {
|
|
105
|
+
buildInlineScripts(data, context, componentName, layouts) {
|
|
106
|
+
const layoutMetadata = layouts ? layouts.map((l) => ({
|
|
107
|
+
name: l.layout.displayName || l.layout.name || "default",
|
|
108
|
+
props: l.props
|
|
109
|
+
})) : [];
|
|
106
110
|
return `<script>
|
|
107
|
-
window.__INITIAL_STATE__ = ${
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
window.
|
|
111
|
-
isJSON: true
|
|
112
|
-
})};
|
|
113
|
-
window.__COMPONENT_NAME__ = ${serialize(componentName, {
|
|
114
|
-
isJSON: true
|
|
115
|
-
})};
|
|
111
|
+
window.__INITIAL_STATE__ = ${uneval(data)};
|
|
112
|
+
window.__CONTEXT__ = ${uneval(context)};
|
|
113
|
+
window.__COMPONENT_NAME__ = ${uneval(componentName)};
|
|
114
|
+
window.__LAYOUTS__ = ${uneval(layoutMetadata)};
|
|
116
115
|
</script>`;
|
|
117
116
|
}
|
|
118
117
|
/**
|
|
@@ -421,12 +420,14 @@ var RenderService = class _RenderService {
|
|
|
421
420
|
isDevelopment;
|
|
422
421
|
ssrMode;
|
|
423
422
|
entryServerPath;
|
|
424
|
-
|
|
423
|
+
rootLayout = void 0;
|
|
424
|
+
rootLayoutChecked = false;
|
|
425
|
+
constructor(templateParser, streamingErrorHandler, ssrMode, defaultHead, customTemplate) {
|
|
425
426
|
this.templateParser = templateParser;
|
|
426
427
|
this.streamingErrorHandler = streamingErrorHandler;
|
|
427
428
|
this.defaultHead = defaultHead;
|
|
428
429
|
this.isDevelopment = process.env.NODE_ENV !== "production";
|
|
429
|
-
this.ssrMode = ssrMode || process.env.SSR_MODE || "
|
|
430
|
+
this.ssrMode = ssrMode || process.env.SSR_MODE || "stream";
|
|
430
431
|
const absoluteServerPath = join(__dirname, "/templates/entry-server.tsx");
|
|
431
432
|
const relativeServerPath = relative(process.cwd(), absoluteServerPath);
|
|
432
433
|
if (relativeServerPath.startsWith("..")) {
|
|
@@ -434,36 +435,54 @@ var RenderService = class _RenderService {
|
|
|
434
435
|
} else {
|
|
435
436
|
this.entryServerPath = "/" + relativeServerPath.replace(/\\/g, "/");
|
|
436
437
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
join(__dirname, "../src/templates/index.html"),
|
|
442
|
-
join(__dirname, "../../src/templates/index.html")
|
|
443
|
-
];
|
|
444
|
-
const localTemplatePath = join(process.cwd(), "src/views/index.html");
|
|
445
|
-
const foundPackageTemplate = packageTemplatePaths.find((p) => existsSync(p));
|
|
446
|
-
if (foundPackageTemplate) {
|
|
447
|
-
templatePath = foundPackageTemplate;
|
|
448
|
-
} else if (existsSync(localTemplatePath)) {
|
|
449
|
-
templatePath = localTemplatePath;
|
|
438
|
+
if (customTemplate) {
|
|
439
|
+
if (customTemplate.includes("<!DOCTYPE") || customTemplate.includes("<html")) {
|
|
440
|
+
this.template = customTemplate;
|
|
441
|
+
this.logger.log(`\u2713 Loaded custom template (inline)`);
|
|
450
442
|
} else {
|
|
451
|
-
|
|
443
|
+
const customTemplatePath = customTemplate.startsWith("/") ? customTemplate : join(process.cwd(), customTemplate);
|
|
444
|
+
if (!existsSync(customTemplatePath)) {
|
|
445
|
+
throw new Error(`Custom template file not found at ${customTemplatePath}`);
|
|
446
|
+
}
|
|
447
|
+
try {
|
|
448
|
+
this.template = readFileSync(customTemplatePath, "utf-8");
|
|
449
|
+
this.logger.log(`\u2713 Loaded custom template from ${customTemplatePath}`);
|
|
450
|
+
} catch (error) {
|
|
451
|
+
throw new Error(`Failed to read custom template file at ${customTemplatePath}: ${error.message}`);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
} else {
|
|
455
|
+
let templatePath;
|
|
456
|
+
if (this.isDevelopment) {
|
|
457
|
+
const packageTemplatePaths = [
|
|
458
|
+
join(__dirname, "../templates/index.html"),
|
|
459
|
+
join(__dirname, "../src/templates/index.html"),
|
|
460
|
+
join(__dirname, "../../src/templates/index.html")
|
|
461
|
+
];
|
|
462
|
+
const localTemplatePath = join(process.cwd(), "src/views/index.html");
|
|
463
|
+
const foundPackageTemplate = packageTemplatePaths.find((p) => existsSync(p));
|
|
464
|
+
if (foundPackageTemplate) {
|
|
465
|
+
templatePath = foundPackageTemplate;
|
|
466
|
+
} else if (existsSync(localTemplatePath)) {
|
|
467
|
+
templatePath = localTemplatePath;
|
|
468
|
+
} else {
|
|
469
|
+
throw new Error(`Template file not found. Tried:
|
|
452
470
|
` + packageTemplatePaths.map((p) => ` - ${p} (package template)`).join("\n") + `
|
|
453
471
|
- ${localTemplatePath} (local template)`);
|
|
472
|
+
}
|
|
473
|
+
} else {
|
|
474
|
+
templatePath = join(process.cwd(), "dist/client/index.html");
|
|
475
|
+
if (!existsSync(templatePath)) {
|
|
476
|
+
throw new Error(`Template file not found at ${templatePath}. Make sure to run the build process first.`);
|
|
477
|
+
}
|
|
454
478
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
479
|
+
try {
|
|
480
|
+
this.template = readFileSync(templatePath, "utf-8");
|
|
481
|
+
this.logger.log(`\u2713 Loaded template from ${templatePath}`);
|
|
482
|
+
} catch (error) {
|
|
483
|
+
throw new Error(`Failed to read template file at ${templatePath}: ${error.message}`);
|
|
459
484
|
}
|
|
460
485
|
}
|
|
461
|
-
try {
|
|
462
|
-
this.template = readFileSync(templatePath, "utf-8");
|
|
463
|
-
this.logger.log(`\u2713 Loaded template from ${templatePath}`);
|
|
464
|
-
} catch (error) {
|
|
465
|
-
throw new Error(`Failed to read template file at ${templatePath}: ${error.message}`);
|
|
466
|
-
}
|
|
467
486
|
if (!this.isDevelopment) {
|
|
468
487
|
const manifestPath = join(process.cwd(), "dist/client/.vite/manifest.json");
|
|
469
488
|
if (existsSync(manifestPath)) {
|
|
@@ -483,6 +502,52 @@ var RenderService = class _RenderService {
|
|
|
483
502
|
this.vite = vite;
|
|
484
503
|
}
|
|
485
504
|
/**
|
|
505
|
+
* Get the root layout component if it exists
|
|
506
|
+
* Auto-discovers layout files at conventional paths:
|
|
507
|
+
* - src/views/layout.tsx
|
|
508
|
+
* - src/views/layout/index.tsx
|
|
509
|
+
* - src/views/_layout.tsx
|
|
510
|
+
*/
|
|
511
|
+
async getRootLayout() {
|
|
512
|
+
if (this.rootLayoutChecked) {
|
|
513
|
+
return this.rootLayout;
|
|
514
|
+
}
|
|
515
|
+
this.rootLayoutChecked = true;
|
|
516
|
+
const conventionalPaths = [
|
|
517
|
+
"src/views/layout.tsx",
|
|
518
|
+
"src/views/layout/index.tsx",
|
|
519
|
+
"src/views/_layout.tsx"
|
|
520
|
+
];
|
|
521
|
+
try {
|
|
522
|
+
for (const path of conventionalPaths) {
|
|
523
|
+
const absolutePath = join(process.cwd(), path);
|
|
524
|
+
if (!existsSync(absolutePath)) {
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
this.logger.log(`\u2713 Found root layout at ${path}`);
|
|
528
|
+
if (this.vite) {
|
|
529
|
+
const layoutModule = await this.vite.ssrLoadModule("/" + path);
|
|
530
|
+
this.rootLayout = layoutModule.default;
|
|
531
|
+
return this.rootLayout;
|
|
532
|
+
} else {
|
|
533
|
+
const prodPath = path.replace("src/views", "dist/server/views").replace(".tsx", ".js");
|
|
534
|
+
const absoluteProdPath = join(process.cwd(), prodPath);
|
|
535
|
+
if (existsSync(absoluteProdPath)) {
|
|
536
|
+
const layoutModule = await import(absoluteProdPath);
|
|
537
|
+
this.rootLayout = layoutModule.default;
|
|
538
|
+
return this.rootLayout;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
this.rootLayout = null;
|
|
543
|
+
return null;
|
|
544
|
+
} catch (error) {
|
|
545
|
+
this.logger.warn(`\u26A0\uFE0F Error loading root layout: ${error.message}`);
|
|
546
|
+
this.rootLayout = null;
|
|
547
|
+
return null;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
486
551
|
* Main render method that routes to string or stream mode
|
|
487
552
|
*/
|
|
488
553
|
async render(viewComponent, data = {}, res, head) {
|
|
@@ -544,20 +609,19 @@ var RenderService = class _RenderService {
|
|
|
544
609
|
throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
|
|
545
610
|
}
|
|
546
611
|
}
|
|
547
|
-
const { data: pageData, __context: context } = data;
|
|
612
|
+
const { data: pageData, __context: context, __layouts: layouts } = data;
|
|
548
613
|
const appHtml = await renderModule.renderComponent(viewComponent, data);
|
|
549
614
|
const componentName = viewComponent.displayName || viewComponent.name || "Component";
|
|
615
|
+
const layoutMetadata = layouts ? layouts.map((l) => ({
|
|
616
|
+
name: l.layout.displayName || l.layout.name || "default",
|
|
617
|
+
props: l.props
|
|
618
|
+
})) : [];
|
|
550
619
|
const initialStateScript = `
|
|
551
620
|
<script>
|
|
552
|
-
window.__INITIAL_STATE__ = ${
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
window.
|
|
556
|
-
isJSON: true
|
|
557
|
-
})};
|
|
558
|
-
window.__COMPONENT_NAME__ = ${serialize(componentName, {
|
|
559
|
-
isJSON: true
|
|
560
|
-
})};
|
|
621
|
+
window.__INITIAL_STATE__ = ${uneval(pageData)};
|
|
622
|
+
window.__CONTEXT__ = ${uneval(context)};
|
|
623
|
+
window.__COMPONENT_NAME__ = ${uneval(componentName)};
|
|
624
|
+
window.__LAYOUTS__ = ${uneval(layoutMetadata)};
|
|
561
625
|
</script>
|
|
562
626
|
`;
|
|
563
627
|
let clientScript = "";
|
|
@@ -630,9 +694,9 @@ var RenderService = class _RenderService {
|
|
|
630
694
|
throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
|
|
631
695
|
}
|
|
632
696
|
}
|
|
633
|
-
const { data: pageData, __context: context } = data;
|
|
697
|
+
const { data: pageData, __context: context, __layouts: layouts } = data;
|
|
634
698
|
const componentName = viewComponent.displayName || viewComponent.name || "Component";
|
|
635
|
-
const inlineScripts = this.templateParser.buildInlineScripts(pageData, context, componentName);
|
|
699
|
+
const inlineScripts = this.templateParser.buildInlineScripts(pageData, context, componentName, layouts);
|
|
636
700
|
const clientScript = this.templateParser.getClientScriptTag(this.isDevelopment, this.manifest);
|
|
637
701
|
const stylesheetTags = this.templateParser.getStylesheetTags(this.isDevelopment, this.manifest);
|
|
638
702
|
const headTags = this.templateParser.buildHeadTags(head);
|
|
@@ -688,22 +752,38 @@ RenderService = _ts_decorate3([
|
|
|
688
752
|
_ts_param2(2, Inject("SSR_MODE")),
|
|
689
753
|
_ts_param2(3, Optional()),
|
|
690
754
|
_ts_param2(3, Inject("DEFAULT_HEAD")),
|
|
755
|
+
_ts_param2(4, Optional()),
|
|
756
|
+
_ts_param2(4, Inject("CUSTOM_TEMPLATE")),
|
|
691
757
|
_ts_metadata2("design:type", Function),
|
|
692
758
|
_ts_metadata2("design:paramtypes", [
|
|
693
759
|
typeof TemplateParserService === "undefined" ? Object : TemplateParserService,
|
|
694
760
|
typeof StreamingErrorHandler === "undefined" ? Object : StreamingErrorHandler,
|
|
695
761
|
typeof SSRMode === "undefined" ? Object : SSRMode,
|
|
696
|
-
typeof HeadData === "undefined" ? Object : HeadData
|
|
762
|
+
typeof HeadData === "undefined" ? Object : HeadData,
|
|
763
|
+
String
|
|
697
764
|
])
|
|
698
765
|
], RenderService);
|
|
699
766
|
var RENDER_KEY = "render";
|
|
700
|
-
|
|
767
|
+
var RENDER_OPTIONS_KEY = "render_options";
|
|
768
|
+
function Render(component, options) {
|
|
701
769
|
return (target, propertyKey, descriptor) => {
|
|
702
770
|
SetMetadata(RENDER_KEY, component)(target, propertyKey, descriptor);
|
|
771
|
+
if (options) {
|
|
772
|
+
SetMetadata(RENDER_OPTIONS_KEY, options)(target, propertyKey, descriptor);
|
|
773
|
+
}
|
|
703
774
|
};
|
|
704
775
|
}
|
|
705
776
|
__name(Render, "Render");
|
|
706
|
-
var
|
|
777
|
+
var LAYOUT_KEY = "layout";
|
|
778
|
+
function Layout(layout, options) {
|
|
779
|
+
return (target) => {
|
|
780
|
+
SetMetadata(LAYOUT_KEY, {
|
|
781
|
+
layout,
|
|
782
|
+
options
|
|
783
|
+
})(target);
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
__name(Layout, "Layout");
|
|
707
787
|
|
|
708
788
|
// src/render/render.interceptor.ts
|
|
709
789
|
function _ts_decorate4(decorators, target, key, desc) {
|
|
@@ -717,6 +797,12 @@ function _ts_metadata3(k, v) {
|
|
|
717
797
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
718
798
|
}
|
|
719
799
|
__name(_ts_metadata3, "_ts_metadata");
|
|
800
|
+
function _ts_param3(paramIndex, decorator) {
|
|
801
|
+
return function(target, key) {
|
|
802
|
+
decorator(target, key, paramIndex);
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
__name(_ts_param3, "_ts_param");
|
|
720
806
|
function isRenderResponse(data) {
|
|
721
807
|
return data && typeof data === "object" && "props" in data;
|
|
722
808
|
}
|
|
@@ -727,9 +813,60 @@ var RenderInterceptor = class {
|
|
|
727
813
|
}
|
|
728
814
|
reflector;
|
|
729
815
|
renderService;
|
|
730
|
-
|
|
816
|
+
allowedHeaders;
|
|
817
|
+
allowedCookies;
|
|
818
|
+
constructor(reflector, renderService, allowedHeaders, allowedCookies) {
|
|
731
819
|
this.reflector = reflector;
|
|
732
820
|
this.renderService = renderService;
|
|
821
|
+
this.allowedHeaders = allowedHeaders;
|
|
822
|
+
this.allowedCookies = allowedCookies;
|
|
823
|
+
}
|
|
824
|
+
/**
|
|
825
|
+
* Resolve the layout hierarchy for a given route
|
|
826
|
+
* Hierarchy: Root Layout → Controller Layout → Method Layout → Page
|
|
827
|
+
*
|
|
828
|
+
* Props are merged in priority order:
|
|
829
|
+
* 1. Static props from @Layout decorator (base)
|
|
830
|
+
* 2. Static props from @Render decorator (override)
|
|
831
|
+
* 3. Dynamic props from controller return (final override)
|
|
832
|
+
*/
|
|
833
|
+
async resolveLayoutChain(context, dynamicLayoutProps) {
|
|
834
|
+
const layouts = [];
|
|
835
|
+
const rootLayout = await this.renderService.getRootLayout();
|
|
836
|
+
if (rootLayout) {
|
|
837
|
+
layouts.push({
|
|
838
|
+
layout: rootLayout,
|
|
839
|
+
props: dynamicLayoutProps || {}
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
const controllerLayoutMeta = this.reflector.get(LAYOUT_KEY, context.getClass());
|
|
843
|
+
const renderOptions = this.reflector.get(RENDER_OPTIONS_KEY, context.getHandler());
|
|
844
|
+
if (renderOptions?.layout === null) {
|
|
845
|
+
return [];
|
|
846
|
+
} else if (renderOptions?.layout === false) {
|
|
847
|
+
return layouts;
|
|
848
|
+
}
|
|
849
|
+
if (controllerLayoutMeta) {
|
|
850
|
+
const mergedProps = {
|
|
851
|
+
...controllerLayoutMeta.options?.props || {},
|
|
852
|
+
...dynamicLayoutProps || {}
|
|
853
|
+
};
|
|
854
|
+
layouts.push({
|
|
855
|
+
layout: controllerLayoutMeta.layout,
|
|
856
|
+
props: mergedProps
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
if (renderOptions?.layout) {
|
|
860
|
+
const mergedProps = {
|
|
861
|
+
...renderOptions.layoutProps || {},
|
|
862
|
+
...dynamicLayoutProps || {}
|
|
863
|
+
};
|
|
864
|
+
layouts.push({
|
|
865
|
+
layout: renderOptions.layout,
|
|
866
|
+
props: mergedProps
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
return layouts;
|
|
733
870
|
}
|
|
734
871
|
intercept(context, next) {
|
|
735
872
|
const viewPathOrComponent = this.reflector.get(RENDER_KEY, context.getHandler());
|
|
@@ -745,16 +882,36 @@ var RenderInterceptor = class {
|
|
|
745
882
|
path: request.path,
|
|
746
883
|
query: request.query,
|
|
747
884
|
params: request.params,
|
|
748
|
-
|
|
749
|
-
acceptLanguage: request.headers["accept-language"],
|
|
750
|
-
referer: request.headers.referer
|
|
885
|
+
method: request.method
|
|
751
886
|
};
|
|
887
|
+
if (this.allowedHeaders?.length) {
|
|
888
|
+
for (const headerName of this.allowedHeaders) {
|
|
889
|
+
const value = request.headers[headerName.toLowerCase()];
|
|
890
|
+
if (value) {
|
|
891
|
+
renderContext[headerName] = Array.isArray(value) ? value.join(", ") : value;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
if (this.allowedCookies?.length && request.cookies) {
|
|
896
|
+
const cookies = {};
|
|
897
|
+
for (const cookieName of this.allowedCookies) {
|
|
898
|
+
const value = request.cookies[cookieName];
|
|
899
|
+
if (value !== void 0) {
|
|
900
|
+
cookies[cookieName] = value;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
if (Object.keys(cookies).length > 0) {
|
|
904
|
+
renderContext.cookies = cookies;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
752
907
|
const renderResponse = isRenderResponse(data) ? data : {
|
|
753
908
|
props: data
|
|
754
909
|
};
|
|
910
|
+
const layoutChain = await this.resolveLayoutChain(context, renderResponse.layoutProps);
|
|
755
911
|
const fullData = {
|
|
756
912
|
data: renderResponse.props,
|
|
757
|
-
__context: renderContext
|
|
913
|
+
__context: renderContext,
|
|
914
|
+
__layouts: layoutChain
|
|
758
915
|
};
|
|
759
916
|
try {
|
|
760
917
|
const html = await this.renderService.render(viewPathOrComponent, fullData, response, renderResponse.head);
|
|
@@ -771,10 +928,16 @@ var RenderInterceptor = class {
|
|
|
771
928
|
};
|
|
772
929
|
RenderInterceptor = _ts_decorate4([
|
|
773
930
|
Injectable(),
|
|
931
|
+
_ts_param3(2, Optional()),
|
|
932
|
+
_ts_param3(2, Inject("ALLOWED_HEADERS")),
|
|
933
|
+
_ts_param3(3, Optional()),
|
|
934
|
+
_ts_param3(3, Inject("ALLOWED_COOKIES")),
|
|
774
935
|
_ts_metadata3("design:type", Function),
|
|
775
936
|
_ts_metadata3("design:paramtypes", [
|
|
776
937
|
typeof Reflector === "undefined" ? Object : Reflector,
|
|
777
|
-
typeof RenderService === "undefined" ? Object : RenderService
|
|
938
|
+
typeof RenderService === "undefined" ? Object : RenderService,
|
|
939
|
+
Array,
|
|
940
|
+
Array
|
|
778
941
|
])
|
|
779
942
|
], RenderInterceptor);
|
|
780
943
|
function _ts_decorate5(decorators, target, key, desc) {
|
|
@@ -788,12 +951,12 @@ function _ts_metadata4(k, v) {
|
|
|
788
951
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
789
952
|
}
|
|
790
953
|
__name(_ts_metadata4, "_ts_metadata");
|
|
791
|
-
function
|
|
954
|
+
function _ts_param4(paramIndex, decorator) {
|
|
792
955
|
return function(target, key) {
|
|
793
956
|
decorator(target, key, paramIndex);
|
|
794
957
|
};
|
|
795
958
|
}
|
|
796
|
-
__name(
|
|
959
|
+
__name(_ts_param4, "_ts_param");
|
|
797
960
|
var ViteInitializerService = class _ViteInitializerService {
|
|
798
961
|
static {
|
|
799
962
|
__name(this, "ViteInitializerService");
|
|
@@ -909,8 +1072,8 @@ var ViteInitializerService = class _ViteInitializerService {
|
|
|
909
1072
|
};
|
|
910
1073
|
ViteInitializerService = _ts_decorate5([
|
|
911
1074
|
Injectable(),
|
|
912
|
-
|
|
913
|
-
|
|
1075
|
+
_ts_param4(2, Optional()),
|
|
1076
|
+
_ts_param4(2, Inject("VITE_CONFIG")),
|
|
914
1077
|
_ts_metadata4("design:type", Function),
|
|
915
1078
|
_ts_metadata4("design:paramtypes", [
|
|
916
1079
|
typeof RenderService === "undefined" ? Object : RenderService,
|
|
@@ -1003,6 +1166,20 @@ var RenderModule = class _RenderModule {
|
|
|
1003
1166
|
useValue: config.defaultHead
|
|
1004
1167
|
});
|
|
1005
1168
|
}
|
|
1169
|
+
if (config?.template) {
|
|
1170
|
+
providers.push({
|
|
1171
|
+
provide: "CUSTOM_TEMPLATE",
|
|
1172
|
+
useValue: config.template
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
1175
|
+
providers.push({
|
|
1176
|
+
provide: "ALLOWED_HEADERS",
|
|
1177
|
+
useValue: config?.allowedHeaders || []
|
|
1178
|
+
});
|
|
1179
|
+
providers.push({
|
|
1180
|
+
provide: "ALLOWED_COOKIES",
|
|
1181
|
+
useValue: config?.allowedCookies || []
|
|
1182
|
+
});
|
|
1006
1183
|
return {
|
|
1007
1184
|
global: true,
|
|
1008
1185
|
module: _RenderModule,
|
|
@@ -1095,6 +1272,30 @@ var RenderModule = class _RenderModule {
|
|
|
1095
1272
|
inject: [
|
|
1096
1273
|
"RENDER_CONFIG"
|
|
1097
1274
|
]
|
|
1275
|
+
},
|
|
1276
|
+
// Custom template provider - reads from config
|
|
1277
|
+
{
|
|
1278
|
+
provide: "CUSTOM_TEMPLATE",
|
|
1279
|
+
useFactory: /* @__PURE__ */ __name((config) => config?.template, "useFactory"),
|
|
1280
|
+
inject: [
|
|
1281
|
+
"RENDER_CONFIG"
|
|
1282
|
+
]
|
|
1283
|
+
},
|
|
1284
|
+
// Allowed headers provider - reads from config
|
|
1285
|
+
{
|
|
1286
|
+
provide: "ALLOWED_HEADERS",
|
|
1287
|
+
useFactory: /* @__PURE__ */ __name((config) => config?.allowedHeaders || [], "useFactory"),
|
|
1288
|
+
inject: [
|
|
1289
|
+
"RENDER_CONFIG"
|
|
1290
|
+
]
|
|
1291
|
+
},
|
|
1292
|
+
// Allowed cookies provider - reads from config
|
|
1293
|
+
{
|
|
1294
|
+
provide: "ALLOWED_COOKIES",
|
|
1295
|
+
useFactory: /* @__PURE__ */ __name((config) => config?.allowedCookies || [], "useFactory"),
|
|
1296
|
+
inject: [
|
|
1297
|
+
"RENDER_CONFIG"
|
|
1298
|
+
]
|
|
1098
1299
|
}
|
|
1099
1300
|
];
|
|
1100
1301
|
return {
|
|
@@ -1131,25 +1332,198 @@ RenderModule = _ts_decorate6([
|
|
|
1131
1332
|
})
|
|
1132
1333
|
], RenderModule);
|
|
1133
1334
|
var PageContext = /* @__PURE__ */ createContext(null);
|
|
1134
|
-
function
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
}
|
|
1139
|
-
return context;
|
|
1335
|
+
function PageContextProvider({ context, children }) {
|
|
1336
|
+
return /* @__PURE__ */ React.createElement(PageContext.Provider, {
|
|
1337
|
+
value: context
|
|
1338
|
+
}, children);
|
|
1140
1339
|
}
|
|
1141
|
-
__name(
|
|
1142
|
-
function
|
|
1143
|
-
return
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1340
|
+
__name(PageContextProvider, "PageContextProvider");
|
|
1341
|
+
function createSSRHooks() {
|
|
1342
|
+
return {
|
|
1343
|
+
/**
|
|
1344
|
+
* Hook to access the full page context with your app's type.
|
|
1345
|
+
* Contains URL metadata, headers, and any custom properties you've added.
|
|
1346
|
+
*/
|
|
1347
|
+
usePageContext: /* @__PURE__ */ __name(() => {
|
|
1348
|
+
const context = useContext(PageContext);
|
|
1349
|
+
if (!context) {
|
|
1350
|
+
throw new Error("usePageContext must be used within PageContextProvider");
|
|
1351
|
+
}
|
|
1352
|
+
return context;
|
|
1353
|
+
}, "usePageContext"),
|
|
1354
|
+
/**
|
|
1355
|
+
* Hook to access route parameters.
|
|
1356
|
+
*
|
|
1357
|
+
* @example
|
|
1358
|
+
* ```tsx
|
|
1359
|
+
* // Route: /users/:id
|
|
1360
|
+
* const params = useParams();
|
|
1361
|
+
* console.log(params.id); // '123'
|
|
1362
|
+
* ```
|
|
1363
|
+
*/
|
|
1364
|
+
useParams: /* @__PURE__ */ __name(() => {
|
|
1365
|
+
const context = useContext(PageContext);
|
|
1366
|
+
if (!context) {
|
|
1367
|
+
throw new Error("useParams must be used within PageContextProvider");
|
|
1368
|
+
}
|
|
1369
|
+
return context.params;
|
|
1370
|
+
}, "useParams"),
|
|
1371
|
+
/**
|
|
1372
|
+
* Hook to access query string parameters.
|
|
1373
|
+
*
|
|
1374
|
+
* @example
|
|
1375
|
+
* ```tsx
|
|
1376
|
+
* // URL: /search?q=react&sort=date
|
|
1377
|
+
* const query = useQuery();
|
|
1378
|
+
* console.log(query.q); // 'react'
|
|
1379
|
+
* console.log(query.sort); // 'date'
|
|
1380
|
+
* ```
|
|
1381
|
+
*/
|
|
1382
|
+
useQuery: /* @__PURE__ */ __name(() => {
|
|
1383
|
+
const context = useContext(PageContext);
|
|
1384
|
+
if (!context) {
|
|
1385
|
+
throw new Error("useQuery must be used within PageContextProvider");
|
|
1386
|
+
}
|
|
1387
|
+
return context.query;
|
|
1388
|
+
}, "useQuery"),
|
|
1389
|
+
/**
|
|
1390
|
+
* Alias for usePageContext() with a more intuitive name.
|
|
1391
|
+
* Returns the full request context with your app's type.
|
|
1392
|
+
*
|
|
1393
|
+
* @example
|
|
1394
|
+
* ```tsx
|
|
1395
|
+
* const request = useRequest();
|
|
1396
|
+
* console.log(request.path); // '/users/123'
|
|
1397
|
+
* console.log(request.method); // 'GET'
|
|
1398
|
+
* console.log(request.params); // { id: '123' }
|
|
1399
|
+
* console.log(request.query); // { search: 'foo' }
|
|
1400
|
+
* ```
|
|
1401
|
+
*/
|
|
1402
|
+
useRequest: /* @__PURE__ */ __name(() => {
|
|
1403
|
+
const context = useContext(PageContext);
|
|
1404
|
+
if (!context) {
|
|
1405
|
+
throw new Error("useRequest must be used within PageContextProvider");
|
|
1406
|
+
}
|
|
1407
|
+
return context;
|
|
1408
|
+
}, "useRequest"),
|
|
1409
|
+
/**
|
|
1410
|
+
* Hook to access headers configured via allowedHeaders.
|
|
1411
|
+
* Returns all headers as a Record.
|
|
1412
|
+
*
|
|
1413
|
+
* Configure in module registration:
|
|
1414
|
+
* ```typescript
|
|
1415
|
+
* RenderModule.register({
|
|
1416
|
+
* allowedHeaders: ['user-agent', 'x-tenant-id', 'x-api-version']
|
|
1417
|
+
* })
|
|
1418
|
+
* ```
|
|
1419
|
+
*
|
|
1420
|
+
* @example
|
|
1421
|
+
* ```tsx
|
|
1422
|
+
* const headers = useHeaders();
|
|
1423
|
+
* console.log(headers['user-agent']); // 'Mozilla/5.0...'
|
|
1424
|
+
* console.log(headers['x-tenant-id']); // 'tenant-123'
|
|
1425
|
+
* console.log(headers['x-api-version']); // 'v2'
|
|
1426
|
+
* ```
|
|
1427
|
+
*/
|
|
1428
|
+
useHeaders: /* @__PURE__ */ __name(() => {
|
|
1429
|
+
const context = useContext(PageContext);
|
|
1430
|
+
if (!context) {
|
|
1431
|
+
throw new Error("useHeaders must be used within PageContextProvider");
|
|
1432
|
+
}
|
|
1433
|
+
const baseKeys = /* @__PURE__ */ new Set([
|
|
1434
|
+
"url",
|
|
1435
|
+
"path",
|
|
1436
|
+
"query",
|
|
1437
|
+
"params",
|
|
1438
|
+
"method",
|
|
1439
|
+
"cookies"
|
|
1440
|
+
]);
|
|
1441
|
+
const headers = {};
|
|
1442
|
+
for (const [key, value] of Object.entries(context)) {
|
|
1443
|
+
if (!baseKeys.has(key) && typeof value === "string") {
|
|
1444
|
+
headers[key] = value;
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
return headers;
|
|
1448
|
+
}, "useHeaders"),
|
|
1449
|
+
/**
|
|
1450
|
+
* Hook to access a specific custom header by name.
|
|
1451
|
+
* Returns undefined if the header is not configured or not present.
|
|
1452
|
+
*
|
|
1453
|
+
* @param name - The header name (as configured in allowedHeaders)
|
|
1454
|
+
*
|
|
1455
|
+
* @example
|
|
1456
|
+
* ```tsx
|
|
1457
|
+
* const tenantId = useHeader('x-tenant-id');
|
|
1458
|
+
* if (tenantId) {
|
|
1459
|
+
* console.log(`Tenant: ${tenantId}`);
|
|
1460
|
+
* }
|
|
1461
|
+
* ```
|
|
1462
|
+
*/
|
|
1463
|
+
useHeader: /* @__PURE__ */ __name((name) => {
|
|
1464
|
+
const context = useContext(PageContext);
|
|
1465
|
+
if (!context) {
|
|
1466
|
+
throw new Error("useHeader must be used within PageContextProvider");
|
|
1467
|
+
}
|
|
1468
|
+
const value = context[name];
|
|
1469
|
+
return typeof value === "string" ? value : void 0;
|
|
1470
|
+
}, "useHeader"),
|
|
1471
|
+
/**
|
|
1472
|
+
* Hook to access cookies configured via allowedCookies.
|
|
1473
|
+
* Returns all allowed cookies as a Record.
|
|
1474
|
+
*
|
|
1475
|
+
* Configure in module registration:
|
|
1476
|
+
* ```typescript
|
|
1477
|
+
* RenderModule.register({
|
|
1478
|
+
* allowedCookies: ['theme', 'locale', 'consent']
|
|
1479
|
+
* })
|
|
1480
|
+
* ```
|
|
1481
|
+
*
|
|
1482
|
+
* @example
|
|
1483
|
+
* ```tsx
|
|
1484
|
+
* const cookies = useCookies();
|
|
1485
|
+
* console.log(cookies.theme); // 'dark'
|
|
1486
|
+
* console.log(cookies.locale); // 'en-US'
|
|
1487
|
+
* ```
|
|
1488
|
+
*/
|
|
1489
|
+
useCookies: /* @__PURE__ */ __name(() => {
|
|
1490
|
+
const context = useContext(PageContext);
|
|
1491
|
+
if (!context) {
|
|
1492
|
+
throw new Error("useCookies must be used within PageContextProvider");
|
|
1493
|
+
}
|
|
1494
|
+
const cookies = context.cookies;
|
|
1495
|
+
return typeof cookies === "object" && cookies !== null ? cookies : {};
|
|
1496
|
+
}, "useCookies"),
|
|
1497
|
+
/**
|
|
1498
|
+
* Hook to access a specific cookie by name.
|
|
1499
|
+
* Returns undefined if the cookie is not configured or not present.
|
|
1500
|
+
*
|
|
1501
|
+
* @param name - The cookie name (as configured in allowedCookies)
|
|
1502
|
+
*
|
|
1503
|
+
* @example
|
|
1504
|
+
* ```tsx
|
|
1505
|
+
* const theme = useCookie('theme');
|
|
1506
|
+
* if (theme === 'dark') {
|
|
1507
|
+
* console.log('Dark mode enabled');
|
|
1508
|
+
* }
|
|
1509
|
+
* ```
|
|
1510
|
+
*/
|
|
1511
|
+
useCookie: /* @__PURE__ */ __name((name) => {
|
|
1512
|
+
const context = useContext(PageContext);
|
|
1513
|
+
if (!context) {
|
|
1514
|
+
throw new Error("useCookie must be used within PageContextProvider");
|
|
1515
|
+
}
|
|
1516
|
+
const contextObj = context;
|
|
1517
|
+
const cookies = contextObj.cookies;
|
|
1518
|
+
if (typeof cookies === "object" && cookies !== null && !Array.isArray(cookies)) {
|
|
1519
|
+
const cookiesRecord = cookies;
|
|
1520
|
+
const value = cookiesRecord[name];
|
|
1521
|
+
return typeof value === "string" ? value : void 0;
|
|
1522
|
+
}
|
|
1523
|
+
return void 0;
|
|
1524
|
+
}, "useCookie")
|
|
1525
|
+
};
|
|
1152
1526
|
}
|
|
1153
|
-
__name(
|
|
1527
|
+
__name(createSSRHooks, "createSSRHooks");
|
|
1154
1528
|
|
|
1155
|
-
export { ErrorPageDevelopment, ErrorPageProduction,
|
|
1529
|
+
export { ErrorPageDevelopment, ErrorPageProduction, Layout, PageContextProvider, Render, RenderInterceptor, RenderModule, RenderService, StreamingErrorHandler, TemplateParserService, createSSRHooks };
|