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,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AppSync Events client with AWS SigV4 signing.
|
|
3
|
+
*
|
|
4
|
+
* This client handles:
|
|
5
|
+
* - HTTP requests to publish events (with IAM signing)
|
|
6
|
+
* - WebSocket connections for real-time subscriptions (with IAM signing)
|
|
7
|
+
*/
|
|
8
|
+
import { Sha256 } from "@aws-crypto/sha256-js";
|
|
9
|
+
import { defaultProvider } from "@aws-sdk/credential-provider-node";
|
|
10
|
+
import { HttpRequest } from "@aws-sdk/protocol-http";
|
|
11
|
+
import { SignatureV4 } from "@aws-sdk/signature-v4";
|
|
12
|
+
import WebSocket from "ws";
|
|
13
|
+
/**
|
|
14
|
+
* Client for AppSync Events API
|
|
15
|
+
*/
|
|
16
|
+
export class AppSyncEventsClient {
|
|
17
|
+
httpEndpoint;
|
|
18
|
+
realtimeEndpoint;
|
|
19
|
+
region;
|
|
20
|
+
ws = null;
|
|
21
|
+
constructor(config) {
|
|
22
|
+
this.httpEndpoint = config.httpEndpoint;
|
|
23
|
+
this.realtimeEndpoint = config.realtimeEndpoint;
|
|
24
|
+
// Extract region from endpoint URL
|
|
25
|
+
// Format: https://{api-id}.appsync-api.{region}.amazonaws.com/event
|
|
26
|
+
const match = config.httpEndpoint.match(/\.([a-z0-9-]+)\.amazonaws\.com/);
|
|
27
|
+
this.region =
|
|
28
|
+
config.region ?? match?.[1] ?? process.env.AWS_REGION ?? "us-east-1";
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Publish a message to a channel and wait for a response on another channel.
|
|
32
|
+
*/
|
|
33
|
+
async publishAndWaitForResponse(options) {
|
|
34
|
+
const { publishChannel, subscribeChannel, message, timeoutMs, matchResponse, } = options;
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
const timeoutId = setTimeout(() => {
|
|
37
|
+
this.close();
|
|
38
|
+
reject(new Error(`Timeout waiting for response after ${timeoutMs}ms`));
|
|
39
|
+
}, timeoutMs);
|
|
40
|
+
// Set up WebSocket connection first
|
|
41
|
+
this.connectAndSubscribe(subscribeChannel, (receivedMessage) => {
|
|
42
|
+
if (matchResponse(receivedMessage)) {
|
|
43
|
+
clearTimeout(timeoutId);
|
|
44
|
+
resolve(receivedMessage);
|
|
45
|
+
return true; // Signal to stop listening
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
})
|
|
49
|
+
.then(() => {
|
|
50
|
+
// Once subscribed, publish the message
|
|
51
|
+
return this.publish(publishChannel, message);
|
|
52
|
+
})
|
|
53
|
+
.catch((err) => {
|
|
54
|
+
clearTimeout(timeoutId);
|
|
55
|
+
reject(err);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Publish a message to a channel via HTTP
|
|
61
|
+
*/
|
|
62
|
+
async publish(channel, message) {
|
|
63
|
+
const url = new URL(this.httpEndpoint);
|
|
64
|
+
const body = JSON.stringify({
|
|
65
|
+
channel,
|
|
66
|
+
events: [JSON.stringify(message)],
|
|
67
|
+
});
|
|
68
|
+
// AppSync Events requires /event path for publishing
|
|
69
|
+
const path = url.pathname.endsWith("/event") ? url.pathname : "/event";
|
|
70
|
+
const request = new HttpRequest({
|
|
71
|
+
method: "POST",
|
|
72
|
+
protocol: url.protocol,
|
|
73
|
+
hostname: url.hostname,
|
|
74
|
+
path,
|
|
75
|
+
headers: {
|
|
76
|
+
"Content-Type": "application/json",
|
|
77
|
+
host: url.hostname,
|
|
78
|
+
},
|
|
79
|
+
body,
|
|
80
|
+
});
|
|
81
|
+
// Sign the request
|
|
82
|
+
const signer = new SignatureV4({
|
|
83
|
+
credentials: defaultProvider(),
|
|
84
|
+
region: this.region,
|
|
85
|
+
service: "appsync",
|
|
86
|
+
sha256: Sha256,
|
|
87
|
+
});
|
|
88
|
+
const signedRequest = await signer.sign(request);
|
|
89
|
+
// Make the HTTP request - use the correct endpoint with /event path
|
|
90
|
+
const publishUrl = `${url.protocol}//${url.hostname}${path}`;
|
|
91
|
+
const response = await fetch(publishUrl, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
headers: signedRequest.headers,
|
|
94
|
+
body,
|
|
95
|
+
});
|
|
96
|
+
if (!response.ok) {
|
|
97
|
+
const text = await response.text();
|
|
98
|
+
throw new Error(`Failed to publish event: ${response.status} ${text}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Subscribe to a channel and receive messages continuously.
|
|
103
|
+
* Returns an unsubscribe function.
|
|
104
|
+
*/
|
|
105
|
+
async subscribe(options) {
|
|
106
|
+
const { channel, onMessage, onError } = options;
|
|
107
|
+
await this.connectAndSubscribeContinuous(channel, onMessage, onError);
|
|
108
|
+
return () => {
|
|
109
|
+
this.close();
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Check if WebSocket is connected
|
|
114
|
+
*/
|
|
115
|
+
isConnected() {
|
|
116
|
+
return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Connect to WebSocket and subscribe to a channel
|
|
120
|
+
*/
|
|
121
|
+
async connectAndSubscribe(channel, onMessage) {
|
|
122
|
+
// Build signed WebSocket connection
|
|
123
|
+
const [wsUrl, subprotocols] = await this.buildSignedWebSocketConnection();
|
|
124
|
+
return new Promise((resolve, reject) => {
|
|
125
|
+
this.ws = new WebSocket(wsUrl, subprotocols);
|
|
126
|
+
this.ws.on("open", () => {
|
|
127
|
+
console.log("[Bridge] WebSocket connected");
|
|
128
|
+
// Send connection init
|
|
129
|
+
this.ws?.send(JSON.stringify({ type: "connection_init" }));
|
|
130
|
+
});
|
|
131
|
+
this.ws.on("message", (data) => {
|
|
132
|
+
const message = JSON.parse(data.toString());
|
|
133
|
+
if (message.type === "connection_ack") {
|
|
134
|
+
console.log("[Bridge] Connection acknowledged");
|
|
135
|
+
// Subscribe to channel with authorization
|
|
136
|
+
this.createSubscribeAuthorization(channel).then((auth) => {
|
|
137
|
+
this.ws?.send(JSON.stringify({
|
|
138
|
+
type: "subscribe",
|
|
139
|
+
id: "sub-1",
|
|
140
|
+
channel,
|
|
141
|
+
authorization: auth,
|
|
142
|
+
}));
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
else if (message.type === "subscribe_success") {
|
|
146
|
+
console.log(`[Bridge] Subscribed to ${channel}`);
|
|
147
|
+
resolve();
|
|
148
|
+
}
|
|
149
|
+
else if (message.type === "data" && message.id === "sub-1") {
|
|
150
|
+
// Parse the event data
|
|
151
|
+
try {
|
|
152
|
+
const eventData = JSON.parse(message.event);
|
|
153
|
+
const shouldStop = onMessage(eventData);
|
|
154
|
+
if (shouldStop) {
|
|
155
|
+
this.close();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
console.error("[Bridge] Failed to parse event data:", err);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
else if (message.type === "error") {
|
|
163
|
+
console.error("[Bridge] WebSocket error:", message);
|
|
164
|
+
reject(new Error(message.errors
|
|
165
|
+
?.map((e) => e.message)
|
|
166
|
+
.join(", ") ?? "Unknown error"));
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
this.ws.on("error", (err) => {
|
|
170
|
+
console.error("[Bridge] WebSocket error:", err);
|
|
171
|
+
reject(err);
|
|
172
|
+
});
|
|
173
|
+
this.ws.on("close", () => {
|
|
174
|
+
console.log("[Bridge] WebSocket closed");
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Connect to WebSocket and subscribe to a channel with continuous message handling.
|
|
180
|
+
* Unlike connectAndSubscribe, this doesn't close after receiving a message.
|
|
181
|
+
*/
|
|
182
|
+
async connectAndSubscribeContinuous(channel, onMessage, onError) {
|
|
183
|
+
// Build signed WebSocket connection
|
|
184
|
+
const [wsUrl, subprotocols] = await this.buildSignedWebSocketConnection();
|
|
185
|
+
return new Promise((resolve, reject) => {
|
|
186
|
+
this.ws = new WebSocket(wsUrl, subprotocols);
|
|
187
|
+
this.ws.on("open", () => {
|
|
188
|
+
console.log("[AppSync] WebSocket connected");
|
|
189
|
+
// Send connection init
|
|
190
|
+
this.ws?.send(JSON.stringify({ type: "connection_init" }));
|
|
191
|
+
});
|
|
192
|
+
this.ws.on("message", async (data) => {
|
|
193
|
+
const message = JSON.parse(data.toString());
|
|
194
|
+
if (message.type === "connection_ack") {
|
|
195
|
+
console.log("[AppSync] Connection acknowledged");
|
|
196
|
+
// Subscribe to channel with authorization
|
|
197
|
+
this.createSubscribeAuthorization(channel).then((auth) => {
|
|
198
|
+
this.ws?.send(JSON.stringify({
|
|
199
|
+
type: "subscribe",
|
|
200
|
+
id: "sub-1",
|
|
201
|
+
channel,
|
|
202
|
+
authorization: auth,
|
|
203
|
+
}));
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
else if (message.type === "subscribe_success") {
|
|
207
|
+
console.log(`[AppSync] Subscribed to ${channel}`);
|
|
208
|
+
resolve();
|
|
209
|
+
}
|
|
210
|
+
else if (message.type === "data" && message.id === "sub-1") {
|
|
211
|
+
// Parse the event data
|
|
212
|
+
try {
|
|
213
|
+
const eventData = JSON.parse(message.event);
|
|
214
|
+
await onMessage(eventData);
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
console.error("[AppSync] Failed to parse event data:", err);
|
|
218
|
+
onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
else if (message.type === "error") {
|
|
222
|
+
console.error("[AppSync] WebSocket error:", message);
|
|
223
|
+
const error = new Error(message.errors
|
|
224
|
+
?.map((e) => e.message)
|
|
225
|
+
.join(", ") ?? "Unknown error");
|
|
226
|
+
onError?.(error);
|
|
227
|
+
reject(error);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
this.ws.on("error", (err) => {
|
|
231
|
+
console.error("[AppSync] WebSocket error:", err);
|
|
232
|
+
onError?.(err);
|
|
233
|
+
reject(err);
|
|
234
|
+
});
|
|
235
|
+
this.ws.on("close", () => {
|
|
236
|
+
console.log("[AppSync] WebSocket closed");
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Create authorization headers for subscribe operation
|
|
242
|
+
*/
|
|
243
|
+
async createSubscribeAuthorization(channel) {
|
|
244
|
+
const httpUrl = new URL(this.httpEndpoint);
|
|
245
|
+
const payload = JSON.stringify({ channel });
|
|
246
|
+
const request = new HttpRequest({
|
|
247
|
+
method: "POST",
|
|
248
|
+
protocol: "https:",
|
|
249
|
+
hostname: httpUrl.hostname,
|
|
250
|
+
path: "/event",
|
|
251
|
+
headers: {
|
|
252
|
+
accept: "application/json, text/javascript",
|
|
253
|
+
"content-encoding": "amz-1.0",
|
|
254
|
+
"content-type": "application/json; charset=UTF-8",
|
|
255
|
+
host: httpUrl.hostname,
|
|
256
|
+
},
|
|
257
|
+
body: payload,
|
|
258
|
+
});
|
|
259
|
+
const signer = new SignatureV4({
|
|
260
|
+
credentials: defaultProvider(),
|
|
261
|
+
region: this.region,
|
|
262
|
+
service: "appsync",
|
|
263
|
+
sha256: Sha256,
|
|
264
|
+
});
|
|
265
|
+
const signedRequest = await signer.sign(request);
|
|
266
|
+
const auth = {
|
|
267
|
+
accept: "application/json, text/javascript",
|
|
268
|
+
"content-encoding": "amz-1.0",
|
|
269
|
+
"content-type": "application/json; charset=UTF-8",
|
|
270
|
+
host: httpUrl.hostname,
|
|
271
|
+
"x-amz-date": signedRequest.headers["x-amz-date"],
|
|
272
|
+
"x-amz-content-sha256": signedRequest.headers["x-amz-content-sha256"],
|
|
273
|
+
Authorization: signedRequest.headers["authorization"],
|
|
274
|
+
};
|
|
275
|
+
if (signedRequest.headers["x-amz-security-token"]) {
|
|
276
|
+
auth["x-amz-security-token"] =
|
|
277
|
+
signedRequest.headers["x-amz-security-token"];
|
|
278
|
+
}
|
|
279
|
+
return auth;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Build signed WebSocket connection info for AppSync Events
|
|
283
|
+
* Returns [url, subprotocols] for WebSocket constructor
|
|
284
|
+
*/
|
|
285
|
+
async buildSignedWebSocketConnection() {
|
|
286
|
+
const realtimeUrl = new URL(this.realtimeEndpoint);
|
|
287
|
+
realtimeUrl.pathname = "/event/realtime";
|
|
288
|
+
const httpUrl = new URL(this.httpEndpoint);
|
|
289
|
+
// For IAM auth, sign a POST request to the HTTP endpoint
|
|
290
|
+
const request = new HttpRequest({
|
|
291
|
+
method: "POST",
|
|
292
|
+
protocol: "https:",
|
|
293
|
+
hostname: httpUrl.hostname,
|
|
294
|
+
path: "/event",
|
|
295
|
+
headers: {
|
|
296
|
+
accept: "application/json, text/javascript",
|
|
297
|
+
"content-encoding": "amz-1.0",
|
|
298
|
+
"content-type": "application/json; charset=UTF-8",
|
|
299
|
+
host: httpUrl.hostname,
|
|
300
|
+
},
|
|
301
|
+
body: "{}",
|
|
302
|
+
});
|
|
303
|
+
const signer = new SignatureV4({
|
|
304
|
+
credentials: defaultProvider(),
|
|
305
|
+
region: this.region,
|
|
306
|
+
service: "appsync",
|
|
307
|
+
sha256: Sha256,
|
|
308
|
+
});
|
|
309
|
+
const signedRequest = await signer.sign(request);
|
|
310
|
+
// Build header payload for subprotocol - include all signed headers
|
|
311
|
+
const headerPayload = {
|
|
312
|
+
accept: "application/json, text/javascript",
|
|
313
|
+
"content-encoding": "amz-1.0",
|
|
314
|
+
"content-type": "application/json; charset=UTF-8",
|
|
315
|
+
host: httpUrl.hostname,
|
|
316
|
+
"x-amz-date": signedRequest.headers["x-amz-date"],
|
|
317
|
+
"x-amz-content-sha256": signedRequest.headers["x-amz-content-sha256"],
|
|
318
|
+
Authorization: signedRequest.headers["authorization"],
|
|
319
|
+
};
|
|
320
|
+
// Add session token if present
|
|
321
|
+
if (signedRequest.headers["x-amz-security-token"]) {
|
|
322
|
+
headerPayload["x-amz-security-token"] =
|
|
323
|
+
signedRequest.headers["x-amz-security-token"];
|
|
324
|
+
}
|
|
325
|
+
// Base64url encode (no padding, URL-safe)
|
|
326
|
+
const encodedHeader = Buffer.from(JSON.stringify(headerPayload))
|
|
327
|
+
.toString("base64")
|
|
328
|
+
.replace(/\+/g, "-")
|
|
329
|
+
.replace(/\//g, "_")
|
|
330
|
+
.replace(/=+$/, "");
|
|
331
|
+
// Auth is passed as header-{base64url} subprotocol
|
|
332
|
+
const authSubprotocol = `header-${encodedHeader}`;
|
|
333
|
+
return [realtimeUrl.toString(), ["aws-appsync-event-ws", authSubprotocol]];
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Close the WebSocket connection
|
|
337
|
+
*/
|
|
338
|
+
async close() {
|
|
339
|
+
if (this.ws) {
|
|
340
|
+
this.ws.close();
|
|
341
|
+
this.ws = null;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwc3luYy1jbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZnVuY3Rpb25zL2JyaWRnZS9hcHBzeW5jLWNsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sdUJBQXVCLENBQUE7QUFDOUMsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG1DQUFtQyxDQUFBO0FBQ25FLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQTtBQUNwRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sdUJBQXVCLENBQUE7QUFDbkQsT0FBTyxTQUFTLE1BQU0sSUFBSSxDQUFBO0FBc0IxQjs7R0FFRztBQUNILE1BQU0sT0FBTyxtQkFBbUI7SUFDYixZQUFZLENBQVE7SUFDcEIsZ0JBQWdCLENBQVE7SUFDeEIsTUFBTSxDQUFRO0lBQ3ZCLEVBQUUsR0FBcUIsSUFBSSxDQUFBO0lBRW5DLFlBQVksTUFBaUM7UUFDM0MsSUFBSSxDQUFDLFlBQVksR0FBRyxNQUFNLENBQUMsWUFBWSxDQUFBO1FBQ3ZDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUE7UUFDL0MsbUNBQW1DO1FBQ25DLG9FQUFvRTtRQUNwRSxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFBO1FBQ3pFLElBQUksQ0FBQyxNQUFNO1lBQ1QsTUFBTSxDQUFDLE1BQU0sSUFBSSxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsSUFBSSxXQUFXLENBQUE7SUFDeEUsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLHlCQUF5QixDQUM3QixPQUFpQztRQUVqQyxNQUFNLEVBQ0osY0FBYyxFQUNkLGdCQUFnQixFQUNoQixPQUFPLEVBQ1AsU0FBUyxFQUNULGFBQWEsR0FDZCxHQUFHLE9BQU8sQ0FBQTtRQUVYLE9BQU8sSUFBSSxPQUFPLENBQUksQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDeEMsTUFBTSxTQUFTLEdBQUcsVUFBVSxDQUFDLEdBQUcsRUFBRTtnQkFDaEMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFBO2dCQUNaLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxzQ0FBc0MsU0FBUyxJQUFJLENBQUMsQ0FBQyxDQUFBO1lBQ3hFLENBQUMsRUFBRSxTQUFTLENBQUMsQ0FBQTtZQUViLG9DQUFvQztZQUNwQyxJQUFJLENBQUMsbUJBQW1CLENBQUksZ0JBQWdCLEVBQUUsQ0FBQyxlQUFlLEVBQUUsRUFBRTtnQkFDaEUsSUFBSSxhQUFhLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQztvQkFDbkMsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFBO29CQUN2QixPQUFPLENBQUMsZUFBZSxDQUFDLENBQUE7b0JBQ3hCLE9BQU8sSUFBSSxDQUFBLENBQUMsMkJBQTJCO2dCQUN6QyxDQUFDO2dCQUNELE9BQU8sS0FBSyxDQUFBO1lBQ2QsQ0FBQyxDQUFDO2lCQUNDLElBQUksQ0FBQyxHQUFHLEVBQUU7Z0JBQ1QsdUNBQXVDO2dCQUN2QyxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxFQUFFLE9BQU8sQ0FBQyxDQUFBO1lBQzlDLENBQUMsQ0FBQztpQkFDRCxLQUFLLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRTtnQkFDYixZQUFZLENBQUMsU0FBUyxDQUFDLENBQUE7Z0JBQ3ZCLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQTtZQUNiLENBQUMsQ0FBQyxDQUFBO1FBQ04sQ0FBQyxDQUFDLENBQUE7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsT0FBTyxDQUFDLE9BQWUsRUFBRSxPQUFnQjtRQUM3QyxNQUFNLEdBQUcsR0FBRyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUE7UUFDdEMsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQztZQUMxQixPQUFPO1lBQ1AsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztTQUNsQyxDQUFDLENBQUE7UUFFRixxREFBcUQ7UUFDckQsTUFBTSxJQUFJLEdBQUcsR0FBRyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQTtRQUV0RSxNQUFNLE9BQU8sR0FBRyxJQUFJLFdBQVcsQ0FBQztZQUM5QixNQUFNLEVBQUUsTUFBTTtZQUNkLFFBQVEsRUFBRSxHQUFHLENBQUMsUUFBUTtZQUN0QixRQUFRLEVBQUUsR0FBRyxDQUFDLFFBQVE7WUFDdEIsSUFBSTtZQUNKLE9BQU8sRUFBRTtnQkFDUCxjQUFjLEVBQUUsa0JBQWtCO2dCQUNsQyxJQUFJLEVBQUUsR0FBRyxDQUFDLFFBQVE7YUFDbkI7WUFDRCxJQUFJO1NBQ0wsQ0FBQyxDQUFBO1FBRUYsbUJBQW1CO1FBQ25CLE1BQU0sTUFBTSxHQUFHLElBQUksV0FBVyxDQUFDO1lBQzdCLFdBQVcsRUFBRSxlQUFlLEVBQUU7WUFDOUIsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNO1lBQ25CLE9BQU8sRUFBRSxTQUFTO1lBQ2xCLE1BQU0sRUFBRSxNQUFNO1NBQ2YsQ0FBQyxDQUFBO1FBRUYsTUFBTSxhQUFhLEdBQUcsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBRWhELG9FQUFvRTtRQUNwRSxNQUFNLFVBQVUsR0FBRyxHQUFHLEdBQUcsQ0FBQyxRQUFRLEtBQUssR0FBRyxDQUFDLFFBQVEsR0FBRyxJQUFJLEVBQUUsQ0FBQTtRQUM1RCxNQUFNLFFBQVEsR0FBRyxNQUFNLEtBQUssQ0FBQyxVQUFVLEVBQUU7WUFDdkMsTUFBTSxFQUFFLE1BQU07WUFDZCxPQUFPLEVBQUUsYUFBYSxDQUFDLE9BQWlDO1lBQ3hELElBQUk7U0FDTCxDQUFDLENBQUE7UUFFRixJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQ2pCLE1BQU0sSUFBSSxHQUFHLE1BQU0sUUFBUSxDQUFDLElBQUksRUFBRSxDQUFBO1lBQ2xDLE1BQU0sSUFBSSxLQUFLLENBQUMsNEJBQTRCLFFBQVEsQ0FBQyxNQUFNLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQTtRQUN4RSxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxTQUFTLENBQUksT0FBK0I7UUFDaEQsTUFBTSxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLEdBQUcsT0FBTyxDQUFBO1FBRS9DLE1BQU0sSUFBSSxDQUFDLDZCQUE2QixDQUFJLE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFFeEUsT0FBTyxHQUFHLEVBQUU7WUFDVixJQUFJLENBQUMsS0FBSyxFQUFFLENBQUE7UUFDZCxDQUFDLENBQUE7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxXQUFXO1FBQ1QsT0FBTyxJQUFJLENBQUMsRUFBRSxLQUFLLElBQUksSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDLFVBQVUsS0FBSyxTQUFTLENBQUMsSUFBSSxDQUFBO0lBQ2xFLENBQUM7SUFFRDs7T0FFRztJQUNLLEtBQUssQ0FBQyxtQkFBbUIsQ0FDL0IsT0FBZSxFQUNmLFNBQWtDO1FBRWxDLG9DQUFvQztRQUNwQyxNQUFNLENBQUMsS0FBSyxFQUFFLFlBQVksQ0FBQyxHQUFHLE1BQU0sSUFBSSxDQUFDLDhCQUE4QixFQUFFLENBQUE7UUFFekUsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUNyQyxJQUFJLENBQUMsRUFBRSxHQUFHLElBQUksU0FBUyxDQUFDLEtBQUssRUFBRSxZQUFZLENBQUMsQ0FBQTtZQUU1QyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsR0FBRyxFQUFFO2dCQUN0QixPQUFPLENBQUMsR0FBRyxDQUFDLDhCQUE4QixDQUFDLENBQUE7Z0JBQzNDLHVCQUF1QjtnQkFDdkIsSUFBSSxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLElBQUksRUFBRSxpQkFBaUIsRUFBRSxDQUFDLENBQUMsQ0FBQTtZQUM1RCxDQUFDLENBQUMsQ0FBQTtZQUVGLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLFNBQVMsRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFO2dCQUM3QixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFBO2dCQUUzQyxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssZ0JBQWdCLEVBQUUsQ0FBQztvQkFDdEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQ0FBa0MsQ0FBQyxDQUFBO29CQUMvQywwQ0FBMEM7b0JBQzFDLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTt3QkFDdkQsSUFBSSxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQ1gsSUFBSSxDQUFDLFNBQVMsQ0FBQzs0QkFDYixJQUFJLEVBQUUsV0FBVzs0QkFDakIsRUFBRSxFQUFFLE9BQU87NEJBQ1gsT0FBTzs0QkFDUCxhQUFhLEVBQUUsSUFBSTt5QkFDcEIsQ0FBQyxDQUNILENBQUE7b0JBQ0gsQ0FBQyxDQUFDLENBQUE7Z0JBQ0osQ0FBQztxQkFBTSxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssbUJBQW1CLEVBQUUsQ0FBQztvQkFDaEQsT0FBTyxDQUFDLEdBQUcsQ0FBQywwQkFBMEIsT0FBTyxFQUFFLENBQUMsQ0FBQTtvQkFDaEQsT0FBTyxFQUFFLENBQUE7Z0JBQ1gsQ0FBQztxQkFBTSxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssTUFBTSxJQUFJLE9BQU8sQ0FBQyxFQUFFLEtBQUssT0FBTyxFQUFFLENBQUM7b0JBQzdELHVCQUF1QjtvQkFDdkIsSUFBSSxDQUFDO3dCQUNILE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBTSxDQUFBO3dCQUNoRCxNQUFNLFVBQVUsR0FBRyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUE7d0JBQ3ZDLElBQUksVUFBVSxFQUFFLENBQUM7NEJBQ2YsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFBO3dCQUNkLENBQUM7b0JBQ0gsQ0FBQztvQkFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO3dCQUNiLE9BQU8sQ0FBQyxLQUFLLENBQUMsc0NBQXNDLEVBQUUsR0FBRyxDQUFDLENBQUE7b0JBQzVELENBQUM7Z0JBQ0gsQ0FBQztxQkFBTSxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssT0FBTyxFQUFFLENBQUM7b0JBQ3BDLE9BQU8sQ0FBQyxLQUFLLENBQUMsMkJBQTJCLEVBQUUsT0FBTyxDQUFDLENBQUE7b0JBQ25ELE1BQU0sQ0FDSixJQUFJLEtBQUssQ0FDUCxPQUFPLENBQUMsTUFBTTt3QkFDWixFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQXNCLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUM7eUJBQzNDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxlQUFlLENBQ2pDLENBQ0YsQ0FBQTtnQkFDSCxDQUFDO1lBQ0gsQ0FBQyxDQUFDLENBQUE7WUFFRixJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRTtnQkFDMUIsT0FBTyxDQUFDLEtBQUssQ0FBQywyQkFBMkIsRUFBRSxHQUFHLENBQUMsQ0FBQTtnQkFDL0MsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBQ2IsQ0FBQyxDQUFDLENBQUE7WUFFRixJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsR0FBRyxFQUFFO2dCQUN2QixPQUFPLENBQUMsR0FBRyxDQUFDLDJCQUEyQixDQUFDLENBQUE7WUFDMUMsQ0FBQyxDQUFDLENBQUE7UUFDSixDQUFDLENBQUMsQ0FBQTtJQUNKLENBQUM7SUFFRDs7O09BR0c7SUFDSyxLQUFLLENBQUMsNkJBQTZCLENBQ3pDLE9BQWUsRUFDZixTQUErQyxFQUMvQyxPQUFnQztRQUVoQyxvQ0FBb0M7UUFDcEMsTUFBTSxDQUFDLEtBQUssRUFBRSxZQUFZLENBQUMsR0FBRyxNQUFNLElBQUksQ0FBQyw4QkFBOEIsRUFBRSxDQUFBO1FBRXpFLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDckMsSUFBSSxDQUFDLEVBQUUsR0FBRyxJQUFJLFNBQVMsQ0FBQyxLQUFLLEVBQUUsWUFBWSxDQUFDLENBQUE7WUFFNUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRTtnQkFDdEIsT0FBTyxDQUFDLEdBQUcsQ0FBQywrQkFBK0IsQ0FBQyxDQUFBO2dCQUM1Qyx1QkFBdUI7Z0JBQ3ZCLElBQUksQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxJQUFJLEVBQUUsaUJBQWlCLEVBQUUsQ0FBQyxDQUFDLENBQUE7WUFDNUQsQ0FBQyxDQUFDLENBQUE7WUFFRixJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxTQUFTLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFO2dCQUNuQyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFBO2dCQUUzQyxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssZ0JBQWdCLEVBQUUsQ0FBQztvQkFDdEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxtQ0FBbUMsQ0FBQyxDQUFBO29CQUNoRCwwQ0FBMEM7b0JBQzFDLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTt3QkFDdkQsSUFBSSxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQ1gsSUFBSSxDQUFDLFNBQVMsQ0FBQzs0QkFDYixJQUFJLEVBQUUsV0FBVzs0QkFDakIsRUFBRSxFQUFFLE9BQU87NEJBQ1gsT0FBTzs0QkFDUCxhQUFhLEVBQUUsSUFBSTt5QkFDcEIsQ0FBQyxDQUNILENBQUE7b0JBQ0gsQ0FBQyxDQUFDLENBQUE7Z0JBQ0osQ0FBQztxQkFBTSxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssbUJBQW1CLEVBQUUsQ0FBQztvQkFDaEQsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsT0FBTyxFQUFFLENBQUMsQ0FBQTtvQkFDakQsT0FBTyxFQUFFLENBQUE7Z0JBQ1gsQ0FBQztxQkFBTSxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssTUFBTSxJQUFJLE9BQU8sQ0FBQyxFQUFFLEtBQUssT0FBTyxFQUFFLENBQUM7b0JBQzdELHVCQUF1QjtvQkFDdkIsSUFBSSxDQUFDO3dCQUNILE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBTSxDQUFBO3dCQUNoRCxNQUFNLFNBQVMsQ0FBQyxTQUFTLENBQUMsQ0FBQTtvQkFDNUIsQ0FBQztvQkFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO3dCQUNiLE9BQU8sQ0FBQyxLQUFLLENBQUMsdUNBQXVDLEVBQUUsR0FBRyxDQUFDLENBQUE7d0JBQzNELE9BQU8sRUFBRSxDQUFDLEdBQUcsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQTtvQkFDaEUsQ0FBQztnQkFDSCxDQUFDO3FCQUFNLElBQUksT0FBTyxDQUFDLElBQUksS0FBSyxPQUFPLEVBQUUsQ0FBQztvQkFDcEMsT0FBTyxDQUFDLEtBQUssQ0FBQyw0QkFBNEIsRUFBRSxPQUFPLENBQUMsQ0FBQTtvQkFDcEQsTUFBTSxLQUFLLEdBQUcsSUFBSSxLQUFLLENBQ3JCLE9BQU8sQ0FBQyxNQUFNO3dCQUNaLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBc0IsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQzt5QkFDM0MsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLGVBQWUsQ0FDakMsQ0FBQTtvQkFDRCxPQUFPLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQTtvQkFDaEIsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFBO2dCQUNmLENBQUM7WUFDSCxDQUFDLENBQUMsQ0FBQTtZQUVGLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFO2dCQUMxQixPQUFPLENBQUMsS0FBSyxDQUFDLDRCQUE0QixFQUFFLEdBQUcsQ0FBQyxDQUFBO2dCQUNoRCxPQUFPLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQTtnQkFDZCxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUE7WUFDYixDQUFDLENBQUMsQ0FBQTtZQUVGLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxHQUFHLEVBQUU7Z0JBQ3ZCLE9BQU8sQ0FBQyxHQUFHLENBQUMsNEJBQTRCLENBQUMsQ0FBQTtZQUMzQyxDQUFDLENBQUMsQ0FBQTtRQUNKLENBQUMsQ0FBQyxDQUFBO0lBQ0osQ0FBQztJQUVEOztPQUVHO0lBQ0ssS0FBSyxDQUFDLDRCQUE0QixDQUN4QyxPQUFlO1FBRWYsTUFBTSxPQUFPLEdBQUcsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFBO1FBQzFDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFBO1FBRTNDLE1BQU0sT0FBTyxHQUFHLElBQUksV0FBVyxDQUFDO1lBQzlCLE1BQU0sRUFBRSxNQUFNO1lBQ2QsUUFBUSxFQUFFLFFBQVE7WUFDbEIsUUFBUSxFQUFFLE9BQU8sQ0FBQyxRQUFRO1lBQzFCLElBQUksRUFBRSxRQUFRO1lBQ2QsT0FBTyxFQUFFO2dCQUNQLE1BQU0sRUFBRSxtQ0FBbUM7Z0JBQzNDLGtCQUFrQixFQUFFLFNBQVM7Z0JBQzdCLGNBQWMsRUFBRSxpQ0FBaUM7Z0JBQ2pELElBQUksRUFBRSxPQUFPLENBQUMsUUFBUTthQUN2QjtZQUNELElBQUksRUFBRSxPQUFPO1NBQ2QsQ0FBQyxDQUFBO1FBRUYsTUFBTSxNQUFNLEdBQUcsSUFBSSxXQUFXLENBQUM7WUFDN0IsV0FBVyxFQUFFLGVBQWUsRUFBRTtZQUM5QixNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07WUFDbkIsT0FBTyxFQUFFLFNBQVM7WUFDbEIsTUFBTSxFQUFFLE1BQU07U0FDZixDQUFDLENBQUE7UUFFRixNQUFNLGFBQWEsR0FBRyxNQUFNLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUE7UUFFaEQsTUFBTSxJQUFJLEdBQTJCO1lBQ25DLE1BQU0sRUFBRSxtQ0FBbUM7WUFDM0Msa0JBQWtCLEVBQUUsU0FBUztZQUM3QixjQUFjLEVBQUUsaUNBQWlDO1lBQ2pELElBQUksRUFBRSxPQUFPLENBQUMsUUFBUTtZQUN0QixZQUFZLEVBQUUsYUFBYSxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUM7WUFDakQsc0JBQXNCLEVBQUUsYUFBYSxDQUFDLE9BQU8sQ0FBQyxzQkFBc0IsQ0FBQztZQUNyRSxhQUFhLEVBQUUsYUFBYSxDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUM7U0FDdEQsQ0FBQTtRQUVELElBQUksYUFBYSxDQUFDLE9BQU8sQ0FBQyxzQkFBc0IsQ0FBQyxFQUFFLENBQUM7WUFDbEQsSUFBSSxDQUFDLHNCQUFzQixDQUFDO2dCQUMxQixhQUFhLENBQUMsT0FBTyxDQUFDLHNCQUFzQixDQUFDLENBQUE7UUFDakQsQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFBO0lBQ2IsQ0FBQztJQUVEOzs7T0FHRztJQUNLLEtBQUssQ0FBQyw4QkFBOEI7UUFDMUMsTUFBTSxXQUFXLEdBQUcsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUE7UUFDbEQsV0FBVyxDQUFDLFFBQVEsR0FBRyxpQkFBaUIsQ0FBQTtRQUN4QyxNQUFNLE9BQU8sR0FBRyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUE7UUFFMUMseURBQXlEO1FBQ3pELE1BQU0sT0FBTyxHQUFHLElBQUksV0FBVyxDQUFDO1lBQzlCLE1BQU0sRUFBRSxNQUFNO1lBQ2QsUUFBUSxFQUFFLFFBQVE7WUFDbEIsUUFBUSxFQUFFLE9BQU8sQ0FBQyxRQUFRO1lBQzFCLElBQUksRUFBRSxRQUFRO1lBQ2QsT0FBTyxFQUFFO2dCQUNQLE1BQU0sRUFBRSxtQ0FBbUM7Z0JBQzNDLGtCQUFrQixFQUFFLFNBQVM7Z0JBQzdCLGNBQWMsRUFBRSxpQ0FBaUM7Z0JBQ2pELElBQUksRUFBRSxPQUFPLENBQUMsUUFBUTthQUN2QjtZQUNELElBQUksRUFBRSxJQUFJO1NBQ1gsQ0FBQyxDQUFBO1FBRUYsTUFBTSxNQUFNLEdBQUcsSUFBSSxXQUFXLENBQUM7WUFDN0IsV0FBVyxFQUFFLGVBQWUsRUFBRTtZQUM5QixNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07WUFDbkIsT0FBTyxFQUFFLFNBQVM7WUFDbEIsTUFBTSxFQUFFLE1BQU07U0FDZixDQUFDLENBQUE7UUFFRixNQUFNLGFBQWEsR0FBRyxNQUFNLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUE7UUFFaEQsb0VBQW9FO1FBQ3BFLE1BQU0sYUFBYSxHQUEyQjtZQUM1QyxNQUFNLEVBQUUsbUNBQW1DO1lBQzNDLGtCQUFrQixFQUFFLFNBQVM7WUFDN0IsY0FBYyxFQUFFLGlDQUFpQztZQUNqRCxJQUFJLEVBQUUsT0FBTyxDQUFDLFFBQVE7WUFDdEIsWUFBWSxFQUFFLGFBQWEsQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDO1lBQ2pELHNCQUFzQixFQUFFLGFBQWEsQ0FBQyxPQUFPLENBQUMsc0JBQXNCLENBQUM7WUFDckUsYUFBYSxFQUFFLGFBQWEsQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDO1NBQ3RELENBQUE7UUFFRCwrQkFBK0I7UUFDL0IsSUFBSSxhQUFhLENBQUMsT0FBTyxDQUFDLHNCQUFzQixDQUFDLEVBQUUsQ0FBQztZQUNsRCxhQUFhLENBQUMsc0JBQXNCLENBQUM7Z0JBQ25DLGFBQWEsQ0FBQyxPQUFPLENBQUMsc0JBQXNCLENBQUMsQ0FBQTtRQUNqRCxDQUFDO1FBRUQsMENBQTBDO1FBQzFDLE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsQ0FBQzthQUM3RCxRQUFRLENBQUMsUUFBUSxDQUFDO2FBQ2xCLE9BQU8sQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDO2FBQ25CLE9BQU8sQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDO2FBQ25CLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUE7UUFFckIsbURBQW1EO1FBQ25ELE1BQU0sZUFBZSxHQUFHLFVBQVUsYUFBYSxFQUFFLENBQUE7UUFFakQsT0FBTyxDQUFDLFdBQVcsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLHNCQUFzQixFQUFFLGVBQWUsQ0FBQyxDQUFDLENBQUE7SUFDNUUsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLEtBQUs7UUFDVCxJQUFJLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNaLElBQUksQ0FBQyxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUE7WUFDZixJQUFJLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQTtRQUNoQixDQUFDO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBcHBTeW5jIEV2ZW50cyBjbGllbnQgd2l0aCBBV1MgU2lnVjQgc2lnbmluZy5cbiAqXG4gKiBUaGlzIGNsaWVudCBoYW5kbGVzOlxuICogLSBIVFRQIHJlcXVlc3RzIHRvIHB1Ymxpc2ggZXZlbnRzICh3aXRoIElBTSBzaWduaW5nKVxuICogLSBXZWJTb2NrZXQgY29ubmVjdGlvbnMgZm9yIHJlYWwtdGltZSBzdWJzY3JpcHRpb25zICh3aXRoIElBTSBzaWduaW5nKVxuICovXG5cbmltcG9ydCB7IFNoYTI1NiB9IGZyb20gXCJAYXdzLWNyeXB0by9zaGEyNTYtanNcIlxuaW1wb3J0IHsgZGVmYXVsdFByb3ZpZGVyIH0gZnJvbSBcIkBhd3Mtc2RrL2NyZWRlbnRpYWwtcHJvdmlkZXItbm9kZVwiXG5pbXBvcnQgeyBIdHRwUmVxdWVzdCB9IGZyb20gXCJAYXdzLXNkay9wcm90b2NvbC1odHRwXCJcbmltcG9ydCB7IFNpZ25hdHVyZVY0IH0gZnJvbSBcIkBhd3Mtc2RrL3NpZ25hdHVyZS12NFwiXG5pbXBvcnQgV2ViU29ja2V0IGZyb20gXCJ3c1wiXG5cbmV4cG9ydCBpbnRlcmZhY2UgQXBwU3luY0V2ZW50c0NsaWVudENvbmZpZyB7XG4gIGh0dHBFbmRwb2ludDogc3RyaW5nXG4gIHJlYWx0aW1lRW5kcG9pbnQ6IHN0cmluZ1xuICByZWdpb24/OiBzdHJpbmdcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQdWJsaXNoQW5kV2FpdE9wdGlvbnM8VD4ge1xuICBwdWJsaXNoQ2hhbm5lbDogc3RyaW5nXG4gIHN1YnNjcmliZUNoYW5uZWw6IHN0cmluZ1xuICBtZXNzYWdlOiB1bmtub3duXG4gIHRpbWVvdXRNczogbnVtYmVyXG4gIG1hdGNoUmVzcG9uc2U6IChtZXNzYWdlOiBUKSA9PiBib29sZWFuXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3Vic2NyaXB0aW9uT3B0aW9uczxUPiB7XG4gIGNoYW5uZWw6IHN0cmluZ1xuICBvbk1lc3NhZ2U6IChtZXNzYWdlOiBUKSA9PiB2b2lkIHwgUHJvbWlzZTx2b2lkPlxuICBvbkVycm9yPzogKGVycm9yOiBFcnJvcikgPT4gdm9pZFxufVxuXG4vKipcbiAqIENsaWVudCBmb3IgQXBwU3luYyBFdmVudHMgQVBJXG4gKi9cbmV4cG9ydCBjbGFzcyBBcHBTeW5jRXZlbnRzQ2xpZW50IHtcbiAgcHJpdmF0ZSByZWFkb25seSBodHRwRW5kcG9pbnQ6IHN0cmluZ1xuICBwcml2YXRlIHJlYWRvbmx5IHJlYWx0aW1lRW5kcG9pbnQ6IHN0cmluZ1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZ2lvbjogc3RyaW5nXG4gIHByaXZhdGUgd3M6IFdlYlNvY2tldCB8IG51bGwgPSBudWxsXG5cbiAgY29uc3RydWN0b3IoY29uZmlnOiBBcHBTeW5jRXZlbnRzQ2xpZW50Q29uZmlnKSB7XG4gICAgdGhpcy5odHRwRW5kcG9pbnQgPSBjb25maWcuaHR0cEVuZHBvaW50XG4gICAgdGhpcy5yZWFsdGltZUVuZHBvaW50ID0gY29uZmlnLnJlYWx0aW1lRW5kcG9pbnRcbiAgICAvLyBFeHRyYWN0IHJlZ2lvbiBmcm9tIGVuZHBvaW50IFVSTFxuICAgIC8vIEZvcm1hdDogaHR0cHM6Ly97YXBpLWlkfS5hcHBzeW5jLWFwaS57cmVnaW9ufS5hbWF6b25hd3MuY29tL2V2ZW50XG4gICAgY29uc3QgbWF0Y2ggPSBjb25maWcuaHR0cEVuZHBvaW50Lm1hdGNoKC9cXC4oW2EtejAtOS1dKylcXC5hbWF6b25hd3NcXC5jb20vKVxuICAgIHRoaXMucmVnaW9uID1cbiAgICAgIGNvbmZpZy5yZWdpb24gPz8gbWF0Y2g/LlsxXSA/PyBwcm9jZXNzLmVudi5BV1NfUkVHSU9OID8/IFwidXMtZWFzdC0xXCJcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaXNoIGEgbWVzc2FnZSB0byBhIGNoYW5uZWwgYW5kIHdhaXQgZm9yIGEgcmVzcG9uc2Ugb24gYW5vdGhlciBjaGFubmVsLlxuICAgKi9cbiAgYXN5bmMgcHVibGlzaEFuZFdhaXRGb3JSZXNwb25zZTxUPihcbiAgICBvcHRpb25zOiBQdWJsaXNoQW5kV2FpdE9wdGlvbnM8VD4sXG4gICk6IFByb21pc2U8VD4ge1xuICAgIGNvbnN0IHtcbiAgICAgIHB1Ymxpc2hDaGFubmVsLFxuICAgICAgc3Vic2NyaWJlQ2hhbm5lbCxcbiAgICAgIG1lc3NhZ2UsXG4gICAgICB0aW1lb3V0TXMsXG4gICAgICBtYXRjaFJlc3BvbnNlLFxuICAgIH0gPSBvcHRpb25zXG5cbiAgICByZXR1cm4gbmV3IFByb21pc2U8VD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3QgdGltZW91dElkID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHRoaXMuY2xvc2UoKVxuICAgICAgICByZWplY3QobmV3IEVycm9yKGBUaW1lb3V0IHdhaXRpbmcgZm9yIHJlc3BvbnNlIGFmdGVyICR7dGltZW91dE1zfW1zYCkpXG4gICAgICB9LCB0aW1lb3V0TXMpXG5cbiAgICAgIC8vIFNldCB1cCBXZWJTb2NrZXQgY29ubmVjdGlvbiBmaXJzdFxuICAgICAgdGhpcy5jb25uZWN0QW5kU3Vic2NyaWJlPFQ+KHN1YnNjcmliZUNoYW5uZWwsIChyZWNlaXZlZE1lc3NhZ2UpID0+IHtcbiAgICAgICAgaWYgKG1hdGNoUmVzcG9uc2UocmVjZWl2ZWRNZXNzYWdlKSkge1xuICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0SWQpXG4gICAgICAgICAgcmVzb2x2ZShyZWNlaXZlZE1lc3NhZ2UpXG4gICAgICAgICAgcmV0dXJuIHRydWUgLy8gU2lnbmFsIHRvIHN0b3AgbGlzdGVuaW5nXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlXG4gICAgICB9KVxuICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgLy8gT25jZSBzdWJzY3JpYmVkLCBwdWJsaXNoIHRoZSBtZXNzYWdlXG4gICAgICAgICAgcmV0dXJuIHRoaXMucHVibGlzaChwdWJsaXNoQ2hhbm5lbCwgbWVzc2FnZSlcbiAgICAgICAgfSlcbiAgICAgICAgLmNhdGNoKChlcnIpID0+IHtcbiAgICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dElkKVxuICAgICAgICAgIHJlamVjdChlcnIpXG4gICAgICAgIH0pXG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaXNoIGEgbWVzc2FnZSB0byBhIGNoYW5uZWwgdmlhIEhUVFBcbiAgICovXG4gIGFzeW5jIHB1Ymxpc2goY2hhbm5lbDogc3RyaW5nLCBtZXNzYWdlOiB1bmtub3duKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgdXJsID0gbmV3IFVSTCh0aGlzLmh0dHBFbmRwb2ludClcbiAgICBjb25zdCBib2R5ID0gSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgY2hhbm5lbCxcbiAgICAgIGV2ZW50czogW0pTT04uc3RyaW5naWZ5KG1lc3NhZ2UpXSxcbiAgICB9KVxuXG4gICAgLy8gQXBwU3luYyBFdmVudHMgcmVxdWlyZXMgL2V2ZW50IHBhdGggZm9yIHB1Ymxpc2hpbmdcbiAgICBjb25zdCBwYXRoID0gdXJsLnBhdGhuYW1lLmVuZHNXaXRoKFwiL2V2ZW50XCIpID8gdXJsLnBhdGhuYW1lIDogXCIvZXZlbnRcIlxuXG4gICAgY29uc3QgcmVxdWVzdCA9IG5ldyBIdHRwUmVxdWVzdCh7XG4gICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgcHJvdG9jb2w6IHVybC5wcm90b2NvbCxcbiAgICAgIGhvc3RuYW1lOiB1cmwuaG9zdG5hbWUsXG4gICAgICBwYXRoLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgICAgaG9zdDogdXJsLmhvc3RuYW1lLFxuICAgICAgfSxcbiAgICAgIGJvZHksXG4gICAgfSlcblxuICAgIC8vIFNpZ24gdGhlIHJlcXVlc3RcbiAgICBjb25zdCBzaWduZXIgPSBuZXcgU2lnbmF0dXJlVjQoe1xuICAgICAgY3JlZGVudGlhbHM6IGRlZmF1bHRQcm92aWRlcigpLFxuICAgICAgcmVnaW9uOiB0aGlzLnJlZ2lvbixcbiAgICAgIHNlcnZpY2U6IFwiYXBwc3luY1wiLFxuICAgICAgc2hhMjU2OiBTaGEyNTYsXG4gICAgfSlcblxuICAgIGNvbnN0IHNpZ25lZFJlcXVlc3QgPSBhd2FpdCBzaWduZXIuc2lnbihyZXF1ZXN0KVxuXG4gICAgLy8gTWFrZSB0aGUgSFRUUCByZXF1ZXN0IC0gdXNlIHRoZSBjb3JyZWN0IGVuZHBvaW50IHdpdGggL2V2ZW50IHBhdGhcbiAgICBjb25zdCBwdWJsaXNoVXJsID0gYCR7dXJsLnByb3RvY29sfS8vJHt1cmwuaG9zdG5hbWV9JHtwYXRofWBcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKHB1Ymxpc2hVcmwsIHtcbiAgICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgICBoZWFkZXJzOiBzaWduZWRSZXF1ZXN0LmhlYWRlcnMgYXMgUmVjb3JkPHN0cmluZywgc3RyaW5nPixcbiAgICAgIGJvZHksXG4gICAgfSlcblxuICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgIGNvbnN0IHRleHQgPSBhd2FpdCByZXNwb25zZS50ZXh0KClcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIHB1Ymxpc2ggZXZlbnQ6ICR7cmVzcG9uc2Uuc3RhdHVzfSAke3RleHR9YClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU3Vic2NyaWJlIHRvIGEgY2hhbm5lbCBhbmQgcmVjZWl2ZSBtZXNzYWdlcyBjb250aW51b3VzbHkuXG4gICAqIFJldHVybnMgYW4gdW5zdWJzY3JpYmUgZnVuY3Rpb24uXG4gICAqL1xuICBhc3luYyBzdWJzY3JpYmU8VD4ob3B0aW9uczogU3Vic2NyaXB0aW9uT3B0aW9uczxUPik6IFByb21pc2U8KCkgPT4gdm9pZD4ge1xuICAgIGNvbnN0IHsgY2hhbm5lbCwgb25NZXNzYWdlLCBvbkVycm9yIH0gPSBvcHRpb25zXG5cbiAgICBhd2FpdCB0aGlzLmNvbm5lY3RBbmRTdWJzY3JpYmVDb250aW51b3VzPFQ+KGNoYW5uZWwsIG9uTWVzc2FnZSwgb25FcnJvcilcblxuICAgIHJldHVybiAoKSA9PiB7XG4gICAgICB0aGlzLmNsb3NlKClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgaWYgV2ViU29ja2V0IGlzIGNvbm5lY3RlZFxuICAgKi9cbiAgaXNDb25uZWN0ZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMud3MgIT09IG51bGwgJiYgdGhpcy53cy5yZWFkeVN0YXRlID09PSBXZWJTb2NrZXQuT1BFTlxuICB9XG5cbiAgLyoqXG4gICAqIENvbm5lY3QgdG8gV2ViU29ja2V0IGFuZCBzdWJzY3JpYmUgdG8gYSBjaGFubmVsXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGNvbm5lY3RBbmRTdWJzY3JpYmU8VD4oXG4gICAgY2hhbm5lbDogc3RyaW5nLFxuICAgIG9uTWVzc2FnZTogKG1lc3NhZ2U6IFQpID0+IGJvb2xlYW4sXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIEJ1aWxkIHNpZ25lZCBXZWJTb2NrZXQgY29ubmVjdGlvblxuICAgIGNvbnN0IFt3c1VybCwgc3VicHJvdG9jb2xzXSA9IGF3YWl0IHRoaXMuYnVpbGRTaWduZWRXZWJTb2NrZXRDb25uZWN0aW9uKClcblxuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICB0aGlzLndzID0gbmV3IFdlYlNvY2tldCh3c1VybCwgc3VicHJvdG9jb2xzKVxuXG4gICAgICB0aGlzLndzLm9uKFwib3BlblwiLCAoKSA9PiB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiW0JyaWRnZV0gV2ViU29ja2V0IGNvbm5lY3RlZFwiKVxuICAgICAgICAvLyBTZW5kIGNvbm5lY3Rpb24gaW5pdFxuICAgICAgICB0aGlzLndzPy5zZW5kKEpTT04uc3RyaW5naWZ5KHsgdHlwZTogXCJjb25uZWN0aW9uX2luaXRcIiB9KSlcbiAgICAgIH0pXG5cbiAgICAgIHRoaXMud3Mub24oXCJtZXNzYWdlXCIsIChkYXRhKSA9PiB7XG4gICAgICAgIGNvbnN0IG1lc3NhZ2UgPSBKU09OLnBhcnNlKGRhdGEudG9TdHJpbmcoKSlcblxuICAgICAgICBpZiAobWVzc2FnZS50eXBlID09PSBcImNvbm5lY3Rpb25fYWNrXCIpIHtcbiAgICAgICAgICBjb25zb2xlLmxvZyhcIltCcmlkZ2VdIENvbm5lY3Rpb24gYWNrbm93bGVkZ2VkXCIpXG4gICAgICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5uZWwgd2l0aCBhdXRob3JpemF0aW9uXG4gICAgICAgICAgdGhpcy5jcmVhdGVTdWJzY3JpYmVBdXRob3JpemF0aW9uKGNoYW5uZWwpLnRoZW4oKGF1dGgpID0+IHtcbiAgICAgICAgICAgIHRoaXMud3M/LnNlbmQoXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICB0eXBlOiBcInN1YnNjcmliZVwiLFxuICAgICAgICAgICAgICAgIGlkOiBcInN1Yi0xXCIsXG4gICAgICAgICAgICAgICAgY2hhbm5lbCxcbiAgICAgICAgICAgICAgICBhdXRob3JpemF0aW9uOiBhdXRoLFxuICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIClcbiAgICAgICAgICB9KVxuICAgICAgICB9IGVsc2UgaWYgKG1lc3NhZ2UudHlwZSA9PT0gXCJzdWJzY3JpYmVfc3VjY2Vzc1wiKSB7XG4gICAgICAgICAgY29uc29sZS5sb2coYFtCcmlkZ2VdIFN1YnNjcmliZWQgdG8gJHtjaGFubmVsfWApXG4gICAgICAgICAgcmVzb2x2ZSgpXG4gICAgICAgIH0gZWxzZSBpZiAobWVzc2FnZS50eXBlID09PSBcImRhdGFcIiAmJiBtZXNzYWdlLmlkID09PSBcInN1Yi0xXCIpIHtcbiAgICAgICAgICAvLyBQYXJzZSB0aGUgZXZlbnQgZGF0YVxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBldmVudERhdGEgPSBKU09OLnBhcnNlKG1lc3NhZ2UuZXZlbnQpIGFzIFRcbiAgICAgICAgICAgIGNvbnN0IHNob3VsZFN0b3AgPSBvbk1lc3NhZ2UoZXZlbnREYXRhKVxuICAgICAgICAgICAgaWYgKHNob3VsZFN0b3ApIHtcbiAgICAgICAgICAgICAgdGhpcy5jbG9zZSgpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiW0JyaWRnZV0gRmFpbGVkIHRvIHBhcnNlIGV2ZW50IGRhdGE6XCIsIGVycilcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAobWVzc2FnZS50eXBlID09PSBcImVycm9yXCIpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKFwiW0JyaWRnZV0gV2ViU29ja2V0IGVycm9yOlwiLCBtZXNzYWdlKVxuICAgICAgICAgIHJlamVjdChcbiAgICAgICAgICAgIG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgbWVzc2FnZS5lcnJvcnNcbiAgICAgICAgICAgICAgICA/Lm1hcCgoZTogeyBtZXNzYWdlOiBzdHJpbmcgfSkgPT4gZS5tZXNzYWdlKVxuICAgICAgICAgICAgICAgIC5qb2luKFwiLCBcIikgPz8gXCJVbmtub3duIGVycm9yXCIsXG4gICAgICAgICAgICApLFxuICAgICAgICAgIClcbiAgICAgICAgfVxuICAgICAgfSlcblxuICAgICAgdGhpcy53cy5vbihcImVycm9yXCIsIChlcnIpID0+IHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcIltCcmlkZ2VdIFdlYlNvY2tldCBlcnJvcjpcIiwgZXJyKVxuICAgICAgICByZWplY3QoZXJyKVxuICAgICAgfSlcblxuICAgICAgdGhpcy53cy5vbihcImNsb3NlXCIsICgpID0+IHtcbiAgICAgICAgY29uc29sZS5sb2coXCJbQnJpZGdlXSBXZWJTb2NrZXQgY2xvc2VkXCIpXG4gICAgICB9KVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogQ29ubmVjdCB0byBXZWJTb2NrZXQgYW5kIHN1YnNjcmliZSB0byBhIGNoYW5uZWwgd2l0aCBjb250aW51b3VzIG1lc3NhZ2UgaGFuZGxpbmcuXG4gICAqIFVubGlrZSBjb25uZWN0QW5kU3Vic2NyaWJlLCB0aGlzIGRvZXNuJ3QgY2xvc2UgYWZ0ZXIgcmVjZWl2aW5nIGEgbWVzc2FnZS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgY29ubmVjdEFuZFN1YnNjcmliZUNvbnRpbnVvdXM8VD4oXG4gICAgY2hhbm5lbDogc3RyaW5nLFxuICAgIG9uTWVzc2FnZTogKG1lc3NhZ2U6IFQpID0+IHZvaWQgfCBQcm9taXNlPHZvaWQ+LFxuICAgIG9uRXJyb3I/OiAoZXJyb3I6IEVycm9yKSA9PiB2b2lkLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAvLyBCdWlsZCBzaWduZWQgV2ViU29ja2V0IGNvbm5lY3Rpb25cbiAgICBjb25zdCBbd3NVcmwsIHN1YnByb3RvY29sc10gPSBhd2FpdCB0aGlzLmJ1aWxkU2lnbmVkV2ViU29ja2V0Q29ubmVjdGlvbigpXG5cbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgdGhpcy53cyA9IG5ldyBXZWJTb2NrZXQod3NVcmwsIHN1YnByb3RvY29scylcblxuICAgICAgdGhpcy53cy5vbihcIm9wZW5cIiwgKCkgPT4ge1xuICAgICAgICBjb25zb2xlLmxvZyhcIltBcHBTeW5jXSBXZWJTb2NrZXQgY29ubmVjdGVkXCIpXG4gICAgICAgIC8vIFNlbmQgY29ubmVjdGlvbiBpbml0XG4gICAgICAgIHRoaXMud3M/LnNlbmQoSlNPTi5zdHJpbmdpZnkoeyB0eXBlOiBcImNvbm5lY3Rpb25faW5pdFwiIH0pKVxuICAgICAgfSlcblxuICAgICAgdGhpcy53cy5vbihcIm1lc3NhZ2VcIiwgYXN5bmMgKGRhdGEpID0+IHtcbiAgICAgICAgY29uc3QgbWVzc2FnZSA9IEpTT04ucGFyc2UoZGF0YS50b1N0cmluZygpKVxuXG4gICAgICAgIGlmIChtZXNzYWdlLnR5cGUgPT09IFwiY29ubmVjdGlvbl9hY2tcIikge1xuICAgICAgICAgIGNvbnNvbGUubG9nKFwiW0FwcFN5bmNdIENvbm5lY3Rpb24gYWNrbm93bGVkZ2VkXCIpXG4gICAgICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5uZWwgd2l0aCBhdXRob3JpemF0aW9uXG4gICAgICAgICAgdGhpcy5jcmVhdGVTdWJzY3JpYmVBdXRob3JpemF0aW9uKGNoYW5uZWwpLnRoZW4oKGF1dGgpID0+IHtcbiAgICAgICAgICAgIHRoaXMud3M/LnNlbmQoXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICB0eXBlOiBcInN1YnNjcmliZVwiLFxuICAgICAgICAgICAgICAgIGlkOiBcInN1Yi0xXCIsXG4gICAgICAgICAgICAgICAgY2hhbm5lbCxcbiAgICAgICAgICAgICAgICBhdXRob3JpemF0aW9uOiBhdXRoLFxuICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIClcbiAgICAgICAgICB9KVxuICAgICAgICB9IGVsc2UgaWYgKG1lc3NhZ2UudHlwZSA9PT0gXCJzdWJzY3JpYmVfc3VjY2Vzc1wiKSB7XG4gICAgICAgICAgY29uc29sZS5sb2coYFtBcHBTeW5jXSBTdWJzY3JpYmVkIHRvICR7Y2hhbm5lbH1gKVxuICAgICAgICAgIHJlc29sdmUoKVxuICAgICAgICB9IGVsc2UgaWYgKG1lc3NhZ2UudHlwZSA9PT0gXCJkYXRhXCIgJiYgbWVzc2FnZS5pZCA9PT0gXCJzdWItMVwiKSB7XG4gICAgICAgICAgLy8gUGFyc2UgdGhlIGV2ZW50IGRhdGFcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgZXZlbnREYXRhID0gSlNPTi5wYXJzZShtZXNzYWdlLmV2ZW50KSBhcyBUXG4gICAgICAgICAgICBhd2FpdCBvbk1lc3NhZ2UoZXZlbnREYXRhKVxuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIltBcHBTeW5jXSBGYWlsZWQgdG8gcGFyc2UgZXZlbnQgZGF0YTpcIiwgZXJyKVxuICAgICAgICAgICAgb25FcnJvcj8uKGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyIDogbmV3IEVycm9yKFN0cmluZyhlcnIpKSlcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAobWVzc2FnZS50eXBlID09PSBcImVycm9yXCIpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKFwiW0FwcFN5bmNdIFdlYlNvY2tldCBlcnJvcjpcIiwgbWVzc2FnZSlcbiAgICAgICAgICBjb25zdCBlcnJvciA9IG5ldyBFcnJvcihcbiAgICAgICAgICAgIG1lc3NhZ2UuZXJyb3JzXG4gICAgICAgICAgICAgID8ubWFwKChlOiB7IG1lc3NhZ2U6IHN0cmluZyB9KSA9PiBlLm1lc3NhZ2UpXG4gICAgICAgICAgICAgIC5qb2luKFwiLCBcIikgPz8gXCJVbmtub3duIGVycm9yXCIsXG4gICAgICAgICAgKVxuICAgICAgICAgIG9uRXJyb3I/LihlcnJvcilcbiAgICAgICAgICByZWplY3QoZXJyb3IpXG4gICAgICAgIH1cbiAgICAgIH0pXG5cbiAgICAgIHRoaXMud3Mub24oXCJlcnJvclwiLCAoZXJyKSA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJbQXBwU3luY10gV2ViU29ja2V0IGVycm9yOlwiLCBlcnIpXG4gICAgICAgIG9uRXJyb3I/LihlcnIpXG4gICAgICAgIHJlamVjdChlcnIpXG4gICAgICB9KVxuXG4gICAgICB0aGlzLndzLm9uKFwiY2xvc2VcIiwgKCkgPT4ge1xuICAgICAgICBjb25zb2xlLmxvZyhcIltBcHBTeW5jXSBXZWJTb2NrZXQgY2xvc2VkXCIpXG4gICAgICB9KVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGF1dGhvcml6YXRpb24gaGVhZGVycyBmb3Igc3Vic2NyaWJlIG9wZXJhdGlvblxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBjcmVhdGVTdWJzY3JpYmVBdXRob3JpemF0aW9uKFxuICAgIGNoYW5uZWw6IHN0cmluZyxcbiAgKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+PiB7XG4gICAgY29uc3QgaHR0cFVybCA9IG5ldyBVUkwodGhpcy5odHRwRW5kcG9pbnQpXG4gICAgY29uc3QgcGF5bG9hZCA9IEpTT04uc3RyaW5naWZ5KHsgY2hhbm5lbCB9KVxuXG4gICAgY29uc3QgcmVxdWVzdCA9IG5ldyBIdHRwUmVxdWVzdCh7XG4gICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgcHJvdG9jb2w6IFwiaHR0cHM6XCIsXG4gICAgICBob3N0bmFtZTogaHR0cFVybC5ob3N0bmFtZSxcbiAgICAgIHBhdGg6IFwiL2V2ZW50XCIsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgIGFjY2VwdDogXCJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L2phdmFzY3JpcHRcIixcbiAgICAgICAgXCJjb250ZW50LWVuY29kaW5nXCI6IFwiYW16LTEuMFwiLFxuICAgICAgICBcImNvbnRlbnQtdHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb247IGNoYXJzZXQ9VVRGLThcIixcbiAgICAgICAgaG9zdDogaHR0cFVybC5ob3N0bmFtZSxcbiAgICAgIH0sXG4gICAgICBib2R5OiBwYXlsb2FkLFxuICAgIH0pXG5cbiAgICBjb25zdCBzaWduZXIgPSBuZXcgU2lnbmF0dXJlVjQoe1xuICAgICAgY3JlZGVudGlhbHM6IGRlZmF1bHRQcm92aWRlcigpLFxuICAgICAgcmVnaW9uOiB0aGlzLnJlZ2lvbixcbiAgICAgIHNlcnZpY2U6IFwiYXBwc3luY1wiLFxuICAgICAgc2hhMjU2OiBTaGEyNTYsXG4gICAgfSlcblxuICAgIGNvbnN0IHNpZ25lZFJlcXVlc3QgPSBhd2FpdCBzaWduZXIuc2lnbihyZXF1ZXN0KVxuXG4gICAgY29uc3QgYXV0aDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICAgIGFjY2VwdDogXCJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L2phdmFzY3JpcHRcIixcbiAgICAgIFwiY29udGVudC1lbmNvZGluZ1wiOiBcImFtei0xLjBcIixcbiAgICAgIFwiY29udGVudC10eXBlXCI6IFwiYXBwbGljYXRpb24vanNvbjsgY2hhcnNldD1VVEYtOFwiLFxuICAgICAgaG9zdDogaHR0cFVybC5ob3N0bmFtZSxcbiAgICAgIFwieC1hbXotZGF0ZVwiOiBzaWduZWRSZXF1ZXN0LmhlYWRlcnNbXCJ4LWFtei1kYXRlXCJdLFxuICAgICAgXCJ4LWFtei1jb250ZW50LXNoYTI1NlwiOiBzaWduZWRSZXF1ZXN0LmhlYWRlcnNbXCJ4LWFtei1jb250ZW50LXNoYTI1NlwiXSxcbiAgICAgIEF1dGhvcml6YXRpb246IHNpZ25lZFJlcXVlc3QuaGVhZGVyc1tcImF1dGhvcml6YXRpb25cIl0sXG4gICAgfVxuXG4gICAgaWYgKHNpZ25lZFJlcXVlc3QuaGVhZGVyc1tcIngtYW16LXNlY3VyaXR5LXRva2VuXCJdKSB7XG4gICAgICBhdXRoW1wieC1hbXotc2VjdXJpdHktdG9rZW5cIl0gPVxuICAgICAgICBzaWduZWRSZXF1ZXN0LmhlYWRlcnNbXCJ4LWFtei1zZWN1cml0eS10b2tlblwiXVxuICAgIH1cblxuICAgIHJldHVybiBhdXRoXG4gIH1cblxuICAvKipcbiAgICogQnVpbGQgc2lnbmVkIFdlYlNvY2tldCBjb25uZWN0aW9uIGluZm8gZm9yIEFwcFN5bmMgRXZlbnRzXG4gICAqIFJldHVybnMgW3VybCwgc3VicHJvdG9jb2xzXSBmb3IgV2ViU29ja2V0IGNvbnN0cnVjdG9yXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGJ1aWxkU2lnbmVkV2ViU29ja2V0Q29ubmVjdGlvbigpOiBQcm9taXNlPFtzdHJpbmcsIHN0cmluZ1tdXT4ge1xuICAgIGNvbnN0IHJlYWx0aW1lVXJsID0gbmV3IFVSTCh0aGlzLnJlYWx0aW1lRW5kcG9pbnQpXG4gICAgcmVhbHRpbWVVcmwucGF0aG5hbWUgPSBcIi9ldmVudC9yZWFsdGltZVwiXG4gICAgY29uc3QgaHR0cFVybCA9IG5ldyBVUkwodGhpcy5odHRwRW5kcG9pbnQpXG5cbiAgICAvLyBGb3IgSUFNIGF1dGgsIHNpZ24gYSBQT1NUIHJlcXVlc3QgdG8gdGhlIEhUVFAgZW5kcG9pbnRcbiAgICBjb25zdCByZXF1ZXN0ID0gbmV3IEh0dHBSZXF1ZXN0KHtcbiAgICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgICBwcm90b2NvbDogXCJodHRwczpcIixcbiAgICAgIGhvc3RuYW1lOiBodHRwVXJsLmhvc3RuYW1lLFxuICAgICAgcGF0aDogXCIvZXZlbnRcIixcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgYWNjZXB0OiBcImFwcGxpY2F0aW9uL2pzb24sIHRleHQvamF2YXNjcmlwdFwiLFxuICAgICAgICBcImNvbnRlbnQtZW5jb2RpbmdcIjogXCJhbXotMS4wXCIsXG4gICAgICAgIFwiY29udGVudC10eXBlXCI6IFwiYXBwbGljYXRpb24vanNvbjsgY2hhcnNldD1VVEYtOFwiLFxuICAgICAgICBob3N0OiBodHRwVXJsLmhvc3RuYW1lLFxuICAgICAgfSxcbiAgICAgIGJvZHk6IFwie31cIixcbiAgICB9KVxuXG4gICAgY29uc3Qgc2lnbmVyID0gbmV3IFNpZ25hdHVyZVY0KHtcbiAgICAgIGNyZWRlbnRpYWxzOiBkZWZhdWx0UHJvdmlkZXIoKSxcbiAgICAgIHJlZ2lvbjogdGhpcy5yZWdpb24sXG4gICAgICBzZXJ2aWNlOiBcImFwcHN5bmNcIixcbiAgICAgIHNoYTI1NjogU2hhMjU2LFxuICAgIH0pXG5cbiAgICBjb25zdCBzaWduZWRSZXF1ZXN0ID0gYXdhaXQgc2lnbmVyLnNpZ24ocmVxdWVzdClcblxuICAgIC8vIEJ1aWxkIGhlYWRlciBwYXlsb2FkIGZvciBzdWJwcm90b2NvbCAtIGluY2x1ZGUgYWxsIHNpZ25lZCBoZWFkZXJzXG4gICAgY29uc3QgaGVhZGVyUGF5bG9hZDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICAgIGFjY2VwdDogXCJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L2phdmFzY3JpcHRcIixcbiAgICAgIFwiY29udGVudC1lbmNvZGluZ1wiOiBcImFtei0xLjBcIixcbiAgICAgIFwiY29udGVudC10eXBlXCI6IFwiYXBwbGljYXRpb24vanNvbjsgY2hhcnNldD1VVEYtOFwiLFxuICAgICAgaG9zdDogaHR0cFVybC5ob3N0bmFtZSxcbiAgICAgIFwieC1hbXotZGF0ZVwiOiBzaWduZWRSZXF1ZXN0LmhlYWRlcnNbXCJ4LWFtei1kYXRlXCJdLFxuICAgICAgXCJ4LWFtei1jb250ZW50LXNoYTI1NlwiOiBzaWduZWRSZXF1ZXN0LmhlYWRlcnNbXCJ4LWFtei1jb250ZW50LXNoYTI1NlwiXSxcbiAgICAgIEF1dGhvcml6YXRpb246IHNpZ25lZFJlcXVlc3QuaGVhZGVyc1tcImF1dGhvcml6YXRpb25cIl0sXG4gICAgfVxuXG4gICAgLy8gQWRkIHNlc3Npb24gdG9rZW4gaWYgcHJlc2VudFxuICAgIGlmIChzaWduZWRSZXF1ZXN0LmhlYWRlcnNbXCJ4LWFtei1zZWN1cml0eS10b2tlblwiXSkge1xuICAgICAgaGVhZGVyUGF5bG9hZFtcIngtYW16LXNlY3VyaXR5LXRva2VuXCJdID1cbiAgICAgICAgc2lnbmVkUmVxdWVzdC5oZWFkZXJzW1wieC1hbXotc2VjdXJpdHktdG9rZW5cIl1cbiAgICB9XG5cbiAgICAvLyBCYXNlNjR1cmwgZW5jb2RlIChubyBwYWRkaW5nLCBVUkwtc2FmZSlcbiAgICBjb25zdCBlbmNvZGVkSGVhZGVyID0gQnVmZmVyLmZyb20oSlNPTi5zdHJpbmdpZnkoaGVhZGVyUGF5bG9hZCkpXG4gICAgICAudG9TdHJpbmcoXCJiYXNlNjRcIilcbiAgICAgIC5yZXBsYWNlKC9cXCsvZywgXCItXCIpXG4gICAgICAucmVwbGFjZSgvXFwvL2csIFwiX1wiKVxuICAgICAgLnJlcGxhY2UoLz0rJC8sIFwiXCIpXG5cbiAgICAvLyBBdXRoIGlzIHBhc3NlZCBhcyBoZWFkZXIte2Jhc2U2NHVybH0gc3VicHJvdG9jb2xcbiAgICBjb25zdCBhdXRoU3VicHJvdG9jb2wgPSBgaGVhZGVyLSR7ZW5jb2RlZEhlYWRlcn1gXG5cbiAgICByZXR1cm4gW3JlYWx0aW1lVXJsLnRvU3RyaW5nKCksIFtcImF3cy1hcHBzeW5jLWV2ZW50LXdzXCIsIGF1dGhTdWJwcm90b2NvbF1dXG4gIH1cblxuICAvKipcbiAgICogQ2xvc2UgdGhlIFdlYlNvY2tldCBjb25uZWN0aW9uXG4gICAqL1xuICBhc3luYyBjbG9zZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy53cykge1xuICAgICAgdGhpcy53cy5jbG9zZSgpXG4gICAgICB0aGlzLndzID0gbnVsbFxuICAgIH1cbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge Lambda handler that forwards invocations to the local daemon via AppSync Events.
|
|
3
|
+
*
|
|
4
|
+
* This handler:
|
|
5
|
+
* 1. Receives Lambda invocations from AWS
|
|
6
|
+
* 2. Publishes the invocation to AppSync Events channel
|
|
7
|
+
* 3. Subscribes to response channel
|
|
8
|
+
* 4. Waits for the daemon to process and respond
|
|
9
|
+
* 5. Returns the response or throws an error
|
|
10
|
+
*
|
|
11
|
+
* AppSync endpoints are read from SSM Parameter Store at runtime.
|
|
12
|
+
*/
|
|
13
|
+
import type { Context } from "aws-lambda";
|
|
14
|
+
/**
|
|
15
|
+
* Main Lambda handler - forwards all invocations to the local daemon
|
|
16
|
+
*/
|
|
17
|
+
export declare function handler(event: unknown, context: Context): Promise<unknown>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge Lambda handler that forwards invocations to the local daemon via AppSync Events.
|
|
3
|
+
*
|
|
4
|
+
* This handler:
|
|
5
|
+
* 1. Receives Lambda invocations from AWS
|
|
6
|
+
* 2. Publishes the invocation to AppSync Events channel
|
|
7
|
+
* 3. Subscribes to response channel
|
|
8
|
+
* 4. Waits for the daemon to process and respond
|
|
9
|
+
* 5. Returns the response or throws an error
|
|
10
|
+
*
|
|
11
|
+
* AppSync endpoints are read from SSM Parameter Store at runtime.
|
|
12
|
+
*/
|
|
13
|
+
import { buildChannelName, filterEnvVars, } from "../../shared/types.js";
|
|
14
|
+
import { AppSyncEventsClient } from "./appsync-client.js";
|
|
15
|
+
import { getAppSyncEndpoints } from "./ssm-config.js";
|
|
16
|
+
// Timeout waiting for daemon response (ms)
|
|
17
|
+
const RESPONSE_TIMEOUT_MS = 290_000; // 4:50 to leave buffer for 5 min Lambda timeout
|
|
18
|
+
/**
|
|
19
|
+
* Main Lambda handler - forwards all invocations to the local daemon
|
|
20
|
+
*/
|
|
21
|
+
export async function handler(event, context) {
|
|
22
|
+
const functionName = context.functionName;
|
|
23
|
+
const requestId = context.awsRequestId;
|
|
24
|
+
console.log(`[Bridge] Processing invocation for ${functionName}`);
|
|
25
|
+
console.log(`[Bridge] Request ID: ${requestId}`);
|
|
26
|
+
// Get AppSync endpoints from SSM
|
|
27
|
+
const { httpEndpoint, realtimeEndpoint } = await getAppSyncEndpoints();
|
|
28
|
+
// Create AppSync client
|
|
29
|
+
const client = new AppSyncEventsClient({
|
|
30
|
+
httpEndpoint,
|
|
31
|
+
realtimeEndpoint,
|
|
32
|
+
});
|
|
33
|
+
// Build channel names
|
|
34
|
+
const invocationChannel = buildChannelName.invocation(functionName);
|
|
35
|
+
const responseChannel = buildChannelName.response(functionName);
|
|
36
|
+
try {
|
|
37
|
+
// Create the invocation message with filtered env vars
|
|
38
|
+
const invocationMessage = {
|
|
39
|
+
type: "invocation",
|
|
40
|
+
requestId,
|
|
41
|
+
event,
|
|
42
|
+
context: {
|
|
43
|
+
functionName: context.functionName,
|
|
44
|
+
functionVersion: context.functionVersion,
|
|
45
|
+
invokedFunctionArn: context.invokedFunctionArn,
|
|
46
|
+
memoryLimitInMB: context.memoryLimitInMB,
|
|
47
|
+
awsRequestId: context.awsRequestId,
|
|
48
|
+
logGroupName: context.logGroupName,
|
|
49
|
+
logStreamName: context.logStreamName,
|
|
50
|
+
getRemainingTimeInMillis: context.getRemainingTimeInMillis(),
|
|
51
|
+
},
|
|
52
|
+
env: filterEnvVars(process.env),
|
|
53
|
+
};
|
|
54
|
+
// Subscribe to response channel first, then publish invocation
|
|
55
|
+
const response = await client.publishAndWaitForResponse({
|
|
56
|
+
publishChannel: invocationChannel,
|
|
57
|
+
subscribeChannel: responseChannel,
|
|
58
|
+
message: invocationMessage,
|
|
59
|
+
timeoutMs: RESPONSE_TIMEOUT_MS,
|
|
60
|
+
matchResponse: (msg) => msg.requestId === requestId,
|
|
61
|
+
});
|
|
62
|
+
console.log(`[Bridge] Received response for ${requestId}`);
|
|
63
|
+
// Check for error response
|
|
64
|
+
if (response.error) {
|
|
65
|
+
const error = new Error(response.error.errorMessage);
|
|
66
|
+
error.name = response.error.errorType;
|
|
67
|
+
if (response.error.stackTrace) {
|
|
68
|
+
error.stack = response.error.stackTrace.join("\n");
|
|
69
|
+
}
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
return response.result;
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
// Clean up client connection
|
|
76
|
+
await client.close();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9mdW5jdGlvbnMvYnJpZGdlL2hhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7O0dBV0c7QUFHSCxPQUFPLEVBQ0wsZ0JBQWdCLEVBQ2hCLGFBQWEsR0FHZCxNQUFNLHVCQUF1QixDQUFBO0FBQzlCLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBQ3pELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBRXJELDJDQUEyQztBQUMzQyxNQUFNLG1CQUFtQixHQUFHLE9BQU8sQ0FBQSxDQUFDLGdEQUFnRDtBQUVwRjs7R0FFRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsT0FBTyxDQUMzQixLQUFjLEVBQ2QsT0FBZ0I7SUFFaEIsTUFBTSxZQUFZLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQTtJQUN6QyxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFBO0lBRXRDLE9BQU8sQ0FBQyxHQUFHLENBQUMsc0NBQXNDLFlBQVksRUFBRSxDQUFDLENBQUE7SUFDakUsT0FBTyxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsU0FBUyxFQUFFLENBQUMsQ0FBQTtJQUVoRCxpQ0FBaUM7SUFDakMsTUFBTSxFQUFFLFlBQVksRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLE1BQU0sbUJBQW1CLEVBQUUsQ0FBQTtJQUV0RSx3QkFBd0I7SUFDeEIsTUFBTSxNQUFNLEdBQUcsSUFBSSxtQkFBbUIsQ0FBQztRQUNyQyxZQUFZO1FBQ1osZ0JBQWdCO0tBQ2pCLENBQUMsQ0FBQTtJQUVGLHNCQUFzQjtJQUN0QixNQUFNLGlCQUFpQixHQUFHLGdCQUFnQixDQUFDLFVBQVUsQ0FBQyxZQUFZLENBQUMsQ0FBQTtJQUNuRSxNQUFNLGVBQWUsR0FBRyxnQkFBZ0IsQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLENBQUE7SUFFL0QsSUFBSSxDQUFDO1FBQ0gsdURBQXVEO1FBQ3ZELE1BQU0saUJBQWlCLEdBQXNCO1lBQzNDLElBQUksRUFBRSxZQUFZO1lBQ2xCLFNBQVM7WUFDVCxLQUFLO1lBQ0wsT0FBTyxFQUFFO2dCQUNQLFlBQVksRUFBRSxPQUFPLENBQUMsWUFBWTtnQkFDbEMsZUFBZSxFQUFFLE9BQU8sQ0FBQyxlQUFlO2dCQUN4QyxrQkFBa0IsRUFBRSxPQUFPLENBQUMsa0JBQWtCO2dCQUM5QyxlQUFlLEVBQUUsT0FBTyxDQUFDLGVBQWU7Z0JBQ3hDLFlBQVksRUFBRSxPQUFPLENBQUMsWUFBWTtnQkFDbEMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxZQUFZO2dCQUNsQyxhQUFhLEVBQUUsT0FBTyxDQUFDLGFBQWE7Z0JBQ3BDLHdCQUF3QixFQUFFLE9BQU8sQ0FBQyx3QkFBd0IsRUFBRTthQUM3RDtZQUNELEdBQUcsRUFBRSxhQUFhLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQztTQUNoQyxDQUFBO1FBRUQsK0RBQStEO1FBQy9ELE1BQU0sUUFBUSxHQUFHLE1BQU0sTUFBTSxDQUFDLHlCQUF5QixDQUFrQjtZQUN2RSxjQUFjLEVBQUUsaUJBQWlCO1lBQ2pDLGdCQUFnQixFQUFFLGVBQWU7WUFDakMsT0FBTyxFQUFFLGlCQUFpQjtZQUMxQixTQUFTLEVBQUUsbUJBQW1CO1lBQzlCLGFBQWEsRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLFNBQVMsS0FBSyxTQUFTO1NBQ3BELENBQUMsQ0FBQTtRQUVGLE9BQU8sQ0FBQyxHQUFHLENBQUMsa0NBQWtDLFNBQVMsRUFBRSxDQUFDLENBQUE7UUFFMUQsMkJBQTJCO1FBQzNCLElBQUksUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ25CLE1BQU0sS0FBSyxHQUFHLElBQUksS0FBSyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLENBQUE7WUFDcEQsS0FBSyxDQUFDLElBQUksR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQTtZQUNyQyxJQUFJLFFBQVEsQ0FBQyxLQUFLLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQzlCLEtBQUssQ0FBQyxLQUFLLEdBQUcsUUFBUSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO1lBQ3BELENBQUM7WUFDRCxNQUFNLEtBQUssQ0FBQTtRQUNiLENBQUM7UUFFRCxPQUFPLFFBQVEsQ0FBQyxNQUFNLENBQUE7SUFDeEIsQ0FBQztZQUFTLENBQUM7UUFDVCw2QkFBNkI7UUFDN0IsTUFBTSxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUE7SUFDdEIsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEJyaWRnZSBMYW1iZGEgaGFuZGxlciB0aGF0IGZvcndhcmRzIGludm9jYXRpb25zIHRvIHRoZSBsb2NhbCBkYWVtb24gdmlhIEFwcFN5bmMgRXZlbnRzLlxuICpcbiAqIFRoaXMgaGFuZGxlcjpcbiAqIDEuIFJlY2VpdmVzIExhbWJkYSBpbnZvY2F0aW9ucyBmcm9tIEFXU1xuICogMi4gUHVibGlzaGVzIHRoZSBpbnZvY2F0aW9uIHRvIEFwcFN5bmMgRXZlbnRzIGNoYW5uZWxcbiAqIDMuIFN1YnNjcmliZXMgdG8gcmVzcG9uc2UgY2hhbm5lbFxuICogNC4gV2FpdHMgZm9yIHRoZSBkYWVtb24gdG8gcHJvY2VzcyBhbmQgcmVzcG9uZFxuICogNS4gUmV0dXJucyB0aGUgcmVzcG9uc2Ugb3IgdGhyb3dzIGFuIGVycm9yXG4gKlxuICogQXBwU3luYyBlbmRwb2ludHMgYXJlIHJlYWQgZnJvbSBTU00gUGFyYW1ldGVyIFN0b3JlIGF0IHJ1bnRpbWUuXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBDb250ZXh0IH0gZnJvbSBcImF3cy1sYW1iZGFcIlxuaW1wb3J0IHtcbiAgYnVpbGRDaGFubmVsTmFtZSxcbiAgZmlsdGVyRW52VmFycyxcbiAgdHlwZSBJbnZvY2F0aW9uTWVzc2FnZSxcbiAgdHlwZSBSZXNwb25zZU1lc3NhZ2UsXG59IGZyb20gXCIuLi8uLi9zaGFyZWQvdHlwZXMuanNcIlxuaW1wb3J0IHsgQXBwU3luY0V2ZW50c0NsaWVudCB9IGZyb20gXCIuL2FwcHN5bmMtY2xpZW50LmpzXCJcbmltcG9ydCB7IGdldEFwcFN5bmNFbmRwb2ludHMgfSBmcm9tIFwiLi9zc20tY29uZmlnLmpzXCJcblxuLy8gVGltZW91dCB3YWl0aW5nIGZvciBkYWVtb24gcmVzcG9uc2UgKG1zKVxuY29uc3QgUkVTUE9OU0VfVElNRU9VVF9NUyA9IDI5MF8wMDAgLy8gNDo1MCB0byBsZWF2ZSBidWZmZXIgZm9yIDUgbWluIExhbWJkYSB0aW1lb3V0XG5cbi8qKlxuICogTWFpbiBMYW1iZGEgaGFuZGxlciAtIGZvcndhcmRzIGFsbCBpbnZvY2F0aW9ucyB0byB0aGUgbG9jYWwgZGFlbW9uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBoYW5kbGVyKFxuICBldmVudDogdW5rbm93bixcbiAgY29udGV4dDogQ29udGV4dCxcbik6IFByb21pc2U8dW5rbm93bj4ge1xuICBjb25zdCBmdW5jdGlvbk5hbWUgPSBjb250ZXh0LmZ1bmN0aW9uTmFtZVxuICBjb25zdCByZXF1ZXN0SWQgPSBjb250ZXh0LmF3c1JlcXVlc3RJZFxuXG4gIGNvbnNvbGUubG9nKGBbQnJpZGdlXSBQcm9jZXNzaW5nIGludm9jYXRpb24gZm9yICR7ZnVuY3Rpb25OYW1lfWApXG4gIGNvbnNvbGUubG9nKGBbQnJpZGdlXSBSZXF1ZXN0IElEOiAke3JlcXVlc3RJZH1gKVxuXG4gIC8vIEdldCBBcHBTeW5jIGVuZHBvaW50cyBmcm9tIFNTTVxuICBjb25zdCB7IGh0dHBFbmRwb2ludCwgcmVhbHRpbWVFbmRwb2ludCB9ID0gYXdhaXQgZ2V0QXBwU3luY0VuZHBvaW50cygpXG5cbiAgLy8gQ3JlYXRlIEFwcFN5bmMgY2xpZW50XG4gIGNvbnN0IGNsaWVudCA9IG5ldyBBcHBTeW5jRXZlbnRzQ2xpZW50KHtcbiAgICBodHRwRW5kcG9pbnQsXG4gICAgcmVhbHRpbWVFbmRwb2ludCxcbiAgfSlcblxuICAvLyBCdWlsZCBjaGFubmVsIG5hbWVzXG4gIGNvbnN0IGludm9jYXRpb25DaGFubmVsID0gYnVpbGRDaGFubmVsTmFtZS5pbnZvY2F0aW9uKGZ1bmN0aW9uTmFtZSlcbiAgY29uc3QgcmVzcG9uc2VDaGFubmVsID0gYnVpbGRDaGFubmVsTmFtZS5yZXNwb25zZShmdW5jdGlvbk5hbWUpXG5cbiAgdHJ5IHtcbiAgICAvLyBDcmVhdGUgdGhlIGludm9jYXRpb24gbWVzc2FnZSB3aXRoIGZpbHRlcmVkIGVudiB2YXJzXG4gICAgY29uc3QgaW52b2NhdGlvbk1lc3NhZ2U6IEludm9jYXRpb25NZXNzYWdlID0ge1xuICAgICAgdHlwZTogXCJpbnZvY2F0aW9uXCIsXG4gICAgICByZXF1ZXN0SWQsXG4gICAgICBldmVudCxcbiAgICAgIGNvbnRleHQ6IHtcbiAgICAgICAgZnVuY3Rpb25OYW1lOiBjb250ZXh0LmZ1bmN0aW9uTmFtZSxcbiAgICAgICAgZnVuY3Rpb25WZXJzaW9uOiBjb250ZXh0LmZ1bmN0aW9uVmVyc2lvbixcbiAgICAgICAgaW52b2tlZEZ1bmN0aW9uQXJuOiBjb250ZXh0Lmludm9rZWRGdW5jdGlvbkFybixcbiAgICAgICAgbWVtb3J5TGltaXRJbk1COiBjb250ZXh0Lm1lbW9yeUxpbWl0SW5NQixcbiAgICAgICAgYXdzUmVxdWVzdElkOiBjb250ZXh0LmF3c1JlcXVlc3RJZCxcbiAgICAgICAgbG9nR3JvdXBOYW1lOiBjb250ZXh0LmxvZ0dyb3VwTmFtZSxcbiAgICAgICAgbG9nU3RyZWFtTmFtZTogY29udGV4dC5sb2dTdHJlYW1OYW1lLFxuICAgICAgICBnZXRSZW1haW5pbmdUaW1lSW5NaWxsaXM6IGNvbnRleHQuZ2V0UmVtYWluaW5nVGltZUluTWlsbGlzKCksXG4gICAgICB9LFxuICAgICAgZW52OiBmaWx0ZXJFbnZWYXJzKHByb2Nlc3MuZW52KSxcbiAgICB9XG5cbiAgICAvLyBTdWJzY3JpYmUgdG8gcmVzcG9uc2UgY2hhbm5lbCBmaXJzdCwgdGhlbiBwdWJsaXNoIGludm9jYXRpb25cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNsaWVudC5wdWJsaXNoQW5kV2FpdEZvclJlc3BvbnNlPFJlc3BvbnNlTWVzc2FnZT4oe1xuICAgICAgcHVibGlzaENoYW5uZWw6IGludm9jYXRpb25DaGFubmVsLFxuICAgICAgc3Vic2NyaWJlQ2hhbm5lbDogcmVzcG9uc2VDaGFubmVsLFxuICAgICAgbWVzc2FnZTogaW52b2NhdGlvbk1lc3NhZ2UsXG4gICAgICB0aW1lb3V0TXM6IFJFU1BPTlNFX1RJTUVPVVRfTVMsXG4gICAgICBtYXRjaFJlc3BvbnNlOiAobXNnKSA9PiBtc2cucmVxdWVzdElkID09PSByZXF1ZXN0SWQsXG4gICAgfSlcblxuICAgIGNvbnNvbGUubG9nKGBbQnJpZGdlXSBSZWNlaXZlZCByZXNwb25zZSBmb3IgJHtyZXF1ZXN0SWR9YClcblxuICAgIC8vIENoZWNrIGZvciBlcnJvciByZXNwb25zZVxuICAgIGlmIChyZXNwb25zZS5lcnJvcikge1xuICAgICAgY29uc3QgZXJyb3IgPSBuZXcgRXJyb3IocmVzcG9uc2UuZXJyb3IuZXJyb3JNZXNzYWdlKVxuICAgICAgZXJyb3IubmFtZSA9IHJlc3BvbnNlLmVycm9yLmVycm9yVHlwZVxuICAgICAgaWYgKHJlc3BvbnNlLmVycm9yLnN0YWNrVHJhY2UpIHtcbiAgICAgICAgZXJyb3Iuc3RhY2sgPSByZXNwb25zZS5lcnJvci5zdGFja1RyYWNlLmpvaW4oXCJcXG5cIilcbiAgICAgIH1cbiAgICAgIHRocm93IGVycm9yXG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3BvbnNlLnJlc3VsdFxuICB9IGZpbmFsbHkge1xuICAgIC8vIENsZWFuIHVwIGNsaWVudCBjb25uZWN0aW9uXG4gICAgYXdhaXQgY2xpZW50LmNsb3NlKClcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSM parameter reader for AppSync endpoints.
|
|
3
|
+
*
|
|
4
|
+
* Reads the AppSync HTTP and realtime endpoints from SSM Parameter Store
|
|
5
|
+
* and caches them to avoid repeated SSM calls during Lambda warm starts.
|
|
6
|
+
*/
|
|
7
|
+
export interface AppSyncEndpoints {
|
|
8
|
+
httpEndpoint: string;
|
|
9
|
+
realtimeEndpoint: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Get AppSync endpoints from SSM Parameter Store.
|
|
13
|
+
* Results are cached after the first call.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getAppSyncEndpoints(): Promise<AppSyncEndpoints>;
|
|
16
|
+
/**
|
|
17
|
+
* Clear the cached endpoints. Useful for testing.
|
|
18
|
+
*/
|
|
19
|
+
export declare function clearEndpointCache(): void;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSM parameter reader for AppSync endpoints.
|
|
3
|
+
*
|
|
4
|
+
* Reads the AppSync HTTP and realtime endpoints from SSM Parameter Store
|
|
5
|
+
* and caches them to avoid repeated SSM calls during Lambda warm starts.
|
|
6
|
+
*/
|
|
7
|
+
import { GetParameterCommand, SSMClient } from "@aws-sdk/client-ssm";
|
|
8
|
+
import { SSM_BASE_PATH } from "../../shared/types.js";
|
|
9
|
+
// Cache endpoints to avoid repeated SSM calls
|
|
10
|
+
let cachedEndpoints = null;
|
|
11
|
+
/**
|
|
12
|
+
* Get AppSync endpoints from SSM Parameter Store.
|
|
13
|
+
* Results are cached after the first call.
|
|
14
|
+
*/
|
|
15
|
+
export async function getAppSyncEndpoints() {
|
|
16
|
+
if (cachedEndpoints)
|
|
17
|
+
return cachedEndpoints;
|
|
18
|
+
const client = new SSMClient({});
|
|
19
|
+
const qualifier = process.env.CDK_BOOTSTRAP_QUALIFIER ?? "hnb659fds";
|
|
20
|
+
const basePath = `${SSM_BASE_PATH}/${qualifier}`;
|
|
21
|
+
const [httpResponse, realtimeResponse] = await Promise.all([
|
|
22
|
+
client.send(new GetParameterCommand({
|
|
23
|
+
Name: `${basePath}/http-endpoint`,
|
|
24
|
+
})),
|
|
25
|
+
client.send(new GetParameterCommand({
|
|
26
|
+
Name: `${basePath}/realtime-endpoint`,
|
|
27
|
+
})),
|
|
28
|
+
]);
|
|
29
|
+
if (!httpResponse.Parameter?.Value || !realtimeResponse.Parameter?.Value) {
|
|
30
|
+
throw new Error(`[LiveLambda] SSM parameters not found at ${basePath}. ` +
|
|
31
|
+
"Ensure the bootstrap stack is deployed.");
|
|
32
|
+
}
|
|
33
|
+
cachedEndpoints = {
|
|
34
|
+
httpEndpoint: httpResponse.Parameter.Value,
|
|
35
|
+
realtimeEndpoint: realtimeResponse.Parameter.Value,
|
|
36
|
+
};
|
|
37
|
+
return cachedEndpoints;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Clear the cached endpoints. Useful for testing.
|
|
41
|
+
*/
|
|
42
|
+
export function clearEndpointCache() {
|
|
43
|
+
cachedEndpoints = null;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3NtLWNvbmZpZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9mdW5jdGlvbnMvYnJpZGdlL3NzbS1jb25maWcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7O0dBS0c7QUFFSCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsU0FBUyxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDcEUsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHVCQUF1QixDQUFBO0FBT3JELDhDQUE4QztBQUM5QyxJQUFJLGVBQWUsR0FBNEIsSUFBSSxDQUFBO0FBRW5EOzs7R0FHRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsbUJBQW1CO0lBQ3ZDLElBQUksZUFBZTtRQUFFLE9BQU8sZUFBZSxDQUFBO0lBRTNDLE1BQU0sTUFBTSxHQUFHLElBQUksU0FBUyxDQUFDLEVBQUUsQ0FBQyxDQUFBO0lBQ2hDLE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsdUJBQXVCLElBQUksV0FBVyxDQUFBO0lBQ3BFLE1BQU0sUUFBUSxHQUFHLEdBQUcsYUFBYSxJQUFJLFNBQVMsRUFBRSxDQUFBO0lBRWhELE1BQU0sQ0FBQyxZQUFZLEVBQUUsZ0JBQWdCLENBQUMsR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUM7UUFDekQsTUFBTSxDQUFDLElBQUksQ0FDVCxJQUFJLG1CQUFtQixDQUFDO1lBQ3RCLElBQUksRUFBRSxHQUFHLFFBQVEsZ0JBQWdCO1NBQ2xDLENBQUMsQ0FDSDtRQUNELE1BQU0sQ0FBQyxJQUFJLENBQ1QsSUFBSSxtQkFBbUIsQ0FBQztZQUN0QixJQUFJLEVBQUUsR0FBRyxRQUFRLG9CQUFvQjtTQUN0QyxDQUFDLENBQ0g7S0FDRixDQUFDLENBQUE7SUFFRixJQUFJLENBQUMsWUFBWSxDQUFDLFNBQVMsRUFBRSxLQUFLLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxTQUFTLEVBQUUsS0FBSyxFQUFFLENBQUM7UUFDekUsTUFBTSxJQUFJLEtBQUssQ0FDYiw0Q0FBNEMsUUFBUSxJQUFJO1lBQ3RELHlDQUF5QyxDQUM1QyxDQUFBO0lBQ0gsQ0FBQztJQUVELGVBQWUsR0FBRztRQUNoQixZQUFZLEVBQUUsWUFBWSxDQUFDLFNBQVMsQ0FBQyxLQUFLO1FBQzFDLGdCQUFnQixFQUFFLGdCQUFnQixDQUFDLFNBQVMsQ0FBQyxLQUFLO0tBQ25ELENBQUE7SUFFRCxPQUFPLGVBQWUsQ0FBQTtBQUN4QixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsa0JBQWtCO0lBQ2hDLGVBQWUsR0FBRyxJQUFJLENBQUE7QUFDeEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU1NNIHBhcmFtZXRlciByZWFkZXIgZm9yIEFwcFN5bmMgZW5kcG9pbnRzLlxuICpcbiAqIFJlYWRzIHRoZSBBcHBTeW5jIEhUVFAgYW5kIHJlYWx0aW1lIGVuZHBvaW50cyBmcm9tIFNTTSBQYXJhbWV0ZXIgU3RvcmVcbiAqIGFuZCBjYWNoZXMgdGhlbSB0byBhdm9pZCByZXBlYXRlZCBTU00gY2FsbHMgZHVyaW5nIExhbWJkYSB3YXJtIHN0YXJ0cy5cbiAqL1xuXG5pbXBvcnQgeyBHZXRQYXJhbWV0ZXJDb21tYW5kLCBTU01DbGllbnQgfSBmcm9tIFwiQGF3cy1zZGsvY2xpZW50LXNzbVwiXG5pbXBvcnQgeyBTU01fQkFTRV9QQVRIIH0gZnJvbSBcIi4uLy4uL3NoYXJlZC90eXBlcy5qc1wiXG5cbmV4cG9ydCBpbnRlcmZhY2UgQXBwU3luY0VuZHBvaW50cyB7XG4gIGh0dHBFbmRwb2ludDogc3RyaW5nXG4gIHJlYWx0aW1lRW5kcG9pbnQ6IHN0cmluZ1xufVxuXG4vLyBDYWNoZSBlbmRwb2ludHMgdG8gYXZvaWQgcmVwZWF0ZWQgU1NNIGNhbGxzXG5sZXQgY2FjaGVkRW5kcG9pbnRzOiBBcHBTeW5jRW5kcG9pbnRzIHwgbnVsbCA9IG51bGxcblxuLyoqXG4gKiBHZXQgQXBwU3luYyBlbmRwb2ludHMgZnJvbSBTU00gUGFyYW1ldGVyIFN0b3JlLlxuICogUmVzdWx0cyBhcmUgY2FjaGVkIGFmdGVyIHRoZSBmaXJzdCBjYWxsLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0QXBwU3luY0VuZHBvaW50cygpOiBQcm9taXNlPEFwcFN5bmNFbmRwb2ludHM+IHtcbiAgaWYgKGNhY2hlZEVuZHBvaW50cykgcmV0dXJuIGNhY2hlZEVuZHBvaW50c1xuXG4gIGNvbnN0IGNsaWVudCA9IG5ldyBTU01DbGllbnQoe30pXG4gIGNvbnN0IHF1YWxpZmllciA9IHByb2Nlc3MuZW52LkNES19CT09UU1RSQVBfUVVBTElGSUVSID8/IFwiaG5iNjU5ZmRzXCJcbiAgY29uc3QgYmFzZVBhdGggPSBgJHtTU01fQkFTRV9QQVRIfS8ke3F1YWxpZmllcn1gXG5cbiAgY29uc3QgW2h0dHBSZXNwb25zZSwgcmVhbHRpbWVSZXNwb25zZV0gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgY2xpZW50LnNlbmQoXG4gICAgICBuZXcgR2V0UGFyYW1ldGVyQ29tbWFuZCh7XG4gICAgICAgIE5hbWU6IGAke2Jhc2VQYXRofS9odHRwLWVuZHBvaW50YCxcbiAgICAgIH0pLFxuICAgICksXG4gICAgY2xpZW50LnNlbmQoXG4gICAgICBuZXcgR2V0UGFyYW1ldGVyQ29tbWFuZCh7XG4gICAgICAgIE5hbWU6IGAke2Jhc2VQYXRofS9yZWFsdGltZS1lbmRwb2ludGAsXG4gICAgICB9KSxcbiAgICApLFxuICBdKVxuXG4gIGlmICghaHR0cFJlc3BvbnNlLlBhcmFtZXRlcj8uVmFsdWUgfHwgIXJlYWx0aW1lUmVzcG9uc2UuUGFyYW1ldGVyPy5WYWx1ZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBbTGl2ZUxhbWJkYV0gU1NNIHBhcmFtZXRlcnMgbm90IGZvdW5kIGF0ICR7YmFzZVBhdGh9LiBgICtcbiAgICAgICAgXCJFbnN1cmUgdGhlIGJvb3RzdHJhcCBzdGFjayBpcyBkZXBsb3llZC5cIixcbiAgICApXG4gIH1cblxuICBjYWNoZWRFbmRwb2ludHMgPSB7XG4gICAgaHR0cEVuZHBvaW50OiBodHRwUmVzcG9uc2UuUGFyYW1ldGVyLlZhbHVlLFxuICAgIHJlYWx0aW1lRW5kcG9pbnQ6IHJlYWx0aW1lUmVzcG9uc2UuUGFyYW1ldGVyLlZhbHVlLFxuICB9XG5cbiAgcmV0dXJuIGNhY2hlZEVuZHBvaW50c1xufVxuXG4vKipcbiAqIENsZWFyIHRoZSBjYWNoZWQgZW5kcG9pbnRzLiBVc2VmdWwgZm9yIHRlc3RpbmcuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjbGVhckVuZHBvaW50Q2FjaGUoKTogdm9pZCB7XG4gIGNhY2hlZEVuZHBvaW50cyA9IG51bGxcbn1cbiJdfQ==
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom resource handler that builds and uploads the bridge Lambda code.
|
|
3
|
+
*
|
|
4
|
+
* This handler:
|
|
5
|
+
* 1. Receives the bridge source code (base64 encoded) and AppSync endpoints
|
|
6
|
+
* 2. Replaces endpoint placeholders with actual values
|
|
7
|
+
* 3. Creates a zip file with the code
|
|
8
|
+
* 4. Uploads the zip to S3
|
|
9
|
+
* 5. Returns the S3 location for Lambda functions to use
|
|
10
|
+
*/
|
|
11
|
+
import type { CloudFormationCustomResourceEvent, CloudFormationCustomResourceResponse } from "aws-lambda";
|
|
12
|
+
export declare function handler(event: CloudFormationCustomResourceEvent): Promise<CloudFormationCustomResourceResponse>;
|