serverless-spy 2.3.10 → 2.3.11

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 (224) hide show
  1. package/.jsii +2 -2
  2. package/dist/releasetag.txt +1 -1
  3. package/lib/_virtual/rolldown_runtime.js +25 -0
  4. package/lib/_virtual/rolldown_runtime.mjs +11 -0
  5. package/lib/cli/cli.d.mts +1 -0
  6. package/lib/cli/cli.d.ts +1 -2
  7. package/lib/cli/cli.js +151 -208
  8. package/lib/cli/cli.js.map +1 -0
  9. package/lib/cli/cli.mjs +144 -205
  10. package/lib/cli/cli.mjs.map +1 -0
  11. package/lib/cli/sampleData.d.mts +896 -0
  12. package/lib/cli/sampleData.d.ts +860 -856
  13. package/lib/cli/sampleData.js +496 -480
  14. package/lib/cli/sampleData.js.map +1 -0
  15. package/lib/cli/sampleData.mjs +495 -477
  16. package/lib/cli/sampleData.mjs.map +1 -0
  17. package/lib/common/SpyEventSender.d.mts +26 -0
  18. package/lib/common/SpyEventSender.d.ts +23 -18
  19. package/lib/common/SpyEventSender.js +180 -230
  20. package/lib/common/SpyEventSender.js.map +1 -0
  21. package/lib/common/SpyEventSender.mjs +180 -227
  22. package/lib/common/SpyEventSender.mjs.map +1 -0
  23. package/lib/common/getWebSocketUrl.d.mts +7 -0
  24. package/lib/common/getWebSocketUrl.d.ts +7 -2
  25. package/lib/common/getWebSocketUrl.js +51 -62
  26. package/lib/common/getWebSocketUrl.js.map +1 -0
  27. package/lib/common/getWebSocketUrl.mjs +49 -60
  28. package/lib/common/getWebSocketUrl.mjs.map +1 -0
  29. package/lib/common/spyEvents/DynamoDBSpyEvent.d.mts +15 -0
  30. package/lib/common/spyEvents/DynamoDBSpyEvent.d.ts +14 -9
  31. package/lib/common/spyEvents/DynamoDBSpyEvent.js +0 -3
  32. package/lib/common/spyEvents/DynamoDBSpyEvent.mjs +1 -2
  33. package/lib/common/spyEvents/EventBridgeBaseSpyEvent.d.mts +14 -0
  34. package/lib/common/spyEvents/EventBridgeBaseSpyEvent.d.ts +13 -8
  35. package/lib/common/spyEvents/EventBridgeBaseSpyEvent.js +0 -3
  36. package/lib/common/spyEvents/EventBridgeBaseSpyEvent.mjs +1 -2
  37. package/lib/common/spyEvents/EventBridgeRuleSpyEvent.d.mts +9 -0
  38. package/lib/common/spyEvents/EventBridgeRuleSpyEvent.d.ts +8 -3
  39. package/lib/common/spyEvents/EventBridgeRuleSpyEvent.js +0 -3
  40. package/lib/common/spyEvents/EventBridgeRuleSpyEvent.mjs +1 -2
  41. package/lib/common/spyEvents/EventBridgeSpyEvent.d.mts +9 -0
  42. package/lib/common/spyEvents/EventBridgeSpyEvent.d.ts +8 -3
  43. package/lib/common/spyEvents/EventBridgeSpyEvent.js +0 -3
  44. package/lib/common/spyEvents/EventBridgeSpyEvent.mjs +1 -2
  45. package/lib/common/spyEvents/FunctionBaseSpyEvent.d.mts +11 -0
  46. package/lib/common/spyEvents/FunctionBaseSpyEvent.d.ts +10 -5
  47. package/lib/common/spyEvents/FunctionBaseSpyEvent.js +0 -3
  48. package/lib/common/spyEvents/FunctionBaseSpyEvent.mjs +1 -2
  49. package/lib/common/spyEvents/FunctionConsole.d.mts +10 -0
  50. package/lib/common/spyEvents/FunctionConsole.d.ts +9 -5
  51. package/lib/common/spyEvents/FunctionConsole.js +0 -3
  52. package/lib/common/spyEvents/FunctionConsole.mjs +1 -2
  53. package/lib/common/spyEvents/FunctionConsoleSpyEvent.d.mts +11 -0
  54. package/lib/common/spyEvents/FunctionConsoleSpyEvent.d.ts +10 -5
  55. package/lib/common/spyEvents/FunctionConsoleSpyEvent.js +0 -3
  56. package/lib/common/spyEvents/FunctionConsoleSpyEvent.mjs +1 -2
  57. package/lib/common/spyEvents/FunctionContext.d.mts +12 -0
  58. package/lib/common/spyEvents/FunctionContext.d.ts +11 -6
  59. package/lib/common/spyEvents/FunctionContext.js +0 -3
  60. package/lib/common/spyEvents/FunctionContext.mjs +1 -2
  61. package/lib/common/spyEvents/FunctionErrorSpyEvent.d.mts +13 -0
  62. package/lib/common/spyEvents/FunctionErrorSpyEvent.d.ts +12 -7
  63. package/lib/common/spyEvents/FunctionErrorSpyEvent.js +0 -3
  64. package/lib/common/spyEvents/FunctionErrorSpyEvent.mjs +1 -2
  65. package/lib/common/spyEvents/FunctionRequestSpyEvent.d.mts +12 -0
  66. package/lib/common/spyEvents/FunctionRequestSpyEvent.d.ts +11 -6
  67. package/lib/common/spyEvents/FunctionRequestSpyEvent.js +0 -3
  68. package/lib/common/spyEvents/FunctionRequestSpyEvent.mjs +1 -2
  69. package/lib/common/spyEvents/FunctionResponseSpyEvent.d.mts +10 -0
  70. package/lib/common/spyEvents/FunctionResponseSpyEvent.d.ts +9 -4
  71. package/lib/common/spyEvents/FunctionResponseSpyEvent.js +0 -3
  72. package/lib/common/spyEvents/FunctionResponseSpyEvent.mjs +1 -2
  73. package/lib/common/spyEvents/S3SpyEvent.d.mts +13 -0
  74. package/lib/common/spyEvents/S3SpyEvent.d.ts +12 -7
  75. package/lib/common/spyEvents/S3SpyEvent.js +0 -3
  76. package/lib/common/spyEvents/S3SpyEvent.mjs +1 -2
  77. package/lib/common/spyEvents/SnsSpyEventBase.d.mts +15 -0
  78. package/lib/common/spyEvents/SnsSpyEventBase.d.ts +14 -9
  79. package/lib/common/spyEvents/SnsSpyEventBase.js +0 -3
  80. package/lib/common/spyEvents/SnsSpyEventBase.mjs +1 -2
  81. package/lib/common/spyEvents/SnsSubscriptionSpyEvent.d.mts +9 -0
  82. package/lib/common/spyEvents/SnsSubscriptionSpyEvent.d.ts +8 -3
  83. package/lib/common/spyEvents/SnsSubscriptionSpyEvent.js +0 -3
  84. package/lib/common/spyEvents/SnsSubscriptionSpyEvent.mjs +1 -2
  85. package/lib/common/spyEvents/SnsTopicSpyEvent.d.mts +9 -0
  86. package/lib/common/spyEvents/SnsTopicSpyEvent.d.ts +8 -3
  87. package/lib/common/spyEvents/SnsTopicSpyEvent.js +0 -3
  88. package/lib/common/spyEvents/SnsTopicSpyEvent.mjs +1 -2
  89. package/lib/common/spyEvents/SpyEvent.d.mts +7 -0
  90. package/lib/common/spyEvents/SpyEvent.d.ts +6 -2
  91. package/lib/common/spyEvents/SpyEvent.js +0 -3
  92. package/lib/common/spyEvents/SpyEvent.mjs +1 -2
  93. package/lib/common/spyEvents/SpyMessage.d.mts +11 -0
  94. package/lib/common/spyEvents/SpyMessage.d.ts +10 -5
  95. package/lib/common/spyEvents/SpyMessage.js +0 -3
  96. package/lib/common/spyEvents/SpyMessage.mjs +1 -2
  97. package/lib/common/spyEvents/SqsSpyEvent.d.mts +12 -0
  98. package/lib/common/spyEvents/SqsSpyEvent.d.ts +11 -6
  99. package/lib/common/spyEvents/SqsSpyEvent.js +0 -3
  100. package/lib/common/spyEvents/SqsSpyEvent.mjs +1 -2
  101. package/lib/extension/dist/layer/nodejs/node_modules/interceptor.js +2 -2
  102. package/lib/extension/dist/layer/nodejs/node_modules/interceptor.js.map +2 -2
  103. package/lib/functions/onConnect.d.mts +1 -0
  104. package/lib/functions/onConnect.d.ts +1 -1
  105. package/lib/functions/onConnect.js +28 -26
  106. package/lib/functions/onConnect.js.map +1 -0
  107. package/lib/functions/onConnect.mjs +35 -26
  108. package/lib/functions/onConnect.mjs.map +1 -0
  109. package/lib/functions/onDisconnect.d.mts +10 -0
  110. package/lib/functions/onDisconnect.d.ts +9 -4
  111. package/lib/functions/onDisconnect.js +28 -27
  112. package/lib/functions/onDisconnect.js.map +1 -0
  113. package/lib/functions/onDisconnect.mjs +29 -25
  114. package/lib/functions/onDisconnect.mjs.map +1 -0
  115. package/lib/functions/sendMessage.d.mts +8 -0
  116. package/lib/functions/sendMessage.d.ts +7 -3
  117. package/lib/functions/sendMessage.js +26 -21
  118. package/lib/functions/sendMessage.js.map +1 -0
  119. package/lib/functions/sendMessage.mjs +28 -19
  120. package/lib/functions/sendMessage.mjs.map +1 -0
  121. package/lib/functions/sqsSubscriptionAndDropAllMessages.d.mts +5 -0
  122. package/lib/functions/sqsSubscriptionAndDropAllMessages.d.ts +5 -1
  123. package/lib/functions/sqsSubscriptionAndDropAllMessages.js +6 -5
  124. package/lib/functions/sqsSubscriptionAndDropAllMessages.js.map +1 -0
  125. package/lib/functions/sqsSubscriptionAndDropAllMessages.mjs +7 -3
  126. package/lib/functions/sqsSubscriptionAndDropAllMessages.mjs.map +1 -0
  127. package/lib/index.d.mts +4 -0
  128. package/lib/index.d.ts +4 -2
  129. package/lib/index.js +6 -19
  130. package/lib/index.mjs +5 -3
  131. package/lib/listener/PrettifyForDisplay.d.mts +5 -0
  132. package/lib/listener/PrettifyForDisplay.d.ts +5 -3
  133. package/lib/listener/PrettifyForDisplay.js +0 -3
  134. package/lib/listener/PrettifyForDisplay.mjs +1 -2
  135. package/lib/listener/RecursivePartial.d.mts +7 -0
  136. package/lib/listener/RecursivePartial.d.ts +7 -4
  137. package/lib/listener/RecursivePartial.js +0 -3
  138. package/lib/listener/RecursivePartial.mjs +1 -2
  139. package/lib/listener/ServerlessSpyListener.d.mts +23 -0
  140. package/lib/listener/ServerlessSpyListener.d.ts +22 -42
  141. package/lib/listener/ServerlessSpyListener.js +0 -3
  142. package/lib/listener/ServerlessSpyListener.mjs +1 -2
  143. package/lib/listener/ServerlessSpyListenerParams.d.mts +14 -0
  144. package/lib/listener/ServerlessSpyListenerParams.d.ts +13 -8
  145. package/lib/listener/ServerlessSpyListenerParams.js +0 -3
  146. package/lib/listener/ServerlessSpyListenerParams.mjs +1 -2
  147. package/lib/listener/SpyHandlers.ts.d.mts +158 -0
  148. package/lib/listener/SpyHandlers.ts.d.ts +144 -144
  149. package/lib/listener/SpyHandlers.ts.js +0 -3
  150. package/lib/listener/SpyHandlers.ts.mjs +1 -2
  151. package/lib/listener/WaitForParams.d.mts +10 -0
  152. package/lib/listener/WaitForParams.d.ts +9 -4
  153. package/lib/listener/WaitForParams.js +0 -3
  154. package/lib/listener/WaitForParams.mjs +1 -2
  155. package/lib/listener/WsListener.d.mts +27 -0
  156. package/lib/listener/WsListener.d.ts +26 -21
  157. package/lib/listener/WsListener.js +173 -231
  158. package/lib/listener/WsListener.js.map +1 -0
  159. package/lib/listener/WsListener.mjs +174 -228
  160. package/lib/listener/WsListener.mjs.map +1 -0
  161. package/lib/listener/createServerlessSpyListener.d.mts +8 -0
  162. package/lib/listener/createServerlessSpyListener.d.ts +8 -2
  163. package/lib/listener/createServerlessSpyListener.js +25 -25
  164. package/lib/listener/createServerlessSpyListener.js.map +1 -0
  165. package/lib/listener/createServerlessSpyListener.mjs +26 -23
  166. package/lib/listener/createServerlessSpyListener.mjs.map +1 -0
  167. package/lib/listener/index.d.mts +3 -0
  168. package/lib/listener/index.d.ts +3 -2
  169. package/lib/listener/index.js +3 -19
  170. package/lib/listener/index.mjs +3 -3
  171. package/lib/listener/iot-connection.d.mts +13 -0
  172. package/lib/listener/iot-connection.d.ts +12 -7
  173. package/lib/listener/iot-connection.js +48 -46
  174. package/lib/listener/iot-connection.js.map +1 -0
  175. package/lib/listener/iot-connection.mjs +46 -44
  176. package/lib/listener/iot-connection.mjs.map +1 -0
  177. package/lib/listener/matchers.d.mts +1 -0
  178. package/lib/listener/matchers.d.ts +1 -0
  179. package/lib/listener/matchers.js +0 -55
  180. package/lib/listener/matchers.mjs +1 -55
  181. package/lib/listener/setup.d.mts +1 -0
  182. package/lib/listener/setup.d.ts +1 -0
  183. package/lib/listener/setup.js +0 -21
  184. package/lib/listener/setup.mjs +1 -21
  185. package/lib/listener/topic.d.mts +6 -0
  186. package/lib/listener/topic.d.ts +6 -2
  187. package/lib/listener/topic.js +9 -7
  188. package/lib/listener/topic.js.map +1 -0
  189. package/lib/listener/topic.mjs +8 -4
  190. package/lib/listener/topic.mjs.map +1 -0
  191. package/lib/node_modules/tsdown/esm-shims.mjs +11 -0
  192. package/lib/node_modules/tsdown/esm-shims.mjs.map +1 -0
  193. package/lib/node_modules/uuid/dist/esm-node/native.js +10 -0
  194. package/lib/node_modules/uuid/dist/esm-node/native.js.map +1 -0
  195. package/lib/node_modules/uuid/dist/esm-node/native.mjs +8 -0
  196. package/lib/node_modules/uuid/dist/esm-node/native.mjs.map +1 -0
  197. package/lib/node_modules/uuid/dist/esm-node/rng.js +18 -0
  198. package/lib/node_modules/uuid/dist/esm-node/rng.js.map +1 -0
  199. package/lib/node_modules/uuid/dist/esm-node/rng.mjs +16 -0
  200. package/lib/node_modules/uuid/dist/esm-node/rng.mjs.map +1 -0
  201. package/lib/node_modules/uuid/dist/esm-node/stringify.js +15 -0
  202. package/lib/node_modules/uuid/dist/esm-node/stringify.js.map +1 -0
  203. package/lib/node_modules/uuid/dist/esm-node/stringify.mjs +14 -0
  204. package/lib/node_modules/uuid/dist/esm-node/stringify.mjs.map +1 -0
  205. package/lib/node_modules/uuid/dist/esm-node/v4.js +23 -0
  206. package/lib/node_modules/uuid/dist/esm-node/v4.js.map +1 -0
  207. package/lib/node_modules/uuid/dist/esm-node/v4.mjs +23 -0
  208. package/lib/node_modules/uuid/dist/esm-node/v4.mjs.map +1 -0
  209. package/lib/src/ServerlessSpy.d.mts +77 -0
  210. package/lib/src/ServerlessSpy.js +1 -1
  211. package/lib/src/ServerlessSpy.js.map +1 -0
  212. package/lib/src/ServerlessSpy.mjs +441 -618
  213. package/lib/src/ServerlessSpy.mjs.map +1 -0
  214. package/lib/src/common/envVariableNames.d.mts +35 -0
  215. package/lib/src/common/envVariableNames.js.map +1 -0
  216. package/lib/src/common/envVariableNames.mjs +43 -35
  217. package/lib/src/common/envVariableNames.mjs.map +1 -0
  218. package/lib/src/index.d.mts +2 -0
  219. package/lib/src/index.mjs +3 -2
  220. package/node_modules/debug/package.json +2 -3
  221. package/node_modules/debug/src/browser.js +1 -1
  222. package/node_modules/debug/src/common.js +1 -1
  223. package/package.json +2 -1
  224. package/tsdown.config.ts +16 -0
@@ -1,618 +1,441 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
- import { PythonLayerVersion } from '@aws-cdk/aws-lambda-python-alpha';
4
- import { aws_iam, BundlingFileAccess, CfnOutput, custom_resources, Duration, Stack, } from 'aws-cdk-lib';
5
- import * as dynamoDb from 'aws-cdk-lib/aws-dynamodb';
6
- import * as events from 'aws-cdk-lib/aws-events';
7
- import * as targets from 'aws-cdk-lib/aws-events-targets';
8
- import { Effect } from 'aws-cdk-lib/aws-iam';
9
- import * as lambda from 'aws-cdk-lib/aws-lambda';
10
- import { Architecture, SingletonFunction, } from 'aws-cdk-lib/aws-lambda';
11
- import * as dynamoDbStream from 'aws-cdk-lib/aws-lambda-event-sources';
12
- import { SqsEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
13
- import * as lambdaNode from 'aws-cdk-lib/aws-lambda-nodejs';
14
- import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
15
- import * as s3 from 'aws-cdk-lib/aws-s3';
16
- import * as s3notif from 'aws-cdk-lib/aws-s3-notifications';
17
- import * as sns from 'aws-cdk-lib/aws-sns';
18
- import * as snsSubs from 'aws-cdk-lib/aws-sns-subscriptions';
19
- import * as sqs from 'aws-cdk-lib/aws-sqs';
20
- import { Construct } from 'constructs';
21
- import { envVariableNames } from './common/envVariableNames';
22
- const isLambdaFunction = (node) => 'functionName' in node && 'functionArn' in node && 'runtime' in node;
23
- const serverlessSpyIotEndpointCrNamePrefix = 'ServerlessSpyIotEndpoint';
24
- export class ServerlessSpy extends Construct {
25
- constructor(scope, id, props) {
26
- super(scope, id);
27
- this.props = props;
28
- this.createdResourcesBySSpy = [];
29
- this.lambdaSubscriptionPool = [];
30
- this.lambdasSpied = [];
31
- this.serviceKeys = [];
32
- this.spiedNodes = [];
33
- this.layerMap = {};
34
- const rootStack = this.cleanName(this.findRootStack(Stack.of(this)).node.id);
35
- const getIoTEndpoint = new custom_resources.AwsCustomResource(this, serverlessSpyIotEndpointCrNamePrefix, {
36
- onCreate: {
37
- service: 'Iot',
38
- action: 'describeEndpoint',
39
- physicalResourceId: custom_resources.PhysicalResourceId.fromResponse('endpointAddress'),
40
- parameters: {
41
- endpointType: 'iot:Data-ATS',
42
- },
43
- },
44
- onUpdate: {
45
- service: 'Iot',
46
- action: 'describeEndpoint',
47
- physicalResourceId: custom_resources.PhysicalResourceId.fromResponse('endpointAddress'),
48
- parameters: {
49
- endpointType: 'iot:Data-ATS',
50
- },
51
- },
52
- installLatestAwsSdk: false,
53
- policy: custom_resources.AwsCustomResourcePolicy.fromSdkCalls({
54
- resources: custom_resources.AwsCustomResourcePolicy.ANY_RESOURCE,
55
- }),
56
- functionName: serverlessSpyIotEndpointCrNamePrefix + rootStack,
57
- });
58
- this.iotEndpoint = getIoTEndpoint.getResponseField('endpointAddress');
59
- this.createdResourcesBySSpy.push(getIoTEndpoint);
60
- new CfnOutput(this, 'ServerlessSpyIoTEndpoint', {
61
- key: 'ServerlessSpyWsUrl',
62
- value: `${this.iotEndpoint}/${rootStack}`,
63
- });
64
- this.lambdaSubscriptionMain = this.provideFunctionForSubscription();
65
- }
66
- getDefaultLambdaEnvironmentVariables() {
67
- return {
68
- NODE_OPTIONS: '--enable-source-maps',
69
- };
70
- }
71
- /**
72
- * Initalize spying on resources given as parameter.
73
- * @param nodes Which reources and their children to spy on.
74
- */
75
- spyNodes(nodes) {
76
- for (const node of nodes) {
77
- let ns = this.getAllNodes(node);
78
- this.internalSpyNodes(ns);
79
- }
80
- this.finalizeSpy();
81
- }
82
- /**
83
- * Initalize spying on resources.
84
- * @param filter Limit which resources to spy on.
85
- */
86
- spy(filter) {
87
- let nodes = this.getAllNodes(Stack.of(this));
88
- const filterWithDefaults = {
89
- spyLambda: true,
90
- spySqs: true,
91
- spySnsTopic: true,
92
- spySnsSubsription: true,
93
- spyEventBridge: true,
94
- spyEventBridgeRule: true,
95
- spyS3: true,
96
- spyDynamoDB: true,
97
- ...filter,
98
- };
99
- const CRID = 'AWS' +
100
- custom_resources.AwsCustomResource.PROVIDER_FUNCTION_UUID.replace(/-/gi, '').substring(0, 16);
101
- nodes = nodes.filter((node) => {
102
- if (
103
- // Ignore the custom resource and the Provider (as well as any other Providers using the same provider function), otherwise we cause
104
- // circular dependencies
105
- node.node.id.startsWith(CRID) ||
106
- node.node.id === 'Provider' ||
107
- // Ignore singleton functions as they can cause very odd behavior and crashes
108
- node instanceof SingletonFunction) {
109
- if (this.props?.debugMode) {
110
- console.info(`Skipping ${node.node.id}`);
111
- }
112
- return false;
113
- }
114
- else if (filterWithDefaults.spyLambda &&
115
- (node instanceof lambda.Function ||
116
- node instanceof NodejsFunction ||
117
- isLambdaFunction(node))) {
118
- return true;
119
- }
120
- else if (filterWithDefaults.spySnsTopic && node instanceof sns.Topic) {
121
- return true;
122
- }
123
- else if (filterWithDefaults.spySnsSubsription &&
124
- node instanceof sns.Subscription) {
125
- return true;
126
- }
127
- else if (filterWithDefaults.spyS3 && node instanceof s3.Bucket) {
128
- return true;
129
- }
130
- else if (filterWithDefaults.spyDynamoDB &&
131
- node instanceof dynamoDb.Table) {
132
- return true;
133
- }
134
- else if (filterWithDefaults.spyDynamoDB &&
135
- node instanceof dynamoDb.TableV2) {
136
- return true;
137
- }
138
- else if (filterWithDefaults.spyEventBridge &&
139
- node instanceof events.EventBus) {
140
- return true;
141
- }
142
- else if (filterWithDefaults.spyEventBridgeRule &&
143
- node instanceof events.Rule) {
144
- return true;
145
- }
146
- else if (filterWithDefaults.spySqs &&
147
- node instanceof lambda.CfnEventSourceMapping) {
148
- return true;
149
- }
150
- else if (filterWithDefaults.spySqs &&
151
- this.props?.spySqsWithNoSubscriptionAndDropAllMessages &&
152
- node instanceof sqs.Queue) {
153
- return true;
154
- }
155
- return false;
156
- });
157
- this.internalSpyNodes(nodes);
158
- this.finalizeSpy();
159
- }
160
- internalSpyNodes(nodes) {
161
- for (const node of nodes) {
162
- this.internalSpyNode(node);
163
- }
164
- }
165
- finalizeSpy() {
166
- //set mapping property for all functions we created
167
- for (const func of this.lambdaSubscriptionPool) {
168
- func.function.addEnvironment(envVariableNames.SSPY_INFRA_MAPPING, JSON.stringify(func.mapping));
169
- }
170
- //set mapping property for all functions we spy on
171
- for (const func of this.lambdasSpied) {
172
- func.function.addEnvironment(envVariableNames.SSPY_INFRA_MAPPING, JSON.stringify(func.mapping));
173
- }
174
- if (this.props?.generateSpyEventsFileLocation) {
175
- this.writeSpyEventsClass(this.props?.generateSpyEventsFileLocation);
176
- }
177
- }
178
- getExtensionAssetLocation() {
179
- let extensionAssetLocation = path.join(__dirname, '../extension/dist/layer');
180
- const extensionAssetLocationAlt = path.join(__dirname, '../lib/extension/dist/layer');
181
- if (!fs.existsSync(extensionAssetLocation)) {
182
- if (!fs.existsSync(extensionAssetLocationAlt)) {
183
- throw new Error(`Folder with assets for extension does not exists at ${extensionAssetLocation} or at ${extensionAssetLocationAlt} `);
184
- }
185
- else {
186
- extensionAssetLocation = extensionAssetLocationAlt;
187
- }
188
- }
189
- const extensionAssetLocationWrapper = path.join(extensionAssetLocation, 'spy-wrapper');
190
- if (!fs.existsSync(extensionAssetLocationWrapper)) {
191
- throw new Error(`Wrapper script for extension does not exists ${extensionAssetLocation}`);
192
- }
193
- const extensionAssetLocationCode = path.join(extensionAssetLocation, `nodejs/node_modules/interceptor.js`);
194
- if (!fs.existsSync(extensionAssetLocationCode)) {
195
- throw new Error(`Code for extension does not exists ${extensionAssetLocationCode}`);
196
- }
197
- return extensionAssetLocation;
198
- }
199
- getLanguageExtensionAssetLocation(language) {
200
- const rootDir = path.join(__dirname, '..');
201
- let extensionAssetLocation = path.join(rootDir, `extensions/${language}`);
202
- const extensionAssetLocationAlt = path.join(rootDir, `lib/extensions/${language}`);
203
- if (!fs.existsSync(extensionAssetLocation)) {
204
- if (!fs.existsSync(extensionAssetLocationAlt)) {
205
- throw new Error(`Folder with assets for extension for ${language} does not exists at ${extensionAssetLocation} or at ${extensionAssetLocationAlt} `);
206
- }
207
- else {
208
- extensionAssetLocation = extensionAssetLocationAlt;
209
- }
210
- }
211
- const extensionAssetLocationWrapper = path.join(
212
- // extensionAssetLocation.substring(
213
- // 0,
214
- // extensionAssetLocation.lastIndexOf(path.sep)
215
- // ),
216
- extensionAssetLocation, 'spy-wrapper');
217
- if (!fs.existsSync(extensionAssetLocationWrapper)) {
218
- throw new Error(`Wrapper script for extension does not exists at ${extensionAssetLocationWrapper}`);
219
- }
220
- return extensionAssetLocation;
221
- }
222
- /**
223
- * Write SpyEvents class, which helps with writing the code for tests.
224
- * @param fileLocation
225
- */
226
- writeSpyEventsClass(fileLocation) {
227
- fs.mkdirSync(path.dirname(fileLocation), { recursive: true });
228
- const properties = this.serviceKeys
229
- .map((sk) => ` ${sk.replace(/#/g, '')}: '${sk}' = '${sk}';\n`)
230
- .join('');
231
- const code = `/* eslint-disable */\nexport class ServerlessSpyEvents {\n${properties}}\n`;
232
- fs.writeFileSync(fileLocation, code);
233
- }
234
- getAllNodes(parent) {
235
- const nodes = [];
236
- nodes.push(parent);
237
- this.getAllNodesRecursive(parent, nodes);
238
- return nodes;
239
- }
240
- getAllNodesRecursive(parent, nodes) {
241
- for (const node of parent.node.children) {
242
- nodes.push(node);
243
- this.getAllNodesRecursive(node, nodes);
244
- }
245
- }
246
- internalSpyNode(node) {
247
- if (this.spiedNodes.includes(node)) {
248
- return;
249
- }
250
- this.spiedNodes.push(node);
251
- if (this.createdResourcesBySSpy.includes(node)) {
252
- return;
253
- }
254
- if (this.lambdaSubscriptionPool.find((s) => s.function === node)) {
255
- return;
256
- }
257
- if (this.props?.debugMode) {
258
- console.info('Spy on node', this.getConstructName(node));
259
- }
260
- if (node instanceof lambda.Function ||
261
- node instanceof NodejsFunction ||
262
- isLambdaFunction(node)) {
263
- this.internalSpyLambda(node);
264
- }
265
- else if (node instanceof sns.Topic) {
266
- this.internalSpySnsTopic(node);
267
- }
268
- else if (node instanceof sns.Subscription) {
269
- this.internalSpySnsSubscription(node);
270
- }
271
- else if (node instanceof s3.Bucket) {
272
- this.internalSpyS3(node);
273
- }
274
- else if (node instanceof dynamoDb.Table) {
275
- this.internalSpyDynamodb(node);
276
- }
277
- else if (node instanceof dynamoDb.TableV2) {
278
- this.internalSpyDynamodb(node);
279
- }
280
- else if (node instanceof events.EventBus) {
281
- this.internalSpyEventBus(node);
282
- }
283
- else if (node instanceof events.Rule) {
284
- this.internalSpyEventBusRule(node);
285
- }
286
- else if (node instanceof lambda.CfnEventSourceMapping) {
287
- this.internalSpySqs(node);
288
- }
289
- else if (node instanceof sqs.Queue) {
290
- if (this.props?.spySqsWithNoSubscriptionAndDropAllMessages) {
291
- this.internalSpySpySqsWithNoSubscription(node);
292
- }
293
- }
294
- }
295
- getExtensionForRuntime(runtime, architecture) {
296
- const layerKey = `sspy_extension_${runtime.toString()}_${architecture.name.toString()}`.replace(/\./g, '_');
297
- let layer = this.layerMap[layerKey];
298
- let spyWrapperPath = '/opt/spy-wrapper';
299
- switch (runtime.name) {
300
- case lambda.Runtime.PYTHON_3_8.name:
301
- case lambda.Runtime.PYTHON_3_9.name:
302
- case lambda.Runtime.PYTHON_3_10.name:
303
- case lambda.Runtime.PYTHON_3_11.name:
304
- case lambda.Runtime.PYTHON_3_12.name:
305
- spyWrapperPath = '/opt/python/spy-wrapper';
306
- layer =
307
- layer ||
308
- new PythonLayerVersion(this, layerKey, {
309
- compatibleRuntimes: [runtime],
310
- compatibleArchitectures: [architecture],
311
- entry: this.getLanguageExtensionAssetLocation('python'),
312
- bundling: {
313
- bundlingFileAccess: BundlingFileAccess.VOLUME_COPY,
314
- },
315
- });
316
- break;
317
- case lambda.Runtime.NODEJS_12_X.name:
318
- case lambda.Runtime.NODEJS_14_X.name:
319
- case lambda.Runtime.NODEJS_16_X.name:
320
- case lambda.Runtime.NODEJS_18_X.name:
321
- case lambda.Runtime.NODEJS_20_X.name:
322
- case lambda.Runtime.NODEJS_22_X.name:
323
- layer =
324
- layer ||
325
- new lambda.LayerVersion(this, layerKey, {
326
- compatibleRuntimes: [runtime],
327
- compatibleArchitectures: [architecture],
328
- code: lambda.Code.fromAsset(this.getExtensionAssetLocation()),
329
- });
330
- break;
331
- default:
332
- console.log(`No extensions available for ${runtime.toString()}`);
333
- return undefined;
334
- }
335
- this.layerMap[layerKey] = layer;
336
- this.createdResourcesBySSpy.push(layer);
337
- return { layer, spyWrapperPath };
338
- }
339
- internalSpySpySqsWithNoSubscription(queue) {
340
- const subscription = this.findElement((n) => n instanceof lambda.CfnEventSourceMapping &&
341
- n.eventSourceArn === queue.queueArn);
342
- if (subscription) {
343
- return; //already have subscription
344
- }
345
- const queueName = this.getConstructName(queue);
346
- const func = new NodejsFunction(this, `${queueName}SqsSubscriptionAndDropAllMessages`, {
347
- memorySize: 512,
348
- timeout: Duration.seconds(5),
349
- runtime: lambda.Runtime.NODEJS_22_X,
350
- handler: 'handler',
351
- entry: this.getAssetLocation('functions/sqsSubscriptionAndDropAllMessages.js'),
352
- environment: this.getDefaultLambdaEnvironmentVariables(),
353
- });
354
- func.addEventSource(new SqsEventSource(queue));
355
- this.setupForIoT(func);
356
- const { layer, spyWrapperPath } = this.getExtensionForRuntime(func.runtime, func.architecture);
357
- func.addLayers(layer);
358
- func.addEnvironment('AWS_LAMBDA_EXEC_WRAPPER', spyWrapperPath);
359
- if (this.props?.debugMode) {
360
- func.addEnvironment(envVariableNames.SSPY_DEBUG, 'true');
361
- }
362
- this.createdResourcesBySSpy.push(func);
363
- const serviceKey = `Sqs#${queueName}`;
364
- this.addMappingToFunction(func, {
365
- key: queue.queueArn,
366
- value: serviceKey,
367
- });
368
- this.serviceKeys.push(serviceKey);
369
- func.addEnvironment(envVariableNames.SSPY_SUBSCRIBED_TO_SQS, 'true');
370
- }
371
- internalSpySqs(node) {
372
- const queue = this.findElement((n) => n instanceof sqs.Queue &&
373
- n.queueArn === node.eventSourceArn);
374
- const func = this.findElement((n) => n instanceof lambda.Function &&
375
- n.functionName === node.functionName);
376
- if (queue && func) {
377
- const queueName = this.getConstructName(queue);
378
- const serviceKey = `Sqs#${queueName}`;
379
- this.addMappingToFunction(func, {
380
- key: queue.queueArn,
381
- value: serviceKey,
382
- });
383
- this.serviceKeys.push(serviceKey);
384
- func.addEnvironment(envVariableNames.SSPY_SUBSCRIBED_TO_SQS, 'true');
385
- }
386
- }
387
- createFunctionForSubscription(index) {
388
- const func = new lambdaNode.NodejsFunction(this, `Subscription${index}`, {
389
- memorySize: 512,
390
- timeout: Duration.seconds(5),
391
- runtime: lambda.Runtime.NODEJS_22_X,
392
- handler: 'handler',
393
- entry: this.getAssetLocation('functions/sendMessage.js'),
394
- environment: {
395
- NODE_OPTIONS: '--enable-source-maps',
396
- },
397
- });
398
- this.setupForIoT(func);
399
- return func;
400
- }
401
- internalSpyS3(s3Bucket) {
402
- s3Bucket.addEventNotification(s3.EventType.OBJECT_CREATED_PUT, new s3notif.LambdaDestination(this.lambdaSubscriptionMain.function));
403
- const name = this.getConstructName(s3Bucket);
404
- const serviceKey = `S3#${name}`;
405
- this.lambdaSubscriptionMain.mapping[s3Bucket.bucketArn] = serviceKey;
406
- this.serviceKeys.push(serviceKey);
407
- }
408
- internalSpyDynamodb(table) {
409
- // enable DynamoDB streams with a hack
410
- table.node.defaultChild.streamSpecification = {
411
- streamViewType: dynamoDb.StreamViewType.NEW_AND_OLD_IMAGES,
412
- };
413
- table.tableStreamArn = table.node.defaultChild.attrStreamArn;
414
- this.lambdaSubscriptionMain.function.addEventSource(new dynamoDbStream.DynamoEventSource(table, {
415
- startingPosition: lambda.StartingPosition.LATEST,
416
- batchSize: 1,
417
- retryAttempts: 0,
418
- }));
419
- const name = this.getConstructName(table);
420
- const serviceKey = `DynamoDB#${name}`;
421
- this.lambdaSubscriptionMain.mapping[table.tableArn] = serviceKey;
422
- this.serviceKeys.push(serviceKey);
423
- }
424
- internalSpyEventBusRule(rule) {
425
- const { eventBusName } = rule.node.defaultChild;
426
- let bridgeName = 'Default';
427
- if (!!eventBusName) {
428
- const eventBridge = this.getEventBridge(eventBusName);
429
- if (!eventBridge) {
430
- throw new Error(`Can not find EventBridge with name "${eventBusName}"`);
431
- }
432
- bridgeName = this.getConstructName(eventBridge);
433
- }
434
- const functionSubscription = this.provideFunctionForSubscription((s) => !s.usedForEventBridge);
435
- functionSubscription.usedForEventBridge = true;
436
- rule.addTarget(new targets.LambdaFunction(functionSubscription.function));
437
- const ruleName = this.getConstructName(rule);
438
- const serviceKey = `EventBridgeRule#${bridgeName}#${ruleName}`;
439
- functionSubscription.mapping.eventBridge = serviceKey;
440
- this.serviceKeys.push(serviceKey);
441
- }
442
- internalSpyEventBus(eventBus) {
443
- const functionSubscription = this.provideFunctionForSubscription((s) => !s.usedForEventBridge);
444
- functionSubscription.usedForEventBridge = true;
445
- const bridgeName = this.getConstructName(eventBus);
446
- const rule = new events.Rule(this, `RuleAll${bridgeName}`, {
447
- eventBus,
448
- eventPattern: { version: ['0'] },
449
- targets: [new targets.LambdaFunction(functionSubscription.function)],
450
- });
451
- this.createdResourcesBySSpy.push(rule);
452
- const serviceKey = `EventBridge#${bridgeName}`;
453
- functionSubscription.mapping.eventBridge = serviceKey;
454
- this.serviceKeys.push(serviceKey);
455
- }
456
- internalSpySnsTopic(topic) {
457
- const functionSubscription = this.provideFunctionForSubscription((s) => !s.subsribedTopics.includes(topic));
458
- const subscription = topic.addSubscription(new snsSubs.LambdaSubscription(functionSubscription.function));
459
- this.createdResourcesBySSpy.push(subscription);
460
- const topicName = this.getConstructName(topic);
461
- const serviceKey = `SnsTopic#${topicName}`;
462
- functionSubscription.mapping[topic.topicArn] = serviceKey;
463
- this.serviceKeys.push(serviceKey);
464
- functionSubscription.subsribedTopics.push(topic);
465
- }
466
- internalSpySnsSubscription(subscription) {
467
- if (!subscription.node.scope) {
468
- return;
469
- }
470
- const topic = this.getTopic(subscription.node.defaultChild.topicArn);
471
- if (!topic) {
472
- throw new Error('Can not find Topic');
473
- }
474
- const functionSubscription = this.provideFunctionForSubscription((s) => !s.subsribedTopics.includes(topic));
475
- const { filterPolicy } = subscription.node
476
- .defaultChild;
477
- const subscriptionClone = topic.addSubscription(new snsSubs.LambdaSubscription(functionSubscription.function));
478
- subscriptionClone.node.defaultChild.filterPolicy =
479
- filterPolicy;
480
- this.createdResourcesBySSpy.push(subscriptionClone);
481
- const topicName = this.getConstructName(topic);
482
- const targetName = this.getConstructName(subscription.node.scope);
483
- functionSubscription.subsribedTopics.push(topic);
484
- const serviceKey = `SnsSubscription#${topicName}#${targetName}`;
485
- functionSubscription.mapping[topic.topicArn] = serviceKey;
486
- this.serviceKeys.push(serviceKey);
487
- }
488
- provideFunctionForSubscription(filterFunction) {
489
- let functionSubscription;
490
- if (filterFunction) {
491
- functionSubscription = this.lambdaSubscriptionPool.find(filterFunction);
492
- }
493
- else if (this.lambdaSubscriptionPool.length > 0) {
494
- functionSubscription = this.lambdaSubscriptionPool[0];
495
- }
496
- if (!functionSubscription) {
497
- functionSubscription = {
498
- subsribedTopics: [],
499
- usedForEventBridge: false,
500
- mapping: {},
501
- function: this.createFunctionForSubscription(this.lambdaSubscriptionPool.length),
502
- };
503
- this.lambdaSubscriptionPool.push(functionSubscription);
504
- }
505
- return functionSubscription;
506
- }
507
- setupForIoT(func) {
508
- func.addEnvironment(envVariableNames.SSPY_ROOT_STACK, this.cleanName(this.findRootStack(Stack.of(this)).node.id));
509
- func.addEnvironment(envVariableNames.SSPY_IOT_ENDPOINT, this.iotEndpoint);
510
- func.addToRolePolicy(new aws_iam.PolicyStatement({
511
- actions: ['iot:*'],
512
- effect: Effect.ALLOW,
513
- resources: ['*'],
514
- }));
515
- }
516
- internalSpyLambda(func) {
517
- const { layer, spyWrapperPath } = this.getExtensionForRuntime(func.runtime, func.architecture || Architecture.X86_64);
518
- if (!layer) {
519
- return;
520
- }
521
- func.addLayers(layer);
522
- const functionName = this.getConstructName(func);
523
- func.addEnvironment(envVariableNames.SSPY_FUNCTION_NAME, functionName);
524
- func.addEnvironment('AWS_LAMBDA_EXEC_WRAPPER', spyWrapperPath);
525
- if (this.props?.debugMode) {
526
- func.addEnvironment(envVariableNames.SSPY_DEBUG, 'true');
527
- }
528
- this.setupForIoT(func);
529
- this.serviceKeys.push(`Function#${functionName}#Request`);
530
- this.serviceKeys.push(`Function#${functionName}#Error`);
531
- this.serviceKeys.push(`Function#${functionName}#Console`);
532
- this.serviceKeys.push(`Function#${functionName}#Response`);
533
- this.addMappingToFunction(func);
534
- }
535
- getConstructName(construct) {
536
- let constructName = construct.node.path;
537
- const { node } = Stack.of(this);
538
- if (constructName.startsWith(node.id)) {
539
- constructName = constructName.substring(node.id.length + 1);
540
- }
541
- return this.cleanName(constructName);
542
- }
543
- cleanName(name) {
544
- //snake case to camel case including dash and first letter to upper case
545
- return name
546
- .replace(/[-_]+/g, ' ')
547
- .replace(/[^\w\s]/g, '')
548
- .replace(/\s(.)/g, ($1) => $1.toUpperCase())
549
- .replace(/\s/g, '')
550
- .replace(/^(.)/, ($1) => $1.toUpperCase());
551
- }
552
- getTopic(topicArn) {
553
- const topic = this.findElement((node) => node instanceof sns.Topic && node.topicArn === topicArn);
554
- return topic;
555
- }
556
- getEventBridge(eventBusName) {
557
- const eventBridge = this.findElement((node) => (node instanceof events.EventBus ||
558
- node.constructor.name === 'ImportedEventBus') &&
559
- node.eventBusName === eventBusName);
560
- return eventBridge;
561
- }
562
- findRootStack(stack) {
563
- if (stack.nested) {
564
- const parentStack = stack.nestedStackParent;
565
- if (parentStack)
566
- return this.findRootStack(parentStack);
567
- return stack;
568
- }
569
- else {
570
- return stack;
571
- }
572
- }
573
- findElement(filterFunc, parent) {
574
- if (!parent) {
575
- parent = this.findRootStack(Stack.of(this));
576
- }
577
- for (const node of parent.node.children) {
578
- if (filterFunc(node)) {
579
- return node;
580
- }
581
- const elementFoundInChild = this.findElement(filterFunc, node);
582
- if (elementFoundInChild) {
583
- return elementFoundInChild;
584
- }
585
- }
586
- return undefined;
587
- }
588
- addMappingToFunction(func, keyValue) {
589
- for (const fs of this.lambdasSpied) {
590
- if (fs.function === func) {
591
- if (keyValue) {
592
- fs.mapping[keyValue.key] = keyValue.value;
593
- }
594
- return;
595
- }
596
- }
597
- const fs = {
598
- function: func,
599
- mapping: {},
600
- };
601
- if (keyValue) {
602
- fs.mapping[keyValue.key] = keyValue.value;
603
- }
604
- this.lambdasSpied.push(fs);
605
- }
606
- getAssetLocation(location) {
607
- const loc = path.join(__dirname, '../lib/' + location);
608
- if (fs.existsSync(loc)) {
609
- return loc;
610
- }
611
- const loc2 = path.join(__dirname, '../../lib/' + location);
612
- if (fs.existsSync(loc2)) {
613
- return loc2;
614
- }
615
- throw new Error(`Location ${loc} and ${loc2} does not exists.`);
616
- }
617
- }
618
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VydmVybGVzc1NweS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9TZXJ2ZXJsZXNzU3B5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQ3pCLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQzdCLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ3RFLE9BQU8sRUFDTCxPQUFPLEVBQ1Asa0JBQWtCLEVBQ2xCLFNBQVMsRUFDVCxnQkFBZ0IsRUFDaEIsUUFBUSxFQUVSLEtBQUssR0FDTixNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEtBQUssUUFBUSxNQUFNLDBCQUEwQixDQUFDO0FBQ3JELE9BQU8sS0FBSyxNQUFNLE1BQU0sd0JBQXdCLENBQUM7QUFDakQsT0FBTyxLQUFLLE9BQU8sTUFBTSxnQ0FBZ0MsQ0FBQztBQUMxRCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDN0MsT0FBTyxLQUFLLE1BQU0sTUFBTSx3QkFBd0IsQ0FBQztBQUNqRCxPQUFPLEVBQ0wsWUFBWSxFQUVaLGlCQUFpQixHQUNsQixNQUFNLHdCQUF3QixDQUFDO0FBQ2hDLE9BQU8sS0FBSyxjQUFjLE1BQU0sc0NBQXNDLENBQUM7QUFDdkUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHNDQUFzQyxDQUFDO0FBQ3RFLE9BQU8sS0FBSyxVQUFVLE1BQU0sK0JBQStCLENBQUM7QUFDNUQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQy9ELE9BQU8sS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDekMsT0FBTyxLQUFLLE9BQU8sTUFBTSxrQ0FBa0MsQ0FBQztBQUM1RCxPQUFPLEtBQUssR0FBRyxNQUFNLHFCQUFxQixDQUFDO0FBQzNDLE9BQU8sS0FBSyxPQUFPLE1BQU0sbUNBQW1DLENBQUM7QUFD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QUFFLENBQUM7b0JBQ2IsRUFBRSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEdBQUcsUUFBUSxDQUFDLEtBQUssQ0FBQztnQkFDNUMsQ0FBQztnQkFDRCxPQUFPO1lBQ1QsQ0FBQztRQUNILENBQUM7UUFFRCxNQUFNLEVBQUUsR0FBZ0I7WUFDdEIsUUFBUSxFQUFFLElBQUk7WUFDZCxPQUFPLEVBQUUsRUFBRTtTQUNaLENBQUM7UUFFRixJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQ2IsRUFBRSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEdBQUcsUUFBUSxDQUFDLEtBQUssQ0FBQztRQUM1QyxDQUFDO1FBRUQsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDN0IsQ0FBQztJQUVPLGdCQUFnQixDQUFDLFFBQWdCO1FBQ3ZDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLFNBQVMsR0FBRyxRQUFRLENBQUMsQ0FBQztRQUV2RCxJQUFJLEVBQUUsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUN2QixPQUFPLEdBQUcsQ0FBQztRQUNiLENBQUM7UUFFRCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxZQUFZLEdBQUcsUUFBUSxDQUFDLENBQUM7UUFFM0QsSUFBSSxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDeEIsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBRUQsTUFBTSxJQUFJLEtBQUssQ0FBQyxZQUFZLEdBQUcsUUFBUSxJQUFJLG1CQUFtQixDQUFDLENBQUM7SUFDbEUsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IFB5dGhvbkxheWVyVmVyc2lvbiB9IGZyb20gJ0Bhd3MtY2RrL2F3cy1sYW1iZGEtcHl0aG9uLWFscGhhJztcbmltcG9ydCB7XG4gIGF3c19pYW0sXG4gIEJ1bmRsaW5nRmlsZUFjY2VzcyxcbiAgQ2ZuT3V0cHV0LFxuICBjdXN0b21fcmVzb3VyY2VzLFxuICBEdXJhdGlvbixcbiAgTmVzdGVkU3RhY2ssXG4gIFN0YWNrLFxufSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgKiBhcyBkeW5hbW9EYiBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZHluYW1vZGInO1xuaW1wb3J0ICogYXMgZXZlbnRzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1ldmVudHMnO1xuaW1wb3J0ICogYXMgdGFyZ2V0cyBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZXZlbnRzLXRhcmdldHMnO1xuaW1wb3J0IHsgRWZmZWN0IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWlhbSc7XG5pbXBvcnQgKiBhcyBsYW1iZGEgZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYSc7XG5pbXBvcnQge1xuICBBcmNoaXRlY3R1cmUsXG4gIElMYXllclZlcnNpb24sXG4gIFNpbmdsZXRvbkZ1bmN0aW9uLFxufSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhJztcbmltcG9ydCAqIGFzIGR5bmFtb0RiU3RyZWFtIGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEtZXZlbnQtc291cmNlcyc7XG5pbXBvcnQgeyBTcXNFdmVudFNvdXJjZSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEtZXZlbnQtc291cmNlcyc7XG5pbXBvcnQgKiBhcyBsYW1iZGFOb2RlIGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEtbm9kZWpzJztcbmltcG9ydCB7IE5vZGVqc0Z1bmN0aW9uIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYS1ub2RlanMnO1xuaW1wb3J0ICogYXMgczMgZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzJztcbmltcG9ydCAqIGFzIHMzbm90aWYgZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzLW5vdGlmaWNhdGlvbnMnO1xuaW1wb3J0ICogYXMgc25zIGZyb20gJ2F3cy1jZGstbGliL2F3cy1zbnMnO1xuaW1wb3J0ICogYXMgc25zU3VicyBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtc25zLXN1YnNjcmlwdGlvbnMnO1xuaW1wb3J0ICogYXMgc3FzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1zcXMnO1xuaW1wb3J0IHsgQ29uc3RydWN0LCBJQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBlbnZWYXJpYWJsZU5hbWVzIH0gZnJvbSAnLi9jb21tb24vZW52VmFyaWFibGVOYW1lcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2VydmVybGVzc1NweVByb3BzIHtcbiAgcmVhZG9ubHkgZ2VuZXJhdGVTcHlFdmVudHNGaWxlTG9jYXRpb24/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHNweVNxc1dpdGhOb1N1YnNjcmlwdGlvbkFuZERyb3BBbGxNZXNzYWdlcz86IGJvb2xlYW47XG4gIHJlYWRvbmx5IGRlYnVnTW9kZT86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3B5RmlsdGVyIHtcbiAgcmVhZG9ubHkgc3B5TGFtYmRhPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgc3B5U3FzPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgc3B5U25zVG9waWM/OiBib29sZWFuO1xuICByZWFkb25seSBzcHlTbnNTdWJzcmlwdGlvbj86IGJvb2xlYW47XG4gIHJlYWRvbmx5IHNweUV2ZW50QnJpZGdlPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgc3B5RXZlbnRCcmlkZ2VSdWxlPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgc3B5UzM/OiBib29sZWFuO1xuICByZWFkb25seSBzcHlEeW5hbW9EQj86IGJvb2xlYW47XG59XG5cbmNvbnN0IGlzTGFtYmRhRnVuY3Rpb24gPSAobm9kZTogSUNvbnN0cnVjdCk6IG5vZGUgaXMgbGFtYmRhLkZ1bmN0aW9uID0+XG4gICdmdW5jdGlvbk5hbWUnIGluIG5vZGUgJiYgJ2Z1bmN0aW9uQXJuJyBpbiBub2RlICYmICdydW50aW1lJyBpbiBub2RlO1xuXG5jb25zdCBzZXJ2ZXJsZXNzU3B5SW90RW5kcG9pbnRDck5hbWVQcmVmaXggPSAnU2VydmVybGVzc1NweUlvdEVuZHBvaW50JztcblxuZXhwb3J0IGNsYXNzIFNlcnZlcmxlc3NTcHkgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBwcml2YXRlIGNyZWF0ZWRSZXNvdXJjZXNCeVNTcHk6IElDb25zdHJ1Y3RbXSA9IFtdO1xuICBwcml2YXRlIGxhbWJkYVN1YnNjcmlwdGlvblBvb2w6IExhbWJkYVN1YnNjcmlwdGlvbltdID0gW107XG4gIHByaXZhdGUgbGFtYmRhU3Vic2NyaXB0aW9uTWFpbjogTGFtYmRhU3Vic2NyaXB0aW9uO1xuICBwcml2YXRlIGxhbWJkYXNTcGllZDogTGFtYmRhU3BpZWRbXSA9IFtdO1xuICBwdWJsaWMgc2VydmljZUtleXM6IHN0cmluZ1tdID0gW107XG4gIHByaXZhdGUgc3BpZWROb2RlczogSUNvbnN0cnVjdFtdID0gW107XG4gIHByaXZhdGUgbGF5ZXJNYXA6IFBhcnRpYWw8UmVjb3JkPHN0cmluZywgSUxheWVyVmVyc2lvbj4+ID0ge307XG4gIHByaXZhdGUgcmVhZG9ubHkgaW90RW5kcG9pbnQ6IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcihcbiAgICBzY29wZTogQ29uc3RydWN0LFxuICAgIGlkOiBzdHJpbmcsXG4gICAgcHJpdmF0ZSBwcm9wcz86IFNlcnZlcmxlc3NTcHlQcm9wc1xuICApIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgY29uc3Qgcm9vdFN0YWNrID0gdGhpcy5jbGVhbk5hbWUoXG4gICAgICB0aGlzLmZpbmRSb290U3RhY2soU3RhY2sub2YodGhpcykpLm5vZGUuaWRcbiAgICApO1xuXG4gICAgY29uc3QgZ2V0SW9URW5kcG9pbnQgPSBuZXcgY3VzdG9tX3Jlc291cmNlcy5Bd3NDdXN0b21SZXNvdXJjZShcbiAgICAgIHRoaXMsXG4gICAgICBzZXJ2ZXJsZXNzU3B5SW90RW5kcG9pbnRDck5hbWVQcmVmaXgsXG4gICAgICB7XG4gICAgICAgIG9uQ3JlYXRlOiB7XG4gICAgICAgICAgc2VydmljZTogJ0lvdCcsXG4gICAgICAgICAgYWN0aW9uOiAnZGVzY3JpYmVFbmRwb2ludCcsXG4gICAgICAgICAgcGh5c2ljYWxSZXNvdXJjZUlkOlxuICAgICAgICAgICAgY3VzdG9tX3Jlc291cmNlcy5QaHlzaWNhbFJlc291cmNlSWQuZnJvbVJlc3BvbnNlKCdlbmRwb2ludEFkZHJlc3MnKSxcbiAgICAgICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgICAgICBlbmRwb2ludFR5cGU6ICdpb3Q6RGF0YS1BVFMnLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIG9uVXBkYXRlOiB7XG4gICAgICAgICAgc2VydmljZTogJ0lvdCcsXG4gICAgICAgICAgYWN0aW9uOiAnZGVzY3JpYmVFbmRwb2ludCcsXG4gICAgICAgICAgcGh5c2ljYWxSZXNvdXJjZUlkOlxuICAgICAgICAgICAgY3VzdG9tX3Jlc291cmNlcy5QaHlzaWNhbFJlc291cmNlSWQuZnJvbVJlc3BvbnNlKCdlbmRwb2ludEFkZHJlc3MnKSxcbiAgICAgICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgICAgICBlbmRwb2ludFR5cGU6ICdpb3Q6RGF0YS1BVFMnLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIGluc3RhbGxMYXRlc3RBd3NTZGs6IGZhbHNlLFxuICAgICAgICBwb2xpY3k6IGN1c3RvbV9yZXNvdXJjZXMuQXdzQ3VzdG9tUmVzb3VyY2VQb2xpY3kuZnJvbVNka0NhbGxzKHtcbiAgICAgICAgICByZXNvdXJjZXM6IGN1c3RvbV9yZXNvdXJjZXMuQXdzQ3VzdG9tUmVzb3VyY2VQb2xpY3kuQU5ZX1JFU09VUkNFLFxuICAgICAgICB9KSxcbiAgICAgICAgZnVuY3Rpb25OYW1lOiBzZXJ2ZXJsZXNzU3B5SW90RW5kcG9pbnRDck5hbWVQcmVmaXggKyByb290U3RhY2ssXG4gICAgICB9XG4gICAgKTtcbiAgICB0aGlzLmlvdEVuZHBvaW50ID0gZ2V0SW9URW5kcG9pbnQuZ2V0UmVzcG9uc2VGaWVsZCgnZW5kcG9pbnRBZGRyZXNzJyk7XG5cbiAgICB0aGlzLmNyZWF0ZWRSZXNvdXJjZXNCeVNTcHkucHVzaChnZXRJb1RFbmRwb2ludCk7XG5cbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsICdTZXJ2ZXJsZXNzU3B5SW9URW5kcG9pbnQnLCB7XG4gICAgICBrZXk6ICdTZXJ2ZXJsZXNzU3B5V3NVcmwnLFxuICAgICAgdmFsdWU6IGAke3RoaXMuaW90RW5kcG9pbnR9LyR7cm9vdFN0YWNrfWAsXG4gICAgfSk7XG5cbiAgICB0aGlzLmxhbWJkYVN1YnNjcmlwdGlvbk1haW4gPSB0aGlzLnByb3ZpZGVGdW5jdGlvbkZvclN1YnNjcmlwdGlvbigpO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXREZWZhdWx0TGFtYmRhRW52aXJvbm1lbnRWYXJpYWJsZXMoKTogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIE5PREVfT1BUSU9OUzogJy0tZW5hYmxlLXNvdXJjZS1tYXBzJyxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEluaXRhbGl6ZSBzcHlpbmcgb24gcmVzb3VyY2VzIGdpdmVuIGFzIHBhcmFtZXRlci5cbiAgICogQHBhcmFtIG5vZGVzIFdoaWNoIHJlb3VyY2VzIGFuZCB0aGVpciBjaGlsZHJlbiB0byBzcHkgb24uXG4gICAqL1xuICBwdWJsaWMgc3B5Tm9kZXMobm9kZXM6IElDb25zdHJ1Y3RbXSkge1xuICAgIGZvciAoY29uc3Qgbm9kZSBvZiBub2Rlcykge1xuICAgICAgbGV0IG5zID0gdGhpcy5nZXRBbGxOb2Rlcyhub2RlKTtcbiAgICAgIHRoaXMuaW50ZXJuYWxTcHlOb2Rlcyhucyk7XG4gICAgfVxuXG4gICAgdGhpcy5maW5hbGl6ZVNweSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEluaXRhbGl6ZSBzcHlpbmcgb24gcmVzb3VyY2VzLlxuICAgKiBAcGFyYW0gZmlsdGVyIExpbWl0IHdoaWNoIHJlc291cmNlcyB0byBzcHkgb24uXG4gICAqL1xuICBwdWJsaWMgc3B5KGZpbHRlcj86IFNweUZpbHRlcikge1xuICAgIGxldCBub2RlcyA9IHRoaXMuZ2V0QWxsTm9kZXMoU3RhY2sub2YodGhpcykpO1xuXG4gICAgY29uc3QgZmlsdGVyV2l0aERlZmF1bHRzOiBSZXF1aXJlZDxTcHlGaWx0ZXI+ID0ge1xuICAgICAgc3B5TGFtYmRhOiB0cnVlLFxuICAgICAgc3B5U3FzOiB0cnVlLFxuICAgICAgc3B5U25zVG9waWM6IHRydWUsXG4gICAgICBzcHlTbnNTdWJzcmlwdGlvbjogdHJ1ZSxcbiAgICAgIHNweUV2ZW50QnJpZGdlOiB0cnVlLFxuICAgICAgc3B5RXZlbnRCcmlkZ2VSdWxlOiB0cnVlLFxuICAgICAgc3B5UzM6IHRydWUsXG4gICAgICBzcHlEeW5hbW9EQjogdHJ1ZSxcbiAgICAgIC4uLmZpbHRlcixcbiAgICB9O1xuXG4gICAgY29uc3QgQ1JJRCA9XG4gICAgICAnQVdTJyArXG4gICAgICBjdXN0b21fcmVzb3VyY2VzLkF3c0N1c3RvbVJlc291cmNlLlBST1ZJREVSX0ZVTkNUSU9OX1VVSUQucmVwbGFjZShcbiAgICAgICAgLy0vZ2ksXG4gICAgICAgICcnXG4gICAgICApLnN1YnN0cmluZygwLCAxNik7XG5cbiAgICBub2RlcyA9IG5vZGVzLmZpbHRlcigobm9kZSkgPT4ge1xuICAgICAgaWYgKFxuICAgICAgICAvLyBJZ25vcmUgdGhlIGN1c3RvbSByZXNvdXJjZSBhbmQgdGhlIFByb3ZpZGVyIChhcyB3ZWxsIGFzIGFueSBvdGhlciBQcm92aWRlcnMgdXNpbmcgdGhlIHNhbWUgcHJvdmlkZXIgZnVuY3Rpb24pLCBvdGhlcndpc2Ugd2UgY2F1c2VcbiAgICAgICAgLy8gY2lyY3VsYXIgZGVwZW5kZW5jaWVzXG4gICAgICAgIG5vZGUubm9kZS5pZC5zdGFydHNXaXRoKENSSUQpIHx8XG4gICAgICAgIG5vZGUubm9kZS5pZCA9PT0gJ1Byb3ZpZGVyJyB8fFxuICAgICAgICAvLyBJZ25vcmUgc2luZ2xldG9uIGZ1bmN0aW9ucyBhcyB0aGV5IGNhbiBjYXVzZSB2ZXJ5IG9kZCBiZWhhdmlvciBhbmQgY3Jhc2hlc1xuICAgICAgICBub2RlIGluc3RhbmNlb2YgU2luZ2xldG9uRnVuY3Rpb25cbiAgICAgICkge1xuICAgICAgICBpZiAodGhpcy5wcm9wcz8uZGVidWdNb2RlKSB7XG4gICAgICAgICAgY29uc29sZS5pbmZvKGBTa2lwcGluZyAke25vZGUubm9kZS5pZH1gKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9IGVsc2UgaWYgKFxuICAgICAgICBmaWx0ZXJXaXRoRGVmYXVsdHMuc3B5TGFtYmRhICYmXG4gICAgICAgIChub2RlIGluc3RhbmNlb2YgbGFtYmRhLkZ1bmN0aW9uIHx8XG4gICAgICAgICAgbm9kZSBpbnN0YW5jZW9mIE5vZGVqc0Z1bmN0aW9uIHx8XG4gICAgICAgICAgaXNMYW1iZGFGdW5jdGlvbihub2RlKSlcbiAgICAgICkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH0gZWxzZSBpZiAoZmlsdGVyV2l0aERlZmF1bHRzLnNweVNuc1RvcGljICYmIG5vZGUgaW5zdGFuY2VvZiBzbnMuVG9waWMpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9IGVsc2UgaWYgKFxuICAgICAgICBmaWx0ZXJXaXRoRGVmYXVsdHMuc3B5U25zU3Vic3JpcHRpb24gJiZcbiAgICAgICAgbm9kZSBpbnN0YW5jZW9mIHNucy5TdWJzY3JpcHRpb25cbiAgICAgICkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH0gZWxzZSBpZiAoZmlsdGVyV2l0aERlZmF1bHRzLnNweVMzICYmIG5vZGUgaW5zdGFuY2VvZiBzMy5CdWNrZXQpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9IGVsc2UgaWYgKFxuICAgICAgICBmaWx0ZXJXaXRoRGVmYXVsdHMuc3B5RHluYW1vREIgJiZcbiAgICAgICAgbm9kZSBpbnN0YW5jZW9mIGR5bmFtb0RiLlRhYmxlXG4gICAgICApIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9IGVsc2UgaWYgKFxuICAgICAgICBmaWx0ZXJXaXRoRGVmYXVsdHMuc3B5RHluYW1vREIgJiZcbiAgICAgICAgbm9kZSBpbnN0YW5jZW9mIGR5bmFtb0RiLlRhYmxlVjJcbiAgICAgICkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgIGZpbHRlcldpdGhEZWZhdWx0cy5zcHlFdmVudEJyaWRnZSAmJlxuICAgICAgICBub2RlIGluc3RhbmNlb2YgZXZlbnRzLkV2ZW50QnVzXG4gICAgICApIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9IGVsc2UgaWYgKFxuICAgICAgICBmaWx0ZXJXaXRoRGVmYXVsdHMuc3B5RXZlbnRCcmlkZ2VSdWxlICYmXG4gICAgICAgIG5vZGUgaW5zdGFuY2VvZiBldmVudHMuUnVsZVxuICAgICAgKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgZmlsdGVyV2l0aERlZmF1bHRzLnNweVNxcyAmJlxuICAgICAgICBub2RlIGluc3RhbmNlb2YgbGFtYmRhLkNmbkV2ZW50U291cmNlTWFwcGluZ1xuICAgICAgKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgZmlsdGVyV2l0aERlZmF1bHRzLnNweVNxcyAmJlxuICAgICAgICB0aGlzLnByb3BzPy5zcHlTcXNXaXRoTm9TdWJzY3JpcHRpb25BbmREcm9wQWxsTWVzc2FnZXMgJiZcbiAgICAgICAgbm9kZSBpbnN0YW5jZW9mIHNxcy5RdWV1ZVxuICAgICAgKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfSk7XG5cbiAgICB0aGlzLmludGVybmFsU3B5Tm9kZXMobm9kZXMpO1xuICAgIHRoaXMuZmluYWxpemVTcHkoKTtcbiAgfVxuXG4gIHByaXZhdGUgaW50ZXJuYWxTcHlOb2Rlcyhub2RlczogSUNvbnN0cnVjdFtdKSB7XG4gICAgZm9yIChjb25zdCBub2RlIG9mIG5vZGVzKSB7XG4gICAgICB0aGlzLmludGVybmFsU3B5Tm9kZShub2RlKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGZpbmFsaXplU3B5KCkge1xuICAgIC8vc2V0IG1hcHBpbmcgcHJvcGVydHkgZm9yIGFsbCBmdW5jdGlvbnMgd2UgY3JlYXRlZFxuICAgIGZvciAoY29uc3QgZnVuYyBvZiB0aGlzLmxhbWJkYVN1YnNjcmlwdGlvblBvb2wpIHtcbiAgICAgIGZ1bmMuZnVuY3Rpb24uYWRkRW52aXJvbm1lbnQoXG4gICAgICAgIGVudlZhcmlhYmxlTmFtZXMuU1NQWV9JTkZSQV9NQVBQSU5HLFxuICAgICAgICBKU09OLnN0cmluZ2lmeShmdW5jLm1hcHBpbmcpXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vc2V0IG1hcHBpbmcgcHJvcGVydHkgZm9yIGFsbCBmdW5jdGlvbnMgd2Ugc3B5IG9uXG4gICAgZm9yIChjb25zdCBmdW5jIG9mIHRoaXMubGFtYmRhc1NwaWVkKSB7XG4gICAgICBmdW5jLmZ1bmN0aW9uLmFkZEVudmlyb25tZW50KFxuICAgICAgICBlbnZWYXJpYWJsZU5hbWVzLlNTUFlfSU5GUkFfTUFQUElORyxcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkoZnVuYy5tYXBwaW5nKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5wcm9wcz8uZ2VuZXJhdGVTcHlFdmVudHNGaWxlTG9jYXRpb24pIHtcbiAgICAgIHRoaXMud3JpdGVTcHlFdmVudHNDbGFzcyh0aGlzLnByb3BzPy5nZW5lcmF0ZVNweUV2ZW50c0ZpbGVMb2NhdGlvbik7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZXRFeHRlbnNpb25Bc3NldExvY2F0aW9uKCkge1xuICAgIGxldCBleHRlbnNpb25Bc3NldExvY2F0aW9uID0gcGF0aC5qb2luKFxuICAgICAgX19kaXJuYW1lLFxuICAgICAgJy4uL2V4dGVuc2lvbi9kaXN0L2xheWVyJ1xuICAgICk7XG5cbiAgICBjb25zdCBleHRlbnNpb25Bc3NldExvY2F0aW9uQWx0ID0gcGF0aC5qb2luKFxuICAgICAgX19kaXJuYW1lLFxuICAgICAgJy4uL2xpYi9leHRlbnNpb24vZGlzdC9sYXllcidcbiAgICApO1xuXG4gICAgaWYgKCFmcy5leGlzdHNTeW5jKGV4dGVuc2lvbkFzc2V0TG9jYXRpb24pKSB7XG4gICAgICBpZiAoIWZzLmV4aXN0c1N5bmMoZXh0ZW5zaW9uQXNzZXRMb2NhdGlvbkFsdCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGBGb2xkZXIgd2l0aCBhc3NldHMgZm9yIGV4dGVuc2lvbiBkb2VzIG5vdCBleGlzdHMgYXQgJHtleHRlbnNpb25Bc3NldExvY2F0aW9ufSBvciBhdCAke2V4dGVuc2lvbkFzc2V0TG9jYXRpb25BbHR9IGBcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGV4dGVuc2lvbkFzc2V0TG9jYXRpb24gPSBleHRlbnNpb25Bc3NldExvY2F0aW9uQWx0O1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGV4dGVuc2lvbkFzc2V0TG9jYXRpb25XcmFwcGVyID0gcGF0aC5qb2luKFxuICAgICAgZXh0ZW5zaW9uQXNzZXRMb2NhdGlvbixcbiAgICAgICdzcHktd3JhcHBlcidcbiAgICApO1xuICAgIGlmICghZnMuZXhpc3RzU3luYyhleHRlbnNpb25Bc3NldExvY2F0aW9uV3JhcHBlcikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYFdyYXBwZXIgc2NyaXB0IGZvciBleHRlbnNpb24gZG9lcyBub3QgZXhpc3RzICR7ZXh0ZW5zaW9uQXNzZXRMb2NhdGlvbn1gXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGV4dGVuc2lvbkFzc2V0TG9jYXRpb25Db2RlID0gcGF0aC5qb2luKFxuICAgICAgZXh0ZW5zaW9uQXNzZXRMb2NhdGlvbixcbiAgICAgIGBub2RlanMvbm9kZV9tb2R1bGVzL2ludGVyY2VwdG9yLmpzYFxuICAgICk7XG4gICAgaWYgKCFmcy5leGlzdHNTeW5jKGV4dGVuc2lvbkFzc2V0TG9jYXRpb25Db2RlKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgQ29kZSBmb3IgZXh0ZW5zaW9uIGRvZXMgbm90IGV4aXN0cyAke2V4dGVuc2lvbkFzc2V0TG9jYXRpb25Db2RlfWBcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBleHRlbnNpb25Bc3NldExvY2F0aW9uO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRMYW5ndWFnZUV4dGVuc2lvbkFzc2V0TG9jYXRpb24obGFuZ3VhZ2U6IHN0cmluZykge1xuICAgIGNvbnN0IHJvb3REaXIgPSBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4nKTtcblxuICAgIGxldCBleHRlbnNpb25Bc3NldExvY2F0aW9uID0gcGF0aC5qb2luKHJvb3REaXIsIGBleHRlbnNpb25zLyR7bGFuZ3VhZ2V9YCk7XG5cbiAgICBjb25zdCBleHRlbnNpb25Bc3NldExvY2F0aW9uQWx0ID0gcGF0aC5qb2luKFxuICAgICAgcm9vdERpcixcbiAgICAgIGBsaWIvZXh0ZW5zaW9ucy8ke2xhbmd1YWdlfWBcbiAgICApO1xuXG4gICAgaWYgKCFmcy5leGlzdHNTeW5jKGV4dGVuc2lvbkFzc2V0TG9jYXRpb24pKSB7XG4gICAgICBpZiAoIWZzLmV4aXN0c1N5bmMoZXh0ZW5zaW9uQXNzZXRMb2NhdGlvbkFsdCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGBGb2xkZXIgd2l0aCBhc3NldHMgZm9yIGV4dGVuc2lvbiBmb3IgJHtsYW5ndWFnZX0gZG9lcyBub3QgZXhpc3RzIGF0ICR7ZXh0ZW5zaW9uQXNzZXRMb2NhdGlvbn0gb3IgYXQgJHtleHRlbnNpb25Bc3NldExvY2F0aW9uQWx0fSBgXG4gICAgICAgICk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBleHRlbnNpb25Bc3NldExvY2F0aW9uID0gZXh0ZW5zaW9uQXNzZXRMb2NhdGlvbkFsdDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBleHRlbnNpb25Bc3NldExvY2F0aW9uV3JhcHBlciA9IHBhdGguam9pbihcbiAgICAgIC8vIGV4dGVuc2lvbkFzc2V0TG9jYXRpb24uc3Vic3RyaW5nKFxuICAgICAgLy8gICAwLFxuICAgICAgLy8gICBleHRlbnNpb25Bc3NldExvY2F0aW9uLmxhc3RJbmRleE9mKHBhdGguc2VwKVxuICAgICAgLy8gKSxcbiAgICAgIGV4dGVuc2lvbkFzc2V0TG9jYXRpb24sXG4gICAgICAnc3B5LXdyYXBwZXInXG4gICAgKTtcbiAgICBpZiAoIWZzLmV4aXN0c1N5bmMoZXh0ZW5zaW9uQXNzZXRMb2NhdGlvbldyYXBwZXIpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBXcmFwcGVyIHNjcmlwdCBmb3IgZXh0ZW5zaW9uIGRvZXMgbm90IGV4aXN0cyBhdCAke2V4dGVuc2lvbkFzc2V0TG9jYXRpb25XcmFwcGVyfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGV4dGVuc2lvbkFzc2V0TG9jYXRpb247XG4gIH1cblxuICAvKipcbiAgICogV3JpdGUgU3B5RXZlbnRzIGNsYXNzLCB3aGljaCBoZWxwcyB3aXRoIHdyaXRpbmcgdGhlIGNvZGUgZm9yIHRlc3RzLlxuICAgKiBAcGFyYW0gZmlsZUxvY2F0aW9uXG4gICAqL1xuICBwcml2YXRlIHdyaXRlU3B5RXZlbnRzQ2xhc3MoZmlsZUxvY2F0aW9uOiBzdHJpbmcpIHtcbiAgICBmcy5ta2RpclN5bmMocGF0aC5kaXJuYW1lKGZpbGVMb2NhdGlvbiksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuXG4gICAgY29uc3QgcHJvcGVydGllcyA9IHRoaXMuc2VydmljZUtleXNcbiAgICAgIC5tYXAoKHNrKSA9PiBgICAke3NrLnJlcGxhY2UoLyMvZywgJycpfTogJyR7c2t9JyA9ICcke3NrfSc7XFxuYClcbiAgICAgIC5qb2luKCcnKTtcblxuICAgIGNvbnN0IGNvZGUgPSBgLyogZXNsaW50LWRpc2FibGUgKi9cXG5leHBvcnQgY2xhc3MgU2VydmVybGVzc1NweUV2ZW50cyB7XFxuJHtwcm9wZXJ0aWVzfX1cXG5gO1xuXG4gICAgZnMud3JpdGVGaWxlU3luYyhmaWxlTG9jYXRpb24sIGNvZGUpO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRBbGxOb2RlcyhwYXJlbnQ6IElDb25zdHJ1Y3QpIHtcbiAgICBjb25zdCBub2RlczogSUNvbnN0cnVjdFtdID0gW107XG4gICAgbm9kZXMucHVzaChwYXJlbnQpO1xuICAgIHRoaXMuZ2V0QWxsTm9kZXNSZWN1cnNpdmUocGFyZW50LCBub2Rlcyk7XG4gICAgcmV0dXJuIG5vZGVzO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRBbGxOb2Rlc1JlY3Vyc2l2ZShwYXJlbnQ6IElDb25zdHJ1Y3QsIG5vZGVzOiBJQ29uc3RydWN0W10pIHtcbiAgICBmb3IgKGNvbnN0IG5vZGUgb2YgcGFyZW50Lm5vZGUuY2hpbGRyZW4pIHtcbiAgICAgIG5vZGVzLnB1c2gobm9kZSk7XG4gICAgICB0aGlzLmdldEFsbE5vZGVzUmVjdXJzaXZlKG5vZGUsIG5vZGVzKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGludGVybmFsU3B5Tm9kZShub2RlOiBJQ29uc3RydWN0KSB7XG4gICAgaWYgKHRoaXMuc3BpZWROb2Rlcy5pbmNsdWRlcyhub2RlKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuc3BpZWROb2Rlcy5wdXNoKG5vZGUpO1xuXG4gICAgaWYgKHRoaXMuY3JlYXRlZFJlc291cmNlc0J5U1NweS5pbmNsdWRlcyhub2RlKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmxhbWJkYVN1YnNjcmlwdGlvblBvb2wuZmluZCgocykgPT4gcy5mdW5jdGlvbiA9PT0gbm9kZSkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5wcm9wcz8uZGVidWdNb2RlKSB7XG4gICAgICBjb25zb2xlLmluZm8oJ1NweSBvbiBub2RlJywgdGhpcy5nZXRDb25zdHJ1Y3ROYW1lKG5vZGUpKTtcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICBub2RlIGluc3RhbmNlb2YgbGFtYmRhLkZ1bmN0aW9uIHx8XG4gICAgICBub2RlIGluc3RhbmNlb2YgTm9kZWpzRnVuY3Rpb24gfHxcbiAgICAgIGlzTGFtYmRhRnVuY3Rpb24obm9kZSlcbiAgICApIHtcbiAgICAgIHRoaXMuaW50ZXJuYWxTcHlMYW1iZGEobm9kZSk7XG4gICAgfSBlbHNlIGlmIChub2RlIGluc3RhbmNlb2Ygc25zLlRvcGljKSB7XG4gICAgICB0aGlzLmludGVybmFsU3B5U25zVG9waWMobm9kZSk7XG4gICAgfSBlbHNlIGlmIChub2RlIGluc3RhbmNlb2Ygc25zLlN1YnNjcmlwdGlvbikge1xuICAgICAgdGhpcy5pbnRlcm5hbFNweVNuc1N1YnNjcmlwdGlvbihub2RlKTtcbiAgICB9IGVsc2UgaWYgKG5vZGUgaW5zdGFuY2VvZiBzMy5CdWNrZXQpIHtcbiAgICAgIHRoaXMuaW50ZXJuYWxTcHlTMyhub2RlKTtcbiAgICB9IGVsc2UgaWYgKG5vZGUgaW5zdGFuY2VvZiBkeW5hbW9EYi5UYWJsZSkge1xuICAgICAgdGhpcy5pbnRlcm5hbFNweUR5bmFtb2RiKG5vZGUpO1xuICAgIH0gZWxzZSBpZiAobm9kZSBpbnN0YW5jZW9mIGR5bmFtb0RiLlRhYmxlVjIpIHtcbiAgICAgIHRoaXMuaW50ZXJuYWxTcHlEeW5hbW9kYihub2RlKTtcbiAgICB9IGVsc2UgaWYgKG5vZGUgaW5zdGFuY2VvZiBldmVudHMuRXZlbnRCdXMpIHtcbiAgICAgIHRoaXMuaW50ZXJuYWxTcHlFdmVudEJ1cyhub2RlKTtcbiAgICB9IGVsc2UgaWYgKG5vZGUgaW5zdGFuY2VvZiBldmVudHMuUnVsZSkge1xuICAgICAgdGhpcy5pbnRlcm5hbFNweUV2ZW50QnVzUnVsZShub2RlKTtcbiAgICB9IGVsc2UgaWYgKG5vZGUgaW5zdGFuY2VvZiBsYW1iZGEuQ2ZuRXZlbnRTb3VyY2VNYXBwaW5nKSB7XG4gICAgICB0aGlzLmludGVybmFsU3B5U3FzKG5vZGUpO1xuICAgIH0gZWxzZSBpZiAobm9kZSBpbnN0YW5jZW9mIHNxcy5RdWV1ZSkge1xuICAgICAgaWYgKHRoaXMucHJvcHM/LnNweVNxc1dpdGhOb1N1YnNjcmlwdGlvbkFuZERyb3BBbGxNZXNzYWdlcykge1xuICAgICAgICB0aGlzLmludGVybmFsU3B5U3B5U3FzV2l0aE5vU3Vic2NyaXB0aW9uKG5vZGUpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZ2V0RXh0ZW5zaW9uRm9yUnVudGltZShcbiAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZSxcbiAgICBhcmNoaXRlY3R1cmU6IGxhbWJkYS5BcmNoaXRlY3R1cmVcbiAgKTogeyBsYXllcjogbGFtYmRhLklMYXllclZlcnNpb247IHNweVdyYXBwZXJQYXRoOiBzdHJpbmcgfSB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgbGF5ZXJLZXkgPVxuICAgICAgYHNzcHlfZXh0ZW5zaW9uXyR7cnVudGltZS50b1N0cmluZygpfV8ke2FyY2hpdGVjdHVyZS5uYW1lLnRvU3RyaW5nKCl9YC5yZXBsYWNlKFxuICAgICAgICAvXFwuL2csXG4gICAgICAgICdfJ1xuICAgICAgKTtcblxuICAgIGxldCBsYXllciA9IHRoaXMubGF5ZXJNYXBbbGF5ZXJLZXldO1xuICAgIGxldCBzcHlXcmFwcGVyUGF0aCA9ICcvb3B0L3NweS13cmFwcGVyJztcblxuICAgIHN3aXRjaCAocnVudGltZS5uYW1lKSB7XG4gICAgICBjYXNlIGxhbWJkYS5SdW50aW1lLlBZVEhPTl8zXzgubmFtZTpcbiAgICAgIGNhc2UgbGFtYmRhLlJ1bnRpbWUuUFlUSE9OXzNfOS5uYW1lOlxuICAgICAgY2FzZSBsYW1iZGEuUnVudGltZS5QWVRIT05fM18xMC5uYW1lOlxuICAgICAgY2FzZSBsYW1iZGEuUnVudGltZS5QWVRIT05fM18xMS5uYW1lOlxuICAgICAgY2FzZSBsYW1iZGEuUnVudGltZS5QWVRIT05fM18xMi5uYW1lOlxuICAgICAgICBzcHlXcmFwcGVyUGF0aCA9ICcvb3B0L3B5dGhvbi9zcHktd3JhcHBlcic7XG4gICAgICAgIGxheWVyID1cbiAgICAgICAgICBsYXllciB8fFxuICAgICAgICAgIG5ldyBQeXRob25MYXllclZlcnNpb24odGhpcywgbGF5ZXJLZXksIHtcbiAgICAgICAgICAgIGNvbXBhdGlibGVSdW50aW1lczogW3J1bnRpbWVdLFxuICAgICAgICAgICAgY29tcGF0aWJsZUFyY2hpdGVjdHVyZXM6IFthcmNoaXRlY3R1cmVdLFxuICAgICAgICAgICAgZW50cnk6IHRoaXMuZ2V0TGFuZ3VhZ2VFeHRlbnNpb25Bc3NldExvY2F0aW9uKCdweXRob24nKSxcbiAgICAgICAgICAgIGJ1bmRsaW5nOiB7XG4gICAgICAgICAgICAgIGJ1bmRsaW5nRmlsZUFjY2VzczogQnVuZGxpbmdGaWxlQWNjZXNzLlZPTFVNRV9DT1BZLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIGxhbWJkYS5SdW50aW1lLk5PREVKU18xMl9YLm5hbWU6XG4gICAgICBjYXNlIGxhbWJkYS5SdW50aW1lLk5PREVKU18xNF9YLm5hbWU6XG4gICAgICBjYXNlIGxhbWJkYS5SdW50aW1lLk5PREVKU18xNl9YLm5hbWU6XG4gICAgICBjYXNlIGxhbWJkYS5SdW50aW1lLk5PREVKU18xOF9YLm5hbWU6XG4gICAgICBjYXNlIGxhbWJkYS5SdW50aW1lLk5PREVKU18yMF9YLm5hbWU6XG4gICAgICBjYXNlIGxhbWJkYS5SdW50aW1lLk5PREVKU18yMl9YLm5hbWU6XG4gICAgICAgIGxheWVyID1cbiAgICAgICAgICBsYXllciB8fFxuICAgICAgICAgIG5ldyBsYW1iZGEuTGF5ZXJWZXJzaW9uKHRoaXMsIGxheWVyS2V5LCB7XG4gICAgICAgICAgICBjb21wYXRpYmxlUnVudGltZXM6IFtydW50aW1lXSxcbiAgICAgICAgICAgIGNvbXBhdGlibGVBcmNoaXRlY3R1cmVzOiBbYXJjaGl0ZWN0dXJlXSxcbiAgICAgICAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21Bc3NldCh0aGlzLmdldEV4dGVuc2lvbkFzc2V0TG9jYXRpb24oKSksXG4gICAgICAgICAgfSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgY29uc29sZS5sb2coYE5vIGV4dGVuc2lvbnMgYXZhaWxhYmxlIGZvciAke3J1bnRpbWUudG9TdHJpbmcoKX1gKTtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICB0aGlzLmxheWVyTWFwW2xheWVyS2V5XSA9IGxheWVyO1xuICAgIHRoaXMuY3JlYXRlZFJlc291cmNlc0J5U1NweS5wdXNoKGxheWVyKTtcbiAgICByZXR1cm4geyBsYXllciwgc3B5V3JhcHBlclBhdGggfTtcbiAgfVxuXG4gIHByaXZhdGUgaW50ZXJuYWxTcHlTcHlTcXNXaXRoTm9TdWJzY3JpcHRpb24ocXVldWU6IHNxcy5RdWV1ZSkge1xuICAgIGNvbnN0IHN1YnNjcmlwdGlvbiA9IHRoaXMuZmluZEVsZW1lbnQ8bGFtYmRhLkNmbkV2ZW50U291cmNlTWFwcGluZz4oXG4gICAgICAobjogSUNvbnN0cnVjdCkgPT5cbiAgICAgICAgbiBpbnN0YW5jZW9mIGxhbWJkYS5DZm5FdmVudFNvdXJjZU1hcHBpbmcgJiZcbiAgICAgICAgKG4gYXMgbGFtYmRhLkNmbkV2ZW50U291cmNlTWFwcGluZykuZXZlbnRTb3VyY2VBcm4gPT09IHF1ZXVlLnF1ZXVlQXJuXG4gICAgKTtcblxuICAgIGlmIChzdWJzY3JpcHRpb24pIHtcbiAgICAgIHJldHVybjsgLy9hbHJlYWR5IGhhdmUgc3Vic2NyaXB0aW9uXG4gICAgfVxuXG4gICAgY29uc3QgcXVldWVOYW1lID0gdGhpcy5nZXRDb25zdHJ1Y3ROYW1lKHF1ZXVlKTtcbiAgICBjb25zdCBmdW5jID0gbmV3IE5vZGVqc0Z1bmN0aW9uKFxuICAgICAgdGhpcyxcbiAgICAgIGAke3F1ZXVlTmFtZX1TcXNTdWJzY3JpcHRpb25BbmREcm9wQWxsTWVzc2FnZXNgLFxuICAgICAge1xuICAgICAgICBtZW1vcnlTaXplOiA1MTIsXG4gICAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLnNlY29uZHMoNSksXG4gICAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLk5PREVKU18yMl9YLFxuICAgICAgICBoYW5kbGVyOiAnaGFuZGxlcicsXG4gICAgICAgIGVudHJ5OiB0aGlzLmdldEFzc2V0TG9jYXRpb24oXG4gICAgICAgICAgJ2Z1bmN0aW9ucy9zcXNTdWJzY3JpcHRpb25BbmREcm9wQWxsTWVzc2FnZXMuanMnXG4gICAgICAgICksXG4gICAgICAgIGVudmlyb25tZW50OiB0aGlzLmdldERlZmF1bHRMYW1iZGFFbnZpcm9ubWVudFZhcmlhYmxlcygpLFxuICAgICAgfVxuICAgICk7XG4gICAgZnVuYy5hZGRFdmVudFNvdXJjZShuZXcgU3FzRXZlbnRTb3VyY2UocXVldWUpKTtcbiAgICB0aGlzLnNldHVwRm9ySW9UKGZ1bmMpO1xuICAgIGNvbnN0IHsgbGF5ZXIsIHNweVdyYXBwZXJQYXRoIH0gPSB0aGlzLmdldEV4dGVuc2lvbkZvclJ1bnRpbWUoXG4gICAgICBmdW5jLnJ1bnRpbWUsXG4gICAgICBmdW5jLmFyY2hpdGVjdHVyZVxuICAgICkhO1xuICAgIGZ1bmMuYWRkTGF5ZXJzKGxheWVyKTtcblxuICAgIGZ1bmMuYWRkRW52aXJvbm1lbnQoJ0FXU19MQU1CREFfRVhFQ19XUkFQUEVSJywgc3B5V3JhcHBlclBhdGgpO1xuXG4gICAgaWYgKHRoaXMucHJvcHM/LmRlYnVnTW9kZSkge1xuICAgICAgZnVuYy5hZGRFbnZpcm9ubWVudChlbnZWYXJpYWJsZU5hbWVzLlNTUFlfREVCVUcsICd0cnVlJyk7XG4gICAgfVxuXG4gICAgdGhpcy5jcmVhdGVkUmVzb3VyY2VzQnlTU3B5LnB1c2goZnVuYyk7XG5cbiAgICBjb25zdCBzZXJ2aWNlS2V5ID0gYFNxcyMke3F1ZXVlTmFtZX1gO1xuXG4gICAgdGhpcy5hZGRNYXBwaW5nVG9GdW5jdGlvbihmdW5jLCB7XG4gICAgICBrZXk6IHF1ZXVlLnF1ZXVlQXJuLFxuICAgICAgdmFsdWU6IHNlcnZpY2VLZXksXG4gICAgfSk7XG5cbiAgICB0aGlzLnNlcnZpY2VLZXlzLnB1c2goc2VydmljZUtleSk7XG4gICAgZnVuYy5hZGRFbnZpcm9ubWVudChlbnZWYXJpYWJsZU5hbWVzLlNTUFlfU1VCU0NSSUJFRF9UT19TUVMsICd0cnVlJyk7XG4gIH1cblxuICBwcml2YXRlIGludGVybmFsU3B5U3FzKG5vZGU6IGxhbWJkYS5DZm5FdmVudFNvdXJjZU1hcHBpbmcpIHtcbiAgICBjb25zdCBxdWV1ZSA9IHRoaXMuZmluZEVsZW1lbnQ8c3FzLlF1ZXVlPihcbiAgICAgIChuOiBJQ29uc3RydWN0KSA9PlxuICAgICAgICBuIGluc3RhbmNlb2Ygc3FzLlF1ZXVlICYmXG4gICAgICAgIChuIGFzIHNxcy5RdWV1ZSkucXVldWVBcm4gPT09IG5vZGUuZXZlbnRTb3VyY2VBcm5cbiAgICApO1xuXG4gICAgY29uc3QgZnVuYyA9IHRoaXMuZmluZEVsZW1lbnQ8bGFtYmRhLkZ1bmN0aW9uPihcbiAgICAgIChuOiBJQ29uc3RydWN0KSA9PlxuICAgICAgICBuIGluc3RhbmNlb2YgbGFtYmRhLkZ1bmN0aW9uICYmXG4gICAgICAgIChuIGFzIGxhbWJkYS5GdW5jdGlvbikuZnVuY3Rpb25OYW1lID09PSBub2RlLmZ1bmN0aW9uTmFtZVxuICAgICk7XG5cbiAgICBpZiAocXVldWUgJiYgZnVuYykge1xuICAgICAgY29uc3QgcXVldWVOYW1lID0gdGhpcy5nZXRDb25zdHJ1Y3ROYW1lKHF1ZXVlKTtcblxuICAgICAgY29uc3Qgc2VydmljZUtleSA9IGBTcXMjJHtxdWV1ZU5hbWV9YDtcblxuICAgICAgdGhpcy5hZGRNYXBwaW5nVG9GdW5jdGlvbihmdW5jLCB7XG4gICAgICAgIGtleTogcXVldWUucXVldWVBcm4sXG4gICAgICAgIHZhbHVlOiBzZXJ2aWNlS2V5LFxuICAgICAgfSk7XG5cbiAgICAgIHRoaXMuc2VydmljZUtleXMucHVzaChzZXJ2aWNlS2V5KTtcbiAgICAgIGZ1bmMuYWRkRW52aXJvbm1lbnQoZW52VmFyaWFibGVOYW1lcy5TU1BZX1NVQlNDUklCRURfVE9fU1FTLCAndHJ1ZScpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlRnVuY3Rpb25Gb3JTdWJzY3JpcHRpb24oaW5kZXg6IG51bWJlcikge1xuICAgIGNvbnN0IGZ1bmMgPSBuZXcgbGFtYmRhTm9kZS5Ob2RlanNGdW5jdGlvbih0aGlzLCBgU3Vic2NyaXB0aW9uJHtpbmRleH1gLCB7XG4gICAgICBtZW1vcnlTaXplOiA1MTIsXG4gICAgICB0aW1lb3V0OiBEdXJhdGlvbi5zZWNvbmRzKDUpLFxuICAgICAgcnVudGltZTogbGFtYmRhLlJ1bnRpbWUuTk9ERUpTXzIyX1gsXG4gICAgICBoYW5kbGVyOiAnaGFuZGxlcicsXG4gICAgICBlbnRyeTogdGhpcy5nZXRBc3NldExvY2F0aW9uKCdmdW5jdGlvbnMvc2VuZE1lc3NhZ2UuanMnKSxcbiAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgIE5PREVfT1BUSU9OUzogJy0tZW5hYmxlLXNvdXJjZS1tYXBzJyxcbiAgICAgIH0sXG4gICAgfSk7XG4gICAgdGhpcy5zZXR1cEZvcklvVChmdW5jKTtcbiAgICByZXR1cm4gZnVuYztcbiAgfVxuXG4gIHByaXZhdGUgaW50ZXJuYWxTcHlTMyhzM0J1Y2tldDogczMuQnVja2V0KSB7XG4gICAgczNCdWNrZXQuYWRkRXZlbnROb3RpZmljYXRpb24oXG4gICAgICBzMy5FdmVudFR5cGUuT0JKRUNUX0NSRUFURURfUFVULFxuICAgICAgbmV3IHMzbm90aWYuTGFtYmRhRGVzdGluYXRpb24odGhpcy5sYW1iZGFTdWJzY3JpcHRpb25NYWluLmZ1bmN0aW9uKVxuICAgICk7XG5cbiAgICBjb25zdCBuYW1lID0gdGhpcy5nZXRDb25zdHJ1Y3ROYW1lKHMzQnVja2V0KTtcblxuICAgIGNvbnN0IHNlcnZpY2VLZXkgPSBgUzMjJHtuYW1lfWA7XG4gICAgdGhpcy5sYW1iZGFTdWJzY3JpcHRpb25NYWluLm1hcHBpbmdbczNCdWNrZXQuYnVja2V0QXJuXSA9IHNlcnZpY2VLZXk7XG4gICAgdGhpcy5zZXJ2aWNlS2V5cy5wdXNoKHNlcnZpY2VLZXkpO1xuICB9XG5cbiAgcHJpdmF0ZSBpbnRlcm5hbFNweUR5bmFtb2RiKHRhYmxlOiBkeW5hbW9EYi5UYWJsZSB8IGR5bmFtb0RiLlRhYmxlVjIpIHtcbiAgICAvLyBlbmFibGUgRHluYW1vREIgc3RyZWFtcyB3aXRoIGEgaGFja1xuICAgICh0YWJsZS5ub2RlLmRlZmF1bHRDaGlsZCBhcyBkeW5hbW9EYi5DZm5UYWJsZSkuc3RyZWFtU3BlY2lmaWNhdGlvbiA9IHtcbiAgICAgIHN0cmVhbVZpZXdUeXBlOiBkeW5hbW9EYi5TdHJlYW1WaWV3VHlwZS5ORVdfQU5EX09MRF9JTUFHRVMsXG4gICAgfTtcbiAgICAodGFibGUgYXMgYW55KS50YWJsZVN0cmVhbUFybiA9IChcbiAgICAgIHRhYmxlLm5vZGUuZGVmYXVsdENoaWxkIGFzIGR5bmFtb0RiLkNmblRhYmxlXG4gICAgKS5hdHRyU3RyZWFtQXJuO1xuXG4gICAgdGhpcy5sYW1iZGFTdWJzY3JpcHRpb25NYWluLmZ1bmN0aW9uLmFkZEV2ZW50U291cmNlKFxuICAgICAgbmV3IGR5bmFtb0RiU3RyZWFtLkR5bmFtb0V2ZW50U291cmNlKHRhYmxlLCB7XG4gICAgICAgIHN0YXJ0aW5nUG9zaXRpb246IGxhbWJkYS5TdGFydGluZ1Bvc2l0aW9uLkxBVEVTVCxcbiAgICAgICAgYmF0Y2hTaXplOiAxLFxuICAgICAgICByZXRyeUF0dGVtcHRzOiAwLFxuICAgICAgfSlcbiAgICApO1xuXG4gICAgY29uc3QgbmFtZSA9IHRoaXMuZ2V0Q29uc3RydWN0TmFtZSh0YWJsZSk7XG5cbiAgICBjb25zdCBzZXJ2aWNlS2V5ID0gYER5bmFtb0RCIyR7bmFtZX1gO1xuICAgIHRoaXMubGFtYmRhU3Vic2NyaXB0aW9uTWFpbi5tYXBwaW5nW3RhYmxlLnRhYmxlQXJuXSA9IHNlcnZpY2VLZXk7XG4gICAgdGhpcy5zZXJ2aWNlS2V5cy5wdXNoKHNlcnZpY2VLZXkpO1xuICB9XG5cbiAgcHJpdmF0ZSBpbnRlcm5hbFNweUV2ZW50QnVzUnVsZShydWxlOiBldmVudHMuUnVsZSkge1xuICAgIGNvbnN0IHsgZXZlbnRCdXNOYW1lIH0gPSBydWxlLm5vZGUuZGVmYXVsdENoaWxkIGFzIGV2ZW50cy5DZm5SdWxlO1xuICAgIGxldCBicmlkZ2VOYW1lID0gJ0RlZmF1bHQnO1xuICAgIGlmICghIWV2ZW50QnVzTmFtZSkge1xuICAgICAgY29uc3QgZXZlbnRCcmlkZ2UgPSB0aGlzLmdldEV2ZW50QnJpZGdlKGV2ZW50QnVzTmFtZSk7XG5cbiAgICAgIGlmICghZXZlbnRCcmlkZ2UpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW4gbm90IGZpbmQgRXZlbnRCcmlkZ2Ugd2l0aCBuYW1lIFwiJHtldmVudEJ1c05hbWV9XCJgKTtcbiAgICAgIH1cbiAgICAgIGJyaWRnZU5hbWUgPSB0aGlzLmdldENvbnN0cnVjdE5hbWUoZXZlbnRCcmlkZ2UpO1xuICAgIH1cblxuICAgIGNvbnN0IGZ1bmN0aW9uU3Vic2NyaXB0aW9uID0gdGhpcy5wcm92aWRlRnVuY3Rpb25Gb3JTdWJzY3JpcHRpb24oXG4gICAgICAocykgPT4gIXMudXNlZEZvckV2ZW50QnJpZGdlXG4gICAgKTtcbiAgICBmdW5jdGlvblN1YnNjcmlwdGlvbi51c2VkRm9yRXZlbnRCcmlkZ2UgPSB0cnVlO1xuXG4gICAgcnVsZS5hZGRUYXJnZXQobmV3IHRhcmdldHMuTGFtYmRhRnVuY3Rpb24oZnVuY3Rpb25TdWJzY3JpcHRpb24uZnVuY3Rpb24pKTtcblxuICAgIGNvbnN0IHJ1bGVOYW1lID0gdGhpcy5nZXRDb25zdHJ1Y3ROYW1lKHJ1bGUpO1xuICAgIGNvbnN0IHNlcnZpY2VLZXkgPSBgRXZlbnRCcmlkZ2VSdWxlIyR7YnJpZGdlTmFtZX0jJHtydWxlTmFtZX1gO1xuICAgIGZ1bmN0aW9uU3Vic2NyaXB0aW9uLm1hcHBpbmcuZXZlbnRCcmlkZ2UgPSBzZXJ2aWNlS2V5O1xuICAgIHRoaXMuc2VydmljZUtleXMucHVzaChzZXJ2aWNlS2V5KTtcbiAgfVxuXG4gIHByaXZhdGUgaW50ZXJuYWxTcHlFdmVudEJ1cyhldmVudEJ1czogZXZlbnRzLkV2ZW50QnVzKSB7XG4gICAgY29uc3QgZnVuY3Rpb25TdWJzY3JpcHRpb24gPSB0aGlzLnByb3ZpZGVGdW5jdGlvbkZvclN1YnNjcmlwdGlvbihcbiAgICAgIChzKSA9PiAhcy51c2VkRm9yRXZlbnRCcmlkZ2VcbiAgICApO1xuICAgIGZ1bmN0aW9uU3Vic2NyaXB0aW9uLnVzZWRGb3JFdmVudEJyaWRnZSA9IHRydWU7XG5cbiAgICBjb25zdCBicmlkZ2VOYW1lID0gdGhpcy5nZXRDb25zdHJ1Y3ROYW1lKGV2ZW50QnVzKTtcbiAgICBjb25zdCBydWxlID0gbmV3IGV2ZW50cy5SdWxlKHRoaXMsIGBSdWxlQWxsJHticmlkZ2VOYW1lfWAsIHtcbiAgICAgIGV2ZW50QnVzLFxuICAgICAgZXZlbnRQYXR0ZXJuOiB7IHZlcnNpb246IFsnMCddIH0sXG4gICAgICB0YXJnZXRzOiBbbmV3IHRhcmdldHMuTGFtYmRhRnVuY3Rpb24oZnVuY3Rpb25TdWJzY3JpcHRpb24uZnVuY3Rpb24pXSxcbiAgICB9KTtcblxuICAgIHRoaXMuY3JlYXRlZFJlc291cmNlc0J5U1NweS5wdXNoKHJ1bGUpO1xuICAgIGNvbnN0IHNlcnZpY2VLZXkgPSBgRXZlbnRCcmlkZ2UjJHticmlkZ2VOYW1lfWA7XG4gICAgZnVuY3Rpb25TdWJzY3JpcHRpb24ubWFwcGluZy5ldmVudEJyaWRnZSA9IHNlcnZpY2VLZXk7XG4gICAgdGhpcy5zZXJ2aWNlS2V5cy5wdXNoKHNlcnZpY2VLZXkpO1xuICB9XG5cbiAgcHJpdmF0ZSBpbnRlcm5hbFNweVNuc1RvcGljKHRvcGljOiBzbnMuVG9waWMpIHtcbiAgICBjb25zdCBmdW5jdGlvblN1YnNjcmlwdGlvbiA9IHRoaXMucHJvdmlkZUZ1bmN0aW9uRm9yU3Vic2NyaXB0aW9uKFxuICAgICAgKHMpID0+ICFzLnN1YnNyaWJlZFRvcGljcy5pbmNsdWRlcyh0b3BpYylcbiAgICApO1xuXG4gICAgY29uc3Qgc3Vic2NyaXB0aW9uID0gdG9waWMuYWRkU3Vic2NyaXB0aW9uKFxuICAgICAgbmV3IHNuc1N1YnMuTGFtYmRhU3Vic2NyaXB0aW9uKGZ1bmN0aW9uU3Vic2NyaXB0aW9uLmZ1bmN0aW9uKVxuICAgICk7XG4gICAgdGhpcy5jcmVhdGVkUmVzb3VyY2VzQnlTU3B5LnB1c2goc3Vic2NyaXB0aW9uKTtcbiAgICBjb25zdCB0b3BpY05hbWUgPSB0aGlzLmdldENvbnN0cnVjdE5hbWUodG9waWMpO1xuICAgIGNvbnN0IHNlcnZpY2VLZXkgPSBgU25zVG9waWMjJHt0b3BpY05hbWV9YDtcbiAgICBmdW5jdGlvblN1YnNjcmlwdGlvbi5tYXBwaW5nW3RvcGljLnRvcGljQXJuXSA9IHNlcnZpY2VLZXk7XG4gICAgdGhpcy5zZXJ2aWNlS2V5cy5wdXNoKHNlcnZpY2VLZXkpO1xuICAgIGZ1bmN0aW9uU3Vic2NyaXB0aW9uLnN1YnNyaWJlZFRvcGljcy5wdXNoKHRvcGljKTtcbiAgfVxuXG4gIHByaXZhdGUgaW50ZXJuYWxTcHlTbnNTdWJzY3JpcHRpb24oc3Vic2NyaXB0aW9uOiBzbnMuU3Vic2NyaXB0aW9uKSB7XG4gICAgaWYgKCFzdWJzY3JpcHRpb24ubm9kZS5zY29wZSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHRvcGljID0gdGhpcy5nZXRUb3BpYyhcbiAgICAgIChzdWJzY3JpcHRpb24ubm9kZS5kZWZhdWx0Q2hpbGQgYXMgc25zLkNmblN1YnNjcmlwdGlvbikudG9waWNBcm5cbiAgICApO1xuXG4gICAgaWYgKCF0b3BpYykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW4gbm90IGZpbmQgVG9waWMnKTtcbiAgICB9XG5cbiAgICBjb25zdCBmdW5jdGlvblN1YnNjcmlwdGlvbiA9IHRoaXMucHJvdmlkZUZ1bmN0aW9uRm9yU3Vic2NyaXB0aW9uKFxuICAgICAgKHMpID0+ICFzLnN1YnNyaWJlZFRvcGljcy5pbmNsdWRlcyh0b3BpYylcbiAgICApO1xuXG4gICAgY29uc3QgeyBmaWx0ZXJQb2xpY3kgfSA9IHN1YnNjcmlwdGlvbi5ub2RlXG4gICAgICAuZGVmYXVsdENoaWxkIGFzIHNucy5DZm5TdWJzY3JpcHRpb247XG5cbiAgICBjb25zdCBzdWJzY3JpcHRpb25DbG9uZSA9IHRvcGljLmFkZFN1YnNjcmlwdGlvbihcbiAgICAgIG5ldyBzbnNTdWJzLkxhbWJkYVN1YnNjcmlwdGlvbihmdW5jdGlvblN1YnNjcmlwdGlvbi5mdW5jdGlvbilcbiAgICApO1xuICAgIChzdWJzY3JpcHRpb25DbG9uZS5ub2RlLmRlZmF1bHRDaGlsZCBhcyBzbnMuQ2ZuU3Vic2NyaXB0aW9uKS5maWx0ZXJQb2xpY3kgPVxuICAgICAgZmlsdGVyUG9saWN5O1xuXG4gICAgdGhpcy5jcmVhdGVkUmVzb3VyY2VzQnlTU3B5LnB1c2goc3Vic2NyaXB0aW9uQ2xvbmUpO1xuXG4gICAgY29uc3QgdG9waWNOYW1lID0gdGhpcy5nZXRDb25zdHJ1Y3ROYW1lKHRvcGljKTtcbiAgICBjb25zdCB0YXJnZXROYW1lID0gdGhpcy5nZXRDb25zdHJ1Y3ROYW1lKHN1YnNjcmlwdGlvbi5ub2RlLnNjb3BlKTtcblxuICAgIGZ1bmN0aW9uU3Vic2NyaXB0aW9uLnN1YnNyaWJlZFRvcGljcy5wdXNoKHRvcGljKTtcbiAgICBjb25zdCBzZXJ2aWNlS2V5ID0gYFNuc1N1YnNjcmlwdGlvbiMke3RvcGljTmFtZX0jJHt0YXJnZXROYW1lfWA7XG4gICAgZnVuY3Rpb25TdWJzY3JpcHRpb24ubWFwcGluZ1t0b3BpYy50b3BpY0Fybl0gPSBzZXJ2aWNlS2V5O1xuICAgIHRoaXMuc2VydmljZUtleXMucHVzaChzZXJ2aWNlS2V5KTtcbiAgfVxuXG4gIHByaXZhdGUgcHJvdmlkZUZ1bmN0aW9uRm9yU3Vic2NyaXB0aW9uKFxuICAgIGZpbHRlckZ1bmN0aW9uPzogKHN1YnNjcmlwdGlvbjogTGFtYmRhU3Vic2NyaXB0aW9uKSA9PiBib29sZWFuXG4gICkge1xuICAgIGxldCBmdW5jdGlvblN1YnNjcmlwdGlvbjogTGFtYmRhU3Vic2NyaXB0aW9uIHwgdW5kZWZpbmVkO1xuXG4gICAgaWYgKGZpbHRlckZ1bmN0aW9uKSB7XG4gICAgICBmdW5jdGlvblN1YnNjcmlwdGlvbiA9IHRoaXMubGFtYmRhU3Vic2NyaXB0aW9uUG9vbC5maW5kKGZpbHRlckZ1bmN0aW9uKTtcbiAgICB9IGVsc2UgaWYgKHRoaXMubGFtYmRhU3Vic2NyaXB0aW9uUG9vbC5sZW5ndGggPiAwKSB7XG4gICAgICBmdW5jdGlvblN1YnNjcmlwdGlvbiA9IHRoaXMubGFtYmRhU3Vic2NyaXB0aW9uUG9vbFswXTtcbiAgICB9XG5cbiAgICBpZiAoIWZ1bmN0aW9uU3Vic2NyaXB0aW9uKSB7XG4gICAgICBmdW5jdGlvblN1YnNjcmlwdGlvbiA9IHtcbiAgICAgICAgc3Vic3JpYmVkVG9waWNzOiBbXSxcbiAgICAgICAgdXNlZEZvckV2ZW50QnJpZGdlOiBmYWxzZSxcbiAgICAgICAgbWFwcGluZzoge30sXG4gICAgICAgIGZ1bmN0aW9uOiB0aGlzLmNyZWF0ZUZ1bmN0aW9uRm9yU3Vic2NyaXB0aW9uKFxuICAgICAgICAgIHRoaXMubGFtYmRhU3Vic2NyaXB0aW9uUG9vbC5sZW5ndGhcbiAgICAgICAgKSxcbiAgICAgIH07XG4gICAgICB0aGlzLmxhbWJkYVN1YnNjcmlwdGlvblBvb2wucHVzaChmdW5jdGlvblN1YnNjcmlwdGlvbik7XG4gICAgfVxuICAgIHJldHVybiBmdW5jdGlvblN1YnNjcmlwdGlvbjtcbiAgfVxuXG4gIHByaXZhdGUgc2V0dXBGb3JJb1QoZnVuYzogbGFtYmRhLkZ1bmN0aW9uKSB7XG4gICAgZnVuYy5hZGRFbnZpcm9ubWVudChcbiAgICAgIGVudlZhcmlhYmxlTmFtZXMuU1NQWV9ST09UX1NUQUNLLFxuICAgICAgdGhpcy5jbGVhbk5hbWUodGhpcy5maW5kUm9vdFN0YWNrKFN0YWNrLm9mKHRoaXMpKS5ub2RlLmlkKVxuICAgICk7XG4gICAgZnVuYy5hZGRFbnZpcm9ubWVudChlbnZWYXJpYWJsZU5hbWVzLlNTUFlfSU9UX0VORFBPSU5ULCB0aGlzLmlvdEVuZHBvaW50KTtcblxuICAgIGZ1bmMuYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IGF3c19pYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgYWN0aW9uczogWydpb3Q6KiddLFxuICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPVyxcbiAgICAgICAgcmVzb3VyY2VzOiBbJyonXSxcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgaW50ZXJuYWxTcHlMYW1iZGEoZnVuYzogbGFtYmRhLkZ1bmN0aW9uKSB7XG4gICAgY29uc3QgeyBsYXllciwgc3B5V3JhcHBlclBhdGggfSA9IHRoaXMuZ2V0RXh0ZW5zaW9uRm9yUnVudGltZShcbiAgICAgIGZ1bmMucnVudGltZSxcbiAgICAgIGZ1bmMuYXJjaGl0ZWN0dXJlIHx8IEFyY2hpdGVjdHVyZS5YODZfNjRcbiAgICApITtcbiAgICBpZiAoIWxheWVyKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGZ1bmMuYWRkTGF5ZXJzKGxheWVyKTtcblxuICAgIGNvbnN0IGZ1bmN0aW9uTmFtZSA9IHRoaXMuZ2V0Q29uc3RydWN0TmFtZShmdW5jKTtcblxuICAgIGZ1bmMuYWRkRW52aXJvbm1lbnQoZW52VmFyaWFibGVOYW1lcy5TU1BZX0ZVTkNUSU9OX05BTUUsIGZ1bmN0aW9uTmFtZSk7XG4gICAgZnVuYy5hZGRFbnZpcm9ubWVudCgnQVdTX0xBTUJEQV9FWEVDX1dSQVBQRVInLCBzcHlXcmFwcGVyUGF0aCk7XG5cbiAgICBpZiAodGhpcy5wcm9wcz8uZGVidWdNb2RlKSB7XG4gICAgICBmdW5jLmFkZEVudmlyb25tZW50KGVudlZhcmlhYmxlTmFtZXMuU1NQWV9ERUJVRywgJ3RydWUnKTtcbiAgICB9XG5cbiAgICB0aGlzLnNldHVwRm9ySW9UKGZ1bmMpO1xuXG4gICAgdGhpcy5zZXJ2aWNlS2V5cy5wdXNoKGBGdW5jdGlvbiMke2Z1bmN0aW9uTmFtZX0jUmVxdWVzdGApO1xuICAgIHRoaXMuc2VydmljZUtleXMucHVzaChgRnVuY3Rpb24jJHtmdW5jdGlvbk5hbWV9I0Vycm9yYCk7XG4gICAgdGhpcy5zZXJ2aWNlS2V5cy5wdXNoKGBGdW5jdGlvbiMke2Z1bmN0aW9uTmFtZX0jQ29uc29sZWApO1xuICAgIHRoaXMuc2VydmljZUtleXMucHVzaChgRnVuY3Rpb24jJHtmdW5jdGlvbk5hbWV9I1Jlc3BvbnNlYCk7XG5cbiAgICB0aGlzLmFkZE1hcHBpbmdUb0Z1bmN0aW9uKGZ1bmMpO1xuICB9XG5cbiAgcHVibGljIGdldENvbnN0cnVjdE5hbWUoY29uc3RydWN0OiBJQ29uc3RydWN0KSB7XG4gICAgbGV0IGNvbnN0cnVjdE5hbWUgPSBjb25zdHJ1Y3Qubm9kZS5wYXRoO1xuICAgIGNvbnN0IHsgbm9kZSB9ID0gU3RhY2sub2YodGhpcyk7XG5cbiAgICBpZiAoY29uc3RydWN0TmFtZS5zdGFydHNXaXRoKG5vZGUuaWQpKSB7XG4gICAgICBjb25zdHJ1Y3ROYW1lID0gY29uc3RydWN0TmFtZS5zdWJzdHJpbmcobm9kZS5pZC5sZW5ndGggKyAxKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5jbGVhbk5hbWUoY29uc3RydWN0TmFtZSk7XG4gIH1cblxuICBwcml2YXRlIGNsZWFuTmFtZShuYW1lOiBzdHJpbmcpIHtcbiAgICAvL3NuYWtlIGNhc2UgdG8gY2FtZWwgY2FzZSBpbmNsdWRpbmcgZGFzaCBhbmQgZmlyc3QgbGV0dGVyIHRvIHVwcGVyIGNhc2VcbiAgICByZXR1cm4gbmFtZVxuICAgICAgLnJlcGxhY2UoL1stX10rL2csICcgJylcbiAgICAgIC5yZXBsYWNlKC9bXlxcd1xcc10vZywgJycpXG4gICAgICAucmVwbGFjZSgvXFxzKC4pL2csICgkMSkgPT4gJDEudG9VcHBlckNhc2UoKSlcbiAgICAgIC5yZXBsYWNlKC9cXHMvZywgJycpXG4gICAgICAucmVwbGFjZSgvXiguKS8sICgkMSkgPT4gJDEudG9VcHBlckNhc2UoKSk7XG4gIH1cblxuICBwcml2YXRlIGdldFRvcGljKHRvcGljQXJuOiBzdHJpbmcpOiBzbnMuVG9waWMgfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IHRvcGljID0gdGhpcy5maW5kRWxlbWVudDxzbnMuVG9waWM+KFxuICAgICAgKG5vZGU6IElDb25zdHJ1Y3QpID0+XG4gICAgICAgIG5vZGUgaW5zdGFuY2VvZiBzbnMuVG9waWMgJiYgKG5vZGUgYXMgc25zLlRvcGljKS50b3BpY0FybiA9PT0gdG9waWNBcm5cbiAgICApO1xuXG4gICAgcmV0dXJuIHRvcGljO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRFdmVudEJyaWRnZShldmVudEJ1c05hbWU6IHN0cmluZyk6IGV2ZW50cy5JRXZlbnRCdXMgfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IGV2ZW50QnJpZGdlID0gdGhpcy5maW5kRWxlbWVudDxldmVudHMuSUV2ZW50QnVzPihcbiAgICAgIChub2RlOiBJQ29uc3RydWN0KSA9PlxuICAgICAgICAobm9kZSBpbnN0YW5jZW9mIGV2ZW50cy5FdmVudEJ1cyB8fFxuICAgICAgICAgIG5vZGUuY29uc3RydWN0b3IubmFtZSA9PT0gJ0ltcG9ydGVkRXZlbnRCdXMnKSAmJlxuICAgICAgICAobm9kZSBhcyBldmVudHMuSUV2ZW50QnVzKS5ldmVudEJ1c05hbWUgPT09IGV2ZW50QnVzTmFtZVxuICAgICk7XG5cbiAgICByZXR1cm4gZXZlbnRCcmlkZ2U7XG4gIH1cblxuICBwcml2YXRlIGZpbmRSb290U3RhY2soc3RhY2s6IFN0YWNrKTogU3RhY2sge1xuICAgIGlmIChzdGFjay5uZXN0ZWQpIHtcbiAgICAgIGNvbnN0IHBhcmVudFN0YWNrID0gKHN0YWNrIGFzIE5lc3RlZFN0YWNrKS5uZXN0ZWRTdGFja1BhcmVudDtcbiAgICAgIGlmIChwYXJlbnRTdGFjaykgcmV0dXJuIHRoaXMuZmluZFJvb3RTdGFjayhwYXJlbnRTdGFjayk7XG4gICAgICByZXR1cm4gc3RhY2s7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBzdGFjaztcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGZpbmRFbGVtZW50PFQgZXh0ZW5kcyBJQ29uc3RydWN0ID0gSUNvbnN0cnVjdD4oXG4gICAgZmlsdGVyRnVuYzogKG5vZGU6IElDb25zdHJ1Y3QpID0+IGJvb2xlYW4sXG4gICAgcGFyZW50PzogSUNvbnN0cnVjdFxuICApOiBUIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoIXBhcmVudCkge1xuICAgICAgcGFyZW50ID0gdGhpcy5maW5kUm9vdFN0YWNrKFN0YWNrLm9mKHRoaXMpKTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IG5vZGUgb2YgcGFyZW50Lm5vZGUuY2hpbGRyZW4pIHtcbiAgICAgIGlmIChmaWx0ZXJGdW5jKG5vZGUpKSB7XG4gICAgICAgIHJldHVybiBub2RlIGFzIFQ7XG4gICAgICB9XG4gICAgICBjb25zdCBlbGVtZW50Rm91bmRJbkNoaWxkID0gdGhpcy5maW5kRWxlbWVudDxUPihmaWx0ZXJGdW5jLCBub2RlKTtcbiAgICAgIGlmIChlbGVtZW50Rm91bmRJbkNoaWxkKSB7XG4gICAgICAgIHJldHVybiBlbGVtZW50Rm91bmRJbkNoaWxkO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBwcml2YXRlIGFkZE1hcHBpbmdUb0Z1bmN0aW9uKFxuICAgIGZ1bmM6IGxhbWJkYS5GdW5jdGlvbixcbiAgICBrZXlWYWx1ZT86IHsga2V5OiBzdHJpbmc7IHZhbHVlOiBzdHJpbmcgfVxuICApIHtcbiAgICBmb3IgKGNvbnN0IGZzIG9mIHRoaXMubGFtYmRhc1NwaWVkKSB7XG4gICAgICBpZiAoZnMuZnVuY3Rpb24gPT09IGZ1bmMpIHtcbiAgICAgICAgaWYgKGtleVZhbHVlKSB7XG4gICAgICAgICAgZnMubWFwcGluZ1trZXlWYWx1ZS5rZXldID0ga2V5VmFsdWUudmFsdWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGZzOiBMYW1iZGFTcGllZCA9IHtcbiAgICAgIGZ1bmN0aW9uOiBmdW5jLFxuICAgICAgbWFwcGluZzoge30sXG4gICAgfTtcblxuICAgIGlmIChrZXlWYWx1ZSkge1xuICAgICAgZnMubWFwcGluZ1trZXlWYWx1ZS5rZXldID0ga2V5VmFsdWUudmFsdWU7XG4gICAgfVxuXG4gICAgdGhpcy5sYW1iZGFzU3BpZWQucHVzaChmcyk7XG4gIH1cblxuICBwcml2YXRlIGdldEFzc2V0TG9jYXRpb24obG9jYXRpb246IHN0cmluZykge1xuICAgIGNvbnN0IGxvYyA9IHBhdGguam9pbihfX2Rpcm5hbWUsICcuLi9saWIvJyArIGxvY2F0aW9uKTtcblxuICAgIGlmIChmcy5leGlzdHNTeW5jKGxvYykpIHtcbiAgICAgIHJldHVybiBsb2M7XG4gICAgfVxuXG4gICAgY29uc3QgbG9jMiA9IHBhdGguam9pbihfX2Rpcm5hbWUsICcuLi8uLi9saWIvJyArIGxvY2F0aW9uKTtcblxuICAgIGlmIChmcy5leGlzdHNTeW5jKGxvYzIpKSB7XG4gICAgICByZXR1cm4gbG9jMjtcbiAgICB9XG5cbiAgICB0aHJvdyBuZXcgRXJyb3IoYExvY2F0aW9uICR7bG9jfSBhbmQgJHtsb2MyfSBkb2VzIG5vdCBleGlzdHMuYCk7XG4gIH1cbn1cblxudHlwZSBMYW1iZGFTdWJzY3JpcHRpb24gPSB7XG4gIHN1YnNyaWJlZFRvcGljczogc25zLlRvcGljW107XG4gIHVzZWRGb3JFdmVudEJyaWRnZTogYm9vbGVhbjtcbiAgZnVuY3Rpb246IGxhbWJkYU5vZGUuTm9kZWpzRnVuY3Rpb247XG4gIG1hcHBpbmc6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG59O1xuXG50eXBlIExhbWJkYVNwaWVkID0ge1xuICBmdW5jdGlvbjogbGFtYmRhLkZ1bmN0aW9uO1xuICBtYXBwaW5nOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xufTtcbiJdfQ==
1
+ import { __dirname } from "../node_modules/tsdown/esm-shims.mjs";
2
+ import { envVariableNames, init_envVariableNames } from "./common/envVariableNames.mjs";
3
+ import * as fs from "fs";
4
+ import * as path from "path";
5
+ import { PythonLayerVersion } from "@aws-cdk/aws-lambda-python-alpha";
6
+ import { BundlingFileAccess, CfnOutput, Duration, Stack, aws_iam, custom_resources } from "aws-cdk-lib";
7
+ import * as dynamoDb from "aws-cdk-lib/aws-dynamodb";
8
+ import * as events from "aws-cdk-lib/aws-events";
9
+ import * as targets from "aws-cdk-lib/aws-events-targets";
10
+ import { Effect } from "aws-cdk-lib/aws-iam";
11
+ import * as lambda from "aws-cdk-lib/aws-lambda";
12
+ import { Architecture, SingletonFunction } from "aws-cdk-lib/aws-lambda";
13
+ import * as dynamoDbStream from "aws-cdk-lib/aws-lambda-event-sources";
14
+ import { SqsEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
15
+ import * as lambdaNode from "aws-cdk-lib/aws-lambda-nodejs";
16
+ import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
17
+ import * as s3 from "aws-cdk-lib/aws-s3";
18
+ import * as s3notif from "aws-cdk-lib/aws-s3-notifications";
19
+ import * as sns from "aws-cdk-lib/aws-sns";
20
+ import * as snsSubs from "aws-cdk-lib/aws-sns-subscriptions";
21
+ import * as sqs from "aws-cdk-lib/aws-sqs";
22
+ import { Construct } from "constructs";
23
+
24
+ //#region src/ServerlessSpy.ts
25
+ init_envVariableNames();
26
+ const isLambdaFunction = (node) => "functionName" in node && "functionArn" in node && "runtime" in node;
27
+ const serverlessSpyIotEndpointCrNamePrefix = "ServerlessSpyIotEndpoint";
28
+ var ServerlessSpy = class extends Construct {
29
+ constructor(scope, id, props) {
30
+ super(scope, id);
31
+ this.props = props;
32
+ this.createdResourcesBySSpy = [];
33
+ this.lambdaSubscriptionPool = [];
34
+ this.lambdasSpied = [];
35
+ this.serviceKeys = [];
36
+ this.spiedNodes = [];
37
+ this.layerMap = {};
38
+ const rootStack = this.cleanName(this.findRootStack(Stack.of(this)).node.id);
39
+ const getIoTEndpoint = new custom_resources.AwsCustomResource(this, serverlessSpyIotEndpointCrNamePrefix, {
40
+ onCreate: {
41
+ service: "Iot",
42
+ action: "describeEndpoint",
43
+ physicalResourceId: custom_resources.PhysicalResourceId.fromResponse("endpointAddress"),
44
+ parameters: { endpointType: "iot:Data-ATS" }
45
+ },
46
+ onUpdate: {
47
+ service: "Iot",
48
+ action: "describeEndpoint",
49
+ physicalResourceId: custom_resources.PhysicalResourceId.fromResponse("endpointAddress"),
50
+ parameters: { endpointType: "iot:Data-ATS" }
51
+ },
52
+ installLatestAwsSdk: false,
53
+ policy: custom_resources.AwsCustomResourcePolicy.fromSdkCalls({ resources: custom_resources.AwsCustomResourcePolicy.ANY_RESOURCE }),
54
+ functionName: serverlessSpyIotEndpointCrNamePrefix + rootStack
55
+ });
56
+ this.iotEndpoint = getIoTEndpoint.getResponseField("endpointAddress");
57
+ this.createdResourcesBySSpy.push(getIoTEndpoint);
58
+ new CfnOutput(this, "ServerlessSpyIoTEndpoint", {
59
+ key: "ServerlessSpyWsUrl",
60
+ value: `${this.iotEndpoint}/${rootStack}`
61
+ });
62
+ this.lambdaSubscriptionMain = this.provideFunctionForSubscription();
63
+ }
64
+ getDefaultLambdaEnvironmentVariables() {
65
+ return { NODE_OPTIONS: "--enable-source-maps" };
66
+ }
67
+ /**
68
+ * Initalize spying on resources given as parameter.
69
+ * @param nodes Which reources and their children to spy on.
70
+ */
71
+ spyNodes(nodes) {
72
+ for (const node of nodes) {
73
+ let ns = this.getAllNodes(node);
74
+ this.internalSpyNodes(ns);
75
+ }
76
+ this.finalizeSpy();
77
+ }
78
+ /**
79
+ * Initalize spying on resources.
80
+ * @param filter Limit which resources to spy on.
81
+ */
82
+ spy(filter) {
83
+ let nodes = this.getAllNodes(Stack.of(this));
84
+ const filterWithDefaults = {
85
+ spyLambda: true,
86
+ spySqs: true,
87
+ spySnsTopic: true,
88
+ spySnsSubsription: true,
89
+ spyEventBridge: true,
90
+ spyEventBridgeRule: true,
91
+ spyS3: true,
92
+ spyDynamoDB: true,
93
+ ...filter
94
+ };
95
+ const CRID = "AWS" + custom_resources.AwsCustomResource.PROVIDER_FUNCTION_UUID.replace(/-/gi, "").substring(0, 16);
96
+ nodes = nodes.filter((node) => {
97
+ if (node.node.id.startsWith(CRID) || node.node.id === "Provider" || node instanceof SingletonFunction) {
98
+ if (this.props?.debugMode) console.info(`Skipping ${node.node.id}`);
99
+ return false;
100
+ } else if (filterWithDefaults.spyLambda && (node instanceof lambda.Function || node instanceof NodejsFunction || isLambdaFunction(node))) return true;
101
+ else if (filterWithDefaults.spySnsTopic && node instanceof sns.Topic) return true;
102
+ else if (filterWithDefaults.spySnsSubsription && node instanceof sns.Subscription) return true;
103
+ else if (filterWithDefaults.spyS3 && node instanceof s3.Bucket) return true;
104
+ else if (filterWithDefaults.spyDynamoDB && node instanceof dynamoDb.Table) return true;
105
+ else if (filterWithDefaults.spyDynamoDB && node instanceof dynamoDb.TableV2) return true;
106
+ else if (filterWithDefaults.spyEventBridge && node instanceof events.EventBus) return true;
107
+ else if (filterWithDefaults.spyEventBridgeRule && node instanceof events.Rule) return true;
108
+ else if (filterWithDefaults.spySqs && node instanceof lambda.CfnEventSourceMapping) return true;
109
+ else if (filterWithDefaults.spySqs && this.props?.spySqsWithNoSubscriptionAndDropAllMessages && node instanceof sqs.Queue) return true;
110
+ return false;
111
+ });
112
+ this.internalSpyNodes(nodes);
113
+ this.finalizeSpy();
114
+ }
115
+ internalSpyNodes(nodes) {
116
+ for (const node of nodes) this.internalSpyNode(node);
117
+ }
118
+ finalizeSpy() {
119
+ for (const func of this.lambdaSubscriptionPool) func.function.addEnvironment(envVariableNames.SSPY_INFRA_MAPPING, JSON.stringify(func.mapping));
120
+ for (const func of this.lambdasSpied) func.function.addEnvironment(envVariableNames.SSPY_INFRA_MAPPING, JSON.stringify(func.mapping));
121
+ if (this.props?.generateSpyEventsFileLocation) this.writeSpyEventsClass(this.props?.generateSpyEventsFileLocation);
122
+ }
123
+ getExtensionAssetLocation() {
124
+ let extensionAssetLocation = path.join(__dirname, "../extension/dist/layer");
125
+ const extensionAssetLocationAlt = path.join(__dirname, "../lib/extension/dist/layer");
126
+ if (!fs.existsSync(extensionAssetLocation)) if (!fs.existsSync(extensionAssetLocationAlt)) throw new Error(`Folder with assets for extension does not exists at ${extensionAssetLocation} or at ${extensionAssetLocationAlt} `);
127
+ else extensionAssetLocation = extensionAssetLocationAlt;
128
+ const extensionAssetLocationWrapper = path.join(extensionAssetLocation, "spy-wrapper");
129
+ if (!fs.existsSync(extensionAssetLocationWrapper)) throw new Error(`Wrapper script for extension does not exists ${extensionAssetLocation}`);
130
+ const extensionAssetLocationCode = path.join(extensionAssetLocation, `nodejs/node_modules/interceptor.js`);
131
+ if (!fs.existsSync(extensionAssetLocationCode)) throw new Error(`Code for extension does not exists ${extensionAssetLocationCode}`);
132
+ return extensionAssetLocation;
133
+ }
134
+ getLanguageExtensionAssetLocation(language) {
135
+ const rootDir = path.join(__dirname, "..");
136
+ let extensionAssetLocation = path.join(rootDir, `extensions/${language}`);
137
+ const extensionAssetLocationAlt = path.join(rootDir, `lib/extensions/${language}`);
138
+ if (!fs.existsSync(extensionAssetLocation)) if (!fs.existsSync(extensionAssetLocationAlt)) throw new Error(`Folder with assets for extension for ${language} does not exists at ${extensionAssetLocation} or at ${extensionAssetLocationAlt} `);
139
+ else extensionAssetLocation = extensionAssetLocationAlt;
140
+ const extensionAssetLocationWrapper = path.join(extensionAssetLocation, "spy-wrapper");
141
+ if (!fs.existsSync(extensionAssetLocationWrapper)) throw new Error(`Wrapper script for extension does not exists at ${extensionAssetLocationWrapper}`);
142
+ return extensionAssetLocation;
143
+ }
144
+ /**
145
+ * Write SpyEvents class, which helps with writing the code for tests.
146
+ * @param fileLocation
147
+ */
148
+ writeSpyEventsClass(fileLocation) {
149
+ fs.mkdirSync(path.dirname(fileLocation), { recursive: true });
150
+ const code = `/* eslint-disable */\nexport class ServerlessSpyEvents {\n${this.serviceKeys.map((sk) => ` ${sk.replace(/#/g, "")}: '${sk}' = '${sk}';\n`).join("")}}\n`;
151
+ fs.writeFileSync(fileLocation, code);
152
+ }
153
+ getAllNodes(parent) {
154
+ const nodes = [];
155
+ nodes.push(parent);
156
+ this.getAllNodesRecursive(parent, nodes);
157
+ return nodes;
158
+ }
159
+ getAllNodesRecursive(parent, nodes) {
160
+ for (const node of parent.node.children) {
161
+ nodes.push(node);
162
+ this.getAllNodesRecursive(node, nodes);
163
+ }
164
+ }
165
+ internalSpyNode(node) {
166
+ if (this.spiedNodes.includes(node)) return;
167
+ this.spiedNodes.push(node);
168
+ if (this.createdResourcesBySSpy.includes(node)) return;
169
+ if (this.lambdaSubscriptionPool.find((s) => s.function === node)) return;
170
+ if (this.props?.debugMode) console.info("Spy on node", this.getConstructName(node));
171
+ if (node instanceof lambda.Function || node instanceof NodejsFunction || isLambdaFunction(node)) this.internalSpyLambda(node);
172
+ else if (node instanceof sns.Topic) this.internalSpySnsTopic(node);
173
+ else if (node instanceof sns.Subscription) this.internalSpySnsSubscription(node);
174
+ else if (node instanceof s3.Bucket) this.internalSpyS3(node);
175
+ else if (node instanceof dynamoDb.Table) this.internalSpyDynamodb(node);
176
+ else if (node instanceof dynamoDb.TableV2) this.internalSpyDynamodb(node);
177
+ else if (node instanceof events.EventBus) this.internalSpyEventBus(node);
178
+ else if (node instanceof events.Rule) this.internalSpyEventBusRule(node);
179
+ else if (node instanceof lambda.CfnEventSourceMapping) this.internalSpySqs(node);
180
+ else if (node instanceof sqs.Queue) {
181
+ if (this.props?.spySqsWithNoSubscriptionAndDropAllMessages) this.internalSpySpySqsWithNoSubscription(node);
182
+ }
183
+ }
184
+ getExtensionForRuntime(runtime, architecture) {
185
+ const layerKey = `sspy_extension_${runtime.toString()}_${architecture.name.toString()}`.replace(/\./g, "_");
186
+ let layer = this.layerMap[layerKey];
187
+ let spyWrapperPath = "/opt/spy-wrapper";
188
+ switch (runtime.name) {
189
+ case lambda.Runtime.PYTHON_3_8.name:
190
+ case lambda.Runtime.PYTHON_3_9.name:
191
+ case lambda.Runtime.PYTHON_3_10.name:
192
+ case lambda.Runtime.PYTHON_3_11.name:
193
+ case lambda.Runtime.PYTHON_3_12.name:
194
+ spyWrapperPath = "/opt/python/spy-wrapper";
195
+ layer = layer || new PythonLayerVersion(this, layerKey, {
196
+ compatibleRuntimes: [runtime],
197
+ compatibleArchitectures: [architecture],
198
+ entry: this.getLanguageExtensionAssetLocation("python"),
199
+ bundling: { bundlingFileAccess: BundlingFileAccess.VOLUME_COPY }
200
+ });
201
+ break;
202
+ case lambda.Runtime.NODEJS_12_X.name:
203
+ case lambda.Runtime.NODEJS_14_X.name:
204
+ case lambda.Runtime.NODEJS_16_X.name:
205
+ case lambda.Runtime.NODEJS_18_X.name:
206
+ case lambda.Runtime.NODEJS_20_X.name:
207
+ case lambda.Runtime.NODEJS_22_X.name:
208
+ layer = layer || new lambda.LayerVersion(this, layerKey, {
209
+ compatibleRuntimes: [runtime],
210
+ compatibleArchitectures: [architecture],
211
+ code: lambda.Code.fromAsset(this.getExtensionAssetLocation())
212
+ });
213
+ break;
214
+ default:
215
+ console.log(`No extensions available for ${runtime.toString()}`);
216
+ return;
217
+ }
218
+ this.layerMap[layerKey] = layer;
219
+ this.createdResourcesBySSpy.push(layer);
220
+ return {
221
+ layer,
222
+ spyWrapperPath
223
+ };
224
+ }
225
+ internalSpySpySqsWithNoSubscription(queue) {
226
+ if (this.findElement((n) => n instanceof lambda.CfnEventSourceMapping && n.eventSourceArn === queue.queueArn)) return;
227
+ const queueName = this.getConstructName(queue);
228
+ const func = new NodejsFunction(this, `${queueName}SqsSubscriptionAndDropAllMessages`, {
229
+ memorySize: 512,
230
+ timeout: Duration.seconds(5),
231
+ runtime: lambda.Runtime.NODEJS_22_X,
232
+ handler: "handler",
233
+ entry: this.getAssetLocation("functions/sqsSubscriptionAndDropAllMessages.js"),
234
+ environment: this.getDefaultLambdaEnvironmentVariables()
235
+ });
236
+ func.addEventSource(new SqsEventSource(queue));
237
+ this.setupForIoT(func);
238
+ const { layer, spyWrapperPath } = this.getExtensionForRuntime(func.runtime, func.architecture);
239
+ func.addLayers(layer);
240
+ func.addEnvironment("AWS_LAMBDA_EXEC_WRAPPER", spyWrapperPath);
241
+ if (this.props?.debugMode) func.addEnvironment(envVariableNames.SSPY_DEBUG, "true");
242
+ this.createdResourcesBySSpy.push(func);
243
+ const serviceKey = `Sqs#${queueName}`;
244
+ this.addMappingToFunction(func, {
245
+ key: queue.queueArn,
246
+ value: serviceKey
247
+ });
248
+ this.serviceKeys.push(serviceKey);
249
+ func.addEnvironment(envVariableNames.SSPY_SUBSCRIBED_TO_SQS, "true");
250
+ }
251
+ internalSpySqs(node) {
252
+ const queue = this.findElement((n) => n instanceof sqs.Queue && n.queueArn === node.eventSourceArn);
253
+ const func = this.findElement((n) => n instanceof lambda.Function && n.functionName === node.functionName);
254
+ if (queue && func) {
255
+ const serviceKey = `Sqs#${this.getConstructName(queue)}`;
256
+ this.addMappingToFunction(func, {
257
+ key: queue.queueArn,
258
+ value: serviceKey
259
+ });
260
+ this.serviceKeys.push(serviceKey);
261
+ func.addEnvironment(envVariableNames.SSPY_SUBSCRIBED_TO_SQS, "true");
262
+ }
263
+ }
264
+ createFunctionForSubscription(index) {
265
+ const func = new lambdaNode.NodejsFunction(this, `Subscription${index}`, {
266
+ memorySize: 512,
267
+ timeout: Duration.seconds(5),
268
+ runtime: lambda.Runtime.NODEJS_22_X,
269
+ handler: "handler",
270
+ entry: this.getAssetLocation("functions/sendMessage.js"),
271
+ environment: { NODE_OPTIONS: "--enable-source-maps" }
272
+ });
273
+ this.setupForIoT(func);
274
+ return func;
275
+ }
276
+ internalSpyS3(s3Bucket) {
277
+ s3Bucket.addEventNotification(s3.EventType.OBJECT_CREATED_PUT, new s3notif.LambdaDestination(this.lambdaSubscriptionMain.function));
278
+ const serviceKey = `S3#${this.getConstructName(s3Bucket)}`;
279
+ this.lambdaSubscriptionMain.mapping[s3Bucket.bucketArn] = serviceKey;
280
+ this.serviceKeys.push(serviceKey);
281
+ }
282
+ internalSpyDynamodb(table) {
283
+ table.node.defaultChild.streamSpecification = { streamViewType: dynamoDb.StreamViewType.NEW_AND_OLD_IMAGES };
284
+ table.tableStreamArn = table.node.defaultChild.attrStreamArn;
285
+ this.lambdaSubscriptionMain.function.addEventSource(new dynamoDbStream.DynamoEventSource(table, {
286
+ startingPosition: lambda.StartingPosition.LATEST,
287
+ batchSize: 1,
288
+ retryAttempts: 0
289
+ }));
290
+ const serviceKey = `DynamoDB#${this.getConstructName(table)}`;
291
+ this.lambdaSubscriptionMain.mapping[table.tableArn] = serviceKey;
292
+ this.serviceKeys.push(serviceKey);
293
+ }
294
+ internalSpyEventBusRule(rule) {
295
+ const { eventBusName } = rule.node.defaultChild;
296
+ let bridgeName = "Default";
297
+ if (!!eventBusName) {
298
+ const eventBridge = this.getEventBridge(eventBusName);
299
+ if (!eventBridge) throw new Error(`Can not find EventBridge with name "${eventBusName}"`);
300
+ bridgeName = this.getConstructName(eventBridge);
301
+ }
302
+ const functionSubscription = this.provideFunctionForSubscription((s) => !s.usedForEventBridge);
303
+ functionSubscription.usedForEventBridge = true;
304
+ rule.addTarget(new targets.LambdaFunction(functionSubscription.function));
305
+ const ruleName = this.getConstructName(rule);
306
+ const serviceKey = `EventBridgeRule#${bridgeName}#${ruleName}`;
307
+ functionSubscription.mapping.eventBridge = serviceKey;
308
+ this.serviceKeys.push(serviceKey);
309
+ }
310
+ internalSpyEventBus(eventBus) {
311
+ const functionSubscription = this.provideFunctionForSubscription((s) => !s.usedForEventBridge);
312
+ functionSubscription.usedForEventBridge = true;
313
+ const bridgeName = this.getConstructName(eventBus);
314
+ const rule = new events.Rule(this, `RuleAll${bridgeName}`, {
315
+ eventBus,
316
+ eventPattern: { version: ["0"] },
317
+ targets: [new targets.LambdaFunction(functionSubscription.function)]
318
+ });
319
+ this.createdResourcesBySSpy.push(rule);
320
+ const serviceKey = `EventBridge#${bridgeName}`;
321
+ functionSubscription.mapping.eventBridge = serviceKey;
322
+ this.serviceKeys.push(serviceKey);
323
+ }
324
+ internalSpySnsTopic(topic) {
325
+ const functionSubscription = this.provideFunctionForSubscription((s) => !s.subsribedTopics.includes(topic));
326
+ const subscription = topic.addSubscription(new snsSubs.LambdaSubscription(functionSubscription.function));
327
+ this.createdResourcesBySSpy.push(subscription);
328
+ const serviceKey = `SnsTopic#${this.getConstructName(topic)}`;
329
+ functionSubscription.mapping[topic.topicArn] = serviceKey;
330
+ this.serviceKeys.push(serviceKey);
331
+ functionSubscription.subsribedTopics.push(topic);
332
+ }
333
+ internalSpySnsSubscription(subscription) {
334
+ if (!subscription.node.scope) return;
335
+ const topic = this.getTopic(subscription.node.defaultChild.topicArn);
336
+ if (!topic) throw new Error("Can not find Topic");
337
+ const functionSubscription = this.provideFunctionForSubscription((s) => !s.subsribedTopics.includes(topic));
338
+ const { filterPolicy } = subscription.node.defaultChild;
339
+ const subscriptionClone = topic.addSubscription(new snsSubs.LambdaSubscription(functionSubscription.function));
340
+ subscriptionClone.node.defaultChild.filterPolicy = filterPolicy;
341
+ this.createdResourcesBySSpy.push(subscriptionClone);
342
+ const topicName = this.getConstructName(topic);
343
+ const targetName = this.getConstructName(subscription.node.scope);
344
+ functionSubscription.subsribedTopics.push(topic);
345
+ const serviceKey = `SnsSubscription#${topicName}#${targetName}`;
346
+ functionSubscription.mapping[topic.topicArn] = serviceKey;
347
+ this.serviceKeys.push(serviceKey);
348
+ }
349
+ provideFunctionForSubscription(filterFunction) {
350
+ let functionSubscription;
351
+ if (filterFunction) functionSubscription = this.lambdaSubscriptionPool.find(filterFunction);
352
+ else if (this.lambdaSubscriptionPool.length > 0) functionSubscription = this.lambdaSubscriptionPool[0];
353
+ if (!functionSubscription) {
354
+ functionSubscription = {
355
+ subsribedTopics: [],
356
+ usedForEventBridge: false,
357
+ mapping: {},
358
+ function: this.createFunctionForSubscription(this.lambdaSubscriptionPool.length)
359
+ };
360
+ this.lambdaSubscriptionPool.push(functionSubscription);
361
+ }
362
+ return functionSubscription;
363
+ }
364
+ setupForIoT(func) {
365
+ func.addEnvironment(envVariableNames.SSPY_ROOT_STACK, this.cleanName(this.findRootStack(Stack.of(this)).node.id));
366
+ func.addEnvironment(envVariableNames.SSPY_IOT_ENDPOINT, this.iotEndpoint);
367
+ func.addToRolePolicy(new aws_iam.PolicyStatement({
368
+ actions: ["iot:*"],
369
+ effect: Effect.ALLOW,
370
+ resources: ["*"]
371
+ }));
372
+ }
373
+ internalSpyLambda(func) {
374
+ const { layer, spyWrapperPath } = this.getExtensionForRuntime(func.runtime, func.architecture || Architecture.X86_64);
375
+ if (!layer) return;
376
+ func.addLayers(layer);
377
+ const functionName = this.getConstructName(func);
378
+ func.addEnvironment(envVariableNames.SSPY_FUNCTION_NAME, functionName);
379
+ func.addEnvironment("AWS_LAMBDA_EXEC_WRAPPER", spyWrapperPath);
380
+ if (this.props?.debugMode) func.addEnvironment(envVariableNames.SSPY_DEBUG, "true");
381
+ this.setupForIoT(func);
382
+ this.serviceKeys.push(`Function#${functionName}#Request`);
383
+ this.serviceKeys.push(`Function#${functionName}#Error`);
384
+ this.serviceKeys.push(`Function#${functionName}#Console`);
385
+ this.serviceKeys.push(`Function#${functionName}#Response`);
386
+ this.addMappingToFunction(func);
387
+ }
388
+ getConstructName(construct) {
389
+ let constructName = construct.node.path;
390
+ const { node } = Stack.of(this);
391
+ if (constructName.startsWith(node.id)) constructName = constructName.substring(node.id.length + 1);
392
+ return this.cleanName(constructName);
393
+ }
394
+ cleanName(name) {
395
+ return name.replace(/[-_]+/g, " ").replace(/[^\w\s]/g, "").replace(/\s(.)/g, ($1) => $1.toUpperCase()).replace(/\s/g, "").replace(/^(.)/, ($1) => $1.toUpperCase());
396
+ }
397
+ getTopic(topicArn) {
398
+ return this.findElement((node) => node instanceof sns.Topic && node.topicArn === topicArn);
399
+ }
400
+ getEventBridge(eventBusName) {
401
+ return this.findElement((node) => (node instanceof events.EventBus || node.constructor.name === "ImportedEventBus") && node.eventBusName === eventBusName);
402
+ }
403
+ findRootStack(stack) {
404
+ if (stack.nested) {
405
+ const parentStack = stack.nestedStackParent;
406
+ if (parentStack) return this.findRootStack(parentStack);
407
+ return stack;
408
+ } else return stack;
409
+ }
410
+ findElement(filterFunc, parent) {
411
+ if (!parent) parent = this.findRootStack(Stack.of(this));
412
+ for (const node of parent.node.children) {
413
+ if (filterFunc(node)) return node;
414
+ const elementFoundInChild = this.findElement(filterFunc, node);
415
+ if (elementFoundInChild) return elementFoundInChild;
416
+ }
417
+ }
418
+ addMappingToFunction(func, keyValue) {
419
+ for (const fs$2 of this.lambdasSpied) if (fs$2.function === func) {
420
+ if (keyValue) fs$2.mapping[keyValue.key] = keyValue.value;
421
+ return;
422
+ }
423
+ const fs$1 = {
424
+ function: func,
425
+ mapping: {}
426
+ };
427
+ if (keyValue) fs$1.mapping[keyValue.key] = keyValue.value;
428
+ this.lambdasSpied.push(fs$1);
429
+ }
430
+ getAssetLocation(location) {
431
+ const loc = path.join(__dirname, "../lib/" + location);
432
+ if (fs.existsSync(loc)) return loc;
433
+ const loc2 = path.join(__dirname, "../../lib/" + location);
434
+ if (fs.existsSync(loc2)) return loc2;
435
+ throw new Error(`Location ${loc} and ${loc2} does not exists.`);
436
+ }
437
+ };
438
+
439
+ //#endregion
440
+ export { ServerlessSpy };
441
+ //# sourceMappingURL=ServerlessSpy.mjs.map