@middy/util 6.1.5 → 6.2.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 (4) hide show
  1. package/index.d.ts +117 -117
  2. package/index.js +256 -249
  3. package/package.json +67 -71
  4. package/type-utils.d.ts +73 -56
package/index.d.ts CHANGED
@@ -1,147 +1,147 @@
1
- import middy from '@middy/core'
2
- import { Context as LambdaContext } from 'aws-lambda'
1
+ import type middy from "@middy/core";
2
+ import type { Context as LambdaContext } from "aws-lambda";
3
3
  import type {
4
- ArrayValues,
5
- Choose,
6
- DeepAwaited,
7
- IsUnknown,
8
- SanitizeKey,
9
- SanitizeKeys
10
- } from './type-utils.d.ts'
4
+ ArrayValues,
5
+ Choose,
6
+ DeepAwaited,
7
+ IsUnknown,
8
+ SanitizeKey,
9
+ SanitizeKeys,
10
+ } from "./type-utils.d.ts";
11
11
 
12
12
  interface Options<Client, ClientOptions> {
13
- AwsClient?: new (...[config]: [any] | any) => Client
14
- awsClientOptions?: Partial<ClientOptions>
15
- awsClientAssumeRole?: string
16
- awsClientCapture?: (service: Client) => Client
17
- fetchData?: { [key: string]: string }
18
- disablePrefetch?: boolean
19
- cacheKey?: string
20
- cacheExpiry?: number
21
- setToContext?: boolean
13
+ AwsClient?: new (...[config]: [any] | any) => Client;
14
+ awsClientOptions?: Partial<ClientOptions>;
15
+ awsClientAssumeRole?: string;
16
+ awsClientCapture?: (service: Client) => Client;
17
+ fetchData?: { [key: string]: string };
18
+ disablePrefetch?: boolean;
19
+ cacheKey?: string;
20
+ cacheExpiry?: number;
21
+ setToContext?: boolean;
22
22
  }
23
23
 
24
24
  declare class HttpError extends Error {
25
- status: number
26
- statusCode: number
27
- expose: boolean;
28
- [key: string]: any
29
- [key: number]: any
25
+ status: number;
26
+ statusCode: number;
27
+ expose: boolean;
28
+ [key: string]: any;
29
+ [key: number]: any;
30
30
  }
31
31
 
32
- declare function createPrefetchClient<Client, ClientOptions> (
33
- options: Options<Client, ClientOptions>
34
- ): Client
32
+ declare function createPrefetchClient<Client, ClientOptions>(
33
+ options: Options<Client, ClientOptions>,
34
+ ): Client;
35
35
 
36
- declare function createClient<Client, ClientOptions> (
37
- options: Options<Client, ClientOptions>,
38
- request: middy.Request
39
- ): Promise<Client>
36
+ declare function createClient<Client, ClientOptions>(
37
+ options: Options<Client, ClientOptions>,
38
+ request: middy.Request,
39
+ ): Promise<Client>;
40
40
 
41
- declare function canPrefetch<Client, ClientOptions> (
42
- options: Options<Client, ClientOptions>
43
- ): boolean
41
+ declare function canPrefetch<Client, ClientOptions>(
42
+ options: Options<Client, ClientOptions>,
43
+ ): boolean;
44
44
 
45
45
  type InternalOutput<TVariables> = TVariables extends string[]
46
- ? { [key in TVariables[number]]: unknown }
47
- : never
46
+ ? { [key in TVariables[number]]: unknown }
47
+ : never;
48
48
 
49
49
  // get an empty object if false is passed
50
50
  declare function getInternal<
51
- TContext extends LambdaContext,
52
- TInternal extends Record<string, unknown>
53
- > (
54
- variables: false,
55
- request: middy.Request<unknown, unknown, unknown, TContext, TInternal>
56
- ): Promise<{}>
51
+ TContext extends LambdaContext,
52
+ TInternal extends Record<string, unknown>,
53
+ >(
54
+ variables: false,
55
+ request: middy.Request<unknown, unknown, unknown, TContext, TInternal>,
56
+ ): Promise<{}>;
57
57
 
58
58
  // get all internal values if true is passed (with promises resolved)
59
59
  declare function getInternal<
60
- TContext extends LambdaContext,
61
- TInternal extends Record<string, unknown>
62
- > (
63
- variables: true,
64
- request: middy.Request<unknown, unknown, unknown, TContext, TInternal>
65
- ): Promise<DeepAwaited<TInternal>>
60
+ TContext extends LambdaContext,
61
+ TInternal extends Record<string, unknown>,
62
+ >(
63
+ variables: true,
64
+ request: middy.Request<unknown, unknown, unknown, TContext, TInternal>,
65
+ ): Promise<DeepAwaited<TInternal>>;
66
66
 
67
67
  // get a single value
68
68
  declare function getInternal<
69
- TContext extends LambdaContext,
70
- TInternal extends Record<string, unknown>,
71
- TVars extends keyof TInternal | string
72
- > (
73
- variables: TVars,
74
- request: middy.Request<unknown, unknown, unknown, TContext, TInternal>
69
+ TContext extends LambdaContext,
70
+ TInternal extends Record<string, unknown>,
71
+ TVars extends keyof TInternal | string,
72
+ >(
73
+ variables: TVars,
74
+ request: middy.Request<unknown, unknown, unknown, TContext, TInternal>,
75
75
  ): TVars extends keyof TInternal
76
- ? Promise<DeepAwaited<{ [_ in SanitizeKey<TVars>]: TInternal[TVars] }>>
77
- : TVars extends string
78
- ? IsUnknown<Choose<DeepAwaited<TInternal>, TVars>> extends true
79
- ? unknown // could not find the path
80
- : Promise<{
81
- [_ in SanitizeKey<TVars>]: Choose<DeepAwaited<TInternal>, TVars>
82
- }>
83
- : unknown // path is not a string or a keyof TInternal
76
+ ? Promise<DeepAwaited<{ [_ in SanitizeKey<TVars>]: TInternal[TVars] }>>
77
+ : TVars extends string
78
+ ? IsUnknown<Choose<DeepAwaited<TInternal>, TVars>> extends true
79
+ ? unknown // could not find the path
80
+ : Promise<{
81
+ [_ in SanitizeKey<TVars>]: Choose<DeepAwaited<TInternal>, TVars>;
82
+ }>
83
+ : unknown; // path is not a string or a keyof TInternal
84
84
 
85
85
  // get multiple values
86
86
  declare function getInternal<
87
- TContext extends LambdaContext,
88
- TInternal extends Record<string, unknown>,
89
- TVars extends Array<keyof TInternal | string>
90
- > (
91
- variables: TVars,
92
- request: middy.Request<unknown, unknown, unknown, TContext, TInternal>
87
+ TContext extends LambdaContext,
88
+ TInternal extends Record<string, unknown>,
89
+ TVars extends Array<keyof TInternal | string>,
90
+ >(
91
+ variables: TVars,
92
+ request: middy.Request<unknown, unknown, unknown, TContext, TInternal>,
93
93
  ): Promise<
94
- SanitizeKeys<{
95
- [TVar in ArrayValues<TVars>]: TVar extends keyof TInternal
96
- ? DeepAwaited<TInternal[TVar]>
97
- : TVar extends string
98
- ? Choose<DeepAwaited<TInternal>, TVar>
99
- : unknown // path is not a string or a keyof TInternal
100
- }>
101
- >
94
+ SanitizeKeys<{
95
+ [TVar in ArrayValues<TVars>]: TVar extends keyof TInternal
96
+ ? DeepAwaited<TInternal[TVar]>
97
+ : TVar extends string
98
+ ? Choose<DeepAwaited<TInternal>, TVar>
99
+ : unknown; // path is not a string or a keyof TInternal
100
+ }>
101
+ >;
102
102
 
103
103
  // remap object
104
104
  declare function getInternal<
105
- TContext extends LambdaContext,
106
- TInternal extends Record<string, unknown>,
107
- TMap extends Record<string, keyof TInternal | string>
108
- > (
109
- variables: TMap,
110
- request: middy.Request<unknown, unknown, unknown, TContext, TInternal>
105
+ TContext extends LambdaContext,
106
+ TInternal extends Record<string, unknown>,
107
+ TMap extends Record<string, keyof TInternal | string>,
108
+ >(
109
+ variables: TMap,
110
+ request: middy.Request<unknown, unknown, unknown, TContext, TInternal>,
111
111
  ): Promise<{
112
- [P in keyof TMap]: TMap[P] extends keyof TInternal
113
- ? DeepAwaited<TInternal[TMap[P]]>
114
- : TMap[P] extends string
115
- ? Choose<DeepAwaited<TInternal>, TMap[P]>
116
- : unknown // path is not a string or a keyof TInternal
117
- }>
118
-
119
- declare function sanitizeKey<T extends string> (key: T): SanitizeKey<T>
120
-
121
- declare function processCache<Client, ClientOptions> (
122
- options: Options<Client, ClientOptions>,
123
- fetch: (request: middy.Request, cachedValues: any) => any,
124
- request?: middy.Request
125
- ): { value: any, expiry: number }
126
-
127
- declare function getCache (keys: string): any
128
-
129
- declare function clearCache (keys?: string | string[] | null): void
130
-
131
- declare function jsonSafeParse (
132
- string: string,
133
- reviver?: (key: string, value: any) => any
134
- ): any
135
-
136
- declare function normalizeHttpResponse (
137
- request: any,
138
- fallbackResponse?: any
139
- ): any
140
-
141
- declare function createError (
142
- code: number,
143
- message: string,
144
- properties?: Record<string, any>
145
- ): HttpError
146
-
147
- declare function modifyCache (cacheKey: string, value: any): void
112
+ [P in keyof TMap]: TMap[P] extends keyof TInternal
113
+ ? DeepAwaited<TInternal[TMap[P]]>
114
+ : TMap[P] extends string
115
+ ? Choose<DeepAwaited<TInternal>, TMap[P]>
116
+ : unknown; // path is not a string or a keyof TInternal
117
+ }>;
118
+
119
+ declare function sanitizeKey<T extends string>(key: T): SanitizeKey<T>;
120
+
121
+ declare function processCache<Client, ClientOptions>(
122
+ options: Options<Client, ClientOptions>,
123
+ fetch: (request: middy.Request, cachedValues: any) => any,
124
+ request?: middy.Request,
125
+ ): { value: any; expiry: number };
126
+
127
+ declare function getCache(keys: string): any;
128
+
129
+ declare function clearCache(keys?: string | string[] | null): void;
130
+
131
+ declare function jsonSafeParse(
132
+ string: string,
133
+ reviver?: (key: string, value: any) => any,
134
+ ): any;
135
+
136
+ declare function normalizeHttpResponse(
137
+ request: any,
138
+ fallbackResponse?: any,
139
+ ): any;
140
+
141
+ declare function createError(
142
+ code: number,
143
+ message: string,
144
+ properties?: Record<string, any>,
145
+ ): HttpError;
146
+
147
+ declare function modifyCache(cacheKey: string, value: any): void;
package/index.js CHANGED
@@ -1,295 +1,302 @@
1
1
  export const createPrefetchClient = (options) => {
2
- const { awsClientOptions } = options
3
- const client = new options.AwsClient(awsClientOptions)
2
+ const { awsClientOptions } = options;
3
+ const client = new options.AwsClient(awsClientOptions);
4
4
 
5
- // AWS XRay
6
- if (options.awsClientCapture && options.disablePrefetch) {
7
- return options.awsClientCapture(client)
8
- } else if (options.awsClientCapture) {
9
- console.warn('Unable to apply X-Ray outside of handler invocation scope.')
10
- }
5
+ // AWS XRay
6
+ if (options.awsClientCapture) {
7
+ if (options.disablePrefetch) {
8
+ return options.awsClientCapture(client);
9
+ }
10
+ console.warn("Unable to apply X-Ray outside of handler invocation scope.");
11
+ }
11
12
 
12
- return client
13
- }
13
+ return client;
14
+ };
14
15
 
15
16
  export const createClient = async (options, request) => {
16
- let awsClientCredentials = {}
17
+ let awsClientCredentials = {};
17
18
 
18
- // Role Credentials
19
- if (options.awsClientAssumeRole) {
20
- if (!request) {
21
- throw new Error('Request required when assuming role', {
22
- cause: { package: '@middy/util' }
23
- })
24
- }
25
- awsClientCredentials = await getInternal(
26
- { credentials: options.awsClientAssumeRole },
27
- request
28
- )
29
- }
19
+ // Role Credentials
20
+ if (options.awsClientAssumeRole) {
21
+ if (!request) {
22
+ throw new Error("Request required when assuming role", {
23
+ cause: { package: "@middy/util" },
24
+ });
25
+ }
26
+ awsClientCredentials = await getInternal(
27
+ { credentials: options.awsClientAssumeRole },
28
+ request,
29
+ );
30
+ }
30
31
 
31
- awsClientCredentials = {
32
- ...awsClientCredentials,
33
- ...options.awsClientOptions
34
- }
32
+ awsClientCredentials = {
33
+ ...awsClientCredentials,
34
+ ...options.awsClientOptions,
35
+ };
35
36
 
36
- return createPrefetchClient({
37
- ...options,
38
- awsClientOptions: awsClientCredentials
39
- })
40
- }
37
+ return createPrefetchClient({
38
+ ...options,
39
+ awsClientOptions: awsClientCredentials,
40
+ });
41
+ };
41
42
 
42
43
  export const canPrefetch = (options = {}) => {
43
- return !options.awsClientAssumeRole && !options.disablePrefetch
44
- }
44
+ return !options.awsClientAssumeRole && !options.disablePrefetch;
45
+ };
45
46
 
46
47
  // Internal Context
47
48
  export const getInternal = async (variables, request) => {
48
- if (!variables || !request) return {}
49
- let keys = []
50
- let values = []
51
- if (variables === true) {
52
- keys = values = Object.keys(request.internal)
53
- } else if (typeof variables === 'string') {
54
- keys = values = [variables]
55
- } else if (Array.isArray(variables)) {
56
- keys = values = variables
57
- } else if (typeof variables === 'object') {
58
- keys = Object.keys(variables)
59
- values = Object.values(variables)
60
- }
61
- const promises = []
62
- for (const internalKey of values) {
63
- // 'internal.key.sub_value' -> { [key]: internal.key.sub_value }
64
- const pathOptionKey = internalKey.split('.')
65
- const rootOptionKey = pathOptionKey.shift()
66
- let valuePromise = request.internal[rootOptionKey]
67
- if (!isPromise(valuePromise)) {
68
- valuePromise = Promise.resolve(valuePromise)
69
- }
70
- promises.push(
71
- valuePromise.then((value) =>
72
- pathOptionKey.reduce((p, c) => p?.[c], value)
73
- )
74
- )
75
- }
76
- // ensure promise has resolved by the time it's needed
77
- // If one of the promises throws it will bubble up to @middy/core
78
- values = await Promise.allSettled(promises)
79
- const errors = values
80
- .filter((res) => res.status === 'rejected')
81
- .map((res) => res.reason)
82
- if (errors.length) {
83
- throw new Error('Failed to resolve internal values', {
84
- cause: { package: '@middy/util', data: errors }
85
- })
86
- }
87
- return keys.reduce(
88
- (obj, key, index) => ({ ...obj, [sanitizeKey(key)]: values[index].value }),
89
- {}
90
- )
91
- }
49
+ if (!variables || !request) return {};
50
+ let keys = [];
51
+ let values = [];
52
+ if (variables === true) {
53
+ keys = values = Object.keys(request.internal);
54
+ } else if (typeof variables === "string") {
55
+ keys = values = [variables];
56
+ } else if (Array.isArray(variables)) {
57
+ keys = values = variables;
58
+ } else if (typeof variables === "object") {
59
+ keys = Object.keys(variables);
60
+ values = Object.values(variables);
61
+ }
62
+ const promises = [];
63
+ for (const internalKey of values) {
64
+ // 'internal.key.sub_value' -> { [key]: internal.key.sub_value }
65
+ const pathOptionKey = internalKey.split(".");
66
+ const rootOptionKey = pathOptionKey.shift();
67
+ let valuePromise = request.internal[rootOptionKey];
68
+ if (!isPromise(valuePromise)) {
69
+ valuePromise = Promise.resolve(valuePromise);
70
+ }
71
+ promises.push(
72
+ valuePromise.then((value) =>
73
+ pathOptionKey.reduce((p, c) => p?.[c], value),
74
+ ),
75
+ );
76
+ }
77
+ // ensure promise has resolved by the time it's needed
78
+ // If one of the promises throws it will bubble up to @middy/core
79
+ values = await Promise.allSettled(promises);
80
+ const errors = values
81
+ .filter((res) => res.status === "rejected")
82
+ .map((res) => res.reason);
83
+ if (errors.length) {
84
+ throw new Error("Failed to resolve internal values", {
85
+ cause: { package: "@middy/util", data: errors },
86
+ });
87
+ }
88
+ return keys.reduce(
89
+ (obj, key, index) =>
90
+ Object.assign(obj, { [sanitizeKey(key)]: values[index].value }),
91
+ {},
92
+ );
93
+ };
92
94
 
93
- const isPromise = (promise) => typeof promise?.then === 'function'
95
+ const isPromise = (promise) => typeof promise?.then === "function";
94
96
 
95
- const sanitizeKeyPrefixLeadingNumber = /^([0-9])/
96
- const sanitizeKeyRemoveDisallowedChar = /[^a-zA-Z0-9]+/g
97
+ const sanitizeKeyPrefixLeadingNumber = /^([0-9])/;
98
+ const sanitizeKeyRemoveDisallowedChar = /[^a-zA-Z0-9]+/g;
97
99
  export const sanitizeKey = (key) => {
98
- return key
99
- .replace(sanitizeKeyPrefixLeadingNumber, '_$1')
100
- .replace(sanitizeKeyRemoveDisallowedChar, '_')
101
- }
100
+ return key
101
+ .replace(sanitizeKeyPrefixLeadingNumber, "_$1")
102
+ .replace(sanitizeKeyRemoveDisallowedChar, "_");
103
+ };
102
104
 
103
105
  // fetch Cache
104
- const cache = {} // key: { value:{fetchKey:Promise}, expiry }
106
+ const cache = {}; // key: { value:{fetchKey:Promise}, expiry }
105
107
  export const processCache = (
106
- options,
107
- middlewareFetch = () => undefined,
108
- request
108
+ options,
109
+ middlewareFetch = () => undefined,
110
+ request = {},
109
111
  ) => {
110
- let { cacheKey, cacheKeyExpiry, cacheExpiry } = options
111
- cacheExpiry = cacheKeyExpiry?.[cacheKey] ?? cacheExpiry
112
- const now = Date.now()
113
- if (cacheExpiry) {
114
- const cached = getCache(cacheKey)
115
- const unexpired = cached.expiry && (cacheExpiry < 0 || cached.expiry > now)
112
+ let { cacheKey, cacheKeyExpiry, cacheExpiry } = options;
113
+ cacheExpiry = cacheKeyExpiry?.[cacheKey] ?? cacheExpiry;
114
+ const now = Date.now();
115
+ if (cacheExpiry) {
116
+ const cached = getCache(cacheKey);
117
+ const unexpired = cached.expiry && (cacheExpiry < 0 || cached.expiry > now);
116
118
 
117
- if (unexpired) {
118
- if (cached.modified) {
119
- const value = middlewareFetch(request, cached.value)
120
- Object.assign(cached.value, value)
121
- cache[cacheKey] = { value: cached.value, expiry: cached.expiry }
122
- return cache[cacheKey]
123
- }
124
- return { ...cached, cache: true }
125
- }
126
- }
127
- const value = middlewareFetch(request)
128
- // secrets-manager can override to unix timestamp
129
- const expiry = cacheExpiry > 86400000 ? cacheExpiry : now + cacheExpiry
130
- const duration = cacheExpiry > 86400000 ? cacheExpiry - now : cacheExpiry
131
- if (cacheExpiry) {
132
- const refresh =
133
- duration > 0
134
- ? setTimeout(
135
- () => processCache(options, middlewareFetch, request),
136
- duration
137
- )
138
- : undefined
139
- cache[cacheKey] = { value, expiry, refresh }
140
- }
141
- return { value, expiry }
142
- }
119
+ if (unexpired) {
120
+ if (cached.modified) {
121
+ const value = middlewareFetch(request, cached.value);
122
+ Object.assign(cached.value, value);
123
+ cache[cacheKey] = { value: cached.value, expiry: cached.expiry };
124
+ return cache[cacheKey];
125
+ }
126
+ return { ...cached, cache: true };
127
+ }
128
+ }
129
+ const value = middlewareFetch(request);
130
+ // secrets-manager can override to unix timestamp
131
+ const expiry = cacheExpiry > 86400000 ? cacheExpiry : now + cacheExpiry;
132
+ const duration = cacheExpiry > 86400000 ? cacheExpiry - now : cacheExpiry;
133
+ if (cacheExpiry) {
134
+ const refresh =
135
+ duration > 0
136
+ ? setTimeout(
137
+ () => processCache(options, middlewareFetch, request),
138
+ duration,
139
+ )
140
+ : undefined;
141
+ cache[cacheKey] = { value, expiry, refresh };
142
+ }
143
+ return { value, expiry };
144
+ };
143
145
 
144
146
  export const catchInvalidSignatureException = (e, client, command) => {
145
- if (e.__type === 'InvalidSignatureException') {
146
- return client.send(command)
147
- }
148
- throw e
149
- }
147
+ if (e.__type === "InvalidSignatureException") {
148
+ return client.send(command);
149
+ }
150
+ throw e;
151
+ };
150
152
 
151
153
  export const getCache = (key) => {
152
- if (!cache[key]) return {}
153
- return cache[key]
154
- }
154
+ if (!cache[key]) return {};
155
+ return cache[key];
156
+ };
155
157
 
156
158
  // Used to remove parts of a cache
157
159
  export const modifyCache = (cacheKey, value) => {
158
- if (!cache[cacheKey]) return
159
- clearTimeout(cache[cacheKey]?.refresh)
160
- cache[cacheKey] = { ...cache[cacheKey], value, modified: true }
161
- }
160
+ if (!cache[cacheKey]) return;
161
+ clearTimeout(cache[cacheKey]?.refresh);
162
+ cache[cacheKey] = { ...cache[cacheKey], value, modified: true };
163
+ };
162
164
 
163
- export const clearCache = (keys = null) => {
164
- keys = keys ?? Object.keys(cache)
165
- if (!Array.isArray(keys)) keys = [keys]
166
- for (const cacheKey of keys) {
167
- clearTimeout(cache[cacheKey]?.refresh)
168
- cache[cacheKey] = undefined
169
- }
170
- }
165
+ export const clearCache = (inputKeys = null) => {
166
+ let keys = inputKeys;
167
+ keys ??= Object.keys(cache);
168
+ if (!Array.isArray(keys)) {
169
+ keys = [keys];
170
+ }
171
+ for (const cacheKey of keys) {
172
+ clearTimeout(cache[cacheKey]?.refresh);
173
+ cache[cacheKey] = undefined;
174
+ }
175
+ };
171
176
 
172
177
  export const jsonSafeParse = (text, reviver) => {
173
- if (typeof text !== 'string') return text
174
- const firstChar = text[0]
175
- if (firstChar !== '{' && firstChar !== '[' && firstChar !== '"') return text
176
- try {
177
- return JSON.parse(text, reviver)
178
- } catch (e) {}
178
+ if (typeof text !== "string") return text;
179
+ const firstChar = text[0];
180
+ if (firstChar !== "{" && firstChar !== "[" && firstChar !== '"') return text;
181
+ try {
182
+ return JSON.parse(text, reviver);
183
+ } catch (e) {}
179
184
 
180
- return text
181
- }
185
+ return text;
186
+ };
182
187
 
183
188
  export const jsonSafeStringify = (value, replacer, space) => {
184
- try {
185
- return JSON.stringify(value, replacer, space)
186
- } catch (e) {}
189
+ try {
190
+ return JSON.stringify(value, replacer, space);
191
+ } catch (e) {}
187
192
 
188
- return value
189
- }
193
+ return value;
194
+ };
190
195
 
191
196
  export const normalizeHttpResponse = (request) => {
192
- let { response } = request
193
- if (typeof response === 'undefined') {
194
- response = {}
195
- } else if (
196
- typeof response?.statusCode === 'undefined' &&
197
- typeof response?.body === 'undefined' &&
198
- typeof response?.headers === 'undefined'
199
- ) {
200
- response = { statusCode: 200, body: response }
201
- }
202
- response.statusCode ??= 500
203
- response.headers ??= {}
204
- request.response = response
205
- return response
206
- }
197
+ let { response } = request;
198
+ if (typeof response === "undefined") {
199
+ response = {};
200
+ } else if (
201
+ typeof response?.statusCode === "undefined" &&
202
+ typeof response?.body === "undefined" &&
203
+ typeof response?.headers === "undefined"
204
+ ) {
205
+ response = { statusCode: 200, body: response };
206
+ }
207
+ response.statusCode ??= 500;
208
+ response.headers ??= {};
209
+ request.response = response;
210
+ return response;
211
+ };
207
212
 
208
- const createErrorRegexp = /[^a-zA-Z]/g
213
+ const createErrorRegexp = /[^a-zA-Z]/g;
209
214
  export class HttpError extends Error {
210
- constructor (code, message, options = {}) {
211
- if (message && typeof message !== 'string') {
212
- options = message
213
- message = undefined
214
- }
215
- message ??= httpErrorCodes[code]
216
- super(message, options)
215
+ constructor(code, optionalMessage, optionalOptions = {}) {
216
+ let message = optionalMessage;
217
+ let options = optionalOptions;
218
+ if (message && typeof message !== "string") {
219
+ options = message;
220
+ message = undefined;
221
+ }
222
+ message ??= httpErrorCodes[code];
223
+ super(message, options);
217
224
 
218
- const name = httpErrorCodes[code].replace(createErrorRegexp, '')
219
- this.name = name.substr(-5) !== 'Error' ? name + 'Error' : name
225
+ const name = httpErrorCodes[code].replace(createErrorRegexp, "");
226
+ this.name = name.substr(-5) !== "Error" ? `${name}Error` : name;
220
227
 
221
- this.status = this.statusCode = code // setting `status` for backwards compatibility w/ `http-errors`
222
- this.expose = options.expose ?? code < 500
223
- }
228
+ this.status = this.statusCode = code; // setting `status` for backwards compatibility w/ `http-errors`
229
+ this.expose = options.expose ?? code < 500;
230
+ }
224
231
  }
225
232
 
226
233
  export const createError = (code, message, properties = {}) => {
227
- return new HttpError(code, message, properties)
228
- }
234
+ return new HttpError(code, message, properties);
235
+ };
229
236
 
230
237
  const httpErrorCodes = {
231
- 100: 'Continue',
232
- 101: 'Switching Protocols',
233
- 102: 'Processing',
234
- 103: 'Early Hints',
235
- 200: 'OK',
236
- 201: 'Created',
237
- 202: 'Accepted',
238
- 203: 'Non-Authoritative Information',
239
- 204: 'No Content',
240
- 205: 'Reset Content',
241
- 206: 'Partial Content',
242
- 207: 'Multi-Status',
243
- 208: 'Already Reported',
244
- 226: 'IM Used',
245
- 300: 'Multiple Choices',
246
- 301: 'Moved Permanently',
247
- 302: 'Found',
248
- 303: 'See Other',
249
- 304: 'Not Modified',
250
- 305: 'Use Proxy',
251
- 306: '(Unused)',
252
- 307: 'Temporary Redirect',
253
- 308: 'Permanent Redirect',
254
- 400: 'Bad Request',
255
- 401: 'Unauthorized',
256
- 402: 'Payment Required',
257
- 403: 'Forbidden',
258
- 404: 'Not Found',
259
- 405: 'Method Not Allowed',
260
- 406: 'Not Acceptable',
261
- 407: 'Proxy Authentication Required',
262
- 408: 'Request Timeout',
263
- 409: 'Conflict',
264
- 410: 'Gone',
265
- 411: 'Length Required',
266
- 412: 'Precondition Failed',
267
- 413: 'Payload Too Large',
268
- 414: 'URI Too Long',
269
- 415: 'Unsupported Media Type',
270
- 416: 'Range Not Satisfiable',
271
- 417: 'Expectation Failed',
272
- 418: "I'm a teapot",
273
- 421: 'Misdirected Request',
274
- 422: 'Unprocessable Entity',
275
- 423: 'Locked',
276
- 424: 'Failed Dependency',
277
- 425: 'Unordered Collection',
278
- 426: 'Upgrade Required',
279
- 428: 'Precondition Required',
280
- 429: 'Too Many Requests',
281
- 431: 'Request Header Fields Too Large',
282
- 451: 'Unavailable For Legal Reasons',
283
- 500: 'Internal Server Error',
284
- 501: 'Not Implemented',
285
- 502: 'Bad Gateway',
286
- 503: 'Service Unavailable',
287
- 504: 'Gateway Timeout',
288
- 505: 'HTTP Version Not Supported',
289
- 506: 'Variant Also Negotiates',
290
- 507: 'Insufficient Storage',
291
- 508: 'Loop Detected',
292
- 509: 'Bandwidth Limit Exceeded',
293
- 510: 'Not Extended',
294
- 511: 'Network Authentication Required'
295
- }
238
+ 100: "Continue",
239
+ 101: "Switching Protocols",
240
+ 102: "Processing",
241
+ 103: "Early Hints",
242
+ 200: "OK",
243
+ 201: "Created",
244
+ 202: "Accepted",
245
+ 203: "Non-Authoritative Information",
246
+ 204: "No Content",
247
+ 205: "Reset Content",
248
+ 206: "Partial Content",
249
+ 207: "Multi-Status",
250
+ 208: "Already Reported",
251
+ 226: "IM Used",
252
+ 300: "Multiple Choices",
253
+ 301: "Moved Permanently",
254
+ 302: "Found",
255
+ 303: "See Other",
256
+ 304: "Not Modified",
257
+ 305: "Use Proxy",
258
+ 306: "(Unused)",
259
+ 307: "Temporary Redirect",
260
+ 308: "Permanent Redirect",
261
+ 400: "Bad Request",
262
+ 401: "Unauthorized",
263
+ 402: "Payment Required",
264
+ 403: "Forbidden",
265
+ 404: "Not Found",
266
+ 405: "Method Not Allowed",
267
+ 406: "Not Acceptable",
268
+ 407: "Proxy Authentication Required",
269
+ 408: "Request Timeout",
270
+ 409: "Conflict",
271
+ 410: "Gone",
272
+ 411: "Length Required",
273
+ 412: "Precondition Failed",
274
+ 413: "Payload Too Large",
275
+ 414: "URI Too Long",
276
+ 415: "Unsupported Media Type",
277
+ 416: "Range Not Satisfiable",
278
+ 417: "Expectation Failed",
279
+ 418: "I'm a teapot",
280
+ 421: "Misdirected Request",
281
+ 422: "Unprocessable Entity",
282
+ 423: "Locked",
283
+ 424: "Failed Dependency",
284
+ 425: "Unordered Collection",
285
+ 426: "Upgrade Required",
286
+ 428: "Precondition Required",
287
+ 429: "Too Many Requests",
288
+ 431: "Request Header Fields Too Large",
289
+ 451: "Unavailable For Legal Reasons",
290
+ 500: "Internal Server Error",
291
+ 501: "Not Implemented",
292
+ 502: "Bad Gateway",
293
+ 503: "Service Unavailable",
294
+ 504: "Gateway Timeout",
295
+ 505: "HTTP Version Not Supported",
296
+ 506: "Variant Also Negotiates",
297
+ 507: "Insufficient Storage",
298
+ 508: "Loop Detected",
299
+ 509: "Bandwidth Limit Exceeded",
300
+ 510: "Not Extended",
301
+ 511: "Network Authentication Required",
302
+ };
package/package.json CHANGED
@@ -1,73 +1,69 @@
1
1
  {
2
- "name": "@middy/util",
3
- "version": "6.1.5",
4
- "description": "🛵 The stylish Node.js middleware engine for AWS Lambda (util package)",
5
- "type": "module",
6
- "engines": {
7
- "node": ">=20"
8
- },
9
- "engineStrict": true,
10
- "publishConfig": {
11
- "access": "public"
12
- },
13
- "module": "./index.js",
14
- "exports": {
15
- ".": {
16
- "import": {
17
- "types": "./index.d.ts",
18
- "default": "./index.js"
19
- },
20
- "require": {
21
- "default": "./index.js"
22
- }
23
- }
24
- },
25
- "types": "index.d.ts",
26
- "files": [
27
- "index.js",
28
- "index.d.ts",
29
- "type-utils.d.ts"
30
- ],
31
- "scripts": {
32
- "test": "npm run test:unit && npm run test:fuzz",
33
- "test:unit": "node --test __tests__/index.js",
34
- "test:fuzz": "node --test __tests__/fuzz.js",
35
- "test:benchmark": "node __benchmarks__/index.js"
36
- },
37
- "license": "MIT",
38
- "keywords": [
39
- "Lambda",
40
- "Middleware",
41
- "Serverless",
42
- "Framework",
43
- "AWS",
44
- "AWS Lambda",
45
- "helper",
46
- "util"
47
- ],
48
- "author": {
49
- "name": "Middy contributors",
50
- "url": "https://github.com/middyjs/middy/graphs/contributors"
51
- },
52
- "repository": {
53
- "type": "git",
54
- "url": "git+https://github.com/middyjs/middy.git",
55
- "directory": "packages/util"
56
- },
57
- "bugs": {
58
- "url": "https://github.com/middyjs/middy/issues"
59
- },
60
- "devDependencies": {
61
- "@aws-sdk/client-ssm": "^3.0.0",
62
- "@middy/core": "6.1.5",
63
- "@types/aws-lambda": "^8.10.76",
64
- "@types/node": "^20.0.0",
65
- "aws-xray-sdk": "^3.3.3"
66
- },
67
- "homepage": "https://middy.js.org",
68
- "funding": {
69
- "type": "github",
70
- "url": "https://github.com/sponsors/willfarrell"
71
- },
72
- "gitHead": "7a6c0fbb8ab71d6a2171e678697de9f237568431"
2
+ "name": "@middy/util",
3
+ "version": "6.2.0",
4
+ "description": "🛵 The stylish Node.js middleware engine for AWS Lambda (util package)",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=20"
8
+ },
9
+ "engineStrict": true,
10
+ "publishConfig": {
11
+ "access": "public"
12
+ },
13
+ "module": "./index.js",
14
+ "exports": {
15
+ ".": {
16
+ "import": {
17
+ "types": "./index.d.ts",
18
+ "default": "./index.js"
19
+ },
20
+ "require": {
21
+ "default": "./index.js"
22
+ }
23
+ }
24
+ },
25
+ "types": "index.d.ts",
26
+ "files": ["index.js", "index.d.ts", "type-utils.d.ts"],
27
+ "scripts": {
28
+ "test": "npm run test:unit && npm run test:fuzz",
29
+ "test:unit": "node --test",
30
+ "test:fuzz": "node --test index.fuzz.js",
31
+ "test:perf": "node --test index.perf.js"
32
+ },
33
+ "license": "MIT",
34
+ "keywords": [
35
+ "Lambda",
36
+ "Middleware",
37
+ "Serverless",
38
+ "Framework",
39
+ "AWS",
40
+ "AWS Lambda",
41
+ "helper",
42
+ "util"
43
+ ],
44
+ "author": {
45
+ "name": "Middy contributors",
46
+ "url": "https://github.com/middyjs/middy/graphs/contributors"
47
+ },
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "git+https://github.com/middyjs/middy.git",
51
+ "directory": "packages/util"
52
+ },
53
+ "bugs": {
54
+ "url": "https://github.com/middyjs/middy/issues"
55
+ },
56
+ "devDependencies": {
57
+ "@aws-sdk/client-ssm": "^3.0.0",
58
+ "@middy/core": "6.2.0",
59
+ "@types/aws-lambda": "^8.10.76",
60
+ "@types/node": "^20.0.0",
61
+ "aws-xray-sdk": "^3.3.3"
62
+ },
63
+ "homepage": "https://middy.js.org",
64
+ "funding": {
65
+ "type": "github",
66
+ "url": "https://github.com/sponsors/willfarrell"
67
+ },
68
+ "gitHead": "7a6c0fbb8ab71d6a2171e678697de9f237568431"
73
69
  }
package/type-utils.d.ts CHANGED
@@ -1,71 +1,88 @@
1
- type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
2
- type LetterLower = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i'
3
- | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't'
4
- | 'u' | 'v' | 'w' | 'x' | 'y' | 'z'
5
- type LetterUpper = Uppercase<LetterLower>
6
- type AlphaNumeric = Digit | LetterLower | LetterUpper
1
+ type Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
2
+ type LetterLower =
3
+ | "a"
4
+ | "b"
5
+ | "c"
6
+ | "d"
7
+ | "e"
8
+ | "f"
9
+ | "g"
10
+ | "h"
11
+ | "i"
12
+ | "j"
13
+ | "k"
14
+ | "l"
15
+ | "m"
16
+ | "n"
17
+ | "o"
18
+ | "p"
19
+ | "q"
20
+ | "r"
21
+ | "s"
22
+ | "t"
23
+ | "u"
24
+ | "v"
25
+ | "w"
26
+ | "x"
27
+ | "y"
28
+ | "z";
29
+ type LetterUpper = Uppercase<LetterLower>;
30
+ type AlphaNumeric = Digit | LetterLower | LetterUpper;
7
31
 
8
32
  type SanitizeKeyPrefixLeadingNumber<T> =
9
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
10
- T extends `${infer _ extends Digit}${any}`
11
- ? `_${T}`
12
- : T
33
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
34
+ T extends `${infer _ extends Digit}${any}` ? `_${T}` : T;
13
35
 
14
36
  type SanitizeKeyRemoveDisallowedChar<T> =
15
- T extends `${infer First}${infer Rest}`
16
- ? First extends AlphaNumeric
17
- ? `${First}${SanitizeKeyRemoveDisallowedChar<Rest>}`
18
- : `_${SanitizeKeyRemoveDisallowedChar<Rest>}`
19
- : T extends ''
20
- ? T
21
- : never
37
+ T extends `${infer First}${infer Rest}`
38
+ ? First extends AlphaNumeric
39
+ ? `${First}${SanitizeKeyRemoveDisallowedChar<Rest>}`
40
+ : `_${SanitizeKeyRemoveDisallowedChar<Rest>}`
41
+ : T extends ""
42
+ ? T
43
+ : never;
22
44
 
23
- type RemoveAllLeadingUnderscore<T> =
24
- T extends `_${infer Rest}`
25
- ? RemoveAllLeadingUnderscore<Rest>
26
- : T extends string
27
- ? T
28
- : never
45
+ type RemoveAllLeadingUnderscore<T> = T extends `_${infer Rest}`
46
+ ? RemoveAllLeadingUnderscore<Rest>
47
+ : T extends string
48
+ ? T
49
+ : never;
29
50
 
30
- type RemoveRepeatedUnderscore<T> =
31
- T extends `${infer First}_${infer Rest}`
32
- ? `${First}_${RemoveRepeatedUnderscore<RemoveAllLeadingUnderscore<Rest>>}`
33
- : T extends string
34
- ? T
35
- : never
51
+ type RemoveRepeatedUnderscore<T> = T extends `${infer First}_${infer Rest}`
52
+ ? `${First}_${RemoveRepeatedUnderscore<RemoveAllLeadingUnderscore<Rest>>}`
53
+ : T extends string
54
+ ? T
55
+ : never;
36
56
 
37
- export type SanitizeKey<T> =
38
- RemoveRepeatedUnderscore<
39
- SanitizeKeyRemoveDisallowedChar<
40
- SanitizeKeyPrefixLeadingNumber<T>
41
- >
42
- >
57
+ export type SanitizeKey<T> = RemoveRepeatedUnderscore<
58
+ SanitizeKeyRemoveDisallowedChar<SanitizeKeyPrefixLeadingNumber<T>>
59
+ >;
43
60
 
44
61
  export type SanitizeKeys<T extends Record<string, unknown>> = {
45
- [P in keyof T as SanitizeKey<P>]: T[P]
46
- }
62
+ [P in keyof T as SanitizeKey<P>]: T[P];
63
+ };
47
64
 
48
65
  // recursion limit hack from https://www.angularfix.com/2022/01/why-am-i-getting-instantiation-is.html
49
- type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
50
- export type DeepAwaited<T, RecursionDepth extends Prev[number] = 4> =
51
- [RecursionDepth] extends [never]
52
- ? unknown // stop evaluating recursively rather than failing with never
53
- : T extends Promise<infer R>
54
- ? Awaited<R>
55
- : T extends Record<any, any>
56
- ? {
57
- [P in keyof T]:
58
- T[P] extends Promise<infer R>
59
- ? Awaited<R> // if it's a Promise resolve
60
- : DeepAwaited<T[P], Prev[RecursionDepth]>
61
- }
62
- : T
66
+ type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
67
+ export type DeepAwaited<T, RecursionDepth extends Prev[number] = 4> = [
68
+ RecursionDepth,
69
+ ] extends [never]
70
+ ? unknown // stop evaluating recursively rather than failing with never
71
+ : T extends Promise<infer R>
72
+ ? Awaited<R>
73
+ : T extends Record<any, any>
74
+ ? {
75
+ [P in keyof T]: T[P] extends Promise<infer R>
76
+ ? Awaited<R> // if it's a Promise resolve
77
+ : DeepAwaited<T[P], Prev[RecursionDepth]>;
78
+ }
79
+ : T;
63
80
 
64
81
  export type Choose<
65
- T extends Record<string | number, any>,
66
- K extends string
67
- > = K extends `${infer U}.${infer Rest}` ? Choose<T[U], Rest> : T[K]
82
+ T extends Record<string | number, any>,
83
+ K extends string,
84
+ > = K extends `${infer U}.${infer Rest}` ? Choose<T[U], Rest> : T[K];
68
85
 
69
- export type IsUnknown<T> = unknown extends T ? true : false
86
+ export type IsUnknown<T> = unknown extends T ? true : false;
70
87
 
71
- export type ArrayValues<T> = T extends Array<infer U> ? U : never
88
+ export type ArrayValues<T> = T extends Array<infer U> ? U : never;