chore: caching optimisations in sync endpoints (#2111)

Co-authored-by: Johannes <72809645+jobenjada@users.noreply.github.com>
This commit is contained in:
Matti Nannt
2024-02-22 19:18:06 +01:00
committed by GitHub
parent 312858e278
commit 186feefdb5
66 changed files with 494 additions and 625 deletions
+2 -3
View File
@@ -29,7 +29,6 @@ export default function AppPage({}) {
environmentId: process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID,
apiHost: process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST,
userId,
debug: true,
attributes,
});
window.formbricks = formbricks;
@@ -105,8 +104,8 @@ export default function AppPage({}) {
Reset person / pull data from Formbricks app
</h3>
<p className="text-slate-700 dark:text-slate-300">
On formbricks.reset() a few things happen: <strong>New person is created</strong> and{" "}
<strong>surveys & no-code actions are pulled from Formbricks:</strong>.
On formbricks.reset() the local state will <strong>be deleted</strong> and formbricks gets{" "}
<strong>reinitialized</strong>.
</p>
<button
className="my-4 rounded-lg bg-slate-500 px-6 py-3 text-white hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600"
@@ -45,8 +45,7 @@ Adds an Actions for a given User by their User ID
curl --location --request POST 'https://app.formbricks.com/api/v1/client/<environment-id>/actions' \
--data-raw '{
"userId": "1",
"name": "new_action_v2",
"properties":{}
"name": "new_action_v2"
}'
```
@@ -54,8 +53,7 @@ Adds an Actions for a given User by their User ID
```json {{ title: 'Example Request Body' }}
{
"userId": "1",
"name": "new_action_v3",
"properties":{}
"name": "new_action_v3"
}
```
+1 -2
View File
@@ -1,6 +1,5 @@
import { responses } from "@/app/lib/api/response";
import { headers } from "next/headers";
import { NextResponse } from "next/server";
import { ProductFeatureKeys } from "@formbricks/ee/billing/lib/constants";
import { reportUsageToStripe } from "@formbricks/ee/billing/lib/reportUsage";
@@ -52,7 +51,7 @@ async function reportTeamUsage(team: TTeam) {
}
}
export async function POST(): Promise<NextResponse> {
export async function POST(): Promise<Response> {
const headersList = headers();
const apiKey = headersList.get("x-api-key");
@@ -1,6 +1,5 @@
import { responses } from "@/app/lib/api/response";
import { headers } from "next/headers";
import { NextResponse } from "next/server";
import { prisma } from "@formbricks/database";
import { CRON_SECRET } from "@formbricks/lib/constants";
@@ -10,7 +9,7 @@ import { EnvironmentData, NotificationResponse, ProductData, Survey, SurveyRespo
const BATCH_SIZE = 500;
export async function POST(): Promise<NextResponse> {
export async function POST(): Promise<Response> {
// Check authentication
if (headers().get("x-api-key") !== CRON_SECRET) {
return responses.notAuthenticatedResponse();
@@ -1,6 +1,5 @@
import { responses } from "@/app/lib/api/response";
import { google } from "googleapis";
import { NextRequest, NextResponse } from "next/server";
import {
GOOGLE_SHEETS_CLIENT_ID,
@@ -10,7 +9,7 @@ import {
} from "@formbricks/lib/constants";
import { createOrUpdateIntegration } from "@formbricks/lib/integration/service";
export async function GET(req: NextRequest) {
export async function GET(req: Request) {
const url = req.url;
const queryParams = new URLSearchParams(url.split("?")[1]); // Split the URL and get the query parameters
const environmentId = queryParams.get("state"); // Get the value of the 'state' parameter
@@ -66,6 +65,6 @@ export async function GET(req: NextRequest) {
const result = await createOrUpdateIntegration(environmentId, googleSheetIntegration);
if (result) {
return NextResponse.redirect(`${WEBAPP_URL}/environments/${environmentId}/integrations/google-sheets`);
return Response.redirect(`${WEBAPP_URL}/environments/${environmentId}/integrations/google-sheets`);
}
}
@@ -1,7 +1,7 @@
import { responses } from "@/app/lib/api/response";
import { AsyncParser } from "@json2csv/node";
import { getServerSession } from "next-auth";
import { NextRequest, NextResponse } from "next/server";
import { NextRequest } from "next/server";
import { authOptions } from "@formbricks/lib/authOptions";
@@ -40,7 +40,7 @@ export async function POST(request: NextRequest) {
`attachment; filename="${fallbackFileName}"; filename*=UTF-8''${encodedFileName}`
);
return NextResponse.json(
return Response.json(
{
fileResponse: csv,
},
@@ -1,6 +1,6 @@
import { responses } from "@/app/lib/api/response";
import { getServerSession } from "next-auth";
import { NextRequest, NextResponse } from "next/server";
import { NextRequest } from "next/server";
import * as xlsx from "xlsx";
import { authOptions } from "@formbricks/lib/authOptions";
@@ -36,7 +36,7 @@ export async function POST(request: NextRequest) {
`attachment; filename="${fallbackFileName}"; filename*=UTF-8''${encodedFileName}`
);
return NextResponse.json(
return Response.json(
{
fileResponse: base64String,
},
+1 -2
View File
@@ -1,7 +1,6 @@
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { headers } from "next/headers";
import { NextResponse } from "next/server";
import { prisma } from "@formbricks/database";
import { INTERNAL_SECRET } from "@formbricks/lib/constants";
@@ -185,5 +184,5 @@ export async function POST(request: Request) {
await updateSurveyStatus(surveyId);
}
return NextResponse.json({ data: {} });
return Response.json({ data: {} });
}
@@ -1,6 +1,5 @@
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { getActionClasses } from "@formbricks/lib/actionClass/service";
import { createAttributeClass, getAttributeClassByName } from "@formbricks/lib/attributeClass/service";
@@ -18,11 +17,11 @@ interface Context {
};
}
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function POST(req: Request, context: Context): Promise<NextResponse> {
export async function POST(req: Request, context: Context): Promise<Response> {
try {
const { userId, environmentId } = context.params;
const personId = userId; // legacy workaround for formbricks-js 1.2.0 & 1.2.1
@@ -1,13 +1,12 @@
import { responses } from "@/app/lib/api/response";
import { NextResponse } from "next/server";
import { markDisplayRespondedLegacy } from "@formbricks/lib/display/service";
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function POST(_: Request, { params }: { params: { displayId: string } }): Promise<NextResponse> {
export async function POST(_: Request, { params }: { params: { displayId: string } }): Promise<Response> {
const { displayId } = params;
if (!displayId) {
@@ -1,18 +1,17 @@
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { updateDisplayLegacy } from "@formbricks/lib/display/service";
import { ZDisplayLegacyUpdateInput } from "@formbricks/types/displays";
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function PUT(
request: Request,
{ params }: { params: { displayId: string } }
): Promise<NextResponse> {
): Promise<Response> {
const { displayId } = params;
if (!displayId) {
return responses.badRequestResponse("Missing displayId", undefined, true);
@@ -1,6 +1,5 @@
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { createDisplayLegacy } from "@formbricks/lib/display/service";
import { capturePosthogEnvironmentEvent } from "@formbricks/lib/posthogServer";
@@ -8,11 +7,11 @@ import { getSurvey } from "@formbricks/lib/survey/service";
import { TDisplay, ZDisplayLegacyCreateInput } from "@formbricks/types/displays";
import { InvalidInputError } from "@formbricks/types/errors";
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function POST(request: Request): Promise<NextResponse> {
export async function POST(request: Request): Promise<Response> {
const jsonInput = await request.json();
if (jsonInput.personId === "legacy") {
delete jsonInput.personId;
@@ -1,6 +1,5 @@
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { getActionClasses } from "@formbricks/lib/actionClass/service";
import { createAttributeClass, getAttributeClassByName } from "@formbricks/lib/attributeClass/service";
@@ -18,11 +17,11 @@ interface Context {
};
}
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function POST(req: Request, context: Context): Promise<NextResponse> {
export async function POST(req: Request, context: Context): Promise<Response> {
try {
const { personId, environmentId } = context.params;
const jsonInput = await req.json();
@@ -1,21 +1,20 @@
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { sendToPipeline } from "@/app/lib/pipelines";
import { NextResponse } from "next/server";
import { updateResponse } from "@formbricks/lib/response/service";
import { getSurvey } from "@formbricks/lib/survey/service";
import { DatabaseError, InvalidInputError, ResourceNotFoundError } from "@formbricks/types/errors";
import { ZResponseUpdateInput } from "@formbricks/types/responses";
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function PUT(
request: Request,
{ params }: { params: { responseId: string } }
): Promise<NextResponse> {
): Promise<Response> {
const { responseId } = params;
if (!responseId) {
@@ -2,7 +2,6 @@ import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { sendToPipeline } from "@/app/lib/pipelines";
import { headers } from "next/headers";
import { NextResponse } from "next/server";
import { UAParser } from "ua-parser-js";
import { capturePosthogEnvironmentEvent } from "@formbricks/lib/posthogServer";
@@ -12,11 +11,11 @@ import { InvalidInputError } from "@formbricks/types/errors";
import { TResponse, ZResponseLegacyInput } from "@formbricks/types/responses";
import { TSurvey } from "@formbricks/types/surveys";
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function POST(request: Request): Promise<NextResponse> {
export async function POST(request: Request): Promise<Response> {
const responseInput = await request.json();
if (responseInput.personId === "legacy") {
responseInput.personId = null;
@@ -1,10 +1,9 @@
import { responses } from "@/app/lib/api/response";
import { NextResponse } from "next/server";
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function POST(): Promise<NextResponse> {
export async function POST(): Promise<Response> {
return responses.successResponse({}, true);
}
@@ -1,7 +1,6 @@
import { getUpdatedState } from "@/app/api/v1/(legacy)/js/sync/lib/sync";
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { createAttributeClass, getAttributeClassByName } from "@formbricks/lib/attributeClass/service";
import { personCache } from "@formbricks/lib/person/cache";
@@ -10,11 +9,11 @@ import { surveyCache } from "@formbricks/lib/survey/cache";
import { ZJsPeopleLegacyAttributeInput } from "@formbricks/types/js";
import { TPersonClient } from "@formbricks/types/people";
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function POST(req: Request, { params }): Promise<NextResponse> {
export async function POST(req: Request, { params }): Promise<Response> {
try {
const { personId } = params;
@@ -1,16 +1,15 @@
import { getUpdatedState } from "@/app/api/v1/(legacy)/js/sync/lib/sync";
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { createPerson, getPersonByUserId } from "@formbricks/lib/person/service";
import { ZJsPeopleUserIdInput } from "@formbricks/types/js";
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function POST(req: Request): Promise<NextResponse> {
export async function POST(req: Request): Promise<Response> {
try {
const jsonInput = await req.json();
@@ -1,16 +1,15 @@
import { getUpdatedState } from "@/app/api/v1/(legacy)/js/sync/lib/sync";
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { ZJsSyncLegacyInput } from "@formbricks/types/js";
import { TPersonClient } from "@formbricks/types/people";
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function POST(req: Request): Promise<NextResponse> {
export async function POST(req: Request): Promise<Response> {
try {
const jsonInput = await req.json();
+1 -2
View File
@@ -1,5 +1,4 @@
import { responses } from "@/app/lib/api/response";
import { NextResponse } from "next/server";
import { getApiKeyFromKey } from "@formbricks/lib/apiKey/service";
import { TAuthenticationApiKey } from "@formbricks/types/auth";
@@ -21,7 +20,7 @@ export async function authenticateRequest(request: Request): Promise<TAuthentica
return null;
}
export function handleErrorResponse(error: any): NextResponse {
export function handleErrorResponse(error: any): Response {
switch (error.message) {
case "NotAuthenticated":
return responses.notAuthenticatedResponse();
@@ -1,6 +1,5 @@
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { createAction } from "@formbricks/lib/action/service";
import { ZActionInput } from "@formbricks/types/actions";
@@ -11,11 +10,11 @@ interface Context {
};
}
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function POST(req: Request, context: Context): Promise<NextResponse> {
export async function POST(req: Request, context: Context): Promise<Response> {
try {
const jsonInput = await req.json();
@@ -1,6 +1,5 @@
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { updateDisplay } from "@formbricks/lib/display/service";
import { ZDisplayUpdateInput } from "@formbricks/types/displays";
@@ -12,11 +11,11 @@ interface Context {
};
}
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function PUT(request: Request, context: Context): Promise<NextResponse> {
export async function PUT(request: Request, context: Context): Promise<Response> {
const { displayId, environmentId } = context.params;
const jsonInput = await request.json();
const inputValidation = ZDisplayUpdateInput.safeParse({
@@ -1,6 +1,5 @@
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { createDisplay } from "@formbricks/lib/display/service";
import { capturePosthogEnvironmentEvent } from "@formbricks/lib/posthogServer";
@@ -13,11 +12,11 @@ interface Context {
};
}
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function POST(request: Request, context: Context): Promise<NextResponse> {
export async function POST(request: Request, context: Context): Promise<Response> {
const jsonInput = await request.json();
const inputValidation = ZDisplayCreateInput.safeParse({
...jsonInput,
@@ -1,7 +1,7 @@
import { sendFreeLimitReachedEventToPosthogBiWeekly } from "@/app/api/v1/client/[environmentId]/in-app/sync/lib/posthog";
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextRequest, NextResponse, userAgent } from "next/server";
import { NextRequest, userAgent } from "next/server";
import { getLatestActionByPersonId } from "@formbricks/lib/action/service";
import { getActionClasses } from "@formbricks/lib/actionClass/service";
@@ -22,7 +22,7 @@ import {
import { TEnvironment } from "@formbricks/types/environment";
import { TJsStateSync, ZJsPeopleUserIdInput } from "@formbricks/types/js";
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
@@ -36,7 +36,7 @@ export async function GET(
userId: string;
};
}
): Promise<NextResponse> {
): Promise<Response> {
try {
const { device } = userAgent(request);
const apiVersion = request.nextUrl.searchParams.get("version");
@@ -103,12 +103,20 @@ export async function GET(
const errorMessage = `Monthly Active Users limit in the current plan is reached in ${environmentId}`;
if (!person) {
// if it's a new person and MAU limit is reached, throw an error
throw new Error(errorMessage);
return responses.tooManyRequestsResponse(
errorMessage,
true,
"public, s-maxage=600, max-age=840, stale-while-revalidate=600, stale-if-error=600"
);
} else {
// check if person has been active this month
const latestAction = await getLatestActionByPersonId(person.id);
if (!latestAction || new Date(latestAction.createdAt).getMonth() !== new Date().getMonth()) {
throw new Error(errorMessage);
return responses.tooManyRequestsResponse(
errorMessage,
true,
"public, s-maxage=600, max-age=840, stale-while-revalidate=600, stale-if-error=600"
);
}
}
}
@@ -136,7 +144,11 @@ export async function GET(
product,
};
return responses.successResponse({ ...state }, true);
return responses.successResponse(
{ ...state },
true,
"public, s-maxage=100, max-age=110, stale-while-revalidate=100, stale-if-error=100"
);
} catch (error) {
console.error(error);
return responses.internalServerErrorResponse("Unable to handle the request: " + error.message, true);
@@ -1,7 +1,7 @@
import { sendFreeLimitReachedEventToPosthogBiWeekly } from "@/app/api/v1/client/[environmentId]/in-app/sync/lib/posthog";
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextRequest, NextResponse } from "next/server";
import { NextRequest } from "next/server";
import { getActionClasses } from "@formbricks/lib/actionClass/service";
import { IS_FORMBRICKS_CLOUD, PRICING_APPSURVEYS_FREE_RESPONSES } from "@formbricks/lib/constants";
@@ -11,14 +11,14 @@ import { getSurveys } from "@formbricks/lib/survey/service";
import { getMonthlyTeamResponseCount, getTeamByEnvironmentId } from "@formbricks/lib/team/service";
import { TJsStateSync, ZJsPublicSyncInput } from "@formbricks/types/js";
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function GET(
_: NextRequest,
{ params }: { params: { environmentId: string } }
): Promise<NextResponse> {
): Promise<Response> {
try {
// validate using zod
const environmentIdValidation = ZJsPublicSyncInput.safeParse({
@@ -1,6 +1,5 @@
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { createPerson, getPersonByUserId, updatePerson } from "@formbricks/lib/person/service";
import { ZPersonUpdateInput } from "@formbricks/types/people";
@@ -12,11 +11,11 @@ interface Context {
};
}
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function POST(req: Request, context: Context): Promise<NextResponse> {
export async function POST(req: Request, context: Context): Promise<Response> {
try {
const { userId, environmentId } = context.params;
const jsonInput = await req.json();
@@ -40,9 +39,35 @@ export async function POST(req: Request, context: Context): Promise<NextResponse
person = await createPerson(environmentId, userId);
}
// Check if the person is already up to date
const updatedAtttributes = inputValidation.data.attributes;
const oldAttributes = person.attributes;
let isUpToDate = true;
for (const key in updatedAtttributes) {
if (updatedAtttributes[key] !== oldAttributes[key]) {
isUpToDate = false;
break;
}
}
if (isUpToDate) {
return responses.successResponse(
{
changed: false,
message: "No updates were necessary; the person is already up to date.",
},
true
);
}
await updatePerson(person.id, inputValidation.data);
return responses.successResponse({}, true);
return responses.successResponse(
{
changed: true,
message: "The person was successfully updated.",
},
true
);
} catch (error) {
console.error(error);
return responses.internalServerErrorResponse(`Unable to complete request: ${error.message}`, true);
@@ -1,7 +1,6 @@
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { sendToPipeline } from "@/app/lib/pipelines";
import { NextResponse } from "next/server";
import { getPerson } from "@formbricks/lib/person/service";
import { updateResponse } from "@formbricks/lib/response/service";
@@ -9,14 +8,14 @@ import { getSurvey } from "@formbricks/lib/survey/service";
import { DatabaseError, InvalidInputError, ResourceNotFoundError } from "@formbricks/types/errors";
import { ZResponseUpdateInput } from "@formbricks/types/responses";
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function PUT(
request: Request,
{ params }: { params: { responseId: string } }
): Promise<NextResponse> {
): Promise<Response> {
const { responseId } = params;
if (!responseId) {
@@ -2,7 +2,6 @@ import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { sendToPipeline } from "@/app/lib/pipelines";
import { headers } from "next/headers";
import { NextResponse } from "next/server";
import { UAParser } from "ua-parser-js";
import { getPerson } from "@formbricks/lib/person/service";
@@ -19,11 +18,11 @@ interface Context {
};
}
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
export async function POST(request: Request, context: Context): Promise<NextResponse> {
export async function POST(request: Request, context: Context): Promise<Response> {
const { environmentId } = context.params;
const environmentIdValidation = ZId.safeParse(environmentId);
@@ -3,7 +3,7 @@
// method -> PUT (to be the same as the signedUrl method)
import { responses } from "@/app/lib/api/response";
import { headers } from "next/headers";
import { NextRequest, NextResponse } from "next/server";
import { NextRequest } from "next/server";
import { UPLOADS_DIR } from "@formbricks/lib/constants";
import { validateLocalSignedUrl } from "@formbricks/lib/crypto";
@@ -18,8 +18,8 @@ interface Context {
};
}
export async function OPTIONS(): Promise<NextResponse> {
return NextResponse.json(
export async function OPTIONS(): Promise<Response> {
return Response.json(
{},
{
headers: {
@@ -32,7 +32,7 @@ export async function OPTIONS(): Promise<NextResponse> {
);
}
export async function POST(req: NextRequest, context: Context): Promise<NextResponse> {
export async function POST(req: NextRequest, context: Context): Promise<Response> {
const environmentId = context.params.environmentId;
const accessType = "private"; // private files are accessible only by authorized users
@@ -1,5 +1,5 @@
import { responses } from "@/app/lib/api/response";
import { NextRequest, NextResponse } from "next/server";
import { NextRequest } from "next/server";
import { getSurvey } from "@formbricks/lib/survey/service";
import { getTeamByEnvironmentId } from "@formbricks/lib/team/service";
@@ -12,7 +12,7 @@ interface Context {
};
}
export async function OPTIONS(): Promise<NextResponse> {
export async function OPTIONS(): Promise<Response> {
return responses.successResponse({}, true);
}
@@ -22,7 +22,7 @@ export async function OPTIONS(): Promise<NextResponse> {
// use this to let users upload files to a survey for example
// this api endpoint will return a signed url for uploading the file to s3 and another url for uploading file to the local storage
export async function POST(req: NextRequest, context: Context): Promise<NextResponse> {
export async function POST(req: NextRequest, context: Context): Promise<Response> {
const environmentId = context.params.environmentId;
const { fileName, fileType, surveyId } = await req.json();
@@ -1,6 +1,6 @@
import { responses } from "@/app/lib/api/response";
import { getServerSession } from "next-auth";
import { NextRequest, NextResponse } from "next/server";
import { NextRequest } from "next/server";
import * as z from "zod";
import { connectAirtable, fetchAirtableAuthToken } from "@formbricks/lib/airtable/service";
@@ -70,7 +70,7 @@ export async function GET(req: NextRequest) {
email,
key,
});
return NextResponse.redirect(`${WEBAPP_URL}/environments/${environmentId}/integrations/airtable`);
return Response.redirect(`${WEBAPP_URL}/environments/${environmentId}/integrations/airtable`);
} catch (error) {
console.error(error);
responses.internalServerErrorResponse(error);
@@ -1,5 +1,5 @@
import { responses } from "@/app/lib/api/response";
import { NextRequest, NextResponse } from "next/server";
import { NextRequest } from "next/server";
import {
ENCRYPTION_KEY,
@@ -66,10 +66,10 @@ export async function GET(req: NextRequest) {
const result = await createOrUpdateIntegration(environmentId, notionIntegration);
if (result) {
return NextResponse.redirect(`${WEBAPP_URL}/environments/${environmentId}/integrations/notion`);
return Response.redirect(`${WEBAPP_URL}/environments/${environmentId}/integrations/notion`);
}
} else if (error) {
return NextResponse.redirect(
return Response.redirect(
`${WEBAPP_URL}/environments/${environmentId}/integrations/notion?error=${error}`
);
}
@@ -1,8 +1,6 @@
import { authenticateRequest } from "@/app/api/v1/auth";
import { handleErrorResponse } from "@/app/api/v1/auth";
import { authenticateRequest, handleErrorResponse } from "@/app/api/v1/auth";
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { deleteActionClass, getActionClass, updateActionClass } from "@formbricks/lib/actionClass/service";
import { TActionClass, ZActionClassInput } from "@formbricks/types/actionClasses";
@@ -25,7 +23,7 @@ async function fetchAndAuthorizeActionClass(
export async function GET(
request: Request,
{ params }: { params: { actionClassId: string } }
): Promise<NextResponse> {
): Promise<Response> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
@@ -42,7 +40,7 @@ export async function GET(
export async function PUT(
request: Request,
{ params }: { params: { actionClassId: string } }
): Promise<NextResponse> {
): Promise<Response> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
@@ -75,7 +73,7 @@ export async function PUT(
export async function DELETE(
request: Request,
{ params }: { params: { actionClassId: string } }
): Promise<NextResponse> {
): Promise<Response> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
@@ -1,7 +1,6 @@
import { authenticateRequest } from "@/app/api/v1/auth";
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { createActionClass, getActionClasses } from "@formbricks/lib/actionClass/service";
import { TActionClass, ZActionClassInput } from "@formbricks/types/actionClasses";
@@ -21,7 +20,7 @@ export async function GET(request: Request) {
}
}
export async function POST(request: Request): Promise<NextResponse> {
export async function POST(request: Request): Promise<Response> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
@@ -1,8 +1,6 @@
import { handleErrorResponse } from "@/app/api/v1/auth";
import { authenticateRequest } from "@/app/api/v1/auth";
import { authenticateRequest, handleErrorResponse } from "@/app/api/v1/auth";
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import {
deleteAttributeClass,
@@ -29,7 +27,7 @@ async function fetchAndAuthorizeAttributeClass(
export async function GET(
request: Request,
{ params }: { params: { attributeClassId: string } }
): Promise<NextResponse> {
): Promise<Response> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
@@ -46,7 +44,7 @@ export async function GET(
export async function DELETE(
request: Request,
{ params }: { params: { attributeClassId: string } }
): Promise<NextResponse> {
): Promise<Response> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
@@ -67,7 +65,7 @@ export async function DELETE(
export async function PUT(
request: Request,
{ params }: { params: { attributeClassId: string } }
): Promise<NextResponse> {
): Promise<Response> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
@@ -1,7 +1,6 @@
import { authenticateRequest } from "@/app/api/v1/auth";
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { createAttributeClass, getAttributeClasses } from "@formbricks/lib/attributeClass/service";
import { TAttributeClass, ZAttributeClassInput } from "@formbricks/types/attributeClasses";
@@ -21,7 +20,7 @@ export async function GET(request: Request) {
}
}
export async function POST(request: Request): Promise<NextResponse> {
export async function POST(request: Request): Promise<Response> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
+2 -3
View File
@@ -1,6 +1,5 @@
import { getSessionUser, hashApiKey } from "@/app/lib/api/apiHelper";
import { headers } from "next/headers";
import { NextResponse } from "next/server";
import { prisma } from "@formbricks/database";
@@ -35,7 +34,7 @@ export async function GET() {
status: 401,
});
}
return NextResponse.json(apiKeyData.environment);
return Response.json(apiKeyData.environment);
} else {
const sessionUser = await getSessionUser();
if (!sessionUser) {
@@ -50,6 +49,6 @@ export async function GET() {
},
});
return NextResponse.json(user);
return Response.json(user);
}
}
@@ -1,11 +1,12 @@
import { authenticateRequest, handleErrorResponse } from "@/app/api/v1/auth";
import { responses } from "@/app/lib/api/response";
import { NextResponse } from "next/server";
import { deletePerson, getPerson } from "@formbricks/lib/person/service";
import { TAuthenticationApiKey } from "@formbricks/types/auth";
import { TPerson } from "@formbricks/types/people";
// Please use the methods provided by the client API to update a person
async function fetchAndAuthorizePerson(
authentication: TAuthenticationApiKey,
personId: string
@@ -20,10 +21,7 @@ async function fetchAndAuthorizePerson(
return person;
}
export async function GET(
request: Request,
{ params }: { params: { personId: string } }
): Promise<NextResponse> {
export async function GET(request: Request, { params }: { params: { personId: string } }): Promise<Response> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
@@ -37,31 +35,6 @@ export async function GET(
}
}
// Please use the methods provided by the client API to update a person
/* export async function PUT(
request: Request,
{ params }: { params: { personId: string } }
): Promise<NextResponse> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
await fetchAndAuthorizePerson(authentication, params.personId);
const personUpdate = await request.json();
const inputValidation = ZPersonUpdateInput.safeParse(personUpdate);
if (!inputValidation.success) {
return responses.badRequestResponse(
"Fields are missing or incorrectly formatted",
transformErrorToDetails(inputValidation.error)
);
}
return responses.successResponse(await updatePerson(params.personId, inputValidation.data));
} catch (error) {
return handleErrorResponse(error);
}
} */
export async function DELETE(request: Request, { params }: { params: { personId: string } }) {
try {
const authentication = await authenticateRequest(request);
@@ -20,17 +20,3 @@ export async function GET(request: Request) {
}
// Please use the client API to create a new person
/* export async function POST(request: Request): Promise<NextResponse> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
const person: TPerson = await createPerson(authentication.environmentId);
return responses.successResponse(person);
} catch (error) {
if (error instanceof DatabaseError) {
return responses.badRequestResponse(error.message);
}
throw error;
}
} */
@@ -1,8 +1,6 @@
import { authenticateRequest } from "@/app/api/v1/auth";
import { handleErrorResponse } from "@/app/api/v1/auth";
import { authenticateRequest, handleErrorResponse } from "@/app/api/v1/auth";
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { hasUserEnvironmentAccess } from "@formbricks/lib/environment/auth";
import { deleteResponse, getResponse, updateResponse } from "@formbricks/lib/response/service";
@@ -33,7 +31,7 @@ const canUserAccessResponse = async (authentication: any, response: TResponse):
export async function GET(
request: Request,
{ params }: { params: { responseId: string } }
): Promise<NextResponse> {
): Promise<Response> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
@@ -51,7 +49,7 @@ export async function GET(
export async function DELETE(
request: Request,
{ params }: { params: { responseId: string } }
): Promise<NextResponse> {
): Promise<Response> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
@@ -69,7 +67,7 @@ export async function DELETE(
export async function PUT(
request: Request,
{ params }: { params: { responseId: string } }
): Promise<NextResponse> {
): Promise<Response> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
@@ -4,7 +4,7 @@
import { responses } from "@/app/lib/api/response";
import { getServerSession } from "next-auth";
import { headers } from "next/headers";
import { NextRequest, NextResponse } from "next/server";
import { NextRequest } from "next/server";
import { authOptions } from "@formbricks/lib/authOptions";
import { UPLOADS_DIR } from "@formbricks/lib/constants";
@@ -13,7 +13,7 @@ import { env } from "@formbricks/lib/env.mjs";
import { hasUserEnvironmentAccess } from "@formbricks/lib/environment/auth";
import { putFileToLocalStorage } from "@formbricks/lib/storage/service";
export async function POST(req: NextRequest): Promise<NextResponse> {
export async function POST(req: NextRequest): Promise<Response> {
const accessType = "public"; // public files are accessible by anyone
const headersList = headers();
@@ -1,6 +1,6 @@
import { responses } from "@/app/lib/api/response";
import { getServerSession } from "next-auth";
import { NextRequest, NextResponse } from "next/server";
import { NextRequest } from "next/server";
import { authOptions } from "@formbricks/lib/authOptions";
import { hasUserEnvironmentAccess } from "@formbricks/lib/environment/auth";
@@ -13,7 +13,7 @@ import getSignedUrlForPublicFile from "./lib/getSignedUrl";
// use this to upload files for a specific resource, e.g. a user profile picture or a survey
// this api endpoint will return a signed url for uploading the file to s3 and another url for uploading file to the local storage
export async function POST(req: NextRequest): Promise<NextResponse> {
export async function POST(req: NextRequest): Promise<Response> {
const { fileName, fileType, environmentId, allowedFileExtensions } = await req.json();
if (!fileName) {
@@ -1,8 +1,6 @@
import { authenticateRequest } from "@/app/api/v1/auth";
import { handleErrorResponse } from "@/app/api/v1/auth";
import { authenticateRequest, handleErrorResponse } from "@/app/api/v1/auth";
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { deleteSurvey, getSurvey, updateSurvey } from "@formbricks/lib/survey/service";
import { TSurvey, ZSurvey } from "@formbricks/types/surveys";
@@ -18,10 +16,7 @@ async function fetchAndAuthorizeSurvey(authentication: any, surveyId: string): P
return survey;
}
export async function GET(
request: Request,
{ params }: { params: { surveyId: string } }
): Promise<NextResponse> {
export async function GET(request: Request, { params }: { params: { surveyId: string } }): Promise<Response> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
@@ -38,7 +33,7 @@ export async function GET(
export async function DELETE(
request: Request,
{ params }: { params: { surveyId: string } }
): Promise<NextResponse> {
): Promise<Response> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
@@ -53,10 +48,7 @@ export async function DELETE(
}
}
export async function PUT(
request: Request,
{ params }: { params: { surveyId: string } }
): Promise<NextResponse> {
export async function PUT(request: Request, { params }: { params: { surveyId: string } }): Promise<Response> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
@@ -1,7 +1,6 @@
import { authenticateRequest } from "@/app/api/v1/auth";
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { NextResponse } from "next/server";
import { createSurvey, getSurveys } from "@formbricks/lib/survey/service";
import { DatabaseError } from "@formbricks/types/errors";
@@ -21,7 +20,7 @@ export async function GET(request: Request) {
}
}
export async function POST(request: Request): Promise<NextResponse> {
export async function POST(request: Request): Promise<Response> {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
-42
View File
@@ -1,42 +0,0 @@
import { getSessionUser } from "@/app/lib/api/apiHelper";
import { NextResponse } from "next/server";
import { prisma } from "@formbricks/database";
export async function GET() {
const sessionUser = await getSessionUser();
if (!sessionUser) {
return new Response("Not authenticated", {
status: 401,
});
}
// get memberships
const memberships = await prisma.membership.findMany({
where: {
userId: sessionUser.id,
},
include: {
team: {
select: {
id: true,
name: true,
products: {
select: {
id: true,
name: true,
environments: {
select: {
id: true,
type: true,
},
},
},
},
},
},
},
});
return NextResponse.json(memberships);
}
@@ -1,5 +1,3 @@
import { NextResponse } from "next/server";
import { prisma } from "@formbricks/database";
import { sendForgotPasswordEmail } from "@formbricks/lib/emails/emails";
@@ -14,13 +12,13 @@ export async function POST(request: Request) {
});
if (!foundUser) {
return NextResponse.json({ error: "No user with this email found" }, { status: 409 });
return Response.json({ error: "No user with this email found" }, { status: 409 });
}
await sendForgotPasswordEmail(foundUser);
return NextResponse.json({});
return Response.json({});
} catch (e) {
return NextResponse.json(
return Response.json(
{
error: e.message,
errorCode: e.code,
+5 -5
View File
@@ -1,6 +1,6 @@
import { getSessionUser } from "@/app/lib/api/apiHelper";
import { MembershipRole } from "@prisma/client";
import { NextRequest, NextResponse } from "next/server";
import { NextRequest } from "next/server";
import { prisma } from "@formbricks/database";
@@ -23,7 +23,7 @@ export async function GET() {
},
});
return NextResponse.json(user);
return Response.json(user);
}
export async function PUT(request: NextRequest) {
@@ -42,7 +42,7 @@ export async function PUT(request: NextRequest) {
data: body,
});
return NextResponse.json(user);
return Response.json(user);
}
const deleteUser = async (userId: string) => {
@@ -130,8 +130,8 @@ export async function DELETE() {
await deleteUser(currentUser.id);
return NextResponse.json({ deletedUser: currentUser }, { status: 200 });
return Response.json({ deletedUser: currentUser }, { status: 200 });
} catch (error) {
return NextResponse.json({ message: error.message }, { status: 500 });
return Response.json({ message: error.message }, { status: 500 });
}
}
@@ -1,5 +1,3 @@
import { NextResponse } from "next/server";
import { prisma } from "@formbricks/database";
import { sendPasswordResetNotifyEmail } from "@formbricks/lib/emails/emails";
import { verifyToken } from "@formbricks/lib/jwt";
@@ -15,16 +13,16 @@ export async function POST(request: Request) {
},
});
if (!user) {
return NextResponse.json({ error: "Invalid token provided or no longer valid" }, { status: 409 });
return Response.json({ error: "Invalid token provided or no longer valid" }, { status: 409 });
}
await prisma.user.update({
where: { id: user.id },
data: { password: hashedPassword },
});
await sendPasswordResetNotifyEmail(user);
return NextResponse.json({});
return Response.json({});
} catch (e) {
return NextResponse.json(
return Response.json(
{
error: e.message,
errorCode: e.code,
+6 -8
View File
@@ -1,5 +1,3 @@
import { NextResponse } from "next/server";
import { prisma } from "@formbricks/database";
import {
EMAIL_AUTH_ENABLED,
@@ -19,7 +17,7 @@ import { createUser, updateUser } from "@formbricks/lib/user/service";
export async function POST(request: Request) {
let { inviteToken, ...user } = await request.json();
if (!EMAIL_AUTH_ENABLED || inviteToken ? INVITE_DISABLED : !SIGNUP_ENABLED) {
return NextResponse.json({ error: "Signup disabled" }, { status: 403 });
return Response.json({ error: "Signup disabled" }, { status: 403 });
}
user = { ...user, ...{ email: user.email.toLowerCase() } };
@@ -44,7 +42,7 @@ export async function POST(request: Request) {
});
if (!invite) {
return NextResponse.json({ error: "Invalid invite ID" }, { status: 400 });
return Response.json({ error: "Invalid invite ID" }, { status: 400 });
}
// assign user to existing team
@@ -60,7 +58,7 @@ export async function POST(request: Request) {
await sendInviteAcceptedEmail(invite.creator.name, user.name, invite.creator.email);
await deleteInvite(inviteId);
return NextResponse.json(user);
return Response.json(user);
}
// User signs up without invite
@@ -103,10 +101,10 @@ export async function POST(request: Request) {
await sendVerificationEmail(user);
}
return NextResponse.json(user);
return Response.json(user);
} catch (e) {
if (e.code === "P2002") {
return NextResponse.json(
return Response.json(
{
error: "user with this email address already exists",
errorCode: e.code,
@@ -114,7 +112,7 @@ export async function POST(request: Request) {
{ status: 409 }
);
} else {
return NextResponse.json(
return Response.json(
{
error: e.message,
errorCode: e.code,
@@ -1,5 +1,3 @@
import { NextResponse } from "next/server";
import { prisma } from "@formbricks/database";
import { sendVerificationEmail } from "@formbricks/lib/emails/emails";
@@ -11,15 +9,15 @@ export async function POST(request: Request) {
where: { email },
});
if (!user) {
return NextResponse.json({ error: "No user with this email address found" }, { status: 404 });
return Response.json({ error: "No user with this email address found" }, { status: 404 });
}
if (user.emailVerified) {
return NextResponse.json({ error: "Email address has already been verified" }, { status: 400 });
return Response.json({ error: "Email address has already been verified" }, { status: 400 });
}
await sendVerificationEmail(user);
return NextResponse.json(user);
return Response.json(user);
} catch (e) {
return NextResponse.json(
return Response.json(
{
error: e.message,
errorCode: e.code,
+1 -2
View File
@@ -1,7 +1,6 @@
import { responses } from "@/app/lib/api/response";
import { transformErrorToDetails } from "@/app/lib/api/validator";
import { headers } from "next/headers";
import { NextResponse } from "next/server";
import { getApiKeyFromKey } from "@formbricks/lib/apiKey/service";
import { createWebhook, getWebhooks } from "@formbricks/lib/webhook/service";
@@ -21,7 +20,7 @@ export async function GET() {
// get webhooks from database
try {
const webhooks = await getWebhooks(apiKeyData.environmentId);
return NextResponse.json({ data: webhooks });
return Response.json({ data: webhooks });
} catch (error) {
if (error instanceof DatabaseError) {
return responses.badRequestResponse(error.message);
+45 -12
View File
@@ -1,5 +1,4 @@
import { NextApiResponse } from "next";
import { NextResponse } from "next/server";
export type ApiResponse = ApiSuccessResponse | ApiErrorResponse;
@@ -30,7 +29,7 @@ const corsHeaders = {
};
const badRequestResponse = (message: string, details?: { [key: string]: string }, cors: boolean = false) =>
NextResponse.json(
Response.json(
{
code: "bad_request",
message,
@@ -56,7 +55,7 @@ const methodNotAllowedResponse = (
allowedMethods: string[],
cors: boolean = false
) =>
NextResponse.json(
Response.json(
{
code: "method_not_allowed",
message: `The HTTP ${res.req?.method} method is not supported by this route.`,
@@ -71,7 +70,7 @@ const methodNotAllowedResponse = (
);
const notFoundResponse = (resourceType: string, resourceId: string, cors: boolean = false) =>
NextResponse.json(
Response.json(
{
code: "not_found",
message: `${resourceType} not found`,
@@ -87,7 +86,7 @@ const notFoundResponse = (resourceType: string, resourceId: string, cors: boolea
);
const notAuthenticatedResponse = (cors: boolean = false) =>
NextResponse.json(
Response.json(
{
code: "not_authenticated",
message: "Not authenticated",
@@ -102,7 +101,7 @@ const notAuthenticatedResponse = (cors: boolean = false) =>
);
const unauthorizedResponse = (cors: boolean = false) =>
NextResponse.json(
Response.json(
{
code: "unauthorized",
message: "You are not authorized to access this resource",
@@ -115,24 +114,33 @@ const unauthorizedResponse = (cors: boolean = false) =>
);
const successResponse = (data: Object, cors: boolean = false, cache: string = "private, no-store") => {
const responseHeaders = {
const headers = {
...(cors && corsHeaders),
"Cache-Control": cache,
};
return NextResponse.json(
return Response.json(
{
data,
} as ApiSuccessResponse<typeof data>,
{
status: 200,
headers: responseHeaders,
headers,
}
);
};
const internalServerErrorResponse = (message: string, cors: boolean = false) =>
NextResponse.json(
const internalServerErrorResponse = (
message: string,
cors: boolean = false,
cache: string = "private, no-store"
) => {
const headers = {
...(cors && corsHeaders),
"Cache-Control": cache,
};
return Response.json(
{
code: "internal_server_error",
message,
@@ -140,9 +148,33 @@ const internalServerErrorResponse = (message: string, cors: boolean = false) =>
} as ApiErrorResponse,
{
status: 500,
...(cors && { headers: corsHeaders }),
headers,
}
);
};
const tooManyRequestsResponse = (
message: string,
cors: boolean = false,
cache: string = "private, no-store"
) => {
const headers = {
...(cors && corsHeaders),
"Cache-Control": cache,
};
return Response.json(
{
code: "internal_server_error",
message,
details: {},
} as ApiErrorResponse,
{
status: 429,
headers,
}
);
};
export const responses = {
badRequestResponse,
@@ -153,4 +185,5 @@ export const responses = {
unauthorizedResponse,
notFoundResponse,
successResponse,
tooManyRequestsResponse,
};
+13 -13
View File
@@ -22,40 +22,40 @@
"@formbricks/ui": "workspace:*",
"@headlessui/react": "^1.7.18",
"@heroicons/react": "^2.1.1",
"@json2csv/node": "^7.0.5",
"@json2csv/node": "^7.0.6",
"@paralleldrive/cuid2": "^2.2.2",
"@radix-ui/react-collapsible": "^1.0.3",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@react-email/components": "^0.0.14",
"@sentry/nextjs": "^7.99.0",
"@react-email/components": "^0.0.15",
"@sentry/nextjs": "^7.102.1",
"@vercel/og": "^0.6.2",
"@vercel/speed-insights": "^1.0.9",
"@vercel/speed-insights": "^1.0.10",
"bcryptjs": "^2.4.3",
"dotenv": "^16.4.1",
"dotenv": "^16.4.5",
"encoding": "^0.1.13",
"framer-motion": "11.0.3",
"googleapis": "^131.0.0",
"framer-motion": "11.0.5",
"googleapis": "^133.0.0",
"jsonwebtoken": "^9.0.2",
"lodash": "^4.17.21",
"lru-cache": "^10.2.0",
"lucide-react": "^0.321.0",
"lucide-react": "^0.336.0",
"mime": "^4.0.1",
"next": "14.1.0",
"nodemailer": "^6.9.9",
"nodemailer": "^6.9.10",
"otplib": "^12.0.1",
"posthog-js": "^1.104.4",
"posthog-js": "^1.108.2",
"prismjs": "^1.29.0",
"qrcode": "^1.5.3",
"react": "18.2.0",
"react-beautiful-dnd": "^13.1.1",
"react-dom": "18.2.0",
"react-email": "^2.0.0",
"react-hook-form": "^7.50.0",
"react-email": "^2.1.0",
"react-hook-form": "^7.50.1",
"react-hot-toast": "^2.4.1",
"react-icons": "^5.0.1",
"sharp": "^0.33.2",
"ua-parser-js": "^1.0.37",
"webpack": "^5.90.1",
"webpack": "^5.90.3",
"xlsx": "^0.18.5"
},
"devDependencies": {
+1 -1
View File
@@ -5,7 +5,7 @@
},
"app/api/v1/client/**/*.ts": {
"maxDuration": 10,
"memory": 512
"memory": 300
},
"app/**/*.ts": {
"maxDuration": 10,