@middy/util 3.0.0-alpha.3 → 3.0.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +146 -169
- package/package.json +3 -3
package/index.js
CHANGED
|
@@ -1,247 +1,224 @@
|
|
|
1
|
-
import { Agent } from 'https'
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import statuses from './codes.js'
|
|
5
|
-
import { inherits } from 'util'
|
|
6
|
-
// import { NodeHttpHandler } from '@aws-sdk/node-http-handler' // aws-sdk v3
|
|
7
|
-
|
|
1
|
+
import { Agent } from 'https';
|
|
2
|
+
import statuses from './codes.js';
|
|
3
|
+
import { inherits } from 'util';
|
|
8
4
|
export const awsClientDefaultOptions = {
|
|
9
|
-
// AWS SDK v3
|
|
10
|
-
// Docs: https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/enforcing-tls.html
|
|
11
|
-
/* requestHandler: new NodeHttpHandler({
|
|
12
|
-
httpsAgent: new Agent(
|
|
13
|
-
{
|
|
14
|
-
secureProtocol: 'TLSv1_2_method'
|
|
15
|
-
}
|
|
16
|
-
)
|
|
17
|
-
}) */
|
|
18
|
-
// Docs: https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/enforcing-tls.html
|
|
19
5
|
httpOptions: {
|
|
20
6
|
agent: new Agent({
|
|
21
7
|
secureProtocol: 'TLSv1_2_method'
|
|
22
8
|
})
|
|
23
9
|
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const awsClientOptions = {
|
|
28
|
-
...awsClientDefaultOptions,
|
|
10
|
+
};
|
|
11
|
+
export const createPrefetchClient = options => {
|
|
12
|
+
const awsClientOptions = { ...awsClientDefaultOptions,
|
|
29
13
|
...options.awsClientOptions
|
|
30
|
-
}
|
|
31
|
-
const client = new options.AwsClient(awsClientOptions)
|
|
14
|
+
};
|
|
15
|
+
const client = new options.AwsClient(awsClientOptions);
|
|
32
16
|
|
|
33
|
-
// AWS XRay
|
|
34
17
|
if (options.awsClientCapture && options.disablePrefetch) {
|
|
35
|
-
return options.awsClientCapture(client)
|
|
18
|
+
return options.awsClientCapture(client);
|
|
36
19
|
} else if (options.awsClientCapture) {
|
|
37
|
-
console.warn('Unable to apply X-Ray outside of handler invocation scope.')
|
|
20
|
+
console.warn('Unable to apply X-Ray outside of handler invocation scope.');
|
|
38
21
|
}
|
|
39
22
|
|
|
40
|
-
return client
|
|
41
|
-
}
|
|
42
|
-
|
|
23
|
+
return client;
|
|
24
|
+
};
|
|
43
25
|
export const createClient = async (options, request) => {
|
|
44
|
-
let awsClientCredentials = {}
|
|
26
|
+
let awsClientCredentials = {};
|
|
45
27
|
|
|
46
|
-
// Role Credentials
|
|
47
28
|
if (options.awsClientAssumeRole) {
|
|
48
|
-
if (!request) throw new Error('Request required when assuming role')
|
|
49
|
-
awsClientCredentials = await getInternal(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
)
|
|
29
|
+
if (!request) throw new Error('Request required when assuming role');
|
|
30
|
+
awsClientCredentials = await getInternal({
|
|
31
|
+
credentials: options.awsClientAssumeRole
|
|
32
|
+
}, request);
|
|
53
33
|
}
|
|
54
34
|
|
|
55
|
-
awsClientCredentials = {
|
|
56
|
-
...awsClientCredentials,
|
|
35
|
+
awsClientCredentials = { ...awsClientCredentials,
|
|
57
36
|
...options.awsClientOptions
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return createPrefetchClient({
|
|
61
|
-
...options,
|
|
37
|
+
};
|
|
38
|
+
return createPrefetchClient({ ...options,
|
|
62
39
|
awsClientOptions: awsClientCredentials
|
|
63
|
-
})
|
|
64
|
-
}
|
|
65
|
-
|
|
40
|
+
});
|
|
41
|
+
};
|
|
66
42
|
export const canPrefetch = (options = {}) => {
|
|
67
|
-
return !options.awsClientAssumeRole && !options.disablePrefetch
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Internal Context
|
|
43
|
+
return !options.awsClientAssumeRole && !options.disablePrefetch;
|
|
44
|
+
};
|
|
71
45
|
export const getInternal = async (variables, request) => {
|
|
72
|
-
if (!variables || !request) return {}
|
|
73
|
-
let keys = []
|
|
74
|
-
let values = []
|
|
46
|
+
if (!variables || !request) return {};
|
|
47
|
+
let keys = [];
|
|
48
|
+
let values = [];
|
|
49
|
+
|
|
75
50
|
if (variables === true) {
|
|
76
|
-
keys = values = Object.keys(request.internal)
|
|
51
|
+
keys = values = Object.keys(request.internal);
|
|
77
52
|
} else if (typeof variables === 'string') {
|
|
78
|
-
keys = values = [variables]
|
|
53
|
+
keys = values = [variables];
|
|
79
54
|
} else if (Array.isArray(variables)) {
|
|
80
|
-
keys = values = variables
|
|
55
|
+
keys = values = variables;
|
|
81
56
|
} else if (typeof variables === 'object') {
|
|
82
|
-
keys = Object.keys(variables)
|
|
83
|
-
values = Object.values(variables)
|
|
57
|
+
keys = Object.keys(variables);
|
|
58
|
+
values = Object.values(variables);
|
|
84
59
|
}
|
|
85
|
-
|
|
60
|
+
|
|
61
|
+
const promises = [];
|
|
62
|
+
|
|
86
63
|
for (const internalKey of values) {
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
64
|
+
const pathOptionKey = internalKey.split('.');
|
|
65
|
+
const rootOptionKey = pathOptionKey.shift();
|
|
66
|
+
let valuePromise = request.internal[rootOptionKey];
|
|
67
|
+
|
|
91
68
|
if (typeof valuePromise.then !== 'function') {
|
|
92
|
-
valuePromise = Promise.resolve(valuePromise)
|
|
69
|
+
valuePromise = Promise.resolve(valuePromise);
|
|
93
70
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
pathOptionKey.reduce((p, c) => p?.[c], value)
|
|
97
|
-
)
|
|
98
|
-
)
|
|
71
|
+
|
|
72
|
+
promises.push(valuePromise.then(value => pathOptionKey.reduce((p, c) => p === null || p === void 0 ? void 0 : p[c], value)));
|
|
99
73
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
.filter((res) => res.status === 'rejected')
|
|
105
|
-
.map((res) => res.reason)
|
|
74
|
+
|
|
75
|
+
values = await Promise.allSettled(promises);
|
|
76
|
+
const errors = values.filter(res => res.status === 'rejected').map(res => res.reason);
|
|
77
|
+
|
|
106
78
|
if (errors.length) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
error
|
|
110
|
-
throw error
|
|
79
|
+
const error = new Error('Failed to resolve internal values');
|
|
80
|
+
error.cause = errors;
|
|
81
|
+
throw error;
|
|
111
82
|
}
|
|
112
|
-
return keys.reduce(
|
|
113
|
-
(obj, key, index) => ({ ...obj, [sanitizeKey(key)]: values[index].value }),
|
|
114
|
-
{}
|
|
115
|
-
)
|
|
116
|
-
}
|
|
117
|
-
const sanitizeKeyPrefixLeadingNumber = /^([0-9])/
|
|
118
|
-
const sanitizeKeyRemoveDisallowedChar = /[^a-zA-Z0-9]+/g
|
|
119
|
-
export const sanitizeKey = (key) => {
|
|
120
|
-
return key
|
|
121
|
-
.replace(sanitizeKeyPrefixLeadingNumber, '_$1')
|
|
122
|
-
.replace(sanitizeKeyRemoveDisallowedChar, '_')
|
|
123
|
-
}
|
|
124
83
|
|
|
125
|
-
|
|
126
|
-
|
|
84
|
+
return keys.reduce((obj, key, index) => ({ ...obj,
|
|
85
|
+
[sanitizeKey(key)]: values[index].value
|
|
86
|
+
}), {});
|
|
87
|
+
};
|
|
88
|
+
const sanitizeKeyPrefixLeadingNumber = /^([0-9])/;
|
|
89
|
+
const sanitizeKeyRemoveDisallowedChar = /[^a-zA-Z0-9]+/g;
|
|
90
|
+
export const sanitizeKey = key => {
|
|
91
|
+
return key.replace(sanitizeKeyPrefixLeadingNumber, '_$1').replace(sanitizeKeyRemoveDisallowedChar, '_');
|
|
92
|
+
};
|
|
93
|
+
const cache = {};
|
|
127
94
|
export const processCache = (options, fetch = () => undefined, request) => {
|
|
128
|
-
const {
|
|
95
|
+
const {
|
|
96
|
+
cacheExpiry,
|
|
97
|
+
cacheKey
|
|
98
|
+
} = options;
|
|
99
|
+
|
|
129
100
|
if (cacheExpiry) {
|
|
130
|
-
const cached = getCache(cacheKey)
|
|
131
|
-
const unexpired = cached.expiry && (cacheExpiry < 0 || cached.expiry > Date.now())
|
|
101
|
+
const cached = getCache(cacheKey);
|
|
102
|
+
const unexpired = cached.expiry && (cacheExpiry < 0 || cached.expiry > Date.now());
|
|
132
103
|
|
|
133
104
|
if (unexpired && cached.modified) {
|
|
134
|
-
const value = fetch(request, cached.value)
|
|
105
|
+
const value = fetch(request, cached.value);
|
|
135
106
|
cache[cacheKey] = {
|
|
136
|
-
value: { ...cached.value,
|
|
107
|
+
value: { ...cached.value,
|
|
108
|
+
...value
|
|
109
|
+
},
|
|
137
110
|
expiry: cached.expiry
|
|
138
|
-
}
|
|
139
|
-
return cache[cacheKey]
|
|
111
|
+
};
|
|
112
|
+
return cache[cacheKey];
|
|
140
113
|
}
|
|
114
|
+
|
|
141
115
|
if (unexpired) {
|
|
142
|
-
return { ...cached,
|
|
116
|
+
return { ...cached,
|
|
117
|
+
cache: true
|
|
118
|
+
};
|
|
143
119
|
}
|
|
144
120
|
}
|
|
145
|
-
const value = fetch(request)
|
|
146
121
|
|
|
147
|
-
const
|
|
122
|
+
const value = fetch(request);
|
|
123
|
+
const expiry = Date.now() + cacheExpiry;
|
|
124
|
+
|
|
148
125
|
if (cacheExpiry) {
|
|
149
|
-
cache[cacheKey] = {
|
|
126
|
+
cache[cacheKey] = {
|
|
127
|
+
value,
|
|
128
|
+
expiry
|
|
129
|
+
};
|
|
150
130
|
}
|
|
151
|
-
return { value, expiry }
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export const getCache = (key) => {
|
|
155
|
-
if (!cache[key]) return {}
|
|
156
|
-
return cache[key]
|
|
157
|
-
}
|
|
158
131
|
|
|
159
|
-
|
|
132
|
+
return {
|
|
133
|
+
value,
|
|
134
|
+
expiry
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
export const getCache = key => {
|
|
138
|
+
if (!cache[key]) return {};
|
|
139
|
+
return cache[key];
|
|
140
|
+
};
|
|
160
141
|
export const modifyCache = (cacheKey, value) => {
|
|
161
|
-
if (!cache[cacheKey]) return
|
|
162
|
-
cache[cacheKey] = { ...cache[cacheKey],
|
|
163
|
-
|
|
164
|
-
|
|
142
|
+
if (!cache[cacheKey]) return;
|
|
143
|
+
cache[cacheKey] = { ...cache[cacheKey],
|
|
144
|
+
value,
|
|
145
|
+
modified: true
|
|
146
|
+
};
|
|
147
|
+
};
|
|
165
148
|
export const clearCache = (keys = null) => {
|
|
166
|
-
keys = keys ?? Object.keys(cache)
|
|
167
|
-
if (!Array.isArray(keys)) keys = [keys]
|
|
149
|
+
keys = keys ?? Object.keys(cache);
|
|
150
|
+
if (!Array.isArray(keys)) keys = [keys];
|
|
151
|
+
|
|
168
152
|
for (const cacheKey of keys) {
|
|
169
|
-
cache[cacheKey] = undefined
|
|
153
|
+
cache[cacheKey] = undefined;
|
|
170
154
|
}
|
|
171
|
-
}
|
|
172
|
-
|
|
155
|
+
};
|
|
173
156
|
export const jsonSafeParse = (string, reviver) => {
|
|
174
|
-
if (typeof string !== 'string') return string
|
|
175
|
-
const firstChar = string[0]
|
|
176
|
-
if (firstChar !== '{' && firstChar !== '[' && firstChar !== '"') return string
|
|
157
|
+
if (typeof string !== 'string') return string;
|
|
158
|
+
const firstChar = string[0];
|
|
159
|
+
if (firstChar !== '{' && firstChar !== '[' && firstChar !== '"') return string;
|
|
160
|
+
|
|
177
161
|
try {
|
|
178
|
-
return JSON.parse(string, reviver)
|
|
162
|
+
return JSON.parse(string, reviver);
|
|
179
163
|
} catch (e) {}
|
|
180
164
|
|
|
181
|
-
return string
|
|
182
|
-
}
|
|
165
|
+
return string;
|
|
166
|
+
};
|
|
167
|
+
export const normalizeHttpResponse = request => {
|
|
168
|
+
var _response, _response2, _response3, _response4;
|
|
169
|
+
|
|
170
|
+
let {
|
|
171
|
+
response
|
|
172
|
+
} = request;
|
|
183
173
|
|
|
184
|
-
export const normalizeHttpResponse = (request) => {
|
|
185
|
-
let { response } = request
|
|
186
174
|
if (response === undefined) {
|
|
187
|
-
response = {}
|
|
188
|
-
} else if (response
|
|
189
|
-
response = {
|
|
175
|
+
response = {};
|
|
176
|
+
} else if (((_response = response) === null || _response === void 0 ? void 0 : _response.statusCode) === undefined && ((_response2 = response) === null || _response2 === void 0 ? void 0 : _response2.body) === undefined && ((_response3 = response) === null || _response3 === void 0 ? void 0 : _response3.headers) === undefined) {
|
|
177
|
+
response = {
|
|
178
|
+
body: response
|
|
179
|
+
};
|
|
190
180
|
}
|
|
191
|
-
response.headers ??= {}
|
|
192
|
-
request.response = response
|
|
193
|
-
return response
|
|
194
|
-
}
|
|
195
181
|
|
|
196
|
-
|
|
182
|
+
(_response4 = response).headers ?? (_response4.headers = {});
|
|
183
|
+
request.response = response;
|
|
184
|
+
return response;
|
|
185
|
+
};
|
|
186
|
+
const createErrorRegexp = /[^a-zA-Z]/g;
|
|
197
187
|
export const createError = (code, message, properties = {}) => {
|
|
198
|
-
const name = statuses[code].replace(createErrorRegexp, '')
|
|
199
|
-
const className = name.substr(-5) !== 'Error' ? name + 'Error' : name
|
|
200
|
-
|
|
201
|
-
function HttpError
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
// capture a stack trace to the construction point
|
|
207
|
-
Error.captureStackTrace(err, HttpError)
|
|
208
|
-
|
|
209
|
-
// adjust the [[Prototype]]
|
|
210
|
-
Object.setPrototypeOf(err, HttpError.prototype)
|
|
211
|
-
|
|
212
|
-
// redefine the error message
|
|
188
|
+
const name = statuses[code].replace(createErrorRegexp, '');
|
|
189
|
+
const className = name.substr(-5) !== 'Error' ? name + 'Error' : name;
|
|
190
|
+
|
|
191
|
+
function HttpError(message) {
|
|
192
|
+
const msg = message ?? statuses[code];
|
|
193
|
+
const err = new Error(msg);
|
|
194
|
+
Error.captureStackTrace(err, HttpError);
|
|
195
|
+
Object.setPrototypeOf(err, HttpError.prototype);
|
|
213
196
|
Object.defineProperty(err, 'message', {
|
|
214
197
|
enumerable: true,
|
|
215
198
|
configurable: true,
|
|
216
199
|
value: msg,
|
|
217
200
|
writable: true
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
// redefine the error name
|
|
201
|
+
});
|
|
221
202
|
Object.defineProperty(err, 'name', {
|
|
222
203
|
enumerable: false,
|
|
223
204
|
configurable: true,
|
|
224
205
|
value: className,
|
|
225
206
|
writable: true
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
-
return err
|
|
207
|
+
});
|
|
208
|
+
return err;
|
|
229
209
|
}
|
|
230
210
|
|
|
231
|
-
inherits(HttpError, Error)
|
|
232
|
-
const desc = Object.getOwnPropertyDescriptor(HttpError, 'name')
|
|
233
|
-
desc.value = className
|
|
234
|
-
Object.defineProperty(HttpError, 'name', desc)
|
|
235
|
-
|
|
211
|
+
inherits(HttpError, Error);
|
|
212
|
+
const desc = Object.getOwnPropertyDescriptor(HttpError, 'name');
|
|
213
|
+
desc.value = className;
|
|
214
|
+
Object.defineProperty(HttpError, 'name', desc);
|
|
236
215
|
Object.assign(HttpError.prototype, {
|
|
237
216
|
status: code,
|
|
238
217
|
statusCode: code,
|
|
239
218
|
expose: code < 500
|
|
240
|
-
}, properties)
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
|
|
219
|
+
}, properties);
|
|
220
|
+
return new HttpError(message);
|
|
221
|
+
};
|
|
245
222
|
export default {
|
|
246
223
|
createPrefetchClient,
|
|
247
224
|
createClient,
|
|
@@ -255,4 +232,4 @@ export default {
|
|
|
255
232
|
jsonSafeParse,
|
|
256
233
|
normalizeHttpResponse,
|
|
257
234
|
createError
|
|
258
|
-
}
|
|
235
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@middy/util",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.4",
|
|
4
4
|
"description": "🛵 The stylish Node.js middleware engine for AWS Lambda (util package)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -46,12 +46,12 @@
|
|
|
46
46
|
"url": "https://github.com/middyjs/middy/issues"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@middy/core": "^3.0.0-alpha.
|
|
49
|
+
"@middy/core": "^3.0.0-alpha.4",
|
|
50
50
|
"@types/aws-lambda": "^8.10.76",
|
|
51
51
|
"@types/node": "^17.0.0",
|
|
52
52
|
"aws-sdk": "^2.939.0",
|
|
53
53
|
"aws-xray-sdk": "^3.3.3"
|
|
54
54
|
},
|
|
55
55
|
"homepage": "https://github.com/middyjs/middy#readme",
|
|
56
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "d4bea7f4e21f6a9bbb1f6f6908361169598b9e53"
|
|
57
57
|
}
|