@e22m4u/js-trie-router 0.2.0 → 0.3.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.
Files changed (69) hide show
  1. package/README.md +3 -3
  2. package/dist/cjs/index.cjs +225 -213
  3. package/examples/{cookie-parsing-example.js → cookies-parsing-example.js} +8 -8
  4. package/examples/params-parsing-example.js +11 -7
  5. package/examples/query-parsing-example.js +11 -7
  6. package/examples/uptime-example.js +4 -4
  7. package/package.json +9 -8
  8. package/src/debuggable-service.d.ts +2 -10
  9. package/src/debuggable-service.js +16 -17
  10. package/src/hooks/hook-invoker.js +3 -4
  11. package/src/hooks/hook-invoker.spec.js +3 -3
  12. package/src/hooks/hook-registry.d.ts +1 -1
  13. package/src/hooks/hook-registry.js +6 -7
  14. package/src/hooks/hook-registry.spec.js +14 -5
  15. package/src/parsers/body-parser.js +10 -11
  16. package/src/parsers/body-parser.spec.js +4 -4
  17. package/src/parsers/cookies-parser.d.ts +15 -0
  18. package/src/parsers/cookies-parser.js +33 -0
  19. package/src/parsers/{cookie-parser.spec.js → cookies-parser.spec.js} +6 -6
  20. package/src/parsers/index.d.ts +1 -1
  21. package/src/parsers/index.js +1 -1
  22. package/src/parsers/query-parser.js +4 -3
  23. package/src/parsers/request-parser.d.ts +2 -2
  24. package/src/parsers/request-parser.js +7 -7
  25. package/src/parsers/request-parser.spec.js +12 -12
  26. package/src/request-context.d.ts +3 -3
  27. package/src/request-context.js +5 -5
  28. package/src/request-context.spec.js +3 -3
  29. package/src/route-registry.js +14 -14
  30. package/src/route-registry.spec.js +4 -1
  31. package/src/route.d.ts +12 -7
  32. package/src/route.js +16 -14
  33. package/src/route.spec.js +13 -7
  34. package/src/router-options.js +1 -1
  35. package/src/router-options.spec.js +1 -1
  36. package/src/senders/data-sender.js +6 -5
  37. package/src/senders/error-sender.js +11 -4
  38. package/src/trie-router.js +46 -38
  39. package/src/trie-router.spec.js +54 -3
  40. package/src/utils/create-cookies-string.d.ts +6 -0
  41. package/src/utils/{create-cookie-string.js → create-cookies-string.js} +4 -4
  42. package/src/utils/{create-cookie-string.spec.js → create-cookies-string.spec.js} +7 -7
  43. package/src/utils/create-debugger.js +1 -1
  44. package/src/utils/create-debugger.spec.js +1 -1
  45. package/src/utils/create-error.js +2 -2
  46. package/src/utils/create-error.spec.js +2 -2
  47. package/src/utils/create-request-mock.d.ts +1 -1
  48. package/src/utils/create-request-mock.js +47 -43
  49. package/src/utils/create-request-mock.spec.js +18 -18
  50. package/src/utils/fetch-request-body.d.ts +11 -2
  51. package/src/utils/fetch-request-body.js +10 -17
  52. package/src/utils/fetch-request-body.spec.js +8 -9
  53. package/src/utils/get-request-pathname.js +1 -1
  54. package/src/utils/get-request-pathname.spec.js +1 -1
  55. package/src/utils/index.d.ts +2 -2
  56. package/src/utils/index.js +2 -2
  57. package/src/utils/is-readable-stream.js +1 -2
  58. package/src/utils/is-response-sent.js +1 -1
  59. package/src/utils/is-response-sent.spec.js +1 -1
  60. package/src/utils/parse-content-type.js +1 -1
  61. package/src/utils/parse-cookies.d.ts +19 -0
  62. package/src/utils/{parse-cookie.js → parse-cookies.js} +8 -5
  63. package/src/utils/{parse-cookie.spec.js → parse-cookies.spec.js} +13 -8
  64. package/src/utils/to-camel-case.js +1 -1
  65. package/src/utils/to-camel-case.spec.js +1 -1
  66. package/src/parsers/cookie-parser.d.ts +0 -15
  67. package/src/parsers/cookie-parser.js +0 -32
  68. package/src/utils/create-cookie-string.d.ts +0 -6
  69. package/src/utils/parse-cookie.d.ts +0 -19
@@ -1,5 +1,5 @@
1
1
  import {HookType} from './hooks/index.js';
2
- import {isPromise} from './utils/index.js';
2
+ import {isPromise, isResponseSent} from './utils/index.js';
3
3
  import {HookInvoker} from './hooks/index.js';
4
4
  import {DataSender} from './senders/index.js';
5
5
  import {HookRegistry} from './hooks/index.js';
@@ -31,11 +31,11 @@ export class TrieRouter extends DebuggableService {
31
31
  * ```
32
32
  * const router = new TrieRouter();
33
33
  * router.defineRoute({
34
- * method: HttpMethod.POST, // Request method.
34
+ * method: HttpMethod.POST, // Request method.
35
35
  * path: '/users/:id', // The path template may have parameters.
36
- * preHandler(ctx) { ... }, // The "preHandler" is executed before a route handler.
36
+ * preHandler(ctx) { ... }, // The "preHandler" executes before a route handler.
37
37
  * handler(ctx) { ... }, // Request handler function.
38
- * postHandler(ctx, data) { ... }, // The "postHandler" is executed after a route handler.
38
+ * postHandler(ctx, data) { ... }, // The "postHandler" executes after a route handler.
39
39
  * });
40
40
  * ```
41
41
  *
@@ -75,11 +75,16 @@ export class TrieRouter extends DebuggableService {
75
75
  * @private
76
76
  */
77
77
  async _handleRequest(req, res) {
78
+ const debug = this.getDebuggerFor(this._handleRequest);
78
79
  const requestPath = (req.url || '/').replace(/\?.*$/, '');
79
- this.debug('Preparing to handle %s %v.', req.method, requestPath);
80
+ debug(
81
+ 'Preparing to handle an incoming request %s %v.',
82
+ req.method,
83
+ requestPath,
84
+ );
80
85
  const resolved = this.getService(RouteRegistry).matchRouteByRequest(req);
81
86
  if (!resolved) {
82
- this.debug('No route for the request %s %v.', req.method, requestPath);
87
+ debug('No route for the request %s %v.', req.method, requestPath);
83
88
  this.getService(ErrorSender).send404(req, res);
84
89
  } else {
85
90
  const {route, params} = resolved;
@@ -95,27 +100,28 @@ export class TrieRouter extends DebuggableService {
95
100
  // так как они были определены в момент
96
101
  // поиска подходящего роута
97
102
  context.params = params;
98
- // разбор тела, заголовков и других данных
99
- // запроса выполняется отдельным сервисом,
100
- // после чего результат записывается
101
- // в контекст передаваемый обработчику
102
- const reqDataOrPromise = this.getService(RequestParser).parse(req);
103
- // результат разбора может являться асинхронным,
104
- // и вместо того, что бы разрывать поток выполнения,
105
- // стоит проверить, действительно ли необходимо
106
- // использование оператора "await"
107
- if (isPromise(reqDataOrPromise)) {
108
- const reqData = await reqDataOrPromise;
109
- Object.assign(context, reqData);
110
- } else {
111
- Object.assign(context, reqDataOrPromise);
112
- }
113
- // получение данных от обработчика, который
114
- // находится в найденном роуте, и отправка
115
- // результата в качестве ответа сервера
116
- let data, error;
117
- const hookInvoker = this.getService(HookInvoker);
103
+ // при разборе входящих данных и выполнении обработчиков
104
+ // запроса, требуется перехватывать возможные ошибки
105
+ // для корректной отправки сервисом ErrorSender
106
+ let data;
118
107
  try {
108
+ // разбор тела, заголовков и других данных запроса
109
+ // выполняется отдельным сервисом, после чего результат
110
+ // записывается в контекст передаваемый обработчику
111
+ const reqDataOrPromise = this.getService(RequestParser).parse(req);
112
+ // результат разбора может являться асинхронным, и вместо
113
+ // того, что бы разрывать поток выполнения, стоит проверить,
114
+ // действительно ли необходимо использование оператора "await"
115
+ if (isPromise(reqDataOrPromise)) {
116
+ const reqData = await reqDataOrPromise;
117
+ Object.assign(context, reqData);
118
+ } else {
119
+ Object.assign(context, reqDataOrPromise);
120
+ }
121
+ // получение данных от обработчика, который находится
122
+ // в найденном маршруте, и отправка результата в качестве
123
+ // ответа сервера
124
+ const hookInvoker = this.getService(HookInvoker);
119
125
  // если результатом вызова хуков "preHandler" является
120
126
  // значение (или Promise) отличное от "undefined" и "null",
121
127
  // то такое значение используется в качестве ответа
@@ -126,15 +132,15 @@ export class TrieRouter extends DebuggableService {
126
132
  context,
127
133
  );
128
134
  if (isPromise(data)) data = await data;
129
- // если ответ не определен хуками "preHandler",
130
- // то вызывается обработчик роута, результат
131
- // которого передается в хуки "postHandler"
132
- if (data == null) {
135
+ // если ответ не бы отправлен внутри "preHandler" хуков,
136
+ // и сами "preHandler" хуки не вернули значения, то вызывается
137
+ // основной обработчик маршрута, результат которого передается
138
+ // в хуки "postHandler"
139
+ if (!isResponseSent(res) && data == null) {
133
140
  data = route.handle(context);
134
141
  if (isPromise(data)) data = await data;
135
- // вызываются хуки "postHandler", результат
136
- // которых также может быть использован
137
- // в качестве ответа
142
+ // вызываются хуки "postHandler", результат которых
143
+ // также может быть использован в качестве ответа
138
144
  let postHandlerData = hookInvoker.invokeAndContinueUntilValueReceived(
139
145
  route,
140
146
  HookType.POST_HANDLER,
@@ -146,12 +152,14 @@ export class TrieRouter extends DebuggableService {
146
152
  postHandlerData = await postHandlerData;
147
153
  if (postHandlerData != null) data = postHandlerData;
148
154
  }
149
- } catch (err) {
150
- error = err;
151
- }
152
- if (error) {
155
+ } catch (error) {
153
156
  this.getService(ErrorSender).send(req, res, error);
154
- } else {
157
+ return;
158
+ }
159
+ // если ответ не был отправлен во время выполнения
160
+ // хуков и основного обработчика запроса,
161
+ // то результат передается в DataSender
162
+ if (!isResponseSent(res)) {
155
163
  this.getService(DataSender).send(res, data);
156
164
  }
157
165
  }
@@ -75,13 +75,13 @@ describe('TrieRouter', function () {
75
75
  router.requestListener(req, res);
76
76
  });
77
77
 
78
- it('passes parsed cookie to the request context', function (done) {
78
+ it('passes parsed cookies to the request context', function (done) {
79
79
  const router = new TrieRouter();
80
80
  router.defineRoute({
81
81
  method: HttpMethod.GET,
82
82
  path: '/',
83
- handler: ({cookie}) => {
84
- expect(cookie).to.be.eql({p1: 'foo', p2: 'bar'});
83
+ handler: ({cookies}) => {
84
+ expect(cookies).to.be.eql({p1: 'foo', p2: 'bar'});
85
85
  done();
86
86
  },
87
87
  });
@@ -472,6 +472,57 @@ describe('TrieRouter', function () {
472
472
  const res = createResponseMock();
473
473
  router.requestListener(req, res);
474
474
  });
475
+
476
+ it('should send parsing error response instead of throwing error', async function () {
477
+ const router = new TrieRouter();
478
+ router.defineRoute({
479
+ method: HttpMethod.POST,
480
+ path: '/',
481
+ handler() {},
482
+ });
483
+ const req = createRequestMock({
484
+ method: HttpMethod.POST,
485
+ headers: {'content-type': 'application/json'},
486
+ body: 'invalid',
487
+ });
488
+ const res = createResponseMock();
489
+ router.requestListener(req, res);
490
+ const body = await res.getBody();
491
+ expect(res.statusCode).to.be.eq(400);
492
+ expect(JSON.parse(body)).to.be.eql({
493
+ error: {
494
+ message: `Unexpected token 'i', "invalid" is not valid JSON`,
495
+ },
496
+ });
497
+ });
498
+
499
+ it('should not invoke the main handler if a preHandler sends the response asynchronously', async function () {
500
+ let handlerCalled = false;
501
+ const router = new TrieRouter();
502
+ router.defineRoute({
503
+ method: 'GET',
504
+ path: '/',
505
+ preHandler(ctx) {
506
+ return new Promise(resolve => {
507
+ setTimeout(() => {
508
+ ctx.res.setHeader('Content-Type', 'text/plain');
509
+ ctx.res.end('Response from preHandler');
510
+ resolve(undefined);
511
+ }, 10);
512
+ });
513
+ },
514
+ handler() {
515
+ handlerCalled = true;
516
+ return 'Response from main handler';
517
+ },
518
+ });
519
+ const req = createRequestMock({method: 'GET', path: '/'});
520
+ const res = createResponseMock();
521
+ await router._handleRequest(req, res);
522
+ const responseBody = await res.getBody();
523
+ expect(responseBody).to.equal('Response from preHandler');
524
+ expect(handlerCalled).to.be.false;
525
+ });
475
526
  });
476
527
 
477
528
  describe('addHook', function () {
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Create cookies string.
3
+ *
4
+ * @param data
5
+ */
6
+ export declare function createCookiesString(data: object): string;
@@ -1,16 +1,16 @@
1
1
  import {Errorf} from '@e22m4u/js-format';
2
2
 
3
3
  /**
4
- * Create cookie string.
4
+ * Create cookies string.
5
5
  *
6
6
  * @param {object} data
7
7
  * @returns {string}
8
8
  */
9
- export function createCookieString(data) {
9
+ export function createCookiesString(data) {
10
10
  if (!data || typeof data !== 'object' || Array.isArray(data))
11
11
  throw new Errorf(
12
- 'The first parameter of "createCookieString" should be ' +
13
- 'an Object, but %v given.',
12
+ 'The first parameter of "createCookiesString" should be ' +
13
+ 'an Object, but %v was given.',
14
14
  data,
15
15
  );
16
16
  let cookies = '';
@@ -1,14 +1,14 @@
1
1
  import {expect} from '../chai.js';
2
2
  import {format} from '@e22m4u/js-format';
3
- import {createCookieString} from './create-cookie-string.js';
3
+ import {createCookiesString} from './create-cookies-string.js';
4
4
 
5
- describe('createCookieString', function () {
5
+ describe('createCookiesString', function () {
6
6
  it('requires the first argument to be an object', function () {
7
- const throwable = v => () => createCookieString(v);
7
+ const throwable = v => () => createCookiesString(v);
8
8
  const error = v =>
9
9
  format(
10
- 'The first parameter of "createCookieString" should be ' +
11
- 'an Object, but %s given.',
10
+ 'The first parameter of "createCookiesString" should be ' +
11
+ 'an Object, but %s was given.',
12
12
  v,
13
13
  );
14
14
  expect(throwable('str')).to.throw(error('"str"'));
@@ -25,12 +25,12 @@ describe('createCookieString', function () {
25
25
  });
26
26
 
27
27
  it('returns an empty string if no keys', function () {
28
- expect(createCookieString({})).to.be.eq('');
28
+ expect(createCookiesString({})).to.be.eq('');
29
29
  });
30
30
 
31
31
  it('returns a cookies string from a given object', function () {
32
32
  const data = {foo: 'bar', baz: 'quz'};
33
- const result = createCookieString(data);
33
+ const result = createCookiesString(data);
34
34
  expect(result).to.be.eq('foo=bar; baz=quz;');
35
35
  });
36
36
  });
@@ -11,7 +11,7 @@ export function createDebugger(name) {
11
11
  if (typeof name !== 'string')
12
12
  throw new Errorf(
13
13
  'The first argument of "createDebugger" should be ' +
14
- 'a String, but %v given.',
14
+ 'a String, but %v was given.',
15
15
  name,
16
16
  );
17
17
  const debug = DebugFactory(`jsTrieRouter:${name}`);
@@ -8,7 +8,7 @@ describe('createDebugger', function () {
8
8
  const error = v =>
9
9
  format(
10
10
  'The first argument of "createDebugger" should be ' +
11
- 'a String, but %s given.',
11
+ 'a String, but %s was given.',
12
12
  v,
13
13
  );
14
14
  expect(throwable(10)).to.throw(error('10'));
@@ -13,13 +13,13 @@ export function createError(errorCtor, message, ...args) {
13
13
  if (typeof errorCtor !== 'function')
14
14
  throw new Errorf(
15
15
  'The first argument of "createError" should be ' +
16
- 'a constructor, but %v given.',
16
+ 'a constructor, but %v was given.',
17
17
  errorCtor,
18
18
  );
19
19
  if (message != null && typeof message !== 'string')
20
20
  throw new Errorf(
21
21
  'The second argument of "createError" should be ' +
22
- 'a String, but %v given.',
22
+ 'a String, but %v was given.',
23
23
  message,
24
24
  );
25
25
  if (message == null) return new errorCtor();
@@ -8,7 +8,7 @@ describe('createError', function () {
8
8
  const error = v =>
9
9
  format(
10
10
  'The first argument of "createError" should be ' +
11
- 'a constructor, but %s given.',
11
+ 'a constructor, but %s was given.',
12
12
  v,
13
13
  );
14
14
  expect(throwable('str')).to.throw(error('"str"'));
@@ -29,7 +29,7 @@ describe('createError', function () {
29
29
  const error = v =>
30
30
  format(
31
31
  'The second argument of "createError" should be ' +
32
- 'a String, but %s given.',
32
+ 'a String, but %s was given.',
33
33
  v,
34
34
  );
35
35
  expect(throwable(10)).to.throw(error('10'));
@@ -10,7 +10,7 @@ type RequestPatch = {
10
10
  secure?: boolean;
11
11
  path?: string;
12
12
  query?: object;
13
- cookie?: object;
13
+ cookies?: object;
14
14
  headers?: object;
15
15
  body?: string;
16
16
  stream?: Readable;
@@ -4,8 +4,8 @@ import {IncomingMessage} from 'http';
4
4
  import queryString from 'querystring';
5
5
  import {Errorf} from '@e22m4u/js-format';
6
6
  import {isReadableStream} from './is-readable-stream.js';
7
- import {createCookieString} from './create-cookie-string.js';
8
- import {BUFFER_ENCODING_LIST} from './fetch-request-body.js';
7
+ import {createCookiesString} from './create-cookies-string.js';
8
+ import {CHARACTER_ENCODING_LIST} from './fetch-request-body.js';
9
9
 
10
10
  /**
11
11
  * @typedef {{
@@ -14,7 +14,7 @@ import {BUFFER_ENCODING_LIST} from './fetch-request-body.js';
14
14
  * secure?: boolean;
15
15
  * path?: string;
16
16
  * query?: object;
17
- * cookie?: object;
17
+ * cookies?: object;
18
18
  * headers?: object;
19
19
  * body?: string;
20
20
  * stream?: import('stream').Readable;
@@ -32,7 +32,7 @@ export function createRequestMock(patch) {
32
32
  if ((patch != null && typeof patch !== 'object') || Array.isArray(patch)) {
33
33
  throw new Errorf(
34
34
  'The first parameter of "createRequestMock" ' +
35
- 'should be an Object, but %v given.',
35
+ 'should be an Object, but %v was given.',
36
36
  patch,
37
37
  );
38
38
  }
@@ -40,25 +40,25 @@ export function createRequestMock(patch) {
40
40
  if (patch.host != null && typeof patch.host !== 'string')
41
41
  throw new Errorf(
42
42
  'The parameter "host" of "createRequestMock" ' +
43
- 'should be a String, but %v given.',
43
+ 'should be a String, but %v was given.',
44
44
  patch.host,
45
45
  );
46
46
  if (patch.method != null && typeof patch.method !== 'string')
47
47
  throw new Errorf(
48
48
  'The parameter "method" of "createRequestMock" ' +
49
- 'should be a String, but %v given.',
49
+ 'should be a String, but %v was given.',
50
50
  patch.method,
51
51
  );
52
52
  if (patch.secure != null && typeof patch.secure !== 'boolean')
53
53
  throw new Errorf(
54
54
  'The parameter "secure" of "createRequestMock" ' +
55
- 'should be a Boolean, but %v given.',
55
+ 'should be a Boolean, but %v was given.',
56
56
  patch.secure,
57
57
  );
58
58
  if (patch.path != null && typeof patch.path !== 'string')
59
59
  throw new Errorf(
60
60
  'The parameter "path" of "createRequestMock" ' +
61
- 'should be a String, but %v given.',
61
+ 'should be a String, but %v was given.',
62
62
  patch.path,
63
63
  );
64
64
  if (
@@ -69,20 +69,20 @@ export function createRequestMock(patch) {
69
69
  ) {
70
70
  throw new Errorf(
71
71
  'The parameter "query" of "createRequestMock" ' +
72
- 'should be a String or Object, but %v given.',
72
+ 'should be a String or Object, but %v was given.',
73
73
  patch.query,
74
74
  );
75
75
  }
76
76
  if (
77
- (patch.cookie != null &&
78
- typeof patch.cookie !== 'string' &&
79
- typeof patch.cookie !== 'object') ||
80
- Array.isArray(patch.cookie)
77
+ (patch.cookies != null &&
78
+ typeof patch.cookies !== 'string' &&
79
+ typeof patch.cookies !== 'object') ||
80
+ Array.isArray(patch.cookies)
81
81
  ) {
82
82
  throw new Errorf(
83
- 'The parameter "cookie" of "createRequestMock" ' +
84
- 'should be a String or Object, but %v given.',
85
- patch.cookie,
83
+ 'The parameter "cookies" of "createRequestMock" ' +
84
+ 'should be a String or Object, but %v was given.',
85
+ patch.cookies,
86
86
  );
87
87
  }
88
88
  if (
@@ -91,25 +91,28 @@ export function createRequestMock(patch) {
91
91
  ) {
92
92
  throw new Errorf(
93
93
  'The parameter "headers" of "createRequestMock" ' +
94
- 'should be an Object, but %v given.',
94
+ 'should be an Object, but %v was given.',
95
95
  patch.headers,
96
96
  );
97
97
  }
98
98
  if (patch.stream != null && !isReadableStream(patch.stream))
99
99
  throw new Errorf(
100
100
  'The parameter "stream" of "createRequestMock" ' +
101
- 'should be a Stream, but %v given.',
101
+ 'should be a Stream, but %v was given.',
102
102
  patch.stream,
103
103
  );
104
104
  if (patch.encoding != null) {
105
105
  if (typeof patch.encoding !== 'string')
106
106
  throw new Errorf(
107
107
  'The parameter "encoding" of "createRequestMock" ' +
108
- 'should be a String, but %v given.',
108
+ 'should be a String, but %v was given.',
109
+ patch.encoding,
110
+ );
111
+ if (!CHARACTER_ENCODING_LIST.includes(patch.encoding))
112
+ throw new Errorf(
113
+ 'Character encoding %v is not supported.',
109
114
  patch.encoding,
110
115
  );
111
- if (!BUFFER_ENCODING_LIST.includes(patch.encoding))
112
- throw new Errorf('Buffer encoding %v is not supported.', patch.encoding);
113
116
  }
114
117
  // если передан поток, выполняется
115
118
  // проверка на несовместимые опции
@@ -141,7 +144,7 @@ export function createRequestMock(patch) {
141
144
  patch.host,
142
145
  patch.secure,
143
146
  patch.body,
144
- patch.cookie,
147
+ patch.cookies,
145
148
  patch.encoding,
146
149
  patch.headers,
147
150
  );
@@ -161,7 +164,7 @@ function createRequestStream(secure, body, encoding) {
161
164
  if (encoding != null && typeof encoding !== 'string')
162
165
  throw new Errorf(
163
166
  'The parameter "encoding" of "createRequestStream" ' +
164
- 'should be a String, but %v given.',
167
+ 'should be a String, but %v was given.',
165
168
  encoding,
166
169
  );
167
170
  encoding = encoding || 'utf-8';
@@ -198,7 +201,7 @@ function createRequestUrl(path, query) {
198
201
  if (typeof path !== 'string')
199
202
  throw new Errorf(
200
203
  'The parameter "path" of "createRequestUrl" ' +
201
- 'should be a String, but %v given.',
204
+ 'should be a String, but %v was given.',
202
205
  path,
203
206
  );
204
207
  if (
@@ -207,7 +210,7 @@ function createRequestUrl(path, query) {
207
210
  ) {
208
211
  throw new Errorf(
209
212
  'The parameter "query" of "createRequestUrl" ' +
210
- 'should be a String or Object, but %v given.',
213
+ 'should be a String or Object, but %v was given.',
211
214
  query,
212
215
  );
213
216
  }
@@ -227,36 +230,36 @@ function createRequestUrl(path, query) {
227
230
  * @param {string|null|undefined} host
228
231
  * @param {boolean|null|undefined} secure
229
232
  * @param {*} body
230
- * @param {string|object|null|undefined} cookie
233
+ * @param {string|object|null|undefined} cookies
231
234
  * @param {import('buffer').BufferEncoding|null|undefined} encoding
232
235
  * @param {object|null|undefined} headers
233
236
  * @returns {object}
234
237
  */
235
- function createRequestHeaders(host, secure, body, cookie, encoding, headers) {
238
+ function createRequestHeaders(host, secure, body, cookies, encoding, headers) {
236
239
  if (host != null && typeof host !== 'string')
237
240
  throw new Errorf(
238
241
  'The parameter "host" of "createRequestHeaders" ' +
239
- 'a non-empty String, but %v given.',
242
+ 'a non-empty String, but %v was given.',
240
243
  host,
241
244
  );
242
245
  host = host || 'localhost';
243
246
  if (secure != null && typeof secure !== 'boolean')
244
247
  throw new Errorf(
245
248
  'The parameter "secure" of "createRequestHeaders" ' +
246
- 'should be a String, but %v given.',
249
+ 'should be a String, but %v was given.',
247
250
  secure,
248
251
  );
249
252
  secure = Boolean(secure);
250
253
  if (
251
- (cookie != null &&
252
- typeof cookie !== 'object' &&
253
- typeof cookie !== 'string') ||
254
- Array.isArray(cookie)
254
+ (cookies != null &&
255
+ typeof cookies !== 'object' &&
256
+ typeof cookies !== 'string') ||
257
+ Array.isArray(cookies)
255
258
  ) {
256
259
  throw new Errorf(
257
- 'The parameter "cookie" of "createRequestHeaders" ' +
258
- 'should be a String or Object, but %v given.',
259
- cookie,
260
+ 'The parameter "cookies" of "createRequestHeaders" ' +
261
+ 'should be a String or Object, but %v was given.',
262
+ cookies,
260
263
  );
261
264
  }
262
265
  if (
@@ -265,7 +268,7 @@ function createRequestHeaders(host, secure, body, cookie, encoding, headers) {
265
268
  ) {
266
269
  throw new Errorf(
267
270
  'The parameter "headers" of "createRequestHeaders" ' +
268
- 'should be an Object, but %v given.',
271
+ 'should be an Object, but %v was given.',
269
272
  headers,
270
273
  );
271
274
  }
@@ -273,7 +276,7 @@ function createRequestHeaders(host, secure, body, cookie, encoding, headers) {
273
276
  if (encoding != null && typeof encoding !== 'string')
274
277
  throw new Errorf(
275
278
  'The parameter "encoding" of "createRequestHeaders" ' +
276
- 'should be a String, but %v given.',
279
+ 'should be a String, but %v was given.',
277
280
  encoding,
278
281
  );
279
282
  encoding = encoding || 'utf-8';
@@ -282,13 +285,14 @@ function createRequestHeaders(host, secure, body, cookie, encoding, headers) {
282
285
  if (secure) obj['x-forwarded-proto'] = 'https';
283
286
  // формирование заголовка Cookie
284
287
  // из строки или объекта
285
- if (cookie != null) {
286
- if (typeof cookie === 'string') {
288
+ if (cookies != null) {
289
+ if (typeof cookies === 'string') {
287
290
  obj['cookie'] = obj['cookie'] ? obj['cookie'] : '';
288
- obj['cookie'] += cookie;
289
- } else if (typeof cookie === 'object') {
291
+ obj['cookie'] += obj['cookie'] ? `; ${cookies}` : cookies;
292
+ } else if (typeof cookies === 'object') {
290
293
  obj['cookie'] = obj['cookie'] ? obj['cookie'] : '';
291
- obj['cookie'] += createCookieString(cookie);
294
+ const newCookies = createCookiesString(cookies);
295
+ obj['cookie'] += obj['cookie'] ? `; ${newCookies}` : newCookies;
292
296
  }
293
297
  }
294
298
  // установка заголовка "content-type"