Skip to content

Instantly share code, notes, and snippets.

@serkan-ozal
Created December 4, 2025 08:03
Show Gist options
  • Select an option

  • Save serkan-ozal/80f5ae2452e612b95e40fea9b01830f0 to your computer and use it in GitHub Desktop.

Select an option

Save serkan-ozal/80f5ae2452e612b95e40fea9b01830f0 to your computer and use it in GitHub Desktop.
AWS Lambda Nodejs Runtime Code Extracter
import { readdir, readFile } from "fs/promises";
import { statSync } from "fs";
import path from "path";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
const ROOT_DIR = "/var/runtime";
const s3 = new S3Client({
region: process.env.BUCKET_REGION ?? process.env.AWS_REGION,
});
/**
* Parse SKIP_PATHS env var into normalized array
*/
function getSkipList() {
const raw = process.env.SKIP_PATHS || "";
return raw
.split(",")
.map((x) => x.trim())
.filter(Boolean)
.map((x) => x.replace(/^\/+/, "")); // remove leading slash
}
/**
* Check if a relative path should be skipped.
*/
function shouldSkip(relativePath, skipList) {
return skipList.some((skip) => {
// Skip if path starts with skip or contains it at any folder depth
return (
relativePath === skip ||
relativePath.startsWith(skip + "/") ||
relativePath.includes("/" + skip + "/")
);
});
}
/**
* Recursively gathers all file paths under a directory.
*/
async function collectFiles(dir, baseDir = ROOT_DIR, skipList = []) {
const entries = await readdir(dir, { withFileTypes: true });
const files = [];
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
const info = statSync(fullPath);
const relativePath = path.relative(baseDir, fullPath);
// Check skip list
if (shouldSkip(relativePath, skipList)) {
console.log(`Skipping: ${relativePath}`);
continue;
}
if (info.isDirectory()) {
const subFiles = await collectFiles(fullPath, baseDir, skipList);
files.push(...subFiles);
} else if (info.isFile()) {
files.push({ fullPath, relativePath });
}
}
return files;
}
/**
* Upload file to S3
*/
async function uploadFile(bucket, prefix, file) {
let keyPrefix = prefix || "";
if (keyPrefix && !keyPrefix.endsWith("/")) keyPrefix += "/";
const key = keyPrefix + file.relativePath.replace(/\\/g, "/");
console.log(`Uploading ${file.fullPath} -> s3://${bucket}/${key}`);
await s3.send(
new PutObjectCommand({
Bucket: bucket,
Key: key,
Body: await readFile(file.fullPath),
})
);
}
/**
* Lambda handler
*/
export const handler = async () => {
const bucket = process.env.BUCKET_NAME;
const prefix = process.env.S3_PREFIX || "";
const skipList = getSkipList();
if (!bucket) {
throw new Error("BUCKET_NAME env var is required");
}
console.log("Skip list:", skipList);
const files = await collectFiles(ROOT_DIR, ROOT_DIR, skipList);
console.log(`Found ${files.length} files after skipping.`);
for (const file of files) {
await uploadFile(bucket, prefix, file);
}
return {
status: "ok",
uploadedFiles: files.length,
bucket,
prefix,
skipped: skipList,
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment