@angular/common 20.0.0-next.3 → 20.0.0-next.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2903 @@
1
+ /**
2
+ * @license Angular v20.0.0-next.5
3
+ * (c) 2010-2025 Google LLC. https://angular.io/
4
+ * License: MIT
5
+ */
6
+
7
+ import * as i0 from '@angular/core';
8
+ import { ɵRuntimeError as _RuntimeError, Injectable, inject, NgZone, InjectionToken, ɵPendingTasksInternal as _PendingTasksInternal, PLATFORM_ID, ɵConsole as _Console, ɵformatRuntimeError as _formatRuntimeError, runInInjectionContext, DOCUMENT, Inject, makeEnvironmentProviders, NgModule } from '@angular/core';
9
+ import { concatMap, filter, map, finalize, switchMap } from 'rxjs/operators';
10
+ import { of, Observable, from } from 'rxjs';
11
+ import { b as isPlatformServer, X as XhrFactory, p as parseCookieValue } from './xhr-BdgfMvBr.mjs';
12
+
13
+ /**
14
+ * Transforms an `HttpRequest` into a stream of `HttpEvent`s, one of which will likely be a
15
+ * `HttpResponse`.
16
+ *
17
+ * `HttpHandler` is injectable. When injected, the handler instance dispatches requests to the
18
+ * first interceptor in the chain, which dispatches to the second, etc, eventually reaching the
19
+ * `HttpBackend`.
20
+ *
21
+ * In an `HttpInterceptor`, the `HttpHandler` parameter is the next interceptor in the chain.
22
+ *
23
+ * @publicApi
24
+ */
25
+ class HttpHandler {
26
+ }
27
+ /**
28
+ * A final `HttpHandler` which will dispatch the request via browser HTTP APIs to a backend.
29
+ *
30
+ * Interceptors sit between the `HttpClient` interface and the `HttpBackend`.
31
+ *
32
+ * When injected, `HttpBackend` dispatches requests directly to the backend, without going
33
+ * through the interceptor chain.
34
+ *
35
+ * @publicApi
36
+ */
37
+ class HttpBackend {
38
+ }
39
+
40
+ /**
41
+ * Represents the header configuration options for an HTTP request.
42
+ * Instances are immutable. Modifying methods return a cloned
43
+ * instance with the change. The original object is never changed.
44
+ *
45
+ * @publicApi
46
+ */
47
+ class HttpHeaders {
48
+ /**
49
+ * Internal map of lowercase header names to values.
50
+ */
51
+ headers;
52
+ /**
53
+ * Internal map of lowercased header names to the normalized
54
+ * form of the name (the form seen first).
55
+ */
56
+ normalizedNames = new Map();
57
+ /**
58
+ * Complete the lazy initialization of this object (needed before reading).
59
+ */
60
+ lazyInit;
61
+ /**
62
+ * Queued updates to be materialized the next initialization.
63
+ */
64
+ lazyUpdate = null;
65
+ /** Constructs a new HTTP header object with the given values.*/
66
+ constructor(headers) {
67
+ if (!headers) {
68
+ this.headers = new Map();
69
+ }
70
+ else if (typeof headers === 'string') {
71
+ this.lazyInit = () => {
72
+ this.headers = new Map();
73
+ headers.split('\n').forEach((line) => {
74
+ const index = line.indexOf(':');
75
+ if (index > 0) {
76
+ const name = line.slice(0, index);
77
+ const value = line.slice(index + 1).trim();
78
+ this.addHeaderEntry(name, value);
79
+ }
80
+ });
81
+ };
82
+ }
83
+ else if (typeof Headers !== 'undefined' && headers instanceof Headers) {
84
+ this.headers = new Map();
85
+ headers.forEach((value, name) => {
86
+ this.addHeaderEntry(name, value);
87
+ });
88
+ }
89
+ else {
90
+ this.lazyInit = () => {
91
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
92
+ assertValidHeaders(headers);
93
+ }
94
+ this.headers = new Map();
95
+ Object.entries(headers).forEach(([name, values]) => {
96
+ this.setHeaderEntries(name, values);
97
+ });
98
+ };
99
+ }
100
+ }
101
+ /**
102
+ * Checks for existence of a given header.
103
+ *
104
+ * @param name The header name to check for existence.
105
+ *
106
+ * @returns True if the header exists, false otherwise.
107
+ */
108
+ has(name) {
109
+ this.init();
110
+ return this.headers.has(name.toLowerCase());
111
+ }
112
+ /**
113
+ * Retrieves the first value of a given header.
114
+ *
115
+ * @param name The header name.
116
+ *
117
+ * @returns The value string if the header exists, null otherwise
118
+ */
119
+ get(name) {
120
+ this.init();
121
+ const values = this.headers.get(name.toLowerCase());
122
+ return values && values.length > 0 ? values[0] : null;
123
+ }
124
+ /**
125
+ * Retrieves the names of the headers.
126
+ *
127
+ * @returns A list of header names.
128
+ */
129
+ keys() {
130
+ this.init();
131
+ return Array.from(this.normalizedNames.values());
132
+ }
133
+ /**
134
+ * Retrieves a list of values for a given header.
135
+ *
136
+ * @param name The header name from which to retrieve values.
137
+ *
138
+ * @returns A string of values if the header exists, null otherwise.
139
+ */
140
+ getAll(name) {
141
+ this.init();
142
+ return this.headers.get(name.toLowerCase()) || null;
143
+ }
144
+ /**
145
+ * Appends a new value to the existing set of values for a header
146
+ * and returns them in a clone of the original instance.
147
+ *
148
+ * @param name The header name for which to append the values.
149
+ * @param value The value to append.
150
+ *
151
+ * @returns A clone of the HTTP headers object with the value appended to the given header.
152
+ */
153
+ append(name, value) {
154
+ return this.clone({ name, value, op: 'a' });
155
+ }
156
+ /**
157
+ * Sets or modifies a value for a given header in a clone of the original instance.
158
+ * If the header already exists, its value is replaced with the given value
159
+ * in the returned object.
160
+ *
161
+ * @param name The header name.
162
+ * @param value The value or values to set or override for the given header.
163
+ *
164
+ * @returns A clone of the HTTP headers object with the newly set header value.
165
+ */
166
+ set(name, value) {
167
+ return this.clone({ name, value, op: 's' });
168
+ }
169
+ /**
170
+ * Deletes values for a given header in a clone of the original instance.
171
+ *
172
+ * @param name The header name.
173
+ * @param value The value or values to delete for the given header.
174
+ *
175
+ * @returns A clone of the HTTP headers object with the given value deleted.
176
+ */
177
+ delete(name, value) {
178
+ return this.clone({ name, value, op: 'd' });
179
+ }
180
+ maybeSetNormalizedName(name, lcName) {
181
+ if (!this.normalizedNames.has(lcName)) {
182
+ this.normalizedNames.set(lcName, name);
183
+ }
184
+ }
185
+ init() {
186
+ if (!!this.lazyInit) {
187
+ if (this.lazyInit instanceof HttpHeaders) {
188
+ this.copyFrom(this.lazyInit);
189
+ }
190
+ else {
191
+ this.lazyInit();
192
+ }
193
+ this.lazyInit = null;
194
+ if (!!this.lazyUpdate) {
195
+ this.lazyUpdate.forEach((update) => this.applyUpdate(update));
196
+ this.lazyUpdate = null;
197
+ }
198
+ }
199
+ }
200
+ copyFrom(other) {
201
+ other.init();
202
+ Array.from(other.headers.keys()).forEach((key) => {
203
+ this.headers.set(key, other.headers.get(key));
204
+ this.normalizedNames.set(key, other.normalizedNames.get(key));
205
+ });
206
+ }
207
+ clone(update) {
208
+ const clone = new HttpHeaders();
209
+ clone.lazyInit = !!this.lazyInit && this.lazyInit instanceof HttpHeaders ? this.lazyInit : this;
210
+ clone.lazyUpdate = (this.lazyUpdate || []).concat([update]);
211
+ return clone;
212
+ }
213
+ applyUpdate(update) {
214
+ const key = update.name.toLowerCase();
215
+ switch (update.op) {
216
+ case 'a':
217
+ case 's':
218
+ let value = update.value;
219
+ if (typeof value === 'string') {
220
+ value = [value];
221
+ }
222
+ if (value.length === 0) {
223
+ return;
224
+ }
225
+ this.maybeSetNormalizedName(update.name, key);
226
+ const base = (update.op === 'a' ? this.headers.get(key) : undefined) || [];
227
+ base.push(...value);
228
+ this.headers.set(key, base);
229
+ break;
230
+ case 'd':
231
+ const toDelete = update.value;
232
+ if (!toDelete) {
233
+ this.headers.delete(key);
234
+ this.normalizedNames.delete(key);
235
+ }
236
+ else {
237
+ let existing = this.headers.get(key);
238
+ if (!existing) {
239
+ return;
240
+ }
241
+ existing = existing.filter((value) => toDelete.indexOf(value) === -1);
242
+ if (existing.length === 0) {
243
+ this.headers.delete(key);
244
+ this.normalizedNames.delete(key);
245
+ }
246
+ else {
247
+ this.headers.set(key, existing);
248
+ }
249
+ }
250
+ break;
251
+ }
252
+ }
253
+ addHeaderEntry(name, value) {
254
+ const key = name.toLowerCase();
255
+ this.maybeSetNormalizedName(name, key);
256
+ if (this.headers.has(key)) {
257
+ this.headers.get(key).push(value);
258
+ }
259
+ else {
260
+ this.headers.set(key, [value]);
261
+ }
262
+ }
263
+ setHeaderEntries(name, values) {
264
+ const headerValues = (Array.isArray(values) ? values : [values]).map((value) => value.toString());
265
+ const key = name.toLowerCase();
266
+ this.headers.set(key, headerValues);
267
+ this.maybeSetNormalizedName(name, key);
268
+ }
269
+ /**
270
+ * @internal
271
+ */
272
+ forEach(fn) {
273
+ this.init();
274
+ Array.from(this.normalizedNames.keys()).forEach((key) => fn(this.normalizedNames.get(key), this.headers.get(key)));
275
+ }
276
+ }
277
+ /**
278
+ * Verifies that the headers object has the right shape: the values
279
+ * must be either strings, numbers or arrays. Throws an error if an invalid
280
+ * header value is present.
281
+ */
282
+ function assertValidHeaders(headers) {
283
+ for (const [key, value] of Object.entries(headers)) {
284
+ if (!(typeof value === 'string' || typeof value === 'number') && !Array.isArray(value)) {
285
+ throw new Error(`Unexpected value of the \`${key}\` header provided. ` +
286
+ `Expecting either a string, a number or an array, but got: \`${value}\`.`);
287
+ }
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Provides encoding and decoding of URL parameter and query-string values.
293
+ *
294
+ * Serializes and parses URL parameter keys and values to encode and decode them.
295
+ * If you pass URL query parameters without encoding,
296
+ * the query parameters can be misinterpreted at the receiving end.
297
+ *
298
+ *
299
+ * @publicApi
300
+ */
301
+ class HttpUrlEncodingCodec {
302
+ /**
303
+ * Encodes a key name for a URL parameter or query-string.
304
+ * @param key The key name.
305
+ * @returns The encoded key name.
306
+ */
307
+ encodeKey(key) {
308
+ return standardEncoding(key);
309
+ }
310
+ /**
311
+ * Encodes the value of a URL parameter or query-string.
312
+ * @param value The value.
313
+ * @returns The encoded value.
314
+ */
315
+ encodeValue(value) {
316
+ return standardEncoding(value);
317
+ }
318
+ /**
319
+ * Decodes an encoded URL parameter or query-string key.
320
+ * @param key The encoded key name.
321
+ * @returns The decoded key name.
322
+ */
323
+ decodeKey(key) {
324
+ return decodeURIComponent(key);
325
+ }
326
+ /**
327
+ * Decodes an encoded URL parameter or query-string value.
328
+ * @param value The encoded value.
329
+ * @returns The decoded value.
330
+ */
331
+ decodeValue(value) {
332
+ return decodeURIComponent(value);
333
+ }
334
+ }
335
+ function paramParser(rawParams, codec) {
336
+ const map = new Map();
337
+ if (rawParams.length > 0) {
338
+ // The `window.location.search` can be used while creating an instance of the `HttpParams` class
339
+ // (e.g. `new HttpParams({ fromString: window.location.search })`). The `window.location.search`
340
+ // may start with the `?` char, so we strip it if it's present.
341
+ const params = rawParams.replace(/^\?/, '').split('&');
342
+ params.forEach((param) => {
343
+ const eqIdx = param.indexOf('=');
344
+ const [key, val] = eqIdx == -1
345
+ ? [codec.decodeKey(param), '']
346
+ : [codec.decodeKey(param.slice(0, eqIdx)), codec.decodeValue(param.slice(eqIdx + 1))];
347
+ const list = map.get(key) || [];
348
+ list.push(val);
349
+ map.set(key, list);
350
+ });
351
+ }
352
+ return map;
353
+ }
354
+ /**
355
+ * Encode input string with standard encodeURIComponent and then un-encode specific characters.
356
+ */
357
+ const STANDARD_ENCODING_REGEX = /%(\d[a-f0-9])/gi;
358
+ const STANDARD_ENCODING_REPLACEMENTS = {
359
+ '40': '@',
360
+ '3A': ':',
361
+ '24': '$',
362
+ '2C': ',',
363
+ '3B': ';',
364
+ '3D': '=',
365
+ '3F': '?',
366
+ '2F': '/',
367
+ };
368
+ function standardEncoding(v) {
369
+ return encodeURIComponent(v).replace(STANDARD_ENCODING_REGEX, (s, t) => STANDARD_ENCODING_REPLACEMENTS[t] ?? s);
370
+ }
371
+ function valueToString(value) {
372
+ return `${value}`;
373
+ }
374
+ /**
375
+ * An HTTP request/response body that represents serialized parameters,
376
+ * per the MIME type `application/x-www-form-urlencoded`.
377
+ *
378
+ * This class is immutable; all mutation operations return a new instance.
379
+ *
380
+ * @publicApi
381
+ */
382
+ class HttpParams {
383
+ map;
384
+ encoder;
385
+ updates = null;
386
+ cloneFrom = null;
387
+ constructor(options = {}) {
388
+ this.encoder = options.encoder || new HttpUrlEncodingCodec();
389
+ if (options.fromString) {
390
+ if (options.fromObject) {
391
+ throw new _RuntimeError(2805 /* RuntimeErrorCode.CANNOT_SPECIFY_BOTH_FROM_STRING_AND_FROM_OBJECT */, ngDevMode && 'Cannot specify both fromString and fromObject.');
392
+ }
393
+ this.map = paramParser(options.fromString, this.encoder);
394
+ }
395
+ else if (!!options.fromObject) {
396
+ this.map = new Map();
397
+ Object.keys(options.fromObject).forEach((key) => {
398
+ const value = options.fromObject[key];
399
+ // convert the values to strings
400
+ const values = Array.isArray(value) ? value.map(valueToString) : [valueToString(value)];
401
+ this.map.set(key, values);
402
+ });
403
+ }
404
+ else {
405
+ this.map = null;
406
+ }
407
+ }
408
+ /**
409
+ * Reports whether the body includes one or more values for a given parameter.
410
+ * @param param The parameter name.
411
+ * @returns True if the parameter has one or more values,
412
+ * false if it has no value or is not present.
413
+ */
414
+ has(param) {
415
+ this.init();
416
+ return this.map.has(param);
417
+ }
418
+ /**
419
+ * Retrieves the first value for a parameter.
420
+ * @param param The parameter name.
421
+ * @returns The first value of the given parameter,
422
+ * or `null` if the parameter is not present.
423
+ */
424
+ get(param) {
425
+ this.init();
426
+ const res = this.map.get(param);
427
+ return !!res ? res[0] : null;
428
+ }
429
+ /**
430
+ * Retrieves all values for a parameter.
431
+ * @param param The parameter name.
432
+ * @returns All values in a string array,
433
+ * or `null` if the parameter not present.
434
+ */
435
+ getAll(param) {
436
+ this.init();
437
+ return this.map.get(param) || null;
438
+ }
439
+ /**
440
+ * Retrieves all the parameters for this body.
441
+ * @returns The parameter names in a string array.
442
+ */
443
+ keys() {
444
+ this.init();
445
+ return Array.from(this.map.keys());
446
+ }
447
+ /**
448
+ * Appends a new value to existing values for a parameter.
449
+ * @param param The parameter name.
450
+ * @param value The new value to add.
451
+ * @return A new body with the appended value.
452
+ */
453
+ append(param, value) {
454
+ return this.clone({ param, value, op: 'a' });
455
+ }
456
+ /**
457
+ * Constructs a new body with appended values for the given parameter name.
458
+ * @param params parameters and values
459
+ * @return A new body with the new value.
460
+ */
461
+ appendAll(params) {
462
+ const updates = [];
463
+ Object.keys(params).forEach((param) => {
464
+ const value = params[param];
465
+ if (Array.isArray(value)) {
466
+ value.forEach((_value) => {
467
+ updates.push({ param, value: _value, op: 'a' });
468
+ });
469
+ }
470
+ else {
471
+ updates.push({ param, value: value, op: 'a' });
472
+ }
473
+ });
474
+ return this.clone(updates);
475
+ }
476
+ /**
477
+ * Replaces the value for a parameter.
478
+ * @param param The parameter name.
479
+ * @param value The new value.
480
+ * @return A new body with the new value.
481
+ */
482
+ set(param, value) {
483
+ return this.clone({ param, value, op: 's' });
484
+ }
485
+ /**
486
+ * Removes a given value or all values from a parameter.
487
+ * @param param The parameter name.
488
+ * @param value The value to remove, if provided.
489
+ * @return A new body with the given value removed, or with all values
490
+ * removed if no value is specified.
491
+ */
492
+ delete(param, value) {
493
+ return this.clone({ param, value, op: 'd' });
494
+ }
495
+ /**
496
+ * Serializes the body to an encoded string, where key-value pairs (separated by `=`) are
497
+ * separated by `&`s.
498
+ */
499
+ toString() {
500
+ this.init();
501
+ return (this.keys()
502
+ .map((key) => {
503
+ const eKey = this.encoder.encodeKey(key);
504
+ // `a: ['1']` produces `'a=1'`
505
+ // `b: []` produces `''`
506
+ // `c: ['1', '2']` produces `'c=1&c=2'`
507
+ return this.map.get(key)
508
+ .map((value) => eKey + '=' + this.encoder.encodeValue(value))
509
+ .join('&');
510
+ })
511
+ // filter out empty values because `b: []` produces `''`
512
+ // which results in `a=1&&c=1&c=2` instead of `a=1&c=1&c=2` if we don't
513
+ .filter((param) => param !== '')
514
+ .join('&'));
515
+ }
516
+ clone(update) {
517
+ const clone = new HttpParams({ encoder: this.encoder });
518
+ clone.cloneFrom = this.cloneFrom || this;
519
+ clone.updates = (this.updates || []).concat(update);
520
+ return clone;
521
+ }
522
+ init() {
523
+ if (this.map === null) {
524
+ this.map = new Map();
525
+ }
526
+ if (this.cloneFrom !== null) {
527
+ this.cloneFrom.init();
528
+ this.cloneFrom.keys().forEach((key) => this.map.set(key, this.cloneFrom.map.get(key)));
529
+ this.updates.forEach((update) => {
530
+ switch (update.op) {
531
+ case 'a':
532
+ case 's':
533
+ const base = (update.op === 'a' ? this.map.get(update.param) : undefined) || [];
534
+ base.push(valueToString(update.value));
535
+ this.map.set(update.param, base);
536
+ break;
537
+ case 'd':
538
+ if (update.value !== undefined) {
539
+ let base = this.map.get(update.param) || [];
540
+ const idx = base.indexOf(valueToString(update.value));
541
+ if (idx !== -1) {
542
+ base.splice(idx, 1);
543
+ }
544
+ if (base.length > 0) {
545
+ this.map.set(update.param, base);
546
+ }
547
+ else {
548
+ this.map.delete(update.param);
549
+ }
550
+ }
551
+ else {
552
+ this.map.delete(update.param);
553
+ break;
554
+ }
555
+ }
556
+ });
557
+ this.cloneFrom = this.updates = null;
558
+ }
559
+ }
560
+ }
561
+
562
+ /**
563
+ * A token used to manipulate and access values stored in `HttpContext`.
564
+ *
565
+ * @publicApi
566
+ */
567
+ class HttpContextToken {
568
+ defaultValue;
569
+ constructor(defaultValue) {
570
+ this.defaultValue = defaultValue;
571
+ }
572
+ }
573
+ /**
574
+ * Http context stores arbitrary user defined values and ensures type safety without
575
+ * actually knowing the types. It is backed by a `Map` and guarantees that keys do not clash.
576
+ *
577
+ * This context is mutable and is shared between cloned requests unless explicitly specified.
578
+ *
579
+ * @usageNotes
580
+ *
581
+ * ### Usage Example
582
+ *
583
+ * ```ts
584
+ * // inside cache.interceptors.ts
585
+ * export const IS_CACHE_ENABLED = new HttpContextToken<boolean>(() => false);
586
+ *
587
+ * export class CacheInterceptor implements HttpInterceptor {
588
+ *
589
+ * intercept(req: HttpRequest<any>, delegate: HttpHandler): Observable<HttpEvent<any>> {
590
+ * if (req.context.get(IS_CACHE_ENABLED) === true) {
591
+ * return ...;
592
+ * }
593
+ * return delegate.handle(req);
594
+ * }
595
+ * }
596
+ *
597
+ * // inside a service
598
+ *
599
+ * this.httpClient.get('/api/weather', {
600
+ * context: new HttpContext().set(IS_CACHE_ENABLED, true)
601
+ * }).subscribe(...);
602
+ * ```
603
+ *
604
+ * @publicApi
605
+ */
606
+ class HttpContext {
607
+ map = new Map();
608
+ /**
609
+ * Store a value in the context. If a value is already present it will be overwritten.
610
+ *
611
+ * @param token The reference to an instance of `HttpContextToken`.
612
+ * @param value The value to store.
613
+ *
614
+ * @returns A reference to itself for easy chaining.
615
+ */
616
+ set(token, value) {
617
+ this.map.set(token, value);
618
+ return this;
619
+ }
620
+ /**
621
+ * Retrieve the value associated with the given token.
622
+ *
623
+ * @param token The reference to an instance of `HttpContextToken`.
624
+ *
625
+ * @returns The stored value or default if one is defined.
626
+ */
627
+ get(token) {
628
+ if (!this.map.has(token)) {
629
+ this.map.set(token, token.defaultValue());
630
+ }
631
+ return this.map.get(token);
632
+ }
633
+ /**
634
+ * Delete the value associated with the given token.
635
+ *
636
+ * @param token The reference to an instance of `HttpContextToken`.
637
+ *
638
+ * @returns A reference to itself for easy chaining.
639
+ */
640
+ delete(token) {
641
+ this.map.delete(token);
642
+ return this;
643
+ }
644
+ /**
645
+ * Checks for existence of a given token.
646
+ *
647
+ * @param token The reference to an instance of `HttpContextToken`.
648
+ *
649
+ * @returns True if the token exists, false otherwise.
650
+ */
651
+ has(token) {
652
+ return this.map.has(token);
653
+ }
654
+ /**
655
+ * @returns a list of tokens currently stored in the context.
656
+ */
657
+ keys() {
658
+ return this.map.keys();
659
+ }
660
+ }
661
+
662
+ /**
663
+ * Determine whether the given HTTP method may include a body.
664
+ */
665
+ function mightHaveBody(method) {
666
+ switch (method) {
667
+ case 'DELETE':
668
+ case 'GET':
669
+ case 'HEAD':
670
+ case 'OPTIONS':
671
+ case 'JSONP':
672
+ return false;
673
+ default:
674
+ return true;
675
+ }
676
+ }
677
+ /**
678
+ * Safely assert whether the given value is an ArrayBuffer.
679
+ *
680
+ * In some execution environments ArrayBuffer is not defined.
681
+ */
682
+ function isArrayBuffer(value) {
683
+ return typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer;
684
+ }
685
+ /**
686
+ * Safely assert whether the given value is a Blob.
687
+ *
688
+ * In some execution environments Blob is not defined.
689
+ */
690
+ function isBlob(value) {
691
+ return typeof Blob !== 'undefined' && value instanceof Blob;
692
+ }
693
+ /**
694
+ * Safely assert whether the given value is a FormData instance.
695
+ *
696
+ * In some execution environments FormData is not defined.
697
+ */
698
+ function isFormData(value) {
699
+ return typeof FormData !== 'undefined' && value instanceof FormData;
700
+ }
701
+ /**
702
+ * Safely assert whether the given value is a URLSearchParams instance.
703
+ *
704
+ * In some execution environments URLSearchParams is not defined.
705
+ */
706
+ function isUrlSearchParams(value) {
707
+ return typeof URLSearchParams !== 'undefined' && value instanceof URLSearchParams;
708
+ }
709
+ /**
710
+ * `Content-Type` is an HTTP header used to indicate the media type
711
+ * (also known as MIME type) of the resource being sent to the client
712
+ * or received from the server.
713
+ */
714
+ const CONTENT_TYPE_HEADER = 'Content-Type';
715
+ /**
716
+ * The `Accept` header is an HTTP request header that indicates the media types
717
+ * (or content types) the client is willing to receive from the server.
718
+ */
719
+ const ACCEPT_HEADER = 'Accept';
720
+ /**
721
+ * `X-Request-URL` is a custom HTTP header used in older browser versions,
722
+ * including Firefox (< 32), Chrome (< 37), Safari (< 8), and Internet Explorer,
723
+ * to include the full URL of the request in cross-origin requests.
724
+ */
725
+ const X_REQUEST_URL_HEADER = 'X-Request-URL';
726
+ /**
727
+ * `text/plain` is a content type used to indicate that the content being
728
+ * sent is plain text with no special formatting or structured data
729
+ * like HTML, XML, or JSON.
730
+ */
731
+ const TEXT_CONTENT_TYPE = 'text/plain';
732
+ /**
733
+ * `application/json` is a content type used to indicate that the content
734
+ * being sent is in the JSON format.
735
+ */
736
+ const JSON_CONTENT_TYPE = 'application/json';
737
+ /**
738
+ * `application/json, text/plain, *\/*` is a content negotiation string often seen in the
739
+ * Accept header of HTTP requests. It indicates the types of content the client is willing
740
+ * to accept from the server, with a preference for `application/json` and `text/plain`,
741
+ * but also accepting any other type (*\/*).
742
+ */
743
+ const ACCEPT_HEADER_VALUE = `${JSON_CONTENT_TYPE}, ${TEXT_CONTENT_TYPE}, */*`;
744
+ /**
745
+ * An outgoing HTTP request with an optional typed body.
746
+ *
747
+ * `HttpRequest` represents an outgoing request, including URL, method,
748
+ * headers, body, and other request configuration options. Instances should be
749
+ * assumed to be immutable. To modify a `HttpRequest`, the `clone`
750
+ * method should be used.
751
+ *
752
+ * @publicApi
753
+ */
754
+ class HttpRequest {
755
+ url;
756
+ /**
757
+ * The request body, or `null` if one isn't set.
758
+ *
759
+ * Bodies are not enforced to be immutable, as they can include a reference to any
760
+ * user-defined data type. However, interceptors should take care to preserve
761
+ * idempotence by treating them as such.
762
+ */
763
+ body = null;
764
+ /**
765
+ * Outgoing headers for this request.
766
+ */
767
+ headers;
768
+ /**
769
+ * Shared and mutable context that can be used by interceptors
770
+ */
771
+ context;
772
+ /**
773
+ * Whether this request should be made in a way that exposes progress events.
774
+ *
775
+ * Progress events are expensive (change detection runs on each event) and so
776
+ * they should only be requested if the consumer intends to monitor them.
777
+ *
778
+ * Note: The `FetchBackend` doesn't support progress report on uploads.
779
+ */
780
+ reportProgress = false;
781
+ /**
782
+ * Whether this request should be sent with outgoing credentials (cookies).
783
+ */
784
+ withCredentials = false;
785
+ /**
786
+ * The expected response type of the server.
787
+ *
788
+ * This is used to parse the response appropriately before returning it to
789
+ * the requestee.
790
+ */
791
+ responseType = 'json';
792
+ /**
793
+ * The outgoing HTTP request method.
794
+ */
795
+ method;
796
+ /**
797
+ * Outgoing URL parameters.
798
+ *
799
+ * To pass a string representation of HTTP parameters in the URL-query-string format,
800
+ * the `HttpParamsOptions`' `fromString` may be used. For example:
801
+ *
802
+ * ```ts
803
+ * new HttpParams({fromString: 'angular=awesome'})
804
+ * ```
805
+ */
806
+ params;
807
+ /**
808
+ * The outgoing URL with all URL parameters set.
809
+ */
810
+ urlWithParams;
811
+ /**
812
+ * The HttpTransferCache option for the request
813
+ */
814
+ transferCache;
815
+ constructor(method, url, third, fourth) {
816
+ this.url = url;
817
+ this.method = method.toUpperCase();
818
+ // Next, need to figure out which argument holds the HttpRequestInit
819
+ // options, if any.
820
+ let options;
821
+ // Check whether a body argument is expected. The only valid way to omit
822
+ // the body argument is to use a known no-body method like GET.
823
+ if (mightHaveBody(this.method) || !!fourth) {
824
+ // Body is the third argument, options are the fourth.
825
+ this.body = third !== undefined ? third : null;
826
+ options = fourth;
827
+ }
828
+ else {
829
+ // No body required, options are the third argument. The body stays null.
830
+ options = third;
831
+ }
832
+ // If options have been passed, interpret them.
833
+ if (options) {
834
+ // Normalize reportProgress and withCredentials.
835
+ this.reportProgress = !!options.reportProgress;
836
+ this.withCredentials = !!options.withCredentials;
837
+ // Override default response type of 'json' if one is provided.
838
+ if (!!options.responseType) {
839
+ this.responseType = options.responseType;
840
+ }
841
+ // Override headers if they're provided.
842
+ if (!!options.headers) {
843
+ this.headers = options.headers;
844
+ }
845
+ if (!!options.context) {
846
+ this.context = options.context;
847
+ }
848
+ if (!!options.params) {
849
+ this.params = options.params;
850
+ }
851
+ // We do want to assign transferCache even if it's falsy (false is valid value)
852
+ this.transferCache = options.transferCache;
853
+ }
854
+ // If no headers have been passed in, construct a new HttpHeaders instance.
855
+ this.headers ??= new HttpHeaders();
856
+ // If no context have been passed in, construct a new HttpContext instance.
857
+ this.context ??= new HttpContext();
858
+ // If no parameters have been passed in, construct a new HttpUrlEncodedParams instance.
859
+ if (!this.params) {
860
+ this.params = new HttpParams();
861
+ this.urlWithParams = url;
862
+ }
863
+ else {
864
+ // Encode the parameters to a string in preparation for inclusion in the URL.
865
+ const params = this.params.toString();
866
+ if (params.length === 0) {
867
+ // No parameters, the visible URL is just the URL given at creation time.
868
+ this.urlWithParams = url;
869
+ }
870
+ else {
871
+ // Does the URL already have query parameters? Look for '?'.
872
+ const qIdx = url.indexOf('?');
873
+ // There are 3 cases to handle:
874
+ // 1) No existing parameters -> append '?' followed by params.
875
+ // 2) '?' exists and is followed by existing query string ->
876
+ // append '&' followed by params.
877
+ // 3) '?' exists at the end of the url -> append params directly.
878
+ // This basically amounts to determining the character, if any, with
879
+ // which to join the URL and parameters.
880
+ const sep = qIdx === -1 ? '?' : qIdx < url.length - 1 ? '&' : '';
881
+ this.urlWithParams = url + sep + params;
882
+ }
883
+ }
884
+ }
885
+ /**
886
+ * Transform the free-form body into a serialized format suitable for
887
+ * transmission to the server.
888
+ */
889
+ serializeBody() {
890
+ // If no body is present, no need to serialize it.
891
+ if (this.body === null) {
892
+ return null;
893
+ }
894
+ // Check whether the body is already in a serialized form. If so,
895
+ // it can just be returned directly.
896
+ if (typeof this.body === 'string' ||
897
+ isArrayBuffer(this.body) ||
898
+ isBlob(this.body) ||
899
+ isFormData(this.body) ||
900
+ isUrlSearchParams(this.body)) {
901
+ return this.body;
902
+ }
903
+ // Check whether the body is an instance of HttpUrlEncodedParams.
904
+ if (this.body instanceof HttpParams) {
905
+ return this.body.toString();
906
+ }
907
+ // Check whether the body is an object or array, and serialize with JSON if so.
908
+ if (typeof this.body === 'object' ||
909
+ typeof this.body === 'boolean' ||
910
+ Array.isArray(this.body)) {
911
+ return JSON.stringify(this.body);
912
+ }
913
+ // Fall back on toString() for everything else.
914
+ return this.body.toString();
915
+ }
916
+ /**
917
+ * Examine the body and attempt to infer an appropriate MIME type
918
+ * for it.
919
+ *
920
+ * If no such type can be inferred, this method will return `null`.
921
+ */
922
+ detectContentTypeHeader() {
923
+ // An empty body has no content type.
924
+ if (this.body === null) {
925
+ return null;
926
+ }
927
+ // FormData bodies rely on the browser's content type assignment.
928
+ if (isFormData(this.body)) {
929
+ return null;
930
+ }
931
+ // Blobs usually have their own content type. If it doesn't, then
932
+ // no type can be inferred.
933
+ if (isBlob(this.body)) {
934
+ return this.body.type || null;
935
+ }
936
+ // Array buffers have unknown contents and thus no type can be inferred.
937
+ if (isArrayBuffer(this.body)) {
938
+ return null;
939
+ }
940
+ // Technically, strings could be a form of JSON data, but it's safe enough
941
+ // to assume they're plain strings.
942
+ if (typeof this.body === 'string') {
943
+ return TEXT_CONTENT_TYPE;
944
+ }
945
+ // `HttpUrlEncodedParams` has its own content-type.
946
+ if (this.body instanceof HttpParams) {
947
+ return 'application/x-www-form-urlencoded;charset=UTF-8';
948
+ }
949
+ // Arrays, objects, boolean and numbers will be encoded as JSON.
950
+ if (typeof this.body === 'object' ||
951
+ typeof this.body === 'number' ||
952
+ typeof this.body === 'boolean') {
953
+ return JSON_CONTENT_TYPE;
954
+ }
955
+ // No type could be inferred.
956
+ return null;
957
+ }
958
+ clone(update = {}) {
959
+ // For method, url, and responseType, take the current value unless
960
+ // it is overridden in the update hash.
961
+ const method = update.method || this.method;
962
+ const url = update.url || this.url;
963
+ const responseType = update.responseType || this.responseType;
964
+ // Carefully handle the transferCache to differentiate between
965
+ // `false` and `undefined` in the update args.
966
+ const transferCache = update.transferCache ?? this.transferCache;
967
+ // The body is somewhat special - a `null` value in update.body means
968
+ // whatever current body is present is being overridden with an empty
969
+ // body, whereas an `undefined` value in update.body implies no
970
+ // override.
971
+ const body = update.body !== undefined ? update.body : this.body;
972
+ // Carefully handle the boolean options to differentiate between
973
+ // `false` and `undefined` in the update args.
974
+ const withCredentials = update.withCredentials ?? this.withCredentials;
975
+ const reportProgress = update.reportProgress ?? this.reportProgress;
976
+ // Headers and params may be appended to if `setHeaders` or
977
+ // `setParams` are used.
978
+ let headers = update.headers || this.headers;
979
+ let params = update.params || this.params;
980
+ // Pass on context if needed
981
+ const context = update.context ?? this.context;
982
+ // Check whether the caller has asked to add headers.
983
+ if (update.setHeaders !== undefined) {
984
+ // Set every requested header.
985
+ headers = Object.keys(update.setHeaders).reduce((headers, name) => headers.set(name, update.setHeaders[name]), headers);
986
+ }
987
+ // Check whether the caller has asked to set params.
988
+ if (update.setParams) {
989
+ // Set every requested param.
990
+ params = Object.keys(update.setParams).reduce((params, param) => params.set(param, update.setParams[param]), params);
991
+ }
992
+ // Finally, construct the new HttpRequest using the pieces from above.
993
+ return new HttpRequest(method, url, body, {
994
+ params,
995
+ headers,
996
+ context,
997
+ reportProgress,
998
+ responseType,
999
+ withCredentials,
1000
+ transferCache,
1001
+ });
1002
+ }
1003
+ }
1004
+
1005
+ /**
1006
+ * Type enumeration for the different kinds of `HttpEvent`.
1007
+ *
1008
+ * @publicApi
1009
+ */
1010
+ var HttpEventType;
1011
+ (function (HttpEventType) {
1012
+ /**
1013
+ * The request was sent out over the wire.
1014
+ */
1015
+ HttpEventType[HttpEventType["Sent"] = 0] = "Sent";
1016
+ /**
1017
+ * An upload progress event was received.
1018
+ *
1019
+ * Note: The `FetchBackend` doesn't support progress report on uploads.
1020
+ */
1021
+ HttpEventType[HttpEventType["UploadProgress"] = 1] = "UploadProgress";
1022
+ /**
1023
+ * The response status code and headers were received.
1024
+ */
1025
+ HttpEventType[HttpEventType["ResponseHeader"] = 2] = "ResponseHeader";
1026
+ /**
1027
+ * A download progress event was received.
1028
+ */
1029
+ HttpEventType[HttpEventType["DownloadProgress"] = 3] = "DownloadProgress";
1030
+ /**
1031
+ * The full response including the body was received.
1032
+ */
1033
+ HttpEventType[HttpEventType["Response"] = 4] = "Response";
1034
+ /**
1035
+ * A custom event from an interceptor or a backend.
1036
+ */
1037
+ HttpEventType[HttpEventType["User"] = 5] = "User";
1038
+ })(HttpEventType || (HttpEventType = {}));
1039
+ /**
1040
+ * Base class for both `HttpResponse` and `HttpHeaderResponse`.
1041
+ *
1042
+ * @publicApi
1043
+ */
1044
+ class HttpResponseBase {
1045
+ /**
1046
+ * All response headers.
1047
+ */
1048
+ headers;
1049
+ /**
1050
+ * Response status code.
1051
+ */
1052
+ status;
1053
+ /**
1054
+ * Textual description of response status code, defaults to OK.
1055
+ *
1056
+ * Do not depend on this.
1057
+ */
1058
+ statusText;
1059
+ /**
1060
+ * URL of the resource retrieved, or null if not available.
1061
+ */
1062
+ url;
1063
+ /**
1064
+ * Whether the status code falls in the 2xx range.
1065
+ */
1066
+ ok;
1067
+ /**
1068
+ * Type of the response, narrowed to either the full response or the header.
1069
+ */
1070
+ type;
1071
+ /**
1072
+ * Super-constructor for all responses.
1073
+ *
1074
+ * The single parameter accepted is an initialization hash. Any properties
1075
+ * of the response passed there will override the default values.
1076
+ */
1077
+ constructor(init, defaultStatus = 200, defaultStatusText = 'OK') {
1078
+ // If the hash has values passed, use them to initialize the response.
1079
+ // Otherwise use the default values.
1080
+ this.headers = init.headers || new HttpHeaders();
1081
+ this.status = init.status !== undefined ? init.status : defaultStatus;
1082
+ this.statusText = init.statusText || defaultStatusText;
1083
+ this.url = init.url || null;
1084
+ // Cache the ok value to avoid defining a getter.
1085
+ this.ok = this.status >= 200 && this.status < 300;
1086
+ }
1087
+ }
1088
+ /**
1089
+ * A partial HTTP response which only includes the status and header data,
1090
+ * but no response body.
1091
+ *
1092
+ * `HttpHeaderResponse` is a `HttpEvent` available on the response
1093
+ * event stream, only when progress events are requested.
1094
+ *
1095
+ * @publicApi
1096
+ */
1097
+ class HttpHeaderResponse extends HttpResponseBase {
1098
+ /**
1099
+ * Create a new `HttpHeaderResponse` with the given parameters.
1100
+ */
1101
+ constructor(init = {}) {
1102
+ super(init);
1103
+ }
1104
+ type = HttpEventType.ResponseHeader;
1105
+ /**
1106
+ * Copy this `HttpHeaderResponse`, overriding its contents with the
1107
+ * given parameter hash.
1108
+ */
1109
+ clone(update = {}) {
1110
+ // Perform a straightforward initialization of the new HttpHeaderResponse,
1111
+ // overriding the current parameters with new ones if given.
1112
+ return new HttpHeaderResponse({
1113
+ headers: update.headers || this.headers,
1114
+ status: update.status !== undefined ? update.status : this.status,
1115
+ statusText: update.statusText || this.statusText,
1116
+ url: update.url || this.url || undefined,
1117
+ });
1118
+ }
1119
+ }
1120
+ /**
1121
+ * A full HTTP response, including a typed response body (which may be `null`
1122
+ * if one was not returned).
1123
+ *
1124
+ * `HttpResponse` is a `HttpEvent` available on the response event
1125
+ * stream.
1126
+ *
1127
+ * @publicApi
1128
+ */
1129
+ class HttpResponse extends HttpResponseBase {
1130
+ /**
1131
+ * The response body, or `null` if one was not returned.
1132
+ */
1133
+ body;
1134
+ /**
1135
+ * Construct a new `HttpResponse`.
1136
+ */
1137
+ constructor(init = {}) {
1138
+ super(init);
1139
+ this.body = init.body !== undefined ? init.body : null;
1140
+ }
1141
+ type = HttpEventType.Response;
1142
+ clone(update = {}) {
1143
+ return new HttpResponse({
1144
+ body: update.body !== undefined ? update.body : this.body,
1145
+ headers: update.headers || this.headers,
1146
+ status: update.status !== undefined ? update.status : this.status,
1147
+ statusText: update.statusText || this.statusText,
1148
+ url: update.url || this.url || undefined,
1149
+ });
1150
+ }
1151
+ }
1152
+ /**
1153
+ * A response that represents an error or failure, either from a
1154
+ * non-successful HTTP status, an error while executing the request,
1155
+ * or some other failure which occurred during the parsing of the response.
1156
+ *
1157
+ * Any error returned on the `Observable` response stream will be
1158
+ * wrapped in an `HttpErrorResponse` to provide additional context about
1159
+ * the state of the HTTP layer when the error occurred. The error property
1160
+ * will contain either a wrapped Error object or the error response returned
1161
+ * from the server.
1162
+ *
1163
+ * @publicApi
1164
+ */
1165
+ class HttpErrorResponse extends HttpResponseBase {
1166
+ name = 'HttpErrorResponse';
1167
+ message;
1168
+ error;
1169
+ /**
1170
+ * Errors are never okay, even when the status code is in the 2xx success range.
1171
+ */
1172
+ ok = false;
1173
+ constructor(init) {
1174
+ // Initialize with a default status of 0 / Unknown Error.
1175
+ super(init, 0, 'Unknown Error');
1176
+ // If the response was successful, then this was a parse error. Otherwise, it was
1177
+ // a protocol-level failure of some sort. Either the request failed in transit
1178
+ // or the server returned an unsuccessful status code.
1179
+ if (this.status >= 200 && this.status < 300) {
1180
+ this.message = `Http failure during parsing for ${init.url || '(unknown url)'}`;
1181
+ }
1182
+ else {
1183
+ this.message = `Http failure response for ${init.url || '(unknown url)'}: ${init.status} ${init.statusText}`;
1184
+ }
1185
+ this.error = init.error || null;
1186
+ }
1187
+ }
1188
+ /**
1189
+ * We use these constant to prevent pulling the whole HttpStatusCode enum
1190
+ * Those are the only ones referenced directly by the framework
1191
+ */
1192
+ const HTTP_STATUS_CODE_OK = 200;
1193
+ const HTTP_STATUS_CODE_NO_CONTENT = 204;
1194
+ /**
1195
+ * Http status codes.
1196
+ * As per https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
1197
+ * @publicApi
1198
+ */
1199
+ var HttpStatusCode;
1200
+ (function (HttpStatusCode) {
1201
+ HttpStatusCode[HttpStatusCode["Continue"] = 100] = "Continue";
1202
+ HttpStatusCode[HttpStatusCode["SwitchingProtocols"] = 101] = "SwitchingProtocols";
1203
+ HttpStatusCode[HttpStatusCode["Processing"] = 102] = "Processing";
1204
+ HttpStatusCode[HttpStatusCode["EarlyHints"] = 103] = "EarlyHints";
1205
+ HttpStatusCode[HttpStatusCode["Ok"] = 200] = "Ok";
1206
+ HttpStatusCode[HttpStatusCode["Created"] = 201] = "Created";
1207
+ HttpStatusCode[HttpStatusCode["Accepted"] = 202] = "Accepted";
1208
+ HttpStatusCode[HttpStatusCode["NonAuthoritativeInformation"] = 203] = "NonAuthoritativeInformation";
1209
+ HttpStatusCode[HttpStatusCode["NoContent"] = 204] = "NoContent";
1210
+ HttpStatusCode[HttpStatusCode["ResetContent"] = 205] = "ResetContent";
1211
+ HttpStatusCode[HttpStatusCode["PartialContent"] = 206] = "PartialContent";
1212
+ HttpStatusCode[HttpStatusCode["MultiStatus"] = 207] = "MultiStatus";
1213
+ HttpStatusCode[HttpStatusCode["AlreadyReported"] = 208] = "AlreadyReported";
1214
+ HttpStatusCode[HttpStatusCode["ImUsed"] = 226] = "ImUsed";
1215
+ HttpStatusCode[HttpStatusCode["MultipleChoices"] = 300] = "MultipleChoices";
1216
+ HttpStatusCode[HttpStatusCode["MovedPermanently"] = 301] = "MovedPermanently";
1217
+ HttpStatusCode[HttpStatusCode["Found"] = 302] = "Found";
1218
+ HttpStatusCode[HttpStatusCode["SeeOther"] = 303] = "SeeOther";
1219
+ HttpStatusCode[HttpStatusCode["NotModified"] = 304] = "NotModified";
1220
+ HttpStatusCode[HttpStatusCode["UseProxy"] = 305] = "UseProxy";
1221
+ HttpStatusCode[HttpStatusCode["Unused"] = 306] = "Unused";
1222
+ HttpStatusCode[HttpStatusCode["TemporaryRedirect"] = 307] = "TemporaryRedirect";
1223
+ HttpStatusCode[HttpStatusCode["PermanentRedirect"] = 308] = "PermanentRedirect";
1224
+ HttpStatusCode[HttpStatusCode["BadRequest"] = 400] = "BadRequest";
1225
+ HttpStatusCode[HttpStatusCode["Unauthorized"] = 401] = "Unauthorized";
1226
+ HttpStatusCode[HttpStatusCode["PaymentRequired"] = 402] = "PaymentRequired";
1227
+ HttpStatusCode[HttpStatusCode["Forbidden"] = 403] = "Forbidden";
1228
+ HttpStatusCode[HttpStatusCode["NotFound"] = 404] = "NotFound";
1229
+ HttpStatusCode[HttpStatusCode["MethodNotAllowed"] = 405] = "MethodNotAllowed";
1230
+ HttpStatusCode[HttpStatusCode["NotAcceptable"] = 406] = "NotAcceptable";
1231
+ HttpStatusCode[HttpStatusCode["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
1232
+ HttpStatusCode[HttpStatusCode["RequestTimeout"] = 408] = "RequestTimeout";
1233
+ HttpStatusCode[HttpStatusCode["Conflict"] = 409] = "Conflict";
1234
+ HttpStatusCode[HttpStatusCode["Gone"] = 410] = "Gone";
1235
+ HttpStatusCode[HttpStatusCode["LengthRequired"] = 411] = "LengthRequired";
1236
+ HttpStatusCode[HttpStatusCode["PreconditionFailed"] = 412] = "PreconditionFailed";
1237
+ HttpStatusCode[HttpStatusCode["PayloadTooLarge"] = 413] = "PayloadTooLarge";
1238
+ HttpStatusCode[HttpStatusCode["UriTooLong"] = 414] = "UriTooLong";
1239
+ HttpStatusCode[HttpStatusCode["UnsupportedMediaType"] = 415] = "UnsupportedMediaType";
1240
+ HttpStatusCode[HttpStatusCode["RangeNotSatisfiable"] = 416] = "RangeNotSatisfiable";
1241
+ HttpStatusCode[HttpStatusCode["ExpectationFailed"] = 417] = "ExpectationFailed";
1242
+ HttpStatusCode[HttpStatusCode["ImATeapot"] = 418] = "ImATeapot";
1243
+ HttpStatusCode[HttpStatusCode["MisdirectedRequest"] = 421] = "MisdirectedRequest";
1244
+ HttpStatusCode[HttpStatusCode["UnprocessableEntity"] = 422] = "UnprocessableEntity";
1245
+ HttpStatusCode[HttpStatusCode["Locked"] = 423] = "Locked";
1246
+ HttpStatusCode[HttpStatusCode["FailedDependency"] = 424] = "FailedDependency";
1247
+ HttpStatusCode[HttpStatusCode["TooEarly"] = 425] = "TooEarly";
1248
+ HttpStatusCode[HttpStatusCode["UpgradeRequired"] = 426] = "UpgradeRequired";
1249
+ HttpStatusCode[HttpStatusCode["PreconditionRequired"] = 428] = "PreconditionRequired";
1250
+ HttpStatusCode[HttpStatusCode["TooManyRequests"] = 429] = "TooManyRequests";
1251
+ HttpStatusCode[HttpStatusCode["RequestHeaderFieldsTooLarge"] = 431] = "RequestHeaderFieldsTooLarge";
1252
+ HttpStatusCode[HttpStatusCode["UnavailableForLegalReasons"] = 451] = "UnavailableForLegalReasons";
1253
+ HttpStatusCode[HttpStatusCode["InternalServerError"] = 500] = "InternalServerError";
1254
+ HttpStatusCode[HttpStatusCode["NotImplemented"] = 501] = "NotImplemented";
1255
+ HttpStatusCode[HttpStatusCode["BadGateway"] = 502] = "BadGateway";
1256
+ HttpStatusCode[HttpStatusCode["ServiceUnavailable"] = 503] = "ServiceUnavailable";
1257
+ HttpStatusCode[HttpStatusCode["GatewayTimeout"] = 504] = "GatewayTimeout";
1258
+ HttpStatusCode[HttpStatusCode["HttpVersionNotSupported"] = 505] = "HttpVersionNotSupported";
1259
+ HttpStatusCode[HttpStatusCode["VariantAlsoNegotiates"] = 506] = "VariantAlsoNegotiates";
1260
+ HttpStatusCode[HttpStatusCode["InsufficientStorage"] = 507] = "InsufficientStorage";
1261
+ HttpStatusCode[HttpStatusCode["LoopDetected"] = 508] = "LoopDetected";
1262
+ HttpStatusCode[HttpStatusCode["NotExtended"] = 510] = "NotExtended";
1263
+ HttpStatusCode[HttpStatusCode["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired";
1264
+ })(HttpStatusCode || (HttpStatusCode = {}));
1265
+
1266
+ /**
1267
+ * Constructs an instance of `HttpRequestOptions<T>` from a source `HttpMethodOptions` and
1268
+ * the given `body`. This function clones the object and adds the body.
1269
+ *
1270
+ * Note that the `responseType` *options* value is a String that identifies the
1271
+ * single data type of the response.
1272
+ * A single overload version of the method handles each response type.
1273
+ * The value of `responseType` cannot be a union, as the combined signature could imply.
1274
+ *
1275
+ */
1276
+ function addBody(options, body) {
1277
+ return {
1278
+ body,
1279
+ headers: options.headers,
1280
+ context: options.context,
1281
+ observe: options.observe,
1282
+ params: options.params,
1283
+ reportProgress: options.reportProgress,
1284
+ responseType: options.responseType,
1285
+ withCredentials: options.withCredentials,
1286
+ transferCache: options.transferCache,
1287
+ };
1288
+ }
1289
+ /**
1290
+ * Performs HTTP requests.
1291
+ * This service is available as an injectable class, with methods to perform HTTP requests.
1292
+ * Each request method has multiple signatures, and the return type varies based on
1293
+ * the signature that is called (mainly the values of `observe` and `responseType`).
1294
+ *
1295
+ * Note that the `responseType` *options* value is a String that identifies the
1296
+ * single data type of the response.
1297
+ * A single overload version of the method handles each response type.
1298
+ * The value of `responseType` cannot be a union, as the combined signature could imply.
1299
+ *
1300
+ * @usageNotes
1301
+ *
1302
+ * ### HTTP Request Example
1303
+ *
1304
+ * ```ts
1305
+ * // GET heroes whose name contains search term
1306
+ * searchHeroes(term: string): observable<Hero[]>{
1307
+ *
1308
+ * const params = new HttpParams({fromString: 'name=term'});
1309
+ * return this.httpClient.request('GET', this.heroesUrl, {responseType:'json', params});
1310
+ * }
1311
+ * ```
1312
+ *
1313
+ * Alternatively, the parameter string can be used without invoking HttpParams
1314
+ * by directly joining to the URL.
1315
+ * ```ts
1316
+ * this.httpClient.request('GET', this.heroesUrl + '?' + 'name=term', {responseType:'json'});
1317
+ * ```
1318
+ *
1319
+ *
1320
+ * ### JSONP Example
1321
+ * ```ts
1322
+ * requestJsonp(url, callback = 'callback') {
1323
+ * return this.httpClient.jsonp(this.heroesURL, callback);
1324
+ * }
1325
+ * ```
1326
+ *
1327
+ * ### PATCH Example
1328
+ * ```ts
1329
+ * // PATCH one of the heroes' name
1330
+ * patchHero (id: number, heroName: string): Observable<{}> {
1331
+ * const url = `${this.heroesUrl}/${id}`; // PATCH api/heroes/42
1332
+ * return this.httpClient.patch(url, {name: heroName}, httpOptions)
1333
+ * .pipe(catchError(this.handleError('patchHero')));
1334
+ * }
1335
+ * ```
1336
+ *
1337
+ * @see [HTTP Guide](guide/http)
1338
+ * @see [HTTP Request](api/common/http/HttpRequest)
1339
+ *
1340
+ * @publicApi
1341
+ */
1342
+ class HttpClient {
1343
+ handler;
1344
+ constructor(handler) {
1345
+ this.handler = handler;
1346
+ }
1347
+ /**
1348
+ * Constructs an observable for a generic HTTP request that, when subscribed,
1349
+ * fires the request through the chain of registered interceptors and on to the
1350
+ * server.
1351
+ *
1352
+ * You can pass an `HttpRequest` directly as the only parameter. In this case,
1353
+ * the call returns an observable of the raw `HttpEvent` stream.
1354
+ *
1355
+ * Alternatively you can pass an HTTP method as the first parameter,
1356
+ * a URL string as the second, and an options hash containing the request body as the third.
1357
+ * See `addBody()`. In this case, the specified `responseType` and `observe` options determine the
1358
+ * type of returned observable.
1359
+ * * The `responseType` value determines how a successful response body is parsed.
1360
+ * * If `responseType` is the default `json`, you can pass a type interface for the resulting
1361
+ * object as a type parameter to the call.
1362
+ *
1363
+ * The `observe` value determines the return type, according to what you are interested in
1364
+ * observing.
1365
+ * * An `observe` value of events returns an observable of the raw `HttpEvent` stream, including
1366
+ * progress events by default.
1367
+ * * An `observe` value of response returns an observable of `HttpResponse<T>`,
1368
+ * where the `T` parameter depends on the `responseType` and any optionally provided type
1369
+ * parameter.
1370
+ * * An `observe` value of body returns an observable of `<T>` with the same `T` body type.
1371
+ *
1372
+ */
1373
+ request(first, url, options = {}) {
1374
+ let req;
1375
+ // First, check whether the primary argument is an instance of `HttpRequest`.
1376
+ if (first instanceof HttpRequest) {
1377
+ // It is. The other arguments must be undefined (per the signatures) and can be
1378
+ // ignored.
1379
+ req = first;
1380
+ }
1381
+ else {
1382
+ // It's a string, so it represents a URL. Construct a request based on it,
1383
+ // and incorporate the remaining arguments (assuming `GET` unless a method is
1384
+ // provided.
1385
+ // Figure out the headers.
1386
+ let headers = undefined;
1387
+ if (options.headers instanceof HttpHeaders) {
1388
+ headers = options.headers;
1389
+ }
1390
+ else {
1391
+ headers = new HttpHeaders(options.headers);
1392
+ }
1393
+ // Sort out parameters.
1394
+ let params = undefined;
1395
+ if (!!options.params) {
1396
+ if (options.params instanceof HttpParams) {
1397
+ params = options.params;
1398
+ }
1399
+ else {
1400
+ params = new HttpParams({ fromObject: options.params });
1401
+ }
1402
+ }
1403
+ // Construct the request.
1404
+ req = new HttpRequest(first, url, options.body !== undefined ? options.body : null, {
1405
+ headers,
1406
+ context: options.context,
1407
+ params,
1408
+ reportProgress: options.reportProgress,
1409
+ // By default, JSON is assumed to be returned for all calls.
1410
+ responseType: options.responseType || 'json',
1411
+ withCredentials: options.withCredentials,
1412
+ transferCache: options.transferCache,
1413
+ });
1414
+ }
1415
+ // Start with an Observable.of() the initial request, and run the handler (which
1416
+ // includes all interceptors) inside a concatMap(). This way, the handler runs
1417
+ // inside an Observable chain, which causes interceptors to be re-run on every
1418
+ // subscription (this also makes retries re-run the handler, including interceptors).
1419
+ const events$ = of(req).pipe(concatMap((req) => this.handler.handle(req)));
1420
+ // If coming via the API signature which accepts a previously constructed HttpRequest,
1421
+ // the only option is to get the event stream. Otherwise, return the event stream if
1422
+ // that is what was requested.
1423
+ if (first instanceof HttpRequest || options.observe === 'events') {
1424
+ return events$;
1425
+ }
1426
+ // The requested stream contains either the full response or the body. In either
1427
+ // case, the first step is to filter the event stream to extract a stream of
1428
+ // responses(s).
1429
+ const res$ = (events$.pipe(filter((event) => event instanceof HttpResponse)));
1430
+ // Decide which stream to return.
1431
+ switch (options.observe || 'body') {
1432
+ case 'body':
1433
+ // The requested stream is the body. Map the response stream to the response
1434
+ // body. This could be done more simply, but a misbehaving interceptor might
1435
+ // transform the response body into a different format and ignore the requested
1436
+ // responseType. Guard against this by validating that the response is of the
1437
+ // requested type.
1438
+ switch (req.responseType) {
1439
+ case 'arraybuffer':
1440
+ return res$.pipe(map((res) => {
1441
+ // Validate that the body is an ArrayBuffer.
1442
+ if (res.body !== null && !(res.body instanceof ArrayBuffer)) {
1443
+ throw new _RuntimeError(2806 /* RuntimeErrorCode.RESPONSE_IS_NOT_AN_ARRAY_BUFFER */, ngDevMode && 'Response is not an ArrayBuffer.');
1444
+ }
1445
+ return res.body;
1446
+ }));
1447
+ case 'blob':
1448
+ return res$.pipe(map((res) => {
1449
+ // Validate that the body is a Blob.
1450
+ if (res.body !== null && !(res.body instanceof Blob)) {
1451
+ throw new _RuntimeError(2807 /* RuntimeErrorCode.RESPONSE_IS_NOT_A_BLOB */, ngDevMode && 'Response is not a Blob.');
1452
+ }
1453
+ return res.body;
1454
+ }));
1455
+ case 'text':
1456
+ return res$.pipe(map((res) => {
1457
+ // Validate that the body is a string.
1458
+ if (res.body !== null && typeof res.body !== 'string') {
1459
+ throw new _RuntimeError(2808 /* RuntimeErrorCode.RESPONSE_IS_NOT_A_STRING */, ngDevMode && 'Response is not a string.');
1460
+ }
1461
+ return res.body;
1462
+ }));
1463
+ case 'json':
1464
+ default:
1465
+ // No validation needed for JSON responses, as they can be of any type.
1466
+ return res$.pipe(map((res) => res.body));
1467
+ }
1468
+ case 'response':
1469
+ // The response stream was requested directly, so return it.
1470
+ return res$;
1471
+ default:
1472
+ // Guard against new future observe types being added.
1473
+ throw new _RuntimeError(2809 /* RuntimeErrorCode.UNHANDLED_OBSERVE_TYPE */, ngDevMode && `Unreachable: unhandled observe type ${options.observe}}`);
1474
+ }
1475
+ }
1476
+ /**
1477
+ * Constructs an observable that, when subscribed, causes the configured
1478
+ * `DELETE` request to execute on the server. See the individual overloads for
1479
+ * details on the return type.
1480
+ *
1481
+ * @param url The endpoint URL.
1482
+ * @param options The HTTP options to send with the request.
1483
+ *
1484
+ */
1485
+ delete(url, options = {}) {
1486
+ return this.request('DELETE', url, options);
1487
+ }
1488
+ /**
1489
+ * Constructs an observable that, when subscribed, causes the configured
1490
+ * `GET` request to execute on the server. See the individual overloads for
1491
+ * details on the return type.
1492
+ */
1493
+ get(url, options = {}) {
1494
+ return this.request('GET', url, options);
1495
+ }
1496
+ /**
1497
+ * Constructs an observable that, when subscribed, causes the configured
1498
+ * `HEAD` request to execute on the server. The `HEAD` method returns
1499
+ * meta information about the resource without transferring the
1500
+ * resource itself. See the individual overloads for
1501
+ * details on the return type.
1502
+ */
1503
+ head(url, options = {}) {
1504
+ return this.request('HEAD', url, options);
1505
+ }
1506
+ /**
1507
+ * Constructs an `Observable` that, when subscribed, causes a request with the special method
1508
+ * `JSONP` to be dispatched via the interceptor pipeline.
1509
+ * The [JSONP pattern](https://en.wikipedia.org/wiki/JSONP) works around limitations of certain
1510
+ * API endpoints that don't support newer,
1511
+ * and preferable [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) protocol.
1512
+ * JSONP treats the endpoint API as a JavaScript file and tricks the browser to process the
1513
+ * requests even if the API endpoint is not located on the same domain (origin) as the client-side
1514
+ * application making the request.
1515
+ * The endpoint API must support JSONP callback for JSONP requests to work.
1516
+ * The resource API returns the JSON response wrapped in a callback function.
1517
+ * You can pass the callback function name as one of the query parameters.
1518
+ * Note that JSONP requests can only be used with `GET` requests.
1519
+ *
1520
+ * @param url The resource URL.
1521
+ * @param callbackParam The callback function name.
1522
+ *
1523
+ */
1524
+ jsonp(url, callbackParam) {
1525
+ return this.request('JSONP', url, {
1526
+ params: new HttpParams().append(callbackParam, 'JSONP_CALLBACK'),
1527
+ observe: 'body',
1528
+ responseType: 'json',
1529
+ });
1530
+ }
1531
+ /**
1532
+ * Constructs an `Observable` that, when subscribed, causes the configured
1533
+ * `OPTIONS` request to execute on the server. This method allows the client
1534
+ * to determine the supported HTTP methods and other capabilities of an endpoint,
1535
+ * without implying a resource action. See the individual overloads for
1536
+ * details on the return type.
1537
+ */
1538
+ options(url, options = {}) {
1539
+ return this.request('OPTIONS', url, options);
1540
+ }
1541
+ /**
1542
+ * Constructs an observable that, when subscribed, causes the configured
1543
+ * `PATCH` request to execute on the server. See the individual overloads for
1544
+ * details on the return type.
1545
+ */
1546
+ patch(url, body, options = {}) {
1547
+ return this.request('PATCH', url, addBody(options, body));
1548
+ }
1549
+ /**
1550
+ * Constructs an observable that, when subscribed, causes the configured
1551
+ * `POST` request to execute on the server. The server responds with the location of
1552
+ * the replaced resource. See the individual overloads for
1553
+ * details on the return type.
1554
+ */
1555
+ post(url, body, options = {}) {
1556
+ return this.request('POST', url, addBody(options, body));
1557
+ }
1558
+ /**
1559
+ * Constructs an observable that, when subscribed, causes the configured
1560
+ * `PUT` request to execute on the server. The `PUT` method replaces an existing resource
1561
+ * with a new set of values.
1562
+ * See the individual overloads for details on the return type.
1563
+ */
1564
+ put(url, body, options = {}) {
1565
+ return this.request('PUT', url, addBody(options, body));
1566
+ }
1567
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpClient, deps: [{ token: HttpHandler }], target: i0.ɵɵFactoryTarget.Injectable });
1568
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpClient });
1569
+ }
1570
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpClient, decorators: [{
1571
+ type: Injectable
1572
+ }], ctorParameters: () => [{ type: HttpHandler }] });
1573
+
1574
+ const XSSI_PREFIX$1 = /^\)\]\}',?\n/;
1575
+ /**
1576
+ * Determine an appropriate URL for the response, by checking either
1577
+ * response url or the X-Request-URL header.
1578
+ */
1579
+ function getResponseUrl$1(response) {
1580
+ if (response.url) {
1581
+ return response.url;
1582
+ }
1583
+ // stored as lowercase in the map
1584
+ const xRequestUrl = X_REQUEST_URL_HEADER.toLocaleLowerCase();
1585
+ return response.headers.get(xRequestUrl);
1586
+ }
1587
+ /**
1588
+ * An internal injection token to reference `FetchBackend` implementation
1589
+ * in a tree-shakable way.
1590
+ */
1591
+ const FETCH_BACKEND = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'FETCH_BACKEND' : '');
1592
+ /**
1593
+ * Uses `fetch` to send requests to a backend server.
1594
+ *
1595
+ * This `FetchBackend` requires the support of the
1596
+ * [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) which is available on all
1597
+ * supported browsers and on Node.js v18 or later.
1598
+ *
1599
+ * @see {@link HttpHandler}
1600
+ *
1601
+ * @publicApi
1602
+ */
1603
+ class FetchBackend {
1604
+ // We use an arrow function to always reference the current global implementation of `fetch`.
1605
+ // This is helpful for cases when the global `fetch` implementation is modified by external code,
1606
+ // see https://github.com/angular/angular/issues/57527.
1607
+ fetchImpl = inject(FetchFactory, { optional: true })?.fetch ?? ((...args) => globalThis.fetch(...args));
1608
+ ngZone = inject(NgZone);
1609
+ handle(request) {
1610
+ return new Observable((observer) => {
1611
+ const aborter = new AbortController();
1612
+ this.doRequest(request, aborter.signal, observer).then(noop, (error) => observer.error(new HttpErrorResponse({ error })));
1613
+ return () => aborter.abort();
1614
+ });
1615
+ }
1616
+ async doRequest(request, signal, observer) {
1617
+ const init = this.createRequestInit(request);
1618
+ let response;
1619
+ try {
1620
+ // Run fetch outside of Angular zone.
1621
+ // This is due to Node.js fetch implementation (Undici) which uses a number of setTimeouts to check if
1622
+ // the response should eventually timeout which causes extra CD cycles every 500ms
1623
+ const fetchPromise = this.ngZone.runOutsideAngular(() => this.fetchImpl(request.urlWithParams, { signal, ...init }));
1624
+ // Make sure Zone.js doesn't trigger false-positive unhandled promise
1625
+ // error in case the Promise is rejected synchronously. See function
1626
+ // description for additional information.
1627
+ silenceSuperfluousUnhandledPromiseRejection(fetchPromise);
1628
+ // Send the `Sent` event before awaiting the response.
1629
+ observer.next({ type: HttpEventType.Sent });
1630
+ response = await fetchPromise;
1631
+ }
1632
+ catch (error) {
1633
+ observer.error(new HttpErrorResponse({
1634
+ error,
1635
+ status: error.status ?? 0,
1636
+ statusText: error.statusText,
1637
+ url: request.urlWithParams,
1638
+ headers: error.headers,
1639
+ }));
1640
+ return;
1641
+ }
1642
+ const headers = new HttpHeaders(response.headers);
1643
+ const statusText = response.statusText;
1644
+ const url = getResponseUrl$1(response) ?? request.urlWithParams;
1645
+ let status = response.status;
1646
+ let body = null;
1647
+ if (request.reportProgress) {
1648
+ observer.next(new HttpHeaderResponse({ headers, status, statusText, url }));
1649
+ }
1650
+ if (response.body) {
1651
+ // Read Progress
1652
+ const contentLength = response.headers.get('content-length');
1653
+ const chunks = [];
1654
+ const reader = response.body.getReader();
1655
+ let receivedLength = 0;
1656
+ let decoder;
1657
+ let partialText;
1658
+ // We have to check whether the Zone is defined in the global scope because this may be called
1659
+ // when the zone is nooped.
1660
+ const reqZone = typeof Zone !== 'undefined' && Zone.current;
1661
+ // Perform response processing outside of Angular zone to
1662
+ // ensure no excessive change detection runs are executed
1663
+ // Here calling the async ReadableStreamDefaultReader.read() is responsible for triggering CD
1664
+ await this.ngZone.runOutsideAngular(async () => {
1665
+ while (true) {
1666
+ const { done, value } = await reader.read();
1667
+ if (done) {
1668
+ break;
1669
+ }
1670
+ chunks.push(value);
1671
+ receivedLength += value.length;
1672
+ if (request.reportProgress) {
1673
+ partialText =
1674
+ request.responseType === 'text'
1675
+ ? (partialText ?? '') +
1676
+ (decoder ??= new TextDecoder()).decode(value, { stream: true })
1677
+ : undefined;
1678
+ const reportProgress = () => observer.next({
1679
+ type: HttpEventType.DownloadProgress,
1680
+ total: contentLength ? +contentLength : undefined,
1681
+ loaded: receivedLength,
1682
+ partialText,
1683
+ });
1684
+ reqZone ? reqZone.run(reportProgress) : reportProgress();
1685
+ }
1686
+ }
1687
+ });
1688
+ // Combine all chunks.
1689
+ const chunksAll = this.concatChunks(chunks, receivedLength);
1690
+ try {
1691
+ const contentType = response.headers.get(CONTENT_TYPE_HEADER) ?? '';
1692
+ body = this.parseBody(request, chunksAll, contentType);
1693
+ }
1694
+ catch (error) {
1695
+ // Body loading or parsing failed
1696
+ observer.error(new HttpErrorResponse({
1697
+ error,
1698
+ headers: new HttpHeaders(response.headers),
1699
+ status: response.status,
1700
+ statusText: response.statusText,
1701
+ url: getResponseUrl$1(response) ?? request.urlWithParams,
1702
+ }));
1703
+ return;
1704
+ }
1705
+ }
1706
+ // Same behavior as the XhrBackend
1707
+ if (status === 0) {
1708
+ status = body ? HTTP_STATUS_CODE_OK : 0;
1709
+ }
1710
+ // ok determines whether the response will be transmitted on the event or
1711
+ // error channel. Unsuccessful status codes (not 2xx) will always be errors,
1712
+ // but a successful status code can still result in an error if the user
1713
+ // asked for JSON data and the body cannot be parsed as such.
1714
+ const ok = status >= 200 && status < 300;
1715
+ if (ok) {
1716
+ observer.next(new HttpResponse({
1717
+ body,
1718
+ headers,
1719
+ status,
1720
+ statusText,
1721
+ url,
1722
+ }));
1723
+ // The full body has been received and delivered, no further events
1724
+ // are possible. This request is complete.
1725
+ observer.complete();
1726
+ }
1727
+ else {
1728
+ observer.error(new HttpErrorResponse({
1729
+ error: body,
1730
+ headers,
1731
+ status,
1732
+ statusText,
1733
+ url,
1734
+ }));
1735
+ }
1736
+ }
1737
+ parseBody(request, binContent, contentType) {
1738
+ switch (request.responseType) {
1739
+ case 'json':
1740
+ // stripping the XSSI when present
1741
+ const text = new TextDecoder().decode(binContent).replace(XSSI_PREFIX$1, '');
1742
+ return text === '' ? null : JSON.parse(text);
1743
+ case 'text':
1744
+ return new TextDecoder().decode(binContent);
1745
+ case 'blob':
1746
+ return new Blob([binContent], { type: contentType });
1747
+ case 'arraybuffer':
1748
+ return binContent.buffer;
1749
+ }
1750
+ }
1751
+ createRequestInit(req) {
1752
+ // We could share some of this logic with the XhrBackend
1753
+ const headers = {};
1754
+ const credentials = req.withCredentials ? 'include' : undefined;
1755
+ // Setting all the requested headers.
1756
+ req.headers.forEach((name, values) => (headers[name] = values.join(',')));
1757
+ // Add an Accept header if one isn't present already.
1758
+ if (!req.headers.has(ACCEPT_HEADER)) {
1759
+ headers[ACCEPT_HEADER] = ACCEPT_HEADER_VALUE;
1760
+ }
1761
+ // Auto-detect the Content-Type header if one isn't present already.
1762
+ if (!req.headers.has(CONTENT_TYPE_HEADER)) {
1763
+ const detectedType = req.detectContentTypeHeader();
1764
+ // Sometimes Content-Type detection fails.
1765
+ if (detectedType !== null) {
1766
+ headers[CONTENT_TYPE_HEADER] = detectedType;
1767
+ }
1768
+ }
1769
+ return {
1770
+ body: req.serializeBody(),
1771
+ method: req.method,
1772
+ headers,
1773
+ credentials,
1774
+ };
1775
+ }
1776
+ concatChunks(chunks, totalLength) {
1777
+ const chunksAll = new Uint8Array(totalLength);
1778
+ let position = 0;
1779
+ for (const chunk of chunks) {
1780
+ chunksAll.set(chunk, position);
1781
+ position += chunk.length;
1782
+ }
1783
+ return chunksAll;
1784
+ }
1785
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: FetchBackend, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1786
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: FetchBackend });
1787
+ }
1788
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: FetchBackend, decorators: [{
1789
+ type: Injectable
1790
+ }] });
1791
+ /**
1792
+ * Abstract class to provide a mocked implementation of `fetch()`
1793
+ */
1794
+ class FetchFactory {
1795
+ }
1796
+ function noop() { }
1797
+ /**
1798
+ * Zone.js treats a rejected promise that has not yet been awaited
1799
+ * as an unhandled error. This function adds a noop `.then` to make
1800
+ * sure that Zone.js doesn't throw an error if the Promise is rejected
1801
+ * synchronously.
1802
+ */
1803
+ function silenceSuperfluousUnhandledPromiseRejection(promise) {
1804
+ promise.then(noop, noop);
1805
+ }
1806
+
1807
+ function interceptorChainEndFn(req, finalHandlerFn) {
1808
+ return finalHandlerFn(req);
1809
+ }
1810
+ /**
1811
+ * Constructs a `ChainedInterceptorFn` which adapts a legacy `HttpInterceptor` to the
1812
+ * `ChainedInterceptorFn` interface.
1813
+ */
1814
+ function adaptLegacyInterceptorToChain(chainTailFn, interceptor) {
1815
+ return (initialRequest, finalHandlerFn) => interceptor.intercept(initialRequest, {
1816
+ handle: (downstreamRequest) => chainTailFn(downstreamRequest, finalHandlerFn),
1817
+ });
1818
+ }
1819
+ /**
1820
+ * Constructs a `ChainedInterceptorFn` which wraps and invokes a functional interceptor in the given
1821
+ * injector.
1822
+ */
1823
+ function chainedInterceptorFn(chainTailFn, interceptorFn, injector) {
1824
+ return (initialRequest, finalHandlerFn) => runInInjectionContext(injector, () => interceptorFn(initialRequest, (downstreamRequest) => chainTailFn(downstreamRequest, finalHandlerFn)));
1825
+ }
1826
+ /**
1827
+ * A multi-provider token that represents the array of registered
1828
+ * `HttpInterceptor` objects.
1829
+ *
1830
+ * @publicApi
1831
+ */
1832
+ const HTTP_INTERCEPTORS = new InjectionToken(ngDevMode ? 'HTTP_INTERCEPTORS' : '');
1833
+ /**
1834
+ * A multi-provided token of `HttpInterceptorFn`s.
1835
+ */
1836
+ const HTTP_INTERCEPTOR_FNS = new InjectionToken(ngDevMode ? 'HTTP_INTERCEPTOR_FNS' : '');
1837
+ /**
1838
+ * A multi-provided token of `HttpInterceptorFn`s that are only set in root.
1839
+ */
1840
+ const HTTP_ROOT_INTERCEPTOR_FNS = new InjectionToken(ngDevMode ? 'HTTP_ROOT_INTERCEPTOR_FNS' : '');
1841
+ // TODO(atscott): We need a larger discussion about stability and what should contribute to stability.
1842
+ // Should the whole interceptor chain contribute to stability or just the backend request #55075?
1843
+ // Should HttpClient contribute to stability automatically at all?
1844
+ const REQUESTS_CONTRIBUTE_TO_STABILITY = new InjectionToken(ngDevMode ? 'REQUESTS_CONTRIBUTE_TO_STABILITY' : '', { providedIn: 'root', factory: () => true });
1845
+ /**
1846
+ * Creates an `HttpInterceptorFn` which lazily initializes an interceptor chain from the legacy
1847
+ * class-based interceptors and runs the request through it.
1848
+ */
1849
+ function legacyInterceptorFnFactory() {
1850
+ let chain = null;
1851
+ return (req, handler) => {
1852
+ if (chain === null) {
1853
+ const interceptors = inject(HTTP_INTERCEPTORS, { optional: true }) ?? [];
1854
+ // Note: interceptors are wrapped right-to-left so that final execution order is
1855
+ // left-to-right. That is, if `interceptors` is the array `[a, b, c]`, we want to
1856
+ // produce a chain that is conceptually `c(b(a(end)))`, which we build from the inside
1857
+ // out.
1858
+ chain = interceptors.reduceRight(adaptLegacyInterceptorToChain, interceptorChainEndFn);
1859
+ }
1860
+ const pendingTasks = inject(_PendingTasksInternal);
1861
+ const contributeToStability = inject(REQUESTS_CONTRIBUTE_TO_STABILITY);
1862
+ if (contributeToStability) {
1863
+ const taskId = pendingTasks.add();
1864
+ return chain(req, handler).pipe(finalize(() => pendingTasks.remove(taskId)));
1865
+ }
1866
+ else {
1867
+ return chain(req, handler);
1868
+ }
1869
+ };
1870
+ }
1871
+ let fetchBackendWarningDisplayed = false;
1872
+ class HttpInterceptorHandler extends HttpHandler {
1873
+ backend;
1874
+ injector;
1875
+ chain = null;
1876
+ pendingTasks = inject(_PendingTasksInternal);
1877
+ contributeToStability = inject(REQUESTS_CONTRIBUTE_TO_STABILITY);
1878
+ constructor(backend, injector) {
1879
+ super();
1880
+ this.backend = backend;
1881
+ this.injector = injector;
1882
+ // We strongly recommend using fetch backend for HTTP calls when SSR is used
1883
+ // for an application. The logic below checks if that's the case and produces
1884
+ // a warning otherwise.
1885
+ if ((typeof ngDevMode === 'undefined' || ngDevMode) && !fetchBackendWarningDisplayed) {
1886
+ const isServer = isPlatformServer(injector.get(PLATFORM_ID));
1887
+ // This flag is necessary because provideHttpClientTesting() overrides the backend
1888
+ // even if `withFetch()` is used within the test. When the testing HTTP backend is provided,
1889
+ // no HTTP calls are actually performed during the test, so producing a warning would be
1890
+ // misleading.
1891
+ const isTestingBackend = this.backend.isTestingBackend;
1892
+ if (isServer && !(this.backend instanceof FetchBackend) && !isTestingBackend) {
1893
+ fetchBackendWarningDisplayed = true;
1894
+ injector
1895
+ .get(_Console)
1896
+ .warn(_formatRuntimeError(2801 /* RuntimeErrorCode.NOT_USING_FETCH_BACKEND_IN_SSR */, 'Angular detected that `HttpClient` is not configured ' +
1897
+ "to use `fetch` APIs. It's strongly recommended to " +
1898
+ 'enable `fetch` for applications that use Server-Side Rendering ' +
1899
+ 'for better performance and compatibility. ' +
1900
+ 'To enable `fetch`, add the `withFetch()` to the `provideHttpClient()` ' +
1901
+ 'call at the root of the application.'));
1902
+ }
1903
+ }
1904
+ }
1905
+ handle(initialRequest) {
1906
+ if (this.chain === null) {
1907
+ const dedupedInterceptorFns = Array.from(new Set([
1908
+ ...this.injector.get(HTTP_INTERCEPTOR_FNS),
1909
+ ...this.injector.get(HTTP_ROOT_INTERCEPTOR_FNS, []),
1910
+ ]));
1911
+ // Note: interceptors are wrapped right-to-left so that final execution order is
1912
+ // left-to-right. That is, if `dedupedInterceptorFns` is the array `[a, b, c]`, we want to
1913
+ // produce a chain that is conceptually `c(b(a(end)))`, which we build from the inside
1914
+ // out.
1915
+ this.chain = dedupedInterceptorFns.reduceRight((nextSequencedFn, interceptorFn) => chainedInterceptorFn(nextSequencedFn, interceptorFn, this.injector), interceptorChainEndFn);
1916
+ }
1917
+ if (this.contributeToStability) {
1918
+ const taskId = this.pendingTasks.add();
1919
+ return this.chain(initialRequest, (downstreamRequest) => this.backend.handle(downstreamRequest)).pipe(finalize(() => this.pendingTasks.remove(taskId)));
1920
+ }
1921
+ else {
1922
+ return this.chain(initialRequest, (downstreamRequest) => this.backend.handle(downstreamRequest));
1923
+ }
1924
+ }
1925
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpInterceptorHandler, deps: [{ token: HttpBackend }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable });
1926
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpInterceptorHandler });
1927
+ }
1928
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpInterceptorHandler, decorators: [{
1929
+ type: Injectable
1930
+ }], ctorParameters: () => [{ type: HttpBackend }, { type: i0.EnvironmentInjector }] });
1931
+
1932
+ // Every request made through JSONP needs a callback name that's unique across the
1933
+ // whole page. Each request is assigned an id and the callback name is constructed
1934
+ // from that. The next id to be assigned is tracked in a global variable here that
1935
+ // is shared among all applications on the page.
1936
+ let nextRequestId = 0;
1937
+ /**
1938
+ * When a pending <script> is unsubscribed we'll move it to this document, so it won't be
1939
+ * executed.
1940
+ */
1941
+ let foreignDocument;
1942
+ // Error text given when a JSONP script is injected, but doesn't invoke the callback
1943
+ // passed in its URL.
1944
+ const JSONP_ERR_NO_CALLBACK = 'JSONP injected script did not invoke callback.';
1945
+ // Error text given when a request is passed to the JsonpClientBackend that doesn't
1946
+ // have a request method JSONP.
1947
+ const JSONP_ERR_WRONG_METHOD = 'JSONP requests must use JSONP request method.';
1948
+ const JSONP_ERR_WRONG_RESPONSE_TYPE = 'JSONP requests must use Json response type.';
1949
+ // Error text given when a request is passed to the JsonpClientBackend that has
1950
+ // headers set
1951
+ const JSONP_ERR_HEADERS_NOT_SUPPORTED = 'JSONP requests do not support headers.';
1952
+ /**
1953
+ * DI token/abstract type representing a map of JSONP callbacks.
1954
+ *
1955
+ * In the browser, this should always be the `window` object.
1956
+ *
1957
+ *
1958
+ */
1959
+ class JsonpCallbackContext {
1960
+ }
1961
+ /**
1962
+ * Factory function that determines where to store JSONP callbacks.
1963
+ *
1964
+ * Ordinarily JSONP callbacks are stored on the `window` object, but this may not exist
1965
+ * in test environments. In that case, callbacks are stored on an anonymous object instead.
1966
+ *
1967
+ *
1968
+ */
1969
+ function jsonpCallbackContext() {
1970
+ if (typeof window === 'object') {
1971
+ return window;
1972
+ }
1973
+ return {};
1974
+ }
1975
+ /**
1976
+ * Processes an `HttpRequest` with the JSONP method,
1977
+ * by performing JSONP style requests.
1978
+ * @see {@link HttpHandler}
1979
+ * @see {@link HttpXhrBackend}
1980
+ *
1981
+ * @publicApi
1982
+ */
1983
+ class JsonpClientBackend {
1984
+ callbackMap;
1985
+ document;
1986
+ /**
1987
+ * A resolved promise that can be used to schedule microtasks in the event handlers.
1988
+ */
1989
+ resolvedPromise = Promise.resolve();
1990
+ constructor(callbackMap, document) {
1991
+ this.callbackMap = callbackMap;
1992
+ this.document = document;
1993
+ }
1994
+ /**
1995
+ * Get the name of the next callback method, by incrementing the global `nextRequestId`.
1996
+ */
1997
+ nextCallback() {
1998
+ return `ng_jsonp_callback_${nextRequestId++}`;
1999
+ }
2000
+ /**
2001
+ * Processes a JSONP request and returns an event stream of the results.
2002
+ * @param req The request object.
2003
+ * @returns An observable of the response events.
2004
+ *
2005
+ */
2006
+ handle(req) {
2007
+ // Firstly, check both the method and response type. If either doesn't match
2008
+ // then the request was improperly routed here and cannot be handled.
2009
+ if (req.method !== 'JSONP') {
2010
+ throw new _RuntimeError(2810 /* RuntimeErrorCode.JSONP_WRONG_METHOD */, ngDevMode && JSONP_ERR_WRONG_METHOD);
2011
+ }
2012
+ else if (req.responseType !== 'json') {
2013
+ throw new _RuntimeError(2811 /* RuntimeErrorCode.JSONP_WRONG_RESPONSE_TYPE */, ngDevMode && JSONP_ERR_WRONG_RESPONSE_TYPE);
2014
+ }
2015
+ // Check the request headers. JSONP doesn't support headers and
2016
+ // cannot set any that were supplied.
2017
+ if (req.headers.keys().length > 0) {
2018
+ throw new _RuntimeError(2812 /* RuntimeErrorCode.JSONP_HEADERS_NOT_SUPPORTED */, ngDevMode && JSONP_ERR_HEADERS_NOT_SUPPORTED);
2019
+ }
2020
+ // Everything else happens inside the Observable boundary.
2021
+ return new Observable((observer) => {
2022
+ // The first step to make a request is to generate the callback name, and replace the
2023
+ // callback placeholder in the URL with the name. Care has to be taken here to ensure
2024
+ // a trailing &, if matched, gets inserted back into the URL in the correct place.
2025
+ const callback = this.nextCallback();
2026
+ const url = req.urlWithParams.replace(/=JSONP_CALLBACK(&|$)/, `=${callback}$1`);
2027
+ // Construct the <script> tag and point it at the URL.
2028
+ const node = this.document.createElement('script');
2029
+ node.src = url;
2030
+ // A JSONP request requires waiting for multiple callbacks. These variables
2031
+ // are closed over and track state across those callbacks.
2032
+ // The response object, if one has been received, or null otherwise.
2033
+ let body = null;
2034
+ // Whether the response callback has been called.
2035
+ let finished = false;
2036
+ // Set the response callback in this.callbackMap (which will be the window
2037
+ // object in the browser. The script being loaded via the <script> tag will
2038
+ // eventually call this callback.
2039
+ this.callbackMap[callback] = (data) => {
2040
+ // Data has been received from the JSONP script. Firstly, delete this callback.
2041
+ delete this.callbackMap[callback];
2042
+ // Set state to indicate data was received.
2043
+ body = data;
2044
+ finished = true;
2045
+ };
2046
+ // cleanup() is a utility closure that removes the <script> from the page and
2047
+ // the response callback from the window. This logic is used in both the
2048
+ // success, error, and cancellation paths, so it's extracted out for convenience.
2049
+ const cleanup = () => {
2050
+ node.removeEventListener('load', onLoad);
2051
+ node.removeEventListener('error', onError);
2052
+ // Remove the <script> tag if it's still on the page.
2053
+ node.remove();
2054
+ // Remove the response callback from the callbackMap (window object in the
2055
+ // browser).
2056
+ delete this.callbackMap[callback];
2057
+ };
2058
+ // onLoad() is the success callback which runs after the response callback
2059
+ // if the JSONP script loads successfully. The event itself is unimportant.
2060
+ // If something went wrong, onLoad() may run without the response callback
2061
+ // having been invoked.
2062
+ const onLoad = () => {
2063
+ // We wrap it in an extra Promise, to ensure the microtask
2064
+ // is scheduled after the loaded endpoint has executed any potential microtask itself,
2065
+ // which is not guaranteed in Internet Explorer and EdgeHTML. See issue #39496
2066
+ this.resolvedPromise.then(() => {
2067
+ // Cleanup the page.
2068
+ cleanup();
2069
+ // Check whether the response callback has run.
2070
+ if (!finished) {
2071
+ // It hasn't, something went wrong with the request. Return an error via
2072
+ // the Observable error path. All JSONP errors have status 0.
2073
+ observer.error(new HttpErrorResponse({
2074
+ url,
2075
+ status: 0,
2076
+ statusText: 'JSONP Error',
2077
+ error: new Error(JSONP_ERR_NO_CALLBACK),
2078
+ }));
2079
+ return;
2080
+ }
2081
+ // Success. body either contains the response body or null if none was
2082
+ // returned.
2083
+ observer.next(new HttpResponse({
2084
+ body,
2085
+ status: HTTP_STATUS_CODE_OK,
2086
+ statusText: 'OK',
2087
+ url,
2088
+ }));
2089
+ // Complete the stream, the response is over.
2090
+ observer.complete();
2091
+ });
2092
+ };
2093
+ // onError() is the error callback, which runs if the script returned generates
2094
+ // a Javascript error. It emits the error via the Observable error channel as
2095
+ // a HttpErrorResponse.
2096
+ const onError = (error) => {
2097
+ cleanup();
2098
+ // Wrap the error in a HttpErrorResponse.
2099
+ observer.error(new HttpErrorResponse({
2100
+ error,
2101
+ status: 0,
2102
+ statusText: 'JSONP Error',
2103
+ url,
2104
+ }));
2105
+ };
2106
+ // Subscribe to both the success (load) and error events on the <script> tag,
2107
+ // and add it to the page.
2108
+ node.addEventListener('load', onLoad);
2109
+ node.addEventListener('error', onError);
2110
+ this.document.body.appendChild(node);
2111
+ // The request has now been successfully sent.
2112
+ observer.next({ type: HttpEventType.Sent });
2113
+ // Cancellation handler.
2114
+ return () => {
2115
+ if (!finished) {
2116
+ this.removeListeners(node);
2117
+ }
2118
+ // And finally, clean up the page.
2119
+ cleanup();
2120
+ };
2121
+ });
2122
+ }
2123
+ removeListeners(script) {
2124
+ // Issue #34818
2125
+ // Changing <script>'s ownerDocument will prevent it from execution.
2126
+ // https://html.spec.whatwg.org/multipage/scripting.html#execute-the-script-block
2127
+ foreignDocument ??= this.document.implementation.createHTMLDocument();
2128
+ foreignDocument.adoptNode(script);
2129
+ }
2130
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: JsonpClientBackend, deps: [{ token: JsonpCallbackContext }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable });
2131
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: JsonpClientBackend });
2132
+ }
2133
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: JsonpClientBackend, decorators: [{
2134
+ type: Injectable
2135
+ }], ctorParameters: () => [{ type: JsonpCallbackContext }, { type: undefined, decorators: [{
2136
+ type: Inject,
2137
+ args: [DOCUMENT]
2138
+ }] }] });
2139
+ /**
2140
+ * Identifies requests with the method JSONP and shifts them to the `JsonpClientBackend`.
2141
+ */
2142
+ function jsonpInterceptorFn(req, next) {
2143
+ if (req.method === 'JSONP') {
2144
+ return inject(JsonpClientBackend).handle(req);
2145
+ }
2146
+ // Fall through for normal HTTP requests.
2147
+ return next(req);
2148
+ }
2149
+ /**
2150
+ * Identifies requests with the method JSONP and
2151
+ * shifts them to the `JsonpClientBackend`.
2152
+ *
2153
+ * @see {@link HttpInterceptor}
2154
+ *
2155
+ * @publicApi
2156
+ */
2157
+ class JsonpInterceptor {
2158
+ injector;
2159
+ constructor(injector) {
2160
+ this.injector = injector;
2161
+ }
2162
+ /**
2163
+ * Identifies and handles a given JSONP request.
2164
+ * @param initialRequest The outgoing request object to handle.
2165
+ * @param next The next interceptor in the chain, or the backend
2166
+ * if no interceptors remain in the chain.
2167
+ * @returns An observable of the event stream.
2168
+ */
2169
+ intercept(initialRequest, next) {
2170
+ return runInInjectionContext(this.injector, () => jsonpInterceptorFn(initialRequest, (downstreamRequest) => next.handle(downstreamRequest)));
2171
+ }
2172
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: JsonpInterceptor, deps: [{ token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable });
2173
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: JsonpInterceptor });
2174
+ }
2175
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: JsonpInterceptor, decorators: [{
2176
+ type: Injectable
2177
+ }], ctorParameters: () => [{ type: i0.EnvironmentInjector }] });
2178
+
2179
+ const XSSI_PREFIX = /^\)\]\}',?\n/;
2180
+ const X_REQUEST_URL_REGEXP = RegExp(`^${X_REQUEST_URL_HEADER}:`, 'm');
2181
+ /**
2182
+ * Determine an appropriate URL for the response, by checking either
2183
+ * XMLHttpRequest.responseURL or the X-Request-URL header.
2184
+ */
2185
+ function getResponseUrl(xhr) {
2186
+ if ('responseURL' in xhr && xhr.responseURL) {
2187
+ return xhr.responseURL;
2188
+ }
2189
+ if (X_REQUEST_URL_REGEXP.test(xhr.getAllResponseHeaders())) {
2190
+ return xhr.getResponseHeader(X_REQUEST_URL_HEADER);
2191
+ }
2192
+ return null;
2193
+ }
2194
+ /**
2195
+ * Uses `XMLHttpRequest` to send requests to a backend server.
2196
+ * @see {@link HttpHandler}
2197
+ * @see {@link JsonpClientBackend}
2198
+ *
2199
+ * @publicApi
2200
+ */
2201
+ class HttpXhrBackend {
2202
+ xhrFactory;
2203
+ constructor(xhrFactory) {
2204
+ this.xhrFactory = xhrFactory;
2205
+ }
2206
+ /**
2207
+ * Processes a request and returns a stream of response events.
2208
+ * @param req The request object.
2209
+ * @returns An observable of the response events.
2210
+ */
2211
+ handle(req) {
2212
+ // Quick check to give a better error message when a user attempts to use
2213
+ // HttpClient.jsonp() without installing the HttpClientJsonpModule
2214
+ if (req.method === 'JSONP') {
2215
+ throw new _RuntimeError(-2800 /* RuntimeErrorCode.MISSING_JSONP_MODULE */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
2216
+ `Cannot make a JSONP request without JSONP support. To fix the problem, either add the \`withJsonpSupport()\` call (if \`provideHttpClient()\` is used) or import the \`HttpClientJsonpModule\` in the root NgModule.`);
2217
+ }
2218
+ // Check whether this factory has a special function to load an XHR implementation
2219
+ // for various non-browser environments. We currently limit it to only `ServerXhr`
2220
+ // class, which needs to load an XHR implementation.
2221
+ const xhrFactory = this.xhrFactory;
2222
+ const source = xhrFactory.ɵloadImpl
2223
+ ? from(xhrFactory.ɵloadImpl())
2224
+ : of(null);
2225
+ return source.pipe(switchMap(() => {
2226
+ // Everything happens on Observable subscription.
2227
+ return new Observable((observer) => {
2228
+ // Start by setting up the XHR object with request method, URL, and withCredentials
2229
+ // flag.
2230
+ const xhr = xhrFactory.build();
2231
+ xhr.open(req.method, req.urlWithParams);
2232
+ if (req.withCredentials) {
2233
+ xhr.withCredentials = true;
2234
+ }
2235
+ // Add all the requested headers.
2236
+ req.headers.forEach((name, values) => xhr.setRequestHeader(name, values.join(',')));
2237
+ // Add an Accept header if one isn't present already.
2238
+ if (!req.headers.has(ACCEPT_HEADER)) {
2239
+ xhr.setRequestHeader(ACCEPT_HEADER, ACCEPT_HEADER_VALUE);
2240
+ }
2241
+ // Auto-detect the Content-Type header if one isn't present already.
2242
+ if (!req.headers.has(CONTENT_TYPE_HEADER)) {
2243
+ const detectedType = req.detectContentTypeHeader();
2244
+ // Sometimes Content-Type detection fails.
2245
+ if (detectedType !== null) {
2246
+ xhr.setRequestHeader(CONTENT_TYPE_HEADER, detectedType);
2247
+ }
2248
+ }
2249
+ // Set the responseType if one was requested.
2250
+ if (req.responseType) {
2251
+ const responseType = req.responseType.toLowerCase();
2252
+ // JSON responses need to be processed as text. This is because if the server
2253
+ // returns an XSSI-prefixed JSON response, the browser will fail to parse it,
2254
+ // xhr.response will be null, and xhr.responseText cannot be accessed to
2255
+ // retrieve the prefixed JSON data in order to strip the prefix. Thus, all JSON
2256
+ // is parsed by first requesting text and then applying JSON.parse.
2257
+ xhr.responseType = (responseType !== 'json' ? responseType : 'text');
2258
+ }
2259
+ // Serialize the request body if one is present. If not, this will be set to null.
2260
+ const reqBody = req.serializeBody();
2261
+ // If progress events are enabled, response headers will be delivered
2262
+ // in two events - the HttpHeaderResponse event and the full HttpResponse
2263
+ // event. However, since response headers don't change in between these
2264
+ // two events, it doesn't make sense to parse them twice. So headerResponse
2265
+ // caches the data extracted from the response whenever it's first parsed,
2266
+ // to ensure parsing isn't duplicated.
2267
+ let headerResponse = null;
2268
+ // partialFromXhr extracts the HttpHeaderResponse from the current XMLHttpRequest
2269
+ // state, and memoizes it into headerResponse.
2270
+ const partialFromXhr = () => {
2271
+ if (headerResponse !== null) {
2272
+ return headerResponse;
2273
+ }
2274
+ const statusText = xhr.statusText || 'OK';
2275
+ // Parse headers from XMLHttpRequest - this step is lazy.
2276
+ const headers = new HttpHeaders(xhr.getAllResponseHeaders());
2277
+ // Read the response URL from the XMLHttpResponse instance and fall back on the
2278
+ // request URL.
2279
+ const url = getResponseUrl(xhr) || req.url;
2280
+ // Construct the HttpHeaderResponse and memoize it.
2281
+ headerResponse = new HttpHeaderResponse({ headers, status: xhr.status, statusText, url });
2282
+ return headerResponse;
2283
+ };
2284
+ // Next, a few closures are defined for the various events which XMLHttpRequest can
2285
+ // emit. This allows them to be unregistered as event listeners later.
2286
+ // First up is the load event, which represents a response being fully available.
2287
+ const onLoad = () => {
2288
+ // Read response state from the memoized partial data.
2289
+ let { headers, status, statusText, url } = partialFromXhr();
2290
+ // The body will be read out if present.
2291
+ let body = null;
2292
+ if (status !== HTTP_STATUS_CODE_NO_CONTENT) {
2293
+ // Use XMLHttpRequest.response if set, responseText otherwise.
2294
+ body = typeof xhr.response === 'undefined' ? xhr.responseText : xhr.response;
2295
+ }
2296
+ // Normalize another potential bug (this one comes from CORS).
2297
+ if (status === 0) {
2298
+ status = !!body ? HTTP_STATUS_CODE_OK : 0;
2299
+ }
2300
+ // ok determines whether the response will be transmitted on the event or
2301
+ // error channel. Unsuccessful status codes (not 2xx) will always be errors,
2302
+ // but a successful status code can still result in an error if the user
2303
+ // asked for JSON data and the body cannot be parsed as such.
2304
+ let ok = status >= 200 && status < 300;
2305
+ // Check whether the body needs to be parsed as JSON (in many cases the browser
2306
+ // will have done that already).
2307
+ if (req.responseType === 'json' && typeof body === 'string') {
2308
+ // Save the original body, before attempting XSSI prefix stripping.
2309
+ const originalBody = body;
2310
+ body = body.replace(XSSI_PREFIX, '');
2311
+ try {
2312
+ // Attempt the parse. If it fails, a parse error should be delivered to the
2313
+ // user.
2314
+ body = body !== '' ? JSON.parse(body) : null;
2315
+ }
2316
+ catch (error) {
2317
+ // Since the JSON.parse failed, it's reasonable to assume this might not have
2318
+ // been a JSON response. Restore the original body (including any XSSI prefix)
2319
+ // to deliver a better error response.
2320
+ body = originalBody;
2321
+ // If this was an error request to begin with, leave it as a string, it
2322
+ // probably just isn't JSON. Otherwise, deliver the parsing error to the user.
2323
+ if (ok) {
2324
+ // Even though the response status was 2xx, this is still an error.
2325
+ ok = false;
2326
+ // The parse error contains the text of the body that failed to parse.
2327
+ body = { error, text: body };
2328
+ }
2329
+ }
2330
+ }
2331
+ if (ok) {
2332
+ // A successful response is delivered on the event stream.
2333
+ observer.next(new HttpResponse({
2334
+ body,
2335
+ headers,
2336
+ status,
2337
+ statusText,
2338
+ url: url || undefined,
2339
+ }));
2340
+ // The full body has been received and delivered, no further events
2341
+ // are possible. This request is complete.
2342
+ observer.complete();
2343
+ }
2344
+ else {
2345
+ // An unsuccessful request is delivered on the error channel.
2346
+ observer.error(new HttpErrorResponse({
2347
+ // The error in this case is the response body (error from the server).
2348
+ error: body,
2349
+ headers,
2350
+ status,
2351
+ statusText,
2352
+ url: url || undefined,
2353
+ }));
2354
+ }
2355
+ };
2356
+ // The onError callback is called when something goes wrong at the network level.
2357
+ // Connection timeout, DNS error, offline, etc. These are actual errors, and are
2358
+ // transmitted on the error channel.
2359
+ const onError = (error) => {
2360
+ const { url } = partialFromXhr();
2361
+ const res = new HttpErrorResponse({
2362
+ error,
2363
+ status: xhr.status || 0,
2364
+ statusText: xhr.statusText || 'Unknown Error',
2365
+ url: url || undefined,
2366
+ });
2367
+ observer.error(res);
2368
+ };
2369
+ // The sentHeaders flag tracks whether the HttpResponseHeaders event
2370
+ // has been sent on the stream. This is necessary to track if progress
2371
+ // is enabled since the event will be sent on only the first download
2372
+ // progress event.
2373
+ let sentHeaders = false;
2374
+ // The download progress event handler, which is only registered if
2375
+ // progress events are enabled.
2376
+ const onDownProgress = (event) => {
2377
+ // Send the HttpResponseHeaders event if it hasn't been sent already.
2378
+ if (!sentHeaders) {
2379
+ observer.next(partialFromXhr());
2380
+ sentHeaders = true;
2381
+ }
2382
+ // Start building the download progress event to deliver on the response
2383
+ // event stream.
2384
+ let progressEvent = {
2385
+ type: HttpEventType.DownloadProgress,
2386
+ loaded: event.loaded,
2387
+ };
2388
+ // Set the total number of bytes in the event if it's available.
2389
+ if (event.lengthComputable) {
2390
+ progressEvent.total = event.total;
2391
+ }
2392
+ // If the request was for text content and a partial response is
2393
+ // available on XMLHttpRequest, include it in the progress event
2394
+ // to allow for streaming reads.
2395
+ if (req.responseType === 'text' && !!xhr.responseText) {
2396
+ progressEvent.partialText = xhr.responseText;
2397
+ }
2398
+ // Finally, fire the event.
2399
+ observer.next(progressEvent);
2400
+ };
2401
+ // The upload progress event handler, which is only registered if
2402
+ // progress events are enabled.
2403
+ const onUpProgress = (event) => {
2404
+ // Upload progress events are simpler. Begin building the progress
2405
+ // event.
2406
+ let progress = {
2407
+ type: HttpEventType.UploadProgress,
2408
+ loaded: event.loaded,
2409
+ };
2410
+ // If the total number of bytes being uploaded is available, include
2411
+ // it.
2412
+ if (event.lengthComputable) {
2413
+ progress.total = event.total;
2414
+ }
2415
+ // Send the event.
2416
+ observer.next(progress);
2417
+ };
2418
+ // By default, register for load and error events.
2419
+ xhr.addEventListener('load', onLoad);
2420
+ xhr.addEventListener('error', onError);
2421
+ xhr.addEventListener('timeout', onError);
2422
+ xhr.addEventListener('abort', onError);
2423
+ // Progress events are only enabled if requested.
2424
+ if (req.reportProgress) {
2425
+ // Download progress is always enabled if requested.
2426
+ xhr.addEventListener('progress', onDownProgress);
2427
+ // Upload progress depends on whether there is a body to upload.
2428
+ if (reqBody !== null && xhr.upload) {
2429
+ xhr.upload.addEventListener('progress', onUpProgress);
2430
+ }
2431
+ }
2432
+ // Fire the request, and notify the event stream that it was fired.
2433
+ xhr.send(reqBody);
2434
+ observer.next({ type: HttpEventType.Sent });
2435
+ // This is the return from the Observable function, which is the
2436
+ // request cancellation handler.
2437
+ return () => {
2438
+ // On a cancellation, remove all registered event listeners.
2439
+ xhr.removeEventListener('error', onError);
2440
+ xhr.removeEventListener('abort', onError);
2441
+ xhr.removeEventListener('load', onLoad);
2442
+ xhr.removeEventListener('timeout', onError);
2443
+ if (req.reportProgress) {
2444
+ xhr.removeEventListener('progress', onDownProgress);
2445
+ if (reqBody !== null && xhr.upload) {
2446
+ xhr.upload.removeEventListener('progress', onUpProgress);
2447
+ }
2448
+ }
2449
+ // Finally, abort the in-flight request.
2450
+ if (xhr.readyState !== xhr.DONE) {
2451
+ xhr.abort();
2452
+ }
2453
+ };
2454
+ });
2455
+ }));
2456
+ }
2457
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpXhrBackend, deps: [{ token: XhrFactory }], target: i0.ɵɵFactoryTarget.Injectable });
2458
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpXhrBackend });
2459
+ }
2460
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpXhrBackend, decorators: [{
2461
+ type: Injectable
2462
+ }], ctorParameters: () => [{ type: XhrFactory }] });
2463
+
2464
+ const XSRF_ENABLED = new InjectionToken(ngDevMode ? 'XSRF_ENABLED' : '');
2465
+ const XSRF_DEFAULT_COOKIE_NAME = 'XSRF-TOKEN';
2466
+ const XSRF_COOKIE_NAME = new InjectionToken(ngDevMode ? 'XSRF_COOKIE_NAME' : '', {
2467
+ providedIn: 'root',
2468
+ factory: () => XSRF_DEFAULT_COOKIE_NAME,
2469
+ });
2470
+ const XSRF_DEFAULT_HEADER_NAME = 'X-XSRF-TOKEN';
2471
+ const XSRF_HEADER_NAME = new InjectionToken(ngDevMode ? 'XSRF_HEADER_NAME' : '', {
2472
+ providedIn: 'root',
2473
+ factory: () => XSRF_DEFAULT_HEADER_NAME,
2474
+ });
2475
+ /**
2476
+ * Retrieves the current XSRF token to use with the next outgoing request.
2477
+ *
2478
+ * @publicApi
2479
+ */
2480
+ class HttpXsrfTokenExtractor {
2481
+ }
2482
+ /**
2483
+ * `HttpXsrfTokenExtractor` which retrieves the token from a cookie.
2484
+ */
2485
+ class HttpXsrfCookieExtractor {
2486
+ doc;
2487
+ platform;
2488
+ cookieName;
2489
+ lastCookieString = '';
2490
+ lastToken = null;
2491
+ /**
2492
+ * @internal for testing
2493
+ */
2494
+ parseCount = 0;
2495
+ constructor(doc, platform, cookieName) {
2496
+ this.doc = doc;
2497
+ this.platform = platform;
2498
+ this.cookieName = cookieName;
2499
+ }
2500
+ getToken() {
2501
+ if (this.platform === 'server') {
2502
+ return null;
2503
+ }
2504
+ const cookieString = this.doc.cookie || '';
2505
+ if (cookieString !== this.lastCookieString) {
2506
+ this.parseCount++;
2507
+ this.lastToken = parseCookieValue(cookieString, this.cookieName);
2508
+ this.lastCookieString = cookieString;
2509
+ }
2510
+ return this.lastToken;
2511
+ }
2512
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpXsrfCookieExtractor, deps: [{ token: DOCUMENT }, { token: PLATFORM_ID }, { token: XSRF_COOKIE_NAME }], target: i0.ɵɵFactoryTarget.Injectable });
2513
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpXsrfCookieExtractor });
2514
+ }
2515
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpXsrfCookieExtractor, decorators: [{
2516
+ type: Injectable
2517
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
2518
+ type: Inject,
2519
+ args: [DOCUMENT]
2520
+ }] }, { type: undefined, decorators: [{
2521
+ type: Inject,
2522
+ args: [PLATFORM_ID]
2523
+ }] }, { type: undefined, decorators: [{
2524
+ type: Inject,
2525
+ args: [XSRF_COOKIE_NAME]
2526
+ }] }] });
2527
+ function xsrfInterceptorFn(req, next) {
2528
+ const lcUrl = req.url.toLowerCase();
2529
+ // Skip both non-mutating requests and absolute URLs.
2530
+ // Non-mutating requests don't require a token, and absolute URLs require special handling
2531
+ // anyway as the cookie set
2532
+ // on our origin is not the same as the token expected by another origin.
2533
+ if (!inject(XSRF_ENABLED) ||
2534
+ req.method === 'GET' ||
2535
+ req.method === 'HEAD' ||
2536
+ lcUrl.startsWith('http://') ||
2537
+ lcUrl.startsWith('https://')) {
2538
+ return next(req);
2539
+ }
2540
+ const token = inject(HttpXsrfTokenExtractor).getToken();
2541
+ const headerName = inject(XSRF_HEADER_NAME);
2542
+ // Be careful not to overwrite an existing header of the same name.
2543
+ if (token != null && !req.headers.has(headerName)) {
2544
+ req = req.clone({ headers: req.headers.set(headerName, token) });
2545
+ }
2546
+ return next(req);
2547
+ }
2548
+ /**
2549
+ * `HttpInterceptor` which adds an XSRF token to eligible outgoing requests.
2550
+ */
2551
+ class HttpXsrfInterceptor {
2552
+ injector;
2553
+ constructor(injector) {
2554
+ this.injector = injector;
2555
+ }
2556
+ intercept(initialRequest, next) {
2557
+ return runInInjectionContext(this.injector, () => xsrfInterceptorFn(initialRequest, (downstreamRequest) => next.handle(downstreamRequest)));
2558
+ }
2559
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpXsrfInterceptor, deps: [{ token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable });
2560
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpXsrfInterceptor });
2561
+ }
2562
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpXsrfInterceptor, decorators: [{
2563
+ type: Injectable
2564
+ }], ctorParameters: () => [{ type: i0.EnvironmentInjector }] });
2565
+
2566
+ /**
2567
+ * Identifies a particular kind of `HttpFeature`.
2568
+ *
2569
+ * @publicApi
2570
+ */
2571
+ var HttpFeatureKind;
2572
+ (function (HttpFeatureKind) {
2573
+ HttpFeatureKind[HttpFeatureKind["Interceptors"] = 0] = "Interceptors";
2574
+ HttpFeatureKind[HttpFeatureKind["LegacyInterceptors"] = 1] = "LegacyInterceptors";
2575
+ HttpFeatureKind[HttpFeatureKind["CustomXsrfConfiguration"] = 2] = "CustomXsrfConfiguration";
2576
+ HttpFeatureKind[HttpFeatureKind["NoXsrfProtection"] = 3] = "NoXsrfProtection";
2577
+ HttpFeatureKind[HttpFeatureKind["JsonpSupport"] = 4] = "JsonpSupport";
2578
+ HttpFeatureKind[HttpFeatureKind["RequestsMadeViaParent"] = 5] = "RequestsMadeViaParent";
2579
+ HttpFeatureKind[HttpFeatureKind["Fetch"] = 6] = "Fetch";
2580
+ })(HttpFeatureKind || (HttpFeatureKind = {}));
2581
+ function makeHttpFeature(kind, providers) {
2582
+ return {
2583
+ ɵkind: kind,
2584
+ ɵproviders: providers,
2585
+ };
2586
+ }
2587
+ /**
2588
+ * Configures Angular's `HttpClient` service to be available for injection.
2589
+ *
2590
+ * By default, `HttpClient` will be configured for injection with its default options for XSRF
2591
+ * protection of outgoing requests. Additional configuration options can be provided by passing
2592
+ * feature functions to `provideHttpClient`. For example, HTTP interceptors can be added using the
2593
+ * `withInterceptors(...)` feature.
2594
+ *
2595
+ * <div class="docs-alert docs-alert-helpful">
2596
+ *
2597
+ * It's strongly recommended to enable
2598
+ * [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) for applications that use
2599
+ * Server-Side Rendering for better performance and compatibility. To enable `fetch`, add
2600
+ * `withFetch()` feature to the `provideHttpClient()` call at the root of the application:
2601
+ *
2602
+ * ```ts
2603
+ * provideHttpClient(withFetch());
2604
+ * ```
2605
+ *
2606
+ * </div>
2607
+ *
2608
+ * @see {@link withInterceptors}
2609
+ * @see {@link withInterceptorsFromDi}
2610
+ * @see {@link withXsrfConfiguration}
2611
+ * @see {@link withNoXsrfProtection}
2612
+ * @see {@link withJsonpSupport}
2613
+ * @see {@link withRequestsMadeViaParent}
2614
+ * @see {@link withFetch}
2615
+ */
2616
+ function provideHttpClient(...features) {
2617
+ if (ngDevMode) {
2618
+ const featureKinds = new Set(features.map((f) => f.ɵkind));
2619
+ if (featureKinds.has(HttpFeatureKind.NoXsrfProtection) &&
2620
+ featureKinds.has(HttpFeatureKind.CustomXsrfConfiguration)) {
2621
+ throw new Error(ngDevMode
2622
+ ? `Configuration error: found both withXsrfConfiguration() and withNoXsrfProtection() in the same call to provideHttpClient(), which is a contradiction.`
2623
+ : '');
2624
+ }
2625
+ }
2626
+ const providers = [
2627
+ HttpClient,
2628
+ HttpXhrBackend,
2629
+ HttpInterceptorHandler,
2630
+ { provide: HttpHandler, useExisting: HttpInterceptorHandler },
2631
+ {
2632
+ provide: HttpBackend,
2633
+ useFactory: () => {
2634
+ return inject(FETCH_BACKEND, { optional: true }) ?? inject(HttpXhrBackend);
2635
+ },
2636
+ },
2637
+ {
2638
+ provide: HTTP_INTERCEPTOR_FNS,
2639
+ useValue: xsrfInterceptorFn,
2640
+ multi: true,
2641
+ },
2642
+ { provide: XSRF_ENABLED, useValue: true },
2643
+ { provide: HttpXsrfTokenExtractor, useClass: HttpXsrfCookieExtractor },
2644
+ ];
2645
+ for (const feature of features) {
2646
+ providers.push(...feature.ɵproviders);
2647
+ }
2648
+ return makeEnvironmentProviders(providers);
2649
+ }
2650
+ /**
2651
+ * Adds one or more functional-style HTTP interceptors to the configuration of the `HttpClient`
2652
+ * instance.
2653
+ *
2654
+ * @see {@link HttpInterceptorFn}
2655
+ * @see {@link provideHttpClient}
2656
+ * @publicApi
2657
+ */
2658
+ function withInterceptors(interceptorFns) {
2659
+ return makeHttpFeature(HttpFeatureKind.Interceptors, interceptorFns.map((interceptorFn) => {
2660
+ return {
2661
+ provide: HTTP_INTERCEPTOR_FNS,
2662
+ useValue: interceptorFn,
2663
+ multi: true,
2664
+ };
2665
+ }));
2666
+ }
2667
+ const LEGACY_INTERCEPTOR_FN = new InjectionToken(ngDevMode ? 'LEGACY_INTERCEPTOR_FN' : '');
2668
+ /**
2669
+ * Includes class-based interceptors configured using a multi-provider in the current injector into
2670
+ * the configured `HttpClient` instance.
2671
+ *
2672
+ * Prefer `withInterceptors` and functional interceptors instead, as support for DI-provided
2673
+ * interceptors may be phased out in a later release.
2674
+ *
2675
+ * @see {@link HttpInterceptor}
2676
+ * @see {@link HTTP_INTERCEPTORS}
2677
+ * @see {@link provideHttpClient}
2678
+ */
2679
+ function withInterceptorsFromDi() {
2680
+ // Note: the legacy interceptor function is provided here via an intermediate token
2681
+ // (`LEGACY_INTERCEPTOR_FN`), using a pattern which guarantees that if these providers are
2682
+ // included multiple times, all of the multi-provider entries will have the same instance of the
2683
+ // interceptor function. That way, the `HttpINterceptorHandler` will dedup them and legacy
2684
+ // interceptors will not run multiple times.
2685
+ return makeHttpFeature(HttpFeatureKind.LegacyInterceptors, [
2686
+ {
2687
+ provide: LEGACY_INTERCEPTOR_FN,
2688
+ useFactory: legacyInterceptorFnFactory,
2689
+ },
2690
+ {
2691
+ provide: HTTP_INTERCEPTOR_FNS,
2692
+ useExisting: LEGACY_INTERCEPTOR_FN,
2693
+ multi: true,
2694
+ },
2695
+ ]);
2696
+ }
2697
+ /**
2698
+ * Customizes the XSRF protection for the configuration of the current `HttpClient` instance.
2699
+ *
2700
+ * This feature is incompatible with the `withNoXsrfProtection` feature.
2701
+ *
2702
+ * @see {@link provideHttpClient}
2703
+ */
2704
+ function withXsrfConfiguration({ cookieName, headerName, }) {
2705
+ const providers = [];
2706
+ if (cookieName !== undefined) {
2707
+ providers.push({ provide: XSRF_COOKIE_NAME, useValue: cookieName });
2708
+ }
2709
+ if (headerName !== undefined) {
2710
+ providers.push({ provide: XSRF_HEADER_NAME, useValue: headerName });
2711
+ }
2712
+ return makeHttpFeature(HttpFeatureKind.CustomXsrfConfiguration, providers);
2713
+ }
2714
+ /**
2715
+ * Disables XSRF protection in the configuration of the current `HttpClient` instance.
2716
+ *
2717
+ * This feature is incompatible with the `withXsrfConfiguration` feature.
2718
+ *
2719
+ * @see {@link provideHttpClient}
2720
+ */
2721
+ function withNoXsrfProtection() {
2722
+ return makeHttpFeature(HttpFeatureKind.NoXsrfProtection, [
2723
+ {
2724
+ provide: XSRF_ENABLED,
2725
+ useValue: false,
2726
+ },
2727
+ ]);
2728
+ }
2729
+ /**
2730
+ * Add JSONP support to the configuration of the current `HttpClient` instance.
2731
+ *
2732
+ * @see {@link provideHttpClient}
2733
+ */
2734
+ function withJsonpSupport() {
2735
+ return makeHttpFeature(HttpFeatureKind.JsonpSupport, [
2736
+ JsonpClientBackend,
2737
+ { provide: JsonpCallbackContext, useFactory: jsonpCallbackContext },
2738
+ { provide: HTTP_INTERCEPTOR_FNS, useValue: jsonpInterceptorFn, multi: true },
2739
+ ]);
2740
+ }
2741
+ /**
2742
+ * Configures the current `HttpClient` instance to make requests via the parent injector's
2743
+ * `HttpClient` instead of directly.
2744
+ *
2745
+ * By default, `provideHttpClient` configures `HttpClient` in its injector to be an independent
2746
+ * instance. For example, even if `HttpClient` is configured in the parent injector with
2747
+ * one or more interceptors, they will not intercept requests made via this instance.
2748
+ *
2749
+ * With this option enabled, once the request has passed through the current injector's
2750
+ * interceptors, it will be delegated to the parent injector's `HttpClient` chain instead of
2751
+ * dispatched directly, and interceptors in the parent configuration will be applied to the request.
2752
+ *
2753
+ * If there are several `HttpClient` instances in the injector hierarchy, it's possible for
2754
+ * `withRequestsMadeViaParent` to be used at multiple levels, which will cause the request to
2755
+ * "bubble up" until either reaching the root level or an `HttpClient` which was not configured with
2756
+ * this option.
2757
+ *
2758
+ * @see {@link provideHttpClient}
2759
+ * @publicApi
2760
+ */
2761
+ function withRequestsMadeViaParent() {
2762
+ return makeHttpFeature(HttpFeatureKind.RequestsMadeViaParent, [
2763
+ {
2764
+ provide: HttpBackend,
2765
+ useFactory: () => {
2766
+ const handlerFromParent = inject(HttpHandler, { skipSelf: true, optional: true });
2767
+ if (ngDevMode && handlerFromParent === null) {
2768
+ throw new Error('withRequestsMadeViaParent() can only be used when the parent injector also configures HttpClient');
2769
+ }
2770
+ return handlerFromParent;
2771
+ },
2772
+ },
2773
+ ]);
2774
+ }
2775
+ /**
2776
+ * Configures the current `HttpClient` instance to make requests using the fetch API.
2777
+ *
2778
+ * Note: The Fetch API doesn't support progress report on uploads.
2779
+ *
2780
+ * @publicApi
2781
+ */
2782
+ function withFetch() {
2783
+ return makeHttpFeature(HttpFeatureKind.Fetch, [
2784
+ FetchBackend,
2785
+ { provide: FETCH_BACKEND, useExisting: FetchBackend },
2786
+ { provide: HttpBackend, useExisting: FetchBackend },
2787
+ ]);
2788
+ }
2789
+
2790
+ /**
2791
+ * Configures XSRF protection support for outgoing requests.
2792
+ *
2793
+ * For a server that supports a cookie-based XSRF protection system,
2794
+ * use directly to configure XSRF protection with the correct
2795
+ * cookie and header names.
2796
+ *
2797
+ * If no names are supplied, the default cookie name is `XSRF-TOKEN`
2798
+ * and the default header name is `X-XSRF-TOKEN`.
2799
+ *
2800
+ * @publicApi
2801
+ * @deprecated Use withXsrfConfiguration({cookieName: 'XSRF-TOKEN', headerName: 'X-XSRF-TOKEN'}) as
2802
+ * providers instead or `withNoXsrfProtection` if you want to disabled XSRF protection.
2803
+ */
2804
+ class HttpClientXsrfModule {
2805
+ /**
2806
+ * Disable the default XSRF protection.
2807
+ */
2808
+ static disable() {
2809
+ return {
2810
+ ngModule: HttpClientXsrfModule,
2811
+ providers: [withNoXsrfProtection().ɵproviders],
2812
+ };
2813
+ }
2814
+ /**
2815
+ * Configure XSRF protection.
2816
+ * @param options An object that can specify either or both
2817
+ * cookie name or header name.
2818
+ * - Cookie name default is `XSRF-TOKEN`.
2819
+ * - Header name default is `X-XSRF-TOKEN`.
2820
+ *
2821
+ */
2822
+ static withOptions(options = {}) {
2823
+ return {
2824
+ ngModule: HttpClientXsrfModule,
2825
+ providers: withXsrfConfiguration(options).ɵproviders,
2826
+ };
2827
+ }
2828
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpClientXsrfModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2829
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpClientXsrfModule });
2830
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpClientXsrfModule, providers: [
2831
+ HttpXsrfInterceptor,
2832
+ { provide: HTTP_INTERCEPTORS, useExisting: HttpXsrfInterceptor, multi: true },
2833
+ { provide: HttpXsrfTokenExtractor, useClass: HttpXsrfCookieExtractor },
2834
+ withXsrfConfiguration({
2835
+ cookieName: XSRF_DEFAULT_COOKIE_NAME,
2836
+ headerName: XSRF_DEFAULT_HEADER_NAME,
2837
+ }).ɵproviders,
2838
+ { provide: XSRF_ENABLED, useValue: true },
2839
+ ] });
2840
+ }
2841
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpClientXsrfModule, decorators: [{
2842
+ type: NgModule,
2843
+ args: [{
2844
+ providers: [
2845
+ HttpXsrfInterceptor,
2846
+ { provide: HTTP_INTERCEPTORS, useExisting: HttpXsrfInterceptor, multi: true },
2847
+ { provide: HttpXsrfTokenExtractor, useClass: HttpXsrfCookieExtractor },
2848
+ withXsrfConfiguration({
2849
+ cookieName: XSRF_DEFAULT_COOKIE_NAME,
2850
+ headerName: XSRF_DEFAULT_HEADER_NAME,
2851
+ }).ɵproviders,
2852
+ { provide: XSRF_ENABLED, useValue: true },
2853
+ ],
2854
+ }]
2855
+ }] });
2856
+ /**
2857
+ * Configures the dependency injector for `HttpClient`
2858
+ * with supporting services for XSRF. Automatically imported by `HttpClientModule`.
2859
+ *
2860
+ * You can add interceptors to the chain behind `HttpClient` by binding them to the
2861
+ * multiprovider for built-in DI token `HTTP_INTERCEPTORS`.
2862
+ *
2863
+ * @publicApi
2864
+ * @deprecated use `provideHttpClient(withInterceptorsFromDi())` as providers instead
2865
+ */
2866
+ class HttpClientModule {
2867
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpClientModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2868
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpClientModule });
2869
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpClientModule, providers: [provideHttpClient(withInterceptorsFromDi())] });
2870
+ }
2871
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpClientModule, decorators: [{
2872
+ type: NgModule,
2873
+ args: [{
2874
+ /**
2875
+ * Configures the dependency injector where it is imported
2876
+ * with supporting services for HTTP communications.
2877
+ */
2878
+ providers: [provideHttpClient(withInterceptorsFromDi())],
2879
+ }]
2880
+ }] });
2881
+ /**
2882
+ * Configures the dependency injector for `HttpClient`
2883
+ * with supporting services for JSONP.
2884
+ * Without this module, Jsonp requests reach the backend
2885
+ * with method JSONP, where they are rejected.
2886
+ *
2887
+ * @publicApi
2888
+ * @deprecated `withJsonpSupport()` as providers instead
2889
+ */
2890
+ class HttpClientJsonpModule {
2891
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpClientJsonpModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2892
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpClientJsonpModule });
2893
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpClientJsonpModule, providers: [withJsonpSupport().ɵproviders] });
2894
+ }
2895
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: HttpClientJsonpModule, decorators: [{
2896
+ type: NgModule,
2897
+ args: [{
2898
+ providers: [withJsonpSupport().ɵproviders],
2899
+ }]
2900
+ }] });
2901
+
2902
+ export { HttpErrorResponse as A, HttpHeaderResponse as B, HttpResponseBase as C, HttpStatusCode as D, HttpXhrBackend as E, FetchBackend as F, HttpXsrfTokenExtractor as G, HttpEventType as H, JsonpClientBackend as J, REQUESTS_CONTRIBUTE_TO_STABILITY as R, HttpClient as a, HttpHeaders as b, HttpParams as c, HttpRequest as d, HTTP_ROOT_INTERCEPTOR_FNS as e, HttpResponse as f, HttpBackend as g, HttpHandler as h, HttpContext as i, HttpContextToken as j, HTTP_INTERCEPTORS as k, HttpInterceptorHandler as l, JsonpInterceptor as m, HttpClientJsonpModule as n, HttpClientModule as o, HttpClientXsrfModule as p, HttpUrlEncodingCodec as q, HttpFeatureKind as r, provideHttpClient as s, withInterceptors as t, withInterceptorsFromDi as u, withJsonpSupport as v, withFetch as w, withNoXsrfProtection as x, withRequestsMadeViaParent as y, withXsrfConfiguration as z };
2903
+ //# sourceMappingURL=module-TRKGK7nU.mjs.map