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.
Files changed (64) hide show
  1. package/.eslintrc.yml +97 -0
  2. package/.gitattributes +24 -0
  3. package/.husky/pre-commit +4 -0
  4. package/.jsii +3199 -0
  5. package/.prettierignore +1 -0
  6. package/.prettierrc.json +5 -0
  7. package/API.md +123 -0
  8. package/LICENSE +202 -0
  9. package/README.md +1 -0
  10. package/cli/cli.ts +97 -0
  11. package/cli/index.html +43 -0
  12. package/cli/package-lock.json +2356 -0
  13. package/cli/package.json +14 -0
  14. package/cli/serverlessSpy.js +73 -0
  15. package/cli/spy_log.json +0 -0
  16. package/cli/style.css +43 -0
  17. package/cli/ws.ts +79 -0
  18. package/common/getWebSocketUrl.ts +68 -0
  19. package/common/package.json +22 -0
  20. package/common/spyEvents/DynamoDBSpyEvent.ts +12 -0
  21. package/common/spyEvents/EventBridgeRuleSpyEvent.ts +13 -0
  22. package/common/spyEvents/EventBridgeSpyEvent.ts +13 -0
  23. package/common/spyEvents/FunctionConsoleSpyEvent.ts +11 -0
  24. package/common/spyEvents/FunctionContext.ts +8 -0
  25. package/common/spyEvents/FunctionErrorSpyEvent.ts +9 -0
  26. package/common/spyEvents/FunctionRequestSpyEvent.ts +8 -0
  27. package/common/spyEvents/FunctionResponseSpyEvent.ts +10 -0
  28. package/common/spyEvents/S3SpyEvent.ts +9 -0
  29. package/common/spyEvents/SnsSubscriptionSpyEvent.ts +12 -0
  30. package/common/spyEvents/SnsTopicSpyEvent.ts +12 -0
  31. package/common/spyEvents/SpyEvent.ts +3 -0
  32. package/common/spyEvents/SpyMessage.ts +7 -0
  33. package/common/spyEvents/SqsSpyEvent.ts +8 -0
  34. package/functions/onConnect.ts +29 -0
  35. package/functions/onDisconnect.ts +28 -0
  36. package/functions/sendMessage.ts +277 -0
  37. package/functions/tsconfig.dev.json +16 -0
  38. package/functions/tsconfig.json +16 -0
  39. package/index.ts +2 -0
  40. package/lambda-extension/aws/Common.ts +88 -0
  41. package/lambda-extension/aws/Errors.ts +140 -0
  42. package/lambda-extension/aws/UserFunction.ts +169 -0
  43. package/lambda-extension/interceptor.ts +146 -0
  44. package/lambda-extension/spy-wrapper +4 -0
  45. package/lambda-extension/tsconfig.json +16 -0
  46. package/lib/ServerlessSpy.d.ts +27 -0
  47. package/lib/ServerlessSpy.js +301 -0
  48. package/lib/index.d.ts +1 -0
  49. package/lib/index.js +14 -0
  50. package/listener/PrettifyForDisplay.ts +5 -0
  51. package/listener/RecursivePartial.ts +9 -0
  52. package/listener/SpyHandlers.ts.ts +190 -0
  53. package/listener/SpyListener.ts +104 -0
  54. package/listener/createServerlessSpyListener.ts +258 -0
  55. package/listener/index.ts +1 -0
  56. package/listener/matchers.ts +53 -0
  57. package/listener/package.json +19 -0
  58. package/listener/setup.ts +21 -0
  59. package/listener/tsconfig.dev.json +16 -0
  60. package/listener/tsconfig.json +16 -0
  61. package/package.json +132 -0
  62. package/scripts/run-task +1836 -0
  63. package/sst-esbuild/esbuild.js +57 -0
  64. package/x_jest.config.ts +203 -0
@@ -0,0 +1,301 @@
1
+ "use strict";
2
+ var _a;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.ServerlessSpy = void 0;
5
+ const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
6
+ const path = require("path");
7
+ const apiGwV2 = require("@aws-cdk/aws-apigatewayv2-alpha");
8
+ const apiGwV2Int = require("@aws-cdk/aws-apigatewayv2-integrations-alpha");
9
+ const aws_cdk_lib_1 = require("aws-cdk-lib");
10
+ const dynamoDb = require("aws-cdk-lib/aws-dynamodb");
11
+ const events = require("aws-cdk-lib/aws-events");
12
+ const targets = require("aws-cdk-lib/aws-events-targets");
13
+ const lambda = require("aws-cdk-lib/aws-lambda");
14
+ const dynamoDbStream = require("aws-cdk-lib/aws-lambda-event-sources");
15
+ const lambdaNode = require("aws-cdk-lib/aws-lambda-nodejs");
16
+ const s3 = require("aws-cdk-lib/aws-s3");
17
+ const s3notif = require("aws-cdk-lib/aws-s3-notifications");
18
+ const sns = require("aws-cdk-lib/aws-sns");
19
+ const snsSubs = require("aws-cdk-lib/aws-sns-subscriptions");
20
+ const sqs = require("aws-cdk-lib/aws-sqs");
21
+ const constructs_1 = require("constructs");
22
+ class ServerlessSpy extends constructs_1.Construct {
23
+ constructor(scope, id) {
24
+ super(scope, id);
25
+ this.ownContructs = [];
26
+ this.functionSubscriptionPool = [];
27
+ this.extensionLayer = new lambda.LayerVersion(this, 'Extension', {
28
+ compatibleRuntimes: [
29
+ lambda.Runtime.NODEJS_12_X,
30
+ lambda.Runtime.NODEJS_14_X,
31
+ lambda.Runtime.NODEJS_16_X,
32
+ ],
33
+ code: lambda.Code.fromAsset(path.join(__dirname, '../lambda-extension/dist/layer')),
34
+ });
35
+ this.ownContructs.push(this.extensionLayer);
36
+ this.table = new dynamoDb.Table(this, 'WebSocket', {
37
+ partitionKey: {
38
+ name: 'connectionId',
39
+ type: dynamoDb.AttributeType.STRING,
40
+ },
41
+ billingMode: dynamoDb.BillingMode.PAY_PER_REQUEST,
42
+ });
43
+ this.ownContructs.push(this.table);
44
+ const functionOnConnect = new lambdaNode.NodejsFunction(this, 'OnConnect', {
45
+ memorySize: 512,
46
+ timeout: aws_cdk_lib_1.Duration.seconds(5),
47
+ runtime: lambda.Runtime.NODEJS_16_X,
48
+ handler: 'handler',
49
+ entry: path.join(__dirname, '../functions/onConnect.ts'),
50
+ environment: {
51
+ TABLE_NAME: this.table.tableName,
52
+ },
53
+ });
54
+ this.table.grantWriteData(functionOnConnect);
55
+ this.ownContructs.push(functionOnConnect);
56
+ const functionOnDisconnect = new lambdaNode.NodejsFunction(this, 'OnDisconnect', {
57
+ memorySize: 512,
58
+ timeout: aws_cdk_lib_1.Duration.seconds(5),
59
+ runtime: lambda.Runtime.NODEJS_16_X,
60
+ handler: 'handler',
61
+ entry: path.join(__dirname, '../functions/onDisconnect.ts'),
62
+ environment: {
63
+ TABLE_NAME: this.table.tableName,
64
+ },
65
+ });
66
+ this.table.grantWriteData(functionOnDisconnect);
67
+ this.ownContructs.push(functionOnDisconnect);
68
+ this.webSocketApi = new apiGwV2.WebSocketApi(this, 'ApiGwWebSocket');
69
+ this.ownContructs.push(this.webSocketApi);
70
+ this.webSocketStage = new apiGwV2.WebSocketStage(this, 'ApiGwWebSocketStage', {
71
+ webSocketApi: this.webSocketApi,
72
+ stageName: 'prod',
73
+ autoDeploy: true,
74
+ });
75
+ this.ownContructs.push(this.webSocketStage);
76
+ const webSocketApiRoute = this.webSocketApi.addRoute('$connect', {
77
+ integration: new apiGwV2Int.WebSocketLambdaIntegration('$connect', functionOnConnect),
78
+ });
79
+ webSocketApiRoute.node.defaultChild.authorizationType =
80
+ 'AWS_IAM';
81
+ this.webSocketApi.addRoute('$disconnect', {
82
+ integration: new apiGwV2Int.WebSocketLambdaIntegration('$disconnect', functionOnDisconnect),
83
+ });
84
+ this.functionSubscriptionMain = this.provideFunctionForSubscription();
85
+ this.webSocketApi.addRoute('sendmessage', {
86
+ integration: new apiGwV2Int.WebSocketLambdaIntegration('SendMessage', this.functionSubscriptionMain.function),
87
+ });
88
+ this.iterateAllElements(aws_cdk_lib_1.Stack.of(this));
89
+ for (const func of this.functionSubscriptionPool) {
90
+ func.function.addEnvironment('INFRA_MAPPING', JSON.stringify(func.mapping));
91
+ }
92
+ // new CfnOutput(this, "API_URL", {
93
+ // value: `wss://${this.webSocketApi.apiId}.execute-api.${
94
+ // Stack.of(scope).region
95
+ // }.amazonaws.com/${this.webSocketStage.stageName}`,
96
+ // });
97
+ this.wsUrl = `wss://${this.webSocketApi.apiId}.execute-api.${aws_cdk_lib_1.Stack.of(this).region}.amazonaws.com/${this.webSocketStage.stageName}`;
98
+ // new CfnOutput(this, "API_URL", {
99
+ // value: this.wsUrl,
100
+ // });
101
+ }
102
+ iterateAllElements(parent) {
103
+ for (const node of parent.node.children) {
104
+ if (this.ownContructs.includes(node)) {
105
+ continue;
106
+ }
107
+ if (this.functionSubscriptionPool.find((s) => s.function === node)) {
108
+ continue;
109
+ }
110
+ console.log('NODE', node.constructor.name);
111
+ if (node instanceof lambda.Function) {
112
+ this.interceptFunction(node);
113
+ }
114
+ else if (node instanceof sns.Topic) {
115
+ console.log('interceptSnsTopic');
116
+ this.interceptSnsTopic(node);
117
+ }
118
+ else if (node instanceof sns.Subscription) {
119
+ this.interceptSnsSubscription(node);
120
+ }
121
+ else if (node instanceof s3.Bucket) {
122
+ this.interceptS3(node);
123
+ }
124
+ else if (node instanceof dynamoDb.Table) {
125
+ this.interceptDynamodb(node);
126
+ }
127
+ else if (node instanceof events.EventBus) {
128
+ this.interceptEventBus(node);
129
+ }
130
+ else if (node instanceof events.Rule) {
131
+ this.interceptEventBusRule(node);
132
+ }
133
+ else if (node instanceof lambda.CfnEventSourceMapping) {
134
+ this.interceptSqs(node);
135
+ }
136
+ else {
137
+ // console.log('NO MATCH', node);
138
+ }
139
+ this.iterateAllElements(node);
140
+ }
141
+ }
142
+ interceptSqs(node) {
143
+ const queue = this.findElement((n) => n instanceof sqs.Queue &&
144
+ n.queueArn === node.eventSourceArn);
145
+ const func = this.findElement((n) => n instanceof lambda.Function &&
146
+ n.functionName === node.functionName);
147
+ if (queue && func) {
148
+ const queueName = this.getConstructName(queue);
149
+ this.functionSubscriptionMain.mapping[queue.queueArn] = `Sqs#${queueName}`;
150
+ func.addEnvironment('FLUENT_TEST_SUBSCRIBED_TO_SQS', 'true');
151
+ }
152
+ }
153
+ createFunctionForSubscription(index) {
154
+ const func = new lambdaNode.NodejsFunction(this, `Subscription${index}`, {
155
+ memorySize: 512,
156
+ timeout: aws_cdk_lib_1.Duration.seconds(5),
157
+ runtime: lambda.Runtime.NODEJS_16_X,
158
+ handler: 'handler',
159
+ entry: path.join(__dirname, '../functions/sendMessage.ts'),
160
+ environment: {
161
+ TABLE_NAME: this.table.tableName,
162
+ },
163
+ });
164
+ this.table.grantWriteData(func);
165
+ this.table.grantReadData(func);
166
+ func.addEnvironment('WS_ENDPOINT', `https://${this.webSocketApi.apiId}.execute-api.${aws_cdk_lib_1.Stack.of(this).region}.amazonaws.com/${this.webSocketStage.stageName}`);
167
+ this.webSocketApi.grantManageConnections(func);
168
+ return func;
169
+ }
170
+ interceptS3(s3Bucket) {
171
+ s3Bucket.addEventNotification(s3.EventType.OBJECT_CREATED_PUT, new s3notif.LambdaDestination(this.functionSubscriptionMain.function));
172
+ const name = this.getConstructName(s3Bucket);
173
+ this.functionSubscriptionMain.mapping[s3Bucket.bucketArn] = `S3#${name}`;
174
+ }
175
+ interceptDynamodb(table) {
176
+ // enable DynamoDB streams with a hack
177
+ table.node.defaultChild.streamSpecification = {
178
+ streamViewType: dynamoDb.StreamViewType.NEW_AND_OLD_IMAGES,
179
+ };
180
+ table.tableStreamArn = table.node.defaultChild.attrStreamArn;
181
+ this.functionSubscriptionMain.function.addEventSource(new dynamoDbStream.DynamoEventSource(table, {
182
+ startingPosition: lambda.StartingPosition.LATEST,
183
+ batchSize: 1,
184
+ retryAttempts: 0,
185
+ }));
186
+ const name = this.getConstructName(table);
187
+ this.functionSubscriptionMain.mapping[table.tableArn] = `DynamoDB#${name}`;
188
+ }
189
+ interceptEventBusRule(rule) {
190
+ const { eventBusName } = rule.node.defaultChild;
191
+ const eventBridge = this.getEventBridge(rule.node.defaultChild.eventBusName);
192
+ if (!eventBridge) {
193
+ throw new Error(`Can not find EventBridge with name "${eventBusName}"`);
194
+ }
195
+ const functionSubscription = this.provideFunctionForSubscription((s) => !s.usedForEventBridge);
196
+ functionSubscription.usedForEventBridge = true;
197
+ rule.addTarget(new targets.LambdaFunction(functionSubscription.function));
198
+ const bridgeName = this.getConstructName(eventBridge);
199
+ const ruleName = this.getConstructName(rule);
200
+ functionSubscription.mapping.eventBridge = `EventBridgeRule#${bridgeName}#${ruleName}`;
201
+ }
202
+ interceptEventBus(eventBus) {
203
+ const functionSubscription = this.provideFunctionForSubscription((s) => !s.usedForEventBridge);
204
+ functionSubscription.usedForEventBridge = true;
205
+ const bridgeName = this.getConstructName(eventBus);
206
+ const rule = new events.Rule(this, `RuleAll${bridgeName}`, {
207
+ eventBus,
208
+ eventPattern: { version: ['0'] },
209
+ targets: [new targets.LambdaFunction(functionSubscription.function)],
210
+ });
211
+ this.ownContructs.push(rule);
212
+ functionSubscription.mapping.eventBridge = `EventBridge#${bridgeName}`;
213
+ }
214
+ interceptSnsTopic(topic) {
215
+ const functionSubscription = this.provideFunctionForSubscription((s) => !s.subsribedTopics.includes(topic));
216
+ topic.addSubscription(new snsSubs.LambdaSubscription(functionSubscription.function));
217
+ const topicName = this.getConstructName(topic);
218
+ functionSubscription.mapping[topic.topicArn] = `SnsTopic#${topicName}`;
219
+ functionSubscription.subsribedTopics.push(topic);
220
+ }
221
+ interceptSnsSubscription(subscription) {
222
+ if (!subscription.node.scope) {
223
+ return;
224
+ }
225
+ const topic = this.getTopic(subscription.node.defaultChild.topicArn);
226
+ if (!topic) {
227
+ throw new Error('Can not find Topic');
228
+ }
229
+ const functionSubscription = this.provideFunctionForSubscription((s) => !s.subsribedTopics.includes(topic));
230
+ const { filterPolicy } = subscription.node
231
+ .defaultChild;
232
+ const subscriptionClone = topic.addSubscription(new snsSubs.LambdaSubscription(functionSubscription.function));
233
+ subscriptionClone.node.defaultChild.filterPolicy =
234
+ filterPolicy;
235
+ this.ownContructs.push(subscriptionClone);
236
+ const topicName = this.getConstructName(topic);
237
+ const targetName = this.getConstructName(subscription.node.scope);
238
+ functionSubscription.subsribedTopics.push(topic);
239
+ functionSubscription.mapping[topic.topicArn] = `SnsSubscription#${topicName}#${targetName}`;
240
+ }
241
+ provideFunctionForSubscription(filterFunction) {
242
+ let functionSubscription;
243
+ if (filterFunction) {
244
+ functionSubscription = this.functionSubscriptionPool.find(filterFunction);
245
+ }
246
+ else if (this.functionSubscriptionPool.length > 0) {
247
+ functionSubscription = this.functionSubscriptionPool[0];
248
+ }
249
+ if (!functionSubscription) {
250
+ functionSubscription = {
251
+ subsribedTopics: [],
252
+ usedForEventBridge: false,
253
+ mapping: {},
254
+ function: this.createFunctionForSubscription(this.functionSubscriptionPool.length),
255
+ };
256
+ this.functionSubscriptionPool.push(functionSubscription);
257
+ }
258
+ return functionSubscription;
259
+ }
260
+ interceptFunction(func) {
261
+ func.addLayers(this.extensionLayer);
262
+ this.functionSubscriptionMain.function.grantInvoke(func);
263
+ const functionName = this.getConstructName(func);
264
+ func.addEnvironment('FUNCTION_NAME', functionName);
265
+ func.addEnvironment('AWS_LAMBDA_EXEC_WRAPPER', '/opt/spy-wrapper');
266
+ func.addEnvironment('FLUENT_TEST_SEND_FUNCTION_NAME', this.functionSubscriptionMain.function.functionName);
267
+ }
268
+ getConstructName(construct) {
269
+ let functionName = construct.node.path;
270
+ const { stackName } = aws_cdk_lib_1.Stack.of(this);
271
+ if (functionName.startsWith(stackName)) {
272
+ functionName = functionName.substring(stackName.length + 1);
273
+ }
274
+ return functionName;
275
+ }
276
+ getTopic(topicArn) {
277
+ const topic = this.findElement((node) => node instanceof sns.Topic && node.topicArn === topicArn);
278
+ return topic;
279
+ }
280
+ getEventBridge(eventBusName) {
281
+ const eventBridge = this.findElement((node) => node instanceof events.EventBus &&
282
+ node.eventBusName === eventBusName);
283
+ return eventBridge;
284
+ }
285
+ findElement(filterFunc, parent) {
286
+ if (!parent) {
287
+ parent = aws_cdk_lib_1.Stack.of(this);
288
+ }
289
+ for (const node of parent.node.children) {
290
+ if (filterFunc(node)) {
291
+ return node;
292
+ }
293
+ this.findElement(filterFunc, node);
294
+ }
295
+ return undefined;
296
+ }
297
+ }
298
+ exports.ServerlessSpy = ServerlessSpy;
299
+ _a = JSII_RTTI_SYMBOL_1;
300
+ ServerlessSpy[_a] = { fqn: "serverless-spy.ServerlessSpy", version: "0.0.0" };
301
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VydmVybGVzc1NweS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9TZXJ2ZXJsZXNzU3B5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsNkJBQTZCO0FBQzdCLDJEQUEyRDtBQUMzRCwyRUFBMkU7QUFDM0UsNkNBQThDO0FBRTlDLHFEQUFxRDtBQUNyRCxpREFBaUQ7QUFDakQsMERBQTBEO0FBQzFELGlEQUFpRDtBQUNqRCx1RUFBdUU7QUFDdkUsNERBQTREO0FBQzVELHlDQUF5QztBQUN6Qyw0REFBNEQ7QUFDNUQsMkNBQTJDO0FBQzNDLDZEQUE2RDtBQUM3RCwyQ0FBMkM7QUFDM0MsMkNBQW1EO0FBRW5ELE1BQWEsYUFBYyxTQUFRLHNCQUFTO0lBaUIxQyxZQUFZLEtBQWdCLEVBQUUsRUFBVTtRQUN0QyxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBWFgsaUJBQVksR0FBaUIsRUFBRSxDQUFDO1FBRWhDLDZCQUF3QixHQUEyQixFQUFFLENBQUM7UUFXNUQsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLE1BQU0sQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLFdBQVcsRUFBRTtZQUMvRCxrQkFBa0IsRUFBRTtnQkFDbEIsTUFBTSxDQUFDLE9BQU8sQ0FBQyxXQUFXO2dCQUMxQixNQUFNLENBQUMsT0FBTyxDQUFDLFdBQVc7Z0JBQzFCLE1BQU0sQ0FBQyxPQUFPLENBQUMsV0FBVzthQUMzQjtZQUNELElBQUksRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FDekIsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsZ0NBQWdDLENBQUMsQ0FDdkQ7U0FDRixDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7UUFFNUMsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLFFBQVEsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFF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QUFZLE1BQU0sQ0FBQyxRQUFRO1lBQzlCLElBQXdCLENBQUMsWUFBWSxLQUFLLFlBQVksQ0FDMUQsQ0FBQztRQUVGLE9BQU8sV0FBVyxDQUFDO0lBQ3JCLENBQUM7SUFFTyxXQUFXLENBQ2pCLFVBQXlDLEVBQ3pDLE1BQW1CO1FBRW5CLElBQUksQ0FBQyxNQUFNLEVBQUU7WUFDWCxNQUFNLEdBQUcsbUJBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDekI7UUFFRCxLQUFLLE1BQU0sSUFBSSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFO1lBQ3ZDLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFO2dCQUNwQixPQUFPLElBQVMsQ0FBQzthQUNsQjtZQUNELElBQUksQ0FBQyxXQUFXLENBQUksVUFBVSxFQUFFLElBQUksQ0FBQyxDQUFDO1NBQ3ZDO1FBRUQsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQzs7QUFyYUgsc0NBc2FDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCAqIGFzIGFwaUd3VjIgZnJvbSAnQGF3cy1jZGsvYXdzLWFwaWdhdGV3YXl2Mi1hbHBoYSc7XG5pbXBvcnQgKiBhcyBhcGlHd1YySW50IGZyb20gJ0Bhd3MtY2RrL2F3cy1hcGlnYXRld2F5djItaW50ZWdyYXRpb25zLWFscGhhJztcbmltcG9ydCB7IER1cmF0aW9uLCBTdGFjayB9IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCAqIGFzIGFndyBmcm9tICdhd3MtY2RrLWxpYi9hd3MtYXBpZ2F0ZXdheXYyJztcbmltcG9ydCAqIGFzIGR5bmFtb0RiIGZyb20gJ2F3cy1jZGstbGliL2F3cy1keW5hbW9kYic7XG5pbXBvcnQgKiBhcyBldmVudHMgZnJvbSAnYXdzLWNkay1saWIvYXdzLWV2ZW50cyc7XG5pbXBvcnQgKiBhcyB0YXJnZXRzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1ldmVudHMtdGFyZ2V0cyc7XG5pbXBvcnQgKiBhcyBsYW1iZGEgZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYSc7XG5pbXBvcnQgKiBhcyBkeW5hbW9EYlN0cmVhbSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhLWV2ZW50LXNvdXJjZXMnO1xuaW1wb3J0ICogYXMgbGFtYmRhTm9kZSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhLW5vZGVqcyc7XG5pbXBvcnQgKiBhcyBzMyBmcm9tICdhd3MtY2RrLWxpYi9hd3MtczMnO1xuaW1wb3J0ICogYXMgczNub3RpZiBmcm9tICdhd3MtY2RrLWxpYi9hd3MtczMtbm90aWZpY2F0aW9ucyc7XG5pbXBvcnQgKiBhcyBzbnMgZnJvbSAnYXdzLWNkay1saWIvYXdzLXNucyc7XG5pbXBvcnQgKiBhcyBzbnNTdWJzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1zbnMtc3Vic2NyaXB0aW9ucyc7XG5pbXBvcnQgKiBhcyBzcXMgZnJvbSAnYXdzLWNkay1saWIvYXdzLXNxcyc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QsIElDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcblxuZXhwb3J0IGNsYXNzIFNlcnZlcmxlc3NTcHkgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBwcml2YXRlIGV4dGVuc2lvbkxheWVyOiBsYW1iZGEuTGF5ZXJWZXJzaW9uO1xuXG4gIHByaXZhdGUgdGFibGU6IGR5bmFtb0RiLlRhYmxlO1xuXG4gIHByaXZhdGUgd2ViU29ja2V0QXBpOiBhcGlHd1YyLldlYlNvY2tldEFwaTtcblxuICBwcml2YXRlIG93bkNvbnRydWN0czogSUNvbnN0cnVjdFtdID0gW107XG5cbiAgcHJpdmF0ZSBmdW5jdGlvblN1YnNjcmlwdGlvblBvb2w6IEZ1bmN0aW9uU3Vic2NyaXB0aW9uW10gPSBbXTtcblxuICBwcml2YXRlIGZ1bmN0aW9uU3Vic2NyaXB0aW9uTWFpbjogRnVuY3Rpb25TdWJzY3JpcHRpb247XG5cbiAgcHJpdmF0ZSB3ZWJTb2NrZXRTdGFnZTogYXBpR3dWMi5XZWJTb2NrZXRTdGFnZTtcblxuICB3c1VybDogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgdGhpcy5leHRlbnNpb25MYXllciA9IG5ldyBsYW1iZGEuTGF5ZXJWZXJzaW9uKHRoaXMsICdFeHRlbnNpb24nLCB7XG4gICAgICBjb21wYXRpYmxlUnVudGltZXM6IFtcbiAgICAgICAgbGFtYmRhLlJ1bnRpbWUuTk9ERUpTXzEyX1gsXG4gICAgICAgIGxhbWJkYS5SdW50aW1lLk5PREVKU18xNF9YLFxuICAgICAgICBsYW1iZGEuUnVudGltZS5OT0RFSlNfMTZfWCxcbiAgICAgIF0sXG4gICAgICBjb2RlOiBsYW1iZGEuQ29kZS5mcm9tQXNzZXQoXG4gICAgICAgIHBhdGguam9pbihfX2Rpcm5hbWUsICcuLi9sYW1iZGEtZXh0ZW5zaW9uL2Rpc3QvbGF5ZXInKVxuICAgICAgKSxcbiAgICB9KTtcbiAgICB0aGlzLm93bkNvbnRydWN0cy5wdXNoKHRoaXMuZXh0ZW5zaW9uTGF5ZXIpO1xuXG4gICAgdGhpcy50YWJsZSA9IG5ldyBkeW5hbW9EYi5UYWJsZSh0aGlzLCAnV2ViU29ja2V0Jywge1xuICAgICAgcGFydGl0aW9uS2V5OiB7XG4gICAgICAgIG5hbWU6ICdjb25uZWN0aW9uSWQnLFxuICAgICAgICB0eXBlOiBkeW5hbW9EYi5BdHRyaWJ1dGVUeXBlLlNUUklORyxcbiAgICAgIH0sXG4gICAgICBiaWxsaW5nTW9kZTogZHluYW1vRGIuQmlsbGluZ01vZGUuUEFZX1BFUl9SRVFVRVNULFxuICAgIH0pO1xuICAgIHRoaXMub3duQ29udHJ1Y3RzLnB1c2godGhpcy50YWJsZSk7XG5cbiAgICBjb25zdCBmdW5jdGlvbk9uQ29ubmVjdCA9IG5ldyBsYW1iZGFOb2RlLk5vZGVqc0Z1bmN0aW9uKHRoaXMsICdPbkNvbm5lY3QnLCB7XG4gICAgICBtZW1vcnlTaXplOiA1MTIsXG4gICAgICB0aW1lb3V0OiBEdXJhdGlvbi5zZWNvbmRzKDUpLFxuICAgICAgcnVudGltZTogbGFtYmRhLlJ1bnRpbWUuTk9ERUpTXzE2X1gsXG4gICAgICBoYW5kbGVyOiAnaGFuZGxlcicsXG4gICAgICBlbnRyeTogcGF0aC5qb2luKF9fZGlybmFtZSwgJy4uL2Z1bmN0aW9ucy9vbkNvbm5lY3QudHMnKSxcbiAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgIFRBQkxFX05BTUU6IHRoaXMudGFibGUudGFibGVOYW1lLFxuICAgICAgfSxcbiAgICB9KTtcbiAgICB0aGlzLnRhYmxlLmdyYW50V3JpdGVEYXRhKGZ1bmN0aW9uT25Db25uZWN0KTtcbiAgICB0aGlzLm93bkNvbnRydWN0cy5wdXNoKGZ1bmN0aW9uT25Db25uZWN0KTtcblxuICAgIGNvbnN0IGZ1bmN0aW9uT25EaXNjb25uZWN0ID0gbmV3IGxhbWJkYU5vZGUuTm9kZWpzRnVuY3Rpb24oXG4gICAgICB0aGlzLFxuICAgICAgJ09uRGlzY29ubmVjdCcsXG4gICAgICB7XG4gICAgICAgIG1lbW9yeVNpemU6IDUxMixcbiAgICAgICAgdGltZW91dDogRHVyYXRpb24uc2Vjb25kcyg1KSxcbiAgICAgICAgcnVudGltZTogbGFtYmRhLlJ1bnRpbWUuTk9ERUpTXzE2X1gsXG4gICAgICAgIGhhbmRsZXI6ICdoYW5kbGVyJyxcbiAgICAgICAgZW50cnk6IHBhdGguam9pbihfX2Rpcm5hbWUsICcuLi9mdW5jdGlvbnMvb25EaXNjb25uZWN0LnRzJyksXG4gICAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgICAgVEFCTEVfTkFNRTogdGhpcy50YWJsZS50YWJsZU5hbWUsXG4gICAgICAgIH0sXG4gICAgICB9XG4gICAgKTtcbiAgICB0aGlzLnRhYmxlLmdyYW50V3JpdGVEYXRhKGZ1bmN0aW9uT25EaXNjb25uZWN0KTtcbiAgICB0aGlzLm93bkNvbnRydWN0cy5wdXNoKGZ1bmN0aW9uT25EaXNjb25uZWN0KTtcblxuICAgIHRoaXMud2ViU29ja2V0QXBpID0gbmV3IGFwaUd3VjIuV2ViU29ja2V0QXBpKHRoaXMsICdBcGlHd1dlYlNvY2tldCcpO1xuICAgIHRoaXMub3duQ29udHJ1Y3RzLnB1c2godGhpcy53ZWJTb2NrZXRBcGkpO1xuICAgIHRoaXMud2ViU29ja2V0U3RhZ2UgPSBuZXcgYXBpR3dWMi5XZWJTb2NrZXRTdGFnZShcbiAgICAgIHRoaXMsXG4gICAgICAnQXBpR3dXZWJTb2NrZXRTdGFnZScsXG4gICAgICB7XG4gICAgICAgIHdlYlNvY2tldEFwaTogdGhpcy53ZWJTb2NrZXRBcGksXG4gICAgICAgIHN0YWdlTmFtZTogJ3Byb2QnLFxuICAgICAgICBhdXRvRGVwbG95OiB0cnVlLFxuICAgICAgfVxuICAgICk7XG4gICAgdGhpcy5vd25Db250cnVjdHMucHVzaCh0aGlzLndlYlNvY2tldFN0YWdlKTtcbiAgICBjb25zdCB3ZWJTb2NrZXRBcGlSb3V0ZSA9IHRoaXMud2ViU29ja2V0QXBpLmFkZFJvdXRlKCckY29ubmVjdCcsIHtcbiAgICAgIGludGVncmF0aW9uOiBuZXcgYXBpR3dWMkludC5XZWJTb2NrZXRMYW1iZGFJbnRlZ3JhdGlvbihcbiAgICAgICAgJyRjb25uZWN0JyxcbiAgICAgICAgZnVuY3Rpb25PbkNvbm5lY3RcbiAgICAgICksXG4gICAgfSk7XG4gICAgKHdlYlNvY2tldEFwaVJvdXRlLm5vZGUuZGVmYXVsdENoaWxkIGFzIGFndy5DZm5Sb3V0ZSkuYXV0aG9yaXphdGlvblR5cGUgPVxuICAgICAgJ0FXU19JQU0nO1xuXG4gICAgdGhpcy53ZWJTb2NrZXRBcGkuYWRkUm91dGUoJyRkaXNjb25uZWN0Jywge1xuICAgICAgaW50ZWdyYXRpb246IG5ldyBhcGlHd1YySW50LldlYlNvY2tldExhbWJkYUludGVncmF0aW9uKFxuICAgICAgICAnJGRpc2Nvbm5lY3QnLFxuICAgICAgICBmdW5jdGlvbk9uRGlzY29ubmVjdFxuICAgICAgKSxcbiAgICB9KTtcblxuICAgIHRoaXMuZnVuY3Rpb25TdWJzY3JpcHRpb25NYWluID0gdGhpcy5wcm92aWRlRnVuY3Rpb25Gb3JTdWJzY3JpcHRpb24oKTtcblxuICAgIHRoaXMud2ViU29ja2V0QXBpLmFkZFJvdXRlKCdzZW5kbWVzc2FnZScsIHtcbiAgICAgIGludGVncmF0aW9uOiBuZXcgYXBpR3dWMkludC5XZWJTb2NrZXRMYW1iZGFJbnRlZ3JhdGlvbihcbiAgICAgICAgJ1NlbmRNZXNzYWdlJyxcbiAgICAgICAgdGhpcy5mdW5jdGlvblN1YnNjcmlwdGlvbk1haW4uZnVuY3Rpb25cbiAgICAgICksXG4gICAgfSk7XG5cbiAgICB0aGlzLml0ZXJhdGVBbGxFbGVtZW50cyhTdGFjay5vZih0aGlzKSk7XG5cbiAgICBmb3IgKGNvbnN0IGZ1bmMgb2YgdGhpcy5mdW5jdGlvblN1YnNjcmlwdGlvblBvb2wpIHtcbiAgICAgIGZ1bmMuZnVuY3Rpb24uYWRkRW52aXJvbm1lbnQoXG4gICAgICAgICdJTkZSQV9NQVBQSU5HJyxcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkoZnVuYy5tYXBwaW5nKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBuZXcgQ2ZuT3V0cHV0KHRoaXMsIFwiQVBJX1VSTFwiLCB7XG4gICAgLy8gICB2YWx1ZTogYHdzczovLyR7dGhpcy53ZWJTb2NrZXRBcGkuYXBpSWR9LmV4ZWN1dGUtYXBpLiR7XG4gICAgLy8gICAgIFN0YWNrLm9mKHNjb3BlKS5yZWdpb25cbiAgICAvLyAgIH0uYW1hem9uYXdzLmNvbS8ke3RoaXMud2ViU29ja2V0U3RhZ2Uuc3RhZ2VOYW1lfWAsXG4gICAgLy8gfSk7XG5cbiAgICB0aGlzLndzVXJsID0gYHdzczovLyR7dGhpcy53ZWJTb2NrZXRBcGkuYXBpSWR9LmV4ZWN1dGUtYXBpLiR7XG4gICAgICBTdGFjay5vZih0aGlzKS5yZWdpb25cbiAgICB9LmFtYXpvbmF3cy5jb20vJHt0aGlzLndlYlNvY2tldFN0YWdlLnN0YWdlTmFtZX1gO1xuXG4gICAgLy8gbmV3IENmbk91dHB1dCh0aGlzLCBcIkFQSV9VUkxcIiwge1xuICAgIC8vICAgdmFsdWU6IHRoaXMud3NVcmwsXG4gICAgLy8gfSk7XG4gIH1cblxuICBwcml2YXRlIGl0ZXJhdGVBbGxFbGVtZW50cyhwYXJlbnQ6IElDb25zdHJ1Y3QpIHtcbiAgICBmb3IgKGNvbnN0IG5vZGUgb2YgcGFyZW50Lm5vZGUuY2hpbGRyZW4pIHtcbiAgICAgIGlmICh0aGlzLm93bkNvbnRydWN0cy5pbmNsdWRlcyhub2RlKSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuZnVuY3Rpb25TdWJzY3JpcHRpb25Qb29sLmZpbmQoKHMpID0+IHMuZnVuY3Rpb24gPT09IG5vZGUpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBjb25zb2xlLmxvZygnTk9ERScsIG5vZGUuY29uc3RydWN0b3IubmFtZSk7XG5cbiAgICAgIGlmIChub2RlIGluc3RhbmNlb2YgbGFtYmRhLkZ1bmN0aW9uKSB7XG4gICAgICAgIHRoaXMuaW50ZXJjZXB0RnVuY3Rpb24obm9kZSk7XG4gICAgICB9IGVsc2UgaWYgKG5vZGUgaW5zdGFuY2VvZiBzbnMuVG9waWMpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ2ludGVyY2VwdFNuc1RvcGljJyk7XG4gICAgICAgIHRoaXMuaW50ZXJjZXB0U25zVG9waWMobm9kZSk7XG4gICAgICB9IGVsc2UgaWYgKG5vZGUgaW5zdGFuY2VvZiBzbnMuU3Vic2NyaXB0aW9uKSB7XG4gICAgICAgIHRoaXMuaW50ZXJjZXB0U25zU3Vic2NyaXB0aW9uKG5vZGUpO1xuICAgICAgfSBlbHNlIGlmIChub2RlIGluc3RhbmNlb2YgczMuQnVja2V0KSB7XG4gICAgICAgIHRoaXMuaW50ZXJjZXB0UzMobm9kZSk7XG4gICAgICB9IGVsc2UgaWYgKG5vZGUgaW5zdGFuY2VvZiBkeW5hbW9EYi5UYWJsZSkge1xuICAgICAgICB0aGlzLmludGVyY2VwdER5bmFtb2RiKG5vZGUpO1xuICAgICAgfSBlbHNlIGlmIChub2RlIGluc3RhbmNlb2YgZXZlbnRzLkV2ZW50QnVzKSB7XG4gICAgICAgIHRoaXMuaW50ZXJjZXB0RXZlbnRCdXMobm9kZSk7XG4gICAgICB9IGVsc2UgaWYgKG5vZGUgaW5zdGFuY2VvZiBldmVudHMuUnVsZSkge1xuICAgICAgICB0aGlzLmludGVyY2VwdEV2ZW50QnVzUnVsZShub2RlKTtcbiAgICAgIH0gZWxzZSBpZiAobm9kZSBpbnN0YW5jZW9mIGxhbWJkYS5DZm5FdmVudFNvdXJjZU1hcHBpbmcpIHtcbiAgICAgICAgdGhpcy5pbnRlcmNlcHRTcXMobm9kZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBjb25zb2xlLmxvZygnTk8gTUFUQ0gnLCBub2RlKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5pdGVyYXRlQWxsRWxlbWVudHMobm9kZSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBpbnRlcmNlcHRTcXMobm9kZTogbGFtYmRhLkNmbkV2ZW50U291cmNlTWFwcGluZykge1xuICAgIGNvbnN0IHF1ZXVlID0gdGhpcy5maW5kRWxlbWVudDxzcXMuUXVldWU+KFxuICAgICAgKG46IElDb25zdHJ1Y3QpID0+XG4gICAgICAgIG4gaW5zdGFuY2VvZiBzcXMuUXVldWUgJiZcbiAgICAgICAgKG4gYXMgc3FzLlF1ZXVlKS5xdWV1ZUFybiA9PT0gbm9kZS5ldmVudFNvdXJjZUFyblxuICAgICk7XG5cbiAgICBjb25zdCBmdW5jID0gdGhpcy5maW5kRWxlbWVudDxsYW1iZGEuRnVuY3Rpb24+KFxuICAgICAgKG46IElDb25zdHJ1Y3QpID0+XG4gICAgICAgIG4gaW5zdGFuY2VvZiBsYW1iZGEuRnVuY3Rpb24gJiZcbiAgICAgICAgKG4gYXMgbGFtYmRhLkZ1bmN0aW9uKS5mdW5jdGlvbk5hbWUgPT09IG5vZGUuZnVuY3Rpb25OYW1lXG4gICAgKTtcblxuICAgIGlmIChxdWV1ZSAmJiBmdW5jKSB7XG4gICAgICBjb25zdCBxdWV1ZU5hbWUgPSB0aGlzLmdldENvbnN0cnVjdE5hbWUocXVldWUpO1xuICAgICAgdGhpcy5mdW5jdGlvblN1YnNjcmlwdGlvbk1haW4ubWFwcGluZ1tcbiAgICAgICAgcXVldWUucXVldWVBcm5cbiAgICAgIF0gPSBgU3FzIyR7cXVldWVOYW1lfWA7XG4gICAgICBmdW5jLmFkZEVudmlyb25tZW50KCdGTFVFTlRfVEVTVF9TVUJTQ1JJQkVEX1RPX1NRUycsICd0cnVlJyk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVGdW5jdGlvbkZvclN1YnNjcmlwdGlvbihpbmRleDogbnVtYmVyKSB7XG4gICAgY29uc3QgZnVuYyA9IG5ldyBsYW1iZGFOb2RlLk5vZGVqc0Z1bmN0aW9uKHRoaXMsIGBTdWJzY3JpcHRpb24ke2luZGV4fWAsIHtcbiAgICAgIG1lbW9yeVNpemU6IDUxMixcbiAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLnNlY29uZHMoNSksXG4gICAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5OT0RFSlNfMTZfWCxcbiAgICAgIGhhbmRsZXI6ICdoYW5kbGVyJyxcbiAgICAgIGVudHJ5OiBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vZnVuY3Rpb25zL3NlbmRNZXNzYWdlLnRzJyksXG4gICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICBUQUJMRV9OQU1FOiB0aGlzLnRhYmxlLnRhYmxlTmFtZSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICB0aGlzLnRhYmxlLmdyYW50V3JpdGVEYXRhKGZ1bmMpO1xuICAgIHRoaXMudGFibGUuZ3JhbnRSZWFkRGF0YShmdW5jKTtcbiAgICBmdW5jLmFkZEVudmlyb25tZW50KFxuICAgICAgJ1dTX0VORFBPSU5UJyxcbiAgICAgIGBodHRwczovLyR7dGhpcy53ZWJTb2NrZXRBcGkuYXBpSWR9LmV4ZWN1dGUtYXBpLiR7XG4gICAgICAgIFN0YWNrLm9mKHRoaXMpLnJlZ2lvblxuICAgICAgfS5hbWF6b25hd3MuY29tLyR7dGhpcy53ZWJTb2NrZXRTdGFnZS5zdGFnZU5hbWV9YFxuICAgICk7XG5cbiAgICB0aGlzLndlYlNvY2tldEFwaS5ncmFudE1hbmFnZUNvbm5lY3Rpb25zKGZ1bmMpO1xuICAgIHJldHVybiBmdW5jO1xuICB9XG5cbiAgcHJpdmF0ZSBpbnRlcmNlcHRTMyhzM0J1Y2tldDogczMuQnVja2V0KSB7XG4gICAgczNCdWNrZXQuYWRkRXZlbnROb3RpZmljYXRpb24oXG4gICAgICBzMy5FdmVudFR5cGUuT0JKRUNUX0NSRUFURURfUFVULFxuICAgICAgbmV3IHMzbm90aWYuTGFtYmRhRGVzdGluYXRpb24odGhpcy5mdW5jdGlvblN1YnNjcmlwdGlvbk1haW4uZnVuY3Rpb24pXG4gICAgKTtcblxuICAgIGNvbnN0IG5hbWUgPSB0aGlzLmdldENvbnN0cnVjdE5hbWUoczNCdWNrZXQpO1xuICAgIHRoaXMuZnVuY3Rpb25TdWJzY3JpcHRpb25NYWluLm1hcHBpbmdbczNCdWNrZXQuYnVja2V0QXJuXSA9IGBTMyMke25hbWV9YDtcbiAgfVxuXG4gIHByaXZhdGUgaW50ZXJjZXB0RHluYW1vZGIodGFibGU6IGR5bmFtb0RiLlRhYmxlKSB7XG4gICAgLy8gZW5hYmxlIER5bmFtb0RCIHN0cmVhbXMgd2l0aCBhIGhhY2tcbiAgICAodGFibGUubm9kZS5kZWZhdWx0Q2hpbGQgYXMgZHluYW1vRGIuQ2ZuVGFibGUpLnN0cmVhbVNwZWNpZmljYXRpb24gPSB7XG4gICAgICBzdHJlYW1WaWV3VHlwZTogZHluYW1vRGIuU3RyZWFtVmlld1R5cGUuTkVXX0FORF9PTERfSU1BR0VTLFxuICAgIH07XG4gICAgKHRhYmxlIGFzIGFueSkudGFibGVTdHJlYW1Bcm4gPSAoXG4gICAgICB0YWJsZS5ub2RlLmRlZmF1bHRDaGlsZCBhcyBkeW5hbW9EYi5DZm5UYWJsZVxuICAgICkuYXR0clN0cmVhbUFybjtcblxuICAgIHRoaXMuZnVuY3Rpb25TdWJzY3JpcHRpb25NYWluLmZ1bmN0aW9uLmFkZEV2ZW50U291cmNlKFxuICAgICAgbmV3IGR5bmFtb0RiU3RyZWFtLkR5bmFtb0V2ZW50U291cmNlKHRhYmxlLCB7XG4gICAgICAgIHN0YXJ0aW5nUG9zaXRpb246IGxhbWJkYS5TdGFydGluZ1Bvc2l0aW9uLkxBVEVTVCxcbiAgICAgICAgYmF0Y2hTaXplOiAxLFxuICAgICAgICByZXRyeUF0dGVtcHRzOiAwLFxuICAgICAgfSlcbiAgICApO1xuXG4gICAgY29uc3QgbmFtZSA9IHRoaXMuZ2V0Q29uc3RydWN0TmFtZSh0YWJsZSk7XG5cbiAgICB0aGlzLmZ1bmN0aW9uU3Vic2NyaXB0aW9uTWFpbi5tYXBwaW5nW3RhYmxlLnRhYmxlQXJuXSA9IGBEeW5hbW9EQiMke25hbWV9YDtcbiAgfVxuXG4gIHByaXZhdGUgaW50ZXJjZXB0RXZlbnRCdXNSdWxlKHJ1bGU6IGV2ZW50cy5SdWxlKSB7XG4gICAgY29uc3QgeyBldmVudEJ1c05hbWUgfSA9IHJ1bGUubm9kZS5kZWZhdWx0Q2hpbGQgYXMgZXZlbnRzLkNmblJ1bGU7XG4gICAgY29uc3QgZXZlbnRCcmlkZ2UgPSB0aGlzLmdldEV2ZW50QnJpZGdlKFxuICAgICAgKHJ1bGUubm9kZS5kZWZhdWx0Q2hpbGQgYXMgYW55KS5ldmVudEJ1c05hbWVcbiAgICApO1xuXG4gICAgaWYgKCFldmVudEJyaWRnZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW4gbm90IGZpbmQgRXZlbnRCcmlkZ2Ugd2l0aCBuYW1lIFwiJHtldmVudEJ1c05hbWV9XCJgKTtcbiAgICB9XG5cbiAgICBjb25zdCBmdW5jdGlvblN1YnNjcmlwdGlvbiA9IHRoaXMucHJvdmlkZUZ1bmN0aW9uRm9yU3Vic2NyaXB0aW9uKFxuICAgICAgKHMpID0+ICFzLnVzZWRGb3JFdmVudEJyaWRnZVxuICAgICk7XG4gICAgZnVuY3Rpb25TdWJzY3JpcHRpb24udXNlZEZvckV2ZW50QnJpZGdlID0gdHJ1ZTtcblxuICAgIHJ1bGUuYWRkVGFyZ2V0KG5ldyB0YXJnZXRzLkxhbWJkYUZ1bmN0aW9uKGZ1bmN0aW9uU3Vic2NyaXB0aW9uLmZ1bmN0aW9uKSk7XG5cbiAgICBjb25zdCBicmlkZ2VOYW1lID0gdGhpcy5nZXRDb25zdHJ1Y3ROYW1lKGV2ZW50QnJpZGdlKTtcbiAgICBjb25zdCBydWxlTmFtZSA9IHRoaXMuZ2V0Q29uc3RydWN0TmFtZShydWxlKTtcbiAgICBmdW5jdGlvblN1YnNjcmlwdGlvbi5tYXBwaW5nLmV2ZW50QnJpZGdlID0gYEV2ZW50QnJpZGdlUnVsZSMke2JyaWRnZU5hbWV9IyR7cnVsZU5hbWV9YDtcbiAgfVxuXG4gIHByaXZhdGUgaW50ZXJjZXB0RXZlbnRCdXMoZXZlbnRCdXM6IGV2ZW50cy5FdmVudEJ1cykge1xuICAgIGNvbnN0IGZ1bmN0aW9uU3Vic2NyaXB0aW9uID0gdGhpcy5wcm92aWRlRnVuY3Rpb25Gb3JTdWJzY3JpcHRpb24oXG4gICAgICAocykgPT4gIXMudXNlZEZvckV2ZW50QnJpZGdlXG4gICAgKTtcbiAgICBmdW5jdGlvblN1YnNjcmlwdGlvbi51c2VkRm9yRXZlbnRCcmlkZ2UgPSB0cnVlO1xuXG4gICAgY29uc3QgYnJpZGdlTmFtZSA9IHRoaXMuZ2V0Q29uc3RydWN0TmFtZShldmVudEJ1cyk7XG4gICAgY29uc3QgcnVsZSA9IG5ldyBldmVudHMuUnVsZSh0aGlzLCBgUnVsZUFsbCR7YnJpZGdlTmFtZX1gLCB7XG4gICAgICBldmVudEJ1cyxcbiAgICAgIGV2ZW50UGF0dGVybjogeyB2ZXJzaW9uOiBbJzAnXSB9LFxuICAgICAgdGFyZ2V0czogW25ldyB0YXJnZXRzLkxhbWJkYUZ1bmN0aW9uKGZ1bmN0aW9uU3Vic2NyaXB0aW9uLmZ1bmN0aW9uKV0sXG4gICAgfSk7XG5cbiAgICB0aGlzLm93bkNvbnRydWN0cy5wdXNoKHJ1bGUpO1xuICAgIGZ1bmN0aW9uU3Vic2NyaXB0aW9uLm1hcHBpbmcuZXZlbnRCcmlkZ2UgPSBgRXZlbnRCcmlkZ2UjJHticmlkZ2VOYW1lfWA7XG4gIH1cblxuICBwcml2YXRlIGludGVyY2VwdFNuc1RvcGljKHRvcGljOiBzbnMuVG9waWMpIHtcbiAgICBjb25zdCBmdW5jdGlvblN1YnNjcmlwdGlvbiA9IHRoaXMucHJvdmlkZUZ1bmN0aW9uRm9yU3Vic2NyaXB0aW9uKFxuICAgICAgKHMpID0+ICFzLnN1YnNyaWJlZFRvcGljcy5pbmNsdWRlcyh0b3BpYylcbiAgICApO1xuXG4gICAgdG9waWMuYWRkU3Vic2NyaXB0aW9uKFxuICAgICAgbmV3IHNuc1N1YnMuTGFtYmRhU3Vic2NyaXB0aW9uKGZ1bmN0aW9uU3Vic2NyaXB0aW9uLmZ1bmN0aW9uKVxuICAgICk7XG4gICAgY29uc3QgdG9waWNOYW1lID0gdGhpcy5nZXRDb25zdHJ1Y3ROYW1lKHRvcGljKTtcbiAgICBmdW5jdGlvblN1YnNjcmlwdGlvbi5tYXBwaW5nW3RvcGljLnRvcGljQXJuXSA9IGBTbnNUb3BpYyMke3RvcGljTmFtZX1gO1xuICAgIGZ1bmN0aW9uU3Vic2NyaXB0aW9uLnN1YnNyaWJlZFRvcGljcy5wdXNoKHRvcGljKTtcbiAgfVxuXG4gIHByaXZhdGUgaW50ZXJjZXB0U25zU3Vic2NyaXB0aW9uKHN1YnNjcmlwdGlvbjogc25zLlN1YnNjcmlwdGlvbikge1xuICAgIGlmICghc3Vic2NyaXB0aW9uLm5vZGUuc2NvcGUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCB0b3BpYyA9IHRoaXMuZ2V0VG9waWMoXG4gICAgICAoc3Vic2NyaXB0aW9uLm5vZGUuZGVmYXVsdENoaWxkIGFzIHNucy5DZm5TdWJzY3JpcHRpb24pLnRvcGljQXJuXG4gICAgKTtcblxuICAgIGlmICghdG9waWMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ2FuIG5vdCBmaW5kIFRvcGljJyk7XG4gICAgfVxuXG4gICAgY29uc3QgZnVuY3Rpb25TdWJzY3JpcHRpb24gPSB0aGlzLnByb3ZpZGVGdW5jdGlvbkZvclN1YnNjcmlwdGlvbihcbiAgICAgIChzKSA9PiAhcy5zdWJzcmliZWRUb3BpY3MuaW5jbHVkZXModG9waWMpXG4gICAgKTtcblxuICAgIGNvbnN0IHsgZmlsdGVyUG9saWN5IH0gPSBzdWJzY3JpcHRpb24ubm9kZVxuICAgICAgLmRlZmF1bHRDaGlsZCBhcyBzbnMuQ2ZuU3Vic2NyaXB0aW9uO1xuXG4gICAgY29uc3Qgc3Vic2NyaXB0aW9uQ2xvbmUgPSB0b3BpYy5hZGRTdWJzY3JpcHRpb24oXG4gICAgICBuZXcgc25zU3Vicy5MYW1iZGFTdWJzY3JpcHRpb24oZnVuY3Rpb25TdWJzY3JpcHRpb24uZnVuY3Rpb24pXG4gICAgKTtcbiAgICAoc3Vic2NyaXB0aW9uQ2xvbmUubm9kZS5kZWZhdWx0Q2hpbGQgYXMgc25zLkNmblN1YnNjcmlwdGlvbikuZmlsdGVyUG9saWN5ID1cbiAgICAgIGZpbHRlclBvbGljeTtcblxuICAgIHRoaXMub3duQ29udHJ1Y3RzLnB1c2goc3Vic2NyaXB0aW9uQ2xvbmUpO1xuXG4gICAgY29uc3QgdG9waWNOYW1lID0gdGhpcy5nZXRDb25zdHJ1Y3ROYW1lKHRvcGljKTtcbiAgICBjb25zdCB0YXJnZXROYW1lID0gdGhpcy5nZXRDb25zdHJ1Y3ROYW1lKHN1YnNjcmlwdGlvbi5ub2RlLnNjb3BlKTtcblxuICAgIGZ1bmN0aW9uU3Vic2NyaXB0aW9uLnN1YnNyaWJlZFRvcGljcy5wdXNoKHRvcGljKTtcbiAgICBmdW5jdGlvblN1YnNjcmlwdGlvbi5tYXBwaW5nW1xuICAgICAgdG9waWMudG9waWNBcm5cbiAgICBdID0gYFNuc1N1YnNjcmlwdGlvbiMke3RvcGljTmFtZX0jJHt0YXJnZXROYW1lfWA7XG4gIH1cblxuICBwcml2YXRlIHByb3ZpZGVGdW5jdGlvbkZvclN1YnNjcmlwdGlvbihcbiAgICBmaWx0ZXJGdW5jdGlvbj86IChzdWJzY3JpcHRpb246IEZ1bmN0aW9uU3Vic2NyaXB0aW9uKSA9PiBib29sZWFuXG4gICkge1xuICAgIGxldCBmdW5jdGlvblN1YnNjcmlwdGlvbjogRnVuY3Rpb25TdWJzY3JpcHRpb24gfCB1bmRlZmluZWQ7XG5cbiAgICBpZiAoZmlsdGVyRnVuY3Rpb24pIHtcbiAgICAgIGZ1bmN0aW9uU3Vic2NyaXB0aW9uID0gdGhpcy5mdW5jdGlvblN1YnNjcmlwdGlvblBvb2wuZmluZChmaWx0ZXJGdW5jdGlvbik7XG4gICAgfSBlbHNlIGlmICh0aGlzLmZ1bmN0aW9uU3Vic2NyaXB0aW9uUG9vbC5sZW5ndGggPiAwKSB7XG4gICAgICBmdW5jdGlvblN1YnNjcmlwdGlvbiA9IHRoaXMuZnVuY3Rpb25TdWJzY3JpcHRpb25Qb29sWzBdO1xuICAgIH1cblxuICAgIGlmICghZnVuY3Rpb25TdWJzY3JpcHRpb24pIHtcbiAgICAgIGZ1bmN0aW9uU3Vic2NyaXB0aW9uID0ge1xuICAgICAgICBzdWJzcmliZWRUb3BpY3M6IFtdLFxuICAgICAgICB1c2VkRm9yRXZlbnRCcmlkZ2U6IGZhbHNlLFxuICAgICAgICBtYXBwaW5nOiB7fSxcbiAgICAgICAgZnVuY3Rpb246IHRoaXMuY3JlYXRlRnVuY3Rpb25Gb3JTdWJzY3JpcHRpb24oXG4gICAgICAgICAgdGhpcy5mdW5jdGlvblN1YnNjcmlwdGlvblBvb2wubGVuZ3RoXG4gICAgICAgICksXG4gICAgICB9O1xuICAgICAgdGhpcy5mdW5jdGlvblN1YnNjcmlwdGlvblBvb2wucHVzaChmdW5jdGlvblN1YnNjcmlwdGlvbik7XG4gICAgfVxuICAgIHJldHVybiBmdW5jdGlvblN1YnNjcmlwdGlvbjtcbiAgfVxuXG4gIHByaXZhdGUgaW50ZXJjZXB0RnVuY3Rpb24oZnVuYzogbGFtYmRhLkZ1bmN0aW9uKSB7XG4gICAgZnVuYy5hZGRMYXllcnModGhpcy5leHRlbnNpb25MYXllcik7XG4gICAgdGhpcy5mdW5jdGlvblN1YnNjcmlwdGlvbk1haW4uZnVuY3Rpb24uZ3JhbnRJbnZva2UoZnVuYyk7XG5cbiAgICBjb25zdCBmdW5jdGlvbk5hbWUgPSB0aGlzLmdldENvbnN0cnVjdE5hbWUoZnVuYyk7XG5cbiAgICBmdW5jLmFkZEVudmlyb25tZW50KCdGVU5DVElPTl9OQU1FJywgZnVuY3Rpb25OYW1lKTtcbiAgICBmdW5jLmFkZEVudmlyb25tZW50KCdBV1NfTEFNQkRBX0VYRUNfV1JBUFBFUicsICcvb3B0L3NweS13cmFwcGVyJyk7XG4gICAgZnVuYy5hZGRFbnZpcm9ubWVudChcbiAgICAgICdGTFVFTlRfVEVTVF9TRU5EX0ZVTkNUSU9OX05BTUUnLFxuICAgICAgdGhpcy5mdW5jdGlvblN1YnNjcmlwdGlvbk1haW4uZnVuY3Rpb24uZnVuY3Rpb25OYW1lXG4gICAgKTtcbiAgfVxuXG4gIHB1YmxpYyBnZXRDb25zdHJ1Y3ROYW1lKGNvbnN0cnVjdDogSUNvbnN0cnVjdCkge1xuICAgIGxldCBmdW5jdGlvbk5hbWUgPSBjb25zdHJ1Y3Qubm9kZS5wYXRoO1xuICAgIGNvbnN0IHsgc3RhY2tOYW1lIH0gPSBTdGFjay5vZih0aGlzKTtcblxuICAgIGlmIChmdW5jdGlvbk5hbWUuc3RhcnRzV2l0aChzdGFja05hbWUpKSB7XG4gICAgICBmdW5jdGlvbk5hbWUgPSBmdW5jdGlvbk5hbWUuc3Vic3RyaW5nKHN0YWNrTmFtZS5sZW5ndGggKyAxKTtcbiAgICB9XG4gICAgcmV0dXJuIGZ1bmN0aW9uTmFtZTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0VG9waWModG9waWNBcm46IHN0cmluZyk6IHNucy5Ub3BpYyB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgdG9waWMgPSB0aGlzLmZpbmRFbGVtZW50PHNucy5Ub3BpYz4oXG4gICAgICAobm9kZTogSUNvbnN0cnVjdCkgPT5cbiAgICAgICAgbm9kZSBpbnN0YW5jZW9mIHNucy5Ub3BpYyAmJiAobm9kZSBhcyBzbnMuVG9waWMpLnRvcGljQXJuID09PSB0b3BpY0FyblxuICAgICk7XG5cbiAgICByZXR1cm4gdG9waWM7XG4gIH1cblxuICBwcml2YXRlIGdldEV2ZW50QnJpZGdlKGV2ZW50QnVzTmFtZTogc3RyaW5nKTogZXZlbnRzLkV2ZW50QnVzIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCBldmVudEJyaWRnZSA9IHRoaXMuZmluZEVsZW1lbnQ8ZXZlbnRzLkV2ZW50QnVzPihcbiAgICAgIChub2RlOiBJQ29uc3RydWN0KSA9PlxuICAgICAgICBub2RlIGluc3RhbmNlb2YgZXZlbnRzLkV2ZW50QnVzICYmXG4gICAgICAgIChub2RlIGFzIGV2ZW50cy5FdmVudEJ1cykuZXZlbnRCdXNOYW1lID09PSBldmVudEJ1c05hbWVcbiAgICApO1xuXG4gICAgcmV0dXJuIGV2ZW50QnJpZGdlO1xuICB9XG5cbiAgcHJpdmF0ZSBmaW5kRWxlbWVudDxUIGV4dGVuZHMgSUNvbnN0cnVjdCA9IElDb25zdHJ1Y3Q+KFxuICAgIGZpbHRlckZ1bmM6IChub2RlOiBJQ29uc3RydWN0KSA9PiBib29sZWFuLFxuICAgIHBhcmVudD86IElDb25zdHJ1Y3RcbiAgKTogVCB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKCFwYXJlbnQpIHtcbiAgICAgIHBhcmVudCA9IFN0YWNrLm9mKHRoaXMpO1xuICAgIH1cblxuICAgIGZvciAoY29uc3Qgbm9kZSBvZiBwYXJlbnQubm9kZS5jaGlsZHJlbikge1xuICAgICAgaWYgKGZpbHRlckZ1bmMobm9kZSkpIHtcbiAgICAgICAgcmV0dXJuIG5vZGUgYXMgVDtcbiAgICAgIH1cbiAgICAgIHRoaXMuZmluZEVsZW1lbnQ8VD4oZmlsdGVyRnVuYywgbm9kZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG50eXBlIEZ1bmN0aW9uU3Vic2NyaXB0aW9uID0ge1xuICBzdWJzcmliZWRUb3BpY3M6IHNucy5Ub3BpY1tdO1xuICB1c2VkRm9yRXZlbnRCcmlkZ2U6IGJvb2xlYW47XG4gIGZ1bmN0aW9uOiBsYW1iZGFOb2RlLk5vZGVqc0Z1bmN0aW9uO1xuICBtYXBwaW5nOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xufTtcbiJdfQ==
package/lib/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './ServerlessSpy';
package/lib/index.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p);
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ __exportStar(require("./ServerlessSpy"), exports);
14
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBQUEsa0RBQWdDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0ICogZnJvbSAnLi9TZXJ2ZXJsZXNzU3B5JztcbiJdfQ==
@@ -0,0 +1,5 @@
1
+ export type PrettifyForDisplay<T> = T extends Function
2
+ ? T
3
+ : {
4
+ [K in keyof T]: T[K];
5
+ };
@@ -0,0 +1,9 @@
1
+ import { PrettifyForDisplay } from './PrettifyForDisplay';
2
+
3
+ export type RecursivePartial<T> = {
4
+ [P in keyof T]?: T[P] extends (infer U)[]
5
+ ? PrettifyForDisplay<RecursivePartial<U>>[]
6
+ : T[P] extends object
7
+ ? PrettifyForDisplay<RecursivePartial<T[P]>>
8
+ : T[P];
9
+ };
@@ -0,0 +1,190 @@
1
+ import { DynamoDBSpyEvent } from 'serverless-spy-common/spyEvents/DynamoDBSpyEvent';
2
+ import { EventBridgeRuleSpyEvent } from 'serverless-spy-common/spyEvents/EventBridgeRuleSpyEvent';
3
+ import { EventBridgeSpyEvent } from 'serverless-spy-common/spyEvents/EventBridgeSpyEvent';
4
+ import { FunctionConsoleSpyEvent } from 'serverless-spy-common/spyEvents/FunctionConsoleSpyEvent';
5
+ import { FunctionContext } from 'serverless-spy-common/spyEvents/FunctionContext';
6
+ import { FunctionRequestSpyEvent } from 'serverless-spy-common/spyEvents/FunctionRequestSpyEvent';
7
+ import { FunctionResponseSpyEvent } from 'serverless-spy-common/spyEvents/FunctionResponseSpyEvent';
8
+ import { S3SpyEvent } from 'serverless-spy-common/spyEvents/S3SpyEvent';
9
+ import { SnsSubscriptionSpyEvent } from 'serverless-spy-common/spyEvents/SnsSubscriptionSpyEvent';
10
+ import { SnsTopicSpyEvent } from 'serverless-spy-common/spyEvents/SnsTopicSpyEvent';
11
+ import { SqsSpyEvent } from 'serverless-spy-common/spyEvents/SqsSpyEvent';
12
+ import { PrettifyForDisplay } from './PrettifyForDisplay';
13
+ import { RecursivePartial } from './RecursivePartial';
14
+
15
+ type MyJestMatchers = ReturnType<typeof expect>;
16
+ type MyJestMatchersWitOnlyFunctions = Pick<
17
+ MyJestMatchers,
18
+ {
19
+ [P in keyof MyJestMatchers]: MyJestMatchers[P] extends (...args: any) => any
20
+ ? P
21
+ : never;
22
+ }[keyof MyJestMatchers]
23
+ >;
24
+ type JestExpectWithSpyMethods<TSpyEvent, TSpyHandler> = Omit<
25
+ {
26
+ // toMatchObject: (expected: RecursivePartial<TSpyEvent>) => TSpyHandler;
27
+ [K in keyof MyJestMatchersWitOnlyFunctions]: (
28
+ ...args: Parameters<MyJestMatchersWitOnlyFunctions[K]>
29
+ ) => TSpyHandler;
30
+ },
31
+ 'toContainEqual' | 'toEqual' | 'toMatchObject' | 'toStrictEqual'
32
+ > & {
33
+ /**
34
+ * Used when you want to check that an item is in a list.
35
+ * For testing the items in the list, this matcher recursively checks the
36
+ * equality of all fields, rather than checking for object identity.
37
+ *
38
+ * Optionally, you can provide a type for the expected value via a generic.
39
+ * This is particularly useful for ensuring expected objects have the right structure.
40
+ */
41
+
42
+ toContainEqual(expected: TSpyEvent): TSpyHandler;
43
+ /**
44
+ * Used when you want to check that two objects have the same value.
45
+ * This matcher recursively checks the equality of all fields, rather than checking for object identity.
46
+ *
47
+ * Optionally, you can provide a type for the expected value via a generic.
48
+ * This is particularly useful for ensuring expected objects have the right structure.
49
+ */
50
+
51
+ toEqual(expected: TSpyEvent): TSpyHandler;
52
+
53
+ /**
54
+ * Used to check that a JavaScript object matches a subset of the properties of an object
55
+ *
56
+ * Optionally, you can provide an object to use as Generic type for the expected value.
57
+ * This ensures that the matching object matches the structure of the provided object-like type.
58
+ *
59
+ * @example
60
+ *
61
+ * type House = {
62
+ * bath: boolean;
63
+ * bedrooms: number;
64
+ * kitchen: {
65
+ * amenities: string[];
66
+ * area: number;
67
+ * wallColor: string;
68
+ * }
69
+ * };
70
+ *
71
+ * expect(desiredHouse).toMatchObject<House>({...standardHouse, kitchen: {area: 20}}) // wherein standardHouse is some base object of type House
72
+ */
73
+
74
+ toMatchObject(
75
+ expected: PrettifyForDisplay<RecursivePartial<TSpyEvent>>
76
+ ): TSpyHandler;
77
+
78
+ /**
79
+ * Use to test that objects have the same types as well as structure.
80
+ *
81
+ * Optionally, you can provide a type for the expected value via a generic.
82
+ * This is particularly useful for ensuring expected objects have the right structure.
83
+ */
84
+
85
+ toStrictEqual(expected: TSpyEvent): TSpyHandler;
86
+ };
87
+
88
+ export interface DynamoDBSpyHandler<TData = any>
89
+ extends JestExpectWithSpyMethods<
90
+ DynamoDBSpyEvent<TData>,
91
+ DynamoDBSpyHandler<TData>
92
+ > {
93
+ getData: () => PrettifyForDisplay<DynamoDBSpyEvent<TData>>;
94
+ }
95
+ export interface EventBridgeRuleSpyHandler<TData = any>
96
+ extends JestExpectWithSpyMethods<
97
+ EventBridgeRuleSpyEvent<TData>,
98
+ DynamoDBSpyHandler<TData>
99
+ > {
100
+ getData: () => PrettifyForDisplay<EventBridgeRuleSpyEvent<TData>>;
101
+ }
102
+ export interface EventBridgeSpyHandler<TData = any>
103
+ extends JestExpectWithSpyMethods<
104
+ EventBridgeSpyEvent<TData>,
105
+ DynamoDBSpyHandler<TData>
106
+ > {
107
+ getData: () => PrettifyForDisplay<EventBridgeSpyEvent<TData>>;
108
+ }
109
+
110
+ export interface FunctionBaseSpyHandler<TData = any>
111
+ extends JestExpectWithSpyMethods<
112
+ FunctionRequestSpyEvent<TData>,
113
+ FunctionRequestSpyHandler<TData>
114
+ > {
115
+ // follwedByConsoleLog: () => Promise<
116
+ // FunctionBaseSpyHandler<TData> &
117
+ // JestExpectWithSpyMethods<
118
+ // FunctionRequestSpyEvent<TData>,
119
+ // FunctionRequestSpyHandler<TData>
120
+ // >
121
+ // >;
122
+ followedByResponse: <TDataResponse = any>(
123
+ // This implementation confuses TypeScript which does not accurately display the type.
124
+ // Leave it for reference!
125
+ // param: PrettifyForDisplay<
126
+ // WaitForParams<
127
+ // PrettifyForDisplay<FunctionResponseSpyEvent<TData, TDataResponse>>
128
+ // >
129
+ // >
130
+ param: {
131
+ condition?: (event: {
132
+ spyEventType: 'FunctionResponse';
133
+ request: TData;
134
+ context: FunctionContext;
135
+ response: TDataResponse;
136
+ }) => boolean;
137
+ timoutMs?: number;
138
+ }
139
+ ) => Promise<
140
+ FunctionResponseSpyHandler &
141
+ JestExpectWithSpyMethods<
142
+ FunctionRequestSpyEvent<TData>,
143
+ FunctionRequestSpyHandler<TData>
144
+ >
145
+ >;
146
+ }
147
+
148
+ export interface FunctionRequestSpyHandler<TData = any>
149
+ extends FunctionBaseSpyHandler<TData> {
150
+ getData: () => PrettifyForDisplay<FunctionRequestSpyEvent<TData>>;
151
+ }
152
+
153
+ export interface FunctionConsoleSpyHandler<TData = any>
154
+ extends FunctionBaseSpyHandler<TData> {
155
+ getData: () => PrettifyForDisplay<FunctionConsoleSpyEvent<TData>>;
156
+ }
157
+
158
+ export interface FunctionResponseSpyHandler<TData = any>
159
+ extends JestExpectWithSpyMethods<
160
+ FunctionResponseSpyEvent<TData>,
161
+ FunctionResponseSpyHandler<TData>
162
+ > {
163
+ getData: () => PrettifyForDisplay<FunctionResponseSpyEvent<TData>>;
164
+ }
165
+
166
+ export interface S3SpyHandler
167
+ extends JestExpectWithSpyMethods<S3SpyEvent, DynamoDBSpyHandler> {
168
+ getData: () => S3SpyEvent;
169
+ }
170
+ export interface SnsSubscriptionSpyHandler<TData = any>
171
+ extends JestExpectWithSpyMethods<
172
+ SnsSubscriptionSpyEvent<TData>,
173
+ DynamoDBSpyHandler<TData>
174
+ > {
175
+ getData: () => PrettifyForDisplay<SnsSubscriptionSpyEvent<TData>>;
176
+ }
177
+ export interface SnsTopicSpyHandler<TData = any>
178
+ extends JestExpectWithSpyMethods<
179
+ SnsTopicSpyEvent<TData>,
180
+ DynamoDBSpyHandler<TData>
181
+ > {
182
+ getData: () => PrettifyForDisplay<SnsTopicSpyEvent<TData>>;
183
+ }
184
+ export interface SqsSpyHandler<TData = any>
185
+ extends JestExpectWithSpyMethods<
186
+ SqsSpyEvent<TData>,
187
+ DynamoDBSpyHandler<TData>
188
+ > {
189
+ getData: () => PrettifyForDisplay<SqsSpyEvent<TData>>;
190
+ }