serverless-offline 8.8.0 → 9.1.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 +12 -11
- package/package.json +33 -58
- package/src/ServerlessOffline.js +409 -0
- package/src/config/commandOptions.js +159 -0
- package/src/config/constants.js +22 -0
- package/{dist → src}/config/defaultOptions.js +9 -17
- package/src/config/index.js +4 -0
- package/src/config/supportedRuntimes.js +47 -0
- package/src/events/authCanExecuteResource.js +35 -0
- package/src/events/authFunctionNameExtractor.js +75 -0
- package/src/events/authMatchPolicyResource.js +71 -0
- package/src/events/authValidateContext.js +51 -0
- package/src/events/http/Endpoint.js +135 -0
- package/src/events/http/Http.js +50 -0
- package/src/events/http/HttpEventDefinition.js +20 -0
- package/src/events/http/HttpServer.js +1242 -0
- package/src/events/http/OfflineEndpoint.js +33 -0
- package/src/events/http/authJWTSettingsExtractor.js +70 -0
- package/src/events/http/createAuthScheme.js +176 -0
- package/src/events/http/createJWTAuthScheme.js +106 -0
- package/src/events/http/index.js +1 -0
- package/src/events/http/javaHelpers.js +102 -0
- package/src/events/http/lambda-events/LambdaIntegrationEvent.js +57 -0
- package/src/events/http/lambda-events/LambdaProxyIntegrationEvent.js +233 -0
- package/src/events/http/lambda-events/LambdaProxyIntegrationEventV2.js +190 -0
- package/src/events/http/lambda-events/VelocityContext.js +147 -0
- package/src/events/http/lambda-events/index.js +4 -0
- package/src/events/http/lambda-events/renderVelocityTemplateObject.js +93 -0
- package/{dist → src}/events/http/parseResources.js +73 -78
- package/src/events/http/payloadSchemaValidator.js +13 -0
- package/{dist → src}/events/http/templates/offline-default.req.vm +0 -0
- package/{dist → src}/events/http/templates/offline-default.res.vm +0 -0
- package/src/events/schedule/Schedule.js +131 -0
- package/src/events/schedule/ScheduleEvent.js +18 -0
- package/src/events/schedule/ScheduleEventDefinition.js +21 -0
- package/src/events/schedule/index.js +1 -0
- package/src/events/websocket/HttpServer.js +69 -0
- package/src/events/websocket/WebSocket.js +52 -0
- package/src/events/websocket/WebSocketClients.js +462 -0
- package/src/events/websocket/WebSocketEventDefinition.js +18 -0
- package/src/events/websocket/WebSocketServer.js +73 -0
- package/src/events/websocket/http-routes/_catchAll/catchAllRoute.js +16 -0
- package/src/events/websocket/http-routes/_catchAll/index.js +1 -0
- package/src/events/websocket/http-routes/connections/ConnectionsController.js +28 -0
- package/src/events/websocket/http-routes/connections/connectionsRoutes.js +70 -0
- package/src/events/websocket/http-routes/connections/index.js +1 -0
- package/src/events/websocket/http-routes/index.js +2 -0
- package/src/events/websocket/index.js +1 -0
- package/src/events/websocket/lambda-events/WebSocketAuthorizerEvent.js +65 -0
- package/src/events/websocket/lambda-events/WebSocketConnectEvent.js +68 -0
- package/src/events/websocket/lambda-events/WebSocketDisconnectEvent.js +31 -0
- package/src/events/websocket/lambda-events/WebSocketEvent.js +29 -0
- package/src/events/websocket/lambda-events/WebSocketRequestContext.js +67 -0
- package/src/events/websocket/lambda-events/index.js +4 -0
- package/src/index.js +12 -0
- package/src/lambda/HttpServer.js +108 -0
- package/src/lambda/Lambda.js +68 -0
- package/src/lambda/LambdaContext.js +33 -0
- package/src/lambda/LambdaFunction.js +309 -0
- package/src/lambda/LambdaFunctionPool.js +109 -0
- package/src/lambda/__tests__/LambdaContext.test.js +30 -0
- package/src/lambda/__tests__/LambdaFunction.test.js +196 -0
- package/src/lambda/__tests__/fixtures/Lambda/LambdaFunctionThatReturnsJSONObject.fixture.js +47 -0
- package/src/lambda/__tests__/fixtures/Lambda/LambdaFunctionThatReturnsNativeString.fixture.js +46 -0
- package/src/lambda/__tests__/fixtures/Lambda/package.json +3 -0
- package/src/lambda/__tests__/fixtures/lambdaFunction.fixture.js +145 -0
- package/src/lambda/__tests__/fixtures/package.json +3 -0
- package/src/lambda/__tests__/routes/invocations/InvocationsController.test.js +42 -0
- package/src/lambda/handler-runner/HandlerRunner.js +136 -0
- package/src/lambda/handler-runner/child-process-runner/ChildProcessRunner.js +72 -0
- package/src/lambda/handler-runner/child-process-runner/childProcessHelper.js +42 -0
- package/src/lambda/handler-runner/child-process-runner/index.js +1 -0
- package/src/lambda/handler-runner/docker-runner/DockerContainer.js +417 -0
- package/src/lambda/handler-runner/docker-runner/DockerImage.js +35 -0
- package/src/lambda/handler-runner/docker-runner/DockerRunner.js +63 -0
- package/src/lambda/handler-runner/docker-runner/index.js +1 -0
- package/src/lambda/handler-runner/go-runner/GoRunner.js +167 -0
- package/src/lambda/handler-runner/go-runner/index.js +1 -0
- package/src/lambda/handler-runner/in-process-runner/InProcessRunner.js +125 -0
- package/src/lambda/handler-runner/in-process-runner/index.js +1 -0
- package/src/lambda/handler-runner/index.js +1 -0
- package/src/lambda/handler-runner/java-runner/JavaRunner.js +114 -0
- package/src/lambda/handler-runner/java-runner/index.js +1 -0
- package/src/lambda/handler-runner/python-runner/PythonRunner.js +138 -0
- package/src/lambda/handler-runner/python-runner/index.js +1 -0
- package/{dist → src}/lambda/handler-runner/python-runner/invoke.py +0 -0
- package/src/lambda/handler-runner/ruby-runner/RubyRunner.js +107 -0
- package/src/lambda/handler-runner/ruby-runner/index.js +1 -0
- package/{dist → src}/lambda/handler-runner/ruby-runner/invoke.rb +0 -0
- package/src/lambda/handler-runner/worker-thread-runner/WorkerThreadRunner.js +70 -0
- package/src/lambda/handler-runner/worker-thread-runner/index.js +1 -0
- package/src/lambda/handler-runner/worker-thread-runner/workerThreadHelper.js +29 -0
- package/src/lambda/index.js +1 -0
- package/src/lambda/routes/index.js +2 -0
- package/src/lambda/routes/invocations/InvocationsController.js +102 -0
- package/src/lambda/routes/invocations/index.js +1 -0
- package/src/lambda/routes/invocations/invocationsRoute.js +77 -0
- package/src/lambda/routes/invoke-async/InvokeAsyncController.js +20 -0
- package/src/lambda/routes/invoke-async/index.js +1 -0
- package/src/lambda/routes/invoke-async/invokeAsyncRoute.js +33 -0
- package/src/utils/__tests__/createUniqueId.test.js +18 -0
- package/src/utils/__tests__/formatToClfTime.test.js +14 -0
- package/src/utils/__tests__/generateHapiPath.test.js +46 -0
- package/src/utils/__tests__/lowerCaseKeys.test.js +30 -0
- package/src/utils/__tests__/parseHeaders.test.js +13 -0
- package/src/utils/__tests__/parseMultiValueHeaders.test.js +24 -0
- package/src/utils/__tests__/parseMultiValueQueryStringParameters.test.js +159 -0
- package/src/utils/__tests__/parseQueryStringParameters.test.js +15 -0
- package/src/utils/__tests__/splitHandlerPathAndName.test.js +54 -0
- package/src/utils/__tests__/unflatten.test.js +32 -0
- package/src/utils/checkDockerDaemon.js +19 -0
- package/src/utils/checkGoVersion.js +16 -0
- package/src/utils/createApiKey.js +5 -0
- package/src/utils/createUniqueId.js +5 -0
- package/src/utils/detectExecutable.js +11 -0
- package/{dist → src}/utils/formatToClfTime.js +6 -14
- package/src/utils/generateHapiPath.js +26 -0
- package/src/utils/getHttpApiCorsConfig.js +28 -0
- package/src/utils/index.js +42 -0
- package/src/utils/jsonPath.js +13 -0
- package/src/utils/logRoutes.js +64 -0
- package/src/utils/lowerCaseKeys.js +6 -0
- package/src/utils/parseHeaders.js +14 -0
- package/src/utils/parseMultiValueHeaders.js +27 -0
- package/src/utils/parseMultiValueQueryStringParameters.js +31 -0
- package/src/utils/parseQueryStringParameters.js +15 -0
- package/src/utils/splitHandlerPathAndName.js +31 -0
- package/src/utils/unflatten.js +11 -0
- package/dist/ServerlessOffline.js +0 -514
- package/dist/config/commandOptions.js +0 -149
- package/dist/config/constants.js +0 -30
- package/dist/config/index.js +0 -55
- package/dist/config/supportedRuntimes.js +0 -40
- package/dist/debugLog.js +0 -12
- package/dist/events/authCanExecuteResource.js +0 -35
- package/dist/events/authFunctionNameExtractor.js +0 -87
- package/dist/events/authMatchPolicyResource.js +0 -62
- package/dist/events/authValidateContext.js +0 -53
- package/dist/events/http/Endpoint.js +0 -173
- package/dist/events/http/Http.js +0 -77
- package/dist/events/http/HttpEventDefinition.js +0 -36
- package/dist/events/http/HttpServer.js +0 -1370
- package/dist/events/http/OfflineEndpoint.js +0 -38
- package/dist/events/http/authJWTSettingsExtractor.js +0 -76
- package/dist/events/http/createAuthScheme.js +0 -184
- package/dist/events/http/createJWTAuthScheme.js +0 -159
- package/dist/events/http/index.js +0 -15
- package/dist/events/http/javaHelpers.js +0 -99
- package/dist/events/http/lambda-events/LambdaIntegrationEvent.js +0 -87
- package/dist/events/http/lambda-events/LambdaProxyIntegrationEvent.js +0 -246
- package/dist/events/http/lambda-events/LambdaProxyIntegrationEventV2.js +0 -225
- package/dist/events/http/lambda-events/VelocityContext.js +0 -170
- package/dist/events/http/lambda-events/index.js +0 -39
- package/dist/events/http/lambda-events/renderVelocityTemplateObject.js +0 -111
- package/dist/events/http/payloadSchemaValidator.js +0 -13
- package/dist/events/schedule/Schedule.js +0 -183
- package/dist/events/schedule/ScheduleEvent.js +0 -27
- package/dist/events/schedule/ScheduleEventDefinition.js +0 -36
- package/dist/events/schedule/index.js +0 -15
- package/dist/events/websocket/HttpServer.js +0 -114
- package/dist/events/websocket/WebSocket.js +0 -78
- package/dist/events/websocket/WebSocketClients.js +0 -577
- package/dist/events/websocket/WebSocketEventDefinition.js +0 -32
- package/dist/events/websocket/WebSocketServer.js +0 -139
- package/dist/events/websocket/http-routes/_catchAll/catchAllRoute.js +0 -33
- package/dist/events/websocket/http-routes/_catchAll/index.js +0 -15
- package/dist/events/websocket/http-routes/connections/ConnectionsController.js +0 -45
- package/dist/events/websocket/http-routes/connections/connectionsRoutes.js +0 -95
- package/dist/events/websocket/http-routes/connections/index.js +0 -15
- package/dist/events/websocket/http-routes/index.js +0 -23
- package/dist/events/websocket/index.js +0 -15
- package/dist/events/websocket/lambda-events/WebSocketAuthorizerEvent.js +0 -99
- package/dist/events/websocket/lambda-events/WebSocketConnectEvent.js +0 -101
- package/dist/events/websocket/lambda-events/WebSocketDisconnectEvent.js +0 -47
- package/dist/events/websocket/lambda-events/WebSocketEvent.js +0 -54
- package/dist/events/websocket/lambda-events/WebSocketRequestContext.js +0 -98
- package/dist/events/websocket/lambda-events/index.js +0 -39
- package/dist/index.js +0 -15
- package/dist/lambda/HttpServer.js +0 -124
- package/dist/lambda/Lambda.js +0 -117
- package/dist/lambda/LambdaContext.js +0 -53
- package/dist/lambda/LambdaFunction.js +0 -390
- package/dist/lambda/LambdaFunctionPool.js +0 -127
- package/dist/lambda/handler-runner/HandlerRunner.js +0 -195
- package/dist/lambda/handler-runner/child-process-runner/ChildProcessRunner.js +0 -124
- package/dist/lambda/handler-runner/child-process-runner/childProcessHelper.js +0 -49
- package/dist/lambda/handler-runner/child-process-runner/index.js +0 -15
- package/dist/lambda/handler-runner/docker-runner/DockerContainer.js +0 -515
- package/dist/lambda/handler-runner/docker-runner/DockerImage.js +0 -67
- package/dist/lambda/handler-runner/docker-runner/DockerRunner.js +0 -74
- package/dist/lambda/handler-runner/docker-runner/index.js +0 -15
- package/dist/lambda/handler-runner/go-runner/GoRunner.js +0 -230
- package/dist/lambda/handler-runner/go-runner/index.js +0 -15
- package/dist/lambda/handler-runner/in-process-runner/InProcessRunner.js +0 -228
- package/dist/lambda/handler-runner/in-process-runner/index.js +0 -15
- package/dist/lambda/handler-runner/index.js +0 -15
- package/dist/lambda/handler-runner/java-runner/JavaRunner.js +0 -153
- package/dist/lambda/handler-runner/java-runner/index.js +0 -15
- package/dist/lambda/handler-runner/python-runner/PythonRunner.js +0 -185
- package/dist/lambda/handler-runner/python-runner/index.js +0 -15
- package/dist/lambda/handler-runner/ruby-runner/RubyRunner.js +0 -147
- package/dist/lambda/handler-runner/ruby-runner/index.js +0 -15
- package/dist/lambda/handler-runner/worker-thread-runner/WorkerThreadRunner.js +0 -92
- package/dist/lambda/handler-runner/worker-thread-runner/index.js +0 -15
- package/dist/lambda/handler-runner/worker-thread-runner/workerThreadHelper.js +0 -31
- package/dist/lambda/index.js +0 -15
- package/dist/lambda/routes/index.js +0 -23
- package/dist/lambda/routes/invocations/InvocationsController.js +0 -142
- package/dist/lambda/routes/invocations/index.js +0 -15
- package/dist/lambda/routes/invocations/invocationsRoute.js +0 -90
- package/dist/lambda/routes/invoke-async/InvokeAsyncController.js +0 -38
- package/dist/lambda/routes/invoke-async/index.js +0 -15
- package/dist/lambda/routes/invoke-async/invokeAsyncRoute.js +0 -43
- package/dist/main.js +0 -11
- package/dist/serverlessLog.js +0 -91
- package/dist/utils/checkDockerDaemon.js +0 -27
- package/dist/utils/checkGoVersion.js +0 -27
- package/dist/utils/createApiKey.js +0 -12
- package/dist/utils/createUniqueId.js +0 -14
- package/dist/utils/detectExecutable.js +0 -21
- package/dist/utils/generateHapiPath.js +0 -28
- package/dist/utils/getHttpApiCorsConfig.js +0 -40
- package/dist/utils/index.js +0 -165
- package/dist/utils/jsonPath.js +0 -21
- package/dist/utils/lowerCaseKeys.js +0 -14
- package/dist/utils/parseHeaders.js +0 -23
- package/dist/utils/parseMultiValueHeaders.js +0 -36
- package/dist/utils/parseMultiValueQueryStringParameters.js +0 -40
- package/dist/utils/parseQueryStringParameters.js +0 -26
- package/dist/utils/resolveJoins.js +0 -36
- package/dist/utils/satisfiesVersionRange.js +0 -20
- package/dist/utils/splitHandlerPathAndName.js +0 -37
- package/dist/utils/unflatten.js +0 -18
package/README.md
CHANGED
|
@@ -89,7 +89,7 @@ plugins:
|
|
|
89
89
|
- serverless-offline
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
You can check
|
|
92
|
+
You can check whether you have successfully installed the plugin by running the serverless command line:
|
|
93
93
|
|
|
94
94
|
`serverless --verbose`
|
|
95
95
|
|
|
@@ -108,7 +108,6 @@ to list all the options for the plugin run:
|
|
|
108
108
|
All CLI options are optional:
|
|
109
109
|
|
|
110
110
|
```
|
|
111
|
-
--allowCache Allows the code of lambda functions to cache if supported.
|
|
112
111
|
--apiKey Defines the API key value to be used for endpoints marked as private Defaults to a random hash.
|
|
113
112
|
--corsAllowHeaders Used as default Access-Control-Allow-Headers header value for responses. Delimit multiple values with commas. Default: 'accept,content-type,x-api-key'
|
|
114
113
|
--corsAllowOrigin Used as default Access-Control-Allow-Origin header value for responses. Delimit multiple values with commas. Default: '*'
|
|
@@ -128,16 +127,18 @@ All CLI options are optional:
|
|
|
128
127
|
--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.
|
|
129
128
|
--lambdaPort Lambda http port to listen on. Default: 3002
|
|
130
129
|
--layersDir The directory layers should be stored in. Default: ${codeDir}/.serverless-offline/layers'
|
|
130
|
+
--localEnvironment Copy local environment variables. Default: false
|
|
131
131
|
--noAuth Turns off all authorizers
|
|
132
132
|
--noPrependStageInUrl Don't prepend http routes with the stage.
|
|
133
133
|
--noStripTrailingSlashInUrl Don't strip trailing slash from http routes.
|
|
134
134
|
--noTimeout -t Disables the timeout feature.
|
|
135
135
|
--prefix -p Adds a prefix to every path, to send your requests to http://localhost:3000/[prefix]/[your_path] instead. Default: ''
|
|
136
136
|
--printOutput Turns on logging of your lambda outputs in the terminal.
|
|
137
|
+
--reloadHandler Reloads handler with each request.
|
|
137
138
|
--resourceRoutes Turns on loading of your HTTP proxy settings from serverless.yml
|
|
138
139
|
--useChildProcesses Run handlers in a child process
|
|
139
140
|
--useDocker Run handlers in a docker container.
|
|
140
|
-
--
|
|
141
|
+
--useInProcess Run handlers in the same process as 'serverless-offline'.
|
|
141
142
|
--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)
|
|
142
143
|
--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)
|
|
143
144
|
--websocketPort WebSocket port to listen on. Default: 3001
|
|
@@ -266,14 +267,14 @@ If you're using least-privilege principals for your AWS roles, this policy shoul
|
|
|
266
267
|
|
|
267
268
|
```json
|
|
268
269
|
{
|
|
269
|
-
"Version": "2012-10-17",
|
|
270
270
|
"Statement": [
|
|
271
271
|
{
|
|
272
|
-
"Effect": "Allow",
|
|
273
272
|
"Action": "lambda:GetLayerVersion",
|
|
273
|
+
"Effect": "Allow",
|
|
274
274
|
"Resource": "arn:aws:lambda:*:*:layer:*:*"
|
|
275
275
|
}
|
|
276
|
-
]
|
|
276
|
+
],
|
|
277
|
+
"Version": "2012-10-17"
|
|
277
278
|
}
|
|
278
279
|
```
|
|
279
280
|
|
|
@@ -603,13 +604,13 @@ Add a new [launch configuration](https://code.visualstudio.com/docs/editor/debug
|
|
|
603
604
|
|
|
604
605
|
```json
|
|
605
606
|
{
|
|
606
|
-
"type": "node",
|
|
607
|
-
"request": "launch",
|
|
608
|
-
"name": "Debug Serverless Offline",
|
|
609
607
|
"cwd": "${workspaceFolder}",
|
|
610
|
-
"
|
|
608
|
+
"name": "Debug Serverless Offline",
|
|
609
|
+
"request": "launch",
|
|
611
610
|
"runtimeArgs": ["run", "debug"],
|
|
612
|
-
"
|
|
611
|
+
"runtimeExecutable": "npm",
|
|
612
|
+
"sourceMaps": true,
|
|
613
|
+
"type": "node"
|
|
613
614
|
}
|
|
614
615
|
```
|
|
615
616
|
|
package/package.json
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dedicatedTo": "Blue, a great migrating bird.",
|
|
3
3
|
"name": "serverless-offline",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "9.1.0",
|
|
5
5
|
"description": "Emulate AWS λ and API Gateway locally when developing your Serverless project",
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"main": "
|
|
8
|
-
"
|
|
7
|
+
"main": "./src/index.js",
|
|
8
|
+
"exports": "./src/index.js",
|
|
9
|
+
"type": "module",
|
|
9
10
|
"scripts": {
|
|
10
|
-
"build": "rimraf dist && babel src --ignore \"**/__tests__/**/*\" --out-dir dist && copyfiles -u 1 \"src/**/*.{vm,py,rb}\" dist",
|
|
11
11
|
"format": "eslint . --fix",
|
|
12
12
|
"lint": "eslint .",
|
|
13
13
|
"lint:updated": "pipe-git-updated --ext=js -- eslint",
|
|
14
14
|
"list-contributors": "echo 'clone https://github.com/mgechev/github-contributors-list.git first, then run npm install' && cd ../github-contributors-list && node bin/githubcontrib --owner dherault --repo serverless-offline --sortBy contributions --showlogin true --sortOrder desc > contributors.md",
|
|
15
|
-
"prepare": "
|
|
15
|
+
"prepare": "husky install",
|
|
16
16
|
"prepare-release": "standard-version && prettier --write CHANGELOG.md",
|
|
17
|
-
"prepublishOnly": "npm run lint
|
|
17
|
+
"prepublishOnly": "npm run lint",
|
|
18
18
|
"prettier-check": "prettier -c --ignore-path .gitignore \"**/*.{css,html,js,json,md,yaml,yml}\"",
|
|
19
19
|
"prettier-check:updated": "pipe-git-updated --ext=css --ext=html --ext=js --ext=json --ext=md --ext=yaml --ext=yml -- prettier -c",
|
|
20
20
|
"prettify": "prettier --write --ignore-path .gitignore \"**/*.{css,html,js,json,md,yaml,yml}\"",
|
|
21
21
|
"prettify:updated": "pipe-git-updated --ext=css --ext=html --ext=js --ext=json --ext=md --ext=yaml --ext=yml -- prettier --write",
|
|
22
|
-
"test": "
|
|
22
|
+
"test": "mocha --require ./tests/mochaHooks.cjs",
|
|
23
|
+
"test:jest": "npm run build && jest --verbose --silent --runInBand",
|
|
23
24
|
"test:cov": "npm run build && jest --coverage --silent --runInBand --collectCoverageFrom=src/**/*.js",
|
|
24
25
|
"test:log": "npm run build && jest --verbose",
|
|
25
26
|
"test:noBuild": "jest --verbose --runInBand --bail",
|
|
@@ -49,7 +50,7 @@
|
|
|
49
50
|
"websocket"
|
|
50
51
|
],
|
|
51
52
|
"files": [
|
|
52
|
-
"
|
|
53
|
+
"src/**",
|
|
53
54
|
"package.json",
|
|
54
55
|
"LICENSE",
|
|
55
56
|
"README.md"
|
|
@@ -162,21 +163,8 @@
|
|
|
162
163
|
"Fernando Alvarez (https://github.com/jefer590)",
|
|
163
164
|
"Eric Carter (https://github.com/ericctsf)"
|
|
164
165
|
],
|
|
165
|
-
"husky": {
|
|
166
|
-
"hooks": {
|
|
167
|
-
"pre-commit": "lint-staged"
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
"lint-staged": {
|
|
171
|
-
"*.js": [
|
|
172
|
-
"eslint"
|
|
173
|
-
],
|
|
174
|
-
"*.{css,html,js,json,md,yaml,yml}": [
|
|
175
|
-
"prettier -c"
|
|
176
|
-
]
|
|
177
|
-
},
|
|
178
166
|
"engines": {
|
|
179
|
-
"node": ">=
|
|
167
|
+
"node": ">=14.18.0"
|
|
180
168
|
},
|
|
181
169
|
"standard-version": {
|
|
182
170
|
"skip": {
|
|
@@ -203,59 +191,46 @@
|
|
|
203
191
|
]
|
|
204
192
|
},
|
|
205
193
|
"dependencies": {
|
|
206
|
-
"@hapi/boom": "^
|
|
194
|
+
"@hapi/boom": "^10.0.0",
|
|
207
195
|
"@hapi/h2o2": "^9.1.0",
|
|
208
196
|
"@hapi/hapi": "^20.2.2",
|
|
209
|
-
"aws-sdk": "^2.
|
|
210
|
-
"boxen": "^
|
|
211
|
-
"chalk": "^
|
|
212
|
-
"
|
|
213
|
-
"execa": "^5.1.1",
|
|
197
|
+
"aws-sdk": "^2.1181.0",
|
|
198
|
+
"boxen": "^7.0.0",
|
|
199
|
+
"chalk": "^5.0.1",
|
|
200
|
+
"execa": "^6.1.0",
|
|
214
201
|
"fs-extra": "^10.1.0",
|
|
215
202
|
"java-invoke-local": "0.0.6",
|
|
216
203
|
"js-string-escape": "^1.0.1",
|
|
217
|
-
"jsonpath-plus": "^
|
|
218
|
-
"jsonschema": "^1.4.
|
|
204
|
+
"jsonpath-plus": "^7.0.0",
|
|
205
|
+
"jsonschema": "^1.4.1",
|
|
219
206
|
"jsonwebtoken": "^8.5.1",
|
|
220
|
-
"jszip": "^3.
|
|
221
|
-
"luxon": "^
|
|
222
|
-
"node-fetch": "^2.
|
|
207
|
+
"jszip": "^3.10.0",
|
|
208
|
+
"luxon": "^3.0.1",
|
|
209
|
+
"node-fetch": "^3.2.9",
|
|
223
210
|
"node-schedule": "^2.1.0",
|
|
224
|
-
"
|
|
225
|
-
"p-
|
|
226
|
-
"p-retry": "^
|
|
227
|
-
"semver": "^7.3.7",
|
|
228
|
-
"update-notifier": "^5.1.0",
|
|
211
|
+
"object.hasown": "^1.1.1",
|
|
212
|
+
"p-memoize": "^7.1.0",
|
|
213
|
+
"p-retry": "^5.1.1",
|
|
229
214
|
"velocityjs": "^2.0.6",
|
|
230
|
-
"ws": "^
|
|
215
|
+
"ws": "^8.8.1"
|
|
231
216
|
},
|
|
232
217
|
"devDependencies": {
|
|
233
|
-
"@babel/cli": "^7.17.10",
|
|
234
|
-
"@babel/core": "^7.17.12",
|
|
235
|
-
"@babel/plugin-proposal-class-properties": "^7.17.12",
|
|
236
|
-
"@babel/plugin-proposal-dynamic-import": "^7.16.7",
|
|
237
|
-
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.17.12",
|
|
238
|
-
"@babel/plugin-proposal-optional-chaining": "^7.17.12",
|
|
239
|
-
"@babel/plugin-transform-modules-commonjs": "^7.17.12",
|
|
240
|
-
"@babel/register": "^7.17.7",
|
|
241
218
|
"archiver": "^5.3.1",
|
|
242
|
-
"
|
|
243
|
-
"eslint": "^8.15.0",
|
|
219
|
+
"eslint": "^8.20.0",
|
|
244
220
|
"eslint-config-airbnb-base": "^15.0.0",
|
|
245
221
|
"eslint-config-prettier": "^8.5.0",
|
|
246
222
|
"eslint-plugin-import": "^2.25.4",
|
|
247
|
-
"eslint-plugin-prettier": "^4.
|
|
223
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
248
224
|
"git-list-updated": "^1.2.1",
|
|
249
|
-
"husky": "^
|
|
250
|
-
"
|
|
251
|
-
"
|
|
252
|
-
"
|
|
253
|
-
"
|
|
254
|
-
"rimraf": "^3.0.2",
|
|
255
|
-
"serverless": "^2.72.3",
|
|
225
|
+
"husky": "^8.0.1",
|
|
226
|
+
"lint-staged": "^13.0.3",
|
|
227
|
+
"mocha": "^10.0.0",
|
|
228
|
+
"prettier": "^2.7.1",
|
|
229
|
+
"serverless": "^3.21.0",
|
|
256
230
|
"standard-version": "^9.5.0"
|
|
257
231
|
},
|
|
258
232
|
"peerDependencies": {
|
|
259
|
-
"serverless": "^
|
|
233
|
+
"@serverless/utils": "^6.7.0",
|
|
234
|
+
"serverless": "^3.2.0"
|
|
260
235
|
}
|
|
261
236
|
}
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
import process, { exit } from 'node:process'
|
|
2
|
+
import { log } from '@serverless/utils/log.js'
|
|
3
|
+
import chalk from 'chalk'
|
|
4
|
+
import {
|
|
5
|
+
commandOptions,
|
|
6
|
+
CUSTOM_OPTION,
|
|
7
|
+
defaultOptions,
|
|
8
|
+
SERVER_SHUTDOWN_TIMEOUT,
|
|
9
|
+
} from './config/index.js'
|
|
10
|
+
|
|
11
|
+
export default class ServerlessOffline {
|
|
12
|
+
#cliOptions = null
|
|
13
|
+
|
|
14
|
+
#http = null
|
|
15
|
+
|
|
16
|
+
#lambda = null
|
|
17
|
+
|
|
18
|
+
#options = null
|
|
19
|
+
|
|
20
|
+
#schedule = null
|
|
21
|
+
|
|
22
|
+
#serverless = null
|
|
23
|
+
|
|
24
|
+
#webSocket = null
|
|
25
|
+
|
|
26
|
+
constructor(serverless, cliOptions) {
|
|
27
|
+
this.#cliOptions = cliOptions
|
|
28
|
+
this.#serverless = serverless
|
|
29
|
+
|
|
30
|
+
this.commands = {
|
|
31
|
+
offline: {
|
|
32
|
+
// add start nested options
|
|
33
|
+
commands: {
|
|
34
|
+
functionsUpdated: {
|
|
35
|
+
lifecycleEvents: ['cleanup'],
|
|
36
|
+
type: 'entrypoint',
|
|
37
|
+
},
|
|
38
|
+
start: {
|
|
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
|
+
},
|
|
44
|
+
},
|
|
45
|
+
lifecycleEvents: ['start'],
|
|
46
|
+
options: commandOptions,
|
|
47
|
+
usage: 'Simulates API Gateway to call your lambda functions offline.',
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.hooks = {
|
|
52
|
+
'offline:functionsUpdated:cleanup': this.#cleanupFunctions.bind(this),
|
|
53
|
+
'offline:start': this.#startWithExplicitEnd.bind(this),
|
|
54
|
+
'offline:start:end': this.end.bind(this),
|
|
55
|
+
'offline:start:init': this.start.bind(this),
|
|
56
|
+
'offline:start:ready': this.#ready.bind(this),
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Entry point for the plugin (sls offline) when running 'sls offline start'
|
|
61
|
+
async start() {
|
|
62
|
+
this.#mergeOptions()
|
|
63
|
+
|
|
64
|
+
const { httpEvents, lambdas, scheduleEvents, webSocketEvents } =
|
|
65
|
+
this.#getEvents()
|
|
66
|
+
|
|
67
|
+
// if (lambdas.length > 0) {
|
|
68
|
+
await this.#createLambda(lambdas)
|
|
69
|
+
// }
|
|
70
|
+
|
|
71
|
+
const eventModules = []
|
|
72
|
+
|
|
73
|
+
if (httpEvents.length > 0) {
|
|
74
|
+
eventModules.push(this.#createHttp(httpEvents))
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!this.#options.disableScheduledEvents && scheduleEvents.length > 0) {
|
|
78
|
+
eventModules.push(this.#createSchedule(scheduleEvents))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (webSocketEvents.length > 0) {
|
|
82
|
+
eventModules.push(this.#createWebSocket(webSocketEvents))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
await Promise.all(eventModules)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async #ready() {
|
|
89
|
+
await this.#listenForTermination()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async end(skipExit) {
|
|
93
|
+
log.info('Halting offline server')
|
|
94
|
+
|
|
95
|
+
const eventModules = []
|
|
96
|
+
|
|
97
|
+
if (this.#lambda) {
|
|
98
|
+
eventModules.push(this.#lambda.cleanup())
|
|
99
|
+
eventModules.push(this.#lambda.stop(SERVER_SHUTDOWN_TIMEOUT))
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (this.#http) {
|
|
103
|
+
eventModules.push(this.#http.stop(SERVER_SHUTDOWN_TIMEOUT))
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// if (this.#schedule) {
|
|
107
|
+
// eventModules.push(this.#schedule.stop())
|
|
108
|
+
// }
|
|
109
|
+
|
|
110
|
+
if (this.#webSocket) {
|
|
111
|
+
eventModules.push(this.#webSocket.stop(SERVER_SHUTDOWN_TIMEOUT))
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
await Promise.all(eventModules)
|
|
115
|
+
|
|
116
|
+
if (!skipExit) {
|
|
117
|
+
exit(0)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async #cleanupFunctions() {
|
|
122
|
+
if (this.#lambda) {
|
|
123
|
+
log.debug('Forcing cleanup of Lambda functions')
|
|
124
|
+
await this.#lambda.cleanup()
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Entry point for the plugin (serverless offline) when running 'serverless offline'
|
|
130
|
+
* The call to this.end() would terminate the process before 'offline:start:end' could be consumed
|
|
131
|
+
* by downstream plugins. When running serverless offline that can be expected, but docs say that
|
|
132
|
+
* 'serverless offline start' will provide the init and end hooks for other plugins to consume
|
|
133
|
+
* */
|
|
134
|
+
async #startWithExplicitEnd() {
|
|
135
|
+
await this.start()
|
|
136
|
+
await this.#ready()
|
|
137
|
+
this.end()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async #listenForTermination() {
|
|
141
|
+
const command = await new Promise((resolve) => {
|
|
142
|
+
process
|
|
143
|
+
// SIGINT will be usually sent when user presses ctrl+c
|
|
144
|
+
.on('SIGINT', () => resolve('SIGINT'))
|
|
145
|
+
// SIGTERM is a default termination signal in many cases,
|
|
146
|
+
// for example when "killing" a subprocess spawned in node
|
|
147
|
+
// with child_process methods
|
|
148
|
+
.on('SIGTERM', () => resolve('SIGTERM'))
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
log.info(`Got ${command} signal. Offline Halting...`)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async #createLambda(lambdas, skipStart) {
|
|
155
|
+
const { default: Lambda } = await import('./lambda/index.js')
|
|
156
|
+
|
|
157
|
+
this.#lambda = new Lambda(this.#serverless, this.#options)
|
|
158
|
+
|
|
159
|
+
this.#lambda.create(lambdas)
|
|
160
|
+
|
|
161
|
+
if (!skipStart) {
|
|
162
|
+
await this.#lambda.start()
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async #createHttp(events, skipStart) {
|
|
167
|
+
const { default: Http } = await import('./events/http/index.js')
|
|
168
|
+
|
|
169
|
+
this.#http = new Http(this.#serverless, this.#options, this.#lambda)
|
|
170
|
+
|
|
171
|
+
await this.#http.registerPlugins()
|
|
172
|
+
|
|
173
|
+
this.#http.create(events)
|
|
174
|
+
|
|
175
|
+
// HTTP Proxy defined in Resource
|
|
176
|
+
this.#http.createResourceRoutes()
|
|
177
|
+
|
|
178
|
+
// Not found handling
|
|
179
|
+
// we have to create the 404 routes last, otherwise we could have
|
|
180
|
+
// collisions with catch all routes, e.g. any (proxy+}
|
|
181
|
+
this.#http.create404Route()
|
|
182
|
+
|
|
183
|
+
if (!skipStart) {
|
|
184
|
+
await this.#http.start()
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async #createSchedule(events) {
|
|
189
|
+
const { default: Schedule } = await import('./events/schedule/index.js')
|
|
190
|
+
|
|
191
|
+
this.#schedule = new Schedule(
|
|
192
|
+
this.#lambda,
|
|
193
|
+
this.#serverless.service.provider.region,
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
this.#schedule.create(events)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async #createWebSocket(events) {
|
|
200
|
+
const { default: WebSocket } = await import('./events/websocket/index.js')
|
|
201
|
+
|
|
202
|
+
this.#webSocket = new WebSocket(
|
|
203
|
+
this.#serverless,
|
|
204
|
+
this.#options,
|
|
205
|
+
this.#lambda,
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
this.#webSocket.create(events)
|
|
209
|
+
|
|
210
|
+
return this.#webSocket.start()
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
#mergeOptions() {
|
|
214
|
+
const {
|
|
215
|
+
service: { custom = {}, provider },
|
|
216
|
+
} = this.#serverless
|
|
217
|
+
|
|
218
|
+
const customOptions = custom[CUSTOM_OPTION]
|
|
219
|
+
|
|
220
|
+
// merge options
|
|
221
|
+
// order of Precedence: command line options, custom options, defaults.
|
|
222
|
+
this.#options = {
|
|
223
|
+
...defaultOptions,
|
|
224
|
+
...customOptions,
|
|
225
|
+
...this.#cliOptions,
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Parse CORS options
|
|
229
|
+
this.#options.corsAllowHeaders = this.#options.corsAllowHeaders
|
|
230
|
+
.replace(/\s/g, '')
|
|
231
|
+
.split(',')
|
|
232
|
+
this.#options.corsAllowOrigin = this.#options.corsAllowOrigin
|
|
233
|
+
.replace(/\s/g, '')
|
|
234
|
+
.split(',')
|
|
235
|
+
this.#options.corsExposedHeaders = this.#options.corsExposedHeaders
|
|
236
|
+
.replace(/\s/g, '')
|
|
237
|
+
.split(',')
|
|
238
|
+
|
|
239
|
+
if (this.#options.corsDisallowCredentials) {
|
|
240
|
+
this.#options.corsAllowCredentials = false
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
this.#options.corsConfig = {
|
|
244
|
+
credentials: this.#options.corsAllowCredentials,
|
|
245
|
+
exposedHeaders: this.#options.corsExposedHeaders,
|
|
246
|
+
headers: this.#options.corsAllowHeaders,
|
|
247
|
+
origin: this.#options.corsAllowOrigin,
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
log.notice()
|
|
251
|
+
log.notice(
|
|
252
|
+
`Starting Offline at stage ${provider.stage} ${chalk.gray(
|
|
253
|
+
`(${provider.region})`,
|
|
254
|
+
)}`,
|
|
255
|
+
)
|
|
256
|
+
log.notice()
|
|
257
|
+
log.debug('options:', this.#options)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
#getEvents() {
|
|
261
|
+
const { service } = this.#serverless
|
|
262
|
+
|
|
263
|
+
const httpEvents = []
|
|
264
|
+
const lambdas = []
|
|
265
|
+
const scheduleEvents = []
|
|
266
|
+
const webSocketEvents = []
|
|
267
|
+
|
|
268
|
+
const functionKeys = service.getAllFunctions()
|
|
269
|
+
|
|
270
|
+
let hasPrivateHttpEvent = false
|
|
271
|
+
|
|
272
|
+
functionKeys.forEach((functionKey) => {
|
|
273
|
+
const functionDefinition = service.getFunction(functionKey)
|
|
274
|
+
|
|
275
|
+
lambdas.push({ functionDefinition, functionKey })
|
|
276
|
+
|
|
277
|
+
const events = service.getAllEventsInFunction(functionKey) || []
|
|
278
|
+
|
|
279
|
+
events.forEach((event) => {
|
|
280
|
+
const { http, httpApi, schedule, websocket } = event
|
|
281
|
+
|
|
282
|
+
if ((http || httpApi) && functionDefinition.handler) {
|
|
283
|
+
const httpEvent = {
|
|
284
|
+
functionKey,
|
|
285
|
+
handler: functionDefinition.handler,
|
|
286
|
+
http: http || httpApi,
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (httpApi) {
|
|
290
|
+
// Ensure definitions for 'httpApi' events are objects so that they can be marked
|
|
291
|
+
// with an 'isHttpApi' property (they are handled differently to 'http' events)
|
|
292
|
+
if (typeof httpEvent.http === 'string') {
|
|
293
|
+
httpEvent.http = {
|
|
294
|
+
routeKey: httpEvent.http === '*' ? '$default' : httpEvent.http,
|
|
295
|
+
}
|
|
296
|
+
} else if (typeof httpEvent.http === 'object') {
|
|
297
|
+
if (!httpEvent.http.method) {
|
|
298
|
+
log.warning(
|
|
299
|
+
`Event definition is missing a method for function "${functionKey}"`,
|
|
300
|
+
)
|
|
301
|
+
httpEvent.http.method = ''
|
|
302
|
+
}
|
|
303
|
+
if (
|
|
304
|
+
httpEvent.http.method === '*' &&
|
|
305
|
+
httpEvent.http.path === '*'
|
|
306
|
+
) {
|
|
307
|
+
httpEvent.http.routeKey = '$default'
|
|
308
|
+
} else {
|
|
309
|
+
const resolvedMethod =
|
|
310
|
+
httpEvent.http.method === '*'
|
|
311
|
+
? 'ANY'
|
|
312
|
+
: httpEvent.http.method.toUpperCase()
|
|
313
|
+
httpEvent.http.routeKey = `${resolvedMethod} ${httpEvent.http.path}`
|
|
314
|
+
}
|
|
315
|
+
// Clear these properties to avoid confusion (they will be derived from the routeKey
|
|
316
|
+
// when needed later)
|
|
317
|
+
delete httpEvent.http.method
|
|
318
|
+
delete httpEvent.http.path
|
|
319
|
+
} else {
|
|
320
|
+
log.warning(
|
|
321
|
+
`Event definition must be a string or object but received ${typeof httpEvent.http} for function "${functionKey}"`,
|
|
322
|
+
)
|
|
323
|
+
httpEvent.http.routeKey = ''
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
httpEvent.http.isHttpApi = true
|
|
327
|
+
if (
|
|
328
|
+
functionDefinition.httpApi &&
|
|
329
|
+
functionDefinition.httpApi.payload
|
|
330
|
+
) {
|
|
331
|
+
httpEvent.http.payload = functionDefinition.httpApi.payload
|
|
332
|
+
} else {
|
|
333
|
+
httpEvent.http.payload =
|
|
334
|
+
service.provider.httpApi && service.provider.httpApi.payload
|
|
335
|
+
? service.provider.httpApi.payload
|
|
336
|
+
: '2.0'
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (http && http.private) {
|
|
341
|
+
hasPrivateHttpEvent = true
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
httpEvents.push(httpEvent)
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (schedule) {
|
|
348
|
+
scheduleEvents.push({
|
|
349
|
+
functionKey,
|
|
350
|
+
schedule,
|
|
351
|
+
})
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (websocket) {
|
|
355
|
+
webSocketEvents.push({
|
|
356
|
+
functionKey,
|
|
357
|
+
websocket,
|
|
358
|
+
})
|
|
359
|
+
}
|
|
360
|
+
})
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
// for simple API Key authentication model
|
|
364
|
+
if (hasPrivateHttpEvent) {
|
|
365
|
+
log.notice(`Key with token: ${this.#options.apiKey}`)
|
|
366
|
+
|
|
367
|
+
if (this.#options.noAuth) {
|
|
368
|
+
log.notice(
|
|
369
|
+
'Authorizers are turned off. You do not need to use x-api-key header.',
|
|
370
|
+
)
|
|
371
|
+
} else {
|
|
372
|
+
log.notice('Remember to use x-api-key on the request headers')
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return {
|
|
377
|
+
httpEvents,
|
|
378
|
+
lambdas,
|
|
379
|
+
scheduleEvents,
|
|
380
|
+
webSocketEvents,
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// TODO FIXME
|
|
385
|
+
// TEMP quick fix to expose for testing, look for better solution
|
|
386
|
+
internals() {
|
|
387
|
+
return {
|
|
388
|
+
createHttp: (events, skipStart) => {
|
|
389
|
+
return this.#createHttp(events, skipStart)
|
|
390
|
+
},
|
|
391
|
+
|
|
392
|
+
createLambda: (lambdas, skipStart) => {
|
|
393
|
+
return this.#createLambda(lambdas, skipStart)
|
|
394
|
+
},
|
|
395
|
+
|
|
396
|
+
getApiGatewayServer: () => {
|
|
397
|
+
return this.#http.getServer()
|
|
398
|
+
},
|
|
399
|
+
|
|
400
|
+
getEvents: () => {
|
|
401
|
+
return this.#getEvents()
|
|
402
|
+
},
|
|
403
|
+
|
|
404
|
+
mergeOptions: () => {
|
|
405
|
+
this.#mergeOptions()
|
|
406
|
+
},
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|