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,414 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docker container management utilities.
|
|
3
|
+
*
|
|
4
|
+
* Handles running Docker containers with the Lambda Runtime API
|
|
5
|
+
* environment configured. Uses @effect/platform Command for
|
|
6
|
+
* proper Effect-based process management.
|
|
7
|
+
*/
|
|
8
|
+
import * as os from "node:os";
|
|
9
|
+
import { CommandExecutor, Command as PlatformCommand } from "@effect/platform";
|
|
10
|
+
import { Context, Effect, Layer, Stream } from "effect";
|
|
11
|
+
/**
|
|
12
|
+
* Detect the Docker runtime environment.
|
|
13
|
+
*/
|
|
14
|
+
export const detectDockerRuntime = () => Effect.try({
|
|
15
|
+
try: () => {
|
|
16
|
+
const platform = os.platform();
|
|
17
|
+
const isLinux = platform === "linux";
|
|
18
|
+
const isWsl = isLinux &&
|
|
19
|
+
(process.env.WSL_DISTRO_NAME !== undefined ||
|
|
20
|
+
process.env.WSL_INTEROP !== undefined);
|
|
21
|
+
// On Mac/Windows Docker Desktop, use host.docker.internal
|
|
22
|
+
// On Linux, we need to use the host's IP or --network=host
|
|
23
|
+
const isDockerDesktop = !isLinux || isWsl;
|
|
24
|
+
const hostAddress = isDockerDesktop
|
|
25
|
+
? "host.docker.internal"
|
|
26
|
+
: "172.17.0.1"; // Default Docker bridge gateway
|
|
27
|
+
return {
|
|
28
|
+
dockerPath: "docker",
|
|
29
|
+
isLinux,
|
|
30
|
+
isWsl,
|
|
31
|
+
isDockerDesktop,
|
|
32
|
+
hostAddress,
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
catch: (error) => new Error(`Failed to detect Docker runtime: ${String(error)}`),
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* Build Docker run arguments from config.
|
|
39
|
+
*/
|
|
40
|
+
const buildDockerRunArgs = (config, runtime) => {
|
|
41
|
+
const args = ["run", "--rm"];
|
|
42
|
+
// Container name (add timestamp for uniqueness)
|
|
43
|
+
if (config.containerName) {
|
|
44
|
+
args.push("--name", `${config.containerName}-${Date.now()}`);
|
|
45
|
+
}
|
|
46
|
+
// Platform - allow running ARM64 images on x86_64 via QEMU
|
|
47
|
+
if (config.platform) {
|
|
48
|
+
args.push("--platform", config.platform);
|
|
49
|
+
}
|
|
50
|
+
// Memory limit
|
|
51
|
+
args.push("--memory", `${config.memoryMB}m`);
|
|
52
|
+
// Network mode
|
|
53
|
+
if (config.networkMode === "host") {
|
|
54
|
+
args.push("--network", "host");
|
|
55
|
+
}
|
|
56
|
+
else if (config.networkMode !== "none") {
|
|
57
|
+
// For bridge mode, add host mapping for non-Linux
|
|
58
|
+
if (runtime.isDockerDesktop) {
|
|
59
|
+
// host.docker.internal is automatically available on Docker Desktop
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// On Linux, add explicit host mapping and helper address
|
|
63
|
+
args.push("--add-host", `host.docker.internal:${runtime.hostAddress}`);
|
|
64
|
+
args.push("--add-host", `host.containers.internal:${runtime.hostAddress}`);
|
|
65
|
+
args.push("--add-host", `runtime.api:${runtime.hostAddress}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Extra hosts
|
|
69
|
+
if (config.extraHosts) {
|
|
70
|
+
for (const host of config.extraHosts) {
|
|
71
|
+
args.push("--add-host", host);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Environment variables
|
|
75
|
+
for (const [key, value] of Object.entries(config.environment)) {
|
|
76
|
+
args.push("-e", `${key}=${value}`);
|
|
77
|
+
}
|
|
78
|
+
// Working directory
|
|
79
|
+
if (config.workdir) {
|
|
80
|
+
args.push("-w", config.workdir);
|
|
81
|
+
}
|
|
82
|
+
// Additional arguments
|
|
83
|
+
if (config.additionalArgs) {
|
|
84
|
+
args.push(...config.additionalArgs);
|
|
85
|
+
}
|
|
86
|
+
// Entrypoint override
|
|
87
|
+
if (config.entrypoint && config.entrypoint.length > 0) {
|
|
88
|
+
args.push("--entrypoint", config.entrypoint[0]);
|
|
89
|
+
}
|
|
90
|
+
// Image
|
|
91
|
+
args.push(config.imageUri);
|
|
92
|
+
// Entrypoint additional args (after image)
|
|
93
|
+
if (config.entrypoint && config.entrypoint.length > 1) {
|
|
94
|
+
args.push(...config.entrypoint.slice(1));
|
|
95
|
+
}
|
|
96
|
+
// Command override (after image and entrypoint args)
|
|
97
|
+
if (config.command) {
|
|
98
|
+
args.push(...config.command);
|
|
99
|
+
}
|
|
100
|
+
return args;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Docker Service tag for dependency injection.
|
|
104
|
+
*/
|
|
105
|
+
export class Docker extends Context.Tag("Docker")() {
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Create the live Docker service implementation.
|
|
109
|
+
*/
|
|
110
|
+
const makeDockerService = Effect.gen(function* () {
|
|
111
|
+
const runtime = yield* detectDockerRuntime();
|
|
112
|
+
const getRuntimeInfo = () => Effect.succeed(runtime);
|
|
113
|
+
const run = (config) => Effect.gen(function* () {
|
|
114
|
+
const args = buildDockerRunArgs(config, runtime);
|
|
115
|
+
yield* Effect.logDebug(`Running: docker ${args.join(" ")}`);
|
|
116
|
+
const command = PlatformCommand.make(runtime.dockerPath, ...args);
|
|
117
|
+
const stdout = [];
|
|
118
|
+
const stderr = [];
|
|
119
|
+
// Run the command and collect output
|
|
120
|
+
const proc = yield* PlatformCommand.start(command);
|
|
121
|
+
// Lambda RIC error/output patterns that are expected during poll timeout
|
|
122
|
+
// These are suppressed from output to avoid scary error messages
|
|
123
|
+
const isExpectedRicOutput = (line) => line.includes("LAMBDA_RUNTIME Failed to get next invocation") ||
|
|
124
|
+
line.includes("Failed to get next invocation, error 503") ||
|
|
125
|
+
// Filter out the Node.js stack trace from Lambda RIC exit
|
|
126
|
+
line.includes("triggerUncaughtException") ||
|
|
127
|
+
line.includes("[Error: Failed to get next invocation") ||
|
|
128
|
+
// "Node.js v" version line after error
|
|
129
|
+
line.startsWith("Node.js v") ||
|
|
130
|
+
line.includes("node:internal/process/promises") ||
|
|
131
|
+
// Stack trace caret line (just whitespace and ^)
|
|
132
|
+
/^\s*\^?\s*$/.test(line);
|
|
133
|
+
// Pattern to parse Lambda log format: TIMESTAMP\tREQUEST_ID\tLEVEL\tMESSAGE
|
|
134
|
+
// Lambda uses tabs between fields. Captures: [1] = request ID, [2] = level + message
|
|
135
|
+
const lambdaLogPattern = /^(\d{4}-\d{2}-\d{2}T[\d:.]+Z)[\t\s]+([0-9a-f-]{36})[\t\s]+(.*)$/i;
|
|
136
|
+
// Helper to format log line with invocation prefix
|
|
137
|
+
const formatLine = (rawLine) => {
|
|
138
|
+
// Strip carriage returns that can cause terminal corruption
|
|
139
|
+
const line = rawLine.replace(/\r/g, "");
|
|
140
|
+
const match = lambdaLogPattern.exec(line);
|
|
141
|
+
if (match && config.invocationContexts) {
|
|
142
|
+
const requestId = match[2];
|
|
143
|
+
const ctx = config.invocationContexts.get(requestId);
|
|
144
|
+
if (ctx) {
|
|
145
|
+
// Strip timestamp and request ID, keep just LEVEL MESSAGE
|
|
146
|
+
return { prefix: `[${ctx.num}]`, content: match[3] };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return { prefix: "[Container]", content: line };
|
|
150
|
+
};
|
|
151
|
+
// Process stdout - filter expected errors, forward the rest
|
|
152
|
+
const stdoutFiber = yield* proc.stdout.pipe(Stream.decodeText(), Stream.splitLines, Stream.runForEach((rawLine) => Effect.sync(() => {
|
|
153
|
+
stdout.push(rawLine);
|
|
154
|
+
// Suppress expected RIC output (poll timeout errors)
|
|
155
|
+
if (!isExpectedRicOutput(rawLine)) {
|
|
156
|
+
const { prefix, content } = formatLine(rawLine);
|
|
157
|
+
process.stdout.write(`${prefix} ${content}\n`);
|
|
158
|
+
}
|
|
159
|
+
})), Effect.fork);
|
|
160
|
+
// Process stderr - filter expected errors, forward the rest
|
|
161
|
+
const stderrFiber = yield* proc.stderr.pipe(Stream.decodeText(), Stream.splitLines, Stream.runForEach((rawLine) => Effect.sync(() => {
|
|
162
|
+
stderr.push(rawLine);
|
|
163
|
+
// Suppress expected RIC output (poll timeout errors)
|
|
164
|
+
if (!isExpectedRicOutput(rawLine)) {
|
|
165
|
+
const { prefix, content } = formatLine(rawLine);
|
|
166
|
+
process.stderr.write(`${prefix} ${content}\n`);
|
|
167
|
+
}
|
|
168
|
+
})), Effect.fork);
|
|
169
|
+
// Wait for both streams and exit code
|
|
170
|
+
yield* Effect.all([
|
|
171
|
+
Effect.fromFiber(stdoutFiber),
|
|
172
|
+
Effect.fromFiber(stderrFiber),
|
|
173
|
+
]);
|
|
174
|
+
const exitCode = yield* proc.exitCode;
|
|
175
|
+
// Only suppress warnings for expected exit codes:
|
|
176
|
+
// - 0: Clean exit
|
|
177
|
+
// - 1: Lambda RIC exit after 503 poll timeout (expected)
|
|
178
|
+
// - 143 (128+15): SIGTERM from docker stop
|
|
179
|
+
// - 137 (128+9): SIGKILL from docker stop timeout
|
|
180
|
+
const expectedExitCodes = [0, 1, 143, 137];
|
|
181
|
+
if (!expectedExitCodes.includes(exitCode)) {
|
|
182
|
+
yield* Effect.logWarning(`Container exited with code ${exitCode}`);
|
|
183
|
+
}
|
|
184
|
+
else if (exitCode !== 0) {
|
|
185
|
+
yield* Effect.logDebug(`Container exited with code ${exitCode}`);
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
exitCode,
|
|
189
|
+
stdout: stdout.join("\n"),
|
|
190
|
+
stderr: stderr.join("\n"),
|
|
191
|
+
};
|
|
192
|
+
});
|
|
193
|
+
const runScoped = (config) => Effect.gen(function* () {
|
|
194
|
+
const args = buildDockerRunArgs(config, runtime);
|
|
195
|
+
yield* Effect.logInfo(`Running (scoped): docker ${args.join(" ")}`);
|
|
196
|
+
const command = PlatformCommand.make(runtime.dockerPath, ...args);
|
|
197
|
+
const proc = yield* PlatformCommand.start(command);
|
|
198
|
+
// Fork output processing in background (will be interrupted when scope closes)
|
|
199
|
+
yield* proc.stdout.pipe(Stream.decodeText(), Stream.splitLines, Stream.runForEach((line) => Effect.sync(() => {
|
|
200
|
+
process.stdout.write(`[Container] ${line}\n`);
|
|
201
|
+
})), Effect.fork);
|
|
202
|
+
yield* proc.stderr.pipe(Stream.decodeText(), Stream.splitLines, Stream.runForEach((line) => Effect.sync(() => {
|
|
203
|
+
process.stderr.write(`[Container] ${line}\n`);
|
|
204
|
+
})), Effect.fork);
|
|
205
|
+
return proc;
|
|
206
|
+
});
|
|
207
|
+
const build = (options) => Effect.gen(function* () {
|
|
208
|
+
const args = [
|
|
209
|
+
"build",
|
|
210
|
+
"-t",
|
|
211
|
+
options.imageName,
|
|
212
|
+
"--platform",
|
|
213
|
+
options.platform ?? "linux/arm64",
|
|
214
|
+
options.contextPath,
|
|
215
|
+
];
|
|
216
|
+
yield* Effect.logInfo(`Building image: ${options.imageName}`);
|
|
217
|
+
yield* Effect.logDebug(`Context: ${options.contextPath}`);
|
|
218
|
+
const command = PlatformCommand.make(runtime.dockerPath, ...args);
|
|
219
|
+
const proc = yield* PlatformCommand.start(command);
|
|
220
|
+
// Process stdout (debug only)
|
|
221
|
+
const stdoutFiber = yield* proc.stdout.pipe(Stream.decodeText(), Stream.splitLines, Stream.runForEach((line) => Effect.logDebug(`[Docker] ${line}`)), Effect.fork);
|
|
222
|
+
// Process stderr (debug only)
|
|
223
|
+
const stderrFiber = yield* proc.stderr.pipe(Stream.decodeText(), Stream.splitLines, Stream.runForEach((line) => Effect.logDebug(`[Docker] ${line}`)), Effect.fork);
|
|
224
|
+
// Wait for streams and exit code
|
|
225
|
+
yield* Effect.all([
|
|
226
|
+
Effect.fromFiber(stdoutFiber),
|
|
227
|
+
Effect.fromFiber(stderrFiber),
|
|
228
|
+
]);
|
|
229
|
+
const exitCode = yield* proc.exitCode;
|
|
230
|
+
if (exitCode !== 0) {
|
|
231
|
+
return yield* Effect.fail(new Error(`Docker build failed with code ${exitCode}`));
|
|
232
|
+
}
|
|
233
|
+
yield* Effect.logInfo(`Built image: ${options.imageName}`);
|
|
234
|
+
});
|
|
235
|
+
const pull = (imageUri) => Effect.gen(function* () {
|
|
236
|
+
yield* Effect.logInfo(`Pulling image: ${imageUri}`);
|
|
237
|
+
const command = PlatformCommand.make(runtime.dockerPath, "pull", imageUri);
|
|
238
|
+
const proc = yield* PlatformCommand.start(command);
|
|
239
|
+
// Process stdout (debug only)
|
|
240
|
+
const stdoutFiber = yield* proc.stdout.pipe(Stream.decodeText(), Stream.splitLines, Stream.runForEach((line) => Effect.logDebug(`[Docker] ${line}`)), Effect.fork);
|
|
241
|
+
// Process stderr (debug only)
|
|
242
|
+
const stderrFiber = yield* proc.stderr.pipe(Stream.decodeText(), Stream.splitLines, Stream.runForEach((line) => Effect.logDebug(`[Docker] ${line}`)), Effect.fork);
|
|
243
|
+
// Wait for streams and exit code
|
|
244
|
+
yield* Effect.all([
|
|
245
|
+
Effect.fromFiber(stdoutFiber),
|
|
246
|
+
Effect.fromFiber(stderrFiber),
|
|
247
|
+
]);
|
|
248
|
+
const exitCode = yield* proc.exitCode;
|
|
249
|
+
if (exitCode !== 0) {
|
|
250
|
+
return yield* Effect.fail(new Error(`Docker pull failed with code ${exitCode}`));
|
|
251
|
+
}
|
|
252
|
+
yield* Effect.logInfo(`Pulled image: ${imageUri}`);
|
|
253
|
+
});
|
|
254
|
+
const list = (containerNameFilter) => Effect.gen(function* () {
|
|
255
|
+
const command = PlatformCommand.make(runtime.dockerPath, "ps", "-q", "--filter", `name=${containerNameFilter}`);
|
|
256
|
+
const proc = yield* PlatformCommand.start(command);
|
|
257
|
+
// Collect stdout
|
|
258
|
+
const containerIds = [];
|
|
259
|
+
yield* proc.stdout.pipe(Stream.decodeText(), Stream.splitLines, Stream.runForEach((line) => Effect.sync(() => {
|
|
260
|
+
const trimmed = line.trim();
|
|
261
|
+
if (trimmed) {
|
|
262
|
+
containerIds.push(trimmed);
|
|
263
|
+
}
|
|
264
|
+
})));
|
|
265
|
+
const exitCode = yield* proc.exitCode;
|
|
266
|
+
if (exitCode !== 0) {
|
|
267
|
+
return yield* Effect.fail(new Error(`Docker ps failed with code ${exitCode}`));
|
|
268
|
+
}
|
|
269
|
+
return containerIds;
|
|
270
|
+
});
|
|
271
|
+
const stop = (containerNameFilter, timeoutSeconds) => Effect.gen(function* () {
|
|
272
|
+
// First list matching containers
|
|
273
|
+
const containerIds = yield* list(containerNameFilter);
|
|
274
|
+
if (containerIds.length === 0) {
|
|
275
|
+
yield* Effect.logDebug(`No containers found matching: ${containerNameFilter}`);
|
|
276
|
+
return 0;
|
|
277
|
+
}
|
|
278
|
+
yield* Effect.logInfo(`Stopping containers: ${containerIds.join(", ")}`);
|
|
279
|
+
// Build stop command with optional timeout
|
|
280
|
+
// -t 0 sends SIGKILL immediately, useful for fast restarts
|
|
281
|
+
const timeoutArg = timeoutSeconds !== undefined ? ["-t", String(timeoutSeconds)] : [];
|
|
282
|
+
const command = PlatformCommand.make(runtime.dockerPath, "stop", ...timeoutArg, ...containerIds);
|
|
283
|
+
const proc = yield* PlatformCommand.start(command);
|
|
284
|
+
// Process output for logging
|
|
285
|
+
yield* proc.stdout.pipe(Stream.decodeText(), Stream.splitLines, Stream.runForEach((line) => Effect.logDebug(`[Docker stop] ${line.trim()}`)));
|
|
286
|
+
const exitCode = yield* proc.exitCode;
|
|
287
|
+
if (exitCode !== 0) {
|
|
288
|
+
yield* Effect.logWarning(`Docker stop exited with code ${exitCode} (some containers may have already stopped)`);
|
|
289
|
+
}
|
|
290
|
+
return containerIds.length;
|
|
291
|
+
});
|
|
292
|
+
const inspect = (imageUri) => Effect.gen(function* () {
|
|
293
|
+
const executor = yield* CommandExecutor.CommandExecutor;
|
|
294
|
+
// Get entrypoint
|
|
295
|
+
const entrypointCmd = PlatformCommand.make(runtime.dockerPath, "inspect", "--format", "{{json .Config.Entrypoint}}", imageUri);
|
|
296
|
+
const entrypointProc = yield* executor.start(entrypointCmd);
|
|
297
|
+
const entrypointOutput = yield* Stream.runCollect(Stream.decodeText(entrypointProc.stdout));
|
|
298
|
+
const entrypointExitCode = yield* entrypointProc.exitCode;
|
|
299
|
+
if (entrypointExitCode !== 0) {
|
|
300
|
+
yield* Effect.fail(new Error(`Failed to inspect image entrypoint: ${imageUri}`));
|
|
301
|
+
}
|
|
302
|
+
const entrypointJson = Array.from(entrypointOutput).join("").trim();
|
|
303
|
+
// Get cmd
|
|
304
|
+
const cmdCmd = PlatformCommand.make(runtime.dockerPath, "inspect", "--format", "{{json .Config.Cmd}}", imageUri);
|
|
305
|
+
const cmdProc = yield* executor.start(cmdCmd);
|
|
306
|
+
const cmdOutput = yield* Stream.runCollect(Stream.decodeText(cmdProc.stdout));
|
|
307
|
+
const cmdExitCode = yield* cmdProc.exitCode;
|
|
308
|
+
if (cmdExitCode !== 0) {
|
|
309
|
+
yield* Effect.fail(new Error(`Failed to inspect image cmd: ${imageUri}`));
|
|
310
|
+
}
|
|
311
|
+
const cmdJson = Array.from(cmdOutput).join("").trim();
|
|
312
|
+
// Parse JSON - null is valid, so handle that
|
|
313
|
+
const parseJsonArray = (json) => {
|
|
314
|
+
if (json === "null" || json === "")
|
|
315
|
+
return null;
|
|
316
|
+
try {
|
|
317
|
+
const parsed = JSON.parse(json);
|
|
318
|
+
return Array.isArray(parsed) ? parsed : null;
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
return {
|
|
325
|
+
entrypoint: parseJsonArray(entrypointJson),
|
|
326
|
+
cmd: parseJsonArray(cmdJson),
|
|
327
|
+
};
|
|
328
|
+
});
|
|
329
|
+
return {
|
|
330
|
+
run,
|
|
331
|
+
runScoped,
|
|
332
|
+
build,
|
|
333
|
+
pull,
|
|
334
|
+
stop,
|
|
335
|
+
list,
|
|
336
|
+
getRuntimeInfo,
|
|
337
|
+
inspect,
|
|
338
|
+
};
|
|
339
|
+
});
|
|
340
|
+
/**
|
|
341
|
+
* Live Docker service layer.
|
|
342
|
+
* Note: Does not require CommandExecutor in the layer - it's required
|
|
343
|
+
* when the service methods are called.
|
|
344
|
+
*/
|
|
345
|
+
export const DockerLive = Layer.effect(Docker, makeDockerService);
|
|
346
|
+
/**
|
|
347
|
+
* Create a container config for running a Lambda container.
|
|
348
|
+
*/
|
|
349
|
+
export const makeLambdaContainerConfig = (options) => ({
|
|
350
|
+
imageUri: options.imageUri,
|
|
351
|
+
containerName: `lambda-${options.functionName.replace(/[^a-zA-Z0-9]/g, "-")}`,
|
|
352
|
+
platform: options.platform,
|
|
353
|
+
environment: {
|
|
354
|
+
AWS_LAMBDA_RUNTIME_API: `${options.runtimeApiHost}:${options.runtimeApiPort}`,
|
|
355
|
+
AWS_LAMBDA_FUNCTION_NAME: options.functionName,
|
|
356
|
+
AWS_LAMBDA_FUNCTION_VERSION: options.functionVersion,
|
|
357
|
+
AWS_LAMBDA_FUNCTION_MEMORY_SIZE: String(options.memoryMB),
|
|
358
|
+
AWS_REGION: options.awsRegion ?? "us-east-1",
|
|
359
|
+
AWS_DEFAULT_REGION: options.awsRegion ?? "us-east-1",
|
|
360
|
+
AWS_LAMBDA_LOG_GROUP_NAME: `/aws/lambda/${options.functionName}`,
|
|
361
|
+
AWS_LAMBDA_LOG_STREAM_NAME: "local",
|
|
362
|
+
_HANDLER: options.handler ?? "index.handler",
|
|
363
|
+
...options.additionalEnv,
|
|
364
|
+
},
|
|
365
|
+
memoryMB: options.memoryMB,
|
|
366
|
+
timeoutSeconds: options.timeoutSeconds,
|
|
367
|
+
networkMode: "bridge",
|
|
368
|
+
invocationContexts: options.invocationContexts,
|
|
369
|
+
});
|
|
370
|
+
/**
|
|
371
|
+
* Shell-quote a string for safe inclusion in a shell command.
|
|
372
|
+
* Uses single quotes and escapes any embedded single quotes.
|
|
373
|
+
*/
|
|
374
|
+
const shellQuote = (s) => {
|
|
375
|
+
// Single quotes are safest - escape any embedded single quotes
|
|
376
|
+
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
377
|
+
};
|
|
378
|
+
/**
|
|
379
|
+
* Build a wrapper command that starts Lambda extensions before the main app.
|
|
380
|
+
*
|
|
381
|
+
* This mimics AWS Lambda's behavior of automatically starting all executables
|
|
382
|
+
* in /opt/extensions/ as background processes before running the main command.
|
|
383
|
+
*
|
|
384
|
+
* @param originalEntrypoint - The image's original ENTRYPOINT
|
|
385
|
+
* @param originalCmd - The image's original CMD
|
|
386
|
+
* @returns Entrypoint and command arrays to pass to Docker
|
|
387
|
+
*/
|
|
388
|
+
export const buildExtensionWrapperCommand = (originalEntrypoint, originalCmd) => {
|
|
389
|
+
// Combine original entrypoint + cmd into the full command
|
|
390
|
+
// Docker behavior: ENTRYPOINT + CMD are concatenated
|
|
391
|
+
const originalCommand = [
|
|
392
|
+
...(originalEntrypoint ?? []),
|
|
393
|
+
...(originalCmd ?? []),
|
|
394
|
+
];
|
|
395
|
+
// Script to start all executable files in /opt/extensions/ as background processes
|
|
396
|
+
const extensionStarter = 'for ext in /opt/extensions/*; do [ -x "$ext" ] && "$ext" & done';
|
|
397
|
+
// Build the full wrapper command
|
|
398
|
+
let fullCommand;
|
|
399
|
+
if (originalCommand.length > 0) {
|
|
400
|
+
// Quote each argument and join with spaces
|
|
401
|
+
const quotedOriginal = originalCommand.map(shellQuote).join(" ");
|
|
402
|
+
// Start extensions, then exec the original command
|
|
403
|
+
fullCommand = `${extensionStarter}; exec ${quotedOriginal}`;
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
// No original command - just start extensions (unusual but handle it)
|
|
407
|
+
fullCommand = extensionStarter;
|
|
408
|
+
}
|
|
409
|
+
return {
|
|
410
|
+
entrypoint: ["/bin/sh"],
|
|
411
|
+
command: ["-c", fullCommand],
|
|
412
|
+
};
|
|
413
|
+
};
|
|
414
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGFpbmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NsaS9kb2NrZXIvY29udGFpbmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUVILE9BQU8sS0FBSyxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQzdCLE9BQU8sRUFBRSxlQUFlLEVBQUUsT0FBTyxJQUFJLGVBQWUsRUFBRSxNQUFNLGtCQUFrQixDQUFBO0FBRTlFLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBYyxNQUFNLEVBQUUsTUFBTSxRQUFRLENBQUE7QUFRbkU7O0dBRUc7QUFDSCxNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBRyxHQUdqQyxFQUFFLENBQ0YsTUFBTSxDQUFDLEdBQUcsQ0FBQztJQUNULEdBQUcsRUFBRSxHQUFHLEVBQUU7UUFDUixNQUFNLFFBQVEsR0FBRyxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUE7UUFDOUIsTUFBTSxPQUFPLEdBQUcsUUFBUSxLQUFLLE9BQU8sQ0FBQTtRQUNwQyxNQUFNLEtBQUssR0FDVCxPQUFPO1lBQ1AsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsS0FBSyxTQUFTO2dCQUN4QyxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsS0FBSyxTQUFTLENBQUMsQ0FBQTtRQUUxQywwREFBMEQ7UUFDMUQsMkRBQTJEO1FBQzNELE1BQU0sZUFBZSxHQUFHLENBQUMsT0FBTyxJQUFJLEtBQUssQ0FBQTtRQUV6QyxNQUFNLFdBQVcsR0FBRyxlQUFlO1lBQ2pDLENBQUMsQ0FBQyxzQkFBc0I7WUFDeEIsQ0FBQyxDQUFDLFlBQVksQ0FBQSxDQUFDLGdDQUFnQztRQUVqRCxPQUFPO1lBQ0wsVUFBVSxFQUFFLFFBQVE7WUFDcEIsT0FBTztZQUNQLEtBQUs7WUFDTCxlQUFlO1lBQ2YsV0FBVztTQUNaLENBQUE7SUFDSCxDQUFDO0lBQ0QsS0FBSyxFQUFFLENBQUMsS0FBSyxF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QyxXQUE0QixFQUNpQixFQUFFO0lBQy9DLDBEQUEwRDtJQUMxRCxxREFBcUQ7SUFDckQsTUFBTSxlQUFlLEdBQUc7UUFDdEIsR0FBRyxDQUFDLGtCQUFrQixJQUFJLEVBQUUsQ0FBQztRQUM3QixHQUFHLENBQUMsV0FBVyxJQUFJLEVBQUUsQ0FBQztLQUN2QixDQUFBO0lBRUQsbUZBQW1GO0lBQ25GLE1BQU0sZ0JBQWdCLEdBQ3BCLGlFQUFpRSxDQUFBO0lBRW5FLGlDQUFpQztJQUNqQyxJQUFJLFdBQW1CLENBQUE7SUFDdkIsSUFBSSxlQUFlLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQy9CLDJDQUEyQztRQUMzQyxNQUFNLGNBQWMsR0FBRyxlQUFlLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUNoRSxtREFBbUQ7UUFDbkQsV0FBVyxHQUFHLEdBQUcsZ0JBQWdCLFVBQVUsY0FBYyxFQUFFLENBQUE7SUFDN0QsQ0FBQztTQUFNLENBQUM7UUFDTixzRUFBc0U7UUFDdEUsV0FBVyxHQUFHLGdCQUFnQixDQUFBO0lBQ2hDLENBQUM7SUFFRCxPQUFPO1FBQ0wsVUFBVSxFQUFFLENBQUMsU0FBUyxDQUFDO1FBQ3ZCLE9BQU8sRUFBRSxDQUFDLElBQUksRUFBRSxXQUFXLENBQUM7S0FDN0IsQ0FBQTtBQUNILENBQUMsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRG9ja2VyIGNvbnRhaW5lciBtYW5hZ2VtZW50IHV0aWxpdGllcy5cbiAqXG4gKiBIYW5kbGVzIHJ1bm5pbmcgRG9ja2VyIGNvbnRhaW5lcnMgd2l0aCB0aGUgTGFtYmRhIFJ1bnRpbWUgQVBJXG4gKiBlbnZpcm9ubWVudCBjb25maWd1cmVkLiBVc2VzIEBlZmZlY3QvcGxhdGZvcm0gQ29tbWFuZCBmb3JcbiAqIHByb3BlciBFZmZlY3QtYmFzZWQgcHJvY2VzcyBtYW5hZ2VtZW50LlxuICovXG5cbmltcG9ydCAqIGFzIG9zIGZyb20gXCJub2RlOm9zXCJcbmltcG9ydCB7IENvbW1hbmRFeGVjdXRvciwgQ29tbWFuZCBhcyBQbGF0Zm9ybUNvbW1hbmQgfSBmcm9tIFwiQGVmZmVjdC9wbGF0Zm9ybVwiXG5pbXBvcnQgdHlwZSB7IFByb2Nlc3MgYXMgRWZmZWN0UHJvY2VzcyB9IGZyb20gXCJAZWZmZWN0L3BsYXRmb3JtL0NvbW1hbmRFeGVjdXRvclwiXG5pbXBvcnQgeyBDb250ZXh0LCBFZmZlY3QsIExheWVyLCB0eXBlIFNjb3BlLCBTdHJlYW0gfSBmcm9tIFwiZWZmZWN0XCJcbmltcG9ydCB0eXBlIHtcbiAgRG9ja2VySW1hZ2VDb25maWcsXG4gIERvY2tlclJ1bkNvbmZpZyxcbiAgRG9ja2VyUnVuUmVzdWx0LFxuICBEb2NrZXJSdW50aW1lSW5mbyxcbn0gZnJvbSBcIi4vdHlwZXMuanNcIlxuXG4vKipcbiAqIERldGVjdCB0aGUgRG9ja2VyIHJ1bnRpbWUgZW52aXJvbm1lbnQuXG4gKi9cbmV4cG9ydCBjb25zdCBkZXRlY3REb2NrZXJSdW50aW1lID0gKCk6IEVmZmVjdC5FZmZlY3Q8XG4gIERvY2tlclJ1bnRpbWVJbmZvLFxuICBFcnJvclxuPiA9PlxuICBFZmZlY3QudHJ5KHtcbiAgICB0cnk6ICgpID0+IHtcbiAgICAgIGNvbnN0IHBsYXRmb3JtID0gb3MucGxhdGZvcm0oKVxuICAgICAgY29uc3QgaXNMaW51eCA9IHBsYXRmb3JtID09PSBcImxpbnV4XCJcbiAgICAgIGNvbnN0IGlzV3NsID1cbiAgICAgICAgaXNMaW51eCAmJlxuICAgICAgICAocHJvY2Vzcy5lbnYuV1NMX0RJU1RST19OQU1FICE9PSB1bmRlZmluZWQgfHxcbiAgICAgICAgICBwcm9jZXNzLmVudi5XU0xfSU5URVJPUCAhPT0gdW5kZWZpbmVkKVxuXG4gICAgICAvLyBPbiBNYWMvV2luZG93cyBEb2NrZXIgRGVza3RvcCwgdXNlIGhvc3QuZG9ja2VyLmludGVybmFsXG4gICAgICAvLyBPbiBMaW51eCwgd2UgbmVlZCB0byB1c2UgdGhlIGhvc3QncyBJUCBvciAtLW5ldHdvcms9aG9zdFxuICAgICAgY29uc3QgaXNEb2NrZXJEZXNrdG9wID0gIWlzTGludXggfHwgaXNXc2xcblxuICAgICAgY29uc3QgaG9zdEFkZHJlc3MgPSBpc0RvY2tlckRlc2t0b3BcbiAgICAgICAgPyBcImhvc3QuZG9ja2VyLmludGVybmFsXCJcbiAgICAgICAgOiBcIjE3Mi4xNy4wLjFcIiAvLyBEZWZhdWx0IERvY2tlciBicmlkZ2UgZ2F0ZXdheVxuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBkb2NrZXJQYXRoOiBcImRvY2tlclwiLFxuICAgICAgICBpc0xpbnV4LFxuICAgICAgICBpc1dzbCxcbiAgICAgICAgaXNEb2NrZXJEZXNrdG9wLFxuICAgICAgICBob3N0QWRkcmVzcyxcbiAgICAgIH1cbiAgICB9LFxuICAgIGNhdGNoOiAoZXJyb3IpID0+XG4gICAgICBuZXcgRXJyb3IoYEZhaWxlZCB0byBkZXRlY3QgRG9ja2VyIHJ1bnRpbWU6ICR7U3RyaW5nKGVycm9yKX1gKSxcbiAgfSlcblxuLyoqXG4gKiBCdWlsZCBEb2NrZXIgcnVuIGFyZ3VtZW50cyBmcm9tIGNvbmZpZy5cbiAqL1xuY29uc3QgYnVpbGREb2NrZXJSdW5BcmdzID0gKFxuICBjb25maWc6IERvY2tlclJ1bkNvbmZpZyxcbiAgcnVudGltZTogRG9ja2VyUnVudGltZUluZm8sXG4pOiBzdHJpbmdbXSA9PiB7XG4gIGNvbnN0IGFyZ3M6IHN0cmluZ1tdID0gW1wicnVuXCIsIFwiLS1ybVwiXVxuXG4gIC8vIENvbnRhaW5lciBuYW1lIChhZGQgdGltZXN0YW1wIGZvciB1bmlxdWVuZXNzKVxuICBpZiAoY29uZmlnLmNvbnRhaW5lck5hbWUpIHtcbiAgICBhcmdzLnB1c2goXCItLW5hbWVcIiwgYCR7Y29uZmlnLmNvbnRhaW5lck5hbWV9LSR7RGF0ZS5ub3coKX1gKVxuICB9XG5cbiAgLy8gUGxhdGZvcm0gLSBhbGxvdyBydW5uaW5nIEFSTTY0IGltYWdlcyBvbiB4ODZfNjQgdmlhIFFFTVVcbiAgaWYgKGNvbmZpZy5wbGF0Zm9ybSkge1xuICAgIGFyZ3MucHVzaChcIi0tcGxhdGZvcm1cIiwgY29uZmlnLnBsYXRmb3JtKVxuICB9XG5cbiAgLy8gTWVtb3J5IGxpbWl0XG4gIGFyZ3MucHVzaChcIi0tbWVtb3J5XCIsIGAke2NvbmZpZy5tZW1vcnlNQn1tYClcblxuICAvLyBOZXR3b3JrIG1vZGVcbiAgaWYgKGNvbmZpZy5uZXR3b3JrTW9kZSA9PT0gXCJob3N0XCIpIHtcbiAgICBhcmdzLnB1c2goXCItLW5ldHdvcmtcIiwgXCJob3N0XCIpXG4gIH0gZWxzZSBpZiAoY29uZmlnLm5ldHdvcmtNb2RlICE9PSBcIm5vbmVcIikge1xuICAgIC8vIEZvciBicmlkZ2UgbW9kZSwgYWRkIGhvc3QgbWFwcGluZyBmb3Igbm9uLUxpbnV4XG4gICAgaWYgKHJ1bnRpbWUuaXNEb2NrZXJEZXNrdG9wKSB7XG4gICAgICAvLyBob3N0LmRvY2tlci5pbnRlcm5hbCBpcyBhdXRvbWF0aWNhbGx5IGF2YWlsYWJsZSBvbiBEb2NrZXIgRGVza3RvcFxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBPbiBMaW51eCwgYWRkIGV4cGxpY2l0IGhvc3QgbWFwcGluZyBhbmQgaGVscGVyIGFkZHJlc3NcbiAgICAgIGFyZ3MucHVzaChcIi0tYWRkLWhvc3RcIiwgYGhvc3QuZG9ja2VyLmludGVybmFsOiR7cnVudGltZS5ob3N0QWRkcmVzc31gKVxuICAgICAgYXJncy5wdXNoKFwiLS1hZGQtaG9zdFwiLCBgaG9zdC5jb250YWluZXJzLmludGVybmFsOiR7cnVudGltZS5ob3N0QWRkcmVzc31gKVxuICAgICAgYXJncy5wdXNoKFwiLS1hZGQtaG9zdFwiLCBgcnVudGltZS5hcGk6JHtydW50aW1lLmhvc3RBZGRyZXNzfWApXG4gICAgfVxuICB9XG5cbiAgLy8gRXh0cmEgaG9zdHNcbiAgaWYgKGNvbmZpZy5leHRyYUhvc3RzKSB7XG4gICAgZm9yIChjb25zdCBob3N0IG9mIGNvbmZpZy5leHRyYUhvc3RzKSB7XG4gICAgICBhcmdzLnB1c2goXCItLWFkZC1ob3N0XCIsIGhvc3QpXG4gICAgfVxuICB9XG5cbiAgLy8gRW52aXJvbm1lbnQgdmFyaWFibGVzXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKGNvbmZpZy5lbnZpcm9ubWVudCkpIHtcbiAgICBhcmdzLnB1c2goXCItZVwiLCBgJHtrZXl9PSR7dmFsdWV9YClcbiAgfVxuXG4gIC8vIFdvcmtpbmcgZGlyZWN0b3J5XG4gIGlmIChjb25maWcud29ya2Rpcikge1xuICAgIGFyZ3MucHVzaChcIi13XCIsIGNvbmZpZy53b3JrZGlyKVxuICB9XG5cbiAgLy8gQWRkaXRpb25hbCBhcmd1bWVudHNcbiAgaWYgKGNvbmZpZy5hZGRpdGlvbmFsQXJncykge1xuICAgIGFyZ3MucHVzaCguLi5jb25maWcuYWRkaXRpb25hbEFyZ3MpXG4gIH1cblxuICAvLyBFbnRyeXBvaW50IG92ZXJyaWRlXG4gIGlmIChjb25maWcuZW50cnlwb2ludCAmJiBjb25maWcuZW50cnlwb2ludC5sZW5ndGggPiAwKSB7XG4gICAgYXJncy5wdXNoKFwiLS1lbnRyeXBvaW50XCIsIGNvbmZpZy5lbnRyeXBvaW50WzBdKVxuICB9XG5cbiAgLy8gSW1hZ2VcbiAgYXJncy5wdXNoKGNvbmZpZy5pbWFnZVVyaSlcblxuICAvLyBFbnRyeXBvaW50IGFkZGl0aW9uYWwgYXJncyAoYWZ0ZXIgaW1hZ2UpXG4gIGlmIChjb25maWcuZW50cnlwb2ludCAmJiBjb25maWcuZW50cnlwb2ludC5sZW5ndGggPiAxKSB7XG4gICAgYXJncy5wdXNoKC4uLmNvbmZpZy5lbnRyeXBvaW50LnNsaWNlKDEpKVxuICB9XG5cbiAgLy8gQ29tbWFuZCBvdmVycmlkZSAoYWZ0ZXIgaW1hZ2UgYW5kIGVudHJ5cG9pbnQgYXJncylcbiAgaWYgKGNvbmZpZy5jb21tYW5kKSB7XG4gICAgYXJncy5wdXNoKC4uLmNvbmZpZy5jb21tYW5kKVxuICB9XG5cbiAgcmV0dXJuIGFyZ3Ncbn1cblxuLyoqXG4gKiBEb2NrZXIgU2VydmljZSBpbnRlcmZhY2UgZm9yIEVmZmVjdC1iYXNlZCBEb2NrZXIgb3BlcmF0aW9ucy5cbiAqIEFsbCBzY29wZWQgb3BlcmF0aW9ucyByZXF1aXJlIGJvdGggU2NvcGUgYW5kIENvbW1hbmRFeGVjdXRvci5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEb2NrZXJTZXJ2aWNlIHtcbiAgLyoqXG4gICAqIFJ1biBhIERvY2tlciBjb250YWluZXIgYW5kIHdhaXQgZm9yIGl0IHRvIGNvbXBsZXRlLlxuICAgKiBPdXRwdXQgaXMgc3RyZWFtZWQgdG8gc3Rkb3V0L3N0ZGVyci5cbiAgICovXG4gIHJlYWRvbmx5IHJ1bjogKFxuICAgIGNvbmZpZzogRG9ja2VyUnVuQ29uZmlnLFxuICApID0+IEVmZmVjdC5FZmZlY3Q8XG4gICAgRG9ja2VyUnVuUmVzdWx0LFxuICAgIEVycm9yLFxuICAgIFNjb3BlLlNjb3BlIHwgQ29tbWFuZEV4ZWN1dG9yLkNvbW1hbmRFeGVjdXRvclxuICA+XG5cbiAgLyoqXG4gICAqIFJ1biBhIERvY2tlciBjb250YWluZXIgd2l0aCBzY29wZWQgbGlmZWN5Y2xlIG1hbmFnZW1lbnQuXG4gICAqIFJldHVybnMgdGhlIHJ1bm5pbmcgcHJvY2VzcyB3aGljaCBjYW4gYmUgaW50ZXJydXB0ZWQgdmlhIHNjb3BlLlxuICAgKi9cbiAgcmVhZG9ubHkgcnVuU2NvcGVkOiAoXG4gICAgY29uZmlnOiBEb2NrZXJSdW5Db25maWcsXG4gICkgPT4gRWZmZWN0LkVmZmVjdDxcbiAgICBFZmZlY3RQcm9jZXNzLFxuICAgIEVycm9yLFxuICAgIFNjb3BlLlNjb3BlIHwgQ29tbWFuZEV4ZWN1dG9yLkNvbW1hbmRFeGVjdXRvclxuICA+XG5cbiAgLyoqXG4gICAqIEJ1aWxkIGEgRG9ja2VyIGltYWdlIGZyb20gYSBsb2NhbCBjb250ZXh0IGRpcmVjdG9yeS5cbiAgICovXG4gIHJlYWRvbmx5IGJ1aWxkOiAob3B0aW9uczoge1xuICAgIGNvbnRleHRQYXRoOiBzdHJpbmdcbiAgICBpbWFnZU5hbWU6IHN0cmluZ1xuICAgIHBsYXRmb3JtPzogc3RyaW5nXG4gIH0pID0+IEVmZmVjdC5FZmZlY3Q8XG4gICAgdm9pZCxcbiAgICBFcnJvcixcbiAgICBTY29wZS5TY29wZSB8IENvbW1hbmRFeGVjdXRvci5Db21tYW5kRXhlY3V0b3JcbiAgPlxuXG4gIC8qKlxuICAgKiBQdWxsIGEgRG9ja2VyIGltYWdlIGlmIG5vdCBhbHJlYWR5IHByZXNlbnQuXG4gICAqL1xuICByZWFkb25seSBwdWxsOiAoXG4gICAgaW1hZ2VVcmk6IHN0cmluZyxcbiAgKSA9PiBFZmZlY3QuRWZmZWN0PHZvaWQsIEVycm9yLCBTY29wZS5TY29wZSB8IENvbW1hbmRFeGVjdXRvci5Db21tYW5kRXhlY3V0b3I+XG5cbiAgLyoqXG4gICAqIFN0b3AgRG9ja2VyIGNvbnRhaW5lcnMgbWF0Y2hpbmcgYSBuYW1lIGZpbHRlci5cbiAgICogUmV0dXJucyB0aGUgbnVtYmVyIG9mIGNvbnRhaW5lcnMgc3RvcHBlZC5cbiAgICogQHBhcmFtIGNvbnRhaW5lck5hbWVGaWx0ZXIgLSBGaWx0ZXIgdG8gbWF0Y2ggY29udGFpbmVyIG5hbWVzXG4gICAqIEBwYXJhbSB0aW1lb3V0U2Vjb25kcyAtIFNlY29uZHMgdG8gd2FpdCBiZWZvcmUgU0lHS0lMTCAoZGVmYXVsdDogMTApXG4gICAqL1xuICByZWFkb25seSBzdG9wOiAoXG4gICAgY29udGFpbmVyTmFtZUZpbHRlcjogc3RyaW5nLFxuICAgIHRpbWVvdXRTZWNvbmRzPzogbnVtYmVyLFxuICApID0+IEVmZmVjdC5FZmZlY3Q8XG4gICAgbnVtYmVyLFxuICAgIEVycm9yLFxuICAgIFNjb3BlLlNjb3BlIHwgQ29tbWFuZEV4ZWN1dG9yLkNvbW1hbmRFeGVjdXRvclxuICA+XG5cbiAgLyoqXG4gICAqIExpc3QgRG9ja2VyIGNvbnRhaW5lciBJRHMgbWF0Y2hpbmcgYSBuYW1lIGZpbHRlci5cbiAgICovXG4gIHJlYWRvbmx5IGxpc3Q6IChcbiAgICBjb250YWluZXJOYW1lRmlsdGVyOiBzdHJpbmcsXG4gICkgPT4gRWZmZWN0LkVmZmVjdDxcbiAgICBzdHJpbmdbXSxcbiAgICBFcnJvcixcbiAgICBTY29wZS5TY29wZSB8IENvbW1hbmRFeGVjdXRvci5Db21tYW5kRXhlY3V0b3JcbiAgPlxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGRldGVjdGVkIERvY2tlciBydW50aW1lIGluZm8uXG4gICAqL1xuICByZWFkb25seSBnZXRSdW50aW1lSW5mbzogKCkgPT4gRWZmZWN0LkVmZmVjdDxEb2NrZXJSdW50aW1lSW5mbywgRXJyb3I+XG5cbiAgLyoqXG4gICAqIEluc3BlY3QgYSBEb2NrZXIgaW1hZ2UgdG8gZ2V0IGl0cyBjb25maWd1cmF0aW9uLlxuICAgKiBSZXR1cm5zIHRoZSBFTlRSWVBPSU5UIGFuZCBDTUQgZnJvbSB0aGUgaW1hZ2UuXG4gICAqL1xuICByZWFkb25seSBpbnNwZWN0OiAoXG4gICAgaW1hZ2VVcmk6IHN0cmluZyxcbiAgKSA9PiBFZmZlY3QuRWZmZWN0PFxuICAgIERvY2tlckltYWdlQ29uZmlnLFxuICAgIEVycm9yLFxuICAgIFNjb3BlLlNjb3BlIHwgQ29tbWFuZEV4ZWN1dG9yLkNvbW1hbmRFeGVjdXRvclxuICA+XG59XG5cbi8qKlxuICogRG9ja2VyIFNlcnZpY2UgdGFnIGZvciBkZXBlbmRlbmN5IGluamVjdGlvbi5cbiAqL1xuZXhwb3J0IGNsYXNzIERvY2tlciBleHRlbmRzIENvbnRleHQuVGFnKFwiRG9ja2VyXCIpPERvY2tlciwgRG9ja2VyU2VydmljZT4oKSB7fVxuXG4vKipcbiAqIENyZWF0ZSB0aGUgbGl2ZSBEb2NrZXIgc2VydmljZSBpbXBsZW1lbnRhdGlvbi5cbiAqL1xuY29uc3QgbWFrZURvY2tlclNlcnZpY2U6IEVmZmVjdC5FZmZlY3Q8RG9ja2VyU2VydmljZSwgRXJyb3I+ID0gRWZmZWN0LmdlbihcbiAgZnVuY3Rpb24qICgpIHtcbiAgICBjb25zdCBydW50aW1lID0geWllbGQqIGRldGVjdERvY2tlclJ1bnRpbWUoKVxuXG4gICAgY29uc3QgZ2V0UnVudGltZUluZm86IERvY2tlclNlcnZpY2VbXCJnZXRSdW50aW1lSW5mb1wiXSA9ICgpID0+XG4gICAgICBFZmZlY3Quc3VjY2VlZChydW50aW1lKVxuXG4gICAgY29uc3QgcnVuOiBEb2NrZXJTZXJ2aWNlW1wicnVuXCJdID0gKGNvbmZpZykgPT5cbiAgICAgIEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcbiAgICAgICAgY29uc3QgYXJncyA9IGJ1aWxkRG9ja2VyUnVuQXJncyhjb25maWcsIHJ1bnRpbWUpXG5cbiAgICAgICAgeWllbGQqIEVmZmVjdC5sb2dEZWJ1ZyhgUnVubmluZzogZG9ja2VyICR7YXJncy5qb2luKFwiIFwiKX1gKVxuXG4gICAgICAgIGNvbnN0IGNvbW1hbmQgPSBQbGF0Zm9ybUNvbW1hbmQubWFrZShydW50aW1lLmRvY2tlclBhdGgsIC4uLmFyZ3MpXG5cbiAgICAgICAgY29uc3Qgc3Rkb3V0OiBzdHJpbmdbXSA9IFtdXG4gICAgICAgIGNvbnN0IHN0ZGVycjogc3RyaW5nW10gPSBbXVxuXG4gICAgICAgIC8vIFJ1biB0aGUgY29tbWFuZCBhbmQgY29sbGVjdCBvdXRwdXRcbiAgICAgICAgY29uc3QgcHJvYyA9IHlpZWxkKiBQbGF0Zm9ybUNvbW1hbmQuc3RhcnQoY29tbWFuZClcblxuICAgICAgICAvLyBMYW1iZGEgUklDIGVycm9yL291dHB1dCBwYXR0ZXJucyB0aGF0IGFyZSBleHBlY3RlZCBkdXJpbmcgcG9sbCB0aW1lb3V0XG4gICAgICAgIC8vIFRoZXNlIGFyZSBzdXBwcmVzc2VkIGZyb20gb3V0cHV0IHRvIGF2b2lkIHNjYXJ5IGVycm9yIG1lc3NhZ2VzXG4gICAgICAgIGNvbnN0IGlzRXhwZWN0ZWRSaWNPdXRwdXQgPSAobGluZTogc3RyaW5nKTogYm9vbGVhbiA9PlxuICAgICAgICAgIGxpbmUuaW5jbHVkZXMoXCJMQU1CREFfUlVOVElNRSBGYWlsZWQgdG8gZ2V0IG5leHQgaW52b2NhdGlvblwiKSB8fFxuICAgICAgICAgIGxpbmUuaW5jbHVkZXMoXCJGYWlsZWQgdG8gZ2V0IG5leHQgaW52b2NhdGlvbiwgZXJyb3IgNTAzXCIpIHx8XG4gICAgICAgICAgLy8gRmlsdGVyIG91dCB0aGUgTm9kZS5qcyBzdGFjayB0cmFjZSBmcm9tIExhbWJkYSBSSUMgZXhpdFxuICAgICAgICAgIGxpbmUuaW5jbHVkZXMoXCJ0cmlnZ2VyVW5jYXVnaHRFeGNlcHRpb25cIikgfHxcbiAgICAgICAgICBsaW5lLmluY2x1ZGVzKFwiW0Vycm9yOiBGYWlsZWQgdG8gZ2V0IG5leHQgaW52b2NhdGlvblwiKSB8fFxuICAgICAgICAgIC8vIFwiTm9kZS5qcyB2XCIgdmVyc2lvbiBsaW5lIGFmdGVyIGVycm9yXG4gICAgICAgICAgbGluZS5zdGFydHNXaXRoKFwiTm9kZS5qcyB2XCIpIHx8XG4gICAgICAgICAgbGluZS5pbmNsdWRlcyhcIm5vZGU6aW50ZXJuYWwvcHJvY2Vzcy9wcm9taXNlc1wiKSB8fFxuICAgICAgICAgIC8vIFN0YWNrIHRyYWNlIGNhcmV0IGxpbmUgKGp1c3Qgd2hpdGVzcGFjZSBhbmQgXilcbiAgICAgICAgICAvXlxccypcXF4/XFxzKiQvLnRlc3QobGluZSlcblxuICAgICAgICAvLyBQYXR0ZXJuIHRvIHBhcnNlIExhbWJkYSBsb2cgZm9ybWF0OiBUSU1FU1RBTVBcXHRSRVFVRVNUX0lEXFx0TEVWRUxcXHRNRVNTQUdFXG4gICAgICAgIC8vIExhbWJkYSB1c2VzIHRhYnMgYmV0d2VlbiBmaWVsZHMuIENhcHR1cmVzOiBbMV0gPSByZXF1ZXN0IElELCBbMl0gPSBsZXZlbCArIG1lc3NhZ2VcbiAgICAgICAgY29uc3QgbGFtYmRhTG9nUGF0dGVybiA9XG4gICAgICAgICAgL14oXFxkezR9LVxcZHsyfS1cXGR7Mn1UW1xcZDouXStaKVtcXHRcXHNdKyhbMC05YS1mLV17MzZ9KVtcXHRcXHNdKyguKikkL2lcblxuICAgICAgICAvLyBIZWxwZXIgdG8gZm9ybWF0IGxvZyBsaW5lIHdpdGggaW52b2NhdGlvbiBwcmVmaXhcbiAgICAgICAgY29uc3QgZm9ybWF0TGluZSA9IChcbiAgICAgICAgICByYXdMaW5lOiBzdHJpbmcsXG4gICAgICAgICk6IHsgcHJlZml4OiBzdHJpbmc7IGNvbnRlbnQ6IHN0cmluZyB9ID0+IHtcbiAgICAgICAgICAvLyBTdHJpcCBjYXJyaWFnZSByZXR1cm5zIHRoYXQgY2FuIGNhdXNlIHRlcm1pbmFsIGNvcnJ1cHRpb25cbiAgICAgICAgICBjb25zdCBsaW5lID0gcmF3TGluZS5yZXBsYWNlKC9cXHIvZywgXCJcIilcbiAgICAgICAgICBjb25zdCBtYXRjaCA9IGxhbWJkYUxvZ1BhdHRlcm4uZXhlYyhsaW5lKVxuICAgICAgICAgIGlmIChtYXRjaCAmJiBjb25maWcuaW52b2NhdGlvbkNvbnRleHRzKSB7XG4gICAgICAgICAgICBjb25zdCByZXF1ZXN0SWQgPSBtYXRjaFsyXVxuICAgICAgICAgICAgY29uc3QgY3R4ID0gY29uZmlnLmludm9jYXRpb25Db250ZXh0cy5nZXQocmVxdWVzdElkKVxuICAgICAgICAgICAgaWYgKGN0eCkge1xuICAgICAgICAgICAgICAvLyBTdHJpcCB0aW1lc3RhbXAgYW5kIHJlcXVlc3QgSUQsIGtlZXAganVzdCBMRVZFTCBNRVNTQUdFXG4gICAgICAgICAgICAgIHJldHVybiB7IHByZWZpeDogYFske2N0eC5udW19XWAsIGNvbnRlbnQ6IG1hdGNoWzNdIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHsgcHJlZml4OiBcIltDb250YWluZXJdXCIsIGNvbnRlbnQ6IGxpbmUgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gUHJvY2VzcyBzdGRvdXQgLSBmaWx0ZXIgZXhwZWN0ZWQgZXJyb3JzLCBmb3J3YXJkIHRoZSByZXN0XG4gICAgICAgIGNvbnN0IHN0ZG91dEZpYmVyID0geWllbGQqIHByb2Muc3Rkb3V0LnBpcGUoXG4gICAgICAgICAgU3RyZWFtLmRlY29kZVRleHQoKSxcbiAgICAgICAgICBTdHJlYW0uc3BsaXRMaW5lcyxcbiAgICAgICAgICBTdHJlYW0ucnVuRm9yRWFjaCgocmF3TGluZSkgPT5cbiAgICAgICAgICAgIEVmZmVjdC5zeW5jKCgpID0+IHtcbiAgICAgICAgICAgICAgc3Rkb3V0LnB1c2gocmF3TGluZSlcbiAgICAgICAgICAgICAgLy8gU3VwcHJlc3MgZXhwZWN0ZWQgUklDIG91dHB1dCAocG9sbCB0aW1lb3V0IGVycm9ycylcbiAgICAgICAgICAgICAgaWYgKCFpc0V4cGVjdGVkUmljT3V0cHV0KHJhd0xpbmUpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgeyBwcmVmaXgsIGNvbnRlbnQgfSA9IGZvcm1hdExpbmUocmF3TGluZSlcbiAgICAgICAgICAgICAgICBwcm9jZXNzLnN0ZG91dC53cml0ZShgJHtwcmVmaXh9ICR7Y29udGVudH1cXG5gKVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApLFxuICAgICAgICAgIEVmZmVjdC5mb3JrLFxuICAgICAgICApXG5cbiAgICAgICAgLy8gUHJvY2VzcyBzdGRlcnIgLSBmaWx0ZXIgZXhwZWN0ZWQgZXJyb3JzLCBmb3J3YXJkIHRoZSByZXN0XG4gICAgICAgIGNvbnN0IHN0ZGVyckZpYmVyID0geWllbGQqIHByb2Muc3RkZXJyLnBpcGUoXG4gICAgICAgICAgU3RyZWFtLmRlY29kZVRleHQoKSxcbiAgICAgICAgICBTdHJlYW0uc3BsaXRMaW5lcyxcbiAgICAgICAgICBTdHJlYW0ucnVuRm9yRWFjaCgocmF3TGluZSkgPT5cbiAgICAgICAgICAgIEVmZmVjdC5zeW5jKCgpID0+IHtcbiAgICAgICAgICAgICAgc3RkZXJyLnB1c2gocmF3TGluZSlcbiAgICAgICAgICAgICAgLy8gU3VwcHJlc3MgZXhwZWN0ZWQgUklDIG91dHB1dCAocG9sbCB0aW1lb3V0IGVycm9ycylcbiAgICAgICAgICAgICAgaWYgKCFpc0V4cGVjdGVkUmljT3V0cHV0KHJhd0xpbmUpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgeyBwcmVmaXgsIGNvbnRlbnQgfSA9IGZvcm1hdExpbmUocmF3TGluZSlcbiAgICAgICAgICAgICAgICBwcm9jZXNzLnN0ZGVyci53cml0ZShgJHtwcmVmaXh9ICR7Y29udGVudH1cXG5gKVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApLFxuICAgICAgICAgIEVmZmVjdC5mb3JrLFxuICAgICAgICApXG5cbiAgICAgICAgLy8gV2FpdCBmb3IgYm90aCBzdHJlYW1zIGFuZCBleGl0IGNvZGVcbiAgICAgICAgeWllbGQqIEVmZmVjdC5hbGwoW1xuICAgICAgICAgIEVmZmVjdC5mcm9tRmliZXIoc3Rkb3V0RmliZXIpLFxuICAgICAgICAgIEVmZmVjdC5mcm9tRmliZXIoc3RkZXJyRmliZXIpLFxuICAgICAgICBdKVxuXG4gICAgICAgIGNvbnN0IGV4aXRDb2RlID0geWllbGQqIHByb2MuZXhpdENvZGVcblxuICAgICAgICAvLyBPbmx5IHN1cHByZXNzIHdhcm5pbmdzIGZvciBleHBlY3RlZCBleGl0IGNvZGVzOlxuICAgICAgICAvLyAtIDA6IENsZWFuIGV4aXRcbiAgICAgICAgLy8gLSAxOiBMYW1iZGEgUklDIGV4aXQgYWZ0ZXIgNTAzIHBvbGwgdGltZW91dCAoZXhwZWN0ZWQpXG4gICAgICAgIC8vIC0gMTQzICgxMjgrMTUpOiBTSUdURVJNIGZyb20gZG9ja2VyIHN0b3BcbiAgICAgICAgLy8gLSAxMzcgKDEyOCs5KTogU0lHS0lMTCBmcm9tIGRvY2tlciBzdG9wIHRpbWVvdXRcbiAgICAgICAgY29uc3QgZXhwZWN0ZWRFeGl0Q29kZXMgPSBbMCwgMSwgMTQzLCAxMzddXG4gICAgICAgIGlmICghZXhwZWN0ZWRFeGl0Q29kZXMuaW5jbHVkZXMoZXhpdENvZGUpKSB7XG4gICAgICAgICAgeWllbGQqIEVmZmVjdC5sb2dXYXJuaW5nKGBDb250YWluZXIgZXhpdGVkIHdpdGggY29kZSAke2V4aXRDb2RlfWApXG4gICAgICAgIH0gZWxzZSBpZiAoZXhpdENvZGUgIT09IDApIHtcbiAgICAgICAgICB5aWVsZCogRWZmZWN0LmxvZ0RlYnVnKGBDb250YWluZXIgZXhpdGVkIHdpdGggY29kZSAke2V4aXRDb2RlfWApXG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGV4aXRDb2RlLFxuICAgICAgICAgIHN0ZG91dDogc3Rkb3V0LmpvaW4oXCJcXG5cIiksXG4gICAgICAgICAgc3RkZXJyOiBzdGRlcnIuam9pbihcIlxcblwiKSxcbiAgICAgICAgfVxuICAgICAgfSlcblxuICAgIGNvbnN0IHJ1blNjb3BlZDogRG9ja2VyU2VydmljZVtcInJ1blNjb3BlZFwiXSA9IChjb25maWcpID0+XG4gICAgICBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG4gICAgICAgIGNvbnN0IGFyZ3MgPSBidWlsZERvY2tlclJ1bkFyZ3MoY29uZmlnLCBydW50aW1lKVxuXG4gICAgICAgIHlpZWxkKiBFZmZlY3QubG9nSW5mbyhgUnVubmluZyAoc2NvcGVkKTogZG9ja2VyICR7YXJncy5qb2luKFwiIFwiKX1gKVxuXG4gICAgICAgIGNvbnN0IGNvbW1hbmQgPSBQbGF0Zm9ybUNvbW1hbmQubWFrZShydW50aW1lLmRvY2tlclBhdGgsIC4uLmFyZ3MpXG5cbiAgICAgICAgY29uc3QgcHJvYyA9IHlpZWxkKiBQbGF0Zm9ybUNvbW1hbmQuc3RhcnQoY29tbWFuZClcblxuICAgICAgICAvLyBGb3JrIG91dHB1dCBwcm9jZXNzaW5nIGluIGJhY2tncm91bmQgKHdpbGwgYmUgaW50ZXJydXB0ZWQgd2hlbiBzY29wZSBjbG9zZXMpXG4gICAgICAgIHlpZWxkKiBwcm9jLnN0ZG91dC5waXBlKFxuICAgICAgICAgIFN0cmVhbS5kZWNvZGVUZXh0KCksXG4gICAgICAgICAgU3RyZWFtLnNwbGl0TGluZXMsXG4gICAgICAgICAgU3RyZWFtLnJ1bkZvckVhY2goKGxpbmUpID0+XG4gICAgICAgICAgICBFZmZlY3Quc3luYygoKSA9PiB7XG4gICAgICAgICAgICAgIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGBbQ29udGFpbmVyXSAke2xpbmV9XFxuYClcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICksXG4gICAgICAgICAgRWZmZWN0LmZvcmssXG4gICAgICAgIClcblxuICAgICAgICB5aWVsZCogcHJvYy5zdGRlcnIucGlwZShcbiAgICAgICAgICBTdHJlYW0uZGVjb2RlVGV4dCgpLFxuICAgICAgICAgIFN0cmVhbS5zcGxpdExpbmVzLFxuICAgICAgICAgIFN0cmVhbS5ydW5Gb3JFYWNoKChsaW5lKSA9PlxuICAgICAgICAgICAgRWZmZWN0LnN5bmMoKCkgPT4ge1xuICAgICAgICAgICAgICBwcm9jZXNzLnN0ZGVyci53cml0ZShgW0NvbnRhaW5lcl0gJHtsaW5lfVxcbmApXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApLFxuICAgICAgICAgIEVmZmVjdC5mb3JrLFxuICAgICAgICApXG5cbiAgICAgICAgcmV0dXJuIHByb2NcbiAgICAgIH0pXG5cbiAgICBjb25zdCBidWlsZDogRG9ja2VyU2VydmljZVtcImJ1aWxkXCJdID0gKG9wdGlvbnMpID0+XG4gICAgICBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG4gICAgICAgIGNvbnN0IGFyZ3MgPSBbXG4gICAgICAgICAgXCJidWlsZFwiLFxuICAgICAgICAgIFwiLXRcIixcbiAgICAgICAgICBvcHRpb25zLmltYWdlTmFtZSxcbiAgICAgICAgICBcIi0tcGxhdGZvcm1cIixcbiAgICAgICAgICBvcHRpb25zLnBsYXRmb3JtID8/IFwibGludXgvYXJtNjRcIixcbiAgICAgICAgICBvcHRpb25zLmNvbnRleHRQYXRoLFxuICAgICAgICBdXG5cbiAgICAgICAgeWllbGQqIEVmZmVjdC5sb2dJbmZvKGBCdWlsZGluZyBpbWFnZTogJHtvcHRpb25zLmltYWdlTmFtZX1gKVxuICAgICAgICB5aWVsZCogRWZmZWN0LmxvZ0RlYnVnKGBDb250ZXh0OiAke29wdGlvbnMuY29udGV4dFBhdGh9YClcblxuICAgICAgICBjb25zdCBjb21tYW5kID0gUGxhdGZvcm1Db21tYW5kLm1ha2UocnVudGltZS5kb2NrZXJQYXRoLCAuLi5hcmdzKVxuXG4gICAgICAgIGNvbnN0IHByb2MgPSB5aWVsZCogUGxhdGZvcm1Db21tYW5kLnN0YXJ0KGNvbW1hbmQpXG5cbiAgICAgICAgLy8gUHJvY2VzcyBzdGRvdXQgKGRlYnVnIG9ubHkpXG4gICAgICAgIGNvbnN0IHN0ZG91dEZpYmVyID0geWllbGQqIHByb2Muc3Rkb3V0LnBpcGUoXG4gICAgICAgICAgU3RyZWFtLmRlY29kZVRleHQoKSxcbiAgICAgICAgICBTdHJlYW0uc3BsaXRMaW5lcyxcbiAgICAgICAgICBTdHJlYW0ucnVuRm9yRWFjaCgobGluZSkgPT4gRWZmZWN0LmxvZ0RlYnVnKGBbRG9ja2VyXSAke2xpbmV9YCkpLFxuICAgICAgICAgIEVmZmVjdC5mb3JrLFxuICAgICAgICApXG5cbiAgICAgICAgLy8gUHJvY2VzcyBzdGRlcnIgKGRlYnVnIG9ubHkpXG4gICAgICAgIGNvbnN0IHN0ZGVyckZpYmVyID0geWllbGQqIHByb2Muc3RkZXJyLnBpcGUoXG4gICAgICAgICAgU3RyZWFtLmRlY29kZVRleHQoKSxcbiAgICAgICAgICBTdHJlYW0uc3BsaXRMaW5lcyxcbiAgICAgICAgICBTdHJlYW0ucnVuRm9yRWFjaCgobGluZSkgPT4gRWZmZWN0LmxvZ0RlYnVnKGBbRG9ja2VyXSAke2xpbmV9YCkpLFxuICAgICAgICAgIEVmZmVjdC5mb3JrLFxuICAgICAgICApXG5cbiAgICAgICAgLy8gV2FpdCBmb3Igc3RyZWFtcyBhbmQgZXhpdCBjb2RlXG4gICAgICAgIHlpZWxkKiBFZmZlY3QuYWxsKFtcbiAgICAgICAgICBFZmZlY3QuZnJvbUZpYmVyKHN0ZG91dEZpYmVyKSxcbiAgICAgICAgICBFZmZlY3QuZnJvbUZpYmVyKHN0ZGVyckZpYmVyKSxcbiAgICAgICAgXSlcblxuICAgICAgICBjb25zdCBleGl0Q29kZSA9IHlpZWxkKiBwcm9jLmV4aXRDb2RlXG5cbiAgICAgICAgaWYgKGV4aXRDb2RlICE9PSAwKSB7XG4gICAgICAgICAgcmV0dXJuIHlpZWxkKiBFZmZlY3QuZmFpbChcbiAgICAgICAgICAgIG5ldyBFcnJvcihgRG9ja2VyIGJ1aWxkIGZhaWxlZCB3aXRoIGNvZGUgJHtleGl0Q29kZX1gKSxcbiAgICAgICAgICApXG4gICAgICAgIH1cblxuICAgICAgICB5aWVsZCogRWZmZWN0LmxvZ0luZm8oYEJ1aWx0IGltYWdlOiAke29wdGlvbnMuaW1hZ2VOYW1lfWApXG4gICAgICB9KVxuXG4gICAgY29uc3QgcHVsbDogRG9ja2VyU2VydmljZVtcInB1bGxcIl0gPSAoaW1hZ2VVcmkpID0+XG4gICAgICBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG4gICAgICAgIHlpZWxkKiBFZmZlY3QubG9nSW5mbyhgUHVsbGluZyBpbWFnZTogJHtpbWFnZVVyaX1gKVxuXG4gICAgICAgIGNvbnN0IGNvbW1hbmQgPSBQbGF0Zm9ybUNvbW1hbmQubWFrZShcbiAgICAgICAgICBydW50aW1lLmRvY2tlclBhdGgsXG4gICAgICAgICAgXCJwdWxsXCIsXG4gICAgICAgICAgaW1hZ2VVcmksXG4gICAgICAgIClcblxuICAgICAgICBjb25zdCBwcm9jID0geWllbGQqIFBsYXRmb3JtQ29tbWFuZC5zdGFydChjb21tYW5kKVxuXG4gICAgICAgIC8vIFByb2Nlc3Mgc3Rkb3V0IChkZWJ1ZyBvbmx5KVxuICAgICAgICBjb25zdCBzdGRvdXRGaWJlciA9IHlpZWxkKiBwcm9jLnN0ZG91dC5waXBlKFxuICAgICAgICAgIFN0cmVhbS5kZWNvZGVUZXh0KCksXG4gICAgICAgICAgU3RyZWFtLnNwbGl0TGluZXMsXG4gICAgICAgICAgU3RyZWFtLnJ1bkZvckVhY2goKGxpbmUpID0+IEVmZmVjdC5sb2dEZWJ1ZyhgW0RvY2tlcl0gJHtsaW5lfWApKSxcbiAgICAgICAgICBFZmZlY3QuZm9yayxcbiAgICAgICAgKVxuXG4gICAgICAgIC8vIFByb2Nlc3Mgc3RkZXJyIChkZWJ1ZyBvbmx5KVxuICAgICAgICBjb25zdCBzdGRlcnJGaWJlciA9IHlpZWxkKiBwcm9jLnN0ZGVyci5waXBlKFxuICAgICAgICAgIFN0cmVhbS5kZWNvZGVUZXh0KCksXG4gICAgICAgICAgU3RyZWFtLnNwbGl0TGluZXMsXG4gICAgICAgICAgU3RyZWFtLnJ1bkZvckVhY2goKGxpbmUpID0+IEVmZmVjdC5sb2dEZWJ1ZyhgW0RvY2tlcl0gJHtsaW5lfWApKSxcbiAgICAgICAgICBFZmZlY3QuZm9yayxcbiAgICAgICAgKVxuXG4gICAgICAgIC8vIFdhaXQgZm9yIHN0cmVhbXMgYW5kIGV4aXQgY29kZVxuICAgICAgICB5aWVsZCogRWZmZWN0LmFsbChbXG4gICAgICAgICAgRWZmZWN0LmZyb21GaWJlcihzdGRvdXRGaWJlciksXG4gICAgICAgICAgRWZmZWN0LmZyb21GaWJlcihzdGRlcnJGaWJlciksXG4gICAgICAgIF0pXG5cbiAgICAgICAgY29uc3QgZXhpdENvZGUgPSB5aWVsZCogcHJvYy5leGl0Q29kZVxuXG4gICAgICAgIGlmIChleGl0Q29kZSAhPT0gMCkge1xuICAgICAgICAgIHJldHVybiB5aWVsZCogRWZmZWN0LmZhaWwoXG4gICAgICAgICAgICBuZXcgRXJyb3IoYERvY2tlciBwdWxsIGZhaWxlZCB3aXRoIGNvZGUgJHtleGl0Q29kZX1gKSxcbiAgICAgICAgICApXG4gICAgICAgIH1cblxuICAgICAgICB5aWVsZCogRWZmZWN0LmxvZ0luZm8oYFB1bGxlZCBpbWFnZTogJHtpbWFnZVVyaX1gKVxuICAgICAgfSlcblxuICAgIGNvbnN0IGxpc3Q6IERvY2tlclNlcnZpY2VbXCJsaXN0XCJdID0gKGNvbnRhaW5lck5hbWVGaWx0ZXIpID0+XG4gICAgICBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG4gICAgICAgIGNvbnN0IGNvbW1hbmQgPSBQbGF0Zm9ybUNvbW1hbmQubWFrZShcbiAgICAgICAgICBydW50aW1lLmRvY2tlclBhdGgsXG4gICAgICAgICAgXCJwc1wiLFxuICAgICAgICAgIFwiLXFcIixcbiAgICAgICAgICBcIi0tZmlsdGVyXCIsXG4gICAgICAgICAgYG5hbWU9JHtjb250YWluZXJOYW1lRmlsdGVyfWAsXG4gICAgICAgIClcblxuICAgICAgICBjb25zdCBwcm9jID0geWllbGQqIFBsYXRmb3JtQ29tbWFuZC5zdGFydChjb21tYW5kKVxuXG4gICAgICAgIC8vIENvbGxlY3Qgc3Rkb3V0XG4gICAgICAgIGNvbnN0IGNvbnRhaW5lcklkczogc3RyaW5nW10gPSBbXVxuICAgICAgICB5aWVsZCogcHJvYy5zdGRvdXQucGlwZShcbiAgICAgICAgICBTdHJlYW0uZGVjb2RlVGV4dCgpLFxuICAgICAgICAgIFN0cmVhbS5zcGxpdExpbmVzLFxuICAgICAgICAgIFN0cmVhbS5ydW5Gb3JFYWNoKChsaW5lKSA9PlxuICAgICAgICAgICAgRWZmZWN0LnN5bmMoKCkgPT4ge1xuICAgICAgICAgICAgICBjb25zdCB0cmltbWVkID0gbGluZS50cmltKClcbiAgICAgICAgICAgICAgaWYgKHRyaW1tZWQpIHtcbiAgICAgICAgICAgICAgICBjb250YWluZXJJZHMucHVzaCh0cmltbWVkKVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApLFxuICAgICAgICApXG5cbiAgICAgICAgY29uc3QgZXhpdENvZGUgPSB5aWVsZCogcHJvYy5leGl0Q29kZVxuXG4gICAgICAgIGlmIChleGl0Q29kZSAhPT0gMCkge1xuICAgICAgICAgIHJldHVybiB5aWVsZCogRWZmZWN0LmZhaWwoXG4gICAgICAgICAgICBuZXcgRXJyb3IoYERvY2tlciBwcyBmYWlsZWQgd2l0aCBjb2RlICR7ZXhpdENvZGV9YCksXG4gICAgICAgICAgKVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNvbnRhaW5lcklkc1xuICAgICAgfSlcblxuICAgIGNvbnN0IHN0b3A6IERvY2tlclNlcnZpY2VbXCJzdG9wXCJdID0gKGNvbnRhaW5lck5hbWVGaWx0ZXIsIHRpbWVvdXRTZWNvbmRzKSA9PlxuICAgICAgRWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuICAgICAgICAvLyBGaXJzdCBsaXN0IG1hdGNoaW5nIGNvbnRhaW5lcnNcbiAgICAgICAgY29uc3QgY29udGFpbmVySWRzID0geWllbGQqIGxpc3QoY29udGFpbmVyTmFtZUZpbHRlcilcblxuICAgICAgICBpZiAoY29udGFpbmVySWRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgIHlpZWxkKiBFZmZlY3QubG9nRGVidWcoXG4gICAgICAgICAgICBgTm8gY29udGFpbmVycyBmb3VuZCBtYXRjaGluZzogJHtjb250YWluZXJOYW1lRmlsdGVyfWAsXG4gICAgICAgICAgKVxuICAgICAgICAgIHJldHVybiAwXG4gICAgICAgIH1cblxuICAgICAgICB5aWVsZCogRWZmZWN0LmxvZ0luZm8oYFN0b3BwaW5nIGNvbnRhaW5lcnM6ICR7Y29udGFpbmVySWRzLmpvaW4oXCIsIFwiKX1gKVxuXG4gICAgICAgIC8vIEJ1aWxkIHN0b3AgY29tbWFuZCB3aXRoIG9wdGlvbmFsIHRpbWVvdXRcbiAgICAgICAgLy8gLXQgMCBzZW5kcyBTSUdLSUxMIGltbWVkaWF0ZWx5LCB1c2VmdWwgZm9yIGZhc3QgcmVzdGFydHNcbiAgICAgICAgY29uc3QgdGltZW91dEFyZyA9XG4gICAgICAgICAgdGltZW91dFNlY29uZHMgIT09IHVuZGVmaW5lZCA/IFtcIi10XCIsIFN0cmluZyh0aW1lb3V0U2Vjb25kcyldIDogW11cbiAgICAgICAgY29uc3QgY29tbWFuZCA9IFBsYXRmb3JtQ29tbWFuZC5tYWtlKFxuICAgICAgICAgIHJ1bnRpbWUuZG9ja2VyUGF0aCxcbiAgICAgICAgICBcInN0b3BcIixcbiAgICAgICAgICAuLi50aW1lb3V0QXJnLFxuICAgICAgICAgIC4uLmNvbnRhaW5lcklkcyxcbiAgICAgICAgKVxuXG4gICAgICAgIGNvbnN0IHByb2MgPSB5aWVsZCogUGxhdGZvcm1Db21tYW5kLnN0YXJ0KGNvbW1hbmQpXG5cbiAgICAgICAgLy8gUHJvY2VzcyBvdXRwdXQgZm9yIGxvZ2dpbmdcbiAgICAgICAgeWllbGQqIHByb2Muc3Rkb3V0LnBpcGUoXG4gICAgICAgICAgU3RyZWFtLmRlY29kZVRleHQoKSxcbiAgICAgICAgICBTdHJlYW0uc3BsaXRMaW5lcyxcbiAgICAgICAgICBTdHJlYW0ucnVuRm9yRWFjaCgobGluZSkgPT5cbiAgICAgICAgICAgIEVmZmVjdC5sb2dEZWJ1ZyhgW0RvY2tlciBzdG9wXSAke2xpbmUudHJpbSgpfWApLFxuICAgICAgICAgICksXG4gICAgICAgIClcblxuICAgICAgICBjb25zdCBleGl0Q29kZSA9IHlpZWxkKiBwcm9jLmV4aXRDb2RlXG5cbiAgICAgICAgaWYgKGV4aXRDb2RlICE9PSAwKSB7XG4gICAgICAgICAgeWllbGQqIEVmZmVjdC5sb2dXYXJuaW5nKFxuICAgICAgICAgICAgYERvY2tlciBzdG9wIGV4aXRlZCB3aXRoIGNvZGUgJHtleGl0Q29kZX0gKHNvbWUgY29udGFpbmVycyBtYXkgaGF2ZSBhbHJlYWR5IHN0b3BwZWQpYCxcbiAgICAgICAgICApXG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY29udGFpbmVySWRzLmxlbmd0aFxuICAgICAgfSlcblxuICAgIGNvbnN0IGluc3BlY3Q6IERvY2tlclNlcnZpY2VbXCJpbnNwZWN0XCJdID0gKGltYWdlVXJpKSA9PlxuICAgICAgRWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuICAgICAgICBjb25zdCBleGVjdXRvciA9IHlpZWxkKiBDb21tYW5kRXhlY3V0b3IuQ29tbWFuZEV4ZWN1dG9yXG5cbiAgICAgICAgLy8gR2V0IGVudHJ5cG9pbnRcbiAgICAgICAgY29uc3QgZW50cnlwb2ludENtZCA9IFBsYXRmb3JtQ29tbWFuZC5tYWtlKFxuICAgICAgICAgIHJ1bnRpbWUuZG9ja2VyUGF0aCxcbiAgICAgICAgICBcImluc3BlY3RcIixcbiAgICAgICAgICBcIi0tZm9ybWF0XCIsXG4gICAgICAgICAgXCJ7e2pzb24gLkNvbmZpZy5FbnRyeXBvaW50fX1cIixcbiAgICAgICAgICBpbWFnZVVyaSxcbiAgICAgICAgKVxuICAgICAgICBjb25zdCBlbnRyeXBvaW50UHJvYyA9IHlpZWxkKiBleGVjdXRvci5zdGFydChlbnRyeXBvaW50Q21kKVxuICAgICAgICBjb25zdCBlbnRyeXBvaW50T3V0cHV0ID0geWllbGQqIFN0cmVhbS5ydW5Db2xsZWN0KFxuICAgICAgICAgIFN0cmVhbS5kZWNvZGVUZXh0KGVudHJ5cG9pbnRQcm9jLnN0ZG91dCksXG4gICAgICAgIClcbiAgICAgICAgY29uc3QgZW50cnlwb2ludEV4aXRDb2RlID0geWllbGQqIGVudHJ5cG9pbnRQcm9jLmV4aXRDb2RlXG4gICAgICAgIGlmIChlbnRyeXBvaW50RXhpdENvZGUgIT09IDApIHtcbiAgICAgICAgICB5aWVsZCogRWZmZWN0LmZhaWwoXG4gICAgICAgICAgICBuZXcgRXJyb3IoYEZhaWxlZCB0byBpbnNwZWN0IGltYWdlIGVudHJ5cG9pbnQ6ICR7aW1hZ2VVcml9YCksXG4gICAgICAgICAgKVxuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGVudHJ5cG9pbnRKc29uID0gQXJyYXkuZnJvbShlbnRyeXBvaW50T3V0cHV0KS5qb2luKFwiXCIpLnRyaW0oKVxuXG4gICAgICAgIC8vIEdldCBjbWRcbiAgICAgICAgY29uc3QgY21kQ21kID0gUGxhdGZvcm1Db21tYW5kLm1ha2UoXG4gICAgICAgICAgcnVudGltZS5kb2NrZXJQYXRoLFxuICAgICAgICAgIFwiaW5zcGVjdFwiLFxuICAgICAgICAgIFwiLS1mb3JtYXRcIixcbiAgICAgICAgICBcInt7anNvbiAuQ29uZmlnLkNtZH19XCIsXG4gICAgICAgICAgaW1hZ2VVcmksXG4gICAgICAgIClcbiAgICAgICAgY29uc3QgY21kUHJvYyA9IHlpZWxkKiBleGVjdXRvci5zdGFydChjbWRDbWQpXG4gICAgICAgIGNvbnN0IGNtZE91dHB1dCA9IHlpZWxkKiBTdHJlYW0ucnVuQ29sbGVjdChcbiAgICAgICAgICBTdHJlYW0uZGVjb2RlVGV4dChjbWRQcm9jLnN0ZG91dCksXG4gICAgICAgIClcbiAgICAgICAgY29uc3QgY21kRXhpdENvZGUgPSB5aWVsZCogY21kUHJvYy5leGl0Q29kZVxuICAgICAgICBpZiAoY21kRXhpdENvZGUgIT09IDApIHtcbiAgICAgICAgICB5aWVsZCogRWZmZWN0LmZhaWwoXG4gICAgICAgICAgICBuZXcgRXJyb3IoYEZhaWxlZCB0byBpbnNwZWN0IGltYWdlIGNtZDogJHtpbWFnZVVyaX1gKSxcbiAgICAgICAgICApXG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgY21kSnNvbiA9IEFycmF5LmZyb20oY21kT3V0cHV0KS5qb2luKFwiXCIpLnRyaW0oKVxuXG4gICAgICAgIC8vIFBhcnNlIEpTT04gLSBudWxsIGlzIHZhbGlkLCBzbyBoYW5kbGUgdGhhdFxuICAgICAgICBjb25zdCBwYXJzZUpzb25BcnJheSA9IChqc29uOiBzdHJpbmcpOiBzdHJpbmdbXSB8IG51bGwgPT4ge1xuICAgICAgICAgIGlmIChqc29uID09PSBcIm51bGxcIiB8fCBqc29uID09PSBcIlwiKSByZXR1cm4gbnVsbFxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBwYXJzZWQgPSBKU09OLnBhcnNlKGpzb24pXG4gICAgICAgICAgICByZXR1cm4gQXJyYXkuaXNBcnJheShwYXJzZWQpID8gcGFyc2VkIDogbnVsbFxuICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgcmV0dXJuIG51bGxcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGVudHJ5cG9pbnQ6IHBhcnNlSnNvbkFycmF5KGVudHJ5cG9pbnRKc29uKSxcbiAgICAgICAgICBjbWQ6IHBhcnNlSnNvbkFycmF5KGNtZEpzb24pLFxuICAgICAgICB9XG4gICAgICB9KVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHJ1bixcbiAgICAgIHJ1blNjb3BlZCxcbiAgICAgIGJ1aWxkLFxuICAgICAgcHVsbCxcbiAgICAgIHN0b3AsXG4gICAgICBsaXN0LFxuICAgICAgZ2V0UnVudGltZUluZm8sXG4gICAgICBpbnNwZWN0LFxuICAgIH0gc2F0aXNmaWVzIERvY2tlclNlcnZpY2VcbiAgfSxcbilcblxuLyoqXG4gKiBMaXZlIERvY2tlciBzZXJ2aWNlIGxheWVyLlxuICogTm90ZTogRG9lcyBub3QgcmVxdWlyZSBDb21tYW5kRXhlY3V0b3IgaW4gdGhlIGxheWVyIC0gaXQncyByZXF1aXJlZFxuICogd2hlbiB0aGUgc2VydmljZSBtZXRob2RzIGFyZSBjYWxsZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBEb2NrZXJMaXZlOiBMYXllci5MYXllcjxEb2NrZXIsIEVycm9yPiA9IExheWVyLmVmZmVjdChcbiAgRG9ja2VyLFxuICBtYWtlRG9ja2VyU2VydmljZSxcbilcblxuLyoqXG4gKiBDcmVhdGUgYSBjb250YWluZXIgY29uZmlnIGZvciBydW5uaW5nIGEgTGFtYmRhIGNvbnRhaW5lci5cbiAqL1xuZXhwb3J0IGNvbnN0IG1ha2VMYW1iZGFDb250YWluZXJDb25maWcgPSAob3B0aW9uczoge1xuICBpbWFnZVVyaTogc3RyaW5nXG4gIHJ1bnRpbWVBcGlIb3N0OiBzdHJpbmdcbiAgcnVudGltZUFwaVBvcnQ6IG51bWJlclxuICBmdW5jdGlvbk5hbWU6IHN0cmluZ1xuICBmdW5jdGlvblZlcnNpb246IHN0cmluZ1xuICBtZW1vcnlNQjogbnVtYmVyXG4gIHRpbWVvdXRTZWNvbmRzOiBudW1iZXJcbiAgaGFuZGxlcj86IHN0cmluZ1xuICBhd3NSZWdpb24/OiBzdHJpbmdcbiAgcGxhdGZvcm0/OiBzdHJpbmdcbiAgYWRkaXRpb25hbEVudj86IFJlY29yZDxzdHJpbmcsIHN0cmluZz5cbiAgaW52b2NhdGlvbkNvbnRleHRzPzogTWFwPHN0cmluZywgeyBudW06IG51bWJlciB9PlxufSk6IERvY2tlclJ1bkNvbmZpZyA9PiAoe1xuICBpbWFnZVVyaTogb3B0aW9ucy5pbWFnZVVyaSxcbiAgY29udGFpbmVyTmFtZTogYGxhbWJkYS0ke29wdGlvbnMuZnVuY3Rpb25OYW1lLnJlcGxhY2UoL1teYS16QS1aMC05XS9nLCBcIi1cIil9YCxcbiAgcGxhdGZvcm06IG9wdGlvbnMucGxhdGZvcm0sXG4gIGVudmlyb25tZW50OiB7XG4gICAgQVdTX0xBTUJEQV9SVU5USU1FX0FQSTogYCR7b3B0aW9ucy5ydW50aW1lQXBpSG9zdH06JHtvcHRpb25zLnJ1bnRpbWVBcGlQb3J0fWAsXG4gICAgQVdTX0xBTUJEQV9GVU5DVElPTl9OQU1FOiBvcHRpb25zLmZ1bmN0aW9uTmFtZSxcbiAgICBBV1NfTEFNQkRBX0ZVTkNUSU9OX1ZFUlNJT046IG9wdGlvbnMuZnVuY3Rpb25WZXJzaW9uLFxuICAgIEFXU19MQU1CREFfRlVOQ1RJT05fTUVNT1JZX1NJWkU6IFN0cmluZyhvcHRpb25zLm1lbW9yeU1CKSxcbiAgICBBV1NfUkVHSU9OOiBvcHRpb25zLmF3c1JlZ2lvbiA/PyBcInVzLWVhc3QtMVwiLFxuICAgIEFXU19ERUZBVUxUX1JFR0lPTjogb3B0aW9ucy5hd3NSZWdpb24gPz8gXCJ1cy1lYXN0LTFcIixcbiAgICBBV1NfTEFNQkRBX0xPR19HUk9VUF9OQU1FOiBgL2F3cy9sYW1iZGEvJHtvcHRpb25zLmZ1bmN0aW9uTmFtZX1gLFxuICAgIEFXU19MQU1CREFfTE9HX1NUUkVBTV9OQU1FOiBcImxvY2FsXCIsXG4gICAgX0hBTkRMRVI6IG9wdGlvbnMuaGFuZGxlciA/PyBcImluZGV4LmhhbmRsZXJcIixcbiAgICAuLi5vcHRpb25zLmFkZGl0aW9uYWxFbnYsXG4gIH0sXG4gIG1lbW9yeU1COiBvcHRpb25zLm1lbW9yeU1CLFxuICB0aW1lb3V0U2Vjb25kczogb3B0aW9ucy50aW1lb3V0U2Vjb25kcyxcbiAgbmV0d29ya01vZGU6IFwiYnJpZGdlXCIsXG4gIGludm9jYXRpb25Db250ZXh0czogb3B0aW9ucy5pbnZvY2F0aW9uQ29udGV4dHMsXG59KVxuXG4vKipcbiAqIFN0cmVhbSBvdXRwdXQgZnJvbSBhIERvY2tlciBjb250YWluZXIuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29udGFpbmVyT3V0cHV0IHtcbiAgdHlwZTogXCJzdGRvdXRcIiB8IFwic3RkZXJyXCJcbiAgZGF0YTogc3RyaW5nXG59XG5cbi8qKlxuICogU2hlbGwtcXVvdGUgYSBzdHJpbmcgZm9yIHNhZmUgaW5jbHVzaW9uIGluIGEgc2hlbGwgY29tbWFuZC5cbiAqIFVzZXMgc2luZ2xlIHF1b3RlcyBhbmQgZXNjYXBlcyBhbnkgZW1iZWRkZWQgc2luZ2xlIHF1b3Rlcy5cbiAqL1xuY29uc3Qgc2hlbGxRdW90ZSA9IChzOiBzdHJpbmcpOiBzdHJpbmcgPT4ge1xuICAvLyBTaW5nbGUgcXVvdGVzIGFyZSBzYWZlc3QgLSBlc2NhcGUgYW55IGVtYmVkZGVkIHNpbmdsZSBxdW90ZXNcbiAgcmV0dXJuIGAnJHtzLnJlcGxhY2UoLycvZywgXCInXFxcXCcnXCIpfSdgXG59XG5cbi8qKlxuICogQnVpbGQgYSB3cmFwcGVyIGNvbW1hbmQgdGhhdCBzdGFydHMgTGFtYmRhIGV4dGVuc2lvbnMgYmVmb3JlIHRoZSBtYWluIGFwcC5cbiAqXG4gKiBUaGlzIG1pbWljcyBBV1MgTGFtYmRhJ3MgYmVoYXZpb3Igb2YgYXV0b21hdGljYWxseSBzdGFydGluZyBhbGwgZXhlY3V0YWJsZXNcbiAqIGluIC9vcHQvZXh0ZW5zaW9ucy8gYXMgYmFja2dyb3VuZCBwcm9jZXNzZXMgYmVmb3JlIHJ1bm5pbmcgdGhlIG1haW4gY29tbWFuZC5cbiAqXG4gKiBAcGFyYW0gb3JpZ2luYWxFbnRyeXBvaW50IC0gVGhlIGltYWdlJ3Mgb3JpZ2luYWwgRU5UUllQT0lOVFxuICogQHBhcmFtIG9yaWdpbmFsQ21kIC0gVGhlIGltYWdlJ3Mgb3JpZ2luYWwgQ01EXG4gKiBAcmV0dXJucyBFbnRyeXBvaW50IGFuZCBjb21tYW5kIGFycmF5cyB0byBwYXNzIHRvIERvY2tlclxuICovXG5leHBvcnQgY29uc3QgYnVpbGRFeHRlbnNpb25XcmFwcGVyQ29tbWFuZCA9IChcbiAgb3JpZ2luYWxFbnRyeXBvaW50OiBzdHJpbmdbXSB8IG51bGwsXG4gIG9yaWdpbmFsQ21kOiBzdHJpbmdbXSB8IG51bGwsXG4pOiB7IGVudHJ5cG9pbnQ6IHN0cmluZ1tdOyBjb21tYW5kOiBzdHJpbmdbXSB9ID0+IHtcbiAgLy8gQ29tYmluZSBvcmlnaW5hbCBlbnRyeXBvaW50ICsgY21kIGludG8gdGhlIGZ1bGwgY29tbWFuZFxuICAvLyBEb2NrZXIgYmVoYXZpb3I6IEVOVFJZUE9JTlQgKyBDTUQgYXJlIGNvbmNhdGVuYXRlZFxuICBjb25zdCBvcmlnaW5hbENvbW1hbmQgPSBbXG4gICAgLi4uKG9yaWdpbmFsRW50cnlwb2ludCA/PyBbXSksXG4gICAgLi4uKG9yaWdpbmFsQ21kID8/IFtdKSxcbiAgXVxuXG4gIC8vIFNjcmlwdCB0byBzdGFydCBhbGwgZXhlY3V0YWJsZSBmaWxlcyBpbiAvb3B0L2V4dGVuc2lvbnMvIGFzIGJhY2tncm91bmQgcHJvY2Vzc2VzXG4gIGNvbnN0IGV4dGVuc2lvblN0YXJ0ZXIgPVxuICAgICdmb3IgZXh0IGluIC9vcHQvZXh0ZW5zaW9ucy8qOyBkbyBbIC14IFwiJGV4dFwiIF0gJiYgXCIkZXh0XCIgJiBkb25lJ1xuXG4gIC8vIEJ1aWxkIHRoZSBmdWxsIHdyYXBwZXIgY29tbWFuZFxuICBsZXQgZnVsbENvbW1hbmQ6IHN0cmluZ1xuICBpZiAob3JpZ2luYWxDb21tYW5kLmxlbmd0aCA+IDApIHtcbiAgICAvLyBRdW90ZSBlYWNoIGFyZ3VtZW50IGFuZCBqb2luIHdpdGggc3BhY2VzXG4gICAgY29uc3QgcXVvdGVkT3JpZ2luYWwgPSBvcmlnaW5hbENvbW1hbmQubWFwKHNoZWxsUXVvdGUpLmpvaW4oXCIgXCIpXG4gICAgLy8gU3RhcnQgZXh0ZW5zaW9ucywgdGhlbiBleGVjIHRoZSBvcmlnaW5hbCBjb21tYW5kXG4gICAgZnVsbENvbW1hbmQgPSBgJHtleHRlbnNpb25TdGFydGVyfTsgZXhlYyAke3F1b3RlZE9yaWdpbmFsfWBcbiAgfSBlbHNlIHtcbiAgICAvLyBObyBvcmlnaW5hbCBjb21tYW5kIC0ganVzdCBzdGFydCBleHRlbnNpb25zICh1bnVzdWFsIGJ1dCBoYW5kbGUgaXQpXG4gICAgZnVsbENvbW1hbmQgPSBleHRlbnNpb25TdGFydGVyXG4gIH1cblxuICByZXR1cm4ge1xuICAgIGVudHJ5cG9pbnQ6IFtcIi9iaW4vc2hcIl0sXG4gICAgY29tbWFuZDogW1wiLWNcIiwgZnVsbENvbW1hbmRdLFxuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for Docker container management.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Configuration for running a Docker container.
|
|
6
|
+
*/
|
|
7
|
+
export interface DockerRunConfig {
|
|
8
|
+
/** The Docker image URI to run */
|
|
9
|
+
imageUri: string;
|
|
10
|
+
/** Container name (optional) */
|
|
11
|
+
containerName?: string;
|
|
12
|
+
/** Platform (e.g., linux/arm64, linux/amd64) for cross-platform execution */
|
|
13
|
+
platform?: string;
|
|
14
|
+
/** Environment variables to pass to the container */
|
|
15
|
+
environment: Record<string, string>;
|
|
16
|
+
/** Memory limit in MB */
|
|
17
|
+
memoryMB: number;
|
|
18
|
+
/** Timeout in seconds */
|
|
19
|
+
timeoutSeconds: number;
|
|
20
|
+
/** Network mode (bridge, host, none) */
|
|
21
|
+
networkMode: "bridge" | "host" | "none";
|
|
22
|
+
/** Extra host entries (--add-host) */
|
|
23
|
+
extraHosts?: string[];
|
|
24
|
+
/** Working directory inside the container */
|
|
25
|
+
workdir?: string;
|
|
26
|
+
/** Additional Docker run arguments */
|
|
27
|
+
additionalArgs?: string[];
|
|
28
|
+
/** Optional invocation context map for log prefixing (requestId -> { num }) */
|
|
29
|
+
invocationContexts?: Map<string, {
|
|
30
|
+
num: number;
|
|
31
|
+
}>;
|
|
32
|
+
/** Override the container's entrypoint */
|
|
33
|
+
entrypoint?: string[];
|
|
34
|
+
/** Override the container's command (arguments after the image) */
|
|
35
|
+
command?: string[];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Docker image configuration from inspection.
|
|
39
|
+
*/
|
|
40
|
+
export interface DockerImageConfig {
|
|
41
|
+
/** The image's ENTRYPOINT */
|
|
42
|
+
entrypoint: string[] | null;
|
|
43
|
+
/** The image's CMD */
|
|
44
|
+
cmd: string[] | null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Result of running a Docker container.
|
|
48
|
+
*/
|
|
49
|
+
export interface DockerRunResult {
|
|
50
|
+
/** Exit code of the container */
|
|
51
|
+
exitCode: number;
|
|
52
|
+
/** Stdout from the container */
|
|
53
|
+
stdout: string;
|
|
54
|
+
/** Stderr from the container */
|
|
55
|
+
stderr: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Docker runtime detection result.
|
|
59
|
+
*/
|
|
60
|
+
export interface DockerRuntimeInfo {
|
|
61
|
+
/** Path to Docker executable */
|
|
62
|
+
dockerPath: string;
|
|
63
|
+
/** Whether running on Linux */
|
|
64
|
+
isLinux: boolean;
|
|
65
|
+
/** Whether running in WSL */
|
|
66
|
+
isWsl: boolean;
|
|
67
|
+
/** Whether Docker Desktop is detected */
|
|
68
|
+
isDockerDesktop: boolean;
|
|
69
|
+
/** Host address to use for container-to-host communication */
|
|
70
|
+
hostAddress: string;
|
|
71
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for Docker container management.
|
|
3
|
+
*/
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY2xpL2RvY2tlci90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVHlwZXMgZm9yIERvY2tlciBjb250YWluZXIgbWFuYWdlbWVudC5cbiAqL1xuXG4vKipcbiAqIENvbmZpZ3VyYXRpb24gZm9yIHJ1bm5pbmcgYSBEb2NrZXIgY29udGFpbmVyLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIERvY2tlclJ1bkNvbmZpZyB7XG4gIC8qKiBUaGUgRG9ja2VyIGltYWdlIFVSSSB0byBydW4gKi9cbiAgaW1hZ2VVcmk6IHN0cmluZ1xuICAvKiogQ29udGFpbmVyIG5hbWUgKG9wdGlvbmFsKSAqL1xuICBjb250YWluZXJOYW1lPzogc3RyaW5nXG4gIC8qKiBQbGF0Zm9ybSAoZS5nLiwgbGludXgvYXJtNjQsIGxpbnV4L2FtZDY0KSBmb3IgY3Jvc3MtcGxhdGZvcm0gZXhlY3V0aW9uICovXG4gIHBsYXRmb3JtPzogc3RyaW5nXG4gIC8qKiBFbnZpcm9ubWVudCB2YXJpYWJsZXMgdG8gcGFzcyB0byB0aGUgY29udGFpbmVyICovXG4gIGVudmlyb25tZW50OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+XG4gIC8qKiBNZW1vcnkgbGltaXQgaW4gTUIgKi9cbiAgbWVtb3J5TUI6IG51bWJlclxuICAvKiogVGltZW91dCBpbiBzZWNvbmRzICovXG4gIHRpbWVvdXRTZWNvbmRzOiBudW1iZXJcbiAgLyoqIE5ldHdvcmsgbW9kZSAoYnJpZGdlLCBob3N0LCBub25lKSAqL1xuICBuZXR3b3JrTW9kZTogXCJicmlkZ2VcIiB8IFwiaG9zdFwiIHwgXCJub25lXCJcbiAgLyoqIEV4dHJhIGhvc3QgZW50cmllcyAoLS1hZGQtaG9zdCkgKi9cbiAgZXh0cmFIb3N0cz86IHN0cmluZ1tdXG4gIC8qKiBXb3JraW5nIGRpcmVjdG9yeSBpbnNpZGUgdGhlIGNvbnRhaW5lciAqL1xuICB3b3JrZGlyPzogc3RyaW5nXG4gIC8qKiBBZGRpdGlvbmFsIERvY2tlciBydW4gYXJndW1lbnRzICovXG4gIGFkZGl0aW9uYWxBcmdzPzogc3RyaW5nW11cbiAgLyoqIE9wdGlvbmFsIGludm9jYXRpb24gY29udGV4dCBtYXAgZm9yIGxvZyBwcmVmaXhpbmcgKHJlcXVlc3RJZCAtPiB7IG51bSB9KSAqL1xuICBpbnZvY2F0aW9uQ29udGV4dHM/OiBNYXA8c3RyaW5nLCB7IG51bTogbnVtYmVyIH0+XG4gIC8qKiBPdmVycmlkZSB0aGUgY29udGFpbmVyJ3MgZW50cnlwb2ludCAqL1xuICBlbnRyeXBvaW50Pzogc3RyaW5nW11cbiAgLyoqIE92ZXJyaWRlIHRoZSBjb250YWluZXIncyBjb21tYW5kIChhcmd1bWVudHMgYWZ0ZXIgdGhlIGltYWdlKSAqL1xuICBjb21tYW5kPzogc3RyaW5nW11cbn1cblxuLyoqXG4gKiBEb2NrZXIgaW1hZ2UgY29uZmlndXJhdGlvbiBmcm9tIGluc3BlY3Rpb24uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRG9ja2VySW1hZ2VDb25maWcge1xuICAvKiogVGhlIGltYWdlJ3MgRU5UUllQT0lOVCAqL1xuICBlbnRyeXBvaW50OiBzdHJpbmdbXSB8IG51bGxcbiAgLyoqIFRoZSBpbWFnZSdzIENNRCAqL1xuICBjbWQ6IHN0cmluZ1tdIHwgbnVsbFxufVxuXG4vKipcbiAqIFJlc3VsdCBvZiBydW5uaW5nIGEgRG9ja2VyIGNvbnRhaW5lci5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEb2NrZXJSdW5SZXN1bHQge1xuICAvKiogRXhpdCBjb2RlIG9mIHRoZSBjb250YWluZXIgKi9cbiAgZXhpdENvZGU6IG51bWJlclxuICAvKiogU3Rkb3V0IGZyb20gdGhlIGNvbnRhaW5lciAqL1xuICBzdGRvdXQ6IHN0cmluZ1xuICAvKiogU3RkZXJyIGZyb20gdGhlIGNvbnRhaW5lciAqL1xuICBzdGRlcnI6IHN0cmluZ1xufVxuXG4vKipcbiAqIERvY2tlciBydW50aW1lIGRldGVjdGlvbiByZXN1bHQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRG9ja2VyUnVudGltZUluZm8ge1xuICAvKiogUGF0aCB0byBEb2NrZXIgZXhlY3V0YWJsZSAqL1xuICBkb2NrZXJQYXRoOiBzdHJpbmdcbiAgLyoqIFdoZXRoZXIgcnVubmluZyBvbiBMaW51eCAqL1xuICBpc0xpbnV4OiBib29sZWFuXG4gIC8qKiBXaGV0aGVyIHJ1bm5pbmcgaW4gV1NMICovXG4gIGlzV3NsOiBib29sZWFuXG4gIC8qKiBXaGV0aGVyIERvY2tlciBEZXNrdG9wIGlzIGRldGVjdGVkICovXG4gIGlzRG9ja2VyRGVza3RvcDogYm9vbGVhblxuICAvKiogSG9zdCBhZGRyZXNzIHRvIHVzZSBmb3IgY29udGFpbmVyLXRvLWhvc3QgY29tbXVuaWNhdGlvbiAqL1xuICBob3N0QWRkcmVzczogc3RyaW5nXG59XG4iXX0=
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docker context file watching for automatic container rebuilds.
|
|
3
|
+
*
|
|
4
|
+
* Watches Docker context directories and emits events when files change,
|
|
5
|
+
* triggering container rebuilds for Docker-based Lambda functions.
|
|
6
|
+
*/
|
|
7
|
+
import { Stream } from "effect";
|
|
8
|
+
/**
|
|
9
|
+
* Event emitted when a file changes in a Docker context.
|
|
10
|
+
*/
|
|
11
|
+
export interface DockerContextChangeEvent {
|
|
12
|
+
/** The function ID that owns this Docker context */
|
|
13
|
+
functionId: string;
|
|
14
|
+
/** The absolute path to the file that changed */
|
|
15
|
+
filePath: string;
|
|
16
|
+
/** Type of change */
|
|
17
|
+
type: "add" | "change" | "unlink";
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Configuration for a Docker function to watch.
|
|
21
|
+
*/
|
|
22
|
+
export interface WatchedDockerFunction {
|
|
23
|
+
/** Unique function identifier (Lambda function name) */
|
|
24
|
+
functionId: string;
|
|
25
|
+
/** Absolute path to the Docker context directory */
|
|
26
|
+
dockerContextPath: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Watch multiple Docker context directories for file changes.
|
|
30
|
+
*
|
|
31
|
+
* Creates a single chokidar watcher that monitors all registered Docker
|
|
32
|
+
* contexts and emits events when files change. The events are debounced
|
|
33
|
+
* to prevent rapid successive rebuilds during batch operations.
|
|
34
|
+
*
|
|
35
|
+
* @param functions - Array of Docker functions to watch
|
|
36
|
+
* @param debounceMs - Debounce delay in milliseconds (default: 500)
|
|
37
|
+
* @returns Stream of change events with function ownership resolved
|
|
38
|
+
*/
|
|
39
|
+
export declare const watchDockerContexts: (functions: WatchedDockerFunction[], debounceMs?: number) => Stream.Stream<DockerContextChangeEvent, Error>;
|
|
40
|
+
/**
|
|
41
|
+
* Create a watcher for a single Docker function.
|
|
42
|
+
* Convenience wrapper around watchDockerContexts for single-function use.
|
|
43
|
+
*/
|
|
44
|
+
export declare const watchSingleDockerContext: (functionId: string, dockerContextPath: string, debounceMs?: number) => Stream.Stream<DockerContextChangeEvent, Error>;
|