| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622 | 
							- import { map } from '../operators/map';
 
- import { Observable } from '../Observable';
 
- import { AjaxConfig, AjaxRequest, AjaxDirection, ProgressEventType } from './types';
 
- import { AjaxResponse } from './AjaxResponse';
 
- import { AjaxTimeoutError, AjaxError } from './errors';
 
- export interface AjaxCreationMethod {
 
-   /**
 
-    * Creates an observable that will perform an AJAX request using the
 
-    * [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) in
 
-    * global scope by default.
 
-    *
 
-    * This is the most configurable option, and the basis for all other AJAX calls in the library.
 
-    *
 
-    * ## Example
 
-    *
 
-    * ```ts
 
-    * import { ajax } from 'rxjs/ajax';
 
-    * import { map, catchError, of } from 'rxjs';
 
-    *
 
-    * const obs$ = ajax({
 
-    *   method: 'GET',
 
-    *   url: 'https://api.github.com/users?per_page=5',
 
-    *   responseType: 'json'
 
-    * }).pipe(
 
-    *   map(userResponse => console.log('users: ', userResponse)),
 
-    *   catchError(error => {
 
-    *     console.log('error: ', error);
 
-    *     return of(error);
 
-    *   })
 
-    * );
 
-    * ```
 
-    */
 
-   <T>(config: AjaxConfig): Observable<AjaxResponse<T>>;
 
-   /**
 
-    * Perform an HTTP GET using the
 
-    * [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) in
 
-    * global scope. Defaults to a `responseType` of `"json"`.
 
-    *
 
-    * ## Example
 
-    *
 
-    * ```ts
 
-    * import { ajax } from 'rxjs/ajax';
 
-    * import { map, catchError, of } from 'rxjs';
 
-    *
 
-    * const obs$ = ajax('https://api.github.com/users?per_page=5').pipe(
 
-    *   map(userResponse => console.log('users: ', userResponse)),
 
-    *   catchError(error => {
 
-    *     console.log('error: ', error);
 
-    *     return of(error);
 
-    *   })
 
-    * );
 
-    * ```
 
-    */
 
-   <T>(url: string): Observable<AjaxResponse<T>>;
 
-   /**
 
-    * Performs an HTTP GET using the
 
-    * [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) in
 
-    * global scope by default, and a `responseType` of `"json"`.
 
-    *
 
-    * @param url The URL to get the resource from
 
-    * @param headers Optional headers. Case-Insensitive.
 
-    */
 
-   get<T>(url: string, headers?: Record<string, string>): Observable<AjaxResponse<T>>;
 
-   /**
 
-    * Performs an HTTP POST using the
 
-    * [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) in
 
-    * global scope by default, and a `responseType` of `"json"`.
 
-    *
 
-    * Before sending the value passed to the `body` argument, it is automatically serialized
 
-    * based on the specified `responseType`. By default, a JavaScript object will be serialized
 
-    * to JSON. A `responseType` of `application/x-www-form-urlencoded` will flatten any provided
 
-    * dictionary object to a url-encoded string.
 
-    *
 
-    * @param url The URL to get the resource from
 
-    * @param body The content to send. The body is automatically serialized.
 
-    * @param headers Optional headers. Case-Insensitive.
 
-    */
 
-   post<T>(url: string, body?: any, headers?: Record<string, string>): Observable<AjaxResponse<T>>;
 
-   /**
 
-    * Performs an HTTP PUT using the
 
-    * [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) in
 
-    * global scope by default, and a `responseType` of `"json"`.
 
-    *
 
-    * Before sending the value passed to the `body` argument, it is automatically serialized
 
-    * based on the specified `responseType`. By default, a JavaScript object will be serialized
 
-    * to JSON. A `responseType` of `application/x-www-form-urlencoded` will flatten any provided
 
-    * dictionary object to a url-encoded string.
 
-    *
 
-    * @param url The URL to get the resource from
 
-    * @param body The content to send. The body is automatically serialized.
 
-    * @param headers Optional headers. Case-Insensitive.
 
-    */
 
-   put<T>(url: string, body?: any, headers?: Record<string, string>): Observable<AjaxResponse<T>>;
 
-   /**
 
-    * Performs an HTTP PATCH using the
 
-    * [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) in
 
-    * global scope by default, and a `responseType` of `"json"`.
 
-    *
 
-    * Before sending the value passed to the `body` argument, it is automatically serialized
 
-    * based on the specified `responseType`. By default, a JavaScript object will be serialized
 
-    * to JSON. A `responseType` of `application/x-www-form-urlencoded` will flatten any provided
 
-    * dictionary object to a url-encoded string.
 
-    *
 
-    * @param url The URL to get the resource from
 
-    * @param body The content to send. The body is automatically serialized.
 
-    * @param headers Optional headers. Case-Insensitive.
 
-    */
 
-   patch<T>(url: string, body?: any, headers?: Record<string, string>): Observable<AjaxResponse<T>>;
 
-   /**
 
-    * Performs an HTTP DELETE using the
 
-    * [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) in
 
-    * global scope by default, and a `responseType` of `"json"`.
 
-    *
 
-    * @param url The URL to get the resource from
 
-    * @param headers Optional headers. Case-Insensitive.
 
-    */
 
-   delete<T>(url: string, headers?: Record<string, string>): Observable<AjaxResponse<T>>;
 
-   /**
 
-    * Performs an HTTP GET using the
 
-    * [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) in
 
-    * global scope by default, and returns the hydrated JavaScript object from the
 
-    * response.
 
-    *
 
-    * @param url The URL to get the resource from
 
-    * @param headers Optional headers. Case-Insensitive.
 
-    */
 
-   getJSON<T>(url: string, headers?: Record<string, string>): Observable<T>;
 
- }
 
- function ajaxGet<T>(url: string, headers?: Record<string, string>): Observable<AjaxResponse<T>> {
 
-   return ajax({ method: 'GET', url, headers });
 
- }
 
- function ajaxPost<T>(url: string, body?: any, headers?: Record<string, string>): Observable<AjaxResponse<T>> {
 
-   return ajax({ method: 'POST', url, body, headers });
 
- }
 
- function ajaxDelete<T>(url: string, headers?: Record<string, string>): Observable<AjaxResponse<T>> {
 
-   return ajax({ method: 'DELETE', url, headers });
 
- }
 
- function ajaxPut<T>(url: string, body?: any, headers?: Record<string, string>): Observable<AjaxResponse<T>> {
 
-   return ajax({ method: 'PUT', url, body, headers });
 
- }
 
- function ajaxPatch<T>(url: string, body?: any, headers?: Record<string, string>): Observable<AjaxResponse<T>> {
 
-   return ajax({ method: 'PATCH', url, body, headers });
 
- }
 
- const mapResponse = map((x: AjaxResponse<any>) => x.response);
 
- function ajaxGetJSON<T>(url: string, headers?: Record<string, string>): Observable<T> {
 
-   return mapResponse(
 
-     ajax<T>({
 
-       method: 'GET',
 
-       url,
 
-       headers,
 
-     })
 
-   );
 
- }
 
- /**
 
-  * There is an ajax operator on the Rx object.
 
-  *
 
-  * It creates an observable for an Ajax request with either a request object with
 
-  * url, headers, etc or a string for a URL.
 
-  *
 
-  * ## Examples
 
-  *
 
-  * Using `ajax()` to fetch the response object that is being returned from API
 
-  *
 
-  * ```ts
 
-  * import { ajax } from 'rxjs/ajax';
 
-  * import { map, catchError, of } from 'rxjs';
 
-  *
 
-  * const obs$ = ajax('https://api.github.com/users?per_page=5').pipe(
 
-  *   map(userResponse => console.log('users: ', userResponse)),
 
-  *   catchError(error => {
 
-  *     console.log('error: ', error);
 
-  *     return of(error);
 
-  *   })
 
-  * );
 
-  *
 
-  * obs$.subscribe({
 
-  *   next: value => console.log(value),
 
-  *   error: err => console.log(err)
 
-  * });
 
-  * ```
 
-  *
 
-  * Using `ajax.getJSON()` to fetch data from API
 
-  *
 
-  * ```ts
 
-  * import { ajax } from 'rxjs/ajax';
 
-  * import { map, catchError, of } from 'rxjs';
 
-  *
 
-  * const obs$ = ajax.getJSON('https://api.github.com/users?per_page=5').pipe(
 
-  *   map(userResponse => console.log('users: ', userResponse)),
 
-  *   catchError(error => {
 
-  *     console.log('error: ', error);
 
-  *     return of(error);
 
-  *   })
 
-  * );
 
-  *
 
-  * obs$.subscribe({
 
-  *   next: value => console.log(value),
 
-  *   error: err => console.log(err)
 
-  * });
 
-  * ```
 
-  *
 
-  * Using `ajax()` with object as argument and method POST with a two seconds delay
 
-  *
 
-  * ```ts
 
-  * import { ajax } from 'rxjs/ajax';
 
-  * import { map, catchError, of } from 'rxjs';
 
-  *
 
-  * const users = ajax({
 
-  *   url: 'https://httpbin.org/delay/2',
 
-  *   method: 'POST',
 
-  *   headers: {
 
-  *     'Content-Type': 'application/json',
 
-  *     'rxjs-custom-header': 'Rxjs'
 
-  *   },
 
-  *   body: {
 
-  *     rxjs: 'Hello World!'
 
-  *   }
 
-  * }).pipe(
 
-  *   map(response => console.log('response: ', response)),
 
-  *   catchError(error => {
 
-  *     console.log('error: ', error);
 
-  *     return of(error);
 
-  *   })
 
-  * );
 
-  *
 
-  * users.subscribe({
 
-  *   next: value => console.log(value),
 
-  *   error: err => console.log(err)
 
-  * });
 
-  * ```
 
-  *
 
-  * Using `ajax()` to fetch. An error object that is being returned from the request
 
-  *
 
-  * ```ts
 
-  * import { ajax } from 'rxjs/ajax';
 
-  * import { map, catchError, of } from 'rxjs';
 
-  *
 
-  * const obs$ = ajax('https://api.github.com/404').pipe(
 
-  *   map(userResponse => console.log('users: ', userResponse)),
 
-  *   catchError(error => {
 
-  *     console.log('error: ', error);
 
-  *     return of(error);
 
-  *   })
 
-  * );
 
-  *
 
-  * obs$.subscribe({
 
-  *   next: value => console.log(value),
 
-  *   error: err => console.log(err)
 
-  * });
 
-  * ```
 
-  */
 
- export const ajax: AjaxCreationMethod = (() => {
 
-   const create = <T>(urlOrConfig: string | AjaxConfig) => {
 
-     const config: AjaxConfig =
 
-       typeof urlOrConfig === 'string'
 
-         ? {
 
-             url: urlOrConfig,
 
-           }
 
-         : urlOrConfig;
 
-     return fromAjax<T>(config);
 
-   };
 
-   create.get = ajaxGet;
 
-   create.post = ajaxPost;
 
-   create.delete = ajaxDelete;
 
-   create.put = ajaxPut;
 
-   create.patch = ajaxPatch;
 
-   create.getJSON = ajaxGetJSON;
 
-   return create;
 
- })();
 
- const UPLOAD = 'upload';
 
- const DOWNLOAD = 'download';
 
- const LOADSTART = 'loadstart';
 
- const PROGRESS = 'progress';
 
- const LOAD = 'load';
 
- export function fromAjax<T>(init: AjaxConfig): Observable<AjaxResponse<T>> {
 
-   return new Observable((destination) => {
 
-     const config = {
 
-       // Defaults
 
-       async: true,
 
-       crossDomain: false,
 
-       withCredentials: false,
 
-       method: 'GET',
 
-       timeout: 0,
 
-       responseType: 'json' as XMLHttpRequestResponseType,
 
-       ...init,
 
-     };
 
-     const { queryParams, body: configuredBody, headers: configuredHeaders } = config;
 
-     let url = config.url;
 
-     if (!url) {
 
-       throw new TypeError('url is required');
 
-     }
 
-     if (queryParams) {
 
-       let searchParams: URLSearchParams;
 
-       if (url.includes('?')) {
 
-         // If the user has passed a URL with a querystring already in it,
 
-         // we need to combine them. So we're going to split it. There
 
-         // should only be one `?` in a valid URL.
 
-         const parts = url.split('?');
 
-         if (2 < parts.length) {
 
-           throw new TypeError('invalid url');
 
-         }
 
-         // Add the passed queryParams to the params already in the url provided.
 
-         searchParams = new URLSearchParams(parts[1]);
 
-         // queryParams is converted to any because the runtime is *much* more permissive than
 
-         // the types are.
 
-         new URLSearchParams(queryParams as any).forEach((value, key) => searchParams.set(key, value));
 
-         // We have to do string concatenation here, because `new URL(url)` does
 
-         // not like relative URLs like `/this` without a base url, which we can't
 
-         // specify, nor can we assume `location` will exist, because of node.
 
-         url = parts[0] + '?' + searchParams;
 
-       } else {
 
-         // There is no preexisting querystring, so we can just use URLSearchParams
 
-         // to convert the passed queryParams into the proper format and encodings.
 
-         // queryParams is converted to any because the runtime is *much* more permissive than
 
-         // the types are.
 
-         searchParams = new URLSearchParams(queryParams as any);
 
-         url = url + '?' + searchParams;
 
-       }
 
-     }
 
-     // Normalize the headers. We're going to make them all lowercase, since
 
-     // Headers are case insensitive by design. This makes it easier to verify
 
-     // that we aren't setting or sending duplicates.
 
-     const headers: Record<string, any> = {};
 
-     if (configuredHeaders) {
 
-       for (const key in configuredHeaders) {
 
-         if (configuredHeaders.hasOwnProperty(key)) {
 
-           headers[key.toLowerCase()] = configuredHeaders[key];
 
-         }
 
-       }
 
-     }
 
-     const crossDomain = config.crossDomain;
 
-     // Set the x-requested-with header. This is a non-standard header that has
 
-     // come to be a de facto standard for HTTP requests sent by libraries and frameworks
 
-     // using XHR. However, we DO NOT want to set this if it is a CORS request. This is
 
-     // because sometimes this header can cause issues with CORS. To be clear,
 
-     // None of this is necessary, it's only being set because it's "the thing libraries do"
 
-     // Starting back as far as JQuery, and continuing with other libraries such as Angular 1,
 
-     // Axios, et al.
 
-     if (!crossDomain && !('x-requested-with' in headers)) {
 
-       headers['x-requested-with'] = 'XMLHttpRequest';
 
-     }
 
-     // Allow users to provide their XSRF cookie name and the name of a custom header to use to
 
-     // send the cookie.
 
-     const { withCredentials, xsrfCookieName, xsrfHeaderName } = config;
 
-     if ((withCredentials || !crossDomain) && xsrfCookieName && xsrfHeaderName) {
 
-       const xsrfCookie = document?.cookie.match(new RegExp(`(^|;\\s*)(${xsrfCookieName})=([^;]*)`))?.pop() ?? '';
 
-       if (xsrfCookie) {
 
-         headers[xsrfHeaderName] = xsrfCookie;
 
-       }
 
-     }
 
-     // Examine the body and determine whether or not to serialize it
 
-     // and set the content-type in `headers`, if we're able.
 
-     const body = extractContentTypeAndMaybeSerializeBody(configuredBody, headers);
 
-     // The final request settings.
 
-     const _request: Readonly<AjaxRequest> = {
 
-       ...config,
 
-       // Set values we ensured above
 
-       url,
 
-       headers,
 
-       body,
 
-     };
 
-     let xhr: XMLHttpRequest;
 
-     // Create our XHR so we can get started.
 
-     xhr = init.createXHR ? init.createXHR() : new XMLHttpRequest();
 
-     {
 
-       ///////////////////////////////////////////////////
 
-       // set up the events before open XHR
 
-       // https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest
 
-       // You need to add the event listeners before calling open() on the request.
 
-       // Otherwise the progress events will not fire.
 
-       ///////////////////////////////////////////////////
 
-       const { progressSubscriber, includeDownloadProgress = false, includeUploadProgress = false } = init;
 
-       /**
 
-        * Wires up an event handler that will emit an error when fired. Used
 
-        * for timeout and abort events.
 
-        * @param type The type of event we're treating as an error
 
-        * @param errorFactory A function that creates the type of error to emit.
 
-        */
 
-       const addErrorEvent = (type: string, errorFactory: () => any) => {
 
-         xhr.addEventListener(type, () => {
 
-           const error = errorFactory();
 
-           progressSubscriber?.error?.(error);
 
-           destination.error(error);
 
-         });
 
-       };
 
-       // If the request times out, handle errors appropriately.
 
-       addErrorEvent('timeout', () => new AjaxTimeoutError(xhr, _request));
 
-       // If the request aborts (due to a network disconnection or the like), handle
 
-       // it as an error.
 
-       addErrorEvent('abort', () => new AjaxError('aborted', xhr, _request));
 
-       /**
 
-        * Creates a response object to emit to the consumer.
 
-        * @param direction the direction related to the event. Prefixes the event `type` in the
 
-        * `AjaxResponse` object with "upload_" for events related to uploading and "download_"
 
-        * for events related to downloading.
 
-        * @param event the actual event object.
 
-        */
 
-       const createResponse = (direction: AjaxDirection, event: ProgressEvent) =>
 
-         new AjaxResponse<T>(event, xhr, _request, `${direction}_${event.type as ProgressEventType}` as const);
 
-       /**
 
-        * Wires up an event handler that emits a Response object to the consumer, used for
 
-        * all events that emit responses, loadstart, progress, and load.
 
-        * Note that download load handling is a bit different below, because it has
 
-        * more logic it needs to run.
 
-        * @param target The target, either the XHR itself or the Upload object.
 
-        * @param type The type of event to wire up
 
-        * @param direction The "direction", used to prefix the response object that is
 
-        * emitted to the consumer. (e.g. "upload_" or "download_")
 
-        */
 
-       const addProgressEvent = (target: any, type: string, direction: AjaxDirection) => {
 
-         target.addEventListener(type, (event: ProgressEvent) => {
 
-           destination.next(createResponse(direction, event));
 
-         });
 
-       };
 
-       if (includeUploadProgress) {
 
-         [LOADSTART, PROGRESS, LOAD].forEach((type) => addProgressEvent(xhr.upload, type, UPLOAD));
 
-       }
 
-       if (progressSubscriber) {
 
-         [LOADSTART, PROGRESS].forEach((type) => xhr.upload.addEventListener(type, (e: any) => progressSubscriber?.next?.(e)));
 
-       }
 
-       if (includeDownloadProgress) {
 
-         [LOADSTART, PROGRESS].forEach((type) => addProgressEvent(xhr, type, DOWNLOAD));
 
-       }
 
-       const emitError = (status?: number) => {
 
-         const msg = 'ajax error' + (status ? ' ' + status : '');
 
-         destination.error(new AjaxError(msg, xhr, _request));
 
-       };
 
-       xhr.addEventListener('error', (e) => {
 
-         progressSubscriber?.error?.(e);
 
-         emitError();
 
-       });
 
-       xhr.addEventListener(LOAD, (event) => {
 
-         const { status } = xhr;
 
-         // 4xx and 5xx should error (https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)
 
-         if (status < 400) {
 
-           progressSubscriber?.complete?.();
 
-           let response: AjaxResponse<T>;
 
-           try {
 
-             // This can throw in IE, because we end up needing to do a JSON.parse
 
-             // of the response in some cases to produce object we'd expect from
 
-             // modern browsers.
 
-             response = createResponse(DOWNLOAD, event);
 
-           } catch (err) {
 
-             destination.error(err);
 
-             return;
 
-           }
 
-           destination.next(response);
 
-           destination.complete();
 
-         } else {
 
-           progressSubscriber?.error?.(event);
 
-           emitError(status);
 
-         }
 
-       });
 
-     }
 
-     const { user, method, async } = _request;
 
-     // open XHR
 
-     if (user) {
 
-       xhr.open(method, url, async, user, _request.password);
 
-     } else {
 
-       xhr.open(method, url, async);
 
-     }
 
-     // timeout, responseType and withCredentials can be set once the XHR is open
 
-     if (async) {
 
-       xhr.timeout = _request.timeout;
 
-       xhr.responseType = _request.responseType;
 
-     }
 
-     if ('withCredentials' in xhr) {
 
-       xhr.withCredentials = _request.withCredentials;
 
-     }
 
-     // set headers
 
-     for (const key in headers) {
 
-       if (headers.hasOwnProperty(key)) {
 
-         xhr.setRequestHeader(key, headers[key]);
 
-       }
 
-     }
 
-     // finally send the request
 
-     if (body) {
 
-       xhr.send(body);
 
-     } else {
 
-       xhr.send();
 
-     }
 
-     return () => {
 
-       if (xhr && xhr.readyState !== 4 /*XHR done*/) {
 
-         xhr.abort();
 
-       }
 
-     };
 
-   });
 
- }
 
- /**
 
-  * Examines the body to determine if we need to serialize it for them or not.
 
-  * If the body is a type that XHR handles natively, we just allow it through,
 
-  * otherwise, if the body is something that *we* can serialize for the user,
 
-  * we will serialize it, and attempt to set the `content-type` header, if it's
 
-  * not already set.
 
-  * @param body The body passed in by the user
 
-  * @param headers The normalized headers
 
-  */
 
- function extractContentTypeAndMaybeSerializeBody(body: any, headers: Record<string, string>) {
 
-   if (
 
-     !body ||
 
-     typeof body === 'string' ||
 
-     isFormData(body) ||
 
-     isURLSearchParams(body) ||
 
-     isArrayBuffer(body) ||
 
-     isFile(body) ||
 
-     isBlob(body) ||
 
-     isReadableStream(body)
 
-   ) {
 
-     // The XHR instance itself can handle serializing these, and set the content-type for us
 
-     // so we don't need to do that. https://xhr.spec.whatwg.org/#the-send()-method
 
-     return body;
 
-   }
 
-   if (isArrayBufferView(body)) {
 
-     // This is a typed array (e.g. Float32Array or Uint8Array), or a DataView.
 
-     // XHR can handle this one too: https://fetch.spec.whatwg.org/#concept-bodyinit-extract
 
-     return body.buffer;
 
-   }
 
-   if (typeof body === 'object') {
 
-     // If we have made it here, this is an object, probably a POJO, and we'll try
 
-     // to serialize it for them. If this doesn't work, it will throw, obviously, which
 
-     // is okay. The workaround for users would be to manually set the body to their own
 
-     // serialized string (accounting for circular references or whatever), then set
 
-     // the content-type manually as well.
 
-     headers['content-type'] = headers['content-type'] ?? 'application/json;charset=utf-8';
 
-     return JSON.stringify(body);
 
-   }
 
-   // If we've gotten past everything above, this is something we don't quite know how to
 
-   // handle. Throw an error. This will be caught and emitted from the observable.
 
-   throw new TypeError('Unknown body type');
 
- }
 
- const _toString = Object.prototype.toString;
 
- function toStringCheck(obj: any, name: string): boolean {
 
-   return _toString.call(obj) === `[object ${name}]`;
 
- }
 
- function isArrayBuffer(body: any): body is ArrayBuffer {
 
-   return toStringCheck(body, 'ArrayBuffer');
 
- }
 
- function isFile(body: any): body is File {
 
-   return toStringCheck(body, 'File');
 
- }
 
- function isBlob(body: any): body is Blob {
 
-   return toStringCheck(body, 'Blob');
 
- }
 
- function isArrayBufferView(body: any): body is ArrayBufferView {
 
-   return typeof ArrayBuffer !== 'undefined' && ArrayBuffer.isView(body);
 
- }
 
- function isFormData(body: any): body is FormData {
 
-   return typeof FormData !== 'undefined' && body instanceof FormData;
 
- }
 
- function isURLSearchParams(body: any): body is URLSearchParams {
 
-   return typeof URLSearchParams !== 'undefined' && body instanceof URLSearchParams;
 
- }
 
- function isReadableStream(body: any): body is ReadableStream {
 
-   return typeof ReadableStream !== 'undefined' && body instanceof ReadableStream;
 
- }
 
 
  |