serverless-offline 13.3.1 → 13.3.3
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 +17 -17
- package/package.json +14 -13
- package/src/ServerlessOffline.js +42 -42
- package/src/config/colors.js +9 -9
- package/src/config/commandOptions.js +61 -61
- package/src/config/constants.js +5 -5
- package/src/config/defaultOptions.js +6 -6
- package/src/config/index.js +4 -4
- package/src/config/supportedRuntimes.js +18 -18
- package/src/errors/index.js +1 -1
- package/src/events/alb/Alb.js +2 -2
- package/src/events/alb/AlbEventDefinition.js +2 -2
- package/src/events/alb/HttpServer.js +54 -54
- package/src/events/alb/index.js +1 -1
- package/src/events/alb/lambda-events/LambdaAlbRequestEvent.js +2 -2
- package/src/events/alb/lambda-events/index.js +1 -1
- package/src/events/authCanExecuteResource.js +3 -3
- package/src/events/authFunctionNameExtractor.js +9 -9
- package/src/events/authMatchPolicyResource.js +8 -8
- package/src/events/authValidateContext.js +11 -11
- package/src/events/http/Endpoint.js +26 -26
- package/src/events/http/Http.js +2 -2
- package/src/events/http/HttpEventDefinition.js +2 -2
- package/src/events/http/HttpServer.js +156 -156
- package/src/events/http/OfflineEndpoint.js +7 -7
- package/src/events/http/authJWTSettingsExtractor.js +2 -2
- package/src/events/http/createAuthScheme.js +29 -27
- package/src/events/http/createJWTAuthScheme.js +12 -12
- package/src/events/http/index.js +1 -1
- package/src/events/http/javaHelpers.js +2 -2
- package/src/events/http/lambda-events/LambdaIntegrationEvent.js +5 -5
- package/src/events/http/lambda-events/LambdaProxyIntegrationEvent.js +47 -47
- package/src/events/http/lambda-events/LambdaProxyIntegrationEventV2.js +27 -27
- package/src/events/http/lambda-events/VelocityContext.js +28 -32
- package/src/events/http/lambda-events/index.js +4 -4
- package/src/events/http/lambda-events/renderVelocityTemplateObject.js +13 -13
- package/src/events/http/parseResources.js +6 -6
- package/src/events/http/payloadSchemaValidator.js +2 -2
- package/src/events/schedule/Schedule.js +21 -21
- package/src/events/schedule/ScheduleEvent.js +7 -7
- package/src/events/schedule/ScheduleEventDefinition.js +1 -1
- package/src/events/schedule/index.js +1 -1
- package/src/events/websocket/HttpServer.js +9 -9
- package/src/events/websocket/WebSocket.js +4 -4
- package/src/events/websocket/WebSocketClients.js +29 -29
- package/src/events/websocket/WebSocketEventDefinition.js +1 -1
- package/src/events/websocket/WebSocketServer.js +9 -9
- package/src/events/websocket/http-routes/_catchAll/catchAllRoute.js +3 -3
- package/src/events/websocket/http-routes/_catchAll/index.js +1 -1
- package/src/events/websocket/http-routes/connections/ConnectionsController.js +1 -1
- package/src/events/websocket/http-routes/connections/connectionsRoutes.js +6 -6
- package/src/events/websocket/http-routes/connections/index.js +1 -1
- package/src/events/websocket/http-routes/index.js +2 -2
- package/src/events/websocket/index.js +1 -1
- package/src/events/websocket/lambda-events/WebSocketAuthorizerEvent.js +5 -5
- package/src/events/websocket/lambda-events/WebSocketConnectEvent.js +7 -6
- package/src/events/websocket/lambda-events/WebSocketDisconnectEvent.js +5 -5
- package/src/events/websocket/lambda-events/WebSocketEvent.js +2 -2
- package/src/events/websocket/lambda-events/WebSocketRequestContext.js +12 -11
- package/src/events/websocket/lambda-events/index.js +4 -4
- package/src/index.js +1 -1
- package/src/lambda/HttpServer.js +11 -11
- package/src/lambda/Lambda.js +2 -2
- package/src/lambda/LambdaContext.js +1 -1
- package/src/lambda/LambdaFunction.js +34 -34
- package/src/lambda/LambdaFunctionPool.js +3 -3
- package/src/lambda/handler-runner/HandlerRunner.js +12 -12
- package/src/lambda/handler-runner/docker-runner/DockerContainer.js +59 -59
- package/src/lambda/handler-runner/docker-runner/DockerImage.js +6 -6
- package/src/lambda/handler-runner/docker-runner/DockerRunner.js +2 -2
- package/src/lambda/handler-runner/docker-runner/index.js +1 -1
- package/src/lambda/handler-runner/go-runner/GoRunner.js +34 -34
- package/src/lambda/handler-runner/go-runner/index.js +1 -1
- package/src/lambda/handler-runner/in-process-runner/InProcessRunner.js +7 -7
- package/src/lambda/handler-runner/in-process-runner/aws-lambda-ric/UserFunction.js +52 -52
- package/src/lambda/handler-runner/in-process-runner/index.js +1 -1
- package/src/lambda/handler-runner/index.js +1 -1
- package/src/lambda/handler-runner/java-runner/JavaRunner.js +13 -13
- package/src/lambda/handler-runner/java-runner/index.js +1 -1
- package/src/lambda/handler-runner/python-runner/PythonRunner.js +21 -21
- package/src/lambda/handler-runner/python-runner/index.js +1 -1
- package/src/lambda/handler-runner/ruby-runner/RubyRunner.js +11 -11
- package/src/lambda/handler-runner/ruby-runner/index.js +1 -1
- package/src/lambda/handler-runner/worker-thread-runner/WorkerThreadRunner.js +6 -6
- package/src/lambda/handler-runner/worker-thread-runner/index.js +1 -1
- package/src/lambda/handler-runner/worker-thread-runner/workerThreadHelper.js +4 -4
- package/src/lambda/index.js +1 -1
- package/src/lambda/routes/index.js +2 -2
- package/src/lambda/routes/invocations/InvocationsController.js +11 -11
- package/src/lambda/routes/invocations/index.js +1 -1
- package/src/lambda/routes/invocations/invocationsRoute.js +15 -15
- package/src/lambda/routes/invoke-async/index.js +1 -1
- package/src/lambda/routes/invoke-async/invokeAsyncRoute.js +6 -6
- package/src/utils/checkDockerDaemon.js +8 -8
- package/src/utils/checkGoVersion.js +3 -3
- package/src/utils/createApiKey.js +2 -2
- package/src/utils/detectExecutable.js +2 -2
- package/src/utils/formatToClfTime.js +2 -2
- package/src/utils/generateHapiPath.js +8 -8
- package/src/utils/getApiKeysValues.js +10 -2
- package/src/utils/getHttpApiCorsConfig.js +11 -11
- package/src/utils/getRawQueryParams.js +2 -2
- package/src/utils/index.js +25 -26
- package/src/utils/jsonPath.js +1 -1
- package/src/utils/logRoutes.js +13 -13
- package/src/utils/parseHeaders.js +1 -1
- package/src/utils/parseMultiValueHeaders.js +1 -1
- package/src/utils/parseMultiValueQueryStringParameters.js +1 -1
- package/src/utils/parseQueryStringParameters.js +1 -1
- package/src/utils/parseQueryStringParametersForPayloadV2.js +1 -1
- package/src/utils/splitHandlerPathAndName.js +3 -3
- package/src/utils/createUniqueId.js +0 -5
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { WebSocket } from
|
|
2
|
-
import { isBoom } from
|
|
3
|
-
import { log } from
|
|
1
|
+
import { WebSocket } from "ws"
|
|
2
|
+
import { isBoom } from "@hapi/boom"
|
|
3
|
+
import { log } from "@serverless/utils/log.js"
|
|
4
4
|
import {
|
|
5
5
|
WebSocketAuthorizerEvent,
|
|
6
6
|
WebSocketConnectEvent,
|
|
7
7
|
WebSocketDisconnectEvent,
|
|
8
8
|
WebSocketEvent,
|
|
9
|
-
} from
|
|
10
|
-
import authCanExecuteResource from
|
|
11
|
-
import authFunctionNameExtractor from
|
|
12
|
-
import authValidateContext from
|
|
9
|
+
} from "./lambda-events/index.js"
|
|
10
|
+
import authCanExecuteResource from "../authCanExecuteResource.js"
|
|
11
|
+
import authFunctionNameExtractor from "../authFunctionNameExtractor.js"
|
|
12
|
+
import authValidateContext from "../authValidateContext.js"
|
|
13
13
|
import {
|
|
14
14
|
DEFAULT_WEBSOCKETS_API_ROUTE_SELECTION_EXPRESSION,
|
|
15
15
|
DEFAULT_WEBSOCKETS_ROUTE,
|
|
16
|
-
} from
|
|
17
|
-
import { jsonPath } from
|
|
16
|
+
} from "../../config/index.js"
|
|
17
|
+
import { jsonPath } from "../../utils/index.js"
|
|
18
18
|
|
|
19
19
|
const { parse, stringify } = JSON
|
|
20
20
|
|
|
@@ -72,7 +72,7 @@ export default class WebSocketClients {
|
|
|
72
72
|
const timeoutId = setTimeout(() => {
|
|
73
73
|
log.debug(`timeout:hard:${connectionId}`)
|
|
74
74
|
|
|
75
|
-
client.close(1001,
|
|
75
|
+
client.close(1001, "Going away")
|
|
76
76
|
}, this.#options.webSocketHardTimeout * 1000)
|
|
77
77
|
|
|
78
78
|
this.#hardTimeouts.set(client, timeoutId)
|
|
@@ -91,7 +91,7 @@ export default class WebSocketClients {
|
|
|
91
91
|
|
|
92
92
|
const timeoutId = setTimeout(() => {
|
|
93
93
|
log.debug(`timeout:idle:${connectionId}:trigger`)
|
|
94
|
-
client.close(1001,
|
|
94
|
+
client.close(1001, "Going away")
|
|
95
95
|
}, this.#options.webSocketIdleTimeout * 1000)
|
|
96
96
|
this.#idleTimeouts.set(client, timeoutId)
|
|
97
97
|
}
|
|
@@ -102,7 +102,7 @@ export default class WebSocketClients {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
async verifyClient(connectionId, request) {
|
|
105
|
-
const routeName =
|
|
105
|
+
const routeName = "$connect"
|
|
106
106
|
const route = this.#webSocketRoutes.get(routeName)
|
|
107
107
|
if (!route) {
|
|
108
108
|
return {
|
|
@@ -137,7 +137,7 @@ export default class WebSocketClients {
|
|
|
137
137
|
|
|
138
138
|
try {
|
|
139
139
|
const result = await authorizerFunction.runHandler()
|
|
140
|
-
if (result ===
|
|
140
|
+
if (result === "Unauthorized") {
|
|
141
141
|
return {
|
|
142
142
|
statusCode: 401,
|
|
143
143
|
verified: false,
|
|
@@ -189,14 +189,14 @@ export default class WebSocketClients {
|
|
|
189
189
|
|
|
190
190
|
this.#webSocketAuthorizersCache.set(connectionId, {
|
|
191
191
|
authorizer: {
|
|
192
|
-
integrationLatency:
|
|
192
|
+
integrationLatency: "42",
|
|
193
193
|
principalId: policy.principalId,
|
|
194
194
|
...policy.context,
|
|
195
195
|
},
|
|
196
196
|
identity: {
|
|
197
197
|
apiKey: policy.usageIdentifierKey,
|
|
198
198
|
sourceIp: authorizeEvent.requestContext.sourceIp,
|
|
199
|
-
userAgent: authorizeEvent.headers[
|
|
199
|
+
userAgent: authorizeEvent.headers["user-agent"] || "",
|
|
200
200
|
},
|
|
201
201
|
})
|
|
202
202
|
} catch (err) {
|
|
@@ -251,8 +251,8 @@ export default class WebSocketClients {
|
|
|
251
251
|
async #processEvent(websocketClient, connectionId, routeKey, event) {
|
|
252
252
|
let route = this.#webSocketRoutes.get(routeKey)
|
|
253
253
|
|
|
254
|
-
if (!route && routeKey !==
|
|
255
|
-
route = this.#webSocketRoutes.get(
|
|
254
|
+
if (!route && routeKey !== "$disconnect") {
|
|
255
|
+
route = this.#webSocketRoutes.get("$default")
|
|
256
256
|
}
|
|
257
257
|
|
|
258
258
|
if (!route) {
|
|
@@ -264,8 +264,8 @@ export default class WebSocketClients {
|
|
|
264
264
|
websocketClient.send(
|
|
265
265
|
stringify({
|
|
266
266
|
connectionId,
|
|
267
|
-
message:
|
|
268
|
-
requestId:
|
|
267
|
+
message: "Internal server error",
|
|
268
|
+
requestId: "1234567890",
|
|
269
269
|
}),
|
|
270
270
|
)
|
|
271
271
|
}
|
|
@@ -289,8 +289,8 @@ export default class WebSocketClients {
|
|
|
289
289
|
const { body } = await lambdaFunction.runHandler()
|
|
290
290
|
if (
|
|
291
291
|
body &&
|
|
292
|
-
routeKey !==
|
|
293
|
-
route.definition.routeResponseSelectionExpression ===
|
|
292
|
+
routeKey !== "$disconnect" &&
|
|
293
|
+
route.definition.routeResponseSelectionExpression === "$default"
|
|
294
294
|
) {
|
|
295
295
|
// https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-selection-expressions.html#apigateway-websocket-api-route-response-selection-expressions
|
|
296
296
|
// TODO: Once API gateway supports RouteResponses, this will need to change to support that functionality
|
|
@@ -314,11 +314,11 @@ export default class WebSocketClients {
|
|
|
314
314
|
}
|
|
315
315
|
|
|
316
316
|
const routeSelectionExpression =
|
|
317
|
-
this.#websocketsApiRouteSelectionExpression.replace(
|
|
317
|
+
this.#websocketsApiRouteSelectionExpression.replace("request.body", "")
|
|
318
318
|
|
|
319
319
|
const route = jsonPath(json, routeSelectionExpression)
|
|
320
320
|
|
|
321
|
-
if (typeof route !==
|
|
321
|
+
if (typeof route !== "string") {
|
|
322
322
|
return DEFAULT_WEBSOCKETS_ROUTE
|
|
323
323
|
}
|
|
324
324
|
|
|
@@ -328,7 +328,7 @@ export default class WebSocketClients {
|
|
|
328
328
|
addClient(webSocketClient, connectionId) {
|
|
329
329
|
this.#addWebSocketClient(webSocketClient, connectionId)
|
|
330
330
|
|
|
331
|
-
webSocketClient.on(
|
|
331
|
+
webSocketClient.on("close", () => {
|
|
332
332
|
log.debug(`disconnect:${connectionId}`)
|
|
333
333
|
|
|
334
334
|
this.#removeWebSocketClient(webSocketClient)
|
|
@@ -349,12 +349,12 @@ export default class WebSocketClients {
|
|
|
349
349
|
this.#processEvent(
|
|
350
350
|
webSocketClient,
|
|
351
351
|
connectionId,
|
|
352
|
-
|
|
352
|
+
"$disconnect",
|
|
353
353
|
disconnectEvent,
|
|
354
354
|
).finally(() => this.#webSocketAuthorizersCache.delete(connectionId))
|
|
355
355
|
})
|
|
356
356
|
|
|
357
|
-
webSocketClient.on(
|
|
357
|
+
webSocketClient.on("message", (data, isBinary) => {
|
|
358
358
|
const message = isBinary ? data : String(data)
|
|
359
359
|
|
|
360
360
|
log.debug(`message:${message}`)
|
|
@@ -377,9 +377,9 @@ export default class WebSocketClients {
|
|
|
377
377
|
|
|
378
378
|
#extractAuthFunctionName(endpoint) {
|
|
379
379
|
if (
|
|
380
|
-
typeof endpoint.authorizer ===
|
|
380
|
+
typeof endpoint.authorizer === "object" &&
|
|
381
381
|
endpoint.authorizer.type &&
|
|
382
|
-
endpoint.authorizer.type.toUpperCase() ===
|
|
382
|
+
endpoint.authorizer.type.toUpperCase() === "TOKEN"
|
|
383
383
|
) {
|
|
384
384
|
log.debug(`Websockets does not support the TOKEN authorization type`)
|
|
385
385
|
|
|
@@ -396,7 +396,7 @@ export default class WebSocketClients {
|
|
|
396
396
|
return
|
|
397
397
|
}
|
|
398
398
|
|
|
399
|
-
if (endpoint.route ===
|
|
399
|
+
if (endpoint.route === "$connect") {
|
|
400
400
|
const authFunctionName = this.#extractAuthFunctionName(endpoint)
|
|
401
401
|
|
|
402
402
|
if (!authFunctionName) {
|
|
@@ -5,7 +5,7 @@ export default class WebSocketEventDefinition {
|
|
|
5
5
|
let rest
|
|
6
6
|
let route
|
|
7
7
|
|
|
8
|
-
if (typeof rawWebSocketEventDefinition ===
|
|
8
|
+
if (typeof rawWebSocketEventDefinition === "string") {
|
|
9
9
|
route = rawWebSocketEventDefinition
|
|
10
10
|
} else {
|
|
11
11
|
;({ route, ...rest } = rawWebSocketEventDefinition)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import crypto from "node:crypto"
|
|
2
|
+
import { log } from "@serverless/utils/log.js"
|
|
3
|
+
import { WebSocketServer as WsWebSocketServer } from "ws"
|
|
4
4
|
|
|
5
5
|
export default class WebSocketServer {
|
|
6
6
|
#connectionIds = new Map()
|
|
@@ -21,8 +21,8 @@ export default class WebSocketServer {
|
|
|
21
21
|
const server = new WsWebSocketServer({
|
|
22
22
|
server: this.#sharedServer,
|
|
23
23
|
verifyClient: async ({ req }, cb) => {
|
|
24
|
-
const connectionId =
|
|
25
|
-
const key = req.headers[
|
|
24
|
+
const connectionId = crypto.randomUUID()
|
|
25
|
+
const key = req.headers["sec-websocket-key"]
|
|
26
26
|
|
|
27
27
|
log.debug(`verifyClient:${key} ${connectionId}`)
|
|
28
28
|
|
|
@@ -45,11 +45,11 @@ export default class WebSocketServer {
|
|
|
45
45
|
},
|
|
46
46
|
})
|
|
47
47
|
|
|
48
|
-
server.on(
|
|
49
|
-
log.notice(
|
|
48
|
+
server.on("connection", (webSocketClient, request) => {
|
|
49
|
+
log.notice("received connection")
|
|
50
50
|
|
|
51
51
|
const { headers } = request
|
|
52
|
-
const key = headers[
|
|
52
|
+
const key = headers["sec-websocket-key"]
|
|
53
53
|
|
|
54
54
|
const connectionId = this.#connectionIds.get(key)
|
|
55
55
|
|
|
@@ -64,7 +64,7 @@ export default class WebSocketServer {
|
|
|
64
64
|
|
|
65
65
|
log.notice(
|
|
66
66
|
`Offline [websocket] listening on ${
|
|
67
|
-
httpsProtocol ?
|
|
67
|
+
httpsProtocol ? "wss" : "ws"
|
|
68
68
|
}://${host}:${websocketPort}`,
|
|
69
69
|
)
|
|
70
70
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { log } from
|
|
1
|
+
import { log } from "@serverless/utils/log.js"
|
|
2
2
|
|
|
3
3
|
export default function catchAllRoute() {
|
|
4
4
|
return {
|
|
@@ -10,7 +10,7 @@ export default function catchAllRoute() {
|
|
|
10
10
|
return h.response(null).code(426)
|
|
11
11
|
},
|
|
12
12
|
|
|
13
|
-
method:
|
|
14
|
-
path:
|
|
13
|
+
method: "GET",
|
|
14
|
+
path: "/{path*}",
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default } from
|
|
1
|
+
export { default } from "./catchAllRoute.js"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { log } from
|
|
2
|
-
import ConnectionsController from
|
|
1
|
+
import { log } from "@serverless/utils/log.js"
|
|
2
|
+
import ConnectionsController from "./ConnectionsController.js"
|
|
3
3
|
|
|
4
4
|
export default function connectionsRoutes(webSocketClients) {
|
|
5
5
|
const connectionsController = new ConnectionsController(webSocketClients)
|
|
@@ -29,13 +29,13 @@ export default function connectionsRoutes(webSocketClients) {
|
|
|
29
29
|
return null
|
|
30
30
|
},
|
|
31
31
|
|
|
32
|
-
method:
|
|
32
|
+
method: "POST",
|
|
33
33
|
options: {
|
|
34
34
|
payload: {
|
|
35
35
|
parse: false,
|
|
36
36
|
},
|
|
37
37
|
},
|
|
38
|
-
path:
|
|
38
|
+
path: "/@connections/{connectionId}",
|
|
39
39
|
},
|
|
40
40
|
|
|
41
41
|
{
|
|
@@ -58,13 +58,13 @@ export default function connectionsRoutes(webSocketClients) {
|
|
|
58
58
|
return h.response(null).code(204)
|
|
59
59
|
},
|
|
60
60
|
|
|
61
|
-
method:
|
|
61
|
+
method: "DELETE",
|
|
62
62
|
options: {
|
|
63
63
|
payload: {
|
|
64
64
|
parse: false,
|
|
65
65
|
},
|
|
66
66
|
},
|
|
67
|
-
path:
|
|
67
|
+
path: "/@connections/{connectionId}",
|
|
68
68
|
},
|
|
69
69
|
]
|
|
70
70
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default } from
|
|
1
|
+
export { default } from "./connectionsRoutes.js"
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default as catchAllRoute } from
|
|
2
|
-
export { default as connectionsRoutes } from
|
|
1
|
+
export { default as catchAllRoute } from "./_catchAll/index.js"
|
|
2
|
+
export { default as connectionsRoutes } from "./connections/index.js"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default } from
|
|
1
|
+
export { default } from "./WebSocket.js"
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import WebSocketRequestContext from
|
|
1
|
+
import WebSocketRequestContext from "./WebSocketRequestContext.js"
|
|
2
2
|
import {
|
|
3
3
|
parseHeaders,
|
|
4
4
|
parseMultiValueHeaders,
|
|
5
5
|
parseMultiValueQueryStringParameters,
|
|
6
6
|
parseQueryStringParameters,
|
|
7
|
-
} from
|
|
7
|
+
} from "../../../utils/index.js"
|
|
8
8
|
|
|
9
9
|
export default class WebSocketAuthorizerEvent {
|
|
10
10
|
#connectionId = null
|
|
@@ -39,8 +39,8 @@ export default class WebSocketAuthorizerEvent {
|
|
|
39
39
|
const queryStringParameters = parseQueryStringParameters(this.#url)
|
|
40
40
|
|
|
41
41
|
const requestContext = new WebSocketRequestContext(
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
"CONNECT",
|
|
43
|
+
"$connect",
|
|
44
44
|
this.#connectionId,
|
|
45
45
|
).create()
|
|
46
46
|
|
|
@@ -55,7 +55,7 @@ export default class WebSocketAuthorizerEvent {
|
|
|
55
55
|
}),
|
|
56
56
|
...(queryStringParameters && { queryStringParameters }),
|
|
57
57
|
requestContext,
|
|
58
|
-
type:
|
|
58
|
+
type: "REQUEST",
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
// import crypto from 'node:crypto'
|
|
2
|
+
import WebSocketRequestContext from "./WebSocketRequestContext.js"
|
|
2
3
|
import {
|
|
3
4
|
parseHeaders,
|
|
4
5
|
parseMultiValueHeaders,
|
|
5
6
|
parseMultiValueQueryStringParameters,
|
|
6
7
|
parseQueryStringParameters,
|
|
7
|
-
} from
|
|
8
|
+
} from "../../../utils/index.js"
|
|
8
9
|
|
|
9
10
|
export default class WebSocketConnectEvent {
|
|
10
11
|
#connectionId = null
|
|
@@ -32,9 +33,9 @@ export default class WebSocketConnectEvent {
|
|
|
32
33
|
// const headers = {
|
|
33
34
|
// Host: 'localhost',
|
|
34
35
|
// 'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits',
|
|
35
|
-
// 'Sec-WebSocket-Key':
|
|
36
|
+
// 'Sec-WebSocket-Key': crypto.randomUUID(),
|
|
36
37
|
// 'Sec-WebSocket-Version': '13',
|
|
37
|
-
// 'X-Amzn-Trace-Id': `Root=${
|
|
38
|
+
// 'X-Amzn-Trace-Id': `Root=${crypto.randomUUID()}`,
|
|
38
39
|
// 'X-Forwarded-For': '127.0.0.1',
|
|
39
40
|
// 'X-Forwarded-Port': String(this.#websocketPort),
|
|
40
41
|
// 'X-Forwarded-Proto': ${httpsProtocol ? 'https' : 'http'},
|
|
@@ -47,8 +48,8 @@ export default class WebSocketConnectEvent {
|
|
|
47
48
|
const queryStringParameters = parseQueryStringParameters(this.#url)
|
|
48
49
|
|
|
49
50
|
const requestContext = new WebSocketRequestContext(
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
"CONNECT",
|
|
52
|
+
"$connect",
|
|
52
53
|
this.#connectionId,
|
|
53
54
|
).create()
|
|
54
55
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import WebSocketRequestContext from
|
|
2
|
-
import { parseHeaders, parseMultiValueHeaders } from
|
|
1
|
+
import WebSocketRequestContext from "./WebSocketRequestContext.js"
|
|
2
|
+
import { parseHeaders, parseMultiValueHeaders } from "../../../utils/index.js"
|
|
3
3
|
|
|
4
4
|
export default class WebSocketDisconnectEvent {
|
|
5
5
|
#connectionId = null
|
|
@@ -10,14 +10,14 @@ export default class WebSocketDisconnectEvent {
|
|
|
10
10
|
|
|
11
11
|
create() {
|
|
12
12
|
// TODO FIXME not sure where the headers come from
|
|
13
|
-
const rawHeaders = [
|
|
13
|
+
const rawHeaders = ["Host", "localhost", "x-api-key", "", "x-restapi", ""]
|
|
14
14
|
|
|
15
15
|
const headers = parseHeaders(rawHeaders)
|
|
16
16
|
const multiValueHeaders = parseMultiValueHeaders(rawHeaders)
|
|
17
17
|
|
|
18
18
|
const requestContext = new WebSocketRequestContext(
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
"DISCONNECT",
|
|
20
|
+
"$disconnect",
|
|
21
21
|
this.#connectionId,
|
|
22
22
|
).create()
|
|
23
23
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import WebSocketRequestContext from
|
|
1
|
+
import WebSocketRequestContext from "./WebSocketRequestContext.js"
|
|
2
2
|
|
|
3
3
|
export default class WebSocketEvent {
|
|
4
4
|
#connectionId = null
|
|
@@ -15,7 +15,7 @@ export default class WebSocketEvent {
|
|
|
15
15
|
|
|
16
16
|
create() {
|
|
17
17
|
const requestContext = new WebSocketRequestContext(
|
|
18
|
-
|
|
18
|
+
"MESSAGE",
|
|
19
19
|
this.#route,
|
|
20
20
|
this.#connectionId,
|
|
21
21
|
).create()
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import crypto from "node:crypto"
|
|
2
|
+
import { formatToClfTime } from "../../../utils/index.js"
|
|
2
3
|
|
|
3
4
|
const { now } = Date
|
|
4
5
|
|
|
@@ -18,13 +19,13 @@ export default class WebSocketRequestContext {
|
|
|
18
19
|
this.#eventType = eventType
|
|
19
20
|
this.#route = route
|
|
20
21
|
|
|
21
|
-
if (eventType ===
|
|
22
|
+
if (eventType === "CONNECT") {
|
|
22
23
|
connectedAt.set(connectionId, now())
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
this.#connectedAt = connectedAt.get(connectionId)
|
|
26
27
|
|
|
27
|
-
if (eventType ===
|
|
28
|
+
if (eventType === "DISCONNECT") {
|
|
28
29
|
connectedAt.delete(connectionId)
|
|
29
30
|
}
|
|
30
31
|
}
|
|
@@ -33,12 +34,12 @@ export default class WebSocketRequestContext {
|
|
|
33
34
|
const timeEpoch = now()
|
|
34
35
|
|
|
35
36
|
const requestContext = {
|
|
36
|
-
apiId:
|
|
37
|
+
apiId: "private",
|
|
37
38
|
connectedAt: this.#connectedAt,
|
|
38
39
|
connectionId: this.#connectionId,
|
|
39
|
-
domainName:
|
|
40
|
+
domainName: "localhost",
|
|
40
41
|
eventType: this.#eventType,
|
|
41
|
-
extendedRequestId:
|
|
42
|
+
extendedRequestId: crypto.randomUUID(),
|
|
42
43
|
identity: {
|
|
43
44
|
accessKey: null,
|
|
44
45
|
accountId: null,
|
|
@@ -48,18 +49,18 @@ export default class WebSocketRequestContext {
|
|
|
48
49
|
cognitoIdentityId: null,
|
|
49
50
|
cognitoIdentityPoolId: null,
|
|
50
51
|
principalOrgId: null,
|
|
51
|
-
sourceIp:
|
|
52
|
+
sourceIp: "127.0.0.1",
|
|
52
53
|
user: null,
|
|
53
54
|
userAgent: null,
|
|
54
55
|
userArn: null,
|
|
55
56
|
},
|
|
56
|
-
messageDirection:
|
|
57
|
-
messageId:
|
|
58
|
-
requestId:
|
|
57
|
+
messageDirection: "IN",
|
|
58
|
+
messageId: crypto.randomUUID(),
|
|
59
|
+
requestId: crypto.randomUUID(),
|
|
59
60
|
requestTime: formatToClfTime(timeEpoch),
|
|
60
61
|
requestTimeEpoch: timeEpoch,
|
|
61
62
|
routeKey: this.#route,
|
|
62
|
-
stage:
|
|
63
|
+
stage: "local",
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
return requestContext
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { default as WebSocketConnectEvent } from
|
|
2
|
-
export { default as WebSocketDisconnectEvent } from
|
|
3
|
-
export { default as WebSocketEvent } from
|
|
4
|
-
export { default as WebSocketAuthorizerEvent } from
|
|
1
|
+
export { default as WebSocketConnectEvent } from "./WebSocketConnectEvent.js"
|
|
2
|
+
export { default as WebSocketDisconnectEvent } from "./WebSocketDisconnectEvent.js"
|
|
3
|
+
export { default as WebSocketEvent } from "./WebSocketEvent.js"
|
|
4
|
+
export { default as WebSocketAuthorizerEvent } from "./WebSocketAuthorizerEvent.js"
|
package/src/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default } from
|
|
1
|
+
export { default } from "./ServerlessOffline.js"
|
package/src/lambda/HttpServer.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { exit } from
|
|
2
|
-
import { Server } from
|
|
3
|
-
import { log } from
|
|
4
|
-
import { invocationsRoute, invokeAsyncRoute } from
|
|
1
|
+
import { exit } from "node:process"
|
|
2
|
+
import { Server } from "@hapi/hapi"
|
|
3
|
+
import { log } from "@serverless/utils/log.js"
|
|
4
|
+
import { invocationsRoute, invokeAsyncRoute } from "./routes/index.js"
|
|
5
5
|
|
|
6
6
|
export default class HttpServer {
|
|
7
7
|
#lambda = null
|
|
@@ -45,13 +45,13 @@ export default class HttpServer {
|
|
|
45
45
|
|
|
46
46
|
log.notice(
|
|
47
47
|
`Offline [http for lambda] listening on ${
|
|
48
|
-
httpsProtocol ?
|
|
48
|
+
httpsProtocol ? "https" : "http"
|
|
49
49
|
}://${host}:${lambdaPort}`,
|
|
50
50
|
)
|
|
51
51
|
|
|
52
52
|
// Print all the invocation routes to debug
|
|
53
53
|
const basePath = `${
|
|
54
|
-
httpsProtocol ?
|
|
54
|
+
httpsProtocol ? "https" : "http"
|
|
55
55
|
}://${host}:${lambdaPort}`
|
|
56
56
|
const funcNamePairs = this.#lambda.listFunctionNamePairs()
|
|
57
57
|
|
|
@@ -64,7 +64,7 @@ export default class HttpServer {
|
|
|
64
64
|
(functionName) =>
|
|
65
65
|
` * ${funcNamePairs[functionName]}: ${functionName}`,
|
|
66
66
|
),
|
|
67
|
-
].join(
|
|
67
|
+
].join("\n"),
|
|
68
68
|
)
|
|
69
69
|
log.debug(
|
|
70
70
|
[
|
|
@@ -76,11 +76,11 @@ export default class HttpServer {
|
|
|
76
76
|
` * ${
|
|
77
77
|
invRoute.method
|
|
78
78
|
} ${basePath}${invRoute.path.replace(
|
|
79
|
-
|
|
79
|
+
"{functionName}",
|
|
80
80
|
functionName,
|
|
81
81
|
)}`,
|
|
82
82
|
),
|
|
83
|
-
].join(
|
|
83
|
+
].join("\n"),
|
|
84
84
|
)
|
|
85
85
|
|
|
86
86
|
log.debug(
|
|
@@ -93,11 +93,11 @@ export default class HttpServer {
|
|
|
93
93
|
` * ${
|
|
94
94
|
invAsyncRoute.method
|
|
95
95
|
} ${basePath}${invAsyncRoute.path.replace(
|
|
96
|
-
|
|
96
|
+
"{functionName}",
|
|
97
97
|
functionName,
|
|
98
98
|
)}`,
|
|
99
99
|
),
|
|
100
|
-
].join(
|
|
100
|
+
].join("\n"),
|
|
101
101
|
)
|
|
102
102
|
}
|
|
103
103
|
|
package/src/lambda/Lambda.js
CHANGED
|
@@ -10,7 +10,7 @@ export default class LambdaContext {
|
|
|
10
10
|
callbackWaitsForEmptyEventLoop: true,
|
|
11
11
|
clientContext: undefined,
|
|
12
12
|
functionName,
|
|
13
|
-
functionVersion:
|
|
13
|
+
functionVersion: "$LATEST",
|
|
14
14
|
identity: undefined,
|
|
15
15
|
invokedFunctionArn: `offline_invokedFunctionArn_for_${functionName}`,
|
|
16
16
|
logGroupName: `offline_logGroupName_for_${functionName}`,
|