@mono-labs/dev 0.1.251
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/dist/aws-event-synthesis/index.d.ts +25 -0
- package/dist/aws-event-synthesis/index.d.ts.map +1 -0
- package/dist/aws-event-synthesis/index.js +90 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/local-server/event-synthesizer.d.ts +7 -0
- package/dist/local-server/event-synthesizer.d.ts.map +1 -0
- package/dist/local-server/event-synthesizer.js +62 -0
- package/dist/local-server/index.d.ts +17 -0
- package/dist/local-server/index.d.ts.map +1 -0
- package/dist/local-server/index.js +66 -0
- package/dist/local-server/types.d.ts +14 -0
- package/dist/local-server/types.d.ts.map +1 -0
- package/dist/local-server/types.js +2 -0
- package/dist/websocket/action-router.d.ts +17 -0
- package/dist/websocket/action-router.d.ts.map +1 -0
- package/dist/websocket/action-router.js +48 -0
- package/dist/websocket/connection-registry.d.ts +28 -0
- package/dist/websocket/connection-registry.d.ts.map +1 -0
- package/dist/websocket/connection-registry.js +59 -0
- package/dist/websocket/event-synthesizer.d.ts +24 -0
- package/dist/websocket/event-synthesizer.d.ts.map +1 -0
- package/dist/websocket/event-synthesizer.js +103 -0
- package/dist/websocket/index.d.ts +20 -0
- package/dist/websocket/index.d.ts.map +1 -0
- package/dist/websocket/index.js +132 -0
- package/dist/websocket/local-gateway-client.d.ts +15 -0
- package/dist/websocket/local-gateway-client.d.ts.map +1 -0
- package/dist/websocket/local-gateway-client.js +31 -0
- package/dist/websocket/types.d.ts +55 -0
- package/dist/websocket/types.d.ts.map +1 -0
- package/dist/websocket/types.js +2 -0
- package/package.json +38 -0
- package/src/aws-event-synthesis/index.ts +99 -0
- package/src/index.ts +21 -0
- package/src/local-server/event-synthesizer.ts +71 -0
- package/src/local-server/index.ts +94 -0
- package/src/local-server/types.ts +35 -0
- package/src/websocket/action-router.ts +66 -0
- package/src/websocket/connection-registry.ts +67 -0
- package/src/websocket/event-synthesizer.ts +131 -0
- package/src/websocket/index.ts +146 -0
- package/src/websocket/local-gateway-client.ts +31 -0
- package/src/websocket/types.ts +66 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Context as LambdaContext } from 'aws-lambda';
|
|
2
|
+
import type { Response } from 'express';
|
|
3
|
+
/** Flatten Node.js IncomingHttpHeaders to Record<string, string> */
|
|
4
|
+
export declare function flattenHeaders(headers: Record<string, string | string[] | undefined>): Record<string, string>;
|
|
5
|
+
/** Serialize a request body to string (passthrough if already string, JSON.stringify if object) */
|
|
6
|
+
export declare function serializeBody(body: unknown): string | null;
|
|
7
|
+
/** Convert Express parsed query to Record<string, string | undefined> */
|
|
8
|
+
export declare function extractQueryParams(query: Record<string, unknown>): Record<string, string | undefined>;
|
|
9
|
+
/** Split a URL into path and raw query string */
|
|
10
|
+
export declare function splitUrl(originalUrl: string): {
|
|
11
|
+
path: string;
|
|
12
|
+
queryString: string;
|
|
13
|
+
};
|
|
14
|
+
/** Generate a local request ID */
|
|
15
|
+
export declare function generateRequestId(): string;
|
|
16
|
+
/** Create a minimal mock Lambda Context */
|
|
17
|
+
export declare function createMockLambdaContext(functionName?: string): LambdaContext;
|
|
18
|
+
/** Send a Lambda-style result (API Gateway V2 or ALB) back through Express */
|
|
19
|
+
export declare function sendLambdaResult(res: Response, result: {
|
|
20
|
+
statusCode?: number;
|
|
21
|
+
headers?: Record<string, any>;
|
|
22
|
+
body?: string;
|
|
23
|
+
isBase64Encoded?: boolean;
|
|
24
|
+
}): void;
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/aws-event-synthesis/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAIvC,oEAAoE;AACpE,wBAAgB,cAAc,CAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GACpD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOxB;AAED,mGAAmG;AACnG,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAI1D;AAED,yEAAyE;AACzE,wBAAgB,kBAAkB,CACjC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAOpC;AAED,iDAAiD;AACjD,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAOnF;AAID,kCAAkC;AAClC,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,2CAA2C;AAC3C,wBAAgB,uBAAuB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,aAAa,CAgB5E;AAID,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,QAAQ,EACb,MAAM,EAAE;IACP,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,eAAe,CAAC,EAAE,OAAO,CAAA;CACzB,GACC,IAAI,CAeN"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.flattenHeaders = flattenHeaders;
|
|
4
|
+
exports.serializeBody = serializeBody;
|
|
5
|
+
exports.extractQueryParams = extractQueryParams;
|
|
6
|
+
exports.splitUrl = splitUrl;
|
|
7
|
+
exports.generateRequestId = generateRequestId;
|
|
8
|
+
exports.createMockLambdaContext = createMockLambdaContext;
|
|
9
|
+
exports.sendLambdaResult = sendLambdaResult;
|
|
10
|
+
// --- Header utilities ---
|
|
11
|
+
/** Flatten Node.js IncomingHttpHeaders to Record<string, string> */
|
|
12
|
+
function flattenHeaders(headers) {
|
|
13
|
+
const flat = {};
|
|
14
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
15
|
+
if (typeof value === 'string')
|
|
16
|
+
flat[key] = value;
|
|
17
|
+
else if (Array.isArray(value))
|
|
18
|
+
flat[key] = value.join(', ');
|
|
19
|
+
}
|
|
20
|
+
return flat;
|
|
21
|
+
}
|
|
22
|
+
/** Serialize a request body to string (passthrough if already string, JSON.stringify if object) */
|
|
23
|
+
function serializeBody(body) {
|
|
24
|
+
if (body === undefined || body === null)
|
|
25
|
+
return null;
|
|
26
|
+
if (typeof body === 'string')
|
|
27
|
+
return body;
|
|
28
|
+
return JSON.stringify(body);
|
|
29
|
+
}
|
|
30
|
+
/** Convert Express parsed query to Record<string, string | undefined> */
|
|
31
|
+
function extractQueryParams(query) {
|
|
32
|
+
const params = {};
|
|
33
|
+
for (const [key, value] of Object.entries(query)) {
|
|
34
|
+
if (typeof value === 'string')
|
|
35
|
+
params[key] = value;
|
|
36
|
+
else if (value !== undefined)
|
|
37
|
+
params[key] = String(value);
|
|
38
|
+
}
|
|
39
|
+
return params;
|
|
40
|
+
}
|
|
41
|
+
/** Split a URL into path and raw query string */
|
|
42
|
+
function splitUrl(originalUrl) {
|
|
43
|
+
const qIndex = originalUrl.indexOf('?');
|
|
44
|
+
if (qIndex === -1)
|
|
45
|
+
return { path: originalUrl, queryString: '' };
|
|
46
|
+
return {
|
|
47
|
+
path: originalUrl.slice(0, qIndex),
|
|
48
|
+
queryString: originalUrl.slice(qIndex + 1),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
// --- Mock Lambda context ---
|
|
52
|
+
/** Generate a local request ID */
|
|
53
|
+
function generateRequestId() {
|
|
54
|
+
return `local-${Date.now()}`;
|
|
55
|
+
}
|
|
56
|
+
/** Create a minimal mock Lambda Context */
|
|
57
|
+
function createMockLambdaContext(functionName) {
|
|
58
|
+
const name = functionName ?? 'local-handler';
|
|
59
|
+
return {
|
|
60
|
+
callbackWaitsForEmptyEventLoop: true,
|
|
61
|
+
functionName: name,
|
|
62
|
+
functionVersion: '$LATEST',
|
|
63
|
+
invokedFunctionArn: `arn:aws:lambda:us-east-1:000000000000:function:${name}`,
|
|
64
|
+
memoryLimitInMB: '128',
|
|
65
|
+
awsRequestId: generateRequestId(),
|
|
66
|
+
logGroupName: `/aws/lambda/${name}`,
|
|
67
|
+
logStreamName: 'local',
|
|
68
|
+
getRemainingTimeInMillis: () => 30_000,
|
|
69
|
+
done: () => { },
|
|
70
|
+
fail: () => { },
|
|
71
|
+
succeed: () => { },
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// --- Result -> Express response ---
|
|
75
|
+
/** Send a Lambda-style result (API Gateway V2 or ALB) back through Express */
|
|
76
|
+
function sendLambdaResult(res, result) {
|
|
77
|
+
const statusCode = result.statusCode ?? 200;
|
|
78
|
+
if (result.headers) {
|
|
79
|
+
for (const [key, value] of Object.entries(result.headers)) {
|
|
80
|
+
res.setHeader(key, value);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (result.isBase64Encoded && result.body) {
|
|
84
|
+
const buffer = Buffer.from(result.body, 'base64');
|
|
85
|
+
res.status(statusCode).send(buffer);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
res.status(statusCode).send(result.body ?? '');
|
|
89
|
+
}
|
|
90
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { LocalServer } from './local-server';
|
|
2
|
+
export type { ApiGatewayHandler, ALBHandler, LocalServerConfig } from './local-server/types';
|
|
3
|
+
export { attachSocketAdapter } from './websocket';
|
|
4
|
+
export { ConnectionRegistry } from './websocket/connection-registry';
|
|
5
|
+
export { ActionRouter } from './websocket/action-router';
|
|
6
|
+
export { LocalGatewayClient } from './websocket/local-gateway-client';
|
|
7
|
+
export type { ConnectionId, PostToConnectionFn, SocketAdapterConfig, ConnectHandlerFn, DisconnectHandlerFn, ActionHandler, ActionHandlerContext, ActionHandlerResult, LocalRequestContext, WebSocketUserContext, } from './websocket/types';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAG5F,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAA;AACrE,YAAY,EACX,YAAY,EACZ,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,GACpB,MAAM,mBAAmB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LocalGatewayClient = exports.ActionRouter = exports.ConnectionRegistry = exports.attachSocketAdapter = exports.LocalServer = void 0;
|
|
4
|
+
// Core
|
|
5
|
+
var local_server_1 = require("./local-server");
|
|
6
|
+
Object.defineProperty(exports, "LocalServer", { enumerable: true, get: function () { return local_server_1.LocalServer; } });
|
|
7
|
+
// WebSocket
|
|
8
|
+
var websocket_1 = require("./websocket");
|
|
9
|
+
Object.defineProperty(exports, "attachSocketAdapter", { enumerable: true, get: function () { return websocket_1.attachSocketAdapter; } });
|
|
10
|
+
var connection_registry_1 = require("./websocket/connection-registry");
|
|
11
|
+
Object.defineProperty(exports, "ConnectionRegistry", { enumerable: true, get: function () { return connection_registry_1.ConnectionRegistry; } });
|
|
12
|
+
var action_router_1 = require("./websocket/action-router");
|
|
13
|
+
Object.defineProperty(exports, "ActionRouter", { enumerable: true, get: function () { return action_router_1.ActionRouter; } });
|
|
14
|
+
var local_gateway_client_1 = require("./websocket/local-gateway-client");
|
|
15
|
+
Object.defineProperty(exports, "LocalGatewayClient", { enumerable: true, get: function () { return local_gateway_client_1.LocalGatewayClient; } });
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Request } from 'express';
|
|
2
|
+
import type { APIGatewayProxyEventV2, ALBEvent } from 'aws-lambda';
|
|
3
|
+
/** Synthesize an API Gateway V2 event from an Express request */
|
|
4
|
+
export declare function synthesizeApiGatewayEvent(req: Request): APIGatewayProxyEventV2;
|
|
5
|
+
/** Synthesize an ALB event from an Express request */
|
|
6
|
+
export declare function synthesizeALBEvent(req: Request): ALBEvent;
|
|
7
|
+
//# sourceMappingURL=event-synthesizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-synthesizer.d.ts","sourceRoot":"","sources":["../../src/local-server/event-synthesizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,KAAK,EAAE,sBAAsB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAUlE,iEAAiE;AACjE,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,OAAO,GAAG,sBAAsB,CAoC9E;AAED,sDAAsD;AACtD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,CAmBzD"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.synthesizeApiGatewayEvent = synthesizeApiGatewayEvent;
|
|
4
|
+
exports.synthesizeALBEvent = synthesizeALBEvent;
|
|
5
|
+
const aws_event_synthesis_1 = require("../aws-event-synthesis");
|
|
6
|
+
/** Synthesize an API Gateway V2 event from an Express request */
|
|
7
|
+
function synthesizeApiGatewayEvent(req) {
|
|
8
|
+
const headers = (0, aws_event_synthesis_1.flattenHeaders)(req.headers);
|
|
9
|
+
const body = (0, aws_event_synthesis_1.serializeBody)(req.body);
|
|
10
|
+
const queryParams = (0, aws_event_synthesis_1.extractQueryParams)(req.query);
|
|
11
|
+
const { path, queryString } = (0, aws_event_synthesis_1.splitUrl)(req.originalUrl);
|
|
12
|
+
const requestId = (0, aws_event_synthesis_1.generateRequestId)();
|
|
13
|
+
const now = Date.now();
|
|
14
|
+
return {
|
|
15
|
+
version: '2.0',
|
|
16
|
+
routeKey: `$default`,
|
|
17
|
+
rawPath: path,
|
|
18
|
+
rawQueryString: queryString,
|
|
19
|
+
headers,
|
|
20
|
+
queryStringParameters: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
21
|
+
requestContext: {
|
|
22
|
+
accountId: 'local',
|
|
23
|
+
apiId: 'local',
|
|
24
|
+
domainName: req.hostname ?? 'localhost',
|
|
25
|
+
domainPrefix: 'local',
|
|
26
|
+
http: {
|
|
27
|
+
method: req.method,
|
|
28
|
+
path,
|
|
29
|
+
protocol: req.protocol ?? 'HTTP/1.1',
|
|
30
|
+
sourceIp: req.ip ?? '127.0.0.1',
|
|
31
|
+
userAgent: req.headers['user-agent'] ?? '',
|
|
32
|
+
},
|
|
33
|
+
requestId,
|
|
34
|
+
routeKey: '$default',
|
|
35
|
+
stage: 'local',
|
|
36
|
+
time: new Date(now).toISOString(),
|
|
37
|
+
timeEpoch: now,
|
|
38
|
+
},
|
|
39
|
+
body: body ?? undefined,
|
|
40
|
+
isBase64Encoded: false,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** Synthesize an ALB event from an Express request */
|
|
44
|
+
function synthesizeALBEvent(req) {
|
|
45
|
+
const headers = (0, aws_event_synthesis_1.flattenHeaders)(req.headers);
|
|
46
|
+
const body = (0, aws_event_synthesis_1.serializeBody)(req.body);
|
|
47
|
+
const queryParams = (0, aws_event_synthesis_1.extractQueryParams)(req.query);
|
|
48
|
+
const { path } = (0, aws_event_synthesis_1.splitUrl)(req.originalUrl);
|
|
49
|
+
return {
|
|
50
|
+
requestContext: {
|
|
51
|
+
elb: {
|
|
52
|
+
targetGroupArn: 'arn:aws:elasticloadbalancing:us-east-1:000000000000:targetgroup/local/local',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
httpMethod: req.method,
|
|
56
|
+
path,
|
|
57
|
+
headers,
|
|
58
|
+
queryStringParameters: queryParams,
|
|
59
|
+
body: body ?? '',
|
|
60
|
+
isBase64Encoded: false,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import type { attachSocketAdapter } from '../websocket';
|
|
3
|
+
import type { SocketAdapterConfig } from '../websocket/types';
|
|
4
|
+
import type { ApiGatewayHandler, ALBHandler, LambdaOptionsApiGateway, LambdaOptionsALB, LocalServerConfig } from './types';
|
|
5
|
+
export type { ApiGatewayHandler, ALBHandler, LocalServerConfig } from './types';
|
|
6
|
+
export declare class LocalServer {
|
|
7
|
+
readonly app: express.Express;
|
|
8
|
+
private httpServer;
|
|
9
|
+
private config;
|
|
10
|
+
constructor(config?: LocalServerConfig);
|
|
11
|
+
lambda(path: string, handler: ApiGatewayHandler): this;
|
|
12
|
+
lambda(path: string, handler: ApiGatewayHandler, options: LambdaOptionsApiGateway): this;
|
|
13
|
+
lambda(path: string, handler: ALBHandler, options: LambdaOptionsALB): this;
|
|
14
|
+
attachSocket(adapterFn: typeof attachSocketAdapter, config?: SocketAdapterConfig): ReturnType<typeof attachSocketAdapter>;
|
|
15
|
+
listen(port: number, hostname?: string): void;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/local-server/index.ts"],"names":[],"mappings":"AAEA,OAAO,OAAO,MAAM,SAAS,CAAA;AAO7B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAC7D,OAAO,KAAK,EACX,iBAAiB,EACjB,UAAU,EACV,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,EACjB,MAAM,SAAS,CAAA;AAEhB,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAE/E,qBAAa,WAAW;IACvB,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,CAAA;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,MAAM,CAAmB;gBAErB,MAAM,CAAC,EAAE,iBAAiB;IAgBtC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI;IACtD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,uBAAuB,GAAG,IAAI;IACxF,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAgC1E,YAAY,CACX,SAAS,EAAE,OAAO,mBAAmB,EACrC,MAAM,CAAC,EAAE,mBAAmB,GAC1B,UAAU,CAAC,OAAO,mBAAmB,CAAC;IAKzC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;CAS7C"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LocalServer = void 0;
|
|
7
|
+
const node_http_1 = __importDefault(require("node:http"));
|
|
8
|
+
const express_1 = __importDefault(require("express"));
|
|
9
|
+
const cors_1 = __importDefault(require("cors"));
|
|
10
|
+
const ws_1 = require("ws");
|
|
11
|
+
const aws_event_synthesis_1 = require("../aws-event-synthesis");
|
|
12
|
+
const event_synthesizer_1 = require("./event-synthesizer");
|
|
13
|
+
class LocalServer {
|
|
14
|
+
app;
|
|
15
|
+
httpServer;
|
|
16
|
+
config;
|
|
17
|
+
constructor(config) {
|
|
18
|
+
this.config = config ?? {};
|
|
19
|
+
this.app = (0, express_1.default)();
|
|
20
|
+
this.app.use(express_1.default.json());
|
|
21
|
+
this.app.use((0, cors_1.default)());
|
|
22
|
+
this.app.get('/', (_req, res) => {
|
|
23
|
+
res.send('Hello from Express HTTP Server');
|
|
24
|
+
});
|
|
25
|
+
this.httpServer = node_http_1.default.createServer(this.app);
|
|
26
|
+
}
|
|
27
|
+
lambda(path, handler, options) {
|
|
28
|
+
const eventType = options?.eventType ?? 'api-gateway';
|
|
29
|
+
this.app.use(path, async (req, res) => {
|
|
30
|
+
try {
|
|
31
|
+
const context = (0, aws_event_synthesis_1.createMockLambdaContext)();
|
|
32
|
+
if (eventType === 'alb') {
|
|
33
|
+
const event = (0, event_synthesizer_1.synthesizeALBEvent)(req);
|
|
34
|
+
const result = await handler(event, context);
|
|
35
|
+
(0, aws_event_synthesis_1.sendLambdaResult)(res, result);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
const event = (0, event_synthesizer_1.synthesizeApiGatewayEvent)(req);
|
|
39
|
+
const result = await handler(event, context);
|
|
40
|
+
(0, aws_event_synthesis_1.sendLambdaResult)(res, result ?? {});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
console.error(`[LocalServer] Error handling ${req.method} ${req.originalUrl}:`, err);
|
|
45
|
+
if (!res.headersSent) {
|
|
46
|
+
res.status(500).json({ error: 'Internal Server Error' });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
attachSocket(adapterFn, config) {
|
|
53
|
+
const wss = new ws_1.WebSocketServer({ server: this.httpServer });
|
|
54
|
+
return adapterFn(wss, config);
|
|
55
|
+
}
|
|
56
|
+
listen(port, hostname) {
|
|
57
|
+
const host = hostname ?? '0.0.0.0';
|
|
58
|
+
this.httpServer.listen(port, host, () => {
|
|
59
|
+
if (this.config.debug) {
|
|
60
|
+
console.info(`HTTP Server running at http://localhost:${port}`);
|
|
61
|
+
console.info(`WebSocket server running on ws://localhost:${port}`);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.LocalServer = LocalServer;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Context } from 'aws-lambda';
|
|
2
|
+
import type { APIGatewayProxyEventV2, APIGatewayProxyStructuredResultV2, ALBEvent, ALBResult } from 'aws-lambda';
|
|
3
|
+
export type ApiGatewayHandler = (event: APIGatewayProxyEventV2, context: Context) => Promise<APIGatewayProxyStructuredResultV2>;
|
|
4
|
+
export type ALBHandler = (event: ALBEvent, context: Context) => Promise<ALBResult>;
|
|
5
|
+
export interface LambdaOptionsApiGateway {
|
|
6
|
+
eventType?: 'api-gateway';
|
|
7
|
+
}
|
|
8
|
+
export interface LambdaOptionsALB {
|
|
9
|
+
eventType: 'alb';
|
|
10
|
+
}
|
|
11
|
+
export interface LocalServerConfig {
|
|
12
|
+
debug?: boolean;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/local-server/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACzC,OAAO,KAAK,EACX,sBAAsB,EACtB,iCAAiC,EACjC,QAAQ,EACR,SAAS,EACT,MAAM,YAAY,CAAA;AAInB,MAAM,MAAM,iBAAiB,GAAG,CAC/B,KAAK,EAAE,sBAAsB,EAC7B,OAAO,EAAE,OAAO,KACZ,OAAO,CAAC,iCAAiC,CAAC,CAAA;AAE/C,MAAM,MAAM,UAAU,GAAG,CACxB,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,OAAO,KACZ,OAAO,CAAC,SAAS,CAAC,CAAA;AAIvB,MAAM,WAAW,uBAAuB;IACvC,SAAS,CAAC,EAAE,aAAa,CAAA;CACzB;AAED,MAAM,WAAW,gBAAgB;IAChC,SAAS,EAAE,KAAK,CAAA;CAChB;AAID,MAAM,WAAW,iBAAiB;IACjC,KAAK,CAAC,EAAE,OAAO,CAAA;CACf"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ActionHandler, ActionHandlerResult, ConnectionId, LocalRequestContext, PostToConnectionFn } from './types';
|
|
2
|
+
import type { WebSocketUserContext } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Routes incoming WebSocket messages by `action` field — mirrors
|
|
5
|
+
* API Gateway's `$request.body.action` route selection.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ActionRouter {
|
|
8
|
+
private routes;
|
|
9
|
+
private defaultHandler;
|
|
10
|
+
/** Register a handler for a specific action (equivalent to webSocketApi.addRoute()) */
|
|
11
|
+
addRoute(action: string, handler: ActionHandler): void;
|
|
12
|
+
/** Set the $default handler for unknown actions */
|
|
13
|
+
setDefaultHandler(handler: ActionHandler): void;
|
|
14
|
+
/** Parse incoming message JSON, extract `action`, and dispatch to the matching handler */
|
|
15
|
+
route(connectionId: ConnectionId, rawBody: string, postToConnection: PostToConnectionFn, requestContext: LocalRequestContext, userContext: WebSocketUserContext): Promise<ActionHandlerResult>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=action-router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-router.d.ts","sourceRoot":"","sources":["../../src/websocket/action-router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,aAAa,EAEb,mBAAmB,EACnB,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,MAAM,SAAS,CAAA;AAChB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAEnD;;;GAGG;AACH,qBAAa,YAAY;IACxB,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,cAAc,CAA6B;IAEnD,uFAAuF;IACvF,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI;IAItD,mDAAmD;IACnD,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAI/C,0FAA0F;IACpF,KAAK,CACV,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,kBAAkB,EACpC,cAAc,EAAE,mBAAmB,EACnC,WAAW,EAAE,oBAAoB,GAC/B,OAAO,CAAC,mBAAmB,CAAC;CA8B/B"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ActionRouter = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Routes incoming WebSocket messages by `action` field — mirrors
|
|
6
|
+
* API Gateway's `$request.body.action` route selection.
|
|
7
|
+
*/
|
|
8
|
+
class ActionRouter {
|
|
9
|
+
routes = new Map();
|
|
10
|
+
defaultHandler = null;
|
|
11
|
+
/** Register a handler for a specific action (equivalent to webSocketApi.addRoute()) */
|
|
12
|
+
addRoute(action, handler) {
|
|
13
|
+
this.routes.set(action, handler);
|
|
14
|
+
}
|
|
15
|
+
/** Set the $default handler for unknown actions */
|
|
16
|
+
setDefaultHandler(handler) {
|
|
17
|
+
this.defaultHandler = handler;
|
|
18
|
+
}
|
|
19
|
+
/** Parse incoming message JSON, extract `action`, and dispatch to the matching handler */
|
|
20
|
+
async route(connectionId, rawBody, postToConnection, requestContext, userContext) {
|
|
21
|
+
let parsed;
|
|
22
|
+
try {
|
|
23
|
+
parsed = JSON.parse(rawBody);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return { statusCode: 400, body: JSON.stringify({ error: 'Invalid JSON' }) };
|
|
27
|
+
}
|
|
28
|
+
const action = parsed.action;
|
|
29
|
+
if (!action || typeof action !== 'string') {
|
|
30
|
+
return { statusCode: 400, body: JSON.stringify({ error: 'Missing "action" field' }) };
|
|
31
|
+
}
|
|
32
|
+
const handler = this.routes.get(action) ?? this.defaultHandler;
|
|
33
|
+
if (!handler) {
|
|
34
|
+
return {
|
|
35
|
+
statusCode: 400,
|
|
36
|
+
body: JSON.stringify({ error: `Unknown action: ${action}` }),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const ctx = {
|
|
40
|
+
connectionId,
|
|
41
|
+
requestContext: { ...requestContext, routeKey: action },
|
|
42
|
+
postToConnection,
|
|
43
|
+
userContext,
|
|
44
|
+
};
|
|
45
|
+
return handler(rawBody, ctx);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.ActionRouter = ActionRouter;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { WebSocket } from 'ws';
|
|
2
|
+
import type { ConnectionId } from './types';
|
|
3
|
+
import type { WebSocketUserContext } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* In-memory connection registry — replaces API Gateway's built-in connection management.
|
|
6
|
+
* Maps connectionId → WebSocket instance and connectionId → user context.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ConnectionRegistry {
|
|
9
|
+
private connections;
|
|
10
|
+
private userContexts;
|
|
11
|
+
/** Register a WebSocket and return its assigned connectionId */
|
|
12
|
+
register(ws: WebSocket): ConnectionId;
|
|
13
|
+
/** Remove a connection by ID */
|
|
14
|
+
unregister(connectionId: ConnectionId): void;
|
|
15
|
+
/** Look up a WebSocket by connectionId */
|
|
16
|
+
get(connectionId: ConnectionId): WebSocket | undefined;
|
|
17
|
+
/** Return all active connectionIds */
|
|
18
|
+
getAll(): ConnectionId[];
|
|
19
|
+
/** Store user context for a connection */
|
|
20
|
+
setUserContext(connectionId: ConnectionId, ctx: WebSocketUserContext): void;
|
|
21
|
+
/** Retrieve user context for a connection */
|
|
22
|
+
getUserContext(connectionId: ConnectionId): WebSocketUserContext | undefined;
|
|
23
|
+
/** Find all connectionIds belonging to a specific user */
|
|
24
|
+
getConnectionsByUserId(userId: string): ConnectionId[];
|
|
25
|
+
/** Find all connectionIds belonging to a specific organization */
|
|
26
|
+
getConnectionsByOrgId(orgId: string): ConnectionId[];
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=connection-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-registry.d.ts","sourceRoot":"","sources":["../../src/websocket/connection-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAA;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAC3C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAMnD;;;GAGG;AACH,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,WAAW,CAAqC;IACxD,OAAO,CAAC,YAAY,CAAgD;IAEpE,gEAAgE;IAChE,QAAQ,CAAC,EAAE,EAAE,SAAS,GAAG,YAAY;IAMrC,gCAAgC;IAChC,UAAU,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI;IAK5C,0CAA0C;IAC1C,GAAG,CAAC,YAAY,EAAE,YAAY,GAAG,SAAS,GAAG,SAAS;IAItD,sCAAsC;IACtC,MAAM,IAAI,YAAY,EAAE;IAIxB,0CAA0C;IAC1C,cAAc,CAAC,YAAY,EAAE,YAAY,EAAE,GAAG,EAAE,oBAAoB,GAAG,IAAI;IAI3E,6CAA6C;IAC7C,cAAc,CAAC,YAAY,EAAE,YAAY,GAAG,oBAAoB,GAAG,SAAS;IAI5E,0DAA0D;IAC1D,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE;IAQtD,kEAAkE;IAClE,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE;CAOpD"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConnectionRegistry = void 0;
|
|
4
|
+
/** Generates a unique connection ID (same pattern as socket-real.ts) */
|
|
5
|
+
const makeConnectionId = () => `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
6
|
+
/**
|
|
7
|
+
* In-memory connection registry — replaces API Gateway's built-in connection management.
|
|
8
|
+
* Maps connectionId → WebSocket instance and connectionId → user context.
|
|
9
|
+
*/
|
|
10
|
+
class ConnectionRegistry {
|
|
11
|
+
connections = new Map();
|
|
12
|
+
userContexts = new Map();
|
|
13
|
+
/** Register a WebSocket and return its assigned connectionId */
|
|
14
|
+
register(ws) {
|
|
15
|
+
const connectionId = makeConnectionId();
|
|
16
|
+
this.connections.set(connectionId, ws);
|
|
17
|
+
return connectionId;
|
|
18
|
+
}
|
|
19
|
+
/** Remove a connection by ID */
|
|
20
|
+
unregister(connectionId) {
|
|
21
|
+
this.connections.delete(connectionId);
|
|
22
|
+
this.userContexts.delete(connectionId);
|
|
23
|
+
}
|
|
24
|
+
/** Look up a WebSocket by connectionId */
|
|
25
|
+
get(connectionId) {
|
|
26
|
+
return this.connections.get(connectionId);
|
|
27
|
+
}
|
|
28
|
+
/** Return all active connectionIds */
|
|
29
|
+
getAll() {
|
|
30
|
+
return Array.from(this.connections.keys());
|
|
31
|
+
}
|
|
32
|
+
/** Store user context for a connection */
|
|
33
|
+
setUserContext(connectionId, ctx) {
|
|
34
|
+
this.userContexts.set(connectionId, ctx);
|
|
35
|
+
}
|
|
36
|
+
/** Retrieve user context for a connection */
|
|
37
|
+
getUserContext(connectionId) {
|
|
38
|
+
return this.userContexts.get(connectionId);
|
|
39
|
+
}
|
|
40
|
+
/** Find all connectionIds belonging to a specific user */
|
|
41
|
+
getConnectionsByUserId(userId) {
|
|
42
|
+
const result = [];
|
|
43
|
+
for (const [connId, ctx] of this.userContexts) {
|
|
44
|
+
if (ctx.userId === userId)
|
|
45
|
+
result.push(connId);
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
/** Find all connectionIds belonging to a specific organization */
|
|
50
|
+
getConnectionsByOrgId(orgId) {
|
|
51
|
+
const result = [];
|
|
52
|
+
for (const [connId, ctx] of this.userContexts) {
|
|
53
|
+
if (ctx.organizationId === orgId)
|
|
54
|
+
result.push(connId);
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.ConnectionRegistry = ConnectionRegistry;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { APIGatewayProxyEvent } from 'aws-lambda';
|
|
2
|
+
import type http from 'node:http';
|
|
3
|
+
import type { ConnectionId, LocalRequestContext } from './types';
|
|
4
|
+
/** Synthesize a $connect event */
|
|
5
|
+
export declare function synthesizeConnectEvent(connectionId: ConnectionId, req: http.IncomingMessage, config?: {
|
|
6
|
+
domainName?: string;
|
|
7
|
+
stage?: string;
|
|
8
|
+
}): APIGatewayProxyEvent;
|
|
9
|
+
/** Synthesize a $disconnect event */
|
|
10
|
+
export declare function synthesizeDisconnectEvent(connectionId: ConnectionId, config?: {
|
|
11
|
+
domainName?: string;
|
|
12
|
+
stage?: string;
|
|
13
|
+
}): APIGatewayProxyEvent;
|
|
14
|
+
/** Synthesize a message event with body and routeKey */
|
|
15
|
+
export declare function synthesizeMessageEvent(connectionId: ConnectionId, body: string, routeKey: string, config?: {
|
|
16
|
+
domainName?: string;
|
|
17
|
+
stage?: string;
|
|
18
|
+
}): APIGatewayProxyEvent;
|
|
19
|
+
/** Build a LocalRequestContext from parameters */
|
|
20
|
+
export declare function buildRequestContext(connectionId: ConnectionId, routeKey: string, eventType: LocalRequestContext['eventType'], config?: {
|
|
21
|
+
domainName?: string;
|
|
22
|
+
stage?: string;
|
|
23
|
+
}): LocalRequestContext;
|
|
24
|
+
//# sourceMappingURL=event-synthesizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-synthesizer.d.ts","sourceRoot":"","sources":["../../src/websocket/event-synthesizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AACtD,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAyDhE,kCAAkC;AAClC,wBAAgB,sBAAsB,CACrC,YAAY,EAAE,YAAY,EAC1B,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,MAAM,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C,oBAAoB,CAiBtB;AAED,qCAAqC;AACrC,wBAAgB,yBAAyB,CACxC,YAAY,EAAE,YAAY,EAC1B,MAAM,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C,oBAAoB,CAQtB;AAED,wDAAwD;AACxD,wBAAgB,sBAAsB,CACrC,YAAY,EAAE,YAAY,EAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C,oBAAoB,CAWtB;AAED,kDAAkD;AAClD,wBAAgB,mBAAmB,CAClC,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,mBAAmB,CAAC,WAAW,CAAC,EAC3C,MAAM,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C,mBAAmB,CAQrB"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.synthesizeConnectEvent = synthesizeConnectEvent;
|
|
4
|
+
exports.synthesizeDisconnectEvent = synthesizeDisconnectEvent;
|
|
5
|
+
exports.synthesizeMessageEvent = synthesizeMessageEvent;
|
|
6
|
+
exports.buildRequestContext = buildRequestContext;
|
|
7
|
+
const EMPTY_MULTI_VALUE = {};
|
|
8
|
+
const EMPTY_HEADERS = {};
|
|
9
|
+
/** Creates a minimal APIGatewayProxyEvent shell with the given requestContext fields */
|
|
10
|
+
function baseEvent(requestContext, overrides) {
|
|
11
|
+
return {
|
|
12
|
+
body: null,
|
|
13
|
+
headers: EMPTY_HEADERS,
|
|
14
|
+
multiValueHeaders: EMPTY_MULTI_VALUE,
|
|
15
|
+
httpMethod: 'GET',
|
|
16
|
+
isBase64Encoded: false,
|
|
17
|
+
path: '',
|
|
18
|
+
pathParameters: null,
|
|
19
|
+
queryStringParameters: null,
|
|
20
|
+
multiValueQueryStringParameters: null,
|
|
21
|
+
stageVariables: null,
|
|
22
|
+
resource: '',
|
|
23
|
+
requestContext: {
|
|
24
|
+
accountId: 'local',
|
|
25
|
+
apiId: 'local',
|
|
26
|
+
authorizer: null,
|
|
27
|
+
protocol: 'websocket',
|
|
28
|
+
httpMethod: 'GET',
|
|
29
|
+
identity: {
|
|
30
|
+
accessKey: null,
|
|
31
|
+
accountId: null,
|
|
32
|
+
apiKey: null,
|
|
33
|
+
apiKeyId: null,
|
|
34
|
+
caller: null,
|
|
35
|
+
clientCert: null,
|
|
36
|
+
cognitoAuthenticationProvider: null,
|
|
37
|
+
cognitoAuthenticationType: null,
|
|
38
|
+
cognitoIdentityId: null,
|
|
39
|
+
cognitoIdentityPoolId: null,
|
|
40
|
+
principalOrgId: null,
|
|
41
|
+
sourceIp: '127.0.0.1',
|
|
42
|
+
user: null,
|
|
43
|
+
userAgent: null,
|
|
44
|
+
userArn: null,
|
|
45
|
+
},
|
|
46
|
+
path: '',
|
|
47
|
+
stage: 'local',
|
|
48
|
+
requestId: `local-${Date.now()}`,
|
|
49
|
+
requestTimeEpoch: Date.now(),
|
|
50
|
+
resourceId: '',
|
|
51
|
+
resourcePath: '',
|
|
52
|
+
...requestContext,
|
|
53
|
+
},
|
|
54
|
+
...overrides,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** Synthesize a $connect event */
|
|
58
|
+
function synthesizeConnectEvent(connectionId, req, config) {
|
|
59
|
+
const headers = {};
|
|
60
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
61
|
+
if (typeof value === 'string')
|
|
62
|
+
headers[key] = value;
|
|
63
|
+
else if (Array.isArray(value))
|
|
64
|
+
headers[key] = value.join(', ');
|
|
65
|
+
}
|
|
66
|
+
return baseEvent({
|
|
67
|
+
connectionId,
|
|
68
|
+
domainName: config?.domainName ?? 'localhost',
|
|
69
|
+
stage: config?.stage ?? 'local',
|
|
70
|
+
routeKey: '$connect',
|
|
71
|
+
eventType: 'CONNECT',
|
|
72
|
+
}, { headers });
|
|
73
|
+
}
|
|
74
|
+
/** Synthesize a $disconnect event */
|
|
75
|
+
function synthesizeDisconnectEvent(connectionId, config) {
|
|
76
|
+
return baseEvent({
|
|
77
|
+
connectionId,
|
|
78
|
+
domainName: config?.domainName ?? 'localhost',
|
|
79
|
+
stage: config?.stage ?? 'local',
|
|
80
|
+
routeKey: '$disconnect',
|
|
81
|
+
eventType: 'DISCONNECT',
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/** Synthesize a message event with body and routeKey */
|
|
85
|
+
function synthesizeMessageEvent(connectionId, body, routeKey, config) {
|
|
86
|
+
return baseEvent({
|
|
87
|
+
connectionId,
|
|
88
|
+
domainName: config?.domainName ?? 'localhost',
|
|
89
|
+
stage: config?.stage ?? 'local',
|
|
90
|
+
routeKey,
|
|
91
|
+
eventType: 'MESSAGE',
|
|
92
|
+
}, { body });
|
|
93
|
+
}
|
|
94
|
+
/** Build a LocalRequestContext from parameters */
|
|
95
|
+
function buildRequestContext(connectionId, routeKey, eventType, config) {
|
|
96
|
+
return {
|
|
97
|
+
connectionId,
|
|
98
|
+
domainName: config?.domainName ?? 'localhost',
|
|
99
|
+
stage: config?.stage ?? 'local',
|
|
100
|
+
routeKey,
|
|
101
|
+
eventType,
|
|
102
|
+
};
|
|
103
|
+
}
|