serverless-offline 9.1.4 → 9.1.7
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/package.json +1 -1
- package/src/ServerlessOffline.js +29 -29
- package/src/config/defaultOptions.js +1 -1
- package/src/events/http/HttpServer.js +22 -10
- package/src/events/http/lambda-events/LambdaProxyIntegrationEvent.js +4 -1
- package/src/events/schedule/ScheduleEvent.js +19 -11
- package/src/events/websocket/HttpServer.js +2 -2
- package/src/events/websocket/WebSocketServer.js +2 -2
- package/src/events/websocket/lambda-events/WebSocketConnectEvent.js +1 -1
- package/src/lambda/HttpServer.js +5 -3
- package/src/lambda/handler-runner/child-process-runner/ChildProcessRunner.js +11 -15
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dedicatedTo": "Blue, a great migrating bird.",
|
|
3
3
|
"name": "serverless-offline",
|
|
4
|
-
"version": "9.1.
|
|
4
|
+
"version": "9.1.7",
|
|
5
5
|
"description": "Emulate AWS λ and API Gateway locally when developing your Serverless project",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "./src/index.js",
|
package/src/ServerlessOffline.js
CHANGED
|
@@ -23,38 +23,38 @@ export default class ServerlessOffline {
|
|
|
23
23
|
|
|
24
24
|
#webSocket = null
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
lifecycleEvents: ['init', 'ready', 'end'],
|
|
40
|
-
options: commandOptions,
|
|
41
|
-
usage:
|
|
42
|
-
'Simulates API Gateway to call your lambda functions offline using backward compatible initialization.',
|
|
43
|
-
},
|
|
26
|
+
commands = {
|
|
27
|
+
offline: {
|
|
28
|
+
// add start nested options
|
|
29
|
+
commands: {
|
|
30
|
+
functionsUpdated: {
|
|
31
|
+
lifecycleEvents: ['cleanup'],
|
|
32
|
+
type: 'entrypoint',
|
|
33
|
+
},
|
|
34
|
+
start: {
|
|
35
|
+
lifecycleEvents: ['init', 'ready', 'end'],
|
|
36
|
+
options: commandOptions,
|
|
37
|
+
usage:
|
|
38
|
+
'Simulates API Gateway to call your lambda functions offline using backward compatible initialization.',
|
|
44
39
|
},
|
|
45
|
-
lifecycleEvents: ['start'],
|
|
46
|
-
options: commandOptions,
|
|
47
|
-
usage: 'Simulates API Gateway to call your lambda functions offline.',
|
|
48
40
|
},
|
|
49
|
-
|
|
41
|
+
lifecycleEvents: ['start'],
|
|
42
|
+
options: commandOptions,
|
|
43
|
+
usage: 'Simulates API Gateway to call your lambda functions offline.',
|
|
44
|
+
},
|
|
45
|
+
}
|
|
50
46
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
47
|
+
hooks = {
|
|
48
|
+
'offline:functionsUpdated:cleanup': this.#cleanupFunctions.bind(this),
|
|
49
|
+
'offline:start': this.#startWithExplicitEnd.bind(this),
|
|
50
|
+
'offline:start:end': this.end.bind(this),
|
|
51
|
+
'offline:start:init': this.start.bind(this),
|
|
52
|
+
'offline:start:ready': this.#ready.bind(this),
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
constructor(serverless, cliOptions) {
|
|
56
|
+
this.#cliOptions = cliOptions
|
|
57
|
+
this.#serverless = serverless
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
// Entry point for the plugin (sls offline) when running 'sls offline start'
|
|
@@ -49,6 +49,18 @@ export default class HttpServer {
|
|
|
49
49
|
this.#serverless = serverless
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
async #loadCerts(httpsProtocol) {
|
|
53
|
+
const [cert, key] = await Promise.all([
|
|
54
|
+
readFile(resolve(httpsProtocol, 'cert.pem'), 'utf-8'),
|
|
55
|
+
readFile(resolve(httpsProtocol, 'key.pem'), 'utf-8'),
|
|
56
|
+
])
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
cert,
|
|
60
|
+
key,
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
52
64
|
async createServer() {
|
|
53
65
|
const {
|
|
54
66
|
enforceSecureCookies,
|
|
@@ -77,14 +89,10 @@ export default class HttpServer {
|
|
|
77
89
|
isSameSite: false,
|
|
78
90
|
isSecure: false,
|
|
79
91
|
},
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
serverOptions.tls = {
|
|
85
|
-
cert: readFile(resolve(httpsProtocol, 'cert.pem'), 'ascii'),
|
|
86
|
-
key: readFile(resolve(httpsProtocol, 'key.pem'), 'ascii'),
|
|
87
|
-
}
|
|
92
|
+
// https support
|
|
93
|
+
...(httpsProtocol != null && {
|
|
94
|
+
tls: await this.#loadCerts(httpsProtocol),
|
|
95
|
+
}),
|
|
88
96
|
}
|
|
89
97
|
|
|
90
98
|
// Hapijs server creation
|
|
@@ -103,7 +111,9 @@ export default class HttpServer {
|
|
|
103
111
|
? request.response.output
|
|
104
112
|
: request.response
|
|
105
113
|
|
|
106
|
-
const explicitlySetHeaders = {
|
|
114
|
+
const explicitlySetHeaders = {
|
|
115
|
+
...response.headers,
|
|
116
|
+
}
|
|
107
117
|
|
|
108
118
|
if (
|
|
109
119
|
this.#serverless.service.provider.httpApi &&
|
|
@@ -1010,7 +1020,9 @@ export default class HttpServer {
|
|
|
1010
1020
|
auth: authStrategyName,
|
|
1011
1021
|
cors,
|
|
1012
1022
|
state,
|
|
1013
|
-
timeout: {
|
|
1023
|
+
timeout: {
|
|
1024
|
+
socket: false,
|
|
1025
|
+
},
|
|
1014
1026
|
}
|
|
1015
1027
|
|
|
1016
1028
|
// skip HEAD routes as hapi will fail with 'Method name not allowed: HEAD ...'
|
|
@@ -146,7 +146,10 @@ export default class LambdaProxyIntegrationEvent {
|
|
|
146
146
|
const httpMethod = method.toUpperCase()
|
|
147
147
|
const requestTime = formatToClfTime(received)
|
|
148
148
|
const requestTimeEpoch = received
|
|
149
|
-
|
|
149
|
+
// NOTE replace * added by generateHapiPath util so api gateway event is accurate
|
|
150
|
+
const resource =
|
|
151
|
+
this.#routeKey ||
|
|
152
|
+
route.path.replace(`/${this.#stage}`, '').replace('*', '+')
|
|
150
153
|
|
|
151
154
|
return {
|
|
152
155
|
body,
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
import { createUniqueId } from '../../utils/index.js'
|
|
2
2
|
|
|
3
3
|
export default class ScheduleEvent {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
account = createUniqueId()
|
|
5
|
+
|
|
6
|
+
detail = {};
|
|
7
|
+
|
|
8
|
+
['detail-type'] = 'Scheduled Event'
|
|
9
|
+
|
|
10
|
+
id = createUniqueId()
|
|
11
|
+
|
|
12
|
+
region = null
|
|
7
13
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
resources = []
|
|
15
|
+
|
|
16
|
+
source = 'aws.events'
|
|
17
|
+
|
|
18
|
+
// format of aws displaying the time, e.g.: 2020-02-09T14:13:57Z
|
|
19
|
+
time = new Date().toISOString().replace(/\.(.*)(?=Z)/g, '')
|
|
20
|
+
|
|
21
|
+
version = '0'
|
|
22
|
+
|
|
23
|
+
constructor(region) {
|
|
12
24
|
this.region = region
|
|
13
|
-
this.resources = []
|
|
14
|
-
this.source = 'aws.events'
|
|
15
|
-
this.time = time
|
|
16
|
-
this.version = '0'
|
|
17
25
|
}
|
|
18
26
|
}
|
|
@@ -50,8 +50,8 @@ export default class HttpServer {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
log.notice(
|
|
53
|
-
`Offline [http for websocket] listening on
|
|
54
|
-
httpsProtocol ? '
|
|
53
|
+
`Offline [http for websocket] listening on ${
|
|
54
|
+
httpsProtocol ? 'https' : 'http'
|
|
55
55
|
}://${host}:${websocketPort}`,
|
|
56
56
|
)
|
|
57
57
|
}
|
|
@@ -58,8 +58,8 @@ export default class WebSocketServer {
|
|
|
58
58
|
const { host, httpsProtocol, websocketPort } = this.#options
|
|
59
59
|
|
|
60
60
|
log.notice(
|
|
61
|
-
`Offline [websocket] listening on
|
|
62
|
-
httpsProtocol ? '
|
|
61
|
+
`Offline [websocket] listening on ${
|
|
62
|
+
httpsProtocol ? 'wss' : 'ws'
|
|
63
63
|
}://${host}:${websocketPort}`,
|
|
64
64
|
)
|
|
65
65
|
}
|
|
@@ -37,7 +37,7 @@ export default class WebSocketConnectEvent {
|
|
|
37
37
|
// 'X-Amzn-Trace-Id': `Root=${createUniqueId()}`,
|
|
38
38
|
// 'X-Forwarded-For': '127.0.0.1',
|
|
39
39
|
// 'X-Forwarded-Port': String(this.#websocketPort),
|
|
40
|
-
// 'X-Forwarded-Proto':
|
|
40
|
+
// 'X-Forwarded-Proto': ${httpsProtocol ? 'https' : 'http'},
|
|
41
41
|
// }
|
|
42
42
|
|
|
43
43
|
const headers = parseHeaders(this.#rawHeaders)
|
package/src/lambda/HttpServer.js
CHANGED
|
@@ -44,13 +44,15 @@ export default class HttpServer {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
log.notice(
|
|
47
|
-
`Offline [http for lambda] listening on
|
|
48
|
-
httpsProtocol ? '
|
|
47
|
+
`Offline [http for lambda] listening on ${
|
|
48
|
+
httpsProtocol ? 'https' : 'http'
|
|
49
49
|
}://${host}:${lambdaPort}`,
|
|
50
50
|
)
|
|
51
51
|
|
|
52
52
|
// Print all the invocation routes to debug
|
|
53
|
-
const basePath =
|
|
53
|
+
const basePath = `${
|
|
54
|
+
httpsProtocol ? 'https' : 'http'
|
|
55
|
+
}://${host}:${lambdaPort}`
|
|
54
56
|
const funcNamePairs = this.#lambda.listFunctionNamePairs()
|
|
55
57
|
|
|
56
58
|
log.notice(
|
|
@@ -41,19 +41,6 @@ export default class ChildProcessRunner {
|
|
|
41
41
|
},
|
|
42
42
|
)
|
|
43
43
|
|
|
44
|
-
let message
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
message = new Promise((res, rej) => {
|
|
48
|
-
childProcess.on('message', (data) => {
|
|
49
|
-
if (data.error) rej(data.error)
|
|
50
|
-
else res(data)
|
|
51
|
-
})
|
|
52
|
-
})
|
|
53
|
-
} finally {
|
|
54
|
-
childProcess.kill()
|
|
55
|
-
}
|
|
56
|
-
|
|
57
44
|
childProcess.send({
|
|
58
45
|
context,
|
|
59
46
|
event,
|
|
@@ -63,12 +50,21 @@ export default class ChildProcessRunner {
|
|
|
63
50
|
let result
|
|
64
51
|
|
|
65
52
|
try {
|
|
66
|
-
result = await
|
|
53
|
+
result = await new Promise((res, rej) => {
|
|
54
|
+
childProcess.on('message', (data) => {
|
|
55
|
+
if (data.error) {
|
|
56
|
+
rej(data.error)
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
res(data)
|
|
60
|
+
})
|
|
61
|
+
})
|
|
67
62
|
} catch (err) {
|
|
68
63
|
// TODO
|
|
69
64
|
log.error(err)
|
|
70
|
-
|
|
71
65
|
throw err
|
|
66
|
+
} finally {
|
|
67
|
+
childProcess.kill()
|
|
72
68
|
}
|
|
73
69
|
|
|
74
70
|
return result
|