serverless-offline 9.0.0 → 9.1.2
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 +109 -42
- package/package.json +3 -3
- package/src/ServerlessOffline.js +1 -4
- package/src/config/commandOptions.js +4 -0
- package/src/config/constants.js +2 -2
- package/src/config/defaultOptions.js +1 -0
- package/src/events/http/HttpServer.js +1 -42
- package/src/events/http/lambda-events/LambdaProxyIntegrationEvent.js +2 -12
- package/src/events/http/lambda-events/LambdaProxyIntegrationEventV2.js +2 -11
- package/src/events/schedule/Schedule.js +3 -3
- package/src/lambda/LambdaFunction.js +18 -17
- package/src/lambda/handler-runner/child-process-runner/ChildProcessRunner.js +10 -6
- package/src/lambda/handler-runner/docker-runner/DockerContainer.js +3 -1
- package/src/lambda/handler-runner/go-runner/GoRunner.js +22 -16
- package/src/lambda/handler-runner/in-process-runner/InProcessRunner.js +3 -2
- package/src/lambda/handler-runner/java-runner/JavaRunner.js +5 -3
- package/src/lambda/handler-runner/python-runner/PythonRunner.js +5 -4
- package/src/lambda/handler-runner/ruby-runner/RubyRunner.js +5 -3
- package/src/lambda/handler-runner/worker-thread-runner/workerThreadHelper.js +2 -2
- package/src/utils/resolveJoins.js +0 -29
package/README.md
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
<a href="https://www.npmjs.com/package/serverless-offline">
|
|
8
8
|
<img src="https://img.shields.io/npm/v/serverless-offline.svg?style=flat-square">
|
|
9
9
|
</a>
|
|
10
|
-
<a href="https://github.com/dherault/serverless-offline/actions
|
|
11
|
-
<img src="https://img.shields.io/github/workflow/status/dherault/serverless-offline/
|
|
10
|
+
<a href="https://github.com/dherault/serverless-offline/actions/workflows/integrate.yml">
|
|
11
|
+
<img src="https://img.shields.io/github/workflow/status/dherault/serverless-offline/Integrate">
|
|
12
12
|
</a>
|
|
13
13
|
<img src="https://img.shields.io/node/v/serverless-offline.svg?style=flat-square">
|
|
14
14
|
<a href="https://github.com/serverless/serverless">
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
This [Serverless](https://github.com/serverless/serverless) plugin emulates [AWS λ](https://aws.amazon.com/lambda) and [API Gateway](https://aws.amazon.com/api-gateway) on your local machine to speed up your development cycles.
|
|
30
30
|
To do so, it starts an HTTP server that handles the request's lifecycle like APIG does and invokes your handlers.
|
|
31
31
|
|
|
32
|
-
**Features
|
|
32
|
+
**Features**
|
|
33
33
|
|
|
34
|
-
- [Node.js](https://nodejs.org), [Python](https://www.python.org), [Ruby](https://www.ruby-lang.org)
|
|
34
|
+
- [Node.js](https://nodejs.org), [Python](https://www.python.org), [Ruby](https://www.ruby-lang.org), [Go](https://golang.org), [Java](https://www.java.com) (incl. [Kotlin](https://kotlinlang.org), [Groovy](https://groovy-lang.org), [Scala](https://www.scala-lang.org)) λ runtimes.
|
|
35
35
|
- Velocity templates support.
|
|
36
36
|
- Lazy loading of your handler files.
|
|
37
37
|
- And more: integrations, authorizers, proxies, timeouts, responseParameters, HTTPS, CORS, etc...
|
|
@@ -42,6 +42,7 @@ This plugin is updated by its users, I just do maintenance and ensure that PRs a
|
|
|
42
42
|
|
|
43
43
|
- [Installation](#installation)
|
|
44
44
|
- [Usage and command line options](#usage-and-command-line-options)
|
|
45
|
+
- [Run modes](#run-modes)
|
|
45
46
|
- [Usage with `invoke`](#usage-with-invoke)
|
|
46
47
|
- [The `process.env.IS_OFFLINE` variable](#the-processenvis_offline-variable)
|
|
47
48
|
- [Docker and Layers](#docker-and-layers)
|
|
@@ -84,7 +85,7 @@ Then inside your project's `serverless.yml` file add following entry to the plug
|
|
|
84
85
|
|
|
85
86
|
It should look something like this:
|
|
86
87
|
|
|
87
|
-
```
|
|
88
|
+
```yml
|
|
88
89
|
plugins:
|
|
89
90
|
- serverless-offline
|
|
90
91
|
```
|
|
@@ -127,6 +128,7 @@ All CLI options are optional:
|
|
|
127
128
|
--ignoreJWTSignature When using HttpApi with a JWT authorizer, don't check the signature of the JWT token. This should only be used for local development.
|
|
128
129
|
--lambdaPort Lambda http port to listen on. Default: 3002
|
|
129
130
|
--layersDir The directory layers should be stored in. Default: ${codeDir}/.serverless-offline/layers'
|
|
131
|
+
--localEnvironment Copy local environment variables. Default: false
|
|
130
132
|
--noAuth Turns off all authorizers
|
|
131
133
|
--noPrependStageInUrl Don't prepend http routes with the stage.
|
|
132
134
|
--noStripTrailingSlashInUrl Don't strip trailing slash from http routes.
|
|
@@ -145,13 +147,12 @@ All CLI options are optional:
|
|
|
145
147
|
|
|
146
148
|
Any of the CLI options can be added to your `serverless.yml`. For example:
|
|
147
149
|
|
|
148
|
-
```
|
|
150
|
+
```yml
|
|
149
151
|
custom:
|
|
150
152
|
serverless-offline:
|
|
151
|
-
httpsProtocol:
|
|
153
|
+
httpsProtocol: 'dev-certs'
|
|
152
154
|
httpPort: 4000
|
|
153
|
-
|
|
154
|
-
foo: "bar"
|
|
155
|
+
foo: 'bar'
|
|
155
156
|
```
|
|
156
157
|
|
|
157
158
|
Options passed on the command line override YAML options.
|
|
@@ -163,18 +164,64 @@ By default you can send your requests to `http://localhost:3000/`. Please note t
|
|
|
163
164
|
But if you send an `application/x-www-form-urlencoded` or a `multipart/form-data` body with an `application/json` (or no) Content-Type, API Gateway won't parse your data (you'll get the ugly raw as input), whereas the plugin will answer 400 (malformed JSON).
|
|
164
165
|
Please consider explicitly setting your requests' Content-Type and using separate templates.
|
|
165
166
|
|
|
167
|
+
## Run modes
|
|
168
|
+
|
|
169
|
+
### node.js
|
|
170
|
+
|
|
171
|
+
Lambda handlers for the `node.js` runtime can run in different execution modes with `serverless-offline` and they have subtle differences with a variety of pros and cons. they are mutually exclusive and it is planned to combine the flags into one single flag in the future.
|
|
172
|
+
|
|
173
|
+
#### worker-threads (default)
|
|
174
|
+
|
|
175
|
+
- handlers run in their own context
|
|
176
|
+
- memory is not being shared between handlers, memory consumption is therefore higher
|
|
177
|
+
- memory is being released when handlers reload or after usage
|
|
178
|
+
- environment (process.env) is not being shared across handlers
|
|
179
|
+
- global state is not being shared across handlers
|
|
180
|
+
- easy debugging
|
|
181
|
+
|
|
182
|
+
#### in-process
|
|
183
|
+
|
|
184
|
+
- handlers run in the same context (instance) as `serverless` and `serverless-offline`
|
|
185
|
+
- memory is being shared across lambda handlers as well as with `serverless` and `serverless-offline`
|
|
186
|
+
- no reloading capabilities as it is [currently] not possible to implement for commonjs handlers (without memory leaks) and for esm handlers
|
|
187
|
+
- environment (process.env) is being shared across handlers as well as with `serverless` and `serverless-offline`
|
|
188
|
+
- global state is being shared across lambda handlers as well as with `serverless` and `serverless-offline`
|
|
189
|
+
- easy debugging
|
|
190
|
+
|
|
191
|
+
#### child-processes
|
|
192
|
+
|
|
193
|
+
- handlers run in a separate node.js instance
|
|
194
|
+
- memory is not being shared between handlers, memory consumption is therefore higher
|
|
195
|
+
- memory is being released when handlers reload or after usage
|
|
196
|
+
- environment (process.env) is not being shared across handlers
|
|
197
|
+
- global state is not being shared across handlers
|
|
198
|
+
- debugging more complicated
|
|
199
|
+
|
|
200
|
+
#### docker
|
|
201
|
+
|
|
202
|
+
- handlers run in a docker container
|
|
203
|
+
- memory is not being shared between handlers, memory consumption is therefore higher
|
|
204
|
+
- memory is being released when handlers reload or after usage
|
|
205
|
+
- environment (process.env) is not being shared across handlers
|
|
206
|
+
- global state is not being shared across handlers
|
|
207
|
+
- debugging more complicated
|
|
208
|
+
|
|
209
|
+
### Python, Ruby, Go, Java (incl. Kotlin, Groovy, Scala)
|
|
210
|
+
|
|
211
|
+
the Lambda handler process is running in a child process.
|
|
212
|
+
|
|
166
213
|
## Usage with `invoke`
|
|
167
214
|
|
|
168
|
-
To use `Lambda.invoke` you need to set the lambda endpoint to the serverless-offline endpoint:
|
|
215
|
+
To use `Lambda.invoke` you need to set the lambda endpoint to the `serverless-offline` endpoint:
|
|
169
216
|
|
|
170
217
|
```js
|
|
218
|
+
const { env } = require('node:process')
|
|
171
219
|
const { Lambda } = require('aws-sdk')
|
|
172
220
|
|
|
173
221
|
const lambda = new Lambda({
|
|
174
222
|
apiVersion: '2015-03-31',
|
|
175
|
-
// endpoint needs to be set only if it deviates from the default
|
|
176
|
-
|
|
177
|
-
endpoint: process.env.SOME_VARIABLE
|
|
223
|
+
// endpoint needs to be set only if it deviates from the default
|
|
224
|
+
endpoint: env.IS_OFFLINE
|
|
178
225
|
? 'http://localhost:3002'
|
|
179
226
|
: 'https://lambda.us-east-1.amazonaws.com',
|
|
180
227
|
})
|
|
@@ -183,15 +230,33 @@ const lambda = new Lambda({
|
|
|
183
230
|
All your lambdas can then be invoked in a handler using
|
|
184
231
|
|
|
185
232
|
```js
|
|
233
|
+
const { Buffer } = require('node:buffer')
|
|
234
|
+
const { Lambda } = require('aws-sdk')
|
|
235
|
+
|
|
236
|
+
const { stringify } = JSON
|
|
237
|
+
|
|
238
|
+
const lambda = new Lambda({
|
|
239
|
+
apiVersion: '2015-03-31',
|
|
240
|
+
endpoint: 'http://localhost:3002',
|
|
241
|
+
})
|
|
242
|
+
|
|
186
243
|
exports.handler = async function () {
|
|
244
|
+
const clientContextData = stringify({ foo: 'foo' })
|
|
245
|
+
|
|
187
246
|
const params = {
|
|
247
|
+
ClientContext: Buffer.from(clientContextData).toString('base64'),
|
|
188
248
|
// FunctionName is composed of: service name - stage - function name, e.g.
|
|
189
249
|
FunctionName: 'myServiceName-dev-invokedHandler',
|
|
190
250
|
InvocationType: 'RequestResponse',
|
|
191
|
-
Payload:
|
|
251
|
+
Payload: stringify({ data: 'foo' }),
|
|
192
252
|
}
|
|
193
253
|
|
|
194
254
|
const response = await lambda.invoke(params).promise()
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
body: stringify(response),
|
|
258
|
+
statusCode: 200,
|
|
259
|
+
}
|
|
195
260
|
}
|
|
196
261
|
```
|
|
197
262
|
|
|
@@ -243,7 +308,7 @@ to calling it via `aws-sdk`.
|
|
|
243
308
|
|
|
244
309
|
## The `process.env.IS_OFFLINE` variable
|
|
245
310
|
|
|
246
|
-
Will be `"true"` in your handlers
|
|
311
|
+
Will be `"true"` in your handlers when using `serverless-offline`.
|
|
247
312
|
|
|
248
313
|
## Docker and Layers
|
|
249
314
|
|
|
@@ -266,14 +331,14 @@ If you're using least-privilege principals for your AWS roles, this policy shoul
|
|
|
266
331
|
|
|
267
332
|
```json
|
|
268
333
|
{
|
|
269
|
-
"Version": "2012-10-17",
|
|
270
334
|
"Statement": [
|
|
271
335
|
{
|
|
272
|
-
"Effect": "Allow",
|
|
273
336
|
"Action": "lambda:GetLayerVersion",
|
|
337
|
+
"Effect": "Allow",
|
|
274
338
|
"Resource": "arn:aws:lambda:*:*:layer:*:*"
|
|
275
339
|
}
|
|
276
|
-
]
|
|
340
|
+
],
|
|
341
|
+
"Version": "2012-10-17"
|
|
277
342
|
}
|
|
278
343
|
```
|
|
279
344
|
|
|
@@ -325,11 +390,11 @@ Only [custom authorizers](https://aws.amazon.com/blogs/compute/introducing-custo
|
|
|
325
390
|
|
|
326
391
|
The Custom authorizer is passed an `event` object as below:
|
|
327
392
|
|
|
328
|
-
```
|
|
393
|
+
```js
|
|
329
394
|
{
|
|
330
|
-
"type": "TOKEN",
|
|
331
395
|
"authorizationToken": "<Incoming bearer token>",
|
|
332
|
-
"methodArn": "arn:aws:execute-api:<Region id>:<Account id>:<API id>/<Stage>/<Method>/<Resource path>"
|
|
396
|
+
"methodArn": "arn:aws:execute-api:<Region id>:<Account id>:<API id>/<Stage>/<Method>/<Resource path>",
|
|
397
|
+
"type": "TOKEN"
|
|
333
398
|
}
|
|
334
399
|
```
|
|
335
400
|
|
|
@@ -337,11 +402,11 @@ The `methodArn` does not include the Account id or API id.
|
|
|
337
402
|
|
|
338
403
|
The plugin only supports retrieving Tokens from headers. You can configure the header as below:
|
|
339
404
|
|
|
340
|
-
```
|
|
405
|
+
```js
|
|
341
406
|
"authorizer": {
|
|
342
|
-
"
|
|
407
|
+
"authorizerResultTtlInSeconds": "0",
|
|
343
408
|
"identitySource": "method.request.header.Authorization", // or method.request.header.SomeOtherHeader
|
|
344
|
-
"
|
|
409
|
+
"type": "TOKEN"
|
|
345
410
|
}
|
|
346
411
|
```
|
|
347
412
|
|
|
@@ -369,14 +434,14 @@ If your authentication needs are custom and not satisfied by the existing capabi
|
|
|
369
434
|
```js
|
|
370
435
|
module.exports = function (endpoint, functionKey, method, path) {
|
|
371
436
|
return {
|
|
372
|
-
name: 'your strategy name',
|
|
373
|
-
scheme: 'your scheme name',
|
|
374
|
-
|
|
375
437
|
getAuthenticateFunction: () => ({
|
|
376
438
|
async authenticate(request, h) {
|
|
377
439
|
// your implementation
|
|
378
440
|
},
|
|
379
441
|
}),
|
|
442
|
+
|
|
443
|
+
name: 'your strategy name',
|
|
444
|
+
scheme: 'your scheme name',
|
|
380
445
|
}
|
|
381
446
|
}
|
|
382
447
|
```
|
|
@@ -440,7 +505,7 @@ Now let's make a request with this body: `{ "id": 1 }`
|
|
|
440
505
|
|
|
441
506
|
AWS parses the event as such:
|
|
442
507
|
|
|
443
|
-
```
|
|
508
|
+
```js
|
|
444
509
|
{
|
|
445
510
|
"payload": {
|
|
446
511
|
"id": 1
|
|
@@ -452,7 +517,7 @@ AWS parses the event as such:
|
|
|
452
517
|
|
|
453
518
|
Whereas Offline parses:
|
|
454
519
|
|
|
455
|
-
```
|
|
520
|
+
```js
|
|
456
521
|
{
|
|
457
522
|
"payload": {
|
|
458
523
|
"id": 1
|
|
@@ -504,7 +569,7 @@ Works out of the box. See examples in the manual_test directory.
|
|
|
504
569
|
|
|
505
570
|
Example of enabling proxy:
|
|
506
571
|
|
|
507
|
-
```
|
|
572
|
+
```yml
|
|
508
573
|
custom:
|
|
509
574
|
serverless-offline:
|
|
510
575
|
resourceRoutes: true
|
|
@@ -512,18 +577,18 @@ custom:
|
|
|
512
577
|
|
|
513
578
|
or
|
|
514
579
|
|
|
515
|
-
```
|
|
580
|
+
```yml
|
|
516
581
|
YourCloudFormationMethodId:
|
|
517
|
-
Type: AWS::ApiGateway::Method
|
|
518
582
|
Properties:
|
|
519
583
|
......
|
|
520
584
|
Integration:
|
|
521
585
|
Type: HTTP_PROXY
|
|
522
586
|
Uri: 'https://s3-${self:custom.region}.amazonaws.com/${self:custom.yourBucketName}/{proxy}'
|
|
523
587
|
......
|
|
588
|
+
Type: AWS::ApiGateway::Method
|
|
524
589
|
```
|
|
525
590
|
|
|
526
|
-
```
|
|
591
|
+
```yml
|
|
527
592
|
custom:
|
|
528
593
|
serverless-offline:
|
|
529
594
|
resourceRoutes:
|
|
@@ -541,7 +606,7 @@ May not work properly. Please PR. (Difficulty: hard?)
|
|
|
541
606
|
|
|
542
607
|
Example response velocity template:
|
|
543
608
|
|
|
544
|
-
```
|
|
609
|
+
```js
|
|
545
610
|
"responseParameters": {
|
|
546
611
|
"method.response.header.X-Powered-By": "Serverless", // a string
|
|
547
612
|
"method.response.header.Warning": "integration.response.body", // the whole response
|
|
@@ -558,7 +623,9 @@ Usage in order to send messages back to clients:
|
|
|
558
623
|
Or,
|
|
559
624
|
|
|
560
625
|
```js
|
|
561
|
-
const
|
|
626
|
+
const { ApiGatewayManagementApi } = require('aws-sdk')
|
|
627
|
+
|
|
628
|
+
const apiGatewayManagementApi = new ApiGatewayManagementApi({
|
|
562
629
|
apiVersion: '2018-11-29',
|
|
563
630
|
endpoint: 'http://localhost:3001',
|
|
564
631
|
});
|
|
@@ -603,13 +670,13 @@ Add a new [launch configuration](https://code.visualstudio.com/docs/editor/debug
|
|
|
603
670
|
|
|
604
671
|
```json
|
|
605
672
|
{
|
|
606
|
-
"type": "node",
|
|
607
|
-
"request": "launch",
|
|
608
|
-
"name": "Debug Serverless Offline",
|
|
609
673
|
"cwd": "${workspaceFolder}",
|
|
610
|
-
"
|
|
674
|
+
"name": "Debug Serverless Offline",
|
|
675
|
+
"request": "launch",
|
|
611
676
|
"runtimeArgs": ["run", "debug"],
|
|
612
|
-
"
|
|
677
|
+
"runtimeExecutable": "npm",
|
|
678
|
+
"sourceMaps": true,
|
|
679
|
+
"type": "node"
|
|
613
680
|
}
|
|
614
681
|
```
|
|
615
682
|
|
|
@@ -647,7 +714,7 @@ You can change this profile directly in the code or by setting proper environmen
|
|
|
647
714
|
## Simulation quality
|
|
648
715
|
|
|
649
716
|
This plugin simulates API Gateway for many practical purposes, good enough for development - but is not a perfect simulator.
|
|
650
|
-
Specifically, Lambda currently runs on Node.js
|
|
717
|
+
Specifically, Lambda currently runs on Node.js v12.x, v14.x and v16.x ([AWS Docs](https://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html)), whereas _Offline_ runs on your own runtime where no memory limits are enforced.
|
|
651
718
|
|
|
652
719
|
## Usage with other plugins
|
|
653
720
|
|
|
@@ -660,7 +727,7 @@ Plugins are executed in order, so plugins that process your code or add resource
|
|
|
660
727
|
|
|
661
728
|
For example:
|
|
662
729
|
|
|
663
|
-
```
|
|
730
|
+
```yml
|
|
664
731
|
plugins:
|
|
665
732
|
- serverless-middleware # modifies some of your handler based on configuration
|
|
666
733
|
- serverless-webpack # package your javascript handlers using webpack
|
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.
|
|
4
|
+
"version": "9.1.2",
|
|
5
5
|
"description": "Emulate AWS λ and API Gateway locally when developing your Serverless project",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "./src/index.js",
|
|
@@ -194,7 +194,7 @@
|
|
|
194
194
|
"@hapi/boom": "^10.0.0",
|
|
195
195
|
"@hapi/h2o2": "^9.1.0",
|
|
196
196
|
"@hapi/hapi": "^20.2.2",
|
|
197
|
-
"aws-sdk": "^2.
|
|
197
|
+
"aws-sdk": "^2.1185.0",
|
|
198
198
|
"boxen": "^7.0.0",
|
|
199
199
|
"chalk": "^5.0.1",
|
|
200
200
|
"execa": "^6.1.0",
|
|
@@ -206,7 +206,7 @@
|
|
|
206
206
|
"jsonwebtoken": "^8.5.1",
|
|
207
207
|
"jszip": "^3.10.0",
|
|
208
208
|
"luxon": "^3.0.1",
|
|
209
|
-
"node-fetch": "^3.2.
|
|
209
|
+
"node-fetch": "^3.2.10",
|
|
210
210
|
"node-schedule": "^2.1.0",
|
|
211
211
|
"object.hasown": "^1.1.1",
|
|
212
212
|
"p-memoize": "^7.1.0",
|
package/src/ServerlessOffline.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import process, {
|
|
1
|
+
import process, { exit } from 'node:process'
|
|
2
2
|
import { log } from '@serverless/utils/log.js'
|
|
3
3
|
import chalk from 'chalk'
|
|
4
4
|
import {
|
|
@@ -59,9 +59,6 @@ export default class ServerlessOffline {
|
|
|
59
59
|
|
|
60
60
|
// Entry point for the plugin (sls offline) when running 'sls offline start'
|
|
61
61
|
async start() {
|
|
62
|
-
// Put here so available everywhere, not just in handlers
|
|
63
|
-
env.IS_OFFLINE = true
|
|
64
|
-
|
|
65
62
|
this.#mergeOptions()
|
|
66
63
|
|
|
67
64
|
const { httpEvents, lambdas, scheduleEvents, webSocketEvents } =
|
|
@@ -91,6 +91,10 @@ export default {
|
|
|
91
91
|
usage:
|
|
92
92
|
'The directory layers should be stored in. Default: {codeDir}/.serverless-offline/layers',
|
|
93
93
|
},
|
|
94
|
+
localEnvironment: {
|
|
95
|
+
type: 'boolean',
|
|
96
|
+
usage: 'Copy local environment variables. Default: false',
|
|
97
|
+
},
|
|
94
98
|
noAuth: {
|
|
95
99
|
type: 'boolean',
|
|
96
100
|
usage: 'Turns off all authorizers',
|
package/src/config/constants.js
CHANGED
|
@@ -4,12 +4,12 @@ export const BASE_URL_PLACEHOLDER = 'http://example'
|
|
|
4
4
|
|
|
5
5
|
export const CUSTOM_OPTION = 'serverless-offline'
|
|
6
6
|
|
|
7
|
-
export const DEFAULT_LAMBDA_RUNTIME = '
|
|
7
|
+
export const DEFAULT_LAMBDA_RUNTIME = 'nodejs14.x'
|
|
8
8
|
|
|
9
9
|
// https://docs.aws.amazon.com/lambda/latest/dg/limits.html
|
|
10
10
|
export const DEFAULT_LAMBDA_MEMORY_SIZE = 1024
|
|
11
11
|
// default function timeout in seconds
|
|
12
|
-
export const DEFAULT_LAMBDA_TIMEOUT =
|
|
12
|
+
export const DEFAULT_LAMBDA_TIMEOUT = 6 // 6 seconds
|
|
13
13
|
|
|
14
14
|
// timeout for all connections to be closed
|
|
15
15
|
export const SERVER_SHUTDOWN_TIMEOUT = 5000
|
|
@@ -2,7 +2,7 @@ import { Buffer } from 'node:buffer'
|
|
|
2
2
|
import { readFileSync } from 'node:fs'
|
|
3
3
|
import { createRequire } from 'node:module'
|
|
4
4
|
import { join, resolve } from 'node:path'
|
|
5
|
-
import
|
|
5
|
+
import { exit } from 'node:process'
|
|
6
6
|
import h2o2 from '@hapi/h2o2'
|
|
7
7
|
import { Server } from '@hapi/hapi'
|
|
8
8
|
import { log } from '@serverless/utils/log.js'
|
|
@@ -35,8 +35,6 @@ const { assign, entries, keys } = Object
|
|
|
35
35
|
export default class HttpServer {
|
|
36
36
|
#lambda = null
|
|
37
37
|
|
|
38
|
-
#lastRequestOptions = null
|
|
39
|
-
|
|
40
38
|
#options = null
|
|
41
39
|
|
|
42
40
|
#serverless = null
|
|
@@ -198,17 +196,6 @@ export default class HttpServer {
|
|
|
198
196
|
const server = `${httpsProtocol ? 'https' : 'http'}://${host}:${httpPort}`
|
|
199
197
|
|
|
200
198
|
log.notice(`Server ready: ${server} 🚀`)
|
|
201
|
-
log.notice()
|
|
202
|
-
log.notice('Enter "rp" to replay the last request')
|
|
203
|
-
|
|
204
|
-
process.openStdin().addListener('data', (data) => {
|
|
205
|
-
// note: data is an object, and when converted to a string it will
|
|
206
|
-
// end with a linefeed. so we (rather crudely) account for that
|
|
207
|
-
// with toString() and then trim()
|
|
208
|
-
if (data.toString().trim() === 'rp') {
|
|
209
|
-
this.#injectLastRequest()
|
|
210
|
-
}
|
|
211
|
-
})
|
|
212
199
|
}
|
|
213
200
|
|
|
214
201
|
// stops the server
|
|
@@ -513,24 +500,11 @@ export default class HttpServer {
|
|
|
513
500
|
hapiOptions.tags = ['api']
|
|
514
501
|
|
|
515
502
|
const hapiHandler = async (request, h) => {
|
|
516
|
-
// Here we go
|
|
517
|
-
// Store current request as the last one
|
|
518
|
-
this.#lastRequestOptions = {
|
|
519
|
-
headers: request.headers,
|
|
520
|
-
method: request.method,
|
|
521
|
-
payload: request.payload,
|
|
522
|
-
url: request.url.href,
|
|
523
|
-
}
|
|
524
|
-
|
|
525
503
|
const requestPath =
|
|
526
504
|
endpoint.isHttpApi || this.#options.noPrependStageInUrl
|
|
527
505
|
? request.path
|
|
528
506
|
: request.path.substr(`/${stage}`.length)
|
|
529
507
|
|
|
530
|
-
if (request.auth.credentials && request.auth.strategy) {
|
|
531
|
-
this.#lastRequestOptions.auth = request.auth
|
|
532
|
-
}
|
|
533
|
-
|
|
534
508
|
// Payload processing
|
|
535
509
|
const encoding = detectEncoding(request)
|
|
536
510
|
|
|
@@ -667,24 +641,18 @@ export default class HttpServer {
|
|
|
667
641
|
event = request.payload || {}
|
|
668
642
|
}
|
|
669
643
|
} else if (integration === 'AWS_PROXY') {
|
|
670
|
-
const stageVariables = this.#serverless.service.custom
|
|
671
|
-
? this.#serverless.service.custom.stageVariables
|
|
672
|
-
: null
|
|
673
|
-
|
|
674
644
|
const lambdaProxyIntegrationEvent =
|
|
675
645
|
endpoint.isHttpApi && endpoint.payload === '2.0'
|
|
676
646
|
? new LambdaProxyIntegrationEventV2(
|
|
677
647
|
request,
|
|
678
648
|
stage,
|
|
679
649
|
endpoint.routeKey,
|
|
680
|
-
stageVariables,
|
|
681
650
|
additionalRequestContext,
|
|
682
651
|
)
|
|
683
652
|
: new LambdaProxyIntegrationEvent(
|
|
684
653
|
request,
|
|
685
654
|
stage,
|
|
686
655
|
requestPath,
|
|
687
|
-
stageVariables,
|
|
688
656
|
endpoint.isHttpApi ? endpoint.routeKey : null,
|
|
689
657
|
additionalRequestContext,
|
|
690
658
|
)
|
|
@@ -1257,15 +1225,6 @@ export default class HttpServer {
|
|
|
1257
1225
|
.map((line) => line.trim())
|
|
1258
1226
|
}
|
|
1259
1227
|
|
|
1260
|
-
#injectLastRequest() {
|
|
1261
|
-
if (this.#lastRequestOptions) {
|
|
1262
|
-
log.notice('Replaying HTTP last request')
|
|
1263
|
-
this.#server.inject(this.#lastRequestOptions)
|
|
1264
|
-
} else {
|
|
1265
|
-
log.notice('No last HTTP request to replay!')
|
|
1266
|
-
}
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1269
1228
|
writeRoutesTerminal() {
|
|
1270
1229
|
logRoutes(this.#terminalInfo)
|
|
1271
1230
|
}
|
|
@@ -30,22 +30,12 @@ export default class LambdaProxyIntegrationEvent {
|
|
|
30
30
|
|
|
31
31
|
#stage = null
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
constructor(
|
|
36
|
-
request,
|
|
37
|
-
stage,
|
|
38
|
-
path,
|
|
39
|
-
stageVariables,
|
|
40
|
-
routeKey,
|
|
41
|
-
additionalRequestContext,
|
|
42
|
-
) {
|
|
33
|
+
constructor(request, stage, path, routeKey, additionalRequestContext) {
|
|
43
34
|
this.#additionalRequestContext = additionalRequestContext || {}
|
|
44
35
|
this.#path = path
|
|
45
36
|
this.#routeKey = routeKey
|
|
46
37
|
this.#request = request
|
|
47
38
|
this.#stage = stage
|
|
48
|
-
this.#stageVariables = stageVariables
|
|
49
39
|
}
|
|
50
40
|
|
|
51
41
|
create() {
|
|
@@ -227,7 +217,7 @@ export default class LambdaProxyIntegrationEvent {
|
|
|
227
217
|
stage: this.#stage,
|
|
228
218
|
},
|
|
229
219
|
resource,
|
|
230
|
-
stageVariables:
|
|
220
|
+
stageVariables: null,
|
|
231
221
|
}
|
|
232
222
|
}
|
|
233
223
|
}
|
|
@@ -24,20 +24,11 @@ export default class LambdaProxyIntegrationEventV2 {
|
|
|
24
24
|
|
|
25
25
|
#stage = null
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
constructor(
|
|
30
|
-
request,
|
|
31
|
-
stage,
|
|
32
|
-
routeKey,
|
|
33
|
-
stageVariables,
|
|
34
|
-
additionalRequestContext,
|
|
35
|
-
) {
|
|
27
|
+
constructor(request, stage, routeKey, additionalRequestContext) {
|
|
36
28
|
this.#additionalRequestContext = additionalRequestContext || {}
|
|
37
29
|
this.#routeKey = routeKey
|
|
38
30
|
this.#request = request
|
|
39
31
|
this.#stage = stage
|
|
40
|
-
this.#stageVariables = stageVariables
|
|
41
32
|
}
|
|
42
33
|
|
|
43
34
|
create() {
|
|
@@ -183,7 +174,7 @@ export default class LambdaProxyIntegrationEventV2 {
|
|
|
183
174
|
timeEpoch: requestTimeEpoch,
|
|
184
175
|
},
|
|
185
176
|
routeKey: this.#routeKey,
|
|
186
|
-
stageVariables:
|
|
177
|
+
stageVariables: null,
|
|
187
178
|
version: '2.0',
|
|
188
179
|
}
|
|
189
180
|
}
|
|
@@ -39,9 +39,9 @@ export default class Schedule {
|
|
|
39
39
|
const cron = this.#convertExpressionToCron(entry)
|
|
40
40
|
|
|
41
41
|
log.notice(
|
|
42
|
-
`Scheduling [${functionKey}] cron: [${cron}]
|
|
43
|
-
input
|
|
44
|
-
|
|
42
|
+
`Scheduling [${functionKey}] cron: [${cron}]${
|
|
43
|
+
input ? ` input: ${stringify(input)}` : ''
|
|
44
|
+
}`,
|
|
45
45
|
)
|
|
46
46
|
|
|
47
47
|
nodeSchedule.scheduleJob(cron, async () => {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { readFile, writeFile } from 'node:fs/promises'
|
|
2
2
|
import { dirname, join, resolve } from 'node:path'
|
|
3
|
+
import process from 'node:process'
|
|
3
4
|
import { performance } from 'node:perf_hooks'
|
|
4
5
|
import { log } from '@serverless/utils/log.js'
|
|
5
6
|
import { emptyDir, ensureDir, remove } from 'fs-extra'
|
|
6
7
|
import jszip from 'jszip'
|
|
7
8
|
import HandlerRunner from './handler-runner/index.js'
|
|
8
9
|
import LambdaContext from './LambdaContext.js'
|
|
9
|
-
import resolveJoins from '../utils/resolveJoins.js'
|
|
10
10
|
import {
|
|
11
11
|
DEFAULT_LAMBDA_MEMORY_SIZE,
|
|
12
12
|
DEFAULT_LAMBDA_RUNTIME,
|
|
@@ -15,8 +15,8 @@ import {
|
|
|
15
15
|
} from '../config/index.js'
|
|
16
16
|
import { createUniqueId, splitHandlerPathAndName } from '../utils/index.js'
|
|
17
17
|
|
|
18
|
-
const { entries } = Object
|
|
19
18
|
const { ceil } = Math
|
|
19
|
+
const { entries, fromEntries } = Object
|
|
20
20
|
|
|
21
21
|
export default class LambdaFunction {
|
|
22
22
|
#artifact = null
|
|
@@ -35,6 +35,8 @@ export default class LambdaFunction {
|
|
|
35
35
|
|
|
36
36
|
#functionName = null
|
|
37
37
|
|
|
38
|
+
#handler = null
|
|
39
|
+
|
|
38
40
|
#handlerRunner = null
|
|
39
41
|
|
|
40
42
|
#idleTimeStarted = null
|
|
@@ -86,6 +88,7 @@ export default class LambdaFunction {
|
|
|
86
88
|
// this._executionTimeout = null
|
|
87
89
|
this.#functionKey = functionKey
|
|
88
90
|
this.#functionName = name
|
|
91
|
+
this.#handler = handler
|
|
89
92
|
this.#memorySize = memorySize
|
|
90
93
|
this.#region = provider.region
|
|
91
94
|
this.#runtime = runtime
|
|
@@ -93,11 +96,18 @@ export default class LambdaFunction {
|
|
|
93
96
|
|
|
94
97
|
this.#verifySupportedRuntime()
|
|
95
98
|
|
|
96
|
-
const env =
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
const env = {
|
|
100
|
+
...(options.localEnvironment
|
|
101
|
+
? process.env
|
|
102
|
+
: // we always copy all AWS_xxxx environment variables over from local env
|
|
103
|
+
fromEntries(
|
|
104
|
+
entries(process.env).filter(([key]) => key.startsWith('AWS_')),
|
|
105
|
+
)),
|
|
106
|
+
...this.#getAwsEnvVars(),
|
|
107
|
+
...provider.environment,
|
|
108
|
+
...functionDefinition.environment,
|
|
109
|
+
IS_OFFLINE: 'true',
|
|
110
|
+
}
|
|
101
111
|
|
|
102
112
|
this.#artifact = functionDefinition.package?.artifact
|
|
103
113
|
|
|
@@ -176,6 +186,7 @@ export default class LambdaFunction {
|
|
|
176
186
|
// https://github.com/serverless/serverless/blob/v1.50.0/lib/plugins/aws/invokeLocal/index.js#L108
|
|
177
187
|
#getAwsEnvVars() {
|
|
178
188
|
return {
|
|
189
|
+
_HANDLER: this.#handler,
|
|
179
190
|
AWS_DEFAULT_REGION: this.#region,
|
|
180
191
|
AWS_LAMBDA_FUNCTION_MEMORY_SIZE: this.#memorySize,
|
|
181
192
|
AWS_LAMBDA_FUNCTION_NAME: this.#functionName,
|
|
@@ -194,16 +205,6 @@ export default class LambdaFunction {
|
|
|
194
205
|
}
|
|
195
206
|
}
|
|
196
207
|
|
|
197
|
-
#getEnv(providerEnv, functionDefinitionEnv, handler) {
|
|
198
|
-
return {
|
|
199
|
-
...this.#getAwsEnvVars(),
|
|
200
|
-
...providerEnv,
|
|
201
|
-
...functionDefinitionEnv,
|
|
202
|
-
_HANDLER: handler, // TODO is this available in AWS?
|
|
203
|
-
IS_OFFLINE: true,
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
208
|
setClientContext(clientContext) {
|
|
208
209
|
this.#clientContext = clientContext
|
|
209
210
|
}
|
|
@@ -41,14 +41,18 @@ export default class ChildProcessRunner {
|
|
|
41
41
|
},
|
|
42
42
|
)
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
+
})
|
|
48
52
|
})
|
|
49
|
-
}
|
|
53
|
+
} finally {
|
|
50
54
|
childProcess.kill()
|
|
51
|
-
}
|
|
55
|
+
}
|
|
52
56
|
|
|
53
57
|
childProcess.send({
|
|
54
58
|
context,
|
|
@@ -12,6 +12,8 @@ import pRetry from 'p-retry'
|
|
|
12
12
|
import DockerImage from './DockerImage.js'
|
|
13
13
|
|
|
14
14
|
const { stringify } = JSON
|
|
15
|
+
const { floor, log: mathLog } = Math
|
|
16
|
+
const { parseFloat } = Number
|
|
15
17
|
const { entries, hasOwn } = Object
|
|
16
18
|
|
|
17
19
|
export default class DockerContainer {
|
|
@@ -402,7 +404,7 @@ export default class DockerContainer {
|
|
|
402
404
|
const dm = decimals < 0 ? 0 : decimals
|
|
403
405
|
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
|
404
406
|
|
|
405
|
-
const i =
|
|
407
|
+
const i = floor(mathLog(bytes) / mathLog(k))
|
|
406
408
|
|
|
407
409
|
return `${parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`
|
|
408
410
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { mkdir, readFile, rmdir, writeFile } from 'node:fs/promises'
|
|
1
|
+
import { mkdir, readFile, rm, rmdir, writeFile } from 'node:fs/promises'
|
|
2
2
|
import { EOL } from 'node:os'
|
|
3
|
-
import { sep, resolve, parse as pathParse } from 'node:path'
|
|
4
3
|
import process, { chdir, cwd } from 'node:process'
|
|
4
|
+
import { parse as pathParse, resolve, sep } from 'node:path'
|
|
5
5
|
import { log } from '@serverless/utils/log.js'
|
|
6
|
-
import { execa
|
|
6
|
+
import { execa } from 'execa'
|
|
7
7
|
|
|
8
8
|
const { parse, stringify } = JSON
|
|
9
9
|
|
|
10
|
-
const PAYLOAD_IDENTIFIER = 'offline_payload'
|
|
11
|
-
|
|
12
10
|
export default class GoRunner {
|
|
11
|
+
static #payloadIdentifier = 'offline_payload'
|
|
12
|
+
|
|
13
13
|
#codeDir = null
|
|
14
14
|
|
|
15
15
|
#env = null
|
|
@@ -18,10 +18,10 @@ export default class GoRunner {
|
|
|
18
18
|
|
|
19
19
|
#handlerPath = null
|
|
20
20
|
|
|
21
|
-
#tmpPath = null
|
|
22
|
-
|
|
23
21
|
#tmpFile = null
|
|
24
22
|
|
|
23
|
+
#tmpPath = null
|
|
24
|
+
|
|
25
25
|
constructor(funOptions, env) {
|
|
26
26
|
const { handlerPath, codeDir } = funOptions
|
|
27
27
|
|
|
@@ -32,7 +32,12 @@ export default class GoRunner {
|
|
|
32
32
|
|
|
33
33
|
async cleanup() {
|
|
34
34
|
try {
|
|
35
|
-
|
|
35
|
+
// refresh go.mod
|
|
36
|
+
await rm(this.#tmpFile)
|
|
37
|
+
await execa('go', ['mod', 'tidy'])
|
|
38
|
+
await rmdir(this.#tmpPath, {
|
|
39
|
+
recursive: true,
|
|
40
|
+
})
|
|
36
41
|
} catch {
|
|
37
42
|
// @ignore
|
|
38
43
|
}
|
|
@@ -46,12 +51,10 @@ export default class GoRunner {
|
|
|
46
51
|
let payload
|
|
47
52
|
|
|
48
53
|
for (const item of value.split(EOL)) {
|
|
49
|
-
if (item.
|
|
50
|
-
logs.push(item)
|
|
51
|
-
} else if (item.indexOf(PAYLOAD_IDENTIFIER) !== -1) {
|
|
54
|
+
if (item.includes(GoRunner.#payloadIdentifier)) {
|
|
52
55
|
try {
|
|
53
56
|
const {
|
|
54
|
-
|
|
57
|
+
[GoRunner.#payloadIdentifier]: { error, success },
|
|
55
58
|
} = parse(item)
|
|
56
59
|
|
|
57
60
|
if (success) {
|
|
@@ -62,6 +65,8 @@ export default class GoRunner {
|
|
|
62
65
|
} catch {
|
|
63
66
|
// @ignore
|
|
64
67
|
}
|
|
68
|
+
} else {
|
|
69
|
+
logs.push(item)
|
|
65
70
|
}
|
|
66
71
|
}
|
|
67
72
|
|
|
@@ -119,8 +124,11 @@ export default class GoRunner {
|
|
|
119
124
|
chdir(cwdPath.substring(0, cwdPath.indexOf('main.go')))
|
|
120
125
|
|
|
121
126
|
// Make sure we have the mock-lambda runner
|
|
122
|
-
|
|
123
|
-
|
|
127
|
+
await execa('go', [
|
|
128
|
+
'get',
|
|
129
|
+
'github.com/icarus-sullivan/mock-lambda@e065469',
|
|
130
|
+
])
|
|
131
|
+
await execa('go', ['build'])
|
|
124
132
|
} catch {
|
|
125
133
|
// @ignore
|
|
126
134
|
}
|
|
@@ -154,8 +162,6 @@ export default class GoRunner {
|
|
|
154
162
|
}
|
|
155
163
|
|
|
156
164
|
try {
|
|
157
|
-
// refresh go.mod
|
|
158
|
-
execaSync('go', ['mod', 'tidy'])
|
|
159
165
|
chdir(this.#codeDir)
|
|
160
166
|
} catch {
|
|
161
167
|
// @ignore
|
|
@@ -3,6 +3,7 @@ import { performance } from 'node:perf_hooks'
|
|
|
3
3
|
import process from 'node:process'
|
|
4
4
|
import { log } from '@serverless/utils/log.js'
|
|
5
5
|
|
|
6
|
+
const { floor } = Math
|
|
6
7
|
const { assign } = Object
|
|
7
8
|
|
|
8
9
|
const require = createRequire(import.meta.url)
|
|
@@ -88,11 +89,11 @@ export default class InProcessRunner {
|
|
|
88
89
|
...context,
|
|
89
90
|
done: (err, data) => callback(err, data),
|
|
90
91
|
fail: (err) => callback(err),
|
|
91
|
-
getRemainingTimeInMillis
|
|
92
|
+
getRemainingTimeInMillis() {
|
|
92
93
|
const timeLeft = executionTimeout - performance.now()
|
|
93
94
|
|
|
94
95
|
// just return 0 for now if we are beyond alotted time (timeout)
|
|
95
|
-
return timeLeft > 0 ? timeLeft : 0
|
|
96
|
+
return timeLeft > 0 ? floor(timeLeft) : 0
|
|
96
97
|
},
|
|
97
98
|
succeed: (res) => callback(null, res),
|
|
98
99
|
}
|
|
@@ -4,9 +4,11 @@ import { log } from '@serverless/utils/log.js'
|
|
|
4
4
|
import { invokeJavaLocal } from 'java-invoke-local'
|
|
5
5
|
|
|
6
6
|
const { parse, stringify } = JSON
|
|
7
|
-
const {
|
|
7
|
+
const { hasOwn } = Object
|
|
8
8
|
|
|
9
9
|
export default class JavaRunner {
|
|
10
|
+
static #payloadIdentifier = '__offline_payload__'
|
|
11
|
+
|
|
10
12
|
#deployPackage = null
|
|
11
13
|
|
|
12
14
|
#env = null
|
|
@@ -45,9 +47,9 @@ export default class JavaRunner {
|
|
|
45
47
|
if (
|
|
46
48
|
json &&
|
|
47
49
|
typeof json === 'object' &&
|
|
48
|
-
|
|
50
|
+
hasOwn(json, JavaRunner.#payloadIdentifier)
|
|
49
51
|
) {
|
|
50
|
-
return json
|
|
52
|
+
return json[JavaRunner.#payloadIdentifier]
|
|
51
53
|
}
|
|
52
54
|
}
|
|
53
55
|
|
|
@@ -7,12 +7,13 @@ import { fileURLToPath } from 'node:url'
|
|
|
7
7
|
import { log } from '@serverless/utils/log.js'
|
|
8
8
|
|
|
9
9
|
const { parse, stringify } = JSON
|
|
10
|
-
const { assign } = Object
|
|
11
|
-
const { has } = Reflect
|
|
10
|
+
const { assign, hasOwn } = Object
|
|
12
11
|
|
|
13
12
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
14
13
|
|
|
15
14
|
export default class PythonRunner {
|
|
15
|
+
static #payloadIdentifier = '__offline_payload__'
|
|
16
|
+
|
|
16
17
|
#env = null
|
|
17
18
|
|
|
18
19
|
#handlerName = null
|
|
@@ -83,9 +84,9 @@ export default class PythonRunner {
|
|
|
83
84
|
if (
|
|
84
85
|
json &&
|
|
85
86
|
typeof json === 'object' &&
|
|
86
|
-
|
|
87
|
+
hasOwn(json, PythonRunner.#payloadIdentifier)
|
|
87
88
|
) {
|
|
88
|
-
payload = json
|
|
89
|
+
payload = json[PythonRunner.#payloadIdentifier]
|
|
89
90
|
// everything else is print(), logging, ...
|
|
90
91
|
} else {
|
|
91
92
|
log.notice(item)
|
|
@@ -6,11 +6,13 @@ import { log } from '@serverless/utils/log.js'
|
|
|
6
6
|
import { execa } from 'execa'
|
|
7
7
|
|
|
8
8
|
const { parse, stringify } = JSON
|
|
9
|
-
const {
|
|
9
|
+
const { hasOwn } = Object
|
|
10
10
|
|
|
11
11
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
12
12
|
|
|
13
13
|
export default class RubyRunner {
|
|
14
|
+
static #payloadIdentifier = '__offline_payload__'
|
|
15
|
+
|
|
14
16
|
#env = null
|
|
15
17
|
|
|
16
18
|
#handlerName = null
|
|
@@ -47,9 +49,9 @@ export default class RubyRunner {
|
|
|
47
49
|
if (
|
|
48
50
|
json &&
|
|
49
51
|
typeof json === 'object' &&
|
|
50
|
-
|
|
52
|
+
hasOwn(json, RubyRunner.#payloadIdentifier)
|
|
51
53
|
) {
|
|
52
|
-
payload = json
|
|
54
|
+
payload = json[RubyRunner.#payloadIdentifier]
|
|
53
55
|
} else {
|
|
54
56
|
log.notice(item)
|
|
55
57
|
}
|
|
@@ -2,10 +2,10 @@ import { env } from 'node:process'
|
|
|
2
2
|
import { parentPort, workerData } from 'node:worker_threads'
|
|
3
3
|
import InProcessRunner from '../in-process-runner/index.js'
|
|
4
4
|
|
|
5
|
-
const { functionKey, handlerName, handlerPath } = workerData
|
|
5
|
+
const { functionKey, handlerName, handlerPath, timeout } = workerData
|
|
6
6
|
|
|
7
7
|
parentPort.on('message', async (messageData) => {
|
|
8
|
-
const { context, event, port
|
|
8
|
+
const { context, event, port } = messageData
|
|
9
9
|
|
|
10
10
|
// TODO we could probably cache this in the module scope?
|
|
11
11
|
const inProcessRunner = new InProcessRunner(
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
const { entries } = Object
|
|
2
|
-
|
|
3
|
-
// Used to resolve Fn::Join in environment variables
|
|
4
|
-
export default function resolveJoins(environment) {
|
|
5
|
-
if (!environment) {
|
|
6
|
-
return undefined
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const newEnv = {}
|
|
10
|
-
|
|
11
|
-
entries(environment).forEach(([key, value]) => {
|
|
12
|
-
if (!value) {
|
|
13
|
-
return
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const joinArray = value['Fn::Join']
|
|
17
|
-
const isJoin = Boolean(joinArray)
|
|
18
|
-
|
|
19
|
-
if (isJoin) {
|
|
20
|
-
const separator = joinArray[0]
|
|
21
|
-
const joined = joinArray[1].join(separator)
|
|
22
|
-
newEnv[key] = joined
|
|
23
|
-
} else {
|
|
24
|
-
newEnv[key] = value
|
|
25
|
-
}
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
return newEnv
|
|
29
|
-
}
|