@middy/core 3.0.0-alpha.0 → 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.
Files changed (3) hide show
  1. package/index.d.ts +3 -1
  2. package/index.js +249 -0
  3. package/package.json +5 -6
package/index.d.ts CHANGED
@@ -42,8 +42,10 @@ export interface MiddlewareObj<TEvent = any, TResult = any, TErr = Error, TConte
42
42
  // The AWS provided Handler type uses void | Promise<TResult> so we have no choice but to follow and suppress the linter warning
43
43
  // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
44
44
  type MiddyInputHandler<TEvent, TResult, TContext extends LambdaContext = LambdaContext> = (event: TEvent, context: TContext, callback: LambdaCallback<TResult>) => void | Promise<TResult>
45
+ type MiddyInputPromiseHandler<TEvent, TResult, TContext extends LambdaContext = LambdaContext> = ( event: TEvent, context: TContext, ) => Promise<TResult>;
45
46
 
46
- export interface MiddyfiedHandler<TEvent = any, TResult = any, TErr = Error, TContext extends LambdaContext = LambdaContext> extends MiddyInputHandler<TEvent, TResult, TContext> {
47
+ export interface MiddyfiedHandler<TEvent = any, TResult = any, TErr = Error, TContext extends LambdaContext = LambdaContext> extends MiddyInputHandler<TEvent, TResult, TContext>,
48
+ MiddyInputPromiseHandler<TEvent, TResult, TContext> {
47
49
  use: UseFn<TEvent, TResult, TErr, TContext>
48
50
  before: AttachMiddlewareFn<TEvent, TResult, TErr, TContext>
49
51
  after: AttachMiddlewareFn<TEvent, TResult, TErr, TContext>
package/index.js ADDED
@@ -0,0 +1,249 @@
1
+ const defaultLambdaHandler = () => {};
2
+
3
+ const defaultPlugin = {
4
+ timeoutEarlyInMillis: 5,
5
+ timeoutEarlyResponse: () => {
6
+ throw new Error('Timeout');
7
+ }
8
+ };
9
+
10
+ const middy = (lambdaHandler = defaultLambdaHandler, plugin = {}) => {
11
+ var _plugin$beforePrefetc, _plugin;
12
+
13
+ if (typeof lambdaHandler !== 'function') {
14
+ plugin = lambdaHandler;
15
+ lambdaHandler = defaultLambdaHandler;
16
+ }
17
+
18
+ plugin = { ...defaultPlugin,
19
+ ...plugin
20
+ };
21
+ plugin.timeoutEarly = plugin.timeoutEarlyInMillis > 0;
22
+ (_plugin$beforePrefetc = (_plugin = plugin).beforePrefetch) === null || _plugin$beforePrefetc === void 0 ? void 0 : _plugin$beforePrefetc.call(_plugin);
23
+ const beforeMiddlewares = [];
24
+ const afterMiddlewares = [];
25
+ const onErrorMiddlewares = [];
26
+
27
+ const middy = (event = {}, context = {}) => {
28
+ var _plugin$requestStart, _plugin2;
29
+
30
+ (_plugin$requestStart = (_plugin2 = plugin).requestStart) === null || _plugin$requestStart === void 0 ? void 0 : _plugin$requestStart.call(_plugin2);
31
+ const request = {
32
+ event,
33
+ context,
34
+ response: undefined,
35
+ error: undefined,
36
+ internal: plugin.internal ?? {}
37
+ };
38
+ return runRequest(request, [...beforeMiddlewares], lambdaHandler, [...afterMiddlewares], [...onErrorMiddlewares], plugin);
39
+ };
40
+
41
+ middy.use = middlewares => {
42
+ if (!Array.isArray(middlewares)) {
43
+ middlewares = [middlewares];
44
+ }
45
+
46
+ for (const middleware of middlewares) {
47
+ const {
48
+ before,
49
+ after,
50
+ onError
51
+ } = middleware;
52
+
53
+ if (!before && !after && !onError) {
54
+ throw new Error('Middleware must be an object containing at least one key among "before", "after", "onError"');
55
+ }
56
+
57
+ if (before) middy.before(before);
58
+ if (after) middy.after(after);
59
+ if (onError) middy.onError(onError);
60
+ }
61
+
62
+ return middy;
63
+ };
64
+
65
+ middy.before = beforeMiddleware => {
66
+ beforeMiddlewares.push(beforeMiddleware);
67
+ return middy;
68
+ };
69
+
70
+ middy.after = afterMiddleware => {
71
+ afterMiddlewares.unshift(afterMiddleware);
72
+ return middy;
73
+ };
74
+
75
+ middy.onError = onErrorMiddleware => {
76
+ onErrorMiddlewares.unshift(onErrorMiddleware);
77
+ return middy;
78
+ };
79
+
80
+ middy.handler = replaceLambdaHandler => {
81
+ lambdaHandler = replaceLambdaHandler;
82
+ };
83
+
84
+ return middy;
85
+ };
86
+
87
+ const runRequest = async (request, beforeMiddlewares, lambdaHandler, afterMiddlewares, onErrorMiddlewares, plugin) => {
88
+ const {
89
+ timeoutEarly
90
+ } = plugin;
91
+
92
+ try {
93
+ await runMiddlewares(request, beforeMiddlewares, plugin);
94
+
95
+ if (request.response === undefined) {
96
+ var _plugin$beforeHandler, _plugin$afterHandler;
97
+
98
+ (_plugin$beforeHandler = plugin.beforeHandler) === null || _plugin$beforeHandler === void 0 ? void 0 : _plugin$beforeHandler.call(plugin);
99
+ const handlerAbort = new AbortController();
100
+ let timeoutAbort;
101
+ if (timeoutEarly) timeoutAbort = new AbortController();
102
+ request.response = await Promise.race([lambdaHandler(request.event, request.context, {
103
+ signal: handlerAbort.signal
104
+ }), timeoutEarly ? setTimeoutPromise(request.context.getRemainingTimeInMillis() - plugin.timeoutEarlyInMillis, {
105
+ signal: timeoutAbort.signal
106
+ }).then(() => {
107
+ handlerAbort.abort();
108
+ return plugin.timeoutEarlyResponse();
109
+ }) : Promise.race([])]);
110
+ if (timeoutEarly) timeoutAbort.abort();
111
+ (_plugin$afterHandler = plugin.afterHandler) === null || _plugin$afterHandler === void 0 ? void 0 : _plugin$afterHandler.call(plugin);
112
+ await runMiddlewares(request, afterMiddlewares, plugin);
113
+ }
114
+ } catch (e) {
115
+ request.response = undefined;
116
+ request.error = e;
117
+
118
+ try {
119
+ await runMiddlewares(request, onErrorMiddlewares, plugin);
120
+ } catch (e) {
121
+ e.originalError = request.error;
122
+ request.error = e;
123
+ throw request.error;
124
+ }
125
+
126
+ if (request.response === undefined) throw request.error;
127
+ } finally {
128
+ var _plugin$requestEnd;
129
+
130
+ await ((_plugin$requestEnd = plugin.requestEnd) === null || _plugin$requestEnd === void 0 ? void 0 : _plugin$requestEnd.call(plugin, request));
131
+ }
132
+
133
+ return request.response;
134
+ };
135
+
136
+ const runMiddlewares = async (request, middlewares, plugin) => {
137
+ for (const nextMiddleware of middlewares) {
138
+ var _plugin$beforeMiddlew, _plugin$afterMiddlewa;
139
+
140
+ (_plugin$beforeMiddlew = plugin.beforeMiddleware) === null || _plugin$beforeMiddlew === void 0 ? void 0 : _plugin$beforeMiddlew.call(plugin, nextMiddleware.name);
141
+ const res = await nextMiddleware(request);
142
+ (_plugin$afterMiddlewa = plugin.afterMiddleware) === null || _plugin$afterMiddlewa === void 0 ? void 0 : _plugin$afterMiddlewa.call(plugin, nextMiddleware.name);
143
+
144
+ if (res !== undefined) {
145
+ request.response = res;
146
+ return;
147
+ }
148
+ }
149
+ };
150
+
151
+ const polyfillAbortController = async () => {
152
+ if (process.version < 'v15.0.0') {
153
+ const events = await import('events');
154
+ const {
155
+ EventEmitter
156
+ } = events;
157
+
158
+ class AbortSignal {
159
+ constructor() {
160
+ this.eventEmitter = new EventEmitter();
161
+ this.onabort = null;
162
+ this.aborted = false;
163
+ }
164
+
165
+ toString() {
166
+ return '[object AbortSignal]';
167
+ }
168
+
169
+ get [Symbol.toStringTag]() {
170
+ return 'AbortSignal';
171
+ }
172
+
173
+ removeEventListener(name, handler) {
174
+ this.eventEmitter.removeListener(name, handler);
175
+ }
176
+
177
+ addEventListener(name, handler) {
178
+ this.eventEmitter.on(name, handler);
179
+ }
180
+
181
+ dispatchEvent(type) {
182
+ const event = {
183
+ type,
184
+ target: this
185
+ };
186
+ const handlerName = `on${type}`;
187
+ if (typeof this[handlerName] === 'function') this[handlerName](event);
188
+ this.eventEmitter.emit(type, event);
189
+ }
190
+
191
+ }
192
+
193
+ return class AbortController {
194
+ constructor() {
195
+ this.signal = new AbortSignal();
196
+ }
197
+
198
+ abort() {
199
+ if (this.signal.aborted) return;
200
+ this.signal.aborted = true;
201
+ this.signal.dispatchEvent('abort');
202
+ }
203
+
204
+ toString() {
205
+ return '[object AbortController]';
206
+ }
207
+
208
+ get [Symbol.toStringTag]() {
209
+ return 'AbortController';
210
+ }
211
+
212
+ };
213
+ } else {
214
+ return AbortController;
215
+ }
216
+ };
217
+
218
+ global.AbortController = await polyfillAbortController();
219
+
220
+ const polyfillSetTimeoutPromise = async () => {
221
+ if (process.version < 'v15.0.0') {
222
+ return (ms, {
223
+ signal
224
+ }) => {
225
+ if (signal.aborted) {
226
+ return Promise.reject(new Error('Aborted', 'AbortError'));
227
+ }
228
+
229
+ return new Promise((resolve, reject) => {
230
+ const abortHandler = () => {
231
+ clearTimeout(timeout);
232
+ reject(new Error('Aborted', 'AbortError'));
233
+ };
234
+
235
+ const timeout = setTimeout(() => {
236
+ resolve();
237
+ signal.removeEventListener('abort', abortHandler);
238
+ }, ms);
239
+ signal.addEventListener('abort', abortHandler);
240
+ });
241
+ };
242
+ } else {
243
+ const timers = await import('timers/promises');
244
+ return timers.setTimeout;
245
+ }
246
+ };
247
+
248
+ global.setTimeoutPromise = await polyfillSetTimeoutPromise();
249
+ export default middy;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@middy/core",
3
- "version": "3.0.0-alpha.0",
3
+ "version": "3.0.0-alpha.4",
4
4
  "description": "🛵 The stylish Node.js middleware engine for AWS Lambda (core package)",
5
5
  "type": "module",
6
6
  "engines": {
@@ -13,11 +13,13 @@
13
13
  "exports": "./index.js",
14
14
  "types": "index.d.ts",
15
15
  "files": [
16
+ "index.js",
16
17
  "index.d.ts"
17
18
  ],
18
19
  "scripts": {
19
20
  "test": "npm run test:unit",
20
- "test:unit": "ava"
21
+ "test:unit": "ava",
22
+ "test:benchmark": "node __benchmarks__/index.js"
21
23
  },
22
24
  "license": "MIT",
23
25
  "keywords": [
@@ -45,8 +47,5 @@
45
47
  "@types/aws-lambda": "^8.10.76",
46
48
  "@types/node": "^17.0.0"
47
49
  },
48
- "gitHead": "c533f62841c8a39d061d7b94f30ba178f002c8db",
49
- "dependencies": {
50
- "node-abort-controller": "3.0.1"
51
- }
50
+ "gitHead": "d4bea7f4e21f6a9bbb1f6f6908361169598b9e53"
52
51
  }