UNPKG

6.8 kBJavaScriptView Raw
1import { EventEmitter } from 'events';
2const defaultLambdaHandler = ()=>{};
3const defaultPlugin = {
4 timeoutEarlyInMillis: 5,
5 timeoutEarlyResponse: ()=>{
6 throw new Error('Timeout');
7 }
8};
9const middy = (lambdaHandler = defaultLambdaHandler, plugin = {})=>{
10 if (typeof lambdaHandler !== 'function') {
11 plugin = lambdaHandler;
12 lambdaHandler = defaultLambdaHandler;
13 }
14 plugin = {
15 ...defaultPlugin,
16 ...plugin
17 };
18 plugin.timeoutEarly = plugin.timeoutEarlyInMillis > 0;
19 plugin.beforePrefetch?.();
20 const beforeMiddlewares = [];
21 const afterMiddlewares = [];
22 const onErrorMiddlewares = [];
23 const middy1 = (event = {}, context = {})=>{
24 plugin.requestStart?.();
25 const request = {
26 event,
27 context,
28 response: undefined,
29 error: undefined,
30 internal: plugin.internal ?? {}
31 };
32 return runRequest(request, [
33 ...beforeMiddlewares
34 ], lambdaHandler, [
35 ...afterMiddlewares
36 ], [
37 ...onErrorMiddlewares
38 ], plugin);
39 };
40 middy1.use = (middlewares)=>{
41 if (!Array.isArray(middlewares)) {
42 middlewares = [
43 middlewares
44 ];
45 }
46 for (const middleware of middlewares){
47 const { before , after , onError } = middleware;
48 if (!before && !after && !onError) {
49 throw new Error('Middleware must be an object containing at least one key among "before", "after", "onError"');
50 }
51 if (before) middy1.before(before);
52 if (after) middy1.after(after);
53 if (onError) middy1.onError(onError);
54 }
55 return middy1;
56 };
57 middy1.before = (beforeMiddleware)=>{
58 beforeMiddlewares.push(beforeMiddleware);
59 return middy1;
60 };
61 middy1.after = (afterMiddleware)=>{
62 afterMiddlewares.unshift(afterMiddleware);
63 return middy1;
64 };
65 middy1.onError = (onErrorMiddleware)=>{
66 onErrorMiddlewares.unshift(onErrorMiddleware);
67 return middy1;
68 };
69 middy1.handler = (replaceLambdaHandler)=>{
70 lambdaHandler = replaceLambdaHandler;
71 return middy1;
72 };
73 return middy1;
74};
75const runRequest = async (request, beforeMiddlewares, lambdaHandler, afterMiddlewares, onErrorMiddlewares, plugin)=>{
76 const timeoutEarly = plugin.timeoutEarly && request.context.getRemainingTimeInMillis;
77 try {
78 await runMiddlewares(request, beforeMiddlewares, plugin);
79 if (typeof request.response === 'undefined') {
80 plugin.beforeHandler?.();
81 const handlerAbort = new AbortController();
82 let timeoutAbort;
83 if (timeoutEarly) timeoutAbort = new AbortController();
84 request.response = await Promise.race([
85 lambdaHandler(request.event, request.context, {
86 signal: handlerAbort.signal
87 }),
88 timeoutEarly ? setTimeoutPromise(request.context.getRemainingTimeInMillis() - plugin.timeoutEarlyInMillis, {
89 signal: timeoutAbort.signal
90 }).then(()=>{
91 handlerAbort.abort();
92 return plugin.timeoutEarlyResponse();
93 }) : Promise.race([])
94 ]);
95 if (timeoutEarly) timeoutAbort.abort();
96 plugin.afterHandler?.();
97 await runMiddlewares(request, afterMiddlewares, plugin);
98 }
99 } catch (e) {
100 request.response = undefined;
101 request.error = e;
102 try {
103 await runMiddlewares(request, onErrorMiddlewares, plugin);
104 } catch (e) {
105 e.originalError = request.error;
106 request.error = e;
107 throw request.error;
108 }
109 if (typeof request.response === 'undefined') throw request.error;
110 } finally{
111 await plugin.requestEnd?.(request);
112 }
113 return request.response;
114};
115const runMiddlewares = async (request, middlewares, plugin)=>{
116 for (const nextMiddleware of middlewares){
117 plugin.beforeMiddleware?.(nextMiddleware.name);
118 const res = await nextMiddleware(request);
119 plugin.afterMiddleware?.(nextMiddleware.name);
120 if (typeof res !== 'undefined') {
121 request.response = res;
122 return;
123 }
124 }
125};
126const polyfillAbortController = ()=>{
127 if (process.version < 'v15.0.0') {
128 class AbortSignal {
129 toString() {
130 return '[object AbortSignal]';
131 }
132 get [Symbol.toStringTag]() {
133 return 'AbortSignal';
134 }
135 removeEventListener(name, handler) {
136 this.eventEmitter.removeListener(name, handler);
137 }
138 addEventListener(name, handler) {
139 this.eventEmitter.on(name, handler);
140 }
141 dispatchEvent(type) {
142 const event = {
143 type,
144 target: this
145 };
146 const handlerName = `on${type}`;
147 if (typeof this[handlerName] === 'function') this[handlerName](event);
148 this.eventEmitter.emit(type, event);
149 }
150 constructor(){
151 this.eventEmitter = new EventEmitter();
152 this.onabort = null;
153 this.aborted = false;
154 }
155 }
156 return class AbortController {
157 abort() {
158 if (this.signal.aborted) return;
159 this.signal.aborted = true;
160 this.signal.dispatchEvent('abort');
161 }
162 toString() {
163 return '[object AbortController]';
164 }
165 get [Symbol.toStringTag]() {
166 return 'AbortController';
167 }
168 constructor(){
169 this.signal = new AbortSignal();
170 }
171 };
172 } else {
173 return AbortController;
174 }
175};
176global.AbortController = polyfillAbortController();
177const polyfillSetTimeoutPromise = ()=>{
178 return (ms, { signal })=>{
179 if (signal.aborted) {
180 return Promise.reject(new Error('Aborted', 'AbortError'));
181 }
182 return new Promise((resolve, reject)=>{
183 const abortHandler = ()=>{
184 clearTimeout(timeout);
185 reject(new Error('Aborted', 'AbortError'));
186 };
187 const timeout = setTimeout(()=>{
188 resolve();
189 signal.removeEventListener('abort', abortHandler);
190 }, ms);
191 signal.addEventListener('abort', abortHandler);
192 });
193 };
194};
195const setTimeoutPromise = polyfillSetTimeoutPromise();
196export default middy;
197
198
199//# sourceMappingURL=index.js.map
\No newline at end of file