@middy/core 5.0.0-alpha.0 → 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/README.md +3 -2
- package/index.d.ts +120 -31
- package/index.js +201 -120
- package/package.json +6 -9
- package/index.cjs +0 -136
package/README.md
CHANGED
|
@@ -19,8 +19,9 @@
|
|
|
19
19
|
<a href="https://snyk.io/test/github/middyjs/middy">
|
|
20
20
|
<img src="https://snyk.io/test/github/middyjs/middy/badge.svg" alt="Known Vulnerabilities" data-canonical-src="https://snyk.io/test/github/middyjs/middy" style="max-width:100%;">
|
|
21
21
|
</a>
|
|
22
|
-
<a href="https://
|
|
23
|
-
<img src="https://
|
|
22
|
+
<a href="https://github.com/middyjs/middy/actions/workflows/sast.yml">
|
|
23
|
+
<img src="https://github.com/middyjs/middy/actions/workflows/sast.yml/badge.svg
|
|
24
|
+
?branch=main&event=push" alt="CodeQL" style="max-width:100%;">
|
|
24
25
|
</a>
|
|
25
26
|
<a href="https://bestpractices.coreinfrastructure.org/projects/5280">
|
|
26
27
|
<img src="https://bestpractices.coreinfrastructure.org/projects/5280/badge" alt="Core Infrastructure Initiative (CII) Best Practices" style="max-width:100%;">
|
package/index.d.ts
CHANGED
|
@@ -6,7 +6,9 @@ import {
|
|
|
6
6
|
|
|
7
7
|
declare type PluginHook = () => void
|
|
8
8
|
declare type PluginHookWithMiddlewareName = (middlewareName: string) => void
|
|
9
|
-
declare type PluginHookPromise = (
|
|
9
|
+
declare type PluginHookPromise = (
|
|
10
|
+
request: Request
|
|
11
|
+
) => Promise<unknown> | unknown
|
|
10
12
|
|
|
11
13
|
interface PluginObject {
|
|
12
14
|
internal?: any
|
|
@@ -19,62 +21,149 @@ interface PluginObject {
|
|
|
19
21
|
timeoutEarlyResponse?: PluginHook
|
|
20
22
|
afterHandler?: PluginHook
|
|
21
23
|
requestEnd?: PluginHookPromise
|
|
24
|
+
streamifyResponse?: Boolean
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
export interface Request<
|
|
27
|
+
export interface Request<
|
|
28
|
+
TEvent = any,
|
|
29
|
+
TResult = any,
|
|
30
|
+
TErr = Error,
|
|
31
|
+
TContext extends LambdaContext = LambdaContext,
|
|
32
|
+
TInternal extends Record<string, unknown> = {}
|
|
33
|
+
> {
|
|
25
34
|
event: TEvent
|
|
26
35
|
context: TContext
|
|
27
36
|
response: TResult | null
|
|
28
37
|
error: TErr | null
|
|
29
|
-
internal:
|
|
30
|
-
[key: string]: any
|
|
31
|
-
}
|
|
38
|
+
internal: TInternal
|
|
32
39
|
}
|
|
33
40
|
|
|
34
|
-
declare type MiddlewareFn<
|
|
41
|
+
declare type MiddlewareFn<
|
|
42
|
+
TEvent = any,
|
|
43
|
+
TResult = any,
|
|
44
|
+
TErr = Error,
|
|
45
|
+
TContext extends LambdaContext = LambdaContext,
|
|
46
|
+
TInternal extends Record<string, unknown> = {}
|
|
47
|
+
> = (request: Request<TEvent, TResult, TErr, TContext, TInternal>) => any
|
|
35
48
|
|
|
36
|
-
export interface MiddlewareObj<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
49
|
+
export interface MiddlewareObj<
|
|
50
|
+
TEvent = unknown,
|
|
51
|
+
TResult = any,
|
|
52
|
+
TErr = Error,
|
|
53
|
+
TContext extends LambdaContext = LambdaContext,
|
|
54
|
+
TInternal extends Record<string, unknown> = {}
|
|
55
|
+
> {
|
|
56
|
+
before?: MiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>
|
|
57
|
+
after?: MiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>
|
|
58
|
+
onError?: MiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>
|
|
40
59
|
}
|
|
41
60
|
|
|
42
61
|
// The AWS provided Handler type uses void | Promise<TResult> so we have no choice but to follow and suppress the linter warning
|
|
43
62
|
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
|
44
|
-
type MiddyInputHandler<
|
|
45
|
-
|
|
63
|
+
type MiddyInputHandler<
|
|
64
|
+
TEvent,
|
|
65
|
+
TResult,
|
|
66
|
+
TContext extends LambdaContext = LambdaContext
|
|
67
|
+
> = (
|
|
68
|
+
event: TEvent,
|
|
69
|
+
context: TContext,
|
|
70
|
+
callback: LambdaCallback<TResult>
|
|
71
|
+
) => // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
|
72
|
+
void | Promise<TResult> | TResult
|
|
73
|
+
type MiddyInputPromiseHandler<
|
|
74
|
+
TEvent,
|
|
75
|
+
TResult,
|
|
76
|
+
TContext extends LambdaContext = LambdaContext
|
|
77
|
+
> = (event: TEvent, context: TContext) => Promise<TResult>
|
|
46
78
|
|
|
47
|
-
export interface MiddyfiedHandler<
|
|
79
|
+
export interface MiddyfiedHandler<
|
|
80
|
+
TEvent = any,
|
|
81
|
+
TResult = any,
|
|
82
|
+
TErr = Error,
|
|
83
|
+
TContext extends LambdaContext = LambdaContext,
|
|
84
|
+
TInternal extends Record<string, unknown> = {}
|
|
85
|
+
> extends MiddyInputHandler<TEvent, TResult, TContext>,
|
|
48
86
|
MiddyInputPromiseHandler<TEvent, TResult, TContext> {
|
|
49
|
-
use: UseFn<TEvent, TResult, TErr, TContext>
|
|
50
|
-
before: AttachMiddlewareFn<TEvent, TResult, TErr, TContext>
|
|
51
|
-
after: AttachMiddlewareFn<TEvent, TResult, TErr, TContext>
|
|
52
|
-
onError: AttachMiddlewareFn<TEvent, TResult, TErr, TContext>
|
|
53
|
-
handler: <TAdditional>(
|
|
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>
|
|
91
|
+
handler: <TAdditional>(
|
|
92
|
+
handler: MiddlewareHandler<
|
|
93
|
+
LambdaHandler<TEvent & TAdditional, TResult>,
|
|
94
|
+
TContext
|
|
95
|
+
>
|
|
96
|
+
) => MiddyfiedHandler<TEvent, TResult, TErr, TContext, TInternal>
|
|
54
97
|
}
|
|
55
98
|
|
|
56
|
-
declare type AttachMiddlewareFn<
|
|
57
|
-
|
|
99
|
+
declare type AttachMiddlewareFn<
|
|
100
|
+
TEvent = any,
|
|
101
|
+
TResult = any,
|
|
102
|
+
TErr = Error,
|
|
103
|
+
TContext extends LambdaContext = LambdaContext,
|
|
104
|
+
TInternal extends Record<string, unknown> = {}
|
|
105
|
+
> = (
|
|
106
|
+
middleware: MiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>
|
|
107
|
+
) => MiddyfiedHandler<TEvent, TResult, TErr, TContext, TInternal>
|
|
58
108
|
|
|
59
|
-
declare type AttachMiddlewareObj<
|
|
60
|
-
|
|
109
|
+
declare type AttachMiddlewareObj<
|
|
110
|
+
TEvent = any,
|
|
111
|
+
TResult = any,
|
|
112
|
+
TErr = Error,
|
|
113
|
+
TContext extends LambdaContext = LambdaContext,
|
|
114
|
+
TInternal extends Record<string, unknown> = {}
|
|
115
|
+
> = (
|
|
116
|
+
middleware: MiddlewareObj<TEvent, TResult, TErr, TContext, TInternal>
|
|
117
|
+
) => MiddyfiedHandler<TEvent, TResult, TErr, TContext, TInternal>
|
|
61
118
|
|
|
62
|
-
declare type UseFn<
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
119
|
+
declare type UseFn<
|
|
120
|
+
TEvent = any,
|
|
121
|
+
TResult = any,
|
|
122
|
+
TErr = Error,
|
|
123
|
+
TContext extends LambdaContext = LambdaContext,
|
|
124
|
+
TInternal extends Record<string, unknown> = {}
|
|
125
|
+
> = <TMiddleware extends MiddlewareObj<any, any, Error, any, any>>(
|
|
126
|
+
middlewares: TMiddleware | TMiddleware[]
|
|
127
|
+
) => TMiddleware extends MiddlewareObj<
|
|
128
|
+
infer TMiddlewareEvent,
|
|
129
|
+
any,
|
|
130
|
+
Error,
|
|
131
|
+
infer TMiddlewareContext,
|
|
132
|
+
infer TMiddlewareInternal
|
|
133
|
+
>
|
|
134
|
+
? MiddyfiedHandler<
|
|
135
|
+
TMiddlewareEvent & TEvent,
|
|
136
|
+
TResult,
|
|
137
|
+
TErr,
|
|
138
|
+
TMiddlewareContext & TContext,
|
|
139
|
+
TMiddlewareInternal & TInternal
|
|
140
|
+
> // always true
|
|
141
|
+
: never
|
|
66
142
|
|
|
67
|
-
declare type MiddlewareHandler<
|
|
68
|
-
THandler extends LambdaHandler<
|
|
69
|
-
|
|
70
|
-
|
|
143
|
+
declare type MiddlewareHandler<
|
|
144
|
+
THandler extends LambdaHandler<any, any>,
|
|
145
|
+
TContext extends LambdaContext = LambdaContext
|
|
146
|
+
> = THandler extends LambdaHandler<infer TEvent, infer TResult> // always true
|
|
147
|
+
? MiddyInputHandler<TEvent, TResult, TContext>
|
|
148
|
+
: never
|
|
71
149
|
|
|
72
150
|
/**
|
|
73
151
|
* Middy factory function. Use it to wrap your existing handler to enable middlewares on it.
|
|
74
152
|
* @param handler your original AWS Lambda function
|
|
75
153
|
* @param plugin wraps around each middleware and handler to add custom lifecycle behaviours (e.g. to profile performance)
|
|
76
154
|
*/
|
|
77
|
-
declare function middy<
|
|
155
|
+
declare function middy<
|
|
156
|
+
TEvent = unknown,
|
|
157
|
+
TResult = any,
|
|
158
|
+
TErr = Error,
|
|
159
|
+
TContext extends LambdaContext = LambdaContext,
|
|
160
|
+
TInternal extends Record<string, unknown> = {}
|
|
161
|
+
> (
|
|
162
|
+
handler?:
|
|
163
|
+
| MiddlewareHandler<LambdaHandler<TEvent, TResult>, TContext>
|
|
164
|
+
| PluginObject,
|
|
165
|
+
plugin?: PluginObject
|
|
166
|
+
): MiddyfiedHandler<TEvent, TResult, TErr, TContext, TInternal>
|
|
78
167
|
|
|
79
168
|
declare namespace middy {
|
|
80
169
|
export {
|
package/index.js
CHANGED
|
@@ -1,128 +1,209 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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 = () => {}
|
|
3
7
|
const defaultPlugin = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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 ?? {}
|
|
13
41
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
if (before) middy.before(before);
|
|
52
|
-
if (after) middy.after(after);
|
|
53
|
-
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
|
+
}
|
|
54
78
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
|
78
178
|
try {
|
|
79
|
-
|
|
80
|
-
if (typeof request.response === 'undefined') {
|
|
81
|
-
plugin.beforeHandler?.();
|
|
82
|
-
const handlerAbort = new AbortController();
|
|
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 ? setTimeout(request.context.getRemainingTimeInMillis() - plugin.timeoutEarlyInMillis, undefined, {
|
|
89
|
-
signal: timeoutAbort.signal
|
|
90
|
-
}).then(()=>{
|
|
91
|
-
handlerAbort.abort();
|
|
92
|
-
return plugin.timeoutEarlyResponse();
|
|
93
|
-
}) : Promise.race([])
|
|
94
|
-
]);
|
|
95
|
-
timeoutAbort?.abort();
|
|
96
|
-
plugin.afterHandler?.();
|
|
97
|
-
await runMiddlewares(request, afterMiddlewares, plugin);
|
|
98
|
-
}
|
|
179
|
+
await runMiddlewares(request, onErrorMiddlewares, plugin)
|
|
99
180
|
} catch (e) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
} catch (e) {
|
|
106
|
-
e.originalError = request.error;
|
|
107
|
-
request.error = e;
|
|
108
|
-
throw request.error;
|
|
109
|
-
}
|
|
110
|
-
if (typeof request.response === 'undefined') throw request.error;
|
|
111
|
-
} finally{
|
|
112
|
-
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
|
|
113
186
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
|
125
205
|
}
|
|
126
|
-
}
|
|
127
|
-
|
|
206
|
+
}
|
|
207
|
+
}
|
|
128
208
|
|
|
209
|
+
export default middy
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@middy/core",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
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": {
|
|
@@ -10,24 +10,18 @@
|
|
|
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": {
|
|
@@ -63,7 +57,10 @@
|
|
|
63
57
|
},
|
|
64
58
|
"devDependencies": {
|
|
65
59
|
"@types/aws-lambda": "^8.10.76",
|
|
66
|
-
"@types/node": "^
|
|
60
|
+
"@types/node": "^20.0.0"
|
|
67
61
|
},
|
|
68
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "ebce8d5df8783077fa49ba62ee9be20e8486a7f1",
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"@datastream/core": "0.0.35"
|
|
65
|
+
}
|
|
69
66
|
}
|
package/index.cjs
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(module, "exports", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: ()=>_default
|
|
8
|
-
});
|
|
9
|
-
const _promises = require("node:timers/promises");
|
|
10
|
-
const defaultLambdaHandler = ()=>{};
|
|
11
|
-
const defaultPlugin = {
|
|
12
|
-
timeoutEarlyInMillis: 5,
|
|
13
|
-
timeoutEarlyResponse: ()=>{
|
|
14
|
-
throw new Error('Timeout');
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
const middy = (lambdaHandler = defaultLambdaHandler, plugin = {})=>{
|
|
18
|
-
if (typeof lambdaHandler !== 'function') {
|
|
19
|
-
plugin = lambdaHandler;
|
|
20
|
-
lambdaHandler = defaultLambdaHandler;
|
|
21
|
-
}
|
|
22
|
-
plugin = {
|
|
23
|
-
...defaultPlugin,
|
|
24
|
-
...plugin
|
|
25
|
-
};
|
|
26
|
-
plugin.timeoutEarly = plugin.timeoutEarlyInMillis > 0;
|
|
27
|
-
plugin.beforePrefetch?.();
|
|
28
|
-
const beforeMiddlewares = [];
|
|
29
|
-
const afterMiddlewares = [];
|
|
30
|
-
const onErrorMiddlewares = [];
|
|
31
|
-
const middy = (event = {}, context = {})=>{
|
|
32
|
-
plugin.requestStart?.();
|
|
33
|
-
const request = {
|
|
34
|
-
event,
|
|
35
|
-
context,
|
|
36
|
-
response: undefined,
|
|
37
|
-
error: undefined,
|
|
38
|
-
internal: plugin.internal ?? {}
|
|
39
|
-
};
|
|
40
|
-
return runRequest(request, [
|
|
41
|
-
...beforeMiddlewares
|
|
42
|
-
], lambdaHandler, [
|
|
43
|
-
...afterMiddlewares
|
|
44
|
-
], [
|
|
45
|
-
...onErrorMiddlewares
|
|
46
|
-
], plugin);
|
|
47
|
-
};
|
|
48
|
-
middy.use = (middlewares)=>{
|
|
49
|
-
if (!Array.isArray(middlewares)) {
|
|
50
|
-
middlewares = [
|
|
51
|
-
middlewares
|
|
52
|
-
];
|
|
53
|
-
}
|
|
54
|
-
for (const middleware of middlewares){
|
|
55
|
-
const { before , after , onError } = middleware;
|
|
56
|
-
if (!before && !after && !onError) {
|
|
57
|
-
throw new Error('Middleware must be an object containing at least one key among "before", "after", "onError"');
|
|
58
|
-
}
|
|
59
|
-
if (before) middy.before(before);
|
|
60
|
-
if (after) middy.after(after);
|
|
61
|
-
if (onError) middy.onError(onError);
|
|
62
|
-
}
|
|
63
|
-
return middy;
|
|
64
|
-
};
|
|
65
|
-
middy.before = (beforeMiddleware)=>{
|
|
66
|
-
beforeMiddlewares.push(beforeMiddleware);
|
|
67
|
-
return middy;
|
|
68
|
-
};
|
|
69
|
-
middy.after = (afterMiddleware)=>{
|
|
70
|
-
afterMiddlewares.unshift(afterMiddleware);
|
|
71
|
-
return middy;
|
|
72
|
-
};
|
|
73
|
-
middy.onError = (onErrorMiddleware)=>{
|
|
74
|
-
onErrorMiddlewares.unshift(onErrorMiddleware);
|
|
75
|
-
return middy;
|
|
76
|
-
};
|
|
77
|
-
middy.handler = (replaceLambdaHandler)=>{
|
|
78
|
-
lambdaHandler = replaceLambdaHandler;
|
|
79
|
-
return middy;
|
|
80
|
-
};
|
|
81
|
-
return middy;
|
|
82
|
-
};
|
|
83
|
-
const runRequest = async (request, beforeMiddlewares, lambdaHandler, afterMiddlewares, onErrorMiddlewares, plugin)=>{
|
|
84
|
-
let timeoutAbort;
|
|
85
|
-
const timeoutEarly = plugin.timeoutEarly && request.context.getRemainingTimeInMillis;
|
|
86
|
-
try {
|
|
87
|
-
await runMiddlewares(request, beforeMiddlewares, plugin);
|
|
88
|
-
if (typeof request.response === 'undefined') {
|
|
89
|
-
plugin.beforeHandler?.();
|
|
90
|
-
const handlerAbort = new AbortController();
|
|
91
|
-
if (timeoutEarly) timeoutAbort = new AbortController();
|
|
92
|
-
request.response = await Promise.race([
|
|
93
|
-
lambdaHandler(request.event, request.context, {
|
|
94
|
-
signal: handlerAbort.signal
|
|
95
|
-
}),
|
|
96
|
-
timeoutEarly ? (0, _promises.setTimeout)(request.context.getRemainingTimeInMillis() - plugin.timeoutEarlyInMillis, undefined, {
|
|
97
|
-
signal: timeoutAbort.signal
|
|
98
|
-
}).then(()=>{
|
|
99
|
-
handlerAbort.abort();
|
|
100
|
-
return plugin.timeoutEarlyResponse();
|
|
101
|
-
}) : Promise.race([])
|
|
102
|
-
]);
|
|
103
|
-
timeoutAbort?.abort();
|
|
104
|
-
plugin.afterHandler?.();
|
|
105
|
-
await runMiddlewares(request, afterMiddlewares, plugin);
|
|
106
|
-
}
|
|
107
|
-
} catch (e) {
|
|
108
|
-
timeoutAbort?.abort();
|
|
109
|
-
request.response = undefined;
|
|
110
|
-
request.error = e;
|
|
111
|
-
try {
|
|
112
|
-
await runMiddlewares(request, onErrorMiddlewares, plugin);
|
|
113
|
-
} catch (e) {
|
|
114
|
-
e.originalError = request.error;
|
|
115
|
-
request.error = e;
|
|
116
|
-
throw request.error;
|
|
117
|
-
}
|
|
118
|
-
if (typeof request.response === 'undefined') throw request.error;
|
|
119
|
-
} finally{
|
|
120
|
-
await plugin.requestEnd?.(request);
|
|
121
|
-
}
|
|
122
|
-
return request.response;
|
|
123
|
-
};
|
|
124
|
-
const runMiddlewares = async (request, middlewares, plugin)=>{
|
|
125
|
-
for (const nextMiddleware of middlewares){
|
|
126
|
-
plugin.beforeMiddleware?.(nextMiddleware.name);
|
|
127
|
-
const res = await nextMiddleware(request);
|
|
128
|
-
plugin.afterMiddleware?.(nextMiddleware.name);
|
|
129
|
-
if (typeof res !== 'undefined') {
|
|
130
|
-
request.response = res;
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
const _default = middy;
|
|
136
|
-
|