genezio
Version:
Command line utility to interact with Genezio infrastructure.
282 lines (254 loc) • 12 kB
JavaScript
/* eslint-disable no-useless-escape */
export const genezioRuntimeHandlerGenerator = (className) => `
/** This is an auto generated code. This code should not be modified since the file can be overwritten
* if new genezio commands are executed.
*/
import { ${className.replace(/["]/g, "")} as genezioClass } from "./module.mjs";
var handler = undefined;
const replacer = (key, value) =>
typeof value === "bigint" ? { $bigint: value.toString() } : value;
const reviver = (key, value) =>
value !== null &&
typeof value === "object" &&
"$bigint" in value &&
typeof value.$bigint === "string"
? BigInt(value.$bigint)
: value;
function prepareForSerialization(e) {
if (e instanceof Error) {
const object = { message: e.message, stack: e.stack, info: e.info, code: e.code }
return object;
}
console.error(\`Unsupported error type \${typeof e}\`)
return { message: "Unknown error occurred. Check logs for more information!" }
}
if (!genezioClass) {
console.error(
'Error! No class found with name ${className}. Make sure you exported it from your file.'
);
handler = async function (event) {
return {
statusCode: 500,
body: JSON.stringify({
jsonrpc: "2.0",
error: {
code: -1,
message:
'Error! No class found with name ${className}. Make sure you exported it from your file.',
},
id: 0,
}),
headers: { 'Content-Type': 'application/json', 'X-Powered-By': 'genezio','Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Methods': '*' }
};
};
} else {
const sendError = async function (err) {
// Not implemented
};
let object;
handler ??= async function (event) {
if (event.http && event.http.method === "OPTIONS") {
const response = {
statusCode: 200,
headers: { 'Content-Type': 'application/json', 'X-Powered-By': 'genezio', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Methods': '*' },
};
return response;
}
try {
object ??= new genezioClass();
} catch (error) {
handler = async function (event) {
await sendError(error);
return {
statusCode: 500,
body: JSON.stringify({
jsonrpc: "2.0",
error: {
code: -1,
message: \`Constructor call failure: \$\{error.message\}\`
},
id: 0,
}),
headers: { 'Content-Type': 'application/json', 'X-Powered-By': 'genezio','Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Methods': '*' }
};
};
}
let body = event.body;
let invalidBody = false;
try {
body = JSON.parse(event.body, reviver);
} catch (error) {
invalidBody = true;
}
if (!body || (body && body["jsonrpc"] !== "2.0")) {
// For raw http calls, paths should match \`/funcId/className/methodName\`
const components = event.http.path.substring(1).split("/");
if (!components[1]) {
return {
statusCode: 404,
headers: { 'Content-Type': 'application/json', 'X-Powered-By': 'genezio', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Methods': '*'},
body: JSON.stringify({ error: "Method not found" }),
};
}
const method = components[1];
const http2CompliantHeaders = {};
for (const header in event.headers) {
http2CompliantHeaders[header.toLowerCase()] = event.headers[header];
http2CompliantHeaders['Access-Control-Allow-Origin'.toLowerCase()] = '*';
http2CompliantHeaders['Access-Control-Allow-Headers'.toLowerCase()] = '*';
http2CompliantHeaders['Access-Control-Allow-Methods'.toLowerCase()] = '*';
}
const req = {
headers: http2CompliantHeaders,
http: event.http,
queryStringParameters: Object.fromEntries([...event.url.searchParams]),
timeEpoch: event.requestTimestampMs,
body: event.isBase64Encoded ? Buffer.from(body, "base64") : body,
rawBody: event.body,
};
if (!object[method]) {
return {
statusCode: 404,
headers: { "Content-Type": "text/json", 'X-Powered-By': 'genezio','Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Methods': '*' },
body: JSON.stringify({ error: "Method not found" }),
};
}
try {
const response = await object[method](req);
if (!response.statusCode) {
response.statusCode = 200;
}
if (response.body instanceof Buffer) {
response.body = response.body.toString("base64");
return {
...response,
isBase64Encoded: true,
};
} else if (response.body instanceof Object) {
try {
response.body = JSON.stringify(response.body, replacer);
} catch (error) { }
}
return response;
} catch (error) {
console.error(error);
return {
statusCode: 500,
body: JSON.stringify({ error: error.message }),
headers: { "Content-Type": "application/json", 'X-Powered-By': 'genezio','Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Methods': '*' },
};
}
} else {
if (invalidBody || !body || !body.method || !body.params || !Number.isInteger(body.id)) {
return {
statusCode: 500,
body: JSON.stringify({
jsonrpc: "2.0",
error: { code: -1, message: "Invalid JSON-RPC request" },
id: 0,
}),
headers: { 'Content-Type': 'application/json', 'X-Powered-By': 'genezio','Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Methods': '*' }
};
}
if (('Genezio-Event' in event.headers) && event.headers['Genezio-Event'] === 'cron') {
console.log(
"DEBUG: trigger cron: " + event.headers['Genezio-Cronstring'] + " on method: " + body.method
);
}
let method = null;
try {
const methodElems = body.method.split(".");
method = methodElems[1];
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify({
jsonrpc: "2.0",
error: { code: -1, message: "Invalid Genezio JSON-RPC request" },
id: 0,
}),
headers: { 'Content-Type': 'application/json', 'X-Powered-By': 'genezio','Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Methods': '*' }
};
}
if (!object[method]) {
return {
statusCode: 500,
body: JSON.stringify({
jsonrpc: "2.0",
error: { code: -1, message: "Method not found!" },
id: 0,
}),
headers: { 'Content-Type': 'application/json', 'X-Powered-By': 'genezio','Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Methods': '*' }
};
}
const requestId = body.id;
const errorPromise = new Promise((resolve) => {
process.removeAllListeners("uncaughtException");
process.on("uncaughtException", async function (err) {
console.error(err);
await sendError(err);
resolve({
statusCode: 500,
body: JSON.stringify({
jsonrpc: "2.0",
error: prepareForSerialization(err),
id: requestId,
}),
headers: { 'Content-Type': 'application/json', 'X-Powered-By': 'genezio','Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Methods': '*' }
});
});
});
if(body.params && body.params.length > 0 && body.params[0] && body.params[0].isGnzContext === true ) {
body.params[0].requestContext = {
http: event.http,
url: event.url,
};
body.params[0].headers = event.headers;
}
try {
const response = Promise.resolve(object[method](...(body.params || [])))
.then((result) => {
return {
statusCode: 200,
body: JSON.stringify({
jsonrpc: "2.0",
result: result,
error: null,
id: requestId,
}, replacer),
headers: { 'Content-Type': 'application/json', 'X-Powered-By': 'genezio','Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Methods': '*' }
};
})
.catch(async (err) => {
console.error(err);
await sendError(err);
return {
statusCode: 500,
body: JSON.stringify({
jsonrpc: "2.0",
error: prepareForSerialization(err),
id: requestId,
}),
headers: { 'Content-Type': 'application/json', 'X-Powered-By': 'genezio','Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Methods': '*' }
};
});
const result = await Promise.race([errorPromise, response]);
return result;
} catch (err) {
console.error(err);
await sendError(err);
return {
statusCode: 500,
body: JSON.stringify({
jsonrpc: "2.0",
error: prepareForSerialization(err),
id: requestId,
}),
headers: { 'Content-Type': 'application/json', 'X-Powered-By': 'genezio','Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': '*', 'Access-Control-Allow-Methods': '*' }
};
}
}
}
}
export { handler };
`;