mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-01-08 22:58:01 -05:00
feat(platform): centralize api calls in nextjs for token handling (#10222)
This PR helps to send all the React query requests through a Next.js server proxy. It works something like this: when a user sends a request, our custom mutator sends a request to the proxy server, where we add the auth token to the header and send it to the backend again. 🌐 Users can send a client-side request directly to the backend server because their browser does have access to auth tokens, so they need to go via the Next.js server. 🚀 ### Changes 🏗️ - Change the position of the generated client, mutator, and transfer inside `/src/app/api` - Update the mutator to send the request to the proxy server - Add a proxy server at `/api/proxy`, which handles the request using `makeAuthenticatedRequest` and `makeAuthenticatedFileUpload` helpers and sends the request to the backend - Remove `getSupabaseClient`, because we do not have access to the auth token on client side, hence no need 🔑 - Update Orval configs to generate the client at the new position - Added new backend updates to the auto-generated client. ### Checklist 📋 #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - [x] The setting page is using React Query and is working fine. - [x] The mutator is sending requests to the proxy server correctly. - [x] The proxy server is handling requests correctly. - [x] The response handling is correct in both the proxy server and the custom mutator.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -179,4 +179,4 @@ autogpt_platform/backend/settings.py
|
||||
.claude/settings.local.json
|
||||
|
||||
# Auto generated client
|
||||
autogpt_platform/frontend/src/api/__generated__
|
||||
autogpt_platform/frontend/src/app/api/__generated__
|
||||
|
||||
@@ -3,13 +3,13 @@ import { defineConfig } from "orval";
|
||||
export default defineConfig({
|
||||
autogpt_api_client: {
|
||||
input: {
|
||||
target: `./src/api/openapi.json`,
|
||||
target: `./src/app/api/openapi.json`,
|
||||
override: {
|
||||
transformer: "./src/api/transformers/fix-tags.mjs",
|
||||
transformer: "./src/app/api/transformers/fix-tags.mjs",
|
||||
},
|
||||
},
|
||||
output: {
|
||||
workspace: "./src/api",
|
||||
workspace: "./src/app/api",
|
||||
target: `./__generated__/endpoints`,
|
||||
schemas: "./__generated__/models",
|
||||
mode: "tags-split",
|
||||
@@ -39,13 +39,13 @@ export default defineConfig({
|
||||
},
|
||||
autogpt_zod_schema: {
|
||||
input: {
|
||||
target: `./src/api/openapi.json`,
|
||||
target: `./src/app/api/openapi.json`,
|
||||
override: {
|
||||
transformer: "./src/api/transformers/fix-tags.mjs",
|
||||
transformer: "./src/app/api/transformers/fix-tags.mjs",
|
||||
},
|
||||
},
|
||||
output: {
|
||||
workspace: "./src/api",
|
||||
workspace: "./src/app/api",
|
||||
target: `./__generated__/zod-schema`,
|
||||
schemas: "./__generated__/models",
|
||||
mode: "tags-split",
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
"storybook": "storybook dev -p 6006",
|
||||
"build-storybook": "storybook build",
|
||||
"test-storybook": "test-storybook",
|
||||
"fetch:openapi": "curl http://localhost:8006/openapi.json > ./src/api/openapi.json && prettier --write ./src/api/openapi.json",
|
||||
"test-storybook:ci": "concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"pnpm run build-storybook -- --quiet && npx http-server storybook-static --port 6006 --silent\" \"wait-on tcp:6006 && pnpm run test-storybook\"",
|
||||
"fetch:openapi": "curl http://localhost:8006/openapi.json > ./src/app/api/openapi.json && prettier --write ./src/app/api/openapi.json",
|
||||
"generate:api-client": "orval --config ./orval.config.ts",
|
||||
"generate:api-all": "pnpm run fetch:openapi && pnpm run generate:api-client"
|
||||
},
|
||||
|
||||
@@ -3,8 +3,8 @@ import {
|
||||
getGetV1ListUserApiKeysQueryKey,
|
||||
useDeleteV1RevokeApiKey,
|
||||
useGetV1ListUserApiKeys,
|
||||
} from "@/api/__generated__/endpoints/api-keys/api-keys";
|
||||
import { APIKeyWithoutHash } from "@/api/__generated__/models/aPIKeyWithoutHash";
|
||||
} from "@/app/api/__generated__/endpoints/api-keys/api-keys";
|
||||
import { APIKeyWithoutHash } from "@/app/api/__generated__/models/aPIKeyWithoutHash";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { getQueryClient } from "@/lib/react-query/queryClient";
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
import { useAPIkeysModals } from "./useAPIkeysModals";
|
||||
import { APIKeyPermission } from "@/api/__generated__/models/aPIKeyPermission";
|
||||
import { APIKeyPermission } from "@/app/api/__generated__/models/aPIKeyPermission";
|
||||
|
||||
export const APIKeysModals = () => {
|
||||
const {
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
import {
|
||||
getGetV1ListUserApiKeysQueryKey,
|
||||
usePostV1CreateNewApiKey,
|
||||
} from "@/api/__generated__/endpoints/api-keys/api-keys";
|
||||
import { APIKeyPermission } from "@/api/__generated__/models/aPIKeyPermission";
|
||||
import { CreateAPIKeyResponse } from "@/api/__generated__/models/createAPIKeyResponse";
|
||||
} from "@/app/api/__generated__/endpoints/api-keys/api-keys";
|
||||
import { APIKeyPermission } from "@/app/api/__generated__/models/aPIKeyPermission";
|
||||
import { CreateAPIKeyResponse } from "@/app/api/__generated__/models/createAPIKeyResponse";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { getQueryClient } from "@/lib/react-query/queryClient";
|
||||
import { useState } from "react";
|
||||
|
||||
@@ -6,7 +6,7 @@ import { NotificationPreferenceDTO } from "@/lib/autogpt-server-api/types";
|
||||
import {
|
||||
postV1UpdateNotificationPreferences,
|
||||
postV1UpdateUserEmail,
|
||||
} from "@/api/__generated__/endpoints/auth/auth";
|
||||
} from "@/app/api/__generated__/endpoints/auth/auth";
|
||||
|
||||
export async function updateSettings(formData: FormData) {
|
||||
const supabase = await getServerSupabase();
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { NotificationPreference } from "@/api/__generated__/models/notificationPreference";
|
||||
import { NotificationPreference } from "@/app/api/__generated__/models/notificationPreference";
|
||||
import { User } from "@supabase/supabase-js";
|
||||
import { useSettingsForm } from "./useSettingsForm";
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { z } from "zod";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { updateSettings } from "../../actions";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { NotificationPreference } from "@/api/__generated__/models/notificationPreference";
|
||||
import { NotificationPreference } from "@/app/api/__generated__/models/notificationPreference";
|
||||
import { User } from "@supabase/supabase-js";
|
||||
|
||||
export const useSettingsForm = ({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"use client";
|
||||
import { useGetV1GetNotificationPreferences } from "@/api/__generated__/endpoints/auth/auth";
|
||||
import { useGetV1GetNotificationPreferences } from "@/app/api/__generated__/endpoints/auth/auth";
|
||||
import { SettingsForm } from "@/app/(platform)/profile/(user)/settings/components/SettingsForm/SettingsForm";
|
||||
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
|
||||
import * as React from "react";
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import { getSupabaseClient } from "@/lib/supabase/getSupabaseClient";
|
||||
|
||||
const BASE_URL =
|
||||
process.env.NEXT_PUBLIC_AGPT_SERVER_BASE_URL || "http://localhost:8006";
|
||||
const BASE_URL = "/api/proxy"; // Sending request via nextjs Server
|
||||
|
||||
const getBody = <T>(c: Response | Request): Promise<T> => {
|
||||
const contentType = c.headers.get("content-type");
|
||||
@@ -17,18 +14,6 @@ const getBody = <T>(c: Response | Request): Promise<T> => {
|
||||
return c.text() as Promise<T>;
|
||||
};
|
||||
|
||||
const getSupabaseToken = async () => {
|
||||
const supabase = await getSupabaseClient();
|
||||
|
||||
const {
|
||||
data: { session },
|
||||
} = (await supabase?.auth.getSession()) || {
|
||||
data: { session: null },
|
||||
};
|
||||
|
||||
return session?.access_token;
|
||||
};
|
||||
|
||||
export const customMutator = async <T = any>(
|
||||
url: string,
|
||||
options: RequestInit & {
|
||||
@@ -47,12 +32,6 @@ export const customMutator = async <T = any>(
|
||||
...((requestOptions.headers as Record<string, string>) || {}),
|
||||
};
|
||||
|
||||
const token = await getSupabaseToken();
|
||||
|
||||
if (token) {
|
||||
headers["Authorization"] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
const isFormData = data instanceof FormData;
|
||||
|
||||
// Currently, only two content types are handled here: application/json and multipart/form-data
|
||||
@@ -186,14 +186,16 @@
|
||||
"oneOf": [
|
||||
{ "$ref": "#/components/schemas/OAuth2Credentials" },
|
||||
{ "$ref": "#/components/schemas/APIKeyCredentials" },
|
||||
{ "$ref": "#/components/schemas/UserPasswordCredentials" }
|
||||
{ "$ref": "#/components/schemas/UserPasswordCredentials" },
|
||||
{ "$ref": "#/components/schemas/HostScopedCredentials-Input" }
|
||||
],
|
||||
"discriminator": {
|
||||
"propertyName": "type",
|
||||
"mapping": {
|
||||
"oauth2": "#/components/schemas/OAuth2Credentials",
|
||||
"api_key": "#/components/schemas/APIKeyCredentials",
|
||||
"user_password": "#/components/schemas/UserPasswordCredentials"
|
||||
"user_password": "#/components/schemas/UserPasswordCredentials",
|
||||
"host_scoped": "#/components/schemas/HostScopedCredentials-Input"
|
||||
}
|
||||
},
|
||||
"title": "Credentials"
|
||||
@@ -210,14 +212,18 @@
|
||||
"oneOf": [
|
||||
{ "$ref": "#/components/schemas/OAuth2Credentials" },
|
||||
{ "$ref": "#/components/schemas/APIKeyCredentials" },
|
||||
{ "$ref": "#/components/schemas/UserPasswordCredentials" }
|
||||
{ "$ref": "#/components/schemas/UserPasswordCredentials" },
|
||||
{
|
||||
"$ref": "#/components/schemas/HostScopedCredentials-Output"
|
||||
}
|
||||
],
|
||||
"discriminator": {
|
||||
"propertyName": "type",
|
||||
"mapping": {
|
||||
"oauth2": "#/components/schemas/OAuth2Credentials",
|
||||
"api_key": "#/components/schemas/APIKeyCredentials",
|
||||
"user_password": "#/components/schemas/UserPasswordCredentials"
|
||||
"user_password": "#/components/schemas/UserPasswordCredentials",
|
||||
"host_scoped": "#/components/schemas/HostScopedCredentials-Output"
|
||||
}
|
||||
},
|
||||
"title": "Response Postv1Createcredentials"
|
||||
@@ -270,14 +276,18 @@
|
||||
"oneOf": [
|
||||
{ "$ref": "#/components/schemas/OAuth2Credentials" },
|
||||
{ "$ref": "#/components/schemas/APIKeyCredentials" },
|
||||
{ "$ref": "#/components/schemas/UserPasswordCredentials" }
|
||||
{ "$ref": "#/components/schemas/UserPasswordCredentials" },
|
||||
{
|
||||
"$ref": "#/components/schemas/HostScopedCredentials-Output"
|
||||
}
|
||||
],
|
||||
"discriminator": {
|
||||
"propertyName": "type",
|
||||
"mapping": {
|
||||
"oauth2": "#/components/schemas/OAuth2Credentials",
|
||||
"api_key": "#/components/schemas/APIKeyCredentials",
|
||||
"user_password": "#/components/schemas/UserPasswordCredentials"
|
||||
"user_password": "#/components/schemas/UserPasswordCredentials",
|
||||
"host_scoped": "#/components/schemas/HostScopedCredentials-Output"
|
||||
}
|
||||
},
|
||||
"title": "Response Getv1Getcredential"
|
||||
@@ -434,9 +444,7 @@
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Body_postV1LogRawMetric"
|
||||
}
|
||||
"schema": { "$ref": "#/components/schemas/LogRawMetricRequest" }
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
@@ -3797,16 +3805,6 @@
|
||||
"required": ["type", "data", "data_index"],
|
||||
"title": "Body_postV1LogRawAnalytics"
|
||||
},
|
||||
"Body_postV1LogRawMetric": {
|
||||
"properties": {
|
||||
"metric_name": { "type": "string", "title": "Metric Name" },
|
||||
"metric_value": { "type": "number", "title": "Metric Value" },
|
||||
"data_string": { "type": "string", "title": "Data String" }
|
||||
},
|
||||
"type": "object",
|
||||
"required": ["metric_name", "metric_value", "data_string"],
|
||||
"title": "Body_postV1LogRawMetric"
|
||||
},
|
||||
"Body_postV2Add_credits_to_user": {
|
||||
"properties": {
|
||||
"user_id": { "type": "string", "title": "User Id" },
|
||||
@@ -4019,7 +4017,7 @@
|
||||
"provider": { "$ref": "#/components/schemas/ProviderName" },
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["api_key", "oauth2", "user_password"],
|
||||
"enum": ["api_key", "oauth2", "user_password", "host_scoped"],
|
||||
"title": "Type"
|
||||
}
|
||||
},
|
||||
@@ -4035,7 +4033,7 @@
|
||||
"provider": { "type": "string", "title": "Provider" },
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["api_key", "oauth2", "user_password"],
|
||||
"enum": ["api_key", "oauth2", "user_password", "host_scoped"],
|
||||
"title": "Type"
|
||||
},
|
||||
"title": {
|
||||
@@ -4052,6 +4050,11 @@
|
||||
"username": {
|
||||
"anyOf": [{ "type": "string" }, { "type": "null" }],
|
||||
"title": "Username"
|
||||
},
|
||||
"host": {
|
||||
"anyOf": [{ "type": "string" }, { "type": "null" }],
|
||||
"title": "Host",
|
||||
"description": "Host pattern for host-scoped credentials"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
@@ -4393,6 +4396,70 @@
|
||||
"type": "object",
|
||||
"title": "HTTPValidationError"
|
||||
},
|
||||
"HostScopedCredentials-Input": {
|
||||
"properties": {
|
||||
"id": { "type": "string", "title": "Id" },
|
||||
"provider": { "type": "string", "title": "Provider" },
|
||||
"title": {
|
||||
"anyOf": [{ "type": "string" }, { "type": "null" }],
|
||||
"title": "Title"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "host_scoped",
|
||||
"title": "Type",
|
||||
"default": "host_scoped"
|
||||
},
|
||||
"host": {
|
||||
"type": "string",
|
||||
"title": "Host",
|
||||
"description": "The host/URI pattern to match against request URLs"
|
||||
},
|
||||
"headers": {
|
||||
"additionalProperties": {
|
||||
"type": "string",
|
||||
"format": "password",
|
||||
"writeOnly": true
|
||||
},
|
||||
"type": "object",
|
||||
"title": "Headers",
|
||||
"description": "Key-value header map to add to matching requests"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": ["provider", "host"],
|
||||
"title": "HostScopedCredentials"
|
||||
},
|
||||
"HostScopedCredentials-Output": {
|
||||
"properties": {
|
||||
"id": { "type": "string", "title": "Id" },
|
||||
"provider": { "type": "string", "title": "Provider" },
|
||||
"title": {
|
||||
"anyOf": [{ "type": "string" }, { "type": "null" }],
|
||||
"title": "Title"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "host_scoped",
|
||||
"title": "Type",
|
||||
"default": "host_scoped"
|
||||
},
|
||||
"host": {
|
||||
"type": "string",
|
||||
"title": "Host",
|
||||
"description": "The host/URI pattern to match against request URLs"
|
||||
},
|
||||
"headers": {
|
||||
"additionalProperties": { "type": "string" },
|
||||
"type": "object",
|
||||
"title": "Headers",
|
||||
"description": "Key-value header map to add to matching requests"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": ["provider", "host"],
|
||||
"title": "HostScopedCredentials"
|
||||
},
|
||||
"LibraryAgent": {
|
||||
"properties": {
|
||||
"id": { "type": "string", "title": "Id" },
|
||||
@@ -4712,6 +4779,24 @@
|
||||
"required": ["source_id", "sink_id", "source_name", "sink_name"],
|
||||
"title": "Link"
|
||||
},
|
||||
"LogRawMetricRequest": {
|
||||
"properties": {
|
||||
"metric_name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"title": "Metric Name"
|
||||
},
|
||||
"metric_value": { "type": "number", "title": "Metric Value" },
|
||||
"data_string": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"title": "Data String"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": ["metric_name", "metric_value", "data_string"],
|
||||
"title": "LogRawMetricRequest"
|
||||
},
|
||||
"LoginResponse": {
|
||||
"properties": {
|
||||
"login_url": { "type": "string", "title": "Login Url" },
|
||||
@@ -5459,6 +5544,7 @@
|
||||
"google",
|
||||
"google_maps",
|
||||
"groq",
|
||||
"http",
|
||||
"hubspot",
|
||||
"ideogram",
|
||||
"jina",
|
||||
153
autogpt_platform/frontend/src/app/api/proxy/[...path]/route.ts
Normal file
153
autogpt_platform/frontend/src/app/api/proxy/[...path]/route.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import {
|
||||
makeAuthenticatedRequest,
|
||||
makeAuthenticatedFileUpload,
|
||||
} from "@/lib/autogpt-server-api/helpers";
|
||||
|
||||
const BACKEND_BASE_URL =
|
||||
process.env.NEXT_PUBLIC_AGPT_SERVER_BASE_URL || "http://localhost:8006";
|
||||
|
||||
function buildBackendUrl(path: string[], queryString: string): string {
|
||||
const backendPath = path.join("/");
|
||||
return `${BACKEND_BASE_URL}/${backendPath}${queryString}`;
|
||||
}
|
||||
|
||||
async function handleJsonRequest(
|
||||
req: NextRequest,
|
||||
method: string,
|
||||
backendUrl: string,
|
||||
): Promise<any> {
|
||||
const payload = await req.json();
|
||||
return await makeAuthenticatedRequest(
|
||||
method,
|
||||
backendUrl,
|
||||
payload,
|
||||
"application/json",
|
||||
);
|
||||
}
|
||||
|
||||
async function handleFormDataRequest(
|
||||
req: NextRequest,
|
||||
backendUrl: string,
|
||||
): Promise<any> {
|
||||
const formData = await req.formData();
|
||||
return await makeAuthenticatedFileUpload(backendUrl, formData);
|
||||
}
|
||||
|
||||
async function handleUrlEncodedRequest(
|
||||
req: NextRequest,
|
||||
method: string,
|
||||
backendUrl: string,
|
||||
): Promise<any> {
|
||||
const textPayload = await req.text();
|
||||
const params = new URLSearchParams(textPayload);
|
||||
const payload = Object.fromEntries(params.entries());
|
||||
return await makeAuthenticatedRequest(
|
||||
method,
|
||||
backendUrl,
|
||||
payload,
|
||||
"application/x-www-form-urlencoded",
|
||||
);
|
||||
}
|
||||
|
||||
async function handleRequestWithoutBody(
|
||||
method: string,
|
||||
backendUrl: string,
|
||||
): Promise<any> {
|
||||
return await makeAuthenticatedRequest(method, backendUrl);
|
||||
}
|
||||
|
||||
function createUnsupportedContentTypeResponse(
|
||||
contentType: string | null,
|
||||
): NextResponse {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error:
|
||||
"Unsupported Content-Type for proxying with authentication helpers.",
|
||||
receivedContentType: contentType,
|
||||
supportedContentTypes: [
|
||||
"application/json",
|
||||
"multipart/form-data",
|
||||
"application/x-www-form-urlencoded",
|
||||
],
|
||||
},
|
||||
{ status: 415 }, // Unsupported Media Type
|
||||
);
|
||||
}
|
||||
|
||||
function createResponse(
|
||||
responseBody: any,
|
||||
responseStatus: number,
|
||||
responseHeaders: Record<string, string>,
|
||||
): NextResponse {
|
||||
if (responseStatus === 204) {
|
||||
return new NextResponse(null, { status: responseStatus });
|
||||
} else {
|
||||
return NextResponse.json(responseBody, {
|
||||
status: responseStatus,
|
||||
headers: responseHeaders,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function createErrorResponse(error: unknown): NextResponse {
|
||||
console.error("API proxy error:", error);
|
||||
const detail =
|
||||
error instanceof Error ? error.message : "An unknown error occurred";
|
||||
return NextResponse.json(
|
||||
{ error: "Proxy request failed", detail },
|
||||
{ status: 500 }, // Internal Server Error
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple proxy route that forwards requests to the backend API.
|
||||
* It injects the server-side authentication token into the Authorization header.
|
||||
* It uses the makeAuthenticatedRequest and makeAuthenticatedFileUpload helpers
|
||||
* to handle request body parsing and authentication.
|
||||
*/
|
||||
async function handler(
|
||||
req: NextRequest,
|
||||
{ params }: { params: Promise<{ path: string[] }> },
|
||||
) {
|
||||
const { path } = await params;
|
||||
const url = new URL(req.url);
|
||||
const queryString = url.search;
|
||||
const backendUrl = buildBackendUrl(path, queryString);
|
||||
|
||||
const method = req.method;
|
||||
const contentType = req.headers.get("Content-Type");
|
||||
|
||||
let responseBody: any;
|
||||
const responseStatus: number = 200;
|
||||
const responseHeaders: Record<string, string> = {
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
|
||||
try {
|
||||
if (method === "GET" || method === "DELETE") {
|
||||
responseBody = await handleRequestWithoutBody(method, backendUrl);
|
||||
} else if (contentType?.includes("application/json")) {
|
||||
responseBody = await handleJsonRequest(req, method, backendUrl);
|
||||
} else if (contentType?.includes("multipart/form-data")) {
|
||||
responseBody = await handleFormDataRequest(req, backendUrl);
|
||||
responseHeaders["Content-Type"] = "text/plain";
|
||||
} else if (contentType?.includes("application/x-www-form-urlencoded")) {
|
||||
responseBody = await handleUrlEncodedRequest(req, method, backendUrl);
|
||||
} else {
|
||||
return createUnsupportedContentTypeResponse(contentType);
|
||||
}
|
||||
|
||||
return createResponse(responseBody, responseStatus, responseHeaders);
|
||||
} catch (error) {
|
||||
return createErrorResponse(error);
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
handler as GET,
|
||||
handler as POST,
|
||||
handler as PUT,
|
||||
handler as PATCH,
|
||||
handler as DELETE,
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
import { getServerSupabase } from "@/lib/supabase/server/getServerSupabase";
|
||||
import { createBrowserClient } from "@supabase/ssr";
|
||||
|
||||
const isClient = typeof window !== "undefined";
|
||||
|
||||
export const getSupabaseClient = async () => {
|
||||
return isClient
|
||||
? createBrowserClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
{ isSingleton: true },
|
||||
)
|
||||
: await getServerSupabase();
|
||||
};
|
||||
Reference in New Issue
Block a user