@commercetools/ts-client 1.0.0 → 1.1.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 (25) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/commercetools-ts-client.browser.cjs.js +1167 -1141
  3. package/dist/commercetools-ts-client.browser.esm.js +1163 -1136
  4. package/dist/commercetools-ts-client.cjs.dev.js +1167 -1141
  5. package/dist/commercetools-ts-client.cjs.prod.js +1167 -1141
  6. package/dist/commercetools-ts-client.esm.js +1163 -1136
  7. package/dist/declarations/src/client/builder.d.ts +1 -1
  8. package/dist/declarations/src/client/client.d.ts +1 -1
  9. package/dist/declarations/src/client/index.d.ts +1 -2
  10. package/dist/declarations/src/index.d.ts +1 -10
  11. package/dist/declarations/src/middleware/auth-middleware/anonymous-session-flow.d.ts +1 -1
  12. package/dist/declarations/src/middleware/auth-middleware/auth-request-builder.d.ts +1 -1
  13. package/dist/declarations/src/middleware/auth-middleware/client-credentials-flow.d.ts +1 -1
  14. package/dist/declarations/src/middleware/auth-middleware/existing-token-flow.d.ts +1 -1
  15. package/dist/declarations/src/middleware/auth-middleware/index.d.ts +2 -2
  16. package/dist/declarations/src/middleware/create-correlation-id-middleware.d.ts +1 -1
  17. package/dist/declarations/src/middleware/create-error-middleware.d.ts +1 -1
  18. package/dist/declarations/src/middleware/create-http-middleware.d.ts +1 -1
  19. package/dist/declarations/src/middleware/create-logger-middleware.d.ts +1 -1
  20. package/dist/declarations/src/middleware/index.d.ts +4 -4
  21. package/dist/declarations/src/types/types.d.ts +1 -1
  22. package/dist/declarations/src/utils/executor.d.ts +1 -1
  23. package/dist/declarations/src/utils/index.d.ts +13 -12
  24. package/dist/declarations/src/utils/url.d.ts +2 -0
  25. package/package.json +2 -3
@@ -2,169 +2,125 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var qs = require('querystring');
6
- var crytpo = require('crypto');
7
5
  var fetch$1 = require('node-fetch');
6
+ var crytpo = require('crypto');
8
7
  var _ = require('buffer/');
9
8
  var AbortController = require('abort-controller');
10
9
 
11
10
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
12
11
 
13
- var qs__default = /*#__PURE__*/_interopDefault(qs);
14
- var crytpo__default = /*#__PURE__*/_interopDefault(crytpo);
15
12
  var fetch__default = /*#__PURE__*/_interopDefault(fetch$1);
13
+ var crytpo__default = /*#__PURE__*/_interopDefault(crytpo);
16
14
  var AbortController__default = /*#__PURE__*/_interopDefault(AbortController);
17
15
 
16
+ function _toPrimitive(input, hint) {
17
+ if (typeof input !== "object" || input === null) return input;
18
+ var prim = input[Symbol.toPrimitive];
19
+ if (prim !== undefined) {
20
+ var res = prim.call(input, hint || "default");
21
+ if (typeof res !== "object") return res;
22
+ throw new TypeError("@@toPrimitive must return a primitive value.");
23
+ }
24
+ return (hint === "string" ? String : Number)(input);
25
+ }
26
+
27
+ function _toPropertyKey(arg) {
28
+ var key = _toPrimitive(arg, "string");
29
+ return typeof key === "symbol" ? key : String(key);
30
+ }
31
+
32
+ function _defineProperty(obj, key, value) {
33
+ key = _toPropertyKey(key);
34
+ if (key in obj) {
35
+ Object.defineProperty(obj, key, {
36
+ value: value,
37
+ enumerable: true,
38
+ configurable: true,
39
+ writable: true
40
+ });
41
+ } else {
42
+ obj[key] = value;
43
+ }
44
+ return obj;
45
+ }
46
+
18
47
  const HEADERS_CONTENT_TYPES = ['application/json', 'application/graphql'];
19
48
  const CONCURRENCT_REQUEST = 20;
20
49
  const CTP_API_URL = 'https://api.europe-west1.gcp.commercetools.com';
21
50
  const CTP_AUTH_URL = 'https://auth.europe-west1.gcp.commercetools.com';
22
51
  const DEFAULT_HEADERS = ['content-type', 'access-control-allow-origin', 'access-control-allow-headers', 'access-control-allow-methods', 'access-control-expose-headers', 'access-control-max-ag', 'x-correlation-id', 'server-timing', 'date', 'server', 'transfer-encoding', 'access-control-max-age', 'content-encoding', 'x-envoy-upstream-service-time', 'via', 'alt-svc', 'connection'];
23
52
 
24
- function parse(headers) {
25
- return DEFAULT_HEADERS.reduce((result, key) => {
26
- let val = headers[key] ? headers[key] : typeof headers.get == 'function' ? headers.get(key) : null;
27
- if (val) result[key] = val;
28
- return result;
29
- }, {});
53
+ function DefineError(statusCode, message, meta = {}) {
54
+ // eslint-disable-next-line no-multi-assign
55
+ this.status = this.statusCode = this.code = statusCode;
56
+ this.message = message;
57
+ Object.assign(this, meta);
58
+ this.name = this.constructor.name;
59
+ // eslint-disable-next-line no-proto
60
+ this.constructor.prototype.__proto__ = Error.prototype;
61
+ if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
30
62
  }
31
- function getHeaders(headers) {
32
- if (!headers) return null;
33
-
34
- // node-fetch
35
- if (headers.raw && typeof headers.raw == 'function') return headers.raw();
36
-
37
- // Tmp fix for Firefox until it supports iterables
38
- if (!headers.forEach) return parse(headers);
39
- return headers.forEach((value, name) => value);
63
+ function NetworkError(...args) {
64
+ DefineError.call(this, 0, ...args);
40
65
  }
41
-
42
- function isBuffer(obj) {
43
- return obj != null && obj.constructor != null && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj);
66
+ function HttpError(...args) {
67
+ DefineError.call(this, ...args);
44
68
  }
45
-
46
- function calculateRetryDelay({
47
- retryCount,
48
- retryDelay,
49
- // maxRetries,
50
- backoff,
51
- maxDelay
52
- }) {
53
- if (backoff) {
54
- return retryCount !== 0 // do not increase if it's the first retry
55
- ? Math.min(Math.round((Math.random() + 1) * retryDelay * 2 ** retryCount), maxDelay) : retryDelay;
56
- }
57
- return retryDelay;
69
+ function BadRequest(...args) {
70
+ DefineError.call(this, 400, ...args);
58
71
  }
59
-
60
- // TODO: Polyfill crypto for browsers
61
- function generateID() {
62
- return crytpo__default["default"].randomBytes(32).toString('base64').replace(/[\/\-=+]/gi, '');
72
+ function Unauthorized(...args) {
73
+ DefineError.call(this, 401, ...args);
63
74
  }
64
-
65
- // import { validateUserAgentOptions } from '../utils'
66
-
67
- /*
68
- This is the easiest way, for this use case, to detect if we're running in
69
- Node.js or in a browser environment. In other cases, this won't be even a
70
- problem as Rollup will provide the correct polyfill in the bundle.
71
- The main advantage by doing it this way is that it allows to easily test
72
- the code running in both environments, by overriding `global.window` in
73
- the specific test.
74
- */
75
- const isBrowser = () => window.document && window.document.nodeType === 9;
76
- function getSystemInfo() {
77
- var _process;
78
- if (isBrowser()) return window.navigator.userAgent;
79
- const nodeVersion = ((_process = process) === null || _process === void 0 ? void 0 : _process.version.slice(1)) || 'unknow'; // unknow environment like React Native etc
80
- const platformInfo = `(${process.platform}; ${process.arch})`;
81
-
82
- // return `node.js/${nodeVersion}`
83
- return `node.js/${nodeVersion} ${platformInfo}`;
75
+ function Forbidden(...args) {
76
+ DefineError.call(this, 403, ...args);
84
77
  }
85
- function createUserAgent(options) {
86
- let libraryInfo = null;
87
- let contactInfo = null;
88
-
89
- // validateUserAgentOptions(options)
90
- if (!options) {
91
- throw new Error('Missing required option `name`');
92
- }
93
-
94
- // Main info
95
- const baseInfo = options.version ? `${options.name}/${options.version}` : options.name;
96
-
97
- // Library info
98
- if (options.libraryName && !options.libraryVersion) {
99
- libraryInfo = options.libraryName;
100
- } else if (options.libraryName && options.libraryVersion) {
101
- libraryInfo = `${options.libraryName}/${options.libraryVersion}`;
102
- }
103
-
104
- // Contact info
105
- if (options.contactUrl && !options.contactEmail) {
106
- contactInfo = `(+${options.contactUrl})`;
107
- } else if (!options.contactUrl && options.contactEmail) {
108
- contactInfo = `(+${options.contactEmail})`;
109
- } else if (options.contactUrl && options.contactEmail) {
110
- contactInfo = `(+${options.contactUrl}; +${options.contactEmail})`;
111
- }
112
-
113
- // System info
114
- const systemInfo = getSystemInfo();
115
-
116
- // customName
117
- const customAgent = options.customAgent || '';
118
- return [baseInfo, systemInfo, libraryInfo, contactInfo, customAgent].filter(Boolean).join(' ');
78
+ function NotFound(...args) {
79
+ DefineError.call(this, 404, ...args);
119
80
  }
120
-
121
- function maskAuthData(request) {
122
- const _request = Object.assign({}, request);
123
- if (_request !== null && _request !== void 0 && _request.headers) {
124
- if (_request.headers.Authorization) {
125
- _request.headers['Authorization'] = 'Bearer ********';
126
- }
127
- if (_request.headers.authorization) {
128
- _request.headers['authorization'] = 'Bearer ********';
129
- }
130
- }
131
- return _request;
81
+ function ConcurrentModification(...args) {
82
+ DefineError.call(this, 409, ...args);
132
83
  }
133
-
134
- function calculateExpirationTime(expiresIn) {
135
- return Date.now() +
136
- // Add a gap of 5 minutes before expiration time.
137
- expiresIn * 1000 - 5 * 60 * 1000;
84
+ function InternalServerError(...args) {
85
+ DefineError.call(this, 500, ...args);
138
86
  }
139
-
140
- function buildTokenCacheKey(options) {
141
- var _options$credentials;
142
- if (!(options !== null && options !== void 0 && (_options$credentials = options.credentials) !== null && _options$credentials !== void 0 && _options$credentials.clientId) || !options.projectKey || !options.host) throw new Error('Missing required options.');
143
- return {
144
- clientId: options.credentials.clientId,
145
- host: options.host,
146
- projectKey: options.projectKey
147
- };
87
+ function ServiceUnavailable(...args) {
88
+ DefineError.call(this, 503, ...args);
148
89
  }
149
-
150
- function store(initVal) {
151
- let value = initVal;
152
- return {
153
- get: TokenCacheOption => value,
154
- set: (val, TokenCacheOption) => {
155
- value = val;
156
- }
157
- };
90
+ function getErrorByCode(code) {
91
+ switch (code) {
92
+ case 0:
93
+ return NetworkError;
94
+ case 400:
95
+ return BadRequest;
96
+ case 401:
97
+ return Unauthorized;
98
+ case 403:
99
+ return Forbidden;
100
+ case 404:
101
+ return NotFound;
102
+ case 409:
103
+ return ConcurrentModification;
104
+ case 500:
105
+ return InternalServerError;
106
+ case 503:
107
+ return ServiceUnavailable;
108
+ default:
109
+ return undefined;
110
+ }
158
111
  }
159
112
 
160
- function mergeAuthHeader(token, req) {
161
- return {
162
- ...req,
163
- headers: {
164
- ...req.headers,
165
- Authorization: `Bearer ${token}`
166
- }
167
- };
113
+ function createError({
114
+ statusCode,
115
+ message,
116
+ ...rest
117
+ }) {
118
+ var _rest$originalRequest;
119
+ let errorMessage = message || 'Unexpected non-JSON error response';
120
+ if (statusCode === 404) errorMessage = `URI not found: ${((_rest$originalRequest = rest.originalRequest) === null || _rest$originalRequest === void 0 ? void 0 : _rest$originalRequest.uri) || rest.uri}`;
121
+ const ResponseError = getErrorByCode(statusCode);
122
+ if (ResponseError) return new ResponseError(errorMessage, rest);
123
+ return new HttpError(statusCode, errorMessage, rest);
168
124
  }
169
125
 
170
126
  function predicate(retryCodes, response) {
@@ -281,85 +237,187 @@ async function executor(request) {
281
237
  return data;
282
238
  }
283
239
 
284
- function sleep(ms) {
285
- return new Promise(resolve => {
286
- setTimeout(resolve, ms);
287
- });
240
+ // TODO: Polyfill crypto for browsers
241
+ function generateID() {
242
+ return crytpo__default["default"].randomBytes(32).toString('base64').replace(/[\/\-=+]/gi, '');
288
243
  }
289
244
 
290
- var METHODS = ['ACL', 'BIND', 'CHECKOUT', 'CONNECT', 'COPY', 'DELETE', 'GET', 'HEAD', 'LINK', 'LOCK', 'M-SEARCH', 'MERGE', 'MKACTIVITY', 'MKCALENDAR', 'MKCOL', 'MOVE', 'NOTIFY', 'OPTIONS', 'PATCH', 'POST', 'PROPFIND', 'PROPPATCH', 'PURGE', 'PUT', 'REBIND', 'REPORT', 'SEARCH', 'SOURCE', 'SUBSCRIBE', 'TRACE', 'UNBIND', 'UNLINK', 'UNLOCK', 'UNSUBSCRIBE'];
291
-
292
- function DefineError(statusCode, message, meta = {}) {
293
- // eslint-disable-next-line no-multi-assign
294
- this.status = this.statusCode = this.code = statusCode;
295
- this.message = message;
296
- Object.assign(this, meta);
297
- this.name = this.constructor.name;
298
- // eslint-disable-next-line no-proto
299
- this.constructor.prototype.__proto__ = Error.prototype;
300
- if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
301
- }
302
- function NetworkError(...args) {
303
- DefineError.call(this, 0, ...args);
304
- }
305
- function HttpError(...args) {
306
- DefineError.call(this, ...args);
245
+ function parse(headers) {
246
+ return DEFAULT_HEADERS.reduce((result, key) => {
247
+ let val = headers[key] ? headers[key] : typeof headers.get == 'function' ? headers.get(key) : null;
248
+ if (val) result[key] = val;
249
+ return result;
250
+ }, {});
307
251
  }
308
- function BadRequest(...args) {
309
- DefineError.call(this, 400, ...args);
252
+ function getHeaders(headers) {
253
+ if (!headers) return null;
254
+
255
+ // node-fetch
256
+ if (headers.raw && typeof headers.raw == 'function') return headers.raw();
257
+
258
+ // Tmp fix for Firefox until it supports iterables
259
+ if (!headers.forEach) return parse(headers);
260
+ return headers.forEach((value, name) => value);
310
261
  }
311
- function Unauthorized(...args) {
312
- DefineError.call(this, 401, ...args);
262
+
263
+ function isBuffer(obj) {
264
+ return obj != null && obj.constructor != null && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj);
313
265
  }
314
- function Forbidden(...args) {
315
- DefineError.call(this, 403, ...args);
266
+
267
+ function maskAuthData(request) {
268
+ const _request = Object.assign({}, request);
269
+ if (_request !== null && _request !== void 0 && _request.headers) {
270
+ if (_request.headers.Authorization) {
271
+ _request.headers['Authorization'] = 'Bearer ********';
272
+ }
273
+ if (_request.headers.authorization) {
274
+ _request.headers['authorization'] = 'Bearer ********';
275
+ }
276
+ }
277
+ return _request;
316
278
  }
317
- function NotFound(...args) {
318
- DefineError.call(this, 404, ...args);
279
+
280
+ function mergeAuthHeader(token, req) {
281
+ return {
282
+ ...req,
283
+ headers: {
284
+ ...req.headers,
285
+ Authorization: `Bearer ${token}`
286
+ }
287
+ };
319
288
  }
320
- function ConcurrentModification(...args) {
321
- DefineError.call(this, 409, ...args);
289
+
290
+ var METHODS = ['ACL', 'BIND', 'CHECKOUT', 'CONNECT', 'COPY', 'DELETE', 'GET', 'HEAD', 'LINK', 'LOCK', 'M-SEARCH', 'MERGE', 'MKACTIVITY', 'MKCALENDAR', 'MKCOL', 'MOVE', 'NOTIFY', 'OPTIONS', 'PATCH', 'POST', 'PROPFIND', 'PROPPATCH', 'PURGE', 'PUT', 'REBIND', 'REPORT', 'SEARCH', 'SOURCE', 'SUBSCRIBE', 'TRACE', 'UNBIND', 'UNLINK', 'UNLOCK', 'UNSUBSCRIBE'];
291
+
292
+ function calculateRetryDelay({
293
+ retryCount,
294
+ retryDelay,
295
+ // maxRetries,
296
+ backoff,
297
+ maxDelay
298
+ }) {
299
+ if (backoff) {
300
+ return retryCount !== 0 // do not increase if it's the first retry
301
+ ? Math.min(Math.round((Math.random() + 1) * retryDelay * 2 ** retryCount), maxDelay) : retryDelay;
302
+ }
303
+ return retryDelay;
322
304
  }
323
- function InternalServerError(...args) {
324
- DefineError.call(this, 500, ...args);
305
+
306
+ function sleep(ms) {
307
+ return new Promise(resolve => {
308
+ setTimeout(resolve, ms);
309
+ });
325
310
  }
326
- function ServiceUnavailable(...args) {
327
- DefineError.call(this, 503, ...args);
311
+
312
+ function buildTokenCacheKey(options) {
313
+ var _options$credentials;
314
+ if (!(options !== null && options !== void 0 && (_options$credentials = options.credentials) !== null && _options$credentials !== void 0 && _options$credentials.clientId) || !options.projectKey || !options.host) throw new Error('Missing required options.');
315
+ return {
316
+ clientId: options.credentials.clientId,
317
+ host: options.host,
318
+ projectKey: options.projectKey
319
+ };
328
320
  }
329
- function getErrorByCode(code) {
330
- switch (code) {
331
- case 0:
332
- return NetworkError;
333
- case 400:
334
- return BadRequest;
335
- case 401:
336
- return Unauthorized;
337
- case 403:
338
- return Forbidden;
339
- case 404:
340
- return NotFound;
341
- case 409:
342
- return ConcurrentModification;
343
- case 500:
344
- return InternalServerError;
345
- case 503:
346
- return ServiceUnavailable;
347
- default:
348
- return undefined;
321
+
322
+ function calculateExpirationTime(expiresIn) {
323
+ return Date.now() +
324
+ // Add a gap of 5 minutes before expiration time.
325
+ expiresIn * 1000 - 5 * 60 * 1000;
326
+ }
327
+
328
+ function store(initVal) {
329
+ let value = initVal;
330
+ return {
331
+ get: TokenCacheOption => value,
332
+ set: (val, TokenCacheOption) => {
333
+ value = val;
334
+ }
335
+ };
336
+ }
337
+
338
+ // import { validateUserAgentOptions } from '../utils'
339
+
340
+ /*
341
+ This is the easiest way, for this use case, to detect if we're running in
342
+ Node.js or in a browser environment. In other cases, this won't be even a
343
+ problem as Rollup will provide the correct polyfill in the bundle.
344
+ The main advantage by doing it this way is that it allows to easily test
345
+ the code running in both environments, by overriding `global.window` in
346
+ the specific test.
347
+ */
348
+ const isBrowser = () => window.document && window.document.nodeType === 9;
349
+ function getSystemInfo() {
350
+ var _process;
351
+ if (isBrowser()) return window.navigator.userAgent;
352
+ const nodeVersion = ((_process = process) === null || _process === void 0 ? void 0 : _process.version.slice(1)) || 'unknow'; // unknow environment like React Native etc
353
+ const platformInfo = `(${process.platform}; ${process.arch})`;
354
+
355
+ // return `node.js/${nodeVersion}`
356
+ return `node.js/${nodeVersion} ${platformInfo}`;
357
+ }
358
+ function createUserAgent(options) {
359
+ let libraryInfo = null;
360
+ let contactInfo = null;
361
+
362
+ // validateUserAgentOptions(options)
363
+ if (!options) {
364
+ throw new Error('Missing required option `name`');
365
+ }
366
+
367
+ // Main info
368
+ const baseInfo = options.version ? `${options.name}/${options.version}` : options.name;
369
+
370
+ // Library info
371
+ if (options.libraryName && !options.libraryVersion) {
372
+ libraryInfo = options.libraryName;
373
+ } else if (options.libraryName && options.libraryVersion) {
374
+ libraryInfo = `${options.libraryName}/${options.libraryVersion}`;
375
+ }
376
+
377
+ // Contact info
378
+ if (options.contactUrl && !options.contactEmail) {
379
+ contactInfo = `(+${options.contactUrl})`;
380
+ } else if (!options.contactUrl && options.contactEmail) {
381
+ contactInfo = `(+${options.contactEmail})`;
382
+ } else if (options.contactUrl && options.contactEmail) {
383
+ contactInfo = `(+${options.contactUrl}; +${options.contactEmail})`;
349
384
  }
385
+
386
+ // System info
387
+ const systemInfo = getSystemInfo();
388
+
389
+ // customName
390
+ const customAgent = options.customAgent || '';
391
+ return [baseInfo, systemInfo, libraryInfo, contactInfo, customAgent].filter(Boolean).join(' ');
350
392
  }
351
393
 
352
- function createError({
353
- statusCode,
354
- message,
355
- ...rest
356
- }) {
357
- var _rest$originalRequest;
358
- let errorMessage = message || 'Unexpected non-JSON error response';
359
- if (statusCode === 404) errorMessage = `URI not found: ${((_rest$originalRequest = rest.originalRequest) === null || _rest$originalRequest === void 0 ? void 0 : _rest$originalRequest.uri) || rest.uri}`;
360
- const ResponseError = getErrorByCode(statusCode);
361
- if (ResponseError) return new ResponseError(errorMessage, rest);
362
- return new HttpError(statusCode, errorMessage, rest);
394
+ function urlParser(url) {
395
+ const object = {};
396
+ const data = new URLSearchParams(url);
397
+ for (let x of data.keys()) {
398
+ if (data.getAll(x).length > 1) {
399
+ object[x] = data.getAll(x);
400
+ } else {
401
+ object[x] = data.get(x);
402
+ }
403
+ }
404
+ return object;
405
+ }
406
+ function urlStringifier(object) {
407
+ const params = new URLSearchParams(object);
408
+ for (const [key, value] of Object.entries(object)) {
409
+ if (Array.isArray(value)) {
410
+ params.delete(key);
411
+ value.filter(Boolean).forEach(v => params.append(key, v));
412
+ }
413
+ }
414
+ return params.toString();
415
+ }
416
+ function parseURLString(url, parser = urlParser) {
417
+ return parser(url);
418
+ }
419
+ function stringifyURLString(object, stringifier = urlStringifier) {
420
+ return urlStringifier(object);
363
421
  }
364
422
 
365
423
  /**
@@ -406,1055 +464,1023 @@ function validate(funcName, request, options = {
406
464
  if (!options.allowedMethods.includes(request.method)) throw new Error(`The "${funcName}" Request object requires a valid method. See https://commercetools.github.io/nodejs/sdk/Glossary.html#clientrequest`);
407
465
  }
408
466
 
409
- function compose({
410
- middlewares
411
- }) {
412
- if (middlewares.length === 1) return middlewares[0];
413
- const _middlewares = middlewares.slice();
414
- return _middlewares.reduce((ac, cv) => (...args) => ac(cv.apply(null, args)));
467
+ /**
468
+ *
469
+ * @param {AuthMiddlewareOptions} options
470
+ * @returns { IBuiltRequestParams } *
471
+ */
472
+ function buildRequestForClientCredentialsFlow(options) {
473
+ // Validate options
474
+ if (!options) throw new Error('Missing required options');
475
+ if (!options.host) throw new Error('Missing required option (host)');
476
+ if (!options.projectKey) throw new Error('Missing required option (projectKey)');
477
+ if (!options.credentials) throw new Error('Missing required option (credentials)');
478
+ const {
479
+ clientId,
480
+ clientSecret
481
+ } = options.credentials || {};
482
+ if (!(clientId && clientSecret)) throw new Error('Missing required credentials (clientId, clientSecret)');
483
+ const scope = options.scopes ? options.scopes.join(' ') : undefined;
484
+ const basicAuth = _.Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
485
+ // This is mostly useful for internal testing purposes to be able to check
486
+ // other oauth endpoints.
487
+ const oauthUri = options.oauthUri || '/oauth/token';
488
+ const url = options.host.replace(/\/$/, '') + oauthUri;
489
+ const body = `grant_type=client_credentials${scope ? `&scope=${scope}` : ''}`;
490
+ return {
491
+ url,
492
+ body,
493
+ basicAuth
494
+ };
415
495
  }
416
496
 
417
- // process batch requests
418
- let _options;
419
- function process$1(request, fn, processOpt) {
420
- validate('process', request, {
421
- allowedMethods: ['GET']
422
- });
423
- if (typeof fn !== 'function') throw new Error('The "process" function accepts a "Function" as a second argument that returns a Promise. See https://commercetools.github.io/nodejs/sdk/api/sdkClient.html#processrequest-processfn-options');
424
-
425
- // Set default process options
426
- const opt = {
427
- total: Number.POSITIVE_INFINITY,
428
- accumulate: true,
429
- ...processOpt
497
+ /**
498
+ *
499
+ * @param {AuthMiddlewareOptions} options
500
+ * @returns {IBuiltRequestParams} *
501
+ */
502
+ function buildRequestForAnonymousSessionFlow(options) {
503
+ if (!options) throw new Error('Missing required options');
504
+ if (!options.projectKey) throw new Error('Missing required option (projectKey)');
505
+ const projectKey = options.projectKey;
506
+ options.oauthUri = options.oauthUri || `/oauth/${projectKey}/anonymous/token`;
507
+ const result = buildRequestForClientCredentialsFlow(options);
508
+ if (options.credentials.anonymousId) result.body += `&anonymous_id=${options.credentials.anonymousId}`;
509
+ return {
510
+ ...result
430
511
  };
431
- return new Promise((resolve, reject) => {
432
- let _path,
433
- _queryString = '';
434
- if (request && request.uri) {
435
- const [path, queryString] = request.uri.split('?');
436
- _path = path;
437
- _queryString = queryString;
438
- }
439
- const requestQuery = {
440
- ...qs__default["default"].parse(_queryString)
441
- };
442
- const query = {
443
- // defaults
444
- limit: 20,
445
- // merge given query params
446
- ...requestQuery
447
- };
448
- let itemsToGet = opt.total;
449
- let hasFirstPageBeenProcessed = false;
450
- const processPage = async (lastId, acc = []) => {
451
- // Use the lesser value between limit and itemsToGet in query
452
- const limit = query.limit < itemsToGet ? query.limit : itemsToGet;
453
- const originalQueryString = qs__default["default"].stringify({
454
- ...query,
455
- limit
456
- });
457
- const enhancedQuery = {
458
- sort: 'id asc',
459
- withTotal: false,
460
- ...(lastId ? {
461
- where: `id > "${lastId}"`
462
- } : {})
463
- };
464
- const enhancedQueryString = qs__default["default"].stringify(enhancedQuery);
465
- const enhancedRequest = {
466
- ...request,
467
- uri: `${_path}?${enhancedQueryString}&${originalQueryString}`
468
- };
469
- try {
470
- const payload = await createClient(_options).execute(enhancedRequest);
471
- const {
472
- results,
473
- count: resultsLength
474
- } = (payload === null || payload === void 0 ? void 0 : payload.body) || {};
475
- if (!resultsLength && hasFirstPageBeenProcessed) {
476
- return resolve(acc || []);
477
- }
478
- const result = await Promise.resolve(fn(payload));
479
- let accumulated;
480
- hasFirstPageBeenProcessed = true;
481
- if (opt.accumulate) accumulated = acc.concat(result || []);
482
- itemsToGet -= resultsLength;
483
- // If there are no more items to get, it means the total number
484
- // of items in the original request have been fetched so we
485
- // resolve the promise.
486
- // Also, if we get less results in a page then the limit set it
487
- // means that there are no more pages and that we can finally
488
- // resolve the promise.
489
- if (resultsLength < query.limit || !itemsToGet) {
490
- return resolve(accumulated || []);
491
- }
492
- const last = results[resultsLength - 1];
493
- const newLastId = last && last.id;
494
- processPage(newLastId, accumulated);
495
- } catch (error) {
496
- reject(error);
497
- }
498
- };
499
-
500
- // Start iterating through pages
501
- processPage();
502
- });
503
512
  }
504
- function createClient(middlewares) {
505
- _options = middlewares;
506
- validateClient(middlewares);
507
- const resolver = {
508
- async resolve(rs) {
509
- const {
510
- response,
511
- includeOriginalRequest,
512
- maskSensitiveHeaderData,
513
- ...request
514
- } = rs;
515
- const {
516
- retryCount,
517
- ...rest
518
- } = response;
519
- const res = {
520
- body: null,
521
- error: null,
522
- reject: rs.reject,
523
- resolve: rs.resolve,
524
- ...rest,
525
- ...(includeOriginalRequest ? {
526
- originalRequest: maskSensitiveHeaderData ? maskAuthData(request) : request
527
- } : {}),
528
- ...(response !== null && response !== void 0 && response.retryCount ? {
529
- retryCount: response.retryCount
530
- } : {})
531
- };
532
- if (res.error) {
533
- res.reject(res.error);
534
- return res;
535
- }
536
- res.resolve(res);
537
- return res;
538
- }
539
- };
540
- const dispatch = compose(middlewares)(resolver.resolve);
513
+
514
+ /**
515
+ *
516
+ * @param {RefreshAuthMiddlewareOptions} options
517
+ * @returns {IBuiltRequestParams}
518
+ */
519
+ function buildRequestForRefreshTokenFlow(options) {
520
+ if (!options) throw new Error('Missing required options');
521
+ if (!options.host) throw new Error('Missing required option (host)');
522
+ if (!options.projectKey) throw new Error('Missing required option (projectKey)');
523
+ if (!options.credentials) throw new Error('Missing required option (credentials)');
524
+ if (!options.refreshToken) throw new Error('Missing required option (refreshToken)');
525
+ const {
526
+ clientId,
527
+ clientSecret
528
+ } = options.credentials;
529
+ if (!(clientId && clientSecret)) throw new Error('Missing required credentials (clientId, clientSecret)');
530
+ const basicAuth = _.Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
531
+ // This is mostly useful for internal testing purposes to be able to check
532
+ // other oauth endpoints.
533
+ const oauthUri = options.oauthUri || '/oauth/token';
534
+ const url = options.host.replace(/\/$/, '') + oauthUri;
535
+ const body = `grant_type=refresh_token&refresh_token=${encodeURIComponent(options.refreshToken)}`;
541
536
  return {
542
- process: process$1,
543
- execute(request) {
544
- validate('exec', request);
545
- return new Promise((resolve, reject) => {
546
- return dispatch({
547
- reject,
548
- resolve,
549
- ...request
550
- });
551
- });
552
- }
537
+ basicAuth,
538
+ url,
539
+ body
553
540
  };
554
541
  }
555
542
 
556
- function _toPrimitive(input, hint) {
557
- if (typeof input !== "object" || input === null) return input;
558
- var prim = input[Symbol.toPrimitive];
559
- if (prim !== undefined) {
560
- var res = prim.call(input, hint || "default");
561
- if (typeof res !== "object") return res;
562
- throw new TypeError("@@toPrimitive must return a primitive value.");
563
- }
564
- return (hint === "string" ? String : Number)(input);
565
- }
566
-
567
- function _toPropertyKey(arg) {
568
- var key = _toPrimitive(arg, "string");
569
- return typeof key === "symbol" ? key : String(key);
570
- }
543
+ /**
544
+ * @param {PasswordAuthMiddlewareOptions} options
545
+ * @returns {IBuiltRequestParams}
546
+ */
547
+ function buildRequestForPasswordFlow(options) {
548
+ if (!options) throw new Error('Missing required options');
549
+ if (!options.host) throw new Error('Missing required option (host)');
550
+ if (!options.projectKey) throw new Error('Missing required option (projectKey)');
551
+ if (!options.credentials) throw new Error('Missing required option (credentials)');
552
+ const {
553
+ clientId,
554
+ clientSecret,
555
+ user
556
+ } = options.credentials;
557
+ const projectKey = options.projectKey;
558
+ if (!(clientId && clientSecret && user)) throw new Error('Missing required credentials (clientId, clientSecret, user)');
559
+ const {
560
+ username,
561
+ password
562
+ } = user;
563
+ if (!(username && password)) throw new Error('Missing required user credentials (username, password)');
564
+ const scope = (options.scopes || []).join(' ');
565
+ const scopeStr = scope ? `&scope=${scope}` : '';
566
+ const basicAuth = _.Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
571
567
 
572
- function _defineProperty(obj, key, value) {
573
- key = _toPropertyKey(key);
574
- if (key in obj) {
575
- Object.defineProperty(obj, key, {
576
- value: value,
577
- enumerable: true,
578
- configurable: true,
579
- writable: true
580
- });
581
- } else {
582
- obj[key] = value;
583
- }
584
- return obj;
585
- }
568
+ /**
569
+ * This is mostly useful for internal testing purposes to be able to check
570
+ * other oauth endpoints.
571
+ */
572
+ const oauthUri = options.oauthUri || `/oauth/${projectKey}/customers/token`;
573
+ const url = options.host.replace(/\/$/, '') + oauthUri;
586
574
 
587
- function createCorrelationIdMiddleware$1(options) {
588
- return next => request => {
589
- const nextRequest = {
590
- ...request,
591
- headers: {
592
- ...request.headers,
593
- 'X-Correlation-ID': options.generate && typeof options.generate == 'function' ? options.generate() : generateID()
594
- }
595
- };
596
- return next(nextRequest);
575
+ // encode username and password as requested by the system
576
+ const body = `grant_type=password&username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}${scopeStr}`;
577
+ return {
578
+ basicAuth,
579
+ url,
580
+ body
597
581
  };
598
582
  }
599
583
 
600
- async function executeRequest$1({
601
- url,
602
- httpClient,
603
- clientOptions
604
- }) {
605
- let timer;
584
+ async function executeRequest$1(options) {
606
585
  const {
607
- timeout,
608
586
  request,
609
- abortController,
610
- maskSensitiveHeaderData,
611
- includeRequestInErrorResponse
612
- } = clientOptions;
613
- try {
614
- var _response$data, _response$data2;
615
- if (timeout) timer = setTimeout(() => {
616
- abortController.abort();
617
- }, timeout);
618
- const response = await executor({
619
- url,
620
- ...clientOptions,
621
- httpClient,
622
- method: clientOptions.method,
623
- ...(clientOptions.body ? {
624
- body: clientOptions.body
625
- } : {})
626
- });
627
- if (response.statusCode >= 200 && response.statusCode < 300) {
628
- if (clientOptions.method == 'HEAD') {
629
- return {
630
- body: null,
631
- statusCode: response.statusCode,
632
- retryCount: response.retryCount,
633
- headers: getHeaders(response.headers)
634
- };
635
- }
636
- return {
637
- body: response.data,
638
- statusCode: response.statusCode,
639
- retryCount: response.retryCount,
640
- headers: getHeaders(response.headers)
641
- };
642
- }
643
- const error = createError({
644
- message: (response === null || response === void 0 ? void 0 : (_response$data = response.data) === null || _response$data === void 0 ? void 0 : _response$data.message) || (response === null || response === void 0 ? void 0 : response.message),
645
- statusCode: response.statusCode || (response === null || response === void 0 ? void 0 : (_response$data2 = response.data) === null || _response$data2 === void 0 ? void 0 : _response$data2.statusCode),
646
- headers: getHeaders(response.headers),
647
- method: clientOptions.method,
648
- body: response.data,
649
- retryCount: response.retryCount,
650
- ...(includeRequestInErrorResponse ? {
651
- originalRequest: maskSensitiveHeaderData ? maskAuthData(request) : request
652
- } : {
653
- uri: request.uri
654
- })
655
- });
587
+ httpClient,
588
+ tokenCache,
589
+ tokenCacheKey,
590
+ requestState,
591
+ userOption,
592
+ next
593
+ } = options;
594
+ let url = options.url;
595
+ let body = options.body;
596
+ let basicAuth = options.basicAuth;
656
597
 
657
- /**
658
- * handle non-ok (error) response
659
- * build error body
660
- */
661
- return {
662
- body: response.data,
663
- code: response.statusCode,
664
- statusCode: response.statusCode,
665
- headers: getHeaders(response.headers),
666
- error
667
- };
668
- } catch (e) {
669
- var _e$response, _e$response2, _e$response3, _e$response4, _e$response4$data, _e$response5, _e$response6;
670
- // We know that this is a network error
671
- const headers = getHeaders((_e$response = e.response) === null || _e$response === void 0 ? void 0 : _e$response.headers);
672
- const statusCode = ((_e$response2 = e.response) === null || _e$response2 === void 0 ? void 0 : _e$response2.status) || ((_e$response3 = e.response) === null || _e$response3 === void 0 ? void 0 : _e$response3.data0) || 0;
673
- const message = (_e$response4 = e.response) === null || _e$response4 === void 0 ? void 0 : (_e$response4$data = _e$response4.data) === null || _e$response4$data === void 0 ? void 0 : _e$response4$data.message;
674
- const error = createError({
675
- statusCode,
676
- code: statusCode,
677
- status: statusCode,
678
- message: message || e.message,
679
- headers,
680
- body: ((_e$response5 = e.response) === null || _e$response5 === void 0 ? void 0 : _e$response5.data) || e,
681
- error: (_e$response6 = e.response) === null || _e$response6 === void 0 ? void 0 : _e$response6.data,
682
- ...(includeRequestInErrorResponse ? {
683
- originalRequest: maskSensitiveHeaderData ? maskAuthData(request) : request
684
- } : {
685
- uri: request.uri
686
- })
687
- });
598
+ // get the pending object from option
599
+ let pendingTasks = options.pendingTasks;
600
+ if (!httpClient || typeof httpClient !== 'function') throw new Error('an `httpClient` is not available, please pass in a `fetch` or `axios` instance as an option or have them globally available.');
601
+
602
+ /**
603
+ * If there is a token in the tokenCache, and it's not
604
+ * expired, append the token in the `Authorization` header.
605
+ */
606
+ const tokenCacheObject = tokenCache.get(tokenCacheKey);
607
+ if (tokenCacheObject && tokenCacheObject.token && Date.now() < tokenCacheObject.expirationTime) {
608
+ const requestWithAuth = mergeAuthHeader(tokenCacheObject.token, request);
688
609
  return {
689
- body: error,
690
- error
610
+ ...requestWithAuth
691
611
  };
692
- } finally {
693
- clearTimeout(timer);
694
612
  }
695
- }
696
- function createHttpMiddleware$1(options) {
697
- // validate response
698
- validateHttpOptions(options);
699
- const {
700
- host,
701
- credentialsMode,
702
- httpClient,
703
- timeout,
704
- enableRetry,
705
- retryConfig,
706
- getAbortController,
707
- includeOriginalRequest,
708
- includeRequestInErrorResponse,
709
- maskSensitiveHeaderData,
710
- httpClientOptions
711
- } = options;
712
- return next => {
713
- return async request => {
714
- let abortController;
715
- if (timeout || getAbortController) abortController = (getAbortController ? getAbortController() : null) || new AbortController__default["default"]();
716
- const url = host.replace(/\/$/, '') + request.uri;
717
- const requestHeader = {
718
- ...request.headers
719
- };
720
613
 
721
- // validate header
722
- if (!(Object.prototype.hasOwnProperty.call(requestHeader, 'Content-Type') || Object.prototype.hasOwnProperty.call(requestHeader, 'content-type'))) {
723
- requestHeader['Content-Type'] = 'application/json';
724
- }
725
-
726
- // Unset the content-type header if explicitly asked to (passing `null` as value).
727
- if (requestHeader['Content-Type'] === null) {
728
- delete requestHeader['Content-Type'];
729
- }
614
+ /**
615
+ * Keep pending tasks until a token is fetched
616
+ * Save next function as well, to call it once the token has been fetched, which prevents
617
+ * unexpected behaviour in a context in which the next function uses global vars
618
+ * or Promises to capture the token to hand it to other libraries, e.g. Apollo
619
+ */
620
+ pendingTasks.push({
621
+ request,
622
+ next
623
+ });
730
624
 
731
- // Ensure body is a string if content type is application/{json|graphql}
732
- const body = HEADERS_CONTENT_TYPES.indexOf(requestHeader['Content-Type']) > -1 && typeof request.body === 'string' || isBuffer(request.body) ? request.body : JSON.stringify(request.body || undefined);
733
- if (body && (typeof body === 'string' || isBuffer(body))) {
734
- requestHeader['Content-Length'] = _.Buffer.byteLength(body).toString();
735
- }
736
- const clientOptions = {
737
- enableRetry,
738
- retryConfig,
739
- request: request,
740
- method: request.method,
741
- headers: requestHeader,
742
- includeRequestInErrorResponse,
743
- maskSensitiveHeaderData,
744
- ...httpClientOptions
745
- };
746
- if (credentialsMode) {
747
- clientOptions.credentialsMode = credentialsMode;
748
- }
749
- if (abortController) {
750
- clientOptions.signal = abortController.signal;
751
- }
752
- if (timeout) {
753
- clientOptions.timeout = timeout;
754
- clientOptions.abortController = abortController;
755
- }
756
- if (body) {
757
- clientOptions.body = body;
758
- }
625
+ // if a token is currently being fetched, then wait
626
+ if (requestState.get()) return;
759
627
 
760
- // get result from executed request
761
- const response = await executeRequest$1({
762
- url,
763
- clientOptions,
764
- httpClient
765
- });
766
- const responseWithRequest = {
767
- ...request,
768
- includeOriginalRequest,
769
- maskSensitiveHeaderData,
770
- response
771
- };
772
- return next(responseWithRequest);
773
- };
774
- };
775
- }
628
+ // signal that a token is being fetched
629
+ requestState.set(true);
776
630
 
777
- function createQueueMiddleware$1({
778
- concurrency = 20
779
- }) {
780
- let runningCount = 0;
781
- const queue = [];
782
- const dequeue = next => {
783
- runningCount--;
784
- if (queue.length && runningCount <= concurrency) {
785
- const nextTask = queue.shift();
786
- runningCount++;
787
- return next(nextTask.request);
788
- }
789
- };
790
- const enqueue = ({
791
- request
792
- }) => queue.push({
793
- request
794
- });
795
- return next => request => {
796
- // wrap and override resolve and reject functions
797
- const patchedRequest = {
798
- ...request,
799
- resolve(data) {
800
- request.resolve(data);
801
- dequeue(next);
802
- },
803
- reject(error) {
804
- request.reject(error);
805
- dequeue(next);
806
- }
631
+ /**
632
+ * use refreshToken flow if there is refresh-token
633
+ * and there's either no token or the token is expired
634
+ */
635
+ if (tokenCacheObject && tokenCacheObject.refreshToken && (!tokenCacheObject.token || tokenCacheObject.token && Date.now() > tokenCacheObject.expirationTime)) {
636
+ if (!userOption) throw new Error('Missing required options.');
637
+ const opt = {
638
+ ...buildRequestForRefreshTokenFlow({
639
+ ...userOption,
640
+ refreshToken: tokenCacheObject.refreshToken
641
+ })
807
642
  };
808
643
 
809
- // enqueue requests
810
- enqueue({
811
- request: patchedRequest
812
- });
813
- if (runningCount < concurrency) {
814
- runningCount++;
815
- const nextTask = queue.shift();
816
- return next(nextTask.request);
817
- }
818
- };
819
- }
644
+ // reassign values
645
+ url = opt.url;
646
+ body = opt.body;
647
+ basicAuth = opt.basicAuth;
648
+ }
820
649
 
821
- // error, info, success
822
- function createLoggerMiddleware$1(options) {
823
- return next => {
824
- return async request => {
825
- let response = await next(request);
826
- const originalResponse = Object.assign({}, response);
650
+ // request a new token
651
+ let response;
652
+ try {
653
+ response = await executor({
654
+ url,
655
+ method: 'POST',
656
+ headers: {
657
+ Authorization: `Basic ${basicAuth}`,
658
+ 'Content-Type': 'application/x-www-form-urlencoded',
659
+ 'Conent-Length': _.Buffer.byteLength(body).toString()
660
+ },
661
+ httpClient,
662
+ body
663
+ });
664
+ if (response.statusCode >= 200 && response.statusCode < 300) {
665
+ var _response;
827
666
  const {
828
- loggerFn = console.log,
829
- // logLevel = 'ERROR',
830
- maskSensitiveHeaderData = true,
831
- includeOriginalRequest = true,
832
- includeResponseHeaders = true
833
- // includeRequestInErrorResponse
834
- } = options || {};
835
- if (includeOriginalRequest && maskSensitiveHeaderData) {
836
- maskAuthData(response.request);
837
- }
838
- if (!includeOriginalRequest) {
839
- const {
840
- request,
841
- ...rest
842
- } = response;
843
- response = rest;
844
- }
845
- if (!includeResponseHeaders) {
846
- const {
847
- headers,
848
- ...rest
849
- } = response;
850
- response = rest;
851
- }
852
- if (loggerFn && typeof loggerFn == 'function') {
853
- loggerFn(response);
854
- // return originalResponse
855
- }
667
+ access_token: token,
668
+ expires_in: expiresIn,
669
+ refresh_token: refreshToken
670
+ } = (_response = response) === null || _response === void 0 ? void 0 : _response.data;
856
671
 
857
- // console.log({ Response: response })
858
- return originalResponse;
859
- };
860
- };
861
- }
672
+ // calculate token expiration time
673
+ const expirationTime = calculateExpirationTime(expiresIn);
862
674
 
863
- var packageJson = {
864
- name: "@commercetools/ts-client",
865
- version: "1.0.0",
866
- engines: {
867
- node: ">=14"
868
- },
869
- description: "commercetools Composable Commerce TypeScript SDK client.",
870
- keywords: [
871
- "commercetools",
872
- "composable commerce",
873
- "sdk",
874
- "typescript",
875
- "client",
876
- "middleware",
877
- "http",
878
- "oauth",
879
- "auth"
880
- ],
881
- homepage: "https://github.com/commercetools/commercetools-sdk-typescript",
882
- license: "MIT",
883
- directories: {
884
- lib: "lib",
885
- test: "test"
886
- },
887
- publishConfig: {
888
- access: "public"
889
- },
890
- repository: {
891
- type: "git",
892
- url: "git+https://github.com/commercetools/commercetools-sdk-typescript.git"
893
- },
894
- bugs: {
895
- url: "https://github.com/commercetools/commercetools-sdk-typescript/issues"
896
- },
897
- dependencies: {
898
- "abort-controller": "3.0.0",
899
- buffer: "^6.0.3",
900
- "node-fetch": "^2.6.1",
901
- querystring: "^0.2.1"
902
- },
903
- files: [
904
- "dist",
905
- "CHANGELOG.md"
906
- ],
907
- author: "Chukwuemeka Ajima <meeky.ae@gmail.com>",
908
- main: "dist/commercetools-ts-client.cjs.js",
909
- module: "dist/commercetools-ts-client.esm.js",
910
- browser: {
911
- "./dist/commercetools-ts-client.cjs.js": "./dist/commercetools-ts-client.browser.cjs.js",
912
- "./dist/commercetools-ts-client.esm.js": "./dist/commercetools-ts-client.browser.esm.js"
913
- },
914
- devDependencies: {
915
- "common-tags": "1.8.2",
916
- dotenv: "16.0.3",
917
- jest: "29.5.0",
918
- nock: "12.0.3",
919
- "organize-imports-cli": "0.10.0"
920
- },
921
- scripts: {
922
- organize_imports: "find src -type f -name '*.ts' | xargs organize-imports-cli",
923
- postbuild: "yarn organize_imports",
924
- post_process_generate: "yarn organize_imports"
925
- }
926
- };
675
+ // cache new generated token, refreshToken and expiration time
676
+ tokenCache.set({
677
+ token,
678
+ expirationTime,
679
+ refreshToken
680
+ });
927
681
 
928
- function createUserAgentMiddleware$1(options) {
929
- return next => async request => {
930
- const userAgent = createUserAgent({
931
- ...options,
932
- name: `commercetools-sdk-javascript-v3/${packageJson.version}`
682
+ // signal that a token fetch is complete
683
+ requestState.set(false);
684
+
685
+ /**
686
+ * Freeze and copy pending queue, reset
687
+ * original one for accepting new pending tasks
688
+ */
689
+ const requestQueue = pendingTasks.slice();
690
+
691
+ // reset pendingTask queue
692
+ pendingTasks = [];
693
+ if (requestQueue.length === 1) {
694
+ return mergeAuthHeader(token, requestQueue.pop().request);
695
+ }
696
+
697
+ // execute all pending tasks if any
698
+ for (let i = 0; i < requestQueue.length; i++) {
699
+ const task = requestQueue[i];
700
+ const requestWithAuth = mergeAuthHeader(token, task.request);
701
+
702
+ // execute task
703
+ task.next(requestWithAuth);
704
+ }
705
+ return;
706
+ }
707
+ const error = new Error(response.data.message ? response.data.message : JSON.stringify(response.data));
708
+ /**
709
+ * reject the error immediately
710
+ * and free up the middleware chain
711
+ */
712
+ request.reject({
713
+ ...request,
714
+ headers: {
715
+ ...request.headers
716
+ },
717
+ response: {
718
+ statusCode: response.statusCode || response.data.statusCode,
719
+ error: {
720
+ error,
721
+ body: response
722
+ }
723
+ }
933
724
  });
934
- const requestWithUserAgent = {
725
+ } catch (error) {
726
+ return {
935
727
  ...request,
936
728
  headers: {
937
- ...request.headers,
938
- 'User-Agent': userAgent
729
+ ...request.headers
730
+ },
731
+ response: {
732
+ body: null,
733
+ statusCode: error.statusCode || 0,
734
+ error: {
735
+ ...response,
736
+ error,
737
+ body: response
738
+ }
939
739
  }
940
740
  };
941
- return next(requestWithUserAgent);
942
- };
741
+ }
943
742
  }
944
743
 
945
- function createConcurrentModificationMiddleware$1() {
744
+ function createAuthMiddlewareForAnonymousSessionFlow$1(options) {
745
+ const pendingTasks = [];
746
+ const requestState = store(false);
747
+ const tokenCache = options.tokenCache || store({
748
+ token: '',
749
+ expirationTime: -1
750
+ });
751
+ const tokenCacheKey = buildTokenCacheKey(options);
946
752
  return next => {
947
753
  return async request => {
948
- const response = await next(request);
949
- if (response.statusCode == 409) {
950
- var _response$error, _response$error$body, _response$error$body$, _response$error$body$2;
951
- /**
952
- * extract the currentVersion
953
- * from the error body and update
954
- * request with the currentVersion
955
- */
956
- const version = (_response$error = response.error) === null || _response$error === void 0 ? void 0 : (_response$error$body = _response$error.body) === null || _response$error$body === void 0 ? void 0 : (_response$error$body$ = _response$error$body.errors) === null || _response$error$body$ === void 0 ? void 0 : (_response$error$body$2 = _response$error$body$[0]) === null || _response$error$body$2 === void 0 ? void 0 : _response$error$body$2.currentVersion;
957
-
958
- // update the resource version here
959
- if (version) {
960
- request.body = typeof request.body == 'string' ? {
961
- ...JSON.parse(request.body),
962
- version
963
- } : {
964
- ...request.body,
965
- version
966
- };
967
- return next(request);
968
- }
754
+ // if here is a token in the header, then move on to the next middleware
755
+ if (request.headers && (request.headers.Authorization || request.headers.authorization)) {
756
+ // move on
757
+ return next(request);
969
758
  }
970
- return response;
971
- };
972
- };
973
- }
974
759
 
975
- function createErrorMiddleware$1(options) {
976
- return next => async request => {
977
- const response = await next(request);
978
- if (response.error) {
979
- const {
980
- error
981
- } = response;
982
- return {
983
- ...response,
984
- statusCode: error.statusCode || 0,
985
- headers: error.headers || getHeaders({}),
986
- error: {
987
- ...error,
988
- body: error.data || error
989
- }
760
+ // prepare request options
761
+ const requestOptions = {
762
+ request,
763
+ requestState,
764
+ tokenCache,
765
+ pendingTasks,
766
+ tokenCacheKey,
767
+ httpClient: options.httpClient || fetch__default["default"],
768
+ ...buildRequestForAnonymousSessionFlow(options),
769
+ userOption: options,
770
+ next
990
771
  };
991
- }
992
- return response;
993
- };
994
- }
995
772
 
996
- /**
997
- *
998
- * @param {AuthMiddlewareOptions} options
999
- * @returns { IBuiltRequestParams } *
1000
- */
1001
- function buildRequestForClientCredentialsFlow(options) {
1002
- // Validate options
1003
- if (!options) throw new Error('Missing required options');
1004
- if (!options.host) throw new Error('Missing required option (host)');
1005
- if (!options.projectKey) throw new Error('Missing required option (projectKey)');
1006
- if (!options.credentials) throw new Error('Missing required option (credentials)');
1007
- const {
1008
- clientId,
1009
- clientSecret
1010
- } = options.credentials || {};
1011
- if (!(clientId && clientSecret)) throw new Error('Missing required credentials (clientId, clientSecret)');
1012
- const scope = options.scopes ? options.scopes.join(' ') : undefined;
1013
- const basicAuth = _.Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
1014
- // This is mostly useful for internal testing purposes to be able to check
1015
- // other oauth endpoints.
1016
- const oauthUri = options.oauthUri || '/oauth/token';
1017
- const url = options.host.replace(/\/$/, '') + oauthUri;
1018
- const body = `grant_type=client_credentials${scope ? `&scope=${scope}` : ''}`;
1019
- return {
1020
- url,
1021
- body,
1022
- basicAuth
773
+ // make request to coco
774
+ const requestWithAuth = await executeRequest$1(requestOptions);
775
+ if (requestWithAuth) {
776
+ return next(requestWithAuth);
777
+ }
778
+ };
1023
779
  };
1024
780
  }
1025
781
 
1026
- /**
1027
- *
1028
- * @param {AuthMiddlewareOptions} options
1029
- * @returns {IBuiltRequestParams} *
1030
- */
1031
- function buildRequestForAnonymousSessionFlow(options) {
1032
- if (!options) throw new Error('Missing required options');
1033
- if (!options.projectKey) throw new Error('Missing required option (projectKey)');
1034
- const projectKey = options.projectKey;
1035
- options.oauthUri = options.oauthUri || `/oauth/${projectKey}/anonymous/token`;
1036
- const result = buildRequestForClientCredentialsFlow(options);
1037
- if (options.credentials.anonymousId) result.body += `&anonymous_id=${options.credentials.anonymousId}`;
1038
- return {
1039
- ...result
1040
- };
1041
- }
782
+ function createAuthMiddlewareForClientCredentialsFlow$1(options) {
783
+ const requestState = store(false);
784
+ const pendingTasks = [];
785
+ const tokenCache = options.tokenCache || store({
786
+ token: '',
787
+ expirationTime: -1
788
+ });
789
+ const tokenCacheKey = buildTokenCacheKey(options);
790
+ return next => {
791
+ return async request => {
792
+ // if here is a token in the header, then move on to the next middleware
793
+ if (request.headers && (request.headers.Authorization || request.headers.authorization)) {
794
+ // move on
795
+ return next(request);
796
+ }
1042
797
 
1043
- /**
1044
- *
1045
- * @param {RefreshAuthMiddlewareOptions} options
1046
- * @returns {IBuiltRequestParams}
1047
- */
1048
- function buildRequestForRefreshTokenFlow(options) {
1049
- if (!options) throw new Error('Missing required options');
1050
- if (!options.host) throw new Error('Missing required option (host)');
1051
- if (!options.projectKey) throw new Error('Missing required option (projectKey)');
1052
- if (!options.credentials) throw new Error('Missing required option (credentials)');
1053
- if (!options.refreshToken) throw new Error('Missing required option (refreshToken)');
1054
- const {
1055
- clientId,
1056
- clientSecret
1057
- } = options.credentials;
1058
- if (!(clientId && clientSecret)) throw new Error('Missing required credentials (clientId, clientSecret)');
1059
- const basicAuth = _.Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
1060
- // This is mostly useful for internal testing purposes to be able to check
1061
- // other oauth endpoints.
1062
- const oauthUri = options.oauthUri || '/oauth/token';
1063
- const url = options.host.replace(/\/$/, '') + oauthUri;
1064
- const body = `grant_type=refresh_token&refresh_token=${encodeURIComponent(options.refreshToken)}`;
1065
- return {
1066
- basicAuth,
1067
- url,
1068
- body
798
+ // prepare request options
799
+ const requestOptions = {
800
+ request,
801
+ requestState,
802
+ tokenCache,
803
+ pendingTasks,
804
+ tokenCacheKey,
805
+ httpClient: options.httpClient || fetch__default["default"],
806
+ ...buildRequestForClientCredentialsFlow(options),
807
+ next
808
+ };
809
+
810
+ // make request to coco
811
+ const requestWithAuth = await executeRequest$1(requestOptions);
812
+ if (requestWithAuth) {
813
+ // make the request and inject the token into the header
814
+ return next(requestWithAuth);
815
+ }
816
+ };
1069
817
  };
1070
818
  }
1071
819
 
1072
- /**
1073
- * @param {PasswordAuthMiddlewareOptions} options
1074
- * @returns {IBuiltRequestParams}
1075
- */
1076
- function buildRequestForPasswordFlow(options) {
1077
- if (!options) throw new Error('Missing required options');
1078
- if (!options.host) throw new Error('Missing required option (host)');
1079
- if (!options.projectKey) throw new Error('Missing required option (projectKey)');
1080
- if (!options.credentials) throw new Error('Missing required option (credentials)');
1081
- const {
1082
- clientId,
1083
- clientSecret,
1084
- user
1085
- } = options.credentials;
1086
- const projectKey = options.projectKey;
1087
- if (!(clientId && clientSecret && user)) throw new Error('Missing required credentials (clientId, clientSecret, user)');
1088
- const {
1089
- username,
1090
- password
1091
- } = user;
1092
- if (!(username && password)) throw new Error('Missing required user credentials (username, password)');
1093
- const scope = (options.scopes || []).join(' ');
1094
- const scopeStr = scope ? `&scope=${scope}` : '';
1095
- const basicAuth = _.Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
1096
-
1097
- /**
1098
- * This is mostly useful for internal testing purposes to be able to check
1099
- * other oauth endpoints.
1100
- */
1101
- const oauthUri = options.oauthUri || `/oauth/${projectKey}/customers/token`;
1102
- const url = options.host.replace(/\/$/, '') + oauthUri;
820
+ function createAuthMiddlewareForExistingTokenFlow$1(authorization, options) {
821
+ return next => {
822
+ return async request => {
823
+ if (typeof authorization !== 'string') throw new Error('authorization must be a string');
824
+ const isForce = (options === null || options === void 0 ? void 0 : options.force) === undefined ? true : options.force;
1103
825
 
1104
- // encode username and password as requested by the system
1105
- const body = `grant_type=password&username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}${scopeStr}`;
1106
- return {
1107
- basicAuth,
1108
- url,
1109
- body
826
+ /**
827
+ * The request will not be modified if:
828
+ * 1. no argument is passed
829
+ * 2. force is false and authorization header exists
830
+ */
831
+ if (!authorization || request.headers && (request.headers.Authorization || request.headers.authorization) && isForce === false) {
832
+ return next(request);
833
+ }
834
+ const requestWithAuth = {
835
+ ...request,
836
+ headers: {
837
+ ...request.headers,
838
+ Authorization: authorization
839
+ }
840
+ };
841
+ return next(requestWithAuth);
842
+ };
1110
843
  };
1111
844
  }
1112
845
 
1113
- async function executeRequest(options) {
1114
- const {
1115
- request,
1116
- httpClient,
1117
- tokenCache,
1118
- tokenCacheKey,
1119
- requestState,
1120
- userOption,
1121
- next
1122
- } = options;
1123
- let url = options.url;
1124
- let body = options.body;
1125
- let basicAuth = options.basicAuth;
1126
-
1127
- // get the pending object from option
1128
- let pendingTasks = options.pendingTasks;
1129
- if (!httpClient || typeof httpClient !== 'function') throw new Error('an `httpClient` is not available, please pass in a `fetch` or `axios` instance as an option or have them globally available.');
846
+ function createAuthMiddlewareForPasswordFlow$1(options) {
847
+ const tokenCache = options.tokenCache || store({
848
+ token: '',
849
+ expirationTime: -1
850
+ });
851
+ const pendingTasks = [];
852
+ const requestState = store(false);
853
+ const tokenCacheKey = buildTokenCacheKey(options);
854
+ return next => {
855
+ return async request => {
856
+ if (request.headers && (request.headers.Authorization || request.headers.authorization)) {
857
+ return next(request);
858
+ }
859
+ const requestOptions = {
860
+ request,
861
+ requestState,
862
+ tokenCache,
863
+ pendingTasks,
864
+ tokenCacheKey,
865
+ httpClient: options.httpClient || fetch__default["default"],
866
+ ...buildRequestForPasswordFlow(options),
867
+ userOption: options,
868
+ next
869
+ };
1130
870
 
1131
- /**
1132
- * If there is a token in the tokenCache, and it's not
1133
- * expired, append the token in the `Authorization` header.
1134
- */
1135
- const tokenCacheObject = tokenCache.get(tokenCacheKey);
1136
- if (tokenCacheObject && tokenCacheObject.token && Date.now() < tokenCacheObject.expirationTime) {
1137
- const requestWithAuth = mergeAuthHeader(tokenCacheObject.token, request);
1138
- return {
1139
- ...requestWithAuth
871
+ // make request to coco
872
+ const requestWithAuth = await executeRequest$1(requestOptions);
873
+ if (requestWithAuth) {
874
+ return next(requestWithAuth);
875
+ }
1140
876
  };
1141
- }
877
+ };
878
+ }
1142
879
 
1143
- /**
1144
- * Keep pending tasks until a token is fetched
1145
- * Save next function as well, to call it once the token has been fetched, which prevents
1146
- * unexpected behaviour in a context in which the next function uses global vars
1147
- * or Promises to capture the token to hand it to other libraries, e.g. Apollo
1148
- */
1149
- pendingTasks.push({
1150
- request,
1151
- next
880
+ function createAuthMiddlewareForRefreshTokenFlow$1(options) {
881
+ const tokenCache = options.tokenCache || store({
882
+ token: '',
883
+ tokenCacheKey: null
1152
884
  });
885
+ const pendingTasks = [];
886
+ const requestState = store(false);
887
+ return next => {
888
+ return async request => {
889
+ if (request.headers && (request.headers.Authorization || request.headers.authorization)) {
890
+ return next(request);
891
+ }
892
+
893
+ // prepare request options
894
+ const requestOptions = {
895
+ request,
896
+ requestState,
897
+ tokenCache,
898
+ pendingTasks,
899
+ httpClient: options.httpClient || fetch,
900
+ ...buildRequestForRefreshTokenFlow(options),
901
+ next
902
+ };
1153
903
 
1154
- // if a token is currently being fetched, then wait
1155
- if (requestState.get()) return;
904
+ // make request to coco
905
+ const requestWithAuth = await executeRequest$1(requestOptions);
906
+ if (requestWithAuth) {
907
+ return next(requestWithAuth);
908
+ }
909
+ };
910
+ };
911
+ }
1156
912
 
1157
- // signal that a token is being fetched
1158
- requestState.set(true);
913
+ function createConcurrentModificationMiddleware$1() {
914
+ return next => {
915
+ return async request => {
916
+ const response = await next(request);
917
+ if (response.statusCode == 409) {
918
+ var _response$error, _response$error$body, _response$error$body$, _response$error$body$2;
919
+ /**
920
+ * extract the currentVersion
921
+ * from the error body and update
922
+ * request with the currentVersion
923
+ */
924
+ const version = (_response$error = response.error) === null || _response$error === void 0 ? void 0 : (_response$error$body = _response$error.body) === null || _response$error$body === void 0 ? void 0 : (_response$error$body$ = _response$error$body.errors) === null || _response$error$body$ === void 0 ? void 0 : (_response$error$body$2 = _response$error$body$[0]) === null || _response$error$body$2 === void 0 ? void 0 : _response$error$body$2.currentVersion;
1159
925
 
1160
- /**
1161
- * use refreshToken flow if there is refresh-token
1162
- * and there's either no token or the token is expired
1163
- */
1164
- if (tokenCacheObject && tokenCacheObject.refreshToken && (!tokenCacheObject.token || tokenCacheObject.token && Date.now() > tokenCacheObject.expirationTime)) {
1165
- if (!userOption) throw new Error('Missing required options.');
1166
- const opt = {
1167
- ...buildRequestForRefreshTokenFlow({
1168
- ...userOption,
1169
- refreshToken: tokenCacheObject.refreshToken
1170
- })
926
+ // update the resource version here
927
+ if (version) {
928
+ request.body = typeof request.body == 'string' ? {
929
+ ...JSON.parse(request.body),
930
+ version
931
+ } : {
932
+ ...request.body,
933
+ version
934
+ };
935
+ return next(request);
936
+ }
937
+ }
938
+ return response;
1171
939
  };
940
+ };
941
+ }
1172
942
 
1173
- // reassign values
1174
- url = opt.url;
1175
- body = opt.body;
1176
- basicAuth = opt.basicAuth;
1177
- }
943
+ function createCorrelationIdMiddleware$1(options) {
944
+ return next => request => {
945
+ const nextRequest = {
946
+ ...request,
947
+ headers: {
948
+ ...request.headers,
949
+ 'X-Correlation-ID': options.generate && typeof options.generate == 'function' ? options.generate() : generateID()
950
+ }
951
+ };
952
+ return next(nextRequest);
953
+ };
954
+ }
1178
955
 
1179
- // request a new token
1180
- let response;
956
+ function createErrorMiddleware$1(options) {
957
+ return next => async request => {
958
+ const response = await next(request);
959
+ if (response.error) {
960
+ const {
961
+ error
962
+ } = response;
963
+ return {
964
+ ...response,
965
+ statusCode: error.statusCode || 0,
966
+ headers: error.headers || getHeaders({}),
967
+ error: {
968
+ ...error,
969
+ body: error.data || error
970
+ }
971
+ };
972
+ }
973
+ return response;
974
+ };
975
+ }
976
+
977
+ async function executeRequest({
978
+ url,
979
+ httpClient,
980
+ clientOptions
981
+ }) {
982
+ let timer;
983
+ const {
984
+ timeout,
985
+ request,
986
+ abortController,
987
+ maskSensitiveHeaderData,
988
+ includeRequestInErrorResponse
989
+ } = clientOptions;
1181
990
  try {
1182
- response = await executor({
991
+ var _response$data, _response$data2;
992
+ if (timeout) timer = setTimeout(() => {
993
+ abortController.abort();
994
+ }, timeout);
995
+ const response = await executor({
1183
996
  url,
1184
- method: 'POST',
1185
- headers: {
1186
- Authorization: `Basic ${basicAuth}`,
1187
- 'Content-Type': 'application/x-www-form-urlencoded',
1188
- 'Conent-Length': _.Buffer.byteLength(body).toString()
1189
- },
997
+ ...clientOptions,
1190
998
  httpClient,
1191
- body
999
+ method: clientOptions.method,
1000
+ ...(clientOptions.body ? {
1001
+ body: clientOptions.body
1002
+ } : {})
1192
1003
  });
1193
1004
  if (response.statusCode >= 200 && response.statusCode < 300) {
1194
- var _response;
1195
- const {
1196
- access_token: token,
1197
- expires_in: expiresIn,
1198
- refresh_token: refreshToken
1199
- } = (_response = response) === null || _response === void 0 ? void 0 : _response.data;
1200
-
1201
- // calculate token expiration time
1202
- const expirationTime = calculateExpirationTime(expiresIn);
1005
+ if (clientOptions.method == 'HEAD') {
1006
+ return {
1007
+ body: null,
1008
+ statusCode: response.statusCode,
1009
+ retryCount: response.retryCount,
1010
+ headers: getHeaders(response.headers)
1011
+ };
1012
+ }
1013
+ return {
1014
+ body: response.data,
1015
+ statusCode: response.statusCode,
1016
+ retryCount: response.retryCount,
1017
+ headers: getHeaders(response.headers)
1018
+ };
1019
+ }
1020
+ const error = createError({
1021
+ message: (response === null || response === void 0 ? void 0 : (_response$data = response.data) === null || _response$data === void 0 ? void 0 : _response$data.message) || (response === null || response === void 0 ? void 0 : response.message),
1022
+ statusCode: response.statusCode || (response === null || response === void 0 ? void 0 : (_response$data2 = response.data) === null || _response$data2 === void 0 ? void 0 : _response$data2.statusCode),
1023
+ headers: getHeaders(response.headers),
1024
+ method: clientOptions.method,
1025
+ body: response.data,
1026
+ retryCount: response.retryCount,
1027
+ ...(includeRequestInErrorResponse ? {
1028
+ originalRequest: maskSensitiveHeaderData ? maskAuthData(request) : request
1029
+ } : {
1030
+ uri: request.uri
1031
+ })
1032
+ });
1203
1033
 
1204
- // cache new generated token, refreshToken and expiration time
1205
- tokenCache.set({
1206
- token,
1207
- expirationTime,
1208
- refreshToken
1209
- });
1034
+ /**
1035
+ * handle non-ok (error) response
1036
+ * build error body
1037
+ */
1038
+ return {
1039
+ body: response.data,
1040
+ code: response.statusCode,
1041
+ statusCode: response.statusCode,
1042
+ headers: getHeaders(response.headers),
1043
+ error
1044
+ };
1045
+ } catch (e) {
1046
+ var _e$response, _e$response2, _e$response3, _e$response4, _e$response4$data, _e$response5, _e$response6;
1047
+ // We know that this is a network error
1048
+ const headers = getHeaders((_e$response = e.response) === null || _e$response === void 0 ? void 0 : _e$response.headers);
1049
+ const statusCode = ((_e$response2 = e.response) === null || _e$response2 === void 0 ? void 0 : _e$response2.status) || ((_e$response3 = e.response) === null || _e$response3 === void 0 ? void 0 : _e$response3.data0) || 0;
1050
+ const message = (_e$response4 = e.response) === null || _e$response4 === void 0 ? void 0 : (_e$response4$data = _e$response4.data) === null || _e$response4$data === void 0 ? void 0 : _e$response4$data.message;
1051
+ const error = createError({
1052
+ statusCode,
1053
+ code: statusCode,
1054
+ status: statusCode,
1055
+ message: message || e.message,
1056
+ headers,
1057
+ body: ((_e$response5 = e.response) === null || _e$response5 === void 0 ? void 0 : _e$response5.data) || e,
1058
+ error: (_e$response6 = e.response) === null || _e$response6 === void 0 ? void 0 : _e$response6.data,
1059
+ ...(includeRequestInErrorResponse ? {
1060
+ originalRequest: maskSensitiveHeaderData ? maskAuthData(request) : request
1061
+ } : {
1062
+ uri: request.uri
1063
+ })
1064
+ });
1065
+ return {
1066
+ body: error,
1067
+ error
1068
+ };
1069
+ } finally {
1070
+ clearTimeout(timer);
1071
+ }
1072
+ }
1073
+ function createHttpMiddleware$1(options) {
1074
+ // validate response
1075
+ validateHttpOptions(options);
1076
+ const {
1077
+ host,
1078
+ credentialsMode,
1079
+ httpClient,
1080
+ timeout,
1081
+ enableRetry,
1082
+ retryConfig,
1083
+ getAbortController,
1084
+ includeOriginalRequest,
1085
+ includeRequestInErrorResponse,
1086
+ maskSensitiveHeaderData,
1087
+ httpClientOptions
1088
+ } = options;
1089
+ return next => {
1090
+ return async request => {
1091
+ let abortController;
1092
+ if (timeout || getAbortController) abortController = (getAbortController ? getAbortController() : null) || new AbortController__default["default"]();
1093
+ const url = host.replace(/\/$/, '') + request.uri;
1094
+ const requestHeader = {
1095
+ ...request.headers
1096
+ };
1210
1097
 
1211
- // signal that a token fetch is complete
1212
- requestState.set(false);
1098
+ // validate header
1099
+ if (!(Object.prototype.hasOwnProperty.call(requestHeader, 'Content-Type') || Object.prototype.hasOwnProperty.call(requestHeader, 'content-type'))) {
1100
+ requestHeader['Content-Type'] = 'application/json';
1101
+ }
1213
1102
 
1214
- /**
1215
- * Freeze and copy pending queue, reset
1216
- * original one for accepting new pending tasks
1217
- */
1218
- const requestQueue = pendingTasks.slice();
1103
+ // Unset the content-type header if explicitly asked to (passing `null` as value).
1104
+ if (requestHeader['Content-Type'] === null) {
1105
+ delete requestHeader['Content-Type'];
1106
+ }
1219
1107
 
1220
- // reset pendingTask queue
1221
- pendingTasks = [];
1222
- if (requestQueue.length === 1) {
1223
- return mergeAuthHeader(token, requestQueue.pop().request);
1108
+ // Ensure body is a string if content type is application/{json|graphql}
1109
+ const body = HEADERS_CONTENT_TYPES.indexOf(requestHeader['Content-Type']) > -1 && typeof request.body === 'string' || isBuffer(request.body) ? request.body : JSON.stringify(request.body || undefined);
1110
+ if (body && (typeof body === 'string' || isBuffer(body))) {
1111
+ requestHeader['Content-Length'] = _.Buffer.byteLength(body).toString();
1112
+ }
1113
+ const clientOptions = {
1114
+ enableRetry,
1115
+ retryConfig,
1116
+ request: request,
1117
+ method: request.method,
1118
+ headers: requestHeader,
1119
+ includeRequestInErrorResponse,
1120
+ maskSensitiveHeaderData,
1121
+ ...httpClientOptions
1122
+ };
1123
+ if (credentialsMode) {
1124
+ clientOptions.credentialsMode = credentialsMode;
1224
1125
  }
1225
-
1226
- // execute all pending tasks if any
1227
- for (let i = 0; i < requestQueue.length; i++) {
1228
- const task = requestQueue[i];
1229
- const requestWithAuth = mergeAuthHeader(token, task.request);
1230
-
1231
- // execute task
1232
- task.next(requestWithAuth);
1126
+ if (abortController) {
1127
+ clientOptions.signal = abortController.signal;
1233
1128
  }
1234
- return;
1235
- }
1236
- const error = new Error(response.data.message ? response.data.message : JSON.stringify(response.data));
1237
- /**
1238
- * reject the error immediately
1239
- * and free up the middleware chain
1240
- */
1241
- request.reject({
1242
- ...request,
1243
- headers: {
1244
- ...request.headers
1245
- },
1246
- response: {
1247
- statusCode: response.statusCode || response.data.statusCode,
1248
- error: {
1249
- error,
1250
- body: response
1251
- }
1129
+ if (timeout) {
1130
+ clientOptions.timeout = timeout;
1131
+ clientOptions.abortController = abortController;
1252
1132
  }
1253
- });
1254
- } catch (error) {
1255
- return {
1256
- ...request,
1257
- headers: {
1258
- ...request.headers
1259
- },
1260
- response: {
1261
- body: null,
1262
- statusCode: error.statusCode || 0,
1263
- error: {
1264
- ...response,
1265
- error,
1266
- body: response
1267
- }
1133
+ if (body) {
1134
+ clientOptions.body = body;
1268
1135
  }
1136
+
1137
+ // get result from executed request
1138
+ const response = await executeRequest({
1139
+ url,
1140
+ clientOptions,
1141
+ httpClient
1142
+ });
1143
+ const responseWithRequest = {
1144
+ ...request,
1145
+ includeOriginalRequest,
1146
+ maskSensitiveHeaderData,
1147
+ response
1148
+ };
1149
+ return next(responseWithRequest);
1269
1150
  };
1270
- }
1151
+ };
1271
1152
  }
1272
1153
 
1273
- function createAuthMiddlewareForPasswordFlow$1(options) {
1274
- const tokenCache = options.tokenCache || store({
1275
- token: '',
1276
- expirationTime: -1
1277
- });
1278
- const pendingTasks = [];
1279
- const requestState = store(false);
1280
- const tokenCacheKey = buildTokenCacheKey(options);
1154
+ // error, info, success
1155
+ function createLoggerMiddleware$1(options) {
1281
1156
  return next => {
1282
1157
  return async request => {
1283
- if (request.headers && (request.headers.Authorization || request.headers.authorization)) {
1284
- return next(request);
1158
+ let response = await next(request);
1159
+ const originalResponse = Object.assign({}, response);
1160
+ const {
1161
+ loggerFn = console.log,
1162
+ // logLevel = 'ERROR',
1163
+ maskSensitiveHeaderData = true,
1164
+ includeOriginalRequest = true,
1165
+ includeResponseHeaders = true
1166
+ // includeRequestInErrorResponse
1167
+ } = options || {};
1168
+ if (includeOriginalRequest && maskSensitiveHeaderData) {
1169
+ maskAuthData(response.request);
1285
1170
  }
1286
- const requestOptions = {
1287
- request,
1288
- requestState,
1289
- tokenCache,
1290
- pendingTasks,
1291
- tokenCacheKey,
1292
- httpClient: options.httpClient || fetch__default["default"],
1293
- ...buildRequestForPasswordFlow(options),
1294
- userOption: options,
1295
- next
1296
- };
1297
-
1298
- // make request to coco
1299
- const requestWithAuth = await executeRequest(requestOptions);
1300
- if (requestWithAuth) {
1301
- return next(requestWithAuth);
1171
+ if (!includeOriginalRequest) {
1172
+ const {
1173
+ request,
1174
+ ...rest
1175
+ } = response;
1176
+ response = rest;
1177
+ }
1178
+ if (!includeResponseHeaders) {
1179
+ const {
1180
+ headers,
1181
+ ...rest
1182
+ } = response;
1183
+ response = rest;
1184
+ }
1185
+ if (loggerFn && typeof loggerFn == 'function') {
1186
+ loggerFn(response);
1187
+ // return originalResponse
1302
1188
  }
1189
+
1190
+ // console.log({ Response: response })
1191
+ return originalResponse;
1303
1192
  };
1304
1193
  };
1305
1194
  }
1306
1195
 
1307
- function createAuthMiddlewareForAnonymousSessionFlow$1(options) {
1308
- const pendingTasks = [];
1309
- const requestState = store(false);
1310
- const tokenCache = options.tokenCache || store({
1311
- token: '',
1312
- expirationTime: -1
1196
+ function createQueueMiddleware$1({
1197
+ concurrency = 20
1198
+ }) {
1199
+ let runningCount = 0;
1200
+ const queue = [];
1201
+ const dequeue = next => {
1202
+ runningCount--;
1203
+ if (queue.length && runningCount <= concurrency) {
1204
+ const nextTask = queue.shift();
1205
+ runningCount++;
1206
+ return next(nextTask.request);
1207
+ }
1208
+ };
1209
+ const enqueue = ({
1210
+ request
1211
+ }) => queue.push({
1212
+ request
1313
1213
  });
1314
- const tokenCacheKey = buildTokenCacheKey(options);
1315
- return next => {
1316
- return async request => {
1317
- // if here is a token in the header, then move on to the next middleware
1318
- if (request.headers && (request.headers.Authorization || request.headers.authorization)) {
1319
- // move on
1320
- return next(request);
1214
+ return next => request => {
1215
+ // wrap and override resolve and reject functions
1216
+ const patchedRequest = {
1217
+ ...request,
1218
+ resolve(data) {
1219
+ request.resolve(data);
1220
+ dequeue(next);
1221
+ },
1222
+ reject(error) {
1223
+ request.reject(error);
1224
+ dequeue(next);
1321
1225
  }
1226
+ };
1322
1227
 
1323
- // prepare request options
1324
- const requestOptions = {
1325
- request,
1326
- requestState,
1327
- tokenCache,
1328
- pendingTasks,
1329
- tokenCacheKey,
1330
- httpClient: options.httpClient || fetch__default["default"],
1331
- ...buildRequestForAnonymousSessionFlow(options),
1332
- userOption: options,
1333
- next
1334
- };
1228
+ // enqueue requests
1229
+ enqueue({
1230
+ request: patchedRequest
1231
+ });
1232
+ if (runningCount < concurrency) {
1233
+ runningCount++;
1234
+ const nextTask = queue.shift();
1235
+ return next(nextTask.request);
1236
+ }
1237
+ };
1238
+ }
1239
+
1240
+ var packageJson = {
1241
+ name: "@commercetools/ts-client",
1242
+ version: "1.1.0",
1243
+ engines: {
1244
+ node: ">=14"
1245
+ },
1246
+ description: "commercetools Composable Commerce TypeScript SDK client.",
1247
+ keywords: [
1248
+ "commercetools",
1249
+ "composable commerce",
1250
+ "sdk",
1251
+ "typescript",
1252
+ "client",
1253
+ "middleware",
1254
+ "http",
1255
+ "oauth",
1256
+ "auth"
1257
+ ],
1258
+ homepage: "https://github.com/commercetools/commercetools-sdk-typescript",
1259
+ license: "MIT",
1260
+ directories: {
1261
+ lib: "lib",
1262
+ test: "test"
1263
+ },
1264
+ publishConfig: {
1265
+ access: "public"
1266
+ },
1267
+ repository: {
1268
+ type: "git",
1269
+ url: "git+https://github.com/commercetools/commercetools-sdk-typescript.git"
1270
+ },
1271
+ bugs: {
1272
+ url: "https://github.com/commercetools/commercetools-sdk-typescript/issues"
1273
+ },
1274
+ dependencies: {
1275
+ "abort-controller": "3.0.0",
1276
+ buffer: "^6.0.3",
1277
+ "node-fetch": "^2.6.1"
1278
+ },
1279
+ files: [
1280
+ "dist",
1281
+ "CHANGELOG.md"
1282
+ ],
1283
+ author: "Chukwuemeka Ajima <meeky.ae@gmail.com>",
1284
+ main: "dist/commercetools-ts-client.cjs.js",
1285
+ module: "dist/commercetools-ts-client.esm.js",
1286
+ browser: {
1287
+ "./dist/commercetools-ts-client.cjs.js": "./dist/commercetools-ts-client.browser.cjs.js",
1288
+ "./dist/commercetools-ts-client.esm.js": "./dist/commercetools-ts-client.browser.esm.js"
1289
+ },
1290
+ devDependencies: {
1291
+ "common-tags": "1.8.2",
1292
+ dotenv: "16.0.3",
1293
+ jest: "29.5.0",
1294
+ nock: "12.0.3",
1295
+ "organize-imports-cli": "0.10.0"
1296
+ },
1297
+ scripts: {
1298
+ organize_imports: "find src -type f -name '*.ts' | xargs organize-imports-cli",
1299
+ postbuild: "yarn organize_imports",
1300
+ post_process_generate: "yarn organize_imports"
1301
+ }
1302
+ };
1335
1303
 
1336
- // make request to coco
1337
- const requestWithAuth = await executeRequest(requestOptions);
1338
- if (requestWithAuth) {
1339
- return next(requestWithAuth);
1304
+ function createUserAgentMiddleware$1(options) {
1305
+ return next => async request => {
1306
+ const userAgent = createUserAgent({
1307
+ ...options,
1308
+ name: `commercetools-sdk-javascript-v3/${packageJson.version}`
1309
+ });
1310
+ const requestWithUserAgent = {
1311
+ ...request,
1312
+ headers: {
1313
+ ...request.headers,
1314
+ 'User-Agent': userAgent
1340
1315
  }
1341
1316
  };
1317
+ return next(requestWithUserAgent);
1342
1318
  };
1343
1319
  }
1344
1320
 
1345
- function createAuthMiddlewareForClientCredentialsFlow$1(options) {
1346
- const requestState = store(false);
1347
- const pendingTasks = [];
1348
- const tokenCache = options.tokenCache || store({
1349
- token: '',
1350
- expirationTime: -1
1351
- });
1352
- const tokenCacheKey = buildTokenCacheKey(options);
1353
- return next => {
1354
- return async request => {
1355
- // if here is a token in the header, then move on to the next middleware
1356
- if (request.headers && (request.headers.Authorization || request.headers.authorization)) {
1357
- // move on
1358
- return next(request);
1359
- }
1360
-
1361
- // prepare request options
1362
- const requestOptions = {
1363
- request,
1364
- requestState,
1365
- tokenCache,
1366
- pendingTasks,
1367
- tokenCacheKey,
1368
- httpClient: options.httpClient || fetch__default["default"],
1369
- ...buildRequestForClientCredentialsFlow(options),
1370
- next
1371
- };
1321
+ var middleware = /*#__PURE__*/Object.freeze({
1322
+ __proto__: null,
1323
+ createAuthMiddlewareForAnonymousSessionFlow: createAuthMiddlewareForAnonymousSessionFlow$1,
1324
+ createAuthMiddlewareForClientCredentialsFlow: createAuthMiddlewareForClientCredentialsFlow$1,
1325
+ createAuthMiddlewareForExistingTokenFlow: createAuthMiddlewareForExistingTokenFlow$1,
1326
+ createAuthMiddlewareForPasswordFlow: createAuthMiddlewareForPasswordFlow$1,
1327
+ createAuthMiddlewareForRefreshTokenFlow: createAuthMiddlewareForRefreshTokenFlow$1,
1328
+ createConcurrentModificationMiddleware: createConcurrentModificationMiddleware$1,
1329
+ createCorrelationIdMiddleware: createCorrelationIdMiddleware$1,
1330
+ createErrorMiddleware: createErrorMiddleware$1,
1331
+ createHttpMiddleware: createHttpMiddleware$1,
1332
+ createLoggerMiddleware: createLoggerMiddleware$1,
1333
+ createQueueMiddleware: createQueueMiddleware$1,
1334
+ createUserAgentMiddleware: createUserAgentMiddleware$1
1335
+ });
1372
1336
 
1373
- // make request to coco
1374
- const requestWithAuth = await executeRequest(requestOptions);
1375
- if (requestWithAuth) {
1376
- // make the request and inject the token into the header
1377
- return next(requestWithAuth);
1378
- }
1379
- };
1380
- };
1337
+ function compose({
1338
+ middlewares
1339
+ }) {
1340
+ if (middlewares.length === 1) return middlewares[0];
1341
+ const _middlewares = middlewares.slice();
1342
+ return _middlewares.reduce((ac, cv) => (...args) => ac(cv.apply(null, args)));
1381
1343
  }
1382
1344
 
1383
- function createAuthMiddlewareForRefreshTokenFlow$1(options) {
1384
- const tokenCache = options.tokenCache || store({
1385
- token: '',
1386
- tokenCacheKey: null
1345
+ // process batch requests
1346
+ let _options;
1347
+ function process$1(request, fn, processOpt) {
1348
+ validate('process', request, {
1349
+ allowedMethods: ['GET']
1387
1350
  });
1388
- const pendingTasks = [];
1389
- const requestState = store(false);
1390
- return next => {
1391
- return async request => {
1392
- if (request.headers && (request.headers.Authorization || request.headers.authorization)) {
1393
- return next(request);
1394
- }
1351
+ if (typeof fn !== 'function') throw new Error('The "process" function accepts a "Function" as a second argument that returns a Promise. See https://commercetools.github.io/nodejs/sdk/api/sdkClient.html#processrequest-processfn-options');
1395
1352
 
1396
- // prepare request options
1397
- const requestOptions = {
1398
- request,
1399
- requestState,
1400
- tokenCache,
1401
- pendingTasks,
1402
- httpClient: options.httpClient || fetch,
1403
- ...buildRequestForRefreshTokenFlow(options),
1404
- next
1353
+ // Set default process options
1354
+ const opt = {
1355
+ total: Number.POSITIVE_INFINITY,
1356
+ accumulate: true,
1357
+ ...processOpt
1358
+ };
1359
+ return new Promise((resolve, reject) => {
1360
+ let _path,
1361
+ _queryString = '';
1362
+ if (request && request.uri) {
1363
+ const [path, queryString] = request.uri.split('?');
1364
+ _path = path;
1365
+ _queryString = queryString;
1366
+ }
1367
+ const requestQuery = {
1368
+ ...parseURLString(_queryString)
1369
+ };
1370
+ const query = {
1371
+ // defaults
1372
+ limit: 20,
1373
+ // merge given query params
1374
+ ...requestQuery
1375
+ };
1376
+ let itemsToGet = opt.total;
1377
+ let hasFirstPageBeenProcessed = false;
1378
+ const processPage = async (lastId, acc = []) => {
1379
+ // Use the lesser value between limit and itemsToGet in query
1380
+ const limit = query.limit < itemsToGet ? query.limit : itemsToGet;
1381
+ const originalQueryString = stringifyURLString({
1382
+ ...query,
1383
+ limit
1384
+ });
1385
+ const enhancedQuery = {
1386
+ sort: 'id asc',
1387
+ withTotal: false,
1388
+ ...(lastId ? {
1389
+ where: `id > "${lastId}"`
1390
+ } : {})
1405
1391
  };
1406
-
1407
- // make request to coco
1408
- const requestWithAuth = await executeRequest(requestOptions);
1409
- if (requestWithAuth) {
1410
- return next(requestWithAuth);
1392
+ const enhancedQueryString = stringifyURLString(enhancedQuery);
1393
+ const enhancedRequest = {
1394
+ ...request,
1395
+ uri: `${_path}?${enhancedQueryString}&${originalQueryString}`
1396
+ };
1397
+ try {
1398
+ const payload = await createClient(_options).execute(enhancedRequest);
1399
+ const {
1400
+ results,
1401
+ count: resultsLength
1402
+ } = (payload === null || payload === void 0 ? void 0 : payload.body) || {};
1403
+ if (!resultsLength && hasFirstPageBeenProcessed) {
1404
+ return resolve(acc || []);
1405
+ }
1406
+ const result = await Promise.resolve(fn(payload));
1407
+ let accumulated;
1408
+ hasFirstPageBeenProcessed = true;
1409
+ if (opt.accumulate) accumulated = acc.concat(result || []);
1410
+ itemsToGet -= resultsLength;
1411
+ // If there are no more items to get, it means the total number
1412
+ // of items in the original request have been fetched so we
1413
+ // resolve the promise.
1414
+ // Also, if we get less results in a page then the limit set it
1415
+ // means that there are no more pages and that we can finally
1416
+ // resolve the promise.
1417
+ if (resultsLength < query.limit || !itemsToGet) {
1418
+ return resolve(accumulated || []);
1419
+ }
1420
+ const last = results[resultsLength - 1];
1421
+ const newLastId = last && last.id;
1422
+ processPage(newLastId, accumulated);
1423
+ } catch (error) {
1424
+ reject(error);
1411
1425
  }
1412
1426
  };
1413
- };
1414
- }
1415
1427
 
1416
- function createAuthMiddlewareForExistingTokenFlow$1(authorization, options) {
1417
- return next => {
1418
- return async request => {
1419
- if (typeof authorization !== 'string') throw new Error('authorization must be a string');
1420
- const isForce = (options === null || options === void 0 ? void 0 : options.force) === undefined ? true : options.force;
1421
-
1422
- /**
1423
- * The request will not be modified if:
1424
- * 1. no argument is passed
1425
- * 2. force is false and authorization header exists
1426
- */
1427
- if (!authorization || request.headers && (request.headers.Authorization || request.headers.authorization) && isForce === false) {
1428
- return next(request);
1429
- }
1430
- const requestWithAuth = {
1431
- ...request,
1432
- headers: {
1433
- ...request.headers,
1434
- Authorization: authorization
1435
- }
1428
+ // Start iterating through pages
1429
+ processPage();
1430
+ });
1431
+ }
1432
+ function createClient(middlewares) {
1433
+ _options = middlewares;
1434
+ validateClient(middlewares);
1435
+ const resolver = {
1436
+ async resolve(rs) {
1437
+ const {
1438
+ response,
1439
+ includeOriginalRequest,
1440
+ maskSensitiveHeaderData,
1441
+ ...request
1442
+ } = rs;
1443
+ const {
1444
+ retryCount,
1445
+ ...rest
1446
+ } = response;
1447
+ const res = {
1448
+ body: null,
1449
+ error: null,
1450
+ reject: rs.reject,
1451
+ resolve: rs.resolve,
1452
+ ...rest,
1453
+ ...(includeOriginalRequest ? {
1454
+ originalRequest: maskSensitiveHeaderData ? maskAuthData(request) : request
1455
+ } : {}),
1456
+ ...(response !== null && response !== void 0 && response.retryCount ? {
1457
+ retryCount: response.retryCount
1458
+ } : {})
1436
1459
  };
1437
- return next(requestWithAuth);
1438
- };
1460
+ if (res.error) {
1461
+ res.reject(res.error);
1462
+ return res;
1463
+ }
1464
+ res.resolve(res);
1465
+ return res;
1466
+ }
1467
+ };
1468
+ const dispatch = compose(middlewares)(resolver.resolve);
1469
+ return {
1470
+ process: process$1,
1471
+ execute(request) {
1472
+ validate('exec', request);
1473
+ return new Promise((resolve, reject) => {
1474
+ return dispatch({
1475
+ reject,
1476
+ resolve,
1477
+ ...request
1478
+ });
1479
+ });
1480
+ }
1439
1481
  };
1440
1482
  }
1441
1483
 
1442
- var middleware = /*#__PURE__*/Object.freeze({
1443
- __proto__: null,
1444
- createCorrelationIdMiddleware: createCorrelationIdMiddleware$1,
1445
- createHttpMiddleware: createHttpMiddleware$1,
1446
- createQueueMiddleware: createQueueMiddleware$1,
1447
- createLoggerMiddleware: createLoggerMiddleware$1,
1448
- createUserAgentMiddleware: createUserAgentMiddleware$1,
1449
- createConcurrentModificationMiddleware: createConcurrentModificationMiddleware$1,
1450
- createErrorMiddleware: createErrorMiddleware$1,
1451
- createAuthMiddlewareForPasswordFlow: createAuthMiddlewareForPasswordFlow$1,
1452
- createAuthMiddlewareForClientCredentialsFlow: createAuthMiddlewareForClientCredentialsFlow$1,
1453
- createAuthMiddlewareForAnonymousSessionFlow: createAuthMiddlewareForAnonymousSessionFlow$1,
1454
- createAuthMiddlewareForExistingTokenFlow: createAuthMiddlewareForExistingTokenFlow$1,
1455
- createAuthMiddlewareForRefreshTokenFlow: createAuthMiddlewareForRefreshTokenFlow$1
1456
- });
1457
-
1458
1484
  const {
1459
1485
  createAuthMiddlewareForPasswordFlow,
1460
1486
  createAuthMiddlewareForAnonymousSessionFlow,