serverless-offline 8.7.0 → 8.8.0
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 +89 -93
- package/dist/ServerlessOffline.js +15 -8
- package/dist/config/supportedRuntimes.js +1 -1
- package/dist/debugLog.js +3 -1
- package/dist/events/{http/authValidateContext.js → authValidateContext.js} +8 -3
- package/dist/events/http/Endpoint.js +3 -1
- package/dist/events/http/HttpServer.js +27 -20
- package/dist/events/http/OfflineEndpoint.js +23 -25
- package/dist/events/http/createAuthScheme.js +1 -1
- package/dist/events/http/createJWTAuthScheme.js +6 -2
- package/dist/events/http/lambda-events/LambdaIntegrationEvent.js +4 -2
- package/dist/events/http/lambda-events/LambdaProxyIntegrationEvent.js +16 -14
- package/dist/events/http/lambda-events/LambdaProxyIntegrationEventV2.js +17 -13
- package/dist/events/http/lambda-events/VelocityContext.js +3 -1
- package/dist/events/http/lambda-events/renderVelocityTemplateObject.js +4 -1
- package/dist/events/schedule/Schedule.js +10 -9
- package/dist/events/websocket/HttpServer.js +3 -1
- package/dist/events/websocket/WebSocketClients.js +38 -11
- package/dist/events/websocket/WebSocketServer.js +5 -6
- package/dist/index.js +0 -4
- package/dist/lambda/HttpServer.js +3 -1
- package/dist/lambda/Lambda.js +5 -1
- package/dist/lambda/LambdaFunction.js +1 -2
- package/dist/lambda/handler-runner/HandlerRunner.js +1 -29
- package/dist/lambda/handler-runner/child-process-runner/ChildProcessRunner.js +1 -9
- package/dist/lambda/handler-runner/child-process-runner/childProcessHelper.js +15 -6
- package/dist/lambda/handler-runner/docker-runner/DockerContainer.js +2 -4
- package/dist/lambda/handler-runner/go-runner/GoRunner.js +34 -15
- package/dist/lambda/handler-runner/in-process-runner/InProcessRunner.js +24 -30
- package/dist/lambda/handler-runner/java-runner/JavaRunner.js +3 -1
- package/dist/lambda/handler-runner/python-runner/PythonRunner.js +15 -10
- package/dist/lambda/handler-runner/ruby-runner/RubyRunner.js +3 -4
- package/dist/lambda/handler-runner/worker-thread-runner/WorkerThreadRunner.js +0 -2
- package/dist/lambda/handler-runner/worker-thread-runner/workerThreadHelper.js +4 -3
- package/dist/utils/generateHapiPath.js +1 -1
- package/dist/utils/getHttpApiCorsConfig.js +4 -8
- package/dist/utils/index.js +11 -4
- package/dist/utils/lowerCaseKeys.js +14 -0
- package/dist/utils/resolveJoins.js +4 -2
- package/dist/utils/splitHandlerPathAndName.js +9 -13
- package/package.json +23 -26
- package/dist/checkEngine.js +0 -21
package/README.md
CHANGED
|
@@ -45,15 +45,17 @@ This plugin is updated by its users, I just do maintenance and ensure that PRs a
|
|
|
45
45
|
- [Usage with `invoke`](#usage-with-invoke)
|
|
46
46
|
- [The `process.env.IS_OFFLINE` variable](#the-processenvis_offline-variable)
|
|
47
47
|
- [Docker and Layers](#docker-and-layers)
|
|
48
|
-
- [
|
|
49
|
-
- [
|
|
50
|
-
- [
|
|
51
|
-
- [
|
|
52
|
-
- [
|
|
48
|
+
- [Authorizers](#authorizers)
|
|
49
|
+
- [Token authorizers](#token-authorizers)
|
|
50
|
+
- [Custom authorizers](#custom-authorizers)
|
|
51
|
+
- [Remote authorizers](#remote-authorizers)
|
|
52
|
+
- [JWT authorizers](#jwt-authorizers)
|
|
53
|
+
- [Serverless plugin authorizers](#serverless-plugin-authorizers)
|
|
53
54
|
- [Custom headers](#custom-headers)
|
|
54
55
|
- [Environment variables](#environment-variables)
|
|
55
56
|
- [AWS API Gateway Features](#aws-api-gateway-features)
|
|
56
57
|
- [Velocity Templates](#velocity-templates)
|
|
58
|
+
- [Velocity nuances](#velocity-nuances)
|
|
57
59
|
- [CORS](#cors)
|
|
58
60
|
- [Catch-all Path Variables](#catch-all-path-variables)
|
|
59
61
|
- [ANY method](#any-method)
|
|
@@ -61,13 +63,10 @@ This plugin is updated by its users, I just do maintenance and ensure that PRs a
|
|
|
61
63
|
- [HTTP Proxy](#http-proxy)
|
|
62
64
|
- [Response parameters](#response-parameters)
|
|
63
65
|
- [WebSocket](#websocket)
|
|
64
|
-
- [Usage with Webpack](#usage-with-webpack)
|
|
65
|
-
- [Velocity nuances](#velocity-nuances)
|
|
66
66
|
- [Debug process](#debug-process)
|
|
67
67
|
- [Resource permissions and AWS profile](#resource-permissions-and-aws-profile)
|
|
68
|
-
- [Scoped execution](#scoped-execution)
|
|
69
68
|
- [Simulation quality](#simulation-quality)
|
|
70
|
-
- [Usage with
|
|
69
|
+
- [Usage with other plugins](#usage-with-other-plugins)
|
|
71
70
|
- [Credits and inspiration](#credits-and-inspiration)
|
|
72
71
|
- [License](#license)
|
|
73
72
|
- [Contributing](#contributing)
|
|
@@ -138,7 +137,7 @@ All CLI options are optional:
|
|
|
138
137
|
--resourceRoutes Turns on loading of your HTTP proxy settings from serverless.yml
|
|
139
138
|
--useChildProcesses Run handlers in a child process
|
|
140
139
|
--useDocker Run handlers in a docker container.
|
|
141
|
-
--useWorkerThreads Uses worker threads
|
|
140
|
+
--useWorkerThreads Uses worker threads to run handlers.
|
|
142
141
|
--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)
|
|
143
142
|
--webSocketIdleTimeout Set WebSocket idle timeout in seconds to reproduce AWS limits (https://docs.aws.amazon.com/apigateway/latest/developerguide/limits.html#apigateway-execution-service-websocket-limits-table). Default: 600 (10 minutes)
|
|
144
143
|
--websocketPort WebSocket port to listen on. Default: 3001
|
|
@@ -312,13 +311,15 @@ For certain programming languages and frameworks, it's desirable to be able to w
|
|
|
312
311
|
|
|
313
312
|
By default layers are downloaded on a per-project basis, however, if you want to share them across projects, you can download them to a common place. For example, `layersDir: /tmp/layers` would allow them to be shared across projects. Make sure when using this setting that the directory you are writing layers to can be shared by docker.
|
|
314
313
|
|
|
315
|
-
##
|
|
314
|
+
## Authorizers
|
|
315
|
+
|
|
316
|
+
### Token authorizers
|
|
316
317
|
|
|
317
318
|
As defined in the [Serverless Documentation](https://serverless.com/framework/docs/providers/aws/events/apigateway/#setting-api-keys-for-your-rest-api) you can use API Keys as a simple authentication method.
|
|
318
319
|
|
|
319
320
|
Serverless-offline will emulate the behaviour of APIG and create a random token that's printed on the screen. With this token you can access your private methods adding `x-api-key: generatedToken` to your request header. All api keys will share the same token. To specify a custom token use the `--apiKey` cli option.
|
|
320
321
|
|
|
321
|
-
|
|
322
|
+
### Custom authorizers
|
|
322
323
|
|
|
323
324
|
Only [custom authorizers](https://aws.amazon.com/blogs/compute/introducing-custom-authorizers-in-amazon-api-gateway/) are supported. Custom authorizers are executed before a Lambda function is executed and return an Error or a Policy document.
|
|
324
325
|
|
|
@@ -344,7 +345,7 @@ The plugin only supports retrieving Tokens from headers. You can configure the h
|
|
|
344
345
|
}
|
|
345
346
|
```
|
|
346
347
|
|
|
347
|
-
|
|
348
|
+
### Remote authorizers
|
|
348
349
|
|
|
349
350
|
You are able to mock the response from remote authorizers by setting the environmental variable `AUTHORIZER` before running `sls offline start`
|
|
350
351
|
|
|
@@ -354,14 +355,14 @@ Example:
|
|
|
354
355
|
|
|
355
356
|
> Windows: `SET AUTHORIZER='{"principalId": "123"}'`
|
|
356
357
|
|
|
357
|
-
|
|
358
|
+
### JWT authorizers
|
|
358
359
|
|
|
359
360
|
For HTTP APIs, [JWT authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html)
|
|
360
361
|
defined in the `serverless.yml` can be used to validate the token and scopes in the token. However at this time,
|
|
361
362
|
the signature of the JWT is not validated with the defined issuer. Since this is a security risk, this feature is
|
|
362
363
|
only enabled with the `--ignoreJWTSignature` flag. Make sure to only set this flag for local development work.
|
|
363
364
|
|
|
364
|
-
|
|
365
|
+
### Serverless plugin authorizers
|
|
365
366
|
|
|
366
367
|
If your authentication needs are custom and not satisfied by the existing capabilities of the Serverless offline project, you can inject your own authentication strategy. To inject a custom strategy for Lambda invocation, you define a custom variable under `serverless-offline` called `authenticationProvider` in the serverless.yml file. The value of the custom variable will be used to `require(your authenticationProvider value)` where the location is expected to return a function with the following signature.
|
|
367
368
|
|
|
@@ -423,6 +424,47 @@ For example,
|
|
|
423
424
|
if your function is in code-file: `helloworld.js`,
|
|
424
425
|
your response template should be in file: `helloworld.res.vm` and your request template in file `helloworld.req.vm`.
|
|
425
426
|
|
|
427
|
+
#### Velocity nuances
|
|
428
|
+
|
|
429
|
+
Consider this requestTemplate for a POST endpoint:
|
|
430
|
+
|
|
431
|
+
```json
|
|
432
|
+
"application/json": {
|
|
433
|
+
"payload": "$input.json('$')",
|
|
434
|
+
"id_json": "$input.json('$.id')",
|
|
435
|
+
"id_path": "$input.path('$').id"
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Now let's make a request with this body: `{ "id": 1 }`
|
|
440
|
+
|
|
441
|
+
AWS parses the event as such:
|
|
442
|
+
|
|
443
|
+
```javascript
|
|
444
|
+
{
|
|
445
|
+
"payload": {
|
|
446
|
+
"id": 1
|
|
447
|
+
},
|
|
448
|
+
"id_json": 1,
|
|
449
|
+
"id_path": "1" // Notice the string
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
Whereas Offline parses:
|
|
454
|
+
|
|
455
|
+
```javascript
|
|
456
|
+
{
|
|
457
|
+
"payload": {
|
|
458
|
+
"id": 1
|
|
459
|
+
},
|
|
460
|
+
"id_json": 1,
|
|
461
|
+
"id_path": 1 // Notice the number
|
|
462
|
+
}
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
Accessing an attribute after using `$input.path` will return a string on AWS (expect strings like `"1"` or `"true"`) but not with Offline (`1` or `true`).
|
|
466
|
+
You may find other differences.
|
|
467
|
+
|
|
426
468
|
### CORS
|
|
427
469
|
|
|
428
470
|
[Serverless doc](https://serverless.com/framework/docs/providers/aws/events/apigateway#enabling-cors)
|
|
@@ -531,51 +573,6 @@ Where the `event` is received in the lambda handler function.
|
|
|
531
573
|
|
|
532
574
|
There's support for [websocketsApiRouteSelectionExpression](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-selection-expressions.html) in it's basic form: `$request.body.x.y.z`, where the default value is `$request.body.action`.
|
|
533
575
|
|
|
534
|
-
## Usage with Webpack
|
|
535
|
-
|
|
536
|
-
Use [serverless-webpack](https://github.com/serverless-heaven/serverless-webpack) to compile and bundle your ES-next code
|
|
537
|
-
|
|
538
|
-
## Velocity nuances
|
|
539
|
-
|
|
540
|
-
Consider this requestTemplate for a POST endpoint:
|
|
541
|
-
|
|
542
|
-
```json
|
|
543
|
-
"application/json": {
|
|
544
|
-
"payload": "$input.json('$')",
|
|
545
|
-
"id_json": "$input.json('$.id')",
|
|
546
|
-
"id_path": "$input.path('$').id"
|
|
547
|
-
}
|
|
548
|
-
```
|
|
549
|
-
|
|
550
|
-
Now let's make a request with this body: `{ "id": 1 }`
|
|
551
|
-
|
|
552
|
-
AWS parses the event as such:
|
|
553
|
-
|
|
554
|
-
```javascript
|
|
555
|
-
{
|
|
556
|
-
"payload": {
|
|
557
|
-
"id": 1
|
|
558
|
-
},
|
|
559
|
-
"id_json": 1,
|
|
560
|
-
"id_path": "1" // Notice the string
|
|
561
|
-
}
|
|
562
|
-
```
|
|
563
|
-
|
|
564
|
-
Whereas Offline parses:
|
|
565
|
-
|
|
566
|
-
```javascript
|
|
567
|
-
{
|
|
568
|
-
"payload": {
|
|
569
|
-
"id": 1
|
|
570
|
-
},
|
|
571
|
-
"id_json": 1,
|
|
572
|
-
"id_path": 1 // Notice the number
|
|
573
|
-
}
|
|
574
|
-
```
|
|
575
|
-
|
|
576
|
-
Accessing an attribute after using `$input.path` will return a string on AWS (expect strings like `"1"` or `"true"`) but not with Offline (`1` or `true`).
|
|
577
|
-
You may find other differences.
|
|
578
|
-
|
|
579
576
|
## Debug process
|
|
580
577
|
|
|
581
578
|
Serverless offline plugin will respond to the overall framework settings and output additional information to the console in debug mode. In order to do this you will have to set the `SLS_DEBUG` environmental variable. You can run the following in the command line to switch to debug mode execution.
|
|
@@ -598,27 +595,22 @@ Depending on the breakpoint, you may need to call the URL path for your function
|
|
|
598
595
|
|
|
599
596
|
### Interactive Debugging with Visual Studio Code (VSC)
|
|
600
597
|
|
|
601
|
-
With newer versions of node (6.3+) the node inspector is already part of your node environment and you can take advantage of debugging inside your IDE with source-map support. Here is the example configuration to debug interactively with VSC. It has two steps.
|
|
598
|
+
With newer versions of node (6.3+) the node inspector is already part of your node environment and you can take advantage of debugging inside your IDE with source-map support. Here is the example configuration to debug interactively with VSC. It has two steps.
|
|
602
599
|
|
|
603
600
|
#### Step 1 : Adding a launch configuration in IDE
|
|
604
601
|
|
|
605
602
|
Add a new [launch configuration](https://code.visualstudio.com/docs/editor/debugging) to VSC like this:
|
|
606
603
|
|
|
607
604
|
```json
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
"debug"
|
|
618
|
-
],
|
|
619
|
-
"sourceMaps": true
|
|
620
|
-
}
|
|
621
|
-
|
|
605
|
+
{
|
|
606
|
+
"type": "node",
|
|
607
|
+
"request": "launch",
|
|
608
|
+
"name": "Debug Serverless Offline",
|
|
609
|
+
"cwd": "${workspaceFolder}",
|
|
610
|
+
"runtimeExecutable": "npm",
|
|
611
|
+
"runtimeArgs": ["run", "debug"],
|
|
612
|
+
"sourceMaps": true
|
|
613
|
+
}
|
|
622
614
|
```
|
|
623
615
|
|
|
624
616
|
#### Step2 : Adding a debug script
|
|
@@ -640,8 +632,7 @@ Example:
|
|
|
640
632
|
}
|
|
641
633
|
```
|
|
642
634
|
|
|
643
|
-
In VSC, you can, then, add breakpoints to your code. To start a debug sessions you can either start your script in `package.json` by clicking the hovering debug intellisense icon or
|
|
644
|
-
|
|
635
|
+
In VSC, you can, then, add breakpoints to your code. To start a debug sessions you can either start your script in `package.json` by clicking the hovering debug intellisense icon or by going to your debug pane and selecting the Debug Serverless Offline configuration.
|
|
645
636
|
|
|
646
637
|
## Resource permissions and AWS profile
|
|
647
638
|
|
|
@@ -653,28 +644,33 @@ You can change this profile directly in the code or by setting proper environmen
|
|
|
653
644
|
|
|
654
645
|
`AWS_PROFILE=<profile> serverless offline`
|
|
655
646
|
|
|
656
|
-
## Scoped execution
|
|
657
|
-
|
|
658
|
-
Downstream plugins may tie into the `before:offline:start:end` hook to release resources when the server is shutting down.
|
|
659
|
-
|
|
660
647
|
## Simulation quality
|
|
661
648
|
|
|
662
649
|
This plugin simulates API Gateway for many practical purposes, good enough for development - but is not a perfect simulator.
|
|
663
650
|
Specifically, Lambda currently runs on Node.js v10.x, v12.x and v14.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.
|
|
664
651
|
|
|
665
|
-
## Usage with
|
|
652
|
+
## Usage with other plugins
|
|
653
|
+
|
|
654
|
+
When combining this plugin with other plugins there are a few things that you need to keep in mind.
|
|
666
655
|
|
|
667
|
-
|
|
656
|
+
You should run `serverless offline start` instead of `serverless offline`. The `start` command fires the `offline:start:init` and `offline:start:end` lifecycle hooks which can be used by other plugins to process your code, add resources, perform cleanups, etc.
|
|
668
657
|
|
|
669
|
-
|
|
658
|
+
The order in which plugins are added to `serverless.yml` is relevant.
|
|
659
|
+
Plugins are executed in order, so plugins that process your code or add resources should be added first so they are ready when this plugin starts.
|
|
660
|
+
|
|
661
|
+
For example:
|
|
670
662
|
|
|
671
663
|
```yaml
|
|
672
664
|
plugins:
|
|
673
|
-
- serverless-
|
|
674
|
-
- serverless-
|
|
675
|
-
- serverless-
|
|
665
|
+
- serverless-middleware # modifies some of your handler based on configuration
|
|
666
|
+
- serverless-webpack # package your javascript handlers using webpack
|
|
667
|
+
- serverless-dynamodb-local # adds a local dynamo db
|
|
668
|
+
- serverless-offline # runs last so your code has been pre-processed and dynamo is ready
|
|
676
669
|
```
|
|
677
670
|
|
|
671
|
+
That works because all those plugins listen to the `offline:start:init` to do their processing.
|
|
672
|
+
Similarly they listen to `offline:start:end` to perform cleanup (stop dynamo db, remove temporary files, etc).
|
|
673
|
+
|
|
678
674
|
## Credits and inspiration
|
|
679
675
|
|
|
680
676
|
This plugin was initially a fork of [Nopik](https://github.com/Nopik/)'s [Serverless-serve](https://github.com/Nopik/serverless-serve).
|
|
@@ -812,10 +808,10 @@ We try to follow [Airbnb's JavaScript Style Guide](https://github.com/airbnb/jav
|
|
|
812
808
|
| :------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------: |
|
|
813
809
|
| [lteacher](https://github.com/lteacher) | [martinmicunda](https://github.com/martinmicunda) | [nori3tsu](https://github.com/nori3tsu) | [ppasmanik](https://github.com/ppasmanik) | [ryanzyy](https://github.com/ryanzyy) |
|
|
814
810
|
|
|
815
|
-
| [<img alt="m0ppers" src="https://avatars3.githubusercontent.com/u/819421?v=4&s=117" width="117">](https://github.com/m0ppers) | [<img alt="footballencarta" src="https://avatars0.githubusercontent.com/u/1312258?v=4&s=117" width="117">](https://github.com/footballencarta) | [<img alt="bryanvaz" src="https://avatars0.githubusercontent.com/u/9157498?v=4&s=117" width="117">](https://github.com/bryanvaz) | [<img alt="njyjn" src="https://avatars.githubusercontent.com/u/10694375?v=4&s=117" width="117">](https://github.com/njyjn) |
|
|
816
|
-
| :---------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------: |
|
|
817
|
-
| [m0ppers](https://github.com/m0ppers) | [footballencarta](https://github.com/footballencarta) | [bryanvaz](https://github.com/bryanvaz) | [njyjn](https://github.com/njyjn) | [kdybicz](https://github.com/kdybicz)
|
|
811
|
+
| [<img alt="m0ppers" src="https://avatars3.githubusercontent.com/u/819421?v=4&s=117" width="117">](https://github.com/m0ppers) | [<img alt="footballencarta" src="https://avatars0.githubusercontent.com/u/1312258?v=4&s=117" width="117">](https://github.com/footballencarta) | [<img alt="bryanvaz" src="https://avatars0.githubusercontent.com/u/9157498?v=4&s=117" width="117">](https://github.com/bryanvaz) | [<img alt="njyjn" src="https://avatars.githubusercontent.com/u/10694375?v=4&s=117" width="117">](https://github.com/njyjn) | [<img alt="kdybicz" src="https://avatars.githubusercontent.com/u/13134892?v=4" width="117">](https://github.com/kdybicz) |
|
|
812
|
+
| :---------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------ |
|
|
813
|
+
| [m0ppers](https://github.com/m0ppers) | [footballencarta](https://github.com/footballencarta) | [bryanvaz](https://github.com/bryanvaz) | [njyjn](https://github.com/njyjn) | [kdybicz](https://github.com/kdybicz) |
|
|
818
814
|
|
|
819
|
-
| [<img alt="ericctsf" src="https://avatars.githubusercontent.com/u/42775388?
|
|
820
|
-
|
|
|
821
|
-
|
|
|
815
|
+
| [<img alt="ericctsf" src="https://avatars.githubusercontent.com/u/42775388?v=4" width="117">](https://github.com/ericctsf) | [<img alt="brazilianbytes" src="https://avatars.githubusercontent.com/u/1900570?v=4" width="117">](https://github.com/brazilianbytes) |
|
|
816
|
+
| :------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------: |
|
|
817
|
+
| [ericctsf](https://github.com/erictsf) | [brazilianbytes](https://github.com/brazilianbytes) |
|
|
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
|
|
8
|
+
var _process = _interopRequireWildcard(require("process"));
|
|
9
|
+
|
|
8
10
|
var _updateNotifier = _interopRequireDefault(require("update-notifier"));
|
|
9
11
|
|
|
10
12
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
@@ -117,7 +119,7 @@ class ServerlessOffline {
|
|
|
117
119
|
}
|
|
118
120
|
|
|
119
121
|
_printBlankLine() {
|
|
120
|
-
if (
|
|
122
|
+
if (_process.env.NODE_ENV !== 'test') {
|
|
121
123
|
if (this.log) {
|
|
122
124
|
this.log.notice();
|
|
123
125
|
} else {
|
|
@@ -129,7 +131,7 @@ class ServerlessOffline {
|
|
|
129
131
|
|
|
130
132
|
async start() {
|
|
131
133
|
// Put here so available everywhere, not just in handlers
|
|
132
|
-
|
|
134
|
+
_process.env.IS_OFFLINE = true; // check if update is available
|
|
133
135
|
|
|
134
136
|
(0, _updateNotifier.default)({
|
|
135
137
|
pkg: _package.default
|
|
@@ -167,14 +169,14 @@ class ServerlessOffline {
|
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
async ready() {
|
|
170
|
-
if (
|
|
172
|
+
if (_process.env.NODE_ENV !== 'test') {
|
|
171
173
|
await this._listenForTermination();
|
|
172
174
|
}
|
|
173
175
|
}
|
|
174
176
|
|
|
175
177
|
async end(skipExit) {
|
|
176
178
|
// TEMP FIXME
|
|
177
|
-
if (
|
|
179
|
+
if (_process.env.NODE_ENV === 'test' && skipExit === undefined) {
|
|
178
180
|
return;
|
|
179
181
|
}
|
|
180
182
|
|
|
@@ -205,7 +207,7 @@ class ServerlessOffline {
|
|
|
205
207
|
await Promise.all(eventModules);
|
|
206
208
|
|
|
207
209
|
if (!skipExit) {
|
|
208
|
-
|
|
210
|
+
(0, _process.exit)(0);
|
|
209
211
|
}
|
|
210
212
|
}
|
|
211
213
|
|
|
@@ -231,7 +233,7 @@ class ServerlessOffline {
|
|
|
231
233
|
|
|
232
234
|
async _listenForTermination() {
|
|
233
235
|
const command = await new Promise(resolve => {
|
|
234
|
-
|
|
236
|
+
_process.default // SIGINT will be usually sent when user presses ctrl+c
|
|
235
237
|
.on('SIGINT', () => resolve('SIGINT')) // SIGTERM is a default termination signal in many cases,
|
|
236
238
|
// for example when "killing" a subprocess spawned in node
|
|
237
239
|
// with child_process methods
|
|
@@ -393,10 +395,15 @@ class ServerlessOffline {
|
|
|
393
395
|
httpEvent.http.method = '';
|
|
394
396
|
}
|
|
395
397
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
+
if (httpEvent.http.method === '*' && httpEvent.http.path === '*') {
|
|
399
|
+
httpEvent.http.routeKey = '$default';
|
|
400
|
+
} else {
|
|
401
|
+
const resolvedMethod = httpEvent.http.method === '*' ? 'ANY' : httpEvent.http.method.toUpperCase();
|
|
402
|
+
httpEvent.http.routeKey = `${resolvedMethod} ${httpEvent.http.path}`;
|
|
403
|
+
} // Clear these properties to avoid confusion (they will be derived from the routeKey
|
|
398
404
|
// when needed later)
|
|
399
405
|
|
|
406
|
+
|
|
400
407
|
delete httpEvent.http.method;
|
|
401
408
|
delete httpEvent.http.path;
|
|
402
409
|
} else {
|
|
@@ -23,7 +23,7 @@ const supportedJava = new Set(['java8', 'java11']); // NODE.JS
|
|
|
23
23
|
exports.supportedJava = supportedJava;
|
|
24
24
|
const supportedNodejs = new Set([// deprecated, but still working
|
|
25
25
|
'nodejs4.3', 'nodejs6.10', 'nodejs8.10', // supported
|
|
26
|
-
'nodejs10.x', 'nodejs12.x', 'nodejs14.x']); // PROVIDED
|
|
26
|
+
'nodejs10.x', 'nodejs12.x', 'nodejs14.x', 'nodejs16.x']); // PROVIDED
|
|
27
27
|
|
|
28
28
|
exports.supportedNodejs = supportedNodejs;
|
|
29
29
|
const supportedProvided = new Set(['provided']); // PYTHON
|
package/dist/debugLog.js
CHANGED
|
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
|
|
8
|
-
var
|
|
8
|
+
var _process = require("process");
|
|
9
|
+
|
|
10
|
+
var _default = typeof _process.env.SLS_DEBUG !== 'undefined' ? console.log.bind(null, '[offline]') : () => null;
|
|
9
11
|
|
|
10
12
|
exports.default = _default;
|
|
@@ -7,10 +7,15 @@ exports.default = authValidateContext;
|
|
|
7
7
|
|
|
8
8
|
var _boom = _interopRequireDefault(require("@hapi/boom"));
|
|
9
9
|
|
|
10
|
-
var _serverlessLog = _interopRequireDefault(require("
|
|
10
|
+
var _serverlessLog = _interopRequireDefault(require("../serverlessLog.js"));
|
|
11
11
|
|
|
12
12
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
13
|
|
|
14
|
+
const {
|
|
15
|
+
keys,
|
|
16
|
+
values
|
|
17
|
+
} = Object;
|
|
18
|
+
|
|
14
19
|
function internalServerError(message) {
|
|
15
20
|
const errorType = 'AuthorizerConfigurationException';
|
|
16
21
|
|
|
@@ -23,11 +28,11 @@ function internalServerError(message) {
|
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
function isValidContext(context) {
|
|
26
|
-
return
|
|
31
|
+
return values(context).every(i => typeof i === 'string' || typeof i === 'boolean' || typeof i === 'number');
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
function transform(context) {
|
|
30
|
-
|
|
35
|
+
keys(context).forEach(i => {
|
|
31
36
|
context[i] = context[i].toString();
|
|
32
37
|
});
|
|
33
38
|
return context;
|
|
@@ -63,7 +63,9 @@ class Endpoint {
|
|
|
63
63
|
this.progress = v3Utils.progress;
|
|
64
64
|
this.writeText = v3Utils.writeText;
|
|
65
65
|
this.v3Utils = v3Utils;
|
|
66
|
-
}
|
|
66
|
+
} // TODO FIXME
|
|
67
|
+
// eslint-disable-next-line no-constructor-return
|
|
68
|
+
|
|
67
69
|
|
|
68
70
|
return this._generate();
|
|
69
71
|
} // determine whether we have function level overrides for velocity templates
|
|
@@ -11,6 +11,8 @@ var _fs = require("fs");
|
|
|
11
11
|
|
|
12
12
|
var pathUtils = _interopRequireWildcard(require("path"));
|
|
13
13
|
|
|
14
|
+
var _process = _interopRequireWildcard(require("process"));
|
|
15
|
+
|
|
14
16
|
var _h2o = _interopRequireDefault(require("@hapi/h2o2"));
|
|
15
17
|
|
|
16
18
|
var _hapi = require("@hapi/hapi");
|
|
@@ -57,6 +59,11 @@ const {
|
|
|
57
59
|
parse,
|
|
58
60
|
stringify
|
|
59
61
|
} = JSON;
|
|
62
|
+
const {
|
|
63
|
+
assign,
|
|
64
|
+
entries,
|
|
65
|
+
keys
|
|
66
|
+
} = Object;
|
|
60
67
|
|
|
61
68
|
var _lambda = /*#__PURE__*/_classPrivateFieldLooseKey("lambda");
|
|
62
69
|
|
|
@@ -208,7 +215,7 @@ class HttpServer {
|
|
|
208
215
|
} // Override default headers with headers that have been explicitly set
|
|
209
216
|
|
|
210
217
|
|
|
211
|
-
|
|
218
|
+
keys(explicitlySetHeaders).forEach(key => {
|
|
212
219
|
const value = explicitlySetHeaders[key];
|
|
213
220
|
|
|
214
221
|
if (value) {
|
|
@@ -238,7 +245,7 @@ class HttpServer {
|
|
|
238
245
|
console.error(`Unexpected error while starting serverless-offline server on port ${httpPort}:`, err);
|
|
239
246
|
}
|
|
240
247
|
|
|
241
|
-
|
|
248
|
+
(0, _process.exit)(1);
|
|
242
249
|
} // TODO move the following block
|
|
243
250
|
|
|
244
251
|
|
|
@@ -257,8 +264,8 @@ class HttpServer {
|
|
|
257
264
|
(0, _serverlessLog.default)('Enter "rp" to replay the last request');
|
|
258
265
|
}
|
|
259
266
|
|
|
260
|
-
if (
|
|
261
|
-
|
|
267
|
+
if (_process.env.NODE_ENV !== 'test') {
|
|
268
|
+
_process.default.openStdin().addListener('data', data => {
|
|
262
269
|
// note: data is an object, and when converted to a string it will
|
|
263
270
|
// end with a linefeed. so we (rather crudely) account for that
|
|
264
271
|
// with toString() and then trim()
|
|
@@ -293,7 +300,7 @@ class HttpServer {
|
|
|
293
300
|
|
|
294
301
|
|
|
295
302
|
_printBlankLine() {
|
|
296
|
-
if (
|
|
303
|
+
if (_process.env.NODE_ENV !== 'test') {
|
|
297
304
|
if (this.log) {
|
|
298
305
|
this.log.notice();
|
|
299
306
|
} else {
|
|
@@ -405,7 +412,7 @@ class HttpServer {
|
|
|
405
412
|
if (typeof endpoint.authorizer === 'string') {
|
|
406
413
|
authorizerOptions.name = authFunctionName;
|
|
407
414
|
} else {
|
|
408
|
-
|
|
415
|
+
assign(authorizerOptions, endpoint.authorizer);
|
|
409
416
|
} // Create a unique scheme per endpoint
|
|
410
417
|
// This allows the methodArn on the event property to be set appropriately
|
|
411
418
|
|
|
@@ -803,7 +810,7 @@ class HttpServer {
|
|
|
803
810
|
}
|
|
804
811
|
}
|
|
805
812
|
|
|
806
|
-
for (const [key, value] of
|
|
813
|
+
for (const [key, value] of entries(endpoint.responses)) {
|
|
807
814
|
if (key !== 'default' && errorMessage.match(`^${value.selectionPattern || key}$`)) {
|
|
808
815
|
responseName = key;
|
|
809
816
|
break;
|
|
@@ -825,7 +832,7 @@ class HttpServer {
|
|
|
825
832
|
} = chosenResponse;
|
|
826
833
|
|
|
827
834
|
if (responseParameters) {
|
|
828
|
-
const responseParametersKeys =
|
|
835
|
+
const responseParametersKeys = keys(responseParameters);
|
|
829
836
|
|
|
830
837
|
if (this.log) {
|
|
831
838
|
this.log.debug('_____ RESPONSE PARAMETERS PROCCESSING _____');
|
|
@@ -836,7 +843,7 @@ class HttpServer {
|
|
|
836
843
|
} // responseParameters use the following shape: "key": "value"
|
|
837
844
|
|
|
838
845
|
|
|
839
|
-
|
|
846
|
+
entries(responseParameters).forEach(([key, value]) => {
|
|
840
847
|
const keyArray = key.split('.'); // eg: "method.response.header.location"
|
|
841
848
|
|
|
842
849
|
const valueArray = value.split('.'); // eg: "integration.response.body.redirect.url"
|
|
@@ -930,7 +937,7 @@ class HttpServer {
|
|
|
930
937
|
|
|
931
938
|
if (integration === 'AWS') {
|
|
932
939
|
const endpointResponseHeaders = endpoint.response && endpoint.response.headers || {};
|
|
933
|
-
|
|
940
|
+
entries(endpointResponseHeaders).filter(([, value]) => typeof value === 'string' && /^'.*?'$/.test(value)).forEach(([key, value]) => response.header(key, value.slice(1, -1)));
|
|
934
941
|
/* LAMBDA INTEGRATION RESPONSE TEMPLATE PROCCESSING */
|
|
935
942
|
// If there is a responseTemplate, we apply it to the result
|
|
936
943
|
|
|
@@ -939,7 +946,7 @@ class HttpServer {
|
|
|
939
946
|
} = chosenResponse;
|
|
940
947
|
|
|
941
948
|
if (typeof responseTemplates === 'object') {
|
|
942
|
-
const responseTemplatesKeys =
|
|
949
|
+
const responseTemplatesKeys = keys(responseTemplates);
|
|
943
950
|
|
|
944
951
|
if (responseTemplatesKeys.length) {
|
|
945
952
|
// BAD IMPLEMENTATION: first key in responseTemplates
|
|
@@ -1001,7 +1008,7 @@ class HttpServer {
|
|
|
1001
1008
|
response.source = _buffer.Buffer.from(result, 'base64');
|
|
1002
1009
|
response.variety = 'buffer';
|
|
1003
1010
|
} else if (typeof result === 'string') {
|
|
1004
|
-
response.source =
|
|
1011
|
+
response.source = stringify(result);
|
|
1005
1012
|
} else if (result && result.body && typeof result.body !== 'string') {
|
|
1006
1013
|
return this._reply502(response, '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', {});
|
|
1007
1014
|
} else {
|
|
@@ -1010,7 +1017,7 @@ class HttpServer {
|
|
|
1010
1017
|
} else if (integration === 'AWS_PROXY') {
|
|
1011
1018
|
/* LAMBDA PROXY INTEGRATION HAPIJS RESPONSE CONFIGURATION */
|
|
1012
1019
|
if (endpoint.isHttpApi && endpoint.payload === '2.0' && (typeof result === 'string' || !result.statusCode)) {
|
|
1013
|
-
const body = typeof result === 'string' ? result :
|
|
1020
|
+
const body = typeof result === 'string' ? result : stringify(result);
|
|
1014
1021
|
result = {
|
|
1015
1022
|
isBase64Encoded: false,
|
|
1016
1023
|
statusCode: 200,
|
|
@@ -1031,13 +1038,13 @@ class HttpServer {
|
|
|
1031
1038
|
const headers = {};
|
|
1032
1039
|
|
|
1033
1040
|
if (result && result.headers) {
|
|
1034
|
-
|
|
1041
|
+
keys(result.headers).forEach(header => {
|
|
1035
1042
|
headers[header] = (headers[header] || []).concat(result.headers[header]);
|
|
1036
1043
|
});
|
|
1037
1044
|
}
|
|
1038
1045
|
|
|
1039
1046
|
if (result && result.multiValueHeaders) {
|
|
1040
|
-
|
|
1047
|
+
keys(result.multiValueHeaders).forEach(header => {
|
|
1041
1048
|
headers[header] = (headers[header] || []).concat(result.multiValueHeaders[header]);
|
|
1042
1049
|
});
|
|
1043
1050
|
}
|
|
@@ -1057,7 +1064,7 @@ class HttpServer {
|
|
|
1057
1064
|
});
|
|
1058
1065
|
};
|
|
1059
1066
|
|
|
1060
|
-
|
|
1067
|
+
keys(headers).forEach(header => {
|
|
1061
1068
|
if (header.toLowerCase() === 'set-cookie') {
|
|
1062
1069
|
headers[header].forEach(parseCookies);
|
|
1063
1070
|
} else {
|
|
@@ -1081,7 +1088,7 @@ class HttpServer {
|
|
|
1081
1088
|
});
|
|
1082
1089
|
|
|
1083
1090
|
if (typeof result === 'string') {
|
|
1084
|
-
response.source =
|
|
1091
|
+
response.source = stringify(result);
|
|
1085
1092
|
} else if (result && typeof result.body !== 'undefined') {
|
|
1086
1093
|
if (result.isBase64Encoded) {
|
|
1087
1094
|
response.encoding = 'binary';
|
|
@@ -1164,7 +1171,7 @@ class HttpServer {
|
|
|
1164
1171
|
|
|
1165
1172
|
const resourceRoutes = (0, _parseResources.default)(_classPrivateFieldLooseBase(this, _serverless)[_serverless].service.resources);
|
|
1166
1173
|
|
|
1167
|
-
if (!resourceRoutes || !
|
|
1174
|
+
if (!resourceRoutes || !keys(resourceRoutes).length) {
|
|
1168
1175
|
return;
|
|
1169
1176
|
}
|
|
1170
1177
|
|
|
@@ -1177,7 +1184,7 @@ class HttpServer {
|
|
|
1177
1184
|
(0, _serverlessLog.default)('Routes defined in resources:');
|
|
1178
1185
|
}
|
|
1179
1186
|
|
|
1180
|
-
|
|
1187
|
+
entries(resourceRoutes).forEach(([methodId, resourceRoutesObj]) => {
|
|
1181
1188
|
const {
|
|
1182
1189
|
isProxy,
|
|
1183
1190
|
method,
|
|
@@ -1265,7 +1272,7 @@ class HttpServer {
|
|
|
1265
1272
|
params
|
|
1266
1273
|
} = request;
|
|
1267
1274
|
let resultUri = proxyUriInUse;
|
|
1268
|
-
|
|
1275
|
+
entries(params).forEach(([key, value]) => {
|
|
1269
1276
|
resultUri = resultUri.replace(`{${key}}`, value);
|
|
1270
1277
|
});
|
|
1271
1278
|
|