serverless-offline 8.5.0 → 8.6.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 +49 -4
- package/dist/ServerlessOffline.js +12 -0
- package/dist/events/{http/authCanExecuteResource.js → authCanExecuteResource.js} +0 -0
- package/dist/events/{http/authFunctionNameExtractor.js → authFunctionNameExtractor.js} +1 -1
- package/dist/events/{http/authMatchPolicyResource.js → authMatchPolicyResource.js} +0 -0
- package/dist/events/http/HttpServer.js +1 -1
- package/dist/events/http/createAuthScheme.js +1 -1
- package/dist/events/http/lambda-events/LambdaProxyIntegrationEventV2.js +7 -1
- package/dist/events/websocket/WebSocketClients.js +194 -2
- package/dist/events/websocket/lambda-events/WebSocketAuthorizerEvent.js +99 -0
- package/dist/events/websocket/lambda-events/index.js +8 -0
- package/dist/lambda/LambdaFunction.js +3 -2
- package/dist/lambda/handler-runner/HandlerRunner.js +2 -1
- package/dist/lambda/handler-runner/child-process-runner/ChildProcessRunner.js +9 -1
- package/dist/lambda/handler-runner/docker-runner/DockerContainer.js +4 -1
- package/dist/lambda/handler-runner/in-process-runner/InProcessRunner.js +22 -7
- package/dist/lambda/handler-runner/java-runner/JavaRunner.js +1 -2
- package/dist/lambda/handler-runner/ruby-runner/RubyRunner.js +0 -2
- package/dist/lambda/handler-runner/worker-thread-runner/WorkerThreadRunner.js +2 -0
- package/dist/lambda/handler-runner/worker-thread-runner/workerThreadHelper.js +3 -2
- package/dist/utils/splitHandlerPathAndName.js +13 -9
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -244,7 +244,7 @@ to calling it via `aws-sdk`.
|
|
|
244
244
|
|
|
245
245
|
## The `process.env.IS_OFFLINE` variable
|
|
246
246
|
|
|
247
|
-
Will be `"true"` in your handlers and
|
|
247
|
+
Will be `"true"` in your handlers and throughout the plugin.
|
|
248
248
|
|
|
249
249
|
## Docker and Layers
|
|
250
250
|
|
|
@@ -531,8 +531,6 @@ Where the `event` is received in the lambda handler function.
|
|
|
531
531
|
|
|
532
532
|
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
533
|
|
|
534
|
-
Authorizers and wss:// are currently not supported.
|
|
535
|
-
|
|
536
534
|
## Usage with Webpack
|
|
537
535
|
|
|
538
536
|
Use [serverless-webpack](https://github.com/serverless-heaven/serverless-webpack) to compile and bundle your ES-next code
|
|
@@ -596,7 +594,54 @@ For each debug run:
|
|
|
596
594
|
|
|
597
595
|
The system will start in wait status. This will also automatically start the chrome browser and wait for you to set breakpoints for inspection. Set the breakpoints as needed and, then, click the play button for the debugging to continue.
|
|
598
596
|
|
|
599
|
-
Depending on the breakpoint, you may need to call the URL path for your function in
|
|
597
|
+
Depending on the breakpoint, you may need to call the URL path for your function in separate browser window for your serverless function to be run and made available for debugging.
|
|
598
|
+
|
|
599
|
+
### Interactive Debugging with Visual Studio Code (VSC)
|
|
600
|
+
|
|
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.
|
|
602
|
+
|
|
603
|
+
#### Step 1 : Adding a launch configuration in IDE
|
|
604
|
+
|
|
605
|
+
Add a new [launch configuration](https://code.visualstudio.com/docs/editor/debugging) to VSC like this:
|
|
606
|
+
|
|
607
|
+
```json
|
|
608
|
+
{
|
|
609
|
+
|
|
610
|
+
"type": "node",
|
|
611
|
+
"request": "launch",
|
|
612
|
+
"name": "Debug Serverless Offline",
|
|
613
|
+
"cwd": "${workspaceFolder}",
|
|
614
|
+
"runtimeExecutable": "npm",
|
|
615
|
+
"runtimeArgs": [
|
|
616
|
+
"run",
|
|
617
|
+
"debug"
|
|
618
|
+
],
|
|
619
|
+
"sourceMaps": true
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
#### Step2 : Adding a debug script
|
|
625
|
+
|
|
626
|
+
You will also need to add a `debug` script reference in your `package.json file`
|
|
627
|
+
|
|
628
|
+
Add this to the `scripts` section:
|
|
629
|
+
|
|
630
|
+
> Unix/Mac: `"debug" : "export SLS_DEBUG=* && node --inspect /usr/local/bin/serverless offline"`
|
|
631
|
+
|
|
632
|
+
> Windows: `"debug": "SET SLS_DEBUG=* && node --inspect node_modules\\serverless\\bin\\serverless offline"`
|
|
633
|
+
|
|
634
|
+
Example:
|
|
635
|
+
|
|
636
|
+
```json
|
|
637
|
+
....
|
|
638
|
+
"scripts": {
|
|
639
|
+
"debug" : "SET SLS_DEBUG=* && node --inspect node_modules\\serverless\\bin\\serverless offline"
|
|
640
|
+
}
|
|
641
|
+
```
|
|
642
|
+
|
|
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 by going to your debug pane and selecting the Debug Serverless Offline configuration.
|
|
644
|
+
|
|
600
645
|
|
|
601
646
|
## Resource permissions and AWS profile
|
|
602
647
|
|
|
@@ -96,6 +96,10 @@ class ServerlessOffline {
|
|
|
96
96
|
lifecycleEvents: ['init', 'ready', 'end'],
|
|
97
97
|
options: _index2.commandOptions,
|
|
98
98
|
usage: 'Simulates API Gateway to call your lambda functions offline using backward compatible initialization.'
|
|
99
|
+
},
|
|
100
|
+
functionsUpdated: {
|
|
101
|
+
type: 'entrypoint',
|
|
102
|
+
lifecycleEvents: ['cleanup']
|
|
99
103
|
}
|
|
100
104
|
},
|
|
101
105
|
lifecycleEvents: ['start'],
|
|
@@ -106,6 +110,7 @@ class ServerlessOffline {
|
|
|
106
110
|
this.hooks = {
|
|
107
111
|
'offline:start:init': this.start.bind(this),
|
|
108
112
|
'offline:start:ready': this.ready.bind(this),
|
|
113
|
+
'offline:functionsUpdated:cleanup': this.cleanupFunctions.bind(this),
|
|
109
114
|
'offline:start': this._startWithExplicitEnd.bind(this),
|
|
110
115
|
'offline:start:end': this.end.bind(this)
|
|
111
116
|
};
|
|
@@ -203,6 +208,13 @@ class ServerlessOffline {
|
|
|
203
208
|
process.exit(0);
|
|
204
209
|
}
|
|
205
210
|
}
|
|
211
|
+
|
|
212
|
+
async cleanupFunctions() {
|
|
213
|
+
if (_classPrivateFieldLooseBase(this, _lambda)[_lambda]) {
|
|
214
|
+
(0, _serverlessLog.default)('Forcing cleanup of Lambda functions');
|
|
215
|
+
await _classPrivateFieldLooseBase(this, _lambda)[_lambda].cleanup();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
206
218
|
/**
|
|
207
219
|
* Entry point for the plugin (sls offline) when running 'sls offline'
|
|
208
220
|
* The call to this.end() would terminate the process before 'offline:start:end' could be consumed
|
|
File without changes
|
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = authFunctionNameExtractor;
|
|
7
7
|
|
|
8
|
-
var _serverlessLog2 = _interopRequireDefault(require("
|
|
8
|
+
var _serverlessLog2 = _interopRequireDefault(require("../serverlessLog.js"));
|
|
9
9
|
|
|
10
10
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
11
|
|
|
File without changes
|
|
@@ -17,7 +17,7 @@ var _hapi = require("@hapi/hapi");
|
|
|
17
17
|
|
|
18
18
|
var _module = require("module");
|
|
19
19
|
|
|
20
|
-
var _authFunctionNameExtractor = _interopRequireDefault(require("
|
|
20
|
+
var _authFunctionNameExtractor = _interopRequireDefault(require("../authFunctionNameExtractor.js"));
|
|
21
21
|
|
|
22
22
|
var _authJWTSettingsExtractor = _interopRequireDefault(require("./authJWTSettingsExtractor.js"));
|
|
23
23
|
|
|
@@ -7,7 +7,7 @@ exports.default = createAuthScheme;
|
|
|
7
7
|
|
|
8
8
|
var _boom = _interopRequireDefault(require("@hapi/boom"));
|
|
9
9
|
|
|
10
|
-
var _authCanExecuteResource = _interopRequireDefault(require("
|
|
10
|
+
var _authCanExecuteResource = _interopRequireDefault(require("../authCanExecuteResource.js"));
|
|
11
11
|
|
|
12
12
|
var _debugLog = _interopRequireDefault(require("../../debugLog.js"));
|
|
13
13
|
|
|
@@ -169,7 +169,13 @@ class LambdaProxyIntegrationEventV2 {
|
|
|
169
169
|
const httpMethod = method.toUpperCase();
|
|
170
170
|
const requestTime = (0, _index.formatToClfTime)(received);
|
|
171
171
|
const requestTimeEpoch = received;
|
|
172
|
-
const cookies = Object.entries(_classPrivateFieldLooseBase(this, _request)[_request].state).
|
|
172
|
+
const cookies = Object.entries(_classPrivateFieldLooseBase(this, _request)[_request].state).flatMap(([key, value]) => {
|
|
173
|
+
if (Array.isArray(value)) {
|
|
174
|
+
return value.map(v => `${key}=${v}`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return `${key}=${value}`;
|
|
178
|
+
});
|
|
173
179
|
return {
|
|
174
180
|
version: '2.0',
|
|
175
181
|
routeKey: _classPrivateFieldLooseBase(this, _routeKey)[_routeKey],
|
|
@@ -17,6 +17,10 @@ var _index2 = require("../../config/index.js");
|
|
|
17
17
|
|
|
18
18
|
var _index3 = require("../../utils/index.js");
|
|
19
19
|
|
|
20
|
+
var _authFunctionNameExtractor = _interopRequireDefault(require("../authFunctionNameExtractor.js"));
|
|
21
|
+
|
|
22
|
+
var _authCanExecuteResource = _interopRequireDefault(require("../authCanExecuteResource.js"));
|
|
23
|
+
|
|
20
24
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
21
25
|
|
|
22
26
|
function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { throw new TypeError("attempted to use private field on non-instance"); } return receiver; }
|
|
@@ -36,8 +40,14 @@ var _lambda = /*#__PURE__*/_classPrivateFieldLooseKey("lambda");
|
|
|
36
40
|
|
|
37
41
|
var _options = /*#__PURE__*/_classPrivateFieldLooseKey("options");
|
|
38
42
|
|
|
43
|
+
var _serverless = /*#__PURE__*/_classPrivateFieldLooseKey("serverless");
|
|
44
|
+
|
|
39
45
|
var _webSocketRoutes = /*#__PURE__*/_classPrivateFieldLooseKey("webSocketRoutes");
|
|
40
46
|
|
|
47
|
+
var _webSocketAuthorizers = /*#__PURE__*/_classPrivateFieldLooseKey("webSocketAuthorizers");
|
|
48
|
+
|
|
49
|
+
var _webSocketAuthorizersCache = /*#__PURE__*/_classPrivateFieldLooseKey("webSocketAuthorizersCache");
|
|
50
|
+
|
|
41
51
|
var _websocketsApiRouteSelectionExpression = /*#__PURE__*/_classPrivateFieldLooseKey("websocketsApiRouteSelectionExpression");
|
|
42
52
|
|
|
43
53
|
var _idleTimeouts = /*#__PURE__*/_classPrivateFieldLooseKey("idleTimeouts");
|
|
@@ -58,10 +68,22 @@ class WebSocketClients {
|
|
|
58
68
|
writable: true,
|
|
59
69
|
value: null
|
|
60
70
|
});
|
|
71
|
+
Object.defineProperty(this, _serverless, {
|
|
72
|
+
writable: true,
|
|
73
|
+
value: null
|
|
74
|
+
});
|
|
61
75
|
Object.defineProperty(this, _webSocketRoutes, {
|
|
62
76
|
writable: true,
|
|
63
77
|
value: new Map()
|
|
64
78
|
});
|
|
79
|
+
Object.defineProperty(this, _webSocketAuthorizers, {
|
|
80
|
+
writable: true,
|
|
81
|
+
value: new Map()
|
|
82
|
+
});
|
|
83
|
+
Object.defineProperty(this, _webSocketAuthorizersCache, {
|
|
84
|
+
writable: true,
|
|
85
|
+
value: new Map()
|
|
86
|
+
});
|
|
65
87
|
Object.defineProperty(this, _websocketsApiRouteSelectionExpression, {
|
|
66
88
|
writable: true,
|
|
67
89
|
value: null
|
|
@@ -76,6 +98,7 @@ class WebSocketClients {
|
|
|
76
98
|
});
|
|
77
99
|
_classPrivateFieldLooseBase(this, _lambda)[_lambda] = lambda;
|
|
78
100
|
_classPrivateFieldLooseBase(this, _options)[_options] = options;
|
|
101
|
+
_classPrivateFieldLooseBase(this, _serverless)[_serverless] = serverless;
|
|
79
102
|
_classPrivateFieldLooseBase(this, _websocketsApiRouteSelectionExpression)[_websocketsApiRouteSelectionExpression] = serverless.service.provider.websocketsApiRouteSelectionExpression || _index2.DEFAULT_WEBSOCKETS_API_ROUTE_SELECTION_EXPRESSION;
|
|
80
103
|
|
|
81
104
|
if (v3Utils) {
|
|
@@ -161,7 +184,9 @@ class WebSocketClients {
|
|
|
161
184
|
}
|
|
162
185
|
|
|
163
186
|
async verifyClient(connectionId, request) {
|
|
164
|
-
const
|
|
187
|
+
const routeName = '$connect';
|
|
188
|
+
|
|
189
|
+
const route = _classPrivateFieldLooseBase(this, _webSocketRoutes)[_webSocketRoutes].get(routeName);
|
|
165
190
|
|
|
166
191
|
if (!route) {
|
|
167
192
|
return {
|
|
@@ -172,6 +197,96 @@ class WebSocketClients {
|
|
|
172
197
|
|
|
173
198
|
const connectEvent = new _index.WebSocketConnectEvent(connectionId, request, _classPrivateFieldLooseBase(this, _options)[_options]).create();
|
|
174
199
|
|
|
200
|
+
const authFunName = _classPrivateFieldLooseBase(this, _webSocketAuthorizers)[_webSocketAuthorizers].get(routeName);
|
|
201
|
+
|
|
202
|
+
if (authFunName) {
|
|
203
|
+
const authorizerFunction = _classPrivateFieldLooseBase(this, _lambda)[_lambda].get(authFunName);
|
|
204
|
+
|
|
205
|
+
const authorizeEvent = new _index.WebSocketAuthorizerEvent(connectionId, request, _classPrivateFieldLooseBase(this, _serverless)[_serverless].service.provider, _classPrivateFieldLooseBase(this, _options)[_options]).create();
|
|
206
|
+
authorizerFunction.setEvent(authorizeEvent);
|
|
207
|
+
|
|
208
|
+
if (this.log) {
|
|
209
|
+
this.log.notice();
|
|
210
|
+
this.log.notice(`Running Authorization function for ${routeName} (λ: ${authFunName})`);
|
|
211
|
+
} else {
|
|
212
|
+
console.log(''); // Just to make things a little pretty
|
|
213
|
+
|
|
214
|
+
(0, _serverlessLog.default)(`Running Authorization function for ${routeName} (λ: ${authFunName})`);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
const result = await authorizerFunction.runHandler();
|
|
219
|
+
if (result === 'Unauthorized') return {
|
|
220
|
+
verified: false,
|
|
221
|
+
statusCode: 401
|
|
222
|
+
};
|
|
223
|
+
const policy = result; // Validate that the policy document has the principalId set
|
|
224
|
+
|
|
225
|
+
if (!policy.principalId) {
|
|
226
|
+
if (this.log) {
|
|
227
|
+
this.log.notice(`Authorization response did not include a principalId: (λ: ${authFunName})`);
|
|
228
|
+
} else {
|
|
229
|
+
(0, _serverlessLog.default)(`Authorization response did not include a principalId: (λ: ${authFunName})`);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
verified: false,
|
|
234
|
+
statusCode: 403
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (!(0, _authCanExecuteResource.default)(policy.policyDocument, authorizeEvent.methodArn)) {
|
|
239
|
+
if (this.log) {
|
|
240
|
+
this.log.notice(`Authorization response didn't authorize user to access resource: (λ: ${authFunName})`);
|
|
241
|
+
} else {
|
|
242
|
+
(0, _serverlessLog.default)(`Authorization response didn't authorize user to access resource: (λ: ${authFunName})`);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return {
|
|
246
|
+
verified: false,
|
|
247
|
+
statusCode: 403
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (this.log) {
|
|
252
|
+
this.log.notice(`Authorization function returned a successful response: (λ: ${authFunName})`);
|
|
253
|
+
} else {
|
|
254
|
+
(0, _serverlessLog.default)(`Authorization function returned a successful response: (λ: ${authFunName})`);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
_classPrivateFieldLooseBase(this, _webSocketAuthorizersCache)[_webSocketAuthorizersCache].set(connectionId, {
|
|
258
|
+
identity: {
|
|
259
|
+
apiKey: policy.usageIdentifierKey,
|
|
260
|
+
sourceIp: authorizeEvent.requestContext.sourceIp,
|
|
261
|
+
userAgent: authorizeEvent.headers['user-agent'] || ''
|
|
262
|
+
},
|
|
263
|
+
authorizer: {
|
|
264
|
+
integrationLatency: '42',
|
|
265
|
+
principalId: policy.principalId,
|
|
266
|
+
...policy.context
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
} catch (err) {
|
|
270
|
+
if (this.log) {
|
|
271
|
+
this.log.debug(`Error in route handler '${routeName}' authorizer`, err);
|
|
272
|
+
} else {
|
|
273
|
+
(0, _debugLog.default)(`Error in route handler '${routeName}' authorizer`, err);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
verified: false,
|
|
278
|
+
statusCode: 500
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const authorizerData = _classPrivateFieldLooseBase(this, _webSocketAuthorizersCache)[_webSocketAuthorizersCache].get(connectionId);
|
|
284
|
+
|
|
285
|
+
if (authorizerData) {
|
|
286
|
+
connectEvent.identity = authorizerData.identity;
|
|
287
|
+
connectEvent.authorizer = authorizerData.authorizer;
|
|
288
|
+
}
|
|
289
|
+
|
|
175
290
|
const lambdaFunction = _classPrivateFieldLooseBase(this, _lambda)[_lambda].get(route.functionKey);
|
|
176
291
|
|
|
177
292
|
lambdaFunction.setEvent(connectEvent);
|
|
@@ -186,6 +301,8 @@ class WebSocketClients {
|
|
|
186
301
|
statusCode
|
|
187
302
|
};
|
|
188
303
|
} catch (err) {
|
|
304
|
+
_classPrivateFieldLooseBase(this, _webSocketAuthorizersCache)[_webSocketAuthorizersCache].delete(connectionId);
|
|
305
|
+
|
|
189
306
|
if (this.log) {
|
|
190
307
|
this.log.debug(`Error in route handler '${route.functionKey}'`, err);
|
|
191
308
|
} else {
|
|
@@ -290,7 +407,14 @@ class WebSocketClients {
|
|
|
290
407
|
|
|
291
408
|
this._clearIdleTimeout(webSocketClient);
|
|
292
409
|
|
|
293
|
-
|
|
410
|
+
const authorizerData = _classPrivateFieldLooseBase(this, _webSocketAuthorizersCache)[_webSocketAuthorizersCache].get(connectionId);
|
|
411
|
+
|
|
412
|
+
if (authorizerData) {
|
|
413
|
+
disconnectEvent.identity = authorizerData.identity;
|
|
414
|
+
disconnectEvent.authorizer = authorizerData.authorizer;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
this._processEvent(webSocketClient, connectionId, '$disconnect', disconnectEvent).finally(() => _classPrivateFieldLooseBase(this, _webSocketAuthorizersCache)[_webSocketAuthorizersCache].delete(connectionId));
|
|
294
418
|
});
|
|
295
419
|
webSocketClient.on('message', message => {
|
|
296
420
|
if (this.log) {
|
|
@@ -309,12 +433,76 @@ class WebSocketClients {
|
|
|
309
433
|
|
|
310
434
|
const event = new _index.WebSocketEvent(connectionId, route, message).create();
|
|
311
435
|
|
|
436
|
+
const authorizerData = _classPrivateFieldLooseBase(this, _webSocketAuthorizersCache)[_webSocketAuthorizersCache].get(connectionId);
|
|
437
|
+
|
|
438
|
+
if (authorizerData) {
|
|
439
|
+
event.identity = authorizerData.identity;
|
|
440
|
+
event.authorizer = authorizerData.authorizer;
|
|
441
|
+
}
|
|
442
|
+
|
|
312
443
|
this._onWebSocketUsed(connectionId);
|
|
313
444
|
|
|
314
445
|
this._processEvent(webSocketClient, connectionId, route, event);
|
|
315
446
|
});
|
|
316
447
|
}
|
|
317
448
|
|
|
449
|
+
_extractAuthFunctionName(endpoint) {
|
|
450
|
+
if (typeof endpoint.authorizer === 'object' && endpoint.authorizer.type && endpoint.authorizer.type.toUpperCase() === 'TOKEN') {
|
|
451
|
+
if (this.log) {
|
|
452
|
+
this.log.debug(`Websockets does not support the TOKEN authorization type`);
|
|
453
|
+
} else {
|
|
454
|
+
(0, _debugLog.default)(`WARNING: Websockets does not support the TOKEN authorization type`);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
const result = (0, _authFunctionNameExtractor.default)(endpoint, null, this);
|
|
461
|
+
return result.unsupportedAuth ? null : result.authorizerName;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
_configureAuthorization(endpoint, functionKey) {
|
|
465
|
+
if (!endpoint.authorizer) {
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (endpoint.route === '$connect') {
|
|
470
|
+
const authFunctionName = this._extractAuthFunctionName(endpoint);
|
|
471
|
+
|
|
472
|
+
if (!authFunctionName) {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (this.log) {
|
|
477
|
+
this.log.notice(`Configuring Authorization: ${functionKey} ${authFunctionName}`);
|
|
478
|
+
} else {
|
|
479
|
+
(0, _serverlessLog.default)(`Configuring Authorization: ${functionKey} ${authFunctionName}`);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const authFunction = _classPrivateFieldLooseBase(this, _serverless)[_serverless].service.getFunction(authFunctionName);
|
|
483
|
+
|
|
484
|
+
if (!authFunction) {
|
|
485
|
+
if (this.log) {
|
|
486
|
+
this.log.error(`Authorization function ${authFunctionName} does not exist`);
|
|
487
|
+
} else {
|
|
488
|
+
(0, _serverlessLog.default)(`WARNING: Authorization function ${authFunctionName} does not exist`);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
_classPrivateFieldLooseBase(this, _webSocketAuthorizers)[_webSocketAuthorizers].set(endpoint.route, authFunctionName);
|
|
495
|
+
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
if (this.log) {
|
|
500
|
+
this.log.notice(`Configuring Authorization is supported only on $connect route`);
|
|
501
|
+
} else {
|
|
502
|
+
(0, _serverlessLog.default)(`Configuring Authorization is supported only on $connect route`);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
318
506
|
addRoute(functionKey, definition) {
|
|
319
507
|
// set the route name
|
|
320
508
|
_classPrivateFieldLooseBase(this, _webSocketRoutes)[_webSocketRoutes].set(definition.route, {
|
|
@@ -322,6 +510,10 @@ class WebSocketClients {
|
|
|
322
510
|
definition
|
|
323
511
|
});
|
|
324
512
|
|
|
513
|
+
if (!_classPrivateFieldLooseBase(this, _options)[_options].noAuth) {
|
|
514
|
+
this._configureAuthorization(definition, functionKey);
|
|
515
|
+
}
|
|
516
|
+
|
|
325
517
|
if (this.log) {
|
|
326
518
|
this.log.notice(`route '${definition}'`);
|
|
327
519
|
} else {
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
|
|
8
|
+
var _WebSocketRequestContext = _interopRequireDefault(require("./WebSocketRequestContext.js"));
|
|
9
|
+
|
|
10
|
+
var _index = require("../../../utils/index.js");
|
|
11
|
+
|
|
12
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
|
+
|
|
14
|
+
function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { throw new TypeError("attempted to use private field on non-instance"); } return receiver; }
|
|
15
|
+
|
|
16
|
+
var id = 0;
|
|
17
|
+
|
|
18
|
+
function _classPrivateFieldLooseKey(name) { return "__private_" + id++ + "_" + name; }
|
|
19
|
+
|
|
20
|
+
var _connectionId = /*#__PURE__*/_classPrivateFieldLooseKey("connectionId");
|
|
21
|
+
|
|
22
|
+
var _httpsProtocol = /*#__PURE__*/_classPrivateFieldLooseKey("httpsProtocol");
|
|
23
|
+
|
|
24
|
+
var _rawHeaders = /*#__PURE__*/_classPrivateFieldLooseKey("rawHeaders");
|
|
25
|
+
|
|
26
|
+
var _url = /*#__PURE__*/_classPrivateFieldLooseKey("url");
|
|
27
|
+
|
|
28
|
+
var _websocketPort = /*#__PURE__*/_classPrivateFieldLooseKey("websocketPort");
|
|
29
|
+
|
|
30
|
+
var _provider = /*#__PURE__*/_classPrivateFieldLooseKey("provider");
|
|
31
|
+
|
|
32
|
+
class WebSocketAuthorizerEvent {
|
|
33
|
+
constructor(connectionId, request, provider, options) {
|
|
34
|
+
Object.defineProperty(this, _connectionId, {
|
|
35
|
+
writable: true,
|
|
36
|
+
value: null
|
|
37
|
+
});
|
|
38
|
+
Object.defineProperty(this, _httpsProtocol, {
|
|
39
|
+
writable: true,
|
|
40
|
+
value: null
|
|
41
|
+
});
|
|
42
|
+
Object.defineProperty(this, _rawHeaders, {
|
|
43
|
+
writable: true,
|
|
44
|
+
value: null
|
|
45
|
+
});
|
|
46
|
+
Object.defineProperty(this, _url, {
|
|
47
|
+
writable: true,
|
|
48
|
+
value: null
|
|
49
|
+
});
|
|
50
|
+
Object.defineProperty(this, _websocketPort, {
|
|
51
|
+
writable: true,
|
|
52
|
+
value: null
|
|
53
|
+
});
|
|
54
|
+
Object.defineProperty(this, _provider, {
|
|
55
|
+
writable: true,
|
|
56
|
+
value: null
|
|
57
|
+
});
|
|
58
|
+
const {
|
|
59
|
+
httpsProtocol,
|
|
60
|
+
websocketPort
|
|
61
|
+
} = options;
|
|
62
|
+
const {
|
|
63
|
+
rawHeaders,
|
|
64
|
+
url
|
|
65
|
+
} = request;
|
|
66
|
+
_classPrivateFieldLooseBase(this, _connectionId)[_connectionId] = connectionId;
|
|
67
|
+
_classPrivateFieldLooseBase(this, _httpsProtocol)[_httpsProtocol] = httpsProtocol;
|
|
68
|
+
_classPrivateFieldLooseBase(this, _rawHeaders)[_rawHeaders] = rawHeaders;
|
|
69
|
+
_classPrivateFieldLooseBase(this, _url)[_url] = url;
|
|
70
|
+
_classPrivateFieldLooseBase(this, _websocketPort)[_websocketPort] = websocketPort;
|
|
71
|
+
_classPrivateFieldLooseBase(this, _provider)[_provider] = provider;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
create() {
|
|
75
|
+
const headers = (0, _index.parseHeaders)(_classPrivateFieldLooseBase(this, _rawHeaders)[_rawHeaders]);
|
|
76
|
+
const multiValueHeaders = (0, _index.parseMultiValueHeaders)(_classPrivateFieldLooseBase(this, _rawHeaders)[_rawHeaders]);
|
|
77
|
+
const multiValueQueryStringParameters = (0, _index.parseMultiValueQueryStringParameters)(_classPrivateFieldLooseBase(this, _url)[_url]);
|
|
78
|
+
const queryStringParameters = (0, _index.parseQueryStringParameters)(_classPrivateFieldLooseBase(this, _url)[_url]);
|
|
79
|
+
const requestContext = new _WebSocketRequestContext.default('CONNECT', '$connect', _classPrivateFieldLooseBase(this, _connectionId)[_connectionId]).create();
|
|
80
|
+
return {
|
|
81
|
+
type: 'REQUEST',
|
|
82
|
+
methodArn: `arn:aws:execute-api:${_classPrivateFieldLooseBase(this, _provider)[_provider].region}:${requestContext.accountId}:${requestContext.apiId}/${requestContext.stage}/${requestContext.routeKey}`,
|
|
83
|
+
headers,
|
|
84
|
+
multiValueHeaders,
|
|
85
|
+
// NOTE: multiValueQueryStringParameters and queryStringParameters
|
|
86
|
+
// properties are only defined if they have values
|
|
87
|
+
...(multiValueQueryStringParameters && {
|
|
88
|
+
multiValueQueryStringParameters
|
|
89
|
+
}),
|
|
90
|
+
...(queryStringParameters && {
|
|
91
|
+
queryStringParameters
|
|
92
|
+
}),
|
|
93
|
+
requestContext
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
exports.default = WebSocketAuthorizerEvent;
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
Object.defineProperty(exports, "WebSocketAuthorizerEvent", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _WebSocketAuthorizerEvent.default;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
6
12
|
Object.defineProperty(exports, "WebSocketConnectEvent", {
|
|
7
13
|
enumerable: true,
|
|
8
14
|
get: function () {
|
|
@@ -28,4 +34,6 @@ var _WebSocketDisconnectEvent = _interopRequireDefault(require("./WebSocketDisco
|
|
|
28
34
|
|
|
29
35
|
var _WebSocketEvent = _interopRequireDefault(require("./WebSocketEvent.js"));
|
|
30
36
|
|
|
37
|
+
var _WebSocketAuthorizerEvent = _interopRequireDefault(require("./WebSocketAuthorizerEvent.js"));
|
|
38
|
+
|
|
31
39
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -177,7 +177,7 @@ class LambdaFunction {
|
|
|
177
177
|
name,
|
|
178
178
|
package: functionPackage = {}
|
|
179
179
|
} = functionDefinition;
|
|
180
|
-
const [handlerPath, handlerName] = (0, _index3.splitHandlerPathAndName)(handler);
|
|
180
|
+
const [handlerPath, handlerName, handlerModuleNesting] = (0, _index3.splitHandlerPathAndName)(handler);
|
|
181
181
|
const memorySize = functionDefinition.memorySize || provider.memorySize || _index2.DEFAULT_LAMBDA_MEMORY_SIZE;
|
|
182
182
|
const runtime = functionDefinition.runtime || provider.runtime || _index2.DEFAULT_LAMBDA_RUNTIME;
|
|
183
183
|
const timeout = (functionDefinition.timeout || provider.timeout || _index2.DEFAULT_LAMBDA_TIMEOUT) * 1000; // this._executionTimeout = null
|
|
@@ -212,6 +212,7 @@ class LambdaFunction {
|
|
|
212
212
|
functionKey,
|
|
213
213
|
handler,
|
|
214
214
|
handlerName,
|
|
215
|
+
handlerModuleNesting,
|
|
215
216
|
codeDir: _classPrivateFieldLooseBase(this, _codeDir)[_codeDir],
|
|
216
217
|
handlerPath: (0, _path.resolve)(_classPrivateFieldLooseBase(this, _codeDir)[_codeDir], handlerPath),
|
|
217
218
|
runtime,
|
|
@@ -269,7 +270,7 @@ class LambdaFunction {
|
|
|
269
270
|
LAMBDA_RUNTIME_DIR: '/var/runtime',
|
|
270
271
|
LAMBDA_TASK_ROOT: '/var/task',
|
|
271
272
|
LANG: 'en_US.UTF-8',
|
|
272
|
-
LD_LIBRARY_PATH: '/usr/local/lib64/node-v4.3.x/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib',
|
|
273
|
+
LD_LIBRARY_PATH: '/usr/local/lib64/node-v4.3.x/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib',
|
|
273
274
|
NODE_PATH: '/var/runtime:/var/task:/var/runtime/node_modules'
|
|
274
275
|
};
|
|
275
276
|
}
|
|
@@ -75,6 +75,7 @@ class HandlerRunner {
|
|
|
75
75
|
functionKey,
|
|
76
76
|
handlerName,
|
|
77
77
|
handlerPath,
|
|
78
|
+
handlerModuleNesting,
|
|
78
79
|
runtime,
|
|
79
80
|
timeout
|
|
80
81
|
} = _classPrivateFieldLooseBase(this, _funOptions)[_funOptions];
|
|
@@ -141,7 +142,7 @@ class HandlerRunner {
|
|
|
141
142
|
const {
|
|
142
143
|
default: InProcessRunner
|
|
143
144
|
} = await Promise.resolve().then(() => _interopRequireWildcard(require('./in-process-runner/index.js')));
|
|
144
|
-
return new InProcessRunner(functionKey, handlerPath, handlerName, _classPrivateFieldLooseBase(this, _env)[_env], timeout, allowCache);
|
|
145
|
+
return new InProcessRunner(functionKey, handlerPath, handlerName, handlerModuleNesting, _classPrivateFieldLooseBase(this, _env)[_env], timeout, allowCache);
|
|
145
146
|
}
|
|
146
147
|
|
|
147
148
|
if (_index.supportedGo.has(runtime)) {
|
|
@@ -27,6 +27,8 @@ var _handlerName = /*#__PURE__*/_classPrivateFieldLooseKey("handlerName");
|
|
|
27
27
|
|
|
28
28
|
var _handlerPath = /*#__PURE__*/_classPrivateFieldLooseKey("handlerPath");
|
|
29
29
|
|
|
30
|
+
var _handlerModuleNesting = /*#__PURE__*/_classPrivateFieldLooseKey("handlerModuleNesting");
|
|
31
|
+
|
|
30
32
|
var _timeout = /*#__PURE__*/_classPrivateFieldLooseKey("timeout");
|
|
31
33
|
|
|
32
34
|
var _allowCache = /*#__PURE__*/_classPrivateFieldLooseKey("allowCache");
|
|
@@ -49,6 +51,10 @@ class ChildProcessRunner {
|
|
|
49
51
|
writable: true,
|
|
50
52
|
value: null
|
|
51
53
|
});
|
|
54
|
+
Object.defineProperty(this, _handlerModuleNesting, {
|
|
55
|
+
writable: true,
|
|
56
|
+
value: null
|
|
57
|
+
});
|
|
52
58
|
Object.defineProperty(this, _timeout, {
|
|
53
59
|
writable: true,
|
|
54
60
|
value: null
|
|
@@ -61,6 +67,7 @@ class ChildProcessRunner {
|
|
|
61
67
|
functionKey,
|
|
62
68
|
handlerName,
|
|
63
69
|
handlerPath,
|
|
70
|
+
handlerModuleNesting,
|
|
64
71
|
timeout
|
|
65
72
|
} = funOptions;
|
|
66
73
|
|
|
@@ -75,6 +82,7 @@ class ChildProcessRunner {
|
|
|
75
82
|
_classPrivateFieldLooseBase(this, _functionKey)[_functionKey] = functionKey;
|
|
76
83
|
_classPrivateFieldLooseBase(this, _handlerName)[_handlerName] = handlerName;
|
|
77
84
|
_classPrivateFieldLooseBase(this, _handlerPath)[_handlerPath] = handlerPath;
|
|
85
|
+
_classPrivateFieldLooseBase(this, _handlerModuleNesting)[_handlerModuleNesting] = handlerModuleNesting;
|
|
78
86
|
_classPrivateFieldLooseBase(this, _timeout)[_timeout] = timeout;
|
|
79
87
|
_classPrivateFieldLooseBase(this, _allowCache)[_allowCache] = allowCache;
|
|
80
88
|
} // no-op
|
|
@@ -84,7 +92,7 @@ class ChildProcessRunner {
|
|
|
84
92
|
cleanup() {}
|
|
85
93
|
|
|
86
94
|
async run(event, context) {
|
|
87
|
-
const childProcess = (0, _execa.node)(childProcessHelperPath, [_classPrivateFieldLooseBase(this, _functionKey)[_functionKey], _classPrivateFieldLooseBase(this, _handlerName)[_handlerName], _classPrivateFieldLooseBase(this, _handlerPath)[_handlerPath]], {
|
|
95
|
+
const childProcess = (0, _execa.node)(childProcessHelperPath, [_classPrivateFieldLooseBase(this, _functionKey)[_functionKey], _classPrivateFieldLooseBase(this, _handlerName)[_handlerName], _classPrivateFieldLooseBase(this, _handlerPath)[_handlerPath], _classPrivateFieldLooseBase(this, _handlerModuleNesting)[_handlerModuleNesting]], {
|
|
88
96
|
env: _classPrivateFieldLooseBase(this, _env)[_env],
|
|
89
97
|
stdio: 'inherit'
|
|
90
98
|
});
|
|
@@ -244,7 +244,10 @@ class DockerContainer {
|
|
|
244
244
|
// Add `host.docker.internal` DNS name to access host from inside the container
|
|
245
245
|
// https://github.com/docker/for-linux/issues/264
|
|
246
246
|
const gatewayIp = await this._getBridgeGatewayIp();
|
|
247
|
-
|
|
247
|
+
|
|
248
|
+
if (gatewayIp) {
|
|
249
|
+
dockerArgs.push('--add-host', `host.docker.internal:${gatewayIp}`);
|
|
250
|
+
}
|
|
248
251
|
}
|
|
249
252
|
|
|
250
253
|
if (_classPrivateFieldLooseBase(this, _dockerOptions)[_dockerOptions].network) {
|
|
@@ -58,8 +58,8 @@ const clearModule = (fP, opts) => {
|
|
|
58
58
|
delete require.cache[filePath];
|
|
59
59
|
|
|
60
60
|
for (const c of cld) {
|
|
61
|
-
// Unload any non node_modules children
|
|
62
|
-
if (!c.filename.match(
|
|
61
|
+
// Unload any non node_modules and non-binary children
|
|
62
|
+
if (!c.filename.match(/\/node_modules\//i) && !c.filename.match(/\.node$/i)) {
|
|
63
63
|
clearModule(c.id, { ...options,
|
|
64
64
|
cleanup: false
|
|
65
65
|
});
|
|
@@ -74,7 +74,7 @@ const clearModule = (fP, opts) => {
|
|
|
74
74
|
cleanup = false;
|
|
75
75
|
|
|
76
76
|
for (const fn of Object.keys(require.cache)) {
|
|
77
|
-
if (require.cache[fn] && require.cache[fn].id !== '.' && require.cache[fn].parent && require.cache[fn].parent.id !== '.' && !require.cache[require.cache[fn].parent.id]) {
|
|
77
|
+
if (require.cache[fn] && require.cache[fn].id !== '.' && require.cache[fn].parent && require.cache[fn].parent.id !== '.' && !require.cache[require.cache[fn].parent.id] && !fn.match(/\/node_modules\//i) && !fn.match(/\.node$/i)) {
|
|
78
78
|
delete require.cache[fn];
|
|
79
79
|
cleanup = true;
|
|
80
80
|
}
|
|
@@ -92,12 +92,14 @@ var _handlerName = /*#__PURE__*/_classPrivateFieldLooseKey("handlerName");
|
|
|
92
92
|
|
|
93
93
|
var _handlerPath = /*#__PURE__*/_classPrivateFieldLooseKey("handlerPath");
|
|
94
94
|
|
|
95
|
+
var _handlerModuleNesting = /*#__PURE__*/_classPrivateFieldLooseKey("handlerModuleNesting");
|
|
96
|
+
|
|
95
97
|
var _timeout = /*#__PURE__*/_classPrivateFieldLooseKey("timeout");
|
|
96
98
|
|
|
97
99
|
var _allowCache = /*#__PURE__*/_classPrivateFieldLooseKey("allowCache");
|
|
98
100
|
|
|
99
101
|
class InProcessRunner {
|
|
100
|
-
constructor(functionKey, handlerPath, handlerName, env, timeout, allowCache) {
|
|
102
|
+
constructor(functionKey, handlerPath, handlerName, handlerModuleNesting, env, timeout, allowCache) {
|
|
101
103
|
Object.defineProperty(this, _env, {
|
|
102
104
|
writable: true,
|
|
103
105
|
value: null
|
|
@@ -114,6 +116,10 @@ class InProcessRunner {
|
|
|
114
116
|
writable: true,
|
|
115
117
|
value: null
|
|
116
118
|
});
|
|
119
|
+
Object.defineProperty(this, _handlerModuleNesting, {
|
|
120
|
+
writable: true,
|
|
121
|
+
value: null
|
|
122
|
+
});
|
|
117
123
|
Object.defineProperty(this, _timeout, {
|
|
118
124
|
writable: true,
|
|
119
125
|
value: null
|
|
@@ -126,6 +132,7 @@ class InProcessRunner {
|
|
|
126
132
|
_classPrivateFieldLooseBase(this, _functionKey)[_functionKey] = functionKey;
|
|
127
133
|
_classPrivateFieldLooseBase(this, _handlerName)[_handlerName] = handlerName;
|
|
128
134
|
_classPrivateFieldLooseBase(this, _handlerPath)[_handlerPath] = handlerPath;
|
|
135
|
+
_classPrivateFieldLooseBase(this, _handlerModuleNesting)[_handlerModuleNesting] = handlerModuleNesting;
|
|
129
136
|
_classPrivateFieldLooseBase(this, _timeout)[_timeout] = timeout;
|
|
130
137
|
_classPrivateFieldLooseBase(this, _allowCache)[_allowCache] = allowCache;
|
|
131
138
|
} // no-op
|
|
@@ -152,9 +159,17 @@ class InProcessRunner {
|
|
|
152
159
|
});
|
|
153
160
|
}
|
|
154
161
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
162
|
+
let handler;
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
const handlerPathExport = await Promise.resolve(`${_classPrivateFieldLooseBase(this, _handlerPath)[_handlerPath]}`).then(s => _interopRequireWildcard(require(s))); // this supports handling of nested handler paths like <pathToFile>/<fileName>.object1.object2.object3.handler
|
|
166
|
+
// a use case for this, is when the handler is further down the export tree or in nested objects
|
|
167
|
+
// NOTE: this feature is supported in AWS Lambda
|
|
168
|
+
|
|
169
|
+
handler = _classPrivateFieldLooseBase(this, _handlerModuleNesting)[_handlerModuleNesting].reduce((obj, key) => obj[key], handlerPathExport);
|
|
170
|
+
} catch (error) {
|
|
171
|
+
throw new Error(`offline: one of the module nesting ${_classPrivateFieldLooseBase(this, _handlerModuleNesting)[_handlerModuleNesting]} for handler ${_classPrivateFieldLooseBase(this, _handlerName)[_handlerName]} is undefined or not exported`);
|
|
172
|
+
}
|
|
158
173
|
|
|
159
174
|
if (typeof handler !== 'function') {
|
|
160
175
|
throw new Error(`offline: handler '${_classPrivateFieldLooseBase(this, _handlerName)[_handlerName]}' in ${_classPrivateFieldLooseBase(this, _handlerPath)[_handlerPath]} is not a function`);
|
|
@@ -116,8 +116,7 @@ class JavaRunner {
|
|
|
116
116
|
data: input,
|
|
117
117
|
function: _classPrivateFieldLooseBase(this, _functionName)[_functionName],
|
|
118
118
|
jsonOutput: true,
|
|
119
|
-
serverlessOffline: true
|
|
120
|
-
allowCache: _classPrivateFieldLooseBase(this, _allowCache)[_allowCache]
|
|
119
|
+
serverlessOffline: true
|
|
121
120
|
});
|
|
122
121
|
const httpOptions = {
|
|
123
122
|
method: 'POST',
|
|
@@ -39,6 +39,7 @@ class WorkerThreadRunner {
|
|
|
39
39
|
functionKey,
|
|
40
40
|
handlerName,
|
|
41
41
|
handlerPath,
|
|
42
|
+
handlerModuleNesting,
|
|
42
43
|
timeout
|
|
43
44
|
} = funOptions;
|
|
44
45
|
_classPrivateFieldLooseBase(this, _allowCache)[_allowCache] = allowCache;
|
|
@@ -49,6 +50,7 @@ class WorkerThreadRunner {
|
|
|
49
50
|
functionKey,
|
|
50
51
|
handlerName,
|
|
51
52
|
handlerPath,
|
|
53
|
+
handlerModuleNesting,
|
|
52
54
|
timeout
|
|
53
55
|
}
|
|
54
56
|
});
|
|
@@ -10,7 +10,8 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
10
10
|
const {
|
|
11
11
|
functionKey,
|
|
12
12
|
handlerName,
|
|
13
|
-
handlerPath
|
|
13
|
+
handlerPath,
|
|
14
|
+
handlerModuleNesting
|
|
14
15
|
} = _worker_threads.workerData;
|
|
15
16
|
|
|
16
17
|
_worker_threads.parentPort.on('message', async messageData => {
|
|
@@ -22,7 +23,7 @@ _worker_threads.parentPort.on('message', async messageData => {
|
|
|
22
23
|
allowCache
|
|
23
24
|
} = messageData; // TODO we could probably cache this in the module scope?
|
|
24
25
|
|
|
25
|
-
const inProcessRunner = new _index.default(functionKey, handlerPath, handlerName, process.env, timeout, allowCache);
|
|
26
|
+
const inProcessRunner = new _index.default(functionKey, handlerPath, handlerName, handlerModuleNesting, process.env, timeout, allowCache);
|
|
26
27
|
const result = await inProcessRunner.run(event, context); // TODO check serializeability (contains function, symbol etc)
|
|
27
28
|
|
|
28
29
|
port.postMessage(result);
|
|
@@ -8,18 +8,18 @@ exports.default = splitHandlerPathAndName;
|
|
|
8
8
|
// some-folder/src.index => some-folder/src
|
|
9
9
|
function splitHandlerPathAndName(handler) {
|
|
10
10
|
// Split handler into method name and path i.e. handler.run
|
|
11
|
-
|
|
11
|
+
const prepathDelimiter = handler.lastIndexOf('/');
|
|
12
|
+
const prepath = handler.substr(0, prepathDelimiter + 1); // include '/' for path
|
|
13
|
+
|
|
14
|
+
const postpath = handler.substr(prepathDelimiter + 1); // Support Ruby paths with namespace resolution operators e.g.
|
|
12
15
|
// ./src/somefolder/source.LambdaFunctions::Handler.process
|
|
13
16
|
// prepath: ./src/somefolder/
|
|
14
17
|
// postpath: source.LambdaFunctions::Handler.process
|
|
15
18
|
// filename: source
|
|
16
19
|
// path: ./src/somefolder/source
|
|
17
20
|
// name: LambdaFunctions::Handler.process
|
|
18
|
-
if (handler.match(/::/)) {
|
|
19
|
-
const prepathDelimiter = handler.lastIndexOf('/');
|
|
20
|
-
const prepath = handler.substr(0, prepathDelimiter + 1); // include '/' for path
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
if (handler.match(/::/)) {
|
|
23
23
|
const nameDelimiter = postpath.indexOf('.');
|
|
24
24
|
const filename = postpath.substr(0, nameDelimiter);
|
|
25
25
|
const path = prepath + filename;
|
|
@@ -30,8 +30,12 @@ function splitHandlerPathAndName(handler) {
|
|
|
30
30
|
// name: run
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
|
|
33
|
+
const [filename, ...moduleNesting] = postpath.split('.');
|
|
34
|
+
const [name] = moduleNesting.slice(-1);
|
|
35
|
+
const path = prepath + filename; // module nesting has been added to support when the
|
|
36
|
+
// handler function is buried deep inside of a module
|
|
37
|
+
// e.g /src/somefoler/handlers/index.layer1.layer2.handler
|
|
38
|
+
// AWS supports this feature
|
|
39
|
+
|
|
40
|
+
return [path, name, moduleNesting];
|
|
37
41
|
}
|
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": "8.
|
|
4
|
+
"version": "8.6.0",
|
|
5
5
|
"description": "Emulate AWS λ and API Gateway locally when developing your Serverless project",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "dist/main.js",
|
|
@@ -117,6 +117,7 @@
|
|
|
117
117
|
"Kiryl Yermakou (https://github.com/rma4ok)",
|
|
118
118
|
"kobanyan (https://github.com/kobanyan)",
|
|
119
119
|
"Leonardo Alifraco (https://github.com/lalifraco-devspark)",
|
|
120
|
+
"Leonardo Medici (https://github.com/doclm)",
|
|
120
121
|
"Luke Chavers (https://github.com/vmadman)",
|
|
121
122
|
"Manuel Böhm (https://github.com/boehmers)",
|
|
122
123
|
"Marc Campbell (https://github.com/marccampbell)",
|
|
@@ -204,7 +205,7 @@
|
|
|
204
205
|
"@hapi/boom": "^9.1.4",
|
|
205
206
|
"@hapi/h2o2": "^9.1.0",
|
|
206
207
|
"@hapi/hapi": "^20.2.1",
|
|
207
|
-
"aws-sdk": "^2.
|
|
208
|
+
"aws-sdk": "^2.1097.0",
|
|
208
209
|
"boxen": "^5.1.2",
|
|
209
210
|
"chalk": "^4.1.2",
|
|
210
211
|
"cuid": "^2.1.8",
|
|
@@ -225,21 +226,20 @@
|
|
|
225
226
|
"p-queue": "^6.6.2",
|
|
226
227
|
"p-retry": "^4.6.1",
|
|
227
228
|
"please-upgrade-node": "^3.2.0",
|
|
228
|
-
"portfinder": "^1.0.28",
|
|
229
229
|
"semver": "^7.3.5",
|
|
230
230
|
"update-notifier": "^5.1.0",
|
|
231
231
|
"velocityjs": "^2.0.6",
|
|
232
232
|
"ws": "^7.5.7"
|
|
233
233
|
},
|
|
234
234
|
"devDependencies": {
|
|
235
|
-
"@babel/cli": "^7.17.
|
|
236
|
-
"@babel/core": "^7.17.
|
|
235
|
+
"@babel/cli": "^7.17.6",
|
|
236
|
+
"@babel/core": "^7.17.8",
|
|
237
237
|
"@babel/plugin-proposal-class-properties": "^7.16.7",
|
|
238
238
|
"@babel/plugin-proposal-dynamic-import": "^7.16.7",
|
|
239
239
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7",
|
|
240
240
|
"@babel/plugin-proposal-optional-chaining": "^7.16.7",
|
|
241
|
-
"@babel/plugin-transform-modules-commonjs": "^7.
|
|
242
|
-
"@babel/register": "^7.17.
|
|
241
|
+
"@babel/plugin-transform-modules-commonjs": "^7.17.7",
|
|
242
|
+
"@babel/register": "^7.17.7",
|
|
243
243
|
"archiver": "^5.3.0",
|
|
244
244
|
"babel-eslint": "^10.1.0",
|
|
245
245
|
"copyfiles": "^2.4.1",
|
|
@@ -253,9 +253,9 @@
|
|
|
253
253
|
"jest": "^26.6.3",
|
|
254
254
|
"lint-staged": "^11.2.6",
|
|
255
255
|
"p-map": "^4.0.0",
|
|
256
|
-
"prettier": "^2.
|
|
256
|
+
"prettier": "^2.6.0",
|
|
257
257
|
"rimraf": "^3.0.2",
|
|
258
|
-
"serverless": "^2.72.
|
|
258
|
+
"serverless": "^2.72.3",
|
|
259
259
|
"standard-version": "^9.3.2"
|
|
260
260
|
},
|
|
261
261
|
"peerDependencies": {
|