@nestjs-ssr/react 0.1.1

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.
@@ -0,0 +1,1110 @@
1
+ 'use strict';
2
+
3
+ var common = require('@nestjs/common');
4
+ var core = require('@nestjs/core');
5
+ var fs = require('fs');
6
+ var path = require('path');
7
+ var serialize = require('serialize-javascript');
8
+ var escapeHtml = require('escape-html');
9
+ var server = require('react-dom/server');
10
+ var react = require('react');
11
+ var operators = require('rxjs/operators');
12
+
13
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
14
+
15
+ var serialize__default = /*#__PURE__*/_interopDefault(serialize);
16
+ var escapeHtml__default = /*#__PURE__*/_interopDefault(escapeHtml);
17
+
18
+ var __defProp = Object.defineProperty;
19
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
20
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
21
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
22
+ }) : x)(function(x) {
23
+ if (typeof require !== "undefined") return require.apply(this, arguments);
24
+ throw Error('Dynamic require of "' + x + '" is not supported');
25
+ });
26
+ function _ts_decorate(decorators, target, key, desc) {
27
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
28
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
29
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
30
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
31
+ }
32
+ __name(_ts_decorate, "_ts_decorate");
33
+ exports.TemplateParserService = class TemplateParserService {
34
+ static {
35
+ __name(this, "TemplateParserService");
36
+ }
37
+ // Mapping of HeadData fields to their HTML tag renderers
38
+ // Order matters: title and description first for SEO best practices
39
+ headTagRenderers = [
40
+ {
41
+ key: "title",
42
+ render: /* @__PURE__ */ __name((v) => `<title>${escapeHtml__default.default(v)}</title>`, "render")
43
+ },
44
+ {
45
+ key: "description",
46
+ render: /* @__PURE__ */ __name((v) => `<meta name="description" content="${escapeHtml__default.default(v)}" />`, "render")
47
+ },
48
+ {
49
+ key: "keywords",
50
+ render: /* @__PURE__ */ __name((v) => `<meta name="keywords" content="${escapeHtml__default.default(v)}" />`, "render")
51
+ },
52
+ {
53
+ key: "canonical",
54
+ render: /* @__PURE__ */ __name((v) => `<link rel="canonical" href="${escapeHtml__default.default(v)}" />`, "render")
55
+ },
56
+ {
57
+ key: "ogTitle",
58
+ render: /* @__PURE__ */ __name((v) => `<meta property="og:title" content="${escapeHtml__default.default(v)}" />`, "render")
59
+ },
60
+ {
61
+ key: "ogDescription",
62
+ render: /* @__PURE__ */ __name((v) => `<meta property="og:description" content="${escapeHtml__default.default(v)}" />`, "render")
63
+ },
64
+ {
65
+ key: "ogImage",
66
+ render: /* @__PURE__ */ __name((v) => `<meta property="og:image" content="${escapeHtml__default.default(v)}" />`, "render")
67
+ }
68
+ ];
69
+ /**
70
+ * Parse HTML template into parts for streaming SSR
71
+ *
72
+ * Splits the template at strategic injection points:
73
+ * - Before root div: Shell HTML (head, body start)
74
+ * - Root div start
75
+ * - Root div end
76
+ * - After root: Scripts and closing tags
77
+ */
78
+ parseTemplate(html) {
79
+ const rootStartMarker = '<div id="root">';
80
+ const rootStartIndex = html.indexOf(rootStartMarker);
81
+ if (rootStartIndex === -1) {
82
+ throw new Error('Template must contain <div id="root">');
83
+ }
84
+ const commentMarker = "<!--app-html-->";
85
+ const commentIndex = html.indexOf(commentMarker, rootStartIndex);
86
+ if (commentIndex === -1) {
87
+ throw new Error("Template must contain <!--app-html--> placeholder");
88
+ }
89
+ const rootEndMarker = "</div>";
90
+ const rootEndIndex = html.indexOf(rootEndMarker, commentIndex);
91
+ if (rootEndIndex === -1) {
92
+ throw new Error("Template must have closing </div> for root");
93
+ }
94
+ const htmlStart = html.substring(0, rootStartIndex);
95
+ const rootStart = rootStartMarker;
96
+ const rootEnd = rootEndMarker;
97
+ const htmlEnd = html.substring(rootEndIndex + rootEndMarker.length);
98
+ return {
99
+ htmlStart,
100
+ rootStart,
101
+ rootEnd,
102
+ htmlEnd
103
+ };
104
+ }
105
+ /**
106
+ * Build inline script that provides initial state to the client
107
+ *
108
+ * Safely serializes data using serialize-javascript to avoid XSS vulnerabilities.
109
+ * This library handles all edge cases including escaping dangerous characters,
110
+ * functions, dates, regexes, and prevents prototype pollution.
111
+ */
112
+ buildInlineScripts(data, context, componentPath) {
113
+ return `<script>
114
+ window.__INITIAL_STATE__ = ${serialize__default.default(data, {
115
+ isJSON: true
116
+ })};
117
+ window.__CONTEXT__ = ${serialize__default.default(context, {
118
+ isJSON: true
119
+ })};
120
+ window.__COMPONENT_PATH__ = ${serialize__default.default(componentPath, {
121
+ isJSON: true
122
+ })};
123
+ </script>`;
124
+ }
125
+ /**
126
+ * Get client script tag for hydration
127
+ *
128
+ * In development: Direct module import with Vite HMR
129
+ * In production: Hashed filename from manifest
130
+ */
131
+ getClientScriptTag(isDevelopment, manifest) {
132
+ if (isDevelopment) {
133
+ return '<script type="module" src="/src/entry-client.tsx"></script>';
134
+ }
135
+ if (!manifest || !manifest["src/entry-client.tsx"]) {
136
+ throw new Error("Manifest missing entry for src/entry-client.tsx");
137
+ }
138
+ const entryFile = manifest["src/entry-client.tsx"].file;
139
+ return `<script type="module" src="/${entryFile}"></script>`;
140
+ }
141
+ /**
142
+ * Get stylesheet link tags
143
+ *
144
+ * In development: Direct link to source CSS file
145
+ * In production: Hashed CSS files from manifest
146
+ */
147
+ getStylesheetTags(isDevelopment, manifest) {
148
+ if (isDevelopment) {
149
+ return "";
150
+ }
151
+ if (!manifest || !manifest["src/entry-client.tsx"]) {
152
+ return "";
153
+ }
154
+ const entry = manifest["src/entry-client.tsx"];
155
+ if (!entry.css || entry.css.length === 0) {
156
+ return "";
157
+ }
158
+ return entry.css.map((css) => `<link rel="stylesheet" href="/${css}" />`).join("\n ");
159
+ }
160
+ /**
161
+ * Build HTML head tags from HeadData
162
+ *
163
+ * Generates title, meta tags, and link tags for SEO and page metadata.
164
+ * Safely escapes content using escape-html to prevent XSS.
165
+ */
166
+ buildHeadTags(head) {
167
+ if (!head) {
168
+ return "";
169
+ }
170
+ const tags = [];
171
+ for (const { key, render } of this.headTagRenderers) {
172
+ const value = head[key];
173
+ if (value && typeof value === "string") {
174
+ tags.push(render(value));
175
+ }
176
+ }
177
+ if (head.links?.length) {
178
+ tags.push(...head.links.map((link) => this.buildTag("link", link)));
179
+ }
180
+ if (head.meta?.length) {
181
+ tags.push(...head.meta.map((meta) => this.buildTag("meta", meta)));
182
+ }
183
+ return tags.join("\n ");
184
+ }
185
+ /**
186
+ * Build an HTML tag from an object of attributes
187
+ */
188
+ buildTag(tagName, attrs) {
189
+ const attrString = Object.entries(attrs).map(([key, value]) => `${key}="${escapeHtml__default.default(String(value))}"`).join(" ");
190
+ return `<${tagName} ${attrString} />`;
191
+ }
192
+ };
193
+ exports.TemplateParserService = _ts_decorate([
194
+ common.Injectable()
195
+ ], exports.TemplateParserService);
196
+
197
+ // src/render/error-pages/error-page-development.tsx
198
+ function ErrorPageDevelopment({ error, viewPath, phase }) {
199
+ const stackLines = error.stack ? error.stack.split("\n").slice(1) : [];
200
+ return /* @__PURE__ */ React.createElement("html", {
201
+ lang: "en"
202
+ }, /* @__PURE__ */ React.createElement("head", null, /* @__PURE__ */ React.createElement("meta", {
203
+ charSet: "UTF-8"
204
+ }), /* @__PURE__ */ React.createElement("meta", {
205
+ name: "viewport",
206
+ content: "width=device-width, initial-scale=1.0"
207
+ }), /* @__PURE__ */ React.createElement("title", null, `SSR Error - ${error.name}`), /* @__PURE__ */ React.createElement("style", {
208
+ dangerouslySetInnerHTML: {
209
+ __html: `
210
+ body {
211
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
212
+ line-height: 1.6;
213
+ padding: 2rem;
214
+ background: #1a1a1a;
215
+ color: #e0e0e0;
216
+ }
217
+ .error-container {
218
+ max-width: 900px;
219
+ margin: 0 auto;
220
+ }
221
+ h1 {
222
+ color: #ff6b6b;
223
+ font-size: 2rem;
224
+ margin-bottom: 0.5rem;
225
+ }
226
+ .error-type {
227
+ color: #ffa502;
228
+ font-size: 1.2rem;
229
+ margin-bottom: 1rem;
230
+ }
231
+ .error-message {
232
+ background: #2d2d2d;
233
+ padding: 1rem;
234
+ border-left: 4px solid #ff6b6b;
235
+ margin: 1rem 0;
236
+ font-family: 'Courier New', Courier, monospace;
237
+ }
238
+ .stack-trace {
239
+ background: #2d2d2d;
240
+ padding: 1rem;
241
+ border-radius: 4px;
242
+ overflow-x: auto;
243
+ margin: 1rem 0;
244
+ }
245
+ .stack-trace pre {
246
+ margin: 0;
247
+ font-family: 'Courier New', Courier, monospace;
248
+ font-size: 0.9rem;
249
+ color: #a0a0a0;
250
+ }
251
+ .meta {
252
+ color: #888;
253
+ font-size: 0.9rem;
254
+ margin-top: 2rem;
255
+ }
256
+ `
257
+ }
258
+ })), /* @__PURE__ */ React.createElement("body", null, /* @__PURE__ */ React.createElement("div", {
259
+ className: "error-container"
260
+ }, /* @__PURE__ */ React.createElement("h1", null, "Server-Side Rendering Error"), /* @__PURE__ */ React.createElement("div", {
261
+ className: "error-type"
262
+ }, error.name), /* @__PURE__ */ React.createElement("div", {
263
+ className: "error-message"
264
+ }, error.message), /* @__PURE__ */ React.createElement("h2", null, "Stack Trace"), /* @__PURE__ */ React.createElement("div", {
265
+ className: "stack-trace"
266
+ }, /* @__PURE__ */ React.createElement("pre", null, stackLines.join("\n"))), /* @__PURE__ */ React.createElement("div", {
267
+ className: "meta"
268
+ }, /* @__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")))));
269
+ }
270
+ __name(ErrorPageDevelopment, "ErrorPageDevelopment");
271
+
272
+ // src/render/error-pages/error-page-production.tsx
273
+ function ErrorPageProduction() {
274
+ return /* @__PURE__ */ React.createElement("html", {
275
+ lang: "en"
276
+ }, /* @__PURE__ */ React.createElement("head", null, /* @__PURE__ */ React.createElement("meta", {
277
+ charSet: "UTF-8"
278
+ }), /* @__PURE__ */ React.createElement("meta", {
279
+ name: "viewport",
280
+ content: "width=device-width, initial-scale=1.0"
281
+ }), /* @__PURE__ */ React.createElement("title", null, "Error"), /* @__PURE__ */ React.createElement("style", {
282
+ dangerouslySetInnerHTML: {
283
+ __html: `
284
+ body {
285
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
286
+ display: flex;
287
+ align-items: center;
288
+ justify-content: center;
289
+ min-height: 100vh;
290
+ margin: 0;
291
+ background: #f5f5f5;
292
+ }
293
+ .error-container {
294
+ text-align: center;
295
+ padding: 2rem;
296
+ }
297
+ h1 {
298
+ font-size: 3rem;
299
+ color: #333;
300
+ margin: 0 0 1rem 0;
301
+ }
302
+ p {
303
+ font-size: 1.2rem;
304
+ color: #666;
305
+ }
306
+ `
307
+ }
308
+ })), /* @__PURE__ */ React.createElement("body", null, /* @__PURE__ */ React.createElement("div", {
309
+ className: "error-container"
310
+ }, /* @__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."))));
311
+ }
312
+ __name(ErrorPageProduction, "ErrorPageProduction");
313
+
314
+ // src/render/streaming-error-handler.ts
315
+ function _ts_decorate2(decorators, target, key, desc) {
316
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
317
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
318
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
319
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
320
+ }
321
+ __name(_ts_decorate2, "_ts_decorate");
322
+ function _ts_metadata(k, v) {
323
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
324
+ }
325
+ __name(_ts_metadata, "_ts_metadata");
326
+ function _ts_param(paramIndex, decorator) {
327
+ return function(target, key) {
328
+ decorator(target, key, paramIndex);
329
+ };
330
+ }
331
+ __name(_ts_param, "_ts_param");
332
+ exports.StreamingErrorHandler = class _StreamingErrorHandler {
333
+ static {
334
+ __name(this, "StreamingErrorHandler");
335
+ }
336
+ errorPageDevelopment;
337
+ errorPageProduction;
338
+ logger = new common.Logger(_StreamingErrorHandler.name);
339
+ constructor(errorPageDevelopment, errorPageProduction) {
340
+ this.errorPageDevelopment = errorPageDevelopment;
341
+ this.errorPageProduction = errorPageProduction;
342
+ }
343
+ /**
344
+ * Handle error that occurred before shell was ready
345
+ * Can still set HTTP status code and send error page
346
+ */
347
+ handleShellError(error, res, viewPath, isDevelopment) {
348
+ this.logger.error(`Shell error rendering ${viewPath}: ${error.message}`, error.stack);
349
+ res.statusCode = 500;
350
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
351
+ if (isDevelopment) {
352
+ res.send(this.renderDevelopmentErrorPage(error, viewPath, "shell"));
353
+ } else {
354
+ res.send(this.renderProductionErrorPage());
355
+ }
356
+ }
357
+ /**
358
+ * Handle error that occurred during streaming
359
+ * Headers already sent, can only log the error
360
+ */
361
+ handleStreamError(error, viewPath) {
362
+ this.logger.error(`Streaming error rendering ${viewPath}: ${error.message}`, error.stack);
363
+ }
364
+ /**
365
+ * Render development error page using React component
366
+ */
367
+ renderDevelopmentErrorPage(error, viewPath, phase) {
368
+ const ErrorComponent = this.errorPageDevelopment || ErrorPageDevelopment;
369
+ const element = react.createElement(ErrorComponent, {
370
+ error,
371
+ viewPath,
372
+ phase
373
+ });
374
+ return "<!DOCTYPE html>\n" + server.renderToStaticMarkup(element);
375
+ }
376
+ /**
377
+ * Render production error page using React component
378
+ */
379
+ renderProductionErrorPage() {
380
+ const ErrorComponent = this.errorPageProduction || ErrorPageProduction;
381
+ const element = react.createElement(ErrorComponent);
382
+ return "<!DOCTYPE html>\n" + server.renderToStaticMarkup(element);
383
+ }
384
+ };
385
+ exports.StreamingErrorHandler = _ts_decorate2([
386
+ common.Injectable(),
387
+ _ts_param(0, common.Optional()),
388
+ _ts_param(0, common.Inject("ERROR_PAGE_DEVELOPMENT")),
389
+ _ts_param(1, common.Optional()),
390
+ _ts_param(1, common.Inject("ERROR_PAGE_PRODUCTION")),
391
+ _ts_metadata("design:type", Function),
392
+ _ts_metadata("design:paramtypes", [
393
+ typeof ComponentType === "undefined" ? Object : ComponentType,
394
+ typeof ComponentType === "undefined" ? Object : ComponentType
395
+ ])
396
+ ], exports.StreamingErrorHandler);
397
+
398
+ // src/render/render.service.ts
399
+ function _ts_decorate3(decorators, target, key, desc) {
400
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
401
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
402
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
403
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
404
+ }
405
+ __name(_ts_decorate3, "_ts_decorate");
406
+ function _ts_metadata2(k, v) {
407
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
408
+ }
409
+ __name(_ts_metadata2, "_ts_metadata");
410
+ function _ts_param2(paramIndex, decorator) {
411
+ return function(target, key) {
412
+ decorator(target, key, paramIndex);
413
+ };
414
+ }
415
+ __name(_ts_param2, "_ts_param");
416
+ exports.RenderService = class _RenderService {
417
+ static {
418
+ __name(this, "RenderService");
419
+ }
420
+ templateParser;
421
+ streamingErrorHandler;
422
+ defaultHead;
423
+ logger = new common.Logger(_RenderService.name);
424
+ vite = null;
425
+ template;
426
+ manifest = null;
427
+ serverManifest = null;
428
+ isDevelopment;
429
+ ssrMode;
430
+ constructor(templateParser, streamingErrorHandler, ssrMode, defaultHead) {
431
+ this.templateParser = templateParser;
432
+ this.streamingErrorHandler = streamingErrorHandler;
433
+ this.defaultHead = defaultHead;
434
+ this.isDevelopment = process.env.NODE_ENV !== "production";
435
+ this.ssrMode = ssrMode || process.env.SSR_MODE || "string";
436
+ let templatePath;
437
+ if (this.isDevelopment) {
438
+ const packageTemplatePaths = [
439
+ path.join(__dirname, "../templates/index.html"),
440
+ path.join(__dirname, "../src/templates/index.html"),
441
+ path.join(__dirname, "../../src/templates/index.html")
442
+ ];
443
+ const localTemplatePath = path.join(process.cwd(), "src/views/index.html");
444
+ const foundPackageTemplate = packageTemplatePaths.find((p) => fs.existsSync(p));
445
+ if (foundPackageTemplate) {
446
+ templatePath = foundPackageTemplate;
447
+ } else if (fs.existsSync(localTemplatePath)) {
448
+ templatePath = localTemplatePath;
449
+ } else {
450
+ throw new Error(`Template file not found. Tried:
451
+ ` + packageTemplatePaths.map((p) => ` - ${p} (package template)`).join("\n") + `
452
+ - ${localTemplatePath} (local template)`);
453
+ }
454
+ } else {
455
+ templatePath = path.join(process.cwd(), "dist/client/index.html");
456
+ if (!fs.existsSync(templatePath)) {
457
+ throw new Error(`Template file not found at ${templatePath}. Make sure to run the build process first.`);
458
+ }
459
+ }
460
+ try {
461
+ this.template = fs.readFileSync(templatePath, "utf-8");
462
+ this.logger.log(`\u2713 Loaded template from ${templatePath}`);
463
+ } catch (error) {
464
+ throw new Error(`Failed to read template file at ${templatePath}: ${error.message}`);
465
+ }
466
+ if (!this.isDevelopment) {
467
+ const manifestPath = path.join(process.cwd(), "dist/client/.vite/manifest.json");
468
+ if (fs.existsSync(manifestPath)) {
469
+ this.manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
470
+ } else {
471
+ this.logger.warn("\u26A0\uFE0F Client manifest not found. Run `pnpm build:client` first.");
472
+ }
473
+ const serverManifestPath = path.join(process.cwd(), "dist/server/.vite/manifest.json");
474
+ if (fs.existsSync(serverManifestPath)) {
475
+ this.serverManifest = JSON.parse(fs.readFileSync(serverManifestPath, "utf-8"));
476
+ } else {
477
+ this.logger.warn("\u26A0\uFE0F Server manifest not found. Run `pnpm build:server` first.");
478
+ }
479
+ }
480
+ }
481
+ setViteServer(vite) {
482
+ this.vite = vite;
483
+ }
484
+ /**
485
+ * Main render method that routes to string or stream mode
486
+ */
487
+ async render(viewPath, data = {}, res, head) {
488
+ const mergedHead = this.mergeHead(this.defaultHead, head);
489
+ if (this.ssrMode === "stream") {
490
+ if (!res) {
491
+ throw new Error("Response object is required for streaming SSR mode. Pass res as third parameter.");
492
+ }
493
+ return this.renderToStream(viewPath, data, res, mergedHead);
494
+ }
495
+ return this.renderToString(viewPath, data, mergedHead);
496
+ }
497
+ /**
498
+ * Merge default head with page-specific head
499
+ * Page-specific head values override defaults
500
+ */
501
+ mergeHead(defaultHead, pageHead) {
502
+ if (!defaultHead && !pageHead) {
503
+ return void 0;
504
+ }
505
+ return {
506
+ ...defaultHead,
507
+ ...pageHead,
508
+ // Merge arrays (links and meta) instead of replacing
509
+ links: [
510
+ ...defaultHead?.links || [],
511
+ ...pageHead?.links || []
512
+ ],
513
+ meta: [
514
+ ...defaultHead?.meta || [],
515
+ ...pageHead?.meta || []
516
+ ]
517
+ };
518
+ }
519
+ /**
520
+ * Traditional string-based SSR using renderToString
521
+ */
522
+ async renderToString(viewPath, data = {}, head) {
523
+ const startTime = Date.now();
524
+ try {
525
+ let template = this.template;
526
+ if (this.vite) {
527
+ template = await this.vite.transformIndexHtml("/", template);
528
+ }
529
+ let renderModule;
530
+ if (this.vite) {
531
+ renderModule = await this.vite.ssrLoadModule("/src/entry-server.tsx");
532
+ } else {
533
+ if (this.serverManifest) {
534
+ const manifestEntry = Object.entries(this.serverManifest).find(([key, value]) => value.isEntry && key.includes("entry-server"));
535
+ if (manifestEntry) {
536
+ const [, entry] = manifestEntry;
537
+ const serverPath = path.join(process.cwd(), "dist/server", entry.file);
538
+ renderModule = await import(serverPath);
539
+ } else {
540
+ throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
541
+ }
542
+ } else {
543
+ throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
544
+ }
545
+ }
546
+ const { data: pageData, __context: context } = data;
547
+ const appHtml = await renderModule.renderComponent(viewPath, data);
548
+ const initialStateScript = `
549
+ <script>
550
+ window.__INITIAL_STATE__ = ${serialize__default.default(pageData, {
551
+ isJSON: true
552
+ })};
553
+ window.__CONTEXT__ = ${serialize__default.default(context, {
554
+ isJSON: true
555
+ })};
556
+ window.__COMPONENT_PATH__ = ${serialize__default.default(viewPath, {
557
+ isJSON: true
558
+ })};
559
+ </script>
560
+ `;
561
+ let clientScript = "";
562
+ let styles = "";
563
+ if (this.vite) {
564
+ clientScript = `<script type="module" src="/src/entry-client.tsx"></script>`;
565
+ styles = "";
566
+ } else {
567
+ if (this.manifest) {
568
+ const manifestEntry = Object.entries(this.manifest).find(([key, value]) => value.isEntry && key.includes("entry-client"));
569
+ if (manifestEntry) {
570
+ const [, entry] = manifestEntry;
571
+ const entryFile = entry.file;
572
+ clientScript = `<script type="module" src="/${entryFile}"></script>`;
573
+ if (entry.css) {
574
+ const cssFiles = entry.css;
575
+ styles = cssFiles.map((css) => `<link rel="stylesheet" href="/${css}" />`).join("\n ");
576
+ }
577
+ } else {
578
+ this.logger.error("\u26A0\uFE0F Client entry not found in manifest");
579
+ clientScript = `<script type="module" src="/assets/client.js"></script>`;
580
+ }
581
+ } else {
582
+ this.logger.error("\u26A0\uFE0F Client manifest not found");
583
+ clientScript = `<script type="module" src="/assets/client.js"></script>`;
584
+ }
585
+ }
586
+ const headTags = this.templateParser.buildHeadTags(head);
587
+ let html = template.replace("<!--app-html-->", appHtml);
588
+ html = html.replace("<!--initial-state-->", initialStateScript);
589
+ html = html.replace("<!--client-scripts-->", clientScript);
590
+ html = html.replace("<!--styles-->", styles);
591
+ html = html.replace("<!--head-meta-->", headTags);
592
+ if (this.isDevelopment) {
593
+ const duration = Date.now() - startTime;
594
+ this.logger.log(`[SSR] ${viewPath} rendered in ${duration}ms (string mode)`);
595
+ }
596
+ return html;
597
+ } catch (error) {
598
+ throw error;
599
+ }
600
+ }
601
+ /**
602
+ * Modern streaming SSR using renderToPipeableStream
603
+ */
604
+ async renderToStream(viewPath, data = {}, res, head) {
605
+ const startTime = Date.now();
606
+ let shellReadyTime = 0;
607
+ try {
608
+ let template = this.template;
609
+ if (this.vite) {
610
+ template = await this.vite.transformIndexHtml("/", template);
611
+ }
612
+ const templateParts = this.templateParser.parseTemplate(template);
613
+ let renderModule;
614
+ if (this.vite) {
615
+ renderModule = await this.vite.ssrLoadModule("/src/entry-server.tsx");
616
+ } else {
617
+ if (this.serverManifest) {
618
+ const manifestEntry = Object.entries(this.serverManifest).find(([key, value]) => value.isEntry && key.includes("entry-server"));
619
+ if (manifestEntry) {
620
+ const [, entry] = manifestEntry;
621
+ const serverPath = path.join(process.cwd(), "dist/server", entry.file);
622
+ renderModule = await import(serverPath);
623
+ } else {
624
+ throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
625
+ }
626
+ } else {
627
+ throw new Error("Server bundle not found in manifest. Run `pnpm build:server` to generate the server bundle.");
628
+ }
629
+ }
630
+ const { data: pageData, __context: context } = data;
631
+ const inlineScripts = this.templateParser.buildInlineScripts(pageData, context, viewPath);
632
+ const clientScript = this.templateParser.getClientScriptTag(this.isDevelopment, this.manifest);
633
+ const stylesheetTags = this.templateParser.getStylesheetTags(this.isDevelopment, this.manifest);
634
+ const headTags = this.templateParser.buildHeadTags(head);
635
+ let didError = false;
636
+ const { pipe, abort } = renderModule.renderComponentStream(viewPath, data, {
637
+ onShellReady: /* @__PURE__ */ __name(() => {
638
+ shellReadyTime = Date.now();
639
+ res.statusCode = didError ? 500 : 200;
640
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
641
+ let htmlStart = templateParts.htmlStart;
642
+ htmlStart = htmlStart.replace("<!--styles-->", stylesheetTags);
643
+ htmlStart = htmlStart.replace("<!--head-meta-->", headTags);
644
+ res.write(htmlStart);
645
+ res.write(templateParts.rootStart);
646
+ pipe(res);
647
+ if (this.isDevelopment) {
648
+ const ttfb = shellReadyTime - startTime;
649
+ this.logger.log(`[SSR] ${viewPath} shell ready in ${ttfb}ms (stream mode - TTFB)`);
650
+ }
651
+ }, "onShellReady"),
652
+ onShellError: /* @__PURE__ */ __name((error) => {
653
+ this.streamingErrorHandler.handleShellError(error, res, viewPath, this.isDevelopment);
654
+ }, "onShellError"),
655
+ onError: /* @__PURE__ */ __name((error) => {
656
+ didError = true;
657
+ this.streamingErrorHandler.handleStreamError(error, viewPath);
658
+ }, "onError"),
659
+ onAllReady: /* @__PURE__ */ __name(() => {
660
+ res.write(inlineScripts);
661
+ res.write(clientScript);
662
+ res.write(templateParts.rootEnd);
663
+ res.write(templateParts.htmlEnd);
664
+ res.end();
665
+ if (this.isDevelopment) {
666
+ const totalTime = Date.now() - startTime;
667
+ const streamTime = Date.now() - shellReadyTime;
668
+ this.logger.log(`[SSR] ${viewPath} streaming complete in ${totalTime}ms total (${streamTime}ms streaming)`);
669
+ }
670
+ }, "onAllReady")
671
+ });
672
+ res.on("close", () => {
673
+ abort();
674
+ });
675
+ } catch (error) {
676
+ this.streamingErrorHandler.handleShellError(error, res, viewPath, this.isDevelopment);
677
+ }
678
+ }
679
+ };
680
+ exports.RenderService = _ts_decorate3([
681
+ common.Injectable(),
682
+ _ts_param2(2, common.Optional()),
683
+ _ts_param2(2, common.Inject("SSR_MODE")),
684
+ _ts_param2(3, common.Optional()),
685
+ _ts_param2(3, common.Inject("DEFAULT_HEAD")),
686
+ _ts_metadata2("design:type", Function),
687
+ _ts_metadata2("design:paramtypes", [
688
+ typeof exports.TemplateParserService === "undefined" ? Object : exports.TemplateParserService,
689
+ typeof exports.StreamingErrorHandler === "undefined" ? Object : exports.StreamingErrorHandler,
690
+ typeof SSRMode === "undefined" ? Object : SSRMode,
691
+ typeof HeadData === "undefined" ? Object : HeadData
692
+ ])
693
+ ], exports.RenderService);
694
+ var RENDER_KEY = "render";
695
+
696
+ // src/render/render.interceptor.ts
697
+ function _ts_decorate4(decorators, target, key, desc) {
698
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
699
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
700
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
701
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
702
+ }
703
+ __name(_ts_decorate4, "_ts_decorate");
704
+ function _ts_metadata3(k, v) {
705
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
706
+ }
707
+ __name(_ts_metadata3, "_ts_metadata");
708
+ function isRenderResponse(data) {
709
+ return data && typeof data === "object" && "props" in data;
710
+ }
711
+ __name(isRenderResponse, "isRenderResponse");
712
+ exports.RenderInterceptor = class RenderInterceptor {
713
+ static {
714
+ __name(this, "RenderInterceptor");
715
+ }
716
+ reflector;
717
+ renderService;
718
+ constructor(reflector, renderService) {
719
+ this.reflector = reflector;
720
+ this.renderService = renderService;
721
+ }
722
+ intercept(context, next) {
723
+ const viewPath = this.reflector.get(RENDER_KEY, context.getHandler());
724
+ if (!viewPath) {
725
+ return next.handle();
726
+ }
727
+ return next.handle().pipe(operators.switchMap(async (data) => {
728
+ const httpContext = context.switchToHttp();
729
+ const request = httpContext.getRequest();
730
+ const response = httpContext.getResponse();
731
+ const renderContext = {
732
+ url: request.url,
733
+ path: request.path,
734
+ query: request.query,
735
+ params: request.params,
736
+ userAgent: request.headers["user-agent"],
737
+ acceptLanguage: request.headers["accept-language"],
738
+ referer: request.headers.referer
739
+ };
740
+ const renderResponse = isRenderResponse(data) ? data : {
741
+ props: data
742
+ };
743
+ const fullData = {
744
+ data: renderResponse.props,
745
+ __context: renderContext
746
+ };
747
+ try {
748
+ const html = await this.renderService.render(viewPath, fullData, response, renderResponse.head);
749
+ if (html !== void 0) {
750
+ response.type("text/html");
751
+ return html;
752
+ }
753
+ return;
754
+ } catch (error) {
755
+ throw error;
756
+ }
757
+ }));
758
+ }
759
+ };
760
+ exports.RenderInterceptor = _ts_decorate4([
761
+ common.Injectable(),
762
+ _ts_metadata3("design:type", Function),
763
+ _ts_metadata3("design:paramtypes", [
764
+ typeof core.Reflector === "undefined" ? Object : core.Reflector,
765
+ typeof exports.RenderService === "undefined" ? Object : exports.RenderService
766
+ ])
767
+ ], exports.RenderInterceptor);
768
+ function _ts_decorate5(decorators, target, key, desc) {
769
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
770
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
771
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
772
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
773
+ }
774
+ __name(_ts_decorate5, "_ts_decorate");
775
+ function _ts_metadata4(k, v) {
776
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
777
+ }
778
+ __name(_ts_metadata4, "_ts_metadata");
779
+ function _ts_param3(paramIndex, decorator) {
780
+ return function(target, key) {
781
+ decorator(target, key, paramIndex);
782
+ };
783
+ }
784
+ __name(_ts_param3, "_ts_param");
785
+ var ViteInitializerService = class _ViteInitializerService {
786
+ static {
787
+ __name(this, "ViteInitializerService");
788
+ }
789
+ renderService;
790
+ httpAdapterHost;
791
+ logger = new common.Logger(_ViteInitializerService.name);
792
+ viteMode;
793
+ vitePort;
794
+ constructor(renderService, httpAdapterHost, viteConfig) {
795
+ this.renderService = renderService;
796
+ this.httpAdapterHost = httpAdapterHost;
797
+ this.viteMode = viteConfig?.mode || "embedded";
798
+ this.vitePort = viteConfig?.port || 5173;
799
+ }
800
+ async onModuleInit() {
801
+ const isDevelopment = process.env.NODE_ENV !== "production";
802
+ if (isDevelopment) {
803
+ await this.setupDevelopmentMode();
804
+ } else {
805
+ this.setupProductionMode();
806
+ }
807
+ }
808
+ async setupDevelopmentMode() {
809
+ try {
810
+ const { createServer: createViteServer } = await import('vite');
811
+ const vite = await createViteServer({
812
+ server: {
813
+ middlewareMode: true
814
+ },
815
+ appType: "custom"
816
+ });
817
+ this.renderService.setViteServer(vite);
818
+ if (this.viteMode === "embedded") {
819
+ await this.mountViteMiddleware(vite);
820
+ } else if (this.viteMode === "proxy") {
821
+ await this.setupViteProxy();
822
+ }
823
+ this.logger.log(`\u2713 Vite initialized for SSR (mode: ${this.viteMode})`);
824
+ } catch (error) {
825
+ this.logger.warn(`Failed to initialize Vite: ${error.message}. Make sure vite is installed.`);
826
+ }
827
+ }
828
+ async mountViteMiddleware(vite) {
829
+ try {
830
+ const httpAdapter = this.httpAdapterHost.httpAdapter;
831
+ if (!httpAdapter) {
832
+ this.logger.warn("HTTP adapter not available, skipping Vite middleware setup");
833
+ return;
834
+ }
835
+ const app = httpAdapter.getInstance();
836
+ app.use(vite.middlewares);
837
+ this.logger.log(`\u2713 Vite middleware mounted (embedded mode with HMR)`);
838
+ } catch (error) {
839
+ this.logger.warn(`Failed to mount Vite middleware: ${error.message}`);
840
+ }
841
+ }
842
+ async setupViteProxy() {
843
+ try {
844
+ const httpAdapter = this.httpAdapterHost.httpAdapter;
845
+ if (!httpAdapter) {
846
+ this.logger.warn("HTTP adapter not available, skipping Vite proxy setup");
847
+ return;
848
+ }
849
+ const app = httpAdapter.getInstance();
850
+ const { createProxyMiddleware } = await import('http-proxy-middleware');
851
+ const viteProxy = createProxyMiddleware({
852
+ target: `http://localhost:${this.vitePort}`,
853
+ changeOrigin: true,
854
+ ws: true,
855
+ pathFilter: /* @__PURE__ */ __name((pathname) => {
856
+ return pathname.startsWith("/src/") || pathname.startsWith("/@") || pathname.startsWith("/node_modules/");
857
+ }, "pathFilter")
858
+ });
859
+ app.use(viteProxy);
860
+ this.logger.log(`\u2713 Vite HMR proxy configured (external Vite on port ${this.vitePort})`);
861
+ } catch (error) {
862
+ this.logger.warn(`Failed to setup Vite proxy: ${error.message}. Make sure http-proxy-middleware is installed.`);
863
+ }
864
+ }
865
+ setupProductionMode() {
866
+ try {
867
+ const httpAdapter = this.httpAdapterHost.httpAdapter;
868
+ if (httpAdapter) {
869
+ const app = httpAdapter.getInstance();
870
+ const { join: join2 } = __require("path");
871
+ const express = __require("express");
872
+ app.use(express.static(join2(process.cwd(), "dist/client"), {
873
+ index: false,
874
+ maxAge: "1y"
875
+ }));
876
+ this.logger.log("\u2713 Static assets configured (dist/client)");
877
+ }
878
+ } catch (error) {
879
+ this.logger.warn(`Failed to setup static assets: ${error.message}`);
880
+ }
881
+ }
882
+ };
883
+ ViteInitializerService = _ts_decorate5([
884
+ common.Injectable(),
885
+ _ts_param3(2, common.Optional()),
886
+ _ts_param3(2, common.Inject("VITE_CONFIG")),
887
+ _ts_metadata4("design:type", Function),
888
+ _ts_metadata4("design:paramtypes", [
889
+ typeof exports.RenderService === "undefined" ? Object : exports.RenderService,
890
+ typeof core.HttpAdapterHost === "undefined" ? Object : core.HttpAdapterHost,
891
+ typeof ViteConfig === "undefined" ? Object : ViteConfig
892
+ ])
893
+ ], ViteInitializerService);
894
+
895
+ // src/render/render.module.ts
896
+ function _ts_decorate6(decorators, target, key, desc) {
897
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
898
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
899
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
900
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
901
+ }
902
+ __name(_ts_decorate6, "_ts_decorate");
903
+ exports.RenderModule = class _RenderModule {
904
+ static {
905
+ __name(this, "RenderModule");
906
+ }
907
+ /**
908
+ * Register the render module with optional configuration
909
+ *
910
+ * @param config - Optional render configuration
911
+ * @returns Dynamic module
912
+ *
913
+ * @example
914
+ * ```ts
915
+ * // Zero config - embedded mode by default (simplest)
916
+ * @Module({
917
+ * imports: [RenderModule],
918
+ * })
919
+ *
920
+ * // Enable HMR with proxy mode
921
+ * @Module({
922
+ * imports: [
923
+ * RenderModule.register({
924
+ * vite: { mode: 'proxy', port: 5173 }
925
+ * })
926
+ * ],
927
+ * })
928
+ *
929
+ * // Enable streaming SSR
930
+ * RenderModule.register({ mode: 'stream' })
931
+ *
932
+ * // Custom error pages
933
+ * RenderModule.register({
934
+ * mode: 'stream',
935
+ * errorPageDevelopment: MyCustomDevErrorPage,
936
+ * errorPageProduction: MyCustomProdErrorPage,
937
+ * })
938
+ * ```
939
+ */
940
+ static register(config) {
941
+ const providers = [
942
+ exports.RenderService,
943
+ exports.TemplateParserService,
944
+ exports.StreamingErrorHandler,
945
+ ViteInitializerService,
946
+ {
947
+ provide: core.APP_INTERCEPTOR,
948
+ useClass: exports.RenderInterceptor
949
+ }
950
+ ];
951
+ providers.push({
952
+ provide: "VITE_CONFIG",
953
+ useValue: config?.vite || {}
954
+ });
955
+ if (config?.mode) {
956
+ providers.push({
957
+ provide: "SSR_MODE",
958
+ useValue: config.mode
959
+ });
960
+ }
961
+ if (config?.errorPageDevelopment) {
962
+ providers.push({
963
+ provide: "ERROR_PAGE_DEVELOPMENT",
964
+ useValue: config.errorPageDevelopment
965
+ });
966
+ }
967
+ if (config?.errorPageProduction) {
968
+ providers.push({
969
+ provide: "ERROR_PAGE_PRODUCTION",
970
+ useValue: config.errorPageProduction
971
+ });
972
+ }
973
+ if (config?.defaultHead) {
974
+ providers.push({
975
+ provide: "DEFAULT_HEAD",
976
+ useValue: config.defaultHead
977
+ });
978
+ }
979
+ return {
980
+ global: true,
981
+ module: _RenderModule,
982
+ providers,
983
+ exports: [
984
+ exports.RenderService
985
+ ]
986
+ };
987
+ }
988
+ /**
989
+ * Register the render module asynchronously with dynamic configuration
990
+ *
991
+ * Use this when you need to inject services (e.g., load config from database)
992
+ *
993
+ * @param options - Async configuration options
994
+ * @returns Dynamic module
995
+ *
996
+ * @example
997
+ * ```ts
998
+ * // Load default head from database
999
+ * RenderModule.registerAsync({
1000
+ * imports: [TenantModule],
1001
+ * inject: [TenantRepository],
1002
+ * useFactory: async (tenantRepo: TenantRepository) => {
1003
+ * const tenant = await tenantRepo.findDefaultTenant();
1004
+ * return {
1005
+ * defaultHead: {
1006
+ * title: tenant.appName,
1007
+ * description: tenant.description,
1008
+ * links: [
1009
+ * { rel: 'icon', href: tenant.favicon }
1010
+ * ]
1011
+ * }
1012
+ * };
1013
+ * }
1014
+ * })
1015
+ * ```
1016
+ */
1017
+ static registerAsync(options) {
1018
+ const configProvider = {
1019
+ provide: "RENDER_CONFIG",
1020
+ useFactory: options.useFactory,
1021
+ inject: options.inject || []
1022
+ };
1023
+ const providers = [
1024
+ configProvider,
1025
+ exports.RenderService,
1026
+ exports.TemplateParserService,
1027
+ exports.StreamingErrorHandler,
1028
+ ViteInitializerService,
1029
+ {
1030
+ provide: core.APP_INTERCEPTOR,
1031
+ useClass: exports.RenderInterceptor
1032
+ },
1033
+ // Vite configuration provider - reads from config
1034
+ {
1035
+ provide: "VITE_CONFIG",
1036
+ useFactory: /* @__PURE__ */ __name((config) => config?.vite || {}, "useFactory"),
1037
+ inject: [
1038
+ "RENDER_CONFIG"
1039
+ ]
1040
+ },
1041
+ // SSR mode provider - reads from config
1042
+ {
1043
+ provide: "SSR_MODE",
1044
+ useFactory: /* @__PURE__ */ __name((config) => config?.mode, "useFactory"),
1045
+ inject: [
1046
+ "RENDER_CONFIG"
1047
+ ]
1048
+ },
1049
+ // Error page providers - read from config
1050
+ {
1051
+ provide: "ERROR_PAGE_DEVELOPMENT",
1052
+ useFactory: /* @__PURE__ */ __name((config) => config?.errorPageDevelopment, "useFactory"),
1053
+ inject: [
1054
+ "RENDER_CONFIG"
1055
+ ]
1056
+ },
1057
+ {
1058
+ provide: "ERROR_PAGE_PRODUCTION",
1059
+ useFactory: /* @__PURE__ */ __name((config) => config?.errorPageProduction, "useFactory"),
1060
+ inject: [
1061
+ "RENDER_CONFIG"
1062
+ ]
1063
+ },
1064
+ // Default head provider - reads from config
1065
+ {
1066
+ provide: "DEFAULT_HEAD",
1067
+ useFactory: /* @__PURE__ */ __name((config) => config?.defaultHead, "useFactory"),
1068
+ inject: [
1069
+ "RENDER_CONFIG"
1070
+ ]
1071
+ }
1072
+ ];
1073
+ return {
1074
+ global: true,
1075
+ module: _RenderModule,
1076
+ imports: options.imports || [],
1077
+ providers,
1078
+ exports: [
1079
+ exports.RenderService
1080
+ ]
1081
+ };
1082
+ }
1083
+ };
1084
+ exports.RenderModule = _ts_decorate6([
1085
+ common.Global(),
1086
+ common.Module({
1087
+ providers: [
1088
+ exports.RenderService,
1089
+ exports.TemplateParserService,
1090
+ exports.StreamingErrorHandler,
1091
+ ViteInitializerService,
1092
+ {
1093
+ provide: core.APP_INTERCEPTOR,
1094
+ useClass: exports.RenderInterceptor
1095
+ },
1096
+ {
1097
+ provide: "VITE_CONFIG",
1098
+ useValue: {}
1099
+ }
1100
+ ],
1101
+ exports: [
1102
+ exports.RenderService
1103
+ ]
1104
+ })
1105
+ ], exports.RenderModule);
1106
+
1107
+ exports.ErrorPageDevelopment = ErrorPageDevelopment;
1108
+ exports.ErrorPageProduction = ErrorPageProduction;
1109
+ //# sourceMappingURL=index.js.map
1110
+ //# sourceMappingURL=index.js.map