@middy/util
Advanced tools
Comparing version 3.0.0-alpha.3 to 3.0.0-alpha.4
313
index.js
@@ -1,19 +0,5 @@ | ||
import { Agent } from 'https' | ||
// smaller version of `http-errors` | ||
import statuses from './codes.js' | ||
import { inherits } from 'util' | ||
// import { NodeHttpHandler } from '@aws-sdk/node-http-handler' // aws-sdk v3 | ||
import { Agent } from 'https'; | ||
import statuses from './codes.js'; | ||
import { inherits } from 'util'; | ||
export const awsClientDefaultOptions = { | ||
// AWS SDK v3 | ||
// Docs: https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/enforcing-tls.html | ||
/* requestHandler: new NodeHttpHandler({ | ||
httpsAgent: new Agent( | ||
{ | ||
secureProtocol: 'TLSv1_2_method' | ||
} | ||
) | ||
}) */ | ||
// Docs: https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/enforcing-tls.html | ||
httpOptions: { | ||
@@ -24,191 +10,188 @@ agent: new Agent({ | ||
} | ||
} | ||
export const createPrefetchClient = (options) => { | ||
const awsClientOptions = { | ||
...awsClientDefaultOptions, | ||
}; | ||
export const createPrefetchClient = options => { | ||
const awsClientOptions = { ...awsClientDefaultOptions, | ||
...options.awsClientOptions | ||
} | ||
const client = new options.AwsClient(awsClientOptions) | ||
}; | ||
const client = new options.AwsClient(awsClientOptions); | ||
// AWS XRay | ||
if (options.awsClientCapture && options.disablePrefetch) { | ||
return options.awsClientCapture(client) | ||
return options.awsClientCapture(client); | ||
} else if (options.awsClientCapture) { | ||
console.warn('Unable to apply X-Ray outside of handler invocation scope.') | ||
console.warn('Unable to apply X-Ray outside of handler invocation scope.'); | ||
} | ||
return client | ||
} | ||
return client; | ||
}; | ||
export const createClient = async (options, request) => { | ||
let awsClientCredentials = {} | ||
let awsClientCredentials = {}; | ||
// Role Credentials | ||
if (options.awsClientAssumeRole) { | ||
if (!request) throw new Error('Request required when assuming role') | ||
awsClientCredentials = await getInternal( | ||
{ credentials: options.awsClientAssumeRole }, | ||
request | ||
) | ||
if (!request) throw new Error('Request required when assuming role'); | ||
awsClientCredentials = await getInternal({ | ||
credentials: options.awsClientAssumeRole | ||
}, request); | ||
} | ||
awsClientCredentials = { | ||
...awsClientCredentials, | ||
awsClientCredentials = { ...awsClientCredentials, | ||
...options.awsClientOptions | ||
} | ||
return createPrefetchClient({ | ||
...options, | ||
}; | ||
return createPrefetchClient({ ...options, | ||
awsClientOptions: awsClientCredentials | ||
}) | ||
} | ||
}); | ||
}; | ||
export const canPrefetch = (options = {}) => { | ||
return !options.awsClientAssumeRole && !options.disablePrefetch | ||
} | ||
return !options.awsClientAssumeRole && !options.disablePrefetch; | ||
}; | ||
export const getInternal = async (variables, request) => { | ||
if (!variables || !request) return {}; | ||
let keys = []; | ||
let values = []; | ||
// Internal Context | ||
export const getInternal = async (variables, request) => { | ||
if (!variables || !request) return {} | ||
let keys = [] | ||
let values = [] | ||
if (variables === true) { | ||
keys = values = Object.keys(request.internal) | ||
keys = values = Object.keys(request.internal); | ||
} else if (typeof variables === 'string') { | ||
keys = values = [variables] | ||
keys = values = [variables]; | ||
} else if (Array.isArray(variables)) { | ||
keys = values = variables | ||
keys = values = variables; | ||
} else if (typeof variables === 'object') { | ||
keys = Object.keys(variables) | ||
values = Object.values(variables) | ||
keys = Object.keys(variables); | ||
values = Object.values(variables); | ||
} | ||
const promises = [] | ||
const promises = []; | ||
for (const internalKey of values) { | ||
// 'internal.key.sub_value' -> { [key]: internal.key.sub_value } | ||
const pathOptionKey = internalKey.split('.') | ||
const rootOptionKey = pathOptionKey.shift() | ||
let valuePromise = request.internal[rootOptionKey] | ||
const pathOptionKey = internalKey.split('.'); | ||
const rootOptionKey = pathOptionKey.shift(); | ||
let valuePromise = request.internal[rootOptionKey]; | ||
if (typeof valuePromise.then !== 'function') { | ||
valuePromise = Promise.resolve(valuePromise) | ||
valuePromise = Promise.resolve(valuePromise); | ||
} | ||
promises.push( | ||
valuePromise.then((value) => | ||
pathOptionKey.reduce((p, c) => p?.[c], value) | ||
) | ||
) | ||
promises.push(valuePromise.then(value => pathOptionKey.reduce((p, c) => p === null || p === void 0 ? void 0 : p[c], value))); | ||
} | ||
// ensure promise has resolved by the time it's needed | ||
// If one of the promises throws it will bubble up to @middy/core | ||
values = await Promise.allSettled(promises) | ||
const errors = values | ||
.filter((res) => res.status === 'rejected') | ||
.map((res) => res.reason) | ||
values = await Promise.allSettled(promises); | ||
const errors = values.filter(res => res.status === 'rejected').map(res => res.reason); | ||
if (errors.length) { | ||
// throw new Error('Failed to resolve internal values', { cause: errors }) | ||
const error = new Error('Failed to resolve internal values') | ||
error.cause = errors | ||
throw error | ||
const error = new Error('Failed to resolve internal values'); | ||
error.cause = errors; | ||
throw error; | ||
} | ||
return keys.reduce( | ||
(obj, key, index) => ({ ...obj, [sanitizeKey(key)]: values[index].value }), | ||
{} | ||
) | ||
} | ||
const sanitizeKeyPrefixLeadingNumber = /^([0-9])/ | ||
const sanitizeKeyRemoveDisallowedChar = /[^a-zA-Z0-9]+/g | ||
export const sanitizeKey = (key) => { | ||
return key | ||
.replace(sanitizeKeyPrefixLeadingNumber, '_$1') | ||
.replace(sanitizeKeyRemoveDisallowedChar, '_') | ||
} | ||
// fetch Cache | ||
const cache = {} // key: { value:{fetchKey:Promise}, expiry } | ||
return keys.reduce((obj, key, index) => ({ ...obj, | ||
[sanitizeKey(key)]: values[index].value | ||
}), {}); | ||
}; | ||
const sanitizeKeyPrefixLeadingNumber = /^([0-9])/; | ||
const sanitizeKeyRemoveDisallowedChar = /[^a-zA-Z0-9]+/g; | ||
export const sanitizeKey = key => { | ||
return key.replace(sanitizeKeyPrefixLeadingNumber, '_$1').replace(sanitizeKeyRemoveDisallowedChar, '_'); | ||
}; | ||
const cache = {}; | ||
export const processCache = (options, fetch = () => undefined, request) => { | ||
const { cacheExpiry, cacheKey } = options | ||
const { | ||
cacheExpiry, | ||
cacheKey | ||
} = options; | ||
if (cacheExpiry) { | ||
const cached = getCache(cacheKey) | ||
const unexpired = cached.expiry && (cacheExpiry < 0 || cached.expiry > Date.now()) | ||
const cached = getCache(cacheKey); | ||
const unexpired = cached.expiry && (cacheExpiry < 0 || cached.expiry > Date.now()); | ||
if (unexpired && cached.modified) { | ||
const value = fetch(request, cached.value) | ||
const value = fetch(request, cached.value); | ||
cache[cacheKey] = { | ||
value: { ...cached.value, ...value }, | ||
value: { ...cached.value, | ||
...value | ||
}, | ||
expiry: cached.expiry | ||
} | ||
return cache[cacheKey] | ||
}; | ||
return cache[cacheKey]; | ||
} | ||
if (unexpired) { | ||
return { ...cached, cache: true } | ||
return { ...cached, | ||
cache: true | ||
}; | ||
} | ||
} | ||
const value = fetch(request) | ||
const expiry = Date.now() + cacheExpiry | ||
const value = fetch(request); | ||
const expiry = Date.now() + cacheExpiry; | ||
if (cacheExpiry) { | ||
cache[cacheKey] = { value, expiry } | ||
cache[cacheKey] = { | ||
value, | ||
expiry | ||
}; | ||
} | ||
return { value, expiry } | ||
} | ||
export const getCache = (key) => { | ||
if (!cache[key]) return {} | ||
return cache[key] | ||
} | ||
// Used to remove parts of a cache | ||
return { | ||
value, | ||
expiry | ||
}; | ||
}; | ||
export const getCache = key => { | ||
if (!cache[key]) return {}; | ||
return cache[key]; | ||
}; | ||
export const modifyCache = (cacheKey, value) => { | ||
if (!cache[cacheKey]) return | ||
cache[cacheKey] = { ...cache[cacheKey], value, modified: true } | ||
} | ||
if (!cache[cacheKey]) return; | ||
cache[cacheKey] = { ...cache[cacheKey], | ||
value, | ||
modified: true | ||
}; | ||
}; | ||
export const clearCache = (keys = null) => { | ||
keys = keys ?? Object.keys(cache); | ||
if (!Array.isArray(keys)) keys = [keys]; | ||
export const clearCache = (keys = null) => { | ||
keys = keys ?? Object.keys(cache) | ||
if (!Array.isArray(keys)) keys = [keys] | ||
for (const cacheKey of keys) { | ||
cache[cacheKey] = undefined | ||
cache[cacheKey] = undefined; | ||
} | ||
} | ||
}; | ||
export const jsonSafeParse = (string, reviver) => { | ||
if (typeof string !== 'string') return string; | ||
const firstChar = string[0]; | ||
if (firstChar !== '{' && firstChar !== '[' && firstChar !== '"') return string; | ||
export const jsonSafeParse = (string, reviver) => { | ||
if (typeof string !== 'string') return string | ||
const firstChar = string[0] | ||
if (firstChar !== '{' && firstChar !== '[' && firstChar !== '"') return string | ||
try { | ||
return JSON.parse(string, reviver) | ||
return JSON.parse(string, reviver); | ||
} catch (e) {} | ||
return string | ||
} | ||
return string; | ||
}; | ||
export const normalizeHttpResponse = request => { | ||
var _response, _response2, _response3, _response4; | ||
export const normalizeHttpResponse = (request) => { | ||
let { response } = request | ||
let { | ||
response | ||
} = request; | ||
if (response === undefined) { | ||
response = {} | ||
} else if (response?.statusCode === undefined && response?.body === undefined && response?.headers === undefined) { | ||
response = { body: response } | ||
response = {}; | ||
} 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) { | ||
response = { | ||
body: response | ||
}; | ||
} | ||
response.headers ??= {} | ||
request.response = response | ||
return response | ||
} | ||
const createErrorRegexp = /[^a-zA-Z]/g | ||
(_response4 = response).headers ?? (_response4.headers = {}); | ||
request.response = response; | ||
return response; | ||
}; | ||
const createErrorRegexp = /[^a-zA-Z]/g; | ||
export const createError = (code, message, properties = {}) => { | ||
const name = statuses[code].replace(createErrorRegexp, '') | ||
const className = name.substr(-5) !== 'Error' ? name + 'Error' : name | ||
const name = statuses[code].replace(createErrorRegexp, ''); | ||
const className = name.substr(-5) !== 'Error' ? name + 'Error' : name; | ||
function HttpError (message) { | ||
// create the error object | ||
const msg = message ?? statuses[code] | ||
const err = new Error(msg) | ||
// capture a stack trace to the construction point | ||
Error.captureStackTrace(err, HttpError) | ||
// adjust the [[Prototype]] | ||
Object.setPrototypeOf(err, HttpError.prototype) | ||
// redefine the error message | ||
function HttpError(message) { | ||
const msg = message ?? statuses[code]; | ||
const err = new Error(msg); | ||
Error.captureStackTrace(err, HttpError); | ||
Object.setPrototypeOf(err, HttpError.prototype); | ||
Object.defineProperty(err, 'message', { | ||
@@ -219,5 +202,3 @@ enumerable: true, | ||
writable: true | ||
}) | ||
// redefine the error name | ||
}); | ||
Object.defineProperty(err, 'name', { | ||
@@ -228,12 +209,10 @@ enumerable: false, | ||
writable: true | ||
}) | ||
return err | ||
}); | ||
return err; | ||
} | ||
inherits(HttpError, Error) | ||
const desc = Object.getOwnPropertyDescriptor(HttpError, 'name') | ||
desc.value = className | ||
Object.defineProperty(HttpError, 'name', desc) | ||
inherits(HttpError, Error); | ||
const desc = Object.getOwnPropertyDescriptor(HttpError, 'name'); | ||
desc.value = className; | ||
Object.defineProperty(HttpError, 'name', desc); | ||
Object.assign(HttpError.prototype, { | ||
@@ -243,7 +222,5 @@ status: code, | ||
expose: code < 500 | ||
}, properties) | ||
return new HttpError(message) | ||
} | ||
}, properties); | ||
return new HttpError(message); | ||
}; | ||
export default { | ||
@@ -262,2 +239,2 @@ createPrefetchClient, | ||
createError | ||
} | ||
}; |
{ | ||
"name": "@middy/util", | ||
"version": "3.0.0-alpha.3", | ||
"version": "3.0.0-alpha.4", | ||
"description": "🛵 The stylish Node.js middleware engine for AWS Lambda (util package)", | ||
@@ -49,3 +49,3 @@ "type": "module", | ||
"devDependencies": { | ||
"@middy/core": "^3.0.0-alpha.3", | ||
"@middy/core": "^3.0.0-alpha.4", | ||
"@types/aws-lambda": "^8.10.76", | ||
@@ -57,3 +57,3 @@ "@types/node": "^17.0.0", | ||
"homepage": "https://github.com/middyjs/middy#readme", | ||
"gitHead": "1441158711580313765e6d156046ef0fade0d156" | ||
"gitHead": "d4bea7f4e21f6a9bbb1f6f6908361169598b9e53" | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
14304
307