@naturalcycles/js-lib 14.120.0 → 14.122.0

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.
@@ -80,6 +80,12 @@ export interface FetcherOptions {
80
80
  timeoutSeconds?: number;
81
81
  json?: any;
82
82
  text?: string;
83
+ /**
84
+ * Supports all the types that RequestInit.body supports.
85
+ *
86
+ * Useful when you want to e.g pass FormData.
87
+ */
88
+ body?: Blob | BufferSource | FormData | URLSearchParams | string;
83
89
  credentials?: RequestCredentials;
84
90
  headers?: Record<string, any>;
85
91
  mode?: FetcherMode;
@@ -140,12 +146,22 @@ export declare class Fetcher {
140
146
  onBeforeRetry(hook: FetcherBeforeRetryHook): this;
141
147
  cfg: FetcherNormalizedCfg;
142
148
  static create(cfg?: FetcherCfg & FetcherOptions): Fetcher;
143
- getJson<T = unknown>(url: string, opt?: FetcherOptions): Promise<T>;
144
- postJson<T = unknown>(url: string, opt?: FetcherOptions): Promise<T>;
145
- putJson<T = unknown>(url: string, opt?: FetcherOptions): Promise<T>;
146
- patchJson<T = unknown>(url: string, opt?: FetcherOptions): Promise<T>;
147
- deleteJson<T = unknown>(url: string, opt?: FetcherOptions): Promise<T>;
148
- getText(url: string, opt?: FetcherOptions): Promise<string>;
149
+ get: (url: string, opt?: FetcherOptions) => Promise<void>;
150
+ post: (url: string, opt?: FetcherOptions) => Promise<void>;
151
+ put: (url: string, opt?: FetcherOptions) => Promise<void>;
152
+ patch: (url: string, opt?: FetcherOptions) => Promise<void>;
153
+ delete: (url: string, opt?: FetcherOptions) => Promise<void>;
154
+ head: (url: string, opt?: FetcherOptions) => Promise<void>;
155
+ getText: (url: string, opt?: FetcherOptions) => Promise<string>;
156
+ postText: (url: string, opt?: FetcherOptions) => Promise<string>;
157
+ putText: (url: string, opt?: FetcherOptions) => Promise<string>;
158
+ patchText: (url: string, opt?: FetcherOptions) => Promise<string>;
159
+ deleteText: (url: string, opt?: FetcherOptions) => Promise<string>;
160
+ getJson: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>;
161
+ postJson: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>;
162
+ putJson: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>;
163
+ patchJson: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>;
164
+ deleteJson: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>;
149
165
  fetch<T = unknown>(url: string, opt?: FetcherOptions): Promise<T>;
150
166
  rawFetch<T = unknown>(url: string, rawOpt?: FetcherOptions): Promise<FetcherResponse<T>>;
151
167
  private processRetry;
@@ -9,6 +9,7 @@ const object_util_1 = require("../object/object.util");
9
9
  const pDelay_1 = require("../promise/pDelay");
10
10
  const json_util_1 = require("../string/json.util");
11
11
  const time_util_1 = require("../time/time.util");
12
+ const http_model_1 = require("./http.model");
12
13
  const defRetryOptions = {
13
14
  count: 2,
14
15
  timeout: 500,
@@ -24,6 +25,30 @@ const defRetryOptions = {
24
25
  class Fetcher {
25
26
  constructor(cfg = {}) {
26
27
  this.cfg = this.normalizeCfg(cfg);
28
+ // Dynamically create all helper methods
29
+ http_model_1.HTTP_METHODS.forEach(method => {
30
+ // mode=void
31
+ this[method] = async (url, opt) => {
32
+ return await this.fetch(url, {
33
+ ...opt,
34
+ method,
35
+ });
36
+ };
37
+ this[`${method}Text`] = async (url, opt) => {
38
+ return await this.fetch(url, {
39
+ ...opt,
40
+ method,
41
+ mode: 'text',
42
+ });
43
+ };
44
+ this[`${method}Json`] = async (url, opt) => {
45
+ return await this.fetch(url, {
46
+ ...opt,
47
+ method,
48
+ mode: 'json',
49
+ });
50
+ };
51
+ });
27
52
  }
28
53
  /**
29
54
  * Add BeforeRequest hook at the end of the hooks list.
@@ -46,46 +71,7 @@ class Fetcher {
46
71
  static create(cfg = {}) {
47
72
  return new Fetcher(cfg);
48
73
  }
49
- async getJson(url, opt) {
50
- return await this.fetch(url, {
51
- ...opt,
52
- mode: 'json',
53
- });
54
- }
55
- async postJson(url, opt) {
56
- return await this.fetch(url, {
57
- ...opt,
58
- method: 'post',
59
- mode: 'json',
60
- });
61
- }
62
- async putJson(url, opt) {
63
- return await this.fetch(url, {
64
- ...opt,
65
- method: 'put',
66
- mode: 'json',
67
- });
68
- }
69
- async patchJson(url, opt) {
70
- return await this.fetch(url, {
71
- ...opt,
72
- method: 'patch',
73
- mode: 'json',
74
- });
75
- }
76
- async deleteJson(url, opt) {
77
- return await this.fetch(url, {
78
- ...opt,
79
- method: 'delete',
80
- mode: 'json',
81
- });
82
- }
83
- async getText(url, opt) {
84
- return await this.fetch(url, {
85
- ...opt,
86
- mode: 'text',
87
- });
88
- }
74
+ // headJson!: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>
89
75
  async fetch(url, opt) {
90
76
  const res = await this.rawFetch(url, opt);
91
77
  if (res.err) {
@@ -215,9 +201,9 @@ class Fetcher {
215
201
  if (method === 'post' && !retryPost)
216
202
  return false;
217
203
  const { statusFamily } = res;
218
- if (statusFamily === '5xx' && !retry5xx)
204
+ if (statusFamily === 5 && !retry5xx)
219
205
  return false;
220
- if (statusFamily === '4xx' && !retry4xx)
206
+ if (statusFamily === 4 && !retry4xx)
221
207
  return false;
222
208
  return true; // default is true
223
209
  }
@@ -226,15 +212,15 @@ class Fetcher {
226
212
  if (!status)
227
213
  return;
228
214
  if (status >= 500)
229
- return '5xx';
215
+ return 5;
230
216
  if (status >= 400)
231
- return '4xx';
217
+ return 4;
232
218
  if (status >= 300)
233
- return '3xx';
219
+ return 3;
234
220
  if (status >= 200)
235
- return '2xx';
221
+ return 2;
236
222
  if (status >= 100)
237
- return '1xx';
223
+ return 1;
238
224
  }
239
225
  /**
240
226
  * Returns url without baseUrl and before ?queryString
@@ -323,6 +309,9 @@ class Fetcher {
323
309
  req.init.body = opt.text;
324
310
  req.init.headers['content-type'] = 'text/plain';
325
311
  }
312
+ else if (opt.body !== undefined) {
313
+ req.init.body = opt.body;
314
+ }
326
315
  return req;
327
316
  }
328
317
  }
@@ -1,2 +1,3 @@
1
1
  export type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head';
2
- export type HttpStatusFamily = '5xx' | '4xx' | '3xx' | '2xx' | '1xx';
2
+ export type HttpStatusFamily = 5 | 4 | 3 | 2 | 1;
3
+ export declare const HTTP_METHODS: HttpMethod[];
@@ -1,2 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HTTP_METHODS = void 0;
4
+ exports.HTTP_METHODS = ['get', 'post', 'put', 'patch', 'delete', 'head'];
@@ -7,6 +7,7 @@ import { _filterNullishValues, _filterUndefinedValues, _mapKeys, _merge, _omit,
7
7
  import { pDelay } from '../promise/pDelay';
8
8
  import { _jsonParseIfPossible } from '../string/json.util';
9
9
  import { _since } from '../time/time.util';
10
+ import { HTTP_METHODS } from './http.model';
10
11
  const defRetryOptions = {
11
12
  count: 2,
12
13
  timeout: 500,
@@ -22,6 +23,19 @@ const defRetryOptions = {
22
23
  export class Fetcher {
23
24
  constructor(cfg = {}) {
24
25
  this.cfg = this.normalizeCfg(cfg);
26
+ // Dynamically create all helper methods
27
+ HTTP_METHODS.forEach(method => {
28
+ // mode=void
29
+ this[method] = async (url, opt) => {
30
+ return await this.fetch(url, Object.assign(Object.assign({}, opt), { method }));
31
+ };
32
+ this[`${method}Text`] = async (url, opt) => {
33
+ return await this.fetch(url, Object.assign(Object.assign({}, opt), { method, mode: 'text' }));
34
+ };
35
+ this[`${method}Json`] = async (url, opt) => {
36
+ return await this.fetch(url, Object.assign(Object.assign({}, opt), { method, mode: 'json' }));
37
+ };
38
+ });
25
39
  }
26
40
  /**
27
41
  * Add BeforeRequest hook at the end of the hooks list.
@@ -47,24 +61,7 @@ export class Fetcher {
47
61
  static create(cfg = {}) {
48
62
  return new Fetcher(cfg);
49
63
  }
50
- async getJson(url, opt) {
51
- return await this.fetch(url, Object.assign(Object.assign({}, opt), { mode: 'json' }));
52
- }
53
- async postJson(url, opt) {
54
- return await this.fetch(url, Object.assign(Object.assign({}, opt), { method: 'post', mode: 'json' }));
55
- }
56
- async putJson(url, opt) {
57
- return await this.fetch(url, Object.assign(Object.assign({}, opt), { method: 'put', mode: 'json' }));
58
- }
59
- async patchJson(url, opt) {
60
- return await this.fetch(url, Object.assign(Object.assign({}, opt), { method: 'patch', mode: 'json' }));
61
- }
62
- async deleteJson(url, opt) {
63
- return await this.fetch(url, Object.assign(Object.assign({}, opt), { method: 'delete', mode: 'json' }));
64
- }
65
- async getText(url, opt) {
66
- return await this.fetch(url, Object.assign(Object.assign({}, opt), { mode: 'text' }));
67
- }
64
+ // headJson!: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>
68
65
  async fetch(url, opt) {
69
66
  const res = await this.rawFetch(url, opt);
70
67
  if (res.err) {
@@ -242,9 +239,9 @@ export class Fetcher {
242
239
  if (method === 'post' && !retryPost)
243
240
  return false;
244
241
  const { statusFamily } = res;
245
- if (statusFamily === '5xx' && !retry5xx)
242
+ if (statusFamily === 5 && !retry5xx)
246
243
  return false;
247
- if (statusFamily === '4xx' && !retry4xx)
244
+ if (statusFamily === 4 && !retry4xx)
248
245
  return false;
249
246
  return true; // default is true
250
247
  }
@@ -254,15 +251,15 @@ export class Fetcher {
254
251
  if (!status)
255
252
  return;
256
253
  if (status >= 500)
257
- return '5xx';
254
+ return 5;
258
255
  if (status >= 400)
259
- return '4xx';
256
+ return 4;
260
257
  if (status >= 300)
261
- return '3xx';
258
+ return 3;
262
259
  if (status >= 200)
263
- return '2xx';
260
+ return 2;
264
261
  if (status >= 100)
265
- return '1xx';
262
+ return 1;
266
263
  }
267
264
  /**
268
265
  * Returns url without baseUrl and before ?queryString
@@ -341,6 +338,9 @@ export class Fetcher {
341
338
  req.init.body = opt.text;
342
339
  req.init.headers['content-type'] = 'text/plain';
343
340
  }
341
+ else if (opt.body !== undefined) {
342
+ req.init.body = opt.body;
343
+ }
344
344
  return req;
345
345
  }
346
346
  }
@@ -1 +1 @@
1
- export {};
1
+ export const HTTP_METHODS = ['get', 'post', 'put', 'patch', 'delete', 'head'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
- "version": "14.120.0",
3
+ "version": "14.122.0",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
6
  "build-prod": "build-prod-esm-cjs",
@@ -15,6 +15,7 @@ import { pDelay } from '../promise/pDelay'
15
15
  import { _jsonParseIfPossible } from '../string/json.util'
16
16
  import { _since } from '../time/time.util'
17
17
  import type { Promisable } from '../typeFest'
18
+ import { HTTP_METHODS } from './http.model'
18
19
  import type { HttpMethod, HttpStatusFamily } from './http.model'
19
20
 
20
21
  export interface FetcherNormalizedCfg extends Required<FetcherCfg>, FetcherRequest {
@@ -102,8 +103,15 @@ export interface FetcherOptions {
102
103
  * so both should finish within this single timeout (not each).
103
104
  */
104
105
  timeoutSeconds?: number
106
+
105
107
  json?: any
106
108
  text?: string
109
+ /**
110
+ * Supports all the types that RequestInit.body supports.
111
+ *
112
+ * Useful when you want to e.g pass FormData.
113
+ */
114
+ body?: Blob | BufferSource | FormData | URLSearchParams | string
107
115
 
108
116
  credentials?: RequestCredentials
109
117
 
@@ -179,6 +187,41 @@ const defRetryOptions: FetcherRetryOptions = {
179
187
  export class Fetcher {
180
188
  private constructor(cfg: FetcherCfg & FetcherOptions = {}) {
181
189
  this.cfg = this.normalizeCfg(cfg)
190
+
191
+ // Dynamically create all helper methods
192
+ HTTP_METHODS.forEach(method => {
193
+ // mode=void
194
+ this[method] = async (url: string, opt?: FetcherOptions): Promise<void> => {
195
+ return await this.fetch<void>(url, {
196
+ ...opt,
197
+ method,
198
+ })
199
+ }
200
+
201
+ // mode=text
202
+ ;(this as any)[`${method}Text`] = async (
203
+ url: string,
204
+ opt?: FetcherOptions,
205
+ ): Promise<string> => {
206
+ return await this.fetch<string>(url, {
207
+ ...opt,
208
+ method,
209
+ mode: 'text',
210
+ })
211
+ }
212
+
213
+ // mode=json
214
+ ;(this as any)[`${method}Json`] = async <T = unknown>(
215
+ url: string,
216
+ opt?: FetcherOptions,
217
+ ): Promise<T> => {
218
+ return await this.fetch<T>(url, {
219
+ ...opt,
220
+ method,
221
+ mode: 'json',
222
+ })
223
+ }
224
+ })
182
225
  }
183
226
 
184
227
  /**
@@ -205,47 +248,26 @@ export class Fetcher {
205
248
  return new Fetcher(cfg)
206
249
  }
207
250
 
208
- async getJson<T = unknown>(url: string, opt?: FetcherOptions): Promise<T> {
209
- return await this.fetch<T>(url, {
210
- ...opt,
211
- mode: 'json',
212
- })
213
- }
214
- async postJson<T = unknown>(url: string, opt?: FetcherOptions): Promise<T> {
215
- return await this.fetch<T>(url, {
216
- ...opt,
217
- method: 'post',
218
- mode: 'json',
219
- })
220
- }
221
- async putJson<T = unknown>(url: string, opt?: FetcherOptions): Promise<T> {
222
- return await this.fetch<T>(url, {
223
- ...opt,
224
- method: 'put',
225
- mode: 'json',
226
- })
227
- }
228
- async patchJson<T = unknown>(url: string, opt?: FetcherOptions): Promise<T> {
229
- return await this.fetch<T>(url, {
230
- ...opt,
231
- method: 'patch',
232
- mode: 'json',
233
- })
234
- }
235
- async deleteJson<T = unknown>(url: string, opt?: FetcherOptions): Promise<T> {
236
- return await this.fetch<T>(url, {
237
- ...opt,
238
- method: 'delete',
239
- mode: 'json',
240
- })
241
- }
242
-
243
- async getText(url: string, opt?: FetcherOptions): Promise<string> {
244
- return await this.fetch<string>(url, {
245
- ...opt,
246
- mode: 'text',
247
- })
248
- }
251
+ // These methods are generated dynamically in the constructor
252
+ get!: (url: string, opt?: FetcherOptions) => Promise<void>
253
+ post!: (url: string, opt?: FetcherOptions) => Promise<void>
254
+ put!: (url: string, opt?: FetcherOptions) => Promise<void>
255
+ patch!: (url: string, opt?: FetcherOptions) => Promise<void>
256
+ delete!: (url: string, opt?: FetcherOptions) => Promise<void>
257
+ head!: (url: string, opt?: FetcherOptions) => Promise<void>
258
+
259
+ getText!: (url: string, opt?: FetcherOptions) => Promise<string>
260
+ postText!: (url: string, opt?: FetcherOptions) => Promise<string>
261
+ putText!: (url: string, opt?: FetcherOptions) => Promise<string>
262
+ patchText!: (url: string, opt?: FetcherOptions) => Promise<string>
263
+ deleteText!: (url: string, opt?: FetcherOptions) => Promise<string>
264
+
265
+ getJson!: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>
266
+ postJson!: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>
267
+ putJson!: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>
268
+ patchJson!: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>
269
+ deleteJson!: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>
270
+ // headJson!: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>
249
271
 
250
272
  async fetch<T = unknown>(url: string, opt?: FetcherOptions): Promise<T> {
251
273
  const res = await this.rawFetch<T>(url, opt)
@@ -415,19 +437,19 @@ export class Fetcher {
415
437
  const { method } = res.req.init
416
438
  if (method === 'post' && !retryPost) return false
417
439
  const { statusFamily } = res
418
- if (statusFamily === '5xx' && !retry5xx) return false
419
- if (statusFamily === '4xx' && !retry4xx) return false
440
+ if (statusFamily === 5 && !retry5xx) return false
441
+ if (statusFamily === 4 && !retry4xx) return false
420
442
  return true // default is true
421
443
  }
422
444
 
423
445
  private getStatusFamily(res: FetcherResponse): HttpStatusFamily | undefined {
424
446
  const status = res.fetchResponse?.status
425
447
  if (!status) return
426
- if (status >= 500) return '5xx'
427
- if (status >= 400) return '4xx'
428
- if (status >= 300) return '3xx'
429
- if (status >= 200) return '2xx'
430
- if (status >= 100) return '1xx'
448
+ if (status >= 500) return 5
449
+ if (status >= 400) return 4
450
+ if (status >= 300) return 3
451
+ if (status >= 200) return 2
452
+ if (status >= 100) return 1
431
453
  }
432
454
 
433
455
  /**
@@ -531,6 +553,8 @@ export class Fetcher {
531
553
  } else if (opt.text !== undefined) {
532
554
  req.init.body = opt.text
533
555
  req.init.headers['content-type'] = 'text/plain'
556
+ } else if (opt.body !== undefined) {
557
+ req.init.body = opt.body
534
558
  }
535
559
 
536
560
  return req
@@ -1,3 +1,5 @@
1
1
  export type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head'
2
2
 
3
- export type HttpStatusFamily = '5xx' | '4xx' | '3xx' | '2xx' | '1xx'
3
+ export type HttpStatusFamily = 5 | 4 | 3 | 2 | 1
4
+
5
+ export const HTTP_METHODS: HttpMethod[] = ['get', 'post', 'put', 'patch', 'delete', 'head']