cdk-local-lambda 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +94 -0
  3. package/lib/aspect/docker-function-hook.d.ts +18 -0
  4. package/lib/aspect/docker-function-hook.js +31 -0
  5. package/lib/aspect/live-lambda-aspect.d.ts +85 -0
  6. package/lib/aspect/live-lambda-aspect.js +277 -0
  7. package/lib/aspect/live-lambda-bootstrap.d.ts +17 -0
  8. package/lib/aspect/live-lambda-bootstrap.js +260 -0
  9. package/lib/aspect/nodejs-function-hook.d.ts +20 -0
  10. package/lib/aspect/nodejs-function-hook.js +27 -0
  11. package/lib/bootstrap-stack/bootstrap-stack.d.ts +60 -0
  12. package/lib/bootstrap-stack/bootstrap-stack.js +338 -0
  13. package/lib/cli/appsync/client.d.ts +30 -0
  14. package/lib/cli/appsync/client.js +227 -0
  15. package/lib/cli/cdk-app.d.ts +7 -0
  16. package/lib/cli/cdk-app.js +25 -0
  17. package/lib/cli/commands/bootstrap.d.ts +9 -0
  18. package/lib/cli/commands/bootstrap.js +50 -0
  19. package/lib/cli/commands/local.d.ts +40 -0
  20. package/lib/cli/commands/local.js +1172 -0
  21. package/lib/cli/daemon.d.ts +22 -0
  22. package/lib/cli/daemon.js +18 -0
  23. package/lib/cli/docker/container.d.ts +116 -0
  24. package/lib/cli/docker/container.js +414 -0
  25. package/lib/cli/docker/types.d.ts +71 -0
  26. package/lib/cli/docker/types.js +5 -0
  27. package/lib/cli/docker/watcher.d.ts +44 -0
  28. package/lib/cli/docker/watcher.js +115 -0
  29. package/lib/cli/index.d.ts +9 -0
  30. package/lib/cli/index.js +26 -0
  31. package/lib/cli/runtime-api/server.d.ts +102 -0
  32. package/lib/cli/runtime-api/server.js +396 -0
  33. package/lib/cli/runtime-api/types.d.ts +149 -0
  34. package/lib/cli/runtime-api/types.js +10 -0
  35. package/lib/cli/runtime-wrapper/nodejs-runtime.d.ts +16 -0
  36. package/lib/cli/runtime-wrapper/nodejs-runtime.js +248 -0
  37. package/lib/cli/watcher/file-watcher.d.ts +32 -0
  38. package/lib/cli/watcher/file-watcher.js +57 -0
  39. package/lib/functions/bridge/appsync-client.d.ts +73 -0
  40. package/lib/functions/bridge/appsync-client.js +345 -0
  41. package/lib/functions/bridge/handler.d.ts +17 -0
  42. package/lib/functions/bridge/handler.js +79 -0
  43. package/lib/functions/bridge/ssm-config.d.ts +19 -0
  44. package/lib/functions/bridge/ssm-config.js +45 -0
  45. package/lib/functions/bridge-builder/handler.d.ts +12 -0
  46. package/lib/functions/bridge-builder/handler.js +181 -0
  47. package/lib/functions/bridge-docker/runtime.d.ts +9 -0
  48. package/lib/functions/bridge-docker/runtime.js +127 -0
  49. package/lib/index.d.ts +24 -0
  50. package/lib/index.js +28 -0
  51. package/lib/shared/types.d.ts +102 -0
  52. package/lib/shared/types.js +125 -0
  53. package/package.json +111 -0
@@ -0,0 +1,396 @@
1
+ /**
2
+ * Lambda Runtime API HTTP server using Effect HttpServer.
3
+ *
4
+ * This server emulates the AWS Lambda Runtime API that Docker containers
5
+ * use to receive invocations and send responses.
6
+ *
7
+ * Each Lambda function gets its own server on an ephemeral port. The server
8
+ * maintains a queue of pending invocations. When a container polls
9
+ * /invocation/next, it blocks until an invocation is available.
10
+ *
11
+ * @see https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html
12
+ */
13
+ import * as Headers from "@effect/platform/Headers";
14
+ import * as HttpRouter from "@effect/platform/HttpRouter";
15
+ import * as HttpServerRequest from "@effect/platform/HttpServerRequest";
16
+ import * as HttpServerResponse from "@effect/platform/HttpServerResponse";
17
+ import * as BunHttpServer from "@effect/platform-bun/BunHttpServer";
18
+ import { Effect, HashMap, Option, Queue, Ref } from "effect";
19
+ /**
20
+ * Create a new Runtime API state (queues only, no port).
21
+ *
22
+ * @param functionMetadata - Function metadata for extension registration responses
23
+ */
24
+ export const makeRuntimeApiState = (functionMetadata) => Effect.gen(function* () {
25
+ const invocationQueue = yield* Queue.unbounded();
26
+ const responseQueue = yield* Queue.unbounded();
27
+ const extensions = yield* Ref.make(HashMap.empty());
28
+ return {
29
+ invocationQueue,
30
+ responseQueue,
31
+ extensions,
32
+ functionMetadata,
33
+ };
34
+ });
35
+ /**
36
+ * Default poll timeout - used when not overridden.
37
+ *
38
+ * ## Why containers can't stay warm indefinitely (like AWS Lambda does)
39
+ *
40
+ * AWS Lambda keeps containers warm for ~5-15 minutes between invocations.
41
+ * Their Runtime API implementation can hold HTTP connections open indefinitely
42
+ * because they control the entire infrastructure end-to-end.
43
+ *
44
+ * In local development, we're constrained by HTTP server limitations:
45
+ * - Bun's maximum `idleTimeout` is 255 seconds (~4.25 minutes)
46
+ * - This is a practical limit to prevent resource exhaustion in HTTP servers
47
+ * - When the timeout expires, Bun forcefully closes the connection
48
+ * - The Lambda RIC interprets this as a fatal "No Response from endpoint" error
49
+ *
50
+ * Our solution: timeout slightly before Bun does (240s vs 255s) and return
51
+ * HTTP 503, which causes the RIC to exit gracefully. The container will be
52
+ * automatically restarted on the next invocation (~2 seconds for warm images).
53
+ *
54
+ * This is an inherent limitation of local Lambda emulation - AWS's purpose-built
55
+ * infrastructure simply doesn't have the same timeout constraints.
56
+ */
57
+ const DEFAULT_POLL_TIMEOUT_MS = 240_000; // 4 minutes
58
+ /**
59
+ * Handle GET /2018-06-01/runtime/invocation/next
60
+ * Polls for an invocation with a bounded timeout to handle idle containers gracefully.
61
+ * This ensures that if no invocations arrive within the timeout, the container
62
+ * exits cleanly rather than being killed by an HTTP timeout.
63
+ *
64
+ * When the timeout expires, we return a 503 Service Unavailable which signals
65
+ * to the Lambda RIC that it should exit. The container will be restarted
66
+ * automatically when the next invocation arrives.
67
+ */
68
+ const handleInvocationNext = (state, pollTimeoutMs) => Effect.gen(function* () {
69
+ yield* Effect.logDebug("Container polling for next invocation");
70
+ const startTime = Date.now();
71
+ // Poll with timeout instead of blocking indefinitely
72
+ // This allows us to detect connection issues and keep the invocation in the queue
73
+ let invocation = null;
74
+ while (invocation === null) {
75
+ // Check if we've exceeded the timeout
76
+ if (Date.now() - startTime > pollTimeoutMs) {
77
+ yield* Effect.logDebug("Invocation poll timeout - returning 503 to trigger container exit");
78
+ // Return 503 Service Unavailable to signal the RIC to exit gracefully
79
+ // This is expected behavior for idle containers in local development
80
+ return HttpServerResponse.empty({
81
+ status: 503,
82
+ headers: Headers.fromInput({
83
+ "Content-Type": "application/json",
84
+ }),
85
+ });
86
+ }
87
+ // Try to take from queue with a short timeout
88
+ const result = yield* Queue.poll(state.invocationQueue);
89
+ if (Option.isSome(result)) {
90
+ invocation = result.value;
91
+ }
92
+ else {
93
+ // Queue is empty, wait a bit before retrying
94
+ yield* Effect.sleep("100 millis");
95
+ }
96
+ }
97
+ yield* Effect.logDebug(`Returning invocation ${invocation.requestId} to container`);
98
+ return yield* HttpServerResponse.json(invocation.event, {
99
+ status: 200,
100
+ headers: Headers.fromInput({
101
+ "Lambda-Runtime-Aws-Request-Id": invocation.requestId,
102
+ "Lambda-Runtime-Deadline-Ms": String(invocation.deadlineMs),
103
+ "Lambda-Runtime-Invoked-Function-Arn": invocation.invokedFunctionArn,
104
+ "Lambda-Runtime-Log-Group-Name": invocation.logGroupName,
105
+ "Lambda-Runtime-Log-Stream-Name": invocation.logStreamName,
106
+ }),
107
+ });
108
+ });
109
+ /**
110
+ * Handle POST /2018-06-01/runtime/invocation/:requestId/response
111
+ */
112
+ const handleInvocationResponse = (state) => Effect.gen(function* () {
113
+ const params = yield* HttpRouter.params;
114
+ const requestId = params.requestId ?? "";
115
+ const request = yield* HttpServerRequest.HttpServerRequest;
116
+ // Body might not be JSON, so gracefully handle parse errors
117
+ const body = yield* Effect.orElseSucceed(request.json, () => null);
118
+ const response = {
119
+ requestId,
120
+ body,
121
+ };
122
+ yield* Effect.logDebug(`Received response for ${requestId}`);
123
+ yield* Queue.offer(state.responseQueue, response);
124
+ return HttpServerResponse.empty({ status: 202 });
125
+ });
126
+ /**
127
+ * Handle POST /2018-06-01/runtime/invocation/:requestId/error
128
+ */
129
+ const handleInvocationError = (state) => Effect.gen(function* () {
130
+ const params = yield* HttpRouter.params;
131
+ const requestId = params.requestId ?? "";
132
+ const request = yield* HttpServerRequest.HttpServerRequest;
133
+ // Body might not be JSON, so gracefully handle parse errors
134
+ const errorBody = yield* Effect.orElseSucceed(request.json, () => ({}));
135
+ const errorTypeHeader = Headers.get(request.headers, "lambda-runtime-function-error-type");
136
+ const errorType = Option.getOrElse(errorTypeHeader, () => "Error");
137
+ const error = {
138
+ requestId,
139
+ errorType: String(errorType),
140
+ errorMessage: errorBody.errorMessage ?? "Unknown error",
141
+ stackTrace: errorBody.stackTrace,
142
+ };
143
+ yield* Effect.logDebug(`Received error for ${requestId}: ${error.errorMessage}`);
144
+ yield* Queue.offer(state.responseQueue, error);
145
+ return HttpServerResponse.empty({ status: 202 });
146
+ });
147
+ /**
148
+ * Handle POST /2018-06-01/runtime/init/error
149
+ */
150
+ const handleInitError = (state) => Effect.gen(function* () {
151
+ const request = yield* HttpServerRequest.HttpServerRequest;
152
+ // Body might not be JSON, so gracefully handle parse errors
153
+ const errorBody = yield* Effect.orElseSucceed(request.json, () => ({}));
154
+ const errorTypeHeader = Headers.get(request.headers, "lambda-runtime-function-error-type");
155
+ const errorType = Option.getOrElse(errorTypeHeader, () => "InitError");
156
+ const error = {
157
+ errorType: String(errorType),
158
+ errorMessage: errorBody.errorMessage ?? "Unknown init error",
159
+ stackTrace: errorBody.stackTrace,
160
+ };
161
+ yield* Effect.logDebug(`Received init error: ${error.errorMessage}`);
162
+ yield* Queue.offer(state.responseQueue, error);
163
+ return HttpServerResponse.empty({ status: 202 });
164
+ });
165
+ // ============================================================================
166
+ // Extensions API handlers
167
+ // @see https://docs.aws.amazon.com/lambda/latest/dg/runtimes-extensions-api.html
168
+ // ============================================================================
169
+ /**
170
+ * Handle POST /2020-01-01/extension/register
171
+ * Extensions call this to register for lifecycle events.
172
+ */
173
+ const handleExtensionRegister = (state) => Effect.gen(function* () {
174
+ const request = yield* HttpServerRequest.HttpServerRequest;
175
+ // Get extension name from header (required)
176
+ const extensionNameHeader = Headers.get(request.headers, "lambda-extension-name");
177
+ const extensionName = Option.getOrElse(extensionNameHeader, () => "unknown-extension");
178
+ // Parse request body for events to register for
179
+ const body = yield* Effect.orElseSucceed(request.json, () => ({}));
180
+ const events = body.events ?? ["INVOKE", "SHUTDOWN"];
181
+ // Generate unique extension ID
182
+ const extensionId = crypto.randomUUID();
183
+ // Create event queue for this extension
184
+ const eventQueue = yield* Queue.unbounded();
185
+ const extensionState = {
186
+ extension: {
187
+ extensionId,
188
+ name: extensionName,
189
+ events,
190
+ },
191
+ eventQueue,
192
+ };
193
+ // Register the extension
194
+ yield* Ref.update(state.extensions, (exts) => HashMap.set(exts, extensionId, extensionState));
195
+ yield* Effect.logDebug(`Extension registered: ${extensionName} (${extensionId}) for events: ${events.join(", ")}`);
196
+ return yield* HttpServerResponse.json({
197
+ functionName: state.functionMetadata.functionName,
198
+ functionVersion: state.functionMetadata.functionVersion,
199
+ handler: state.functionMetadata.handler,
200
+ }, {
201
+ status: 200,
202
+ headers: Headers.fromInput({
203
+ "Lambda-Extension-Identifier": extensionId,
204
+ }),
205
+ });
206
+ });
207
+ /**
208
+ * Handle GET /2020-01-01/extension/event/next
209
+ * Extensions call this to poll for the next lifecycle event.
210
+ */
211
+ const handleExtensionEventNext = (state, pollTimeoutMs) => Effect.gen(function* () {
212
+ const request = yield* HttpServerRequest.HttpServerRequest;
213
+ // Get extension ID from header (required)
214
+ const extensionIdHeader = Headers.get(request.headers, "lambda-extension-identifier");
215
+ const extensionId = Option.getOrElse(extensionIdHeader, () => "");
216
+ if (!extensionId) {
217
+ return HttpServerResponse.empty({
218
+ status: 403,
219
+ headers: Headers.fromInput({
220
+ "Content-Type": "application/json",
221
+ }),
222
+ });
223
+ }
224
+ // Find the extension
225
+ const extensions = yield* Ref.get(state.extensions);
226
+ const extensionState = HashMap.get(extensions, extensionId);
227
+ if (Option.isNone(extensionState)) {
228
+ yield* Effect.logDebug(`Extension not found: ${extensionId}`);
229
+ return HttpServerResponse.empty({
230
+ status: 403,
231
+ headers: Headers.fromInput({
232
+ "Content-Type": "application/json",
233
+ }),
234
+ });
235
+ }
236
+ const { eventQueue, extension } = extensionState.value;
237
+ yield* Effect.logDebug(`Extension ${extension.name} polling for next event`);
238
+ const startTime = Date.now();
239
+ // Poll for the next event with timeout
240
+ let event = null;
241
+ while (event === null) {
242
+ if (Date.now() - startTime > pollTimeoutMs) {
243
+ yield* Effect.logDebug("Extension event poll timeout - returning 503 to trigger exit");
244
+ return HttpServerResponse.empty({
245
+ status: 503,
246
+ headers: Headers.fromInput({
247
+ "Content-Type": "application/json",
248
+ }),
249
+ });
250
+ }
251
+ const result = yield* Queue.poll(eventQueue);
252
+ if (Option.isSome(result)) {
253
+ event = result.value;
254
+ }
255
+ else {
256
+ yield* Effect.sleep("100 millis");
257
+ }
258
+ }
259
+ yield* Effect.logDebug(`Returning ${event.eventType} event to extension ${extension.name}`);
260
+ return yield* HttpServerResponse.json(event, {
261
+ status: 200,
262
+ headers: Headers.fromInput({
263
+ "Lambda-Extension-Event-Identifier": crypto.randomUUID(),
264
+ }),
265
+ });
266
+ });
267
+ /**
268
+ * Handle POST /2020-01-01/extension/init/error
269
+ * Extensions call this to report initialization errors.
270
+ */
271
+ const handleExtensionInitError = (state) => Effect.gen(function* () {
272
+ const request = yield* HttpServerRequest.HttpServerRequest;
273
+ const extensionIdHeader = Headers.get(request.headers, "lambda-extension-identifier");
274
+ const extensionId = Option.getOrElse(extensionIdHeader, () => "unknown");
275
+ const errorBody = yield* Effect.orElseSucceed(request.json, () => ({}));
276
+ yield* Effect.logDebug(`Extension ${extensionId} init error: ${errorBody.errorMessage ?? "unknown"}`);
277
+ // Report the error through the response queue
278
+ const initError = {
279
+ errorType: errorBody.errorType ?? "Extension.InitError",
280
+ errorMessage: errorBody.errorMessage ?? "Extension initialization failed",
281
+ };
282
+ yield* Queue.offer(state.responseQueue, initError);
283
+ return HttpServerResponse.empty({ status: 202 });
284
+ });
285
+ /**
286
+ * Handle POST /2020-01-01/extension/exit/error
287
+ * Extensions call this to report errors before exiting.
288
+ */
289
+ const handleExtensionExitError = () => Effect.gen(function* () {
290
+ const request = yield* HttpServerRequest.HttpServerRequest;
291
+ const extensionIdHeader = Headers.get(request.headers, "lambda-extension-identifier");
292
+ const extensionId = Option.getOrElse(extensionIdHeader, () => "unknown");
293
+ const errorBody = yield* Effect.orElseSucceed(request.json, () => ({}));
294
+ yield* Effect.logDebug(`Extension ${extensionId} exit error: ${errorBody.errorMessage ?? "unknown"}`);
295
+ // Just acknowledge - extension is exiting anyway
296
+ return HttpServerResponse.empty({ status: 202 });
297
+ });
298
+ // ============================================================================
299
+ // Router
300
+ // ============================================================================
301
+ /**
302
+ * Create the Runtime API router for a given state.
303
+ */
304
+ const makeRuntimeApiRouter = (state, pollTimeoutMs) => HttpRouter.empty.pipe(
305
+ // Runtime API (2018-06-01)
306
+ HttpRouter.get("/2018-06-01/runtime/invocation/next", handleInvocationNext(state, pollTimeoutMs)), HttpRouter.post("/2018-06-01/runtime/invocation/:requestId/response", handleInvocationResponse(state)), HttpRouter.post("/2018-06-01/runtime/invocation/:requestId/error", handleInvocationError(state)), HttpRouter.post("/2018-06-01/runtime/init/error", handleInitError(state)),
307
+ // Extensions API (2020-01-01)
308
+ HttpRouter.post("/2020-01-01/extension/register", handleExtensionRegister(state)), HttpRouter.get("/2020-01-01/extension/event/next", handleExtensionEventNext(state, pollTimeoutMs)), HttpRouter.post("/2020-01-01/extension/init/error", handleExtensionInitError(state)), HttpRouter.post("/2020-01-01/extension/exit/error", handleExtensionExitError()));
309
+ const DEFAULT_FUNCTION_METADATA = {
310
+ functionName: "local-function",
311
+ functionVersion: "$LATEST",
312
+ handler: "index.handler",
313
+ };
314
+ /**
315
+ * Start a Runtime API server on an ephemeral port.
316
+ * Returns the actual port and state for this server instance.
317
+ *
318
+ * The server is scoped - it will be stopped when the scope closes.
319
+ *
320
+ * @param options - Server configuration options
321
+ */
322
+ export const startRuntimeApiServer = (options = {}) => Effect.gen(function* () {
323
+ const pollTimeoutMs = options.pollTimeoutMs ?? DEFAULT_POLL_TIMEOUT_MS;
324
+ const functionMetadata = options.functionMetadata ?? DEFAULT_FUNCTION_METADATA;
325
+ // Create state (queues) for this server
326
+ const state = yield* makeRuntimeApiState(functionMetadata);
327
+ // Create router for this state
328
+ const router = makeRuntimeApiRouter(state, pollTimeoutMs);
329
+ // Create HTTP server on ephemeral port (port: 0)
330
+ const server = yield* BunHttpServer.make({
331
+ port: 0,
332
+ hostname: "0.0.0.0",
333
+ idleTimeout: 255, // Max allowed by Bun (4.25 minutes) for long-polling
334
+ });
335
+ // Start serving the router
336
+ yield* server.serve(router);
337
+ // Get the actual assigned port
338
+ const address = server.address;
339
+ if (address._tag !== "TcpAddress") {
340
+ // This should never happen since we're using TCP
341
+ throw new Error("Expected TCP address");
342
+ }
343
+ yield* Effect.logDebug(`RuntimeAPI server listening on port ${address.port}`);
344
+ return {
345
+ port: address.port,
346
+ state,
347
+ };
348
+ });
349
+ /**
350
+ * Queue an invocation for the container to process.
351
+ */
352
+ export const queueInvocation = (state, invocation) => Queue.offer(state.invocationQueue, invocation);
353
+ /**
354
+ * Wait for the response to a specific invocation.
355
+ */
356
+ export const waitForResponse = (state) => Queue.take(state.responseQueue);
357
+ /**
358
+ * Notify all registered extensions about an invocation.
359
+ * This sends an INVOKE event to all extensions that registered for it.
360
+ */
361
+ export const notifyExtensionsInvoke = (state, invocation) => Effect.gen(function* () {
362
+ const extensions = yield* Ref.get(state.extensions);
363
+ const invokeEvent = {
364
+ eventType: "INVOKE",
365
+ deadlineMs: invocation.deadlineMs,
366
+ requestId: invocation.requestId,
367
+ invokedFunctionArn: invocation.invokedFunctionArn,
368
+ };
369
+ // Send INVOKE event to all extensions that registered for it
370
+ for (const [, extState] of extensions) {
371
+ if (extState.extension.events.includes("INVOKE")) {
372
+ yield* Queue.offer(extState.eventQueue, invokeEvent);
373
+ yield* Effect.logDebug(`Sent INVOKE event to extension ${extState.extension.name}`);
374
+ }
375
+ }
376
+ });
377
+ /**
378
+ * Notify all registered extensions about shutdown.
379
+ * This sends a SHUTDOWN event to all extensions that registered for it.
380
+ */
381
+ export const notifyExtensionsShutdown = (state, reason = "SPINDOWN") => Effect.gen(function* () {
382
+ const extensions = yield* Ref.get(state.extensions);
383
+ const shutdownEvent = {
384
+ eventType: "SHUTDOWN",
385
+ shutdownReason: reason,
386
+ deadlineMs: Date.now() + 2000, // 2 second deadline for shutdown
387
+ };
388
+ // Send SHUTDOWN event to all extensions that registered for it
389
+ for (const [, extState] of extensions) {
390
+ if (extState.extension.events.includes("SHUTDOWN")) {
391
+ yield* Queue.offer(extState.eventQueue, shutdownEvent);
392
+ yield* Effect.logDebug(`Sent SHUTDOWN event to extension ${extState.extension.name}`);
393
+ }
394
+ }
395
+ });
396
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NsaS9ydW50aW1lLWFwaS9zZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7O0dBV0c7QUFFSCxPQUFPLEtBQUssT0FBTyxNQUFNLDBCQUEwQixDQUFBO0FBQ25ELE9BQU8sS0FBSyxVQUFVLE1BQU0sNkJBQTZCLENBQUE7QUFDekQsT0FBTyxLQUFLLGlCQUFpQixNQUFNLG9DQUFvQyxDQUFBO0FBQ3ZFLE9BQU8sS0FBSyxrQkFBa0IsTUFBTSxxQ0FBcUMsQ0FBQTtBQUN6RSxPQUFPLEtBQUssYUFBYSxNQUFNLG9DQUFvQyxDQUFBO0FBQ25FLE9BQU8sRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFjLE1BQU0sUUFBUSxDQUFBO0FBdUR4RTs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxnQkFBa0MsRUFBRSxFQUFFLENBQ3hFLE1BQU0sQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDO0lBQ2xCLE1BQU0sZUFBZSxHQUFHLEtBQUssQ0FBQyxDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQW9CLENBQUE7SUFDbEUsTUFBTSxhQUFhLEdBQUcsS0FBSyxDQUFDLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFFekMsQ0FBQTtJQUNILE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBMEIsQ0FBQyxDQUFBO0lBRTNFLE9BQU87UUFDTCxlQUFlO1FBQ2YsYUFBYTtRQUNiLFVBQVU7UUFDVixnQkFBZ0I7S0FDUyxDQUFBO0FBQzdCLENBQUMsQ0FBQyxDQUFBO0FBRUo7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFCRztBQUNILE1BQU0sdUJBQXVCLEdBQUcsT0FBTyxDQUFBLENBQUMsWUFBWTtBQUVwRDs7Ozs7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LENBQUMsRUFBRSxRQUFRLENBQUMsSUFBSSxVQUFVLEVBQUUsQ0FBQztRQUN0QyxJQUFJLFFBQVEsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQ25ELEtBQUssQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRSxhQUFhLENBQUMsQ0FBQTtZQUN0RCxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUNwQixvQ0FBb0MsUUFBUSxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUUsQ0FDOUQsQ0FBQTtRQUNILENBQUM7SUFDSCxDQUFDO0FBQ0gsQ0FBQyxDQUFDLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIExhbWJkYSBSdW50aW1lIEFQSSBIVFRQIHNlcnZlciB1c2luZyBFZmZlY3QgSHR0cFNlcnZlci5cbiAqXG4gKiBUaGlzIHNlcnZlciBlbXVsYXRlcyB0aGUgQVdTIExhbWJkYSBSdW50aW1lIEFQSSB0aGF0IERvY2tlciBjb250YWluZXJzXG4gKiB1c2UgdG8gcmVjZWl2ZSBpbnZvY2F0aW9ucyBhbmQgc2VuZCByZXNwb25zZXMuXG4gKlxuICogRWFjaCBMYW1iZGEgZnVuY3Rpb24gZ2V0cyBpdHMgb3duIHNlcnZlciBvbiBhbiBlcGhlbWVyYWwgcG9ydC4gVGhlIHNlcnZlclxuICogbWFpbnRhaW5zIGEgcXVldWUgb2YgcGVuZGluZyBpbnZvY2F0aW9ucy4gV2hlbiBhIGNvbnRhaW5lciBwb2xsc1xuICogL2ludm9jYXRpb24vbmV4dCwgaXQgYmxvY2tzIHVudGlsIGFuIGludm9jYXRpb24gaXMgYXZhaWxhYmxlLlxuICpcbiAqIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2xhbWJkYS9sYXRlc3QvZGcvcnVudGltZXMtYXBpLmh0bWxcbiAqL1xuXG5pbXBvcnQgKiBhcyBIZWFkZXJzIGZyb20gXCJAZWZmZWN0L3BsYXRmb3JtL0hlYWRlcnNcIlxuaW1wb3J0ICogYXMgSHR0cFJvdXRlciBmcm9tIFwiQGVmZmVjdC9wbGF0Zm9ybS9IdHRwUm91dGVyXCJcbmltcG9ydCAqIGFzIEh0dHBTZXJ2ZXJSZXF1ZXN0IGZyb20gXCJAZWZmZWN0L3BsYXRmb3JtL0h0dHBTZXJ2ZXJSZXF1ZXN0XCJcbmltcG9ydCAqIGFzIEh0dHBTZXJ2ZXJSZXNwb25zZSBmcm9tIFwiQGVmZmVjdC9wbGF0Zm9ybS9IdHRwU2VydmVyUmVzcG9uc2VcIlxuaW1wb3J0ICogYXMgQnVuSHR0cFNlcnZlciBmcm9tIFwiQGVmZmVjdC9wbGF0Zm9ybS1idW4vQnVuSHR0cFNlcnZlclwiXG5pbXBvcnQgeyBFZmZlY3QsIEhhc2hNYXAsIE9wdGlvbiwgUXVldWUsIFJlZiwgdHlwZSBTY29wZSB9IGZyb20gXCJlZmZlY3RcIlxuaW1wb3J0IHR5cGUge1xuICBFeHRlbnNpb25FdmVudCxcbiAgRXh0ZW5zaW9uRXZlbnRUeXBlLFxuICBMYW1iZGFFcnJvcixcbiAgTGFtYmRhSW5pdEVycm9yLFxuICBMYW1iZGFJbnZvY2F0aW9uLFxuICBMYW1iZGFSZXNwb25zZSxcbiAgUmVnaXN0ZXJlZEV4dGVuc2lvbixcbn0gZnJvbSBcIi4vdHlwZXMuanNcIlxuXG4vKipcbiAqIFN0YXRlIGZvciBhIHJlZ2lzdGVyZWQgZXh0ZW5zaW9uLlxuICovXG5pbnRlcmZhY2UgRXh0ZW5zaW9uU3RhdGUge1xuICAvKiogRXh0ZW5zaW9uIGluZm8gKi9cbiAgZXh0ZW5zaW9uOiBSZWdpc3RlcmVkRXh0ZW5zaW9uXG4gIC8qKiBRdWV1ZSBvZiBldmVudHMgZm9yIHRoaXMgZXh0ZW5zaW9uICovXG4gIGV2ZW50UXVldWU6IFF1ZXVlLlF1ZXVlPEV4dGVuc2lvbkV2ZW50PlxufVxuXG4vKipcbiAqIEZ1bmN0aW9uIG1ldGFkYXRhIGZvciBleHRlbnNpb24gcmVnaXN0cmF0aW9uIHJlc3BvbnNlcy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBGdW5jdGlvbk1ldGFkYXRhIHtcbiAgZnVuY3Rpb25OYW1lOiBzdHJpbmdcbiAgZnVuY3Rpb25WZXJzaW9uOiBzdHJpbmdcbiAgaGFuZGxlcjogc3RyaW5nXG59XG5cbi8qKlxuICogU3RhdGUgZm9yIGEgUnVudGltZSBBUEkgc2VydmVyIHNlc3Npb24uXG4gKiBTdXBwb3J0cyBtdWx0aXBsZSBpbnZvY2F0aW9ucyB3aXRoIGEgcXVldWUtYmFzZWQgbW9kZWwuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUnVudGltZUFwaVN0YXRlIHtcbiAgLyoqIFF1ZXVlIG9mIHBlbmRpbmcgaW52b2NhdGlvbnMgd2FpdGluZyB0byBiZSBmZXRjaGVkIGJ5IHRoZSBjb250YWluZXIgKi9cbiAgaW52b2NhdGlvblF1ZXVlOiBRdWV1ZS5RdWV1ZTxMYW1iZGFJbnZvY2F0aW9uPlxuICAvKiogUXVldWUgZm9yIHJlc3BvbnNlcy9lcnJvcnMgZnJvbSB0aGUgY29udGFpbmVyICovXG4gIHJlc3BvbnNlUXVldWU6IFF1ZXVlLlF1ZXVlPExhbWJkYVJlc3BvbnNlIHwgTGFtYmRhRXJyb3IgfCBMYW1iZGFJbml0RXJyb3I+XG4gIC8qKiBSZWdpc3RlcmVkIGV4dGVuc2lvbnMgYnkgZXh0ZW5zaW9uIElEICovXG4gIGV4dGVuc2lvbnM6IFJlZi5SZWY8SGFzaE1hcC5IYXNoTWFwPHN0cmluZywgRXh0ZW5zaW9uU3RhdGU+PlxuICAvKiogRnVuY3Rpb24gbWV0YWRhdGEgZm9yIGV4dGVuc2lvbiByZWdpc3RyYXRpb24gKi9cbiAgZnVuY3Rpb25NZXRhZGF0YTogRnVuY3Rpb25NZXRhZGF0YVxufVxuXG4vKipcbiAqIFJlc3VsdCBmcm9tIHN0YXJ0aW5nIGEgUnVudGltZSBBUEkgc2VydmVyLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJ1bnRpbWVBcGlTZXJ2ZXIge1xuICAvKiogVGhlIGFjdHVhbCBwb3J0IHRoZSBzZXJ2ZXIgaXMgbGlzdGVuaW5nIG9uICovXG4gIHBvcnQ6IG51bWJlclxuICAvKiogVGhlIHN0YXRlIGNvbnRhaW5pbmcgdGhlIGludm9jYXRpb24gYW5kIHJlc3BvbnNlIHF1ZXVlcyAqL1xuICBzdGF0ZTogUnVudGltZUFwaVN0YXRlXG59XG5cbi8qKlxuICogQ3JlYXRlIGEgbmV3IFJ1bnRpbWUgQVBJIHN0YXRlIChxdWV1ZXMgb25seSwgbm8gcG9ydCkuXG4gKlxuICogQHBhcmFtIGZ1bmN0aW9uTWV0YWRhdGEgLSBGdW5jdGlvbiBtZXRhZGF0YSBmb3IgZXh0ZW5zaW9uIHJlZ2lzdHJhdGlvbiByZXNwb25zZXNcbiAqL1xuZXhwb3J0IGNvbnN0IG1ha2VSdW50aW1lQXBpU3RhdGUgPSAoZnVuY3Rpb25NZXRhZGF0YTogRnVuY3Rpb25NZXRhZGF0YSkgPT5cbiAgRWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuICAgIGNvbnN0IGludm9jYXRpb25RdWV1ZSA9IHlpZWxkKiBRdWV1ZS51bmJvdW5kZWQ8TGFtYmRhSW52b2NhdGlvbj4oKVxuICAgIGNvbnN0IHJlc3BvbnNlUXVldWUgPSB5aWVsZCogUXVldWUudW5ib3VuZGVkPFxuICAgICAgTGFtYmRhUmVzcG9uc2UgfCBMYW1iZGFFcnJvciB8IExhbWJkYUluaXRFcnJvclxuICAgID4oKVxuICAgIGNvbnN0IGV4dGVuc2lvbnMgPSB5aWVsZCogUmVmLm1ha2UoSGFzaE1hcC5lbXB0eTxzdHJpbmcsIEV4dGVuc2lvblN0YXRlPigpKVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGludm9jYXRpb25RdWV1ZSxcbiAgICAgIHJlc3BvbnNlUXVldWUsXG4gICAgICBleHRlbnNpb25zLFxuICAgICAgZnVuY3Rpb25NZXRhZGF0YSxcbiAgICB9IHNhdGlzZmllcyBSdW50aW1lQXBpU3RhdGVcbiAgfSlcblxuLyoqXG4gKiBEZWZhdWx0IHBvbGwgdGltZW91dCAtIHVzZWQgd2hlbiBub3Qgb3ZlcnJpZGRlbi5cbiAqXG4gKiAjIyBXaHkgY29udGFpbmVycyBjYW4ndCBzdGF5IHdhcm0gaW5kZWZpbml0ZWx5IChsaWtlIEFXUyBMYW1iZGEgZG9lcylcbiAqXG4gKiBBV1MgTGFtYmRhIGtlZXBzIGNvbnRhaW5lcnMgd2FybSBmb3IgfjUtMTUgbWludXRlcyBiZXR3ZWVuIGludm9jYXRpb25zLlxuICogVGhlaXIgUnVudGltZSBBUEkgaW1wbGVtZW50YXRpb24gY2FuIGhvbGQgSFRUUCBjb25uZWN0aW9ucyBvcGVuIGluZGVmaW5pdGVseVxuICogYmVjYXVzZSB0aGV5IGNvbnRyb2wgdGhlIGVudGlyZSBpbmZyYXN0cnVjdHVyZSBlbmQtdG8tZW5kLlxuICpcbiAqIEluIGxvY2FsIGRldmVsb3BtZW50LCB3ZSdyZSBjb25zdHJhaW5lZCBieSBIVFRQIHNlcnZlciBsaW1pdGF0aW9uczpcbiAqIC0gQnVuJ3MgbWF4aW11bSBgaWRsZVRpbWVvdXRgIGlzIDI1NSBzZWNvbmRzICh+NC4yNSBtaW51dGVzKVxuICogLSBUaGlzIGlzIGEgcHJhY3RpY2FsIGxpbWl0IHRvIHByZXZlbnQgcmVzb3VyY2UgZXhoYXVzdGlvbiBpbiBIVFRQIHNlcnZlcnNcbiAqIC0gV2hlbiB0aGUgdGltZW91dCBleHBpcmVzLCBCdW4gZm9yY2VmdWxseSBjbG9zZXMgdGhlIGNvbm5lY3Rpb25cbiAqIC0gVGhlIExhbWJkYSBSSUMgaW50ZXJwcmV0cyB0aGlzIGFzIGEgZmF0YWwgXCJObyBSZXNwb25zZSBmcm9tIGVuZHBvaW50XCIgZXJyb3JcbiAqXG4gKiBPdXIgc29sdXRpb246IHRpbWVvdXQgc2xpZ2h0bHkgYmVmb3JlIEJ1biBkb2VzICgyNDBzIHZzIDI1NXMpIGFuZCByZXR1cm5cbiAqIEhUVFAgNTAzLCB3aGljaCBjYXVzZXMgdGhlIFJJQyB0byBleGl0IGdyYWNlZnVsbHkuIFRoZSBjb250YWluZXIgd2lsbCBiZVxuICogYXV0b21hdGljYWxseSByZXN0YXJ0ZWQgb24gdGhlIG5leHQgaW52b2NhdGlvbiAofjIgc2Vjb25kcyBmb3Igd2FybSBpbWFnZXMpLlxuICpcbiAqIFRoaXMgaXMgYW4gaW5oZXJlbnQgbGltaXRhdGlvbiBvZiBsb2NhbCBMYW1iZGEgZW11bGF0aW9uIC0gQVdTJ3MgcHVycG9zZS1idWlsdFxuICogaW5mcmFzdHJ1Y3R1cmUgc2ltcGx5IGRvZXNuJ3QgaGF2ZSB0aGUgc2FtZSB0aW1lb3V0IGNvbnN0cmFpbnRzLlxuICovXG5jb25zdCBERUZBVUxUX1BPTExfVElNRU9VVF9NUyA9IDI0MF8wMDAgLy8gNCBtaW51dGVzXG5cbi8qKlxuICogSGFuZGxlIEdFVCAvMjAxOC0wNi0wMS9ydW50aW1lL2ludm9jYXRpb24vbmV4dFxuICogUG9sbHMgZm9yIGFuIGludm9jYXRpb24gd2l0aCBhIGJvdW5kZWQgdGltZW91dCB0byBoYW5kbGUgaWRsZSBjb250YWluZXJzIGdyYWNlZnVsbHkuXG4gKiBUaGlzIGVuc3VyZXMgdGhhdCBpZiBubyBpbnZvY2F0aW9ucyBhcnJpdmUgd2l0aGluIHRoZSB0aW1lb3V0LCB0aGUgY29udGFpbmVyXG4gKiBleGl0cyBjbGVhbmx5IHJhdGhlciB0aGFuIGJlaW5nIGtpbGxlZCBieSBhbiBIVFRQIHRpbWVvdXQuXG4gKlxuICogV2hlbiB0aGUgdGltZW91dCBleHBpcmVzLCB3ZSByZXR1cm4gYSA1MDMgU2VydmljZSBVbmF2YWlsYWJsZSB3aGljaCBzaWduYWxzXG4gKiB0byB0aGUgTGFtYmRhIFJJQyB0aGF0IGl0IHNob3VsZCBleGl0LiBUaGUgY29udGFpbmVyIHdpbGwgYmUgcmVzdGFydGVkXG4gKiBhdXRvbWF0aWNhbGx5IHdoZW4gdGhlIG5leHQgaW52b2NhdGlvbiBhcnJpdmVzLlxuICovXG5jb25zdCBoYW5kbGVJbnZvY2F0aW9uTmV4dCA9IChzdGF0ZTogUnVudGltZUFwaVN0YXRlLCBwb2xsVGltZW91dE1zOiBudW1iZXIpID0+XG4gIEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcbiAgICB5aWVsZCogRWZmZWN0LmxvZ0RlYnVnKFwiQ29udGFpbmVyIHBvbGxpbmcgZm9yIG5leHQgaW52b2NhdGlvblwiKVxuXG4gICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKVxuXG4gICAgLy8gUG9sbCB3aXRoIHRpbWVvdXQgaW5zdGVhZCBvZiBibG9ja2luZyBpbmRlZmluaXRlbHlcbiAgICAvLyBUaGlzIGFsbG93cyB1cyB0byBkZXRlY3QgY29ubmVjdGlvbiBpc3N1ZXMgYW5kIGtlZXAgdGhlIGludm9jYXRpb24gaW4gdGhlIHF1ZXVlXG4gICAgbGV0IGludm9jYXRpb246IExhbWJkYUludm9jYXRpb24gfCBudWxsID0gbnVsbFxuXG4gICAgd2hpbGUgKGludm9jYXRpb24gPT09IG51bGwpIHtcbiAgICAgIC8vIENoZWNrIGlmIHdlJ3ZlIGV4Y2VlZGVkIHRoZSB0aW1lb3V0XG4gICAgICBpZiAoRGF0ZS5ub3coKSAtIHN0YXJ0VGltZSA+IHBvbGxUaW1lb3V0TXMpIHtcbiAgICAgICAgeWllbGQqIEVmZmVjdC5sb2dEZWJ1ZyhcbiAgICAgICAgICBcIkludm9jYXRpb24gcG9sbCB0aW1lb3V0IC0gcmV0dXJuaW5nIDUwMyB0byB0cmlnZ2VyIGNvbnRhaW5lciBleGl0XCIsXG4gICAgICAgIClcbiAgICAgICAgLy8gUmV0dXJuIDUwMyBTZXJ2aWNlIFVuYXZhaWxhYmxlIHRvIHNpZ25hbCB0aGUgUklDIHRvIGV4aXQgZ3JhY2VmdWxseVxuICAgICAgICAvLyBUaGlzIGlzIGV4cGVjdGVkIGJlaGF2aW9yIGZvciBpZGxlIGNvbnRhaW5lcnMgaW4gbG9jYWwgZGV2ZWxvcG1lbnRcbiAgICAgICAgcmV0dXJuIEh0dHBTZXJ2ZXJSZXNwb25zZS5lbXB0eSh7XG4gICAgICAgICAgc3RhdHVzOiA1MDMsXG4gICAgICAgICAgaGVhZGVyczogSGVhZGVycy5mcm9tSW5wdXQoe1xuICAgICAgICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICAgICAgfSksXG4gICAgICAgIH0pXG4gICAgICB9XG5cbiAgICAgIC8vIFRyeSB0byB0YWtlIGZyb20gcXVldWUgd2l0aCBhIHNob3J0IHRpbWVvdXRcbiAgICAgIGNvbnN0IHJlc3VsdCA9IHlpZWxkKiBRdWV1ZS5wb2xsKHN0YXRlLmludm9jYXRpb25RdWV1ZSlcblxuICAgICAgaWYgKE9wdGlvbi5pc1NvbWUocmVzdWx0KSkge1xuICAgICAgICBpbnZvY2F0aW9uID0gcmVzdWx0LnZhbHVlXG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBRdWV1ZSBpcyBlbXB0eSwgd2FpdCBhIGJpdCBiZWZvcmUgcmV0cnlpbmdcbiAgICAgICAgeWllbGQqIEVmZmVjdC5zbGVlcChcIjEwMCBtaWxsaXNcIilcbiAgICAgIH1cbiAgICB9XG5cbiAgICB5aWVsZCogRWZmZWN0LmxvZ0RlYnVnKFxuICAgICAgYFJldHVybmluZyBpbnZvY2F0aW9uICR7aW52b2NhdGlvbi5yZXF1ZXN0SWR9IHRvIGNvbnRhaW5lcmAsXG4gICAgKVxuXG4gICAgcmV0dXJuIHlpZWxkKiBIdHRwU2VydmVyUmVzcG9uc2UuanNvbihpbnZvY2F0aW9uLmV2ZW50LCB7XG4gICAgICBzdGF0dXM6IDIwMCxcbiAgICAgIGhlYWRlcnM6IEhlYWRlcnMuZnJvbUlucHV0KHtcbiAgICAgICAgXCJMYW1iZGEtUnVudGltZS1Bd3MtUmVxdWVzdC1JZFwiOiBpbnZvY2F0aW9uLnJlcXVlc3RJZCxcbiAgICAgICAgXCJMYW1iZGEtUnVudGltZS1EZWFkbGluZS1Nc1wiOiBTdHJpbmcoaW52b2NhdGlvbi5kZWFkbGluZU1zKSxcbiAgICAgICAgXCJMYW1iZGEtUnVudGltZS1JbnZva2VkLUZ1bmN0aW9uLUFyblwiOiBpbnZvY2F0aW9uLmludm9rZWRGdW5jdGlvbkFybixcbiAgICAgICAgXCJMYW1iZGEtUnVudGltZS1Mb2ctR3JvdXAtTmFtZVwiOiBpbnZvY2F0aW9uLmxvZ0dyb3VwTmFtZSxcbiAgICAgICAgXCJMYW1iZGEtUnVudGltZS1Mb2ctU3RyZWFtLU5hbWVcIjogaW52b2NhdGlvbi5sb2dTdHJlYW1OYW1lLFxuICAgICAgfSksXG4gICAgfSlcbiAgfSlcblxuLyoqXG4gKiBIYW5kbGUgUE9TVCAvMjAxOC0wNi0wMS9ydW50aW1lL2ludm9jYXRpb24vOnJlcXVlc3RJZC9yZXNwb25zZVxuICovXG5jb25zdCBoYW5kbGVJbnZvY2F0aW9uUmVzcG9uc2UgPSAoc3RhdGU6IFJ1bnRpbWVBcGlTdGF0ZSkgPT5cbiAgRWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuICAgIGNvbnN0IHBhcmFtcyA9IHlpZWxkKiBIdHRwUm91dGVyLnBhcmFtc1xuICAgIGNvbnN0IHJlcXVlc3RJZCA9IHBhcmFtcy5yZXF1ZXN0SWQgPz8gXCJcIlxuICAgIGNvbnN0IHJlcXVlc3QgPSB5aWVsZCogSHR0cFNlcnZlclJlcXVlc3QuSHR0cFNlcnZlclJlcXVlc3RcblxuICAgIC8vIEJvZHkgbWlnaHQgbm90IGJlIEpTT04sIHNvIGdyYWNlZnVsbHkgaGFuZGxlIHBhcnNlIGVycm9yc1xuICAgIGNvbnN0IGJvZHkgPSB5aWVsZCogRWZmZWN0Lm9yRWxzZVN1Y2NlZWQocmVxdWVzdC5qc29uLCAoKSA9PiBudWxsKVxuXG4gICAgY29uc3QgcmVzcG9uc2U6IExhbWJkYVJlc3BvbnNlID0ge1xuICAgICAgcmVxdWVzdElkLFxuICAgICAgYm9keSxcbiAgICB9XG5cbiAgICB5aWVsZCogRWZmZWN0LmxvZ0RlYnVnKGBSZWNlaXZlZCByZXNwb25zZSBmb3IgJHtyZXF1ZXN0SWR9YClcbiAgICB5aWVsZCogUXVldWUub2ZmZXIoc3RhdGUucmVzcG9uc2VRdWV1ZSwgcmVzcG9uc2UpXG5cbiAgICByZXR1cm4gSHR0cFNlcnZlclJlc3BvbnNlLmVtcHR5KHsgc3RhdHVzOiAyMDIgfSlcbiAgfSlcblxuLyoqXG4gKiBIYW5kbGUgUE9TVCAvMjAxOC0wNi0wMS9ydW50aW1lL2ludm9jYXRpb24vOnJlcXVlc3RJZC9lcnJvclxuICovXG5jb25zdCBoYW5kbGVJbnZvY2F0aW9uRXJyb3IgPSAoc3RhdGU6IFJ1bnRpbWVBcGlTdGF0ZSkgPT5cbiAgRWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuICAgIGNvbnN0IHBhcmFtcyA9IHlpZWxkKiBIdHRwUm91dGVyLnBhcmFtc1xuICAgIGNvbnN0IHJlcXVlc3RJZCA9IHBhcmFtcy5yZXF1ZXN0SWQgPz8gXCJcIlxuICAgIGNvbnN0IHJlcXVlc3QgPSB5aWVsZCogSHR0cFNlcnZlclJlcXVlc3QuSHR0cFNlcnZlclJlcXVlc3RcblxuICAgIC8vIEJvZHkgbWlnaHQgbm90IGJlIEpTT04sIHNvIGdyYWNlZnVsbHkgaGFuZGxlIHBhcnNlIGVycm9yc1xuICAgIGNvbnN0IGVycm9yQm9keSA9IHlpZWxkKiBFZmZlY3Qub3JFbHNlU3VjY2VlZChcbiAgICAgIHJlcXVlc3QuanNvbiBhcyBFZmZlY3QuRWZmZWN0PFxuICAgICAgICB7IGVycm9yTWVzc2FnZT86IHN0cmluZzsgc3RhY2tUcmFjZT86IHN0cmluZ1tdIH0sXG4gICAgICAgIHVua25vd25cbiAgICAgID4sXG4gICAgICAoKTogeyBlcnJvck1lc3NhZ2U/OiBzdHJpbmc7IHN0YWNrVHJhY2U/OiBzdHJpbmdbXSB9ID0+ICh7fSksXG4gICAgKVxuXG4gICAgY29uc3QgZXJyb3JUeXBlSGVhZGVyID0gSGVhZGVycy5nZXQoXG4gICAgICByZXF1ZXN0LmhlYWRlcnMsXG4gICAgICBcImxhbWJkYS1ydW50aW1lLWZ1bmN0aW9uLWVycm9yLXR5cGVcIixcbiAgICApXG4gICAgY29uc3QgZXJyb3JUeXBlID0gT3B0aW9uLmdldE9yRWxzZShlcnJvclR5cGVIZWFkZXIsICgpID0+IFwiRXJyb3JcIilcblxuICAgIGNvbnN0IGVycm9yOiBMYW1iZGFFcnJvciA9IHtcbiAgICAgIHJlcXVlc3RJZCxcbiAgICAgIGVycm9yVHlwZTogU3RyaW5nKGVycm9yVHlwZSksXG4gICAgICBlcnJvck1lc3NhZ2U6IGVycm9yQm9keS5lcnJvck1lc3NhZ2UgPz8gXCJVbmtub3duIGVycm9yXCIsXG4gICAgICBzdGFja1RyYWNlOiBlcnJvckJvZHkuc3RhY2tUcmFjZSxcbiAgICB9XG5cbiAgICB5aWVsZCogRWZmZWN0LmxvZ0RlYnVnKFxuICAgICAgYFJlY2VpdmVkIGVycm9yIGZvciAke3JlcXVlc3RJZH06ICR7ZXJyb3IuZXJyb3JNZXNzYWdlfWAsXG4gICAgKVxuICAgIHlpZWxkKiBRdWV1ZS5vZmZlcihzdGF0ZS5yZXNwb25zZVF1ZXVlLCBlcnJvcilcblxuICAgIHJldHVybiBIdHRwU2VydmVyUmVzcG9uc2UuZW1wdHkoeyBzdGF0dXM6IDIwMiB9KVxuICB9KVxuXG4vKipcbiAqIEhhbmRsZSBQT1NUIC8yMDE4LTA2LTAxL3J1bnRpbWUvaW5pdC9lcnJvclxuICovXG5jb25zdCBoYW5kbGVJbml0RXJyb3IgPSAoc3RhdGU6IFJ1bnRpbWVBcGlTdGF0ZSkgPT5cbiAgRWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuICAgIGNvbnN0IHJlcXVlc3QgPSB5aWVsZCogSHR0cFNlcnZlclJlcXVlc3QuSHR0cFNlcnZlclJlcXVlc3RcblxuICAgIC8vIEJvZHkgbWlnaHQgbm90IGJlIEpTT04sIHNvIGdyYWNlZnVsbHkgaGFuZGxlIHBhcnNlIGVycm9yc1xuICAgIGNvbnN0IGVycm9yQm9keSA9IHlpZWxkKiBFZmZlY3Qub3JFbHNlU3VjY2VlZChcbiAgICAgIHJlcXVlc3QuanNvbiBhcyBFZmZlY3QuRWZmZWN0PFxuICAgICAgICB7IGVycm9yTWVzc2FnZT86IHN0cmluZzsgc3RhY2tUcmFjZT86IHN0cmluZ1tdIH0sXG4gICAgICAgIHVua25vd25cbiAgICAgID4sXG4gICAgICAoKTogeyBlcnJvck1lc3NhZ2U/OiBzdHJpbmc7IHN0YWNrVHJhY2U/OiBzdHJpbmdbXSB9ID0+ICh7fSksXG4gICAgKVxuXG4gICAgY29uc3QgZXJyb3JUeXBlSGVhZGVyID0gSGVhZGVycy5nZXQoXG4gICAgICByZXF1ZXN0LmhlYWRlcnMsXG4gICAgICBcImxhbWJkYS1ydW50aW1lLWZ1bmN0aW9uLWVycm9yLXR5cGVcIixcbiAgICApXG4gICAgY29uc3QgZXJyb3JUeXBlID0gT3B0aW9uLmdldE9yRWxzZShlcnJvclR5cGVIZWFkZXIsICgpID0+IFwiSW5pdEVycm9yXCIpXG5cbiAgICBjb25zdCBlcnJvcjogTGFtYmRhSW5pdEVycm9yID0ge1xuICAgICAgZXJyb3JUeXBlOiBTdHJpbmcoZXJyb3JUeXBlKSxcbiAgICAgIGVycm9yTWVzc2FnZTogZXJyb3JCb2R5LmVycm9yTWVzc2FnZSA/PyBcIlVua25vd24gaW5pdCBlcnJvclwiLFxuICAgICAgc3RhY2tUcmFjZTogZXJyb3JCb2R5LnN0YWNrVHJhY2UsXG4gICAgfVxuXG4gICAgeWllbGQqIEVmZmVjdC5sb2dEZWJ1ZyhgUmVjZWl2ZWQgaW5pdCBlcnJvcjogJHtlcnJvci5lcnJvck1lc3NhZ2V9YClcbiAgICB5aWVsZCogUXVldWUub2ZmZXIoc3RhdGUucmVzcG9uc2VRdWV1ZSwgZXJyb3IpXG5cbiAgICByZXR1cm4gSHR0cFNlcnZlclJlc3BvbnNlLmVtcHR5KHsgc3RhdHVzOiAyMDIgfSlcbiAgfSlcblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gRXh0ZW5zaW9ucyBBUEkgaGFuZGxlcnNcbi8vIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2xhbWJkYS9sYXRlc3QvZGcvcnVudGltZXMtZXh0ZW5zaW9ucy1hcGkuaHRtbFxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIEhhbmRsZSBQT1NUIC8yMDIwLTAxLTAxL2V4dGVuc2lvbi9yZWdpc3RlclxuICogRXh0ZW5zaW9ucyBjYWxsIHRoaXMgdG8gcmVnaXN0ZXIgZm9yIGxpZmVjeWNsZSBldmVudHMuXG4gKi9cbmNvbnN0IGhhbmRsZUV4dGVuc2lvblJlZ2lzdGVyID0gKHN0YXRlOiBSdW50aW1lQXBpU3RhdGUpID0+XG4gIEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcbiAgICBjb25zdCByZXF1ZXN0ID0geWllbGQqIEh0dHBTZXJ2ZXJSZXF1ZXN0Lkh0dHBTZXJ2ZXJSZXF1ZXN0XG5cbiAgICAvLyBHZXQgZXh0ZW5zaW9uIG5hbWUgZnJvbSBoZWFkZXIgKHJlcXVpcmVkKVxuICAgIGNvbnN0IGV4dGVuc2lvbk5hbWVIZWFkZXIgPSBIZWFkZXJzLmdldChcbiAgICAgIHJlcXVlc3QuaGVhZGVycyxcbiAgICAgIFwibGFtYmRhLWV4dGVuc2lvbi1uYW1lXCIsXG4gICAgKVxuICAgIGNvbnN0IGV4dGVuc2lvbk5hbWUgPSBPcHRpb24uZ2V0T3JFbHNlKFxuICAgICAgZXh0ZW5zaW9uTmFtZUhlYWRlcixcbiAgICAgICgpID0+IFwidW5rbm93bi1leHRlbnNpb25cIixcbiAgICApXG5cbiAgICAvLyBQYXJzZSByZXF1ZXN0IGJvZHkgZm9yIGV2ZW50cyB0byByZWdpc3RlciBmb3JcbiAgICBjb25zdCBib2R5ID0geWllbGQqIEVmZmVjdC5vckVsc2VTdWNjZWVkKFxuICAgICAgcmVxdWVzdC5qc29uIGFzIEVmZmVjdC5FZmZlY3Q8eyBldmVudHM/OiBFeHRlbnNpb25FdmVudFR5cGVbXSB9LCB1bmtub3duPixcbiAgICAgICgpOiB7IGV2ZW50cz86IEV4dGVuc2lvbkV2ZW50VHlwZVtdIH0gPT4gKHt9KSxcbiAgICApXG4gICAgY29uc3QgZXZlbnRzOiBFeHRlbnNpb25FdmVudFR5cGVbXSA9IGJvZHkuZXZlbnRzID8/IFtcIklOVk9LRVwiLCBcIlNIVVRET1dOXCJdXG5cbiAgICAvLyBHZW5lcmF0ZSB1bmlxdWUgZXh0ZW5zaW9uIElEXG4gICAgY29uc3QgZXh0ZW5zaW9uSWQgPSBjcnlwdG8ucmFuZG9tVVVJRCgpXG5cbiAgICAvLyBDcmVhdGUgZXZlbnQgcXVldWUgZm9yIHRoaXMgZXh0ZW5zaW9uXG4gICAgY29uc3QgZXZlbnRRdWV1ZSA9IHlpZWxkKiBRdWV1ZS51bmJvdW5kZWQ8RXh0ZW5zaW9uRXZlbnQ+KClcblxuICAgIGNvbnN0IGV4dGVuc2lvblN0YXRlOiBFeHRlbnNpb25TdGF0ZSA9IHtcbiAgICAgIGV4dGVuc2lvbjoge1xuICAgICAgICBleHRlbnNpb25JZCxcbiAgICAgICAgbmFtZTogZXh0ZW5zaW9uTmFtZSxcbiAgICAgICAgZXZlbnRzLFxuICAgICAgfSxcbiAgICAgIGV2ZW50UXVldWUsXG4gICAgfVxuXG4gICAgLy8gUmVnaXN0ZXIgdGhlIGV4dGVuc2lvblxuICAgIHlpZWxkKiBSZWYudXBkYXRlKHN0YXRlLmV4dGVuc2lvbnMsIChleHRzKSA9PlxuICAgICAgSGFzaE1hcC5zZXQoZXh0cywgZXh0ZW5zaW9uSWQsIGV4dGVuc2lvblN0YXRlKSxcbiAgICApXG5cbiAgICB5aWVsZCogRWZmZWN0LmxvZ0RlYnVnKFxuICAgICAgYEV4dGVuc2lvbiByZWdpc3RlcmVkOiAke2V4dGVuc2lvbk5hbWV9ICgke2V4dGVuc2lvbklkfSkgZm9yIGV2ZW50czogJHtldmVudHMuam9pbihcIiwgXCIpfWAsXG4gICAgKVxuXG4gICAgcmV0dXJuIHlpZWxkKiBIdHRwU2VydmVyUmVzcG9uc2UuanNvbihcbiAgICAgIHtcbiAgICAgICAgZnVuY3Rpb25OYW1lOiBzdGF0ZS5mdW5jdGlvbk1ldGFkYXRhLmZ1bmN0aW9uTmFtZSxcbiAgICAgICAgZnVuY3Rpb25WZXJzaW9uOiBzdGF0ZS5mdW5jdGlvbk1ldGFkYXRhLmZ1bmN0aW9uVmVyc2lvbixcbiAgICAgICAgaGFuZGxlcjogc3RhdGUuZnVuY3Rpb25NZXRhZGF0YS5oYW5kbGVyLFxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgc3RhdHVzOiAyMDAsXG4gICAgICAgIGhlYWRlcnM6IEhlYWRlcnMuZnJvbUlucHV0KHtcbiAgICAgICAgICBcIkxhbWJkYS1FeHRlbnNpb24tSWRlbnRpZmllclwiOiBleHRlbnNpb25JZCxcbiAgICAgICAgfSksXG4gICAgICB9LFxuICAgIClcbiAgfSlcblxuLyoqXG4gKiBIYW5kbGUgR0VUIC8yMDIwLTAxLTAxL2V4dGVuc2lvbi9ldmVudC9uZXh0XG4gKiBFeHRlbnNpb25zIGNhbGwgdGhpcyB0byBwb2xsIGZvciB0aGUgbmV4dCBsaWZlY3ljbGUgZXZlbnQuXG4gKi9cbmNvbnN0IGhhbmRsZUV4dGVuc2lvbkV2ZW50TmV4dCA9IChcbiAgc3RhdGU6IFJ1bnRpbWVBcGlTdGF0ZSxcbiAgcG9sbFRpbWVvdXRNczogbnVtYmVyLFxuKSA9PlxuICBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG4gICAgY29uc3QgcmVxdWVzdCA9IHlpZWxkKiBIdHRwU2VydmVyUmVxdWVzdC5IdHRwU2VydmVyUmVxdWVzdFxuXG4gICAgLy8gR2V0IGV4dGVuc2lvbiBJRCBmcm9tIGhlYWRlciAocmVxdWlyZWQpXG4gICAgY29uc3QgZXh0ZW5zaW9uSWRIZWFkZXIgPSBIZWFkZXJzLmdldChcbiAgICAgIHJlcXVlc3QuaGVhZGVycyxcbiAgICAgIFwibGFtYmRhLWV4dGVuc2lvbi1pZGVudGlmaWVyXCIsXG4gICAgKVxuICAgIGNvbnN0IGV4dGVuc2lvbklkID0gT3B0aW9uLmdldE9yRWxzZShleHRlbnNpb25JZEhlYWRlciwgKCkgPT4gXCJcIilcblxuICAgIGlmICghZXh0ZW5zaW9uSWQpIHtcbiAgICAgIHJldHVybiBIdHRwU2VydmVyUmVzcG9uc2UuZW1wdHkoe1xuICAgICAgICBzdGF0dXM6IDQwMyxcbiAgICAgICAgaGVhZGVyczogSGVhZGVycy5mcm9tSW5wdXQoe1xuICAgICAgICAgIFwiQ29udGVudC1UeXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiLFxuICAgICAgICB9KSxcbiAgICAgIH0pXG4gICAgfVxuXG4gICAgLy8gRmluZCB0aGUgZXh0ZW5zaW9uXG4gICAgY29uc3QgZXh0ZW5zaW9ucyA9IHlpZWxkKiBSZWYuZ2V0KHN0YXRlLmV4dGVuc2lvbnMpXG4gICAgY29uc3QgZXh0ZW5zaW9uU3RhdGUgPSBIYXNoTWFwLmdldChleHRlbnNpb25zLCBleHRlbnNpb25JZClcblxuICAgIGlmIChPcHRpb24uaXNOb25lKGV4dGVuc2lvblN0YXRlKSkge1xuICAgICAgeWllbGQqIEVmZmVjdC5sb2dEZWJ1ZyhgRXh0ZW5zaW9uIG5vdCBmb3VuZDogJHtleHRlbnNpb25JZH1gKVxuICAgICAgcmV0dXJuIEh0dHBTZXJ2ZXJSZXNwb25zZS5lbXB0eSh7XG4gICAgICAgIHN0YXR1czogNDAzLFxuICAgICAgICBoZWFkZXJzOiBIZWFkZXJzLmZyb21JbnB1dCh7XG4gICAgICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICAgIH0pLFxuICAgICAgfSlcbiAgICB9XG5cbiAgICBjb25zdCB7IGV2ZW50UXVldWUsIGV4dGVuc2lvbiB9ID0gZXh0ZW5zaW9uU3RhdGUudmFsdWVcblxuICAgIHlpZWxkKiBFZmZlY3QubG9nRGVidWcoYEV4dGVuc2lvbiAke2V4dGVuc2lvbi5uYW1lfSBwb2xsaW5nIGZvciBuZXh0IGV2ZW50YClcblxuICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KClcblxuICAgIC8vIFBvbGwgZm9yIHRoZSBuZXh0IGV2ZW50IHdpdGggdGltZW91dFxuICAgIGxldCBldmVudDogRXh0ZW5zaW9uRXZlbnQgfCBudWxsID0gbnVsbFxuXG4gICAgd2hpbGUgKGV2ZW50ID09PSBudWxsKSB7XG4gICAgICBpZiAoRGF0ZS5ub3coKSAtIHN0YXJ0VGltZSA+IHBvbGxUaW1lb3V0TXMpIHtcbiAgICAgICAgeWllbGQqIEVmZmVjdC5sb2dEZWJ1ZyhcbiAgICAgICAgICBcIkV4dGVuc2lvbiBldmVudCBwb2xsIHRpbWVvdXQgLSByZXR1cm5pbmcgNTAzIHRvIHRyaWdnZXIgZXhpdFwiLFxuICAgICAgICApXG4gICAgICAgIHJldHVybiBIdHRwU2VydmVyUmVzcG9uc2UuZW1wdHkoe1xuICAgICAgICAgIHN0YXR1czogNTAzLFxuICAgICAgICAgIGhlYWRlcnM6IEhlYWRlcnMuZnJvbUlucHV0KHtcbiAgICAgICAgICAgIFwiQ29udGVudC1UeXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiLFxuICAgICAgICAgIH0pLFxuICAgICAgICB9KVxuICAgICAgfVxuXG4gICAgICBjb25zdCByZXN1bHQgPSB5aWVsZCogUXVldWUucG9sbChldmVudFF1ZXVlKVxuXG4gICAgICBpZiAoT3B0aW9uLmlzU29tZShyZXN1bHQpKSB7XG4gICAgICAgIGV2ZW50ID0gcmVzdWx0LnZhbHVlXG4gICAgICB9IGVsc2Uge1xuICAgICAgICB5aWVsZCogRWZmZWN0LnNsZWVwKFwiMTAwIG1pbGxpc1wiKVxuICAgICAgfVxuICAgIH1cblxuICAgIHlpZWxkKiBFZmZlY3QubG9nRGVidWcoXG4gICAgICBgUmV0dXJuaW5nICR7ZXZlbnQuZXZlbnRUeXBlfSBldmVudCB0byBleHRlbnNpb24gJHtleHRlbnNpb24ubmFtZX1gLFxuICAgIClcblxuICAgIHJldHVybiB5aWVsZCogSHR0cFNlcnZlclJlc3BvbnNlLmpzb24oZXZlbnQsIHtcbiAgICAgIHN0YXR1czogMjAwLFxuICAgICAgaGVhZGVyczogSGVhZGVycy5mcm9tSW5wdXQoe1xuICAgICAgICBcIkxhbWJkYS1FeHRlbnNpb24tRXZlbnQtSWRlbnRpZmllclwiOiBjcnlwdG8ucmFuZG9tVVVJRCgpLFxuICAgICAgfSksXG4gICAgfSlcbiAgfSlcblxuLyoqXG4gKiBIYW5kbGUgUE9TVCAvMjAyMC0wMS0wMS9leHRlbnNpb24vaW5pdC9lcnJvclxuICogRXh0ZW5zaW9ucyBjYWxsIHRoaXMgdG8gcmVwb3J0IGluaXRpYWxpemF0aW9uIGVycm9ycy5cbiAqL1xuY29uc3QgaGFuZGxlRXh0ZW5zaW9uSW5pdEVycm9yID0gKHN0YXRlOiBSdW50aW1lQXBpU3RhdGUpID0+XG4gIEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcbiAgICBjb25zdCByZXF1ZXN0ID0geWllbGQqIEh0dHBTZXJ2ZXJSZXF1ZXN0Lkh0dHBTZXJ2ZXJSZXF1ZXN0XG5cbiAgICBjb25zdCBleHRlbnNpb25JZEhlYWRlciA9IEhlYWRlcnMuZ2V0KFxuICAgICAgcmVxdWVzdC5oZWFkZXJzLFxuICAgICAgXCJsYW1iZGEtZXh0ZW5zaW9uLWlkZW50aWZpZXJcIixcbiAgICApXG4gICAgY29uc3QgZXh0ZW5zaW9uSWQgPSBPcHRpb24uZ2V0T3JFbHNlKGV4dGVuc2lvbklkSGVhZGVyLCAoKSA9PiBcInVua25vd25cIilcblxuICAgIGNvbnN0IGVycm9yQm9keSA9IHlpZWxkKiBFZmZlY3Qub3JFbHNlU3VjY2VlZChcbiAgICAgIHJlcXVlc3QuanNvbiBhcyBFZmZlY3QuRWZmZWN0PFxuICAgICAgICB7IGVycm9yTWVzc2FnZT86IHN0cmluZzsgZXJyb3JUeXBlPzogc3RyaW5nIH0sXG4gICAgICAgIHVua25vd25cbiAgICAgID4sXG4gICAgICAoKTogeyBlcnJvck1lc3NhZ2U/OiBzdHJpbmc7IGVycm9yVHlwZT86IHN0cmluZyB9ID0+ICh7fSksXG4gICAgKVxuXG4gICAgeWllbGQqIEVmZmVjdC5sb2dEZWJ1ZyhcbiAgICAgIGBFeHRlbnNpb24gJHtleHRlbnNpb25JZH0gaW5pdCBlcnJvcjogJHtlcnJvckJvZHkuZXJyb3JNZXNzYWdlID8/IFwidW5rbm93blwifWAsXG4gICAgKVxuXG4gICAgLy8gUmVwb3J0IHRoZSBlcnJvciB0aHJvdWdoIHRoZSByZXNwb25zZSBxdWV1ZVxuICAgIGNvbnN0IGluaXRFcnJvcjogTGFtYmRhSW5pdEVycm9yID0ge1xuICAgICAgZXJyb3JUeXBlOiBlcnJvckJvZHkuZXJyb3JUeXBlID8/IFwiRXh0ZW5zaW9uLkluaXRFcnJvclwiLFxuICAgICAgZXJyb3JNZXNzYWdlOiBlcnJvckJvZHkuZXJyb3JNZXNzYWdlID8/IFwiRXh0ZW5zaW9uIGluaXRpYWxpemF0aW9uIGZhaWxlZFwiLFxuICAgIH1cbiAgICB5aWVsZCogUXVldWUub2ZmZXIoc3RhdGUucmVzcG9uc2VRdWV1ZSwgaW5pdEVycm9yKVxuXG4gICAgcmV0dXJuIEh0dHBTZXJ2ZXJSZXNwb25zZS5lbXB0eSh7IHN0YXR1czogMjAyIH0pXG4gIH0pXG5cbi8qKlxuICogSGFuZGxlIFBPU1QgLzIwMjAtMDEtMDEvZXh0ZW5zaW9uL2V4aXQvZXJyb3JcbiAqIEV4dGVuc2lvbnMgY2FsbCB0aGlzIHRvIHJlcG9ydCBlcnJvcnMgYmVmb3JlIGV4aXRpbmcuXG4gKi9cbmNvbnN0IGhhbmRsZUV4dGVuc2lvbkV4aXRFcnJvciA9ICgpID0+XG4gIEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcbiAgICBjb25zdCByZXF1ZXN0ID0geWllbGQqIEh0dHBTZXJ2ZXJSZXF1ZXN0Lkh0dHBTZXJ2ZXJSZXF1ZXN0XG5cbiAgICBjb25zdCBleHRlbnNpb25JZEhlYWRlciA9IEhlYWRlcnMuZ2V0KFxuICAgICAgcmVxdWVzdC5oZWFkZXJzLFxuICAgICAgXCJsYW1iZGEtZXh0ZW5zaW9uLWlkZW50aWZpZXJcIixcbiAgICApXG4gICAgY29uc3QgZXh0ZW5zaW9uSWQgPSBPcHRpb24uZ2V0T3JFbHNlKGV4dGVuc2lvbklkSGVhZGVyLCAoKSA9PiBcInVua25vd25cIilcblxuICAgIGNvbnN0IGVycm9yQm9keSA9IHlpZWxkKiBFZmZlY3Qub3JFbHNlU3VjY2VlZChcbiAgICAgIHJlcXVlc3QuanNvbiBhcyBFZmZlY3QuRWZmZWN0PFxuICAgICAgICB7IGVycm9yTWVzc2FnZT86IHN0cmluZzsgZXJyb3JUeXBlPzogc3RyaW5nIH0sXG4gICAgICAgIHVua25vd25cbiAgICAgID4sXG4gICAgICAoKTogeyBlcnJvck1lc3NhZ2U/OiBzdHJpbmc7IGVycm9yVHlwZT86IHN0cmluZyB9ID0+ICh7fSksXG4gICAgKVxuXG4gICAgeWllbGQqIEVmZmVjdC5sb2dEZWJ1ZyhcbiAgICAgIGBFeHRlbnNpb24gJHtleHRlbnNpb25JZH0gZXhpdCBlcnJvcjogJHtlcnJvckJvZHkuZXJyb3JNZXNzYWdlID8/IFwidW5rbm93blwifWAsXG4gICAgKVxuXG4gICAgLy8gSnVzdCBhY2tub3dsZWRnZSAtIGV4dGVuc2lvbiBpcyBleGl0aW5nIGFueXdheVxuICAgIHJldHVybiBIdHRwU2VydmVyUmVzcG9uc2UuZW1wdHkoeyBzdGF0dXM6IDIwMiB9KVxuICB9KVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBSb3V0ZXJcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBDcmVhdGUgdGhlIFJ1bnRpbWUgQVBJIHJvdXRlciBmb3IgYSBnaXZlbiBzdGF0ZS5cbiAqL1xuY29uc3QgbWFrZVJ1bnRpbWVBcGlSb3V0ZXIgPSAoc3RhdGU6IFJ1bnRpbWVBcGlTdGF0ZSwgcG9sbFRpbWVvdXRNczogbnVtYmVyKSA9PlxuICBIdHRwUm91dGVyLmVtcHR5LnBpcGUoXG4gICAgLy8gUnVudGltZSBBUEkgKDIwMTgtMDYtMDEpXG4gICAgSHR0cFJvdXRlci5nZXQoXG4gICAgICBcIi8yMDE4LTA2LTAxL3J1bnRpbWUvaW52b2NhdGlvbi9uZXh0XCIsXG4gICAgICBoYW5kbGVJbnZvY2F0aW9uTmV4dChzdGF0ZSwgcG9sbFRpbWVvdXRNcyksXG4gICAgKSxcbiAgICBIdHRwUm91dGVyLnBvc3QoXG4gICAgICBcIi8yMDE4LTA2LTAxL3J1bnRpbWUvaW52b2NhdGlvbi86cmVxdWVzdElkL3Jlc3BvbnNlXCIsXG4gICAgICBoYW5kbGVJbnZvY2F0aW9uUmVzcG9uc2Uoc3RhdGUpLFxuICAgICksXG4gICAgSHR0cFJvdXRlci5wb3N0KFxuICAgICAgXCIvMjAxOC0wNi0wMS9ydW50aW1lL2ludm9jYXRpb24vOnJlcXVlc3RJZC9lcnJvclwiLFxuICAgICAgaGFuZGxlSW52b2NhdGlvbkVycm9yKHN0YXRlKSxcbiAgICApLFxuICAgIEh0dHBSb3V0ZXIucG9zdChcIi8yMDE4LTA2LTAxL3J1bnRpbWUvaW5pdC9lcnJvclwiLCBoYW5kbGVJbml0RXJyb3Ioc3RhdGUpKSxcbiAgICAvLyBFeHRlbnNpb25zIEFQSSAoMjAyMC0wMS0wMSlcbiAgICBIdHRwUm91dGVyLnBvc3QoXG4gICAgICBcIi8yMDIwLTAxLTAxL2V4dGVuc2lvbi9yZWdpc3RlclwiLFxuICAgICAgaGFuZGxlRXh0ZW5zaW9uUmVnaXN0ZXIoc3RhdGUpLFxuICAgICksXG4gICAgSHR0cFJvdXRlci5nZXQoXG4gICAgICBcIi8yMDIwLTAxLTAxL2V4dGVuc2lvbi9ldmVudC9uZXh0XCIsXG4gICAgICBoYW5kbGVFeHRlbnNpb25FdmVudE5leHQoc3RhdGUsIHBvbGxUaW1lb3V0TXMpLFxuICAgICksXG4gICAgSHR0cFJvdXRlci5wb3N0KFxuICAgICAgXCIvMjAyMC0wMS0wMS9leHRlbnNpb24vaW5pdC9lcnJvclwiLFxuICAgICAgaGFuZGxlRXh0ZW5zaW9uSW5pdEVycm9yKHN0YXRlKSxcbiAgICApLFxuICAgIEh0dHBSb3V0ZXIucG9zdChcbiAgICAgIFwiLzIwMjAtMDEtMDEvZXh0ZW5zaW9uL2V4aXQvZXJyb3JcIixcbiAgICAgIGhhbmRsZUV4dGVuc2lvbkV4aXRFcnJvcigpLFxuICAgICksXG4gIClcblxuLyoqXG4gKiBPcHRpb25zIGZvciBzdGFydGluZyBhIFJ1bnRpbWUgQVBJIHNlcnZlci5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSdW50aW1lQXBpU2VydmVyT3B0aW9ucyB7XG4gIC8qKiBIb3cgbG9uZyB0byB3YWl0IGZvciBhbiBpbnZvY2F0aW9uIGJlZm9yZSByZXR1cm5pbmcgNTAzICovXG4gIHBvbGxUaW1lb3V0TXM/OiBudW1iZXJcbiAgLyoqIEZ1bmN0aW9uIG1ldGFkYXRhIGZvciBleHRlbnNpb24gcmVnaXN0cmF0aW9uICovXG4gIGZ1bmN0aW9uTWV0YWRhdGE/OiBGdW5jdGlvbk1ldGFkYXRhXG59XG5cbmNvbnN0IERFRkFVTFRfRlVOQ1RJT05fTUVUQURBVEE6IEZ1bmN0aW9uTWV0YWRhdGEgPSB7XG4gIGZ1bmN0aW9uTmFtZTogXCJsb2NhbC1mdW5jdGlvblwiLFxuICBmdW5jdGlvblZlcnNpb246IFwiJExBVEVTVFwiLFxuICBoYW5kbGVyOiBcImluZGV4LmhhbmRsZXJcIixcbn1cblxuLyoqXG4gKiBTdGFydCBhIFJ1bnRpbWUgQVBJIHNlcnZlciBvbiBhbiBlcGhlbWVyYWwgcG9ydC5cbiAqIFJldHVybnMgdGhlIGFjdHVhbCBwb3J0IGFuZCBzdGF0ZSBmb3IgdGhpcyBzZXJ2ZXIgaW5zdGFuY2UuXG4gKlxuICogVGhlIHNlcnZlciBpcyBzY29wZWQgLSBpdCB3aWxsIGJlIHN0b3BwZWQgd2hlbiB0aGUgc2NvcGUgY2xvc2VzLlxuICpcbiAqIEBwYXJhbSBvcHRpb25zIC0gU2VydmVyIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICovXG5leHBvcnQgY29uc3Qgc3RhcnRSdW50aW1lQXBpU2VydmVyID0gKFxuICBvcHRpb25zOiBSdW50aW1lQXBpU2VydmVyT3B0aW9ucyA9IHt9LFxuKTogRWZmZWN0LkVmZmVjdDxSdW50aW1lQXBpU2VydmVyLCBuZXZlciwgU2NvcGUuU2NvcGU+ID0+XG4gIEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcbiAgICBjb25zdCBwb2xsVGltZW91dE1zID0gb3B0aW9ucy5wb2xsVGltZW91dE1zID8/IERFRkFVTFRfUE9MTF9USU1FT1VUX01TXG4gICAgY29uc3QgZnVuY3Rpb25NZXRhZGF0YSA9XG4gICAgICBvcHRpb25zLmZ1bmN0aW9uTWV0YWRhdGEgPz8gREVGQVVMVF9GVU5DVElPTl9NRVRBREFUQVxuXG4gICAgLy8gQ3JlYXRlIHN0YXRlIChxdWV1ZXMpIGZvciB0aGlzIHNlcnZlclxuICAgIGNvbnN0IHN0YXRlID0geWllbGQqIG1ha2VSdW50aW1lQXBpU3RhdGUoZnVuY3Rpb25NZXRhZGF0YSlcblxuICAgIC8vIENyZWF0ZSByb3V0ZXIgZm9yIHRoaXMgc3RhdGVcbiAgICBjb25zdCByb3V0ZXIgPSBtYWtlUnVudGltZUFwaVJvdXRlcihzdGF0ZSwgcG9sbFRpbWVvdXRNcylcblxuICAgIC8vIENyZWF0ZSBIVFRQIHNlcnZlciBvbiBlcGhlbWVyYWwgcG9ydCAocG9ydDogMClcbiAgICBjb25zdCBzZXJ2ZXIgPSB5aWVsZCogQnVuSHR0cFNlcnZlci5tYWtlKHtcbiAgICAgIHBvcnQ6IDAsXG4gICAgICBob3N0bmFtZTogXCIwLjAuMC4wXCIsXG4gICAgICBpZGxlVGltZW91dDogMjU1LCAvLyBNYXggYWxsb3dlZCBieSBCdW4gKDQuMjUgbWludXRlcykgZm9yIGxvbmctcG9sbGluZ1xuICAgIH0pXG5cbiAgICAvLyBTdGFydCBzZXJ2aW5nIHRoZSByb3V0ZXJcbiAgICB5aWVsZCogc2VydmVyLnNlcnZlKHJvdXRlcilcblxuICAgIC8vIEdldCB0aGUgYWN0dWFsIGFzc2lnbmVkIHBvcnRcbiAgICBjb25zdCBhZGRyZXNzID0gc2VydmVyLmFkZHJlc3NcbiAgICBpZiAoYWRkcmVzcy5fdGFnICE9PSBcIlRjcEFkZHJlc3NcIikge1xuICAgICAgLy8gVGhpcyBzaG91bGQgbmV2ZXIgaGFwcGVuIHNpbmNlIHdlJ3JlIHVzaW5nIFRDUFxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRXhwZWN0ZWQgVENQIGFkZHJlc3NcIilcbiAgICB9XG5cbiAgICB5aWVsZCogRWZmZWN0LmxvZ0RlYnVnKFxuICAgICAgYFJ1bnRpbWVBUEkgc2VydmVyIGxpc3RlbmluZyBvbiBwb3J0ICR7YWRkcmVzcy5wb3J0fWAsXG4gICAgKVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHBvcnQ6IGFkZHJlc3MucG9ydCxcbiAgICAgIHN0YXRlLFxuICAgIH0gc2F0aXNmaWVzIFJ1bnRpbWVBcGlTZXJ2ZXJcbiAgfSlcblxuLyoqXG4gKiBRdWV1ZSBhbiBpbnZvY2F0aW9uIGZvciB0aGUgY29udGFpbmVyIHRvIHByb2Nlc3MuXG4gKi9cbmV4cG9ydCBjb25zdCBxdWV1ZUludm9jYXRpb24gPSAoXG4gIHN0YXRlOiBSdW50aW1lQXBpU3RhdGUsXG4gIGludm9jYXRpb246IExhbWJkYUludm9jYXRpb24sXG4pOiBFZmZlY3QuRWZmZWN0PHZvaWQ+ID0+IFF1ZXVlLm9mZmVyKHN0YXRlLmludm9jYXRpb25RdWV1ZSwgaW52b2NhdGlvbilcblxuLyoqXG4gKiBXYWl0IGZvciB0aGUgcmVzcG9uc2UgdG8gYSBzcGVjaWZpYyBpbnZvY2F0aW9uLlxuICovXG5leHBvcnQgY29uc3Qgd2FpdEZvclJlc3BvbnNlID0gKFxuICBzdGF0ZTogUnVudGltZUFwaVN0YXRlLFxuKTogRWZmZWN0LkVmZmVjdDxMYW1iZGFSZXNwb25zZSB8IExhbWJkYUVycm9yIHwgTGFtYmRhSW5pdEVycm9yPiA9PlxuICBRdWV1ZS50YWtlKHN0YXRlLnJlc3BvbnNlUXVldWUpXG5cbi8qKlxuICogTm90aWZ5IGFsbCByZWdpc3RlcmVkIGV4dGVuc2lvbnMgYWJvdXQgYW4gaW52b2NhdGlvbi5cbiAqIFRoaXMgc2VuZHMgYW4gSU5WT0tFIGV2ZW50IHRvIGFsbCBleHRlbnNpb25zIHRoYXQgcmVnaXN0ZXJlZCBmb3IgaXQuXG4gKi9cbmV4cG9ydCBjb25zdCBub3RpZnlFeHRlbnNpb25zSW52b2tlID0gKFxuICBzdGF0ZTogUnVudGltZUFwaVN0YXRlLFxuICBpbnZvY2F0aW9uOiBMYW1iZGFJbnZvY2F0aW9uLFxuKTogRWZmZWN0LkVmZmVjdDx2b2lkPiA9PlxuICBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG4gICAgY29uc3QgZXh0ZW5zaW9ucyA9IHlpZWxkKiBSZWYuZ2V0KHN0YXRlLmV4dGVuc2lvbnMpXG5cbiAgICBjb25zdCBpbnZva2VFdmVudDogRXh0ZW5zaW9uRXZlbnQgPSB7XG4gICAgICBldmVudFR5cGU6IFwiSU5WT0tFXCIsXG4gICAgICBkZWFkbGluZU1zOiBpbnZvY2F0aW9uLmRlYWRsaW5lTXMsXG4gICAgICByZXF1ZXN0SWQ6IGludm9jYXRpb24ucmVxdWVzdElkLFxuICAgICAgaW52b2tlZEZ1bmN0aW9uQXJuOiBpbnZvY2F0aW9uLmludm9rZWRGdW5jdGlvbkFybixcbiAgICB9XG5cbiAgICAvLyBTZW5kIElOVk9LRSBldmVudCB0byBhbGwgZXh0ZW5zaW9ucyB0aGF0IHJlZ2lzdGVyZWQgZm9yIGl0XG4gICAgZm9yIChjb25zdCBbLCBleHRTdGF0ZV0gb2YgZXh0ZW5zaW9ucykge1xuICAgICAgaWYgKGV4dFN0YXRlLmV4dGVuc2lvbi5ldmVudHMuaW5jbHVkZXMoXCJJTlZPS0VcIikpIHtcbiAgICAgICAgeWllbGQqIFF1ZXVlLm9mZmVyKGV4dFN0YXRlLmV2ZW50UXVldWUsIGludm9rZUV2ZW50KVxuICAgICAgICB5aWVsZCogRWZmZWN0LmxvZ0RlYnVnKFxuICAgICAgICAgIGBTZW50IElOVk9LRSBldmVudCB0byBleHRlbnNpb24gJHtleHRTdGF0ZS5leHRlbnNpb24ubmFtZX1gLFxuICAgICAgICApXG4gICAgICB9XG4gICAgfVxuICB9KVxuXG4vKipcbiAqIE5vdGlmeSBhbGwgcmVnaXN0ZXJlZCBleHRlbnNpb25zIGFib3V0IHNodXRkb3duLlxuICogVGhpcyBzZW5kcyBhIFNIVVRET1dOIGV2ZW50IHRvIGFsbCBleHRlbnNpb25zIHRoYXQgcmVnaXN0ZXJlZCBmb3IgaXQuXG4gKi9cbmV4cG9ydCBjb25zdCBub3RpZnlFeHRlbnNpb25zU2h1dGRvd24gPSAoXG4gIHN0YXRlOiBSdW50aW1lQXBpU3RhdGUsXG4gIHJlYXNvbjogXCJTUElORE9XTlwiIHwgXCJUSU1FT1VUXCIgfCBcIkZBSUxVUkVcIiA9IFwiU1BJTkRPV05cIixcbik6IEVmZmVjdC5FZmZlY3Q8dm9pZD4gPT5cbiAgRWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuICAgIGNvbnN0IGV4dGVuc2lvbnMgPSB5aWVsZCogUmVmLmdldChzdGF0ZS5leHRlbnNpb25zKVxuXG4gICAgY29uc3Qgc2h1dGRvd25FdmVudDogRXh0ZW5zaW9uRXZlbnQgPSB7XG4gICAgICBldmVudFR5cGU6IFwiU0hVVERPV05cIixcbiAgICAgIHNodXRkb3duUmVhc29uOiByZWFzb24sXG4gICAgICBkZWFkbGluZU1zOiBEYXRlLm5vdygpICsgMjAwMCwgLy8gMiBzZWNvbmQgZGVhZGxpbmUgZm9yIHNodXRkb3duXG4gICAgfVxuXG4gICAgLy8gU2VuZCBTSFVURE9XTiBldmVudCB0byBhbGwgZXh0ZW5zaW9ucyB0aGF0IHJlZ2lzdGVyZWQgZm9yIGl0XG4gICAgZm9yIChjb25zdCBbLCBleHRTdGF0ZV0gb2YgZXh0ZW5zaW9ucykge1xuICAgICAgaWYgKGV4dFN0YXRlLmV4dGVuc2lvbi5ldmVudHMuaW5jbHVkZXMoXCJTSFVURE9XTlwiKSkge1xuICAgICAgICB5aWVsZCogUXVldWUub2ZmZXIoZXh0U3RhdGUuZXZlbnRRdWV1ZSwgc2h1dGRvd25FdmVudClcbiAgICAgICAgeWllbGQqIEVmZmVjdC5sb2dEZWJ1ZyhcbiAgICAgICAgICBgU2VudCBTSFVURE9XTiBldmVudCB0byBleHRlbnNpb24gJHtleHRTdGF0ZS5leHRlbnNpb24ubmFtZX1gLFxuICAgICAgICApXG4gICAgICB9XG4gICAgfVxuICB9KVxuIl19
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Types for Lambda Runtime API implementation.
3
+ *
4
+ * This implements the AWS Lambda Runtime API that Docker containers use
5
+ * to communicate with the Lambda runtime environment.
6
+ *
7
+ * @see https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html
8
+ */
9
+ /**
10
+ * Lambda invocation context passed via headers and body
11
+ */
12
+ export interface LambdaInvocation {
13
+ /** Unique request ID for this invocation */
14
+ requestId: string;
15
+ /** Event payload */
16
+ event: unknown;
17
+ /** Function ARN */
18
+ invokedFunctionArn: string;
19
+ /** Deadline timestamp in milliseconds since epoch */
20
+ deadlineMs: number;
21
+ /** Function name */
22
+ functionName: string;
23
+ /** Function version */
24
+ functionVersion: string;
25
+ /** Memory limit in MB */
26
+ memoryLimitMB: number;
27
+ /** Log group name */
28
+ logGroupName: string;
29
+ /** Log stream name */
30
+ logStreamName: string;
31
+ }
32
+ /**
33
+ * Response from the Lambda handler
34
+ */
35
+ export interface LambdaResponse {
36
+ /** Request ID this response is for */
37
+ requestId: string;
38
+ /** Response body (JSON) */
39
+ body: unknown;
40
+ }
41
+ /**
42
+ * Error response from the Lambda handler
43
+ */
44
+ export interface LambdaError {
45
+ /** Request ID this error is for */
46
+ requestId: string;
47
+ /** Error type (e.g., "Runtime.UnhandledPromiseRejection") */
48
+ errorType: string;
49
+ /** Error message */
50
+ errorMessage: string;
51
+ /** Stack trace lines */
52
+ stackTrace?: string[];
53
+ }
54
+ /**
55
+ * Init error (error during handler initialization)
56
+ */
57
+ export interface LambdaInitError {
58
+ /** Error type */
59
+ errorType: string;
60
+ /** Error message */
61
+ errorMessage: string;
62
+ /** Stack trace lines */
63
+ stackTrace?: string[];
64
+ }
65
+ /**
66
+ * Runtime API server configuration
67
+ */
68
+ export interface RuntimeApiConfig {
69
+ /** Port to listen on (0 for ephemeral) */
70
+ port: number;
71
+ /** Host to bind to */
72
+ host: string;
73
+ }
74
+ /**
75
+ * State of a pending invocation
76
+ */
77
+ export type InvocationState = {
78
+ type: "pending";
79
+ invocation: LambdaInvocation;
80
+ } | {
81
+ type: "completed";
82
+ response: LambdaResponse;
83
+ } | {
84
+ type: "error";
85
+ error: LambdaError;
86
+ } | {
87
+ type: "init-error";
88
+ error: LambdaInitError;
89
+ };
90
+ /**
91
+ * Headers returned by GET /invocation/next
92
+ */
93
+ export interface InvocationNextHeaders {
94
+ "Lambda-Runtime-Aws-Request-Id": string;
95
+ "Lambda-Runtime-Deadline-Ms": string;
96
+ "Lambda-Runtime-Invoked-Function-Arn": string;
97
+ "Lambda-Runtime-Log-Group-Name"?: string;
98
+ "Lambda-Runtime-Log-Stream-Name"?: string;
99
+ "Lambda-Runtime-Trace-Id"?: string;
100
+ }
101
+ /**
102
+ * Event types that extensions can register for.
103
+ * @see https://docs.aws.amazon.com/lambda/latest/dg/runtimes-extensions-api.html
104
+ */
105
+ export type ExtensionEventType = "INVOKE" | "SHUTDOWN";
106
+ /**
107
+ * Registered extension information.
108
+ */
109
+ export interface RegisteredExtension {
110
+ /** Unique identifier for the extension (UUID) */
111
+ extensionId: string;
112
+ /** Name of the extension (from Lambda-Extension-Name header) */
113
+ name: string;
114
+ /** Events this extension is registered for */
115
+ events: ExtensionEventType[];
116
+ }
117
+ /**
118
+ * Extension INVOKE event payload.
119
+ */
120
+ export interface ExtensionInvokeEvent {
121
+ eventType: "INVOKE";
122
+ deadlineMs: number;
123
+ requestId: string;
124
+ invokedFunctionArn: string;
125
+ tracing?: {
126
+ type: string;
127
+ value: string;
128
+ };
129
+ }
130
+ /**
131
+ * Extension SHUTDOWN event payload.
132
+ */
133
+ export interface ExtensionShutdownEvent {
134
+ eventType: "SHUTDOWN";
135
+ shutdownReason: "SPINDOWN" | "TIMEOUT" | "FAILURE";
136
+ deadlineMs: number;
137
+ }
138
+ /**
139
+ * Extension event (either INVOKE or SHUTDOWN).
140
+ */
141
+ export type ExtensionEvent = ExtensionInvokeEvent | ExtensionShutdownEvent;
142
+ /**
143
+ * Response body for extension registration.
144
+ */
145
+ export interface ExtensionRegisterResponse {
146
+ functionName: string;
147
+ functionVersion: string;
148
+ handler: string;
149
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Types for Lambda Runtime API implementation.
3
+ *
4
+ * This implements the AWS Lambda Runtime API that Docker containers use
5
+ * to communicate with the Lambda runtime environment.
6
+ *
7
+ * @see https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY2xpL3J1bnRpbWUtYXBpL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7O0dBT0ciLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFR5cGVzIGZvciBMYW1iZGEgUnVudGltZSBBUEkgaW1wbGVtZW50YXRpb24uXG4gKlxuICogVGhpcyBpbXBsZW1lbnRzIHRoZSBBV1MgTGFtYmRhIFJ1bnRpbWUgQVBJIHRoYXQgRG9ja2VyIGNvbnRhaW5lcnMgdXNlXG4gKiB0byBjb21tdW5pY2F0ZSB3aXRoIHRoZSBMYW1iZGEgcnVudGltZSBlbnZpcm9ubWVudC5cbiAqXG4gKiBAc2VlIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9sYW1iZGEvbGF0ZXN0L2RnL3J1bnRpbWVzLWFwaS5odG1sXG4gKi9cblxuLyoqXG4gKiBMYW1iZGEgaW52b2NhdGlvbiBjb250ZXh0IHBhc3NlZCB2aWEgaGVhZGVycyBhbmQgYm9keVxuICovXG5leHBvcnQgaW50ZXJmYWNlIExhbWJkYUludm9jYXRpb24ge1xuICAvKiogVW5pcXVlIHJlcXVlc3QgSUQgZm9yIHRoaXMgaW52b2NhdGlvbiAqL1xuICByZXF1ZXN0SWQ6IHN0cmluZ1xuICAvKiogRXZlbnQgcGF5bG9hZCAqL1xuICBldmVudDogdW5rbm93blxuICAvKiogRnVuY3Rpb24gQVJOICovXG4gIGludm9rZWRGdW5jdGlvbkFybjogc3RyaW5nXG4gIC8qKiBEZWFkbGluZSB0aW1lc3RhbXAgaW4gbWlsbGlzZWNvbmRzIHNpbmNlIGVwb2NoICovXG4gIGRlYWRsaW5lTXM6IG51bWJlclxuICAvKiogRnVuY3Rpb24gbmFtZSAqL1xuICBmdW5jdGlvbk5hbWU6IHN0cmluZ1xuICAvKiogRnVuY3Rpb24gdmVyc2lvbiAqL1xuICBmdW5jdGlvblZlcnNpb246IHN0cmluZ1xuICAvKiogTWVtb3J5IGxpbWl0IGluIE1CICovXG4gIG1lbW9yeUxpbWl0TUI6IG51bWJlclxuICAvKiogTG9nIGdyb3VwIG5hbWUgKi9cbiAgbG9nR3JvdXBOYW1lOiBzdHJpbmdcbiAgLyoqIExvZyBzdHJlYW0gbmFtZSAqL1xuICBsb2dTdHJlYW1OYW1lOiBzdHJpbmdcbn1cblxuLyoqXG4gKiBSZXNwb25zZSBmcm9tIHRoZSBMYW1iZGEgaGFuZGxlclxuICovXG5leHBvcnQgaW50ZXJmYWNlIExhbWJkYVJlc3BvbnNlIHtcbiAgLyoqIFJlcXVlc3QgSUQgdGhpcyByZXNwb25zZSBpcyBmb3IgKi9cbiAgcmVxdWVzdElkOiBzdHJpbmdcbiAgLyoqIFJlc3BvbnNlIGJvZHkgKEpTT04pICovXG4gIGJvZHk6IHVua25vd25cbn1cblxuLyoqXG4gKiBFcnJvciByZXNwb25zZSBmcm9tIHRoZSBMYW1iZGEgaGFuZGxlclxuICovXG5leHBvcnQgaW50ZXJmYWNlIExhbWJkYUVycm9yIHtcbiAgLyoqIFJlcXVlc3QgSUQgdGhpcyBlcnJvciBpcyBmb3IgKi9cbiAgcmVxdWVzdElkOiBzdHJpbmdcbiAgLyoqIEVycm9yIHR5cGUgKGUuZy4sIFwiUnVudGltZS5VbmhhbmRsZWRQcm9taXNlUmVqZWN0aW9uXCIpICovXG4gIGVycm9yVHlwZTogc3RyaW5nXG4gIC8qKiBFcnJvciBtZXNzYWdlICovXG4gIGVycm9yTWVzc2FnZTogc3RyaW5nXG4gIC8qKiBTdGFjayB0cmFjZSBsaW5lcyAqL1xuICBzdGFja1RyYWNlPzogc3RyaW5nW11cbn1cblxuLyoqXG4gKiBJbml0IGVycm9yIChlcnJvciBkdXJpbmcgaGFuZGxlciBpbml0aWFsaXphdGlvbilcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMYW1iZGFJbml0RXJyb3Ige1xuICAvKiogRXJyb3IgdHlwZSAqL1xuICBlcnJvclR5cGU6IHN0cmluZ1xuICAvKiogRXJyb3IgbWVzc2FnZSAqL1xuICBlcnJvck1lc3NhZ2U6IHN0cmluZ1xuICAvKiogU3RhY2sgdHJhY2UgbGluZXMgKi9cbiAgc3RhY2tUcmFjZT86IHN0cmluZ1tdXG59XG5cbi8qKlxuICogUnVudGltZSBBUEkgc2VydmVyIGNvbmZpZ3VyYXRpb25cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSdW50aW1lQXBpQ29uZmlnIHtcbiAgLyoqIFBvcnQgdG8gbGlzdGVuIG9uICgwIGZvciBlcGhlbWVyYWwpICovXG4gIHBvcnQ6IG51bWJlclxuICAvKiogSG9zdCB0byBiaW5kIHRvICovXG4gIGhvc3Q6IHN0cmluZ1xufVxuXG4vKipcbiAqIFN0YXRlIG9mIGEgcGVuZGluZyBpbnZvY2F0aW9uXG4gKi9cbmV4cG9ydCB0eXBlIEludm9jYXRpb25TdGF0ZSA9XG4gIHwgeyB0eXBlOiBcInBlbmRpbmdcIjsgaW52b2NhdGlvbjogTGFtYmRhSW52b2NhdGlvbiB9XG4gIHwgeyB0eXBlOiBcImNvbXBsZXRlZFwiOyByZXNwb25zZTogTGFtYmRhUmVzcG9uc2UgfVxuICB8IHsgdHlwZTogXCJlcnJvclwiOyBlcnJvcjogTGFtYmRhRXJyb3IgfVxuICB8IHsgdHlwZTogXCJpbml0LWVycm9yXCI7IGVycm9yOiBMYW1iZGFJbml0RXJyb3IgfVxuXG4vKipcbiAqIEhlYWRlcnMgcmV0dXJuZWQgYnkgR0VUIC9pbnZvY2F0aW9uL25leHRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJbnZvY2F0aW9uTmV4dEhlYWRlcnMge1xuICBcIkxhbWJkYS1SdW50aW1lLUF3cy1SZXF1ZXN0LUlkXCI6IHN0cmluZ1xuICBcIkxhbWJkYS1SdW50aW1lLURlYWRsaW5lLU1zXCI6IHN0cmluZ1xuICBcIkxhbWJkYS1SdW50aW1lLUludm9rZWQtRnVuY3Rpb24tQXJuXCI6IHN0cmluZ1xuICBcIkxhbWJkYS1SdW50aW1lLUxvZy1Hcm91cC1OYW1lXCI/OiBzdHJpbmdcbiAgXCJMYW1iZGEtUnVudGltZS1Mb2ctU3RyZWFtLU5hbWVcIj86IHN0cmluZ1xuICBcIkxhbWJkYS1SdW50aW1lLVRyYWNlLUlkXCI/OiBzdHJpbmdcbn1cblxuLyoqXG4gKiBFdmVudCB0eXBlcyB0aGF0IGV4dGVuc2lvbnMgY2FuIHJlZ2lzdGVyIGZvci5cbiAqIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2xhbWJkYS9sYXRlc3QvZGcvcnVudGltZXMtZXh0ZW5zaW9ucy1hcGkuaHRtbFxuICovXG5leHBvcnQgdHlwZSBFeHRlbnNpb25FdmVudFR5cGUgPSBcIklOVk9LRVwiIHwgXCJTSFVURE9XTlwiXG5cbi8qKlxuICogUmVnaXN0ZXJlZCBleHRlbnNpb24gaW5mb3JtYXRpb24uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVnaXN0ZXJlZEV4dGVuc2lvbiB7XG4gIC8qKiBVbmlxdWUgaWRlbnRpZmllciBmb3IgdGhlIGV4dGVuc2lvbiAoVVVJRCkgKi9cbiAgZXh0ZW5zaW9uSWQ6IHN0cmluZ1xuICAvKiogTmFtZSBvZiB0aGUgZXh0ZW5zaW9uIChmcm9tIExhbWJkYS1FeHRlbnNpb24tTmFtZSBoZWFkZXIpICovXG4gIG5hbWU6IHN0cmluZ1xuICAvKiogRXZlbnRzIHRoaXMgZXh0ZW5zaW9uIGlzIHJlZ2lzdGVyZWQgZm9yICovXG4gIGV2ZW50czogRXh0ZW5zaW9uRXZlbnRUeXBlW11cbn1cblxuLyoqXG4gKiBFeHRlbnNpb24gSU5WT0tFIGV2ZW50IHBheWxvYWQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRXh0ZW5zaW9uSW52b2tlRXZlbnQge1xuICBldmVudFR5cGU6IFwiSU5WT0tFXCJcbiAgZGVhZGxpbmVNczogbnVtYmVyXG4gIHJlcXVlc3RJZDogc3RyaW5nXG4gIGludm9rZWRGdW5jdGlvbkFybjogc3RyaW5nXG4gIHRyYWNpbmc/OiB7XG4gICAgdHlwZTogc3RyaW5nXG4gICAgdmFsdWU6IHN0cmluZ1xuICB9XG59XG5cbi8qKlxuICogRXh0ZW5zaW9uIFNIVVRET1dOIGV2ZW50IHBheWxvYWQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRXh0ZW5zaW9uU2h1dGRvd25FdmVudCB7XG4gIGV2ZW50VHlwZTogXCJTSFVURE9XTlwiXG4gIHNodXRkb3duUmVhc29uOiBcIlNQSU5ET1dOXCIgfCBcIlRJTUVPVVRcIiB8IFwiRkFJTFVSRVwiXG4gIGRlYWRsaW5lTXM6IG51bWJlclxufVxuXG4vKipcbiAqIEV4dGVuc2lvbiBldmVudCAoZWl0aGVyIElOVk9LRSBvciBTSFVURE9XTikuXG4gKi9cbmV4cG9ydCB0eXBlIEV4dGVuc2lvbkV2ZW50ID0gRXh0ZW5zaW9uSW52b2tlRXZlbnQgfCBFeHRlbnNpb25TaHV0ZG93bkV2ZW50XG5cbi8qKlxuICogUmVzcG9uc2UgYm9keSBmb3IgZXh0ZW5zaW9uIHJlZ2lzdHJhdGlvbi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBFeHRlbnNpb25SZWdpc3RlclJlc3BvbnNlIHtcbiAgZnVuY3Rpb25OYW1lOiBzdHJpbmdcbiAgZnVuY3Rpb25WZXJzaW9uOiBzdHJpbmdcbiAgaGFuZGxlcjogc3RyaW5nXG59XG4iXX0=