@moostjs/vite 0.6.30 → 0.6.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -40,6 +40,32 @@ const DEFAULT_SSR_OUTLET = "<!--ssr-outlet-->";
40
40
  const DEFAULT_SSR_STATE = "<!--ssr-state-->";
41
41
  const DEFAULT_SSR_HEAD = "<!--ssr-head-->";
42
42
  /**
43
+ * Invokes the SSR `render()` for a page request. Shared by all three render call
44
+ * sites so the render contract stays identical across them:
45
+ * - always passes the page request context ({@link TSSRRenderContext}) as the
46
+ * second `render()` argument;
47
+ * - when a Moost HTTP adapter is provided (and supports it), runs the render
48
+ * inside an HTTP event context seeded from the real `(req, res)` pair, so
49
+ * SSR-time `fetch('/api/...')` self-calls inherit the viewer's identity
50
+ * headers (`forwardHeaders`) instead of arriving anonymous, and `Set-Cookie`
51
+ * headers from those self-calls are drained onto the page response;
52
+ * - degrades to a plain `render(url, ctx)` call when the adapter is absent or
53
+ * predates `withHttpContext`.
54
+ */ async function renderSSRPage(opts) {
55
+ const { render, url, req, res, http } = opts;
56
+ const ctx = {
57
+ headers: req.headers,
58
+ method: req.method || "GET",
59
+ req
60
+ };
61
+ if (http && typeof http.withHttpContext === "function") {
62
+ const { result, response } = await http.withHttpContext(req, res, () => render(url, ctx));
63
+ for (const cookie of response.getSetCookieStrings()) res.appendHeader("set-cookie", cookie);
64
+ return result;
65
+ }
66
+ return render(url, ctx);
67
+ }
68
+ /**
43
69
  * Applies an SSR render result to the HTTP response: sets the status code and
44
70
  * headers, then substitutes the outlet, state and head markers into the HTML
45
71
  * template. Shared by all three render call sites (the dev middleware, the dev
@@ -390,6 +416,14 @@ function moostVite(options) {
390
416
  let moostMiddleware = null;
391
417
  let localFetchTeardown = null;
392
418
  /**
419
+ * Live ref to the booted MoostHttp instance (from Vite's SSR module graph).
420
+ * Used to run SSR renders inside an HTTP event context (`withHttpContext`)
421
+ * so SSR self-fetches inherit the page request's identity. Exposed on the
422
+ * resolved config for the `createSSRServer()` dev branch; re-pointed on every
423
+ * boot, cleared on eject.
424
+ */ const moostHttpRef = { current: null };
425
+ const ssrForwarding = options.ssrFetchForwarding !== false;
426
+ /**
393
427
  * Boot-identity stamps (dev-only "mongrel state" diagnostic — a stale pipeline
394
428
  * presents as security middleware silently switched off). `bootGeneration` is
395
429
  * bumped on every eject; `bootingGeneration` records which generation the
@@ -407,6 +441,7 @@ function moostVite(options) {
407
441
  logger.log(`🔌 Overtaking HTTP.listen`);
408
442
  if (bootingGeneration !== bootGeneration) logger.error(`⚠️ A stale Moost boot captured the HTTP middleware (boot generation ${bootingGeneration}, latest ${bootGeneration}) — an HMR reload race; a follow-up reload will replace it.`);
409
443
  httpCaptured = true;
444
+ moostHttpRef.current = this;
410
445
  if (options.middleware) moostMiddleware = this.getServerCb((req) => {
411
446
  pendingNextMap.get(req)?.();
412
447
  });
@@ -457,6 +492,7 @@ function moostVite(options) {
457
492
  */ const ejectApp = (cleanupInstances) => {
458
493
  bootGeneration++;
459
494
  moostMiddleware = null;
495
+ moostHttpRef.current = null;
460
496
  if (localFetchTeardown) {
461
497
  localFetchTeardown();
462
498
  localFetchTeardown = null;
@@ -476,7 +512,8 @@ function moostVite(options) {
476
512
  const serverDefines = {
477
513
  "process.env.MOOST_DEFERRED_ENV": "\"production\"",
478
514
  __MOOST_ENTRY__: JSON.stringify(`./${entryKey}.js`),
479
- __MOOST_PREFIX__: JSON.stringify(prefixes ?? null)
515
+ __MOOST_PREFIX__: JSON.stringify(prefixes ?? null),
516
+ __MOOST_SSR_FORWARDING__: JSON.stringify(ssrForwarding)
480
517
  };
481
518
  const ssrInput = {
482
519
  server: options.serverEntry || generatedServerEntry(cfg.root),
@@ -578,8 +615,10 @@ function moostVite(options) {
578
615
  port: options.port,
579
616
  ssrOutlet: options.ssrOutlet,
580
617
  ssrState: options.ssrState,
581
- ssrHead: options.ssrHead
618
+ ssrHead: options.ssrHead,
619
+ ssrFetchForwarding: options.ssrFetchForwarding
582
620
  };
621
+ config.__moostViteHttpRef = moostHttpRef;
583
622
  },
584
623
  async transform(code, id) {
585
624
  if (!id.endsWith(".ts")) return null;
@@ -712,7 +751,13 @@ function moostVite(options) {
712
751
  let template = await fs.readFile((0, node_path.resolve)(server.config.root, "index.html"), "utf8");
713
752
  template = await server.transformIndexHtml(url, template);
714
753
  const { render } = await server.ssrLoadModule(options.ssrEntry);
715
- const result = await render(url);
754
+ const result = await renderSSRPage({
755
+ render,
756
+ url,
757
+ req,
758
+ res,
759
+ http: ssrForwarding ? moostHttpRef.current : null
760
+ });
716
761
  sendSSRResponse(res, template, {
717
762
  ssrOutlet,
718
763
  ssrState,
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { PluginOption } from 'vite';
2
+ import { IncomingMessage } from 'node:http';
2
3
 
3
4
  interface TMoostViteDevOptions {
4
5
  /**
@@ -76,6 +77,20 @@ interface TMoostViteDevOptions {
76
77
  * Default: `true`.
77
78
  */
78
79
  ssrFetch?: boolean;
80
+ /**
81
+ * Run each SSR render inside an HTTP event context seeded from the incoming
82
+ * page request. SSR-time `fetch('/api/...')` self-calls then inherit the
83
+ * viewer's identity headers (authorization, cookie, accept-language,
84
+ * x-forwarded-for, x-request-id — see the HTTP adapter's `forwardHeaders`
85
+ * option) instead of arriving anonymous, and `Set-Cookie` headers they
86
+ * produce are drained onto the page response. Applies in dev and is baked
87
+ * into the generated production server.
88
+ *
89
+ * Set to `false` to keep SSR self-calls anonymous.
90
+ *
91
+ * Default: `true`.
92
+ */
93
+ ssrFetchForwarding?: boolean;
79
94
  /**
80
95
  * Run Moost as Connect middleware instead of taking over the server.
81
96
  * When enabled, Moost runs first and unmatched requests fall through to
@@ -161,4 +176,44 @@ interface TMoostViteDevOptions {
161
176
  }
162
177
  declare function moostVite(options: TMoostViteDevOptions): PluginOption;
163
178
 
179
+ /**
180
+ * The value an SSR `render(url)` function may return. Only `html` is required;
181
+ * every other field is optional, so a render returning `{ html }` (or
182
+ * `{ html, state }`) keeps working unchanged.
183
+ */
184
+ interface TSSRRenderResult {
185
+ /** Server-rendered app markup, substituted into the `ssrOutlet` marker. */
186
+ html: string;
187
+ /**
188
+ * Serialized app state. Wrapped in `<script>window.__SSR_STATE__=…</script>`
189
+ * and substituted into the `ssrState` marker (nothing is emitted when absent).
190
+ */
191
+ state?: string;
192
+ /**
193
+ * Ready-to-insert `<head>` tags (`<title>`, `<meta>`, canonical, Open Graph,
194
+ * JSON-LD, …), substituted verbatim into the `ssrHead` marker. This is exactly
195
+ * the shape head managers emit (e.g. unhead's `renderSSRHead(head).headTags`).
196
+ */
197
+ head?: string;
198
+ /** HTTP status code for the response (default `200`) — e.g. `404` for a soft-404, `301` for a redirect. */
199
+ status?: number;
200
+ /** Extra response headers — e.g. `cache-control`, or `location` alongside `status: 301`. */
201
+ headers?: Record<string, string>;
202
+ }
203
+ /**
204
+ * Context of the incoming page request, passed as the second argument to the
205
+ * SSR `render()` entry. Additive: entries typed `render(url)` keep working.
206
+ */
207
+ interface TSSRRenderContext {
208
+ /** Raw request headers of the page request (node `IncomingMessage.headers`). */
209
+ headers: IncomingMessage['headers'];
210
+ /** HTTP method of the page request (the SSR fallbacks only render `GET` today). */
211
+ method: string;
212
+ /** Escape hatch for everything else (socket address, etc.). */
213
+ req: IncomingMessage;
214
+ }
215
+ /** The SSR entry contract: `render(url, ctx?)`. `ctx` is new and optional. */
216
+ type TSSRRender = (url: string, ctx?: TSSRRenderContext) => Promise<TSSRRenderResult> | TSSRRenderResult;
217
+
164
218
  export { moostVite };
219
+ export type { TMoostViteDevOptions, TSSRRender, TSSRRenderContext, TSSRRenderResult };
package/dist/index.mjs CHANGED
@@ -11,6 +11,32 @@ const DEFAULT_SSR_OUTLET = "<!--ssr-outlet-->";
11
11
  const DEFAULT_SSR_STATE = "<!--ssr-state-->";
12
12
  const DEFAULT_SSR_HEAD = "<!--ssr-head-->";
13
13
  /**
14
+ * Invokes the SSR `render()` for a page request. Shared by all three render call
15
+ * sites so the render contract stays identical across them:
16
+ * - always passes the page request context ({@link TSSRRenderContext}) as the
17
+ * second `render()` argument;
18
+ * - when a Moost HTTP adapter is provided (and supports it), runs the render
19
+ * inside an HTTP event context seeded from the real `(req, res)` pair, so
20
+ * SSR-time `fetch('/api/...')` self-calls inherit the viewer's identity
21
+ * headers (`forwardHeaders`) instead of arriving anonymous, and `Set-Cookie`
22
+ * headers from those self-calls are drained onto the page response;
23
+ * - degrades to a plain `render(url, ctx)` call when the adapter is absent or
24
+ * predates `withHttpContext`.
25
+ */ async function renderSSRPage(opts) {
26
+ const { render, url, req, res, http } = opts;
27
+ const ctx = {
28
+ headers: req.headers,
29
+ method: req.method || "GET",
30
+ req
31
+ };
32
+ if (http && typeof http.withHttpContext === "function") {
33
+ const { result, response } = await http.withHttpContext(req, res, () => render(url, ctx));
34
+ for (const cookie of response.getSetCookieStrings()) res.appendHeader("set-cookie", cookie);
35
+ return result;
36
+ }
37
+ return render(url, ctx);
38
+ }
39
+ /**
14
40
  * Applies an SSR render result to the HTTP response: sets the status code and
15
41
  * headers, then substitutes the outlet, state and head markers into the HTML
16
42
  * template. Shared by all three render call sites (the dev middleware, the dev
@@ -359,6 +385,14 @@ function moostVite(options) {
359
385
  let moostMiddleware = null;
360
386
  let localFetchTeardown = null;
361
387
  /**
388
+ * Live ref to the booted MoostHttp instance (from Vite's SSR module graph).
389
+ * Used to run SSR renders inside an HTTP event context (`withHttpContext`)
390
+ * so SSR self-fetches inherit the page request's identity. Exposed on the
391
+ * resolved config for the `createSSRServer()` dev branch; re-pointed on every
392
+ * boot, cleared on eject.
393
+ */ const moostHttpRef = { current: null };
394
+ const ssrForwarding = options.ssrFetchForwarding !== false;
395
+ /**
362
396
  * Boot-identity stamps (dev-only "mongrel state" diagnostic — a stale pipeline
363
397
  * presents as security middleware silently switched off). `bootGeneration` is
364
398
  * bumped on every eject; `bootingGeneration` records which generation the
@@ -376,6 +410,7 @@ function moostVite(options) {
376
410
  logger.log(`🔌 Overtaking HTTP.listen`);
377
411
  if (bootingGeneration !== bootGeneration) logger.error(`⚠️ A stale Moost boot captured the HTTP middleware (boot generation ${bootingGeneration}, latest ${bootGeneration}) — an HMR reload race; a follow-up reload will replace it.`);
378
412
  httpCaptured = true;
413
+ moostHttpRef.current = this;
379
414
  if (options.middleware) moostMiddleware = this.getServerCb((req) => {
380
415
  pendingNextMap.get(req)?.();
381
416
  });
@@ -426,6 +461,7 @@ function moostVite(options) {
426
461
  */ const ejectApp = (cleanupInstances) => {
427
462
  bootGeneration++;
428
463
  moostMiddleware = null;
464
+ moostHttpRef.current = null;
429
465
  if (localFetchTeardown) {
430
466
  localFetchTeardown();
431
467
  localFetchTeardown = null;
@@ -445,7 +481,8 @@ function moostVite(options) {
445
481
  const serverDefines = {
446
482
  "process.env.MOOST_DEFERRED_ENV": "\"production\"",
447
483
  __MOOST_ENTRY__: JSON.stringify(`./${entryKey}.js`),
448
- __MOOST_PREFIX__: JSON.stringify(prefixes ?? null)
484
+ __MOOST_PREFIX__: JSON.stringify(prefixes ?? null),
485
+ __MOOST_SSR_FORWARDING__: JSON.stringify(ssrForwarding)
449
486
  };
450
487
  const ssrInput = {
451
488
  server: options.serverEntry || generatedServerEntry(cfg.root),
@@ -547,8 +584,10 @@ function moostVite(options) {
547
584
  port: options.port,
548
585
  ssrOutlet: options.ssrOutlet,
549
586
  ssrState: options.ssrState,
550
- ssrHead: options.ssrHead
587
+ ssrHead: options.ssrHead,
588
+ ssrFetchForwarding: options.ssrFetchForwarding
551
589
  };
590
+ config.__moostViteHttpRef = moostHttpRef;
552
591
  },
553
592
  async transform(code, id) {
554
593
  if (!id.endsWith(".ts")) return null;
@@ -673,7 +712,13 @@ function moostVite(options) {
673
712
  let template = await fs.readFile(resolve(server.config.root, "index.html"), "utf8");
674
713
  template = await server.transformIndexHtml(url, template);
675
714
  const { render } = await server.ssrLoadModule(options.ssrEntry);
676
- const result = await render(url);
715
+ const result = await renderSSRPage({
716
+ render,
717
+ url,
718
+ req,
719
+ res,
720
+ http: ssrForwarding ? moostHttpRef.current : null
721
+ });
677
722
  sendSSRResponse(res, template, {
678
723
  ssrOutlet,
679
724
  ssrState,
@@ -7,6 +7,32 @@ const DEFAULT_SSR_OUTLET = "<!--ssr-outlet-->";
7
7
  const DEFAULT_SSR_STATE = "<!--ssr-state-->";
8
8
  const DEFAULT_SSR_HEAD = "<!--ssr-head-->";
9
9
  /**
10
+ * Invokes the SSR `render()` for a page request. Shared by all three render call
11
+ * sites so the render contract stays identical across them:
12
+ * - always passes the page request context ({@link TSSRRenderContext}) as the
13
+ * second `render()` argument;
14
+ * - when a Moost HTTP adapter is provided (and supports it), runs the render
15
+ * inside an HTTP event context seeded from the real `(req, res)` pair, so
16
+ * SSR-time `fetch('/api/...')` self-calls inherit the viewer's identity
17
+ * headers (`forwardHeaders`) instead of arriving anonymous, and `Set-Cookie`
18
+ * headers from those self-calls are drained onto the page response;
19
+ * - degrades to a plain `render(url, ctx)` call when the adapter is absent or
20
+ * predates `withHttpContext`.
21
+ */ async function renderSSRPage(opts) {
22
+ const { render, url, req, res, http } = opts;
23
+ const ctx = {
24
+ headers: req.headers,
25
+ method: req.method || "GET",
26
+ req
27
+ };
28
+ if (http && typeof http.withHttpContext === "function") {
29
+ const { result, response } = await http.withHttpContext(req, res, () => render(url, ctx));
30
+ for (const cookie of response.getSetCookieStrings()) res.appendHeader("set-cookie", cookie);
31
+ return result;
32
+ }
33
+ return render(url, ctx);
34
+ }
35
+ /**
10
36
  * Applies an SSR render result to the HTTP response: sets the status code and
11
37
  * headers, then substitutes the outlet, state and head markers into the HTML
12
38
  * template. Shared by all three render call sites (the dev middleware, the dev
@@ -72,6 +98,8 @@ async function createSSRServer(options) {
72
98
  const ssrOutlet = config.ssrOutlet || DEFAULT_SSR_OUTLET;
73
99
  const ssrState = config.ssrState || DEFAULT_SSR_STATE;
74
100
  const ssrHead = config.ssrHead || DEFAULT_SSR_HEAD;
101
+ const ssrForwarding = config.ssrFetchForwarding !== false;
102
+ const httpRef = vite.config.__moostViteHttpRef;
75
103
  let ssrFallback = null;
76
104
  if (ssrEntry) {
77
105
  const fs = await import("node:fs/promises");
@@ -83,7 +111,13 @@ async function createSSRServer(options) {
83
111
  let template = await fs.readFile(path.resolve(vite.config.root, "index.html"), "utf8");
84
112
  template = await vite.transformIndexHtml(url, template);
85
113
  const { render } = await vite.ssrLoadModule(ssrEntry);
86
- const result = await render(url);
114
+ const result = await renderSSRPage({
115
+ render,
116
+ url,
117
+ req,
118
+ res,
119
+ http: ssrForwarding ? httpRef?.current : null
120
+ });
87
121
  sendSSRResponse(res, template, {
88
122
  ssrOutlet,
89
123
  ssrState,
@@ -117,6 +151,7 @@ async function createSSRServer(options) {
117
151
  const ssrState = opts.ssrState || (__MOOST_SSR_STATE__ !== void 0 ? __MOOST_SSR_STATE__ : DEFAULT_SSR_STATE);
118
152
  const ssrHead = opts.ssrHead || (__MOOST_SSR_HEAD__ !== void 0 ? __MOOST_SSR_HEAD__ : DEFAULT_SSR_HEAD);
119
153
  const prefixes = normalizePrefixes(opts.prefix ?? __MOOST_PREFIX__);
154
+ const ssrForwarding = opts.ssrFetchForwarding ?? __MOOST_SSR_FORWARDING__ ?? true;
120
155
  const defaultPort = opts.port || Number(process.env.PORT) || 3e3;
121
156
  const template = await fs.readFile(path.resolve(clientDir, "index.html"), "utf8");
122
157
  let render = null;
@@ -165,7 +200,13 @@ async function createSSRServer(options) {
165
200
  }
166
201
  try {
167
202
  if (render) {
168
- const result = await render(url);
203
+ const result = await renderSSRPage({
204
+ render,
205
+ url,
206
+ req,
207
+ res,
208
+ http: ssrForwarding ? moostHttpRef.instance : null
209
+ });
169
210
  sendSSRResponse(res, template, {
170
211
  ssrOutlet,
171
212
  ssrState,
@@ -24,6 +24,20 @@ interface TSSRRenderResult {
24
24
  /** Extra response headers — e.g. `cache-control`, or `location` alongside `status: 301`. */
25
25
  headers?: Record<string, string>;
26
26
  }
27
+ /**
28
+ * Context of the incoming page request, passed as the second argument to the
29
+ * SSR `render()` entry. Additive: entries typed `render(url)` keep working.
30
+ */
31
+ interface TSSRRenderContext {
32
+ /** Raw request headers of the page request (node `IncomingMessage.headers`). */
33
+ headers: IncomingMessage['headers'];
34
+ /** HTTP method of the page request (the SSR fallbacks only render `GET` today). */
35
+ method: string;
36
+ /** Escape hatch for everything else (socket address, etc.). */
37
+ req: IncomingMessage;
38
+ }
39
+ /** The SSR entry contract: `render(url, ctx?)`. `ctx` is new and optional. */
40
+ type TSSRRender = (url: string, ctx?: TSSRRenderContext) => Promise<TSSRRenderResult> | TSSRRenderResult;
27
41
 
28
42
  type TMiddleware = (req: IncomingMessage, res: ServerResponse, next: () => void) => void;
29
43
  interface TSSRServerOptions {
@@ -48,6 +62,15 @@ interface TSSRServerOptions {
48
62
  ssrState?: string;
49
63
  /** Override: HTML placeholder for SSR-rendered `<head>` tags */
50
64
  ssrHead?: string;
65
+ /**
66
+ * Override: run each SSR render inside an HTTP event context seeded from the
67
+ * incoming page request, so SSR-time `fetch('/api/...')` self-calls inherit
68
+ * the viewer's identity headers (authorization, cookie, accept-language,
69
+ * x-forwarded-for, x-request-id — see the adapter's `forwardHeaders` option)
70
+ * and their `Set-Cookie` headers land on the page response.
71
+ * Set to `false` to keep SSR self-calls anonymous. Default: `true`.
72
+ */
73
+ ssrFetchForwarding?: boolean;
51
74
  }
52
75
  interface TSSRServer {
53
76
  /** Add Connect-compatible middleware (runs in both dev and prod) */
@@ -58,4 +81,4 @@ interface TSSRServer {
58
81
  declare function createSSRServer(options?: TSSRServerOptions): Promise<TSSRServer>;
59
82
 
60
83
  export { createSSRServer };
61
- export type { TSSRRenderResult, TSSRServer, TSSRServerOptions };
84
+ export type { TSSRRender, TSSRRenderContext, TSSRRenderResult, TSSRServer, TSSRServerOptions };
@@ -8,6 +8,32 @@ const DEFAULT_SSR_OUTLET = "<!--ssr-outlet-->";
8
8
  const DEFAULT_SSR_STATE = "<!--ssr-state-->";
9
9
  const DEFAULT_SSR_HEAD = "<!--ssr-head-->";
10
10
  /**
11
+ * Invokes the SSR `render()` for a page request. Shared by all three render call
12
+ * sites so the render contract stays identical across them:
13
+ * - always passes the page request context ({@link TSSRRenderContext}) as the
14
+ * second `render()` argument;
15
+ * - when a Moost HTTP adapter is provided (and supports it), runs the render
16
+ * inside an HTTP event context seeded from the real `(req, res)` pair, so
17
+ * SSR-time `fetch('/api/...')` self-calls inherit the viewer's identity
18
+ * headers (`forwardHeaders`) instead of arriving anonymous, and `Set-Cookie`
19
+ * headers from those self-calls are drained onto the page response;
20
+ * - degrades to a plain `render(url, ctx)` call when the adapter is absent or
21
+ * predates `withHttpContext`.
22
+ */ async function renderSSRPage(opts) {
23
+ const { render, url, req, res, http } = opts;
24
+ const ctx = {
25
+ headers: req.headers,
26
+ method: req.method || "GET",
27
+ req
28
+ };
29
+ if (http && typeof http.withHttpContext === "function") {
30
+ const { result, response } = await http.withHttpContext(req, res, () => render(url, ctx));
31
+ for (const cookie of response.getSetCookieStrings()) res.appendHeader("set-cookie", cookie);
32
+ return result;
33
+ }
34
+ return render(url, ctx);
35
+ }
36
+ /**
11
37
  * Applies an SSR render result to the HTTP response: sets the status code and
12
38
  * headers, then substitutes the outlet, state and head markers into the HTML
13
39
  * template. Shared by all three render call sites (the dev middleware, the dev
@@ -73,6 +99,8 @@ async function createSSRServer(options) {
73
99
  const ssrOutlet = config.ssrOutlet || DEFAULT_SSR_OUTLET;
74
100
  const ssrState = config.ssrState || DEFAULT_SSR_STATE;
75
101
  const ssrHead = config.ssrHead || DEFAULT_SSR_HEAD;
102
+ const ssrForwarding = config.ssrFetchForwarding !== false;
103
+ const httpRef = vite.config.__moostViteHttpRef;
76
104
  let ssrFallback = null;
77
105
  if (ssrEntry) {
78
106
  const fs = await import("node:fs/promises");
@@ -84,7 +112,13 @@ async function createSSRServer(options) {
84
112
  let template = await fs.readFile(path.resolve(vite.config.root, "index.html"), "utf8");
85
113
  template = await vite.transformIndexHtml(url, template);
86
114
  const { render } = await vite.ssrLoadModule(ssrEntry);
87
- const result = await render(url);
115
+ const result = await renderSSRPage({
116
+ render,
117
+ url,
118
+ req,
119
+ res,
120
+ http: ssrForwarding ? httpRef?.current : null
121
+ });
88
122
  sendSSRResponse(res, template, {
89
123
  ssrOutlet,
90
124
  ssrState,
@@ -118,6 +152,7 @@ async function createSSRServer(options) {
118
152
  const ssrState = opts.ssrState || (__MOOST_SSR_STATE__ !== void 0 ? __MOOST_SSR_STATE__ : DEFAULT_SSR_STATE);
119
153
  const ssrHead = opts.ssrHead || (__MOOST_SSR_HEAD__ !== void 0 ? __MOOST_SSR_HEAD__ : DEFAULT_SSR_HEAD);
120
154
  const prefixes = normalizePrefixes(opts.prefix ?? __MOOST_PREFIX__);
155
+ const ssrForwarding = opts.ssrFetchForwarding ?? __MOOST_SSR_FORWARDING__ ?? true;
121
156
  const defaultPort = opts.port || Number(process.env.PORT) || 3e3;
122
157
  const template = await fs.readFile(path.resolve(clientDir, "index.html"), "utf8");
123
158
  let render = null;
@@ -166,7 +201,13 @@ async function createSSRServer(options) {
166
201
  }
167
202
  try {
168
203
  if (render) {
169
- const result = await render(url);
204
+ const result = await renderSSRPage({
205
+ render,
206
+ url,
207
+ req,
208
+ res,
209
+ http: ssrForwarding ? moostHttpRef.instance : null
210
+ });
170
211
  sendSSRResponse(res, template, {
171
212
  ssrOutlet,
172
213
  ssrState,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moostjs/vite",
3
- "version": "0.6.30",
3
+ "version": "0.6.32",
4
4
  "description": "Vite Dev plugin for moostjs",
5
5
  "keywords": [
6
6
  "composables",
@@ -58,8 +58,8 @@
58
58
  "peerDependencies": {
59
59
  "sirv": "^3.0.0",
60
60
  "vite": "^8.0.0",
61
- "@moostjs/event-http": "^0.6.30",
62
- "moost": "^0.6.30"
61
+ "@moostjs/event-http": "^0.6.32",
62
+ "moost": "^0.6.32"
63
63
  },
64
64
  "peerDependenciesMeta": {
65
65
  "sirv": {