@angular/ssr 19.0.0-next.5 → 19.0.0-next.6

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/fesm2022/ssr.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { APP_BASE_HREF, PlatformLocation } from '@angular/common';
2
- import { ɵConsole as _Console, createPlatformFactory, platformCore, ApplicationRef, ɵwhenStable as _whenStable, Compiler, InjectionToken, ɵresetCompiledComponents as _resetCompiledComponents } from '@angular/core';
3
- import { renderModule, renderApplication, INITIAL_CONFIG, ɵINTERNAL_SERVER_PLATFORM_PROVIDERS as _INTERNAL_SERVER_PLATFORM_PROVIDERS, ɵSERVER_CONTEXT as _SERVER_CONTEXT } from '@angular/platform-server';
2
+ import { ɵConsole as _Console, InjectionToken, makeEnvironmentProviders, runInInjectionContext, createPlatformFactory, platformCore, ApplicationRef, ɵwhenStable as _whenStable, Compiler, ɵresetCompiledComponents as _resetCompiledComponents } from '@angular/core';
3
+ import { ɵSERVER_CONTEXT as _SERVER_CONTEXT, renderModule, renderApplication, INITIAL_CONFIG, ɵINTERNAL_SERVER_PLATFORM_PROVIDERS as _INTERNAL_SERVER_PLATFORM_PROVIDERS } from '@angular/platform-server';
4
4
  import { ɵloadChildren as _loadChildren, Router } from '@angular/router';
5
5
  import Critters from '../third_party/critters/index.js';
6
6
 
@@ -217,21 +217,38 @@ function stripIndexHtmlFromURL(url) {
217
217
  * correctly handle route-based rendering.
218
218
  * @param platformProviders - An array of platform providers to be used during the
219
219
  * rendering process.
220
+ * @param serverContext - A string representing the server context, used to provide additional
221
+ * context or metadata during server-side rendering.
220
222
  * @returns A promise that resolves to a string containing the rendered HTML.
221
223
  */
222
- function renderAngular(html, bootstrap, url, platformProviders) {
224
+ function renderAngular(html, bootstrap, url, platformProviders, serverContext) {
225
+ const providers = [
226
+ {
227
+ provide: _SERVER_CONTEXT,
228
+ useValue: serverContext,
229
+ },
230
+ {
231
+ // An Angular Console Provider that does not print a set of predefined logs.
232
+ provide: _Console,
233
+ // Using `useClass` would necessitate decorating `Console` with `@Injectable`,
234
+ // which would require switching from `ts_library` to `ng_module`. This change
235
+ // would also necessitate various patches of `@angular/bazel` to support ESM.
236
+ useFactory: () => new Console(),
237
+ },
238
+ ...platformProviders,
239
+ ];
223
240
  // A request to `http://www.example.com/page/index.html` will render the Angular route corresponding to `http://www.example.com/page`.
224
241
  const urlToRender = stripIndexHtmlFromURL(url).toString();
225
242
  return isNgModule(bootstrap)
226
243
  ? renderModule(bootstrap, {
227
244
  url: urlToRender,
228
245
  document: html,
229
- extraProviders: platformProviders,
246
+ extraProviders: providers,
230
247
  })
231
248
  : renderApplication(bootstrap, {
232
249
  url: urlToRender,
233
250
  document: html,
234
- platformProviders,
251
+ platformProviders: providers,
235
252
  });
236
253
  }
237
254
  /**
@@ -246,10 +263,72 @@ function isNgModule(value) {
246
263
  return 'ɵmod' in value;
247
264
  }
248
265
 
266
+ /**
267
+ * Different rendering modes for server routes.
268
+ * @developerPreview
269
+ */
270
+ var RenderMode;
271
+ (function (RenderMode) {
272
+ /** AppShell rendering mode, typically used for pre-rendered shells of the application. */
273
+ RenderMode[RenderMode["AppShell"] = 0] = "AppShell";
274
+ /** Server-Side Rendering (SSR) mode, where content is rendered on the server for each request. */
275
+ RenderMode[RenderMode["Server"] = 1] = "Server";
276
+ /** Client-Side Rendering (CSR) mode, where content is rendered on the client side in the browser. */
277
+ RenderMode[RenderMode["Client"] = 2] = "Client";
278
+ /** Static Site Generation (SSG) mode, where content is pre-rendered at build time and served as static files. */
279
+ RenderMode[RenderMode["Prerender"] = 3] = "Prerender";
280
+ })(RenderMode || (RenderMode = {}));
281
+ /**
282
+ * Defines the fallback strategies for Static Site Generation (SSG) routes when a pre-rendered path is not available.
283
+ * This is particularly relevant for routes with parameterized URLs where some paths might not be pre-rendered at build time.
284
+ *
285
+ * @developerPreview
286
+ */
287
+ var PrerenderFallback;
288
+ (function (PrerenderFallback) {
289
+ /**
290
+ * Fallback to Server-Side Rendering (SSR) if the pre-rendered path is not available.
291
+ * This strategy dynamically generates the page on the server at request time.
292
+ */
293
+ PrerenderFallback[PrerenderFallback["Server"] = 0] = "Server";
294
+ /**
295
+ * Fallback to Client-Side Rendering (CSR) if the pre-rendered path is not available.
296
+ * This strategy allows the page to be rendered on the client side.
297
+ */
298
+ PrerenderFallback[PrerenderFallback["Client"] = 1] = "Client";
299
+ /**
300
+ * No fallback; if the path is not pre-rendered, the server will not handle the request.
301
+ * This means the application will not provide any response for paths that are not pre-rendered.
302
+ */
303
+ PrerenderFallback[PrerenderFallback["None"] = 2] = "None";
304
+ })(PrerenderFallback || (PrerenderFallback = {}));
305
+ /**
306
+ * Token for providing the server routes configuration.
307
+ * @internal
308
+ */
309
+ const SERVER_ROUTES_CONFIG = new InjectionToken('SERVER_ROUTES_CONFIG');
310
+ /**
311
+ * Configures the necessary providers for server routes configuration.
312
+ *
313
+ * @param routes - An array of server routes to be provided.
314
+ * @returns An `EnvironmentProviders` object that contains the server routes configuration.
315
+ * @developerPreview
316
+ */
317
+ function provideServerRoutesConfig(routes) {
318
+ return makeEnvironmentProviders([
319
+ {
320
+ provide: SERVER_ROUTES_CONFIG,
321
+ useValue: routes,
322
+ },
323
+ ]);
324
+ }
325
+
249
326
  /**
250
327
  * A route tree implementation that supports efficient route matching, including support for wildcard routes.
251
328
  * This structure is useful for organizing and retrieving routes in a hierarchical manner,
252
329
  * enabling complex routing scenarios with nested paths.
330
+ *
331
+ * @typeParam AdditionalMetadata - Type of additional metadata that can be associated with route nodes.
253
332
  */
254
333
  class RouteTree {
255
334
  constructor() {
@@ -422,36 +501,62 @@ class RouteTree {
422
501
  }
423
502
 
424
503
  /**
425
- * Recursively traverses the Angular router configuration to retrieve routes.
504
+ * Regular expression to match segments preceded by a colon in a string.
505
+ */
506
+ const URL_PARAMETER_REGEXP = /(?<!\\):([^/]+)/g;
507
+ /**
508
+ * An set of HTTP status codes that are considered valid for redirect responses.
509
+ */
510
+ const VALID_REDIRECT_RESPONSE_CODES = new Set([301, 302, 303, 307, 308]);
511
+ /**
512
+ * Traverses an array of route configurations to generate route tree node metadata.
426
513
  *
427
- * Iterates through the router configuration, yielding each route along with its potential
428
- * redirection or error status. Handles nested routes and lazy-loaded child routes.
514
+ * This function processes each route and its children, handling redirects, SSG (Static Site Generation) settings,
515
+ * and lazy-loaded routes. It yields route metadata for each route and its potential variants.
429
516
  *
430
- * @param options - An object containing the parameters for traversing routes.
431
- * @returns An async iterator yielding `RouteResult` objects.
517
+ * @param options - The configuration options for traversing routes.
518
+ * @returns An async iterable iterator of route tree node metadata.
432
519
  */
433
- async function* traverseRoutesConfig(options) {
434
- const { routes, compiler, parentInjector, parentRoute } = options;
520
+ async function* traverseRoutesConfig({ routes, compiler, parentInjector, parentRoute, serverConfigRouteTree, invokeGetPrerenderParams, }) {
435
521
  for (const route of routes) {
436
522
  const { path = '', redirectTo, loadChildren, children } = route;
437
523
  const currentRoutePath = joinUrlParts(parentRoute, path);
438
- yield {
524
+ // Get route metadata from the server config route tree, if available
525
+ const metadata = {
526
+ ...(serverConfigRouteTree
527
+ ? getMatchedRouteMetadata(serverConfigRouteTree, currentRoutePath)
528
+ : undefined),
439
529
  route: currentRoutePath,
440
- redirectTo: typeof redirectTo === 'string'
441
- ? resolveRedirectTo(currentRoutePath, redirectTo)
442
- : undefined,
443
530
  };
531
+ // Handle redirects
532
+ if (typeof redirectTo === 'string') {
533
+ const redirectToResolved = resolveRedirectTo(currentRoutePath, redirectTo);
534
+ if (metadata.status && !VALID_REDIRECT_RESPONSE_CODES.has(metadata.status)) {
535
+ throw new Error(`The '${metadata.status}' status code is not a valid redirect response code. ` +
536
+ `Please use one of the following redirect response codes: ${[...VALID_REDIRECT_RESPONSE_CODES.values()].join(', ')}.`);
537
+ }
538
+ yield { ...metadata, redirectTo: redirectToResolved };
539
+ }
540
+ else if (metadata.renderMode === RenderMode.Prerender) {
541
+ // Handle SSG routes
542
+ yield* handleSSGRoute(metadata, parentInjector, invokeGetPrerenderParams);
543
+ }
544
+ else {
545
+ yield metadata;
546
+ }
547
+ // Recursively process child routes
444
548
  if (children?.length) {
445
- // Recursively process child routes.
446
549
  yield* traverseRoutesConfig({
447
550
  routes: children,
448
551
  compiler,
449
552
  parentInjector,
450
553
  parentRoute: currentRoutePath,
554
+ serverConfigRouteTree,
555
+ invokeGetPrerenderParams,
451
556
  });
452
557
  }
558
+ // Load and process lazy-loaded child routes
453
559
  if (loadChildren) {
454
- // Load and process lazy-loaded child routes.
455
560
  const loadedChildRoutes = await _loadChildren(route, compiler, parentInjector).toPromise();
456
561
  if (loadedChildRoutes) {
457
562
  const { routes: childRoutes, injector = parentInjector } = loadedChildRoutes;
@@ -460,11 +565,77 @@ async function* traverseRoutesConfig(options) {
460
565
  compiler,
461
566
  parentInjector: injector,
462
567
  parentRoute: currentRoutePath,
568
+ serverConfigRouteTree,
569
+ invokeGetPrerenderParams,
463
570
  });
464
571
  }
465
572
  }
466
573
  }
467
574
  }
575
+ /**
576
+ * Retrieves the matched route metadata from the server configuration route tree.
577
+ *
578
+ * @param serverConfigRouteTree - The server configuration route tree.
579
+ * @param currentRoutePath - The current route path being processed.
580
+ * @returns The metadata associated with the matched route.
581
+ */
582
+ function getMatchedRouteMetadata(serverConfigRouteTree, currentRoutePath) {
583
+ const metadata = serverConfigRouteTree.match(currentRoutePath);
584
+ if (!metadata) {
585
+ throw new Error(`The '${currentRoutePath}' route does not match any route defined in the server routing configuration. ` +
586
+ 'Please ensure this route is added to the server routing configuration.');
587
+ }
588
+ return metadata;
589
+ }
590
+ /**
591
+ * Handles SSG (Static Site Generation) routes by invoking `getPrerenderParams` and yielding
592
+ * all parameterized paths.
593
+ *
594
+ * @param metadata - The metadata associated with the route tree node.
595
+ * @param parentInjector - The dependency injection container for the parent route.
596
+ * @param invokeGetPrerenderParams - A flag indicating whether to invoke the `getPrerenderParams` function.
597
+ * @returns An async iterable iterator that yields route tree node metadata for each SSG path.
598
+ */
599
+ async function* handleSSGRoute(metadata, parentInjector, invokeGetPrerenderParams) {
600
+ if (metadata.renderMode !== RenderMode.Prerender) {
601
+ throw new Error(`'handleSSGRoute' was called for a route which rendering mode is not prerender.`);
602
+ }
603
+ const { route: currentRoutePath, fallback, ...meta } = metadata;
604
+ const getPrerenderParams = 'getPrerenderParams' in meta ? meta.getPrerenderParams : undefined;
605
+ if ('getPrerenderParams' in meta) {
606
+ delete meta['getPrerenderParams'];
607
+ }
608
+ if (invokeGetPrerenderParams && URL_PARAMETER_REGEXP.test(currentRoutePath)) {
609
+ if (!getPrerenderParams) {
610
+ throw new Error(`The '${currentRoutePath}' route uses prerendering and includes parameters, but 'getPrerenderParams' is missing. ` +
611
+ `Please define 'getPrerenderParams' function for this route in your server routing configuration ` +
612
+ `or specify a different 'renderMode'.`);
613
+ }
614
+ const parameters = await runInInjectionContext(parentInjector, () => getPrerenderParams());
615
+ for (const params of parameters) {
616
+ const routeWithResolvedParams = currentRoutePath.replace(URL_PARAMETER_REGEXP, (match) => {
617
+ const parameterName = match.slice(1);
618
+ const value = params[parameterName];
619
+ if (typeof value !== 'string') {
620
+ throw new Error(`The 'getPrerenderParams' function defined for the '${currentRoutePath}' route ` +
621
+ `returned a non-string value for parameter '${parameterName}'. ` +
622
+ `Please make sure the 'getPrerenderParams' function returns values for all parameters ` +
623
+ 'specified in this route.');
624
+ }
625
+ return value;
626
+ });
627
+ yield { ...meta, route: routeWithResolvedParams };
628
+ }
629
+ }
630
+ // Handle fallback render modes
631
+ if (fallback !== PrerenderFallback.None || !invokeGetPrerenderParams) {
632
+ yield {
633
+ ...meta,
634
+ route: currentRoutePath,
635
+ renderMode: fallback === PrerenderFallback.Client ? RenderMode.Client : RenderMode.Server,
636
+ };
637
+ }
638
+ }
468
639
  /**
469
640
  * Resolves the `redirectTo` property for a given route.
470
641
  *
@@ -486,24 +657,39 @@ function resolveRedirectTo(routePath, redirectTo) {
486
657
  segments.pop(); // Remove the last segment to make it relative.
487
658
  return joinUrlParts(...segments, redirectTo);
488
659
  }
660
+ /**
661
+ * Builds a server configuration route tree from the given server routes configuration.
662
+ *
663
+ * @param serverRoutesConfig - The array of server routes to be used for configuration.
664
+ * @returns A `RouteTree` populated with the server routes and their metadata.
665
+ */
666
+ function buildServerConfigRouteTree(serverRoutesConfig) {
667
+ const serverConfigRouteTree = new RouteTree();
668
+ for (const { path, ...metadata } of serverRoutesConfig) {
669
+ serverConfigRouteTree.insert(path, metadata);
670
+ }
671
+ return serverConfigRouteTree;
672
+ }
489
673
  /**
490
674
  * Retrieves routes from the given Angular application.
491
675
  *
492
676
  * This function initializes an Angular platform, bootstraps the application or module,
493
677
  * and retrieves routes from the Angular router configuration. It handles both module-based
494
- * and function-based bootstrapping. It yields the resulting routes as `RouteResult` objects.
678
+ * and function-based bootstrapping. It yields the resulting routes as `RouteTreeNodeMetadata` objects.
495
679
  *
496
680
  * @param bootstrap - A function that returns a promise resolving to an `ApplicationRef` or an Angular module to bootstrap.
497
681
  * @param document - The initial HTML document used for server-side rendering.
498
682
  * This document is necessary to render the application on the server.
499
683
  * @param url - The URL for server-side rendering. The URL is used to configure `ServerPlatformLocation`. This configuration is crucial
500
684
  * for ensuring that API requests for relative paths succeed, which is essential for accurate route extraction.
685
+ * @param invokeGetPrerenderParams - A boolean flag indicating whether to invoke `getPrerenderParams` for parameterized SSG routes
686
+ * to handle prerendering paths. Defaults to `false`.
501
687
  * See:
502
688
  * - https://github.com/angular/angular/blob/d608b857c689d17a7ffa33bbb510301014d24a17/packages/platform-server/src/location.ts#L51
503
689
  * - https://github.com/angular/angular/blob/6882cc7d9eed26d3caeedca027452367ba25f2b9/packages/platform-server/src/http.ts#L44
504
690
  * @returns A promise that resolves to an object of type `AngularRouterConfigResult`.
505
691
  */
506
- async function getRoutesFromAngularRouterConfig(bootstrap, document, url) {
692
+ async function getRoutesFromAngularRouterConfig(bootstrap, document, url, invokeGetPrerenderParams = false) {
507
693
  const { protocol, host } = url;
508
694
  // Create and initialize the Angular platform for server-side rendering.
509
695
  const platformRef = createPlatformFactory(platformCore, 'server', [
@@ -533,19 +719,25 @@ async function getRoutesFromAngularRouterConfig(bootstrap, document, url) {
533
719
  const routesResults = [];
534
720
  if (router.config.length) {
535
721
  const compiler = injector.get(Compiler);
722
+ const serverRoutesConfig = injector.get(SERVER_ROUTES_CONFIG, null, { optional: true });
723
+ const serverConfigRouteTree = serverRoutesConfig
724
+ ? buildServerConfigRouteTree(serverRoutesConfig)
725
+ : undefined;
536
726
  // Retrieve all routes from the Angular router configuration.
537
727
  const traverseRoutes = traverseRoutesConfig({
538
728
  routes: router.config,
539
729
  compiler,
540
730
  parentInjector: injector,
541
731
  parentRoute: '',
732
+ serverConfigRouteTree,
733
+ invokeGetPrerenderParams,
542
734
  });
543
735
  for await (const result of traverseRoutes) {
544
736
  routesResults.push(result);
545
737
  }
546
738
  }
547
739
  else {
548
- routesResults.push({ route: '' });
740
+ routesResults.push({ route: '', renderMode: RenderMode.Prerender });
549
741
  }
550
742
  const baseHref = injector.get(APP_BASE_HREF, null, { optional: true }) ??
551
743
  injector.get(PlatformLocation).getBaseHrefFromDOM();
@@ -569,18 +761,21 @@ async function getRoutesFromAngularRouterConfig(bootstrap, document, url) {
569
761
  * - https://github.com/angular/angular/blob/6882cc7d9eed26d3caeedca027452367ba25f2b9/packages/platform-server/src/http.ts#L44
570
762
  * @param manifest - An optional `AngularAppManifest` that contains the application's routing and configuration details.
571
763
  * If not provided, the default manifest is retrieved using `getAngularAppManifest()`.
572
- *
764
+ * @param invokeGetPrerenderParams - A boolean flag indicating whether to invoke `getPrerenderParams` for parameterized SSG routes
765
+ * to handle prerendering paths. Defaults to `false`.
573
766
  * @returns A promise that resolves to a populated `RouteTree` containing all extracted routes from the Angular application.
574
767
  */
575
- async function extractRoutesAndCreateRouteTree(url, manifest = getAngularAppManifest()) {
768
+ async function extractRoutesAndCreateRouteTree(url, manifest = getAngularAppManifest(), invokeGetPrerenderParams = false) {
576
769
  const routeTree = new RouteTree();
577
770
  const document = await new ServerAssets(manifest).getIndexServerHtml();
578
771
  const bootstrap = await manifest.bootstrap();
579
- const { baseHref, routes } = await getRoutesFromAngularRouterConfig(bootstrap, document, url);
580
- for (let { route, redirectTo } of routes) {
581
- route = joinUrlParts(baseHref, route);
582
- redirectTo = redirectTo === undefined ? undefined : joinUrlParts(baseHref, redirectTo);
583
- routeTree.insert(route, { redirectTo });
772
+ const { baseHref, routes } = await getRoutesFromAngularRouterConfig(bootstrap, document, url, invokeGetPrerenderParams);
773
+ for (const { route, ...metadata } of routes) {
774
+ if (metadata.redirectTo !== undefined) {
775
+ metadata.redirectTo = joinUrlParts(baseHref, metadata.redirectTo);
776
+ }
777
+ const fullRoute = joinUrlParts(baseHref, route);
778
+ routeTree.insert(fullRoute, metadata);
584
779
  }
585
780
  return routeTree;
586
781
  }
@@ -912,14 +1107,23 @@ class InlineCriticalCssProcessor extends CrittersBase {
912
1107
  }
913
1108
 
914
1109
  /**
915
- * Enum representing the different contexts in which server rendering can occur.
1110
+ * A mapping of `RenderMode` enum values to corresponding string representations.
1111
+ *
1112
+ * This record is used to map each `RenderMode` to a specific string value that represents
1113
+ * the server context. The string values are used internally to differentiate
1114
+ * between various rendering strategies when processing routes.
1115
+ *
1116
+ * - `RenderMode.Prerender` maps to `'ssg'` (Static Site Generation).
1117
+ * - `RenderMode.Server` maps to `'ssr'` (Server-Side Rendering).
1118
+ * - `RenderMode.AppShell` maps to `'app-shell'` (pre-rendered application shell).
1119
+ * - `RenderMode.Client` maps to an empty string `''` (Client-Side Rendering, no server context needed).
916
1120
  */
917
- var ServerRenderContext;
918
- (function (ServerRenderContext) {
919
- ServerRenderContext["SSR"] = "ssr";
920
- ServerRenderContext["SSG"] = "ssg";
921
- ServerRenderContext["AppShell"] = "app-shell";
922
- })(ServerRenderContext || (ServerRenderContext = {}));
1121
+ const SERVER_CONTEXT_VALUE = {
1122
+ [RenderMode.Prerender]: 'ssg',
1123
+ [RenderMode.Server]: 'ssr',
1124
+ [RenderMode.AppShell]: 'app-shell',
1125
+ [RenderMode.Client]: '',
1126
+ };
923
1127
  /**
924
1128
  * Represents a locale-specific Angular server application managed by the server application engine.
925
1129
  *
@@ -948,14 +1152,29 @@ class AngularServerApp {
948
1152
  *
949
1153
  * @param request - The incoming HTTP request to be rendered.
950
1154
  * @param requestContext - Optional additional context for rendering, such as request metadata.
951
- * @param serverContext - The rendering context.
952
1155
  *
953
1156
  * @returns A promise that resolves to the HTTP response object resulting from the rendering, or null if no match is found.
954
1157
  */
955
- render(request, requestContext, serverContext = ServerRenderContext.SSR) {
1158
+ render(request, requestContext) {
956
1159
  return Promise.race([
957
1160
  this.createAbortPromise(request),
958
- this.handleRendering(request, requestContext, serverContext),
1161
+ this.handleRendering(request, /** isSsrMode */ true, requestContext),
1162
+ ]);
1163
+ }
1164
+ /**
1165
+ * Renders a page based on the provided URL via server-side rendering and returns the corresponding HTTP response.
1166
+ * The rendering process can be interrupted by an abort signal, where the first resolved promise (either from the abort
1167
+ * or the render process) will dictate the outcome.
1168
+ *
1169
+ * @param url - The full URL to be processed and rendered by the server.
1170
+ * @param signal - (Optional) An `AbortSignal` object that allows for the cancellation of the rendering process.
1171
+ * @returns A promise that resolves to the generated HTTP response object, or `null` if no matching route is found.
1172
+ */
1173
+ renderStatic(url, signal) {
1174
+ const request = new Request(url, { signal });
1175
+ return Promise.race([
1176
+ this.createAbortPromise(request),
1177
+ this.handleRendering(request, /** isSsrMode */ false),
959
1178
  ]);
960
1179
  }
961
1180
  /**
@@ -978,12 +1197,12 @@ class AngularServerApp {
978
1197
  * This method matches the request URL to a route and performs rendering if a matching route is found.
979
1198
  *
980
1199
  * @param request - The incoming HTTP request to be processed.
1200
+ * @param isSsrMode - A boolean indicating whether the rendering is performed in server-side rendering (SSR) mode.
981
1201
  * @param requestContext - Optional additional context for rendering, such as request metadata.
982
- * @param serverContext - The rendering context. Defaults to server-side rendering (SSR).
983
1202
  *
984
1203
  * @returns A promise that resolves to the rendered response, or null if no matching route is found.
985
1204
  */
986
- async handleRendering(request, requestContext, serverContext = ServerRenderContext.SSR) {
1205
+ async handleRendering(request, isSsrMode, requestContext) {
987
1206
  const url = new URL(request.url);
988
1207
  this.router ??= await ServerRouter.from(this.manifest, url);
989
1208
  const matchedRoute = this.router.match(url);
@@ -991,29 +1210,27 @@ class AngularServerApp {
991
1210
  // Not a known Angular route.
992
1211
  return null;
993
1212
  }
994
- const { redirectTo } = matchedRoute;
1213
+ const { redirectTo, status } = matchedRoute;
995
1214
  if (redirectTo !== undefined) {
1215
+ // Note: The status code is validated during route extraction.
996
1216
  // 302 Found is used by default for redirections
997
1217
  // See: https://developer.mozilla.org/en-US/docs/Web/API/Response/redirect_static#status
998
- return Response.redirect(new URL(redirectTo, url), 302);
1218
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1219
+ return Response.redirect(new URL(redirectTo, url), status ?? 302);
999
1220
  }
1000
- const platformProviders = [
1001
- {
1002
- provide: _SERVER_CONTEXT,
1003
- useValue: serverContext,
1004
- },
1005
- {
1006
- // An Angular Console Provider that does not print a set of predefined logs.
1007
- provide: _Console,
1008
- // Using `useClass` would necessitate decorating `Console` with `@Injectable`,
1009
- // which would require switching from `ts_library` to `ng_module`. This change
1010
- // would also necessitate various patches of `@angular/bazel` to support ESM.
1011
- useFactory: () => new Console(),
1012
- },
1013
- ];
1014
- const isSsrMode = serverContext === ServerRenderContext.SSR;
1015
- const responseInit = {};
1221
+ const { renderMode = isSsrMode ? RenderMode.Server : RenderMode.Prerender, headers } = matchedRoute;
1222
+ const platformProviders = [];
1223
+ let responseInit;
1016
1224
  if (isSsrMode) {
1225
+ // Initialize the response with status and headers if available.
1226
+ responseInit = {
1227
+ status,
1228
+ headers: headers ? new Headers(headers) : undefined,
1229
+ };
1230
+ if (renderMode === RenderMode.Client) {
1231
+ // Serve the client-side rendered version if the route is configured for CSR.
1232
+ return new Response(await this.assets.getServerAsset('index.csr.html'), responseInit);
1233
+ }
1017
1234
  platformProviders.push({
1018
1235
  provide: REQUEST,
1019
1236
  useValue: request,
@@ -1032,7 +1249,7 @@ class AngularServerApp {
1032
1249
  html = await hooks.run('html:transform:pre', { html });
1033
1250
  }
1034
1251
  this.boostrap ??= await manifest.bootstrap();
1035
- html = await renderAngular(html, this.boostrap, new URL(request.url), platformProviders);
1252
+ html = await renderAngular(html, this.boostrap, new URL(request.url), platformProviders, SERVER_CONTEXT_VALUE[renderMode]);
1036
1253
  if (manifest.inlineCriticalCss) {
1037
1254
  // Optionally inline critical CSS.
1038
1255
  this.inlineCriticalCssProcessor ??= new InlineCriticalCssProcessor((path) => {
@@ -1199,7 +1416,7 @@ class AngularAppEngine {
1199
1416
  * @returns A `Map` containing the HTTP headers as key-value pairs.
1200
1417
  * @note This function should be used exclusively for retrieving headers of SSG pages.
1201
1418
  */
1202
- getHeaders(request) {
1419
+ getPrerenderHeaders(request) {
1203
1420
  if (this.manifest.staticPathsHeaders.size === 0) {
1204
1421
  return new Map();
1205
1422
  }
@@ -1209,5 +1426,5 @@ class AngularAppEngine {
1209
1426
  }
1210
1427
  }
1211
1428
 
1212
- export { AngularAppEngine, InlineCriticalCssProcessor as ɵInlineCriticalCssProcessor, ServerRenderContext as ɵServerRenderContext, destroyAngularServerApp as ɵdestroyAngularServerApp, extractRoutesAndCreateRouteTree as ɵextractRoutesAndCreateRouteTree, getOrCreateAngularServerApp as ɵgetOrCreateAngularServerApp, getRoutesFromAngularRouterConfig as ɵgetRoutesFromAngularRouterConfig, setAngularAppEngineManifest as ɵsetAngularAppEngineManifest, setAngularAppManifest as ɵsetAngularAppManifest };
1429
+ export { AngularAppEngine, provideServerRoutesConfig, InlineCriticalCssProcessor as ɵInlineCriticalCssProcessor, destroyAngularServerApp as ɵdestroyAngularServerApp, extractRoutesAndCreateRouteTree as ɵextractRoutesAndCreateRouteTree, getOrCreateAngularServerApp as ɵgetOrCreateAngularServerApp, getRoutesFromAngularRouterConfig as ɵgetRoutesFromAngularRouterConfig, setAngularAppEngineManifest as ɵsetAngularAppEngineManifest, setAngularAppManifest as ɵsetAngularAppManifest };
1213
1430
  //# sourceMappingURL=ssr.mjs.map