fix: proxy error json response (#16)
* chore: remove deprecated package * fix: proxy error json response
This commit is contained in:
parent
dcd513c1e7
commit
e02118f43f
@ -1,3 +0,0 @@
|
||||
{
|
||||
"presets": [["@nx/js/babel", { "useBuiltIns": "usage" }]]
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
{
|
||||
"extends": ["../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
# @fal-ai/serverless-nextjs
|
||||
|
||||
This package is not longer maintained. Check out the [@fal-ai/serverless-proxy](../proxy/)package, which supports Next.js and other Express-based frameworks.
|
||||
@ -1,17 +0,0 @@
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'nextjs',
|
||||
preset: '../../jest.preset.js',
|
||||
globals: {},
|
||||
testEnvironment: 'node',
|
||||
transform: {
|
||||
'^.+\\.[tj]sx?$': [
|
||||
'ts-jest',
|
||||
{
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
},
|
||||
],
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage/libs/nextjs',
|
||||
};
|
||||
@ -1,32 +0,0 @@
|
||||
{
|
||||
"name": "@fal-ai/serverless-nextjs",
|
||||
"description": "The fal-serverless Next.js integration",
|
||||
"version": "0.2.4",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fal-ai/serverless-js.git",
|
||||
"directory": "libs/nextjs"
|
||||
},
|
||||
"keywords": [
|
||||
"fal",
|
||||
"serverless",
|
||||
"client",
|
||||
"next",
|
||||
"nextjs",
|
||||
"proxy"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"next": "^13.0.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
{
|
||||
"name": "nextjs",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "libs/nextjs/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/js:tsc",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"outputPath": "dist/libs/nextjs",
|
||||
"tsConfig": "libs/nextjs/tsconfig.lib.json",
|
||||
"packageJson": "libs/nextjs/package.json",
|
||||
"main": "libs/nextjs/src/index.ts",
|
||||
"assets": ["LICENSE", "CODE_OF_CONDUCT.md", "libs/nextjs/README.md"]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["libs/nextjs/**/*.ts"]
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nx/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"jestConfig": "libs/nextjs/jest.config.ts",
|
||||
"passWithNoTests": true
|
||||
},
|
||||
"configurations": {
|
||||
"ci": {
|
||||
"ci": true,
|
||||
"codeCoverage": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": []
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
import type { RequestMiddleware } from '@fal-ai/serverless-client';
|
||||
|
||||
export type NextProxyConfig = {
|
||||
targetUrl: string;
|
||||
};
|
||||
|
||||
const defaultConfig: NextProxyConfig = {
|
||||
targetUrl: '/api/_fal/proxy',
|
||||
};
|
||||
|
||||
export const TARGET_URL_HEADER = 'x-fal-target-url';
|
||||
|
||||
export function withNextProxy(
|
||||
config: NextProxyConfig = defaultConfig
|
||||
): RequestMiddleware {
|
||||
// when running on the server, we don't need to proxy the request
|
||||
if (typeof window === 'undefined') {
|
||||
return (requestConfig) => Promise.resolve(requestConfig);
|
||||
}
|
||||
return (requestConfig) =>
|
||||
Promise.resolve({
|
||||
...requestConfig,
|
||||
url: config.targetUrl,
|
||||
headers: {
|
||||
[TARGET_URL_HEADER]: requestConfig.url,
|
||||
...(requestConfig.headers || {}),
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -1,113 +0,0 @@
|
||||
import type { NextApiHandler, NextApiRequest, PageConfig } from 'next';
|
||||
import { TARGET_URL_HEADER } from './config';
|
||||
|
||||
const FAL_KEY = process.env.FAL_KEY || process.env.NEXT_PUBLIC_FAL_KEY;
|
||||
const FAL_KEY_ID = process.env.FAL_KEY_ID || process.env.NEXT_PUBLIC_FAL_KEY_ID;
|
||||
const FAL_KEY_SECRET =
|
||||
process.env.FAL_KEY_SECRET || process.env.NEXT_PUBLIC_FAL_KEY_SECRET;
|
||||
|
||||
/**
|
||||
* Utility to get a header value as `string` from a Headers object.
|
||||
*
|
||||
* @private
|
||||
* @param request the Next request object.
|
||||
* @param key the header key.
|
||||
* @returns the header value as `string` or `undefined` if the header is not set.
|
||||
*/
|
||||
function getHeader(request: NextApiRequest, key: string): string | undefined {
|
||||
const headerValue = request.headers[key.toLowerCase()];
|
||||
if (Array.isArray(headerValue)) {
|
||||
return headerValue[0];
|
||||
}
|
||||
return headerValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up headers that should not be forwarded to the proxy.
|
||||
* @param request the Next request object.
|
||||
*/
|
||||
function cleanUpHeaders(request: NextApiRequest) {
|
||||
delete request.headers['origin'];
|
||||
delete request.headers['referer'];
|
||||
delete request.headers[TARGET_URL_HEADER];
|
||||
}
|
||||
|
||||
function getFalKey(): string | undefined {
|
||||
if (FAL_KEY) {
|
||||
return FAL_KEY;
|
||||
}
|
||||
if (FAL_KEY_ID && FAL_KEY_SECRET) {
|
||||
return `${FAL_KEY_ID}:${FAL_KEY_SECRET}`;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Next 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 request the Next request object.
|
||||
* @param response the Next response object.
|
||||
* @returns Promise<any> the promise that will be resolved once the request is done.
|
||||
*/
|
||||
export const handler: NextApiHandler = async (request, response) => {
|
||||
const targetUrl = getHeader(request, TARGET_URL_HEADER);
|
||||
if (!targetUrl) {
|
||||
response.status(400).send(`Missing the ${TARGET_URL_HEADER} header`);
|
||||
return;
|
||||
}
|
||||
if (targetUrl.indexOf('fal.ai') === -1) {
|
||||
response.status(412).send(`Invalid ${TARGET_URL_HEADER} header`);
|
||||
return;
|
||||
}
|
||||
|
||||
cleanUpHeaders(request);
|
||||
|
||||
const falKey = getFalKey();
|
||||
if (!falKey) {
|
||||
response.status(401).send('Missing fal.ai credentials');
|
||||
return;
|
||||
}
|
||||
|
||||
// pass over headers prefixed with x-fal-*
|
||||
const headers: Record<string, string | string[] | undefined> = {};
|
||||
Object.keys(request.headers).forEach((key) => {
|
||||
if (key.toLowerCase().startsWith('x-fal-')) {
|
||||
headers[key.toLowerCase()] = request.headers[key];
|
||||
}
|
||||
});
|
||||
|
||||
const res = await fetch(targetUrl, {
|
||||
method: request.method,
|
||||
headers: {
|
||||
...headers,
|
||||
authorization: getHeader(request, 'authorization') ?? `Key ${falKey}`,
|
||||
accept: 'application/json',
|
||||
'content-type': 'application/json',
|
||||
'x-fal-client-proxy': '@fal-ai/serverless-nextjs',
|
||||
},
|
||||
body:
|
||||
request.method?.toUpperCase() === 'GET'
|
||||
? undefined
|
||||
: JSON.stringify(request.body),
|
||||
});
|
||||
|
||||
// copy headers from res to response
|
||||
res.headers.forEach((value, key) => {
|
||||
response.setHeader(key, value);
|
||||
});
|
||||
|
||||
if (res.headers.get('content-type') === 'application/json') {
|
||||
const data = await res.json();
|
||||
response.status(res.status).json(data);
|
||||
return;
|
||||
}
|
||||
const data = await res.text();
|
||||
response.status(res.status).send(data);
|
||||
};
|
||||
|
||||
export const config: PageConfig = {
|
||||
api: {},
|
||||
};
|
||||
@ -1,2 +0,0 @@
|
||||
export * from './config';
|
||||
export * from './handler';
|
||||
@ -1,13 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"include": [
|
||||
"jest.config.ts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.tsx",
|
||||
"src/**/*.spec.tsx",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.jsx",
|
||||
"src/**/*.spec.jsx",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@fal-ai/serverless-proxy",
|
||||
"version": "0.3.3",
|
||||
"version": "0.3.4",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@ -19,11 +19,10 @@ export const handler: RequestHandler = async (request, response, next) => {
|
||||
method: request.method,
|
||||
respondWith: (status, data) =>
|
||||
typeof data === 'string'
|
||||
? response.status(status).send(data)
|
||||
? response.status(status).json({ details: data })
|
||||
: response.status(status).json(data),
|
||||
getHeaders: () => request.headers,
|
||||
getHeader: (name) => request.headers[name],
|
||||
removeHeader: (name) => response.removeHeader(name),
|
||||
sendHeader: (name, value) => response.setHeader(name, value),
|
||||
getBody: () => JSON.stringify(request.body),
|
||||
});
|
||||
|
||||
@ -18,7 +18,6 @@ export interface ProxyBehavior {
|
||||
respondWith(status: number, data: string | any): void;
|
||||
getHeaders(): Record<string, string | string[] | undefined>;
|
||||
getHeader(name: string): string | string[] | undefined;
|
||||
removeHeader(name: string): void;
|
||||
sendHeader(name: string, value: string): void;
|
||||
getBody(): string | undefined;
|
||||
}
|
||||
@ -42,16 +41,6 @@ function singleHeaderValue(
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up headers that should not be forwarded to the proxy.
|
||||
* @param behavior The proxy implementation.
|
||||
*/
|
||||
function cleanUpHeaders(behavior: ProxyBehavior) {
|
||||
behavior.removeHeader('origin');
|
||||
behavior.removeHeader('referer');
|
||||
behavior.removeHeader(TARGET_URL_HEADER);
|
||||
}
|
||||
|
||||
function getFalKey(): string | undefined {
|
||||
if (FAL_KEY) {
|
||||
return FAL_KEY;
|
||||
@ -82,8 +71,6 @@ export const handleRequest = async (behavior: ProxyBehavior) => {
|
||||
return;
|
||||
}
|
||||
|
||||
cleanUpHeaders(behavior);
|
||||
|
||||
const falKey = getFalKey();
|
||||
if (!falKey) {
|
||||
behavior.respondWith(401, 'Missing fal.ai credentials');
|
||||
@ -118,7 +105,7 @@ export const handleRequest = async (behavior: ProxyBehavior) => {
|
||||
behavior.sendHeader(key, value);
|
||||
});
|
||||
|
||||
if (res.headers.get('content-type') === 'application/json') {
|
||||
if (res.headers.get('content-type').includes('application/json')) {
|
||||
const data = await res.json();
|
||||
behavior.respondWith(res.status, data);
|
||||
return;
|
||||
|
||||
@ -19,11 +19,10 @@ export const handler: NextApiHandler = async (request, response) => {
|
||||
method: request.method,
|
||||
respondWith: (status, data) =>
|
||||
typeof data === 'string'
|
||||
? response.status(status).send(data)
|
||||
? response.status(status).json({ details: data })
|
||||
: response.status(status).json(data),
|
||||
getHeaders: () => request.headers,
|
||||
getHeader: (name) => request.headers[name],
|
||||
removeHeader: (name) => response.removeHeader(name),
|
||||
sendHeader: (name, value) => response.setHeader(name, value),
|
||||
getBody: () => JSON.stringify(request.body),
|
||||
});
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@fal-ai/serverless-client": ["libs/client/src/index.ts"],
|
||||
"@fal-ai/serverless-nextjs": ["libs/nextjs/src/index.ts"],
|
||||
"@fal-ai/serverless-proxy": ["libs/proxy/src/index.ts"],
|
||||
"@fal-ai/serverless-proxy/express": ["libs/proxy/src/express.ts"],
|
||||
"@fal-ai/serverless-proxy/nextjs": ["libs/proxy/src/nextjs.ts"]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user