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,181 @@
|
|
|
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 * as crypto from "node:crypto";
|
|
12
|
+
import * as zlib from "node:zlib";
|
|
13
|
+
import { DeleteObjectCommand, PutObjectCommand, S3Client, } from "@aws-sdk/client-s3";
|
|
14
|
+
const s3 = new S3Client({});
|
|
15
|
+
/**
|
|
16
|
+
* Create a minimal zip file containing a single file.
|
|
17
|
+
* This is a simple implementation that creates a valid zip without external dependencies.
|
|
18
|
+
*/
|
|
19
|
+
function createZip(filename, content) {
|
|
20
|
+
const contentBuffer = Buffer.from(content, "utf-8");
|
|
21
|
+
// Compress the content using deflate
|
|
22
|
+
const compressed = zlib.deflateRawSync(contentBuffer);
|
|
23
|
+
const crc32 = crc32buf(contentBuffer);
|
|
24
|
+
const now = new Date();
|
|
25
|
+
// DOS time and date
|
|
26
|
+
const dosTime = ((now.getHours() << 11) |
|
|
27
|
+
(now.getMinutes() << 5) |
|
|
28
|
+
Math.floor(now.getSeconds() / 2)) &
|
|
29
|
+
0xffff;
|
|
30
|
+
const dosDate = (((now.getFullYear() - 1980) << 9) |
|
|
31
|
+
((now.getMonth() + 1) << 5) |
|
|
32
|
+
now.getDate()) &
|
|
33
|
+
0xffff;
|
|
34
|
+
const filenameBuffer = Buffer.from(filename, "utf-8");
|
|
35
|
+
// Local file header
|
|
36
|
+
const localHeader = Buffer.alloc(30);
|
|
37
|
+
localHeader.writeUInt32LE(0x04034b50, 0); // Local file header signature
|
|
38
|
+
localHeader.writeUInt16LE(20, 4); // Version needed to extract (2.0)
|
|
39
|
+
localHeader.writeUInt16LE(0, 6); // General purpose bit flag
|
|
40
|
+
localHeader.writeUInt16LE(8, 8); // Compression method (deflate)
|
|
41
|
+
localHeader.writeUInt16LE(dosTime, 10); // Last mod file time
|
|
42
|
+
localHeader.writeUInt16LE(dosDate, 12); // Last mod file date
|
|
43
|
+
localHeader.writeUInt32LE(crc32, 14); // CRC-32
|
|
44
|
+
localHeader.writeUInt32LE(compressed.length, 18); // Compressed size
|
|
45
|
+
localHeader.writeUInt32LE(contentBuffer.length, 22); // Uncompressed size
|
|
46
|
+
localHeader.writeUInt16LE(filenameBuffer.length, 26); // Filename length
|
|
47
|
+
localHeader.writeUInt16LE(0, 28); // Extra field length
|
|
48
|
+
// Central directory header
|
|
49
|
+
const centralHeader = Buffer.alloc(46);
|
|
50
|
+
centralHeader.writeUInt32LE(0x02014b50, 0); // Central directory signature
|
|
51
|
+
centralHeader.writeUInt16LE(20, 4); // Version made by
|
|
52
|
+
centralHeader.writeUInt16LE(20, 6); // Version needed to extract
|
|
53
|
+
centralHeader.writeUInt16LE(0, 8); // General purpose bit flag
|
|
54
|
+
centralHeader.writeUInt16LE(8, 10); // Compression method
|
|
55
|
+
centralHeader.writeUInt16LE(dosTime, 12); // Last mod file time
|
|
56
|
+
centralHeader.writeUInt16LE(dosDate, 14); // Last mod file date
|
|
57
|
+
centralHeader.writeUInt32LE(crc32, 16); // CRC-32
|
|
58
|
+
centralHeader.writeUInt32LE(compressed.length, 20); // Compressed size
|
|
59
|
+
centralHeader.writeUInt32LE(contentBuffer.length, 24); // Uncompressed size
|
|
60
|
+
centralHeader.writeUInt16LE(filenameBuffer.length, 28); // Filename length
|
|
61
|
+
centralHeader.writeUInt16LE(0, 30); // Extra field length
|
|
62
|
+
centralHeader.writeUInt16LE(0, 32); // File comment length
|
|
63
|
+
centralHeader.writeUInt16LE(0, 34); // Disk number start
|
|
64
|
+
centralHeader.writeUInt16LE(0, 36); // Internal file attributes
|
|
65
|
+
centralHeader.writeUInt32LE(0, 38); // External file attributes
|
|
66
|
+
centralHeader.writeUInt32LE(0, 42); // Relative offset of local header
|
|
67
|
+
// End of central directory
|
|
68
|
+
const localFileDataSize = localHeader.length + filenameBuffer.length + compressed.length;
|
|
69
|
+
const centralDirSize = centralHeader.length + filenameBuffer.length;
|
|
70
|
+
const endOfCentralDir = Buffer.alloc(22);
|
|
71
|
+
endOfCentralDir.writeUInt32LE(0x06054b50, 0); // End of central dir signature
|
|
72
|
+
endOfCentralDir.writeUInt16LE(0, 4); // Disk number
|
|
73
|
+
endOfCentralDir.writeUInt16LE(0, 6); // Disk number with central dir
|
|
74
|
+
endOfCentralDir.writeUInt16LE(1, 8); // Number of entries on this disk
|
|
75
|
+
endOfCentralDir.writeUInt16LE(1, 10); // Total number of entries
|
|
76
|
+
endOfCentralDir.writeUInt32LE(centralDirSize, 12); // Size of central directory
|
|
77
|
+
endOfCentralDir.writeUInt32LE(localFileDataSize, 16); // Offset of central directory
|
|
78
|
+
endOfCentralDir.writeUInt16LE(0, 20); // Comment length
|
|
79
|
+
return Buffer.concat([
|
|
80
|
+
localHeader,
|
|
81
|
+
filenameBuffer,
|
|
82
|
+
compressed,
|
|
83
|
+
centralHeader,
|
|
84
|
+
filenameBuffer,
|
|
85
|
+
endOfCentralDir,
|
|
86
|
+
]);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Calculate CRC-32 of a buffer.
|
|
90
|
+
*/
|
|
91
|
+
function crc32buf(buf) {
|
|
92
|
+
let crc = 0xffffffff;
|
|
93
|
+
for (let i = 0; i < buf.length; i++) {
|
|
94
|
+
crc ^= buf[i];
|
|
95
|
+
for (let j = 0; j < 8; j++) {
|
|
96
|
+
crc = crc & 1 ? (crc >>> 1) ^ 0xedb88320 : crc >>> 1;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
100
|
+
}
|
|
101
|
+
export async function handler(event) {
|
|
102
|
+
console.log("Received event:", JSON.stringify(event, null, 2));
|
|
103
|
+
const props = event.ResourceProperties;
|
|
104
|
+
const { HttpEndpoint, RealtimeEndpoint, BucketName, BridgeSource } = props;
|
|
105
|
+
// Generate a unique key for this version
|
|
106
|
+
const sourceHash = crypto
|
|
107
|
+
.createHash("md5")
|
|
108
|
+
.update(BridgeSource)
|
|
109
|
+
.digest("hex")
|
|
110
|
+
.substring(0, 8);
|
|
111
|
+
const s3Key = `bridge/handler-${sourceHash}.zip`;
|
|
112
|
+
try {
|
|
113
|
+
if (event.RequestType === "Delete") {
|
|
114
|
+
// Clean up: delete the S3 object
|
|
115
|
+
// Use the physical resource ID from the event, not the computed s3Key
|
|
116
|
+
// This handles the case where the key format changed between versions
|
|
117
|
+
const keyToDelete = event.PhysicalResourceId || s3Key;
|
|
118
|
+
console.log(`Deleting S3 object: s3://${BucketName}/${keyToDelete}`);
|
|
119
|
+
try {
|
|
120
|
+
await s3.send(new DeleteObjectCommand({
|
|
121
|
+
Bucket: BucketName,
|
|
122
|
+
Key: keyToDelete,
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
catch (deleteError) {
|
|
126
|
+
// Ignore delete errors - the object might not exist
|
|
127
|
+
console.log(`Note: Could not delete ${keyToDelete}: ${deleteError}`);
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
Status: "SUCCESS",
|
|
131
|
+
PhysicalResourceId: event.PhysicalResourceId || s3Key,
|
|
132
|
+
StackId: event.StackId,
|
|
133
|
+
RequestId: event.RequestId,
|
|
134
|
+
LogicalResourceId: event.LogicalResourceId,
|
|
135
|
+
Data: {},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
// Create or Update
|
|
139
|
+
// Decode the base64 source
|
|
140
|
+
const bridgeCode = Buffer.from(BridgeSource, "base64").toString("utf-8");
|
|
141
|
+
// Replace placeholders with actual endpoints
|
|
142
|
+
const finalCode = bridgeCode
|
|
143
|
+
.replace(/__APPSYNC_HTTP_ENDPOINT__/g, HttpEndpoint)
|
|
144
|
+
.replace(/__APPSYNC_REALTIME_ENDPOINT__/g, RealtimeEndpoint);
|
|
145
|
+
// Create a zip file containing the handler code
|
|
146
|
+
// Lambda expects the handler file to be named 'index.js' when handler is 'index.handler'
|
|
147
|
+
const zipBuffer = createZip("index.js", finalCode);
|
|
148
|
+
// Upload to S3
|
|
149
|
+
await s3.send(new PutObjectCommand({
|
|
150
|
+
Bucket: BucketName,
|
|
151
|
+
Key: s3Key,
|
|
152
|
+
Body: zipBuffer,
|
|
153
|
+
ContentType: "application/zip",
|
|
154
|
+
}));
|
|
155
|
+
console.log(`Uploaded bridge code to s3://${BucketName}/${s3Key}`);
|
|
156
|
+
return {
|
|
157
|
+
Status: "SUCCESS",
|
|
158
|
+
PhysicalResourceId: s3Key,
|
|
159
|
+
StackId: event.StackId,
|
|
160
|
+
RequestId: event.RequestId,
|
|
161
|
+
LogicalResourceId: event.LogicalResourceId,
|
|
162
|
+
Data: {
|
|
163
|
+
BucketName,
|
|
164
|
+
S3Key: s3Key,
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
console.error("Error:", error);
|
|
170
|
+
return {
|
|
171
|
+
Status: "FAILED",
|
|
172
|
+
Reason: error instanceof Error ? error.message : "Unknown error",
|
|
173
|
+
PhysicalResourceId: s3Key,
|
|
174
|
+
StackId: event.StackId,
|
|
175
|
+
RequestId: event.RequestId,
|
|
176
|
+
LogicalResourceId: event.LogicalResourceId,
|
|
177
|
+
Data: {},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9mdW5jdGlvbnMvYnJpZGdlLWJ1aWxkZXIvaGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7O0dBU0c7QUFFSCxPQUFPLEtBQUssTUFBTSxNQUFNLGFBQWEsQ0FBQTtBQUNyQyxPQUFPLEtBQUssSUFBSSxNQUFNLFdBQVcsQ0FBQTtBQUNqQyxPQUFPLEVBQ0wsbUJBQW1CLEVBQ25CLGdCQUFnQixFQUNoQixRQUFRLEdBQ1QsTUFBTSxvQkFBb0IsQ0FBQTtBQU0zQixNQUFNLEVBQUUsR0FBRyxJQUFJLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQTtBQUUzQjs7O0dBR0c7QUFDSCxTQUFTLFNBQVMsQ0FBQyxRQUFnQixFQUFFLE9BQWU7SUFDbEQsTUFBTSxhQUFhLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUE7SUFFbkQscUNBQXFDO0lBQ3JDLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsYUFBYSxDQUFDLENBQUE7SUFFckQsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxDQUFBO0lBQ3JDLE1BQU0sR0FBRyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUE7SUFFdEIsb0JBQW9CO0lBQ3BCLE1BQU0sT0FBTyxHQUNYLENBQUMsQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLElBQUksRUFBRSxDQUFDO1FBQ3JCLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUN2QixJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxVQUFVLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNuQyxNQUFNLENBQUE7SUFDUixNQUFNLE9BQU8sR0FDWCxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FB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S0FBSyxDQUFDLFFBQVEsRUFBRSxLQUFLLENBQUMsQ0FBQTtRQUU5QixPQUFPO1lBQ0wsTUFBTSxFQUFFLFFBQVE7WUFDaEIsTUFBTSxFQUFFLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLGVBQWU7WUFDaEUsa0JBQWtCLEVBQUUsS0FBSztZQUN6QixPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU87WUFDdEIsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTO1lBQzFCLGlCQUFpQixFQUFFLEtBQUssQ0FBQyxpQkFBaUI7WUFDMUMsSUFBSSxFQUFFLEVBQUU7U0FDVCxDQUFBO0lBQ0gsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEN1c3RvbSByZXNvdXJjZSBoYW5kbGVyIHRoYXQgYnVpbGRzIGFuZCB1cGxvYWRzIHRoZSBicmlkZ2UgTGFtYmRhIGNvZGUuXG4gKlxuICogVGhpcyBoYW5kbGVyOlxuICogMS4gUmVjZWl2ZXMgdGhlIGJyaWRnZSBzb3VyY2UgY29kZSAoYmFzZTY0IGVuY29kZWQpIGFuZCBBcHBTeW5jIGVuZHBvaW50c1xuICogMi4gUmVwbGFjZXMgZW5kcG9pbnQgcGxhY2Vob2xkZXJzIHdpdGggYWN0dWFsIHZhbHVlc1xuICogMy4gQ3JlYXRlcyBhIHppcCBmaWxlIHdpdGggdGhlIGNvZGVcbiAqIDQuIFVwbG9hZHMgdGhlIHppcCB0byBTM1xuICogNS4gUmV0dXJucyB0aGUgUzMgbG9jYXRpb24gZm9yIExhbWJkYSBmdW5jdGlvbnMgdG8gdXNlXG4gKi9cblxuaW1wb3J0ICogYXMgY3J5cHRvIGZyb20gXCJub2RlOmNyeXB0b1wiXG5pbXBvcnQgKiBhcyB6bGliIGZyb20gXCJub2RlOnpsaWJcIlxuaW1wb3J0IHtcbiAgRGVsZXRlT2JqZWN0Q29tbWFuZCxcbiAgUHV0T2JqZWN0Q29tbWFuZCxcbiAgUzNDbGllbnQsXG59IGZyb20gXCJAYXdzLXNkay9jbGllbnQtczNcIlxuaW1wb3J0IHR5cGUge1xuICBDbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQsXG4gIENsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VSZXNwb25zZSxcbn0gZnJvbSBcImF3cy1sYW1iZGFcIlxuXG5jb25zdCBzMyA9IG5ldyBTM0NsaWVudCh7fSlcblxuLyoqXG4gKiBDcmVhdGUgYSBtaW5pbWFsIHppcCBmaWxlIGNvbnRhaW5pbmcgYSBzaW5nbGUgZmlsZS5cbiAqIFRoaXMgaXMgYSBzaW1wbGUgaW1wbGVtZW50YXRpb24gdGhhdCBjcmVhdGVzIGEgdmFsaWQgemlwIHdpdGhvdXQgZXh0ZXJuYWwgZGVwZW5kZW5jaWVzLlxuICovXG5mdW5jdGlvbiBjcmVhdGVaaXAoZmlsZW5hbWU6IHN0cmluZywgY29udGVudDogc3RyaW5nKTogQnVmZmVyIHtcbiAgY29uc3QgY29udGVudEJ1ZmZlciA9IEJ1ZmZlci5mcm9tKGNvbnRlbnQsIFwidXRmLThcIilcblxuICAvLyBDb21wcmVzcyB0aGUgY29udGVudCB1c2luZyBkZWZsYXRlXG4gIGNvbnN0IGNvbXByZXNzZWQgPSB6bGliLmRlZmxhdGVSYXdTeW5jKGNvbnRlbnRCdWZmZXIpXG5cbiAgY29uc3QgY3JjMzIgPSBjcmMzMmJ1Zihjb250ZW50QnVmZmVyKVxuICBjb25zdCBub3cgPSBuZXcgRGF0ZSgpXG5cbiAgLy8gRE9TIHRpbWUgYW5kIGRhdGVcbiAgY29uc3QgZG9zVGltZSA9XG4gICAgKChub3cuZ2V0SG91cnMoKSA8PCAxMSkgfFxuICAgICAgKG5vdy5nZXRNaW51dGVzKCkgPDwgNSkgfFxuICAgICAgTWF0aC5mbG9vcihub3cuZ2V0U2Vjb25kcygpIC8gMikpICZcbiAgICAweGZmZmZcbiAgY29uc3QgZG9zRGF0ZSA9XG4gICAgKCgobm93LmdldEZ1bGxZZWFyKCkgLSAxOTgwKSA8PCA5KSB8XG4gICAgICAoKG5vdy5nZXRNb250aCgpICsgMSkgPDwgNSkgfFxuICAgICAgbm93LmdldERhdGUoKSkgJlxuICAgIDB4ZmZmZlxuXG4gIGNvbnN0IGZpbGVuYW1lQnVmZmVyID0gQnVmZmVyLmZyb20oZmlsZW5hbWUsIFwidXRmLThcIilcblxuICAvLyBMb2NhbCBmaWxlIGhlYWRlclxuICBjb25zdCBsb2NhbEhlYWRlciA9IEJ1ZmZlci5hbGxvYygzMClcbiAgbG9jYWxIZWFkZXIud3JpdGVVSW50MzJMRSgweDA0MDM0YjUwLCAwKSAvLyBMb2NhbCBmaWxlIGhlYWRlciBzaWduYXR1cmVcbiAgbG9jYWxIZWFkZXIud3JpdGVVSW50MTZMRSgyMCwgNCkgLy8gVmVyc2lvbiBuZWVkZWQgdG8gZXh0cmFjdCAoMi4wKVxuICBsb2NhbEhlYWRlci53cml0ZVVJbnQxNkxFKDAsIDYpIC8vIEdlbmVyYWwgcHVycG9zZSBiaXQgZmxhZ1xuICBsb2NhbEhlYWRlci53cml0ZVVJbnQxNkxFKDgsIDgpIC8vIENvbXByZXNzaW9uIG1ldGhvZCAoZGVmbGF0ZSlcbiAgbG9jYWxIZWFkZXIud3JpdGVVSW50MTZMRShkb3NUaW1lLCAxMCkgLy8gTGFzdCBtb2QgZmlsZSB0aW1lXG4gIGxvY2FsSGVhZGVyLndyaXRlVUludDE2TEUoZG9zRGF0ZSwgMTIpIC8vIExhc3QgbW9kIGZpbGUgZGF0ZVxuICBsb2NhbEhlYWRlci53cml0ZVVJbnQzMkxFKGNyYzMyLCAxNCkgLy8gQ1JDLTMyXG4gIGxvY2FsSGVhZGVyLndyaXRlVUludDMyTEUoY29tcHJlc3NlZC5sZW5ndGgsIDE4KSAvLyBDb21wcmVzc2VkIHNpemVcbiAgbG9jYWxIZWFkZXIud3JpdGVVSW50MzJMRShjb250ZW50QnVmZmVyLmxlbmd0aCwgMjIpIC8vIFVuY29tcHJlc3NlZCBzaXplXG4gIGxvY2FsSGVhZGVyLndyaXRlVUludDE2TEUoZmlsZW5hbWVCdWZmZXIubGVuZ3RoLCAyNikgLy8gRmlsZW5hbWUgbGVuZ3RoXG4gIGxvY2FsSGVhZGVyLndyaXRlVUludDE2TEUoMCwgMjgpIC8vIEV4dHJhIGZpZWxkIGxlbmd0aFxuXG4gIC8vIENlbnRyYWwgZGlyZWN0b3J5IGhlYWRlclxuICBjb25zdCBjZW50cmFsSGVhZGVyID0gQnVmZmVyLmFsbG9jKDQ2KVxuICBjZW50cmFsSGVhZGVyLndyaXRlVUludDMyTEUoMHgwMjAxNGI1MCwgMCkgLy8gQ2VudHJhbCBkaXJlY3Rvcnkgc2lnbmF0dXJlXG4gIGNlbnRyYWxIZWFkZXIud3JpdGVVSW50MTZMRSgyMCwgNCkgLy8gVmVyc2lvbiBtYWRlIGJ5XG4gIGNlbnRyYWxIZWFkZXIud3JpdGVVSW50MTZMRSgyMCwgNikgLy8gVmVyc2lvbiBuZWVkZWQgdG8gZXh0cmFjdFxuICBjZW50cmFsSGVhZGVyLndyaXRlVUludDE2TEUoMCwgOCkgLy8gR2VuZXJhbCBwdXJwb3NlIGJpdCBmbGFnXG4gIGNlbnRyYWxIZWFkZXIud3JpdGVVSW50MTZMRSg4LCAxMCkgLy8gQ29tcHJlc3Npb24gbWV0aG9kXG4gIGNlbnRyYWxIZWFkZXIud3JpdGVVSW50MTZMRShkb3NUaW1lLCAxMikgLy8gTGFzdCBtb2QgZmlsZSB0aW1lXG4gIGNlbnRyYWxIZWFkZXIud3JpdGVVSW50MTZMRShkb3NEYXRlLCAxNCkgLy8gTGFzdCBtb2QgZmlsZSBkYXRlXG4gIGNlbnRyYWxIZWFkZXIud3JpdGVVSW50MzJMRShjcmMzMiwgMTYpIC8vIENSQy0zMlxuICBjZW50cmFsSGVhZGVyLndyaXRlVUludDMyTEUoY29tcHJlc3NlZC5sZW5ndGgsIDIwKSAvLyBDb21wcmVzc2VkIHNpemVcbiAgY2VudHJhbEhlYWRlci53cml0ZVVJbnQzMkxFKGNvbnRlbnRCdWZmZXIubGVuZ3RoLCAyNCkgLy8gVW5jb21wcmVzc2VkIHNpemVcbiAgY2VudHJhbEhlYWRlci53cml0ZVVJbnQxNkxFKGZpbGVuYW1lQnVmZmVyLmxlbmd0aCwgMjgpIC8vIEZpbGVuYW1lIGxlbmd0aFxuICBjZW50cmFsSGVhZGVyLndyaXRlVUludDE2TEUoMCwgMzApIC8vIEV4dHJhIGZpZWxkIGxlbmd0aFxuICBjZW50cmFsSGVhZGVyLndyaXRlVUludDE2TEUoMCwgMzIpIC8vIEZpbGUgY29tbWVudCBsZW5ndGhcbiAgY2VudHJhbEhlYWRlci53cml0ZVVJbnQxNkxFKDAsIDM0KSAvLyBEaXNrIG51bWJlciBzdGFydFxuICBjZW50cmFsSGVhZGVyLndyaXRlVUludDE2TEUoMCwgMzYpIC8vIEludGVybmFsIGZpbGUgYXR0cmlidXRlc1xuICBjZW50cmFsSGVhZGVyLndyaXRlVUludDMyTEUoMCwgMzgpIC8vIEV4dGVybmFsIGZpbGUgYXR0cmlidXRlc1xuICBjZW50cmFsSGVhZGVyLndyaXRlVUludDMyTEUoMCwgNDIpIC8vIFJlbGF0aXZlIG9mZnNldCBvZiBsb2NhbCBoZWFkZXJcblxuICAvLyBFbmQgb2YgY2VudHJhbCBkaXJlY3RvcnlcbiAgY29uc3QgbG9jYWxGaWxlRGF0YVNpemUgPVxuICAgIGxvY2FsSGVhZGVyLmxlbmd0aCArIGZpbGVuYW1lQnVmZmVyLmxlbmd0aCArIGNvbXByZXNzZWQubGVuZ3RoXG4gIGNvbnN0IGNlbnRyYWxEaXJTaXplID0gY2VudHJhbEhlYWRlci5sZW5ndGggKyBmaWxlbmFtZUJ1ZmZlci5sZW5ndGhcblxuICBjb25zdCBlbmRPZkNlbnRyYWxEaXIgPSBCdWZmZXIuYWxsb2MoMjIpXG4gIGVuZE9mQ2VudHJhbERpci53cml0ZVVJbnQzMkxFKDB4MDYwNTRiNTAsIDApIC8vIEVuZCBvZiBjZW50cmFsIGRpciBzaWduYXR1cmVcbiAgZW5kT2ZDZW50cmFsRGlyLndyaXRlVUludDE2TEUoMCwgNCkgLy8gRGlzayBudW1iZXJcbiAgZW5kT2ZDZW50cmFsRGlyLndyaXRlVUludDE2TEUoMCwgNikgLy8gRGlzayBudW1iZXIgd2l0aCBjZW50cmFsIGRpclxuICBlbmRPZkNlbnRyYWxEaXIud3JpdGVVSW50MTZMRSgxLCA4KSAvLyBOdW1iZXIgb2YgZW50cmllcyBvbiB0aGlzIGRpc2tcbiAgZW5kT2ZDZW50cmFsRGlyLndyaXRlVUludDE2TEUoMSwgMTApIC8vIFRvdGFsIG51bWJlciBvZiBlbnRyaWVzXG4gIGVuZE9mQ2VudHJhbERpci53cml0ZVVJbnQzMkxFKGNlbnRyYWxEaXJTaXplLCAxMikgLy8gU2l6ZSBvZiBjZW50cmFsIGRpcmVjdG9yeVxuICBlbmRPZkNlbnRyYWxEaXIud3JpdGVVSW50MzJMRShsb2NhbEZpbGVEYXRhU2l6ZSwgMTYpIC8vIE9mZnNldCBvZiBjZW50cmFsIGRpcmVjdG9yeVxuICBlbmRPZkNlbnRyYWxEaXIud3JpdGVVSW50MTZMRSgwLCAyMCkgLy8gQ29tbWVudCBsZW5ndGhcblxuICByZXR1cm4gQnVmZmVyLmNvbmNhdChbXG4gICAgbG9jYWxIZWFkZXIsXG4gICAgZmlsZW5hbWVCdWZmZXIsXG4gICAgY29tcHJlc3NlZCxcbiAgICBjZW50cmFsSGVhZGVyLFxuICAgIGZpbGVuYW1lQnVmZmVyLFxuICAgIGVuZE9mQ2VudHJhbERpcixcbiAgXSlcbn1cblxuLyoqXG4gKiBDYWxjdWxhdGUgQ1JDLTMyIG9mIGEgYnVmZmVyLlxuICovXG5mdW5jdGlvbiBjcmMzMmJ1ZihidWY6IEJ1ZmZlcik6IG51bWJlciB7XG4gIGxldCBjcmMgPSAweGZmZmZmZmZmXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYnVmLmxlbmd0aDsgaSsrKSB7XG4gICAgY3JjIF49IGJ1ZltpXVxuICAgIGZvciAobGV0IGogPSAwOyBqIDwgODsgaisrKSB7XG4gICAgICBjcmMgPSBjcmMgJiAxID8gKGNyYyA+Pj4gMSkgXiAweGVkYjg4MzIwIDogY3JjID4+PiAxXG4gICAgfVxuICB9XG4gIHJldHVybiAoY3JjIF4gMHhmZmZmZmZmZikgPj4+IDBcbn1cblxuaW50ZXJmYWNlIFJlc291cmNlUHJvcGVydGllcyB7XG4gIEh0dHBFbmRwb2ludDogc3RyaW5nXG4gIFJlYWx0aW1lRW5kcG9pbnQ6IHN0cmluZ1xuICBCdWNrZXROYW1lOiBzdHJpbmdcbiAgQnJpZGdlU291cmNlOiBzdHJpbmcgLy8gQmFzZTY0IGVuY29kZWRcbiAgU291cmNlSGFzaD86IHN0cmluZ1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaGFuZGxlcihcbiAgZXZlbnQ6IENsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VFdmVudCxcbik6IFByb21pc2U8Q2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZVJlc3BvbnNlPiB7XG4gIGNvbnNvbGUubG9nKFwiUmVjZWl2ZWQgZXZlbnQ6XCIsIEpTT04uc3RyaW5naWZ5KGV2ZW50LCBudWxsLCAyKSlcblxuICBjb25zdCBwcm9wcyA9IGV2ZW50LlJlc291cmNlUHJvcGVydGllcyBhcyB1bmtub3duIGFzIFJlc291cmNlUHJvcGVydGllc1xuICBjb25zdCB7IEh0dHBFbmRwb2ludCwgUmVhbHRpbWVFbmRwb2ludCwgQnVja2V0TmFtZSwgQnJpZGdlU291cmNlIH0gPSBwcm9wc1xuXG4gIC8vIEdlbmVyYXRlIGEgdW5pcXVlIGtleSBmb3IgdGhpcyB2ZXJzaW9uXG4gIGNvbnN0IHNvdXJjZUhhc2ggPSBjcnlwdG9cbiAgICAuY3JlYXRlSGFzaChcIm1kNVwiKVxuICAgIC51cGRhdGUoQnJpZGdlU291cmNlKVxuICAgIC5kaWdlc3QoXCJoZXhcIilcbiAgICAuc3Vic3RyaW5nKDAsIDgpXG4gIGNvbnN0IHMzS2V5ID0gYGJyaWRnZS9oYW5kbGVyLSR7c291cmNlSGFzaH0uemlwYFxuXG4gIHRyeSB7XG4gICAgaWYgKGV2ZW50LlJlcXVlc3RUeXBlID09PSBcIkRlbGV0ZVwiKSB7XG4gICAgICAvLyBDbGVhbiB1cDogZGVsZXRlIHRoZSBTMyBvYmplY3RcbiAgICAgIC8vIFVzZSB0aGUgcGh5c2ljYWwgcmVzb3VyY2UgSUQgZnJvbSB0aGUgZXZlbnQsIG5vdCB0aGUgY29tcHV0ZWQgczNLZXlcbiAgICAgIC8vIFRoaXMgaGFuZGxlcyB0aGUgY2FzZSB3aGVyZSB0aGUga2V5IGZvcm1hdCBjaGFuZ2VkIGJldHdlZW4gdmVyc2lvbnNcbiAgICAgIGNvbnN0IGtleVRvRGVsZXRlID0gZXZlbnQuUGh5c2ljYWxSZXNvdXJjZUlkIHx8IHMzS2V5XG4gICAgICBjb25zb2xlLmxvZyhgRGVsZXRpbmcgUzMgb2JqZWN0OiBzMzovLyR7QnVja2V0TmFtZX0vJHtrZXlUb0RlbGV0ZX1gKVxuXG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBzMy5zZW5kKFxuICAgICAgICAgIG5ldyBEZWxldGVPYmplY3RDb21tYW5kKHtcbiAgICAgICAgICAgIEJ1Y2tldDogQnVja2V0TmFtZSxcbiAgICAgICAgICAgIEtleToga2V5VG9EZWxldGUsXG4gICAgICAgICAgfSksXG4gICAgICAgIClcbiAgICAgIH0gY2F0Y2ggKGRlbGV0ZUVycm9yKSB7XG4gICAgICAgIC8vIElnbm9yZSBkZWxldGUgZXJyb3JzIC0gdGhlIG9iamVjdCBtaWdodCBub3QgZXhpc3RcbiAgICAgICAgY29uc29sZS5sb2coYE5vdGU6IENvdWxkIG5vdCBkZWxldGUgJHtrZXlUb0RlbGV0ZX06ICR7ZGVsZXRlRXJyb3J9YClcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgU3RhdHVzOiBcIlNVQ0NFU1NcIixcbiAgICAgICAgUGh5c2ljYWxSZXNvdXJjZUlkOiBldmVudC5QaHlzaWNhbFJlc291cmNlSWQgfHwgczNLZXksXG4gICAgICAgIFN0YWNrSWQ6IGV2ZW50LlN0YWNrSWQsXG4gICAgICAgIFJlcXVlc3RJZDogZXZlbnQuUmVxdWVzdElkLFxuICAgICAgICBMb2dpY2FsUmVzb3VyY2VJZDogZXZlbnQuTG9naWNhbFJlc291cmNlSWQsXG4gICAgICAgIERhdGE6IHt9LFxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIENyZWF0ZSBvciBVcGRhdGVcbiAgICAvLyBEZWNvZGUgdGhlIGJhc2U2NCBzb3VyY2VcbiAgICBjb25zdCBicmlkZ2VDb2RlID0gQnVmZmVyLmZyb20oQnJpZGdlU291cmNlLCBcImJhc2U2NFwiKS50b1N0cmluZyhcInV0Zi04XCIpXG5cbiAgICAvLyBSZXBsYWNlIHBsYWNlaG9sZGVycyB3aXRoIGFjdHVhbCBlbmRwb2ludHNcbiAgICBjb25zdCBmaW5hbENvZGUgPSBicmlkZ2VDb2RlXG4gICAgICAucmVwbGFjZSgvX19BUFBTWU5DX0hUVFBfRU5EUE9JTlRfXy9nLCBIdHRwRW5kcG9pbnQpXG4gICAgICAucmVwbGFjZSgvX19BUFBTWU5DX1JFQUxUSU1FX0VORFBPSU5UX18vZywgUmVhbHRpbWVFbmRwb2ludClcblxuICAgIC8vIENyZWF0ZSBhIHppcCBmaWxlIGNvbnRhaW5pbmcgdGhlIGhhbmRsZXIgY29kZVxuICAgIC8vIExhbWJkYSBleHBlY3RzIHRoZSBoYW5kbGVyIGZpbGUgdG8gYmUgbmFtZWQgJ2luZGV4LmpzJyB3aGVuIGhhbmRsZXIgaXMgJ2luZGV4LmhhbmRsZXInXG4gICAgY29uc3QgemlwQnVmZmVyID0gY3JlYXRlWmlwKFwiaW5kZXguanNcIiwgZmluYWxDb2RlKVxuXG4gICAgLy8gVXBsb2FkIHRvIFMzXG4gICAgYXdhaXQgczMuc2VuZChcbiAgICAgIG5ldyBQdXRPYmplY3RDb21tYW5kKHtcbiAgICAgICAgQnVja2V0OiBCdWNrZXROYW1lLFxuICAgICAgICBLZXk6IHMzS2V5LFxuICAgICAgICBCb2R5OiB6aXBCdWZmZXIsXG4gICAgICAgIENvbnRlbnRUeXBlOiBcImFwcGxpY2F0aW9uL3ppcFwiLFxuICAgICAgfSksXG4gICAgKVxuXG4gICAgY29uc29sZS5sb2coYFVwbG9hZGVkIGJyaWRnZSBjb2RlIHRvIHMzOi8vJHtCdWNrZXROYW1lfS8ke3MzS2V5fWApXG5cbiAgICByZXR1cm4ge1xuICAgICAgU3RhdHVzOiBcIlNVQ0NFU1NcIixcbiAgICAgIFBoeXNpY2FsUmVzb3VyY2VJZDogczNLZXksXG4gICAgICBTdGFja0lkOiBldmVudC5TdGFja0lkLFxuICAgICAgUmVxdWVzdElkOiBldmVudC5SZXF1ZXN0SWQsXG4gICAgICBMb2dpY2FsUmVzb3VyY2VJZDogZXZlbnQuTG9naWNhbFJlc291cmNlSWQsXG4gICAgICBEYXRhOiB7XG4gICAgICAgIEJ1Y2tldE5hbWUsXG4gICAgICAgIFMzS2V5OiBzM0tleSxcbiAgICAgIH0sXG4gICAgfVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvcjpcIiwgZXJyb3IpXG5cbiAgICByZXR1cm4ge1xuICAgICAgU3RhdHVzOiBcIkZBSUxFRFwiLFxuICAgICAgUmVhc29uOiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFwiVW5rbm93biBlcnJvclwiLFxuICAgICAgUGh5c2ljYWxSZXNvdXJjZUlkOiBzM0tleSxcbiAgICAgIFN0YWNrSWQ6IGV2ZW50LlN0YWNrSWQsXG4gICAgICBSZXF1ZXN0SWQ6IGV2ZW50LlJlcXVlc3RJZCxcbiAgICAgIExvZ2ljYWxSZXNvdXJjZUlkOiBldmVudC5Mb2dpY2FsUmVzb3VyY2VJZCxcbiAgICAgIERhdGE6IHt9LFxuICAgIH1cbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lambda Custom Runtime implementation for the Docker bridge.
|
|
3
|
+
*
|
|
4
|
+
* This implements the Lambda Runtime API to:
|
|
5
|
+
* 1. Fetch invocations from the runtime API
|
|
6
|
+
* 2. Call the bridge handler
|
|
7
|
+
* 3. Post responses back to the runtime API
|
|
8
|
+
*/
|
|
9
|
+
import { handler as bridgeHandler } from "../bridge/handler.js";
|
|
10
|
+
const RUNTIME_API = process.env.AWS_LAMBDA_RUNTIME_API;
|
|
11
|
+
const HANDLER = process.env._HANDLER || "index.handler";
|
|
12
|
+
if (!RUNTIME_API) {
|
|
13
|
+
console.error("[Runtime] AWS_LAMBDA_RUNTIME_API not set");
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
const RUNTIME_BASE = `http://${RUNTIME_API}/2018-06-01/runtime`;
|
|
17
|
+
async function getNextInvocation() {
|
|
18
|
+
const response = await fetch(`${RUNTIME_BASE}/invocation/next`);
|
|
19
|
+
if (!response.ok) {
|
|
20
|
+
throw new Error(`Failed to get next invocation: ${response.status}`);
|
|
21
|
+
}
|
|
22
|
+
const headers = Object.fromEntries(response.headers.entries());
|
|
23
|
+
const event = await response.json();
|
|
24
|
+
const requestId = headers["lambda-runtime-aws-request-id"];
|
|
25
|
+
const deadlineMs = parseInt(headers["lambda-runtime-deadline-ms"], 10);
|
|
26
|
+
const invokedFunctionArn = headers["lambda-runtime-invoked-function-arn"];
|
|
27
|
+
const traceId = headers["lambda-runtime-trace-id"];
|
|
28
|
+
// Set trace ID environment variable for X-Ray
|
|
29
|
+
if (traceId) {
|
|
30
|
+
process.env._X_AMZN_TRACE_ID = traceId;
|
|
31
|
+
}
|
|
32
|
+
const context = {
|
|
33
|
+
functionName: process.env.AWS_LAMBDA_FUNCTION_NAME || "unknown",
|
|
34
|
+
functionVersion: process.env.AWS_LAMBDA_FUNCTION_VERSION || "$LATEST",
|
|
35
|
+
invokedFunctionArn,
|
|
36
|
+
memoryLimitInMB: process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE || "256",
|
|
37
|
+
awsRequestId: requestId,
|
|
38
|
+
logGroupName: process.env.AWS_LAMBDA_LOG_GROUP_NAME || "/aws/lambda/unknown",
|
|
39
|
+
logStreamName: process.env.AWS_LAMBDA_LOG_STREAM_NAME || "unknown",
|
|
40
|
+
getRemainingTimeInMillis: () => deadlineMs - Date.now(),
|
|
41
|
+
callbackWaitsForEmptyEventLoop: true,
|
|
42
|
+
done: () => { },
|
|
43
|
+
fail: () => { },
|
|
44
|
+
succeed: () => { },
|
|
45
|
+
};
|
|
46
|
+
return { event, context };
|
|
47
|
+
}
|
|
48
|
+
async function postResponse(requestId, response) {
|
|
49
|
+
const res = await fetch(`${RUNTIME_BASE}/invocation/${requestId}/response`, {
|
|
50
|
+
method: "POST",
|
|
51
|
+
headers: { "Content-Type": "application/json" },
|
|
52
|
+
body: JSON.stringify(response),
|
|
53
|
+
});
|
|
54
|
+
if (!res.ok) {
|
|
55
|
+
throw new Error(`Failed to post response: ${res.status}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function postError(requestId, error) {
|
|
59
|
+
const errorPayload = {
|
|
60
|
+
errorType: error.name || "Error",
|
|
61
|
+
errorMessage: error.message,
|
|
62
|
+
stackTrace: error.stack?.split("\n") || [],
|
|
63
|
+
};
|
|
64
|
+
const res = await fetch(`${RUNTIME_BASE}/invocation/${requestId}/error`, {
|
|
65
|
+
method: "POST",
|
|
66
|
+
headers: {
|
|
67
|
+
"Content-Type": "application/json",
|
|
68
|
+
"Lambda-Runtime-Function-Error-Type": "Unhandled",
|
|
69
|
+
},
|
|
70
|
+
body: JSON.stringify(errorPayload),
|
|
71
|
+
});
|
|
72
|
+
if (!res.ok) {
|
|
73
|
+
console.error(`[Runtime] Failed to post error: ${res.status}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function postInitError(error) {
|
|
77
|
+
const errorPayload = {
|
|
78
|
+
errorType: error.name || "Error",
|
|
79
|
+
errorMessage: error.message,
|
|
80
|
+
stackTrace: error.stack?.split("\n") || [],
|
|
81
|
+
};
|
|
82
|
+
const res = await fetch(`${RUNTIME_BASE}/init/error`, {
|
|
83
|
+
method: "POST",
|
|
84
|
+
headers: {
|
|
85
|
+
"Content-Type": "application/json",
|
|
86
|
+
"Lambda-Runtime-Function-Error-Type": "Unhandled",
|
|
87
|
+
},
|
|
88
|
+
body: JSON.stringify(errorPayload),
|
|
89
|
+
});
|
|
90
|
+
if (!res.ok) {
|
|
91
|
+
console.error(`[Runtime] Failed to post init error: ${res.status}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function main() {
|
|
95
|
+
console.log("[Runtime] Starting Lambda custom runtime");
|
|
96
|
+
console.log(`[Runtime] Handler: ${HANDLER}`);
|
|
97
|
+
console.log(`[Runtime] Function: ${process.env.AWS_LAMBDA_FUNCTION_NAME}`);
|
|
98
|
+
// Process invocations in a loop
|
|
99
|
+
while (true) {
|
|
100
|
+
let requestId;
|
|
101
|
+
try {
|
|
102
|
+
// Get next invocation
|
|
103
|
+
const { event, context } = await getNextInvocation();
|
|
104
|
+
requestId = context.awsRequestId;
|
|
105
|
+
console.log(`[Runtime] Processing invocation ${requestId}`);
|
|
106
|
+
// Call the bridge handler
|
|
107
|
+
const result = await bridgeHandler(event, context);
|
|
108
|
+
// Post response
|
|
109
|
+
await postResponse(requestId, result);
|
|
110
|
+
console.log(`[Runtime] Response sent for ${requestId}`);
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
console.error(`[Runtime] Error:`, error);
|
|
114
|
+
if (requestId) {
|
|
115
|
+
await postError(requestId, error instanceof Error ? error : new Error(String(error)));
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
await postInitError(error instanceof Error ? error : new Error(String(error)));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
main().catch((error) => {
|
|
124
|
+
console.error("[Runtime] Fatal error:", error);
|
|
125
|
+
postInitError(error instanceof Error ? error : new Error(String(error))).finally(() => process.exit(1));
|
|
126
|
+
});
|
|
127
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9mdW5jdGlvbnMvYnJpZGdlLWRvY2tlci9ydW50aW1lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7O0dBT0c7QUFHSCxPQUFPLEVBQUUsT0FBTyxJQUFJLGFBQWEsRUFBRSxNQUFNLHNCQUFzQixDQUFBO0FBRS9ELE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsc0JBQXNCLENBQUE7QUFDdEQsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxRQUFRLElBQUksZUFBZSxDQUFBO0FBRXZELElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNqQixPQUFPLENBQUMsS0FBSyxDQUFDLDBDQUEwQyxDQUFDLENBQUE7SUFDekQsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQTtBQUNqQixDQUFDO0FBRUQsTUFBTSxZQUFZLEdBQUcsVUFBVSxXQUFXLHFCQUFxQixDQUFBO0FBVy9ELEtBQUssVUFBVSxpQkFBaUI7SUFJOUIsTUFBTSxRQUFRLEdBQUcsTUFBTSxLQUFLLENBQUMsR0FBRyxZQUFZLGtCQUFrQixDQUFDLENBQUE7SUFFL0QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUNqQixNQUFNLElBQUksS0FBSyxDQUFDLGtDQUFrQyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQTtJQUN0RSxDQUFDO0lBRUQsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FDaEMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FDRSxDQUFBO0lBQzlCLE1BQU0sS0FBSyxHQUFHLE1BQU0sUUFBUSxDQUFDLElBQUksRUFBRSxDQUFBO0lBRW5DLE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQywrQkFBK0IsQ0FBQyxDQUFBO0lBQzFELE1BQU0sVUFBVSxHQUFHLFFBQVEsQ0FBQyxPQUFP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c0NvbnRlbnQiOlsiLyoqXG4gKiBMYW1iZGEgQ3VzdG9tIFJ1bnRpbWUgaW1wbGVtZW50YXRpb24gZm9yIHRoZSBEb2NrZXIgYnJpZGdlLlxuICpcbiAqIFRoaXMgaW1wbGVtZW50cyB0aGUgTGFtYmRhIFJ1bnRpbWUgQVBJIHRvOlxuICogMS4gRmV0Y2ggaW52b2NhdGlvbnMgZnJvbSB0aGUgcnVudGltZSBBUElcbiAqIDIuIENhbGwgdGhlIGJyaWRnZSBoYW5kbGVyXG4gKiAzLiBQb3N0IHJlc3BvbnNlcyBiYWNrIHRvIHRoZSBydW50aW1lIEFQSVxuICovXG5cbmltcG9ydCB0eXBlIHsgQ29udGV4dCB9IGZyb20gXCJhd3MtbGFtYmRhXCJcbmltcG9ydCB7IGhhbmRsZXIgYXMgYnJpZGdlSGFuZGxlciB9IGZyb20gXCIuLi9icmlkZ2UvaGFuZGxlci5qc1wiXG5cbmNvbnN0IFJVTlRJTUVfQVBJID0gcHJvY2Vzcy5lbnYuQVdTX0xBTUJEQV9SVU5USU1FX0FQSVxuY29uc3QgSEFORExFUiA9IHByb2Nlc3MuZW52Ll9IQU5ETEVSIHx8IFwiaW5kZXguaGFuZGxlclwiXG5cbmlmICghUlVOVElNRV9BUEkpIHtcbiAgY29uc29sZS5lcnJvcihcIltSdW50aW1lXSBBV1NfTEFNQkRBX1JVTlRJTUVfQVBJIG5vdCBzZXRcIilcbiAgcHJvY2Vzcy5leGl0KDEpXG59XG5cbmNvbnN0IFJVTlRJTUVfQkFTRSA9IGBodHRwOi8vJHtSVU5USU1FX0FQSX0vMjAxOC0wNi0wMS9ydW50aW1lYFxuXG5pbnRlcmZhY2UgUnVudGltZUhlYWRlcnMge1xuICBcImxhbWJkYS1ydW50aW1lLWF3cy1yZXF1ZXN0LWlkXCI6IHN0cmluZ1xuICBcImxhbWJkYS1ydW50aW1lLWRlYWRsaW5lLW1zXCI6IHN0cmluZ1xuICBcImxhbWJkYS1ydW50aW1lLWludm9rZWQtZnVuY3Rpb24tYXJuXCI6IHN0cmluZ1xuICBcImxhbWJkYS1ydW50aW1lLXRyYWNlLWlkXCI/OiBzdHJpbmdcbiAgXCJsYW1iZGEtcnVudGltZS1jbGllbnQtY29udGV4dFwiPzogc3RyaW5nXG4gIFwibGFtYmRhLXJ1bnRpbWUtY29nbml0by1pZGVudGl0eVwiPzogc3RyaW5nXG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldE5leHRJbnZvY2F0aW9uKCk6IFByb21pc2U8e1xuICBldmVudDogdW5rbm93blxuICBjb250ZXh0OiBDb250ZXh0XG59PiB7XG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7UlVOVElNRV9CQVNFfS9pbnZvY2F0aW9uL25leHRgKVxuXG4gIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byBnZXQgbmV4dCBpbnZvY2F0aW9uOiAke3Jlc3BvbnNlLnN0YXR1c31gKVxuICB9XG5cbiAgY29uc3QgaGVhZGVycyA9IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICByZXNwb25zZS5oZWFkZXJzLmVudHJpZXMoKSxcbiAgKSBhcyB1bmtub3duIGFzIFJ1bnRpbWVIZWFkZXJzXG4gIGNvbnN0IGV2ZW50ID0gYXdhaXQgcmVzcG9uc2UuanNvbigpXG5cbiAgY29uc3QgcmVxdWVzdElkID0gaGVhZGVyc1tcImxhbWJkYS1ydW50aW1lLWF3cy1yZXF1ZXN0LWlkXCJdXG4gIGNvbnN0IGRlYWRsaW5lTXMgPSBwYXJzZUludChoZWFkZXJzW1wibGFtYmRhLXJ1bnRpbWUtZGVhZGxpbmUtbXNcIl0sIDEwKVxuICBjb25zdCBpbnZva2VkRnVuY3Rpb25Bcm4gPSBoZWFkZXJzW1wibGFtYmRhLXJ1bnRpbWUtaW52b2tlZC1mdW5jdGlvbi1hcm5cIl1cbiAgY29uc3QgdHJhY2VJZCA9IGhlYWRlcnNbXCJsYW1iZGEtcnVudGltZS10cmFjZS1pZFwiXVxuXG4gIC8vIFNldCB0cmFjZSBJRCBlbnZpcm9ubWVudCB2YXJpYWJsZSBmb3IgWC1SYXlcbiAgaWYgKHRyYWNlSWQpIHtcbiAgICBwcm9jZXNzLmVudi5fWF9BTVpOX1RSQUNFX0lEID0gdHJhY2VJZFxuICB9XG5cbiAgY29uc3QgY29udGV4dDogQ29udGV4dCA9IHtcbiAgICBmdW5jdGlvbk5hbWU6IHByb2Nlc3MuZW52LkFXU19MQU1CREFfRlVOQ1RJT05fTkFNRSB8fCBcInVua25vd25cIixcbiAgICBmdW5jdGlvblZlcnNpb246IHByb2Nlc3MuZW52LkFXU19MQU1CREFfRlVOQ1RJT05fVkVSU0lPTiB8fCBcIiRMQVRFU1RcIixcbiAgICBpbnZva2VkRnVuY3Rpb25Bcm4sXG4gICAgbWVtb3J5TGltaXRJbk1COiBwcm9jZXNzLmVudi5BV1NfTEFNQkRBX0ZVTkNUSU9OX01FTU9SWV9TSVpFIHx8IFwiMjU2XCIsXG4gICAgYXdzUmVxdWVzdElkOiByZXF1ZXN0SWQsXG4gICAgbG9nR3JvdXBOYW1lOlxuICAgICAgcHJvY2Vzcy5lbnYuQVdTX0xBTUJEQV9MT0dfR1JPVVBfTkFNRSB8fCBcIi9hd3MvbGFtYmRhL3Vua25vd25cIixcbiAgICBsb2dTdHJlYW1OYW1lOiBwcm9jZXNzLmVudi5BV1NfTEFNQkRBX0xPR19TVFJFQU1fTkFNRSB8fCBcInVua25vd25cIixcbiAgICBnZXRSZW1haW5pbmdUaW1lSW5NaWxsaXM6ICgpID0+IGRlYWRsaW5lTXMgLSBEYXRlLm5vdygpLFxuICAgIGNhbGxiYWNrV2FpdHNGb3JFbXB0eUV2ZW50TG9vcDogdHJ1ZSxcbiAgICBkb25lOiAoKSA9PiB7fSxcbiAgICBmYWlsOiAoKSA9PiB7fSxcbiAgICBzdWNjZWVkOiAoKSA9PiB7fSxcbiAgfVxuXG4gIHJldHVybiB7IGV2ZW50LCBjb250ZXh0IH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gcG9zdFJlc3BvbnNlKFxuICByZXF1ZXN0SWQ6IHN0cmluZyxcbiAgcmVzcG9uc2U6IHVua25vd24sXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgcmVzID0gYXdhaXQgZmV0Y2goYCR7UlVOVElNRV9CQVNFfS9pbnZvY2F0aW9uLyR7cmVxdWVzdElkfS9yZXNwb25zZWAsIHtcbiAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgIGhlYWRlcnM6IHsgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIgfSxcbiAgICBib2R5OiBKU09OLnN0cmluZ2lmeShyZXNwb25zZSksXG4gIH0pXG5cbiAgaWYgKCFyZXMub2spIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byBwb3N0IHJlc3BvbnNlOiAke3Jlcy5zdGF0dXN9YClcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBwb3N0RXJyb3IocmVxdWVzdElkOiBzdHJpbmcsIGVycm9yOiBFcnJvcik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBlcnJvclBheWxvYWQgPSB7XG4gICAgZXJyb3JUeXBlOiBlcnJvci5uYW1lIHx8IFwiRXJyb3JcIixcbiAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2UsXG4gICAgc3RhY2tUcmFjZTogZXJyb3Iuc3RhY2s/LnNwbGl0KFwiXFxuXCIpIHx8IFtdLFxuICB9XG5cbiAgY29uc3QgcmVzID0gYXdhaXQgZmV0Y2goYCR7UlVOVElNRV9CQVNFfS9pbnZvY2F0aW9uLyR7cmVxdWVzdElkfS9lcnJvcmAsIHtcbiAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgIGhlYWRlcnM6IHtcbiAgICAgIFwiQ29udGVudC1UeXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiLFxuICAgICAgXCJMYW1iZGEtUnVudGltZS1GdW5jdGlvbi1FcnJvci1UeXBlXCI6IFwiVW5oYW5kbGVkXCIsXG4gICAgfSxcbiAgICBib2R5OiBKU09OLnN0cmluZ2lmeShlcnJvclBheWxvYWQpLFxuICB9KVxuXG4gIGlmICghcmVzLm9rKSB7XG4gICAgY29uc29sZS5lcnJvcihgW1J1bnRpbWVdIEZhaWxlZCB0byBwb3N0IGVycm9yOiAke3Jlcy5zdGF0dXN9YClcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBwb3N0SW5pdEVycm9yKGVycm9yOiBFcnJvcik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBlcnJvclBheWxvYWQgPSB7XG4gICAgZXJyb3JUeXBlOiBlcnJvci5uYW1lIHx8IFwiRXJyb3JcIixcbiAgICBlcnJvck1lc3NhZ2U6IGVycm9yLm1lc3NhZ2UsXG4gICAgc3RhY2tUcmFjZTogZXJyb3Iuc3RhY2s/LnNwbGl0KFwiXFxuXCIpIHx8IFtdLFxuICB9XG5cbiAgY29uc3QgcmVzID0gYXdhaXQgZmV0Y2goYCR7UlVOVElNRV9CQVNFfS9pbml0L2Vycm9yYCwge1xuICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgaGVhZGVyczoge1xuICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICBcIkxhbWJkYS1SdW50aW1lLUZ1bmN0aW9uLUVycm9yLVR5cGVcIjogXCJVbmhhbmRsZWRcIixcbiAgICB9LFxuICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KGVycm9yUGF5bG9hZCksXG4gIH0pXG5cbiAgaWYgKCFyZXMub2spIHtcbiAgICBjb25zb2xlLmVycm9yKGBbUnVudGltZV0gRmFpbGVkIHRvIHBvc3QgaW5pdCBlcnJvcjogJHtyZXMuc3RhdHVzfWApXG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gbWFpbigpIHtcbiAgY29uc29sZS5sb2coXCJbUnVudGltZV0gU3RhcnRpbmcgTGFtYmRhIGN1c3RvbSBydW50aW1lXCIpXG4gIGNvbnNvbGUubG9nKGBbUnVudGltZV0gSGFuZGxlcjogJHtIQU5ETEVSfWApXG4gIGNvbnNvbGUubG9nKGBbUnVudGltZV0gRnVuY3Rpb246ICR7cHJvY2Vzcy5lbnYuQVdTX0xBTUJEQV9GVU5DVElPTl9OQU1FfWApXG5cbiAgLy8gUHJvY2VzcyBpbnZvY2F0aW9ucyBpbiBhIGxvb3BcbiAgd2hpbGUgKHRydWUpIHtcbiAgICBsZXQgcmVxdWVzdElkOiBzdHJpbmcgfCB1bmRlZmluZWRcblxuICAgIHRyeSB7XG4gICAgICAvLyBHZXQgbmV4dCBpbnZvY2F0aW9uXG4gICAgICBjb25zdCB7IGV2ZW50LCBjb250ZXh0IH0gPSBhd2FpdCBnZXROZXh0SW52b2NhdGlvbigpXG4gICAgICByZXF1ZXN0SWQgPSBjb250ZXh0LmF3c1JlcXVlc3RJZFxuXG4gICAgICBjb25zb2xlLmxvZyhgW1J1bnRpbWVdIFByb2Nlc3NpbmcgaW52b2NhdGlvbiAke3JlcXVlc3RJZH1gKVxuXG4gICAgICAvLyBDYWxsIHRoZSBicmlkZ2UgaGFuZGxlclxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYnJpZGdlSGFuZGxlcihldmVudCwgY29udGV4dClcblxuICAgICAgLy8gUG9zdCByZXNwb25zZVxuICAgICAgYXdhaXQgcG9zdFJlc3BvbnNlKHJlcXVlc3RJZCwgcmVzdWx0KVxuICAgICAgY29uc29sZS5sb2coYFtSdW50aW1lXSBSZXNwb25zZSBzZW50IGZvciAke3JlcXVlc3RJZH1gKVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKGBbUnVudGltZV0gRXJyb3I6YCwgZXJyb3IpXG5cbiAgICAgIGlmIChyZXF1ZXN0SWQpIHtcbiAgICAgICAgYXdhaXQgcG9zdEVycm9yKFxuICAgICAgICAgIHJlcXVlc3RJZCxcbiAgICAgICAgICBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IgOiBuZXcgRXJyb3IoU3RyaW5nKGVycm9yKSksXG4gICAgICAgIClcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGF3YWl0IHBvc3RJbml0RXJyb3IoXG4gICAgICAgICAgZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogbmV3IEVycm9yKFN0cmluZyhlcnJvcikpLFxuICAgICAgICApXG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbm1haW4oKS5jYXRjaCgoZXJyb3IpID0+IHtcbiAgY29uc29sZS5lcnJvcihcIltSdW50aW1lXSBGYXRhbCBlcnJvcjpcIiwgZXJyb3IpXG4gIHBvc3RJbml0RXJyb3IoXG4gICAgZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogbmV3IEVycm9yKFN0cmluZyhlcnJvcikpLFxuICApLmZpbmFsbHkoKCkgPT4gcHJvY2Vzcy5leGl0KDEpKVxufSlcbiJdfQ==
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main entry point for cdk-local-lambda.
|
|
3
|
+
*
|
|
4
|
+
* Exports:
|
|
5
|
+
* - LiveLambdaAspect: CDK Aspect to transform Lambda functions
|
|
6
|
+
* - applyLiveLambdaAspect: Helper to apply the aspect if CDK_LIVE=true
|
|
7
|
+
* - isLiveModeEnabled: Check if live mode is enabled
|
|
8
|
+
* - CdkLocalLambdaBootstrapStack: The bootstrap stack for shared infrastructure
|
|
9
|
+
*
|
|
10
|
+
* For Docker function support, you must install the bootstrap BEFORE any CDK
|
|
11
|
+
* imports in your app entry point:
|
|
12
|
+
*
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import "cdk-local-lambda/bootstrap"
|
|
15
|
+
* import * as cdk from "aws-cdk-lib"
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* Node.js: this is sufficient.
|
|
19
|
+
* Bun: use `bun --preload cdk-local-lambda/bootstrap` (static ESM imports are
|
|
20
|
+
* linked before this module runs).
|
|
21
|
+
*/
|
|
22
|
+
export { applyLiveLambdaAspect, isLiveModeEnabled, LiveLambdaAspect, type LiveLambdaAspectProps, } from "./aspect/live-lambda-aspect.js";
|
|
23
|
+
export { CdkLocalLambdaBootstrapStack, type CdkLocalLambdaBootstrapStackProps, } from "./bootstrap-stack/bootstrap-stack.js";
|
|
24
|
+
export { buildChannelName, type ErrorPayload, hashFunctionName, type InvocationMessage, type LambdaContext, LIVE_LAMBDA_DOCKER_TAG, LIVE_LAMBDA_TAG, type ResponseMessage, SSM_BASE_PATH, } from "./shared/types.js";
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main entry point for cdk-local-lambda.
|
|
3
|
+
*
|
|
4
|
+
* Exports:
|
|
5
|
+
* - LiveLambdaAspect: CDK Aspect to transform Lambda functions
|
|
6
|
+
* - applyLiveLambdaAspect: Helper to apply the aspect if CDK_LIVE=true
|
|
7
|
+
* - isLiveModeEnabled: Check if live mode is enabled
|
|
8
|
+
* - CdkLocalLambdaBootstrapStack: The bootstrap stack for shared infrastructure
|
|
9
|
+
*
|
|
10
|
+
* For Docker function support, you must install the bootstrap BEFORE any CDK
|
|
11
|
+
* imports in your app entry point:
|
|
12
|
+
*
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import "cdk-local-lambda/bootstrap"
|
|
15
|
+
* import * as cdk from "aws-cdk-lib"
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* Node.js: this is sufficient.
|
|
19
|
+
* Bun: use `bun --preload cdk-local-lambda/bootstrap` (static ESM imports are
|
|
20
|
+
* linked before this module runs).
|
|
21
|
+
*/
|
|
22
|
+
// Re-export the aspect and helpers
|
|
23
|
+
export { applyLiveLambdaAspect, isLiveModeEnabled, LiveLambdaAspect, } from "./aspect/live-lambda-aspect.js";
|
|
24
|
+
// Re-export the bootstrap stack
|
|
25
|
+
export { CdkLocalLambdaBootstrapStack, } from "./bootstrap-stack/bootstrap-stack.js";
|
|
26
|
+
// Re-export shared types
|
|
27
|
+
export { buildChannelName, hashFunctionName, LIVE_LAMBDA_DOCKER_TAG, LIVE_LAMBDA_TAG, SSM_BASE_PATH, } from "./shared/types.js";
|
|
28
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0JHO0FBRUgsbUNBQW1DO0FBQ25DLE9BQU8sRUFDTCxxQkFBcUIsRUFDckIsaUJBQWlCLEVBQ2pCLGdCQUFnQixHQUVqQixNQUFNLGdDQUFnQyxDQUFBO0FBRXZDLGdDQUFnQztBQUNoQyxPQUFPLEVBQ0wsNEJBQTRCLEdBRTdCLE1BQU0sc0NBQXNDLENBQUE7QUFFN0MseUJBQXlCO0FBQ3pCLE9BQU8sRUFDTCxnQkFBZ0IsRUFFaEIsZ0JBQWdCLEVBR2hCLHNCQUFzQixFQUN0QixlQUFlLEVBRWYsYUFBYSxHQUNkLE1BQU0sbUJBQW1CLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1haW4gZW50cnkgcG9pbnQgZm9yIGNkay1sb2NhbC1sYW1iZGEuXG4gKlxuICogRXhwb3J0czpcbiAqIC0gTGl2ZUxhbWJkYUFzcGVjdDogQ0RLIEFzcGVjdCB0byB0cmFuc2Zvcm0gTGFtYmRhIGZ1bmN0aW9uc1xuICogLSBhcHBseUxpdmVMYW1iZGFBc3BlY3Q6IEhlbHBlciB0byBhcHBseSB0aGUgYXNwZWN0IGlmIENES19MSVZFPXRydWVcbiAqIC0gaXNMaXZlTW9kZUVuYWJsZWQ6IENoZWNrIGlmIGxpdmUgbW9kZSBpcyBlbmFibGVkXG4gKiAtIENka0xvY2FsTGFtYmRhQm9vdHN0cmFwU3RhY2s6IFRoZSBib290c3RyYXAgc3RhY2sgZm9yIHNoYXJlZCBpbmZyYXN0cnVjdHVyZVxuICpcbiAqIEZvciBEb2NrZXIgZnVuY3Rpb24gc3VwcG9ydCwgeW91IG11c3QgaW5zdGFsbCB0aGUgYm9vdHN0cmFwIEJFRk9SRSBhbnkgQ0RLXG4gKiBpbXBvcnRzIGluIHlvdXIgYXBwIGVudHJ5IHBvaW50OlxuICpcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCBcImNkay1sb2NhbC1sYW1iZGEvYm9vdHN0cmFwXCJcbiAqIGltcG9ydCAqIGFzIGNkayBmcm9tIFwiYXdzLWNkay1saWJcIlxuICogYGBgXG4gKlxuICogTm9kZS5qczogdGhpcyBpcyBzdWZmaWNpZW50LlxuICogQnVuOiB1c2UgYGJ1biAtLXByZWxvYWQgY2RrLWxvY2FsLWxhbWJkYS9ib290c3RyYXBgIChzdGF0aWMgRVNNIGltcG9ydHMgYXJlXG4gKiBsaW5rZWQgYmVmb3JlIHRoaXMgbW9kdWxlIHJ1bnMpLlxuICovXG5cbi8vIFJlLWV4cG9ydCB0aGUgYXNwZWN0IGFuZCBoZWxwZXJzXG5leHBvcnQge1xuICBhcHBseUxpdmVMYW1iZGFBc3BlY3QsXG4gIGlzTGl2ZU1vZGVFbmFibGVkLFxuICBMaXZlTGFtYmRhQXNwZWN0LFxuICB0eXBlIExpdmVMYW1iZGFBc3BlY3RQcm9wcyxcbn0gZnJvbSBcIi4vYXNwZWN0L2xpdmUtbGFtYmRhLWFzcGVjdC5qc1wiXG5cbi8vIFJlLWV4cG9ydCB0aGUgYm9vdHN0cmFwIHN0YWNrXG5leHBvcnQge1xuICBDZGtMb2NhbExhbWJkYUJvb3RzdHJhcFN0YWNrLFxuICB0eXBlIENka0xvY2FsTGFtYmRhQm9vdHN0cmFwU3RhY2tQcm9wcyxcbn0gZnJvbSBcIi4vYm9vdHN0cmFwLXN0YWNrL2Jvb3RzdHJhcC1zdGFjay5qc1wiXG5cbi8vIFJlLWV4cG9ydCBzaGFyZWQgdHlwZXNcbmV4cG9ydCB7XG4gIGJ1aWxkQ2hhbm5lbE5hbWUsXG4gIHR5cGUgRXJyb3JQYXlsb2FkLFxuICBoYXNoRnVuY3Rpb25OYW1lLFxuICB0eXBlIEludm9jYXRpb25NZXNzYWdlLFxuICB0eXBlIExhbWJkYUNvbnRleHQsXG4gIExJVkVfTEFNQkRBX0RPQ0tFUl9UQUcsXG4gIExJVkVfTEFNQkRBX1RBRyxcbiAgdHlwZSBSZXNwb25zZU1lc3NhZ2UsXG4gIFNTTV9CQVNFX1BBVEgsXG59IGZyb20gXCIuL3NoYXJlZC90eXBlcy5qc1wiXG4iXX0=
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared constants and types used by bootstrap stack, aspect, and CLI.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* SSM parameter paths for Live Lambda infrastructure
|
|
6
|
+
* Base path for all Live Lambda SSM parameters
|
|
7
|
+
*/
|
|
8
|
+
export declare const SSM_BASE_PATH = "/cdk-local-lambda";
|
|
9
|
+
/**
|
|
10
|
+
* Tag key used to store the local handler path on Lambda functions
|
|
11
|
+
*/
|
|
12
|
+
export declare const LIVE_LAMBDA_TAG = "live-lambda:handler";
|
|
13
|
+
/**
|
|
14
|
+
* Tag key used to store the local Docker context path on DockerImageFunction.
|
|
15
|
+
* The daemon uses this to build and run the container locally.
|
|
16
|
+
*/
|
|
17
|
+
export declare const LIVE_LAMBDA_DOCKER_TAG = "live-lambda:docker-context";
|
|
18
|
+
/**
|
|
19
|
+
* Name of the CDK bootstrap stack
|
|
20
|
+
*/
|
|
21
|
+
export declare const BOOTSTRAP_STACK_NAME = "CdkLocalLambdaBootstrapStack";
|
|
22
|
+
/**
|
|
23
|
+
* Current version of the bootstrap stack.
|
|
24
|
+
* Increment this when making breaking changes to the bootstrap infrastructure.
|
|
25
|
+
*/
|
|
26
|
+
export declare const BOOTSTRAP_VERSION = "1";
|
|
27
|
+
/**
|
|
28
|
+
* Environment variable names used by the bridge handler
|
|
29
|
+
*/
|
|
30
|
+
export declare const ENV_VARS: {
|
|
31
|
+
readonly HTTP_ENDPOINT: "APPSYNC_HTTP_ENDPOINT";
|
|
32
|
+
readonly REALTIME_ENDPOINT: "APPSYNC_REALTIME_ENDPOINT";
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Message types for AppSync Events communication
|
|
36
|
+
*/
|
|
37
|
+
export interface InvocationMessage {
|
|
38
|
+
type: "invocation";
|
|
39
|
+
requestId: string;
|
|
40
|
+
event: unknown;
|
|
41
|
+
context: LambdaContext;
|
|
42
|
+
/** Lambda environment variables (forwarded from bridge on first invocation) */
|
|
43
|
+
env?: Record<string, string>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Environment variables that are set locally by the daemon.
|
|
47
|
+
* These override any values from the bridge Lambda and are excluded from forwarding.
|
|
48
|
+
* Note: AWS_LAMBDA_FUNCTION_MEMORY_SIZE is also set locally but isn't in EXCLUDED_ENV_VARS
|
|
49
|
+
* because it doesn't come from the bridge Lambda's process.env (it's in the context).
|
|
50
|
+
*/
|
|
51
|
+
export declare const LOCAL_OVERRIDE_ENV_VARS: Set<string>;
|
|
52
|
+
/**
|
|
53
|
+
* Environment variables to exclude when forwarding from Lambda.
|
|
54
|
+
* These are either Lambda internals or should use local values instead.
|
|
55
|
+
*/
|
|
56
|
+
export declare const EXCLUDED_ENV_VARS: Set<string>;
|
|
57
|
+
/**
|
|
58
|
+
* Filter environment variables for forwarding to local execution.
|
|
59
|
+
* Removes Lambda internals and system variables that should use local values.
|
|
60
|
+
*/
|
|
61
|
+
export declare function filterEnvVars(env: NodeJS.ProcessEnv): Record<string, string>;
|
|
62
|
+
export interface ResponseMessage {
|
|
63
|
+
type: "response";
|
|
64
|
+
requestId: string;
|
|
65
|
+
result?: unknown;
|
|
66
|
+
error?: ErrorPayload;
|
|
67
|
+
}
|
|
68
|
+
export interface ErrorPayload {
|
|
69
|
+
errorType: string;
|
|
70
|
+
errorMessage: string;
|
|
71
|
+
stackTrace?: string[];
|
|
72
|
+
}
|
|
73
|
+
export interface LambdaContext {
|
|
74
|
+
functionName: string;
|
|
75
|
+
functionVersion: string;
|
|
76
|
+
invokedFunctionArn: string;
|
|
77
|
+
memoryLimitInMB: string;
|
|
78
|
+
awsRequestId: string;
|
|
79
|
+
logGroupName: string;
|
|
80
|
+
logStreamName: string;
|
|
81
|
+
getRemainingTimeInMillis: number;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Hash a function name for use in channel paths.
|
|
85
|
+
* Uses first 16 hex chars of SHA256 to stay within AppSync limits.
|
|
86
|
+
*/
|
|
87
|
+
export declare function hashFunctionName(functionName: string): string;
|
|
88
|
+
/**
|
|
89
|
+
* Channel name builders for AppSync Events
|
|
90
|
+
*/
|
|
91
|
+
export declare const buildChannelName: {
|
|
92
|
+
/**
|
|
93
|
+
* Channel for sending invocations to the daemon
|
|
94
|
+
* Bridge -> Daemon
|
|
95
|
+
*/
|
|
96
|
+
readonly invocation: (functionName: string) => string;
|
|
97
|
+
/**
|
|
98
|
+
* Channel for receiving responses from the daemon
|
|
99
|
+
* Daemon -> Bridge
|
|
100
|
+
*/
|
|
101
|
+
readonly response: (functionName: string) => string;
|
|
102
|
+
};
|