@angular/common 17.0.0-next.6 → 17.0.0-next.8

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.
Files changed (63) hide show
  1. package/esm2022/http/public_api.mjs +1 -1
  2. package/esm2022/http/src/client.mjs +6 -4
  3. package/esm2022/http/src/errors.mjs +1 -1
  4. package/esm2022/http/src/fetch.mjs +3 -3
  5. package/esm2022/http/src/interceptor.mjs +36 -5
  6. package/esm2022/http/src/jsonp.mjs +6 -6
  7. package/esm2022/http/src/module.mjs +12 -12
  8. package/esm2022/http/src/provider.mjs +16 -2
  9. package/esm2022/http/src/request.mjs +3 -1
  10. package/esm2022/http/src/transfer_cache.mjs +73 -18
  11. package/esm2022/http/src/xhr.mjs +3 -3
  12. package/esm2022/http/src/xsrf.mjs +6 -6
  13. package/esm2022/http/testing/src/backend.mjs +3 -3
  14. package/esm2022/http/testing/src/module.mjs +4 -4
  15. package/esm2022/src/common_module.mjs +4 -4
  16. package/esm2022/src/directives/ng_class.mjs +3 -3
  17. package/esm2022/src/directives/ng_component_outlet.mjs +3 -3
  18. package/esm2022/src/directives/ng_for_of.mjs +3 -3
  19. package/esm2022/src/directives/ng_if.mjs +3 -3
  20. package/esm2022/src/directives/ng_optimized_image/index.mjs +3 -2
  21. package/esm2022/src/directives/ng_optimized_image/lcp_image_observer.mjs +7 -7
  22. package/esm2022/src/directives/ng_optimized_image/ng_optimized_image.mjs +6 -16
  23. package/esm2022/src/directives/ng_optimized_image/preconnect_link_checker.mjs +3 -3
  24. package/esm2022/src/directives/ng_optimized_image/preload-link-creator.mjs +3 -3
  25. package/esm2022/src/directives/ng_plural.mjs +6 -6
  26. package/esm2022/src/directives/ng_style.mjs +3 -3
  27. package/esm2022/src/directives/ng_switch.mjs +21 -12
  28. package/esm2022/src/directives/ng_switch_equality.mjs +13 -0
  29. package/esm2022/src/directives/ng_template_outlet.mjs +43 -15
  30. package/esm2022/src/errors.mjs +1 -1
  31. package/esm2022/src/i18n/localization.mjs +6 -6
  32. package/esm2022/src/location/hash_location_strategy.mjs +3 -3
  33. package/esm2022/src/location/location.mjs +3 -3
  34. package/esm2022/src/location/location_strategy.mjs +6 -6
  35. package/esm2022/src/location/platform_location.mjs +6 -6
  36. package/esm2022/src/pipes/async_pipe.mjs +3 -3
  37. package/esm2022/src/pipes/case_conversion_pipes.mjs +9 -9
  38. package/esm2022/src/pipes/date_pipe.mjs +3 -3
  39. package/esm2022/src/pipes/date_pipe_config.mjs +1 -1
  40. package/esm2022/src/pipes/i18n_plural_pipe.mjs +3 -3
  41. package/esm2022/src/pipes/i18n_select_pipe.mjs +3 -3
  42. package/esm2022/src/pipes/json_pipe.mjs +3 -3
  43. package/esm2022/src/pipes/keyvalue_pipe.mjs +3 -3
  44. package/esm2022/src/pipes/number_pipe.mjs +9 -9
  45. package/esm2022/src/pipes/slice_pipe.mjs +3 -3
  46. package/esm2022/src/version.mjs +1 -1
  47. package/esm2022/testing/src/location_mock.mjs +3 -3
  48. package/esm2022/testing/src/mock_location_strategy.mjs +3 -3
  49. package/esm2022/testing/src/mock_platform_location.mjs +3 -3
  50. package/esm2022/upgrade/src/location_upgrade_module.mjs +4 -4
  51. package/fesm2022/common.mjs +176 -145
  52. package/fesm2022/common.mjs.map +1 -1
  53. package/fesm2022/http/testing.mjs +8 -8
  54. package/fesm2022/http.mjs +157 -55
  55. package/fesm2022/http.mjs.map +1 -1
  56. package/fesm2022/testing.mjs +10 -10
  57. package/fesm2022/upgrade.mjs +5 -5
  58. package/http/index.d.ts +271 -4
  59. package/http/testing/index.d.ts +1 -1
  60. package/index.d.ts +19 -23
  61. package/package.json +3 -2
  62. package/testing/index.d.ts +1 -1
  63. package/upgrade/index.d.ts +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v17.0.0-next.6
2
+ * @license Angular v17.0.0-next.8
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -308,10 +308,10 @@ class HttpClientTestingBackend {
308
308
  return `Match by function: ${matcher.name}`;
309
309
  }
310
310
  }
311
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientTestingBackend, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
312
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientTestingBackend }); }
311
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientTestingBackend, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
312
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientTestingBackend }); }
313
313
  }
314
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientTestingBackend, decorators: [{
314
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientTestingBackend, decorators: [{
315
315
  type: Injectable
316
316
  }] });
317
317
  function describeRequest(testRequest) {
@@ -336,13 +336,13 @@ function provideHttpClientTesting() {
336
336
  * @publicApi
337
337
  */
338
338
  class HttpClientTestingModule {
339
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientTestingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
340
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientTestingModule, imports: [HttpClientModule] }); }
341
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientTestingModule, providers: [
339
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientTestingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
340
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientTestingModule, imports: [HttpClientModule] }); }
341
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientTestingModule, providers: [
342
342
  provideHttpClientTesting(),
343
343
  ], imports: [HttpClientModule] }); }
344
344
  }
345
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientTestingModule, decorators: [{
345
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientTestingModule, decorators: [{
346
346
  type: NgModule,
347
347
  args: [{
348
348
  imports: [
package/fesm2022/http.mjs CHANGED
@@ -1,15 +1,15 @@
1
1
  /**
2
- * @license Angular v17.0.0-next.6
2
+ * @license Angular v17.0.0-next.8
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
6
6
 
7
7
  import * as i0 from '@angular/core';
8
- import { Injectable, inject, NgZone, InjectionToken, ɵInitialRenderPendingTasks, Inject, ɵRuntimeError, PLATFORM_ID, makeEnvironmentProviders, NgModule, TransferState, makeStateKey, ɵENABLED_SSR_FEATURES, APP_BOOTSTRAP_LISTENER, ApplicationRef, ɵwhenStable } from '@angular/core';
8
+ import { Injectable, inject, NgZone, InjectionToken, ɵInitialRenderPendingTasks, PLATFORM_ID, ɵConsole, ɵformatRuntimeError, Inject, ɵRuntimeError, makeEnvironmentProviders, NgModule, TransferState, makeStateKey, ɵENABLED_SSR_FEATURES, APP_BOOTSTRAP_LISTENER, ApplicationRef, ɵwhenStable, ɵtruncateMiddle } from '@angular/core';
9
9
  import { of, Observable, from } from 'rxjs';
10
10
  import { concatMap, filter, map, finalize, switchMap, tap } from 'rxjs/operators';
11
11
  import * as i1 from '@angular/common';
12
- import { DOCUMENT, ɵparseCookieValue } from '@angular/common';
12
+ import { isPlatformServer, DOCUMENT, ɵparseCookieValue } from '@angular/common';
13
13
 
14
14
  /**
15
15
  * Transforms an `HttpRequest` into a stream of `HttpEvent`s, one of which will likely be a
@@ -771,6 +771,8 @@ class HttpRequest {
771
771
  if (!!options.params) {
772
772
  this.params = options.params;
773
773
  }
774
+ // We do want to assign transferCache even if it's falsy (false is valid value)
775
+ this.transferCache = options.transferCache;
774
776
  }
775
777
  // If no headers have been passed in, construct a new HttpHeaders instance.
776
778
  if (!this.headers) {
@@ -1093,6 +1095,7 @@ function addBody(options, body) {
1093
1095
  reportProgress: options.reportProgress,
1094
1096
  responseType: options.responseType,
1095
1097
  withCredentials: options.withCredentials,
1098
+ transferCache: options.transferCache,
1096
1099
  };
1097
1100
  }
1098
1101
  /**
@@ -1219,6 +1222,7 @@ class HttpClient {
1219
1222
  // By default, JSON is assumed to be returned for all calls.
1220
1223
  responseType: options.responseType || 'json',
1221
1224
  withCredentials: options.withCredentials,
1225
+ transferCache: options.transferCache,
1222
1226
  });
1223
1227
  }
1224
1228
  // Start with an Observable.of() the initial request, and run the handler (which
@@ -1373,10 +1377,10 @@ class HttpClient {
1373
1377
  put(url, body, options = {}) {
1374
1378
  return this.request('PUT', url, addBody(options, body));
1375
1379
  }
1376
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClient, deps: [{ token: HttpHandler }], target: i0.ɵɵFactoryTarget.Injectable }); }
1377
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClient }); }
1380
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClient, deps: [{ token: HttpHandler }], target: i0.ɵɵFactoryTarget.Injectable }); }
1381
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClient }); }
1378
1382
  }
1379
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClient, decorators: [{
1383
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClient, decorators: [{
1380
1384
  type: Injectable
1381
1385
  }], ctorParameters: () => [{ type: HttpHandler }] });
1382
1386
 
@@ -1581,10 +1585,10 @@ class FetchBackend {
1581
1585
  }
1582
1586
  return chunksAll;
1583
1587
  }
1584
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: FetchBackend, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1585
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: FetchBackend }); }
1588
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: FetchBackend, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1589
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: FetchBackend }); }
1586
1590
  }
1587
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: FetchBackend, decorators: [{
1591
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: FetchBackend, decorators: [{
1588
1592
  type: Injectable
1589
1593
  }] });
1590
1594
  /**
@@ -1639,6 +1643,10 @@ const HTTP_INTERCEPTOR_FNS = new InjectionToken(ngDevMode ? 'HTTP_INTERCEPTOR_FN
1639
1643
  * A multi-provided token of `HttpInterceptorFn`s that are only set in root.
1640
1644
  */
1641
1645
  const HTTP_ROOT_INTERCEPTOR_FNS = new InjectionToken(ngDevMode ? 'HTTP_ROOT_INTERCEPTOR_FNS' : '');
1646
+ /**
1647
+ * A provider to set a global primary http backend. If set, it will override the default one
1648
+ */
1649
+ const PRIMARY_HTTP_BACKEND = new InjectionToken(ngDevMode ? 'PRIMARY_HTTP_BACKEND' : '');
1642
1650
  /**
1643
1651
  * Creates an `HttpInterceptorFn` which lazily initializes an interceptor chain from the legacy
1644
1652
  * class-based interceptors and runs the request through it.
@@ -1659,6 +1667,11 @@ function legacyInterceptorFnFactory() {
1659
1667
  return chain(req, handler).pipe(finalize(() => pendingTasks.remove(taskId)));
1660
1668
  };
1661
1669
  }
1670
+ let fetchBackendWarningDisplayed = false;
1671
+ /** Internal function to reset the flag in tests */
1672
+ function resetFetchBackendWarningFlag() {
1673
+ fetchBackendWarningDisplayed = false;
1674
+ }
1662
1675
  class HttpInterceptorHandler extends HttpHandler {
1663
1676
  constructor(backend, injector) {
1664
1677
  super();
@@ -1666,6 +1679,26 @@ class HttpInterceptorHandler extends HttpHandler {
1666
1679
  this.injector = injector;
1667
1680
  this.chain = null;
1668
1681
  this.pendingTasks = inject(ɵInitialRenderPendingTasks);
1682
+ // Check if there is a preferred HTTP backend configured and use it if that's the case.
1683
+ // This is needed to enable `FetchBackend` globally for all HttpClient's when `withFetch`
1684
+ // is used.
1685
+ const primaryHttpBackend = inject(PRIMARY_HTTP_BACKEND, { optional: true });
1686
+ this.backend = primaryHttpBackend ?? backend;
1687
+ // We strongly recommend using fetch backend for HTTP calls when SSR is used
1688
+ // for an application. The logic below checks if that's the case and produces
1689
+ // a warning otherwise.
1690
+ if ((typeof ngDevMode === 'undefined' || ngDevMode) && !fetchBackendWarningDisplayed) {
1691
+ const isServer = isPlatformServer(injector.get(PLATFORM_ID));
1692
+ if (isServer && !(this.backend instanceof FetchBackend)) {
1693
+ fetchBackendWarningDisplayed = true;
1694
+ injector.get(ɵConsole).warn(ɵformatRuntimeError(2801 /* RuntimeErrorCode.NOT_USING_FETCH_BACKEND_IN_SSR */, 'Angular detected that `HttpClient` is not configured ' +
1695
+ 'to use `fetch` APIs. It\'s strongly recommended to ' +
1696
+ 'enable `fetch` for applications that use Server-Side Rendering ' +
1697
+ 'for better performance and compatibility. ' +
1698
+ 'To enable `fetch`, add the `withFetch()` to the `provideHttpClient()` ' +
1699
+ 'call at the root of the application.'));
1700
+ }
1701
+ }
1669
1702
  }
1670
1703
  handle(initialRequest) {
1671
1704
  if (this.chain === null) {
@@ -1683,10 +1716,10 @@ class HttpInterceptorHandler extends HttpHandler {
1683
1716
  return this.chain(initialRequest, downstreamRequest => this.backend.handle(downstreamRequest))
1684
1717
  .pipe(finalize(() => this.pendingTasks.remove(taskId)));
1685
1718
  }
1686
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpInterceptorHandler, deps: [{ token: HttpBackend }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable }); }
1687
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpInterceptorHandler }); }
1719
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpInterceptorHandler, deps: [{ token: HttpBackend }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable }); }
1720
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpInterceptorHandler }); }
1688
1721
  }
1689
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpInterceptorHandler, decorators: [{
1722
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpInterceptorHandler, decorators: [{
1690
1723
  type: Injectable
1691
1724
  }], ctorParameters: () => [{ type: HttpBackend }, { type: i0.EnvironmentInjector }] });
1692
1725
 
@@ -1888,10 +1921,10 @@ class JsonpClientBackend {
1888
1921
  }
1889
1922
  foreignDocument.adoptNode(script);
1890
1923
  }
1891
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: JsonpClientBackend, deps: [{ token: JsonpCallbackContext }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable }); }
1892
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: JsonpClientBackend }); }
1924
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: JsonpClientBackend, deps: [{ token: JsonpCallbackContext }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable }); }
1925
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: JsonpClientBackend }); }
1893
1926
  }
1894
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: JsonpClientBackend, decorators: [{
1927
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: JsonpClientBackend, decorators: [{
1895
1928
  type: Injectable
1896
1929
  }], ctorParameters: () => [{ type: JsonpCallbackContext }, { type: undefined, decorators: [{
1897
1930
  type: Inject,
@@ -1929,10 +1962,10 @@ class JsonpInterceptor {
1929
1962
  intercept(initialRequest, next) {
1930
1963
  return this.injector.runInContext(() => jsonpInterceptorFn(initialRequest, downstreamRequest => next.handle(downstreamRequest)));
1931
1964
  }
1932
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: JsonpInterceptor, deps: [{ token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable }); }
1933
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: JsonpInterceptor }); }
1965
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: JsonpInterceptor, deps: [{ token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable }); }
1966
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: JsonpInterceptor }); }
1934
1967
  }
1935
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: JsonpInterceptor, decorators: [{
1968
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: JsonpInterceptor, decorators: [{
1936
1969
  type: Injectable
1937
1970
  }], ctorParameters: () => [{ type: i0.EnvironmentInjector }] });
1938
1971
 
@@ -2211,10 +2244,10 @@ class HttpXhrBackend {
2211
2244
  });
2212
2245
  }));
2213
2246
  }
2214
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpXhrBackend, deps: [{ token: i1.XhrFactory }], target: i0.ɵɵFactoryTarget.Injectable }); }
2215
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpXhrBackend }); }
2247
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpXhrBackend, deps: [{ token: i1.XhrFactory }], target: i0.ɵɵFactoryTarget.Injectable }); }
2248
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpXhrBackend }); }
2216
2249
  }
2217
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpXhrBackend, decorators: [{
2250
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpXhrBackend, decorators: [{
2218
2251
  type: Injectable
2219
2252
  }], ctorParameters: () => [{ type: i1.XhrFactory }] });
2220
2253
 
@@ -2263,10 +2296,10 @@ class HttpXsrfCookieExtractor {
2263
2296
  }
2264
2297
  return this.lastToken;
2265
2298
  }
2266
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpXsrfCookieExtractor, deps: [{ token: DOCUMENT }, { token: PLATFORM_ID }, { token: XSRF_COOKIE_NAME }], target: i0.ɵɵFactoryTarget.Injectable }); }
2267
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpXsrfCookieExtractor }); }
2299
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpXsrfCookieExtractor, deps: [{ token: DOCUMENT }, { token: PLATFORM_ID }, { token: XSRF_COOKIE_NAME }], target: i0.ɵɵFactoryTarget.Injectable }); }
2300
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpXsrfCookieExtractor }); }
2268
2301
  }
2269
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpXsrfCookieExtractor, decorators: [{
2302
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpXsrfCookieExtractor, decorators: [{
2270
2303
  type: Injectable
2271
2304
  }], ctorParameters: () => [{ type: undefined, decorators: [{
2272
2305
  type: Inject,
@@ -2306,10 +2339,10 @@ class HttpXsrfInterceptor {
2306
2339
  intercept(initialRequest, next) {
2307
2340
  return this.injector.runInContext(() => xsrfInterceptorFn(initialRequest, downstreamRequest => next.handle(downstreamRequest)));
2308
2341
  }
2309
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpXsrfInterceptor, deps: [{ token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable }); }
2310
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpXsrfInterceptor }); }
2342
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpXsrfInterceptor, deps: [{ token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable }); }
2343
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpXsrfInterceptor }); }
2311
2344
  }
2312
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpXsrfInterceptor, decorators: [{
2345
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpXsrfInterceptor, decorators: [{
2313
2346
  type: Injectable
2314
2347
  }], ctorParameters: () => [{ type: i0.EnvironmentInjector }] });
2315
2348
 
@@ -2342,6 +2375,19 @@ function makeHttpFeature(kind, providers) {
2342
2375
  * feature functions to `provideHttpClient`. For example, HTTP interceptors can be added using the
2343
2376
  * `withInterceptors(...)` feature.
2344
2377
  *
2378
+ * <div class="alert is-helpful">
2379
+ *
2380
+ * It's strongly recommended to enable
2381
+ * [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) for applications that use
2382
+ * Server-Side Rendering for better performance and compatibility. To enable `fetch`, add
2383
+ * `withFetch()` feature to the `provideHttpClient()` call at the root of the application:
2384
+ *
2385
+ * ```
2386
+ * provideHttpClient(withFetch());
2387
+ * ```
2388
+ *
2389
+ * </div>
2390
+ *
2345
2391
  * @see {@link withInterceptors}
2346
2392
  * @see {@link withInterceptorsFromDi}
2347
2393
  * @see {@link withXsrfConfiguration}
@@ -2525,6 +2571,7 @@ function withFetch() {
2525
2571
  return makeHttpFeature(HttpFeatureKind.Fetch, [
2526
2572
  FetchBackend,
2527
2573
  { provide: HttpBackend, useExisting: FetchBackend },
2574
+ { provide: PRIMARY_HTTP_BACKEND, useExisting: FetchBackend },
2528
2575
  ]);
2529
2576
  }
2530
2577
 
@@ -2566,9 +2613,9 @@ class HttpClientXsrfModule {
2566
2613
  providers: withXsrfConfiguration(options).ɵproviders,
2567
2614
  };
2568
2615
  }
2569
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientXsrfModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2570
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientXsrfModule }); }
2571
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientXsrfModule, providers: [
2616
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientXsrfModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2617
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientXsrfModule }); }
2618
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientXsrfModule, providers: [
2572
2619
  HttpXsrfInterceptor,
2573
2620
  { provide: HTTP_INTERCEPTORS, useExisting: HttpXsrfInterceptor, multi: true },
2574
2621
  { provide: HttpXsrfTokenExtractor, useClass: HttpXsrfCookieExtractor },
@@ -2579,7 +2626,7 @@ class HttpClientXsrfModule {
2579
2626
  { provide: XSRF_ENABLED, useValue: true },
2580
2627
  ] }); }
2581
2628
  }
2582
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientXsrfModule, decorators: [{
2629
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientXsrfModule, decorators: [{
2583
2630
  type: NgModule,
2584
2631
  args: [{
2585
2632
  providers: [
@@ -2604,13 +2651,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.6",
2604
2651
  * @publicApi
2605
2652
  */
2606
2653
  class HttpClientModule {
2607
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2608
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientModule }); }
2609
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientModule, providers: [
2654
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2655
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientModule }); }
2656
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientModule, providers: [
2610
2657
  provideHttpClient(withInterceptorsFromDi()),
2611
2658
  ] }); }
2612
2659
  }
2613
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientModule, decorators: [{
2660
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientModule, decorators: [{
2614
2661
  type: NgModule,
2615
2662
  args: [{
2616
2663
  /**
@@ -2631,13 +2678,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.6",
2631
2678
  * @publicApi
2632
2679
  */
2633
2680
  class HttpClientJsonpModule {
2634
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientJsonpModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2635
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientJsonpModule }); }
2636
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientJsonpModule, providers: [
2681
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientJsonpModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2682
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientJsonpModule }); }
2683
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientJsonpModule, providers: [
2637
2684
  withJsonpSupport().ɵproviders,
2638
2685
  ] }); }
2639
2686
  }
2640
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.6", ngImport: i0, type: HttpClientJsonpModule, decorators: [{
2687
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.8", ngImport: i0, type: HttpClientJsonpModule, decorators: [{
2641
2688
  type: NgModule,
2642
2689
  args: [{
2643
2690
  providers: [
@@ -2646,23 +2693,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.6",
2646
2693
  }]
2647
2694
  }] });
2648
2695
 
2649
- const CACHE_STATE = new InjectionToken(ngDevMode ? 'HTTP_TRANSFER_STATE_CACHE_STATE' : '');
2696
+ const CACHE_OPTIONS = new InjectionToken(ngDevMode ? 'HTTP_TRANSFER_STATE_CACHE_OPTIONS' : '');
2650
2697
  /**
2651
2698
  * A list of allowed HTTP methods to cache.
2652
2699
  */
2653
2700
  const ALLOWED_METHODS = ['GET', 'HEAD'];
2654
2701
  function transferCacheInterceptorFn(req, next) {
2655
- const { isCacheActive } = inject(CACHE_STATE);
2656
- // Stop using the cache if the application has stabilized, indicating initial rendering
2657
- // is complete.
2658
- if (!isCacheActive || !ALLOWED_METHODS.includes(req.method)) {
2659
- // Cache is no longer active or method is not HEAD or GET.
2660
- // Pass the request through.
2702
+ const { isCacheActive, ...globalOptions } = inject(CACHE_OPTIONS);
2703
+ const { transferCache: requestOptions, method: requestMethod } = req;
2704
+ // In the following situations we do not want to cache the request
2705
+ if (!isCacheActive ||
2706
+ // POST requests are allowed either globally or at request level
2707
+ (requestMethod === 'POST' && !globalOptions.includePostRequests && !requestOptions) ||
2708
+ (requestMethod !== 'POST' && !ALLOWED_METHODS.includes(requestMethod)) ||
2709
+ requestOptions === false || //
2710
+ (globalOptions.filter?.(req)) === false) {
2661
2711
  return next(req);
2662
2712
  }
2663
2713
  const transferState = inject(TransferState);
2664
2714
  const storeKey = makeCacheKey(req);
2665
2715
  const response = transferState.get(storeKey, null);
2716
+ let headersToInclude = globalOptions.includeHeaders;
2717
+ if (typeof requestOptions === 'object' && requestOptions.includeHeaders) {
2718
+ // Request-specific config takes precedence over the global config.
2719
+ headersToInclude = requestOptions.includeHeaders;
2720
+ }
2666
2721
  if (response) {
2667
2722
  // Request found in cache. Respond using it.
2668
2723
  let body = response.body;
@@ -2674,9 +2729,19 @@ function transferCacheInterceptorFn(req, next) {
2674
2729
  body = new Blob([response.body]);
2675
2730
  break;
2676
2731
  }
2732
+ // We want to warn users accessing a header provided from the cache
2733
+ // That HttpTransferCache alters the headers
2734
+ // The warning will be logged a single time by HttpHeaders instance
2735
+ let headers = new HttpHeaders(response.headers);
2736
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
2737
+ // Append extra logic in dev mode to produce a warning when a header
2738
+ // that was not transferred to the client is accessed in the code via `get`
2739
+ // and `has` calls.
2740
+ headers = appendMissingHeadersDetection(req.url, headers, headersToInclude ?? []);
2741
+ }
2677
2742
  return of(new HttpResponse({
2678
2743
  body,
2679
- headers: new HttpHeaders(response.headers),
2744
+ headers,
2680
2745
  status: response.status,
2681
2746
  statusText: response.statusText,
2682
2747
  url: response.url,
@@ -2687,7 +2752,7 @@ function transferCacheInterceptorFn(req, next) {
2687
2752
  if (event instanceof HttpResponse) {
2688
2753
  transferState.set(storeKey, {
2689
2754
  body: event.body,
2690
- headers: getHeadersMap(event.headers),
2755
+ headers: getFilteredHeaders(event.headers, headersToInclude),
2691
2756
  status: event.status,
2692
2757
  statusText: event.statusText,
2693
2758
  url: event.url || '',
@@ -2696,9 +2761,12 @@ function transferCacheInterceptorFn(req, next) {
2696
2761
  }
2697
2762
  }));
2698
2763
  }
2699
- function getHeadersMap(headers) {
2764
+ function getFilteredHeaders(headers, includeHeaders) {
2765
+ if (!includeHeaders) {
2766
+ return {};
2767
+ }
2700
2768
  const headersMap = {};
2701
- for (const key of headers.keys()) {
2769
+ for (const key of includeHeaders) {
2702
2770
  const values = headers.getAll(key);
2703
2771
  if (values !== null) {
2704
2772
  headersMap[key] = values;
@@ -2741,27 +2809,27 @@ function generateHash(value) {
2741
2809
  * load time.
2742
2810
  *
2743
2811
  */
2744
- function withHttpTransferCache() {
2812
+ function withHttpTransferCache(cacheOptions) {
2745
2813
  return [
2746
2814
  {
2747
- provide: CACHE_STATE,
2815
+ provide: CACHE_OPTIONS,
2748
2816
  useFactory: () => {
2749
2817
  inject(ɵENABLED_SSR_FEATURES).add('httpcache');
2750
- return { isCacheActive: true };
2818
+ return { isCacheActive: true, ...cacheOptions };
2751
2819
  }
2752
2820
  },
2753
2821
  {
2754
2822
  provide: HTTP_ROOT_INTERCEPTOR_FNS,
2755
2823
  useValue: transferCacheInterceptorFn,
2756
2824
  multi: true,
2757
- deps: [TransferState, CACHE_STATE]
2825
+ deps: [TransferState, CACHE_OPTIONS]
2758
2826
  },
2759
2827
  {
2760
2828
  provide: APP_BOOTSTRAP_LISTENER,
2761
2829
  multi: true,
2762
2830
  useFactory: () => {
2763
2831
  const appRef = inject(ApplicationRef);
2764
- const cacheState = inject(CACHE_STATE);
2832
+ const cacheState = inject(CACHE_OPTIONS);
2765
2833
  return () => {
2766
2834
  ɵwhenStable(appRef).then(() => {
2767
2835
  cacheState.isCacheActive = false;
@@ -2771,6 +2839,40 @@ function withHttpTransferCache() {
2771
2839
  }
2772
2840
  ];
2773
2841
  }
2842
+ /**
2843
+ * This function will add a proxy to an HttpHeader to intercept calls to get/has
2844
+ * and log a warning if the header entry requested has been removed
2845
+ */
2846
+ function appendMissingHeadersDetection(url, headers, headersToInclude) {
2847
+ const warningProduced = new Set();
2848
+ return new Proxy(headers, {
2849
+ get(target, prop) {
2850
+ const value = Reflect.get(target, prop);
2851
+ const methods = new Set(['get', 'has', 'getAll']);
2852
+ if (typeof value !== 'function' || !methods.has(prop)) {
2853
+ return value;
2854
+ }
2855
+ return (headerName) => {
2856
+ // We log when the key has been removed and a warning hasn't been produced for the header
2857
+ const key = (prop + ':' + headerName).toLowerCase(); // e.g. `get:cache-control`
2858
+ if (!headersToInclude.includes(headerName) && !warningProduced.has(key)) {
2859
+ warningProduced.add(key);
2860
+ const truncatedUrl = ɵtruncateMiddle(url);
2861
+ // TODO: create Error guide for this warning
2862
+ console.warn(ɵformatRuntimeError(2802 /* RuntimeErrorCode.HEADERS_ALTERED_BY_TRANSFER_CACHE */, `Angular detected that the \`${headerName}\` header is accessed, but the value of the header ` +
2863
+ `was not transferred from the server to the client by the HttpTransferCache. ` +
2864
+ `To include the value of the \`${headerName}\` header for the \`${truncatedUrl}\` request, ` +
2865
+ `use the \`includeHeaders\` list. The \`includeHeaders\` can be defined either ` +
2866
+ `on a request level by adding the \`transferCache\` parameter, or on an application ` +
2867
+ `level by adding the \`httpCacheTransfer.includeHeaders\` argument to the ` +
2868
+ `\`provideClientHydration()\` call. `));
2869
+ }
2870
+ // invoking the original method
2871
+ return value.apply(target, [headerName]);
2872
+ };
2873
+ }
2874
+ });
2875
+ }
2774
2876
 
2775
2877
  // This file is not used to build this module. It is only used during editing
2776
2878