serverless-offline 9.2.3 → 9.2.6
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 +2 -2
- package/package.json +1 -1
- package/src/ServerlessOffline.js +11 -2
- package/src/config/colors.js +10 -0
- package/src/config/commandOptions.js +2 -1
- package/src/events/http/HttpServer.js +1 -6
- package/src/lambda/handler-runner/HandlerRunner.js +8 -1
- package/src/lambda/handler-runner/in-process-runner/InProcessRunner.js +7 -17
- package/src/utils/logRoutes.js +13 -13
package/README.md
CHANGED
|
@@ -137,7 +137,7 @@ All CLI options are optional:
|
|
|
137
137
|
--printOutput Turns on logging of your lambda outputs in the terminal.
|
|
138
138
|
--reloadHandler Reloads handler with each request.
|
|
139
139
|
--resourceRoutes Turns on loading of your HTTP proxy settings from serverless.yml
|
|
140
|
-
--useChildProcesses Run handlers in a child process
|
|
140
|
+
--useChildProcesses [This option is deprecated] Run handlers in a child process.
|
|
141
141
|
--useDocker Run handlers in a docker container.
|
|
142
142
|
--useInProcess Run handlers in the same process as 'serverless-offline'.
|
|
143
143
|
--webSocketHardTimeout Set WebSocket hard timeout in seconds to reproduce AWS limits (https://docs.aws.amazon.com/apigateway/latest/developerguide/limits.html#apigateway-execution-service-websocket-limits-table). Default: 7200 (2 hours)
|
|
@@ -188,7 +188,7 @@ Lambda handlers for the `node.js` runtime can run in different execution modes w
|
|
|
188
188
|
- global state is being shared across lambda handlers as well as with `serverless` and `serverless-offline`
|
|
189
189
|
- easy debugging
|
|
190
190
|
|
|
191
|
-
#### child-processes
|
|
191
|
+
#### child-processes (this option is deprecated, please use the default worker-threads instead)
|
|
192
192
|
|
|
193
193
|
- handlers run in a separate node.js instance
|
|
194
194
|
- memory is not being shared between handlers, memory consumption is therefore higher
|
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.2.
|
|
4
|
+
"version": "9.2.6",
|
|
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
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import process, { exit } from 'node:process'
|
|
2
2
|
import { log } from '@serverless/utils/log.js'
|
|
3
|
-
import chalk from 'chalk'
|
|
4
3
|
import {
|
|
5
4
|
commandOptions,
|
|
6
5
|
CUSTOM_OPTION,
|
|
7
6
|
defaultOptions,
|
|
8
7
|
SERVER_SHUTDOWN_TIMEOUT,
|
|
9
8
|
} from './config/index.js'
|
|
9
|
+
import { gray, orange } from './config/colors.js'
|
|
10
10
|
|
|
11
11
|
export default class ServerlessOffline {
|
|
12
12
|
#cliOptions = null
|
|
@@ -83,6 +83,15 @@ export default class ServerlessOffline {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
await Promise.all(eventModules)
|
|
86
|
+
|
|
87
|
+
if (this.#options.useChildProcesses) {
|
|
88
|
+
log.notice()
|
|
89
|
+
log.warning(
|
|
90
|
+
orange(`'--useChildProcesses' is deprecated and will be removed in the next major version. Worker threads, the current default, should provide the same if not an even better developer experience.
|
|
91
|
+
If you are experiencing any issues please let us know: https://github.com/dherault/serverless-offline/issues`),
|
|
92
|
+
)
|
|
93
|
+
log.notice()
|
|
94
|
+
}
|
|
86
95
|
}
|
|
87
96
|
|
|
88
97
|
async #ready() {
|
|
@@ -247,7 +256,7 @@ export default class ServerlessOffline {
|
|
|
247
256
|
log.notice(
|
|
248
257
|
`Starting Offline at stage ${
|
|
249
258
|
this.#options.stage || provider.stage
|
|
250
|
-
} ${
|
|
259
|
+
} ${gray(`(${this.#options.region || provider.region})`)}`,
|
|
251
260
|
)
|
|
252
261
|
log.notice()
|
|
253
262
|
log.debug('options:', this.#options)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
|
|
3
|
+
export const dodgerblue = chalk.hex('#1e90ff')
|
|
4
|
+
export const gray = chalk.hex('#808080')
|
|
5
|
+
export const lime = chalk.hex('#00ff00')
|
|
6
|
+
export const orange = chalk.hex('#ffa500')
|
|
7
|
+
export const peachpuff = chalk.hex('#ffdab9')
|
|
8
|
+
export const plum = chalk.hex('#dda0dd')
|
|
9
|
+
export const red = chalk.hex('#ff0000')
|
|
10
|
+
export const yellow = chalk.hex('#ffff00')
|
|
@@ -132,7 +132,8 @@ export default {
|
|
|
132
132
|
},
|
|
133
133
|
useChildProcesses: {
|
|
134
134
|
type: 'boolean',
|
|
135
|
-
usage:
|
|
135
|
+
usage:
|
|
136
|
+
'[This option is deprecated] Use separate node process to run handlers.',
|
|
136
137
|
},
|
|
137
138
|
useDocker: {
|
|
138
139
|
type: 'boolean',
|
|
@@ -788,12 +788,6 @@ export default class HttpServer {
|
|
|
788
788
|
response.variety = 'buffer'
|
|
789
789
|
} else if (typeof result === 'string') {
|
|
790
790
|
response.source = stringify(result)
|
|
791
|
-
} else if (result && result.body && typeof result.body !== 'string') {
|
|
792
|
-
return this.#reply502(
|
|
793
|
-
response,
|
|
794
|
-
'According to the API Gateway specs, the body content must be stringified. Check your Lambda response and make sure you are invoking JSON.stringify(YOUR_CONTENT) on your body object',
|
|
795
|
-
{},
|
|
796
|
-
)
|
|
797
791
|
} else {
|
|
798
792
|
response.source = result
|
|
799
793
|
}
|
|
@@ -888,6 +882,7 @@ export default class HttpServer {
|
|
|
888
882
|
response.variety = 'buffer'
|
|
889
883
|
} else {
|
|
890
884
|
if (result && result.body && typeof result.body !== 'string') {
|
|
885
|
+
// FIXME TODO we should probably just write to console instead of returning a payload
|
|
891
886
|
return this.#reply502(
|
|
892
887
|
response,
|
|
893
888
|
'According to the API Gateway specs, the body content must be stringified. Check your Lambda response and make sure you are invoking JSON.stringify(YOUR_CONTENT) on your body object',
|
|
@@ -123,6 +123,13 @@ export default class HandlerRunner {
|
|
|
123
123
|
this.#runner = await this.#loadRunner()
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
try {
|
|
127
|
+
return await this.#runner.run(event, context)
|
|
128
|
+
} catch (err) {
|
|
129
|
+
log.error(
|
|
130
|
+
`Unhandled exception in handler '${this.#funOptions.functionKey}'.`,
|
|
131
|
+
)
|
|
132
|
+
throw err
|
|
133
|
+
}
|
|
127
134
|
}
|
|
128
135
|
}
|
|
@@ -11,8 +11,6 @@ export default class InProcessRunner {
|
|
|
11
11
|
|
|
12
12
|
#env = null
|
|
13
13
|
|
|
14
|
-
#functionKey = null
|
|
15
|
-
|
|
16
14
|
#handler = null
|
|
17
15
|
|
|
18
16
|
#servicePath = null
|
|
@@ -20,11 +18,10 @@ export default class InProcessRunner {
|
|
|
20
18
|
#timeout = null
|
|
21
19
|
|
|
22
20
|
constructor(funOptions, env) {
|
|
23
|
-
const { codeDir,
|
|
21
|
+
const { codeDir, handler, servicePath, timeout } = funOptions
|
|
24
22
|
|
|
25
23
|
this.#codeDir = codeDir
|
|
26
24
|
this.#env = env
|
|
27
|
-
this.#functionKey = functionKey
|
|
28
25
|
this.#handler = handler
|
|
29
26
|
this.#servicePath = servicePath
|
|
30
27
|
this.#timeout = timeout
|
|
@@ -48,7 +45,7 @@ export default class InProcessRunner {
|
|
|
48
45
|
|
|
49
46
|
let callback
|
|
50
47
|
|
|
51
|
-
const
|
|
48
|
+
const callbackWrapper = new Promise((res, rej) => {
|
|
52
49
|
callback = (err, data) => {
|
|
53
50
|
if (err === 'Unauthorized') {
|
|
54
51
|
res('Unauthorized')
|
|
@@ -85,29 +82,22 @@ export default class InProcessRunner {
|
|
|
85
82
|
},
|
|
86
83
|
}
|
|
87
84
|
|
|
88
|
-
let result
|
|
89
|
-
|
|
90
85
|
// execute (run) handler
|
|
91
|
-
try
|
|
92
|
-
|
|
93
|
-
} catch {
|
|
94
|
-
throw new Error(`Uncaught error in '${this.#functionKey}' handler.`)
|
|
95
|
-
}
|
|
86
|
+
// no try/catch so that errors bubble up and are logged with root stack traces
|
|
87
|
+
const result = handler(event, lambdaContext, callback)
|
|
96
88
|
|
|
97
89
|
// // not a Promise, which is not supported by aws
|
|
98
90
|
// if (result == null || typeof result.then !== 'function') {
|
|
99
91
|
// throw new Error(`Synchronous function execution is not supported.`)
|
|
100
92
|
// }
|
|
101
93
|
|
|
102
|
-
const
|
|
94
|
+
const responses = [callbackWrapper]
|
|
103
95
|
|
|
104
96
|
// Promise was returned
|
|
105
97
|
if (result != null && typeof result.then === 'function') {
|
|
106
|
-
|
|
98
|
+
responses.push(result)
|
|
107
99
|
}
|
|
108
100
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return callbackResult
|
|
101
|
+
return Promise.race(responses)
|
|
112
102
|
}
|
|
113
103
|
}
|
package/src/utils/logRoutes.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import boxen from 'boxen'
|
|
2
|
-
import
|
|
2
|
+
import {
|
|
3
|
+
dodgerblue,
|
|
4
|
+
gray,
|
|
5
|
+
lime,
|
|
6
|
+
orange,
|
|
7
|
+
peachpuff,
|
|
8
|
+
plum,
|
|
9
|
+
red,
|
|
10
|
+
yellow,
|
|
11
|
+
} from '../config/colors.js'
|
|
3
12
|
|
|
4
13
|
const { max } = Math
|
|
5
14
|
|
|
6
|
-
const dodgerblue = chalk.hex('#1e90ff')
|
|
7
|
-
const grey = chalk.hex('#808080')
|
|
8
|
-
const lime = chalk.hex('#00ff00')
|
|
9
|
-
const orange = chalk.hex('#ffa500')
|
|
10
|
-
const peachpuff = chalk.hex('#ffdab9')
|
|
11
|
-
const plum = chalk.hex('#dda0dd')
|
|
12
|
-
const red = chalk.hex('#ff0000')
|
|
13
|
-
const yellow = chalk.hex('#ffff00')
|
|
14
|
-
|
|
15
15
|
const colorMethodMapping = new Map([
|
|
16
16
|
['DELETE', red],
|
|
17
17
|
['GET', dodgerblue],
|
|
@@ -28,9 +28,9 @@ function logRoute(method, server, path, maxLength, dimPath = false) {
|
|
|
28
28
|
const methodColor = colorMethodMapping.get(method) ?? peachpuff
|
|
29
29
|
const methodFormatted = method.padEnd(maxLength, ' ')
|
|
30
30
|
|
|
31
|
-
return `${methodColor(methodFormatted)} ${yellow.dim('|')} ${
|
|
31
|
+
return `${methodColor(methodFormatted)} ${yellow.dim('|')} ${gray.dim(
|
|
32
32
|
server,
|
|
33
|
-
)}${dimPath ?
|
|
33
|
+
)}${dimPath ? gray.dim(path) : lime(path)}`
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
function getMaxHttpMethodNameLength(routeInfo) {
|
|
@@ -51,7 +51,7 @@ export default function logRoutes(routeInfo) {
|
|
|
51
51
|
boxen(
|
|
52
52
|
routeInfo
|
|
53
53
|
.map(
|
|
54
|
-
({ method, path, server
|
|
54
|
+
({ invokePath, method, path, server }) =>
|
|
55
55
|
// eslint-disable-next-line prefer-template
|
|
56
56
|
logRoute(method, server, path, maxLength) +
|
|
57
57
|
'\n' +
|