@alessiofrittoli/fetcher 0.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,153 @@
1
+ # Fetcher 🔭
2
+
3
+ [![NPM Latest Version][version-badge]][npm-url] [![Coverage Status][coverage-badge]][coverage-url] [![Socket Status][socket-badge]][socket-url] [![NPM Monthly Downloads][downloads-badge]][npm-url] [![Dependencies][deps-badge]][deps-url]
4
+
5
+ [![GitHub Sponsor][sponsor-badge]][sponsor-url]
6
+
7
+ [version-badge]: https://img.shields.io/npm/v/%40alessiofrittoli%2Ffetcher
8
+ [npm-url]: https://npmjs.org/package/%40alessiofrittoli%2Ffetcher
9
+ [coverage-badge]: https://coveralls.io/repos/github/alessiofrittoli/fetcher/badge.svg
10
+ [coverage-url]: https://coveralls.io/github/alessiofrittoli/fetcher
11
+ [socket-badge]: https://socket.dev/api/badge/npm/package/@alessiofrittoli/fetcher
12
+ [socket-url]: https://socket.dev/npm/package/@alessiofrittoli/fetcher/overview
13
+ [downloads-badge]: https://img.shields.io/npm/dm/%40alessiofrittoli%2Ffetcher.svg
14
+ [deps-badge]: https://img.shields.io/librariesio/release/npm/%40alessiofrittoli%2Ffetcher
15
+ [deps-url]: https://libraries.io/npm/%40alessiofrittoli%2Ffetcher
16
+
17
+ [sponsor-badge]: https://img.shields.io/static/v1?label=Fund%20this%20package&message=%E2%9D%A4&logo=GitHub&color=%23DB61A2
18
+ [sponsor-url]: https://github.com/sponsors/alessiofrittoli
19
+
20
+ ## Typescript fetch/xhr utilities
21
+
22
+ ### Table of Contents
23
+
24
+ - [Getting started](#getting-started)
25
+ - [Development](#development)
26
+ - [Install depenendencies](#install-depenendencies)
27
+ - [Build the source code](#build-the-source-code)
28
+ - [ESLint](#eslint)
29
+ - [Jest](#jest)
30
+ - [Contributing](#contributing)
31
+ - [Security](#security)
32
+ - [Credits](#made-with-)
33
+
34
+ ---
35
+
36
+ ### Getting started
37
+
38
+ Run the following command to start using `fetcher` in your projects:
39
+
40
+ ```bash
41
+ npm i @alessiofrittoli/fetcher
42
+ ```
43
+
44
+ or using `pnpm`
45
+
46
+ ```bash
47
+ pnpm i @alessiofrittoli/fetcher
48
+ ```
49
+
50
+ ---
51
+
52
+ ### Development
53
+
54
+ #### Install depenendencies
55
+
56
+ ```bash
57
+ npm install
58
+ ```
59
+
60
+ or using `pnpm`
61
+
62
+ ```bash
63
+ pnpm i
64
+ ```
65
+
66
+ #### Build the source code
67
+
68
+ Run the following command to test and build code for distribution.
69
+
70
+ ```bash
71
+ pnpm build
72
+ ```
73
+
74
+ #### [ESLint](https://www.npmjs.com/package/eslint)
75
+
76
+ warnings / errors check.
77
+
78
+ ```bash
79
+ pnpm lint
80
+ ```
81
+
82
+ #### [Jest](https://npmjs.com/package/jest)
83
+
84
+ Run all the defined test suites by running the following:
85
+
86
+ ```bash
87
+ # Run tests and watch file changes.
88
+ pnpm test:watch
89
+
90
+ # Run tests in a CI environment.
91
+ pnpm test:ci
92
+ ```
93
+
94
+ - See [`package.json`](./package.json) file scripts for more info.
95
+
96
+ Run tests with coverage.
97
+
98
+ An HTTP server is then started to serve coverage files from `./coverage` folder.
99
+
100
+ ⚠️ You may see a blank page the first time you run this command. Simply refresh the browser to see the updates.
101
+
102
+ ```bash
103
+ test:coverage:serve
104
+ ```
105
+
106
+ ---
107
+
108
+ ### Contributing
109
+
110
+ Contributions are truly welcome!
111
+
112
+ Please refer to the [Contributing Doc](./CONTRIBUTING.md) for more information on how to start contributing to this project.
113
+
114
+ Help keep this project up to date with [GitHub Sponsor][sponsor-url].
115
+
116
+ [![GitHub Sponsor][sponsor-badge]][sponsor-url]
117
+
118
+ ---
119
+
120
+ ### Security
121
+
122
+ If you believe you have found a security vulnerability, we encourage you to **_responsibly disclose this and NOT open a public issue_**. We will investigate all legitimate reports. Email `security@alessiofrittoli.it` to disclose any security vulnerabilities.
123
+
124
+ ### Made with ☕
125
+
126
+ <table style='display:flex;gap:20px;'>
127
+ <tbody>
128
+ <tr>
129
+ <td>
130
+ <img alt="avatar" src='https://avatars.githubusercontent.com/u/35973186' style='width:60px;border-radius:50%;object-fit:contain;'>
131
+ </td>
132
+ <td>
133
+ <table style='display:flex;gap:2px;flex-direction:column;'>
134
+ <tbody>
135
+ <tr>
136
+ <td>
137
+ <a href='https://github.com/alessiofrittoli' target='_blank' rel='noopener'>Alessio Frittoli</a>
138
+ </td>
139
+ </tr>
140
+ <tr>
141
+ <td>
142
+ <small>
143
+ <a href='https://alessiofrittoli.it' target='_blank' rel='noopener'>https://alessiofrittoli.it</a> |
144
+ <a href='mailto:info@alessiofrittoli.it' target='_blank' rel='noopener'>info@alessiofrittoli.it</a>
145
+ </small>
146
+ </td>
147
+ </tr>
148
+ </tbody>
149
+ </table>
150
+ </td>
151
+ </tr>
152
+ </tbody>
153
+ </table>
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _code = require('@alessiofrittoli/exception/code');var o=(r=>(r.XHR_NOT_AVAILABLE="ERR:XHRNOTAVAILABLE",r.XHR_INVALID_STATE="ERR:XHRINVALIDSTATE",r))(o||{}),p= exports.b ={Exception:_code.ErrorCode,Request:o};exports.a = o; exports.b = p;
@@ -0,0 +1 @@
1
+ import{ErrorCode as E}from"@alessiofrittoli/exception/code";var o=(r=>(r.XHR_NOT_AVAILABLE="ERR:XHRNOTAVAILABLE",r.XHR_INVALID_STATE="ERR:XHRINVALIDSTATE",r))(o||{}),t={Exception:E,Request:o};export{o as a,t as b};
@@ -0,0 +1,13 @@
1
+ import { ErrorCode as ErrorCode$1 } from '@alessiofrittoli/exception/code';
2
+
3
+ declare enum Request {
4
+ XHR_NOT_AVAILABLE = "ERR:XHRNOTAVAILABLE",
5
+ XHR_INVALID_STATE = "ERR:XHRINVALIDSTATE"
6
+ }
7
+ declare const ErrorCode: {
8
+ Exception: typeof ErrorCode$1;
9
+ Request: typeof Request;
10
+ };
11
+ type ErrorCode = MergedEnumValue<typeof ErrorCode>;
12
+
13
+ export { ErrorCode, Request };
@@ -0,0 +1,13 @@
1
+ import { ErrorCode as ErrorCode$1 } from '@alessiofrittoli/exception/code';
2
+
3
+ declare enum Request {
4
+ XHR_NOT_AVAILABLE = "ERR:XHRNOTAVAILABLE",
5
+ XHR_INVALID_STATE = "ERR:XHRINVALIDSTATE"
6
+ }
7
+ declare const ErrorCode: {
8
+ Exception: typeof ErrorCode$1;
9
+ Request: typeof Request;
10
+ };
11
+ type ErrorCode = MergedEnumValue<typeof ErrorCode>;
12
+
13
+ export { ErrorCode, Request };
package/dist/error.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkHNNMLJIAjs = require('./chunk-HNNMLJIA.js');exports.ErrorCode = _chunkHNNMLJIAjs.b; exports.Request = _chunkHNNMLJIAjs.a;
package/dist/error.mjs ADDED
@@ -0,0 +1 @@
1
+ import{a,b}from"./chunk-LOWOZ6LK.mjs";export{b as ErrorCode,a as Request};
@@ -0,0 +1,23 @@
1
+ import { AbortSignal } from '@alessiofrittoli/abort-controller';
2
+ import { F as Fetch } from './types-DuGUXaTD.mjs';
3
+ import '@alessiofrittoli/event-emitter';
4
+ import '@alessiofrittoli/exception';
5
+ import '@alessiofrittoli/exception/abort';
6
+ import '@alessiofrittoli/url-utils';
7
+ import './error.mjs';
8
+ import '@alessiofrittoli/exception/code';
9
+
10
+ interface RequestInit extends globalThis.RequestInit {
11
+ signal?: AbortSignal;
12
+ }
13
+ /**
14
+ * An extended version of the global fetch API.
15
+ *
16
+ * @param input The RequestInfo | URL.
17
+ * @param init The RequestInit.
18
+ * @param onfulfilled (Optional) A callback to run on Request fulfill. This could be used to alter the returned result.
19
+ * @returns An object with the parsed Request data, Request error, Request Response instance and Request Headers.
20
+ */
21
+ declare const fetch: <T, U extends RequestInit = RequestInit, V = Fetch.ReturnDataType<T, U>>(input: RequestInfo | URL, init?: U, onfulfilled?: Fetch.OnFulfilledCallback<V>) => Promise<Fetch.Result<V>>;
22
+
23
+ export { fetch };
@@ -0,0 +1,23 @@
1
+ import { AbortSignal } from '@alessiofrittoli/abort-controller';
2
+ import { F as Fetch } from './types-CVc-rxXe.js';
3
+ import '@alessiofrittoli/event-emitter';
4
+ import '@alessiofrittoli/exception';
5
+ import '@alessiofrittoli/exception/abort';
6
+ import '@alessiofrittoli/url-utils';
7
+ import './error.js';
8
+ import '@alessiofrittoli/exception/code';
9
+
10
+ interface RequestInit extends globalThis.RequestInit {
11
+ signal?: AbortSignal;
12
+ }
13
+ /**
14
+ * An extended version of the global fetch API.
15
+ *
16
+ * @param input The RequestInfo | URL.
17
+ * @param init The RequestInit.
18
+ * @param onfulfilled (Optional) A callback to run on Request fulfill. This could be used to alter the returned result.
19
+ * @returns An object with the parsed Request data, Request error, Request Response instance and Request Headers.
20
+ */
21
+ declare const fetch: <T, U extends RequestInit = RequestInit, V = Fetch.ReturnDataType<T, U>>(input: RequestInfo | URL, init?: U, onfulfilled?: Fetch.OnFulfilledCallback<V>) => Promise<Fetch.Result<V>>;
22
+
23
+ export { fetch };
package/dist/fetch.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _chunkHNNMLJIAjs = require('./chunk-HNNMLJIA.js');var _exception = require('@alessiofrittoli/exception');var h=(l,a,s)=>globalThis.fetch(l,a).then(async t=>{let o=t.headers,c=o.get("Content-Type"),i=_optionalChain([c, 'optionalAccess', _ => _.includes, 'call', _2 => _2("application/json")])||_optionalChain([a, 'optionalAccess', _3 => _3.responseType])==="json",u=_optionalChain([c, 'optionalAccess', _4 => _4.includes, 'call', _5 => _5("form-data")])||_optionalChain([a, 'optionalAccess', _6 => _6.responseType])==="formdata",e={response:t,headers:o,data:null,error:null};if(t.ok)return s?s(t):i?(e.data=await t.json(),e):u?(e.data=await t.formData(),e):_optionalChain([a, 'optionalAccess', _7 => _7.responseType])==="arraybuffer"?(e.data=await t.arrayBuffer(),e):_optionalChain([a, 'optionalAccess', _8 => _8.responseType])==="blob"?(e.data=await t.blob(),e):(e.data=await t.text(),e);if(i)throw await t.json();return e.error=new (0, _exception.Exception)(await t.text()||t.statusText,{code:_chunkHNNMLJIAjs.b.Exception.UNKNOWN}),e}).catch(t=>({data:null,headers:null,response:null,error:_exception.Exception.isException(t)?new (0, _exception.Exception)(t.message,{...t}):new (0, _exception.Exception)(t.message,{code:_chunkHNNMLJIAjs.b.Exception.UNKNOWN,name:t.name,cause:t})}));exports.fetch = h;
package/dist/fetch.mjs ADDED
@@ -0,0 +1 @@
1
+ import{b as n}from"./chunk-LOWOZ6LK.mjs";import{Exception as r}from"@alessiofrittoli/exception";var m=(l,a,s)=>globalThis.fetch(l,a).then(async t=>{let o=t.headers,c=o.get("Content-Type"),i=c?.includes("application/json")||a?.responseType==="json",u=c?.includes("form-data")||a?.responseType==="formdata",e={response:t,headers:o,data:null,error:null};if(t.ok)return s?s(t):i?(e.data=await t.json(),e):u?(e.data=await t.formData(),e):a?.responseType==="arraybuffer"?(e.data=await t.arrayBuffer(),e):a?.responseType==="blob"?(e.data=await t.blob(),e):(e.data=await t.text(),e);if(i)throw await t.json();return e.error=new r(await t.text()||t.statusText,{code:n.Exception.UNKNOWN}),e}).catch(t=>({data:null,headers:null,response:null,error:r.isException(t)?new r(t.message,{...t}):new r(t.message,{code:n.Exception.UNKNOWN,name:t.name,cause:t})}));export{m as fetch};
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _webutils = require('@alessiofrittoli/web-utils');var _cryptobuffer = require('@alessiofrittoli/crypto-buffer');var _exception = require('@alessiofrittoli/exception');var m=async n=>{let{response:s}=n,{responseType:o}=n;switch(o){case"document":break;case"json":{let e=s;if(e&&_exception.Exception.isException(e))return new (0, _exception.Exception)(e.message,{...e});break}case"":case"text":case"arraybuffer":case"blob":default:{let e=o==="arraybuffer"?_cryptobuffer.binaryToString.call(void 0, s):o==="blob"?await s.text():s;if(_webutils.isJson.call(void 0, e)){let t=JSON.parse(e);if(_exception.Exception.isException(t))return new (0, _exception.Exception)(t.message,{...t})}break}}return null};exports.getErrorFromResponse = m;
@@ -0,0 +1 @@
1
+ import{isJson as a}from"@alessiofrittoli/web-utils";import{binaryToString as p}from"@alessiofrittoli/crypto-buffer";import{Exception as r}from"@alessiofrittoli/exception";var u=async n=>{let{response:s}=n,{responseType:o}=n;switch(o){case"document":break;case"json":{let e=s;if(e&&r.isException(e))return new r(e.message,{...e});break}case"":case"text":case"arraybuffer":case"blob":default:{let e=o==="arraybuffer"?p(s):o==="blob"?await s.text():s;if(a(e)){let t=JSON.parse(e);if(r.isException(t))return new r(t.message,{...t})}break}}return null};export{u as getErrorFromResponse};
@@ -0,0 +1,12 @@
1
+ declare global {
2
+ interface RequestInit {
3
+ /** The expected ResponseType. */
4
+ responseType?: XMLHttpRequestResponseType | 'formdata';
5
+ }
6
+ interface ProgressEvent {
7
+ readonly type: keyof XMLHttpRequestEventTargetEventMap;
8
+ }
9
+ }
10
+ type DoNotUse = never;
11
+
12
+ export type { DoNotUse };
@@ -0,0 +1,12 @@
1
+ declare global {
2
+ interface RequestInit {
3
+ /** The expected ResponseType. */
4
+ responseType?: XMLHttpRequestResponseType | 'formdata';
5
+ }
6
+ interface ProgressEvent {
7
+ readonly type: keyof XMLHttpRequestEventTargetEventMap;
8
+ }
9
+ }
10
+ type DoNotUse = never;
11
+
12
+ export type { DoNotUse };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";
package/dist/index.mjs ADDED
File without changes
@@ -0,0 +1 @@
1
+ var r=t=>{let e={event:"readystatechange",readyState:t.request.readyState,status:t.request.status,message:""};switch(t.request.readyState){case XMLHttpRequest.UNSENT:e.message="Request unsent";break;case XMLHttpRequest.OPENED:e.message="Request opened";break;case XMLHttpRequest.HEADERS_RECEIVED:e.message="Request headers received";break;case XMLHttpRequest.LOADING:e.message="Request loading";break;case XMLHttpRequest.DONE:e.message="Request done";break}t.log(e)};export{r as logReadyStateChange};
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var a=t=>{let e={event:"readystatechange",readyState:t.request.readyState,status:t.request.status,message:""};switch(t.request.readyState){case XMLHttpRequest.UNSENT:e.message="Request unsent";break;case XMLHttpRequest.OPENED:e.message="Request opened";break;case XMLHttpRequest.HEADERS_RECEIVED:e.message="Request headers received";break;case XMLHttpRequest.LOADING:e.message="Request loading";break;case XMLHttpRequest.DONE:e.message="Request done";break}t.log(e)};exports.logReadyStateChange = a;
@@ -0,0 +1,227 @@
1
+ import Emitter, { EventEmitter } from '@alessiofrittoli/event-emitter';
2
+ import { Exception } from '@alessiofrittoli/exception';
3
+ import { AbortErrorOptions, AbortError } from '@alessiofrittoli/exception/abort';
4
+ import * as _alessiofrittoli_url_utils from '@alessiofrittoli/url-utils';
5
+ import { UrlInput } from '@alessiofrittoli/url-utils';
6
+ import { AbortController } from '@alessiofrittoli/abort-controller';
7
+ import { ErrorCode } from './error.js';
8
+
9
+ /**
10
+ * Easly handle XML HTTP Requests.
11
+ *
12
+ */
13
+ declare class Xhr<TReturn = unknown> extends EventEmitter<XHR.Event.Map<TReturn>> implements XHR.Options {
14
+ /** The XMLHttpRequest instance. */
15
+ request: XMLHttpRequest;
16
+ url: _alessiofrittoli_url_utils.UrlInput;
17
+ method: RequestMethod;
18
+ body: XMLHttpRequestBodyInit | Document | undefined;
19
+ headers: Headers;
20
+ credentials: {
21
+ username?: string | null;
22
+ password?: string | null;
23
+ } | undefined;
24
+ response?: TReturn;
25
+ controller: AbortController<ErrorCode>;
26
+ debug: boolean;
27
+ /** Indicates whether to automatically set the XHR response type based on the Response Content-Type Header. */
28
+ private setResponseType;
29
+ private static NotAvailableErr;
30
+ /** XHR progress events. */
31
+ static readonly ProgressEvents: XHR.Event.Progress[];
32
+ /**
33
+ * Construct a new instance of Xhr.
34
+ *
35
+ * @param options Required options for a proper initialization.
36
+ */
37
+ constructor(options: XHR.Options);
38
+ /**
39
+ * Initialise XMLHttpRequest.
40
+ *
41
+ * @returns The current `Xhr` instance for chaining purposes.
42
+ */
43
+ init(options?: XHR.InitOptions): this;
44
+ /**
45
+ * Send XMLHttpRequest.
46
+ *
47
+ * @returns The current `Xhr` instance for chaining purposes.
48
+ */
49
+ send(): Promise<this>;
50
+ /**
51
+ * Cancels any network activity.
52
+ *
53
+ * @returns The current `Xhr` instance for chaining purposes.
54
+ */
55
+ abort(reason?: string, options?: AbortErrorOptions): this;
56
+ /**
57
+ * Executed when `Xhr.controller` get aborted through `Xhr.abort()` or `Xhr.controller.abort()` methods.
58
+ *
59
+ */
60
+ private controllerAbortListener;
61
+ /**
62
+ * Handle `readystatechange` events.
63
+ *
64
+ * @param event The Event interface.
65
+ */
66
+ private readyStateChangeHandler;
67
+ /**
68
+ * Handle and emit progress events.
69
+ *
70
+ * See {@link Xhr.ProgressEvents} for a list of listened events.
71
+ *
72
+ * @param event The ProgressEvent interface.
73
+ */
74
+ private progressEventHandler;
75
+ /**
76
+ * Emit success or error events based on the received Response on Request Load End.
77
+ *
78
+ */
79
+ private loadEndHandler;
80
+ /**
81
+ * Add listeners to the XMLHttpRequest instance.
82
+ *
83
+ * See {@link Xhr.ProgressEvents} for a list of listened events.
84
+ *
85
+ * @returns The current `Xhr` instance for chaining purposes.
86
+ */
87
+ private addProgressListeners;
88
+ /**
89
+ * Set the request headers.
90
+ *
91
+ * @returns The current `Xhr` instance for chaining purposes.
92
+ */
93
+ private setHeaders;
94
+ /**
95
+ * Convert MIME `Content-Type` to `XMLHttpRequestResponseType`.
96
+ *
97
+ * @param contentType (Optional) The MIME `Content-Type`. Default: `Content-Type` Response Header.
98
+ * @returns The `XMLHttpRequestResponseType` based on the given MIME `Content-Type`.
99
+ */
100
+ private contentTypeToResponseType;
101
+ /**
102
+ * Automatically set `XMLHttpRequestResponseType` based on the received Response `Content-Type` Header.
103
+ *
104
+ * @returns The current `Xhr` instance for chaining purposes.
105
+ */
106
+ private setResponseTypeFromResponseHeaders;
107
+ /**
108
+ * Get formatted response.
109
+ *
110
+ * @returns The response text or an object from a json response.
111
+ */
112
+ getResponse(): TReturn | undefined;
113
+ /**
114
+ * Get `Content-Type` Response Header.
115
+ *
116
+ * @returns The Response Header value, `null` if none has been found.
117
+ */
118
+ getResponseContentType(): string | null;
119
+ /**
120
+ * Get Response Header.
121
+ *
122
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/getResponseHeader)
123
+ *
124
+ * @param name The Header name.
125
+ * @returns The Response Header value, `null` if none has been found.
126
+ */
127
+ getResponseHeader(name: string): string | null;
128
+ /**
129
+ * On success functions.
130
+ *
131
+ * @returns The current `Xhr` instance for chaining purposes.
132
+ */
133
+ private success;
134
+ /**
135
+ * On error functions.
136
+ *
137
+ * @returns The current `Xhr` instance for chaining purposes.
138
+ */
139
+ private error;
140
+ /**
141
+ * Prints to `stdout` with newline.
142
+ *
143
+ * @param data The data print out.
144
+ * @returns The current `Xhr` instance for chaining purposes.
145
+ */
146
+ log(data: Record<'message', string> & Record<string, any>): this;
147
+ }
148
+
149
+ type RequestMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD';
150
+ declare namespace Fetch {
151
+ type Result<T> = {
152
+ /** The received Response. */
153
+ response: Response | null;
154
+ /** The received Response Headers. */
155
+ headers: Headers | null;
156
+ } & ({
157
+ /** The parsed data. */
158
+ data: T;
159
+ error: null;
160
+ } | {
161
+ /** The parsed error. */
162
+ error: Exception;
163
+ data: null;
164
+ });
165
+ type ReturnDataType<T, U extends RequestInit = RequestInit> = (T extends undefined ? (U['responseType'] extends 'blob' ? Blob : U['responseType'] extends 'formdata' ? FormData : U['responseType'] extends 'arraybuffer' ? ArrayBuffer : string) : T);
166
+ type OnFulfilledCallback<V> = (response: Response) => Fetch.Result<V> | PromiseLike<Fetch.Result<V>>;
167
+ }
168
+ declare namespace XHR {
169
+ namespace Event {
170
+ type Progress = keyof XMLHttpRequestEventTargetEventMap;
171
+ type Map<TReturn = unknown> = {
172
+ init: [xhr: Xhr<TReturn>];
173
+ send: [xhr: Xhr<TReturn>];
174
+ success: [response: TReturn, xhr: Xhr<TReturn>];
175
+ error: [error: Exception<string, ErrorCode>, xhr: Xhr<TReturn>];
176
+ abort: [reason: AbortError<string, ErrorCode>, event: ProgressEvent<XMLHttpRequestEventTarget>, xhr: Xhr<TReturn>];
177
+ readystatechange: [event: Event, xhr: Xhr<TReturn>];
178
+ } & {
179
+ [event in Exclude<XHR.Event.Progress, 'abort' | 'error'>]: [event: ProgressEvent<XMLHttpRequestEventTarget>, xhr: Xhr<TReturn>];
180
+ };
181
+ type Listener<TEvent extends keyof XHR.Event.Map<TReturn>, TReturn = unknown> = (Emitter.Listener<XHR.Event.Map<TReturn>, TEvent>);
182
+ }
183
+ interface InitOptions {
184
+ /**
185
+ * A custom controller object that allows you to abort one or more DOM requests as and when desired.
186
+ */
187
+ controller?: AbortController<ErrorCode>;
188
+ }
189
+ interface Options extends XHR.InitOptions {
190
+ /** The URL string or URL object. */
191
+ url: UrlInput;
192
+ /** The request method. Default: `GET`. */
193
+ method?: RequestMethod;
194
+ /** The expected Response Type. */
195
+ responseType?: XMLHttpRequestResponseType;
196
+ /** Automatically set the `responseType` from Response Content-Type Header if set to `true` and `responseType` hasn't been set. Default: `true`. */
197
+ autoResponseType?: boolean;
198
+ /** The body object to send. */
199
+ body?: Document | XMLHttpRequestBodyInit;
200
+ /** The request HeadersInit object. */
201
+ headers?: Headers | HeadersInit;
202
+ /**
203
+ * True when credentials are to be included in a cross-origin request. False when they are to be excluded in a cross-origin request and when cookies are to be ignored in its response. Initially false.
204
+ *
205
+ * When set: throws an "InvalidStateError" DOMException if state is not unsent or opened, or if the send() flag is set.
206
+ */
207
+ withCredentials?: XMLHttpRequest['withCredentials'];
208
+ /**
209
+ * An object with `username` and `password` to send along with the request.
210
+ *
211
+ */
212
+ credentials?: {
213
+ username?: string | null;
214
+ password?: string | null;
215
+ };
216
+ /**
217
+ * Can be set to a time in milliseconds. When set to a non-zero value will cause fetching to terminate after the given time has passed. When the time has passed, the request has not yet completed, and this's synchronous flag is unset, a timeout event will then be dispatched, or a "TimeoutError" DOMException will be thrown otherwise (for the send() method).
218
+ *
219
+ * When set: throws an "InvalidAccessError" DOMException if the synchronous flag is set and current global object is a Window object.
220
+ */
221
+ timeout?: XMLHttpRequest['timeout'];
222
+ /** Whether to `console.log` data on different events. */
223
+ debug?: boolean;
224
+ }
225
+ }
226
+
227
+ export { Fetch as F, type RequestMethod as R, Xhr as X, XHR as a };
@@ -0,0 +1,227 @@
1
+ import Emitter, { EventEmitter } from '@alessiofrittoli/event-emitter';
2
+ import { Exception } from '@alessiofrittoli/exception';
3
+ import { AbortErrorOptions, AbortError } from '@alessiofrittoli/exception/abort';
4
+ import * as _alessiofrittoli_url_utils from '@alessiofrittoli/url-utils';
5
+ import { UrlInput } from '@alessiofrittoli/url-utils';
6
+ import { AbortController } from '@alessiofrittoli/abort-controller';
7
+ import { ErrorCode } from './error.mjs';
8
+
9
+ /**
10
+ * Easly handle XML HTTP Requests.
11
+ *
12
+ */
13
+ declare class Xhr<TReturn = unknown> extends EventEmitter<XHR.Event.Map<TReturn>> implements XHR.Options {
14
+ /** The XMLHttpRequest instance. */
15
+ request: XMLHttpRequest;
16
+ url: _alessiofrittoli_url_utils.UrlInput;
17
+ method: RequestMethod;
18
+ body: XMLHttpRequestBodyInit | Document | undefined;
19
+ headers: Headers;
20
+ credentials: {
21
+ username?: string | null;
22
+ password?: string | null;
23
+ } | undefined;
24
+ response?: TReturn;
25
+ controller: AbortController<ErrorCode>;
26
+ debug: boolean;
27
+ /** Indicates whether to automatically set the XHR response type based on the Response Content-Type Header. */
28
+ private setResponseType;
29
+ private static NotAvailableErr;
30
+ /** XHR progress events. */
31
+ static readonly ProgressEvents: XHR.Event.Progress[];
32
+ /**
33
+ * Construct a new instance of Xhr.
34
+ *
35
+ * @param options Required options for a proper initialization.
36
+ */
37
+ constructor(options: XHR.Options);
38
+ /**
39
+ * Initialise XMLHttpRequest.
40
+ *
41
+ * @returns The current `Xhr` instance for chaining purposes.
42
+ */
43
+ init(options?: XHR.InitOptions): this;
44
+ /**
45
+ * Send XMLHttpRequest.
46
+ *
47
+ * @returns The current `Xhr` instance for chaining purposes.
48
+ */
49
+ send(): Promise<this>;
50
+ /**
51
+ * Cancels any network activity.
52
+ *
53
+ * @returns The current `Xhr` instance for chaining purposes.
54
+ */
55
+ abort(reason?: string, options?: AbortErrorOptions): this;
56
+ /**
57
+ * Executed when `Xhr.controller` get aborted through `Xhr.abort()` or `Xhr.controller.abort()` methods.
58
+ *
59
+ */
60
+ private controllerAbortListener;
61
+ /**
62
+ * Handle `readystatechange` events.
63
+ *
64
+ * @param event The Event interface.
65
+ */
66
+ private readyStateChangeHandler;
67
+ /**
68
+ * Handle and emit progress events.
69
+ *
70
+ * See {@link Xhr.ProgressEvents} for a list of listened events.
71
+ *
72
+ * @param event The ProgressEvent interface.
73
+ */
74
+ private progressEventHandler;
75
+ /**
76
+ * Emit success or error events based on the received Response on Request Load End.
77
+ *
78
+ */
79
+ private loadEndHandler;
80
+ /**
81
+ * Add listeners to the XMLHttpRequest instance.
82
+ *
83
+ * See {@link Xhr.ProgressEvents} for a list of listened events.
84
+ *
85
+ * @returns The current `Xhr` instance for chaining purposes.
86
+ */
87
+ private addProgressListeners;
88
+ /**
89
+ * Set the request headers.
90
+ *
91
+ * @returns The current `Xhr` instance for chaining purposes.
92
+ */
93
+ private setHeaders;
94
+ /**
95
+ * Convert MIME `Content-Type` to `XMLHttpRequestResponseType`.
96
+ *
97
+ * @param contentType (Optional) The MIME `Content-Type`. Default: `Content-Type` Response Header.
98
+ * @returns The `XMLHttpRequestResponseType` based on the given MIME `Content-Type`.
99
+ */
100
+ private contentTypeToResponseType;
101
+ /**
102
+ * Automatically set `XMLHttpRequestResponseType` based on the received Response `Content-Type` Header.
103
+ *
104
+ * @returns The current `Xhr` instance for chaining purposes.
105
+ */
106
+ private setResponseTypeFromResponseHeaders;
107
+ /**
108
+ * Get formatted response.
109
+ *
110
+ * @returns The response text or an object from a json response.
111
+ */
112
+ getResponse(): TReturn | undefined;
113
+ /**
114
+ * Get `Content-Type` Response Header.
115
+ *
116
+ * @returns The Response Header value, `null` if none has been found.
117
+ */
118
+ getResponseContentType(): string | null;
119
+ /**
120
+ * Get Response Header.
121
+ *
122
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/getResponseHeader)
123
+ *
124
+ * @param name The Header name.
125
+ * @returns The Response Header value, `null` if none has been found.
126
+ */
127
+ getResponseHeader(name: string): string | null;
128
+ /**
129
+ * On success functions.
130
+ *
131
+ * @returns The current `Xhr` instance for chaining purposes.
132
+ */
133
+ private success;
134
+ /**
135
+ * On error functions.
136
+ *
137
+ * @returns The current `Xhr` instance for chaining purposes.
138
+ */
139
+ private error;
140
+ /**
141
+ * Prints to `stdout` with newline.
142
+ *
143
+ * @param data The data print out.
144
+ * @returns The current `Xhr` instance for chaining purposes.
145
+ */
146
+ log(data: Record<'message', string> & Record<string, any>): this;
147
+ }
148
+
149
+ type RequestMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD';
150
+ declare namespace Fetch {
151
+ type Result<T> = {
152
+ /** The received Response. */
153
+ response: Response | null;
154
+ /** The received Response Headers. */
155
+ headers: Headers | null;
156
+ } & ({
157
+ /** The parsed data. */
158
+ data: T;
159
+ error: null;
160
+ } | {
161
+ /** The parsed error. */
162
+ error: Exception;
163
+ data: null;
164
+ });
165
+ type ReturnDataType<T, U extends RequestInit = RequestInit> = (T extends undefined ? (U['responseType'] extends 'blob' ? Blob : U['responseType'] extends 'formdata' ? FormData : U['responseType'] extends 'arraybuffer' ? ArrayBuffer : string) : T);
166
+ type OnFulfilledCallback<V> = (response: Response) => Fetch.Result<V> | PromiseLike<Fetch.Result<V>>;
167
+ }
168
+ declare namespace XHR {
169
+ namespace Event {
170
+ type Progress = keyof XMLHttpRequestEventTargetEventMap;
171
+ type Map<TReturn = unknown> = {
172
+ init: [xhr: Xhr<TReturn>];
173
+ send: [xhr: Xhr<TReturn>];
174
+ success: [response: TReturn, xhr: Xhr<TReturn>];
175
+ error: [error: Exception<string, ErrorCode>, xhr: Xhr<TReturn>];
176
+ abort: [reason: AbortError<string, ErrorCode>, event: ProgressEvent<XMLHttpRequestEventTarget>, xhr: Xhr<TReturn>];
177
+ readystatechange: [event: Event, xhr: Xhr<TReturn>];
178
+ } & {
179
+ [event in Exclude<XHR.Event.Progress, 'abort' | 'error'>]: [event: ProgressEvent<XMLHttpRequestEventTarget>, xhr: Xhr<TReturn>];
180
+ };
181
+ type Listener<TEvent extends keyof XHR.Event.Map<TReturn>, TReturn = unknown> = (Emitter.Listener<XHR.Event.Map<TReturn>, TEvent>);
182
+ }
183
+ interface InitOptions {
184
+ /**
185
+ * A custom controller object that allows you to abort one or more DOM requests as and when desired.
186
+ */
187
+ controller?: AbortController<ErrorCode>;
188
+ }
189
+ interface Options extends XHR.InitOptions {
190
+ /** The URL string or URL object. */
191
+ url: UrlInput;
192
+ /** The request method. Default: `GET`. */
193
+ method?: RequestMethod;
194
+ /** The expected Response Type. */
195
+ responseType?: XMLHttpRequestResponseType;
196
+ /** Automatically set the `responseType` from Response Content-Type Header if set to `true` and `responseType` hasn't been set. Default: `true`. */
197
+ autoResponseType?: boolean;
198
+ /** The body object to send. */
199
+ body?: Document | XMLHttpRequestBodyInit;
200
+ /** The request HeadersInit object. */
201
+ headers?: Headers | HeadersInit;
202
+ /**
203
+ * True when credentials are to be included in a cross-origin request. False when they are to be excluded in a cross-origin request and when cookies are to be ignored in its response. Initially false.
204
+ *
205
+ * When set: throws an "InvalidStateError" DOMException if state is not unsent or opened, or if the send() flag is set.
206
+ */
207
+ withCredentials?: XMLHttpRequest['withCredentials'];
208
+ /**
209
+ * An object with `username` and `password` to send along with the request.
210
+ *
211
+ */
212
+ credentials?: {
213
+ username?: string | null;
214
+ password?: string | null;
215
+ };
216
+ /**
217
+ * Can be set to a time in milliseconds. When set to a non-zero value will cause fetching to terminate after the given time has passed. When the time has passed, the request has not yet completed, and this's synchronous flag is unset, a timeout event will then be dispatched, or a "TimeoutError" DOMException will be thrown otherwise (for the send() method).
218
+ *
219
+ * When set: throws an "InvalidAccessError" DOMException if the synchronous flag is set and current global object is a Window object.
220
+ */
221
+ timeout?: XMLHttpRequest['timeout'];
222
+ /** Whether to `console.log` data on different events. */
223
+ debug?: boolean;
224
+ }
225
+ }
226
+
227
+ export { Fetch as F, type RequestMethod as R, Xhr as X, XHR as a };
@@ -0,0 +1,8 @@
1
+ import '@alessiofrittoli/event-emitter';
2
+ import '@alessiofrittoli/exception';
3
+ import '@alessiofrittoli/exception/abort';
4
+ import '@alessiofrittoli/url-utils';
5
+ import '@alessiofrittoli/abort-controller';
6
+ import './error.mjs';
7
+ export { F as Fetch, R as RequestMethod, a as XHR } from './types-DuGUXaTD.mjs';
8
+ import '@alessiofrittoli/exception/code';
@@ -0,0 +1,8 @@
1
+ import '@alessiofrittoli/event-emitter';
2
+ import '@alessiofrittoli/exception';
3
+ import '@alessiofrittoli/exception/abort';
4
+ import '@alessiofrittoli/url-utils';
5
+ import '@alessiofrittoli/abort-controller';
6
+ import './error.js';
7
+ export { F as Fetch, R as RequestMethod, a as XHR } from './types-CVc-rxXe.js';
8
+ import '@alessiofrittoli/exception/code';
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";
package/dist/types.mjs ADDED
File without changes
@@ -0,0 +1,8 @@
1
+ export { X as Xhr } from '../types-DuGUXaTD.mjs';
2
+ import '@alessiofrittoli/url-utils';
3
+ import '@alessiofrittoli/event-emitter';
4
+ import '@alessiofrittoli/exception/abort';
5
+ import '@alessiofrittoli/abort-controller';
6
+ import '../error.mjs';
7
+ import '@alessiofrittoli/exception';
8
+ import '@alessiofrittoli/exception/code';
@@ -0,0 +1,8 @@
1
+ export { X as Xhr } from '../types-CVc-rxXe.js';
2
+ import '@alessiofrittoli/url-utils';
3
+ import '@alessiofrittoli/event-emitter';
4
+ import '@alessiofrittoli/exception/abort';
5
+ import '@alessiofrittoli/abort-controller';
6
+ import '../error.js';
7
+ import '@alessiofrittoli/exception';
8
+ import '@alessiofrittoli/exception/code';
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _chunkHNNMLJIAjs = require('../chunk-HNNMLJIA.js');var _urlutils = require('@alessiofrittoli/url-utils');var _eventemitter = require('@alessiofrittoli/event-emitter');var _exception = require('@alessiofrittoli/exception');var _abortcontroller = require('@alessiofrittoli/abort-controller');var r=class r extends _eventemitter.EventEmitter{constructor(e){super({captureRejections:!0});this.setResponseType=!1;this.controllerAbortListener=()=>{this.controller.signal.removeEventListener("abort",this.controllerAbortListener),this.request.abort(),this.log({message:this.controller.signal.reason.message})};this.readyStateChangeHandler=async e=>{if(this.setResponseType&&this.setResponseTypeFromResponseHeaders(),this.debug){let{logReadyStateChange:t}=await Promise.resolve().then(() => _interopRequireWildcard(require("../logReadyStateChange-MSYI3OBQ.js")));t(this)}this.response=this.getResponse(),this.emit("readystatechange",e,this)};this.progressEventHandler=e=>{let t=e.type;return this.log({event:t,message:`${e.loaded} bytes transferred.`}),t==="abort"?(this.emit("abort",this.controller.signal.reason,e,this),this):t==="error"?this.error(new (0, _exception.Exception)("ProgressEvent Error",{code:_chunkHNNMLJIAjs.b.Exception.UNKNOWN,cause:e})):(this.emit(t,e,this),this)};this.loadEndHandler=async()=>{let{status:e}=this.request;if(e<=0)return this;try{if(e<100||e>=400){if(this.setResponseTypeFromResponseHeaders(),this.contentTypeToResponseType()==="json"&&_exception.Exception.isException(this.response))return this.error(new (0, _exception.Exception)(this.response.message,{...this.response}));let{response:t}=this,{responseType:n}=this.request,{getErrorFromResponse:u}=await Promise.resolve().then(() => _interopRequireWildcard(require("../getErrorFromResponse-7V2YFS4F.js"))),o=await u({responseType:n,response:t});return o?this.error(o):this.error(new (0, _exception.Exception)("Error from the server.",{code:_chunkHNNMLJIAjs.b.Exception.UNKNOWN,cause:this.response}))}return this.success()}catch(t){let n=t;return this.error(new (0, _exception.Exception)(n.message,{code:_chunkHNNMLJIAjs.b.Exception.UNKNOWN,...n}))}};this.request=typeof XMLHttpRequest<"u"?new XMLHttpRequest:null,this.setResponseType=_nullishCoalesce(e.autoResponseType, () => (!0)),this.request&&(typeof e.responseType<"u"&&(this.setResponseType=!1,this.request.responseType=e.responseType),typeof e.withCredentials<"u"&&(this.request.withCredentials=e.withCredentials),e.timeout&&(this.request.timeout=e.timeout)),this.url=e.url,this.method=e.method||"GET",this.body=e.body,this.controller=e.controller||new _abortcontroller.AbortController,this.headers=new Headers(e.headers),this.credentials=e.credentials,this.debug=e.debug||!1}init(e={}){return this.request?(e.controller&&(this.controller=e.controller),this.controller.signal.aborted&&(this.controller=e.controller||new _abortcontroller.AbortController),this.emit("init",this),this.addProgressListeners(),this.request.open(this.method,_urlutils.Url.format(this.url),!0,_optionalChain([this, 'access', _ => _.credentials, 'optionalAccess', _2 => _2.username]),_optionalChain([this, 'access', _3 => _3.credentials, 'optionalAccess', _4 => _4.password])),this.setHeaders(),this.request.removeEventListener("readystatechange",this.readyStateChangeHandler),this.request.addEventListener("readystatechange",this.readyStateChangeHandler),this.once("loadend",this.loadEndHandler),this.controller.signal.addEventListener("abort",this.controllerAbortListener),this):this.error(r.NotAvailableErr)}async send(){if(!this.request)return this.error(r.NotAvailableErr);try{return this.emit("send",this),await this.request.send(this.body),this}catch(e){let t=e,n=t.name==="InvalidStateError"?_chunkHNNMLJIAjs.b.Request.XHR_INVALID_STATE:_chunkHNNMLJIAjs.b.Exception.UNKNOWN;return this.error(new (0, _exception.Exception)(t.message,{code:n,name:t.name,cause:t}))}}abort(e,t){return this.request?(this.controller.abort(e,t),this):this.error(r.NotAvailableErr)}addProgressListeners(){return this.request?(r.ProgressEvents.map(e=>{this.request.removeEventListener(e,this.progressEventHandler),this.request.addEventListener(e,this.progressEventHandler)}),this):this.error(r.NotAvailableErr)}setHeaders(){return this.request?(Array.from(this.headers.entries()).forEach(([e,t])=>{this.request.setRequestHeader(e,t)}),this):this.error(r.NotAvailableErr)}contentTypeToResponseType(e){return typeof e>"u"&&(e=this.getResponseContentType()),e?(e=e.toLowerCase(),e.includes("text/html")||e.includes("application/xml")?"document":e.includes("application/json")?"json":e.includes("application/octet-stream")?"arraybuffer":e.startsWith("image/")||e.startsWith("video/")?"blob":"text"):""}setResponseTypeFromResponseHeaders(){if(this.request.readyState===XMLHttpRequest.LOADING||this.request.readyState===XMLHttpRequest.DONE)return this;let e=this.getResponseContentType();return this.request.responseType=this.contentTypeToResponseType(e),this.log({message:"Set XMLHttpRequest.responseType from Content-Type Response Headers.",contentType:e,XhrResponseType:this.request.responseType}),this}getResponse(){if(!this.request){this.error(r.NotAvailableErr);return}return this.response=this.request.response,this.response}getResponseContentType(){return this.getResponseHeader("Content-Type")}getResponseHeader(e){return this.request.getResponseHeader(e)}success(){return this.emit("success",this.response,this),this}error(e){return this.emit("error",e,this),this}log(e){return this.debug?(console.log({class:"Xhr",...e}),this):this}};r.NotAvailableErr=new (0, _exception.Exception)("XMLHttpRequest not available",{code:_chunkHNNMLJIAjs.b.Request.XHR_NOT_AVAILABLE}),r.ProgressEvents=["abort","timeout","error","loadstart","progress","load","loadend"];var h=r;exports.Xhr = h;
@@ -0,0 +1 @@
1
+ import{b as s}from"../chunk-LOWOZ6LK.mjs";import{Url as p}from"@alessiofrittoli/url-utils";import{EventEmitter as l}from"@alessiofrittoli/event-emitter";import{Exception as i}from"@alessiofrittoli/exception";import{AbortController as a}from"@alessiofrittoli/abort-controller";var r=class r extends l{constructor(e){super({captureRejections:!0});this.setResponseType=!1;this.controllerAbortListener=()=>{this.controller.signal.removeEventListener("abort",this.controllerAbortListener),this.request.abort(),this.log({message:this.controller.signal.reason.message})};this.readyStateChangeHandler=async e=>{if(this.setResponseType&&this.setResponseTypeFromResponseHeaders(),this.debug){let{logReadyStateChange:t}=await import("../logReadyStateChange-2QWX5XIU.mjs");t(this)}this.response=this.getResponse(),this.emit("readystatechange",e,this)};this.progressEventHandler=e=>{let t=e.type;return this.log({event:t,message:`${e.loaded} bytes transferred.`}),t==="abort"?(this.emit("abort",this.controller.signal.reason,e,this),this):t==="error"?this.error(new i("ProgressEvent Error",{code:s.Exception.UNKNOWN,cause:e})):(this.emit(t,e,this),this)};this.loadEndHandler=async()=>{let{status:e}=this.request;if(e<=0)return this;try{if(e<100||e>=400){if(this.setResponseTypeFromResponseHeaders(),this.contentTypeToResponseType()==="json"&&i.isException(this.response))return this.error(new i(this.response.message,{...this.response}));let{response:t}=this,{responseType:n}=this.request,{getErrorFromResponse:u}=await import("../getErrorFromResponse-IJTUOFPH.mjs"),o=await u({responseType:n,response:t});return o?this.error(o):this.error(new i("Error from the server.",{code:s.Exception.UNKNOWN,cause:this.response}))}return this.success()}catch(t){let n=t;return this.error(new i(n.message,{code:s.Exception.UNKNOWN,...n}))}};this.request=typeof XMLHttpRequest<"u"?new XMLHttpRequest:null,this.setResponseType=e.autoResponseType??!0,this.request&&(typeof e.responseType<"u"&&(this.setResponseType=!1,this.request.responseType=e.responseType),typeof e.withCredentials<"u"&&(this.request.withCredentials=e.withCredentials),e.timeout&&(this.request.timeout=e.timeout)),this.url=e.url,this.method=e.method||"GET",this.body=e.body,this.controller=e.controller||new a,this.headers=new Headers(e.headers),this.credentials=e.credentials,this.debug=e.debug||!1}init(e={}){return this.request?(e.controller&&(this.controller=e.controller),this.controller.signal.aborted&&(this.controller=e.controller||new a),this.emit("init",this),this.addProgressListeners(),this.request.open(this.method,p.format(this.url),!0,this.credentials?.username,this.credentials?.password),this.setHeaders(),this.request.removeEventListener("readystatechange",this.readyStateChangeHandler),this.request.addEventListener("readystatechange",this.readyStateChangeHandler),this.once("loadend",this.loadEndHandler),this.controller.signal.addEventListener("abort",this.controllerAbortListener),this):this.error(r.NotAvailableErr)}async send(){if(!this.request)return this.error(r.NotAvailableErr);try{return this.emit("send",this),await this.request.send(this.body),this}catch(e){let t=e,n=t.name==="InvalidStateError"?s.Request.XHR_INVALID_STATE:s.Exception.UNKNOWN;return this.error(new i(t.message,{code:n,name:t.name,cause:t}))}}abort(e,t){return this.request?(this.controller.abort(e,t),this):this.error(r.NotAvailableErr)}addProgressListeners(){return this.request?(r.ProgressEvents.map(e=>{this.request.removeEventListener(e,this.progressEventHandler),this.request.addEventListener(e,this.progressEventHandler)}),this):this.error(r.NotAvailableErr)}setHeaders(){return this.request?(Array.from(this.headers.entries()).forEach(([e,t])=>{this.request.setRequestHeader(e,t)}),this):this.error(r.NotAvailableErr)}contentTypeToResponseType(e){return typeof e>"u"&&(e=this.getResponseContentType()),e?(e=e.toLowerCase(),e.includes("text/html")||e.includes("application/xml")?"document":e.includes("application/json")?"json":e.includes("application/octet-stream")?"arraybuffer":e.startsWith("image/")||e.startsWith("video/")?"blob":"text"):""}setResponseTypeFromResponseHeaders(){if(this.request.readyState===XMLHttpRequest.LOADING||this.request.readyState===XMLHttpRequest.DONE)return this;let e=this.getResponseContentType();return this.request.responseType=this.contentTypeToResponseType(e),this.log({message:"Set XMLHttpRequest.responseType from Content-Type Response Headers.",contentType:e,XhrResponseType:this.request.responseType}),this}getResponse(){if(!this.request){this.error(r.NotAvailableErr);return}return this.response=this.request.response,this.response}getResponseContentType(){return this.getResponseHeader("Content-Type")}getResponseHeader(e){return this.request.getResponseHeader(e)}success(){return this.emit("success",this.response,this),this}error(e){return this.emit("error",e,this),this}log(e){return this.debug?(console.log({class:"Xhr",...e}),this):this}};r.NotAvailableErr=new i("XMLHttpRequest not available",{code:s.Request.XHR_NOT_AVAILABLE}),r.ProgressEvents=["abort","timeout","error","loadstart","progress","load","loadend"];var h=r;export{h as Xhr};
package/license.md ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Alessio Frittoli.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json ADDED
@@ -0,0 +1,125 @@
1
+ {
2
+ "name": "@alessiofrittoli/fetcher",
3
+ "version": "0.1.0-alpha.1",
4
+ "description": "Typescript fetch/xhr utilities",
5
+ "author": {
6
+ "name": "Alessio Frittoli",
7
+ "email": "info@alessiofrittoli.it",
8
+ "url": "https://alessiofrittoli.it"
9
+ },
10
+ "license": "MIT",
11
+ "funding": [
12
+ {
13
+ "type": "github",
14
+ "url": "https://github.com/sponsors/alessiofrittoli"
15
+ }
16
+ ],
17
+ "keywords": [
18
+ "fetch",
19
+ "ajax"
20
+ ],
21
+ "homepage": "https://github.com/alessiofrittoli/fetcher#readme",
22
+ "bugs": {
23
+ "url": "https://github.com/alessiofrittoli/fetcher/issues",
24
+ "email": "info@alessiofrittoli.it"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/alessiofrittoli/fetcher.git"
29
+ },
30
+ "main": "./dist/index.js",
31
+ "module": "./dist/index.mjs",
32
+ "types": "./dist/index.d.ts",
33
+ "files": [
34
+ "dist",
35
+ "scripts/postinstall"
36
+ ],
37
+ "exports": {
38
+ ".": {
39
+ "types": "./dist/index.d.ts",
40
+ "import": "./dist/index.mjs",
41
+ "require": "./dist/index.js"
42
+ },
43
+ "./fetch": {
44
+ "types": "./dist/fetch.d.ts",
45
+ "import": "./dist/fetch.mjs",
46
+ "require": "./dist/fetch.js"
47
+ },
48
+ "./xhr": {
49
+ "types": "./dist/xhr/index.d.ts",
50
+ "import": "./dist/xhr/index.mjs",
51
+ "require": "./dist/xhr/index.js"
52
+ },
53
+ "./error": {
54
+ "types": "./dist/error.d.ts",
55
+ "import": "./dist/error.mjs",
56
+ "require": "./dist/error.js"
57
+ },
58
+ "./types": {
59
+ "types": "./dist/types.d.ts"
60
+ }
61
+ },
62
+ "sideEffects": false,
63
+ "scripts": {
64
+ "//1a": "*********************************************************************",
65
+ "//1b": "******************** DEV - BUILD - LINT - RELEASE *******************",
66
+ "//1c": "*********************************************************************",
67
+ "dev": "NODE_ENV=development tsup --watch",
68
+ "build:prod": "NODE_ENV=production tsup",
69
+ "build": "pnpm lint && pnpm test:ci && pnpm build:prod",
70
+ "lint": "eslint",
71
+ "release": "node scripts/publish.js --verbose --npm",
72
+ "//2a": "*********************************************************************",
73
+ "//2b": "***************************** UNIT TESTS ****************************",
74
+ "//2c": "*********************************************************************",
75
+ "test": "jest --verbose",
76
+ "test:watch": "jest --watchAll --verbose",
77
+ "test:ci": "jest --ci --verbose",
78
+ "//3a": "*********************************************************************",
79
+ "//3b": "************************ UNIT TESTS COVERAGE ************************",
80
+ "//3c": "*********************************************************************",
81
+ "test:coverage": "pnpm test:watch --coverage",
82
+ "test:coverage:ci": "pnpm test:ci --coverage",
83
+ "test:serve-coverage": "http-server ./coverage/lcov-report --gzip true -p 0 -o --silent",
84
+ "test:coverage:serve": "concurrently --prefix none --kill-others \"pnpm test:coverage\" \"pnpm test:serve-coverage\"",
85
+ "//4a": "*********************************************************************",
86
+ "//4b": "************************ TARGETED UNIT TESTS ************************",
87
+ "//4c": "*********************************************************************",
88
+ "test:fetch": "pnpm test:watch fetch.test.ts"
89
+ },
90
+ "devDependencies": {
91
+ "@alessiofrittoli/crypto-buffer": "^3.6.0",
92
+ "@eslint/js": "^9.27.0",
93
+ "@jest/globals": "^29.7.0",
94
+ "@types/jest": "^29.5.14",
95
+ "@types/node": "^22.15.21",
96
+ "concurrently": "^9.1.2",
97
+ "dotenv": "^16.5.0",
98
+ "eslint": "^9.27.0",
99
+ "globals": "^16.1.0",
100
+ "http-server": "^14.1.1",
101
+ "jest": "^29.7.0",
102
+ "jest-environment-jsdom": "^29.7.0",
103
+ "ts-jest": "^29.3.4",
104
+ "ts-node": "^10.9.2",
105
+ "tsup": "^8.5.0",
106
+ "typescript": "^5.8.3",
107
+ "typescript-eslint": "^8.32.1"
108
+ },
109
+ "dependencies": {
110
+ "@alessiofrittoli/abort-controller": "^0.1.0",
111
+ "@alessiofrittoli/chain-functions": "^2.3.0",
112
+ "@alessiofrittoli/event-emitter": "^1.4.0",
113
+ "@alessiofrittoli/exception": "^3.2.0",
114
+ "@alessiofrittoli/node-scripts": "^2.6.0",
115
+ "@alessiofrittoli/type-utils": "^1.8.0",
116
+ "@alessiofrittoli/url-utils": "^3.4.0",
117
+ "@alessiofrittoli/web-utils": "^1.11.0"
118
+ },
119
+ "pnpm": {
120
+ "onlyBuiltDependencies": [
121
+ "@alessiofrittoli/type-utils",
122
+ "esbuild"
123
+ ]
124
+ }
125
+ }
@@ -0,0 +1,16 @@
1
+ const { Chain } = require( '@alessiofrittoli/chain-functions' )
2
+ const tsSetup = require( './ts-setup.js' )
3
+ const project = require( '../../package.json' )
4
+
5
+ /** @type {import( '@alessiofrittoli/chain-functions/types' ).LastChainLink<() => void | Promise<void>>} */
6
+ const lastChainLink = () => () => {
7
+ console.log( {
8
+ package: project.name,
9
+ message: 'Post-Install done'
10
+ } )
11
+ }
12
+
13
+ /** @type {import( '@alessiofrittoli/chain-functions/types' ).ChainFactory<() => void | Promise<void>>} */
14
+ const chain = [ tsSetup, lastChainLink ]
15
+
16
+ Chain.functions( chain )()
@@ -0,0 +1,15 @@
1
+ const project = require( '../../package.json' )
2
+ const { addTypesReference } = require( '@alessiofrittoli/node-scripts/postinstall' )
3
+
4
+
5
+ /** @type {import( '@alessiofrittoli/chain-functions/types' ).ChainLink<() => void | Promise<void>>} */
6
+ const tsSetup = next => () => {
7
+
8
+ addTypesReference( {
9
+ name: project.name,
10
+ } )
11
+
12
+ return next()
13
+ }
14
+
15
+ module.exports = tsSetup