presidium 1.4.3 → 1.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/HTTP.js CHANGED
@@ -2,6 +2,8 @@ const http = require('http')
2
2
  const https = require('https')
3
3
  const path = require('path')
4
4
  const stream = require('stream')
5
+ const httpConfigure = require('./internal/httpConfigure')
6
+ const parseUrl = require('./internal/parseUrl')
5
7
 
6
8
  /**
7
9
  * @name HTTP
@@ -52,35 +54,15 @@ const stream = require('stream')
52
54
  */
53
55
  class HTTP {
54
56
  constructor(baseUrl, requestOptions = {}) {
55
- if (typeof baseUrl == 'string') {
56
- this.baseUrl = new URL(baseUrl)
57
- }
58
- else if (baseUrl == null) {
59
- throw new TypeError('baseUrl invalid')
60
- }
61
- else if (typeof baseUrl.toString == 'function') {
62
- this.baseUrl = new URL(baseUrl)
63
- }
64
- else if (baseUrl.constructor == URL) {
65
- this.baseUrl = baseUrl
57
+ if (
58
+ typeof baseUrl == 'string'
59
+ || typeof baseUrl?.toString == 'function'
60
+ || baseUrl?.constructor == URL
61
+ ) {
62
+ httpConfigure.call(this, baseUrl, requestOptions)
66
63
  } else {
67
- throw new TypeError('baseUrl invalid')
68
- }
69
-
70
- this.client = this.baseUrl.protocol == 'https:' ? https : http
71
- this.requestOptions = {
72
- hostname: this.baseUrl.hostname,
73
- protocol: this.baseUrl.protocol,
74
- ...requestOptions,
75
- }
76
-
77
- this.requestHeaders = {}
78
-
79
- if (this.baseUrl.username && this.baseUrl.password) {
80
- const { username, password } = this.baseUrl
81
- const credentials = `${username}:${password}`
82
- const encodedCredentials = Buffer.from(credentials).toString('base64')
83
- this.requestHeaders['Authorization'] = `Basic ${encodedCredentials}`
64
+ this.client = undefined
65
+ this.requestOptions = {}
84
66
  }
85
67
 
86
68
  this._sockets = new Set()
@@ -89,7 +71,8 @@ class HTTP {
89
71
  request(options) {
90
72
  const { body, ...requestOptions } = options
91
73
  return new Promise((resolve, reject) => {
92
- const request = this.client.request(requestOptions, response => {
74
+ const client = requestOptions.protocol == 'https:' ? https : http
75
+ const request = client.request(requestOptions, response => {
93
76
  response.status = response.statusCode
94
77
  response.ok = response.statusCode >= 200 && response.statusCode <= 299
95
78
 
@@ -178,6 +161,81 @@ class HTTP {
178
161
  })
179
162
  }
180
163
 
164
+ /**
165
+ * @name _requestMethod
166
+ *
167
+ * @docs
168
+ * ```coffeescript [specscript]
169
+ * module http 'https://nodejs.org/docs/latest-v24.x/api/http.html'
170
+ *
171
+ * type RequestOptions = {
172
+ * agent: http.Agent,
173
+ * auth: string,
174
+ * createConnection: function,
175
+ * defaultPort: number,
176
+ * family: number,
177
+ * headers: object,
178
+ * hints: number,
179
+ * host: string,
180
+ * hostname: string,
181
+ * insecureHTTPParser: boolean,
182
+ * joinDuplicateHeaders: boolean,
183
+ * localAddress: string,
184
+ * localPort: number,
185
+ * lookup: function,
186
+ * maxHeaderSize: number,
187
+ * method: string,
188
+ * path: string,
189
+ * port: number,
190
+ * protocol: string,
191
+ * setDefaultHeaders: boolean,
192
+ * setHost: boolean,
193
+ * signal: AbortSignal,
194
+ * socketPath: string,
195
+ * timeout: number,
196
+ * uniqueHeaders: Array<string>,
197
+ * }
198
+ *
199
+ * _requestMethod(
200
+ * method string,
201
+ * relativeUrl string,
202
+ * options RequestOptions
203
+ * ) -> response http.ServerResponse
204
+ * ```
205
+ */
206
+ _requestMethod(method, relativeUrl, options = {}) {
207
+ if (relativeUrl.startsWith('http')) {
208
+ const url_ = new URL(relativeUrl)
209
+ const requestOptions = {
210
+ hostname: url_.hostname,
211
+ protocol: url_.protocol,
212
+ port: url_.port,
213
+ path: url_.pathname,
214
+ method,
215
+ headers: {
216
+ ...options.headers,
217
+ },
218
+ body: options.body,
219
+ }
220
+ return this.request(requestOptions)
221
+ }
222
+
223
+ const requestOptions = {
224
+ ...this.requestOptions,
225
+ hostname: this.baseUrl.hostname,
226
+ protocol: this.baseUrl.protocol,
227
+ port: this.baseUrl.port,
228
+ path: path.join(this.baseUrl.pathname, relativeUrl),
229
+ method,
230
+ headers: {
231
+ ...this.requestHeaders,
232
+ ...options.headers
233
+ },
234
+ body: options.body,
235
+ }
236
+ return this.request(requestOptions)
237
+ }
238
+
181
239
  /**
182
240
  * @name get
183
241
  *
@@ -232,20 +290,7 @@ class HTTP {
232
290
  * ```
233
291
  */
234
292
  get(relativeUrl, options = {}) {
235
- const requestOptions = {
236
- ...this.requestOptions,
237
- hostname: this.baseUrl.hostname,
238
- protocol: this.baseUrl.protocol,
239
- port: this.baseUrl.port,
240
- path: path.join(this.baseUrl.pathname, relativeUrl),
241
- method: 'GET',
242
- headers: {
243
- ...this.requestHeaders,
244
- ...options.headers
245
- },
246
- body: options.body,
247
- }
248
- return this.request(requestOptions)
293
+ return this._requestMethod('GET', relativeUrl, options)
249
294
  }
250
295
 
251
296
  /**
@@ -301,8 +346,8 @@ class HTTP {
301
346
  * const response = await http.GET('/todos/1')
302
347
  * ```
303
348
  */
304
- GET(...args) {
305
- return this.get(...args)
349
+ GET(relativeUrl, options = {}) {
350
+ return this._requestMethod('GET', relativeUrl, options)
306
351
  }
307
352
 
308
353
  /**
@@ -359,20 +404,7 @@ class HTTP {
359
404
  * ```
360
405
  */
361
406
  head(relativeUrl, options = {}) {
362
- const requestOptions = {
363
- ...this.requestOptions,
364
- hostname: this.baseUrl.hostname,
365
- protocol: this.baseUrl.protocol,
366
- port: this.baseUrl.port,
367
- path: path.join(this.baseUrl.pathname, relativeUrl),
368
- method: 'HEAD',
369
- headers: {
370
- ...this.requestHeaders,
371
- ...options.headers
372
- },
373
- body: options.body,
374
- }
375
- return this.request(requestOptions)
407
+ return this._requestMethod('HEAD', relativeUrl, options)
376
408
  }
377
409
 
378
410
  /**
@@ -428,8 +460,8 @@ class HTTP {
428
460
  * const response = await http.HEAD('/todos/1')
429
461
  * ```
430
462
  */
431
- HEAD(...args) {
432
- return this.head(...args)
463
+ HEAD(relativeUrl, options = {}) {
464
+ return this._requestMethod('HEAD', relativeUrl, options)
433
465
  }
434
466
 
435
467
  /**
@@ -486,20 +518,7 @@ class HTTP {
486
518
  * ```
487
519
  */
488
520
  post(relativeUrl, options = {}) {
489
- const requestOptions = {
490
- ...this.requestOptions,
491
- hostname: this.baseUrl.hostname,
492
- protocol: this.baseUrl.protocol,
493
- port: this.baseUrl.port,
494
- path: path.join(this.baseUrl.pathname, relativeUrl),
495
- method: 'POST',
496
- headers: {
497
- ...this.requestHeaders,
498
- ...options.headers
499
- },
500
- body: options.body,
501
- }
502
- return this.request(requestOptions)
521
+ return this._requestMethod('POST', relativeUrl, options)
503
522
  }
504
523
 
505
524
  /**
@@ -555,8 +574,8 @@ class HTTP {
555
574
  * const response = await http.POST('/todos/1')
556
575
  * ```
557
576
  */
558
- POST(...args) {
559
- return this.post(...args)
577
+ POST(relativeUrl, options = {}) {
578
+ return this._requestMethod('POST', relativeUrl, options)
560
579
  }
561
580
 
562
581
  /**
@@ -612,20 +631,7 @@ class HTTP {
612
631
  * ```
613
632
  */
614
633
  put(relativeUrl, options = {}) {
615
- const requestOptions = {
616
- ...this.requestOptions,
617
- hostname: this.baseUrl.hostname,
618
- protocol: this.baseUrl.protocol,
619
- port: this.baseUrl.port,
620
- path: path.join(this.baseUrl.pathname, relativeUrl),
621
- method: 'PUT',
622
- headers: {
623
- ...this.requestHeaders,
624
- ...options.headers
625
- },
626
- body: options.body,
627
- }
628
- return this.request(requestOptions)
634
+ return this._requestMethod('PUT', relativeUrl, options)
629
635
  }
630
636
 
631
637
  /**
@@ -681,8 +687,8 @@ class HTTP {
681
687
  * const response = await http.PUT('/todos/1')
682
688
  * ```
683
689
  */
684
- PUT(...args) {
685
- return this.put(...args)
690
+ PUT(relativeUrl, options = {}) {
691
+ return this._requestMethod('PUT', relativeUrl, options)
686
692
  }
687
693
 
688
694
  /**
@@ -739,20 +745,7 @@ class HTTP {
739
745
  * ```
740
746
  */
741
747
  patch(relativeUrl, options = {}) {
742
- const requestOptions = {
743
- ...this.requestOptions,
744
- hostname: this.baseUrl.hostname,
745
- protocol: this.baseUrl.protocol,
746
- port: this.baseUrl.port,
747
- path: path.join(this.baseUrl.pathname, relativeUrl),
748
- method: 'PATCH',
749
- headers: {
750
- ...this.requestHeaders,
751
- ...options.headers
752
- },
753
- body: options.body,
754
- }
755
- return this.request(requestOptions)
748
+ return this._requestMethod('PATCH', relativeUrl, options)
756
749
  }
757
750
 
758
751
  /**
@@ -808,8 +801,8 @@ class HTTP {
808
801
  * const response = await http.PATCH('/todos/1')
809
802
  * ```
810
803
  */
811
- PATCH(...args) {
812
- return this.patch(...args)
804
+ PATCH(relativeUrl, options = {}) {
805
+ return this._requestMethod('PATCH', relativeUrl, options)
813
806
  }
814
807
 
815
808
  /**
@@ -866,20 +859,7 @@ class HTTP {
866
859
  * ```
867
860
  */
868
861
  delete(relativeUrl, options = {}) {
869
- const requestOptions = {
870
- ...this.requestOptions,
871
- hostname: this.baseUrl.hostname,
872
- protocol: this.baseUrl.protocol,
873
- port: this.baseUrl.port,
874
- path: path.join(this.baseUrl.pathname, relativeUrl),
875
- method: 'DELETE',
876
- headers: {
877
- ...this.requestHeaders,
878
- ...options.headers
879
- },
880
- body: options.body,
881
- }
882
- return this.request(requestOptions)
862
+ return this._requestMethod('DELETE', relativeUrl, options)
883
863
  }
884
864
 
885
865
  /**
@@ -935,8 +915,8 @@ class HTTP {
935
915
  * const response = await http.DELETE('/todos/1')
936
916
  * ```
937
917
  */
938
- DELETE(...args) {
939
- return this.delete(...args)
918
+ DELETE(relativeUrl, options = {}) {
919
+ return this._requestMethod('DELETE', relativeUrl, options)
940
920
  }
941
921
 
942
922
  /**
@@ -1117,20 +1097,7 @@ class HTTP {
1117
1097
  * ```
1118
1098
  */
1119
1099
  options(relativeUrl, options2 = {}) {
1120
- const requestOptions = {
1121
- ...this.requestOptions,
1122
- hostname: this.baseUrl.hostname,
1123
- protocol: this.baseUrl.protocol,
1124
- port: this.baseUrl.port,
1125
- path: path.join(this.baseUrl.pathname, relativeUrl),
1126
- method: 'OPTIONS',
1127
- headers: {
1128
- ...this.requestHeaders,
1129
- ...options2.headers
1130
- },
1131
- body: options2.body,
1132
- }
1133
- return this.request(requestOptions)
1100
+ return this._requestMethod('OPTIONS', relativeUrl, options2)
1134
1101
  }
1135
1102
 
1136
1103
  /**
@@ -1186,8 +1153,8 @@ class HTTP {
1186
1153
  * const response = await http.OPTIONS('/todos/1')
1187
1154
  * ```
1188
1155
  */
1189
- OPTIONS(...args) {
1190
- return this.options(...args)
1156
+ OPTIONS(relativeUrl, options = {}) {
1157
+ return this._requestMethod('OPTIONS', relativeUrl, options)
1191
1158
  }
1192
1159
 
1193
1160
  /**
@@ -1244,20 +1211,7 @@ class HTTP {
1244
1211
  * ```
1245
1212
  */
1246
1213
  trace(relativeUrl, options = {}) {
1247
- const requestOptions = {
1248
- ...this.requestOptions,
1249
- hostname: this.baseUrl.hostname,
1250
- protocol: this.baseUrl.protocol,
1251
- port: this.baseUrl.port,
1252
- path: path.join(this.baseUrl.pathname, relativeUrl),
1253
- method: 'TRACE',
1254
- headers: {
1255
- ...this.requestHeaders,
1256
- ...options.headers
1257
- },
1258
- body: options.body,
1259
- }
1260
- return this.request(requestOptions)
1214
+ return this._requestMethod('TRACE', relativeUrl, options)
1261
1215
  }
1262
1216
 
1263
1217
  /**
@@ -1313,8 +1267,8 @@ class HTTP {
1313
1267
  * const response = await http.TRACE('/todos/1')
1314
1268
  * ```
1315
1269
  */
1316
- TRACE(...args) {
1317
- return this.trace(...args)
1270
+ TRACE(relativeUrl, options = {}) {
1271
+ return this._requestMethod('TRACE', relativeUrl, options)
1318
1272
  }
1319
1273
 
1320
1274
  /**
@@ -1,5 +1,7 @@
1
1
  const Readable = require('../Readable')
2
2
  const AwsError = require('./AwsError')
3
+ const retryableErrorNames = require('./retryableErrorNames')
4
+ const sleep = require('./sleep')
3
5
 
4
6
  /**
5
7
  * @name handleAwsResponse
@@ -0,0 +1,34 @@
1
+ const Test = require('thunk-test')
2
+ const handleAwsResponse = require('./handleAwsResponse')
3
+ const stream = require('stream')
4
+
5
+ const test = new Test('handleAwsResponse', handleAwsResponse)
6
+
7
+ const response1 = stream.Readable.from([JSON.stringify({ A: 1 })])
8
+ response1.ok = true
9
+
10
+ test.case(response1, { A: 1 })
11
+
12
+ const response2 = stream.Readable.from([JSON.stringify({
13
+ __type: 'Forbidden',
14
+ Message: 'A',
15
+ })])
16
+ response2.ok = false
17
+
18
+ test.throws(response2, { name: 'Forbidden', message: 'A' })
19
+
20
+ const response3 = stream.Readable.from([JSON.stringify({
21
+ __type: 'ThrottlingException',
22
+ Message: 'A',
23
+ })])
24
+ response3.ok = false
25
+
26
+ function identity(value) { return value }
27
+
28
+ test.case(response3, identity, 1, 1)
29
+
30
+ if (process.argv[1] == __filename) {
31
+ test()
32
+ }
33
+
34
+ module.exports = test
@@ -0,0 +1,72 @@
1
+ const http = require('http')
2
+ const https = require('https')
3
+
4
+ /**
5
+ * @name httpConfigure
6
+ *
7
+ * @docs
8
+ * ```coffeescript [specscript]
9
+ * type RequestOptions = {
10
+ * agent: http.Agent,
11
+ * auth: string,
12
+ * createConnection: function,
13
+ * defaultPort: number,
14
+ * family: number,
15
+ * headers: object,
16
+ * hints: number,
17
+ * host: string,
18
+ * hostname: string,
19
+ * insecureHTTPParser: boolean,
20
+ * joinDuplicateHeaders: boolean,
21
+ * localAddress: string,
22
+ * localPort: number,
23
+ * lookup: function,
24
+ * maxHeaderSize: number,
25
+ * method: string,
26
+ * path: string,
27
+ * port: number,
28
+ * protocol: string,
29
+ * setDefaultHeaders: boolean,
30
+ * setHost: boolean,
31
+ * signal: AbortSignal,
32
+ * socketPath: string,
33
+ * timeout: number,
34
+ * uniqueHeaders: Array<string>,
35
+ * }
36
+ *
37
+ * httpConfigure(baseUrl string|URL, requestOptions RequestOptions) -> undefined
38
+ * ```
39
+ */
40
+ function httpConfigure(baseUrl, requestOptions) {
41
+ if (typeof baseUrl == 'string') {
42
+ this.baseUrl = new URL(baseUrl)
43
+ }
44
+ else if (typeof baseUrl?.toString == 'function') {
45
+ this.baseUrl = new URL(baseUrl)
46
+ }
47
+ else if (baseUrl?.constructor == URL) {
48
+ this.baseUrl = baseUrl
49
+ }
50
+ else {
51
+ throw new TypeError('Invalid baseUrl')
52
+ }
53
+
54
+ this.client = this.baseUrl.protocol == 'https:' ? https : http
55
+
56
+ this.requestOptions = {
57
+ hostname: this.baseUrl.hostname,
58
+ protocol: this.baseUrl.protocol,
59
+ ...requestOptions,
60
+ }
61
+
62
+ this.requestHeaders = {}
63
+
64
+ if (this.baseUrl.username && this.baseUrl.password) {
65
+ const { username, password } = this.baseUrl
66
+ const credentials = `${username}:${password}`
67
+ const encodedCredentials = Buffer.from(credentials).toString('base64')
68
+ this.requestHeaders['Authorization'] = `Basic ${encodedCredentials}`
69
+ }
70
+ }
71
+
72
+ module.exports = httpConfigure
@@ -0,0 +1,44 @@
1
+ const assert = require('assert')
2
+ const Test = require('thunk-test')
3
+ const httpConfigure = require('./httpConfigure')
4
+
5
+ const test1 = new Test('httpConfigure', httpConfigure)
6
+ test1.case('http://localhost:7357', function baseUrlString() {
7
+ assert.equal(this.baseUrl.constructor, URL)
8
+ })
9
+
10
+ const test2 = new Test('httpConfigure', httpConfigure)
11
+ test2.case({ toString: () => 'http://localhost:7357' }, function baseUrlToString() {
12
+ assert.equal(this.baseUrl.constructor, URL)
13
+ })
14
+
15
+ const test3 = new Test('httpConfigure', httpConfigure)
16
+ test3.throws(undefined, new TypeError('Invalid baseUrl'))
17
+ test3.throws(1, new TypeError('Invalid URL'))
18
+
19
+ const test4 = new Test('httpConfigure', httpConfigure)
20
+ test4.case('http://username:password@localhost:7357', function baseUrlStringWithUsernamePassword() {
21
+ assert.equal(this.baseUrl.constructor, URL)
22
+ assert.equal(this.baseUrl.username, 'username')
23
+ assert.equal(this.baseUrl.password, 'password')
24
+ })
25
+
26
+ const test5 = new Test('httpConfigure', httpConfigure)
27
+ test5.case('https://localhost:7357', function baseUrlString() {
28
+ assert.equal(this.baseUrl.constructor, URL)
29
+ assert.equal(this.baseUrl.protocol, 'https:')
30
+ })
31
+
32
+ const test = Test.all([
33
+ test1,
34
+ test2,
35
+ test3,
36
+ test4,
37
+ test5,
38
+ ])
39
+
40
+ if (process.argv[1] == __filename) {
41
+ test()
42
+ }
43
+
44
+ module.exports = test
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "presidium",
3
- "version": "1.4.3",
3
+ "version": "1.4.5",
4
4
  "description": "A library for creating web services",
5
5
  "author": "Richard Tong",
6
6
  "license": "MIT",