lambda-essentials-ts 6.1.1 → 7.0.3

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.
@@ -4,7 +4,7 @@ exports.ClientException = void 0;
4
4
  const exception_1 = require("./exception");
5
5
  class ClientException extends exception_1.Exception {
6
6
  constructor(serviceName, originalStatusCode, details, originalMessage, statusCodeMapOverride) {
7
- super(`Dependent service "${serviceName}" returned error: ${originalMessage !== null && originalMessage !== void 0 ? originalMessage : 'Unknown error'}`, ClientException.convertStatusCode(originalStatusCode, statusCodeMapOverride), details);
7
+ super(`Dependent service "${serviceName}" returned error: ${originalMessage ?? 'Unknown error'}`, ClientException.convertStatusCode(originalStatusCode, statusCodeMapOverride), details);
8
8
  this.serviceName = serviceName;
9
9
  this.originalStatusCode = originalStatusCode;
10
10
  }
@@ -27,4 +27,5 @@ ClientException.statusCodeMap = {
27
27
  403: 403,
28
28
  404: 422,
29
29
  422: 422,
30
+ 429: 429,
30
31
  };
@@ -1,6 +1,6 @@
1
- import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
2
- import { IAxiosCacheAdapterOptions } from 'axios-cache-adapter';
1
+ import { AxiosHeaderValue, AxiosInstance, AxiosRequestConfig, AxiosResponse, RawAxiosRequestHeaders } from 'axios';
3
2
  import { RetryConfig } from 'retry-axios';
3
+ import { CacheOptions } from 'axios-cache-interceptor';
4
4
  /**
5
5
  * Allows to specify which http data should be logged.
6
6
  */
@@ -27,7 +27,11 @@ export default class HttpClient {
27
27
  /**
28
28
  * Resolves the token with the token provider and adds it to the headers
29
29
  */
30
- createHeadersWithResolvedToken(headers?: Record<string, string>): Promise<Record<string, string>>;
30
+ createHeadersWithResolvedToken(headers?: RawAxiosRequestHeaders | {
31
+ [key: string]: AxiosHeaderValue;
32
+ } | Record<string, string>): Promise<{
33
+ [p: string]: AxiosHeaderValue;
34
+ }>;
31
35
  /**
32
36
  * Get from the given url. Bearer token is automatically injected if tokenResolverFunction was provided to the constructor.
33
37
  */
@@ -83,10 +87,10 @@ export interface HttpClientOptions {
83
87
  */
84
88
  enableCache?: boolean;
85
89
  /**
86
- * Cache options
87
- * @link https://github.com/RasCarlito/axios-cache-adapter/blob/master/axios-cache-adapter.d.ts#L26
90
+ * Cache options (global defaults for axios-cache-interceptor)
91
+ * @link https://axios-cache-interceptor.js.org/config
88
92
  */
89
- cacheOptions?: IAxiosCacheAdapterOptions;
93
+ cacheOptions?: CacheOptions;
90
94
  /**
91
95
  * Enable automatic retries
92
96
  */
@@ -15,29 +15,37 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
28
38
  Object.defineProperty(exports, "__esModule", { value: true });
29
39
  exports.HttpLogType = void 0;
30
40
  const uuid = __importStar(require("uuid"));
31
- const url_1 = require("url");
32
41
  const axios_1 = __importDefault(require("axios"));
33
- const axios_cache_adapter_1 = require("axios-cache-adapter");
34
42
  const rax = __importStar(require("retry-axios"));
35
43
  const md5_1 = __importDefault(require("md5"));
36
44
  const util_1 = require("../util");
37
45
  const internalException_1 = require("../exceptions/internalException");
38
46
  const clientException_1 = require("../exceptions/clientException");
39
47
  const shared_1 = require("../shared");
40
- const deduplicateRequestAdapter_1 = require("./deduplicateRequestAdapter");
48
+ const axios_cache_interceptor_1 = require("axios-cache-interceptor");
41
49
  const invalidToken = 'Invalid token';
42
50
  /**
43
51
  * Allows to specify which http data should be logged.
@@ -46,55 +54,47 @@ var HttpLogType;
46
54
  (function (HttpLogType) {
47
55
  HttpLogType["requests"] = "requests";
48
56
  HttpLogType["responses"] = "responses";
49
- })(HttpLogType = exports.HttpLogType || (exports.HttpLogType = {}));
57
+ })(HttpLogType || (exports.HttpLogType = HttpLogType = {}));
50
58
  class HttpClient {
51
59
  /**
52
60
  * Create a new Instance of the HttpClient
53
61
  */
54
62
  // eslint-disable-next-line complexity
55
63
  constructor(options) {
56
- var _a, _b, _c, _d, _e;
57
64
  // eslint-disable-next-line no-console
58
- this.logFunction = (_a = options === null || options === void 0 ? void 0 : options.logFunction) !== null && _a !== void 0 ? _a : console.log;
59
- this.logOptions = (_b = options === null || options === void 0 ? void 0 : options.logOptions) !== null && _b !== void 0 ? _b : { enabledLogs: [HttpLogType.requests] };
60
- this.tokenResolverFunction = options === null || options === void 0 ? void 0 : options.tokenResolver;
61
- this.correlationIdResolverFunction = options === null || options === void 0 ? void 0 : options.correlationIdResolver;
62
- this.enableCache = (_c = options === null || options === void 0 ? void 0 : options.enableCache) !== null && _c !== void 0 ? _c : false;
63
- this.enableRetry = (_d = options === null || options === void 0 ? void 0 : options.enableRetry) !== null && _d !== void 0 ? _d : false;
64
- this.timeout = options === null || options === void 0 ? void 0 : options.timeout;
65
- this.clientExceptionStatusCodeMapOverride = options === null || options === void 0 ? void 0 : options.clientExceptionStatusCodeMapOverride;
66
- this.client =
67
- (_e = options === null || options === void 0 ? void 0 : options.client) !== null && _e !== void 0 ? _e : axios_1.default.create({
68
- adapter: (() => {
69
- let adapters = axios_1.default.defaults.adapter;
70
- if (this.enableCache) {
71
- const cache = (0, axios_cache_adapter_1.setupCache)({
72
- maxAge: 5 * 60 * 1000,
73
- readHeaders: false,
74
- readOnError: true,
75
- exclude: {
76
- query: false, // also cache requests with query parameters
77
- },
78
- ...options === null || options === void 0 ? void 0 : options.cacheOptions,
79
- key: (req) => HttpClient.generateCacheKey(req),
80
- });
81
- // debounce concurrent calls with the same cacheKey so that only one HTTP request is made
82
- adapters = (0, deduplicateRequestAdapter_1.createDebounceRequestAdapter)(cache.adapter, HttpClient.generateCacheKey);
83
- }
84
- return adapters;
85
- })(),
65
+ this.logFunction = options?.logFunction ?? console.log;
66
+ this.logOptions = options?.logOptions ?? { enabledLogs: [HttpLogType.requests] };
67
+ this.tokenResolverFunction = options?.tokenResolver;
68
+ this.correlationIdResolverFunction = options?.correlationIdResolver;
69
+ this.enableCache = options?.enableCache ?? false;
70
+ this.enableRetry = options?.enableRetry ?? false;
71
+ this.timeout = options?.timeout;
72
+ this.clientExceptionStatusCodeMapOverride = options?.clientExceptionStatusCodeMapOverride;
73
+ this.client = options?.client ?? axios_1.default.create();
74
+ if (this.enableCache) {
75
+ (0, axios_cache_interceptor_1.setupCache)(this.client, {
76
+ // 5 minutes TTL
77
+ ttl: 5 * 60 * 1000,
78
+ // Respect cache-control headers and have ttl as a fallback https://axios-cache-interceptor.js.org/config/request-specifics#cache-interpretheader
79
+ interpretHeader: true,
80
+ // Serve stale cache on error
81
+ staleIfError: true,
82
+ // Use custom cache key to include auth, url, params and body hash
83
+ generateKey: (req) => HttpClient.generateCacheKey(req),
84
+ // Allow overriding defaults via provided options
85
+ ...options?.cacheOptions,
86
86
  });
87
+ }
87
88
  if (this.enableRetry) {
88
89
  this.client.defaults.raxConfig = {
89
- ...options === null || options === void 0 ? void 0 : options.retryOptions,
90
- instance: this.client,
91
- httpMethodsToRetry: ['GET', 'HEAD', 'OPTIONS', 'DELETE', 'PUT', 'POST'],
90
+ ...options?.retryOptions,
91
+ instance: this.client, // always attach retry-axios to the private axios client
92
+ httpMethodsToRetry: ['GET', 'HEAD', 'OPTIONS', 'DELETE', 'PUT', 'POST'], // extending the defaults to retry POST calls
92
93
  onRetryAttempt: (err) => {
93
- var _a, _b;
94
94
  this.logFunction({
95
95
  title: 'HTTP Response Error Retry',
96
96
  level: 'INFO',
97
- retryAttempt: (_b = (_a = err.config) === null || _a === void 0 ? void 0 : _a.raxConfig) === null || _b === void 0 ? void 0 : _b.currentRetryAttempt,
97
+ retryAttempt: err.config?.raxConfig?.currentRetryAttempt,
98
98
  ...HttpClient.extractRequestLogData(err.config),
99
99
  error: (0, util_1.serializeAxiosError)(err),
100
100
  });
@@ -119,7 +119,6 @@ class HttpClient {
119
119
  }
120
120
  return config;
121
121
  }, (error) => {
122
- var _a;
123
122
  const serializedAxiosError = (0, util_1.serializeAxiosError)(error);
124
123
  this.logFunction({
125
124
  title: 'HTTP Request Error',
@@ -127,10 +126,10 @@ class HttpClient {
127
126
  ...HttpClient.extractRequestLogData(error.config),
128
127
  error: serializedAxiosError,
129
128
  });
130
- const hostname = ((_a = error.config) === null || _a === void 0 ? void 0 : _a.url)
131
- ? new url_1.URL(error.config.url, error.config.baseURL).hostname
129
+ const hostname = error.config?.url
130
+ ? new URL(error.config.url, error.config.baseURL).hostname
132
131
  : 'N/A';
133
- throw new clientException_1.ClientException(hostname, serializedAxiosError === null || serializedAxiosError === void 0 ? void 0 : serializedAxiosError.status, serializedAxiosError === null || serializedAxiosError === void 0 ? void 0 : serializedAxiosError.details, serializedAxiosError === null || serializedAxiosError === void 0 ? void 0 : serializedAxiosError.message, this.clientExceptionStatusCodeMapOverride);
132
+ throw new clientException_1.ClientException(hostname, serializedAxiosError?.status, serializedAxiosError?.details, serializedAxiosError?.message, this.clientExceptionStatusCodeMapOverride);
134
133
  });
135
134
  this.client.interceptors.response.use((response) => {
136
135
  if (this.logOptions.enabledLogs.includes(HttpLogType.responses)) {
@@ -143,7 +142,6 @@ class HttpClient {
143
142
  }
144
143
  return response;
145
144
  }, (error) => {
146
- var _a;
147
145
  // when retries are configured, this middleware gets triggered for each retry
148
146
  // it changes the error object to ClientException and therefore the transformation can be run only once
149
147
  if (error instanceof clientException_1.ClientException) {
@@ -166,14 +164,13 @@ class HttpClient {
166
164
  error: serializedAxiosError,
167
165
  });
168
166
  }
169
- const hostname = ((_a = error.config) === null || _a === void 0 ? void 0 : _a.url)
170
- ? new url_1.URL(error.config.url, error.config.baseURL).hostname
167
+ const hostname = error.config?.url
168
+ ? new URL(error.config.url, error.config.baseURL).hostname
171
169
  : 'N/A';
172
- throw new clientException_1.ClientException(hostname, serializedAxiosError === null || serializedAxiosError === void 0 ? void 0 : serializedAxiosError.status, serializedAxiosError === null || serializedAxiosError === void 0 ? void 0 : serializedAxiosError.details, serializedAxiosError === null || serializedAxiosError === void 0 ? void 0 : serializedAxiosError.message, this.clientExceptionStatusCodeMapOverride);
170
+ throw new clientException_1.ClientException(hostname, serializedAxiosError?.status, serializedAxiosError?.details, serializedAxiosError?.message, this.clientExceptionStatusCodeMapOverride);
173
171
  });
174
172
  }
175
173
  static extractRequestLogData(requestConfig) {
176
- var _a;
177
174
  if (!requestConfig) {
178
175
  return {};
179
176
  }
@@ -182,14 +179,13 @@ class HttpClient {
182
179
  url: requestConfig.url,
183
180
  query: requestConfig.params,
184
181
  request: (0, util_1.safeJsonParse)(requestConfig.data, requestConfig.data),
185
- correlationId: (_a = requestConfig.headers) === null || _a === void 0 ? void 0 : _a[shared_1.orionCorrelationIdRoot],
182
+ correlationId: requestConfig.headers?.[shared_1.orionCorrelationIdRoot],
186
183
  };
187
184
  }
188
185
  // implemented based on https://github.com/RasCarlito/axios-cache-adapter/blob/master/src/cache.js#L77
189
186
  static generateCacheKey(req) {
190
- var _a, _b;
191
- const prefix = ((_a = req.headers) === null || _a === void 0 ? void 0 : _a.Authorization)
192
- ? (_b = (0, util_1.safeJwtCanonicalIdParse)(req.headers.Authorization.replace('Bearer ', ''))) !== null && _b !== void 0 ? _b : uuid.v4()
187
+ const prefix = req.headers?.Authorization
188
+ ? (0, util_1.safeJwtCanonicalIdParse)(req.headers.Authorization.replace('Bearer ', '')) ?? uuid.v4()
193
189
  : 'shared';
194
190
  const url = `${req.baseURL ? req.baseURL : ''}${req.url}`;
195
191
  const query = req.params ? JSON.stringify(req.params) : ''; // possible improvement: optimize cache-hit ratio by sorting the query params
@@ -199,13 +195,13 @@ class HttpClient {
199
195
  /**
200
196
  * Resolves the token with the token provider and adds it to the headers
201
197
  */
202
- async createHeadersWithResolvedToken(headers = {}) {
198
+ async createHeadersWithResolvedToken(headers) {
203
199
  const newHeaders = {};
204
200
  if (this.correlationIdResolverFunction) {
205
201
  newHeaders[shared_1.orionCorrelationIdRoot] = this.correlationIdResolverFunction();
206
202
  }
207
203
  if (this.tokenResolverFunction) {
208
- if (headers.Authorization) {
204
+ if (headers && headers.Authorization) {
209
205
  throw new internalException_1.InternalException('Authorization header already specified, please create a new HttpClient with a different (or without a) tokenResolver');
210
206
  }
211
207
  else {
@@ -0,0 +1,2 @@
1
+ import { createClient } from 'redis';
2
+ export default function createRedisStorage(client: ReturnType<typeof createClient>): import("axios-cache-interceptor").AxiosStorage;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = createRedisStorage;
4
+ const axios_cache_interceptor_1 = require("axios-cache-interceptor");
5
+ const KEY_PREFIX = 'axios-cache-';
6
+ const MIN_TTL = 60000;
7
+ function createRedisStorage(client) {
8
+ // source https://axios-cache-interceptor.js.org/guide/storages#node-redis-storage
9
+ return (0, axios_cache_interceptor_1.buildStorage)({
10
+ async find(key) {
11
+ const result = await client.get(`${KEY_PREFIX}${key}`);
12
+ return result ? JSON.parse(result) : undefined;
13
+ },
14
+ // eslint-disable-next-line complexity
15
+ async set(key, value, req) {
16
+ await client.set(`${KEY_PREFIX}${key}`, JSON.stringify(value), {
17
+ PXAT:
18
+ // We don't want to keep indefinitely values in the storage if
19
+ // their request don't finish somehow. Either set its value as
20
+ // the TTL or 1 minute (MIN_TTL).
21
+ value.state === 'loading'
22
+ ? Date.now() +
23
+ (req?.cache && typeof req.cache.ttl === 'number' ? req.cache.ttl : MIN_TTL)
24
+ : (value.state === 'stale' && value.ttl) ||
25
+ (value.state === 'cached' && !(0, axios_cache_interceptor_1.canStale)(value))
26
+ ? value.createdAt + value.ttl
27
+ : // otherwise, we can't determine when it should expire, so we keep
28
+ // it indefinitely.
29
+ undefined,
30
+ });
31
+ },
32
+ async remove(key) {
33
+ await client.del(`${KEY_PREFIX}${key}`);
34
+ },
35
+ });
36
+ }
package/lib/index.d.ts CHANGED
@@ -15,5 +15,6 @@ import { InvalidDataException } from './exceptions/invalidDataException';
15
15
  import { NotFoundException } from './exceptions/notFoundException';
16
16
  import { ValidationException } from './exceptions/validationException';
17
17
  import { serializeObject, serializeAxiosError } from './util';
18
- export { Logger, OpenApiWrapper, ApiResponse, HttpClient, HttpLogType, KmsTokenProvider, SecretsManagerTokenProvider, ValidationException, NotFoundException, InvalidDataException, InternalException, ForbiddenException, Exception, ConflictException, ClientException, serializeObject, serializeAxiosError, };
18
+ import RedisStorage from './httpClient/redisStorage';
19
+ export { Logger, OpenApiWrapper, ApiResponse, HttpClient, HttpLogType, KmsTokenProvider, SecretsManagerTokenProvider, ValidationException, NotFoundException, InvalidDataException, InternalException, ForbiddenException, Exception, ConflictException, ClientException, serializeObject, serializeAxiosError, RedisStorage, };
19
20
  export type { LoggerConfiguration, SuggestedLogObject, HttpClientOptions, HttpLogOptions, ApiRequest, GetRequest, PostRequest, PutRequest, DeleteRequest, TokenProviderHttpClient, KmsTokenProviderOptions, KmsTokenConfiguration, SecretsManagerTokenProviderOptions, SecretsManagerTokenConfiguration, };
package/lib/index.js CHANGED
@@ -15,18 +15,28 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
28
38
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.serializeAxiosError = exports.serializeObject = exports.ClientException = exports.ConflictException = exports.Exception = exports.ForbiddenException = exports.InternalException = exports.InvalidDataException = exports.NotFoundException = exports.ValidationException = exports.SecretsManagerTokenProvider = exports.KmsTokenProvider = exports.HttpLogType = exports.HttpClient = exports.ApiResponse = exports.OpenApiWrapper = exports.Logger = void 0;
39
+ exports.RedisStorage = exports.serializeAxiosError = exports.serializeObject = exports.ClientException = exports.ConflictException = exports.Exception = exports.ForbiddenException = exports.InternalException = exports.InvalidDataException = exports.NotFoundException = exports.ValidationException = exports.SecretsManagerTokenProvider = exports.KmsTokenProvider = exports.HttpLogType = exports.HttpClient = exports.ApiResponse = exports.OpenApiWrapper = exports.Logger = void 0;
30
40
  const httpClient_1 = __importStar(require("./httpClient/httpClient"));
31
41
  exports.HttpClient = httpClient_1.default;
32
42
  Object.defineProperty(exports, "HttpLogType", { enumerable: true, get: function () { return httpClient_1.HttpLogType; } });
@@ -59,3 +69,5 @@ Object.defineProperty(exports, "ValidationException", { enumerable: true, get: f
59
69
  const util_1 = require("./util");
60
70
  Object.defineProperty(exports, "serializeObject", { enumerable: true, get: function () { return util_1.serializeObject; } });
61
71
  Object.defineProperty(exports, "serializeAxiosError", { enumerable: true, get: function () { return util_1.serializeAxiosError; } });
72
+ const redisStorage_1 = __importDefault(require("./httpClient/redisStorage"));
73
+ exports.RedisStorage = redisStorage_1.default;
@@ -2,11 +2,13 @@ export default class Logger {
2
2
  invocationId: string;
3
3
  private readonly logFunction;
4
4
  private readonly jsonSpace;
5
+ private readonly payloadLimit;
5
6
  private staticData;
6
7
  constructor(configuration?: LoggerConfiguration);
7
8
  /**
8
9
  * Create a new invocation which will end up setting the additional invocation metadata for the request, which will be used when logging.
9
10
  * @param staticData Any static data that are assigned to every log message. Typical might be an environment parameter or version number.
11
+ * @param invocationId
10
12
  */
11
13
  startInvocation(staticData?: any, invocationId?: string): void;
12
14
  log(message: string | SuggestedLogObject): void;
@@ -21,6 +23,13 @@ export interface LoggerConfiguration {
21
23
  * the number of spaces that are used then stringifying the message.
22
24
  */
23
25
  jsonSpace?: number;
26
+ /**
27
+ * the limit of a stringified payload in characters above which the payload will be truncated.
28
+ * 3000 characters are reserved
29
+ * @min 10000
30
+ * @default 32768
31
+ */
32
+ payloadLimit?: number;
24
33
  }
25
34
  export interface SuggestedLogObject {
26
35
  /**
@@ -16,13 +16,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
16
16
  }) : function(o, v) {
17
17
  o["default"] = v;
18
18
  });
19
- var __importStar = (this && this.__importStar) || function (mod) {
20
- if (mod && mod.__esModule) return mod;
21
- var result = {};
22
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
23
- __setModuleDefault(result, mod);
24
- return result;
25
- };
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
26
36
  var __importDefault = (this && this.__importDefault) || function (mod) {
27
37
  return (mod && mod.__esModule) ? mod : { "default": mod };
28
38
  };
@@ -31,20 +41,27 @@ const uuid = __importStar(require("uuid"));
31
41
  const fast_safe_stringify_1 = __importDefault(require("fast-safe-stringify"));
32
42
  const is_error_1 = __importDefault(require("is-error"));
33
43
  const util_1 = require("../util");
44
+ const DEFAULT_PAYLOAD_LIMIT = 32768;
45
+ const MIN_PAYLOAD_LIMIT = 10000;
34
46
  class Logger {
35
47
  constructor(configuration) {
36
- var _a, _b;
37
- this.logFunction = (_a = configuration === null || configuration === void 0 ? void 0 : configuration.logFunction) !== null && _a !== void 0 ? _a : console.log;
38
- this.jsonSpace = (_b = configuration === null || configuration === void 0 ? void 0 : configuration.jsonSpace) !== null && _b !== void 0 ? _b : 2;
48
+ this.logFunction = configuration?.logFunction ?? console.log;
49
+ this.jsonSpace = configuration?.jsonSpace ?? 2;
50
+ this.payloadLimit = !configuration?.payloadLimit
51
+ ? DEFAULT_PAYLOAD_LIMIT
52
+ : configuration?.payloadLimit < MIN_PAYLOAD_LIMIT
53
+ ? MIN_PAYLOAD_LIMIT
54
+ : configuration.payloadLimit;
39
55
  this.invocationId = 'none';
40
56
  }
41
57
  /**
42
58
  * Create a new invocation which will end up setting the additional invocation metadata for the request, which will be used when logging.
43
59
  * @param staticData Any static data that are assigned to every log message. Typical might be an environment parameter or version number.
60
+ * @param invocationId
44
61
  */
45
62
  startInvocation(staticData, invocationId) {
46
63
  this.staticData = staticData;
47
- this.invocationId = invocationId !== null && invocationId !== void 0 ? invocationId : uuid.v4();
64
+ this.invocationId = invocationId ?? uuid.v4();
48
65
  }
49
66
  // eslint-disable-next-line complexity
50
67
  log(message) {
@@ -71,7 +88,7 @@ class Logger {
71
88
  }
72
89
  const payload = {
73
90
  invocationId: this.invocationId,
74
- message: messageAsObject,
91
+ ...messageAsObject,
75
92
  };
76
93
  const truncateToken = (innerPayload) => {
77
94
  return innerPayload.replace(/(eyJ[a-zA-Z0-9_-]{5,}\.eyJ[a-zA-Z0-9_-]{5,})\.[a-zA-Z0-9_-]*/gi, (m, p1) => `${p1}.<sig>`);
@@ -79,15 +96,12 @@ class Logger {
79
96
  const replacer = (key, value) => ((0, is_error_1.default)(value) ? Logger.errorToObject(value) : value);
80
97
  let stringifiedPayload = truncateToken((0, fast_safe_stringify_1.default)(payload, replacer, this.jsonSpace));
81
98
  stringifiedPayload = (0, util_1.redactSecret)(stringifiedPayload);
82
- // https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/cloudwatch_limits_cwl.html 256KB => 32768 characters
83
- if (stringifiedPayload.length >= 32768) {
99
+ if (stringifiedPayload.length >= this.payloadLimit) {
84
100
  const replacementPayload = {
85
101
  invocationId: this.invocationId,
86
- message: {
87
- title: 'Payload too large',
88
- fields: Object.keys(payload),
89
- truncatedPayload: stringifiedPayload.substring(0, 10000),
90
- },
102
+ title: 'Payload too large',
103
+ fields: Object.keys(payload),
104
+ truncatedPayload: stringifiedPayload.substring(0, this.payloadLimit - 3000),
91
105
  };
92
106
  stringifiedPayload = (0, fast_safe_stringify_1.default)(replacementPayload, replacer, this.jsonSpace);
93
107
  }
@@ -23,7 +23,7 @@ export interface OpenApiModel {
23
23
  errorMiddleware: ErrorMiddleware;
24
24
  }, overrideLogger?: () => void): any;
25
25
  }
26
- export declare type ApiControllerRoute<T = ApiRequest> = (path: string, handler: (request: T) => Promise<ApiResponse>) => void;
27
- export declare type RequestMiddleware = (request: ApiRequest) => ApiRequest;
28
- export declare type ResponseMiddleware = (request: ApiRequest, response: ApiResponse) => ApiResponse;
29
- export declare type ErrorMiddleware = (request: ApiRequest, error: Exception | Error) => ApiResponse;
26
+ export type ApiControllerRoute<T = ApiRequest> = (path: string, handler: (request: T) => Promise<ApiResponse>) => void;
27
+ export type RequestMiddleware = (request: ApiRequest) => ApiRequest;
28
+ export type ResponseMiddleware = (request: ApiRequest, response: ApiResponse) => ApiResponse;
29
+ export type ErrorMiddleware = (request: ApiRequest, error: Exception | Error) => ApiResponse;
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
@@ -40,19 +50,18 @@ class OpenApiWrapper {
40
50
  this.userPrincipal = this.notSet;
41
51
  this.requestId = this.notSet;
42
52
  this.correlationId = this.notSet;
43
- if (config === null || config === void 0 ? void 0 : config.enableNewRelicTracking) {
53
+ if (config?.enableNewRelicTracking) {
44
54
  // eslint-disable-next-line global-require
45
55
  this.newrelic = require('newrelic');
46
56
  }
47
57
  // @ts-ignore Later Use the options Type from OpenApiFactory
48
58
  this.api = new openapi_factory_1.default({
49
59
  requestMiddleware: async (request) => {
50
- var _a, _b;
51
60
  const correlationId = this.generateCorrelationId(request.headers);
52
61
  requestLogger.startInvocation(null, correlationId);
53
62
  const userData = this.determineUserData(request.headers, request.requestContext.authorizer);
54
- this.userToken = (_a = userData.userToken) !== null && _a !== void 0 ? _a : this.notSet;
55
- this.userPrincipal = (_b = userData.userPrincipal) !== null && _b !== void 0 ? _b : this.notSet;
63
+ this.userToken = userData.userToken ?? this.notSet;
64
+ this.userPrincipal = userData.userPrincipal ?? this.notSet;
56
65
  this.requestId = request.requestContext.requestId;
57
66
  requestLogger.log({
58
67
  title: 'RequestLogger',
@@ -69,7 +78,7 @@ class OpenApiWrapper {
69
78
  user: this.userPrincipal,
70
79
  query: request.multiValueQueryStringParameters,
71
80
  });
72
- if (config === null || config === void 0 ? void 0 : config.enableNewRelicTracking) {
81
+ if (config?.enableNewRelicTracking) {
73
82
  this.newrelic.addCustomAttributes({
74
83
  canonicalId: this.userPrincipal,
75
84
  correlationId,
@@ -141,19 +150,18 @@ class OpenApiWrapper {
141
150
  }
142
151
  generateCorrelationId(headers) {
143
152
  const existingCorrelationId = headers[shared_1.orionCorrelationIdRoot];
144
- this.correlationId = existingCorrelationId !== null && existingCorrelationId !== void 0 ? existingCorrelationId : uuid.v4();
153
+ this.correlationId = existingCorrelationId ?? uuid.v4();
145
154
  return this.correlationId;
146
155
  }
147
156
  determineUserData(headers, authorizerContext) {
148
- var _a, _b, _c;
149
157
  if (authorizerContext) {
150
158
  return {
151
- userPrincipal: (_a = authorizerContext.canonicalId) !== null && _a !== void 0 ? _a : authorizerContext.principalId,
152
- userToken: (_b = authorizerContext.jwt) !== null && _b !== void 0 ? _b : authorizerContext.accessToken,
159
+ userPrincipal: authorizerContext.canonicalId ?? authorizerContext.principalId,
160
+ userToken: authorizerContext.jwt ?? authorizerContext.accessToken,
153
161
  };
154
162
  }
155
163
  if (headers.Authorization) {
156
- const userToken = (_c = headers.Authorization.split(' ')) === null || _c === void 0 ? void 0 : _c[1];
164
+ const userToken = headers.Authorization.split(' ')?.[1];
157
165
  const userPrincipal = (0, util_1.safeJwtCanonicalIdParse)(userToken);
158
166
  return { userToken, userPrincipal };
159
167
  }
@@ -12,11 +12,12 @@ class KmsTokenProvider extends tokenProvider_1.default {
12
12
  this.kmsConfiguration = options.tokenConfiguration;
13
13
  }
14
14
  async getClientSecret() {
15
- var _a;
16
15
  const data = await this.kmsClient.send(new client_kms_1.DecryptCommand({
17
- CiphertextBlob: Buffer.from(this.kmsConfiguration.encryptedClientSecret, 'base64'),
16
+ CiphertextBlob: new Uint8Array(Buffer.from(this.kmsConfiguration.encryptedClientSecret, 'base64')),
18
17
  }));
19
- const secret = (_a = data.Plaintext) === null || _a === void 0 ? void 0 : _a.toString();
18
+ const secret = data.Plaintext
19
+ ? Buffer.from(data.Plaintext).toString()
20
+ : undefined;
20
21
  if (!secret) {
21
22
  throw new Error('Request error: failed to decrypt secret using KMS');
22
23
  }
@@ -15,7 +15,7 @@ class SecretsManagerTokenProvider extends tokenProvider_1.default {
15
15
  const secret = await this.secretsManagerClient.send(new client_secrets_manager_1.GetSecretValueCommand({
16
16
  SecretId: this.secretsManagerConfiguration.clientSecretId,
17
17
  }));
18
- if (!(secret === null || secret === void 0 ? void 0 : secret.SecretString)) {
18
+ if (!secret?.SecretString) {
19
19
  throw new Error('Request error: failed to retrieve secret from Secrets Manager');
20
20
  }
21
21
  return JSON.parse(secret.SecretString);
@@ -5,27 +5,28 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
7
7
  const httpClient_1 = __importDefault(require("../httpClient/httpClient"));
8
+ const logger_1 = __importDefault(require("../logger/logger"));
8
9
  class TokenProvider {
9
10
  /**
10
11
  * Create a new Instance of the TokenProvider
11
12
  */
12
13
  constructor(options) {
13
- var _a;
14
14
  this.httpClient =
15
- (_a = options.httpClient) !== null && _a !== void 0 ? _a : new httpClient_1.default({
16
- enableCache: false,
17
- enableRetry: true,
18
- retryOptions: {
19
- retry: 3,
20
- },
21
- });
15
+ options.httpClient ??
16
+ new httpClient_1.default({
17
+ logFunction: (msg) => new logger_1.default().log(msg),
18
+ enableCache: false,
19
+ enableRetry: true,
20
+ retryOptions: {
21
+ retry: 3,
22
+ },
23
+ });
22
24
  this.configuration = options.tokenConfiguration;
23
25
  }
24
26
  /**
25
27
  * Get access token. Subsequent calls are cached and the token is renewed only if it is expired.
26
28
  */
27
29
  async getToken() {
28
- var _a;
29
30
  if (!this.currentTokenPromise) {
30
31
  this.currentTokenPromise = this.getTokenWithoutCache();
31
32
  return this.currentTokenPromise;
@@ -33,7 +34,7 @@ class TokenProvider {
33
34
  try {
34
35
  const jwtToken = await this.currentTokenPromise;
35
36
  // lower the token expiry time by 10s so that the returned token will be not immediately expired
36
- if (!jwtToken || ((_a = jsonwebtoken_1.default.decode(jwtToken)) === null || _a === void 0 ? void 0 : _a.exp) < Date.now() / 1000 - 10) {
37
+ if (!jwtToken || jsonwebtoken_1.default.decode(jwtToken)?.exp < Date.now() / 1000 - 10) {
37
38
  this.currentTokenPromise = this.getTokenWithoutCache();
38
39
  }
39
40
  return await this.currentTokenPromise;
@@ -48,7 +49,7 @@ class TokenProvider {
48
49
  */
49
50
  async getTokenWithoutCache() {
50
51
  const secret = await this.getClientSecret();
51
- if (!(secret === null || secret === void 0 ? void 0 : secret.Auth0ClientID) || !secret.Auth0ClientSecret) {
52
+ if (!secret?.Auth0ClientID || !secret.Auth0ClientSecret) {
52
53
  throw new Error('Request error: failed to retrieve Auth0 Client ID/Secret');
53
54
  }
54
55
  const headers = { 'Content-Type': 'application/json' };
package/lib/util.d.ts CHANGED
@@ -3,7 +3,7 @@ export declare function safeJwtCanonicalIdParse(jwtToken: string): string | unde
3
3
  export declare function safeJsonParse(input: any, defaultValue: unknown): unknown;
4
4
  export declare const redactSecret: (data: string) => string;
5
5
  export declare function serializeObject(obj: unknown, redact?: boolean): object;
6
- export declare function serializeAxiosError(error: AxiosError): SerializedAxiosError | undefined;
6
+ export declare function serializeAxiosError(error: AxiosError<any>): SerializedAxiosError | undefined;
7
7
  export interface SerializedAxiosError {
8
8
  status: number;
9
9
  details: any;
package/lib/util.js CHANGED
@@ -3,18 +3,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.serializeAxiosError = exports.serializeObject = exports.redactSecret = exports.safeJsonParse = exports.safeJwtCanonicalIdParse = void 0;
6
+ exports.redactSecret = void 0;
7
+ exports.safeJwtCanonicalIdParse = safeJwtCanonicalIdParse;
8
+ exports.safeJsonParse = safeJsonParse;
9
+ exports.serializeObject = serializeObject;
10
+ exports.serializeAxiosError = serializeAxiosError;
7
11
  const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
8
12
  function safeJwtCanonicalIdParse(jwtToken) {
9
- var _a;
10
13
  try {
11
- return (_a = jsonwebtoken_1.default.decode(jwtToken)) === null || _a === void 0 ? void 0 : _a['https://claims.cimpress.io/canonical_id'];
14
+ return jsonwebtoken_1.default.decode(jwtToken)?.['https://claims.cimpress.io/canonical_id'];
12
15
  }
13
- catch (_b) {
16
+ catch {
14
17
  return undefined;
15
18
  }
16
19
  }
17
- exports.safeJwtCanonicalIdParse = safeJwtCanonicalIdParse;
18
20
  function safeJsonParse(input, defaultValue) {
19
21
  try {
20
22
  return JSON.parse(input);
@@ -23,7 +25,6 @@ function safeJsonParse(input, defaultValue) {
23
25
  return defaultValue;
24
26
  }
25
27
  }
26
- exports.safeJsonParse = safeJsonParse;
27
28
  const redactSecret = (data) => {
28
29
  return data.replace(/(\\*"*'*client_secret\\*"*'*:\s*\\*"*'*)([^"'\\]+)(\\*"*'*)/gi, (m, p1, p2, p3) => `${p1}<REDACTED>${p3}`);
29
30
  };
@@ -32,7 +33,6 @@ function serializeObject(obj, redact) {
32
33
  let modObj = obj;
33
34
  if (obj && typeof obj === 'object') {
34
35
  modObj = Object.getOwnPropertyNames(obj).reduce((map, key) => {
35
- // eslint-disable-next-line no-param-reassign
36
36
  map[key] = obj[key];
37
37
  return map;
38
38
  }, {});
@@ -41,9 +41,7 @@ function serializeObject(obj, redact) {
41
41
  ? JSON.parse((0, exports.redactSecret)(JSON.stringify(modObj)))
42
42
  : JSON.parse(JSON.stringify(modObj));
43
43
  }
44
- exports.serializeObject = serializeObject;
45
44
  function serializeAxiosError(error) {
46
- var _a;
47
45
  if (!error.response) {
48
46
  return {
49
47
  status: 500,
@@ -52,9 +50,8 @@ function serializeAxiosError(error) {
52
50
  }
53
51
  const { status, data } = error.response;
54
52
  return {
55
- status: (_a = data.originalStatusCode) !== null && _a !== void 0 ? _a : status,
56
- details: data.details && Object.keys(data.details).length > 0 ? data.details : data,
53
+ status: data.originalStatusCode ?? status, // Propagate original status code of ClientException
54
+ details: data.details && Object.keys(data.details).length > 0 ? data.details : data, // Prevent wrapping of Exception
57
55
  message: data.message,
58
56
  };
59
57
  }
60
- exports.serializeAxiosError = serializeAxiosError;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lambda-essentials-ts",
3
- "version": "6.1.1",
3
+ "version": "7.0.3",
4
4
  "description": "A selection of the finest modules supporting authorization, API routing, error handling, logging and sending HTTP requests.",
5
5
  "main": "lib/index.js",
6
6
  "private": false,
@@ -26,30 +26,33 @@
26
26
  },
27
27
  "homepage": "https://github.com/Cimpress-MCP/lambda-essentials-ts#readme",
28
28
  "dependencies": {
29
- "@aws-sdk/client-kms": "^3.569.0",
30
- "@aws-sdk/client-secrets-manager": "^3.569.0",
31
- "axios": "~0.21.3",
32
- "axios-cache-adapter": "~2.7.3",
33
- "fast-safe-stringify": "~2.0.7",
29
+ "@aws-sdk/client-kms": "^3.930.0",
30
+ "@aws-sdk/client-secrets-manager": "^3.930.0",
31
+ "@types/node": "^24.10.1",
32
+ "axios": "1.13.2",
33
+ "axios-cache-interceptor": "^1.8.3",
34
+ "fast-safe-stringify": "~2.1.1",
34
35
  "is-error": "~2.2.2",
35
- "jsonwebtoken": "9.0.0",
36
+ "jsonwebtoken": "9.0.2",
36
37
  "md5": "~2.3.0",
37
38
  "openapi-factory": "5.4.60",
38
- "retry-axios": "~2.6.0",
39
- "uuid": "~8.3.2"
39
+ "retry-axios": "~3.2.1",
40
+ "uuid": "~11.1.0"
40
41
  },
41
42
  "devDependencies": {
42
- "@types/jest": "^26.0.20",
43
- "@types/newrelic": "^9.14.0",
44
- "eslint": "^7.18.0",
45
- "eslint-config-cimpress-atsquad": "^2.1.2",
46
- "husky": "^4.2.5",
47
- "jest": "^26.2.2",
48
- "lint-staged": "^10.2.13",
49
- "prettier": "^2.7.1",
50
- "ts-jest": "^26.1.4",
51
- "ts-node": "^10.9.1",
52
- "typescript": "^4.8.2"
43
+ "@types/jest": "^29.5.14",
44
+ "@types/newrelic": "^9.14.8",
45
+ "redis": "^5.9.0",
46
+ "axios-mock-adapter": "^2.1.0",
47
+ "eslint": "^8.57.1",
48
+ "eslint-config-cimpress-atsquad": "^2.2.0-beta",
49
+ "husky": "^9.1.7",
50
+ "jest": "^29.7.0",
51
+ "lint-staged": "^15.5.2",
52
+ "prettier": "^2.8.8",
53
+ "ts-jest": "^29.4.5",
54
+ "ts-node": "^10.9.2",
55
+ "typescript": "^5.9.3"
53
56
  },
54
57
  "eslintConfig": {
55
58
  "extends": "cimpress-atsquad"
@@ -74,9 +77,9 @@
74
77
  "collectCoverage": false
75
78
  },
76
79
  "engines": {
77
- "node": ">=14.0.0"
80
+ "node": ">=20.0.0"
78
81
  },
79
82
  "peerDependencies": {
80
- "newrelic": "^10.2.0"
83
+ "newrelic": "^12.0.0"
81
84
  }
82
85
  }
package/CHANGELOG.md DELETED
@@ -1,271 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
6
-
7
- ## [6.1.1] - 2025-10-27
8
-
9
- ### Changed
10
-
11
- - TokenProviderHttpClient now uses the http client with retries as default.
12
-
13
- ## [6.1.0] - 2024-09-30
14
-
15
- ### Changed
16
-
17
- - Preserve the original message in ClientException
18
-
19
- ## [6.0.0] - 2024-02-22
20
-
21
- ### Changed
22
-
23
- - **[Breaking change]** Upgraded aws-sdk to v3 which has `SecretsManager` and `KMS` replaced by `SecretsManagerClient` and `KMSClient` class.
24
- The functionality and interface remains the same, the imports need to be changed.
25
-
26
- ## [5.4.0] - 2024-02-08
27
-
28
- ### Added
29
-
30
- HttpClient options now accept `clientExceptionStatusCodeMapOverride` which can be used to override the default HTTP error status code mapping. This is useful e.g. when a dependent service is not following REST-ful best practices and e.g. returns a 403 when there's an intermittent network error communicating with the authorization service
31
-
32
- ## [5.3.2] - 2024-02-08
33
-
34
- ### Fixed
35
-
36
- Error details of external HTTP error responses are propagated correctly
37
-
38
- ## [5.3.1] - 2023-10-25
39
-
40
- ### Fixed
41
-
42
- The `getUserToken()` and `getUserPrincipal()` order was wrongly set in version `5.3.0`. The new fixed
43
- priority order:
44
-
45
- `getUserToken()`
46
-
47
- 1. `request.authorizerContext.jwt`
48
- 2. `request.authorizerContext.accessToken` (new)
49
- 3. `request.headers.Authorization`
50
-
51
- `getUserPrincipal()`
52
-
53
- 1. `authorizerContext.canonicalId` (**prefer canonicalId**)
54
- 2. `authorizerContext.principalId` (new)
55
- 3. `request.headers.Authorization`
56
-
57
- ## [5.3.0] - 2023-09-07
58
-
59
- ### Changed
60
-
61
- The `getUserToken()` and `getUserPrincipal()` methods now support multiple sources of for their values
62
-
63
- `getUserToken()` in priority order:
64
-
65
- 1. `request.authorizerContext.accessToken` (new)
66
- 2. `request.authorizerContext.jwt`
67
- 3. `request.headers.Authorization`
68
-
69
- `getUserPrincipal()` in priority order:
70
-
71
- 1. `authorizerContext.principalId` (new)
72
- 2. `authorizerContext.canonicalId`
73
- 3. `request.headers.Authorization`
74
-
75
- ## [5.2.2] - 2023-08-25
76
-
77
- ### Added
78
-
79
- HttpClient now also logs unexpected (e.g. network) errors that are not coming from Axios
80
-
81
- ## [5.2.0] - 2023-06-08
82
-
83
- ### Added
84
-
85
- Tracking of `canonicalId` and `correlationId` in New Relic.
86
-
87
- !IMPORTANT! You must exclude the `newrelic` module from `webpack.config.ts` like so:
88
-
89
- ```
90
- externals: ['newrelic']
91
- ```
92
-
93
- ### Added
94
-
95
- The `DeleteRequest` model.
96
-
97
- ## [5.1.10] - 2023-01-13
98
-
99
- ### Changed
100
-
101
- The error middleware logs `4xx` errors with log level `WARN` (previously `INFO`).
102
-
103
- ## [5.1.9] - 2023-01-04
104
-
105
- ### Changed
106
-
107
- Upgraded jsonwebtoken version to 9.0.0 and aws-sdk to version 2.1287.0
108
-
109
- ## [5.1.8] - 2022-12-15
110
-
111
- ### Changed
112
-
113
- Removed client_secret from API response
114
-
115
- ## [5.1.7] - 2022-12-13
116
-
117
- ### Changed
118
-
119
- Add timeout option in HttpClient. If no value is provided the default is no timeout.
120
-
121
- ## [5.1.6] - 2022-11-30
122
-
123
- ### Changed
124
-
125
- Removed logging of client_secret
126
-
127
- ## [5.1.5] - 2022-11-15
128
-
129
- ### Changed
130
-
131
- The fix described in 5.1.4 missed one instance where the bug can occur. This change covers all known instances.
132
-
133
- ## [5.1.4] - 2022-11-08
134
-
135
- ### Changed
136
-
137
- Using `baseURL` in the axios config without specifying the full URL resulted in an error in the exception handling. So the `AxiosError` was thrown instead of a customer `ClientException`.
138
-
139
- ## [5.1.3] - 2022-10-03
140
-
141
- ### Changed
142
-
143
- RequestLogger now logs only `Host`, 'User-Agent`, `orion-correlation-id-parent`, `orion-correlation-id-root` headers.
144
-
145
- ## [5.1.2] - 2022-09-14
146
-
147
- ### Changed
148
-
149
- Properties `stageVariables`, `isBase64Encoded` and `route` from openapi-factory are available in the Typescript definitions.
150
-
151
- ## [5.1.1] - 2022-09-05
152
-
153
- ### Changed
154
-
155
- HttpApi payload version 2.0 events supported for openApiWrapper.
156
-
157
- ## [5.1.0] - 2022-09-05
158
-
159
- ### Changed
160
-
161
- Dependencies aren't pinned to a fixed version to allow users of the library to independently upgrade minor (devDependencies) and patch (dependencies) versions. This will simplify fixing security alerts faster than in this library, for example by applying `npm audit fix`.
162
-
163
- ## [5.0.0] - 2022-02-22
164
-
165
- ### Changed
166
-
167
- - **[Breaking change]** `TokenProvider` was replaced by more specific `KmsTokenProvider` class.
168
- The functionality and interface remains the same, the imports need to be changed.
169
-
170
- ### Added
171
-
172
- - New `SecretsManagerTokenProvider` that relies on AWS Secrets Manager to retrieve client ID and client secret.
173
- The advantage of using AWS Secrets Manager is that it can be supplied with a secret rotation function.
174
-
175
- ## [4.1.5] - 2022-02-10
176
-
177
- ### Changed
178
-
179
- `ClientException` now maps `HTTP 422` client responses to `HTTP 422` server responses (was `HTTP 503` before).
180
-
181
- ## [4.1.2] - 2021-12-02
182
-
183
- ### Changed
184
-
185
- Expose the `Location`, `Access-Control-Allow-Origin` and `orion-correlation-id-root` headers
186
-
187
- ## [4.1.1] - 2021-11-22
188
-
189
- ### Fixed
190
-
191
- - `ApiResponse` default content-type header was renamed to `Content-Type` to overwrite the default header
192
- of [openapi-factory.js](https://github.com/Rhosys/openapi-factory.js/blob/release/5.2/src/response.js#L15)
193
- - Also upgraded `openapi-factory.js` to get support of over-writing response headers
194
-
195
- ## [4.1.0] - 2021-11-22
196
-
197
- ### Changed
198
-
199
- - `ApiResponse` default content-type header was changed from `application/links+json` to `application/hal+json`
200
-
201
- ## [4.0.0] - 2021-11-12
202
-
203
- ### Changed
204
-
205
- - `HttpClient` the [retryAdapterEnhancer axios adapter](https://github.com/kuitos/axios-extensions#cacheadapterenhancer)
206
- was replaced by the more flexible [axios-cache-adapter](https://github.com/RasCarlito/axios-cache-adapter).
207
- - **[Breaking change]** `HttpClientOptions.cacheOptions` now accepts [extensive cache configuration](https://github.com/RasCarlito/axios-cache-adapter/blob/master/axios-cache-adapter.d.ts#L26).
208
- - The cache is now partitioned by `canonical_id` JWT claim.
209
-
210
- ## [3.0.1] - 2021-09-13
211
-
212
- ### Fixed
213
-
214
- - Downgraded Axios to 0.21.1 due to response interceptors not being applied correctly in 0.21.2. [There has been a fix to
215
- axios but a version with the fix is not available yet.](https://github.com/axios/axios/commit/83ae3830e4070adbcdcdcdd6e8afbac568afd708)
216
-
217
- ## [3.0.0] - 2021-09-10
218
-
219
- ### Changed
220
-
221
- - `HttpClient` the [retryAdapterEnhancer axios adapter](https://github.com/kuitos/axios-extensions#retryadapterenhancer)
222
- was replaced by the more flexible [retry-axios interceptor](https://github.com/JustinBeckwith/retry-axios).
223
- - **[Breaking change]** `HttpClientOptions.retryOptions` now accepts [extensive retry configuration](https://github.com/JustinBeckwith/retry-axios/blob/v2.6.0/src/index.ts#L11)
224
- such as specifying HTTP status codes that should be retried.
225
- - **[Breaking change]** All HTTP status codes are no longer retried by default. The new default are these ranges:
226
- - [100, 199] Informational, request still processing
227
- - [429, 429] Too Many Requests
228
- - [500, 599] Server errors
229
-
230
- ## [2.2.2] - 2021-07-08
231
-
232
- ### Fixed bugs
233
-
234
- - Some HTTP error log statements were throwing exceptions. This was due to accessing `error.request.headers[orionCorrelationIdRoot]`
235
- from Axios error object, where the `headers` object was `undefined`. The correct field was `error.config.headers`.
236
-
237
- ## [2.2.1] - 2021-07-08
238
-
239
- ### Changed
240
-
241
- - `HttpClient` logs additional request data (query parameters, body).
242
-
243
- ### Added
244
-
245
- - `HttpClientOptions` now accepts `logOptions` object that allows enabling informational request and **response (new)** logs.
246
-
247
- ```js
248
- {
249
- logOptions: {
250
- enabledLogs: [HttpLogType.requests, HttpLogType.responses];
251
- }
252
- }
253
- ```
254
-
255
- ## [2.1.0] - 2021-03-11
256
-
257
- ### Changed
258
-
259
- - ClientException propagates the original status code and details through multiple services. E.g. instead of `error.detials?.data.details?.userDefinedProp` use `error.details?.userDefinedProp`
260
-
261
- ## [2.0.0] - 2021-03-08
262
-
263
- ### Changed
264
-
265
- - ClientException no longer wraps details in an `error` property. Instead of `error.details?.error.userDefinedProp` use `error.details?.userDefinedProp`
266
-
267
- ## [1.2.0] - 2021-02-16
268
-
269
- ### Updated
270
-
271
- - [IMPORTANT!] HttpClient throws serialized Axios errors through ClientExceptions.
@@ -1,2 +0,0 @@
1
- import { AxiosAdapter } from 'axios';
2
- export declare function createDebounceRequestAdapter(requestAdapter: AxiosAdapter, requestKeyProvider: (AxiosRequestConfig: any) => string): AxiosAdapter;
@@ -1,20 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createDebounceRequestAdapter = void 0;
4
- // adopted from https://github.com/RasCarlito/axios-cache-adapter/issues/231#issuecomment-880288436
5
- function createDebounceRequestAdapter(requestAdapter, requestKeyProvider) {
6
- const runningRequests = {};
7
- return (req) => {
8
- const cacheKey = requestKeyProvider(req);
9
- // Add the request to runningRequests. If it is already there, drop the duplicated request.
10
- if (!runningRequests[cacheKey]) {
11
- runningRequests[cacheKey] = requestAdapter(req);
12
- }
13
- // Return the response promise
14
- return runningRequests[cacheKey].finally(() => {
15
- // Finally, delete the request from the runningRequests whether there's error or not
16
- delete runningRequests[cacheKey];
17
- });
18
- };
19
- }
20
- exports.createDebounceRequestAdapter = createDebounceRequestAdapter;