cdk-local-lambda 0.0.2

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 (53) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +94 -0
  3. package/lib/aspect/docker-function-hook.d.ts +18 -0
  4. package/lib/aspect/docker-function-hook.js +31 -0
  5. package/lib/aspect/live-lambda-aspect.d.ts +85 -0
  6. package/lib/aspect/live-lambda-aspect.js +277 -0
  7. package/lib/aspect/live-lambda-bootstrap.d.ts +17 -0
  8. package/lib/aspect/live-lambda-bootstrap.js +260 -0
  9. package/lib/aspect/nodejs-function-hook.d.ts +20 -0
  10. package/lib/aspect/nodejs-function-hook.js +27 -0
  11. package/lib/bootstrap-stack/bootstrap-stack.d.ts +60 -0
  12. package/lib/bootstrap-stack/bootstrap-stack.js +338 -0
  13. package/lib/cli/appsync/client.d.ts +30 -0
  14. package/lib/cli/appsync/client.js +227 -0
  15. package/lib/cli/cdk-app.d.ts +7 -0
  16. package/lib/cli/cdk-app.js +25 -0
  17. package/lib/cli/commands/bootstrap.d.ts +9 -0
  18. package/lib/cli/commands/bootstrap.js +50 -0
  19. package/lib/cli/commands/local.d.ts +40 -0
  20. package/lib/cli/commands/local.js +1172 -0
  21. package/lib/cli/daemon.d.ts +22 -0
  22. package/lib/cli/daemon.js +18 -0
  23. package/lib/cli/docker/container.d.ts +116 -0
  24. package/lib/cli/docker/container.js +414 -0
  25. package/lib/cli/docker/types.d.ts +71 -0
  26. package/lib/cli/docker/types.js +5 -0
  27. package/lib/cli/docker/watcher.d.ts +44 -0
  28. package/lib/cli/docker/watcher.js +115 -0
  29. package/lib/cli/index.d.ts +9 -0
  30. package/lib/cli/index.js +26 -0
  31. package/lib/cli/runtime-api/server.d.ts +102 -0
  32. package/lib/cli/runtime-api/server.js +396 -0
  33. package/lib/cli/runtime-api/types.d.ts +149 -0
  34. package/lib/cli/runtime-api/types.js +10 -0
  35. package/lib/cli/runtime-wrapper/nodejs-runtime.d.ts +16 -0
  36. package/lib/cli/runtime-wrapper/nodejs-runtime.js +248 -0
  37. package/lib/cli/watcher/file-watcher.d.ts +32 -0
  38. package/lib/cli/watcher/file-watcher.js +57 -0
  39. package/lib/functions/bridge/appsync-client.d.ts +73 -0
  40. package/lib/functions/bridge/appsync-client.js +345 -0
  41. package/lib/functions/bridge/handler.d.ts +17 -0
  42. package/lib/functions/bridge/handler.js +79 -0
  43. package/lib/functions/bridge/ssm-config.d.ts +19 -0
  44. package/lib/functions/bridge/ssm-config.js +45 -0
  45. package/lib/functions/bridge-builder/handler.d.ts +12 -0
  46. package/lib/functions/bridge-builder/handler.js +181 -0
  47. package/lib/functions/bridge-docker/runtime.d.ts +9 -0
  48. package/lib/functions/bridge-docker/runtime.js +127 -0
  49. package/lib/index.d.ts +24 -0
  50. package/lib/index.js +28 -0
  51. package/lib/shared/types.d.ts +102 -0
  52. package/lib/shared/types.js +125 -0
  53. package/package.json +111 -0
@@ -0,0 +1,277 @@
1
+ /**
2
+ * CDK Aspect to transform Lambda functions for live debugging
3
+ *
4
+ * When applied to a CDK app/stack, this aspect:
5
+ * 1. Replaces Lambda code with the bridge handler from the bootstrap stack's S3 bucket
6
+ * 2. Grants IAM permissions for AppSync Events
7
+ * 3. Adds a tag with the local handler path for the daemon to discover
8
+ *
9
+ * The bridge uses AWS_LAMBDA_FUNCTION_NAME (auto-injected by Lambda) for channel routing.
10
+ * The daemon discovers functions by querying Lambda API for functions with the live-lambda tag.
11
+ */
12
+ import * as cdk from "aws-cdk-lib";
13
+ import * as iam from "aws-cdk-lib/aws-iam";
14
+ import * as ssm from "aws-cdk-lib/aws-ssm";
15
+ import { LIVE_LAMBDA_DOCKER_TAG, LIVE_LAMBDA_TAG, SSM_BASE_PATH, } from "../shared/types.js";
16
+ import { getDockerContextPath, isDockerImageFunction, } from "./docker-function-hook.js";
17
+ import { getEntryPath, getHandlerName } from "./nodejs-function-hook.js";
18
+ // Regex to strip file extension from entry path
19
+ const EXTENSION_REGEX = /\.(ts|js|mjs|cjs|mts|cts)$/;
20
+ /**
21
+ * CDK Aspect that transforms Lambda functions for live debugging.
22
+ *
23
+ * Usage in bin/app.ts:
24
+ * ```typescript
25
+ * const app = new cdk.App();
26
+ * const stack = new MyStack(app, 'MyStack');
27
+ *
28
+ * if (process.env.CDK_LIVE === 'true') {
29
+ * cdk.Aspects.of(app).add(new LiveLambdaAspect());
30
+ * }
31
+ * ```
32
+ */
33
+ export class LiveLambdaAspect {
34
+ props;
35
+ processedFunctions = new Set();
36
+ constructor(props = {}) {
37
+ this.props = props;
38
+ }
39
+ visit(node) {
40
+ // Check if this is a Lambda Function using duck-typing instead of instanceof
41
+ // This avoids issues with multiple copies of aws-cdk-lib being loaded
42
+ if (!this.isLambdaFunction(node)) {
43
+ return;
44
+ }
45
+ // Cast to lambda.Function for type checking (we've verified it's a Lambda)
46
+ const fn = node;
47
+ // Skip if already processed (aspects can visit multiple times)
48
+ const nodeId = node.node.addr;
49
+ if (this.processedFunctions.has(nodeId)) {
50
+ return;
51
+ }
52
+ // Generate a unique function ID from the construct path
53
+ const functionId = this.generateFunctionId(fn);
54
+ // Check exclusion list
55
+ if (this.props.excludeFunctions?.includes(functionId)) {
56
+ console.log(`[LiveLambda] Skipping excluded function: ${functionId}`);
57
+ return;
58
+ }
59
+ // Check pattern match
60
+ if (this.props.functionPattern &&
61
+ !this.props.functionPattern.test(functionId)) {
62
+ console.log(`[LiveLambda] Skipping non-matching function: ${functionId}`);
63
+ return;
64
+ }
65
+ console.log(`[LiveLambda] Transforming function: ${functionId}`);
66
+ const stackName = this.props.stackName || cdk.Stack.of(fn).stackName;
67
+ // Check if this is a DockerImageFunction
68
+ const isDockerFunction = isDockerImageFunction(fn);
69
+ if (isDockerFunction) {
70
+ console.log(`[LiveLambda] Detected DockerImageFunction: ${functionId}`);
71
+ this.transformDockerFunction(fn, stackName, functionId);
72
+ }
73
+ else {
74
+ // Get handler paths before we modify anything
75
+ const handlerPaths = this.getHandlerPaths(fn);
76
+ // Skip unsupported functions (not NodejsFunction or DockerImageFunction)
77
+ if (!handlerPaths) {
78
+ return;
79
+ }
80
+ const { originalHandler, localHandler } = handlerPaths;
81
+ // Transform the function
82
+ this.transformFunction(fn, stackName, functionId, originalHandler, localHandler);
83
+ }
84
+ this.processedFunctions.add(nodeId);
85
+ }
86
+ /**
87
+ * Check if a construct is a Lambda Function using duck-typing.
88
+ * This avoids instanceof issues when multiple copies of aws-cdk-lib are loaded.
89
+ */
90
+ isLambdaFunction(node) {
91
+ // Check by constructor name - handles Function, DockerImageFunction, NodejsFunction, etc.
92
+ // Also handles our patched versions like DockerImageFunctionWithCapture
93
+ const constructorName = node.constructor.name;
94
+ // CDK appends "2" to class names in some versions
95
+ const isFunction = constructorName === "Function" ||
96
+ constructorName === "Function2" ||
97
+ constructorName.endsWith("Function") ||
98
+ constructorName.endsWith("Function2") ||
99
+ constructorName.includes("Function"); // Catch patched versions like DockerImageFunctionWithCapture
100
+ if (!isFunction) {
101
+ return false;
102
+ }
103
+ // Exclude CfnFunction (the L1 construct)
104
+ if (constructorName === "CfnFunction") {
105
+ return false;
106
+ }
107
+ // Verify it has expected Lambda Function properties
108
+ const maybeFunction = node;
109
+ // Must have functionName and functionArn (IFunction interface)
110
+ if (!maybeFunction.functionName || !maybeFunction.functionArn) {
111
+ return false;
112
+ }
113
+ // Must have a defaultChild (the CfnFunction)
114
+ if (!maybeFunction.node?.defaultChild) {
115
+ return false;
116
+ }
117
+ return true;
118
+ }
119
+ generateFunctionId(fn) {
120
+ // Use the construct ID as the function ID
121
+ // For nested constructs, join with dashes
122
+ const parts = fn.node.path.split("/");
123
+ // Skip first part (App) and take the rest
124
+ const relevantParts = parts.slice(1);
125
+ return relevantParts.join("-").replace(/[^a-zA-Z0-9-]/g, "-");
126
+ }
127
+ /**
128
+ * Get handler paths for a function.
129
+ * Returns both the original handler (as set in CfnFunction) and the local handler path.
130
+ * Returns null if the function is not supported (e.g., not a NodejsFunction).
131
+ */
132
+ getHandlerPaths(fn) {
133
+ const cfnFunction = fn.node.defaultChild;
134
+ const originalHandler = cfnFunction.handler || "index.handler";
135
+ const constructId = fn.node.id;
136
+ // Check if captured by the NodejsFunction hook
137
+ const entryPath = getEntryPath(fn);
138
+ const handlerName = getHandlerName(fn) || "handler";
139
+ if (entryPath) {
140
+ // Convert entry path to local handler path
141
+ // e.g., "functions/s3-writer/handler.ts" + "handler" -> "functions/s3-writer/handler.handler"
142
+ const localHandler = `${entryPath.replace(EXTENSION_REGEX, "")}.${handlerName}`;
143
+ console.log(`[LiveLambda] Using captured entry for ${constructId}: ${localHandler}`);
144
+ return { originalHandler, localHandler };
145
+ }
146
+ // No handler path found - this function is not supported (not a NodejsFunction or DockerImageFunction)
147
+ console.log(`[LiveLambda] Skipping unsupported function "${constructId}": ` +
148
+ `not a NodejsFunction or DockerImageFunction (or bootstrap hook was not installed early enough)`);
149
+ return null;
150
+ }
151
+ /**
152
+ * Transform a DockerImageFunction to use the bridge Docker image.
153
+ * Stores the local Docker context path in a tag for the daemon to build/run locally.
154
+ */
155
+ transformDockerFunction(fn, _stackName, functionId) {
156
+ const cfnFunction = fn.node.defaultChild;
157
+ const stack = cdk.Stack.of(fn);
158
+ // Get the docker context path from the hook
159
+ const dockerContextPath = getDockerContextPath(fn);
160
+ if (!dockerContextPath) {
161
+ throw new Error(`[LiveLambda] No docker context path for "${functionId}". ` +
162
+ `The bootstrap hook was not installed early enough. ` +
163
+ `Fix: import "cdk-local-lambda/bootstrap" before any CDK imports (Node.js), ` +
164
+ `or run Bun with "bun --preload cdk-local-lambda/bootstrap".`);
165
+ }
166
+ // Get SSM parameters
167
+ const bootstrapQualifier = stack.node.tryGetContext("@aws-cdk/core:bootstrapQualifier") ||
168
+ "hnb659fds";
169
+ const ssmBasePath = `${SSM_BASE_PATH}/${bootstrapQualifier}`;
170
+ const apiArn = ssm.StringParameter.valueForStringParameter(stack, `${ssmBasePath}/api-arn`);
171
+ // Determine architecture and get appropriate bridge image
172
+ const architecture = this.getArchitecture(cfnFunction);
173
+ const bridgeImageParam = architecture === "arm64" ? "bridge-image-arm64" : "bridge-image-x86_64";
174
+ const bridgeImageUri = ssm.StringParameter.valueForStringParameter(stack, `${ssmBasePath}/${bridgeImageParam}`);
175
+ // Add tag with docker context path for daemon discovery
176
+ // The daemon uses this tag to build and run the container locally
177
+ cfnFunction.tags.setTag(LIVE_LAMBDA_DOCKER_TAG, dockerContextPath);
178
+ // Grant permissions to publish/subscribe to AppSync Events
179
+ fn.addToRolePolicy(new iam.PolicyStatement({
180
+ effect: iam.Effect.ALLOW,
181
+ actions: [
182
+ "appsync:EventConnect",
183
+ "appsync:EventPublish",
184
+ "appsync:EventSubscribe",
185
+ ],
186
+ resources: [apiArn, `${apiArn}/*`],
187
+ }));
188
+ // Grant permissions to read SSM parameters (bridge needs AppSync endpoints)
189
+ fn.addToRolePolicy(new iam.PolicyStatement({
190
+ effect: iam.Effect.ALLOW,
191
+ actions: ["ssm:GetParameter", "ssm:GetParameters"],
192
+ resources: [
193
+ `arn:aws:ssm:${stack.region}:${stack.account}:parameter${ssmBasePath}/*`,
194
+ ],
195
+ }));
196
+ // Increase timeout to allow for local debugging
197
+ cfnFunction.timeout = 300; // 5 minutes
198
+ // Replace the Docker image with the bridge image
199
+ cfnFunction.code = {
200
+ imageUri: bridgeImageUri,
201
+ };
202
+ console.log(`[LiveLambda] Replaced Docker image with bridge (${architecture})`);
203
+ }
204
+ /**
205
+ * Determine the architecture of a Lambda function.
206
+ * Defaults to x86_64 if not explicitly set.
207
+ */
208
+ getArchitecture(cfnFunction) {
209
+ const architectures = cfnFunction.architectures;
210
+ if (architectures?.includes("arm64")) {
211
+ return "arm64";
212
+ }
213
+ return "x86_64";
214
+ }
215
+ transformFunction(fn, _stackName, _functionId, _originalHandler, localHandler) {
216
+ const cfnFunction = fn.node.defaultChild;
217
+ const stack = cdk.Stack.of(fn);
218
+ // Read values from SSM parameters (created by bootstrap stack)
219
+ // Use the CDK bootstrap qualifier for proper scoping
220
+ const bootstrapQualifier = stack.node.tryGetContext("@aws-cdk/core:bootstrapQualifier") ||
221
+ "hnb659fds";
222
+ const ssmBasePath = `${SSM_BASE_PATH}/${bootstrapQualifier}`;
223
+ const apiArn = ssm.StringParameter.valueForStringParameter(stack, `${ssmBasePath}/api-arn`);
224
+ const bridgeBucket = ssm.StringParameter.valueForStringParameter(stack, `${ssmBasePath}/bridge-bucket`);
225
+ const bridgeKey = ssm.StringParameter.valueForStringParameter(stack, `${ssmBasePath}/bridge-key`);
226
+ // Add tag with local handler path for daemon discovery
227
+ // The daemon queries Lambda API for functions with this tag
228
+ cfnFunction.tags.setTag(LIVE_LAMBDA_TAG, localHandler);
229
+ // Grant permissions to publish/subscribe to AppSync Events
230
+ fn.addToRolePolicy(new iam.PolicyStatement({
231
+ effect: iam.Effect.ALLOW,
232
+ actions: [
233
+ "appsync:EventConnect",
234
+ "appsync:EventPublish",
235
+ "appsync:EventSubscribe",
236
+ ],
237
+ resources: [apiArn, `${apiArn}/*`],
238
+ }));
239
+ // Grant permissions to read SSM parameters (bridge needs AppSync endpoints)
240
+ fn.addToRolePolicy(new iam.PolicyStatement({
241
+ effect: iam.Effect.ALLOW,
242
+ actions: ["ssm:GetParameter", "ssm:GetParameters"],
243
+ resources: [
244
+ `arn:aws:ssm:${stack.region}:${stack.account}:parameter${ssmBasePath}/*`,
245
+ ],
246
+ }));
247
+ // Increase timeout to allow for local debugging
248
+ cfnFunction.timeout = 300; // 5 minutes
249
+ // Replace the code with bridge handler from bootstrap stack's S3 bucket
250
+ cfnFunction.code = {
251
+ s3Bucket: bridgeBucket,
252
+ s3Key: bridgeKey,
253
+ };
254
+ cfnFunction.handler = "index.handler";
255
+ }
256
+ }
257
+ /**
258
+ * Helper function to check if live mode is enabled
259
+ */
260
+ export function isLiveModeEnabled() {
261
+ return process.env.CDK_LIVE === "true";
262
+ }
263
+ /**
264
+ * Apply live lambda aspect to a CDK app or stack if live mode is enabled.
265
+ *
266
+ * @param scope The CDK app or stack to apply the aspect to
267
+ * @param props Optional configuration for the live lambda aspect
268
+ */
269
+ export function applyLiveLambdaAspect(scope, props = {}) {
270
+ if (!isLiveModeEnabled()) {
271
+ console.log("[LiveLambda] Live mode not enabled (set CDK_LIVE=true to enable)");
272
+ return;
273
+ }
274
+ console.log("[LiveLambda] Live mode enabled - transforming Lambda functions");
275
+ cdk.Aspects.of(scope).add(new LiveLambdaAspect(props));
276
+ }
277
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGl2ZS1sYW1iZGEtYXNwZWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FzcGVjdC9saXZlLWxhbWJkYS1hc3BlY3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7R0FVRztBQUVILE9BQU8sS0FBSyxHQUFHLE1BQU0sYUFBYSxDQUFBO0FBQ2xDLE9BQU8sS0FBSyxHQUFHLE1BQU0scUJBQXFCLENBQUE7QUFFMUMsT0FBTyxLQUFLLEdBQUcsTUFBTSxxQkFBcUIsQ0FBQTtBQUUxQyxPQUFPLEVBQ0wsc0JBQXNCLEVBQ3RCLGVBQWUsRUFDZixhQUFhLEdBQ2QsTUFBTSxvQkFBb0IsQ0FBQTtBQUMzQixPQUFPLEVBQ0wsb0JBQW9CLEVBQ3BCLHFCQUFxQixHQUN0QixNQUFNLDJCQUEyQixDQUFBO0FBQ2xDLE9BQU8sRUFBRSxZQUFZLEVBQUUsY0FBYyxFQUFFLE1BQU0sMkJBQTJCLENBQUE7QUFFeEUsZ0RBQWdEO0FBQ2hELE1BQU0sZUFBZSxHQUFHLDRCQUE0QixDQUFBO0FBd0JwRDs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxNQUFNLE9BQU8sZ0JBQWdCO0lBQ1YsS0FBSyxDQUF1QjtJQUM1QixrQkFBa0IsR0FBZ0IsSUFBSSxHQUFHLEVBQUUsQ0FBQTtJQUU1RCxZQUFZLFFBQStCLEVBQUU7UUFDM0MsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUE7SUFDcEIsQ0FBQztJQUVELEtBQUssQ0FBQyxJQUFnQjtRQUNwQiw2RUFBNkU7UUFDN0Usc0VBQXNFO1FBQ3RFLElBQUksQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUNqQyxPQUFNO1FBQ1IsQ0FBQztRQUVELDJFQUEyRTtRQUMzRSxNQUFNLEVBQUUsR0FBRyxJQUFrQyxDQUFBO1FBRTdDLCtEQUErRDtRQUMvRCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQTtRQUM3QixJ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QUNqQixRQUErQixFQUFFO0lBRWpDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxFQUFFLENBQUM7UUFDekIsT0FBTyxDQUFDLEdBQUcsQ0FDVCxrRUFBa0UsQ0FDbkUsQ0FBQTtRQUNELE9BQU07SUFDUixDQUFDO0lBRUQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnRUFBZ0UsQ0FBQyxDQUFBO0lBQzdFLEdBQUcsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUE7QUFDeEQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ0RLIEFzcGVjdCB0byB0cmFuc2Zvcm0gTGFtYmRhIGZ1bmN0aW9ucyBmb3IgbGl2ZSBkZWJ1Z2dpbmdcbiAqXG4gKiBXaGVuIGFwcGxpZWQgdG8gYSBDREsgYXBwL3N0YWNrLCB0aGlzIGFzcGVjdDpcbiAqIDEuIFJlcGxhY2VzIExhbWJkYSBjb2RlIHdpdGggdGhlIGJyaWRnZSBoYW5kbGVyIGZyb20gdGhlIGJvb3RzdHJhcCBzdGFjaydzIFMzIGJ1Y2tldFxuICogMi4gR3JhbnRzIElBTSBwZXJtaXNzaW9ucyBmb3IgQXBwU3luYyBFdmVudHNcbiAqIDMuIEFkZHMgYSB0YWcgd2l0aCB0aGUgbG9jYWwgaGFuZGxlciBwYXRoIGZvciB0aGUgZGFlbW9uIHRvIGRpc2NvdmVyXG4gKlxuICogVGhlIGJyaWRnZSB1c2VzIEFXU19MQU1CREFfRlVOQ1RJT05fTkFNRSAoYXV0by1pbmplY3RlZCBieSBMYW1iZGEpIGZvciBjaGFubmVsIHJvdXRpbmcuXG4gKiBUaGUgZGFlbW9uIGRpc2NvdmVycyBmdW5jdGlvbnMgYnkgcXVlcnlpbmcgTGFtYmRhIEFQSSBmb3IgZnVuY3Rpb25zIHdpdGggdGhlIGxpdmUtbGFtYmRhIHRhZy5cbiAqL1xuXG5pbXBvcnQgKiBhcyBjZGsgZnJvbSBcImF3cy1jZGstbGliXCJcbmltcG9ydCAqIGFzIGlhbSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWlhbVwiXG5pbXBvcnQgdHlwZSAqIGFzIGxhbWJkYSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWxhbWJkYVwiXG5pbXBvcnQgKiBhcyBzc20gZnJvbSBcImF3cy1jZGstbGliL2F3cy1zc21cIlxuaW1wb3J0IHR5cGUgeyBJQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIlxuaW1wb3J0IHtcbiAgTElWRV9MQU1CREFfRE9DS0VSX1RBRyxcbiAgTElWRV9MQU1CREFfVEFHLFxuICBTU01fQkFTRV9QQVRILFxufSBmcm9tIFwiLi4vc2hhcmVkL3R5cGVzLmpzXCJcbmltcG9ydCB7XG4gIGdldERvY2tlckNvbnRleHRQYXRoLFxuICBpc0RvY2tlckltYWdlRnVuY3Rpb24sXG59IGZyb20gXCIuL2RvY2tlci1mdW5jdGlvbi1ob29rLmpzXCJcbmltcG9ydCB7IGdldEVudHJ5UGF0aCwgZ2V0SGFuZGxlck5hbWUgfSBmcm9tIFwiLi9ub2RlanMtZnVuY3Rpb24taG9vay5qc1wiXG5cbi8vIFJlZ2V4IHRvIHN0cmlwIGZpbGUgZXh0ZW5zaW9uIGZyb20gZW50cnkgcGF0aFxuY29uc3QgRVhURU5TSU9OX1JFR0VYID0gL1xcLih0c3xqc3xtanN8Y2pzfG10c3xjdHMpJC9cblxuLyoqXG4gKiBQcm9wZXJ0aWVzIGZvciBMaXZlTGFtYmRhQXNwZWN0XG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTGl2ZUxhbWJkYUFzcGVjdFByb3BzIHtcbiAgLyoqXG4gICAqIFRoZSBzdGFjayBuYW1lIHRvIHVzZSBmb3IgY2hhbm5lbCByb3V0aW5nLlxuICAgKiBJZiBub3QgcHJvdmlkZWQsIHVzZXMgdGhlIHN0YWNrIG5hbWUgZnJvbSB0aGUgZnVuY3Rpb24ncyBzdGFjay5cbiAgICovXG4gIHN0YWNrTmFtZT86IHN0cmluZ1xuXG4gIC8qKlxuICAgKiBPcHRpb25hbDogUGF0dGVybiB0byBtYXRjaCBmdW5jdGlvbiBjb25zdHJ1Y3QgSURzIHRvIHRyYW5zZm9ybS5cbiAgICogSWYgbm90IHByb3ZpZGVkLCBhbGwgTGFtYmRhIGZ1bmN0aW9ucyBhcmUgdHJhbnNmb3JtZWQuXG4gICAqL1xuICBmdW5jdGlvblBhdHRlcm4/OiBSZWdFeHBcblxuICAvKipcbiAgICogT3B0aW9uYWw6IEZ1bmN0aW9uIGNvbnN0cnVjdCBJRHMgdG8gZXhjbHVkZSBmcm9tIHRyYW5zZm9ybWF0aW9uLlxuICAgKi9cbiAgZXhjbHVkZUZ1bmN0aW9ucz86IHN0cmluZ1tdXG59XG5cbi8qKlxuICogQ0RLIEFzcGVjdCB0aGF0IHRyYW5zZm9ybXMgTGFtYmRhIGZ1bmN0aW9ucyBmb3IgbGl2ZSBkZWJ1Z2dpbmcuXG4gKlxuICogVXNhZ2UgaW4gYmluL2FwcC50czpcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGFwcCA9IG5ldyBjZGsuQXBwKCk7XG4gKiBjb25zdCBzdGFjayA9IG5ldyBNeVN0YWNrKGFwcCwgJ015U3RhY2snKTtcbiAqXG4gKiBpZiAocHJvY2Vzcy5lbnYuQ0RLX0xJVkUgPT09ICd0cnVlJykge1xuICogICBjZGsuQXNwZWN0cy5vZihhcHApLmFkZChuZXcgTGl2ZUxhbWJkYUFzcGVjdCgpKTtcbiAqIH1cbiAqIGBgYFxuICovXG5leHBvcnQgY2xhc3MgTGl2ZUxhbWJkYUFzcGVjdCBpbXBsZW1lbnRzIGNkay5JQXNwZWN0IHtcbiAgcHJpdmF0ZSByZWFkb25seSBwcm9wczogTGl2ZUxhbWJkYUFzcGVjdFByb3BzXG4gIHByaXZhdGUgcmVhZG9ubHkgcHJvY2Vzc2VkRnVuY3Rpb25zOiBTZXQ8c3RyaW5nPiA9IG5ldyBTZXQoKVxuXG4gIGNvbnN0cnVjdG9yKHByb3BzOiBMaXZlTGFtYmRhQXNwZWN0UHJvcHMgPSB7fSkge1xuICAgIHRoaXMucHJvcHMgPSBwcm9wc1xuICB9XG5cbiAgdmlzaXQobm9kZTogSUNvbnN0cnVjdCk6IHZvaWQge1xuICAgIC8vIENoZWNrIGlmIHRoaXMgaXMgYSBMYW1iZGEgRnVuY3Rpb24gdXNpbmcgZHVjay10eXBpbmcgaW5zdGVhZCBvZiBpbnN0YW5jZW9mXG4gICAgLy8gVGhpcyBhdm9pZHMgaXNzdWVzIHdpdGggbXVsdGlwbGUgY29waWVzIG9mIGF3cy1jZGstbGliIGJlaW5nIGxvYWRlZFxuICAgIGlmICghdGhpcy5pc0xhbWJkYUZ1bmN0aW9uKG5vZGUpKSB7XG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICAvLyBDYXN0IHRvIGxhbWJkYS5GdW5jdGlvbiBmb3IgdHlwZSBjaGVja2luZyAod2UndmUgdmVyaWZpZWQgaXQncyBhIExhbWJkYSlcbiAgICBjb25zdCBmbiA9IG5vZGUgYXMgdW5rbm93biBhcyBsYW1iZGEuRnVuY3Rpb25cblxuICAgIC8vIFNraXAgaWYgYWxyZWFkeSBwcm9jZXNzZWQgKGFzcGVjdHMgY2FuIHZpc2l0IG11bHRpcGxlIHRpbWVzKVxuICAgIGNvbnN0IG5vZGVJZCA9IG5vZGUubm9kZS5hZGRyXG4gICAgaWYgKHRoaXMucHJvY2Vzc2VkRnVuY3Rpb25zLmhhcyhub2RlSWQpKSB7XG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICAvLyBHZW5lcmF0ZSBhIHVuaXF1ZSBmdW5jdGlvbiBJRCBmcm9tIHRoZSBjb25zdHJ1Y3QgcGF0aFxuICAgIGNvbnN0IGZ1bmN0aW9uSWQgPSB0aGlzLmdlbmVyYXRlRnVuY3Rpb25JZChmbilcblxuICAgIC8vIENoZWNrIGV4Y2x1c2lvbiBsaXN0XG4gICAgaWYgKHRoaXMucHJvcHMuZXhjbHVkZUZ1bmN0aW9ucz8uaW5jbHVkZXMoZnVuY3Rpb25JZCkpIHtcbiAgICAgIGNvbnNvbGUubG9nKGBbTGl2ZUxhbWJkYV0gU2tpcHBpbmcgZXhjbHVkZWQgZnVuY3Rpb246ICR7ZnVuY3Rpb25JZH1gKVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgcGF0dGVybiBtYXRjaFxuICAgIGlmIChcbiAgICAgIHRoaXMucHJvcHMuZnVuY3Rpb25QYXR0ZXJuICYmXG4gICAgICAhdGhpcy5wcm9wcy5mdW5jdGlvblBhdHRlcm4udGVzdChmdW5jdGlvbklkKVxuICAgICkge1xuICAgICAgY29uc29sZS5sb2coYFtMaXZlTGFtYmRhXSBTa2lwcGluZyBub24tbWF0Y2hpbmcgZnVuY3Rpb246ICR7ZnVuY3Rpb25JZH1gKVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgY29uc29sZS5sb2coYFtMaXZlTGFtYmRhXSBUcmFuc2Zvcm1pbmcgZnVuY3Rpb246ICR7ZnVuY3Rpb25JZH1gKVxuXG4gICAgY29uc3Qgc3RhY2tOYW1lID0gdGhpcy5wcm9wcy5zdGFja05hbWUgfHwgY2RrLlN0YWNrLm9mKGZuKS5zdGFja05hbWVcblxuICAgIC8vIENoZWNrIGlmIHRoaXMgaXMgYSBEb2NrZXJJbWFnZUZ1bmN0aW9uXG4gICAgY29uc3QgaXNEb2NrZXJGdW5jdGlvbiA9IGlzRG9ja2VySW1hZ2VGdW5jdGlvbihmbilcblxuICAgIGlmIChpc0RvY2tlckZ1bmN0aW9uKSB7XG4gICAgICBjb25zb2xlLmxvZyhgW0xpdmVMYW1iZGFdIERldGVjdGVkIERvY2tlckltYWdlRnVuY3Rpb246ICR7ZnVuY3Rpb25JZH1gKVxuICAgICAgdGhpcy50cmFuc2Zvcm1Eb2NrZXJGdW5jdGlvbihmbiwgc3RhY2tOYW1lLCBmdW5jdGlvbklkKVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBHZXQgaGFuZGxlciBwYXRocyBiZWZvcmUgd2UgbW9kaWZ5IGFueXRoaW5nXG4gICAgICBjb25zdCBoYW5kbGVyUGF0aHMgPSB0aGlzLmdldEhhbmRsZXJQYXRocyhmbilcblxuICAgICAgLy8gU2tpcCB1bnN1cHBvcnRlZCBmdW5jdGlvbnMgKG5vdCBOb2RlanNGdW5jdGlvbiBvciBEb2NrZXJJbWFnZUZ1bmN0aW9uKVxuICAgICAgaWYgKCFoYW5kbGVyUGF0aHMpIHtcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHsgb3JpZ2luYWxIYW5kbGVyLCBsb2NhbEhhbmRsZXIgfSA9IGhhbmRsZXJQYXRoc1xuXG4gICAgICAvLyBUcmFuc2Zvcm0gdGhlIGZ1bmN0aW9uXG4gICAgICB0aGlzLnRyYW5zZm9ybUZ1bmN0aW9uKFxuICAgICAgICBmbixcbiAgICAgICAgc3RhY2tOYW1lLFxuICAgICAgICBmdW5jdGlvbklkLFxuICAgICAgICBvcmlnaW5hbEhhbmRsZXIsXG4gICAgICAgIGxvY2FsSGFuZGxlcixcbiAgICAgIClcbiAgICB9XG5cbiAgICB0aGlzLnByb2Nlc3NlZEZ1bmN0aW9ucy5hZGQobm9kZUlkKVxuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIGEgY29uc3RydWN0IGlzIGEgTGFtYmRhIEZ1bmN0aW9uIHVzaW5nIGR1Y2stdHlwaW5nLlxuICAgKiBUaGlzIGF2b2lkcyBpbnN0YW5jZW9mIGlzc3VlcyB3aGVuIG11bHRpcGxlIGNvcGllcyBvZiBhd3MtY2RrLWxpYiBhcmUgbG9hZGVkLlxuICAgKi9cbiAgcHJpdmF0ZSBpc0xhbWJkYUZ1bmN0aW9uKG5vZGU6IElDb25zdHJ1Y3QpOiBib29sZWFuIHtcbiAgICAvLyBDaGVjayBieSBjb25zdHJ1Y3RvciBuYW1lIC0gaGFuZGxlcyBGdW5jdGlvbiwgRG9ja2VySW1hZ2VGdW5jdGlvbiwgTm9kZWpzRnVuY3Rpb24sIGV0Yy5cbiAgICAvLyBBbHNvIGhhbmRsZXMgb3VyIHBhdGNoZWQgdmVyc2lvbnMgbGlrZSBEb2NrZXJJbWFnZUZ1bmN0aW9uV2l0aENhcHR1cmVcbiAgICBjb25zdCBjb25zdHJ1Y3Rvck5hbWUgPSBub2RlLmNvbnN0cnVjdG9yLm5hbWVcbiAgICAvLyBDREsgYXBwZW5kcyBcIjJcIiB0byBjbGFzcyBuYW1lcyBpbiBzb21lIHZlcnNpb25zXG4gICAgY29uc3QgaXNGdW5jdGlvbiA9XG4gICAgICBjb25zdHJ1Y3Rvck5hbWUgPT09IFwiRnVuY3Rpb25cIiB8fFxuICAgICAgY29uc3RydWN0b3JOYW1lID09PSBcIkZ1bmN0aW9uMlwiIHx8XG4gICAgICBjb25zdHJ1Y3Rvck5hbWUuZW5kc1dpdGgoXCJGdW5jdGlvblwiKSB8fFxuICAgICAgY29uc3RydWN0b3JOYW1lLmVuZHNXaXRoKFwiRnVuY3Rpb24yXCIpIHx8XG4gICAgICBjb25zdHJ1Y3Rvck5hbWUuaW5jbHVkZXMoXCJGdW5jdGlvblwiKSAvLyBDYXRjaCBwYXRjaGVkIHZlcnNpb25zIGxpa2UgRG9ja2VySW1hZ2VGdW5jdGlvbldpdGhDYXB0dXJlXG5cbiAgICBpZiAoIWlzRnVuY3Rpb24pIHtcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cblxuICAgIC8vIEV4Y2x1ZGUgQ2ZuRnVuY3Rpb24gKHRoZSBMMSBjb25zdHJ1Y3QpXG4gICAgaWYgKGNvbnN0cnVjdG9yTmFtZSA9PT0gXCJDZm5GdW5jdGlvblwiKSB7XG4gICAgICByZXR1cm4gZmFsc2VcbiAgICB9XG5cbiAgICAvLyBWZXJpZnkgaXQgaGFzIGV4cGVjdGVkIExhbWJkYSBGdW5jdGlvbiBwcm9wZXJ0aWVzXG4gICAgY29uc3QgbWF5YmVGdW5jdGlvbiA9IG5vZGUgYXMgdW5rbm93biBhcyB7XG4gICAgICBmdW5jdGlvbk5hbWU/OiB1bmtub3duXG4gICAgICBmdW5jdGlvbkFybj86IHVua25vd25cbiAgICAgIG5vZGU/OiB7IGRlZmF1bHRDaGlsZD86IHVua25vd24gfVxuICAgIH1cblxuICAgIC8vIE11c3QgaGF2ZSBmdW5jdGlvbk5hbWUgYW5kIGZ1bmN0aW9uQXJuIChJRnVuY3Rpb24gaW50ZXJmYWNlKVxuICAgIGlmICghbWF5YmVGdW5jdGlvbi5mdW5jdGlvbk5hbWUgfHwgIW1heWJlRnVuY3Rpb24uZnVuY3Rpb25Bcm4pIHtcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cblxuICAgIC8vIE11c3QgaGF2ZSBhIGRlZmF1bHRDaGlsZCAodGhlIENmbkZ1bmN0aW9uKVxuICAgIGlmICghbWF5YmVGdW5jdGlvbi5ub2RlPy5kZWZhdWx0Q2hpbGQpIHtcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cblxuICAgIHJldHVybiB0cnVlXG4gIH1cblxuICBwcml2YXRlIGdlbmVyYXRlRnVuY3Rpb25JZChmbjogbGFtYmRhLkZ1bmN0aW9uKTogc3RyaW5nIHtcbiAgICAvLyBVc2UgdGhlIGNvbnN0cnVjdCBJRCBhcyB0aGUgZnVuY3Rpb24gSURcbiAgICAvLyBGb3IgbmVzdGVkIGNvbnN0cnVjdHMsIGpvaW4gd2l0aCBkYXNoZXNcbiAgICBjb25zdCBwYXJ0cyA9IGZuLm5vZGUucGF0aC5zcGxpdChcIi9cIilcbiAgICAvLyBTa2lwIGZpcnN0IHBhcnQgKEFwcCkgYW5kIHRha2UgdGhlIHJlc3RcbiAgICBjb25zdCByZWxldmFudFBhcnRzID0gcGFydHMuc2xpY2UoMSlcbiAgICByZXR1cm4gcmVsZXZhbnRQYXJ0cy5qb2luKFwiLVwiKS5yZXBsYWNlKC9bXmEtekEtWjAtOS1dL2csIFwiLVwiKVxuICB9XG5cbiAgLyoqXG4gICAqIEdldCBoYW5kbGVyIHBhdGhzIGZvciBhIGZ1bmN0aW9uLlxuICAgKiBSZXR1cm5zIGJvdGggdGhlIG9yaWdpbmFsIGhhbmRsZXIgKGFzIHNldCBpbiBDZm5GdW5jdGlvbikgYW5kIHRoZSBsb2NhbCBoYW5kbGVyIHBhdGguXG4gICAqIFJldHVybnMgbnVsbCBpZiB0aGUgZnVuY3Rpb24gaXMgbm90IHN1cHBvcnRlZCAoZS5nLiwgbm90IGEgTm9kZWpzRnVuY3Rpb24pLlxuICAgKi9cbiAgcHJpdmF0ZSBnZXRIYW5kbGVyUGF0aHMoZm46IGxhbWJkYS5GdW5jdGlvbik6IHtcbiAgICBvcmlnaW5hbEhhbmRsZXI6IHN0cmluZ1xuICAgIGxvY2FsSGFuZGxlcjogc3RyaW5nXG4gIH0gfCBudWxsIHtcbiAgICBjb25zdCBjZm5GdW5jdGlvbiA9IGZuLm5vZGUuZGVmYXVsdENoaWxkIGFzIGxhbWJkYS5DZm5GdW5jdGlvblxuICAgIGNvbnN0IG9yaWdpbmFsSGFuZGxlciA9IGNmbkZ1bmN0aW9uLmhhbmRsZXIgfHwgXCJpbmRleC5oYW5kbGVyXCJcbiAgICBjb25zdCBjb25zdHJ1Y3RJZCA9IGZuLm5vZGUuaWRcblxuICAgIC8vIENoZWNrIGlmIGNhcHR1cmVkIGJ5IHRoZSBOb2RlanNGdW5jdGlvbiBob29rXG4gICAgY29uc3QgZW50cnlQYXRoID0gZ2V0RW50cnlQYXRoKGZuKVxuICAgIGNvbnN0IGhhbmRsZXJOYW1lID0gZ2V0SGFuZGxlck5hbWUoZm4pIHx8IFwiaGFuZGxlclwiXG4gICAgaWYgKGVudHJ5UGF0aCkge1xuICAgICAgLy8gQ29udmVydCBlbnRyeSBwYXRoIHRvIGxvY2FsIGhhbmRsZXIgcGF0aFxuICAgICAgLy8gZS5nLiwgXCJmdW5jdGlvbnMvczMtd3JpdGVyL2hhbmRsZXIudHNcIiArIFwiaGFuZGxlclwiIC0+IFwiZnVuY3Rpb25zL3MzLXdyaXRlci9oYW5kbGVyLmhhbmRsZXJcIlxuICAgICAgY29uc3QgbG9jYWxIYW5kbGVyID0gYCR7ZW50cnlQYXRoLnJlcGxhY2UoRVhURU5TSU9OX1JFR0VYLCBcIlwiKX0uJHtoYW5kbGVyTmFtZX1gXG4gICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgYFtMaXZlTGFtYmRhXSBVc2luZyBjYXB0dXJlZCBlbnRyeSBmb3IgJHtjb25zdHJ1Y3RJZH06ICR7bG9jYWxIYW5kbGVyfWAsXG4gICAgICApXG4gICAgICByZXR1cm4geyBvcmlnaW5hbEhhbmRsZXIsIGxvY2FsSGFuZGxlciB9XG4gICAgfVxuXG4gICAgLy8gTm8gaGFuZGxlciBwYXRoIGZvdW5kIC0gdGhpcyBmdW5jdGlvbiBpcyBub3Qgc3VwcG9ydGVkIChub3QgYSBOb2RlanNGdW5jdGlvbiBvciBEb2NrZXJJbWFnZUZ1bmN0aW9uKVxuICAgIGNvbnNvbGUubG9nKFxuICAgICAgYFtMaXZlTGFtYmRhXSBTa2lwcGluZyB1bnN1cHBvcnRlZCBmdW5jdGlvbiBcIiR7Y29uc3RydWN0SWR9XCI6IGAgK1xuICAgICAgICBgbm90IGEgTm9kZWpzRnVuY3Rpb24gb3IgRG9ja2VySW1hZ2VGdW5jdGlvbiAob3IgYm9vdHN0cmFwIGhvb2sgd2FzIG5vdCBpbnN0YWxsZWQgZWFybHkgZW5vdWdoKWAsXG4gICAgKVxuICAgIHJldHVybiBudWxsXG4gIH1cblxuICAvKipcbiAgICogVHJhbnNmb3JtIGEgRG9ja2VySW1hZ2VGdW5jdGlvbiB0byB1c2UgdGhlIGJyaWRnZSBEb2NrZXIgaW1hZ2UuXG4gICAqIFN0b3JlcyB0aGUgbG9jYWwgRG9ja2VyIGNvbnRleHQgcGF0aCBpbiBhIHRhZyBmb3IgdGhlIGRhZW1vbiB0byBidWlsZC9ydW4gbG9jYWxseS5cbiAgICovXG4gIHByaXZhdGUgdHJhbnNmb3JtRG9ja2VyRnVuY3Rpb24oXG4gICAgZm46IGxhbWJkYS5GdW5jdGlvbixcbiAgICBfc3RhY2tOYW1lOiBzdHJpbmcsXG4gICAgZnVuY3Rpb25JZDogc3RyaW5nLFxuICApOiB2b2lkIHtcbiAgICBjb25zdCBjZm5GdW5jdGlvbiA9IGZuLm5vZGUuZGVmYXVsdENoaWxkIGFzIGxhbWJkYS5DZm5GdW5jdGlvblxuICAgIGNvbnN0IHN0YWNrID0gY2RrLlN0YWNrLm9mKGZuKVxuXG4gICAgLy8gR2V0IHRoZSBkb2NrZXIgY29udGV4dCBwYXRoIGZyb20gdGhlIGhvb2tcbiAgICBjb25zdCBkb2NrZXJDb250ZXh0UGF0aCA9IGdldERvY2tlckNvbnRleHRQYXRoKGZuKVxuICAgIGlmICghZG9ja2VyQ29udGV4dFBhdGgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYFtMaXZlTGFtYmRhXSBObyBkb2NrZXIgY29udGV4dCBwYXRoIGZvciBcIiR7ZnVuY3Rpb25JZH1cIi4gYCArXG4gICAgICAgICAgYFRoZSBib290c3RyYXAgaG9vayB3YXMgbm90IGluc3RhbGxlZCBlYXJseSBlbm91Z2guIGAgK1xuICAgICAgICAgIGBGaXg6IGltcG9ydCBcImNkay1sb2NhbC1sYW1iZGEvYm9vdHN0cmFwXCIgYmVmb3JlIGFueSBDREsgaW1wb3J0cyAoTm9kZS5qcyksIGAgK1xuICAgICAgICAgIGBvciBydW4gQnVuIHdpdGggXCJidW4gLS1wcmVsb2FkIGNkay1sb2NhbC1sYW1iZGEvYm9vdHN0cmFwXCIuYCxcbiAgICAgIClcbiAgICB9XG5cbiAgICAvLyBHZXQgU1NNIHBhcmFtZXRlcnNcbiAgICBjb25zdCBib290c3RyYXBRdWFsaWZpZXIgPVxuICAgICAgc3RhY2subm9kZS50cnlHZXRDb250ZXh0KFwiQGF3cy1jZGsvY29yZTpib290c3RyYXBRdWFsaWZpZXJcIikgfHxcbiAgICAgIFwiaG5iNjU5ZmRzXCJcbiAgICBjb25zdCBzc21CYXNlUGF0aCA9IGAke1NTTV9CQVNFX1BBVEh9LyR7Ym9vdHN0cmFwUXVhbGlmaWVyfWBcblxuICAgIGNvbnN0IGFwaUFybiA9IHNzbS5TdHJpbmdQYXJhbWV0ZXIudmFsdWVGb3JTdHJpbmdQYXJhbWV0ZXIoXG4gICAgICBzdGFjayxcbiAgICAgIGAke3NzbUJhc2VQYXRofS9hcGktYXJuYCxcbiAgICApXG5cbiAgICAvLyBEZXRlcm1pbmUgYXJjaGl0ZWN0dXJlIGFuZCBnZXQgYXBwcm9wcmlhdGUgYnJpZGdlIGltYWdlXG4gICAgY29uc3QgYXJjaGl0ZWN0dXJlID0gdGhpcy5nZXRBcmNoaXRlY3R1cmUoY2ZuRnVuY3Rpb24pXG4gICAgY29uc3QgYnJpZGdlSW1hZ2VQYXJhbSA9XG4gICAgICBhcmNoaXRlY3R1cmUgPT09IFwiYXJtNjRcIiA/IFwiYnJpZGdlLWltYWdlLWFybTY0XCIgOiBcImJyaWRnZS1pbWFnZS14ODZfNjRcIlxuXG4gICAgY29uc3QgYnJpZGdlSW1hZ2VVcmkgPSBzc20uU3RyaW5nUGFyYW1ldGVyLnZhbHVlRm9yU3RyaW5nUGFyYW1ldGVyKFxuICAgICAgc3RhY2ssXG4gICAgICBgJHtzc21CYXNlUGF0aH0vJHticmlkZ2VJbWFnZVBhcmFtfWAsXG4gICAgKVxuXG4gICAgLy8gQWRkIHRhZyB3aXRoIGRvY2tlciBjb250ZXh0IHBhdGggZm9yIGRhZW1vbiBkaXNjb3ZlcnlcbiAgICAvLyBUaGUgZGFlbW9uIHVzZXMgdGhpcyB0YWcgdG8gYnVpbGQgYW5kIHJ1biB0aGUgY29udGFpbmVyIGxvY2FsbHlcbiAgICBjZm5GdW5jdGlvbi50YWdzLnNldFRhZyhMSVZFX0xBTUJEQV9ET0NLRVJfVEFHLCBkb2NrZXJDb250ZXh0UGF0aClcblxuICAgIC8vIEdyYW50IHBlcm1pc3Npb25zIHRvIHB1Ymxpc2gvc3Vic2NyaWJlIHRvIEFwcFN5bmMgRXZlbnRzXG4gICAgZm4uYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICBcImFwcHN5bmM6RXZlbnRDb25uZWN0XCIsXG4gICAgICAgICAgXCJhcHBzeW5jOkV2ZW50UHVibGlzaFwiLFxuICAgICAgICAgIFwiYXBwc3luYzpFdmVudFN1YnNjcmliZVwiLFxuICAgICAgICBdLFxuICAgICAgICByZXNvdXJjZXM6IFthcGlBcm4sIGAke2FwaUFybn0vKmBdLFxuICAgICAgfSksXG4gICAgKVxuXG4gICAgLy8gR3JhbnQgcGVybWlzc2lvbnMgdG8gcmVhZCBTU00gcGFyYW1ldGVycyAoYnJpZGdlIG5lZWRzIEFwcFN5bmMgZW5kcG9pbnRzKVxuICAgIGZuLmFkZFRvUm9sZVBvbGljeShcbiAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICBhY3Rpb25zOiBbXCJzc206R2V0UGFyYW1ldGVyXCIsIFwic3NtOkdldFBhcmFtZXRlcnNcIl0sXG4gICAgICAgIHJlc291cmNlczogW1xuICAgICAgICAgIGBhcm46YXdzOnNzbToke3N0YWNrLnJlZ2lvbn06JHtzdGFjay5hY2NvdW50fTpwYXJhbWV0ZXIke3NzbUJhc2VQYXRofS8qYCxcbiAgICAgICAgXSxcbiAgICAgIH0pLFxuICAgIClcblxuICAgIC8vIEluY3JlYXNlIHRpbWVvdXQgdG8gYWxsb3cgZm9yIGxvY2FsIGRlYnVnZ2luZ1xuICAgIGNmbkZ1bmN0aW9uLnRpbWVvdXQgPSAzMDAgLy8gNSBtaW51dGVzXG5cbiAgICAvLyBSZXBsYWNlIHRoZSBEb2NrZXIgaW1hZ2Ugd2l0aCB0aGUgYnJpZGdlIGltYWdlXG4gICAgY2ZuRnVuY3Rpb24uY29kZSA9IHtcbiAgICAgIGltYWdlVXJpOiBicmlkZ2VJbWFnZVVyaSxcbiAgICB9XG5cbiAgICBjb25zb2xlLmxvZyhcbiAgICAgIGBbTGl2ZUxhbWJkYV0gUmVwbGFjZWQgRG9ja2VyIGltYWdlIHdpdGggYnJpZGdlICgke2FyY2hpdGVjdHVyZX0pYCxcbiAgICApXG4gIH1cblxuICAvKipcbiAgICogRGV0ZXJtaW5lIHRoZSBhcmNoaXRlY3R1cmUgb2YgYSBMYW1iZGEgZnVuY3Rpb24uXG4gICAqIERlZmF1bHRzIHRvIHg4Nl82NCBpZiBub3QgZXhwbGljaXRseSBzZXQuXG4gICAqL1xuICBwcml2YXRlIGdldEFyY2hpdGVjdHVyZShjZm5GdW5jdGlvbjogbGFtYmRhLkNmbkZ1bmN0aW9uKTogXCJhcm02NFwiIHwgXCJ4ODZfNjRcIiB7XG4gICAgY29uc3QgYXJjaGl0ZWN0dXJlcyA9IGNmbkZ1bmN0aW9uLmFyY2hpdGVjdHVyZXMgYXMgc3RyaW5nW10gfCB1bmRlZmluZWRcbiAgICBpZiAoYXJjaGl0ZWN0dXJlcz8uaW5jbHVkZXMoXCJhcm02NFwiKSkge1xuICAgICAgcmV0dXJuIFwiYXJtNjRcIlxuICAgIH1cbiAgICByZXR1cm4gXCJ4ODZfNjRcIlxuICB9XG5cbiAgcHJpdmF0ZSB0cmFuc2Zvcm1GdW5jdGlvbihcbiAgICBmbjogbGFtYmRhLkZ1bmN0aW9uLFxuICAgIF9zdGFja05hbWU6IHN0cmluZyxcbiAgICBfZnVuY3Rpb25JZDogc3RyaW5nLFxuICAgIF9vcmlnaW5hbEhhbmRsZXI6IHN0cmluZyxcbiAgICBsb2NhbEhhbmRsZXI6IHN0cmluZyxcbiAgKTogdm9pZCB7XG4gICAgY29uc3QgY2ZuRnVuY3Rpb24gPSBmbi5ub2RlLmRlZmF1bHRDaGlsZCBhcyBsYW1iZGEuQ2ZuRnVuY3Rpb25cbiAgICBjb25zdCBzdGFjayA9IGNkay5TdGFjay5vZihmbilcblxuICAgIC8vIFJlYWQgdmFsdWVzIGZyb20gU1NNIHBhcmFtZXRlcnMgKGNyZWF0ZWQgYnkgYm9vdHN0cmFwIHN0YWNrKVxuICAgIC8vIFVzZSB0aGUgQ0RLIGJvb3RzdHJhcCBxdWFsaWZpZXIgZm9yIHByb3BlciBzY29waW5nXG4gICAgY29uc3QgYm9vdHN0cmFwUXVhbGlmaWVyID1cbiAgICAgIHN0YWNrLm5vZGUudHJ5R2V0Q29udGV4dChcIkBhd3MtY2RrL2NvcmU6Ym9vdHN0cmFwUXVhbGlmaWVyXCIpIHx8XG4gICAgICBcImhuYjY1OWZkc1wiXG4gICAgY29uc3Qgc3NtQmFzZVBhdGggPSBgJHtTU01fQkFTRV9QQVRIfS8ke2Jvb3RzdHJhcFF1YWxpZmllcn1gXG5cbiAgICBjb25zdCBhcGlBcm4gPSBzc20uU3RyaW5nUGFyYW1ldGVyLnZhbHVlRm9yU3RyaW5nUGFyYW1ldGVyKFxuICAgICAgc3RhY2ssXG4gICAgICBgJHtzc21CYXNlUGF0aH0vYXBpLWFybmAsXG4gICAgKVxuICAgIGNvbnN0IGJyaWRnZUJ1Y2tldCA9IHNzbS5TdHJpbmdQYXJhbWV0ZXIudmFsdWVGb3JTdHJpbmdQYXJhbWV0ZXIoXG4gICAgICBzdGFjayxcbiAgICAgIGAke3NzbUJhc2VQYXRofS9icmlkZ2UtYnVja2V0YCxcbiAgICApXG4gICAgY29uc3QgYnJpZGdlS2V5ID0gc3NtLlN0cmluZ1BhcmFtZXRlci52YWx1ZUZvclN0cmluZ1BhcmFtZXRlcihcbiAgICAgIHN0YWNrLFxuICAgICAgYCR7c3NtQmFzZVBhdGh9L2JyaWRnZS1rZXlgLFxuICAgIClcblxuICAgIC8vIEFkZCB0YWcgd2l0aCBsb2NhbCBoYW5kbGVyIHBhdGggZm9yIGRhZW1vbiBkaXNjb3ZlcnlcbiAgICAvLyBUaGUgZGFlbW9uIHF1ZXJpZXMgTGFtYmRhIEFQSSBmb3IgZnVuY3Rpb25zIHdpdGggdGhpcyB0YWdcbiAgICBjZm5GdW5jdGlvbi50YWdzLnNldFRhZyhMSVZFX0xBTUJEQV9UQUcsIGxvY2FsSGFuZGxlcilcblxuICAgIC8vIEdyYW50IHBlcm1pc3Npb25zIHRvIHB1Ymxpc2gvc3Vic2NyaWJlIHRvIEFwcFN5bmMgRXZlbnRzXG4gICAgZm4uYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICBcImFwcHN5bmM6RXZlbnRDb25uZWN0XCIsXG4gICAgICAgICAgXCJhcHBzeW5jOkV2ZW50UHVibGlzaFwiLFxuICAgICAgICAgIFwiYXBwc3luYzpFdmVudFN1YnNjcmliZVwiLFxuICAgICAgICBdLFxuICAgICAgICByZXNvdXJjZXM6IFthcGlBcm4sIGAke2FwaUFybn0vKmBdLFxuICAgICAgfSksXG4gICAgKVxuXG4gICAgLy8gR3JhbnQgcGVybWlzc2lvbnMgdG8gcmVhZCBTU00gcGFyYW1ldGVycyAoYnJpZGdlIG5lZWRzIEFwcFN5bmMgZW5kcG9pbnRzKVxuICAgIGZuLmFkZFRvUm9sZVBvbGljeShcbiAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICBhY3Rpb25zOiBbXCJzc206R2V0UGFyYW1ldGVyXCIsIFwic3NtOkdldFBhcmFtZXRlcnNcIl0sXG4gICAgICAgIHJlc291cmNlczogW1xuICAgICAgICAgIGBhcm46YXdzOnNzbToke3N0YWNrLnJlZ2lvbn06JHtzdGFjay5hY2NvdW50fTpwYXJhbWV0ZXIke3NzbUJhc2VQYXRofS8qYCxcbiAgICAgICAgXSxcbiAgICAgIH0pLFxuICAgIClcblxuICAgIC8vIEluY3JlYXNlIHRpbWVvdXQgdG8gYWxsb3cgZm9yIGxvY2FsIGRlYnVnZ2luZ1xuICAgIGNmbkZ1bmN0aW9uLnRpbWVvdXQgPSAzMDAgLy8gNSBtaW51dGVzXG5cbiAgICAvLyBSZXBsYWNlIHRoZSBjb2RlIHdpdGggYnJpZGdlIGhhbmRsZXIgZnJvbSBib290c3RyYXAgc3RhY2sncyBTMyBidWNrZXRcbiAgICBjZm5GdW5jdGlvbi5jb2RlID0ge1xuICAgICAgczNCdWNrZXQ6IGJyaWRnZUJ1Y2tldCxcbiAgICAgIHMzS2V5OiBicmlkZ2VLZXksXG4gICAgfVxuICAgIGNmbkZ1bmN0aW9uLmhhbmRsZXIgPSBcImluZGV4LmhhbmRsZXJcIlxuICB9XG59XG5cbi8qKlxuICogSGVscGVyIGZ1bmN0aW9uIHRvIGNoZWNrIGlmIGxpdmUgbW9kZSBpcyBlbmFibGVkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0xpdmVNb2RlRW5hYmxlZCgpOiBib29sZWFuIHtcbiAgcmV0dXJuIHByb2Nlc3MuZW52LkNES19MSVZFID09PSBcInRydWVcIlxufVxuXG4vKipcbiAqIEFwcGx5IGxpdmUgbGFtYmRhIGFzcGVjdCB0byBhIENESyBhcHAgb3Igc3RhY2sgaWYgbGl2ZSBtb2RlIGlzIGVuYWJsZWQuXG4gKlxuICogQHBhcmFtIHNjb3BlIFRoZSBDREsgYXBwIG9yIHN0YWNrIHRvIGFwcGx5IHRoZSBhc3BlY3QgdG9cbiAqIEBwYXJhbSBwcm9wcyBPcHRpb25hbCBjb25maWd1cmF0aW9uIGZvciB0aGUgbGl2ZSBsYW1iZGEgYXNwZWN0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhcHBseUxpdmVMYW1iZGFBc3BlY3QoXG4gIHNjb3BlOiBJQ29uc3RydWN0LFxuICBwcm9wczogTGl2ZUxhbWJkYUFzcGVjdFByb3BzID0ge30sXG4pOiB2b2lkIHtcbiAgaWYgKCFpc0xpdmVNb2RlRW5hYmxlZCgpKSB7XG4gICAgY29uc29sZS5sb2coXG4gICAgICBcIltMaXZlTGFtYmRhXSBMaXZlIG1vZGUgbm90IGVuYWJsZWQgKHNldCBDREtfTElWRT10cnVlIHRvIGVuYWJsZSlcIixcbiAgICApXG4gICAgcmV0dXJuXG4gIH1cblxuICBjb25zb2xlLmxvZyhcIltMaXZlTGFtYmRhXSBMaXZlIG1vZGUgZW5hYmxlZCAtIHRyYW5zZm9ybWluZyBMYW1iZGEgZnVuY3Rpb25zXCIpXG4gIGNkay5Bc3BlY3RzLm9mKHNjb3BlKS5hZGQobmV3IExpdmVMYW1iZGFBc3BlY3QocHJvcHMpKVxufVxuIl19
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Bootstrap file that installs hooks for NodejsFunction and DockerImageFunction
3
+ * BEFORE any CDK imports.
4
+ *
5
+ * This must be imported as the very first thing in the CDK app entry point,
6
+ * before any other imports.
7
+ *
8
+ * Runtime support:
9
+ * - Node.js: patches Module._load to intercept module loading
10
+ * - Bun: directly imports and patches modules (Module._load not supported)
11
+ *
12
+ * Hooks installed:
13
+ * - NodejsFunction: captures entry and handler props
14
+ * - DockerImageFunction: captures docker context path from code prop
15
+ * - DockerImageCode.fromImageAsset: captures the directory path
16
+ */
17
+ export {};