telefunc
Version:
Remote functions. Instead of API.
94 lines (93 loc) • 4.7 kB
JavaScript
export { makeHttpRequest };
import { parse } from '@brillout/json-serializer/parse';
import { assert, assertUsage, isObject, objectAssign } from '../utils.js';
import { callOnAbortListeners } from './onAbort.js';
import { STATUS_CODE_THROW_ABORT, STATUS_CODE_INTERNAL_SERVER_ERROR, STATUS_BODY_INTERNAL_SERVER_ERROR, STATUS_CODE_MALFORMED_REQUEST, STATUS_BODY_MALFORMED_REQUEST, STATUS_CODE_SHIELD_VALIDATION_ERROR, STATUS_BODY_SHIELD_VALIDATION_ERROR, STATUS_CODE_SUCCESS, } from '../../shared/constants.js';
const method = 'POST';
async function makeHttpRequest(callContext) {
var _a;
let response;
try {
const fetch = (_a = callContext.fetch) !== null && _a !== void 0 ? _a : window.fetch;
response = await fetch(callContext.telefuncUrl, {
method,
body: callContext.httpRequestBody,
credentials: 'same-origin',
headers: {
...callContext.httpHeaders,
'Content-Type': 'text/plain',
},
});
}
catch (_) {
const telefunctionCallError = new Error('No Server Connection');
objectAssign(telefunctionCallError, { isConnectionError: true });
throw telefunctionCallError;
}
const statusCode = response.status;
if (statusCode === STATUS_CODE_SUCCESS) {
const { ret } = await parseResponseBody(response, callContext);
const telefunctionReturn = ret;
return { telefunctionReturn };
}
else if (statusCode === STATUS_CODE_THROW_ABORT) {
const { ret } = await parseResponseBody(response, callContext);
const abortValue = ret;
const telefunctionCallError = new Error(`Aborted telefunction call ${callContext.telefunctionName}() (${callContext.telefuncFilePath}).`);
objectAssign(telefunctionCallError, { isAbort: true, abortValue });
callOnAbortListeners(telefunctionCallError);
throw telefunctionCallError;
}
else if (statusCode === STATUS_CODE_INTERNAL_SERVER_ERROR) {
const errMsg = await getErrMsg(STATUS_BODY_INTERNAL_SERVER_ERROR, response, callContext);
throw new Error(errMsg);
}
else if (statusCode === STATUS_CODE_SHIELD_VALIDATION_ERROR) {
const errMsg = await getErrMsg(STATUS_BODY_SHIELD_VALIDATION_ERROR, response, callContext, ' (if enabled: https://telefunc.com/log)');
throw new Error(errMsg);
}
else if (statusCode === STATUS_CODE_MALFORMED_REQUEST) {
const responseBody = await response.text();
assertUsage(responseBody === STATUS_BODY_MALFORMED_REQUEST, wrongInstallation({ method, callContext }));
/* With Next.js 12: when renaming a `.telefunc.js` file the client makes a request with the new `.telefunc.js` name while the server is still serving the old `.telefunc.js` name. Seems like a race condition: trying again seems to fix the error.
// This should never happen as the Telefunc Client shouldn't make invalid requests
assert(false)
*/
assertUsage(false, 'Try again. You may need to reload the page. (The client and server are/was out-of-sync.)');
}
else {
assertUsage(statusCode !== 404, wrongInstallation({
reason: 'a 404 HTTP response',
method,
isNotInstalled: true,
callContext,
}));
assertUsage(false, wrongInstallation({
reason: `a status code \`${statusCode}\` which Telefunc never returns`,
method,
callContext,
}));
}
}
async function parseResponseBody(response, callContext) {
const responseBody = await response.text();
const responseBodyParsed = parse(responseBody);
assertUsage(isObject(responseBodyParsed) && 'ret' in responseBodyParsed, wrongInstallation({ method, callContext }));
assert(response.status !== STATUS_CODE_THROW_ABORT || 'abort' in responseBodyParsed);
const { ret } = responseBodyParsed;
return { ret };
}
function wrongInstallation({ reason = 'an HTTP response body that Telefunc never generates', callContext, method, isNotInstalled, }) {
let msg = [`Telefunc doesn't seem to be `];
if (!isNotInstalled)
msg.push('(properly) ');
msg.push('installed on your server');
msg.push(...[`: the HTTP ${method} \`${callContext.telefuncUrl}\` request returned `, reason]);
msg.push(`, see https://telefunc.com/install`);
return msg.join('');
}
async function getErrMsg(errMsg, response, callContext, errMsgAddendum = '') {
const responseBody = await response.text();
assertUsage(responseBody === errMsg, wrongInstallation({ method, callContext }));
return `${errMsg} — see server logs${errMsgAddendum}`;
}