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.
- package/LICENSE +202 -0
- package/README.md +94 -0
- package/lib/aspect/docker-function-hook.d.ts +18 -0
- package/lib/aspect/docker-function-hook.js +31 -0
- package/lib/aspect/live-lambda-aspect.d.ts +85 -0
- package/lib/aspect/live-lambda-aspect.js +277 -0
- package/lib/aspect/live-lambda-bootstrap.d.ts +17 -0
- package/lib/aspect/live-lambda-bootstrap.js +260 -0
- package/lib/aspect/nodejs-function-hook.d.ts +20 -0
- package/lib/aspect/nodejs-function-hook.js +27 -0
- package/lib/bootstrap-stack/bootstrap-stack.d.ts +60 -0
- package/lib/bootstrap-stack/bootstrap-stack.js +338 -0
- package/lib/cli/appsync/client.d.ts +30 -0
- package/lib/cli/appsync/client.js +227 -0
- package/lib/cli/cdk-app.d.ts +7 -0
- package/lib/cli/cdk-app.js +25 -0
- package/lib/cli/commands/bootstrap.d.ts +9 -0
- package/lib/cli/commands/bootstrap.js +50 -0
- package/lib/cli/commands/local.d.ts +40 -0
- package/lib/cli/commands/local.js +1172 -0
- package/lib/cli/daemon.d.ts +22 -0
- package/lib/cli/daemon.js +18 -0
- package/lib/cli/docker/container.d.ts +116 -0
- package/lib/cli/docker/container.js +414 -0
- package/lib/cli/docker/types.d.ts +71 -0
- package/lib/cli/docker/types.js +5 -0
- package/lib/cli/docker/watcher.d.ts +44 -0
- package/lib/cli/docker/watcher.js +115 -0
- package/lib/cli/index.d.ts +9 -0
- package/lib/cli/index.js +26 -0
- package/lib/cli/runtime-api/server.d.ts +102 -0
- package/lib/cli/runtime-api/server.js +396 -0
- package/lib/cli/runtime-api/types.d.ts +149 -0
- package/lib/cli/runtime-api/types.js +10 -0
- package/lib/cli/runtime-wrapper/nodejs-runtime.d.ts +16 -0
- package/lib/cli/runtime-wrapper/nodejs-runtime.js +248 -0
- package/lib/cli/watcher/file-watcher.d.ts +32 -0
- package/lib/cli/watcher/file-watcher.js +57 -0
- package/lib/functions/bridge/appsync-client.d.ts +73 -0
- package/lib/functions/bridge/appsync-client.js +345 -0
- package/lib/functions/bridge/handler.d.ts +17 -0
- package/lib/functions/bridge/handler.js +79 -0
- package/lib/functions/bridge/ssm-config.d.ts +19 -0
- package/lib/functions/bridge/ssm-config.js +45 -0
- package/lib/functions/bridge-builder/handler.d.ts +12 -0
- package/lib/functions/bridge-builder/handler.js +181 -0
- package/lib/functions/bridge-docker/runtime.d.ts +9 -0
- package/lib/functions/bridge-docker/runtime.js +127 -0
- package/lib/index.d.ts +24 -0
- package/lib/index.js +28 -0
- package/lib/shared/types.d.ts +102 -0
- package/lib/shared/types.js +125 -0
- package/package.json +111 -0
|
@@ -0,0 +1,260 @@
|
|
|
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
|
+
import { createRequire } from "node:module";
|
|
18
|
+
const requireFromPackage = createRequire(import.meta.url);
|
|
19
|
+
// Prefer resolving dependencies from the *CDK app project* (process.cwd()).
|
|
20
|
+
// This avoids patching a nested aws-cdk-lib copy when cdk-local-lambda is
|
|
21
|
+
// installed with its own node_modules (common with package managers).
|
|
22
|
+
let requireFromProject = requireFromPackage;
|
|
23
|
+
try {
|
|
24
|
+
requireFromProject = createRequire(`${process.cwd()}/package.json`);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// Fall back to resolving relative to this package.
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Detect if we're running in Bun runtime
|
|
31
|
+
*/
|
|
32
|
+
const isBun = typeof process.versions.bun !== "undefined";
|
|
33
|
+
// Symbols for NodejsFunction
|
|
34
|
+
const ENTRY_SYMBOL = Symbol.for("live-lambda:entry");
|
|
35
|
+
const HANDLER_SYMBOL = Symbol.for("live-lambda:handler");
|
|
36
|
+
// Symbols for DockerImageFunction
|
|
37
|
+
const DOCKER_CONTEXT_SYMBOL = Symbol.for("live-lambda:docker-context");
|
|
38
|
+
/**
|
|
39
|
+
* Map to store docker context paths captured from DockerImageCode.fromImageAsset
|
|
40
|
+
* Key is the DockerImageCode instance, value is the context path
|
|
41
|
+
*/
|
|
42
|
+
const dockerImageCodeContextMap = new WeakMap();
|
|
43
|
+
/**
|
|
44
|
+
* Check if a module request is for aws-lambda-nodejs.
|
|
45
|
+
* We need to match:
|
|
46
|
+
* - "aws-cdk-lib/aws-lambda-nodejs" (direct import)
|
|
47
|
+
* - Paths ending with "/aws-lambda-nodejs" (resolved paths)
|
|
48
|
+
* - Paths containing "/aws-lambda-nodejs/" (submodule imports)
|
|
49
|
+
*/
|
|
50
|
+
function isLambdaNodejsModule(request) {
|
|
51
|
+
return (request === "aws-cdk-lib/aws-lambda-nodejs" ||
|
|
52
|
+
request.endsWith("/aws-lambda-nodejs") ||
|
|
53
|
+
request.includes("/aws-lambda-nodejs/"));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Check if a module request is for aws-lambda (for DockerImageFunction).
|
|
57
|
+
* We need to match:
|
|
58
|
+
* - "aws-cdk-lib/aws-lambda" (direct import)
|
|
59
|
+
* - Paths ending with "/aws-lambda" (resolved paths)
|
|
60
|
+
* - Paths containing "/aws-lambda/" (submodule imports)
|
|
61
|
+
*/
|
|
62
|
+
function isLambdaModule(request) {
|
|
63
|
+
// Be careful not to match aws-lambda-nodejs
|
|
64
|
+
if (request.includes("aws-lambda-nodejs")) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
return (request === "aws-cdk-lib/aws-lambda" ||
|
|
68
|
+
request.endsWith("/aws-lambda") ||
|
|
69
|
+
request.includes("/aws-lambda/"));
|
|
70
|
+
}
|
|
71
|
+
// Cache the lambda module for creating dummy code
|
|
72
|
+
let cachedLambdaModule = null;
|
|
73
|
+
/**
|
|
74
|
+
* Install hooks based on runtime environment.
|
|
75
|
+
*
|
|
76
|
+
* Bun notes:
|
|
77
|
+
* - Bun creates a *snapshot* of CommonJS named exports when importing from ESM.
|
|
78
|
+
* This means that mutating/replacing `module.exports.Foo` AFTER the ESM import
|
|
79
|
+
* was linked will not affect `import { Foo } from "..."` in the current process.
|
|
80
|
+
* - Therefore, Bun patching only works reliably when this bootstrap runs before
|
|
81
|
+
* the app entry point is loaded, e.g. via `bun --preload cdk-local-lambda/bootstrap`.
|
|
82
|
+
*
|
|
83
|
+
* Node.js:
|
|
84
|
+
* - We can patch Module._load to intercept module loading.
|
|
85
|
+
*/
|
|
86
|
+
if (isBun) {
|
|
87
|
+
const isLiveMode = process.env.CDK_LIVE === "true";
|
|
88
|
+
// Best-effort patching for Bun. This is only guaranteed to work when this file
|
|
89
|
+
// is preloaded (see note above). Even then, we keep this logic lightweight.
|
|
90
|
+
if (isLiveMode) {
|
|
91
|
+
const hasPreloadFlag = process.execArgv.includes("--preload");
|
|
92
|
+
if (!hasPreloadFlag) {
|
|
93
|
+
console.warn("[LiveLambda] Warning: Running in Bun without --preload. Automatic handler/docker detection is likely disabled.");
|
|
94
|
+
console.warn("[LiveLambda] Fix: run Bun with `--preload cdk-local-lambda/bootstrap`.");
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
// Patch aws-lambda first so NodejsFunction can create dummy Code.fromInline
|
|
98
|
+
// when CDK_LIVE=true (skips bundling).
|
|
99
|
+
const lambdaModule = requireFromProject("aws-cdk-lib/aws-lambda");
|
|
100
|
+
cachedLambdaModule = lambdaModule;
|
|
101
|
+
patchDockerImageFunction(lambdaModule);
|
|
102
|
+
const nodejsModule = requireFromProject("aws-cdk-lib/aws-lambda-nodejs");
|
|
103
|
+
patchNodejsFunction(nodejsModule);
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
console.warn("[LiveLambda] Warning: Failed to install Bun patches:", err.message);
|
|
107
|
+
console.warn("[LiveLambda] Automatic handler/docker detection is required; ensure bootstrap is preloaded.");
|
|
108
|
+
console.warn("[LiveLambda] See: https://github.com/berenddeboer/cdk-local-lambda#bun-support");
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
// Node.js: use Module._load hook to intercept module loading
|
|
114
|
+
const Module = requireFromPackage("node:module");
|
|
115
|
+
const originalLoad = Module._load;
|
|
116
|
+
Module._load = function (request, parent, isMain) {
|
|
117
|
+
// Call original load - let errors propagate naturally
|
|
118
|
+
const result = originalLoad.call(this, request, parent, isMain);
|
|
119
|
+
// Check if this is the lambda-nodejs module
|
|
120
|
+
if (isLambdaNodejsModule(request)) {
|
|
121
|
+
patchNodejsFunction(result);
|
|
122
|
+
}
|
|
123
|
+
// Check if this is the lambda module (for DockerImageFunction and Code.fromInline)
|
|
124
|
+
if (isLambdaModule(request)) {
|
|
125
|
+
// Cache the lambda module so we can use Code.fromInline in NodejsFunction patch
|
|
126
|
+
cachedLambdaModule = result;
|
|
127
|
+
patchDockerImageFunction(result);
|
|
128
|
+
}
|
|
129
|
+
return result;
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Create a dummy inline code that does nothing.
|
|
134
|
+
* Used to skip bundling when CDK_LIVE=true.
|
|
135
|
+
*/
|
|
136
|
+
function createDummyCode(lambdaModule) {
|
|
137
|
+
// Access lambda.Code.fromInline to create a no-op code
|
|
138
|
+
// This avoids bundling entirely since we provide pre-built code
|
|
139
|
+
const Code = lambdaModule.Code;
|
|
140
|
+
if (Code?.fromInline) {
|
|
141
|
+
return Code.fromInline("// Placeholder - replaced by LiveLambdaAspect");
|
|
142
|
+
}
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Patch NodejsFunction to capture entry and handler props
|
|
147
|
+
*/
|
|
148
|
+
function patchNodejsFunction(module) {
|
|
149
|
+
// If already patched, skip
|
|
150
|
+
if (module?.NodejsFunction?.__liveLambdaPatched) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
// Check if we can patch
|
|
154
|
+
if (module?.NodejsFunction) {
|
|
155
|
+
const OriginalNodejsFunction = module.NodejsFunction;
|
|
156
|
+
const isLiveMode = process.env.CDK_LIVE === "true";
|
|
157
|
+
// Create wrapper class that captures entry/handler props
|
|
158
|
+
class NodejsFunctionWithCapture extends OriginalNodejsFunction {
|
|
159
|
+
constructor(scope, id, props = {}) {
|
|
160
|
+
// In live mode, provide dummy code to skip bundling entirely
|
|
161
|
+
// The aspect will replace this with the bridge code from S3
|
|
162
|
+
let modifiedProps = props;
|
|
163
|
+
if (isLiveMode && !props.code && cachedLambdaModule) {
|
|
164
|
+
const dummyCode = createDummyCode(cachedLambdaModule);
|
|
165
|
+
if (dummyCode) {
|
|
166
|
+
modifiedProps = { ...props, code: dummyCode };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
super(scope, id, modifiedProps);
|
|
170
|
+
// Store the entry path on the instance (validate it's a non-empty string)
|
|
171
|
+
if (typeof props.entry === "string" && props.entry.trim().length > 0) {
|
|
172
|
+
;
|
|
173
|
+
this[ENTRY_SYMBOL] =
|
|
174
|
+
props.entry;
|
|
175
|
+
}
|
|
176
|
+
// Store the handler name (validate and default to 'handler')
|
|
177
|
+
const handler = typeof props.handler === "string" && props.handler.trim().length > 0
|
|
178
|
+
? props.handler
|
|
179
|
+
: "handler";
|
|
180
|
+
this[HANDLER_SYMBOL] = handler;
|
|
181
|
+
}
|
|
182
|
+
static __liveLambdaPatched = true;
|
|
183
|
+
}
|
|
184
|
+
// Try to replace - fail if we can't
|
|
185
|
+
try {
|
|
186
|
+
Object.defineProperty(module, "NodejsFunction", {
|
|
187
|
+
value: NodejsFunctionWithCapture,
|
|
188
|
+
writable: true,
|
|
189
|
+
configurable: true,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
console.error("[LiveLambda] FATAL: Cannot patch NodejsFunction - module is frozen or sealed.");
|
|
194
|
+
console.error("[LiveLambda] This can happen with certain bundlers or Node.js configurations.");
|
|
195
|
+
console.error("[LiveLambda] Error:", err.message);
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Patch DockerImageFunction and DockerImageCode to capture docker context
|
|
202
|
+
*/
|
|
203
|
+
function patchDockerImageFunction(module) {
|
|
204
|
+
if (!module)
|
|
205
|
+
return;
|
|
206
|
+
// First, patch DockerImageCode.fromImageAsset to capture the directory path
|
|
207
|
+
if (module.DockerImageCode && !module.DockerImageCode.__liveLambdaPatched) {
|
|
208
|
+
const OriginalDockerImageCode = module.DockerImageCode;
|
|
209
|
+
const originalFromImageAsset = OriginalDockerImageCode.fromImageAsset;
|
|
210
|
+
// Wrap fromImageAsset to capture the directory
|
|
211
|
+
const patchedFromImageAsset = (directory, props) => {
|
|
212
|
+
const result = originalFromImageAsset.call(OriginalDockerImageCode, directory, props);
|
|
213
|
+
// Store the directory path in the WeakMap, keyed by the result instance
|
|
214
|
+
dockerImageCodeContextMap.set(result, directory);
|
|
215
|
+
return result;
|
|
216
|
+
};
|
|
217
|
+
try {
|
|
218
|
+
Object.defineProperty(OriginalDockerImageCode, "fromImageAsset", {
|
|
219
|
+
value: patchedFromImageAsset,
|
|
220
|
+
writable: true,
|
|
221
|
+
configurable: true,
|
|
222
|
+
});
|
|
223
|
+
OriginalDockerImageCode.__liveLambdaPatched = true;
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
console.warn("[LiveLambda] Could not patch DockerImageCode.fromImageAsset:", err.message);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// Then, patch DockerImageFunction to read from the WeakMap
|
|
230
|
+
if (module.DockerImageFunction &&
|
|
231
|
+
!module.DockerImageFunction.__liveLambdaPatched) {
|
|
232
|
+
const OriginalDockerImageFunction = module.DockerImageFunction;
|
|
233
|
+
// Create wrapper class that captures docker context
|
|
234
|
+
class DockerImageFunctionWithCapture extends OriginalDockerImageFunction {
|
|
235
|
+
constructor(scope, id, props) {
|
|
236
|
+
super(scope, id, props);
|
|
237
|
+
// Look up the docker context from the WeakMap
|
|
238
|
+
if (props.code) {
|
|
239
|
+
const contextPath = dockerImageCodeContextMap.get(props.code);
|
|
240
|
+
if (contextPath) {
|
|
241
|
+
;
|
|
242
|
+
this[DOCKER_CONTEXT_SYMBOL] = contextPath;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
static __liveLambdaPatched = true;
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
Object.defineProperty(module, "DockerImageFunction", {
|
|
250
|
+
value: DockerImageFunctionWithCapture,
|
|
251
|
+
writable: true,
|
|
252
|
+
configurable: true,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
catch (err) {
|
|
256
|
+
console.warn("[LiveLambda] Could not patch DockerImageFunction:", err.message);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGl2ZS1sYW1iZGEtYm9vdHN0cmFwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FzcGVjdC9saXZlLWxhbWJkYS1ib290c3RyYXAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBRUgsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUUzQyxNQUFNLGtCQUFrQixHQUFHLGFBQWEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFBO0FBRXpELDRFQUE0RTtBQUM1RSwwRUFBMEU7QUFDMUUsc0VBQXNFO0FBQ3RFLElBQUksa0JBQWtCLEdBQUcsa0JBQWtCLENBQUE7QUFDM0MsSUFBSSxDQUFDO0lBQ0gsa0JBQWtCLEdBQUcsYUFBYSxDQUFDLEdBQUcsT0FBTyxDQUFDLEdBQUcsRUFBRSxlQUFlLENBQUMsQ0FBQTtBQUNyRSxDQUFDO0FBQUMsTUFBTSxDQUFDO0lBQ1AsbURBQW1EO0FBQ3JELENBQUM7QUFFRDs7R0FFRztBQUNILE1BQU0sS0FBSyxHQUFHLE9BQU8sT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHLEtBQUssV0FBVyxDQUFBO0FBRXpELDZCQUE2QjtBQUM3QixNQUFNLFlBQVksR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLG1CQUFtQixDQUFDLENBQUE7QUFDcEQsTUFBTSxjQUFjLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFBO0FBRXhELGtDQUFrQztBQUNsQyxNQUFNLHFCQUFxQixHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsNEJBQTRCLENBQUMsQ0FBQTtBQUV0RTs7O0dBR0c7QUFDSCxNQUFNLHlCQUF5QixHQUFHLElBQUksT0FBTyxFQUFrQixDQUFBO0FBRS9EOzs7Ozs7R0FNRztBQUNILFNBQVMsb0JBQW9CLENBQUMsT0FBZTtJQUMzQyxPQUFPLENBQ0wsT0FBTyxLQUFLLCtCQUErQjtRQUMzQyxPQUFP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LG9EQUFvRDtRQUNwRCxNQUFNLDhCQUErQixTQUFRLDJCQUEyQjtZQUN0RSxZQUFZLEtBQWMsRUFBRSxFQUFVLEVBQUUsS0FBK0I7Z0JBQ3JFLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFBO2dCQUV2Qiw4Q0FBOEM7Z0JBQzlDLElBQUksS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDO29CQUNmLE1BQU0sV0FBVyxHQUFHLHlCQUF5QixDQUFDLEdBQUcsQ0FDL0MsS0FBSyxDQUFDLElBQWMsQ0FDckIsQ0FBQTtvQkFDRCxJQUFJLFdBQVcsRUFBRSxDQUFDO3dCQUNoQixDQUFDO3dCQUFDLElBQTBDLENBQzFDLHFCQUFxQixDQUN0QixHQUFHLFdBQVcsQ0FBQTtvQkFDakIsQ0FBQztnQkFDSCxDQUFDO1lBQ0gsQ0FBQztZQUVELE1BQU0sQ0FBQyxtQkFBbUIsR0FBRyxJQUFJLENBQUE7O1FBR25DLElBQUksQ0FBQztZQUNILE1BQU0sQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFLHFCQUFxQixFQUFFO2dCQUNuRCxLQUFLLEVBQUUsOEJBQThCO2dCQUNyQyxRQUFRLEVBQUUsSUFBSTtnQkFDZCxZQUFZLEVBQUUsSUFBSTthQUNuQixDQUFDLENBQUE7UUFDSixDQUFDO1FBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztZQUNiLE9BQU8sQ0FBQyxJQUFJLENBQ1YsbURBQW1ELEVBQ2xELEdBQWEsQ0FBQyxPQUFPLENBQ3ZCLENBQUE7UUFDSCxDQUFDO0lBQ0gsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEJvb3RzdHJhcCBmaWxlIHRoYXQgaW5zdGFsbHMgaG9va3MgZm9yIE5vZGVqc0Z1bmN0aW9uIGFuZCBEb2NrZXJJbWFnZUZ1bmN0aW9uXG4gKiBCRUZPUkUgYW55IENESyBpbXBvcnRzLlxuICpcbiAqIFRoaXMgbXVzdCBiZSBpbXBvcnRlZCBhcyB0aGUgdmVyeSBmaXJzdCB0aGluZyBpbiB0aGUgQ0RLIGFwcCBlbnRyeSBwb2ludCxcbiAqIGJlZm9yZSBhbnkgb3RoZXIgaW1wb3J0cy5cbiAqXG4gKiBSdW50aW1lIHN1cHBvcnQ6XG4gKiAtIE5vZGUuanM6IHBhdGNoZXMgTW9kdWxlLl9sb2FkIHRvIGludGVyY2VwdCBtb2R1bGUgbG9hZGluZ1xuICogLSBCdW46IGRpcmVjdGx5IGltcG9ydHMgYW5kIHBhdGNoZXMgbW9kdWxlcyAoTW9kdWxlLl9sb2FkIG5vdCBzdXBwb3J0ZWQpXG4gKlxuICogSG9va3MgaW5zdGFsbGVkOlxuICogLSBOb2RlanNGdW5jdGlvbjogY2FwdHVyZXMgZW50cnkgYW5kIGhhbmRsZXIgcHJvcHNcbiAqIC0gRG9ja2VySW1hZ2VGdW5jdGlvbjogY2FwdHVyZXMgZG9ja2VyIGNvbnRleHQgcGF0aCBmcm9tIGNvZGUgcHJvcFxuICogLSBEb2NrZXJJbWFnZUNvZGUuZnJvbUltYWdlQXNzZXQ6IGNhcHR1cmVzIHRoZSBkaXJlY3RvcnkgcGF0aFxuICovXG5cbmltcG9ydCB7IGNyZWF0ZVJlcXVpcmUgfSBmcm9tIFwibm9kZTptb2R1bGVcIlxuXG5jb25zdCByZXF1aXJlRnJvbVBhY2thZ2UgPSBjcmVhdGVSZXF1aXJlKGltcG9ydC5tZXRhLnVybClcblxuLy8gUHJlZmVyIHJlc29sdmluZyBkZXBlbmRlbmNpZXMgZnJvbSB0aGUgKkNESyBhcHAgcHJvamVjdCogKHByb2Nlc3MuY3dkKCkpLlxuLy8gVGhpcyBhdm9pZHMgcGF0Y2hpbmcgYSBuZXN0ZWQgYXdzLWNkay1saWIgY29weSB3aGVuIGNkay1sb2NhbC1sYW1iZGEgaXNcbi8vIGluc3RhbGxlZCB3aXRoIGl0cyBvd24gbm9kZV9tb2R1bGVzIChjb21tb24gd2l0aCBwYWNrYWdlIG1hbmFnZXJzKS5cbmxldCByZXF1aXJlRnJvbVByb2plY3QgPSByZXF1aXJlRnJvbVBhY2thZ2VcbnRyeSB7XG4gIHJlcXVpcmVGcm9tUHJvamVjdCA9IGNyZWF0ZVJlcXVpcmUoYCR7cHJvY2Vzcy5jd2QoKX0vcGFja2FnZS5qc29uYClcbn0gY2F0Y2gge1xuICAvLyBGYWxsIGJhY2sgdG8gcmVzb2x2aW5nIHJlbGF0aXZlIHRvIHRoaXMgcGFja2FnZS5cbn1cblxuLyoqXG4gKiBEZXRlY3QgaWYgd2UncmUgcnVubmluZyBpbiBCdW4gcnVudGltZVxuICovXG5jb25zdCBpc0J1biA9IHR5cGVvZiBwcm9jZXNzLnZlcnNpb25zLmJ1biAhPT0gXCJ1bmRlZmluZWRcIlxuXG4vLyBTeW1ib2xzIGZvciBOb2RlanNGdW5jdGlvblxuY29uc3QgRU5UUllfU1lNQk9MID0gU3ltYm9sLmZvcihcImxpdmUtbGFtYmRhOmVudHJ5XCIpXG5jb25zdCBIQU5ETEVSX1NZTUJPTCA9IFN5bWJvbC5mb3IoXCJsaXZlLWxhbWJkYTpoYW5kbGVyXCIpXG5cbi8vIFN5bWJvbHMgZm9yIERvY2tlckltYWdlRnVuY3Rpb25cbmNvbnN0IERPQ0tFUl9DT05URVhUX1NZTUJPTCA9IFN5bWJvbC5mb3IoXCJsaXZlLWxhbWJkYTpkb2NrZXItY29udGV4dFwiKVxuXG4vKipcbiAqIE1hcCB0byBzdG9yZSBkb2NrZXIgY29udGV4dCBwYXRocyBjYXB0dXJlZCBmcm9tIERvY2tlckltYWdlQ29kZS5mcm9tSW1hZ2VBc3NldFxuICogS2V5IGlzIHRoZSBEb2NrZXJJbWFnZUNvZGUgaW5zdGFuY2UsIHZhbHVlIGlzIHRoZSBjb250ZXh0IHBhdGhcbiAqL1xuY29uc3QgZG9ja2VySW1hZ2VDb2RlQ29udGV4dE1hcCA9IG5ldyBXZWFrTWFwPG9iamVjdCwgc3RyaW5nPigpXG5cbi8qKlxuICogQ2hlY2sgaWYgYSBtb2R1bGUgcmVxdWVzdCBpcyBmb3IgYXdzLWxhbWJkYS1ub2RlanMuXG4gKiBXZSBuZWVkIHRvIG1hdGNoOlxuICogLSBcImF3cy1jZGstbGliL2F3cy1sYW1iZGEtbm9kZWpzXCIgKGRpcmVjdCBpbXBvcnQpXG4gKiAtIFBhdGhzIGVuZGluZyB3aXRoIFwiL2F3cy1sYW1iZGEtbm9kZWpzXCIgKHJlc29sdmVkIHBhdGhzKVxuICogLSBQYXRocyBjb250YWluaW5nIFwiL2F3cy1sYW1iZGEtbm9kZWpzL1wiIChzdWJtb2R1bGUgaW1wb3J0cylcbiAqL1xuZnVuY3Rpb24gaXNMYW1iZGFOb2RlanNNb2R1bGUocmVxdWVzdDogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiAoXG4gICAgcmVxdWVzdCA9PT0gXCJhd3MtY2RrLWxpYi9hd3MtbGFtYmRhLW5vZGVqc1wiIHx8XG4gICAgcmVxdWVzdC5lbmRzV2l0aChcIi9hd3MtbGFtYmRhLW5vZGVqc1wiKSB8fFxuICAgIHJlcXVlc3QuaW5jbHVkZXMoXCIvYXdzLWxhbWJkYS1ub2RlanMvXCIpXG4gIClcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBhIG1vZHVsZSByZXF1ZXN0IGlzIGZvciBhd3MtbGFtYmRhIChmb3IgRG9ja2VySW1hZ2VGdW5jdGlvbikuXG4gKiBXZSBuZWVkIHRvIG1hdGNoOlxuICogLSBcImF3cy1jZGstbGliL2F3cy1sYW1iZGFcIiAoZGlyZWN0IGltcG9ydClcbiAqIC0gUGF0aHMgZW5kaW5nIHdpdGggXCIvYXdzLWxhbWJkYVwiIChyZXNvbHZlZCBwYXRocylcbiAqIC0gUGF0aHMgY29udGFpbmluZyBcIi9hd3MtbGFtYmRhL1wiIChzdWJtb2R1bGUgaW1wb3J0cylcbiAqL1xuZnVuY3Rpb24gaXNMYW1iZGFNb2R1bGUocmVxdWVzdDogc3RyaW5nKTogYm9vbGVhbiB7XG4gIC8vIEJlIGNhcmVmdWwgbm90IHRvIG1hdGNoIGF3cy1sYW1iZGEtbm9kZWpzXG4gIGlmIChyZXF1ZXN0LmluY2x1ZGVzKFwiYXdzLWxhbWJkYS1ub2RlanNcIikpIHtcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuICByZXR1cm4gKFxuICAgIHJlcXVlc3QgPT09IFwiYXdzLWNkay1saWIvYXdzLWxhbWJkYVwiIHx8XG4gICAgcmVxdWVzdC5lbmRzV2l0aChcIi9hd3MtbGFtYmRhXCIpIHx8XG4gICAgcmVxdWVzdC5pbmNsdWRlcyhcIi9hd3MtbGFtYmRhL1wiKVxuICApXG59XG5cbi8vIE1vZHVsZSB0eXBlIGZvciB0aGUgbGFtYmRhLW5vZGVqcyBleHBvcnRzXG5pbnRlcmZhY2UgTGFtYmRhTm9kZWpzTW9kdWxlIHtcbiAgTm9kZWpzRnVuY3Rpb246IE5vZGVqc0Z1bmN0aW9uQ29uc3RydWN0b3IgJiB7XG4gICAgX19saXZlTGFtYmRhUGF0Y2hlZD86IGJvb2xlYW5cbiAgfVxufVxuXG4vLyBDb25zdHJ1Y3RvciB0eXBlIHRoYXQgY2FuIGJlIGV4dGVuZGVkXG5pbnRlcmZhY2UgTm9kZWpzRnVuY3Rpb25Db25zdHJ1Y3RvciB7XG4gIG5ldyAoXG4gICAgc2NvcGU6IHVua25vd24sXG4gICAgaWQ6IHN0cmluZyxcbiAgICBwcm9wcz86IE5vZGVqc0Z1bmN0aW9uUHJvcHMsXG4gICk6IE5vZGVqc0Z1bmN0aW9uSW5zdGFuY2VcbiAgcHJvdG90eXBlOiBOb2RlanNGdW5jdGlvbkluc3RhbmNlXG59XG5cbmludGVyZmFjZSBOb2RlanNGdW5jdGlvbkluc3RhbmNlIHtcbiAgbm9kZTogeyBhZGRyOiBzdHJpbmcgfVxufVxuXG5pbnRlcmZhY2UgTm9kZWpzRnVuY3Rpb25Qcm9wcyB7XG4gIGVudHJ5Pzogc3RyaW5nXG4gIGhhbmRsZXI/OiBzdHJpbmdcbiAgY29kZT86IHVua25vd24gLy8gbGFtYmRhLkNvZGUgLSBpZiBwcm92aWRlZCwgYnVuZGxpbmcgaXMgc2tpcHBlZFxufVxuXG4vLyBNb2R1bGUgdHlwZSBmb3IgdGhlIGxhbWJkYSBleHBvcnRzXG5pbnRlcmZhY2UgTGFtYmRhTW9kdWxlIHtcbiAgRG9ja2VySW1hZ2VGdW5jdGlvbjogRG9ja2VySW1hZ2VGdW5jdGlvbkNvbnN0cnVjdG9yICYge1xuICAgIF9fbGl2ZUxhbWJkYVBhdGNoZWQ/OiBib29sZWFuXG4gIH1cbiAgRG9ja2VySW1hZ2VDb2RlOiBEb2NrZXJJbWFnZUNvZGVTdGF0aWMgJiB7XG4gICAgX19saXZlTGFtYmRhUGF0Y2hlZD86IGJvb2xlYW5cbiAgfVxufVxuXG4vLyBEb2NrZXJJbWFnZUZ1bmN0aW9uIGNvbnN0cnVjdG9yIHR5cGVcbmludGVyZmFjZSBEb2NrZXJJbWFnZUZ1bmN0aW9uQ29uc3RydWN0b3Ige1xuICBuZXcgKFxuICAgIHNjb3BlOiB1bmtub3duLFxuICAgIGlkOiBzdHJpbmcsXG4gICAgcHJvcHM6IERvY2tlckltYWdlRnVuY3Rpb25Qcm9wcyxcbiAgKTogRG9ja2VySW1hZ2VGdW5jdGlvbkluc3RhbmNlXG4gIHByb3RvdHlwZTogRG9ja2VySW1hZ2VGdW5jdGlvbkluc3RhbmNlXG59XG5cbmludGVyZmFjZSBEb2NrZXJJbWFnZUZ1bmN0aW9uSW5zdGFuY2Uge1xuICBub2RlOiB7IGFkZHI6IHN0cmluZyB9XG59XG5cbmludGVyZmFjZSBEb2NrZXJJbWFnZUZ1bmN0aW9uUHJvcHMge1xuICBjb2RlOiBEb2NrZXJJbWFnZUNvZGVJbnN0YW5jZVxuICBba2V5OiBzdHJpbmddOiB1bmtub3duXG59XG5cbi8vIERvY2tlckltYWdlQ29kZSBzdGF0aWMgdHlwZVxuaW50ZXJmYWNlIERvY2tlckltYWdlQ29kZVN0YXRpYyB7XG4gIGZyb21JbWFnZUFzc2V0KFxuICAgIGRpcmVjdG9yeTogc3RyaW5nLFxuICAgIHByb3BzPzogRG9ja2VySW1hZ2VBc3NldFByb3BzLFxuICApOiBEb2NrZXJJbWFnZUNvZGVJbnN0YW5jZVxufVxuXG5pbnRlcmZhY2UgRG9ja2VySW1hZ2VDb2RlSW5zdGFuY2Uge1xuICAvLyBNYXJrZXIgdG8gaWRlbnRpZnkgZG9ja2VyIGltYWdlIGNvZGUgaW5zdGFuY2VzXG4gIF9faXNEb2NrZXJJbWFnZUNvZGU/OiBib29sZWFuXG59XG5cbmludGVyZmFjZSBEb2NrZXJJbWFnZUFzc2V0UHJvcHMge1xuICBmaWxlPzogc3RyaW5nXG4gIGNtZD86IHN0cmluZ1tdXG4gIFtrZXk6IHN0cmluZ106IHVua25vd25cbn1cblxuLy8gQ2FjaGUgdGhlIGxhbWJkYSBtb2R1bGUgZm9yIGNyZWF0aW5nIGR1bW15IGNvZGVcbmxldCBjYWNoZWRMYW1iZGFNb2R1bGU6IExhbWJkYU1vZHVsZSB8IG51bGwgPSBudWxsXG5cbi8qKlxuICogSW5zdGFsbCBob29rcyBiYXNlZCBvbiBydW50aW1lIGVudmlyb25tZW50LlxuICpcbiAqIEJ1biBub3RlczpcbiAqIC0gQnVuIGNyZWF0ZXMgYSAqc25hcHNob3QqIG9mIENvbW1vbkpTIG5hbWVkIGV4cG9ydHMgd2hlbiBpbXBvcnRpbmcgZnJvbSBFU00uXG4gKiAgIFRoaXMgbWVhbnMgdGhhdCBtdXRhdGluZy9yZXBsYWNpbmcgYG1vZHVsZS5leHBvcnRzLkZvb2AgQUZURVIgdGhlIEVTTSBpbXBvcnRcbiAqICAgd2FzIGxpbmtlZCB3aWxsIG5vdCBhZmZlY3QgYGltcG9ydCB7IEZvbyB9IGZyb20gXCIuLi5cImAgaW4gdGhlIGN1cnJlbnQgcHJvY2Vzcy5cbiAqIC0gVGhlcmVmb3JlLCBCdW4gcGF0Y2hpbmcgb25seSB3b3JrcyByZWxpYWJseSB3aGVuIHRoaXMgYm9vdHN0cmFwIHJ1bnMgYmVmb3JlXG4gKiAgIHRoZSBhcHAgZW50cnkgcG9pbnQgaXMgbG9hZGVkLCBlLmcuIHZpYSBgYnVuIC0tcHJlbG9hZCBjZGstbG9jYWwtbGFtYmRhL2Jvb3RzdHJhcGAuXG4gKlxuICogTm9kZS5qczpcbiAqIC0gV2UgY2FuIHBhdGNoIE1vZHVsZS5fbG9hZCB0byBpbnRlcmNlcHQgbW9kdWxlIGxvYWRpbmcuXG4gKi9cbmlmIChpc0J1bikge1xuICBjb25zdCBpc0xpdmVNb2RlID0gcHJvY2Vzcy5lbnYuQ0RLX0xJVkUgPT09IFwidHJ1ZVwiXG5cbiAgLy8gQmVzdC1lZmZvcnQgcGF0Y2hpbmcgZm9yIEJ1bi4gVGhpcyBpcyBvbmx5IGd1YXJhbnRlZWQgdG8gd29yayB3aGVuIHRoaXMgZmlsZVxuICAvLyBpcyBwcmVsb2FkZWQgKHNlZSBub3RlIGFib3ZlKS4gRXZlbiB0aGVuLCB3ZSBrZWVwIHRoaXMgbG9naWMgbGlnaHR3ZWlnaHQuXG4gIGlmIChpc0xpdmVNb2RlKSB7XG4gICAgY29uc3QgaGFzUHJlbG9hZEZsYWcgPSBwcm9jZXNzLmV4ZWNBcmd2LmluY2x1ZGVzKFwiLS1wcmVsb2FkXCIpXG5cbiAgICBpZiAoIWhhc1ByZWxvYWRGbGFnKSB7XG4gICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgIFwiW0xpdmVMYW1iZGFdIFdhcm5pbmc6IFJ1bm5pbmcgaW4gQnVuIHdpdGhvdXQgLS1wcmVsb2FkLiBBdXRvbWF0aWMgaGFuZGxlci9kb2NrZXIgZGV0ZWN0aW9uIGlzIGxpa2VseSBkaXNhYmxlZC5cIixcbiAgICAgIClcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgXCJbTGl2ZUxhbWJkYV0gRml4OiBydW4gQnVuIHdpdGggYC0tcHJlbG9hZCBjZGstbG9jYWwtbGFtYmRhL2Jvb3RzdHJhcGAuXCIsXG4gICAgICApXG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIC8vIFBhdGNoIGF3cy1sYW1iZGEgZmlyc3Qgc28gTm9kZWpzRnVuY3Rpb24gY2FuIGNyZWF0ZSBkdW1teSBDb2RlLmZyb21JbmxpbmVcbiAgICAgIC8vIHdoZW4gQ0RLX0xJVkU9dHJ1ZSAoc2tpcHMgYnVuZGxpbmcpLlxuICAgICAgY29uc3QgbGFtYmRhTW9kdWxlID0gcmVxdWlyZUZyb21Qcm9qZWN0KFxuICAgICAgICBcImF3cy1jZGstbGliL2F3cy1sYW1iZGFcIixcbiAgICAgICkgYXMgTGFtYmRhTW9kdWxlXG4gICAgICBjYWNoZWRMYW1iZGFNb2R1bGUgPSBsYW1iZGFNb2R1bGVcbiAgICAgIHBhdGNoRG9ja2VySW1hZ2VGdW5jdGlvbihsYW1iZGFNb2R1bGUpXG5cbiAgICAgIGNvbnN0IG5vZGVqc01vZHVsZSA9IHJlcXVpcmVGcm9tUHJvamVjdChcbiAgICAgICAgXCJhd3MtY2RrLWxpYi9hd3MtbGFtYmRhLW5vZGVqc1wiLFxuICAgICAgKSBhcyBMYW1iZGFOb2RlanNNb2R1bGVcbiAgICAgIHBhdGNoTm9kZWpzRnVuY3Rpb24obm9kZWpzTW9kdWxlKVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICBcIltMaXZlTGFtYmRhXSBXYXJuaW5nOiBGYWlsZWQgdG8gaW5zdGFsbCBCdW4gcGF0Y2hlczpcIixcbiAgICAgICAgKGVyciBhcyBFcnJvcikubWVzc2FnZSxcbiAgICAgIClcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgXCJbTGl2ZUxhbWJkYV0gQXV0b21hdGljIGhhbmRsZXIvZG9ja2VyIGRldGVjdGlvbiBpcyByZXF1aXJlZDsgZW5zdXJlIGJvb3RzdHJhcCBpcyBwcmVsb2FkZWQuXCIsXG4gICAgICApXG4gICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgIFwiW0xpdmVMYW1iZGFdIFNlZTogaHR0cHM6Ly9naXRodWIuY29tL2JlcmVuZGRlYm9lci9jZGstbG9jYWwtbGFtYmRhI2J1bi1zdXBwb3J0XCIsXG4gICAgICApXG4gICAgfVxuICB9XG59IGVsc2Uge1xuICAvLyBOb2RlLmpzOiB1c2UgTW9kdWxlLl9sb2FkIGhvb2sgdG8gaW50ZXJjZXB0IG1vZHVsZSBsb2FkaW5nXG4gIGNvbnN0IE1vZHVsZSA9IHJlcXVpcmVGcm9tUGFja2FnZShcIm5vZGU6bW9kdWxlXCIpXG4gIGNvbnN0IG9yaWdpbmFsTG9hZDogKFxuICAgIHJlcXVlc3Q6IHN0cmluZyxcbiAgICBwYXJlbnQ6IE5vZGVNb2R1bGUgfCB1bmRlZmluZWQsXG4gICAgaXNNYWluOiBib29sZWFuLFxuICApID0+IHVua25vd24gPSBNb2R1bGUuX2xvYWRcblxuICBNb2R1bGUuX2xvYWQgPSBmdW5jdGlvbiAoXG4gICAgcmVxdWVzdDogc3RyaW5nLFxuICAgIHBhcmVudDogTm9kZU1vZHVsZSB8IHVuZGVmaW5lZCxcbiAgICBpc01haW46IGJvb2xlYW4sXG4gICk6IHVua25vd24ge1xuICAgIC8vIENhbGwgb3JpZ2luYWwgbG9hZCAtIGxldCBlcnJvcnMgcHJvcGFnYXRlIG5hdHVyYWxseVxuICAgIGNvbnN0IHJlc3VsdCA9IG9yaWdpbmFsTG9hZC5jYWxsKHRoaXMsIHJlcXVlc3QsIHBhcmVudCwgaXNNYWluKVxuXG4gICAgLy8gQ2hlY2sgaWYgdGhpcyBpcyB0aGUgbGFtYmRhLW5vZGVqcyBtb2R1bGVcbiAgICBpZiAoaXNMYW1iZGFOb2RlanNNb2R1bGUocmVxdWVzdCkpIHtcbiAgICAgIHBhdGNoTm9kZWpzRnVuY3Rpb24ocmVzdWx0IGFzIExhbWJkYU5vZGVqc01vZHVsZSB8IG51bGwpXG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgaWYgdGhpcyBpcyB0aGUgbGFtYmRhIG1vZHVsZSAoZm9yIERvY2tlckltYWdlRnVuY3Rpb24gYW5kIENvZGUuZnJvbUlubGluZSlcbiAgICBpZiAoaXNMYW1iZGFNb2R1bGUocmVxdWVzdCkpIHtcbiAgICAgIC8vIENhY2hlIHRoZSBsYW1iZGEgbW9kdWxlIHNvIHdlIGNhbiB1c2UgQ29kZS5mcm9tSW5saW5lIGluIE5vZGVqc0Z1bmN0aW9uIHBhdGNoXG4gICAgICBjYWNoZWRMYW1iZGFNb2R1bGUgPSByZXN1bHQgYXMgTGFtYmRhTW9kdWxlIHwgbnVsbFxuICAgICAgcGF0Y2hEb2NrZXJJbWFnZUZ1bmN0aW9uKHJlc3VsdCBhcyBMYW1iZGFNb2R1bGUgfCBudWxsKVxuICAgIH1cblxuICAgIHJldHVybiByZXN1bHRcbiAgfVxufVxuXG4vKipcbiAqIENyZWF0ZSBhIGR1bW15IGlubGluZSBjb2RlIHRoYXQgZG9lcyBub3RoaW5nLlxuICogVXNlZCB0byBza2lwIGJ1bmRsaW5nIHdoZW4gQ0RLX0xJVkU9dHJ1ZS5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlRHVtbXlDb2RlKGxhbWJkYU1vZHVsZTogTGFtYmRhTW9kdWxlKTogdW5rbm93biB7XG4gIC8vIEFjY2VzcyBsYW1iZGEuQ29kZS5mcm9tSW5saW5lIHRvIGNyZWF0ZSBhIG5vLW9wIGNvZGVcbiAgLy8gVGhpcyBhdm9pZHMgYnVuZGxpbmcgZW50aXJlbHkgc2luY2Ugd2UgcHJvdmlkZSBwcmUtYnVpbHQgY29kZVxuICBjb25zdCBDb2RlID0gKFxuICAgIGxhbWJkYU1vZHVsZSBhcyB1bmtub3duIGFzIHtcbiAgICAgIENvZGU/OiB7IGZyb21JbmxpbmU/OiAoY29kZTogc3RyaW5nKSA9PiB1bmtub3duIH1cbiAgICB9XG4gICkuQ29kZVxuICBpZiAoQ29kZT8uZnJvbUlubGluZSkge1xuICAgIHJldHVybiBDb2RlLmZyb21JbmxpbmUoXCIvLyBQbGFjZWhvbGRlciAtIHJlcGxhY2VkIGJ5IExpdmVMYW1iZGFBc3BlY3RcIilcbiAgfVxuICByZXR1cm4gdW5kZWZpbmVkXG59XG5cbi8qKlxuICogUGF0Y2ggTm9kZWpzRnVuY3Rpb24gdG8gY2FwdHVyZSBlbnRyeSBhbmQgaGFuZGxlciBwcm9wc1xuICovXG5mdW5jdGlvbiBwYXRjaE5vZGVqc0Z1bmN0aW9uKG1vZHVsZTogTGFtYmRhTm9kZWpzTW9kdWxlIHwgbnVsbCk6IHZvaWQge1xuICAvLyBJZiBhbHJlYWR5IHBhdGNoZWQsIHNraXBcbiAgaWYgKG1vZHVsZT8uTm9kZWpzRnVuY3Rpb24/Ll9fbGl2ZUxhbWJkYVBhdGNoZWQpIHtcbiAgICByZXR1cm5cbiAgfVxuXG4gIC8vIENoZWNrIGlmIHdlIGNhbiBwYXRjaFxuICBpZiAobW9kdWxlPy5Ob2RlanNGdW5jdGlvbikge1xuICAgIGNvbnN0IE9yaWdpbmFsTm9kZWpzRnVuY3Rpb24gPSBtb2R1bGUuTm9kZWpzRnVuY3Rpb25cbiAgICBjb25zdCBpc0xpdmVNb2RlID0gcHJvY2Vzcy5lbnYuQ0RLX0xJVkUgPT09IFwidHJ1ZVwiXG5cbiAgICAvLyBDcmVhdGUgd3JhcHBlciBjbGFzcyB0aGF0IGNhcHR1cmVzIGVudHJ5L2hhbmRsZXIgcHJvcHNcbiAgICBjbGFzcyBOb2RlanNGdW5jdGlvbldpdGhDYXB0dXJlIGV4dGVuZHMgT3JpZ2luYWxOb2RlanNGdW5jdGlvbiB7XG4gICAgICBjb25zdHJ1Y3RvcihzY29wZTogdW5rbm93biwgaWQ6IHN0cmluZywgcHJvcHM6IE5vZGVqc0Z1bmN0aW9uUHJvcHMgPSB7fSkge1xuICAgICAgICAvLyBJbiBsaXZlIG1vZGUsIHByb3ZpZGUgZHVtbXkgY29kZSB0byBza2lwIGJ1bmRsaW5nIGVudGlyZWx5XG4gICAgICAgIC8vIFRoZSBhc3BlY3Qgd2lsbCByZXBsYWNlIHRoaXMgd2l0aCB0aGUgYnJpZGdlIGNvZGUgZnJvbSBTM1xuICAgICAgICBsZXQgbW9kaWZpZWRQcm9wcyA9IHByb3BzXG4gICAgICAgIGlmIChpc0xpdmVNb2RlICYmICFwcm9wcy5jb2RlICYmIGNhY2hlZExhbWJkYU1vZHVsZSkge1xuICAgICAgICAgIGNvbnN0IGR1bW15Q29kZSA9IGNyZWF0ZUR1bW15Q29kZShjYWNoZWRMYW1iZGFNb2R1bGUpXG4gICAgICAgICAgaWYgKGR1bW15Q29kZSkge1xuICAgICAgICAgICAgbW9kaWZpZWRQcm9wcyA9IHsgLi4ucHJvcHMsIGNvZGU6IGR1bW15Q29kZSB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgc3VwZXIoc2NvcGUsIGlkLCBtb2RpZmllZFByb3BzKVxuXG4gICAgICAgIC8vIFN0b3JlIHRoZSBlbnRyeSBwYXRoIG9uIHRoZSBpbnN0YW5jZSAodmFsaWRhdGUgaXQncyBhIG5vbi1lbXB0eSBzdHJpbmcpXG4gICAgICAgIGlmICh0eXBlb2YgcHJvcHMuZW50cnkgPT09IFwic3RyaW5nXCIgJiYgcHJvcHMuZW50cnkudHJpbSgpLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICA7KHRoaXMgYXMgdW5rbm93biBhcyBSZWNvcmQ8c3ltYm9sLCBzdHJpbmc+KVtFTlRSWV9TWU1CT0xdID1cbiAgICAgICAgICAgIHByb3BzLmVudHJ5XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTdG9yZSB0aGUgaGFuZGxlciBuYW1lICh2YWxpZGF0ZSBhbmQgZGVmYXVsdCB0byAnaGFuZGxlcicpXG4gICAgICAgIGNvbnN0IGhhbmRsZXIgPVxuICAgICAgICAgIHR5cGVvZiBwcm9wcy5oYW5kbGVyID09PSBcInN0cmluZ1wiICYmIHByb3BzLmhhbmRsZXIudHJpbSgpLmxlbmd0aCA+IDBcbiAgICAgICAgICAgID8gcHJvcHMuaGFuZGxlclxuICAgICAgICAgICAgOiBcImhhbmRsZXJcIlxuICAgICAgICA7KHRoaXMgYXMgdW5rbm93biBhcyBSZWNvcmQ8c3ltYm9sLCBzdHJpbmc+KVtIQU5ETEVSX1NZTUJPTF0gPSBoYW5kbGVyXG4gICAgICB9XG5cbiAgICAgIHN0YXRpYyBfX2xpdmVMYW1iZGFQYXRjaGVkID0gdHJ1ZVxuICAgIH1cblxuICAgIC8vIFRyeSB0byByZXBsYWNlIC0gZmFpbCBpZiB3ZSBjYW4ndFxuICAgIHRyeSB7XG4gICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkobW9kdWxlLCBcIk5vZGVqc0Z1bmN0aW9uXCIsIHtcbiAgICAgICAgdmFsdWU6IE5vZGVqc0Z1bmN0aW9uV2l0aENhcHR1cmUsXG4gICAgICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICB9KVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS5lcnJvcihcbiAgICAgICAgXCJbTGl2ZUxhbWJkYV0gRkFUQUw6IENhbm5vdCBwYXRjaCBOb2RlanNGdW5jdGlvbiAtIG1vZHVsZSBpcyBmcm96ZW4gb3Igc2VhbGVkLlwiLFxuICAgICAgKVxuICAgICAgY29uc29sZS5lcnJvcihcbiAgICAgICAgXCJbTGl2ZUxhbWJkYV0gVGhpcyBjYW4gaGFwcGVuIHdpdGggY2VydGFpbiBidW5kbGVycyBvciBOb2RlLmpzIGNvbmZpZ3VyYXRpb25zLlwiLFxuICAgICAgKVxuICAgICAgY29uc29sZS5lcnJvcihcIltMaXZlTGFtYmRhXSBFcnJvcjpcIiwgKGVyciBhcyBFcnJvcikubWVzc2FnZSlcbiAgICAgIHByb2Nlc3MuZXhpdCgxKVxuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIFBhdGNoIERvY2tlckltYWdlRnVuY3Rpb24gYW5kIERvY2tlckltYWdlQ29kZSB0byBjYXB0dXJlIGRvY2tlciBjb250ZXh0XG4gKi9cbmZ1bmN0aW9uIHBhdGNoRG9ja2VySW1hZ2VGdW5jdGlvbihtb2R1bGU6IExhbWJkYU1vZHVsZSB8IG51bGwpOiB2b2lkIHtcbiAgaWYgKCFtb2R1bGUpIHJldHVyblxuXG4gIC8vIEZpcnN0LCBwYXRjaCBEb2NrZXJJbWFnZUNvZGUuZnJvbUltYWdlQXNzZXQgdG8gY2FwdHVyZSB0aGUgZGlyZWN0b3J5IHBhdGhcbiAgaWYgKG1vZHVsZS5Eb2NrZXJJbWFnZUNvZGUgJiYgIW1vZHVsZS5Eb2NrZXJJbWFnZUNvZGUuX19saXZlTGFtYmRhUGF0Y2hlZCkge1xuICAgIGNvbnN0IE9yaWdpbmFsRG9ja2VySW1hZ2VDb2RlID0gbW9kdWxlLkRvY2tlckltYWdlQ29kZVxuICAgIGNvbnN0IG9yaWdpbmFsRnJvbUltYWdlQXNzZXQgPSBPcmlnaW5hbERvY2tlckltYWdlQ29kZS5mcm9tSW1hZ2VBc3NldFxuXG4gICAgLy8gV3JhcCBmcm9tSW1hZ2VBc3NldCB0byBjYXB0dXJlIHRoZSBkaXJlY3RvcnlcbiAgICBjb25zdCBwYXRjaGVkRnJvbUltYWdlQXNzZXQgPSAoXG4gICAgICBkaXJlY3Rvcnk6IHN0cmluZyxcbiAgICAgIHByb3BzPzogRG9ja2VySW1hZ2VBc3NldFByb3BzLFxuICAgICk6IERvY2tlckltYWdlQ29kZUluc3RhbmNlID0+IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IG9yaWdpbmFsRnJvbUltYWdlQXNzZXQuY2FsbChcbiAgICAgICAgT3JpZ2luYWxEb2NrZXJJbWFnZUNvZGUsXG4gICAgICAgIGRpcmVjdG9yeSxcbiAgICAgICAgcHJvcHMsXG4gICAgICApXG5cbiAgICAgIC8vIFN0b3JlIHRoZSBkaXJlY3RvcnkgcGF0aCBpbiB0aGUgV2Vha01hcCwga2V5ZWQgYnkgdGhlIHJlc3VsdCBpbnN0YW5jZVxuICAgICAgZG9ja2VySW1hZ2VDb2RlQ29udGV4dE1hcC5zZXQocmVzdWx0IGFzIG9iamVjdCwgZGlyZWN0b3J5KVxuXG4gICAgICByZXR1cm4gcmVzdWx0XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShPcmlnaW5hbERvY2tlckltYWdlQ29kZSwgXCJmcm9tSW1hZ2VBc3NldFwiLCB7XG4gICAgICAgIHZhbHVlOiBwYXRjaGVkRnJvbUltYWdlQXNzZXQsXG4gICAgICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICB9KVxuICAgICAgOyhcbiAgICAgICAgT3JpZ2luYWxEb2NrZXJJbWFnZUNvZGUgYXMgRG9ja2VySW1hZ2VDb2RlU3RhdGljICYge1xuICAgICAgICAgIF9fbGl2ZUxhbWJkYVBhdGNoZWQ/OiBib29sZWFuXG4gICAgICAgIH1cbiAgICAgICkuX19saXZlTGFtYmRhUGF0Y2hlZCA9IHRydWVcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgXCJbTGl2ZUxhbWJkYV0gQ291bGQgbm90IHBhdGNoIERvY2tlckltYWdlQ29kZS5mcm9tSW1hZ2VBc3NldDpcIixcbiAgICAgICAgKGVyciBhcyBFcnJvcikubWVzc2FnZSxcbiAgICAgIClcbiAgICB9XG4gIH1cblxuICAvLyBUaGVuLCBwYXRjaCBEb2NrZXJJbWFnZUZ1bmN0aW9uIHRvIHJlYWQgZnJvbSB0aGUgV2Vha01hcFxuICBpZiAoXG4gICAgbW9kdWxlLkRvY2tlckltYWdlRnVuY3Rpb24gJiZcbiAgICAhbW9kdWxlLkRvY2tlckltYWdlRnVuY3Rpb24uX19saXZlTGFtYmRhUGF0Y2hlZFxuICApIHtcbiAgICBjb25zdCBPcmlnaW5hbERvY2tlckltYWdlRnVuY3Rpb24gPSBtb2R1bGUuRG9ja2VySW1hZ2VGdW5jdGlvblxuXG4gICAgLy8gQ3JlYXRlIHdyYXBwZXIgY2xhc3MgdGhhdCBjYXB0dXJlcyBkb2NrZXIgY29udGV4dFxuICAgIGNsYXNzIERvY2tlckltYWdlRnVuY3Rpb25XaXRoQ2FwdHVyZSBleHRlbmRzIE9yaWdpbmFsRG9ja2VySW1hZ2VGdW5jdGlvbiB7XG4gICAgICBjb25zdHJ1Y3RvcihzY29wZTogdW5rbm93biwgaWQ6IHN0cmluZywgcHJvcHM6IERvY2tlckltYWdlRnVuY3Rpb25Qcm9wcykge1xuICAgICAgICBzdXBlcihzY29wZSwgaWQsIHByb3BzKVxuXG4gICAgICAgIC8vIExvb2sgdXAgdGhlIGRvY2tlciBjb250ZXh0IGZyb20gdGhlIFdlYWtNYXBcbiAgICAgICAgaWYgKHByb3BzLmNvZGUpIHtcbiAgICAgICAgICBjb25zdCBjb250ZXh0UGF0aCA9IGRvY2tlckltYWdlQ29kZUNvbnRleHRNYXAuZ2V0KFxuICAgICAgICAgICAgcHJvcHMuY29kZSBhcyBvYmplY3QsXG4gICAgICAgICAgKVxuICAgICAgICAgIGlmIChjb250ZXh0UGF0aCkge1xuICAgICAgICAgICAgOyh0aGlzIGFzIHVua25vd24gYXMgUmVjb3JkPHN5bWJvbCwgc3RyaW5nPilbXG4gICAgICAgICAgICAgIERPQ0tFUl9DT05URVhUX1NZTUJPTFxuICAgICAgICAgICAgXSA9IGNvbnRleHRQYXRoXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHN0YXRpYyBfX2xpdmVMYW1iZGFQYXRjaGVkID0gdHJ1ZVxuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkobW9kdWxlLCBcIkRvY2tlckltYWdlRnVuY3Rpb25cIiwge1xuICAgICAgICB2YWx1ZTogRG9ja2VySW1hZ2VGdW5jdGlvbldpdGhDYXB0dXJlLFxuICAgICAgICB3cml0YWJsZTogdHJ1ZSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgfSlcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgXCJbTGl2ZUxhbWJkYV0gQ291bGQgbm90IHBhdGNoIERvY2tlckltYWdlRnVuY3Rpb246XCIsXG4gICAgICAgIChlcnIgYXMgRXJyb3IpLm1lc3NhZ2UsXG4gICAgICApXG4gICAgfVxuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Functions to retrieve captured entry path and handler name from Lambda functions
|
|
3
|
+
* that were created with NodejsFunction.
|
|
4
|
+
*
|
|
5
|
+
* The live-lambda-bootstrap.ts file installs a hook that captures these values
|
|
6
|
+
* when NodejsFunction instances are created.
|
|
7
|
+
*/
|
|
8
|
+
import type * as lambda from "aws-cdk-lib/aws-lambda";
|
|
9
|
+
/**
|
|
10
|
+
* Get the entry path that was passed to NodejsFunction constructor.
|
|
11
|
+
* Returns undefined if the function was not created with NodejsFunction
|
|
12
|
+
* or if the hook was not installed.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getEntryPath(fn: lambda.Function): string | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Get the handler name that was passed to NodejsFunction constructor.
|
|
17
|
+
* Returns undefined if the function was not created with NodejsFunction
|
|
18
|
+
* or if the hook was not installed.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getHandlerName(fn: lambda.Function): string | undefined;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Functions to retrieve captured entry path and handler name from Lambda functions
|
|
3
|
+
* that were created with NodejsFunction.
|
|
4
|
+
*
|
|
5
|
+
* The live-lambda-bootstrap.ts file installs a hook that captures these values
|
|
6
|
+
* when NodejsFunction instances are created.
|
|
7
|
+
*/
|
|
8
|
+
// Symbols used by the bootstrap hook to store captured values
|
|
9
|
+
const ENTRY_SYMBOL = Symbol.for("live-lambda:entry");
|
|
10
|
+
const HANDLER_SYMBOL = Symbol.for("live-lambda:handler");
|
|
11
|
+
/**
|
|
12
|
+
* Get the entry path that was passed to NodejsFunction constructor.
|
|
13
|
+
* Returns undefined if the function was not created with NodejsFunction
|
|
14
|
+
* or if the hook was not installed.
|
|
15
|
+
*/
|
|
16
|
+
export function getEntryPath(fn) {
|
|
17
|
+
return fn[ENTRY_SYMBOL];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get the handler name that was passed to NodejsFunction constructor.
|
|
21
|
+
* Returns undefined if the function was not created with NodejsFunction
|
|
22
|
+
* or if the hook was not installed.
|
|
23
|
+
*/
|
|
24
|
+
export function getHandlerName(fn) {
|
|
25
|
+
return fn[HANDLER_SYMBOL];
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZWpzLWZ1bmN0aW9uLWhvb2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXNwZWN0L25vZGVqcy1mdW5jdGlvbi1ob29rLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUlILDhEQUE4RDtBQUM5RCxNQUFNLFlBQVksR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLG1CQUFtQixDQUFDLENBQUE7QUFDcEQsTUFBTSxjQUFjLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFBO0FBRXhEOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsWUFBWSxDQUFDLEVBQW1CO0lBQzlDLE9BQVEsRUFBb0QsQ0FBQyxZQUFZLENBQUMsQ0FBQTtBQUM1RSxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxjQUFjLENBQUMsRUFBbUI7SUFDaEQsT0FBUSxFQUFvRCxDQUFDLGNBQWMsQ0FBQyxDQUFBO0FBQzlFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEZ1bmN0aW9ucyB0byByZXRyaWV2ZSBjYXB0dXJlZCBlbnRyeSBwYXRoIGFuZCBoYW5kbGVyIG5hbWUgZnJvbSBMYW1iZGEgZnVuY3Rpb25zXG4gKiB0aGF0IHdlcmUgY3JlYXRlZCB3aXRoIE5vZGVqc0Z1bmN0aW9uLlxuICpcbiAqIFRoZSBsaXZlLWxhbWJkYS1ib290c3RyYXAudHMgZmlsZSBpbnN0YWxscyBhIGhvb2sgdGhhdCBjYXB0dXJlcyB0aGVzZSB2YWx1ZXNcbiAqIHdoZW4gTm9kZWpzRnVuY3Rpb24gaW5zdGFuY2VzIGFyZSBjcmVhdGVkLlxuICovXG5cbmltcG9ydCB0eXBlICogYXMgbGFtYmRhIGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtbGFtYmRhXCJcblxuLy8gU3ltYm9scyB1c2VkIGJ5IHRoZSBib290c3RyYXAgaG9vayB0byBzdG9yZSBjYXB0dXJlZCB2YWx1ZXNcbmNvbnN0IEVOVFJZX1NZTUJPTCA9IFN5bWJvbC5mb3IoXCJsaXZlLWxhbWJkYTplbnRyeVwiKVxuY29uc3QgSEFORExFUl9TWU1CT0wgPSBTeW1ib2wuZm9yKFwibGl2ZS1sYW1iZGE6aGFuZGxlclwiKVxuXG4vKipcbiAqIEdldCB0aGUgZW50cnkgcGF0aCB0aGF0IHdhcyBwYXNzZWQgdG8gTm9kZWpzRnVuY3Rpb24gY29uc3RydWN0b3IuXG4gKiBSZXR1cm5zIHVuZGVmaW5lZCBpZiB0aGUgZnVuY3Rpb24gd2FzIG5vdCBjcmVhdGVkIHdpdGggTm9kZWpzRnVuY3Rpb25cbiAqIG9yIGlmIHRoZSBob29rIHdhcyBub3QgaW5zdGFsbGVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0RW50cnlQYXRoKGZuOiBsYW1iZGEuRnVuY3Rpb24pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICByZXR1cm4gKGZuIGFzIHVua25vd24gYXMgUmVjb3JkPHN5bWJvbCwgc3RyaW5nIHwgdW5kZWZpbmVkPilbRU5UUllfU1lNQk9MXVxufVxuXG4vKipcbiAqIEdldCB0aGUgaGFuZGxlciBuYW1lIHRoYXQgd2FzIHBhc3NlZCB0byBOb2RlanNGdW5jdGlvbiBjb25zdHJ1Y3Rvci5cbiAqIFJldHVybnMgdW5kZWZpbmVkIGlmIHRoZSBmdW5jdGlvbiB3YXMgbm90IGNyZWF0ZWQgd2l0aCBOb2RlanNGdW5jdGlvblxuICogb3IgaWYgdGhlIGhvb2sgd2FzIG5vdCBpbnN0YWxsZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRIYW5kbGVyTmFtZShmbjogbGFtYmRhLkZ1bmN0aW9uKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgcmV0dXJuIChmbiBhcyB1bmtub3duIGFzIFJlY29yZDxzeW1ib2wsIHN0cmluZyB8IHVuZGVmaW5lZD4pW0hBTkRMRVJfU1lNQk9MXVxufVxuIl19
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import * as cdk from "aws-cdk-lib";
|
|
2
|
+
import * as appsync from "aws-cdk-lib/aws-appsync";
|
|
3
|
+
import * as iam from "aws-cdk-lib/aws-iam";
|
|
4
|
+
import * as s3 from "aws-cdk-lib/aws-s3";
|
|
5
|
+
import type { Construct } from "constructs";
|
|
6
|
+
/**
|
|
7
|
+
* Properties for the LiveLambdaBootstrapStack
|
|
8
|
+
*/
|
|
9
|
+
export interface CdkLocalLambdaBootstrapStackProps extends cdk.StackProps {
|
|
10
|
+
/**
|
|
11
|
+
* Optional name for the AppSync Events API
|
|
12
|
+
* @default 'LiveLambdaEventsApi'
|
|
13
|
+
*/
|
|
14
|
+
apiName?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Bootstrap stack that creates the shared AppSync Events API infrastructure
|
|
18
|
+
* for live lambda debugging. This stack should be deployed once per account/region.
|
|
19
|
+
*/
|
|
20
|
+
export declare class CdkLocalLambdaBootstrapStack extends cdk.Stack {
|
|
21
|
+
/**
|
|
22
|
+
* The AppSync Events API for WebSocket communication
|
|
23
|
+
*/
|
|
24
|
+
readonly api: appsync.CfnApi;
|
|
25
|
+
/**
|
|
26
|
+
* The channel namespace for live debugging channels
|
|
27
|
+
*/
|
|
28
|
+
readonly channelNamespace: appsync.CfnChannelNamespace;
|
|
29
|
+
/**
|
|
30
|
+
* The HTTP endpoint for publishing events
|
|
31
|
+
*/
|
|
32
|
+
readonly httpEndpoint: string;
|
|
33
|
+
/**
|
|
34
|
+
* The WebSocket endpoint for real-time subscriptions
|
|
35
|
+
*/
|
|
36
|
+
readonly realtimeEndpoint: string;
|
|
37
|
+
/**
|
|
38
|
+
* IAM role for publishing to the Events API
|
|
39
|
+
*/
|
|
40
|
+
readonly publishRole: iam.Role;
|
|
41
|
+
/**
|
|
42
|
+
* S3 bucket for storing the bridge Lambda code
|
|
43
|
+
*/
|
|
44
|
+
readonly bridgeBucket: s3.Bucket;
|
|
45
|
+
constructor(scope: Construct, id: string, props?: CdkLocalLambdaBootstrapStackProps);
|
|
46
|
+
/**
|
|
47
|
+
* Grant a Lambda function permission to publish and subscribe to the Events API
|
|
48
|
+
*/
|
|
49
|
+
grantPublishSubscribe(grantee: iam.IGrantable): iam.Grant;
|
|
50
|
+
/**
|
|
51
|
+
* Build the bridge handler and upload to S3 using a custom resource.
|
|
52
|
+
* The bridge code has AppSync endpoints baked in at deploy time.
|
|
53
|
+
*/
|
|
54
|
+
private buildAndUploadBridge;
|
|
55
|
+
/**
|
|
56
|
+
* Build Docker bridge images for ARM64 and x86_64 architectures.
|
|
57
|
+
* Uses CDK Docker image assets to build and push to ECR.
|
|
58
|
+
*/
|
|
59
|
+
private buildDockerBridgeImages;
|
|
60
|
+
}
|