Skip to content

Commit

Permalink
update project structure
Browse files Browse the repository at this point in the history
  • Loading branch information
cnuss committed Jun 1, 2024
1 parent 7a77674 commit 053bcf9
Show file tree
Hide file tree
Showing 43 changed files with 406 additions and 38 deletions.
4 changes: 2 additions & 2 deletions cli/index.ts → cli/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { log } from "../src/log";
import { log } from "../src/internal/log";
import packageJson from "../package.json";
import { bootstrap } from "../src/bootstrap";
import { bootstrap } from "../src/internal/bootstrap";

(async () => {
if (process.argv.includes("--version")) {
Expand Down
2 changes: 1 addition & 1 deletion dist/495.main.js → dist/495.bootstrap.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/495.bootstrap.js.map

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/495.main.js.map

This file was deleted.

4 changes: 2 additions & 2 deletions dist/main.js → dist/bootstrap.js

Large diffs are not rendered by default.

File renamed without changes.
1 change: 1 addition & 0 deletions dist/cli/bootstrap.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {};
28 changes: 28 additions & 0 deletions dist/cli/bootstrap.js
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");
})();
2 changes: 0 additions & 2 deletions dist/cli/index.d.ts

This file was deleted.

1 change: 0 additions & 1 deletion dist/cli/index.d.ts.map

This file was deleted.

50 changes: 50 additions & 0 deletions dist/package.json
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"
}
}
1 change: 0 additions & 1 deletion dist/src/bootstrap.d.ts.map

This file was deleted.

7 changes: 3 additions & 4 deletions dist/src/index.d.ts
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
1 change: 0 additions & 1 deletion dist/src/index.d.ts.map

This file was deleted.

9 changes: 9 additions & 0 deletions dist/src/index.js
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; } });
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export declare const bootstrap: () => Promise<void>;
//# sourceMappingURL=bootstrap.d.ts.map
29 changes: 29 additions & 0 deletions dist/src/internal/bootstrap.js
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;
1 change: 0 additions & 1 deletion dist/src/log.d.ts → dist/src/internal/log.d.ts
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
17 changes: 17 additions & 0 deletions dist/src/internal/log.js
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;
1 change: 0 additions & 1 deletion dist/src/proxy.d.ts → dist/src/internal/proxy.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,3 @@ export declare const endpointSpawn: (handler: string, offline: boolean) => Promi
}>;
export declare const endpointExec: ({ requestId, bin, event, deadline, }: EndpointExecRequest) => Promise<EndpointResponse>;
export declare const endpointProxy: ({ requestId, endpoint, event, deadline, }: EndpointProxyRequest) => Promise<EndpointResponse>;
//# sourceMappingURL=proxy.d.ts.map
169 changes: 169 additions & 0 deletions dist/src/internal/proxy.js
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;
1 change: 0 additions & 1 deletion dist/src/routing.d.ts → dist/src/internal/routing.d.ts
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
Loading

0 comments on commit 053bcf9

Please sign in to comment.