-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
43 changed files
with
406 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export {}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const log_1 = require("../src/internal/log"); | ||
const package_json_1 = __importDefault(require("../package.json")); | ||
const bootstrap_1 = require("../src/internal/bootstrap"); | ||
(async () => { | ||
if (process.argv.includes("--version")) { | ||
console.log(package_json_1.default.version); | ||
return; | ||
} | ||
(0, log_1.log)("Starting bootstrap", { env: JSON.stringify(process.env) }); | ||
try { | ||
await (0, bootstrap_1.bootstrap)(); | ||
} | ||
catch (e) { | ||
if (e instanceof Error) { | ||
console.error(e.message); | ||
} | ||
else { | ||
console.error(e); | ||
} | ||
process.exit(1); | ||
} | ||
(0, log_1.log)("Bootstrap complete"); | ||
})(); |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
{ | ||
"name": "@scaffoldly/awslambda-bootstrap", | ||
"version": "1.0.11-0", | ||
"description": "Bootstrap Script for AWS Lambda", | ||
"repository": "https://github.com/scaffoldly/awslambda-bootstrap", | ||
"author": "scaffold.ly", | ||
"license": "MIT", | ||
"main": "dist/main.js", | ||
"files": [ | ||
"build/**/*", | ||
"dist/**/*", | ||
"scripts/**/*" | ||
], | ||
"bin": { | ||
"bootstrap": "dist/bootstrap.js", | ||
"lambda-env": "scripts/lambda-env.cjs" | ||
}, | ||
"scripts": { | ||
"build": "webpack", | ||
"start": "node -r ts-node/register -r tsconfig-paths/register cli/index.ts", | ||
"postinstall": "tsc" | ||
}, | ||
"engines": { | ||
"node": ">=18" | ||
}, | ||
"engineStrict": true, | ||
"keywords": [ | ||
"scaffoldly", | ||
"aws", | ||
"lambda" | ||
], | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"@types/aws-lambda": "^8.10.138", | ||
"@types/node": "18", | ||
"@types/which": "^3.0.3", | ||
"aws-lambda": "^1.0.7", | ||
"axios": "^1.7.2", | ||
"execa": "^9.1.0", | ||
"source-map": "^0.7.4", | ||
"ts-loader": "^9.5.1", | ||
"ts-node": "^10.9.2", | ||
"tsconfig-paths": "^4.2.0", | ||
"types-webpack-bundler": "^1.0.2", | ||
"typescript": "5", | ||
"webpack": "^5.91.0", | ||
"webpack-cli": "^5.1.4", | ||
"which": "^4.0.0" | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,4 @@ | ||
import { endpointSpawn, endpointProxy } from "./proxy"; | ||
import { nextEvent, respondToEvent } from "./runtime"; | ||
import { LambdaEvent, EndpointExecRequest, EndpointProxyRequest, EndpointResponse } from "./types"; | ||
import { endpointSpawn, endpointProxy } from "./internal/proxy"; | ||
import { nextEvent, respondToEvent } from "./internal/runtime"; | ||
import { LambdaEvent, EndpointExecRequest, EndpointProxyRequest, EndpointResponse } from "./internal/types"; | ||
export { endpointSpawn, endpointProxy, nextEvent, respondToEvent, LambdaEvent, EndpointExecRequest, EndpointProxyRequest, EndpointResponse, }; | ||
//# sourceMappingURL=index.d.ts.map |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.respondToEvent = exports.nextEvent = exports.endpointProxy = exports.endpointSpawn = void 0; | ||
const proxy_1 = require("./internal/proxy"); | ||
Object.defineProperty(exports, "endpointSpawn", { enumerable: true, get: function () { return proxy_1.endpointSpawn; } }); | ||
Object.defineProperty(exports, "endpointProxy", { enumerable: true, get: function () { return proxy_1.endpointProxy; } }); | ||
const runtime_1 = require("./internal/runtime"); | ||
Object.defineProperty(exports, "nextEvent", { enumerable: true, get: function () { return runtime_1.nextEvent; } }); | ||
Object.defineProperty(exports, "respondToEvent", { enumerable: true, get: function () { return runtime_1.respondToEvent; } }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1 @@ | ||
export declare const bootstrap: () => Promise<void>; | ||
//# sourceMappingURL=bootstrap.d.ts.map |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.bootstrap = void 0; | ||
const routing_1 = require("./routing"); | ||
const log_1 = require("./log"); | ||
const proxy_1 = require("./proxy"); | ||
const { _HANDLER, IS_OFFLINE, AWS_LAMBDA_RUNTIME_API } = process.env; | ||
const bootstrap = async () => { | ||
if (!AWS_LAMBDA_RUNTIME_API) { | ||
throw new Error("No AWS_LAMBDA_RUNTIME_API specified"); | ||
} | ||
if (!_HANDLER) { | ||
throw new Error("No handler specified"); | ||
} | ||
(0, log_1.log)("Bootstraping", { _HANDLER, IS_OFFLINE, AWS_LAMBDA_RUNTIME_API }); | ||
const { childProcess, bin, endpoint } = await (0, proxy_1.endpointSpawn)(_HANDLER, IS_OFFLINE === "true"); | ||
try { | ||
(0, log_1.log)("Routing events", { bin, endpoint }); | ||
await (0, routing_1.routeEvents)(AWS_LAMBDA_RUNTIME_API, bin, endpoint); | ||
} | ||
catch (e) { | ||
if (childProcess) { | ||
(0, log_1.log)("Killing child process", { pid: childProcess.pid }); | ||
childProcess.kill(); | ||
} | ||
throw e; | ||
} | ||
}; | ||
exports.bootstrap = bootstrap; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
export declare const info: (message: any, obj?: Record<string, any>) => void; | ||
export declare const log: (message: any, obj?: Record<string, any>) => void; | ||
//# sourceMappingURL=log.d.ts.map |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.log = exports.info = void 0; | ||
const package_json_1 = __importDefault(require("../../package.json")); | ||
const info = (message, obj) => { | ||
console.log(`[${package_json_1.default.name}@${package_json_1.default.version}] ${message}`, obj ? JSON.stringify(obj) : undefined); | ||
}; | ||
exports.info = info; | ||
const log = (message, obj) => { | ||
if (!process.env.SLY_DEBUG) | ||
return; | ||
console.log(`[${package_json_1.default.name}@${package_json_1.default.version}] ${message}`, obj ? JSON.stringify(obj) : undefined); | ||
}; | ||
exports.log = log; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.endpointProxy = exports.endpointExec = exports.endpointSpawn = void 0; | ||
const axios_1 = __importStar(require("axios")); | ||
const net_1 = __importDefault(require("net")); | ||
const log_1 = require("./log"); | ||
const child_process_1 = require("child_process"); | ||
function convertHeaders(headers) { | ||
if (!headers) { | ||
return undefined; | ||
} | ||
return Object.keys(headers).reduce((acc, key) => { | ||
const value = headers[key]; | ||
if (!value) | ||
return acc; | ||
if (Array.isArray(value)) { | ||
acc[key] = value.join(", "); | ||
} | ||
else if (typeof value === "string" || | ||
typeof value === "number" || | ||
typeof value === "boolean") { | ||
acc[key] = value; | ||
} | ||
return acc; | ||
}, {}); | ||
} | ||
const waitForEndpoint = async (endpoint, deadline) => { | ||
const start = Date.now(); | ||
const timeout = deadline - start; | ||
// Stop recursing if the deadline has passed | ||
if (timeout < 0) { | ||
return { timeout: 0 }; | ||
} | ||
const hostname = endpoint.hostname; | ||
const port = parseInt(endpoint.port, 10) || (endpoint.protocol === "https:" ? 443 : 80); | ||
return new Promise((resolve) => { | ||
const socket = new net_1.default.Socket(); | ||
const onError = () => { | ||
socket.destroy(); | ||
return waitForEndpoint(endpoint, deadline - (Date.now() - start)).then(resolve); | ||
}; | ||
socket.setTimeout(deadline - start); | ||
socket.once("error", onError); | ||
socket.once("timeout", onError); | ||
socket.connect(port, hostname, () => { | ||
socket.end(); | ||
resolve({ timeout: deadline - Date.now() }); | ||
}); | ||
}); | ||
}; | ||
const endpointSpawn = async (handler, offline) => { | ||
// handler is in the format of | ||
// - `{some-bin}@http://localhost:{the-bins-port} (will start some-bin, and forward requests to the http server) | ||
// - `http://localhost:{some-port}` (will forward the request to the http server) | ||
// - `{some-bin}` (will forward the event to the bin) | ||
let [bin, endpoint] = handler.split(/(?<=^[^@]*)@/); | ||
let childProcess = undefined; | ||
if (bin && !endpoint) { | ||
try { | ||
endpoint = new URL(bin).toString(); | ||
bin = undefined; | ||
} | ||
catch (e) { } | ||
} | ||
if (bin && endpoint) { | ||
(0, log_1.log)("Starting child process", { bin }); | ||
const subcommand = offline ? "dev" : "start"; | ||
(0, log_1.info)(`Running: \`${bin} ${subcommand}\``); | ||
childProcess = (0, child_process_1.spawn)(bin, [subcommand], { | ||
detached: true, | ||
stdio: "inherit", | ||
}); | ||
// TODO Decide if we should do this... | ||
childProcess.unref(); | ||
(0, log_1.log)("Started child process", { bin, subcommand, pid: childProcess.pid }); | ||
} | ||
endpoint = endpoint ? new URL(endpoint) : undefined; | ||
return { childProcess, bin, endpoint }; | ||
}; | ||
exports.endpointSpawn = endpointSpawn; | ||
const endpointExec = async ({ requestId, bin, event, deadline, }) => { | ||
const { execa } = await import("execa"); | ||
const { stdout } = await execa({ | ||
stderr: ["inherit"], | ||
}) `${bin} ${event}`; | ||
// TODO: handle deadline | ||
(0, log_1.info)("TODO: need to handle deadline", { deadline }); | ||
const payload = JSON.parse(stdout); | ||
return { | ||
requestId, | ||
payload, | ||
}; | ||
}; | ||
exports.endpointExec = endpointExec; | ||
const endpointProxy = async ({ requestId, endpoint, event, deadline, }) => { | ||
const { requestContext, rawPath, rawQueryString, headers: rawHeaders, body: rawBody, isBase64Encoded, } = event; | ||
const method = requestContext.http.method; | ||
(0, log_1.log)("Waiting for endpoint to start", { endpoint, deadline }); | ||
const { timeout } = await waitForEndpoint(endpoint, deadline); | ||
if (!timeout) { | ||
throw new Error(`${endpoint.toString()} took longer than ${deadline} milliseconds to start.`); | ||
} | ||
const url = new URL(rawPath, endpoint); | ||
if (rawQueryString) { | ||
url.search = new URLSearchParams(rawQueryString).toString(); | ||
} | ||
const decodedBody = isBase64Encoded && rawBody ? Buffer.from(rawBody, "base64") : rawBody; | ||
(0, log_1.log)("Proxying request", { url, method, rawHeaders, decodedBody, timeout }); | ||
let response = undefined; | ||
try { | ||
response = await axios_1.default.request({ | ||
method: method.toLowerCase(), | ||
url: url.toString(), | ||
headers: rawHeaders, | ||
data: decodedBody, | ||
timeout, | ||
responseType: "arraybuffer", | ||
}); | ||
} | ||
catch (e) { | ||
if ((0, axios_1.isAxiosError)(e) && e.response) { | ||
response = e.response; | ||
} | ||
else { | ||
throw e; | ||
} | ||
} | ||
if (!response) { | ||
throw new Error("No response received"); | ||
} | ||
const { data: rawData, headers: rawResponseHeaders } = response; | ||
(0, log_1.log)("Proxy request complete", { url, method, rawResponseHeaders, rawData }); | ||
return { | ||
requestId, | ||
payload: { | ||
statusCode: response.status, | ||
headers: convertHeaders(rawResponseHeaders), | ||
body: Buffer.from(rawData).toString("base64"), | ||
isBase64Encoded: true, | ||
}, | ||
}; | ||
}; | ||
exports.endpointProxy = endpointProxy; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1 @@ | ||
export declare const routeEvents: (runtimeApi: string, bin?: string, endpoint?: URL) => Promise<void>; | ||
//# sourceMappingURL=routing.d.ts.map |
Oops, something went wrong.