@angular/common 21.0.0-next.9 → 21.0.0-rc.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.
package/fesm2022/http.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v21.0.0-next.9
2
+ * @license Angular v21.0.0-rc.1
3
3
  * (c) 2010-2025 Google LLC. https://angular.dev/
4
4
  * License: MIT
5
5
  */
@@ -11,178 +11,159 @@ import { of } from 'rxjs';
11
11
  import { tap } from 'rxjs/operators';
12
12
  import './_xhr-chunk.mjs';
13
13
 
14
- /**
15
- * `httpResource` makes a reactive HTTP request and exposes the request status and response value as
16
- * a `WritableResource`. By default, it assumes that the backend will return JSON data. To make a
17
- * request that expects a different kind of data, you can use a sub-constructor of `httpResource`,
18
- * such as `httpResource.text`.
19
- *
20
- * @experimental 19.2
21
- * @initializerApiFunction
22
- */
23
14
  const httpResource = (() => {
24
- const jsonFn = makeHttpResourceFn('json');
25
- jsonFn.arrayBuffer = makeHttpResourceFn('arraybuffer');
26
- jsonFn.blob = makeHttpResourceFn('blob');
27
- jsonFn.text = makeHttpResourceFn('text');
28
- return jsonFn;
15
+ const jsonFn = makeHttpResourceFn('json');
16
+ jsonFn.arrayBuffer = makeHttpResourceFn('arraybuffer');
17
+ jsonFn.blob = makeHttpResourceFn('blob');
18
+ jsonFn.text = makeHttpResourceFn('text');
19
+ return jsonFn;
29
20
  })();
30
21
  function makeHttpResourceFn(responseType) {
31
- return function httpResource(request, options) {
32
- if (ngDevMode && !options?.injector) {
33
- assertInInjectionContext(httpResource);
34
- }
35
- const injector = options?.injector ?? inject(Injector);
36
- return new HttpResourceImpl(injector, () => normalizeRequest(request, responseType), options?.defaultValue, options?.parse, options?.equal);
37
- };
22
+ return function httpResource(request, options) {
23
+ if (ngDevMode && !options?.injector) {
24
+ assertInInjectionContext(httpResource);
25
+ }
26
+ const injector = options?.injector ?? inject(Injector);
27
+ return new HttpResourceImpl(injector, () => normalizeRequest(request, responseType), options?.defaultValue, options?.parse, options?.equal);
28
+ };
38
29
  }
39
30
  function normalizeRequest(request, responseType) {
40
- let unwrappedRequest = typeof request === 'function' ? request() : request;
41
- if (unwrappedRequest === undefined) {
42
- return undefined;
43
- }
44
- else if (typeof unwrappedRequest === 'string') {
45
- unwrappedRequest = { url: unwrappedRequest };
46
- }
47
- const headers = unwrappedRequest.headers instanceof HttpHeaders
48
- ? unwrappedRequest.headers
49
- : new HttpHeaders(unwrappedRequest.headers);
50
- const params = unwrappedRequest.params instanceof HttpParams
51
- ? unwrappedRequest.params
52
- : new HttpParams({ fromObject: unwrappedRequest.params });
53
- return new HttpRequest(unwrappedRequest.method ?? 'GET', unwrappedRequest.url, unwrappedRequest.body ?? null, {
54
- headers,
55
- params,
56
- reportProgress: unwrappedRequest.reportProgress,
57
- withCredentials: unwrappedRequest.withCredentials,
58
- keepalive: unwrappedRequest.keepalive,
59
- cache: unwrappedRequest.cache,
60
- priority: unwrappedRequest.priority,
61
- mode: unwrappedRequest.mode,
62
- redirect: unwrappedRequest.redirect,
63
- responseType,
64
- context: unwrappedRequest.context,
65
- transferCache: unwrappedRequest.transferCache,
66
- credentials: unwrappedRequest.credentials,
67
- referrer: unwrappedRequest.referrer,
68
- referrerPolicy: unwrappedRequest.referrerPolicy,
69
- integrity: unwrappedRequest.integrity,
70
- timeout: unwrappedRequest.timeout,
71
- });
31
+ let unwrappedRequest = typeof request === 'function' ? request() : request;
32
+ if (unwrappedRequest === undefined) {
33
+ return undefined;
34
+ } else if (typeof unwrappedRequest === 'string') {
35
+ unwrappedRequest = {
36
+ url: unwrappedRequest
37
+ };
38
+ }
39
+ const headers = unwrappedRequest.headers instanceof HttpHeaders ? unwrappedRequest.headers : new HttpHeaders(unwrappedRequest.headers);
40
+ const params = unwrappedRequest.params instanceof HttpParams ? unwrappedRequest.params : new HttpParams({
41
+ fromObject: unwrappedRequest.params
42
+ });
43
+ return new HttpRequest(unwrappedRequest.method ?? 'GET', unwrappedRequest.url, unwrappedRequest.body ?? null, {
44
+ headers,
45
+ params,
46
+ reportProgress: unwrappedRequest.reportProgress,
47
+ withCredentials: unwrappedRequest.withCredentials,
48
+ keepalive: unwrappedRequest.keepalive,
49
+ cache: unwrappedRequest.cache,
50
+ priority: unwrappedRequest.priority,
51
+ mode: unwrappedRequest.mode,
52
+ redirect: unwrappedRequest.redirect,
53
+ responseType,
54
+ context: unwrappedRequest.context,
55
+ transferCache: unwrappedRequest.transferCache,
56
+ credentials: unwrappedRequest.credentials,
57
+ referrer: unwrappedRequest.referrer,
58
+ referrerPolicy: unwrappedRequest.referrerPolicy,
59
+ integrity: unwrappedRequest.integrity,
60
+ timeout: unwrappedRequest.timeout
61
+ });
72
62
  }
73
63
  class HttpResourceImpl extends _ResourceImpl {
74
- client;
75
- _headers = linkedSignal(...(ngDevMode ? [{ debugName: "_headers", source: this.extRequest,
76
- computation: () => undefined }] : [{
77
- source: this.extRequest,
78
- computation: () => undefined,
79
- }]));
80
- _progress = linkedSignal(...(ngDevMode ? [{ debugName: "_progress", source: this.extRequest,
81
- computation: () => undefined }] : [{
82
- source: this.extRequest,
83
- computation: () => undefined,
84
- }]));
85
- _statusCode = linkedSignal(...(ngDevMode ? [{ debugName: "_statusCode", source: this.extRequest,
86
- computation: () => undefined }] : [{
87
- source: this.extRequest,
88
- computation: () => undefined,
89
- }]));
90
- headers = computed(() => this.status() === 'resolved' || this.status() === 'error' ? this._headers() : undefined, ...(ngDevMode ? [{ debugName: "headers" }] : []));
91
- progress = this._progress.asReadonly();
92
- statusCode = this._statusCode.asReadonly();
93
- constructor(injector, request, defaultValue, parse, equal) {
94
- super(request, ({ params: request, abortSignal }) => {
95
- let sub;
96
- // Track the abort listener so it can be removed if the Observable completes (as a memory
97
- // optimization).
98
- const onAbort = () => sub.unsubscribe();
99
- abortSignal.addEventListener('abort', onAbort);
100
- // Start off stream as undefined.
101
- const stream = signal({ value: undefined }, ...(ngDevMode ? [{ debugName: "stream" }] : []));
102
- let resolve;
103
- const promise = new Promise((r) => (resolve = r));
104
- const send = (value) => {
105
- stream.set(value);
106
- resolve?.(stream);
107
- resolve = undefined;
108
- };
109
- sub = this.client.request(request).subscribe({
110
- next: (event) => {
111
- switch (event.type) {
112
- case HttpEventType.Response:
113
- this._headers.set(event.headers);
114
- this._statusCode.set(event.status);
115
- try {
116
- send({ value: parse ? parse(event.body) : event.body });
117
- }
118
- catch (error) {
119
- send({ error: _encapsulateResourceError(error) });
120
- }
121
- break;
122
- case HttpEventType.DownloadProgress:
123
- this._progress.set(event);
124
- break;
125
- }
126
- },
127
- error: (error) => {
128
- if (error instanceof HttpErrorResponse) {
129
- this._headers.set(error.headers);
130
- this._statusCode.set(error.status);
131
- }
132
- send({ error });
133
- abortSignal.removeEventListener('abort', onAbort);
134
- },
135
- complete: () => {
136
- if (resolve) {
137
- send({
138
- error: new _RuntimeError(991 /* ɵRuntimeErrorCode.RESOURCE_COMPLETED_BEFORE_PRODUCING_VALUE */, ngDevMode && 'Resource completed before producing a value'),
139
- });
140
- }
141
- abortSignal.removeEventListener('abort', onAbort);
142
- },
64
+ client;
65
+ _headers = linkedSignal(...(ngDevMode ? [{
66
+ debugName: "_headers",
67
+ source: this.extRequest,
68
+ computation: () => undefined
69
+ }] : [{
70
+ source: this.extRequest,
71
+ computation: () => undefined
72
+ }]));
73
+ _progress = linkedSignal(...(ngDevMode ? [{
74
+ debugName: "_progress",
75
+ source: this.extRequest,
76
+ computation: () => undefined
77
+ }] : [{
78
+ source: this.extRequest,
79
+ computation: () => undefined
80
+ }]));
81
+ _statusCode = linkedSignal(...(ngDevMode ? [{
82
+ debugName: "_statusCode",
83
+ source: this.extRequest,
84
+ computation: () => undefined
85
+ }] : [{
86
+ source: this.extRequest,
87
+ computation: () => undefined
88
+ }]));
89
+ headers = computed(() => this.status() === 'resolved' || this.status() === 'error' ? this._headers() : undefined, ...(ngDevMode ? [{
90
+ debugName: "headers"
91
+ }] : []));
92
+ progress = this._progress.asReadonly();
93
+ statusCode = this._statusCode.asReadonly();
94
+ constructor(injector, request, defaultValue, parse, equal) {
95
+ super(request, ({
96
+ params: request,
97
+ abortSignal
98
+ }) => {
99
+ let sub;
100
+ const onAbort = () => sub.unsubscribe();
101
+ abortSignal.addEventListener('abort', onAbort);
102
+ const stream = signal({
103
+ value: undefined
104
+ }, ...(ngDevMode ? [{
105
+ debugName: "stream"
106
+ }] : []));
107
+ let resolve;
108
+ const promise = new Promise(r => resolve = r);
109
+ const send = value => {
110
+ stream.set(value);
111
+ resolve?.(stream);
112
+ resolve = undefined;
113
+ };
114
+ sub = this.client.request(request).subscribe({
115
+ next: event => {
116
+ switch (event.type) {
117
+ case HttpEventType.Response:
118
+ this._headers.set(event.headers);
119
+ this._statusCode.set(event.status);
120
+ try {
121
+ send({
122
+ value: parse ? parse(event.body) : event.body
123
+ });
124
+ } catch (error) {
125
+ send({
126
+ error: _encapsulateResourceError(error)
127
+ });
128
+ }
129
+ break;
130
+ case HttpEventType.DownloadProgress:
131
+ this._progress.set(event);
132
+ break;
133
+ }
134
+ },
135
+ error: error => {
136
+ if (error instanceof HttpErrorResponse) {
137
+ this._headers.set(error.headers);
138
+ this._statusCode.set(error.status);
139
+ }
140
+ send({
141
+ error
142
+ });
143
+ abortSignal.removeEventListener('abort', onAbort);
144
+ },
145
+ complete: () => {
146
+ if (resolve) {
147
+ send({
148
+ error: new _RuntimeError(991, ngDevMode && 'Resource completed before producing a value')
143
149
  });
144
- return promise;
145
- }, defaultValue, equal, injector);
146
- this.client = injector.get(HttpClient);
147
- }
148
- set(value) {
149
- super.set(value);
150
- this._headers.set(undefined);
151
- this._progress.set(undefined);
152
- this._statusCode.set(undefined);
153
- }
150
+ }
151
+ abortSignal.removeEventListener('abort', onAbort);
152
+ }
153
+ });
154
+ return promise;
155
+ }, defaultValue, equal, injector);
156
+ this.client = injector.get(HttpClient);
157
+ }
158
+ set(value) {
159
+ super.set(value);
160
+ this._headers.set(undefined);
161
+ this._progress.set(undefined);
162
+ this._statusCode.set(undefined);
163
+ }
154
164
  }
155
165
 
156
- /**
157
- * If your application uses different HTTP origins to make API calls (via `HttpClient`) on the server and
158
- * on the client, the `HTTP_TRANSFER_CACHE_ORIGIN_MAP` token allows you to establish a mapping
159
- * between those origins, so that `HttpTransferCache` feature can recognize those requests as the same
160
- * ones and reuse the data cached on the server during hydration on the client.
161
- *
162
- * **Important note**: the `HTTP_TRANSFER_CACHE_ORIGIN_MAP` token should *only* be provided in
163
- * the *server* code of your application (typically in the `app.server.config.ts` script). Angular throws an
164
- * error if it detects that the token is defined while running on the client.
165
- *
166
- * @usageNotes
167
- *
168
- * When the same API endpoint is accessed via `http://internal-domain.com:8080` on the server and
169
- * via `https://external-domain.com` on the client, you can use the following configuration:
170
- * ```ts
171
- * // in app.server.config.ts
172
- * {
173
- * provide: HTTP_TRANSFER_CACHE_ORIGIN_MAP,
174
- * useValue: {
175
- * 'http://internal-domain.com:8080': 'https://external-domain.com'
176
- * }
177
- * }
178
- * ```
179
- *
180
- * @publicApi
181
- */
182
166
  const HTTP_TRANSFER_CACHE_ORIGIN_MAP = new InjectionToken(typeof ngDevMode !== undefined && ngDevMode ? 'HTTP_TRANSFER_CACHE_ORIGIN_MAP' : '');
183
- /**
184
- * Keys within cached response data structure.
185
- */
186
167
  const BODY = 'b';
187
168
  const HEADERS = 'h';
188
169
  const STATUS = 's';
@@ -190,237 +171,188 @@ const STATUS_TEXT = 'st';
190
171
  const REQ_URL = 'u';
191
172
  const RESPONSE_TYPE = 'rt';
192
173
  const CACHE_OPTIONS = new InjectionToken(typeof ngDevMode !== undefined && ngDevMode ? 'HTTP_TRANSFER_STATE_CACHE_OPTIONS' : '');
193
- /**
194
- * A list of allowed HTTP methods to cache.
195
- */
196
174
  const ALLOWED_METHODS = ['GET', 'HEAD'];
197
175
  function transferCacheInterceptorFn(req, next) {
198
- const { isCacheActive, ...globalOptions } = inject(CACHE_OPTIONS);
199
- const { transferCache: requestOptions, method: requestMethod } = req;
200
- // In the following situations we do not want to cache the request
201
- if (!isCacheActive ||
202
- requestOptions === false ||
203
- // POST requests are allowed either globally or at request level
204
- (requestMethod === 'POST' && !globalOptions.includePostRequests && !requestOptions) ||
205
- (requestMethod !== 'POST' && !ALLOWED_METHODS.includes(requestMethod)) ||
206
- // Do not cache request that require authorization when includeRequestsWithAuthHeaders is falsey
207
- (!globalOptions.includeRequestsWithAuthHeaders && hasAuthHeaders(req)) ||
208
- globalOptions.filter?.(req) === false) {
209
- return next(req);
210
- }
211
- const transferState = inject(TransferState);
212
- const originMap = inject(HTTP_TRANSFER_CACHE_ORIGIN_MAP, {
213
- optional: true,
214
- });
215
- if (typeof ngServerMode !== 'undefined' && !ngServerMode && originMap) {
216
- throw new _RuntimeError(2803 /* RuntimeErrorCode.HTTP_ORIGIN_MAP_USED_IN_CLIENT */, ngDevMode &&
217
- 'Angular detected that the `HTTP_TRANSFER_CACHE_ORIGIN_MAP` token is configured and ' +
218
- 'present in the client side code. Please ensure that this token is only provided in the ' +
219
- 'server code of the application.');
220
- }
221
- const requestUrl = typeof ngServerMode !== 'undefined' && ngServerMode && originMap
222
- ? mapRequestOriginUrl(req.url, originMap)
223
- : req.url;
224
- const storeKey = makeCacheKey(req, requestUrl);
225
- const response = transferState.get(storeKey, null);
226
- let headersToInclude = globalOptions.includeHeaders;
227
- if (typeof requestOptions === 'object' && requestOptions.includeHeaders) {
228
- // Request-specific config takes precedence over the global config.
229
- headersToInclude = requestOptions.includeHeaders;
230
- }
231
- if (response) {
232
- const { [BODY]: undecodedBody, [RESPONSE_TYPE]: responseType, [HEADERS]: httpHeaders, [STATUS]: status, [STATUS_TEXT]: statusText, [REQ_URL]: url, } = response;
233
- // Request found in cache. Respond using it.
234
- let body = undecodedBody;
235
- switch (responseType) {
236
- case 'arraybuffer':
237
- body = new TextEncoder().encode(undecodedBody).buffer;
238
- break;
239
- case 'blob':
240
- body = new Blob([undecodedBody]);
241
- break;
242
- }
243
- // We want to warn users accessing a header provided from the cache
244
- // That HttpTransferCache alters the headers
245
- // The warning will be logged a single time by HttpHeaders instance
246
- let headers = new HttpHeaders(httpHeaders);
247
- if (typeof ngDevMode === 'undefined' || ngDevMode) {
248
- // Append extra logic in dev mode to produce a warning when a header
249
- // that was not transferred to the client is accessed in the code via `get`
250
- // and `has` calls.
251
- headers = appendMissingHeadersDetection(req.url, headers, headersToInclude ?? []);
252
- }
253
- return of(new HttpResponse({
254
- body,
255
- headers,
256
- status,
257
- statusText,
258
- url,
259
- }));
176
+ const {
177
+ isCacheActive,
178
+ ...globalOptions
179
+ } = inject(CACHE_OPTIONS);
180
+ const {
181
+ transferCache: requestOptions,
182
+ method: requestMethod
183
+ } = req;
184
+ if (!isCacheActive || requestOptions === false || requestMethod === 'POST' && !globalOptions.includePostRequests && !requestOptions || requestMethod !== 'POST' && !ALLOWED_METHODS.includes(requestMethod) || !globalOptions.includeRequestsWithAuthHeaders && hasAuthHeaders(req) || globalOptions.filter?.(req) === false) {
185
+ return next(req);
186
+ }
187
+ const transferState = inject(TransferState);
188
+ const originMap = inject(HTTP_TRANSFER_CACHE_ORIGIN_MAP, {
189
+ optional: true
190
+ });
191
+ if (typeof ngServerMode !== 'undefined' && !ngServerMode && originMap) {
192
+ throw new _RuntimeError(2803, ngDevMode && 'Angular detected that the `HTTP_TRANSFER_CACHE_ORIGIN_MAP` token is configured and ' + 'present in the client side code. Please ensure that this token is only provided in the ' + 'server code of the application.');
193
+ }
194
+ const requestUrl = typeof ngServerMode !== 'undefined' && ngServerMode && originMap ? mapRequestOriginUrl(req.url, originMap) : req.url;
195
+ const storeKey = makeCacheKey(req, requestUrl);
196
+ const response = transferState.get(storeKey, null);
197
+ let headersToInclude = globalOptions.includeHeaders;
198
+ if (typeof requestOptions === 'object' && requestOptions.includeHeaders) {
199
+ headersToInclude = requestOptions.includeHeaders;
200
+ }
201
+ if (response) {
202
+ const {
203
+ [BODY]: undecodedBody,
204
+ [RESPONSE_TYPE]: responseType,
205
+ [HEADERS]: httpHeaders,
206
+ [STATUS]: status,
207
+ [STATUS_TEXT]: statusText,
208
+ [REQ_URL]: url
209
+ } = response;
210
+ let body = undecodedBody;
211
+ switch (responseType) {
212
+ case 'arraybuffer':
213
+ body = new TextEncoder().encode(undecodedBody).buffer;
214
+ break;
215
+ case 'blob':
216
+ body = new Blob([undecodedBody]);
217
+ break;
260
218
  }
261
- const event$ = next(req);
262
- if (typeof ngServerMode !== 'undefined' && ngServerMode) {
263
- // Request not found in cache. Make the request and cache it if on the server.
264
- return event$.pipe(tap((event) => {
265
- // Only cache successful HTTP responses.
266
- if (event instanceof HttpResponse) {
267
- transferState.set(storeKey, {
268
- [BODY]: event.body,
269
- [HEADERS]: getFilteredHeaders(event.headers, headersToInclude),
270
- [STATUS]: event.status,
271
- [STATUS_TEXT]: event.statusText,
272
- [REQ_URL]: requestUrl,
273
- [RESPONSE_TYPE]: req.responseType,
274
- });
275
- }
276
- }));
219
+ let headers = new HttpHeaders(httpHeaders);
220
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
221
+ headers = appendMissingHeadersDetection(req.url, headers, headersToInclude ?? []);
277
222
  }
278
- return event$;
223
+ return of(new HttpResponse({
224
+ body,
225
+ headers,
226
+ status,
227
+ statusText,
228
+ url
229
+ }));
230
+ }
231
+ const event$ = next(req);
232
+ if (typeof ngServerMode !== 'undefined' && ngServerMode) {
233
+ return event$.pipe(tap(event => {
234
+ if (event instanceof HttpResponse) {
235
+ transferState.set(storeKey, {
236
+ [BODY]: event.body,
237
+ [HEADERS]: getFilteredHeaders(event.headers, headersToInclude),
238
+ [STATUS]: event.status,
239
+ [STATUS_TEXT]: event.statusText,
240
+ [REQ_URL]: requestUrl,
241
+ [RESPONSE_TYPE]: req.responseType
242
+ });
243
+ }
244
+ }));
245
+ }
246
+ return event$;
279
247
  }
280
- /** @returns true when the requests contains autorization related headers. */
281
248
  function hasAuthHeaders(req) {
282
- return req.headers.has('authorization') || req.headers.has('proxy-authorization');
249
+ return req.headers.has('authorization') || req.headers.has('proxy-authorization');
283
250
  }
284
251
  function getFilteredHeaders(headers, includeHeaders) {
285
- if (!includeHeaders) {
286
- return {};
287
- }
288
- const headersMap = {};
289
- for (const key of includeHeaders) {
290
- const values = headers.getAll(key);
291
- if (values !== null) {
292
- headersMap[key] = values;
293
- }
252
+ if (!includeHeaders) {
253
+ return {};
254
+ }
255
+ const headersMap = {};
256
+ for (const key of includeHeaders) {
257
+ const values = headers.getAll(key);
258
+ if (values !== null) {
259
+ headersMap[key] = values;
294
260
  }
295
- return headersMap;
261
+ }
262
+ return headersMap;
296
263
  }
297
264
  function sortAndConcatParams(params) {
298
- return [...params.keys()]
299
- .sort()
300
- .map((k) => `${k}=${params.getAll(k)}`)
301
- .join('&');
265
+ return [...params.keys()].sort().map(k => `${k}=${params.getAll(k)}`).join('&');
302
266
  }
303
267
  function makeCacheKey(request, mappedRequestUrl) {
304
- // make the params encoded same as a url so it's easy to identify
305
- const { params, method, responseType } = request;
306
- const encodedParams = sortAndConcatParams(params);
307
- let serializedBody = request.serializeBody();
308
- if (serializedBody instanceof URLSearchParams) {
309
- serializedBody = sortAndConcatParams(serializedBody);
310
- }
311
- else if (typeof serializedBody !== 'string') {
312
- serializedBody = '';
313
- }
314
- const key = [method, responseType, mappedRequestUrl, serializedBody, encodedParams].join('|');
315
- const hash = generateHash(key);
316
- return makeStateKey(hash);
268
+ const {
269
+ params,
270
+ method,
271
+ responseType
272
+ } = request;
273
+ const encodedParams = sortAndConcatParams(params);
274
+ let serializedBody = request.serializeBody();
275
+ if (serializedBody instanceof URLSearchParams) {
276
+ serializedBody = sortAndConcatParams(serializedBody);
277
+ } else if (typeof serializedBody !== 'string') {
278
+ serializedBody = '';
279
+ }
280
+ const key = [method, responseType, mappedRequestUrl, serializedBody, encodedParams].join('|');
281
+ const hash = generateHash(key);
282
+ return makeStateKey(hash);
317
283
  }
318
- /**
319
- * A method that returns a hash representation of a string using a variant of DJB2 hash
320
- * algorithm.
321
- *
322
- * This is the same hashing logic that is used to generate component ids.
323
- */
324
284
  function generateHash(value) {
325
- let hash = 0;
326
- for (const char of value) {
327
- hash = (Math.imul(31, hash) + char.charCodeAt(0)) << 0;
328
- }
329
- // Force positive number hash.
330
- // 2147483647 = equivalent of Integer.MAX_VALUE.
331
- hash += 2147483647 + 1;
332
- return hash.toString();
285
+ let hash = 0;
286
+ for (const char of value) {
287
+ hash = Math.imul(31, hash) + char.charCodeAt(0) << 0;
288
+ }
289
+ hash += 2147483647 + 1;
290
+ return hash.toString();
333
291
  }
334
- /**
335
- * Returns the DI providers needed to enable HTTP transfer cache.
336
- *
337
- * By default, when using server rendering, requests are performed twice: once on the server and
338
- * other one on the browser.
339
- *
340
- * When these providers are added, requests performed on the server are cached and reused during the
341
- * bootstrapping of the application in the browser thus avoiding duplicate requests and reducing
342
- * load time.
343
- *
344
- */
345
292
  function withHttpTransferCache(cacheOptions) {
346
- return [
347
- {
348
- provide: CACHE_OPTIONS,
349
- useFactory: () => {
350
- _performanceMarkFeature('NgHttpTransferCache');
351
- return { isCacheActive: true, ...cacheOptions };
352
- },
353
- },
354
- {
355
- provide: HTTP_ROOT_INTERCEPTOR_FNS,
356
- useValue: transferCacheInterceptorFn,
357
- multi: true,
358
- },
359
- {
360
- provide: APP_BOOTSTRAP_LISTENER,
361
- multi: true,
362
- useFactory: () => {
363
- const appRef = inject(ApplicationRef);
364
- const cacheState = inject(CACHE_OPTIONS);
365
- return () => {
366
- appRef.whenStable().then(() => {
367
- cacheState.isCacheActive = false;
368
- });
369
- };
370
- },
371
- },
372
- ];
293
+ return [{
294
+ provide: CACHE_OPTIONS,
295
+ useFactory: () => {
296
+ _performanceMarkFeature('NgHttpTransferCache');
297
+ return {
298
+ isCacheActive: true,
299
+ ...cacheOptions
300
+ };
301
+ }
302
+ }, {
303
+ provide: HTTP_ROOT_INTERCEPTOR_FNS,
304
+ useValue: transferCacheInterceptorFn,
305
+ multi: true
306
+ }, {
307
+ provide: APP_BOOTSTRAP_LISTENER,
308
+ multi: true,
309
+ useFactory: () => {
310
+ const appRef = inject(ApplicationRef);
311
+ const cacheState = inject(CACHE_OPTIONS);
312
+ return () => {
313
+ appRef.whenStable().then(() => {
314
+ cacheState.isCacheActive = false;
315
+ });
316
+ };
317
+ }
318
+ }];
373
319
  }
374
- /**
375
- * This function will add a proxy to an HttpHeader to intercept calls to get/has
376
- * and log a warning if the header entry requested has been removed
377
- */
378
320
  function appendMissingHeadersDetection(url, headers, headersToInclude) {
379
- const warningProduced = new Set();
380
- return new Proxy(headers, {
381
- get(target, prop) {
382
- const value = Reflect.get(target, prop);
383
- const methods = new Set(['get', 'has', 'getAll']);
384
- if (typeof value !== 'function' || !methods.has(prop)) {
385
- return value;
386
- }
387
- return (headerName) => {
388
- // We log when the key has been removed and a warning hasn't been produced for the header
389
- const key = (prop + ':' + headerName).toLowerCase(); // e.g. `get:cache-control`
390
- if (!headersToInclude.includes(headerName) && !warningProduced.has(key)) {
391
- warningProduced.add(key);
392
- const truncatedUrl = _truncateMiddle(url);
393
- console.warn(_formatRuntimeError(-2802 /* RuntimeErrorCode.HEADERS_ALTERED_BY_TRANSFER_CACHE */, `Angular detected that the \`${headerName}\` header is accessed, but the value of the header ` +
394
- `was not transferred from the server to the client by the HttpTransferCache. ` +
395
- `To include the value of the \`${headerName}\` header for the \`${truncatedUrl}\` request, ` +
396
- `use the \`includeHeaders\` list. The \`includeHeaders\` can be defined either ` +
397
- `on a request level by adding the \`transferCache\` parameter, or on an application ` +
398
- `level by adding the \`httpCacheTransfer.includeHeaders\` argument to the ` +
399
- `\`provideClientHydration()\` call. `));
400
- }
401
- // invoking the original method
402
- return value.apply(target, [headerName]);
403
- };
404
- },
405
- });
321
+ const warningProduced = new Set();
322
+ return new Proxy(headers, {
323
+ get(target, prop) {
324
+ const value = Reflect.get(target, prop);
325
+ const methods = new Set(['get', 'has', 'getAll']);
326
+ if (typeof value !== 'function' || !methods.has(prop)) {
327
+ return value;
328
+ }
329
+ return headerName => {
330
+ const key = (prop + ':' + headerName).toLowerCase();
331
+ if (!headersToInclude.includes(headerName) && !warningProduced.has(key)) {
332
+ warningProduced.add(key);
333
+ const truncatedUrl = _truncateMiddle(url);
334
+ console.warn(_formatRuntimeError(-2802, `Angular detected that the \`${headerName}\` header is accessed, but the value of the header ` + `was not transferred from the server to the client by the HttpTransferCache. ` + `To include the value of the \`${headerName}\` header for the \`${truncatedUrl}\` request, ` + `use the \`includeHeaders\` list. The \`includeHeaders\` can be defined either ` + `on a request level by adding the \`transferCache\` parameter, or on an application ` + `level by adding the \`httpCacheTransfer.includeHeaders\` argument to the ` + `\`provideClientHydration()\` call. `));
335
+ }
336
+ return value.apply(target, [headerName]);
337
+ };
338
+ }
339
+ });
406
340
  }
407
341
  function mapRequestOriginUrl(url, originMap) {
408
- const origin = new URL(url, 'resolve://').origin;
409
- const mappedOrigin = originMap[origin];
410
- if (!mappedOrigin) {
411
- return url;
412
- }
413
- if (typeof ngDevMode === 'undefined' || ngDevMode) {
414
- verifyMappedOrigin(mappedOrigin);
415
- }
416
- return url.replace(origin, mappedOrigin);
342
+ const origin = new URL(url, 'resolve://').origin;
343
+ const mappedOrigin = originMap[origin];
344
+ if (!mappedOrigin) {
345
+ return url;
346
+ }
347
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
348
+ verifyMappedOrigin(mappedOrigin);
349
+ }
350
+ return url.replace(origin, mappedOrigin);
417
351
  }
418
352
  function verifyMappedOrigin(url) {
419
- if (new URL(url, 'resolve://').pathname !== '/') {
420
- throw new _RuntimeError(2804 /* RuntimeErrorCode.HTTP_ORIGIN_MAP_CONTAINS_PATH */, 'Angular detected a URL with a path segment in the value provided for the ' +
421
- `\`HTTP_TRANSFER_CACHE_ORIGIN_MAP\` token: ${url}. The map should only contain origins ` +
422
- 'without any other segments.');
423
- }
353
+ if (new URL(url, 'resolve://').pathname !== '/') {
354
+ throw new _RuntimeError(2804, 'Angular detected a URL with a path segment in the value provided for the ' + `\`HTTP_TRANSFER_CACHE_ORIGIN_MAP\` token: ${url}. The map should only contain origins ` + 'without any other segments.');
355
+ }
424
356
  }
425
357
 
426
358
  export { HTTP_TRANSFER_CACHE_ORIGIN_MAP, HttpClient, HttpErrorResponse, HttpEventType, HttpHeaders, HttpParams, HttpRequest, HttpResponse, httpResource, HTTP_ROOT_INTERCEPTOR_FNS as ɵHTTP_ROOT_INTERCEPTOR_FNS, withHttpTransferCache as ɵwithHttpTransferCache };