serverless-spy 0.0.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/.eslintrc.yml +97 -0
- package/.gitattributes +24 -0
- package/.husky/pre-commit +4 -0
- package/.jsii +3199 -0
- package/.prettierignore +1 -0
- package/.prettierrc.json +5 -0
- package/API.md +123 -0
- package/LICENSE +202 -0
- package/README.md +1 -0
- package/cli/cli.ts +97 -0
- package/cli/index.html +43 -0
- package/cli/package-lock.json +2356 -0
- package/cli/package.json +14 -0
- package/cli/serverlessSpy.js +73 -0
- package/cli/spy_log.json +0 -0
- package/cli/style.css +43 -0
- package/cli/ws.ts +79 -0
- package/common/getWebSocketUrl.ts +68 -0
- package/common/package.json +22 -0
- package/common/spyEvents/DynamoDBSpyEvent.ts +12 -0
- package/common/spyEvents/EventBridgeRuleSpyEvent.ts +13 -0
- package/common/spyEvents/EventBridgeSpyEvent.ts +13 -0
- package/common/spyEvents/FunctionConsoleSpyEvent.ts +11 -0
- package/common/spyEvents/FunctionContext.ts +8 -0
- package/common/spyEvents/FunctionErrorSpyEvent.ts +9 -0
- package/common/spyEvents/FunctionRequestSpyEvent.ts +8 -0
- package/common/spyEvents/FunctionResponseSpyEvent.ts +10 -0
- package/common/spyEvents/S3SpyEvent.ts +9 -0
- package/common/spyEvents/SnsSubscriptionSpyEvent.ts +12 -0
- package/common/spyEvents/SnsTopicSpyEvent.ts +12 -0
- package/common/spyEvents/SpyEvent.ts +3 -0
- package/common/spyEvents/SpyMessage.ts +7 -0
- package/common/spyEvents/SqsSpyEvent.ts +8 -0
- package/functions/onConnect.ts +29 -0
- package/functions/onDisconnect.ts +28 -0
- package/functions/sendMessage.ts +277 -0
- package/functions/tsconfig.dev.json +16 -0
- package/functions/tsconfig.json +16 -0
- package/index.ts +2 -0
- package/lambda-extension/aws/Common.ts +88 -0
- package/lambda-extension/aws/Errors.ts +140 -0
- package/lambda-extension/aws/UserFunction.ts +169 -0
- package/lambda-extension/interceptor.ts +146 -0
- package/lambda-extension/spy-wrapper +4 -0
- package/lambda-extension/tsconfig.json +16 -0
- package/lib/ServerlessSpy.d.ts +27 -0
- package/lib/ServerlessSpy.js +301 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +14 -0
- package/listener/PrettifyForDisplay.ts +5 -0
- package/listener/RecursivePartial.ts +9 -0
- package/listener/SpyHandlers.ts.ts +190 -0
- package/listener/SpyListener.ts +104 -0
- package/listener/createServerlessSpyListener.ts +258 -0
- package/listener/index.ts +1 -0
- package/listener/matchers.ts +53 -0
- package/listener/package.json +19 -0
- package/listener/setup.ts +21 -0
- package/listener/tsconfig.dev.json +16 -0
- package/listener/tsconfig.json +16 -0
- package/package.json +132 -0
- package/scripts/run-task +1836 -0
- package/sst-esbuild/esbuild.js +57 -0
- package/x_jest.config.ts +203 -0
package/cli/package.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "serverless-spy-cli",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"scripts": {},
|
|
6
|
+
"author": "",
|
|
7
|
+
"license": "ISC",
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"@aws-sdk/client-sts": "^3.142.0",
|
|
10
|
+
"@aws-sdk/credential-providers": "^3.142.0",
|
|
11
|
+
"esbuild-runner": "^2.2.1",
|
|
12
|
+
"ws": "^8.8.1"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
function run() {
|
|
2
|
+
const tableBody = document.getElementById("tableBody");
|
|
3
|
+
var modal = document.getElementById("myModal");
|
|
4
|
+
var span = document.getElementsByClassName("close")[0];
|
|
5
|
+
const modalContent = document.getElementById("modalContent");
|
|
6
|
+
span.onclick = function () {
|
|
7
|
+
modal.style.display = "none";
|
|
8
|
+
};
|
|
9
|
+
window.onclick = function (event) {
|
|
10
|
+
if (event.target == modal) {
|
|
11
|
+
modal.style.display = "none";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
tableBody.addEventListener("click", function (e) {
|
|
16
|
+
const dataJson = JSON.stringify(
|
|
17
|
+
JSON.parse(e.target.parentElement.children[2].textContent),
|
|
18
|
+
null,
|
|
19
|
+
2
|
|
20
|
+
);
|
|
21
|
+
modalContent.innerText = dataJson;
|
|
22
|
+
modal.style.display = "block";
|
|
23
|
+
//alert();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const url = "SERVERLESS_SPY_WS_URL";
|
|
27
|
+
//"wss://m6g3w6ttdh.execute-api.eu-west-1.amazonaws.com/prod?X-Amz-Security-Token=IQoJb3JpZ2luX2VjELL%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCWV1LXdlc3QtMSJGMEQCIDk%2BzQd0RC2DmEgCJEPoRFAkmnhCZl%2BSIlEG4TummRkIAiBIgNG8Yw%2FOAew3XNAE3yrNCK0G0q%2BZI8MwjEa8xoEonirrAQgbEAQaDDA3NjU4NTk2NzA3NSIMxVUxKhwdqGjFOsRtKsgB2eotQMFgl4CrD8uy%2Fe1UE6K4HVc6uWo0gdjgHMPb5C9Mq0wFgHTiDFjFxIFkJpmCiTRXKqNFrx5lpo9C5Ml1bpcv%2BTopT6wvpbFksxChhhnaqUDHiBaGuys8zEy8Bjlu4jF0nKccmUYdieD70%2FXz99OU4wKPxXyWbr0w82y1Xd6ag8g4VNx3EXEdULq7vkM6H2shSAH8EUlZoTD%2BqvIQvyKS8nta3ebhprO%2BsLRQv2YC6k1w46jHuOjtI7hSnmfSKnkUqAxS6g4wgZrFlwY6mQFNSXz7jSF3IRtdcpMEIp%2Bnghf2LhvZKeW6GkZs4DMeuhPjoBehfmXLJIJWgcvLoheQvIt28ddgHU60%2BoRKhZTxQKhpvSOaAbI6M%2B%2FyHvkC2hTR4fEBtESAMnzo8WocfxdaQQ0YVYq2m5NKSXs3QrrsYIIirkFYhB%2BjAwG8bqBAuE9SQNeIthHjT27hB7KUeIIoXtwSVGutv70%3D&X-Amz-Date=20220808T175057Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIARDVHBDXR4QCRLL4O%2F20220808%2Feu-west-1%2Fexecute-api%2Faws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=d58ab2b792a69f20f8e3bf9bf4fb19c8ec8f271bd1b594f8cd25c02d4c85521d";
|
|
28
|
+
const ws = new WebSocket(url);
|
|
29
|
+
|
|
30
|
+
ws.addEventListener("open", function (event) {
|
|
31
|
+
console.log("connected " + new Date().toISOString());
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
ws.addEventListener("message", function ({ data }) {
|
|
35
|
+
//debugger;
|
|
36
|
+
//console.log(`From server: ${data}`);
|
|
37
|
+
|
|
38
|
+
let parsed;
|
|
39
|
+
try {
|
|
40
|
+
parsed = JSON.parse(data);
|
|
41
|
+
} catch (err) {
|
|
42
|
+
console.error("Can not parse " + data);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
addLog(parsed);
|
|
46
|
+
|
|
47
|
+
// if (parsed) {
|
|
48
|
+
// console.log(
|
|
49
|
+
// `\x1b[47m\x1b[34m${parsed.timestamp} \x1b[31m🍕 ${
|
|
50
|
+
// parsed.serviceKey
|
|
51
|
+
// }\x1b[0m\x1b[32m\n${JSON.stringify(parsed.data, null, 2)}\x1b[0m`
|
|
52
|
+
// );
|
|
53
|
+
// }
|
|
54
|
+
});
|
|
55
|
+
ws.addEventListener("close", function () {
|
|
56
|
+
console.log("disconnected " + new Date().toISOString());
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
function addLog(data) {
|
|
60
|
+
const newRow = document.createElement("tr");
|
|
61
|
+
newRow.innerHTML = `
|
|
62
|
+
<td>${new Date(data.timestamp).toLocaleTimeString()}</td>
|
|
63
|
+
<td>${data.serviceKey}</td>
|
|
64
|
+
<td>${JSON.stringify(data.data)}</td>
|
|
65
|
+
`;
|
|
66
|
+
tableBody.append(newRow);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
71
|
+
console.log("RUN");
|
|
72
|
+
run();
|
|
73
|
+
});
|
package/cli/spy_log.json
ADDED
|
File without changes
|
package/cli/style.css
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
.log {
|
|
2
|
+
white-space: nowrap
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
/* The Modal (background)
|
|
6
|
+
https://www.w3schools.com/howto/howto_css_modals.asp
|
|
7
|
+
*/
|
|
8
|
+
.modal {
|
|
9
|
+
display: none; /* Hidden by default */
|
|
10
|
+
position: fixed; /* Stay in place */
|
|
11
|
+
z-index: 1; /* Sit on top */
|
|
12
|
+
left: 0;
|
|
13
|
+
top: 0;
|
|
14
|
+
width: 100%; /* Full width */
|
|
15
|
+
height: 100%; /* Full height */
|
|
16
|
+
overflow: auto; /* Enable scroll if needed */
|
|
17
|
+
background-color: rgb(0,0,0); /* Fallback color */
|
|
18
|
+
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* Modal Content/Box */
|
|
22
|
+
.modal-content {
|
|
23
|
+
background-color: #fefefe;
|
|
24
|
+
margin: 15% auto; /* 15% from the top and centered */
|
|
25
|
+
padding: 20px;
|
|
26
|
+
border: 1px solid #888;
|
|
27
|
+
width: 80%; /* Could be more or less, depending on screen size */
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* The Close Button */
|
|
31
|
+
.close {
|
|
32
|
+
color: #aaa;
|
|
33
|
+
float: right;
|
|
34
|
+
font-size: 28px;
|
|
35
|
+
font-weight: bold;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.close:hover,
|
|
39
|
+
.close:focus {
|
|
40
|
+
color: black;
|
|
41
|
+
text-decoration: none;
|
|
42
|
+
cursor: pointer;
|
|
43
|
+
}
|
package/cli/ws.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as readline from 'readline';
|
|
3
|
+
import WebSocket from 'ws';
|
|
4
|
+
import { getWebSocketUrl } from '../common/getWebSocketUrl';
|
|
5
|
+
|
|
6
|
+
async function run() {
|
|
7
|
+
// var credentialsProvider = awsCp.fromTemporaryCredentials();
|
|
8
|
+
// const credentials = await credentialsProvider();
|
|
9
|
+
|
|
10
|
+
// const client = new STSClient({});
|
|
11
|
+
// client.send()
|
|
12
|
+
|
|
13
|
+
// const command = new GetSessionTokenCommand({});
|
|
14
|
+
// const { Credentials: credentials } = await client.send(command);
|
|
15
|
+
// //const credentials = s.Credentials;
|
|
16
|
+
|
|
17
|
+
// console.log("credentials", credentials);
|
|
18
|
+
|
|
19
|
+
// const url = process.argv[2];
|
|
20
|
+
const url = 'wss://preh1xo1xh.execute-api.eu-west-1.amazonaws.com/prod';
|
|
21
|
+
|
|
22
|
+
// https://medium.com/@o.bredenberg/iam-sign-your-api-gateway-websocket-connection-request-no-custom-auth-from-your-frontend-65451166757d
|
|
23
|
+
const url2 = await getWebSocketUrl(url);
|
|
24
|
+
|
|
25
|
+
const ws = new WebSocket(url2);
|
|
26
|
+
|
|
27
|
+
const fileDescriptor = fs.openSync('spy_log.json', 'w');
|
|
28
|
+
// 📢📁⚡️💾 💽 💾 💿 📀🛢🪣📑🔊
|
|
29
|
+
|
|
30
|
+
ws.on('open', () => console.log(`connected ${new Date().toISOString()}`));
|
|
31
|
+
ws.on('message', (data: any) => {
|
|
32
|
+
// console.log(`From server: ${data}`);
|
|
33
|
+
|
|
34
|
+
let parsed;
|
|
35
|
+
try {
|
|
36
|
+
parsed = JSON.parse(data);
|
|
37
|
+
} catch (err) {
|
|
38
|
+
console.error(`Can not parse ${data}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (parsed) {
|
|
42
|
+
console.log(
|
|
43
|
+
`\x1b[47m\x1b[34m${parsed.timestamp} \x1b[31m🍕 ${
|
|
44
|
+
parsed.serviceKey
|
|
45
|
+
}\x1b[0m\x1b[32m\n${JSON.stringify(parsed.data, null, 2)}\x1b[0m`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
fs.write(fileDescriptor, data, (error) => {
|
|
50
|
+
if (!error) {
|
|
51
|
+
// fs.close(fileDescriptor);
|
|
52
|
+
} else {
|
|
53
|
+
console.error(error);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
fs.write(fileDescriptor, '\n', (error) => {
|
|
57
|
+
if (!error) {
|
|
58
|
+
// fs.close(fileDescriptor);
|
|
59
|
+
} else {
|
|
60
|
+
console.error(error);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
ws.on('close', () => {
|
|
65
|
+
console.log(`disconnected ${new Date().toISOString()}`);
|
|
66
|
+
fs.close(fileDescriptor);
|
|
67
|
+
process.exit();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
readline
|
|
71
|
+
.createInterface({
|
|
72
|
+
input: process.stdin,
|
|
73
|
+
output: process.stdout,
|
|
74
|
+
})
|
|
75
|
+
.on('line', (data) => {
|
|
76
|
+
ws.send(data);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
run().catch(console.error);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
|
|
2
|
+
import { Credentials } from '@aws-sdk/types';
|
|
3
|
+
import * as aws4 from 'aws4';
|
|
4
|
+
|
|
5
|
+
// ""wss://m6g3w6ttdh.execute-api.eu-west-1.amazonaws.com/prod";"
|
|
6
|
+
|
|
7
|
+
export async function getWebSocketUrl(url: string, credentials?: Credentials) {
|
|
8
|
+
const urlParsed = parseUrl(url);
|
|
9
|
+
const hostParts = urlParsed!.host.split('.');
|
|
10
|
+
|
|
11
|
+
console.log('urlParsed', urlParsed);
|
|
12
|
+
|
|
13
|
+
if (!credentials) {
|
|
14
|
+
const credentialsProvider = fromNodeProviderChain();
|
|
15
|
+
credentials = await credentialsProvider();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const AWS_REGION = hostParts[2]; // The region of your API-gateway
|
|
19
|
+
const SOCKET_HOST = hostParts[0]; // Your API-gateway ID
|
|
20
|
+
const ENV = urlParsed!.pathname!.replace(/^\//, ''); // The stage of your target deployment
|
|
21
|
+
const WEBSOCKET_URL = `${SOCKET_HOST}.execute-api.${AWS_REGION}.amazonaws.com`; // Don't prepend with wss!
|
|
22
|
+
// const AWS_REGION = "eu-west-1"; // The region of your API-gateway
|
|
23
|
+
// const SOCKET_HOST = "m6g3w6ttdh"; // Your API-gateway ID
|
|
24
|
+
// const ENV = "prod"; // The stage of your target deployment
|
|
25
|
+
// const WEBSOCKET_URL = `${SOCKET_HOST}.execute-api.${AWS_REGION}.amazonaws.com`; // Don't prepend with wss!
|
|
26
|
+
|
|
27
|
+
// Get a signed path
|
|
28
|
+
const { path } = aws4.sign(
|
|
29
|
+
{
|
|
30
|
+
method: 'GET',
|
|
31
|
+
host: WEBSOCKET_URL,
|
|
32
|
+
// path: `/${ENV}?X-Amz-Security-Token=${encodeURIComponent(
|
|
33
|
+
// credentials!.SessionToken!
|
|
34
|
+
// )}`,
|
|
35
|
+
path: `/${ENV}`,
|
|
36
|
+
service: 'execute-api',
|
|
37
|
+
region: AWS_REGION,
|
|
38
|
+
signQuery: true,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
accessKeyId: credentials.accessKeyId,
|
|
42
|
+
secretAccessKey: credentials.secretAccessKey,
|
|
43
|
+
sessionToken: credentials.sessionToken,
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const url2 = `wss://${WEBSOCKET_URL}${path}`;
|
|
48
|
+
console.log('path', url2);
|
|
49
|
+
return url2;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function parseUrl(href: string) {
|
|
53
|
+
const match = href.match(
|
|
54
|
+
/^(wss?:)\/\/(([^:/?#]*)(?::([0-9]+))?)([/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/
|
|
55
|
+
);
|
|
56
|
+
return (
|
|
57
|
+
match && {
|
|
58
|
+
href,
|
|
59
|
+
protocol: match[1],
|
|
60
|
+
host: match[2],
|
|
61
|
+
hostname: match[3],
|
|
62
|
+
port: match[4],
|
|
63
|
+
pathname: match[5],
|
|
64
|
+
search: match[6],
|
|
65
|
+
hash: match[7],
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "serverless-spy-common",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"private": true,
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
9
|
+
},
|
|
10
|
+
"author": "",
|
|
11
|
+
"license": "ISC",
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@types/aws4": "^1.11.2"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@aws-sdk/credential-providers": "^3.145.0",
|
|
17
|
+
"@aws-sdk/types": "^3.127.0",
|
|
18
|
+
"@aws-sdk/util-dynamodb": "^3.145.0",
|
|
19
|
+
"aws-lambda": "^1.0.7",
|
|
20
|
+
"aws4": "^1.11.0"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { NativeAttributeValue } from '@aws-sdk/util-dynamodb';
|
|
2
|
+
import { DynamoDBRecord } from 'aws-lambda';
|
|
3
|
+
import { SpyEvent } from './SpyEvent';
|
|
4
|
+
|
|
5
|
+
// asdasd
|
|
6
|
+
export interface DynamoDBSpyEvent<TData = any> extends SpyEvent {
|
|
7
|
+
spyEventType: 'DynamoDB';
|
|
8
|
+
eventName: DynamoDBRecord['eventName'];
|
|
9
|
+
newImage: TData;
|
|
10
|
+
keys: Record<string, NativeAttributeValue>;
|
|
11
|
+
oldImage?: TData;
|
|
12
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SpyEvent } from './SpyEvent';
|
|
2
|
+
|
|
3
|
+
export interface EventBridgeRuleSpyEvent<
|
|
4
|
+
MessageType = any,
|
|
5
|
+
EventBridgeDetailType extends string = string
|
|
6
|
+
> extends SpyEvent {
|
|
7
|
+
spyEventType: 'EventBridgeRule';
|
|
8
|
+
detail: MessageType;
|
|
9
|
+
detailType: EventBridgeDetailType;
|
|
10
|
+
source: string;
|
|
11
|
+
time: string;
|
|
12
|
+
account: string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SpyEvent } from './SpyEvent';
|
|
2
|
+
|
|
3
|
+
export interface EventBridgeSpyEvent<
|
|
4
|
+
MessageType = any,
|
|
5
|
+
EventBridgeDetailType extends string = string
|
|
6
|
+
> extends SpyEvent {
|
|
7
|
+
spyEventType: 'EventBridge';
|
|
8
|
+
detail: MessageType;
|
|
9
|
+
detailType: EventBridgeDetailType;
|
|
10
|
+
source: string;
|
|
11
|
+
time: string;
|
|
12
|
+
account: string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SpyEvent } from './SpyEvent';
|
|
2
|
+
|
|
3
|
+
export interface FunctionConsoleSpyEvent<TRequest = any> extends SpyEvent {
|
|
4
|
+
spyEventType: 'FunctionConsole';
|
|
5
|
+
request: TRequest;
|
|
6
|
+
console: {
|
|
7
|
+
type: 'log' | 'debug' | 'info' | 'error' | 'warn';
|
|
8
|
+
message?: any;
|
|
9
|
+
optionalParams: any[];
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FunctionContext } from './FunctionContext';
|
|
2
|
+
import { SpyEvent } from './SpyEvent';
|
|
3
|
+
|
|
4
|
+
export interface FunctionErrorSpyEvent<TRequest = any> extends SpyEvent {
|
|
5
|
+
spyEventType: 'FunctionError';
|
|
6
|
+
request: TRequest;
|
|
7
|
+
context: FunctionContext;
|
|
8
|
+
error: any;
|
|
9
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FunctionContext } from './FunctionContext';
|
|
2
|
+
import { SpyEvent } from './SpyEvent';
|
|
3
|
+
|
|
4
|
+
export interface FunctionResponseSpyEvent<TRequest = any, TResponse = any>
|
|
5
|
+
extends SpyEvent {
|
|
6
|
+
spyEventType: 'FunctionResponse';
|
|
7
|
+
request: TRequest;
|
|
8
|
+
context: FunctionContext;
|
|
9
|
+
response: TResponse;
|
|
10
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SNSMessageAttributes } from 'aws-lambda';
|
|
2
|
+
import { SpyEvent } from './SpyEvent';
|
|
3
|
+
|
|
4
|
+
export interface SnsSubscriptionSpyEvent<MessageType = any> extends SpyEvent {
|
|
5
|
+
spyEventType: 'FunctionSnsSubscription';
|
|
6
|
+
message: MessageType;
|
|
7
|
+
subject: string;
|
|
8
|
+
timestamp: string;
|
|
9
|
+
topicArn: string;
|
|
10
|
+
messageId: string;
|
|
11
|
+
messageAttributes: SNSMessageAttributes;
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SNSMessageAttributes } from 'aws-lambda';
|
|
2
|
+
import { SpyEvent } from './SpyEvent';
|
|
3
|
+
|
|
4
|
+
export interface SnsTopicSpyEvent<MessageType = any> extends SpyEvent {
|
|
5
|
+
spyEventType: 'FunctionSnsTopic';
|
|
6
|
+
message: MessageType;
|
|
7
|
+
subject: string;
|
|
8
|
+
timestamp: string;
|
|
9
|
+
topicArn: string;
|
|
10
|
+
messageId: string;
|
|
11
|
+
messageAttributes: SNSMessageAttributes;
|
|
12
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { DynamoDBClient, PutItemCommand } from '@aws-sdk/client-dynamodb';
|
|
2
|
+
import { APIGatewayEvent } from 'aws-lambda';
|
|
3
|
+
|
|
4
|
+
const ddb = new DynamoDBClient({
|
|
5
|
+
region: process.env.AWS_REGION,
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
exports.handler = async (event: APIGatewayEvent) => {
|
|
9
|
+
console.log('EVENT', JSON.stringify(event));
|
|
10
|
+
|
|
11
|
+
const putParams = new PutItemCommand({
|
|
12
|
+
TableName: process.env.TABLE_NAME as string,
|
|
13
|
+
Item: {
|
|
14
|
+
connectionId: { S: event.requestContext.connectionId! },
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
await ddb.send(putParams);
|
|
20
|
+
} catch (err) {
|
|
21
|
+
console.error(err);
|
|
22
|
+
return {
|
|
23
|
+
statusCode: 500,
|
|
24
|
+
body: 'Failed to connect: ' + JSON.stringify(err),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return { statusCode: 200, body: 'Connected.' };
|
|
29
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DeleteItemCommand, DynamoDBClient } from '@aws-sdk/client-dynamodb';
|
|
2
|
+
import { APIGatewayEvent } from 'aws-lambda';
|
|
3
|
+
|
|
4
|
+
const ddb = new DynamoDBClient({
|
|
5
|
+
region: process.env.AWS_REGION,
|
|
6
|
+
});
|
|
7
|
+
export const handler = async (event: APIGatewayEvent) => {
|
|
8
|
+
console.log('EVENT', JSON.stringify(event));
|
|
9
|
+
|
|
10
|
+
const deleteParams = new DeleteItemCommand({
|
|
11
|
+
TableName: process.env.TABLE_NAME,
|
|
12
|
+
Key: {
|
|
13
|
+
connectionId: { S: event.requestContext.connectionId! },
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
await ddb.send(deleteParams);
|
|
19
|
+
} catch (err) {
|
|
20
|
+
console.error(err);
|
|
21
|
+
return {
|
|
22
|
+
statusCode: 500,
|
|
23
|
+
body: 'Failed to disconnect: ' + JSON.stringify(err),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return { statusCode: 200, body: 'Disconnected.' };
|
|
28
|
+
};
|