@middy/core 4.6.5 → 5.0.0-alpha.1
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.
- package/index.d.ts +39 -29
- package/index.js +201 -162
- package/package.json +6 -10
- package/index.cjs +0 -180
package/index.d.ts
CHANGED
|
@@ -28,33 +28,34 @@ export interface Request<
|
|
|
28
28
|
TEvent = any,
|
|
29
29
|
TResult = any,
|
|
30
30
|
TErr = Error,
|
|
31
|
-
TContext extends LambdaContext = LambdaContext
|
|
31
|
+
TContext extends LambdaContext = LambdaContext,
|
|
32
|
+
TInternal extends Record<string, unknown> = {}
|
|
32
33
|
> {
|
|
33
34
|
event: TEvent
|
|
34
35
|
context: TContext
|
|
35
36
|
response: TResult | null
|
|
36
37
|
error: TErr | null
|
|
37
|
-
internal:
|
|
38
|
-
[key: string]: any
|
|
39
|
-
}
|
|
38
|
+
internal: TInternal
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
declare type MiddlewareFn<
|
|
43
42
|
TEvent = any,
|
|
44
43
|
TResult = any,
|
|
45
44
|
TErr = Error,
|
|
46
|
-
TContext extends LambdaContext = LambdaContext
|
|
47
|
-
|
|
45
|
+
TContext extends LambdaContext = LambdaContext,
|
|
46
|
+
TInternal extends Record<string, unknown> = {}
|
|
47
|
+
> = (request: Request<TEvent, TResult, TErr, TContext, TInternal>) => any
|
|
48
48
|
|
|
49
49
|
export interface MiddlewareObj<
|
|
50
50
|
TEvent = unknown,
|
|
51
51
|
TResult = any,
|
|
52
52
|
TErr = Error,
|
|
53
|
-
TContext extends LambdaContext = LambdaContext
|
|
53
|
+
TContext extends LambdaContext = LambdaContext,
|
|
54
|
+
TInternal extends Record<string, unknown> = {}
|
|
54
55
|
> {
|
|
55
|
-
before?: MiddlewareFn<TEvent, TResult, TErr, TContext>
|
|
56
|
-
after?: MiddlewareFn<TEvent, TResult, TErr, TContext>
|
|
57
|
-
onError?: MiddlewareFn<TEvent, TResult, TErr, TContext>
|
|
56
|
+
before?: MiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>
|
|
57
|
+
after?: MiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>
|
|
58
|
+
onError?: MiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
// The AWS provided Handler type uses void | Promise<TResult> so we have no choice but to follow and suppress the linter warning
|
|
@@ -79,57 +80,63 @@ export interface MiddyfiedHandler<
|
|
|
79
80
|
TEvent = any,
|
|
80
81
|
TResult = any,
|
|
81
82
|
TErr = Error,
|
|
82
|
-
TContext extends LambdaContext = LambdaContext
|
|
83
|
+
TContext extends LambdaContext = LambdaContext,
|
|
84
|
+
TInternal extends Record<string, unknown> = {}
|
|
83
85
|
> extends MiddyInputHandler<TEvent, TResult, TContext>,
|
|
84
86
|
MiddyInputPromiseHandler<TEvent, TResult, TContext> {
|
|
85
|
-
use: UseFn<TEvent, TResult, TErr, TContext>
|
|
86
|
-
before: AttachMiddlewareFn<TEvent, TResult, TErr, TContext>
|
|
87
|
-
after: AttachMiddlewareFn<TEvent, TResult, TErr, TContext>
|
|
88
|
-
onError: AttachMiddlewareFn<TEvent, TResult, TErr, TContext>
|
|
87
|
+
use: UseFn<TEvent, TResult, TErr, TContext, TInternal>
|
|
88
|
+
before: AttachMiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>
|
|
89
|
+
after: AttachMiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>
|
|
90
|
+
onError: AttachMiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>
|
|
89
91
|
handler: <TAdditional>(
|
|
90
92
|
handler: MiddlewareHandler<
|
|
91
93
|
LambdaHandler<TEvent & TAdditional, TResult>,
|
|
92
94
|
TContext
|
|
93
95
|
>
|
|
94
|
-
) => MiddyfiedHandler<TEvent, TResult, TErr, TContext>
|
|
96
|
+
) => MiddyfiedHandler<TEvent, TResult, TErr, TContext, TInternal>
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
declare type AttachMiddlewareFn<
|
|
98
100
|
TEvent = any,
|
|
99
101
|
TResult = any,
|
|
100
102
|
TErr = Error,
|
|
101
|
-
TContext extends LambdaContext = LambdaContext
|
|
103
|
+
TContext extends LambdaContext = LambdaContext,
|
|
104
|
+
TInternal extends Record<string, unknown> = {}
|
|
102
105
|
> = (
|
|
103
|
-
middleware: MiddlewareFn<TEvent, TResult, TErr, TContext>
|
|
104
|
-
) => MiddyfiedHandler<TEvent, TResult, TErr, TContext>
|
|
106
|
+
middleware: MiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>
|
|
107
|
+
) => MiddyfiedHandler<TEvent, TResult, TErr, TContext, TInternal>
|
|
105
108
|
|
|
106
109
|
declare type AttachMiddlewareObj<
|
|
107
110
|
TEvent = any,
|
|
108
111
|
TResult = any,
|
|
109
112
|
TErr = Error,
|
|
110
|
-
TContext extends LambdaContext = LambdaContext
|
|
113
|
+
TContext extends LambdaContext = LambdaContext,
|
|
114
|
+
TInternal extends Record<string, unknown> = {}
|
|
111
115
|
> = (
|
|
112
|
-
middleware: MiddlewareObj<TEvent, TResult, TErr, TContext>
|
|
113
|
-
) => MiddyfiedHandler<TEvent, TResult, TErr, TContext>
|
|
116
|
+
middleware: MiddlewareObj<TEvent, TResult, TErr, TContext, TInternal>
|
|
117
|
+
) => MiddyfiedHandler<TEvent, TResult, TErr, TContext, TInternal>
|
|
114
118
|
|
|
115
119
|
declare type UseFn<
|
|
116
120
|
TEvent = any,
|
|
117
121
|
TResult = any,
|
|
118
122
|
TErr = Error,
|
|
119
|
-
TContext extends LambdaContext = LambdaContext
|
|
120
|
-
|
|
123
|
+
TContext extends LambdaContext = LambdaContext,
|
|
124
|
+
TInternal extends Record<string, unknown> = {}
|
|
125
|
+
> = <TMiddleware extends MiddlewareObj<any, any, Error, any, any>>(
|
|
121
126
|
middlewares: TMiddleware | TMiddleware[]
|
|
122
127
|
) => TMiddleware extends MiddlewareObj<
|
|
123
128
|
infer TMiddlewareEvent,
|
|
124
129
|
any,
|
|
125
130
|
Error,
|
|
126
|
-
infer TMiddlewareContext
|
|
131
|
+
infer TMiddlewareContext,
|
|
132
|
+
infer TMiddlewareInternal
|
|
127
133
|
>
|
|
128
134
|
? MiddyfiedHandler<
|
|
129
135
|
TMiddlewareEvent & TEvent,
|
|
130
136
|
TResult,
|
|
131
137
|
TErr,
|
|
132
|
-
TMiddlewareContext & TContext
|
|
138
|
+
TMiddlewareContext & TContext,
|
|
139
|
+
TMiddlewareInternal & TInternal
|
|
133
140
|
> // always true
|
|
134
141
|
: never
|
|
135
142
|
|
|
@@ -149,11 +156,14 @@ declare function middy<
|
|
|
149
156
|
TEvent = unknown,
|
|
150
157
|
TResult = any,
|
|
151
158
|
TErr = Error,
|
|
152
|
-
TContext extends LambdaContext = LambdaContext
|
|
159
|
+
TContext extends LambdaContext = LambdaContext,
|
|
160
|
+
TInternal extends Record<string, unknown> = {}
|
|
153
161
|
> (
|
|
154
|
-
handler?:
|
|
162
|
+
handler?:
|
|
163
|
+
| MiddlewareHandler<LambdaHandler<TEvent, TResult>, TContext>
|
|
164
|
+
| PluginObject,
|
|
155
165
|
plugin?: PluginObject
|
|
156
|
-
): MiddyfiedHandler<TEvent, TResult, TErr, TContext>
|
|
166
|
+
): MiddyfiedHandler<TEvent, TResult, TErr, TContext, TInternal>
|
|
157
167
|
|
|
158
168
|
declare namespace middy {
|
|
159
169
|
export {
|
package/index.js
CHANGED
|
@@ -1,170 +1,209 @@
|
|
|
1
|
-
/* global awslambda */
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
1
|
+
/* global awslambda */
|
|
2
|
+
import { Readable } from 'node:stream'
|
|
3
|
+
import { pipeline } from 'node:stream/promises'
|
|
4
|
+
import { setTimeout } from 'node:timers/promises'
|
|
5
|
+
|
|
6
|
+
const defaultLambdaHandler = () => {}
|
|
5
7
|
const defaultPlugin = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
timeoutEarlyInMillis: 5,
|
|
9
|
+
timeoutEarlyResponse: () => {
|
|
10
|
+
const err = new Error('[AbortError]: The operation was aborted.', {
|
|
11
|
+
cause: { package: '@middy/core' }
|
|
12
|
+
})
|
|
13
|
+
err.name = 'TimeoutError'
|
|
14
|
+
throw err
|
|
15
|
+
},
|
|
16
|
+
streamifyResponse: false // Deprecate need for this when AWS provides a flag for when it's looking for it
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const middy = (lambdaHandler = defaultLambdaHandler, plugin = {}) => {
|
|
20
|
+
// Allow base handler to be set using .handler()
|
|
21
|
+
if (typeof lambdaHandler !== 'function') {
|
|
22
|
+
plugin = lambdaHandler
|
|
23
|
+
lambdaHandler = defaultLambdaHandler
|
|
24
|
+
}
|
|
25
|
+
plugin = { ...defaultPlugin, ...plugin }
|
|
26
|
+
plugin.timeoutEarly = plugin.timeoutEarlyInMillis > 0
|
|
27
|
+
|
|
28
|
+
plugin.beforePrefetch?.()
|
|
29
|
+
const beforeMiddlewares = []
|
|
30
|
+
const afterMiddlewares = []
|
|
31
|
+
const onErrorMiddlewares = []
|
|
32
|
+
|
|
33
|
+
const middyHandler = (event = {}, context = {}) => {
|
|
34
|
+
plugin.requestStart?.()
|
|
35
|
+
const request = {
|
|
36
|
+
event,
|
|
37
|
+
context,
|
|
38
|
+
response: undefined,
|
|
39
|
+
error: undefined,
|
|
40
|
+
internal: plugin.internal ?? {}
|
|
17
41
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
handlerStream = handlerBody;
|
|
55
|
-
} else if (typeof handlerBody === 'string') {
|
|
56
|
-
function* iterator(input) {
|
|
57
|
-
const size = 16384 // 16 * 1024 // Node.js default
|
|
58
|
-
;
|
|
59
|
-
let position = 0;
|
|
60
|
-
const length = input.length;
|
|
61
|
-
while(position < length){
|
|
62
|
-
yield input.substring(position, position + size);
|
|
63
|
-
position += size;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
handlerStream = Readable.from(iterator(handlerBody));
|
|
67
|
-
}
|
|
68
|
-
if (!handlerStream) {
|
|
69
|
-
throw new Error('handler response not a ReadableStream');
|
|
70
|
-
}
|
|
71
|
-
await pipeline(handlerStream, responseStream);
|
|
72
|
-
}) : middyHandler;
|
|
73
|
-
middy.use = (middlewares)=>{
|
|
74
|
-
if (!Array.isArray(middlewares)) {
|
|
75
|
-
middlewares = [
|
|
76
|
-
middlewares
|
|
77
|
-
];
|
|
78
|
-
}
|
|
79
|
-
for (const middleware of middlewares){
|
|
80
|
-
const { before, after, onError } = middleware;
|
|
81
|
-
if (!before && !after && !onError) {
|
|
82
|
-
throw new Error('Middleware must be an object containing at least one key among "before", "after", "onError"');
|
|
83
|
-
}
|
|
84
|
-
if (before) middy.before(before);
|
|
85
|
-
if (after) middy.after(after);
|
|
86
|
-
if (onError) middy.onError(onError);
|
|
42
|
+
|
|
43
|
+
return runRequest(
|
|
44
|
+
request,
|
|
45
|
+
[...beforeMiddlewares],
|
|
46
|
+
lambdaHandler,
|
|
47
|
+
[...afterMiddlewares],
|
|
48
|
+
[...onErrorMiddlewares],
|
|
49
|
+
plugin
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
const middy = plugin.streamifyResponse
|
|
53
|
+
? awslambda.streamifyResponse(async (event, responseStream, context) => {
|
|
54
|
+
const handlerResponse = await middyHandler(event, context)
|
|
55
|
+
|
|
56
|
+
let handlerBody = handlerResponse
|
|
57
|
+
if (handlerResponse.statusCode) {
|
|
58
|
+
handlerBody = handlerResponse.body ?? ''
|
|
59
|
+
responseStream = awslambda.HttpResponseStream.from(
|
|
60
|
+
responseStream,
|
|
61
|
+
handlerResponse
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Source @datastream/core (MIT)
|
|
66
|
+
let handlerStream
|
|
67
|
+
if (handlerBody._readableState) {
|
|
68
|
+
handlerStream = handlerBody
|
|
69
|
+
} else if (typeof handlerBody === 'string') {
|
|
70
|
+
function * iterator (input) {
|
|
71
|
+
const size = 16384 // 16 * 1024 // Node.js default
|
|
72
|
+
let position = 0
|
|
73
|
+
const length = input.length
|
|
74
|
+
while (position < length) {
|
|
75
|
+
yield input.substring(position, position + size)
|
|
76
|
+
position += size
|
|
77
|
+
}
|
|
87
78
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
79
|
+
handlerStream = Readable.from(iterator(handlerBody))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (!handlerStream) {
|
|
83
|
+
throw new Error('handler response not a ReadableStream')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
await pipeline(handlerStream, responseStream)
|
|
87
|
+
})
|
|
88
|
+
: middyHandler
|
|
89
|
+
|
|
90
|
+
middy.use = (middlewares) => {
|
|
91
|
+
if (!Array.isArray(middlewares)) {
|
|
92
|
+
middlewares = [middlewares]
|
|
93
|
+
}
|
|
94
|
+
for (const middleware of middlewares) {
|
|
95
|
+
const { before, after, onError } = middleware
|
|
96
|
+
|
|
97
|
+
if (!before && !after && !onError) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
'Middleware must be an object containing at least one key among "before", "after", "onError"'
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (before) middy.before(before)
|
|
104
|
+
if (after) middy.after(after)
|
|
105
|
+
if (onError) middy.onError(onError)
|
|
106
|
+
}
|
|
107
|
+
return middy
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Inline Middlewares
|
|
111
|
+
middy.before = (beforeMiddleware) => {
|
|
112
|
+
beforeMiddlewares.push(beforeMiddleware)
|
|
113
|
+
return middy
|
|
114
|
+
}
|
|
115
|
+
middy.after = (afterMiddleware) => {
|
|
116
|
+
afterMiddlewares.unshift(afterMiddleware)
|
|
117
|
+
return middy
|
|
118
|
+
}
|
|
119
|
+
middy.onError = (onErrorMiddleware) => {
|
|
120
|
+
onErrorMiddlewares.unshift(onErrorMiddleware)
|
|
121
|
+
return middy
|
|
122
|
+
}
|
|
123
|
+
middy.handler = (replaceLambdaHandler) => {
|
|
124
|
+
lambdaHandler = replaceLambdaHandler
|
|
125
|
+
return middy
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return middy
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const runRequest = async (
|
|
132
|
+
request,
|
|
133
|
+
beforeMiddlewares,
|
|
134
|
+
lambdaHandler,
|
|
135
|
+
afterMiddlewares,
|
|
136
|
+
onErrorMiddlewares,
|
|
137
|
+
plugin
|
|
138
|
+
) => {
|
|
139
|
+
let timeoutAbort
|
|
140
|
+
const timeoutEarly =
|
|
141
|
+
plugin.timeoutEarly && request.context.getRemainingTimeInMillis // disable when AWS context missing (tests, containers)
|
|
142
|
+
try {
|
|
143
|
+
await runMiddlewares(request, beforeMiddlewares, plugin)
|
|
144
|
+
// Check if before stack hasn't exit early
|
|
145
|
+
if (typeof request.response === 'undefined') {
|
|
146
|
+
plugin.beforeHandler?.()
|
|
147
|
+
|
|
148
|
+
const handlerAbort = new AbortController()
|
|
149
|
+
|
|
150
|
+
if (timeoutEarly) timeoutAbort = new AbortController()
|
|
151
|
+
request.response = await Promise.race([
|
|
152
|
+
lambdaHandler(request.event, request.context, {
|
|
153
|
+
signal: handlerAbort.signal
|
|
154
|
+
}),
|
|
155
|
+
timeoutEarly
|
|
156
|
+
? setTimeout(
|
|
157
|
+
request.context.getRemainingTimeInMillis() -
|
|
158
|
+
plugin.timeoutEarlyInMillis,
|
|
159
|
+
undefined,
|
|
160
|
+
{ signal: timeoutAbort.signal }
|
|
161
|
+
).then(() => {
|
|
162
|
+
handlerAbort.abort()
|
|
163
|
+
return plugin.timeoutEarlyResponse()
|
|
164
|
+
})
|
|
165
|
+
: Promise.race([])
|
|
166
|
+
])
|
|
167
|
+
timeoutAbort?.abort() // lambdaHandler may not be a promise
|
|
168
|
+
|
|
169
|
+
plugin.afterHandler?.()
|
|
170
|
+
await runMiddlewares(request, afterMiddlewares, plugin)
|
|
171
|
+
}
|
|
172
|
+
} catch (e) {
|
|
173
|
+
timeoutAbort?.abort() // timeout should be aborted on errors
|
|
174
|
+
|
|
175
|
+
// Reset response changes made by after stack before error thrown
|
|
176
|
+
request.response = undefined
|
|
177
|
+
request.error = e
|
|
113
178
|
try {
|
|
114
|
-
|
|
115
|
-
// Check if before stack hasn't exit early
|
|
116
|
-
if (typeof request.response === 'undefined') {
|
|
117
|
-
plugin.beforeHandler?.();
|
|
118
|
-
const handlerAbort = new AbortController();
|
|
119
|
-
if (timeoutEarly) timeoutAbort = new AbortController();
|
|
120
|
-
request.response = await Promise.race([
|
|
121
|
-
lambdaHandler(request.event, request.context, {
|
|
122
|
-
signal: handlerAbort.signal
|
|
123
|
-
}),
|
|
124
|
-
timeoutEarly ? setTimeout(request.context.getRemainingTimeInMillis() - plugin.timeoutEarlyInMillis, undefined, {
|
|
125
|
-
signal: timeoutAbort.signal
|
|
126
|
-
}).then(()=>{
|
|
127
|
-
handlerAbort.abort();
|
|
128
|
-
return plugin.timeoutEarlyResponse();
|
|
129
|
-
}) : Promise.race([])
|
|
130
|
-
]);
|
|
131
|
-
timeoutAbort?.abort() // lambdaHandler may not be a promise
|
|
132
|
-
;
|
|
133
|
-
plugin.afterHandler?.();
|
|
134
|
-
await runMiddlewares(request, afterMiddlewares, plugin);
|
|
135
|
-
}
|
|
179
|
+
await runMiddlewares(request, onErrorMiddlewares, plugin)
|
|
136
180
|
} catch (e) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
try {
|
|
143
|
-
await runMiddlewares(request, onErrorMiddlewares, plugin);
|
|
144
|
-
} catch (e) {
|
|
145
|
-
// Save error that wasn't handled
|
|
146
|
-
e.originalError = request.error;
|
|
147
|
-
request.error = e;
|
|
148
|
-
throw request.error;
|
|
149
|
-
}
|
|
150
|
-
// Catch if onError stack hasn't handled the error
|
|
151
|
-
if (typeof request.response === 'undefined') throw request.error;
|
|
152
|
-
} finally{
|
|
153
|
-
await plugin.requestEnd?.(request);
|
|
181
|
+
// Save error that wasn't handled
|
|
182
|
+
e.originalError = request.error
|
|
183
|
+
request.error = e
|
|
184
|
+
|
|
185
|
+
throw request.error
|
|
154
186
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
187
|
+
// Catch if onError stack hasn't handled the error
|
|
188
|
+
if (typeof request.response === 'undefined') throw request.error
|
|
189
|
+
} finally {
|
|
190
|
+
await plugin.requestEnd?.(request)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return request.response
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const runMiddlewares = async (request, middlewares, plugin) => {
|
|
197
|
+
for (const nextMiddleware of middlewares) {
|
|
198
|
+
plugin.beforeMiddleware?.(nextMiddleware.name)
|
|
199
|
+
const res = await nextMiddleware(request)
|
|
200
|
+
plugin.afterMiddleware?.(nextMiddleware.name)
|
|
201
|
+
// short circuit chaining and respond early
|
|
202
|
+
if (typeof res !== 'undefined') {
|
|
203
|
+
request.response = res
|
|
204
|
+
return
|
|
167
205
|
}
|
|
168
|
-
}
|
|
169
|
-
|
|
206
|
+
}
|
|
207
|
+
}
|
|
170
208
|
|
|
209
|
+
export default middy
|
package/package.json
CHANGED
|
@@ -1,33 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@middy/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0-alpha.1",
|
|
4
4
|
"description": "🛵 The stylish Node.js middleware engine for AWS Lambda (core package)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
|
-
"node": ">=
|
|
7
|
+
"node": ">=18"
|
|
8
8
|
},
|
|
9
9
|
"engineStrict": true,
|
|
10
10
|
"publishConfig": {
|
|
11
11
|
"access": "public"
|
|
12
12
|
},
|
|
13
|
-
"main": "./index.cjs",
|
|
14
13
|
"module": "./index.js",
|
|
15
14
|
"exports": {
|
|
16
15
|
".": {
|
|
17
16
|
"import": {
|
|
18
17
|
"types": "./index.d.ts",
|
|
19
18
|
"default": "./index.js"
|
|
20
|
-
},
|
|
21
|
-
"require": {
|
|
22
|
-
"types": "./index.d.ts",
|
|
23
|
-
"default": "./index.cjs"
|
|
24
19
|
}
|
|
25
20
|
}
|
|
26
21
|
},
|
|
27
22
|
"types": "index.d.ts",
|
|
28
23
|
"files": [
|
|
29
24
|
"index.js",
|
|
30
|
-
"index.cjs",
|
|
31
25
|
"index.d.ts"
|
|
32
26
|
],
|
|
33
27
|
"scripts": {
|
|
@@ -62,9 +56,11 @@
|
|
|
62
56
|
"url": "https://github.com/sponsors/willfarrell"
|
|
63
57
|
},
|
|
64
58
|
"devDependencies": {
|
|
65
|
-
"@datastream/core": "0.0.35",
|
|
66
59
|
"@types/aws-lambda": "^8.10.76",
|
|
67
60
|
"@types/node": "^20.0.0"
|
|
68
61
|
},
|
|
69
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "ebce8d5df8783077fa49ba62ee9be20e8486a7f1",
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"@datastream/core": "0.0.35"
|
|
65
|
+
}
|
|
70
66
|
}
|
package/index.cjs
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
/* global awslambda */ "use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(module, "exports", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return _default;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
const _nodestream = require("node:stream");
|
|
12
|
-
const _promises = require("node:stream/promises");
|
|
13
|
-
const _promises1 = require("node:timers/promises");
|
|
14
|
-
const defaultLambdaHandler = ()=>{};
|
|
15
|
-
const defaultPlugin = {
|
|
16
|
-
timeoutEarlyInMillis: 5,
|
|
17
|
-
timeoutEarlyResponse: ()=>{
|
|
18
|
-
throw new Error('Timeout');
|
|
19
|
-
},
|
|
20
|
-
streamifyResponse: false // Deprecate need for this when AWS provides a flag for when it's looking for it
|
|
21
|
-
};
|
|
22
|
-
const middy = (lambdaHandler = defaultLambdaHandler, plugin = {})=>{
|
|
23
|
-
// Allow base handler to be set using .handler()
|
|
24
|
-
if (typeof lambdaHandler !== 'function') {
|
|
25
|
-
plugin = lambdaHandler;
|
|
26
|
-
lambdaHandler = defaultLambdaHandler;
|
|
27
|
-
}
|
|
28
|
-
plugin = {
|
|
29
|
-
...defaultPlugin,
|
|
30
|
-
...plugin
|
|
31
|
-
};
|
|
32
|
-
plugin.timeoutEarly = plugin.timeoutEarlyInMillis > 0;
|
|
33
|
-
plugin.beforePrefetch?.();
|
|
34
|
-
const beforeMiddlewares = [];
|
|
35
|
-
const afterMiddlewares = [];
|
|
36
|
-
const onErrorMiddlewares = [];
|
|
37
|
-
const middyHandler = (event = {}, context = {})=>{
|
|
38
|
-
plugin.requestStart?.();
|
|
39
|
-
const request = {
|
|
40
|
-
event,
|
|
41
|
-
context,
|
|
42
|
-
response: undefined,
|
|
43
|
-
error: undefined,
|
|
44
|
-
internal: plugin.internal ?? {}
|
|
45
|
-
};
|
|
46
|
-
return runRequest(request, [
|
|
47
|
-
...beforeMiddlewares
|
|
48
|
-
], lambdaHandler, [
|
|
49
|
-
...afterMiddlewares
|
|
50
|
-
], [
|
|
51
|
-
...onErrorMiddlewares
|
|
52
|
-
], plugin);
|
|
53
|
-
};
|
|
54
|
-
const middy = plugin.streamifyResponse ? awslambda.streamifyResponse(async (event, responseStream, context)=>{
|
|
55
|
-
const handlerResponse = await middyHandler(event, context);
|
|
56
|
-
let handlerBody = handlerResponse;
|
|
57
|
-
if (handlerResponse.statusCode) {
|
|
58
|
-
handlerBody = handlerResponse.body ?? '';
|
|
59
|
-
responseStream = awslambda.HttpResponseStream.from(responseStream, handlerResponse);
|
|
60
|
-
}
|
|
61
|
-
// Source @datastream/core (MIT)
|
|
62
|
-
let handlerStream;
|
|
63
|
-
if (handlerBody._readableState) {
|
|
64
|
-
handlerStream = handlerBody;
|
|
65
|
-
} else if (typeof handlerBody === 'string') {
|
|
66
|
-
function* iterator(input) {
|
|
67
|
-
const size = 16384 // 16 * 1024 // Node.js default
|
|
68
|
-
;
|
|
69
|
-
let position = 0;
|
|
70
|
-
const length = input.length;
|
|
71
|
-
while(position < length){
|
|
72
|
-
yield input.substring(position, position + size);
|
|
73
|
-
position += size;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
handlerStream = _nodestream.Readable.from(iterator(handlerBody));
|
|
77
|
-
}
|
|
78
|
-
if (!handlerStream) {
|
|
79
|
-
throw new Error('handler response not a ReadableStream');
|
|
80
|
-
}
|
|
81
|
-
await (0, _promises.pipeline)(handlerStream, responseStream);
|
|
82
|
-
}) : middyHandler;
|
|
83
|
-
middy.use = (middlewares)=>{
|
|
84
|
-
if (!Array.isArray(middlewares)) {
|
|
85
|
-
middlewares = [
|
|
86
|
-
middlewares
|
|
87
|
-
];
|
|
88
|
-
}
|
|
89
|
-
for (const middleware of middlewares){
|
|
90
|
-
const { before, after, onError } = middleware;
|
|
91
|
-
if (!before && !after && !onError) {
|
|
92
|
-
throw new Error('Middleware must be an object containing at least one key among "before", "after", "onError"');
|
|
93
|
-
}
|
|
94
|
-
if (before) middy.before(before);
|
|
95
|
-
if (after) middy.after(after);
|
|
96
|
-
if (onError) middy.onError(onError);
|
|
97
|
-
}
|
|
98
|
-
return middy;
|
|
99
|
-
};
|
|
100
|
-
// Inline Middlewares
|
|
101
|
-
middy.before = (beforeMiddleware)=>{
|
|
102
|
-
beforeMiddlewares.push(beforeMiddleware);
|
|
103
|
-
return middy;
|
|
104
|
-
};
|
|
105
|
-
middy.after = (afterMiddleware)=>{
|
|
106
|
-
afterMiddlewares.unshift(afterMiddleware);
|
|
107
|
-
return middy;
|
|
108
|
-
};
|
|
109
|
-
middy.onError = (onErrorMiddleware)=>{
|
|
110
|
-
onErrorMiddlewares.unshift(onErrorMiddleware);
|
|
111
|
-
return middy;
|
|
112
|
-
};
|
|
113
|
-
middy.handler = (replaceLambdaHandler)=>{
|
|
114
|
-
lambdaHandler = replaceLambdaHandler;
|
|
115
|
-
return middy;
|
|
116
|
-
};
|
|
117
|
-
return middy;
|
|
118
|
-
};
|
|
119
|
-
const runRequest = async (request, beforeMiddlewares, lambdaHandler, afterMiddlewares, onErrorMiddlewares, plugin)=>{
|
|
120
|
-
let timeoutAbort;
|
|
121
|
-
const timeoutEarly = plugin.timeoutEarly && request.context.getRemainingTimeInMillis // disable when AWS context missing (tests, containers)
|
|
122
|
-
;
|
|
123
|
-
try {
|
|
124
|
-
await runMiddlewares(request, beforeMiddlewares, plugin);
|
|
125
|
-
// Check if before stack hasn't exit early
|
|
126
|
-
if (typeof request.response === 'undefined') {
|
|
127
|
-
plugin.beforeHandler?.();
|
|
128
|
-
const handlerAbort = new AbortController();
|
|
129
|
-
if (timeoutEarly) timeoutAbort = new AbortController();
|
|
130
|
-
request.response = await Promise.race([
|
|
131
|
-
lambdaHandler(request.event, request.context, {
|
|
132
|
-
signal: handlerAbort.signal
|
|
133
|
-
}),
|
|
134
|
-
timeoutEarly ? (0, _promises1.setTimeout)(request.context.getRemainingTimeInMillis() - plugin.timeoutEarlyInMillis, undefined, {
|
|
135
|
-
signal: timeoutAbort.signal
|
|
136
|
-
}).then(()=>{
|
|
137
|
-
handlerAbort.abort();
|
|
138
|
-
return plugin.timeoutEarlyResponse();
|
|
139
|
-
}) : Promise.race([])
|
|
140
|
-
]);
|
|
141
|
-
timeoutAbort?.abort() // lambdaHandler may not be a promise
|
|
142
|
-
;
|
|
143
|
-
plugin.afterHandler?.();
|
|
144
|
-
await runMiddlewares(request, afterMiddlewares, plugin);
|
|
145
|
-
}
|
|
146
|
-
} catch (e) {
|
|
147
|
-
timeoutAbort?.abort() // timeout should be aborted on errors
|
|
148
|
-
;
|
|
149
|
-
// Reset response changes made by after stack before error thrown
|
|
150
|
-
request.response = undefined;
|
|
151
|
-
request.error = e;
|
|
152
|
-
try {
|
|
153
|
-
await runMiddlewares(request, onErrorMiddlewares, plugin);
|
|
154
|
-
} catch (e) {
|
|
155
|
-
// Save error that wasn't handled
|
|
156
|
-
e.originalError = request.error;
|
|
157
|
-
request.error = e;
|
|
158
|
-
throw request.error;
|
|
159
|
-
}
|
|
160
|
-
// Catch if onError stack hasn't handled the error
|
|
161
|
-
if (typeof request.response === 'undefined') throw request.error;
|
|
162
|
-
} finally{
|
|
163
|
-
await plugin.requestEnd?.(request);
|
|
164
|
-
}
|
|
165
|
-
return request.response;
|
|
166
|
-
};
|
|
167
|
-
const runMiddlewares = async (request, middlewares, plugin)=>{
|
|
168
|
-
for (const nextMiddleware of middlewares){
|
|
169
|
-
plugin.beforeMiddleware?.(nextMiddleware.name);
|
|
170
|
-
const res = await nextMiddleware(request);
|
|
171
|
-
plugin.afterMiddleware?.(nextMiddleware.name);
|
|
172
|
-
// short circuit chaining and respond early
|
|
173
|
-
if (typeof res !== 'undefined') {
|
|
174
|
-
request.response = res;
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
const _default = middy;
|
|
180
|
-
|