@utiliread/http 1.1.8 → 1.10.2

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.
@@ -1,26 +1,24 @@
1
- import { Fetch, Options } from './http';
1
+ import { Fetch } from './http';
2
2
  import { HttpResponse, HttpResponseOfT } from './http-response';
3
3
  import { TimeoutError } from './timeout-error';
4
- import { Settings } from './settings';
4
+ import { EventAggregator } from './event-aggregator';
5
+ import { Http } from '.';
5
6
 
6
7
  export class HttpBuilder {
7
8
  private _ensureSuccessStatusCode = true;
8
- private _onSend: ((request: Message) => void | Promise<any>)[] = [];
9
- private _onSent: ((request: Message, response: HttpResponse) => void | Promise<any>)[] = [];
9
+ private _onSend = new EventAggregator<[Message]>();
10
+ private _onSent = new EventAggregator<[HttpResponse, Message]>();
10
11
 
11
- constructor(public message: Message, public options: Options) {
12
- if (options.onSent) {
13
- this._onSent.push(options.onSent);
14
- }
12
+ constructor(public message: Message, public options: RequestOptions, /** @internal */ public http: Http) {
15
13
  }
16
14
 
17
- onSend(callback: (request: Message) => void | Promise<any>) {
18
- this._onSend.push(callback);
15
+ onSend(callback: (request: Message) => void | Promise<void>) {
16
+ this._onSend.subscribe(callback);
19
17
  return this;
20
18
  }
21
19
 
22
- onSent(callback: (request: Message, response: HttpResponse) => void | Promise<any>) {
23
- this._onSent.push(callback);
20
+ onSent(callback: (response: HttpResponse, request: Message) => void | Promise<void>) {
21
+ this._onSent.subscribe(callback);
24
22
  return this;
25
23
  }
26
24
 
@@ -29,10 +27,6 @@ export class HttpBuilder {
29
27
  }
30
28
 
31
29
  async send(abortSignal?: AbortSignal) {
32
- if (!this.options.fetch) {
33
- throw Error('fetch() is not properly configured');
34
- }
35
-
36
30
  if (this.message.contentType) {
37
31
  this.message.headers.set('Content-Type', this.message.contentType);
38
32
  }
@@ -41,9 +35,8 @@ export class HttpBuilder {
41
35
  // This makes the final url apper in onSend, onSent, and on Received handlers
42
36
  this.message.url = this.getUrl();
43
37
 
44
- for (const callback of this._onSend) {
45
- await Promise.resolve(callback(this.message));
46
- }
38
+ await this._onSend.publish(this.message);
39
+ await this.http._onSend.publish(this.message);
47
40
 
48
41
  const init: RequestInit = {
49
42
  method: this.message.method,
@@ -54,7 +47,6 @@ export class HttpBuilder {
54
47
 
55
48
  if (abortSignal || this.options.timeout) {
56
49
  var outerController = new AbortController();
57
-
58
50
  if (abortSignal) {
59
51
  abortSignal.addEventListener("abort", () => {
60
52
  outerController.abort();
@@ -86,9 +78,8 @@ export class HttpBuilder {
86
78
  httpResponse.ensureSuccessfulStatusCode();
87
79
  }
88
80
 
89
- for (const callback of this._onSent) {
90
- await Promise.resolve(callback(this.message, httpResponse));
91
- }
81
+ await this._onSent.publish(httpResponse, this.message);
82
+ await this.http._onSent.publish(httpResponse, this.message);
92
83
 
93
84
  return httpResponse;
94
85
  }
@@ -117,34 +108,11 @@ export class HttpBuilder {
117
108
  return this;
118
109
  }
119
110
 
120
- use(settings: Settings) {
121
- if (settings.fetch) {
122
- this.useFetch(settings.fetch);
123
- }
124
- if (settings.corsMode) {
125
- this.useCors(settings.corsMode);
126
- }
127
- if (settings.baseUrl) {
128
- this.useBaseUrl(settings.baseUrl);
129
- }
130
- return this;
131
- }
132
-
133
- useFetch(fetch: Fetch) {
134
- this.options.fetch = fetch;
135
- return this;
136
- }
137
-
138
111
  useCors(mode: RequestMode) {
139
112
  this.message.mode = mode;
140
113
  return this;
141
114
  }
142
115
 
143
- useBaseUrl(baseUrl: string) {
144
- this.options.baseUrl = baseUrl;
145
- return this;
146
- }
147
-
148
116
  useTimeout(timeout: number | null) {
149
117
  this.options.timeout = timeout || undefined;
150
118
  return this;
@@ -187,22 +155,18 @@ export class HttpBuilder {
187
155
  }
188
156
 
189
157
  export class HttpBuilderOfT<T> extends HttpBuilder {
190
- private _onReceived: ((request: Message, response: HttpResponseOfT<T>, value: T) => void | Promise<any>)[] = [];
158
+ private _onReceived = new EventAggregator<[HttpResponseOfT<T>, Message, T]>();
191
159
 
192
160
  constructor(private inner: HttpBuilder, private handler: (response: Response) => Promise<T>) {
193
- super(inner.message, inner.options);
194
-
195
- if (inner.options.onReceived) {
196
- this._onReceived.push(inner.options.onReceived);
197
- }
161
+ super(inner.message, inner.options, inner.http);
198
162
  }
199
163
 
200
- onSend(callback: (request: Message) => void | Promise<any>) {
164
+ onSend(callback: (request: Message) => void | Promise<void>) {
201
165
  this.inner.onSend(callback);
202
166
  return this;
203
167
  }
204
168
 
205
- onSent(callback: (request: Message, response: HttpResponse) => void | Promise<any>) {
169
+ onSent(callback: (response: HttpResponse, request: Message) => void | Promise<void>) {
206
170
  this.inner.onSent(callback);
207
171
  return this;
208
172
  }
@@ -212,34 +176,19 @@ export class HttpBuilderOfT<T> extends HttpBuilder {
212
176
  return this;
213
177
  }
214
178
 
215
- use(settings: Settings) {
216
- this.inner.use(settings);
217
- return this;
218
- }
219
-
220
- useFetch(fetch: Fetch) {
221
- this.inner.useFetch(fetch);
222
- return this;
223
- }
224
-
225
179
  useCors(mode: RequestMode) {
226
180
  this.inner.useCors(mode);
227
181
  return this;
228
182
  }
229
183
 
230
- useBaseUrl(baseUrl: string) {
231
- this.inner.useBaseUrl(baseUrl);
232
- return this;
233
- }
234
-
235
184
  useTimeout(timeout: number) {
236
185
  this.inner.useTimeout(timeout);
237
186
  return this;
238
187
  }
239
188
 
240
189
  allowEmptyResponse() {
241
- if (this._onReceived.length) {
242
- throw new Error("onReceived() should only be called after allowEmptyResponse()");
190
+ if (this._onReceived.any) {
191
+ throw new Error("onReceived() must be called after allowEmptyResponse() because the callback type changes");
243
192
  }
244
193
 
245
194
  return new HttpBuilderOfT<T | null>(this.inner, response => {
@@ -251,8 +200,8 @@ export class HttpBuilderOfT<T> extends HttpBuilder {
251
200
  });
252
201
  }
253
202
 
254
- onReceived(callback: (request: Message, response: HttpResponseOfT<T>, value: T) => void | Promise<any>) {
255
- this._onReceived.push(callback);
203
+ onReceived(callback: (response: HttpResponseOfT<T>, request: Message, value: T) => void | Promise<void>) {
204
+ this._onReceived.subscribe(callback);
256
205
  return this;
257
206
  }
258
207
 
@@ -270,9 +219,8 @@ export class HttpBuilderOfT<T> extends HttpBuilder {
270
219
  const request = this.message;
271
220
  const value = await response.receive();
272
221
 
273
- for (const callback of this._onReceived) {
274
- await Promise.resolve(callback(request, response, value));
275
- }
222
+ await this._onReceived.publish(response, request, value);
223
+ await this.http._onReceived.publish(response, request, value);
276
224
 
277
225
  return value;
278
226
  }
@@ -289,6 +237,12 @@ export interface Message {
289
237
  mode?: RequestMode;
290
238
  }
291
239
 
240
+ export interface RequestOptions {
241
+ fetch: Fetch,
242
+ timeout?: number,
243
+ baseUrl?: string,
244
+ }
245
+
292
246
  export interface SendPromise<T> extends Promise<HttpResponseOfT<T>> {
293
247
  thenReceive(): Promise<T>;
294
248
  }
@@ -9,6 +9,10 @@ export class HttpResponse {
9
9
  return this.rawResponse.status;
10
10
  }
11
11
 
12
+ get headers() {
13
+ return this.rawResponse.headers;
14
+ }
15
+
12
16
  get isInformational() {
13
17
  return this.statusCode >= 100 && this.statusCode < 200;
14
18
  }
package/src/http.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { EventAggregator } from './event-aggregator';
1
2
  import { HttpBuilder, HttpMethod, Message } from './http-builder';
2
3
  import { HttpResponse, HttpResponseOfT } from './http-response';
3
4
  import { QueryString } from './query-string';
@@ -5,13 +6,19 @@ import { QueryString } from './query-string';
5
6
  export type Fetch = (input: RequestInfo, init?: RequestInit) => Promise<Response>;
6
7
 
7
8
  export class Http {
8
- static defaults: Options = {
9
+ static defaults: HttpOptions = {
9
10
  fetch: window.fetch ? window.fetch.bind(window) : undefined,
10
11
  }
11
12
  private static instance?: Http;
12
- options: Readonly<Options>;
13
-
14
- constructor(options?: Partial<Options>) {
13
+ options: HttpOptions;
14
+ /** @internal */
15
+ _onSend = new EventAggregator<[Message]>();
16
+ /** @internal */
17
+ _onSent = new EventAggregator<[HttpResponse, Message]>();
18
+ /** @internal */
19
+ _onReceived = new EventAggregator<[HttpResponseOfT<any>, Message, any]>();
20
+
21
+ constructor(options?: Partial<HttpOptions>) {
15
22
  this.options = Object.assign({}, Http.defaults, options); // Later sources' properties overwrite earlier ones.
16
23
  }
17
24
 
@@ -58,8 +65,16 @@ export class Http {
58
65
  url: url + QueryString.serialize(params),
59
66
  headers: new Headers()
60
67
  };
61
- const options = Object.assign({}, this.options);
62
- return new HttpBuilder(message, options);
68
+ const fetch = this.options.fetch;
69
+ if (!fetch) {
70
+ throw Error('fetch() is not properly configured');
71
+ }
72
+ const builder = new HttpBuilder(message, {
73
+ fetch,
74
+ timeout: this.options.timeout,
75
+ baseUrl: this.options.baseUrl,
76
+ }, this);
77
+ return builder;
63
78
  }
64
79
 
65
80
  head(url: string, params?: any) {
@@ -85,12 +100,22 @@ export class Http {
85
100
  delete(url: string, params?: any) {
86
101
  return this.request('DELETE', url, params);
87
102
  }
103
+
104
+ onSend(callback: (request: Message) => void | Promise<void>) {
105
+ return this._onSend.subscribe(callback);
106
+ }
107
+
108
+ onSent(callback: (response: HttpResponse, request: Message) => void | Promise<void>) {
109
+ return this._onSent.subscribe(callback);
110
+ }
111
+
112
+ onReceived(callback: (response: HttpResponseOfT<any>, request: Message, value: any) => void | Promise<void>) {
113
+ return this._onReceived.subscribe(callback);
114
+ }
88
115
  }
89
116
 
90
- export interface Options {
117
+ export interface HttpOptions {
91
118
  fetch?: Fetch,
92
119
  timeout?: number,
93
120
  baseUrl?: string,
94
- onSent?: (request: Message, response: HttpResponse) => void | Promise<any>;
95
- onReceived?: <T>(request: Message, response: HttpResponseOfT<T>, value: T) => void | Promise<any>;
96
121
  }
package/src/index.ts CHANGED
@@ -13,4 +13,4 @@ export { HttpError } from "./http-error";
13
13
  export { TimeoutError } from "./timeout-error";
14
14
  export * from "./helpers";
15
15
  export { Fetch } from "./http";
16
- export { Settings } from "./settings";
16
+ export { Subscription } from "./event-aggregator";
package/tsconfig.json CHANGED
@@ -8,6 +8,7 @@
8
8
  "strict": true,
9
9
  "rootDir": "src",
10
10
  "outDir": "dist/esm",
11
- "lib": [ "es2017", "dom" ]
11
+ "lib": [ "es2017", "dom" ],
12
+ "stripInternal": true,
12
13
  }
13
14
  }
package/src/settings.ts DELETED
@@ -1,7 +0,0 @@
1
- import { Fetch } from "./http";
2
-
3
- export interface Settings {
4
- fetch?: Fetch;
5
- corsMode?: RequestMode;
6
- baseUrl?: string;
7
- }