Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@middy/core

Package Overview
Dependencies
Maintainers
3
Versions
226
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@middy/core - npm Package Compare versions

Comparing version 5.1.0 to 5.2.0

381

index.js

@@ -1,165 +0,234 @@

import { Readable } from 'node:stream';
import { pipeline } from 'node:stream/promises';
import { setTimeout } from 'node:timers/promises';
const defaultLambdaHandler = ()=>{};
/* global awslambda */
import { Readable } from 'node:stream'
import { pipeline } from 'node:stream/promises'
import { setTimeout } from 'node:timers'
const defaultLambdaHandler = () => {}
const defaultPlugin = {
timeoutEarlyInMillis: 5,
timeoutEarlyResponse: ()=>{
const err = new Error('[AbortError]: The operation was aborted.', {
cause: {
package: '@middy/core'
}
});
err.name = 'TimeoutError';
throw err;
},
streamifyResponse: false
};
const middy = (lambdaHandler = defaultLambdaHandler, plugin = {})=>{
if (typeof lambdaHandler !== 'function') {
plugin = lambdaHandler;
lambdaHandler = defaultLambdaHandler;
timeoutEarlyInMillis: 5,
timeoutEarlyResponse: () => {
const err = new Error('[AbortError]: The operation was aborted.', {
cause: { package: '@middy/core' }
})
err.name = 'TimeoutError'
throw err
},
streamifyResponse: false // Deprecate need for this when AWS provides a flag for when it's looking for it
}
const middy = (lambdaHandler = defaultLambdaHandler, plugin = {}) => {
// Allow base handler to be set using .handler()
if (typeof lambdaHandler !== 'function') {
plugin = lambdaHandler
lambdaHandler = defaultLambdaHandler
}
plugin = { ...defaultPlugin, ...plugin }
plugin.timeoutEarly = plugin.timeoutEarlyInMillis > 0
plugin.beforePrefetch?.()
const beforeMiddlewares = []
const afterMiddlewares = []
const onErrorMiddlewares = []
const middyHandler = (event = {}, context = {}) => {
plugin.requestStart?.()
const request = {
event,
context,
response: undefined,
error: undefined,
internal: plugin.internal ?? {}
}
plugin = {
...defaultPlugin,
...plugin
};
plugin.timeoutEarly = plugin.timeoutEarlyInMillis > 0;
plugin.beforePrefetch?.();
const beforeMiddlewares = [];
const afterMiddlewares = [];
const onErrorMiddlewares = [];
const middyHandler = (event = {}, context = {})=>{
plugin.requestStart?.();
const request = {
event,
context,
response: undefined,
error: undefined,
internal: plugin.internal ?? {}
};
return runRequest(request, [
...beforeMiddlewares
], lambdaHandler, [
...afterMiddlewares
], [
...onErrorMiddlewares
], plugin);
};
const middy = plugin.streamifyResponse ? awslambda.streamifyResponse(async (event, responseStream, context)=>{
const handlerResponse = await middyHandler(event, context);
let handlerBody = handlerResponse;
if (handlerResponse.statusCode) {
handlerBody = handlerResponse.body ?? '';
delete handlerResponse.body;
responseStream = awslambda.HttpResponseStream.from(responseStream, handlerResponse);
return runRequest(
request,
beforeMiddlewares,
lambdaHandler,
afterMiddlewares,
onErrorMiddlewares,
plugin
)
}
const middy = plugin.streamifyResponse
? awslambda.streamifyResponse(async (event, responseStream, context) => {
const handlerResponse = await middyHandler(event, context)
let handlerBody = handlerResponse
if (handlerResponse.statusCode) {
handlerBody = handlerResponse.body ?? ''
delete handlerResponse.body // #1137
responseStream = awslambda.HttpResponseStream.from(
responseStream,
handlerResponse
)
}
// Source @datastream/core (MIT)
let handlerStream
if (handlerBody._readableState) {
handlerStream = handlerBody
} else if (typeof handlerBody === 'string') {
function * iterator (input) {
const size = 16384 // 16 * 1024 // Node.js default
let position = 0
const length = input.length
while (position < length) {
yield input.substring(position, position + size)
position += size
}
}
let handlerStream;
if (handlerBody._readableState) {
handlerStream = handlerBody;
} else if (typeof handlerBody === 'string') {
function* iterator(input) {
const size = 16384;
let position = 0;
const length = input.length;
while(position < length){
yield input.substring(position, position + size);
position += size;
}
handlerStream = Readable.from(iterator(handlerBody))
}
if (!handlerStream) {
throw new Error('handler response not a ReadableStream')
}
await pipeline(handlerStream, responseStream)
})
: middyHandler
middy.use = (middlewares) => {
if (!Array.isArray(middlewares)) {
middlewares = [middlewares]
}
for (const middleware of middlewares) {
const { before, after, onError } = middleware
if (before || after || onError) {
if (before) middy.before(before)
if (after) middy.after(after)
if (onError) middy.onError(onError)
} else {
throw new Error(
'Middleware must be an object containing at least one key among "before", "after", "onError"'
)
}
}
return middy
}
// Inline Middlewares
middy.before = (beforeMiddleware) => {
beforeMiddlewares.push(beforeMiddleware)
return middy
}
middy.after = (afterMiddleware) => {
afterMiddlewares.unshift(afterMiddleware)
return middy
}
middy.onError = (onErrorMiddleware) => {
onErrorMiddlewares.unshift(onErrorMiddleware)
return middy
}
middy.handler = (replaceLambdaHandler) => {
lambdaHandler = replaceLambdaHandler
return middy
}
return middy
}
// shared AbortController, because it's slow
let handlerAbort = new AbortController()
const runRequest = async (
request,
beforeMiddlewares,
lambdaHandler,
afterMiddlewares,
onErrorMiddlewares,
plugin
) => {
let timeoutID
// context.getRemainingTimeInMillis checked for when AWS context missing (tests, containers)
const timeoutEarly =
plugin.timeoutEarly && request.context.getRemainingTimeInMillis
try {
await runMiddlewares(request, beforeMiddlewares, plugin)
// Check if before stack hasn't exit early
if (typeof request.response === 'undefined') {
plugin.beforeHandler?.()
// Can't manually abort and timeout with same AbortSignal
// https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout_static
if (handlerAbort.signal.aborted) {
handlerAbort = new AbortController()
}
const promises = [
lambdaHandler(request.event, request.context, {
signal: handlerAbort.signal
})
]
// clearTimeout pattern is 10x faster than using AbortController
// Note: signal.abort is slow ~6000ns
if (timeoutEarly) {
let timeoutResolve
const timeoutPromise = new Promise((resolve, reject) => {
timeoutResolve = () => {
handlerAbort.abort()
try {
resolve(plugin.timeoutEarlyResponse())
} catch (e) {
reject(e)
}
handlerStream = Readable.from(iterator(handlerBody));
}
if (!handlerStream) {
throw new Error('handler response not a ReadableStream');
}
await pipeline(handlerStream, responseStream);
}) : middyHandler;
middy.use = (middlewares)=>{
if (!Array.isArray(middlewares)) {
middlewares = [
middlewares
];
}
for (const middleware of middlewares){
const { before, after, onError } = middleware;
if (!before && !after && !onError) {
throw new Error('Middleware must be an object containing at least one key among "before", "after", "onError"');
}
if (before) middy.before(before);
if (after) middy.after(after);
if (onError) middy.onError(onError);
}
return middy;
};
middy.before = (beforeMiddleware)=>{
beforeMiddlewares.push(beforeMiddleware);
return middy;
};
middy.after = (afterMiddleware)=>{
afterMiddlewares.unshift(afterMiddleware);
return middy;
};
middy.onError = (onErrorMiddleware)=>{
onErrorMiddlewares.unshift(onErrorMiddleware);
return middy;
};
middy.handler = (replaceLambdaHandler)=>{
lambdaHandler = replaceLambdaHandler;
return middy;
};
return middy;
};
const runRequest = async (request, beforeMiddlewares, lambdaHandler, afterMiddlewares, onErrorMiddlewares, plugin)=>{
let timeoutAbort;
const timeoutEarly = plugin.timeoutEarly && request.context.getRemainingTimeInMillis;
}
})
timeoutID = setTimeout(
timeoutResolve,
request.context.getRemainingTimeInMillis() -
plugin.timeoutEarlyInMillis
)
promises.push(timeoutPromise)
}
request.response = await Promise.race(promises)
if (timeoutID) {
clearTimeout(timeoutID)
}
plugin.afterHandler?.()
await runMiddlewares(request, afterMiddlewares, plugin)
}
} catch (e) {
// timeout should be aborted when errors happen in handler
if (timeoutID) {
clearTimeout(timeoutID)
}
// Reset response changes made by after stack before error thrown
request.response = undefined
request.error = e
try {
await runMiddlewares(request, beforeMiddlewares, plugin);
if (typeof request.response === 'undefined') {
plugin.beforeHandler?.();
const handlerAbort = new AbortController();
if (timeoutEarly) timeoutAbort = new AbortController();
request.response = await Promise.race([
lambdaHandler(request.event, request.context, {
signal: handlerAbort.signal
}),
timeoutEarly ? setTimeout(request.context.getRemainingTimeInMillis() - plugin.timeoutEarlyInMillis, undefined, {
signal: timeoutAbort.signal
}).then(()=>{
handlerAbort.abort();
return plugin.timeoutEarlyResponse();
}) : Promise.race([])
]);
timeoutAbort?.abort();
plugin.afterHandler?.();
await runMiddlewares(request, afterMiddlewares, plugin);
}
await runMiddlewares(request, onErrorMiddlewares, plugin)
} catch (e) {
timeoutAbort?.abort();
request.response = undefined;
request.error = e;
try {
await runMiddlewares(request, onErrorMiddlewares, plugin);
} catch (e) {
e.originalError = request.error;
request.error = e;
throw request.error;
}
if (typeof request.response === 'undefined') throw request.error;
} finally{
await plugin.requestEnd?.(request);
// Save error that wasn't handled
e.originalError = request.error
request.error = e
throw request.error
}
return request.response;
};
const runMiddlewares = async (request, middlewares, plugin)=>{
for (const nextMiddleware of middlewares){
plugin.beforeMiddleware?.(nextMiddleware.name);
const res = await nextMiddleware(request);
plugin.afterMiddleware?.(nextMiddleware.name);
if (typeof res !== 'undefined') {
request.response = res;
return;
}
// Catch if onError stack hasn't handled the error
if (typeof request.response === 'undefined') throw request.error
} finally {
await plugin.requestEnd?.(request)
}
return request.response
}
const runMiddlewares = async (request, middlewares, plugin) => {
for (const nextMiddleware of middlewares) {
plugin.beforeMiddleware?.(nextMiddleware.name)
const res = await nextMiddleware(request)
plugin.afterMiddleware?.(nextMiddleware.name)
// short circuit chaining and respond early
if (typeof res !== 'undefined') {
request.response = res
return
}
};
export default middy;
}
}
export default middy
{
"name": "@middy/core",
"version": "5.1.0",
"version": "5.2.0",
"description": "🛵 The stylish Node.js middleware engine for AWS Lambda (core package)",

@@ -30,3 +30,4 @@ "type": "module",

"test:unit": "ava",
"test:benchmark": "node __benchmarks__/index.js"
"test:benchmark": "node __benchmarks__/index.js",
"test:profile": "node --prof __benchmarks__/index.js && node --prof-process --preprocess -j isolate*.log | speedscope -"
},

@@ -63,3 +64,3 @@ "license": "MIT",

},
"gitHead": "bbdaf5843914921804ba085dd58117273febe6b5",
"gitHead": "2d9096a49cd8fb62359517be96d6c93609df41f0",
"dependencies": {

@@ -66,0 +67,0 @@ "@datastream/core": "0.0.35"

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc