mirror of
https://github.com/formbricks/formbricks.git
synced 2026-03-05 00:48:03 -06:00
fix: build issues in environment service on some systems (#1160)
This commit is contained in:
@@ -28,7 +28,6 @@
|
||||
"@paralleldrive/cuid2": "^2.2.2",
|
||||
"@sindresorhus/slugify": "^2.2.1",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@types/node": "20.6.0",
|
||||
"@types/react-highlight-words": "^0.16.5",
|
||||
"acorn": "^8.10.0",
|
||||
"autoprefixer": "^10.4.15",
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
"dependencies": {
|
||||
"@formbricks/ui": "workspace:*",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
"react-dom": "^18.2.0",
|
||||
"storybook": "^7.4.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formbricks/tsconfig": "workspace:*",
|
||||
"@storybook/addon-essentials": "^7.5.0-alpha.5",
|
||||
"@storybook/addon-interactions": "^7.5.0-alpha.5",
|
||||
"@storybook/addon-links": "^7.5.0-alpha.5",
|
||||
@@ -26,22 +28,11 @@
|
||||
"@storybook/react": "^7.5.0-alpha.5",
|
||||
"@storybook/react-vite": "^7.5.0-alpha.5",
|
||||
"@storybook/testing-library": "^0.2.2",
|
||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||
"@typescript-eslint/parser": "^6.0.0",
|
||||
"@vitejs/plugin-react": "^4.0.3",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"@typescript-eslint/eslint-plugin": "^6.7.5",
|
||||
"@typescript-eslint/parser": "^6.7.5",
|
||||
"@vitejs/plugin-react": "^4.1.0",
|
||||
"esbuild": "^0.19.4",
|
||||
"eslint": "^8.45.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.3",
|
||||
"eslint-plugin-storybook": "^0.6.15",
|
||||
"storybook": "^7.5.0-alpha.5",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"tsup": "^7.2.0",
|
||||
"postcss": "^8.4.31",
|
||||
"vite": "^4.4.5",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-tailwindcss": "^0.4.1",
|
||||
"@formbricks/tsconfig": "workspace:*"
|
||||
"vite": "^4.4.11"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import { env } from "@/env.mjs";
|
||||
import { verifyPassword } from "@/app/lib/auth";
|
||||
import { env } from "@/env.mjs";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { EMAIL_VERIFICATION_DISABLED, ENCRYPTION_KEY } from "@formbricks/lib/constants";
|
||||
import { symmetricDecrypt, symmetricEncrypt } from "@formbricks/lib/crypto";
|
||||
import {
|
||||
EMAIL_VERIFICATION_DISABLED,
|
||||
ENCRYPTION_KEY,
|
||||
INTERNAL_SECRET,
|
||||
WEBAPP_URL,
|
||||
} from "@formbricks/lib/constants";
|
||||
import { verifyToken } from "@formbricks/lib/jwt";
|
||||
import { getProfileByEmail } from "@formbricks/lib/profile/service";
|
||||
import type { IdentityProvider } from "@prisma/client";
|
||||
@@ -288,7 +283,7 @@ export const authOptions: NextAuthOptions = {
|
||||
return "/auth/login?error=A%20user%20with%20this%20email%20exists%20already.";
|
||||
}
|
||||
|
||||
const createdUser = await prisma.user.create({
|
||||
await prisma.user.create({
|
||||
data: {
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
@@ -401,16 +396,6 @@ export const authOptions: NextAuthOptions = {
|
||||
},
|
||||
});
|
||||
|
||||
const teamId = createdUser.memberships?.[0]?.teamId;
|
||||
if (teamId) {
|
||||
fetch(`${WEBAPP_URL}/api/v1/teams/${teamId}/add_demo_product`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"x-api-key": INTERNAL_SECRET,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import { INTERNAL_SECRET } from "@formbricks/lib/constants";
|
||||
import { createDemoProduct } from "@formbricks/lib/team/service";
|
||||
import { NextResponse } from "next/server";
|
||||
import { headers } from "next/headers";
|
||||
import { responses } from "@/app/lib/api/response";
|
||||
|
||||
export async function POST(_: Request, { params }: { params: { teamId: string } }) {
|
||||
// Check Authentication
|
||||
|
||||
if (headers().get("x-api-key") !== INTERNAL_SECRET) {
|
||||
return responses.notAuthenticatedResponse();
|
||||
}
|
||||
|
||||
const teamId = params.teamId;
|
||||
if (teamId === undefined) {
|
||||
return responses.badRequestResponse("Missing teamId");
|
||||
}
|
||||
|
||||
try {
|
||||
const demoProduct = await createDemoProduct(teamId);
|
||||
return NextResponse.json(demoProduct);
|
||||
} catch (err) {
|
||||
throw new Error(err);
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,8 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"clean": "rimraf .turbo node_modules .next",
|
||||
"dev": "next dev",
|
||||
"go": "next dev",
|
||||
"dev": "next dev -p 3000",
|
||||
"go": "next dev -p 3000",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
@@ -30,7 +30,6 @@
|
||||
"@t3-oss/env-nextjs": "^0.7.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"encoding": "^0.1.13",
|
||||
"eslint-config-next": "^13.5.3",
|
||||
"framer-motion": "10.16.4",
|
||||
"googleapis": "^126.0.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
"eslint-config-next": "^13.5.4",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-config-turbo": "latest",
|
||||
"eslint-plugin-react": "7.33.2"
|
||||
"eslint-plugin-react": "7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.3",
|
||||
"eslint-plugin-storybook": "^0.6.15"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
ZId,
|
||||
} from "@formbricks/types/v1/environment";
|
||||
import { DatabaseError, ResourceNotFoundError, ValidationError } from "@formbricks/types/v1/errors";
|
||||
import { EventType, Prisma } from "@prisma/client";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { revalidateTag, unstable_cache } from "next/cache";
|
||||
import "server-only";
|
||||
import { z } from "zod";
|
||||
@@ -172,35 +172,30 @@ export const createEnvironment = async (
|
||||
product: { connect: { id: productId } },
|
||||
widgetSetupCompleted: environmentInput.widgetSetupCompleted || false,
|
||||
eventClasses: {
|
||||
create: populateEnvironment.eventClasses,
|
||||
create: [
|
||||
{
|
||||
name: "New Session",
|
||||
description: "Gets fired when a new session is created",
|
||||
type: "automatic",
|
||||
},
|
||||
{
|
||||
name: "Exit Intent (Desktop)",
|
||||
description: "A user on Desktop leaves the website with the cursor.",
|
||||
type: "automatic",
|
||||
},
|
||||
{
|
||||
name: "50% Scroll",
|
||||
description: "A user scrolled 50% of the current page",
|
||||
type: "automatic",
|
||||
},
|
||||
],
|
||||
},
|
||||
attributeClasses: {
|
||||
create: populateEnvironment.attributeClasses,
|
||||
create: [
|
||||
{ name: "userId", description: "The internal ID of the person", type: "automatic" },
|
||||
{ name: "email", description: "The email of the person", type: "automatic" },
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const populateEnvironment = {
|
||||
eventClasses: [
|
||||
{
|
||||
name: "New Session",
|
||||
description: "Gets fired when a new session is created",
|
||||
type: EventType.automatic,
|
||||
},
|
||||
{
|
||||
name: "Exit Intent (Desktop)",
|
||||
description: "A user on Desktop leaves the website with the cursor.",
|
||||
type: EventType.automatic,
|
||||
},
|
||||
{
|
||||
name: "50% Scroll",
|
||||
description: "A user scrolled 50% of the current page",
|
||||
type: EventType.automatic,
|
||||
},
|
||||
],
|
||||
attributeClasses: [
|
||||
{ name: "userId", description: "The internal ID of the person", type: EventType.automatic },
|
||||
{ name: "email", description: "The email of the person", type: EventType.automatic },
|
||||
],
|
||||
};
|
||||
|
||||
@@ -2,33 +2,13 @@ import "server-only";
|
||||
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
import { DatabaseError, ResourceNotFoundError, ValidationError } from "@formbricks/types/v1/errors";
|
||||
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/v1/errors";
|
||||
import { TTeam, TTeamUpdateInput } from "@formbricks/types/v1/teams";
|
||||
import { TProductUpdateInput } from "@formbricks/types/v1/product";
|
||||
import { createId } from "@paralleldrive/cuid2";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { revalidateTag, unstable_cache } from "next/cache";
|
||||
import {
|
||||
ChurnResponses,
|
||||
ChurnSurvey,
|
||||
DEMO_COMPANIES,
|
||||
DEMO_NAMES,
|
||||
EASResponses,
|
||||
EASSurvey,
|
||||
InterviewPromptResponses,
|
||||
InterviewPromptSurvey,
|
||||
OnboardingResponses,
|
||||
OnboardingSurvey,
|
||||
PMFResponses,
|
||||
PMFSurvey,
|
||||
generateAttributeValue,
|
||||
generateResponsesAndDisplays,
|
||||
populateEnvironment,
|
||||
updateEnvironmentArgs,
|
||||
} from "../utils/createDemoProductHelpers";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
|
||||
import { getEnvironmentCacheTag } from "../environment/service";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
|
||||
export const select = {
|
||||
id: true,
|
||||
@@ -198,181 +178,3 @@ export const deleteTeam = async (teamId: string): Promise<TTeam> => {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const createDemoProduct = async (teamId: string): Promise<TProductUpdateInput> => {
|
||||
validateInputs([teamId, ZId]);
|
||||
|
||||
const demoProduct = await prisma.product.create({
|
||||
data: {
|
||||
name: "Demo Product",
|
||||
team: {
|
||||
connect: {
|
||||
id: teamId,
|
||||
},
|
||||
},
|
||||
environments: {
|
||||
create: [
|
||||
{
|
||||
type: "production",
|
||||
...populateEnvironment,
|
||||
},
|
||||
{
|
||||
type: "development",
|
||||
...populateEnvironment,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
include: {
|
||||
environments: true,
|
||||
},
|
||||
});
|
||||
|
||||
const prodEnvironment = demoProduct.environments.find((environment) => environment.type === "production");
|
||||
|
||||
// add attributes to each environment of the product
|
||||
// dont add dev environment
|
||||
|
||||
const updatedEnvironment = await prisma.environment.update({
|
||||
where: { id: prodEnvironment?.id },
|
||||
data: {
|
||||
...updateEnvironmentArgs,
|
||||
},
|
||||
include: {
|
||||
attributeClasses: true, // include attributeClasses
|
||||
eventClasses: true, // include eventClasses
|
||||
},
|
||||
});
|
||||
|
||||
const eventClasses = updatedEnvironment.eventClasses;
|
||||
|
||||
// check if updatedEnvironment exists and it has attributeClasses
|
||||
if (!updatedEnvironment || !updatedEnvironment.attributeClasses) {
|
||||
throw new ValidationError("Attribute classes could not be created");
|
||||
}
|
||||
|
||||
const attributeClasses = updatedEnvironment.attributeClasses;
|
||||
|
||||
// create an array for all the events that will be created
|
||||
const eventPromises: {
|
||||
eventClassId: string;
|
||||
sessionId: string;
|
||||
}[] = [];
|
||||
|
||||
// create an array for all the attributes that will be created
|
||||
const generatedAttributes: {
|
||||
attributeClassId: string;
|
||||
value: string;
|
||||
personId: string;
|
||||
}[] = [];
|
||||
|
||||
// create an array containing all the person ids to be created
|
||||
const personIds = Array.from({ length: 20 }).map((_) => createId());
|
||||
|
||||
// create an array containing all the session ids to be created
|
||||
const sessionIds = Array.from({ length: 20 }).map((_) => createId());
|
||||
|
||||
// loop over the person ids and create attributes for each person
|
||||
personIds.forEach((personId, i: number) => {
|
||||
generatedAttributes.push(
|
||||
...attributeClasses.map((attributeClass) => {
|
||||
let value = generateAttributeValue(
|
||||
attributeClass.name,
|
||||
DEMO_NAMES[i],
|
||||
DEMO_COMPANIES[i],
|
||||
`${DEMO_COMPANIES[i].toLowerCase().split(" ").join("")}.com`,
|
||||
i
|
||||
);
|
||||
|
||||
return {
|
||||
attributeClassId: attributeClass.id,
|
||||
value: value,
|
||||
personId,
|
||||
};
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
sessionIds.forEach((sessionId) => {
|
||||
for (let eventClass of eventClasses) {
|
||||
// create a random number of events for each event class
|
||||
const eventCount = Math.floor(Math.random() * 5) + 1;
|
||||
for (let j = 0; j < eventCount; j++) {
|
||||
eventPromises.push({
|
||||
eventClassId: eventClass.id,
|
||||
sessionId,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// create the people, sessions, attributes, and events in a transaction
|
||||
// the order of the queries is important because of foreign key constraints
|
||||
try {
|
||||
await prisma.$transaction([
|
||||
prisma.person.createMany({
|
||||
data: personIds.map((personId) => ({
|
||||
id: personId,
|
||||
environmentId: demoProduct.environments[0].id,
|
||||
})),
|
||||
}),
|
||||
|
||||
prisma.session.createMany({
|
||||
data: sessionIds.map((sessionId, idx) => ({
|
||||
id: sessionId,
|
||||
personId: personIds[idx],
|
||||
})),
|
||||
}),
|
||||
|
||||
prisma.attribute.createMany({
|
||||
data: generatedAttributes,
|
||||
}),
|
||||
|
||||
prisma.event.createMany({
|
||||
data: eventPromises.map((eventPromise) => ({
|
||||
eventClassId: eventPromise.eventClassId,
|
||||
sessionId: eventPromise.sessionId,
|
||||
})),
|
||||
}),
|
||||
]);
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseError("Database operation failed");
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Create a function that creates a survey
|
||||
const createSurvey = async (surveyData: any, responses: any, displays: any) => {
|
||||
return await prisma.survey.create({
|
||||
data: {
|
||||
...surveyData,
|
||||
environment: { connect: { id: demoProduct.environments[0].id } },
|
||||
questions: surveyData.questions as any,
|
||||
responses: { create: responses },
|
||||
displays: { create: displays },
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const people = personIds.map((personId) => ({ id: personId }));
|
||||
const PMFResults = generateResponsesAndDisplays(people, PMFResponses);
|
||||
const OnboardingResults = generateResponsesAndDisplays(people, OnboardingResponses);
|
||||
const ChurnResults = generateResponsesAndDisplays(people, ChurnResponses);
|
||||
const EASResults = generateResponsesAndDisplays(people, EASResponses);
|
||||
const InterviewPromptResults = generateResponsesAndDisplays(people, InterviewPromptResponses);
|
||||
|
||||
// Create the surveys
|
||||
await createSurvey(PMFSurvey, PMFResults.responses, PMFResults.displays);
|
||||
await createSurvey(OnboardingSurvey, OnboardingResults.responses, OnboardingResults.displays);
|
||||
await createSurvey(ChurnSurvey, ChurnResults.responses, ChurnResults.displays);
|
||||
await createSurvey(EASSurvey, EASResults.responses, EASResults.displays);
|
||||
await createSurvey(
|
||||
InterviewPromptSurvey,
|
||||
InterviewPromptResults.responses,
|
||||
InterviewPromptResults.displays
|
||||
);
|
||||
|
||||
return demoProduct;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"clean": "rimraf node_modules"
|
||||
"clean": "rimraf node_modules .turbo"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^3.0.3",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"private": true,
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"clean": "rimraf node_modules"
|
||||
"clean": "rimraf node_modules .turbo"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/forms": "^0.5.6",
|
||||
|
||||
@@ -3,10 +3,9 @@ module.exports = {
|
||||
// app content
|
||||
"./app/**/*.{js,ts,jsx,tsx}", // Note the addition of the `app` directory.
|
||||
"./pages/**/*.{js,ts,jsx,tsx}",
|
||||
"./components/**/*.{js,ts,jsx,tsx}",
|
||||
"./lib/**/*.{js,ts,jsx,tsx}",
|
||||
// include packages if not transpiling
|
||||
"../../packages/ui/**/*.{js,ts,jsx,tsx}",
|
||||
"../../packages/ui/**/*.{ts,tsx}",
|
||||
"!../../packages/ui/node_modules/**/*.{js,ts,jsx,tsx}",
|
||||
],
|
||||
theme: {
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
"@types/node": "20.8.6",
|
||||
"@types/react": "18.2.28",
|
||||
"@types/react-dom": "18.2.13",
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.1.6"
|
||||
}
|
||||
}
|
||||
|
||||
878
pnpm-lock.yaml
generated
878
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user