serverless-spy 0.0.36 → 0.0.37
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/.jsii +3 -3
- package/cli/cli.ts +145 -75
- package/cli/icons/Arch_AWS-Lambda_16.svg +18 -0
- package/cli/icons/Arch_Amazon-DynamoDB_16.svg +18 -0
- package/cli/icons/Arch_Amazon-EventBridge_16.svg +18 -0
- package/cli/icons/Arch_Amazon-Simple-Notification-Service_16.svg +18 -0
- package/cli/icons/Arch_Amazon-Simple-Queue-Service_16.svg +18 -0
- package/cli/icons/Arch_Amazon-Simple-Storage-Service_16.svg +18 -0
- package/cli/index.html +84 -25
- package/cli/node_modules/commander/LICENSE +22 -0
- package/cli/node_modules/commander/Readme.md +1114 -0
- package/cli/node_modules/commander/esm.mjs +16 -0
- package/cli/node_modules/commander/index.js +27 -0
- package/cli/node_modules/commander/lib/argument.js +147 -0
- package/cli/node_modules/commander/lib/command.js +2161 -0
- package/cli/node_modules/commander/lib/error.js +45 -0
- package/cli/node_modules/commander/lib/help.js +406 -0
- package/cli/node_modules/commander/lib/option.js +324 -0
- package/cli/node_modules/commander/lib/suggestSimilar.js +100 -0
- package/cli/node_modules/commander/package-support.json +16 -0
- package/cli/node_modules/commander/package.json +80 -0
- package/cli/node_modules/commander/typings/index.d.ts +879 -0
- package/cli/package.json +23 -0
- package/cli/sampleData.ts +518 -0
- package/cli/style.css +66 -42
- package/cli/webServerlessSpy.ts +461 -0
- package/common/SpyEventSender.ts +291 -0
- package/common/getWebSocketUrl.ts +21 -4
- package/common/spyEvents/EventBridgeBaseSpyEvent.ts +13 -0
- package/common/spyEvents/EventBridgeRuleSpyEvent.ts +2 -7
- package/common/spyEvents/EventBridgeSpyEvent.ts +2 -7
- package/common/spyEvents/FunctionBaseSpyEvent.ts +7 -0
- package/common/spyEvents/FunctionConsole.ts +5 -0
- package/common/spyEvents/FunctionConsoleSpyEvent.ts +5 -8
- package/common/spyEvents/FunctionResponseSpyEvent.ts +2 -5
- package/common/spyEvents/SnsSpyEventBase.ts +11 -0
- package/common/spyEvents/SnsSubscriptionSpyEvent.ts +3 -9
- package/common/spyEvents/SnsTopicSpyEvent.ts +3 -9
- package/dist/releasetag.txt +1 -1
- package/extension/interceptor.ts +91 -14
- package/functions/sendMessage.ts +4 -2
- package/lib/cli/cli.js +124 -65
- package/lib/cli/cli.mjs +125 -66
- package/lib/cli/sampleData.d.ts +892 -0
- package/lib/cli/sampleData.js +481 -0
- package/lib/cli/sampleData.mjs +478 -0
- package/lib/cli/webServerlessSpy.js +5516 -0
- package/lib/cli/webServerlessSpy.js.map +7 -0
- package/lib/common/SpyEventSender.d.ts +17 -0
- package/lib/common/SpyEventSender.js +227 -0
- package/lib/common/SpyEventSender.mjs +223 -0
- package/lib/common/getWebSocketUrl.d.ts +1 -1
- package/lib/common/getWebSocketUrl.js +19 -7
- package/lib/common/getWebSocketUrl.mjs +17 -5
- package/lib/common/spyEvents/EventBridgeBaseSpyEvent.d.ts +9 -0
- package/lib/common/spyEvents/EventBridgeBaseSpyEvent.js +3 -0
- package/lib/common/spyEvents/EventBridgeBaseSpyEvent.mjs +2 -0
- package/lib/common/spyEvents/EventBridgeRuleSpyEvent.d.ts +2 -7
- package/lib/common/spyEvents/EventBridgeRuleSpyEvent.js +1 -1
- package/lib/common/spyEvents/EventBridgeRuleSpyEvent.mjs +1 -1
- package/lib/common/spyEvents/EventBridgeSpyEvent.d.ts +2 -7
- package/lib/common/spyEvents/EventBridgeSpyEvent.js +1 -1
- package/lib/common/spyEvents/EventBridgeSpyEvent.mjs +1 -1
- package/lib/common/spyEvents/FunctionBaseSpyEvent.d.ts +6 -0
- package/lib/common/spyEvents/FunctionBaseSpyEvent.js +3 -0
- package/lib/common/spyEvents/FunctionBaseSpyEvent.mjs +2 -0
- package/lib/common/spyEvents/FunctionConsole.d.ts +5 -0
- package/lib/common/spyEvents/FunctionConsole.js +3 -0
- package/lib/common/spyEvents/FunctionConsole.mjs +2 -0
- package/lib/common/spyEvents/FunctionConsoleSpyEvent.d.ts +4 -8
- package/lib/common/spyEvents/FunctionConsoleSpyEvent.js +1 -1
- package/lib/common/spyEvents/FunctionConsoleSpyEvent.mjs +1 -1
- package/lib/common/spyEvents/FunctionResponseSpyEvent.d.ts +2 -5
- package/lib/common/spyEvents/FunctionResponseSpyEvent.js +1 -1
- package/lib/common/spyEvents/FunctionResponseSpyEvent.mjs +1 -1
- package/lib/common/spyEvents/SnsSpyEventBase.d.ts +10 -0
- package/lib/common/spyEvents/SnsSpyEventBase.js +3 -0
- package/lib/common/spyEvents/SnsSpyEventBase.mjs +2 -0
- package/lib/common/spyEvents/SnsSubscriptionSpyEvent.d.ts +2 -9
- package/lib/common/spyEvents/SnsSubscriptionSpyEvent.js +1 -1
- package/lib/common/spyEvents/SnsSubscriptionSpyEvent.mjs +1 -1
- package/lib/common/spyEvents/SnsTopicSpyEvent.d.ts +2 -9
- package/lib/common/spyEvents/SnsTopicSpyEvent.js +1 -1
- package/lib/common/spyEvents/SnsTopicSpyEvent.mjs +1 -1
- package/lib/extension/dist/layer/nodejs/node_modules/interceptor.js +251 -181
- package/lib/extension/dist/layer/nodejs/node_modules/interceptor.js.map +3 -3
- package/lib/listener/SpyHandlers.ts.d.ts +30 -2
- package/lib/listener/SpyHandlers.ts.js +1 -1
- package/lib/listener/SpyHandlers.ts.mjs +1 -1
- package/lib/listener/WsListener.js +11 -11
- package/lib/listener/WsListener.mjs +12 -12
- package/lib/src/ServerlessSpy.js +2 -3
- package/lib/src/ServerlessSpy.mjs +1 -2
- package/listener/SpyHandlers.ts.ts +70 -9
- package/listener/WsListener.ts +21 -18
- package/package.json +5 -3
- package/cli/serverlessSpy.js +0 -73
- package/cli/ws.ts +0 -79
- package/common/publishSpyEvent.ts +0 -269
- package/lib/cli/ws.d.ts +0 -1
- package/lib/cli/ws.js +0 -68
- package/lib/cli/ws.mjs +0 -66
- package/lib/common/publishSpyEvent.d.ts +0 -4
- package/lib/common/publishSpyEvent.js +0 -211
- package/lib/common/publishSpyEvent.mjs +0 -205
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ApiGatewayManagementApi,
|
|
3
|
+
PostToConnectionCommand,
|
|
4
|
+
} from '@aws-sdk/client-apigatewaymanagementapi';
|
|
5
|
+
import {
|
|
6
|
+
AttributeValue,
|
|
7
|
+
DeleteItemCommand,
|
|
8
|
+
DynamoDBClient,
|
|
9
|
+
ScanCommand,
|
|
10
|
+
} from '@aws-sdk/client-dynamodb';
|
|
11
|
+
|
|
12
|
+
import { unmarshall } from '@aws-sdk/util-dynamodb';
|
|
13
|
+
import {
|
|
14
|
+
DynamoDBStreamEvent,
|
|
15
|
+
S3Event,
|
|
16
|
+
SNSEvent,
|
|
17
|
+
EventBridgeEvent,
|
|
18
|
+
SQSEvent,
|
|
19
|
+
} from 'aws-lambda';
|
|
20
|
+
import { envVariableNames } from '../src/common/envVariableNames';
|
|
21
|
+
import { DynamoDBSpyEvent } from './spyEvents/DynamoDBSpyEvent';
|
|
22
|
+
import { EventBridgeRuleSpyEvent } from './spyEvents/EventBridgeRuleSpyEvent';
|
|
23
|
+
import { EventBridgeSpyEvent } from './spyEvents/EventBridgeSpyEvent';
|
|
24
|
+
import { S3SpyEvent } from './spyEvents/S3SpyEvent';
|
|
25
|
+
import { SnsSubscriptionSpyEvent } from './spyEvents/SnsSubscriptionSpyEvent';
|
|
26
|
+
import { SnsTopicSpyEvent } from './spyEvents/SnsTopicSpyEvent';
|
|
27
|
+
import { SpyMessage } from './spyEvents/SpyMessage';
|
|
28
|
+
import { SqsSpyEvent } from './spyEvents/SqsSpyEvent';
|
|
29
|
+
|
|
30
|
+
export class SpyEventSender {
|
|
31
|
+
ddb = new DynamoDBClient({
|
|
32
|
+
region: process.env.AWS_REGION,
|
|
33
|
+
});
|
|
34
|
+
debugMode = process.env[envVariableNames.SSPY_DEBUG] === 'true';
|
|
35
|
+
apigwManagementApi = new ApiGatewayManagementApi({
|
|
36
|
+
apiVersion: '2018-11-29',
|
|
37
|
+
endpoint: process.env[envVariableNames.SSPY_WS_ENDPOINT]!,
|
|
38
|
+
});
|
|
39
|
+
connections: Record<string, AttributeValue>[] | undefined;
|
|
40
|
+
|
|
41
|
+
constructor(params?: {
|
|
42
|
+
log: (message: string, ...optionalParams: any[]) => void;
|
|
43
|
+
logError: (message: string, ...optionalParams: any[]) => void;
|
|
44
|
+
}) {
|
|
45
|
+
if (params?.log) {
|
|
46
|
+
this.log = params.log;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (params?.logError) {
|
|
50
|
+
this.logError = params.logError;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public async publishSpyEvent(event: any) {
|
|
55
|
+
this.log('Event', JSON.stringify(event));
|
|
56
|
+
|
|
57
|
+
const mapping = JSON.parse(
|
|
58
|
+
process.env[envVariableNames.SSPY_INFRA_MAPPING]!
|
|
59
|
+
);
|
|
60
|
+
this.log('ARN to names mapping', JSON.stringify(mapping));
|
|
61
|
+
|
|
62
|
+
let connectionData;
|
|
63
|
+
|
|
64
|
+
const scanParams = new ScanCommand({
|
|
65
|
+
TableName: process.env[envVariableNames.SSPY_WS_TABLE_NAME] as string,
|
|
66
|
+
ProjectionExpression: 'connectionId',
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
connectionData = await this.ddb.send(scanParams);
|
|
70
|
+
|
|
71
|
+
this.connections = connectionData.Items;
|
|
72
|
+
|
|
73
|
+
const postDataPromises: Promise<any>[] = [];
|
|
74
|
+
|
|
75
|
+
if (event?.Records && event.Records[0]?.Sns) {
|
|
76
|
+
//console.log('*** SNS ***');
|
|
77
|
+
const eventSns = event as SNSEvent;
|
|
78
|
+
for (const record of eventSns.Records) {
|
|
79
|
+
const subscriptionArn = record.EventSubscriptionArn;
|
|
80
|
+
|
|
81
|
+
let serviceKey: string;
|
|
82
|
+
if (mapping[subscriptionArn]) {
|
|
83
|
+
// subscription event that could contain filter based on existing subscription
|
|
84
|
+
serviceKey = mapping[subscriptionArn];
|
|
85
|
+
} else {
|
|
86
|
+
// catch all subscription
|
|
87
|
+
const topicArn = record.Sns.TopicArn;
|
|
88
|
+
serviceKey = mapping[topicArn];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let message: string;
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
message = JSON.parse(record.Sns.Message);
|
|
95
|
+
} catch {
|
|
96
|
+
message = record.Sns.Message;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const spyEventType = this.getSpyEventType(serviceKey) as
|
|
100
|
+
| 'FunctionSnsTopic'
|
|
101
|
+
| 'FunctionSnsSubscription';
|
|
102
|
+
|
|
103
|
+
const data: SnsTopicSpyEvent | SnsSubscriptionSpyEvent = {
|
|
104
|
+
spyEventType,
|
|
105
|
+
message,
|
|
106
|
+
subject: record.Sns.Subject,
|
|
107
|
+
timestamp: record.Sns.Timestamp,
|
|
108
|
+
topicArn: record.Sns.TopicArn,
|
|
109
|
+
messageId: record.Sns.MessageId,
|
|
110
|
+
messageAttributes: record.Sns.MessageAttributes,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const fluentEvent: Omit<SpyMessage, 'timestamp'> = {
|
|
114
|
+
data,
|
|
115
|
+
serviceKey,
|
|
116
|
+
};
|
|
117
|
+
postDataPromises.push(this.postData(fluentEvent));
|
|
118
|
+
}
|
|
119
|
+
} else if (event?.Records && event.Records[0]?.eventSource === 'aws:sqs') {
|
|
120
|
+
//console.log('*** SQS ***');
|
|
121
|
+
const eventSqs = event as SQSEvent;
|
|
122
|
+
for (const record of eventSqs.Records) {
|
|
123
|
+
const subscriptionArn = record.eventSourceARN;
|
|
124
|
+
|
|
125
|
+
const serviceKey = mapping[subscriptionArn];
|
|
126
|
+
let body: string;
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
body = JSON.parse(record.body);
|
|
130
|
+
} catch {
|
|
131
|
+
body = record.body;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const data: SqsSpyEvent = {
|
|
135
|
+
spyEventType: 'Sqs',
|
|
136
|
+
body,
|
|
137
|
+
messageAttributes: record.messageAttributes,
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const fluentEvent: Omit<SpyMessage, 'timestamp'> = {
|
|
141
|
+
data,
|
|
142
|
+
serviceKey,
|
|
143
|
+
};
|
|
144
|
+
postDataPromises.push(this.postData(fluentEvent));
|
|
145
|
+
}
|
|
146
|
+
} else if (event?.Records && event.Records[0]?.s3) {
|
|
147
|
+
//console.log('*** S3 ***');
|
|
148
|
+
const eventS3 = event as S3Event;
|
|
149
|
+
for (const record of eventS3.Records) {
|
|
150
|
+
const bucketArn = record.s3.bucket.arn;
|
|
151
|
+
|
|
152
|
+
const data: S3SpyEvent = {
|
|
153
|
+
spyEventType: 'S3',
|
|
154
|
+
eventName: record.eventName,
|
|
155
|
+
eventTime: record.eventTime,
|
|
156
|
+
bucket: record.s3.bucket.name,
|
|
157
|
+
key: record.s3.object.key,
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const fluentEvent: Omit<SpyMessage, 'timestamp'> = {
|
|
161
|
+
data,
|
|
162
|
+
serviceKey: mapping[bucketArn],
|
|
163
|
+
};
|
|
164
|
+
postDataPromises.push(this.postData(fluentEvent));
|
|
165
|
+
}
|
|
166
|
+
} else if (event.Records && event.Records[0]?.dynamodb) {
|
|
167
|
+
//console.log('*** DYNAMODB ***');
|
|
168
|
+
const eventDynamoDB = event as DynamoDBStreamEvent;
|
|
169
|
+
for (const record of eventDynamoDB.Records) {
|
|
170
|
+
let arn = record.eventSourceARN!;
|
|
171
|
+
arn = arn.substring(0, arn.indexOf('/stream/'));
|
|
172
|
+
|
|
173
|
+
const data: DynamoDBSpyEvent = {
|
|
174
|
+
spyEventType: 'DynamoDB',
|
|
175
|
+
eventName: record.eventName,
|
|
176
|
+
newImage: unmarshall(record.dynamodb?.NewImage as any),
|
|
177
|
+
keys: unmarshall(record.dynamodb?.Keys as any),
|
|
178
|
+
oldImage: record.dynamodb?.OldImage
|
|
179
|
+
? unmarshall(record.dynamodb?.OldImage as any)
|
|
180
|
+
: undefined,
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const fluentEvent: Omit<SpyMessage, 'timestamp'> = {
|
|
184
|
+
data,
|
|
185
|
+
serviceKey: mapping[arn],
|
|
186
|
+
};
|
|
187
|
+
postDataPromises.push(this.postData(fluentEvent));
|
|
188
|
+
}
|
|
189
|
+
} else if (
|
|
190
|
+
event.detail &&
|
|
191
|
+
event['detail-type'] &&
|
|
192
|
+
event.version &&
|
|
193
|
+
event.source
|
|
194
|
+
) {
|
|
195
|
+
//console.log('*** EventBridge ***');
|
|
196
|
+
const eventEb = event as EventBridgeEvent<any, any>;
|
|
197
|
+
|
|
198
|
+
const serviceKey = mapping.eventBridge; // the is new lambda for each subscription
|
|
199
|
+
|
|
200
|
+
const spyEventType = this.getSpyEventType(serviceKey) as
|
|
201
|
+
| 'EventBridge'
|
|
202
|
+
| 'EventBridgeRule';
|
|
203
|
+
|
|
204
|
+
const message = eventEb.detail;
|
|
205
|
+
|
|
206
|
+
const data: EventBridgeSpyEvent | EventBridgeRuleSpyEvent = {
|
|
207
|
+
spyEventType,
|
|
208
|
+
detail: message,
|
|
209
|
+
detailType: eventEb['detail-type'],
|
|
210
|
+
eventBridgeId: eventEb['id'],
|
|
211
|
+
source: eventEb.source,
|
|
212
|
+
time: eventEb.time,
|
|
213
|
+
account: eventEb.account,
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const fluentEvent: Omit<SpyMessage, 'timestamp'> = {
|
|
217
|
+
data,
|
|
218
|
+
serviceKey,
|
|
219
|
+
};
|
|
220
|
+
postDataPromises.push(this.postData(fluentEvent));
|
|
221
|
+
} else {
|
|
222
|
+
//console.log('*** OTHER ***');
|
|
223
|
+
const fluentEvent: Omit<SpyMessage, 'timestamp'> = event;
|
|
224
|
+
postDataPromises.push(this.postData(fluentEvent));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
await Promise.all(postDataPromises);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
private async postData(spyMessage: Omit<SpyMessage, 'timestamp'>) {
|
|
231
|
+
this.log('Post spy message', JSON.stringify(spyMessage));
|
|
232
|
+
|
|
233
|
+
if (!this.connections) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const postCalls = this.connections.map(async ({ connectionId }) => {
|
|
238
|
+
this.log(`Sending message to client: ${connectionId.S}`);
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
const postToConnectionCommand = new PostToConnectionCommand({
|
|
242
|
+
ConnectionId: connectionId.S,
|
|
243
|
+
Data: JSON.stringify({
|
|
244
|
+
timestamp: new Date().toISOString(),
|
|
245
|
+
serviceKey: spyMessage.serviceKey,
|
|
246
|
+
data: spyMessage.data,
|
|
247
|
+
}) as any,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
await this.apigwManagementApi.send(postToConnectionCommand);
|
|
251
|
+
} catch (e) {
|
|
252
|
+
this.logError(`Faild sending spy message to: ${connectionId.S}`, e);
|
|
253
|
+
if ((e as any).$metadata.httpStatusCode === 410) {
|
|
254
|
+
this.log(`Found stale connection, deleting ${connectionId}`);
|
|
255
|
+
|
|
256
|
+
const deleteParams = new DeleteItemCommand({
|
|
257
|
+
TableName: process.env[envVariableNames.SSPY_WS_TABLE_NAME],
|
|
258
|
+
Key: { connectionId },
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
await this.ddb.send(deleteParams);
|
|
262
|
+
} else {
|
|
263
|
+
throw e;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
await Promise.all(postCalls);
|
|
269
|
+
this.log('Send spy message finish');
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
private getSpyEventType(serviceKey: string) {
|
|
273
|
+
if (!serviceKey) {
|
|
274
|
+
throw new Error('Missing serviceKey');
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return serviceKey.substring(0, serviceKey.indexOf('#'));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private log(message: string, ...optionalParams: any[]) {
|
|
281
|
+
if (this.debugMode) {
|
|
282
|
+
console.debug('SSPY EXTENSION', message, ...optionalParams);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
private logError(message: string, ...optionalParams: any[]) {
|
|
287
|
+
if (this.debugMode) {
|
|
288
|
+
console.error('SSPY EXTENSION', message, ...optionalParams);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
@@ -4,9 +4,26 @@ import * as aws4 from 'aws4';
|
|
|
4
4
|
|
|
5
5
|
// ""wss://m6g3w6ttdh.execute-api.eu-west-1.amazonaws.com/prod";"
|
|
6
6
|
|
|
7
|
-
export async function
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
export async function getSignedWebSocketUrl(
|
|
8
|
+
url: string,
|
|
9
|
+
credentials?: Credentials
|
|
10
|
+
) {
|
|
11
|
+
let hostParts: string[];
|
|
12
|
+
let pathname: string;
|
|
13
|
+
|
|
14
|
+
if (!url) {
|
|
15
|
+
throw new Error(`Missing websocket URL`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
new URL(url); //validate URL
|
|
20
|
+
|
|
21
|
+
const urlParsed = parseUrl(url);
|
|
22
|
+
pathname = urlParsed!.pathname!;
|
|
23
|
+
hostParts = urlParsed!.host.split('.');
|
|
24
|
+
} catch {
|
|
25
|
+
throw new Error(`Invalid websocket URL ${url}`);
|
|
26
|
+
}
|
|
10
27
|
|
|
11
28
|
if (!credentials) {
|
|
12
29
|
const credentialsProvider = fromNodeProviderChain();
|
|
@@ -15,7 +32,7 @@ export async function getWebSocketUrl(url: string, credentials?: Credentials) {
|
|
|
15
32
|
|
|
16
33
|
const AWS_REGION = hostParts[2]; // The region of your API-gateway
|
|
17
34
|
const SOCKET_HOST = hostParts[0]; // Your API-gateway ID
|
|
18
|
-
const ENV =
|
|
35
|
+
const ENV = pathname.replace(/^\//, ''); // The stage of your target deployment
|
|
19
36
|
const WEBSOCKET_URL = `${SOCKET_HOST}.execute-api.${AWS_REGION}.amazonaws.com`; // Don't prepend with wss!
|
|
20
37
|
// const AWS_REGION = "eu-west-1"; // The region of your API-gateway
|
|
21
38
|
// const SOCKET_HOST = "m6g3w6ttdh"; // Your API-gateway ID
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SpyEvent } from './SpyEvent';
|
|
2
|
+
|
|
3
|
+
export interface EventBridgeBaseSpyEvent<
|
|
4
|
+
MessageType = any,
|
|
5
|
+
EventBridgeDetailType extends string = string
|
|
6
|
+
> extends SpyEvent {
|
|
7
|
+
eventBridgeId: string;
|
|
8
|
+
detail: MessageType;
|
|
9
|
+
detailType: EventBridgeDetailType;
|
|
10
|
+
source: string;
|
|
11
|
+
time: string;
|
|
12
|
+
account: string;
|
|
13
|
+
}
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EventBridgeBaseSpyEvent } from './EventBridgeBaseSpyEvent';
|
|
2
2
|
|
|
3
3
|
export interface EventBridgeRuleSpyEvent<
|
|
4
4
|
MessageType = any,
|
|
5
5
|
EventBridgeDetailType extends string = string
|
|
6
|
-
> extends
|
|
6
|
+
> extends EventBridgeBaseSpyEvent<MessageType, EventBridgeDetailType> {
|
|
7
7
|
spyEventType: 'EventBridgeRule';
|
|
8
|
-
detail: MessageType;
|
|
9
|
-
detailType: EventBridgeDetailType;
|
|
10
|
-
source: string;
|
|
11
|
-
time: string;
|
|
12
|
-
account: string;
|
|
13
8
|
}
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EventBridgeBaseSpyEvent } from './EventBridgeBaseSpyEvent';
|
|
2
2
|
|
|
3
3
|
export interface EventBridgeSpyEvent<
|
|
4
4
|
MessageType = any,
|
|
5
5
|
EventBridgeDetailType extends string = string
|
|
6
|
-
> extends
|
|
6
|
+
> extends EventBridgeBaseSpyEvent<MessageType, EventBridgeDetailType> {
|
|
7
7
|
spyEventType: 'EventBridge';
|
|
8
|
-
detail: MessageType;
|
|
9
|
-
detailType: EventBridgeDetailType;
|
|
10
|
-
source: string;
|
|
11
|
-
time: string;
|
|
12
|
-
account: string;
|
|
13
8
|
}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FunctionBaseSpyEvent } from './FunctionBaseSpyEvent';
|
|
2
|
+
import { FunctionConsole } from './FunctionConsole';
|
|
2
3
|
|
|
3
|
-
export interface FunctionConsoleSpyEvent<TRequest = any>
|
|
4
|
+
export interface FunctionConsoleSpyEvent<TRequest = any>
|
|
5
|
+
extends FunctionBaseSpyEvent<TRequest> {
|
|
4
6
|
spyEventType: 'FunctionConsole';
|
|
5
|
-
|
|
6
|
-
console: {
|
|
7
|
-
type: 'log' | 'debug' | 'info' | 'error' | 'warn';
|
|
8
|
-
message?: any;
|
|
9
|
-
optionalParams: any[];
|
|
10
|
-
};
|
|
7
|
+
console: FunctionConsole;
|
|
11
8
|
}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { SpyEvent } from './SpyEvent';
|
|
1
|
+
import { FunctionBaseSpyEvent } from './FunctionBaseSpyEvent';
|
|
3
2
|
|
|
4
3
|
export interface FunctionResponseSpyEvent<TRequest = any, TResponse = any>
|
|
5
|
-
extends
|
|
4
|
+
extends FunctionBaseSpyEvent<TRequest> {
|
|
6
5
|
spyEventType: 'FunctionResponse';
|
|
7
|
-
request: TRequest;
|
|
8
|
-
context: FunctionContext;
|
|
9
6
|
response: TResponse;
|
|
10
7
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SNSMessageAttributes } from 'aws-lambda';
|
|
2
|
+
import { SpyEvent } from './SpyEvent';
|
|
3
|
+
|
|
4
|
+
export interface SnsSpyEventBase<MessageType = any> extends SpyEvent {
|
|
5
|
+
message: MessageType;
|
|
6
|
+
subject: string;
|
|
7
|
+
timestamp: string;
|
|
8
|
+
topicArn: string;
|
|
9
|
+
messageId: string;
|
|
10
|
+
messageAttributes: SNSMessageAttributes;
|
|
11
|
+
}
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { SpyEvent } from './SpyEvent';
|
|
1
|
+
import { SnsSpyEventBase } from './SnsSpyEventBase';
|
|
3
2
|
|
|
4
|
-
export interface SnsSubscriptionSpyEvent<MessageType = any>
|
|
3
|
+
export interface SnsSubscriptionSpyEvent<MessageType = any>
|
|
4
|
+
extends SnsSpyEventBase<MessageType> {
|
|
5
5
|
spyEventType: 'FunctionSnsSubscription';
|
|
6
|
-
message: MessageType;
|
|
7
|
-
subject: string;
|
|
8
|
-
timestamp: string;
|
|
9
|
-
topicArn: string;
|
|
10
|
-
messageId: string;
|
|
11
|
-
messageAttributes: SNSMessageAttributes;
|
|
12
6
|
}
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { SpyEvent } from './SpyEvent';
|
|
1
|
+
import { SnsSpyEventBase } from './SnsSpyEventBase';
|
|
3
2
|
|
|
4
|
-
export interface SnsTopicSpyEvent<MessageType = any>
|
|
3
|
+
export interface SnsTopicSpyEvent<MessageType = any>
|
|
4
|
+
extends SnsSpyEventBase<MessageType> {
|
|
5
5
|
spyEventType: 'FunctionSnsTopic';
|
|
6
|
-
message: MessageType;
|
|
7
|
-
subject: string;
|
|
8
|
-
timestamp: string;
|
|
9
|
-
topicArn: string;
|
|
10
|
-
messageId: string;
|
|
11
|
-
messageAttributes: SNSMessageAttributes;
|
|
12
6
|
}
|
package/dist/releasetag.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
v0.0.
|
|
1
|
+
v0.0.37
|
package/extension/interceptor.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { LambdaClient, InvokeCommand } from '@aws-sdk/client-lambda';
|
|
2
1
|
import { Callback, Context, Handler } from 'aws-lambda';
|
|
3
|
-
import {
|
|
2
|
+
import { FunctionConsoleSpyEvent } from '../common/spyEvents/FunctionConsoleSpyEvent';
|
|
4
3
|
import { FunctionContext } from '../common/spyEvents/FunctionContext';
|
|
5
4
|
import { FunctionErrorSpyEvent } from '../common/spyEvents/FunctionErrorSpyEvent';
|
|
6
5
|
import { FunctionRequestSpyEvent } from '../common/spyEvents/FunctionRequestSpyEvent';
|
|
7
6
|
import { FunctionResponseSpyEvent } from '../common/spyEvents/FunctionResponseSpyEvent';
|
|
7
|
+
import { SpyEventSender } from '../common/SpyEventSender';
|
|
8
8
|
import { envVariableNames } from '../src/common/envVariableNames';
|
|
9
9
|
import { load } from './aws/UserFunction';
|
|
10
10
|
|
|
@@ -15,6 +15,22 @@ const subscribedToSQS =
|
|
|
15
15
|
|
|
16
16
|
const debugMode = process.env[envVariableNames.SSPY_DEBUG] === 'true';
|
|
17
17
|
|
|
18
|
+
const oldConsoleLog = console.log;
|
|
19
|
+
const oldConsoleWarn = console.warn;
|
|
20
|
+
const oldConsoleDebug = console.debug;
|
|
21
|
+
const oldConsoleInfo = console.info;
|
|
22
|
+
const oldConsoleError = console.error;
|
|
23
|
+
let currentEvent: any;
|
|
24
|
+
let currentContext: FunctionContext | undefined;
|
|
25
|
+
let promises: Promise<any>[] = [];
|
|
26
|
+
|
|
27
|
+
interceptConsole();
|
|
28
|
+
|
|
29
|
+
const spyEventSender = new SpyEventSender({
|
|
30
|
+
log,
|
|
31
|
+
logError,
|
|
32
|
+
});
|
|
33
|
+
|
|
18
34
|
// Wrap original handler.
|
|
19
35
|
// Handler can be async or non-async:
|
|
20
36
|
// https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html
|
|
@@ -23,9 +39,19 @@ export const handler = (
|
|
|
23
39
|
context: Context,
|
|
24
40
|
callback: Callback
|
|
25
41
|
): Promise<any> | undefined => {
|
|
26
|
-
|
|
42
|
+
const contextSpy: FunctionContext = {
|
|
43
|
+
functionName: context.functionName,
|
|
44
|
+
awsRequestId: context.awsRequestId,
|
|
45
|
+
identity: context.identity,
|
|
46
|
+
clientContext: context.clientContext,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
currentEvent = event;
|
|
50
|
+
currentContext = contextSpy;
|
|
27
51
|
|
|
28
|
-
|
|
52
|
+
promises = [];
|
|
53
|
+
|
|
54
|
+
log('Request', JSON.stringify(event));
|
|
29
55
|
|
|
30
56
|
if (subscribedToSQS) {
|
|
31
57
|
// send raw message
|
|
@@ -34,13 +60,6 @@ export const handler = (
|
|
|
34
60
|
promises.push(p);
|
|
35
61
|
}
|
|
36
62
|
|
|
37
|
-
const contextSpy: FunctionContext = {
|
|
38
|
-
functionName: context.functionName,
|
|
39
|
-
awsRequestId: context.awsRequestId,
|
|
40
|
-
identity: context.identity,
|
|
41
|
-
clientContext: context.clientContext,
|
|
42
|
-
};
|
|
43
|
-
|
|
44
63
|
const key = `Function#${
|
|
45
64
|
process.env[envVariableNames.SSPY_FUNCTION_NAME]
|
|
46
65
|
}#Request`;
|
|
@@ -63,6 +82,8 @@ export const handler = (
|
|
|
63
82
|
context: contextSpy,
|
|
64
83
|
});
|
|
65
84
|
promises.push(p);
|
|
85
|
+
currentEvent = undefined;
|
|
86
|
+
currentContext = undefined;
|
|
66
87
|
return Promise.all(promises);
|
|
67
88
|
};
|
|
68
89
|
|
|
@@ -77,6 +98,9 @@ export const handler = (
|
|
|
77
98
|
context: contextSpy,
|
|
78
99
|
});
|
|
79
100
|
promises.push(p);
|
|
101
|
+
currentEvent = undefined;
|
|
102
|
+
currentContext = undefined;
|
|
103
|
+
|
|
80
104
|
return Promise.all(promises);
|
|
81
105
|
};
|
|
82
106
|
|
|
@@ -117,6 +141,59 @@ export const handler = (
|
|
|
117
141
|
}
|
|
118
142
|
};
|
|
119
143
|
|
|
144
|
+
function interceptConsole() {
|
|
145
|
+
const sendLogs = (
|
|
146
|
+
type: 'log' | 'debug' | 'info' | 'error' | 'warn',
|
|
147
|
+
args?: any[]
|
|
148
|
+
) => {
|
|
149
|
+
if (!currentContext) return;
|
|
150
|
+
|
|
151
|
+
log(`Console ${type}`, JSON.stringify(args));
|
|
152
|
+
const message = args?.shift();
|
|
153
|
+
|
|
154
|
+
const key = `Function#${
|
|
155
|
+
process.env[envVariableNames.SSPY_FUNCTION_NAME]
|
|
156
|
+
}#Console`;
|
|
157
|
+
|
|
158
|
+
const p = sendLambdaSpyEvent(key, <FunctionConsoleSpyEvent>{
|
|
159
|
+
request: currentEvent,
|
|
160
|
+
context: currentContext,
|
|
161
|
+
console: {
|
|
162
|
+
type,
|
|
163
|
+
message,
|
|
164
|
+
optionalParams: args,
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
promises.push(p);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
console.log = function (...args: any[]) {
|
|
172
|
+
sendLogs('log', args);
|
|
173
|
+
oldConsoleLog.apply(console, args);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
console.warn = function (...args: any[]) {
|
|
177
|
+
sendLogs('warn', args);
|
|
178
|
+
oldConsoleWarn.apply(console, args);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
console.debug = function (...args: any[]) {
|
|
182
|
+
sendLogs('debug', args);
|
|
183
|
+
oldConsoleDebug.apply(console, args);
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
console.info = function (...args: any[]) {
|
|
187
|
+
sendLogs('info', args);
|
|
188
|
+
oldConsoleInfo.apply(console, args);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
console.error = function (...args: any[]) {
|
|
192
|
+
sendLogs('error', args);
|
|
193
|
+
oldConsoleError.apply(console, args);
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
120
197
|
function isPromise(obj: any): boolean {
|
|
121
198
|
return typeof obj?.then === 'function';
|
|
122
199
|
}
|
|
@@ -136,7 +213,7 @@ async function sendLambdaSpyEvent(
|
|
|
136
213
|
}
|
|
137
214
|
|
|
138
215
|
async function sendRawSpyEvent(data: any) {
|
|
139
|
-
await publishSpyEvent(data);
|
|
216
|
+
await spyEventSender.publishSpyEvent(data);
|
|
140
217
|
}
|
|
141
218
|
|
|
142
219
|
function getOriginalHandler(): Handler {
|
|
@@ -152,12 +229,12 @@ function getOriginalHandler(): Handler {
|
|
|
152
229
|
|
|
153
230
|
function log(message: string, ...optionalParams: any[]) {
|
|
154
231
|
if (debugMode) {
|
|
155
|
-
|
|
232
|
+
oldConsoleDebug('SSPY EXTENSION', message, ...optionalParams);
|
|
156
233
|
}
|
|
157
234
|
}
|
|
158
235
|
|
|
159
236
|
function logError(message: string, ...optionalParams: any[]) {
|
|
160
237
|
if (debugMode) {
|
|
161
|
-
|
|
238
|
+
oldConsoleError('SSPY EXTENSION', message, ...optionalParams);
|
|
162
239
|
}
|
|
163
240
|
}
|
package/functions/sendMessage.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SpyEventSender } from '../common/SpyEventSender';
|
|
2
|
+
|
|
3
|
+
const spyEventSender = new SpyEventSender();
|
|
2
4
|
|
|
3
5
|
export const handler = async (event: any) => {
|
|
4
6
|
try {
|
|
5
|
-
await publishSpyEvent(event);
|
|
7
|
+
await spyEventSender.publishSpyEvent(event);
|
|
6
8
|
} catch (e) {
|
|
7
9
|
console.error(e);
|
|
8
10
|
return { statusCode: 500, body: (e as Error)?.stack };
|