/* global awslambda */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(module, "exports", { enumerable: true, get: function() { return _default; } }); const _nodestream = require("node:stream"); const _promises = require("node:stream/promises"); const _promises1 = require("node:timers/promises"); const defaultLambdaHandler = ()=>{}; const defaultPlugin = { timeoutEarlyInMillis: 5, timeoutEarlyResponse: ()=>{ throw new Error('Timeout'); }, 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 ?? {} }; 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 ?? ''; 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; } } handlerStream = _nodestream.Readable.from(iterator(handlerBody)); } if (!handlerStream) { throw new Error('handler response not a ReadableStream'); } await (0, _promises.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; }; // 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; }; const runRequest = async (request, beforeMiddlewares, lambdaHandler, afterMiddlewares, onErrorMiddlewares, plugin)=>{ let timeoutAbort; const timeoutEarly = plugin.timeoutEarly && request.context.getRemainingTimeInMillis // disable when AWS context missing (tests, containers) ; try { await runMiddlewares(request, beforeMiddlewares, plugin); // Check if before stack hasn't exit early 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 ? (0, _promises1.setTimeout)(request.context.getRemainingTimeInMillis() - plugin.timeoutEarlyInMillis, undefined, { signal: timeoutAbort.signal }).then(()=>{ handlerAbort.abort(); return plugin.timeoutEarlyResponse(); }) : Promise.race([]) ]); timeoutAbort?.abort() // lambdaHandler may not be a promise ; plugin.afterHandler?.(); await runMiddlewares(request, afterMiddlewares, plugin); } } catch (e) { timeoutAbort?.abort() // timeout should be aborted on errors ; // Reset response changes made by after stack before error thrown request.response = undefined; request.error = e; try { await runMiddlewares(request, onErrorMiddlewares, plugin); } catch (e) { // Save error that wasn't handled e.originalError = request.error; request.error = e; throw request.error; } // 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; } } }; const _default = middy;