UNPKG

telefunc

Version:

Remote functions. Instead of API.

142 lines (141 loc) 5.25 kB
export { runTelefunc }; import { assert, objectAssign, isProduction } from '../utils.js'; import { loadTelefuncFiles } from './runTelefunc/loadTelefuncFiles.js'; import { parseHttpRequest } from './runTelefunc/parseHttpRequest.js'; // import { getEtag } from './runTelefunc/getEtag.js' import { executeTelefunction } from './runTelefunc/executeTelefunction.js'; import { serializeTelefunctionResult } from './runTelefunc/serializeTelefunctionResult.js'; import { handleError } from './runTelefunc/handleError.js'; import { callBugListeners } from './runTelefunc/onBug.js'; import { applyShield } from './runTelefunc/applyShield.js'; import { findTelefunction } from './runTelefunc/findTelefunction.js'; import { getServerConfig } from './serverConfig.js'; // HTTP Response for: // - `throw Abort()` const abortedRequestStatusCode = 403; // "Forbidden" // HTTP Response for: // - User's telefunction threw an error that isn't `Abort()` (i.e. the telefunction has a bug). // - The `.telefunc.js` file exports a non-function value. // - The Telefunc code threw an error (i.e. Telefunc has a bug). const serverError = { statusCode: 500, // "Internal Server Error" body: 'Internal Server Error', contentType: 'text/plain', etag: null, }; // HTTP Response for: // - Some non-telefunc client makes a malformed HTTP request. // - The telefunction couldn't be found. const invalidRequest = { statusCode: 400, // "Bad Request" body: 'Invalid Telefunc Request', contentType: 'text/plain', etag: null, }; async function runTelefunc(runContext) { try { return await runTelefunc_(runContext); } catch (err) { callBugListeners(err); handleError(err); return { err, ...serverError, }; } } async function runTelefunc_(httpRequest) { const runContext = {}; { // TODO: remove? Since `serverConfig` is global I don't think we need to set it to `runContext`, see for example https://github.com/brillout/telefunc/commit/5e3367d2d463b72e805e75ddfc68ef7f177a35c0 const serverConfig = getServerConfig(); objectAssign(runContext, { httpRequest, serverConfig: { disableNamingConvention: serverConfig.disableNamingConvention, telefuncUrl: serverConfig.telefuncUrl, log: serverConfig.log, }, appRootDir: serverConfig.root, telefuncFilesManuallyProvidedByUser: serverConfig.telefuncFiles, }); } { const logInvalidRequests = !isProduction(); /* || process.env.DEBUG.includes('telefunc') */ objectAssign(runContext, { logInvalidRequests }); } objectAssign(runContext, { providedContext: httpRequest.context || null, }); { const parsed = parseHttpRequest(runContext); if (parsed.isMalformed) { return invalidRequest; } const { telefunctionKey, telefunctionArgs, telefuncFilePath, telefunctionName } = parsed; objectAssign(runContext, { telefunctionKey, telefunctionArgs, telefuncFilePath, telefunctionName, }); } { const { telefuncFilesLoaded, telefuncFilesAll } = await loadTelefuncFiles(runContext); assert(telefuncFilesLoaded, 'No `.telefunc.js` file found'); objectAssign(runContext, { telefuncFilesLoaded, telefuncFilesAll }); } { const telefunction = await findTelefunction(runContext); if (!telefunction) { return invalidRequest; } objectAssign(runContext, { telefunction }); } { const { isValidRequest } = applyShield(runContext); objectAssign(runContext, { isValidRequest }); if (!isValidRequest) { objectAssign(runContext, { telefunctionAborted: true, telefunctionReturn: undefined, }); const httpResponseBody = serializeTelefunctionResult(runContext); return { statusCode: abortedRequestStatusCode, body: httpResponseBody, contentType: 'text/plain', etag: null, }; } } { assert(runContext.isValidRequest); const { telefunctionReturn, telefunctionAborted, telefunctionHasErrored, telefunctionError } = await executeTelefunction(runContext); objectAssign(runContext, { telefunctionReturn, telefunctionHasErrored, telefunctionAborted, telefunctionError, }); } if (runContext.telefunctionHasErrored) { throw runContext.telefunctionError; } { const httpResponseBody = serializeTelefunctionResult(runContext); objectAssign(runContext, { httpResponseBody }); } // { // const httpResponseEtag = await getEtag(runContext) // objectAssign(runContext, { httpResponseEtag }) // } return { statusCode: runContext.telefunctionAborted ? abortedRequestStatusCode : 200, body: runContext.httpResponseBody, contentType: 'text/plain', // etag: runContext.httpResponseEtag, etag: null, }; }