UNPKG

@fal-ai/serverless-proxy

Version:

Deprecation note: this library has been deprecated in favor of @fal-ai/server-proxy

107 lines 3.96 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.resolveApiKeyFromEnv = exports.responsePassthrough = exports.DEFAULT_PROXY_ROUTE = exports.TARGET_URL_HEADER = void 0; exports.handleRequest = handleRequest; exports.fromHeaders = fromHeaders; exports.TARGET_URL_HEADER = "x-fal-target-url"; exports.DEFAULT_PROXY_ROUTE = "/api/fal/proxy"; const FAL_KEY = process.env.FAL_KEY; const FAL_KEY_ID = process.env.FAL_KEY_ID; const FAL_KEY_SECRET = process.env.FAL_KEY_SECRET; const FAL_URL_REG_EXP = /(\.|^)fal\.(run|ai)$/; /** * Utility to get a header value as `string` from a Headers object. * * @private * @param request the header value. * @returns the header value as `string` or `undefined` if the header is not set. */ function singleHeaderValue(value) { if (!value) { return undefined; } if (Array.isArray(value)) { return value[0]; } return value; } function getFalKey() { if (FAL_KEY) { return FAL_KEY; } if (FAL_KEY_ID && FAL_KEY_SECRET) { return `${FAL_KEY_ID}:${FAL_KEY_SECRET}`; } return undefined; } const EXCLUDED_HEADERS = ["content-length", "content-encoding"]; /** * A request handler that proxies the request to the fal-serverless * endpoint. This is useful so client-side calls to the fal-serverless endpoint * can be made without CORS issues and the correct credentials can be added * effortlessly. * * @param behavior the request proxy behavior. * @returns Promise<any> the promise that will be resolved once the request is done. */ async function handleRequest(behavior) { const targetUrl = singleHeaderValue(behavior.getHeader(exports.TARGET_URL_HEADER)); if (!targetUrl) { return behavior.respondWith(400, `Missing the ${exports.TARGET_URL_HEADER} header`); } const urlHost = new URL(targetUrl).host; if (!FAL_URL_REG_EXP.test(urlHost)) { return behavior.respondWith(412, `Invalid ${exports.TARGET_URL_HEADER} header`); } const falKey = behavior.resolveApiKey ? await behavior.resolveApiKey() : getFalKey(); if (!falKey) { return behavior.respondWith(401, "Missing fal.ai credentials"); } // pass over headers prefixed with x-fal-* const headers = {}; Object.keys(behavior.getHeaders()).forEach((key) => { if (key.toLowerCase().startsWith("x-fal-")) { headers[key.toLowerCase()] = behavior.getHeader(key); } }); const proxyUserAgent = `@fal-ai/serverless-proxy/${behavior.id}`; const userAgent = singleHeaderValue(behavior.getHeader("user-agent")); const res = await fetch(targetUrl, { method: behavior.method, headers: { ...headers, authorization: singleHeaderValue(behavior.getHeader("authorization")) ?? `Key ${falKey}`, accept: "application/json", "content-type": "application/json", "user-agent": userAgent, "x-fal-client-proxy": proxyUserAgent, }, body: behavior.method?.toUpperCase() === "GET" ? undefined : await behavior.getRequestBody(), }); // copy headers from fal to the proxied response res.headers.forEach((value, key) => { if (!EXCLUDED_HEADERS.includes(key.toLowerCase())) { behavior.sendHeader(key, value); } }); return behavior.sendResponse(res); } function fromHeaders(headers) { // TODO once Header.entries() is available, use that instead // Object.fromEntries(headers.entries()); const result = {}; headers.forEach((value, key) => { result[key] = value; }); return result; } const responsePassthrough = (res) => Promise.resolve(res); exports.responsePassthrough = responsePassthrough; const resolveApiKeyFromEnv = () => Promise.resolve(getFalKey()); exports.resolveApiKeyFromEnv = resolveApiKeyFromEnv; //# sourceMappingURL=index.js.map