mirror of
https://github.com/formbricks/formbricks.git
synced 2026-03-05 18:39:20 -06:00
chore: upgrade dependencies and stabilize prisma/zod migrations
This commit is contained in:
@@ -12,18 +12,18 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@chromatic-com/storybook": "^5.0.1",
|
||||
"@storybook/addon-a11y": "10.2.14",
|
||||
"@storybook/addon-links": "10.2.14",
|
||||
"@storybook/addon-onboarding": "10.2.14",
|
||||
"@storybook/react-vite": "10.2.14",
|
||||
"@storybook/addon-a11y": "10.2.15",
|
||||
"@storybook/addon-links": "10.2.15",
|
||||
"@storybook/addon-onboarding": "10.2.15",
|
||||
"@storybook/react-vite": "10.2.15",
|
||||
"@typescript-eslint/eslint-plugin": "8.56.1",
|
||||
"@tailwindcss/vite": "4.2.1",
|
||||
"@typescript-eslint/parser": "8.56.1",
|
||||
"@vitejs/plugin-react": "5.1.4",
|
||||
"eslint-plugin-react-refresh": "0.4.26",
|
||||
"eslint-plugin-storybook": "10.2.14",
|
||||
"storybook": "10.2.14",
|
||||
"storybook": "10.2.15",
|
||||
"vite": "7.3.1",
|
||||
"@storybook/addon-docs": "10.2.14"
|
||||
"@storybook/addon-docs": "10.2.15"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const ZOrganizationTeam = z.object({
|
||||
id: z.string().cuid2(),
|
||||
id: z.cuid2(),
|
||||
name: z.string(),
|
||||
});
|
||||
|
||||
|
||||
@@ -110,8 +110,8 @@ export const getResponseCountAction = authenticatedActionClient
|
||||
|
||||
const ZGetDisplaysWithContactAction = z.object({
|
||||
surveyId: ZId,
|
||||
limit: z.number().int().min(1).max(100),
|
||||
offset: z.number().int().nonnegative(),
|
||||
limit: z.int().min(1).max(100),
|
||||
offset: z.int().nonnegative(),
|
||||
});
|
||||
|
||||
export const getDisplaysWithContactAction = authenticatedActionClient
|
||||
|
||||
@@ -1095,7 +1095,7 @@ export const getResponsesForSummary = reactCache(
|
||||
[limit, ZOptionalNumber],
|
||||
[offset, ZOptionalNumber],
|
||||
[filterCriteria, ZResponseFilterCriteria.optional()],
|
||||
[cursor, z.string().cuid2().optional()]
|
||||
[cursor, z.cuid2().optional()]
|
||||
);
|
||||
|
||||
const queryLimit = limit ?? RESPONSES_PER_PAGE;
|
||||
|
||||
@@ -50,7 +50,7 @@ export const GET = withV1ApiWrapper({
|
||||
{
|
||||
environmentId: params.environmentId,
|
||||
url: req.url,
|
||||
validationError: cuidValidation.error.errors[0]?.message,
|
||||
validationError: cuidValidation.error.issues[0]?.message,
|
||||
},
|
||||
"Invalid CUID v1 format detected"
|
||||
);
|
||||
|
||||
@@ -6,7 +6,7 @@ import { DatabaseError } from "@formbricks/types/errors";
|
||||
import { validateInputs } from "@/lib/utils/validate";
|
||||
|
||||
export const deleteSurvey = async (surveyId: string) => {
|
||||
validateInputs([surveyId, z.string().cuid2()]);
|
||||
validateInputs([surveyId, z.cuid2()]);
|
||||
|
||||
try {
|
||||
const deletedSurvey = await prisma.survey.delete({
|
||||
|
||||
@@ -101,7 +101,9 @@ describe("verifyRecaptchaToken", () => {
|
||||
},
|
||||
signal: {},
|
||||
};
|
||||
vi.spyOn(global, "AbortController").mockImplementation(() => abortController as any);
|
||||
vi.spyOn(global, "AbortController").mockImplementation(function AbortController() {
|
||||
return abortController as any;
|
||||
});
|
||||
(global.fetch as any).mockImplementation(() => new Promise(() => {}));
|
||||
verifyRecaptchaToken("token", 0.5);
|
||||
vi.advanceTimersByTime(5000);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import cuid2 from "@paralleldrive/cuid2";
|
||||
import * as cuid2 from "@paralleldrive/cuid2";
|
||||
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import * as crypto from "@/lib/crypto";
|
||||
import { generateSurveySingleUseId, validateSurveySingleUseId } from "./singleUseSurveys";
|
||||
@@ -20,10 +20,6 @@ vi.mock("@paralleldrive/cuid2", () => {
|
||||
const isCuidMock = vi.fn();
|
||||
|
||||
return {
|
||||
default: {
|
||||
createId: createIdMock,
|
||||
isCuid: isCuidMock,
|
||||
},
|
||||
createId: createIdMock,
|
||||
isCuid: isCuidMock,
|
||||
};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import cuid2 from "@paralleldrive/cuid2";
|
||||
import { createId, isCuid } from "@paralleldrive/cuid2";
|
||||
import { ENCRYPTION_KEY } from "@/lib/constants";
|
||||
import { symmetricDecrypt, symmetricEncrypt } from "@/lib/crypto";
|
||||
|
||||
// generate encrypted single use id for the survey
|
||||
export const generateSurveySingleUseId = (isEncrypted: boolean): string => {
|
||||
const cuid = cuid2.createId();
|
||||
const cuid = createId();
|
||||
if (!isEncrypted) {
|
||||
return cuid;
|
||||
}
|
||||
@@ -30,7 +30,7 @@ export const validateSurveySingleUseId = (surveySingleUseId: string): string | u
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (cuid2.isCuid(decryptedCuid)) {
|
||||
if (isCuid(decryptedCuid)) {
|
||||
return decryptedCuid;
|
||||
} else {
|
||||
return undefined;
|
||||
|
||||
@@ -159,7 +159,7 @@ export const BREVO_LIST_ID = env.BREVO_LIST_ID;
|
||||
export const UNSPLASH_ACCESS_KEY = env.UNSPLASH_ACCESS_KEY;
|
||||
export const UNSPLASH_ALLOWED_DOMAINS = ["api.unsplash.com"];
|
||||
|
||||
export const STRIPE_API_VERSION = "2024-06-20";
|
||||
export const STRIPE_API_VERSION = "2026-02-25.clover";
|
||||
|
||||
// Maximum number of attribute classes allowed:
|
||||
export const MAX_ATTRIBUTE_CLASSES_PER_ENVIRONMENT = 150;
|
||||
|
||||
@@ -71,8 +71,8 @@ export const getDisplaysBySurveyIdWithContact = reactCache(
|
||||
async (surveyId: string, limit?: number, offset?: number): Promise<TDisplayWithContact[]> => {
|
||||
validateInputs(
|
||||
[surveyId, ZId],
|
||||
[limit, z.number().int().min(1).optional()],
|
||||
[offset, z.number().int().nonnegative().optional()]
|
||||
[limit, z.int().min(1).optional()],
|
||||
[offset, z.int().nonnegative().optional()]
|
||||
);
|
||||
|
||||
try {
|
||||
|
||||
@@ -14,7 +14,7 @@ export const env = createEnv({
|
||||
CRON_SECRET: z.string().optional(),
|
||||
BREVO_API_KEY: z.string().optional(),
|
||||
BREVO_LIST_ID: z.string().optional(),
|
||||
DATABASE_URL: z.string().url(),
|
||||
DATABASE_URL: z.url(),
|
||||
DEBUG: z.enum(["1", "0"]).optional(),
|
||||
AUTH_DEFAULT_TEAM_ID: z.string().optional(),
|
||||
AUTH_SKIP_INVITE_FOR_SSO: z.enum(["1", "0"]).optional(),
|
||||
@@ -23,7 +23,7 @@ export const env = createEnv({
|
||||
EMAIL_VERIFICATION_DISABLED: z.enum(["1", "0"]).optional(),
|
||||
ENCRYPTION_KEY: z.string(),
|
||||
ENTERPRISE_LICENSE_KEY: z.string().optional(),
|
||||
ENVIRONMENT: z.enum(["production", "staging"]).default("production"),
|
||||
ENVIRONMENT: z.enum(["production", "staging"]).prefault("production"),
|
||||
GITHUB_ID: z.string().optional(),
|
||||
GITHUB_SECRET: z.string().optional(),
|
||||
GOOGLE_CLIENT_ID: z.string().optional(),
|
||||
@@ -31,21 +31,20 @@ export const env = createEnv({
|
||||
GOOGLE_SHEETS_CLIENT_ID: z.string().optional(),
|
||||
GOOGLE_SHEETS_CLIENT_SECRET: z.string().optional(),
|
||||
GOOGLE_SHEETS_REDIRECT_URL: z.string().optional(),
|
||||
HTTP_PROXY: z.string().url().optional(),
|
||||
HTTPS_PROXY: z.string().url().optional(),
|
||||
HTTP_PROXY: z.url().optional(),
|
||||
HTTPS_PROXY: z.url().optional(),
|
||||
IMPRINT_URL: z
|
||||
.string()
|
||||
.url()
|
||||
.optional()
|
||||
.or(z.string().refine((str) => str === "")),
|
||||
IMPRINT_ADDRESS: z.string().optional(),
|
||||
INVITE_DISABLED: z.enum(["1", "0"]).optional(),
|
||||
CHATWOOT_WEBSITE_TOKEN: z.string().optional(),
|
||||
CHATWOOT_BASE_URL: z.string().url().optional(),
|
||||
CHATWOOT_BASE_URL: z.url().optional(),
|
||||
IS_FORMBRICKS_CLOUD: z.enum(["1", "0"]).optional(),
|
||||
LOG_LEVEL: z.enum(["debug", "info", "warn", "error", "fatal"]).optional(),
|
||||
MAIL_FROM: z.string().email().optional(),
|
||||
NEXTAUTH_URL: z.string().url().optional(),
|
||||
MAIL_FROM: z.email().optional(),
|
||||
NEXTAUTH_URL: z.url().optional(),
|
||||
NEXTAUTH_SECRET: z.string().optional(),
|
||||
MAIL_FROM_NAME: z.string().optional(),
|
||||
NOTION_OAUTH_CLIENT_ID: z.string().optional(),
|
||||
@@ -58,10 +57,9 @@ export const env = createEnv({
|
||||
REDIS_URL:
|
||||
process.env.NODE_ENV === "test"
|
||||
? z.string().optional()
|
||||
: z.string().url("REDIS_URL is required for caching, rate limiting, and audit logging"),
|
||||
: z.url("REDIS_URL is required for caching, rate limiting, and audit logging"),
|
||||
PASSWORD_RESET_DISABLED: z.enum(["1", "0"]).optional(),
|
||||
PRIVACY_URL: z
|
||||
.string()
|
||||
.url()
|
||||
.optional()
|
||||
.or(z.string().refine((str) => str === "")),
|
||||
@@ -86,7 +84,6 @@ export const env = createEnv({
|
||||
STRIPE_SECRET_KEY: z.string().optional(),
|
||||
STRIPE_WEBHOOK_SECRET: z.string().optional(),
|
||||
PUBLIC_URL: z
|
||||
.string()
|
||||
.url()
|
||||
.refine(
|
||||
(url) => {
|
||||
@@ -98,12 +95,11 @@ export const env = createEnv({
|
||||
}
|
||||
},
|
||||
{
|
||||
message: "PUBLIC_URL must be a valid URL with a proper host (e.g., https://example.com)",
|
||||
error: "PUBLIC_URL must be a valid URL with a proper host (e.g., https://example.com)",
|
||||
}
|
||||
)
|
||||
.optional(),
|
||||
TERMS_URL: z
|
||||
.string()
|
||||
.url()
|
||||
.optional()
|
||||
.or(z.string().refine((str) => str === "")),
|
||||
@@ -112,7 +108,7 @@ export const env = createEnv({
|
||||
RECAPTCHA_SITE_KEY: z.string().optional(),
|
||||
RECAPTCHA_SECRET_KEY: z.string().optional(),
|
||||
VERCEL_URL: z.string().optional(),
|
||||
WEBAPP_URL: z.string().url().optional(),
|
||||
WEBAPP_URL: z.url().optional(),
|
||||
UNSPLASH_ACCESS_KEY: z.string().optional(),
|
||||
|
||||
NODE_ENV: z.enum(["development", "production", "test"]).optional(),
|
||||
|
||||
@@ -267,7 +267,7 @@ export const getResponses = reactCache(
|
||||
[limit, ZOptionalNumber],
|
||||
[offset, ZOptionalNumber],
|
||||
[filterCriteria, ZResponseFilterCriteria.optional()],
|
||||
[cursor, z.string().cuid2().optional()]
|
||||
[cursor, z.cuid2().optional()]
|
||||
);
|
||||
|
||||
limit = limit ?? RESPONSES_PER_PAGE;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import "server-only";
|
||||
import { ActionClass, Prisma } from "@prisma/client";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { cache as reactCache } from "react";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { logger } from "@formbricks/logger";
|
||||
@@ -114,7 +114,12 @@ export const selectSurvey = {
|
||||
slug: true,
|
||||
} satisfies Prisma.SurveySelect;
|
||||
|
||||
export const checkTriggersValidity = (triggers: TSurvey["triggers"], actionClasses: ActionClass[]) => {
|
||||
type TriggerWithActionClassId = { actionClass: { id: string } };
|
||||
|
||||
export const checkTriggersValidity = (
|
||||
triggers: TriggerWithActionClassId[] | null | undefined,
|
||||
actionClasses: Array<{ id: string }>
|
||||
) => {
|
||||
if (!triggers) return;
|
||||
|
||||
// check if all the triggers are valid
|
||||
@@ -133,14 +138,14 @@ export const checkTriggersValidity = (triggers: TSurvey["triggers"], actionClass
|
||||
};
|
||||
|
||||
export const handleTriggerUpdates = (
|
||||
updatedTriggers: TSurvey["triggers"],
|
||||
currentTriggers: TSurvey["triggers"],
|
||||
actionClasses: ActionClass[]
|
||||
updatedTriggers: TriggerWithActionClassId[] | null | undefined,
|
||||
currentTriggers: TriggerWithActionClassId[] | null | undefined,
|
||||
actionClasses: Array<{ id: string }>
|
||||
) => {
|
||||
if (!updatedTriggers) return {};
|
||||
checkTriggersValidity(updatedTriggers, actionClasses);
|
||||
|
||||
const currentTriggerIds = currentTriggers.map((trigger) => trigger.actionClass.id);
|
||||
const currentTriggerIds = (currentTriggers ?? []).map((trigger) => trigger.actionClass.id);
|
||||
const updatedTriggerIds = updatedTriggers.map((trigger) => trigger.actionClass.id);
|
||||
|
||||
// added triggers are triggers that are not in the current triggers and are there in the new triggers
|
||||
@@ -149,7 +154,7 @@ export const handleTriggerUpdates = (
|
||||
);
|
||||
|
||||
// deleted triggers are triggers that are not in the new triggers and are there in the current triggers
|
||||
const deletedTriggers = currentTriggers.filter(
|
||||
const deletedTriggers = (currentTriggers ?? []).filter(
|
||||
(trigger) => !updatedTriggerIds.includes(trigger.actionClass.id)
|
||||
);
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ export const getUser = reactCache(async (id: string): Promise<TUser | null> => {
|
||||
});
|
||||
|
||||
export const getUserByEmail = reactCache(async (email: string): Promise<TUser | null> => {
|
||||
validateInputs([email, z.string().email()]);
|
||||
validateInputs([email, z.email()]);
|
||||
|
||||
try {
|
||||
const user = await prisma.user.findFirst({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import cuid2 from "@paralleldrive/cuid2";
|
||||
import * as cuid2 from "@paralleldrive/cuid2";
|
||||
import { beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import * as crypto from "@/lib/crypto";
|
||||
import { env } from "@/lib/env";
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import cuid2 from "@paralleldrive/cuid2";
|
||||
import { createId } from "@paralleldrive/cuid2";
|
||||
import { symmetricEncrypt } from "@/lib/crypto";
|
||||
import { env } from "@/lib/env";
|
||||
|
||||
// generate encrypted single use id for the survey
|
||||
export const generateSurveySingleUseId = (isEncrypted: boolean): string => {
|
||||
const cuid = cuid2.createId();
|
||||
const cuid = createId();
|
||||
if (!isEncrypted) {
|
||||
return cuid;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ export const deleteTagOnResponseAction = authenticatedActionClient.schema(ZDelet
|
||||
|
||||
const ZDeleteResponseAction = z.object({
|
||||
responseId: ZId,
|
||||
decrementQuotas: z.boolean().default(false),
|
||||
decrementQuotas: z.boolean().prefault(false),
|
||||
});
|
||||
|
||||
export const deleteResponseAction = authenticatedActionClient.schema(ZDeleteResponseAction).action(
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
import { z } from "zod";
|
||||
import { extendZodWithOpenApi } from "zod-openapi";
|
||||
|
||||
extendZodWithOpenApi(z);
|
||||
|
||||
export const ZOverallHealthStatus = z
|
||||
.object({
|
||||
main_database: z.boolean().openapi({
|
||||
description: "Main database connection status - true if database is reachable and running",
|
||||
example: true,
|
||||
}),
|
||||
cache_database: z.boolean().openapi({
|
||||
description: "Cache database connection status - true if cache database is reachable and running",
|
||||
example: true,
|
||||
}),
|
||||
main_database: z
|
||||
.boolean()
|
||||
.meta({
|
||||
example: true,
|
||||
})
|
||||
.describe("Main database connection status - true if database is reachable and running"),
|
||||
cache_database: z
|
||||
.boolean()
|
||||
.meta({
|
||||
example: true,
|
||||
})
|
||||
.describe("Cache database connection status - true if cache database is reachable and running"),
|
||||
})
|
||||
.openapi({
|
||||
.meta({
|
||||
title: "Health Check Response",
|
||||
description: "Health check status for critical application dependencies",
|
||||
});
|
||||
})
|
||||
.describe("Health check status for critical application dependencies");
|
||||
|
||||
export type OverallHealthStatus = z.infer<typeof ZOverallHealthStatus>;
|
||||
|
||||
@@ -1,26 +1,22 @@
|
||||
import { z } from "zod";
|
||||
import { extendZodWithOpenApi } from "zod-openapi";
|
||||
import { ZContactAttributeKey } from "@formbricks/database/zod/contact-attribute-keys";
|
||||
|
||||
extendZodWithOpenApi(z);
|
||||
|
||||
export const ZContactAttributeKeyIdSchema = z
|
||||
.string()
|
||||
.cuid2()
|
||||
.openapi({
|
||||
ref: "contactAttributeKeyId",
|
||||
description: "The ID of the contact attribute key",
|
||||
.meta({
|
||||
id: "contactAttributeKeyId",
|
||||
param: {
|
||||
name: "id",
|
||||
in: "path",
|
||||
},
|
||||
});
|
||||
})
|
||||
.describe("The ID of the contact attribute key");
|
||||
|
||||
export const ZContactAttributeKeyUpdateSchema = ZContactAttributeKey.pick({
|
||||
name: true,
|
||||
description: true,
|
||||
}).openapi({
|
||||
ref: "contactAttributeKeyUpdate",
|
||||
}).meta({
|
||||
id: "contactAttributeKeyUpdate",
|
||||
description: "A contact attribute key to update. Key cannot be changed.",
|
||||
});
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ export const getContactAttributeKeysEndpoint: ZodOpenApiOperationObject = {
|
||||
description: "Gets contact attribute keys from the database.",
|
||||
tags: ["Management API - Contact Attribute Keys"],
|
||||
requestParams: {
|
||||
query: ZGetContactAttributeKeysFilter.sourceType(),
|
||||
query: ZGetContactAttributeKeysFilter,
|
||||
},
|
||||
responses: {
|
||||
"200": {
|
||||
|
||||
@@ -17,7 +17,7 @@ export const GET = async (request: NextRequest) =>
|
||||
authenticatedApiClient({
|
||||
request,
|
||||
schemas: {
|
||||
query: ZGetContactAttributeKeysFilter.sourceType(),
|
||||
query: ZGetContactAttributeKeysFilter,
|
||||
},
|
||||
handler: async ({ authentication, parsedInput }) => {
|
||||
const { query } = parsedInput;
|
||||
@@ -49,7 +49,7 @@ export const POST = async (request: NextRequest) =>
|
||||
authenticatedApiClient({
|
||||
request,
|
||||
schemas: {
|
||||
body: ZContactAttributeKeyInput.sourceType(),
|
||||
body: ZContactAttributeKeyInput,
|
||||
},
|
||||
handler: async ({ authentication, parsedInput, auditLog }) => {
|
||||
const { body } = parsedInput;
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import { z } from "zod";
|
||||
import { extendZodWithOpenApi } from "zod-openapi";
|
||||
import { ZContactAttributeKey } from "@formbricks/database/zod/contact-attribute-keys";
|
||||
import { isSafeIdentifier } from "@/lib/utils/safe-identifier";
|
||||
import { ZGetFilter } from "@/modules/api/v2/types/api-filter";
|
||||
|
||||
extendZodWithOpenApi(z);
|
||||
|
||||
export const ZGetContactAttributeKeysFilter = ZGetFilter.extend({
|
||||
environmentId: z.string().cuid2().optional().describe("The environment ID to filter by"),
|
||||
environmentId: z.cuid2().optional().describe("The environment ID to filter by"),
|
||||
})
|
||||
.refine(
|
||||
(data) => {
|
||||
@@ -37,15 +34,15 @@ export const ZContactAttributeKeyInput = ZContactAttributeKey.pick({
|
||||
// Enforce safe identifier format for key
|
||||
if (!isSafeIdentifier(data.key)) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
message:
|
||||
"Key must be a safe identifier: only lowercase letters, numbers, and underscores, and must start with a letter",
|
||||
path: ["key"],
|
||||
});
|
||||
}
|
||||
})
|
||||
.openapi({
|
||||
ref: "contactAttributeKeyInput",
|
||||
.meta({
|
||||
id: "contactAttributeKeyInput",
|
||||
description: "Input data for creating or updating a contact attribute",
|
||||
});
|
||||
|
||||
|
||||
@@ -1,25 +1,21 @@
|
||||
import { z } from "zod";
|
||||
import { extendZodWithOpenApi } from "zod-openapi";
|
||||
import { ZResponse } from "@formbricks/database/zod/responses";
|
||||
|
||||
extendZodWithOpenApi(z);
|
||||
|
||||
export const ZResponseIdSchema = z
|
||||
.string()
|
||||
.cuid2()
|
||||
.openapi({
|
||||
ref: "responseId",
|
||||
description: "The ID of the response",
|
||||
.meta({
|
||||
id: "responseId",
|
||||
param: {
|
||||
name: "id",
|
||||
in: "path",
|
||||
},
|
||||
});
|
||||
})
|
||||
.describe("The ID of the response");
|
||||
|
||||
export const ZResponseUpdateSchema = ZResponse.omit({
|
||||
id: true,
|
||||
surveyId: true,
|
||||
}).openapi({
|
||||
ref: "responseUpdate",
|
||||
}).meta({
|
||||
id: "responseUpdate",
|
||||
description: "A response to update.",
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ export const getResponsesEndpoint: ZodOpenApiOperationObject = {
|
||||
summary: "Get responses",
|
||||
description: "Gets responses from the database.",
|
||||
requestParams: {
|
||||
query: ZGetResponsesFilter.sourceType(),
|
||||
query: ZGetResponsesFilter,
|
||||
},
|
||||
tags: ["Management API - Responses"],
|
||||
responses: {
|
||||
|
||||
@@ -19,7 +19,7 @@ export const GET = async (request: NextRequest) =>
|
||||
authenticatedApiClient({
|
||||
request,
|
||||
schemas: {
|
||||
query: ZGetResponsesFilter.sourceType(),
|
||||
query: ZGetResponsesFilter,
|
||||
},
|
||||
handler: async ({ authentication, parsedInput }) => {
|
||||
const { query } = parsedInput;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ZResponse } from "@formbricks/database/zod/responses";
|
||||
import { ZGetFilter } from "@/modules/api/v2/types/api-filter";
|
||||
|
||||
export const ZGetResponsesFilter = ZGetFilter.extend({
|
||||
surveyId: z.string().cuid2().optional(),
|
||||
surveyId: z.cuid2().optional(),
|
||||
contactId: z.string().optional(),
|
||||
}).refine(
|
||||
(data) => {
|
||||
|
||||
@@ -23,7 +23,7 @@ export const getPersonalizedSurveyLink: ZodOpenApiOperationObject = {
|
||||
schema: makePartialSchema(
|
||||
z.object({
|
||||
data: z.object({
|
||||
surveyUrl: z.string().url(),
|
||||
surveyUrl: z.url(),
|
||||
expiresAt: z
|
||||
.string()
|
||||
.nullable()
|
||||
|
||||
@@ -1,23 +1,18 @@
|
||||
import { z } from "zod";
|
||||
import { extendZodWithOpenApi } from "zod-openapi";
|
||||
|
||||
extendZodWithOpenApi(z);
|
||||
|
||||
export const ZContactLinkParams = z.object({
|
||||
surveyId: z
|
||||
.string()
|
||||
.cuid2()
|
||||
.openapi({
|
||||
description: "The ID of the survey",
|
||||
.meta({
|
||||
param: { name: "surveyId", in: "path" },
|
||||
}),
|
||||
})
|
||||
.describe("The ID of the survey"),
|
||||
contactId: z
|
||||
.string()
|
||||
.cuid2()
|
||||
.openapi({
|
||||
description: "The ID of the contact",
|
||||
.meta({
|
||||
param: { name: "contactId", in: "path" },
|
||||
}),
|
||||
})
|
||||
.describe("The ID of the contact"),
|
||||
});
|
||||
|
||||
export const ZContactLinkQuery = z.object({
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
import { z } from "zod";
|
||||
import { extendZodWithOpenApi } from "zod-openapi";
|
||||
import { ZGetFilter } from "@/modules/api/v2/types/api-filter";
|
||||
|
||||
extendZodWithOpenApi(z);
|
||||
|
||||
export const ZContactLinksBySegmentParams = z.object({
|
||||
surveyId: z
|
||||
.string()
|
||||
.cuid2()
|
||||
.openapi({
|
||||
description: "The ID of the survey",
|
||||
.meta({
|
||||
param: { name: "surveyId", in: "path" },
|
||||
}),
|
||||
})
|
||||
.describe("The ID of the survey"),
|
||||
segmentId: z
|
||||
.string()
|
||||
.cuid2()
|
||||
.openapi({
|
||||
description: "The ID of the segment",
|
||||
.meta({
|
||||
param: { name: "segmentId", in: "path" },
|
||||
}),
|
||||
})
|
||||
.describe("The ID of the segment"),
|
||||
});
|
||||
|
||||
export const ZContactLinksBySegmentQuery = ZGetFilter.pick({
|
||||
@@ -30,7 +25,7 @@ export const ZContactLinksBySegmentQuery = ZGetFilter.pick({
|
||||
.min(1)
|
||||
.max(365)
|
||||
.nullish()
|
||||
.default(null)
|
||||
.prefault(null)
|
||||
.describe("Number of days until the generated JWT expires. If not provided, there is no expiration."),
|
||||
attributeKeys: z
|
||||
.string()
|
||||
@@ -52,7 +47,7 @@ export type TContactWithAttributes = {
|
||||
|
||||
export const ZContactLinkResponse = z.object({
|
||||
contactId: z.string().describe("The ID of the contact"),
|
||||
surveyUrl: z.string().url().describe("Personalized survey link"),
|
||||
surveyUrl: z.url().describe("Personalized survey link"),
|
||||
expiresAt: z.string().nullable().describe("The date and time the link expires, null if no expiration"),
|
||||
attributes: z.record(z.string(), z.string()).describe("The attributes of the contact"),
|
||||
});
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
import { z } from "zod";
|
||||
import { extendZodWithOpenApi } from "zod-openapi";
|
||||
|
||||
extendZodWithOpenApi(z);
|
||||
|
||||
export const surveyIdSchema = z
|
||||
.string()
|
||||
.cuid2()
|
||||
.openapi({
|
||||
ref: "surveyId",
|
||||
description: "The ID of the survey",
|
||||
.meta({
|
||||
id: "surveyId",
|
||||
param: {
|
||||
name: "id",
|
||||
in: "path",
|
||||
},
|
||||
});
|
||||
})
|
||||
.describe("The ID of the survey");
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { z } from "zod";
|
||||
import { extendZodWithOpenApi } from "zod-openapi";
|
||||
import { ZSurveyWithoutQuestionType } from "@formbricks/database/zod/surveys";
|
||||
|
||||
extendZodWithOpenApi(z);
|
||||
|
||||
export const ZGetSurveysFilter = z
|
||||
.object({
|
||||
limit: z.coerce.number().positive().min(1).max(100).optional().default(10),
|
||||
skip: z.coerce.number().nonnegative().optional().default(0),
|
||||
sortBy: z.enum(["createdAt", "updatedAt"]).optional().default("createdAt"),
|
||||
order: z.enum(["asc", "desc"]).optional().default("desc"),
|
||||
limit: z.coerce.number().positive().min(1).max(100).optional().prefault(10),
|
||||
skip: z.coerce.number().nonnegative().optional().prefault(0),
|
||||
sortBy: z.enum(["createdAt", "updatedAt"]).optional().prefault("createdAt"),
|
||||
order: z.enum(["asc", "desc"]).optional().prefault("desc"),
|
||||
startDate: z.coerce.date().optional(),
|
||||
endDate: z.coerce.date().optional(),
|
||||
surveyType: z.enum(["link", "app"]).optional(),
|
||||
@@ -23,7 +20,7 @@ export const ZGetSurveysFilter = z
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message: "startDate must be before endDate",
|
||||
error: "startDate must be before endDate",
|
||||
}
|
||||
);
|
||||
|
||||
@@ -69,8 +66,8 @@ export const ZSurveyInput = ZSurveyWithoutQuestionType.pick({
|
||||
inlineTriggers: true,
|
||||
displayPercentage: true,
|
||||
})
|
||||
.openapi({
|
||||
ref: "surveyInput",
|
||||
.meta({
|
||||
id: "surveyInput",
|
||||
description: "A survey input object for creating or updating surveys",
|
||||
});
|
||||
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
import { z } from "zod";
|
||||
import { extendZodWithOpenApi } from "zod-openapi";
|
||||
import { ZWebhook } from "@formbricks/database/zod/webhooks";
|
||||
|
||||
extendZodWithOpenApi(z);
|
||||
|
||||
export const ZWebhookIdSchema = z
|
||||
.string()
|
||||
.cuid2()
|
||||
.openapi({
|
||||
ref: "webhookId",
|
||||
description: "The ID of the webhook",
|
||||
.meta({
|
||||
id: "webhookId",
|
||||
param: {
|
||||
name: "id",
|
||||
in: "path",
|
||||
},
|
||||
});
|
||||
})
|
||||
.describe("The ID of the webhook");
|
||||
|
||||
export const ZWebhookUpdateSchema = ZWebhook.omit({
|
||||
id: true,
|
||||
@@ -22,7 +18,7 @@ export const ZWebhookUpdateSchema = ZWebhook.omit({
|
||||
updatedAt: true,
|
||||
environmentId: true,
|
||||
secret: true,
|
||||
}).openapi({
|
||||
ref: "webhookUpdate",
|
||||
}).meta({
|
||||
id: "webhookUpdate",
|
||||
description: "A webhook to update.",
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ export const getWebhooksEndpoint: ZodOpenApiOperationObject = {
|
||||
summary: "Get webhooks",
|
||||
description: "Gets webhooks from the database.",
|
||||
requestParams: {
|
||||
query: ZGetWebhooksFilter.sourceType(),
|
||||
query: ZGetWebhooksFilter,
|
||||
},
|
||||
tags: ["Management API - Webhooks"],
|
||||
responses: {
|
||||
|
||||
@@ -11,7 +11,7 @@ export const GET = async (request: NextRequest) =>
|
||||
authenticatedApiClient({
|
||||
request,
|
||||
schemas: {
|
||||
query: ZGetWebhooksFilter.sourceType(),
|
||||
query: ZGetWebhooksFilter,
|
||||
},
|
||||
handler: async ({ authentication, parsedInput }) => {
|
||||
const { query } = parsedInput;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ZWebhook } from "@formbricks/database/zod/webhooks";
|
||||
import { ZGetFilter } from "@/modules/api/v2/types/api-filter";
|
||||
|
||||
export const ZGetWebhooksFilter = ZGetFilter.extend({
|
||||
surveyIds: z.array(z.string().cuid2()).optional(),
|
||||
surveyIds: z.array(z.cuid2()).optional(),
|
||||
}).refine(
|
||||
(data) => {
|
||||
if (data.startDate && data.endDate && data.startDate > data.endDate) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as yaml from "yaml";
|
||||
import { z } from "zod";
|
||||
import { createDocument, extendZodWithOpenApi } from "zod-openapi";
|
||||
import { createDocument } from "zod-openapi";
|
||||
import { ZApiKeyData } from "@formbricks/database/zod/api-keys";
|
||||
import { ZContact } from "@formbricks/database/zod/contact";
|
||||
import { ZContactAttributeKey } from "@formbricks/database/zod/contact-attribute-keys";
|
||||
@@ -27,8 +26,6 @@ import { rolePaths } from "@/modules/api/v2/roles/lib/openapi";
|
||||
import { bulkContactPaths } from "@/modules/ee/contacts/api/v2/management/contacts/bulk/lib/openapi";
|
||||
import { contactPaths } from "@/modules/ee/contacts/api/v2/management/contacts/lib/openapi";
|
||||
|
||||
extendZodWithOpenApi(z);
|
||||
|
||||
const document = createDocument({
|
||||
openapi: "3.1.0",
|
||||
info: {
|
||||
|
||||
@@ -14,7 +14,7 @@ export const getProjectTeamsEndpoint: ZodOpenApiOperationObject = {
|
||||
summary: "Get project teams",
|
||||
description: "Gets projectTeams from the database.",
|
||||
requestParams: {
|
||||
query: ZGetProjectTeamsFilter.sourceType(),
|
||||
query: ZGetProjectTeamsFilter,
|
||||
path: z.object({
|
||||
organizationId: ZOrganizationIdSchema,
|
||||
}),
|
||||
|
||||
@@ -24,7 +24,7 @@ export async function GET(request: Request, props: { params: Promise<{ organizat
|
||||
return authenticatedApiClient({
|
||||
request,
|
||||
schemas: {
|
||||
query: ZGetProjectTeamsFilter.sourceType(),
|
||||
query: ZGetProjectTeamsFilter,
|
||||
params: z.object({ organizationId: ZOrganizationIdSchema }),
|
||||
},
|
||||
externalParams: props.params,
|
||||
|
||||
@@ -3,8 +3,8 @@ import { ZProjectTeam } from "@formbricks/database/zod/project-teams";
|
||||
import { ZGetFilter } from "@/modules/api/v2/types/api-filter";
|
||||
|
||||
export const ZGetProjectTeamsFilter = ZGetFilter.extend({
|
||||
teamId: z.string().cuid2().optional(),
|
||||
projectId: z.string().cuid2().optional(),
|
||||
teamId: z.cuid2().optional(),
|
||||
projectId: z.cuid2().optional(),
|
||||
}).refine(
|
||||
(data) => {
|
||||
if (data.startDate && data.endDate && data.startDate > data.endDate) {
|
||||
@@ -28,8 +28,8 @@ export const ZProjectTeamInput = ZProjectTeam.pick({
|
||||
export type TProjectTeamInput = z.infer<typeof ZProjectTeamInput>;
|
||||
|
||||
export const ZGetProjectTeamUpdateFilter = z.object({
|
||||
teamId: z.string().cuid2(),
|
||||
projectId: z.string().cuid2(),
|
||||
teamId: z.cuid2(),
|
||||
projectId: z.cuid2(),
|
||||
});
|
||||
|
||||
export const ZProjectZTeamUpdateSchema = ZProjectTeam.pick({
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
import { z } from "zod";
|
||||
import { extendZodWithOpenApi } from "zod-openapi";
|
||||
import { ZTeam } from "@formbricks/database/zod/teams";
|
||||
|
||||
extendZodWithOpenApi(z);
|
||||
|
||||
export const ZTeamIdSchema = z
|
||||
.string()
|
||||
.cuid2()
|
||||
.openapi({
|
||||
ref: "teamId",
|
||||
description: "The ID of the team",
|
||||
.meta({
|
||||
id: "teamId",
|
||||
param: {
|
||||
name: "id",
|
||||
in: "path",
|
||||
},
|
||||
});
|
||||
})
|
||||
.describe("The ID of the team");
|
||||
|
||||
export const ZTeamUpdateSchema = ZTeam.omit({
|
||||
id: true,
|
||||
|
||||
@@ -21,7 +21,7 @@ export const getTeamsEndpoint: ZodOpenApiOperationObject = {
|
||||
path: z.object({
|
||||
organizationId: ZOrganizationIdSchema,
|
||||
}),
|
||||
query: ZGetTeamsFilter.sourceType(),
|
||||
query: ZGetTeamsFilter,
|
||||
},
|
||||
tags: ["Organizations API - Teams"],
|
||||
responses: {
|
||||
|
||||
@@ -16,7 +16,7 @@ export const GET = async (request: NextRequest, props: { params: Promise<{ organ
|
||||
authenticatedApiClient({
|
||||
request,
|
||||
schemas: {
|
||||
query: ZGetTeamsFilter.sourceType(),
|
||||
query: ZGetTeamsFilter,
|
||||
params: z.object({ organizationId: ZOrganizationIdSchema }),
|
||||
},
|
||||
externalParams: props.params,
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
import { z } from "zod";
|
||||
import { extendZodWithOpenApi } from "zod-openapi";
|
||||
|
||||
extendZodWithOpenApi(z);
|
||||
|
||||
export const ZOrganizationIdSchema = z
|
||||
.string()
|
||||
.cuid2()
|
||||
.openapi({
|
||||
ref: "organizationId",
|
||||
description: "The ID of the organization",
|
||||
.meta({
|
||||
id: "organizationId",
|
||||
param: {
|
||||
name: "organizationId",
|
||||
in: "path",
|
||||
},
|
||||
});
|
||||
})
|
||||
.describe("The ID of the organization");
|
||||
|
||||
@@ -17,7 +17,7 @@ export const getUsersEndpoint: ZodOpenApiOperationObject = {
|
||||
path: z.object({
|
||||
organizationId: ZOrganizationIdSchema,
|
||||
}),
|
||||
query: ZGetUsersFilter.sourceType(),
|
||||
query: ZGetUsersFilter,
|
||||
},
|
||||
tags: ["Organizations API - Users"],
|
||||
responses: {
|
||||
|
||||
@@ -24,7 +24,7 @@ export const GET = async (request: NextRequest, props: { params: Promise<{ organ
|
||||
authenticatedApiClient({
|
||||
request,
|
||||
schemas: {
|
||||
query: ZGetUsersFilter.sourceType(),
|
||||
query: ZGetUsersFilter,
|
||||
params: z.object({ organizationId: ZOrganizationIdSchema }),
|
||||
},
|
||||
externalParams: props.params,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const ZGetFilter = z.object({
|
||||
limit: z.coerce.number().min(1).max(250).optional().default(50).describe("Number of items to return"),
|
||||
skip: z.coerce.number().min(0).optional().default(0).describe("Number of items to skip"),
|
||||
sortBy: z.enum(["createdAt", "updatedAt"]).optional().default("createdAt").describe("Sort by field"),
|
||||
order: z.enum(["asc", "desc"]).optional().default("desc").describe("Sort order"),
|
||||
limit: z.coerce.number().min(1).max(250).optional().prefault(50).describe("Number of items to return"),
|
||||
skip: z.coerce.number().min(0).optional().prefault(0).describe("Number of items to skip"),
|
||||
sortBy: z.enum(["createdAt", "updatedAt"]).optional().prefault("createdAt").describe("Sort by field"),
|
||||
order: z.enum(["asc", "desc"]).optional().prefault("desc").describe("Sort order"),
|
||||
startDate: z.coerce.date().optional().describe("Start date"),
|
||||
endDate: z.coerce.date().optional().describe("End date"),
|
||||
filterDateField: z.enum(["createdAt", "updatedAt"]).optional().describe("Date field to filter by"),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export function responseWithMetaSchema<T extends z.ZodTypeAny>(contentSchema: T) {
|
||||
export function responseWithMetaSchema<T extends z.ZodType>(contentSchema: T) {
|
||||
return z.object({
|
||||
data: z.array(contentSchema).optional(),
|
||||
meta: z
|
||||
|
||||
@@ -7,7 +7,12 @@ import { getUserByEmail } from "@/lib/user/service";
|
||||
import { actionClient } from "@/lib/utils/action-client";
|
||||
|
||||
const ZCreateEmailTokenAction = z.object({
|
||||
email: z.string().min(5).max(255).email({ message: "Invalid email" }),
|
||||
email: z
|
||||
.email({
|
||||
error: "Invalid email",
|
||||
})
|
||||
.min(5)
|
||||
.max(255),
|
||||
});
|
||||
|
||||
export const createEmailTokenAction = actionClient
|
||||
|
||||
@@ -13,7 +13,7 @@ import { Button } from "@/modules/ui/components/button";
|
||||
import { FormControl, FormError, FormField, FormItem } from "@/modules/ui/components/form";
|
||||
|
||||
const ZForgotPasswordForm = z.object({
|
||||
email: z.string().email(),
|
||||
email: z.email(),
|
||||
});
|
||||
|
||||
type TForgotPasswordForm = z.infer<typeof ZForgotPasswordForm>;
|
||||
|
||||
@@ -1,63 +1,62 @@
|
||||
import { Authenticator } from "@otplib/core";
|
||||
import type { AuthenticatorOptions } from "@otplib/core/authenticator";
|
||||
import { createDigest, createRandomBytes } from "@otplib/plugin-crypto";
|
||||
import { keyDecoder, keyEncoder } from "@otplib/plugin-thirty-two";
|
||||
import { OTP } from "otplib";
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
import { totpAuthenticatorCheck } from "./totp";
|
||||
|
||||
vi.mock("@otplib/core");
|
||||
vi.mock("@otplib/plugin-crypto");
|
||||
vi.mock("@otplib/plugin-thirty-two");
|
||||
vi.mock("otplib", () => ({
|
||||
OTP: vi.fn(),
|
||||
}));
|
||||
|
||||
describe("totpAuthenticatorCheck", () => {
|
||||
const token = "123456";
|
||||
const secret = "JBSWY3DPEHPK3PXP";
|
||||
const opts: Partial<AuthenticatorOptions> = { window: [1, 0] };
|
||||
const opts = { window: [1, 0] as [number, number] };
|
||||
|
||||
test("should check a TOTP token with a base32-encoded secret", () => {
|
||||
const checkMock = vi.fn().mockReturnValue(true);
|
||||
(Authenticator as unknown as vi.Mock).mockImplementation(() => ({
|
||||
check: checkMock,
|
||||
}));
|
||||
const verifySyncMock = vi.fn().mockReturnValue({ valid: true });
|
||||
(OTP as unknown as vi.Mock).mockImplementation(function OTP() {
|
||||
return {
|
||||
verifySync: verifySyncMock,
|
||||
};
|
||||
});
|
||||
|
||||
const result = totpAuthenticatorCheck(token, secret, opts);
|
||||
|
||||
expect(Authenticator).toHaveBeenCalledWith({
|
||||
createDigest,
|
||||
createRandomBytes,
|
||||
keyDecoder,
|
||||
keyEncoder,
|
||||
window: [1, 0],
|
||||
expect(verifySyncMock).toHaveBeenCalledWith({
|
||||
token,
|
||||
secret,
|
||||
period: 30,
|
||||
epochTolerance: [30, 0],
|
||||
});
|
||||
expect(checkMock).toHaveBeenCalledWith(token, secret);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
test("should use default window if none is provided", () => {
|
||||
const checkMock = vi.fn().mockReturnValue(true);
|
||||
(Authenticator as unknown as vi.Mock).mockImplementation(() => ({
|
||||
check: checkMock,
|
||||
}));
|
||||
const verifySyncMock = vi.fn().mockReturnValue({ valid: true });
|
||||
(OTP as unknown as vi.Mock).mockImplementation(function OTP() {
|
||||
return {
|
||||
verifySync: verifySyncMock,
|
||||
};
|
||||
});
|
||||
|
||||
const result = totpAuthenticatorCheck(token, secret);
|
||||
|
||||
expect(Authenticator).toHaveBeenCalledWith({
|
||||
createDigest,
|
||||
createRandomBytes,
|
||||
keyDecoder,
|
||||
keyEncoder,
|
||||
window: [1, 0],
|
||||
expect(verifySyncMock).toHaveBeenCalledWith({
|
||||
token,
|
||||
secret,
|
||||
period: 30,
|
||||
epochTolerance: [30, 0],
|
||||
});
|
||||
expect(checkMock).toHaveBeenCalledWith(token, secret);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
test("should throw an error for invalid token format", () => {
|
||||
(Authenticator as unknown as vi.Mock).mockImplementation(() => ({
|
||||
check: () => {
|
||||
throw new Error("Invalid token format");
|
||||
},
|
||||
}));
|
||||
(OTP as unknown as vi.Mock).mockImplementation(function OTP() {
|
||||
return {
|
||||
verifySync: () => {
|
||||
throw new Error("Invalid token format");
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
expect(() => {
|
||||
totpAuthenticatorCheck("invalidToken", secret);
|
||||
@@ -65,11 +64,13 @@ describe("totpAuthenticatorCheck", () => {
|
||||
});
|
||||
|
||||
test("should throw an error for invalid secret format", () => {
|
||||
(Authenticator as unknown as vi.Mock).mockImplementation(() => ({
|
||||
check: () => {
|
||||
throw new Error("Invalid secret format");
|
||||
},
|
||||
}));
|
||||
(OTP as unknown as vi.Mock).mockImplementation(function OTP() {
|
||||
return {
|
||||
verifySync: () => {
|
||||
throw new Error("Invalid secret format");
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
expect(() => {
|
||||
totpAuthenticatorCheck(token, "invalidSecret");
|
||||
@@ -77,10 +78,12 @@ describe("totpAuthenticatorCheck", () => {
|
||||
});
|
||||
|
||||
test("should return false if token verification fails", () => {
|
||||
const checkMock = vi.fn().mockReturnValue(false);
|
||||
(Authenticator as unknown as vi.Mock).mockImplementation(() => ({
|
||||
check: checkMock,
|
||||
}));
|
||||
const verifySyncMock = vi.fn().mockReturnValue({ valid: false });
|
||||
(OTP as unknown as vi.Mock).mockImplementation(function OTP() {
|
||||
return {
|
||||
verifySync: verifySyncMock,
|
||||
};
|
||||
});
|
||||
|
||||
const result = totpAuthenticatorCheck(token, secret);
|
||||
expect(result).toBe(false);
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import { Authenticator } from "@otplib/core";
|
||||
import type { AuthenticatorOptions } from "@otplib/core/authenticator";
|
||||
import { createDigest, createRandomBytes } from "@otplib/plugin-crypto";
|
||||
import { keyDecoder, keyEncoder } from "@otplib/plugin-thirty-two";
|
||||
import { OTP, type OTPVerifyOptions } from "otplib";
|
||||
|
||||
type TOTPAuthenticatorOptions = {
|
||||
window?: number | [number, number];
|
||||
period?: OTPVerifyOptions["period"];
|
||||
epoch?: OTPVerifyOptions["epoch"];
|
||||
t0?: OTPVerifyOptions["t0"];
|
||||
algorithm?: OTPVerifyOptions["algorithm"];
|
||||
digits?: OTPVerifyOptions["digits"];
|
||||
};
|
||||
|
||||
const createTotp = () => new OTP({ strategy: "totp" });
|
||||
|
||||
/**
|
||||
* Checks the validity of a TOTP token using a base32-encoded secret.
|
||||
@@ -14,16 +22,19 @@ import { keyDecoder, keyEncoder } from "@otplib/plugin-thirty-two";
|
||||
export const totpAuthenticatorCheck = (
|
||||
token: string,
|
||||
secret: string,
|
||||
opts: Partial<AuthenticatorOptions> = {}
|
||||
opts: TOTPAuthenticatorOptions = {}
|
||||
) => {
|
||||
const { window = [1, 0], ...rest } = opts;
|
||||
const authenticator = new Authenticator({
|
||||
createDigest,
|
||||
createRandomBytes,
|
||||
keyDecoder,
|
||||
keyEncoder,
|
||||
window,
|
||||
const { window = [1, 0], period = 30, ...rest } = opts;
|
||||
const [pastWindow, futureWindow] = Array.isArray(window) ? window : [window, window];
|
||||
const totp = createTotp();
|
||||
|
||||
const result = totp.verifySync({
|
||||
token,
|
||||
secret,
|
||||
period,
|
||||
epochTolerance: [pastWindow * period, futureWindow * period],
|
||||
...rest,
|
||||
});
|
||||
return authenticator.check(token, secret);
|
||||
|
||||
return result.valid;
|
||||
};
|
||||
|
||||
@@ -21,11 +21,15 @@ import { FormControl, FormError, FormField, FormItem } from "@/modules/ui/compon
|
||||
import { PasswordInput } from "@/modules/ui/components/password-input";
|
||||
|
||||
const ZLoginForm = z.object({
|
||||
email: z.string().email(),
|
||||
email: z.email(),
|
||||
password: z
|
||||
.string()
|
||||
.min(8, { message: "Password must be at least 8 characters long" })
|
||||
.max(128, { message: "Password must be 128 characters or less" }),
|
||||
.min(8, {
|
||||
error: "Password must be at least 8 characters long",
|
||||
})
|
||||
.max(128, {
|
||||
error: "Password must be 128 characters or less",
|
||||
}),
|
||||
totpCode: z.string().optional(),
|
||||
backupCode: z.string().optional(),
|
||||
});
|
||||
|
||||
@@ -24,7 +24,7 @@ import { PasswordChecks } from "./password-checks";
|
||||
|
||||
const ZSignupInput = z.object({
|
||||
name: ZUserName,
|
||||
email: z.string().email(),
|
||||
email: z.email(),
|
||||
password: ZUserPassword,
|
||||
});
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@ import { z } from "zod";
|
||||
|
||||
export const ZRateLimitConfig = z.object({
|
||||
/** Rate limit window in seconds */
|
||||
interval: z.number().int().positive().describe("Rate limit window in seconds"),
|
||||
interval: z.int().positive().describe("Rate limit window in seconds"),
|
||||
/** Maximum allowed requests per interval */
|
||||
allowedPerInterval: z.number().int().positive().describe("Maximum allowed requests per interval"),
|
||||
allowedPerInterval: z.int().positive().describe("Maximum allowed requests per interval"),
|
||||
/** Namespace for grouping rate limit per feature */
|
||||
namespace: z.string().min(1).describe("Namespace for grouping rate limit per feature"),
|
||||
});
|
||||
|
||||
@@ -73,12 +73,12 @@ export const ZAuditLogEventSchema = z.object({
|
||||
type: ZAuditTarget,
|
||||
}),
|
||||
status: ZAuditStatus,
|
||||
timestamp: z.string().datetime(),
|
||||
timestamp: z.iso.datetime(),
|
||||
organizationId: z.string(),
|
||||
ipAddress: z.string().optional(), // Not using the .ip() here because if we don't enabled it we want to put UNKNOWN_DATA string, to keep the same pattern as the other fields
|
||||
changes: z.record(z.any()).optional(),
|
||||
changes: z.record(z.string(), z.any()).optional(),
|
||||
eventId: z.string().optional(),
|
||||
apiUrl: z.string().url().optional(),
|
||||
apiUrl: z.url().optional(),
|
||||
});
|
||||
|
||||
export type TAuditLogEvent = z.infer<typeof ZAuditLogEventSchema>;
|
||||
|
||||
@@ -16,7 +16,7 @@ import { isSubscriptionCancelled } from "@/modules/ee/billing/api/lib/is-subscri
|
||||
|
||||
const ZUpgradePlanAction = z.object({
|
||||
environmentId: ZId,
|
||||
priceLookupKey: z.nativeEnum(STRIPE_PRICE_LOOKUP_KEYS),
|
||||
priceLookupKey: z.enum(STRIPE_PRICE_LOOKUP_KEYS),
|
||||
});
|
||||
|
||||
export const upgradePlanAction = authenticatedActionClient.schema(ZUpgradePlanAction).action(
|
||||
|
||||
@@ -8,7 +8,8 @@ import { getOrganization, updateOrganization } from "@/lib/organization/service"
|
||||
export const handleInvoiceFinalized = async (event: Stripe.Event) => {
|
||||
const invoice = event.data.object as Stripe.Invoice;
|
||||
|
||||
const subscriptionId = invoice.subscription as string;
|
||||
const subscription = invoice.parent?.subscription_details?.subscription;
|
||||
const subscriptionId = typeof subscription === "string" ? subscription : subscription?.id;
|
||||
if (!subscriptionId) {
|
||||
logger.warn({ invoiceId: invoice.id }, "Invoice finalized without subscription ID");
|
||||
return { status: 400, message: "No subscription ID found in invoice" };
|
||||
|
||||
@@ -34,9 +34,11 @@ export const isSubscriptionCancelled = async (
|
||||
|
||||
for (const subscription of subscriptions.data) {
|
||||
if (subscription.cancel_at_period_end) {
|
||||
const cancellationTimestamp =
|
||||
subscription.cancel_at ?? subscription.ended_at ?? subscription.canceled_at;
|
||||
return {
|
||||
cancelled: true,
|
||||
date: new Date(subscription.current_period_end * 1000),
|
||||
date: cancellationTimestamp ? new Date(cancellationTimestamp * 1000) : null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
|
||||
const ZGetContactsAction = z.object({
|
||||
environmentId: ZId,
|
||||
offset: z.number().int().nonnegative(),
|
||||
offset: z.int().nonnegative(),
|
||||
searchValue: z.string().optional(),
|
||||
});
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ export const POST = withV1ApiWrapper({
|
||||
{
|
||||
environmentId: params.environmentId,
|
||||
url: req.url,
|
||||
validationError: cuidValidation.error.errors[0]?.message,
|
||||
validationError: cuidValidation.error.issues[0]?.message,
|
||||
},
|
||||
"Invalid CUID v1 format detected"
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { isSafeIdentifier } from "@/lib/utils/safe-identifier";
|
||||
|
||||
export const ZContactAttributeKeyCreateInput = z.object({
|
||||
key: z.string().refine((val) => isSafeIdentifier(val), {
|
||||
message:
|
||||
error:
|
||||
"Key must be a safe identifier: only lowercase letters, numbers, and underscores, and must start with a letter",
|
||||
}),
|
||||
description: z.string().optional(),
|
||||
@@ -21,7 +21,7 @@ export const ZContactAttributeKeyUpdateInput = z.object({
|
||||
key: z
|
||||
.string()
|
||||
.refine((val) => isSafeIdentifier(val), {
|
||||
message:
|
||||
error:
|
||||
"Key must be a safe identifier: only lowercase letters, numbers, and underscores, and must start with a letter",
|
||||
})
|
||||
.optional(),
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
const ZCreateContactAttributeKeyAction = z.object({
|
||||
environmentId: ZId,
|
||||
key: z.string().refine((val) => isSafeIdentifier(val), {
|
||||
message:
|
||||
error:
|
||||
"Key must be a safe identifier: only lowercase letters, numbers, and underscores, and must start with a letter",
|
||||
}),
|
||||
name: z.string().optional(),
|
||||
|
||||
@@ -84,7 +84,7 @@ export const UploadContactsCSVButton = ({
|
||||
const parsedRecords = ZContactCSVUploadResponse.safeParse(records);
|
||||
if (!parsedRecords.success) {
|
||||
console.error("Error parsing CSV:", parsedRecords.error);
|
||||
setError(parsedRecords.error.errors[0].message);
|
||||
setError(parsedRecords.error.issues[0].message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ import {
|
||||
} from "@formbricks/types/contact-attribute-key";
|
||||
|
||||
export const ZContact = z.object({
|
||||
id: z.string().cuid2(),
|
||||
id: z.cuid2(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date(),
|
||||
environmentId: z.string().cuid2(),
|
||||
environmentId: z.cuid2(),
|
||||
});
|
||||
|
||||
const ZContactTableAttributeData = z.object({
|
||||
@@ -29,7 +29,7 @@ export const ZContactTableData = z.object({
|
||||
});
|
||||
|
||||
export const ZContactWithAttributes = ZContact.extend({
|
||||
attributes: z.record(z.string()),
|
||||
attributes: z.record(z.string(), z.string()),
|
||||
});
|
||||
|
||||
export type TContactWithAttributes = z.infer<typeof ZContactWithAttributes>;
|
||||
@@ -60,22 +60,26 @@ export const ZContactCSVDuplicateAction = z.enum(["skip", "update", "overwrite"]
|
||||
export type TContactCSVDuplicateAction = z.infer<typeof ZContactCSVDuplicateAction>;
|
||||
|
||||
export const ZContactCSVUploadResponse = z
|
||||
.array(z.record(z.string()))
|
||||
.max(10000, { message: "Maximum 10000 records allowed at a time." })
|
||||
.array(z.record(z.string(), z.string()))
|
||||
.max(10000, {
|
||||
error: "Maximum 10000 records allowed at a time.",
|
||||
})
|
||||
.superRefine((data, ctx) => {
|
||||
for (const record of data) {
|
||||
if (!Object.keys(record).includes("email")) {
|
||||
return ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: "Missing email field for one or more records",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!record.email) {
|
||||
return ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: "Email field is empty for one or more records",
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,10 +88,11 @@ export const ZContactCSVUploadResponse = z
|
||||
const emailSet = new Set(emails);
|
||||
|
||||
if (emails.length !== emailSet.size) {
|
||||
return ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: "Duplicate emails found in the records",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// check for duplicate userIds if present
|
||||
@@ -95,10 +100,11 @@ export const ZContactCSVUploadResponse = z
|
||||
if (userIds?.length > 0) {
|
||||
const userIdSet = new Set(userIds);
|
||||
if (userIds.length !== userIdSet.size) {
|
||||
return ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: "Duplicate userIds found in the records",
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -109,10 +115,11 @@ export const ZContactCSVAttributeMap = z.record(z.string(), z.string()).superRef
|
||||
const values = Object.values(attributeMap);
|
||||
|
||||
if (new Set(values).size !== values.length) {
|
||||
return ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: "Attribute map contains duplicate values",
|
||||
});
|
||||
return;
|
||||
}
|
||||
});
|
||||
export type TContactCSVAttributeMap = z.infer<typeof ZContactCSVAttributeMap>;
|
||||
@@ -142,17 +149,17 @@ export const validateEmailAttribute = (
|
||||
|
||||
if (!emailAttr?.value) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
message: `Email attribute is required${indexSuffix}`,
|
||||
});
|
||||
return { isValid: false };
|
||||
}
|
||||
|
||||
// Check email format
|
||||
const parsedEmail = z.string().email().safeParse(emailAttr.value);
|
||||
const parsedEmail = z.email().safeParse(emailAttr.value);
|
||||
if (!parsedEmail.success) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
message: `Invalid email format${indexSuffix}`,
|
||||
});
|
||||
return { emailAttr, isValid: false };
|
||||
@@ -183,7 +190,7 @@ export const validateUniqueAttributeKeys = (
|
||||
if (duplicateKeys.length > 0) {
|
||||
const indexSuffix = contactIndex !== undefined ? ` for contact at index ${contactIndex}` : "";
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
message: `Duplicate attribute keys found${indexSuffix}. Please ensure each attribute key is unique`,
|
||||
params: {
|
||||
duplicateKeys,
|
||||
@@ -194,10 +201,12 @@ export const validateUniqueAttributeKeys = (
|
||||
};
|
||||
|
||||
export const ZContactBulkUploadRequest = z.object({
|
||||
environmentId: z.string().cuid2(),
|
||||
environmentId: z.cuid2(),
|
||||
contacts: z
|
||||
.array(ZContactBulkUploadContact)
|
||||
.max(250, { message: "Maximum 250 contacts allowed at a time." })
|
||||
.max(250, {
|
||||
error: "Maximum 250 contacts allowed at a time.",
|
||||
})
|
||||
.superRefine((contacts, ctx) => {
|
||||
// Track all data in a single pass
|
||||
const seenEmails = new Set<string>();
|
||||
@@ -236,7 +245,7 @@ export const ZContactBulkUploadRequest = z.object({
|
||||
// Report all validation issues after the single pass
|
||||
if (duplicateEmails.size > 0) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
message: "Duplicate emails found in the records, please ensure each email is unique.",
|
||||
params: {
|
||||
duplicateEmails: Array.from(duplicateEmails),
|
||||
@@ -246,7 +255,7 @@ export const ZContactBulkUploadRequest = z.object({
|
||||
|
||||
if (duplicateUserIds.size > 0) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
message: "Duplicate userIds found in the records, please ensure each userId is unique.",
|
||||
params: {
|
||||
duplicateUserIds: Array.from(duplicateUserIds),
|
||||
@@ -276,21 +285,21 @@ export type TContactBulkUploadResponseSuccess = TContactBulkUploadResponseBase &
|
||||
|
||||
// Schema for single contact creation - simplified with flat attributes
|
||||
export const ZContactCreateRequest = z.object({
|
||||
environmentId: z.string().cuid2(),
|
||||
environmentId: z.cuid2(),
|
||||
attributes: z.record(z.string(), z.string()).superRefine((attributes, ctx) => {
|
||||
// Check if email attribute exists and is valid
|
||||
const email = attributes.email;
|
||||
if (!email) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
message: "Email attribute is required",
|
||||
});
|
||||
} else {
|
||||
// Check email format
|
||||
const parsedEmail = z.string().email().safeParse(email);
|
||||
const parsedEmail = z.email().safeParse(email);
|
||||
if (!parsedEmail.success) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
message: "Invalid email format",
|
||||
});
|
||||
}
|
||||
@@ -302,9 +311,9 @@ export type TContactCreateRequest = z.infer<typeof ZContactCreateRequest>;
|
||||
|
||||
// Type for contact response with flattened attributes
|
||||
export const ZContactResponse = z.object({
|
||||
id: z.string().cuid2(),
|
||||
id: z.cuid2(),
|
||||
createdAt: z.date(),
|
||||
environmentId: z.string().cuid2(),
|
||||
environmentId: z.cuid2(),
|
||||
attributes: z.record(z.string(), z.string()),
|
||||
});
|
||||
|
||||
@@ -336,7 +345,7 @@ export const ZEditContactAttributesForm = z.object({
|
||||
if (indices.length > 1) {
|
||||
indices.forEach((index) => {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
message: `Duplicate key: ${key}`,
|
||||
path: [index, "key"],
|
||||
});
|
||||
@@ -358,13 +367,13 @@ export const ZEditContactAttributesForm = z.object({
|
||||
// When both are empty, show "Either email or userId is required" on both fields
|
||||
if (emailIndex !== -1 && userIdIndex !== -1) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
message: "Either email or userId is required",
|
||||
path: [emailIndex, "value"],
|
||||
});
|
||||
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
message: "Either email or userId is required",
|
||||
path: [userIdIndex, "value"],
|
||||
});
|
||||
@@ -374,10 +383,10 @@ export const ZEditContactAttributesForm = z.object({
|
||||
// Validate email format if key is "email" and has a value
|
||||
attributes.forEach((attr, index) => {
|
||||
if (attr.key === "email" && attr.value && attr.value.trim() !== "") {
|
||||
const emailResult = z.string().email().safeParse(attr.value);
|
||||
const emailResult = z.email().safeParse(attr.value);
|
||||
if (!emailResult.success) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
message: "Invalid email format",
|
||||
path: [index, "value"],
|
||||
});
|
||||
@@ -416,7 +425,7 @@ export const createEditContactAttributesSchema = (
|
||||
if (dataType === "date") {
|
||||
if (!hasValue) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
message: t("environments.contacts.date_value_required"),
|
||||
path: ["attributes", index, "value"],
|
||||
});
|
||||
@@ -426,7 +435,7 @@ export const createEditContactAttributesSchema = (
|
||||
const date = new Date(attr.value);
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
message: t("environments.contacts.invalid_date_format"),
|
||||
path: ["attributes", index, "value"],
|
||||
});
|
||||
@@ -434,7 +443,7 @@ export const createEditContactAttributesSchema = (
|
||||
} else if (dataType === "number") {
|
||||
if (!hasValue) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
message: t("environments.contacts.number_value_required"),
|
||||
path: ["attributes", index, "value"],
|
||||
});
|
||||
@@ -443,7 +452,7 @@ export const createEditContactAttributesSchema = (
|
||||
// Validate number format
|
||||
if (Number.isNaN(Number(attr.value))) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
message: t("environments.contacts.invalid_number_format"),
|
||||
path: ["attributes", index, "value"],
|
||||
});
|
||||
|
||||
@@ -120,14 +120,16 @@ export const QuotaModal = ({
|
||||
defaultValues,
|
||||
resolver: zodResolver(
|
||||
quotaResponseCount > 0
|
||||
? ZSurveyQuotaInput.innerType().extend({
|
||||
limit: z.number().min(quotaResponseCount, {
|
||||
message: t(
|
||||
"environments.surveys.edit.quotas.limit_must_be_greater_than_or_equal_to_the_number_of_responses",
|
||||
{ value: quotaResponseCount }
|
||||
),
|
||||
}),
|
||||
})
|
||||
? ZSurveyQuotaInput.and(
|
||||
z.object({
|
||||
limit: z.number().min(quotaResponseCount, {
|
||||
message: t(
|
||||
"environments.surveys.edit.quotas.limit_must_be_greater_than_or_equal_to_the_number_of_responses",
|
||||
{ value: quotaResponseCount }
|
||||
),
|
||||
}),
|
||||
})
|
||||
)
|
||||
: ZSurveyQuotaInput
|
||||
),
|
||||
mode: "onSubmit",
|
||||
|
||||
@@ -10,7 +10,7 @@ import { validateInputs } from "@/lib/utils/validate";
|
||||
import { createTeamMembership } from "@/modules/auth/signup/lib/team";
|
||||
|
||||
export const getOrganizationByTeamId = reactCache(async (teamId: string): Promise<Organization | null> => {
|
||||
validateInputs([teamId, z.string().cuid2()]);
|
||||
validateInputs([teamId, z.cuid2()]);
|
||||
|
||||
try {
|
||||
const team = await prisma.team.findUnique({
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
import { ZTeamSettingsFormSchema } from "@/modules/ee/teams/team-list/types/team";
|
||||
|
||||
const ZCreateTeamAction = z.object({
|
||||
organizationId: z.string().cuid(),
|
||||
organizationId: z.cuid(),
|
||||
name: z.string().trim().min(1, "Team name is required"),
|
||||
});
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ export const ZOtherTeam = z.object({
|
||||
export type TOtherTeam = z.infer<typeof ZOtherTeam>;
|
||||
|
||||
export const ZOrganizationTeam = z.object({
|
||||
id: z.string().cuid2(),
|
||||
id: z.cuid2(),
|
||||
name: z.string(),
|
||||
});
|
||||
|
||||
@@ -69,7 +69,9 @@ export const ZTeamSettingsFormSchema = z.object({
|
||||
role: ZTeamRole,
|
||||
})
|
||||
)
|
||||
.min(1, { message: "Please add at least one member" }),
|
||||
.min(1, {
|
||||
error: "Please add at least one member",
|
||||
}),
|
||||
projects: z
|
||||
.array(
|
||||
z.object({
|
||||
@@ -77,7 +79,9 @@ export const ZTeamSettingsFormSchema = z.object({
|
||||
permission: ZTeamPermission,
|
||||
})
|
||||
)
|
||||
.min(1, { message: "Please add at least one project" }),
|
||||
.min(1, {
|
||||
error: "Please add at least one project",
|
||||
}),
|
||||
});
|
||||
|
||||
export type TTeamSettingsFormSchema = z.infer<typeof ZTeamSettingsFormSchema>;
|
||||
@@ -94,9 +98,14 @@ export type TTeamMember = z.infer<typeof ZTeamMember>;
|
||||
|
||||
export const ZTeam = z.object({
|
||||
id: z.string(),
|
||||
name: z.string({ message: "Team name is required" }).trim().min(1, {
|
||||
message: "Team name must be at least 1 character long",
|
||||
}),
|
||||
name: z
|
||||
.string({
|
||||
error: "Team name is required",
|
||||
})
|
||||
.trim()
|
||||
.min(1, {
|
||||
error: "Team name must be at least 1 character long",
|
||||
}),
|
||||
teamUsers: z.array(ZTeamMember),
|
||||
});
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ const ZDisableTwoFactorFormState = z
|
||||
backupCode: z.string().optional(),
|
||||
})
|
||||
.refine((data) => (!!data.code && !data.backupCode) || (!data.code && !!data.backupCode), {
|
||||
message: "Please provide either the code OR the backup code",
|
||||
path: ["code"],
|
||||
error: "Please provide either the code OR the backup code",
|
||||
});
|
||||
|
||||
type TDisableTwoFactorFormState = z.infer<typeof ZDisableTwoFactorFormState>;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import crypto from "crypto";
|
||||
import { authenticator } from "otplib";
|
||||
import { generateSecret, generateURI } from "otplib";
|
||||
import qrcode from "qrcode";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { InvalidInputError, ResourceNotFoundError } from "@formbricks/types/errors";
|
||||
@@ -19,7 +19,7 @@ export const setupTwoFactorAuth = async (
|
||||
}> => {
|
||||
// This generates a secret 32 characters in length. Do not modify the number of
|
||||
// bytes without updating the sanity checks in the enable and login endpoints.
|
||||
const secret = authenticator.generateSecret(20);
|
||||
const secret = generateSecret({ length: 20 });
|
||||
|
||||
// generate backup codes with 10 character length
|
||||
const backupCodes = Array.from(Array(10), () => crypto.randomBytes(5).toString("hex"));
|
||||
@@ -64,7 +64,7 @@ export const setupTwoFactorAuth = async (
|
||||
});
|
||||
|
||||
const name = user.email || user.name || user.id.toString();
|
||||
const keyUri = authenticator.keyuri(name, "Formbricks", secret);
|
||||
const keyUri = generateURI({ label: name, issuer: "Formbricks", secret });
|
||||
const dataUri = await qrcode.toDataURL(keyUri);
|
||||
|
||||
return { secret, keyUri, dataUri, backupCodes };
|
||||
|
||||
@@ -37,7 +37,7 @@ export const updateProjectBranding = async (
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (error instanceof z.ZodError) {
|
||||
logger.error(error.errors, "Error updating project branding");
|
||||
logger.error(error.issues, "Error updating project branding");
|
||||
}
|
||||
throw new ValidationError("Data validation of project failed");
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { ZProject } from "@formbricks/types/project";
|
||||
|
||||
export const ZApiKeyEnvironmentPermission = z.object({
|
||||
environmentId: z.string(),
|
||||
permission: z.nativeEnum(ApiKeyPermission),
|
||||
permission: z.enum(ApiKeyPermission),
|
||||
});
|
||||
|
||||
export const ZApiKeyCreateInput = ZApiKey.required({
|
||||
@@ -45,7 +45,7 @@ export type TOrganizationProject = z.infer<typeof OrganizationProject>;
|
||||
|
||||
export const TApiKeyEnvironmentPermission = z.object({
|
||||
environmentId: z.string(),
|
||||
permission: z.nativeEnum(ApiKeyPermission),
|
||||
permission: z.enum(ApiKeyPermission),
|
||||
});
|
||||
|
||||
export type TApiKeyEnvironmentPermission = z.infer<typeof TApiKeyEnvironmentPermission>;
|
||||
|
||||
@@ -43,10 +43,18 @@ export const IndividualInviteTab = ({
|
||||
}: IndividualInviteTabProps) => {
|
||||
const ZFormSchema = z.object({
|
||||
name: ZUserName,
|
||||
email: z.string().min(1, { message: "Email is required" }).email({ message: "Invalid email" }),
|
||||
email: z
|
||||
.email({
|
||||
error: "Invalid email",
|
||||
})
|
||||
.min(1, {
|
||||
error: "Email is required",
|
||||
}),
|
||||
role: ZOrganizationRole,
|
||||
teamIds: showTeamAdminRestrictions
|
||||
? z.array(ZId).min(1, { message: "Team admins must select at least one team" })
|
||||
? z.array(ZId).min(1, {
|
||||
error: "Team admins must select at least one team",
|
||||
})
|
||||
: z.array(ZId),
|
||||
});
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ export const updateProject = async (
|
||||
return project;
|
||||
} catch (error) {
|
||||
if (error instanceof z.ZodError) {
|
||||
logger.error(error.errors, "Error updating project");
|
||||
logger.error(error.issues, "Error updating project");
|
||||
}
|
||||
throw new ValidationError("Data validation of project failed");
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { validateInputs } from "@/lib/utils/validate";
|
||||
|
||||
export const getProjectByEnvironmentId = reactCache(
|
||||
async (environmentId: string): Promise<Project | null> => {
|
||||
validateInputs([environmentId, z.string().cuid2()]);
|
||||
validateInputs([environmentId, z.cuid2()]);
|
||||
|
||||
let projectPrisma;
|
||||
|
||||
|
||||
@@ -12,11 +12,12 @@ export const ZInvitee = ZInvite.pick({
|
||||
export type TInvitee = z.infer<typeof ZInvitee>;
|
||||
|
||||
export const ZInviteMembersFormSchema = z.record(
|
||||
z.string(),
|
||||
ZInvite.pick({
|
||||
email: true,
|
||||
name: true,
|
||||
}).extend({
|
||||
email: z.string().email("Invalid email address"),
|
||||
email: z.email("Invalid email address"),
|
||||
name: ZUserName,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -30,7 +30,9 @@ describe("fileUpload", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
// Mock FileReader
|
||||
global.FileReader = vi.fn(() => mockFileReader) as any;
|
||||
global.FileReader = vi.fn(function FileReader() {
|
||||
return mockFileReader;
|
||||
}) as any;
|
||||
global.atob = (base64) => Buffer.from(base64, "base64").toString("binary");
|
||||
});
|
||||
|
||||
@@ -191,7 +193,9 @@ describe("fileUploadModule.toBase64", () => {
|
||||
result: "data:text/plain;base64,aGVsbG8=",
|
||||
};
|
||||
|
||||
globalThis.FileReader = vi.fn(() => mockFileReaderInstance as unknown as FileReader) as any;
|
||||
globalThis.FileReader = vi.fn(function FileReader() {
|
||||
return mockFileReaderInstance as unknown as FileReader;
|
||||
}) as any;
|
||||
|
||||
const promise = fileUploadModule.toBase64(dummyFile);
|
||||
|
||||
@@ -213,7 +217,9 @@ describe("fileUploadModule.toBase64", () => {
|
||||
result: null,
|
||||
};
|
||||
|
||||
globalThis.FileReader = vi.fn(() => mockFileReaderInstance as unknown as FileReader) as any;
|
||||
globalThis.FileReader = vi.fn(function FileReader() {
|
||||
return mockFileReaderInstance as unknown as FileReader;
|
||||
}) as any;
|
||||
|
||||
const promise = fileUploadModule.toBase64(dummyFile);
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import { checkSpamProtectionPermission } from "@/modules/survey/lib/permission";
|
||||
import { getOrganizationBilling } from "@/modules/survey/lib/survey";
|
||||
|
||||
const ZCreateSurveyAction = z.object({
|
||||
environmentId: z.string().cuid2(),
|
||||
environmentId: z.cuid2(),
|
||||
surveyBody: ZSurveyCreateInput,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ActionClass, Prisma } from "@prisma/client";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { logger } from "@formbricks/logger";
|
||||
import { DatabaseError, InvalidInputError, ResourceNotFoundError } from "@formbricks/types/errors";
|
||||
@@ -134,7 +134,12 @@ export const createSurvey = async (
|
||||
}
|
||||
};
|
||||
|
||||
const checkTriggersValidity = (triggers: TSurvey["triggers"], actionClasses: ActionClass[]) => {
|
||||
type TriggerWithActionClassId = { actionClass: { id: string } };
|
||||
|
||||
const checkTriggersValidity = (
|
||||
triggers: TriggerWithActionClassId[] | null | undefined,
|
||||
actionClasses: Array<{ id: string }>
|
||||
) => {
|
||||
if (!triggers) return;
|
||||
|
||||
// check if all the triggers are valid
|
||||
@@ -153,14 +158,14 @@ const checkTriggersValidity = (triggers: TSurvey["triggers"], actionClasses: Act
|
||||
};
|
||||
|
||||
export const handleTriggerUpdates = (
|
||||
updatedTriggers: TSurvey["triggers"],
|
||||
currentTriggers: TSurvey["triggers"],
|
||||
actionClasses: ActionClass[]
|
||||
updatedTriggers: TriggerWithActionClassId[] | null | undefined,
|
||||
currentTriggers: TriggerWithActionClassId[] | null | undefined,
|
||||
actionClasses: Array<{ id: string }>
|
||||
) => {
|
||||
if (!updatedTriggers) return {};
|
||||
checkTriggersValidity(updatedTriggers, actionClasses);
|
||||
|
||||
const currentTriggerIds = currentTriggers.map((trigger) => trigger.actionClass.id);
|
||||
const currentTriggerIds = (currentTriggers ?? []).map((trigger) => trigger.actionClass.id);
|
||||
const updatedTriggerIds = updatedTriggers.map((trigger) => trigger.actionClass.id);
|
||||
|
||||
// added triggers are triggers that are not in the current triggers and are there in the new triggers
|
||||
@@ -169,7 +174,7 @@ export const handleTriggerUpdates = (
|
||||
);
|
||||
|
||||
// deleted triggers are triggers that are not in the new triggers and are there in the current triggers
|
||||
const deletedTriggers = currentTriggers.filter(
|
||||
const deletedTriggers = (currentTriggers ?? []).filter(
|
||||
(trigger) => !updatedTriggerIds.includes(trigger.actionClass.id)
|
||||
);
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ export const updateSurveyAction = authenticatedActionClient.schema(ZSurvey).acti
|
||||
);
|
||||
|
||||
const ZRefetchProjectAction = z.object({
|
||||
projectId: z.string().cuid2(),
|
||||
projectId: z.cuid2(),
|
||||
});
|
||||
|
||||
export const refetchProjectAction = authenticatedActionClient
|
||||
@@ -236,7 +236,7 @@ const isValidUnsplashUrl = (url: string): boolean => {
|
||||
};
|
||||
|
||||
const ZTriggerDownloadUnsplashImageAction = z.object({
|
||||
downloadUrl: z.string().url(),
|
||||
downloadUrl: z.url(),
|
||||
});
|
||||
|
||||
export const triggerDownloadUnsplashImageAction = actionClient
|
||||
|
||||
@@ -191,7 +191,7 @@ export const SurveyMenuBar = ({
|
||||
const validateSurveyWithZod = (): boolean => {
|
||||
const localSurveyValidation = ZSurvey.safeParse(localSurvey);
|
||||
if (!localSurveyValidation.success) {
|
||||
const currentError = localSurveyValidation.error.errors[0];
|
||||
const currentError = localSurveyValidation.error.issues[0];
|
||||
|
||||
if (currentError.path[0] === "blocks") {
|
||||
const blockIdx = currentError.path[1];
|
||||
|
||||
@@ -168,7 +168,7 @@ describe("action-utils", () => {
|
||||
validateActionNameUniqueness(data, ["existingAction"], ctx, mockT);
|
||||
|
||||
expect(ctx.addIssue).toHaveBeenCalledWith({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
path: ["name"],
|
||||
message: 'Action with name "existingAction" already exists',
|
||||
});
|
||||
@@ -201,7 +201,7 @@ describe("action-utils", () => {
|
||||
validateActionKeyUniqueness(data, ["existingKey"], ctx, mockT);
|
||||
|
||||
expect(ctx.addIssue).toHaveBeenCalledWith({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
path: ["key"],
|
||||
message: 'Action with key "existingKey" already exists',
|
||||
});
|
||||
@@ -251,7 +251,7 @@ describe("action-utils", () => {
|
||||
validateCssSelector(data, ctx, mockT);
|
||||
|
||||
expect(ctx.addIssue).toHaveBeenCalledWith({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
path: ["noCodeConfig", "elementSelector", "cssSelector"],
|
||||
message: "Invalid CSS selector",
|
||||
});
|
||||
@@ -309,7 +309,7 @@ describe("action-utils", () => {
|
||||
validateUrlFilterRegex(data, ctx, mockT);
|
||||
|
||||
expect(ctx.addIssue).toHaveBeenCalledWith({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
path: ["noCodeConfig", "urlFilters", 0, "value"],
|
||||
message: "Invalid regex pattern",
|
||||
});
|
||||
@@ -368,7 +368,7 @@ describe("action-utils", () => {
|
||||
|
||||
expect(ctx.addIssue).toHaveBeenCalledTimes(1);
|
||||
expect(ctx.addIssue).toHaveBeenCalledWith({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
path: ["noCodeConfig", "urlFilters", 1, "value"],
|
||||
message: "Invalid regex pattern",
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@ export const validateActionNameUniqueness = (
|
||||
) => {
|
||||
if (data.name && actionClassNames.includes(data.name)) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
path: ["name"],
|
||||
message: t("environments.actions.action_with_name_already_exists", { name: data.name }),
|
||||
});
|
||||
@@ -54,7 +54,7 @@ export const validateActionKeyUniqueness = (
|
||||
) => {
|
||||
if (data.type === "code" && data.key && actionClassKeys.includes(data.key)) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
path: ["key"],
|
||||
message: t("environments.actions.action_with_key_already_exists", { key: data.key }),
|
||||
});
|
||||
@@ -72,7 +72,7 @@ export const validateCssSelector = (data: TActionClassInput, ctx: z.RefinementCt
|
||||
!isValidCssSelector(data.noCodeConfig.elementSelector.cssSelector)
|
||||
) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
path: ["noCodeConfig", "elementSelector", "cssSelector"],
|
||||
message: t("environments.actions.invalid_css_selector"),
|
||||
});
|
||||
@@ -91,7 +91,7 @@ export const validateUrlFilterRegex = (data: TActionClassInput, ctx: z.Refinemen
|
||||
new RegExp(urlFilter.value);
|
||||
} catch {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
code: "custom",
|
||||
path: ["noCodeConfig", "urlFilters", i, "value"],
|
||||
message: t("environments.actions.invalid_regex"),
|
||||
});
|
||||
|
||||
@@ -40,43 +40,43 @@ describe("getLogicRules", () => {
|
||||
expect(openTextTextRules.options).toEqual([
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.equals)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_equal)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.contains)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.contains,
|
||||
value: ZSurveyLogicConditionsOperator.enum.contains,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_contain)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotContain,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotContain,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.starts_with)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.startsWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.startsWith,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_start_with)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotStartWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotStartWith,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.ends_with)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.endsWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.endsWith,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_end_with)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEndWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEndWith,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_submitted)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_skipped)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -85,19 +85,19 @@ describe("getLogicRules", () => {
|
||||
const openTextNumberRules = logicRules.element[TSurveyQuestionTypeEnum.OpenText + ".number"];
|
||||
expect(openTextNumberRules).toBeDefined();
|
||||
expect(openTextNumberRules.options).toEqual([
|
||||
{ label: "=", value: ZSurveyLogicConditionsOperator.Enum.equals },
|
||||
{ label: "!=", value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual },
|
||||
{ label: ">", value: ZSurveyLogicConditionsOperator.Enum.isGreaterThan },
|
||||
{ label: "<", value: ZSurveyLogicConditionsOperator.Enum.isLessThan },
|
||||
{ label: ">=", value: ZSurveyLogicConditionsOperator.Enum.isGreaterThanOrEqual },
|
||||
{ label: "<=", value: ZSurveyLogicConditionsOperator.Enum.isLessThanOrEqual },
|
||||
{ label: "=", value: ZSurveyLogicConditionsOperator.enum.equals },
|
||||
{ label: "!=", value: ZSurveyLogicConditionsOperator.enum.doesNotEqual },
|
||||
{ label: ">", value: ZSurveyLogicConditionsOperator.enum.isGreaterThan },
|
||||
{ label: "<", value: ZSurveyLogicConditionsOperator.enum.isLessThan },
|
||||
{ label: ">=", value: ZSurveyLogicConditionsOperator.enum.isGreaterThanOrEqual },
|
||||
{ label: "<=", value: ZSurveyLogicConditionsOperator.enum.isLessThanOrEqual },
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_submitted)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_skipped)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -108,23 +108,23 @@ describe("getLogicRules", () => {
|
||||
expect(rules.options).toEqual([
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.equals)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_equal)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.equals_one_of)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equalsOneOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equalsOneOf,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_submitted)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_skipped)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -135,35 +135,35 @@ describe("getLogicRules", () => {
|
||||
expect(rules.options).toEqual([
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.equals)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_equal)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_include_one_of)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotIncludeOneOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotIncludeOneOf,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_include_all_of)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotIncludeAllOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotIncludeAllOf,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.includes_all_of)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.includesAllOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.includesAllOf,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.includes_one_of)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.includesOneOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.includesOneOf,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_submitted)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_skipped)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -174,35 +174,35 @@ describe("getLogicRules", () => {
|
||||
expect(rules.options).toEqual([
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.equals)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_equal)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_include_one_of)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotIncludeOneOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotIncludeOneOf,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_include_all_of)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotIncludeAllOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotIncludeAllOf,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.includes_all_of)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.includesAllOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.includesAllOf,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.includes_one_of)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.includesOneOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.includesOneOf,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_submitted)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_skipped)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -211,19 +211,19 @@ describe("getLogicRules", () => {
|
||||
const rules = logicRules.element[TSurveyQuestionTypeEnum.Rating];
|
||||
expect(rules).toBeDefined();
|
||||
expect(rules.options).toEqual([
|
||||
{ label: "=", value: ZSurveyLogicConditionsOperator.Enum.equals },
|
||||
{ label: "!=", value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual },
|
||||
{ label: ">", value: ZSurveyLogicConditionsOperator.Enum.isGreaterThan },
|
||||
{ label: "<", value: ZSurveyLogicConditionsOperator.Enum.isLessThan },
|
||||
{ label: ">=", value: ZSurveyLogicConditionsOperator.Enum.isGreaterThanOrEqual },
|
||||
{ label: "<=", value: ZSurveyLogicConditionsOperator.Enum.isLessThanOrEqual },
|
||||
{ label: "=", value: ZSurveyLogicConditionsOperator.enum.equals },
|
||||
{ label: "!=", value: ZSurveyLogicConditionsOperator.enum.doesNotEqual },
|
||||
{ label: ">", value: ZSurveyLogicConditionsOperator.enum.isGreaterThan },
|
||||
{ label: "<", value: ZSurveyLogicConditionsOperator.enum.isLessThan },
|
||||
{ label: ">=", value: ZSurveyLogicConditionsOperator.enum.isGreaterThanOrEqual },
|
||||
{ label: "<=", value: ZSurveyLogicConditionsOperator.enum.isLessThanOrEqual },
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_submitted)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_skipped)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -232,19 +232,19 @@ describe("getLogicRules", () => {
|
||||
const rules = logicRules.element[TSurveyQuestionTypeEnum.NPS];
|
||||
expect(rules).toBeDefined();
|
||||
expect(rules.options).toEqual([
|
||||
{ label: "=", value: ZSurveyLogicConditionsOperator.Enum.equals },
|
||||
{ label: "!=", value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual },
|
||||
{ label: ">", value: ZSurveyLogicConditionsOperator.Enum.isGreaterThan },
|
||||
{ label: "<", value: ZSurveyLogicConditionsOperator.Enum.isLessThan },
|
||||
{ label: ">=", value: ZSurveyLogicConditionsOperator.Enum.isGreaterThanOrEqual },
|
||||
{ label: "<=", value: ZSurveyLogicConditionsOperator.Enum.isLessThanOrEqual },
|
||||
{ label: "=", value: ZSurveyLogicConditionsOperator.enum.equals },
|
||||
{ label: "!=", value: ZSurveyLogicConditionsOperator.enum.doesNotEqual },
|
||||
{ label: ">", value: ZSurveyLogicConditionsOperator.enum.isGreaterThan },
|
||||
{ label: "<", value: ZSurveyLogicConditionsOperator.enum.isLessThan },
|
||||
{ label: ">=", value: ZSurveyLogicConditionsOperator.enum.isGreaterThanOrEqual },
|
||||
{ label: "<=", value: ZSurveyLogicConditionsOperator.enum.isLessThanOrEqual },
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_submitted)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_skipped)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -255,11 +255,11 @@ describe("getLogicRules", () => {
|
||||
expect(rules.options).toEqual([
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_clicked)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isClicked,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isClicked,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_not_clicked)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isNotClicked,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isNotClicked,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -270,11 +270,11 @@ describe("getLogicRules", () => {
|
||||
expect(rules.options).toEqual([
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_accepted)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isAccepted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isAccepted,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_skipped)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -285,27 +285,27 @@ describe("getLogicRules", () => {
|
||||
expect(rules.options).toEqual([
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.equals)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_equal)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_before)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isBefore,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isBefore,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_after)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isAfter,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isAfter,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_submitted)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_skipped)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -316,11 +316,11 @@ describe("getLogicRules", () => {
|
||||
expect(rules.options).toEqual([
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_submitted)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_skipped)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -331,11 +331,11 @@ describe("getLogicRules", () => {
|
||||
expect(rules.options).toEqual([
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_submitted)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_skipped)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -346,11 +346,11 @@ describe("getLogicRules", () => {
|
||||
expect(rules.options).toEqual([
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_booked)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isBooked,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isBooked,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_skipped)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -361,15 +361,15 @@ describe("getLogicRules", () => {
|
||||
expect(rules.options).toEqual([
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_partially_submitted)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isPartiallySubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isPartiallySubmitted,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_completely_submitted)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isCompletelySubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isCompletelySubmitted,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_skipped)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -380,23 +380,23 @@ describe("getLogicRules", () => {
|
||||
expect(rules.options).toEqual([
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.equals)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_equal)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_empty)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isEmpty,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isEmpty,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_not_empty)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isNotEmpty,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isNotEmpty,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_any_of)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isAnyOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isAnyOf,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -407,11 +407,11 @@ describe("getLogicRules", () => {
|
||||
expect(rules.options).toEqual([
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_submitted)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_skipped)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -422,11 +422,11 @@ describe("getLogicRules", () => {
|
||||
expect(rules.options).toEqual([
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_submitted)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_skipped)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -439,35 +439,35 @@ describe("getLogicRules", () => {
|
||||
expect(rules.options).toEqual([
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.equals)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_equal)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.contains)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.contains,
|
||||
value: ZSurveyLogicConditionsOperator.enum.contains,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_contain)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotContain,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotContain,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.starts_with)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.startsWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.startsWith,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_start_with)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotStartWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotStartWith,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.ends_with)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.endsWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.endsWith,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_end_with)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEndWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEndWith,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -476,12 +476,12 @@ describe("getLogicRules", () => {
|
||||
const rules = logicRules["variable.number"];
|
||||
expect(rules).toBeDefined();
|
||||
expect(rules.options).toEqual([
|
||||
{ label: "=", value: ZSurveyLogicConditionsOperator.Enum.equals },
|
||||
{ label: "!=", value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual },
|
||||
{ label: ">", value: ZSurveyLogicConditionsOperator.Enum.isGreaterThan },
|
||||
{ label: "<", value: ZSurveyLogicConditionsOperator.Enum.isLessThan },
|
||||
{ label: ">=", value: ZSurveyLogicConditionsOperator.Enum.isGreaterThanOrEqual },
|
||||
{ label: "<=", value: ZSurveyLogicConditionsOperator.Enum.isLessThanOrEqual },
|
||||
{ label: "=", value: ZSurveyLogicConditionsOperator.enum.equals },
|
||||
{ label: "!=", value: ZSurveyLogicConditionsOperator.enum.doesNotEqual },
|
||||
{ label: ">", value: ZSurveyLogicConditionsOperator.enum.isGreaterThan },
|
||||
{ label: "<", value: ZSurveyLogicConditionsOperator.enum.isLessThan },
|
||||
{ label: ">=", value: ZSurveyLogicConditionsOperator.enum.isGreaterThanOrEqual },
|
||||
{ label: "<=", value: ZSurveyLogicConditionsOperator.enum.isLessThanOrEqual },
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -493,43 +493,43 @@ describe("getLogicRules", () => {
|
||||
expect(rules.options).toEqual([
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.equals)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_equal)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.contains)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.contains,
|
||||
value: ZSurveyLogicConditionsOperator.enum.contains,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_contain)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotContain,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotContain,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.starts_with)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.startsWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.startsWith,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_start_with)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotStartWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotStartWith,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.ends_with)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.endsWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.endsWith,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.does_not_end_with)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEndWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEndWith,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_set)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSet,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSet,
|
||||
},
|
||||
{
|
||||
label: "mockTranslate(environments.surveys.edit.is_not_set)",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isNotSet,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isNotSet,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -540,10 +540,10 @@ describe("TLogicRuleOption type", () => {
|
||||
test("should be compatible with the options structure", () => {
|
||||
const sampleOption: TLogicRuleOption[number] = {
|
||||
label: "Test Label",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
};
|
||||
// This test mainly serves as a type check during compilation
|
||||
expect(sampleOption.label).toBe("Test Label");
|
||||
expect(sampleOption.value).toBe(ZSurveyLogicConditionsOperator.Enum.equals);
|
||||
expect(sampleOption.value).toBe(ZSurveyLogicConditionsOperator.enum.equals);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,43 +9,43 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: t("environments.surveys.edit.equals"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_equal"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.contains"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.contains,
|
||||
value: ZSurveyLogicConditionsOperator.enum.contains,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_contain"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotContain,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotContain,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.starts_with"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.startsWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.startsWith,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_start_with"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotStartWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotStartWith,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.ends_with"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.endsWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.endsWith,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_end_with"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEndWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEndWith,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_submitted"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_skipped"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -53,35 +53,35 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: "=",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: "!=",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: ">",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isGreaterThan,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isGreaterThan,
|
||||
},
|
||||
{
|
||||
label: "<",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isLessThan,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isLessThan,
|
||||
},
|
||||
{
|
||||
label: ">=",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isGreaterThanOrEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isGreaterThanOrEqual,
|
||||
},
|
||||
{
|
||||
label: "<=",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isLessThanOrEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isLessThanOrEqual,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_submitted"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_skipped"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -89,23 +89,23 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: t("environments.surveys.edit.equals"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_equal"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.equals_one_of"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equalsOneOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equalsOneOf,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_submitted"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_skipped"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -113,35 +113,35 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: t("environments.surveys.edit.equals"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_equal"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_include_one_of"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotIncludeOneOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotIncludeOneOf,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_include_all_of"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotIncludeAllOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotIncludeAllOf,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.includes_all_of"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.includesAllOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.includesAllOf,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.includes_one_of"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.includesOneOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.includesOneOf,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_submitted"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_skipped"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -149,35 +149,35 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: t("environments.surveys.edit.equals"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_equal"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_include_one_of"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotIncludeOneOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotIncludeOneOf,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_include_all_of"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotIncludeAllOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotIncludeAllOf,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.includes_all_of"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.includesAllOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.includesAllOf,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.includes_one_of"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.includesOneOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.includesOneOf,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_submitted"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_skipped"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -185,35 +185,35 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: "=",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: "!=",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: ">",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isGreaterThan,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isGreaterThan,
|
||||
},
|
||||
{
|
||||
label: "<",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isLessThan,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isLessThan,
|
||||
},
|
||||
{
|
||||
label: ">=",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isGreaterThanOrEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isGreaterThanOrEqual,
|
||||
},
|
||||
{
|
||||
label: "<=",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isLessThanOrEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isLessThanOrEqual,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_submitted"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_skipped"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -221,35 +221,35 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: "=",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: "!=",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: ">",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isGreaterThan,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isGreaterThan,
|
||||
},
|
||||
{
|
||||
label: "<",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isLessThan,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isLessThan,
|
||||
},
|
||||
{
|
||||
label: ">=",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isGreaterThanOrEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isGreaterThanOrEqual,
|
||||
},
|
||||
{
|
||||
label: "<=",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isLessThanOrEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isLessThanOrEqual,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_submitted"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_skipped"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -257,11 +257,11 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: t("environments.surveys.edit.is_clicked"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isClicked,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isClicked,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_not_clicked"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isNotClicked,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isNotClicked,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -269,11 +269,11 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: t("environments.surveys.edit.is_accepted"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isAccepted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isAccepted,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_skipped"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -281,27 +281,27 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: t("environments.surveys.edit.equals"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_equal"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_before"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isBefore,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isBefore,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_after"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isAfter,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isAfter,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_submitted"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_skipped"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -309,11 +309,11 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: t("environments.surveys.edit.is_submitted"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_skipped"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -321,11 +321,11 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: t("environments.surveys.edit.is_submitted"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_skipped"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -333,11 +333,11 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: t("environments.surveys.edit.is_booked"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isBooked,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isBooked,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_skipped"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -345,15 +345,15 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: t("environments.surveys.edit.is_partially_submitted"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isPartiallySubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isPartiallySubmitted,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_completely_submitted"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isCompletelySubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isCompletelySubmitted,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_skipped"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -361,24 +361,24 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: t("environments.surveys.edit.equals"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_equal"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_empty"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isEmpty,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isEmpty,
|
||||
},
|
||||
|
||||
{
|
||||
label: t("environments.surveys.edit.is_not_empty"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isNotEmpty,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isNotEmpty,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_any_of"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isAnyOf,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isAnyOf,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -386,11 +386,11 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: t("environments.surveys.edit.is_submitted"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_skipped"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -398,11 +398,11 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: t("environments.surveys.edit.is_submitted"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSubmitted,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_skipped"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSkipped,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -411,35 +411,35 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: t("environments.surveys.edit.equals"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_equal"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.contains"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.contains,
|
||||
value: ZSurveyLogicConditionsOperator.enum.contains,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_contain"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotContain,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotContain,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.starts_with"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.startsWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.startsWith,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_start_with"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotStartWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotStartWith,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.ends_with"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.endsWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.endsWith,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_end_with"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEndWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEndWith,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -447,27 +447,27 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: "=",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: "!=",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: ">",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isGreaterThan,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isGreaterThan,
|
||||
},
|
||||
{
|
||||
label: "<",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isLessThan,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isLessThan,
|
||||
},
|
||||
{
|
||||
label: ">=",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isGreaterThanOrEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isGreaterThanOrEqual,
|
||||
},
|
||||
{
|
||||
label: "<=",
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isLessThanOrEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isLessThanOrEqual,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -475,43 +475,43 @@ export const getLogicRules = (t: TFunction) => {
|
||||
options: [
|
||||
{
|
||||
label: t("environments.surveys.edit.equals"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.equals,
|
||||
value: ZSurveyLogicConditionsOperator.enum.equals,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_equal"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEqual,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEqual,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.contains"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.contains,
|
||||
value: ZSurveyLogicConditionsOperator.enum.contains,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_contain"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotContain,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotContain,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.starts_with"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.startsWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.startsWith,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_start_with"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotStartWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotStartWith,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.ends_with"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.endsWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.endsWith,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.does_not_end_with"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.doesNotEndWith,
|
||||
value: ZSurveyLogicConditionsOperator.enum.doesNotEndWith,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_set"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isSet,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isSet,
|
||||
},
|
||||
{
|
||||
label: t("environments.surveys.edit.is_not_set"),
|
||||
value: ZSurveyLogicConditionsOperator.Enum.isNotSet,
|
||||
value: ZSurveyLogicConditionsOperator.enum.isNotSet,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ActionClass, Prisma } from "@prisma/client";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { logger } from "@formbricks/logger";
|
||||
import { DatabaseError, InvalidInputError, ResourceNotFoundError } from "@formbricks/types/errors";
|
||||
@@ -286,7 +286,12 @@ export const updateSurvey = async (updatedSurvey: TSurvey): Promise<TSurvey> =>
|
||||
}
|
||||
};
|
||||
|
||||
export const checkTriggersValidity = (triggers: TSurvey["triggers"], actionClasses: ActionClass[]) => {
|
||||
type TriggerWithActionClassId = { actionClass: { id: string } };
|
||||
|
||||
export const checkTriggersValidity = (
|
||||
triggers: TriggerWithActionClassId[] | null | undefined,
|
||||
actionClasses: Array<{ id: string }>
|
||||
) => {
|
||||
if (!triggers) return;
|
||||
|
||||
// check if all the triggers are valid
|
||||
@@ -305,14 +310,14 @@ export const checkTriggersValidity = (triggers: TSurvey["triggers"], actionClass
|
||||
};
|
||||
|
||||
export const handleTriggerUpdates = (
|
||||
updatedTriggers: TSurvey["triggers"],
|
||||
currentTriggers: TSurvey["triggers"],
|
||||
actionClasses: ActionClass[]
|
||||
updatedTriggers: TriggerWithActionClassId[] | null | undefined,
|
||||
currentTriggers: TriggerWithActionClassId[] | null | undefined,
|
||||
actionClasses: Array<{ id: string }>
|
||||
) => {
|
||||
if (!updatedTriggers) return {};
|
||||
checkTriggersValidity(updatedTriggers, actionClasses);
|
||||
|
||||
const currentTriggerIds = currentTriggers.map((trigger) => trigger.actionClass.id);
|
||||
const currentTriggerIds = (currentTriggers ?? []).map((trigger) => trigger.actionClass.id);
|
||||
const updatedTriggerIds = updatedTriggers.map((trigger) => trigger.actionClass.id);
|
||||
|
||||
// added triggers are triggers that are not in the current triggers and are there in the new triggers
|
||||
@@ -321,7 +326,7 @@ export const handleTriggerUpdates = (
|
||||
);
|
||||
|
||||
// deleted triggers are triggers that are not in the new triggers and are there in the current triggers
|
||||
const deletedTriggers = currentTriggers.filter(
|
||||
const deletedTriggers = (currentTriggers ?? []).filter(
|
||||
(trigger) => !updatedTriggerIds.includes(trigger.actionClass.id)
|
||||
);
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ import { z } from "zod";
|
||||
export const ZCreateSurveyFollowUpFormSchema = z.object({
|
||||
followUpName: z.string().trim().min(1, "Name is required"),
|
||||
triggerType: z.enum(["response", "endings"]),
|
||||
endingIds: z.array(z.string().cuid2()).nullable(),
|
||||
endingIds: z.array(z.cuid2()).nullable(),
|
||||
emailTo: z.string().trim().min(1, "To is required"),
|
||||
replyTo: z.array(z.string().email()).min(1, "Replies must have at least one email"),
|
||||
replyTo: z.array(z.email()).min(1, "Replies must have at least one email"),
|
||||
subject: z.string().trim().min(1, "Subject is required"),
|
||||
body: z.string().trim().min(1, "Body is required"),
|
||||
attachResponseData: z.boolean(),
|
||||
|
||||
@@ -7,21 +7,19 @@ import { ZSurveyType } from "@formbricks/types/surveys/types";
|
||||
* Validates essential fields for security/functionality but allows incomplete survey data.
|
||||
* Full validation (ZSurvey) is enforced when publishing.
|
||||
*/
|
||||
export const ZSurveyDraft = z
|
||||
.object({
|
||||
// Essential fields - strictly validated
|
||||
id: ZId,
|
||||
status: z.literal("draft"),
|
||||
environmentId: ZId,
|
||||
type: ZSurveyType,
|
||||
name: z.string().min(1, "Survey name is required"),
|
||||
export const ZSurveyDraft = z.looseObject({
|
||||
// Essential fields - strictly validated
|
||||
id: ZId,
|
||||
status: z.literal("draft"),
|
||||
environmentId: ZId,
|
||||
type: ZSurveyType,
|
||||
name: z.string().min(1, "Survey name is required"),
|
||||
|
||||
// Required fields for database operations - loosely validated
|
||||
blocks: z.array(z.record(z.unknown())).optional(),
|
||||
triggers: z.array(z.record(z.unknown())).optional(),
|
||||
endings: z.array(z.record(z.unknown())).optional(),
|
||||
segment: z.record(z.unknown()).nullable().optional(),
|
||||
})
|
||||
.passthrough(); // Allow all other fields without validation
|
||||
// Required fields for database operations - loosely validated
|
||||
blocks: z.array(z.record(z.string(), z.unknown())).optional(),
|
||||
triggers: z.array(z.record(z.string(), z.unknown())).optional(),
|
||||
endings: z.array(z.record(z.string(), z.unknown())).optional(),
|
||||
segment: z.record(z.string(), z.unknown()).nullable().optional(),
|
||||
}); // Allow all other fields without validation
|
||||
|
||||
export type TSurveyDraft = z.infer<typeof ZSurveyDraft>;
|
||||
|
||||
@@ -30,7 +30,7 @@ const evaluateFollowUp = async (
|
||||
const logoUrl = organization.whitelabel?.logoUrl ?? "";
|
||||
|
||||
// Check if 'to' is a direct email address (team member or user email)
|
||||
const parsedEmailTo = z.string().email().safeParse(to);
|
||||
const parsedEmailTo = z.email().safeParse(to);
|
||||
if (parsedEmailTo.success) {
|
||||
// 'to' is a valid email address, send email directly
|
||||
await sendFollowUpEmail({
|
||||
@@ -62,7 +62,7 @@ const evaluateFollowUp = async (
|
||||
|
||||
if (typeof toValueFromResponse === "string") {
|
||||
// parse this string to check for an email:
|
||||
const parsedResult = z.string().email().safeParse(toValueFromResponse);
|
||||
const parsedResult = z.email().safeParse(toValueFromResponse);
|
||||
if (parsedResult.success) {
|
||||
// send email to this email address
|
||||
await sendFollowUpEmail({
|
||||
@@ -98,7 +98,7 @@ const evaluateFollowUp = async (
|
||||
};
|
||||
}
|
||||
|
||||
const parsedResult = z.string().email().safeParse(emailAddress);
|
||||
const parsedResult = z.email().safeParse(emailAddress);
|
||||
if (parsedResult.data) {
|
||||
await sendFollowUpEmail({
|
||||
followUp,
|
||||
|
||||
@@ -6,7 +6,7 @@ import { DatabaseError } from "@formbricks/types/errors";
|
||||
import { validateInputs } from "@/lib/utils/validate";
|
||||
|
||||
export const getActionClasses = reactCache(async (environmentId: string): Promise<ActionClass[]> => {
|
||||
validateInputs([environmentId, z.string().cuid2()]);
|
||||
validateInputs([environmentId, z.cuid2()]);
|
||||
|
||||
try {
|
||||
return await prisma.actionClass.findMany({
|
||||
|
||||
@@ -30,7 +30,7 @@ export const sendLinkSurveyEmailAction = actionClient
|
||||
});
|
||||
|
||||
const ZValidateSurveyPinAction = z.object({
|
||||
surveyId: z.string().cuid2(),
|
||||
surveyId: z.cuid2(),
|
||||
pin: z.string(),
|
||||
});
|
||||
|
||||
@@ -55,8 +55,8 @@ export const validateSurveyPinAction = actionClient
|
||||
});
|
||||
|
||||
const ZIsSurveyResponsePresentAction = z.object({
|
||||
surveyId: z.string().cuid2(),
|
||||
email: z.string().email(),
|
||||
surveyId: z.cuid2(),
|
||||
email: z.email(),
|
||||
});
|
||||
|
||||
export const isSurveyResponsePresentAction = actionClient
|
||||
|
||||
@@ -32,7 +32,7 @@ interface VerifyEmailProps {
|
||||
}
|
||||
|
||||
const ZVerifyEmailInput = z.object({
|
||||
email: z.string().email(),
|
||||
email: z.email(),
|
||||
});
|
||||
type TVerifyEmailInput = z.infer<typeof ZVerifyEmailInput>;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
} from "@/modules/survey/list/lib/survey";
|
||||
|
||||
const ZGetSurveyAction = z.object({
|
||||
surveyId: z.string().cuid2(),
|
||||
surveyId: z.cuid2(),
|
||||
});
|
||||
|
||||
export const getSurveyAction = authenticatedActionClient
|
||||
@@ -51,8 +51,8 @@ export const getSurveyAction = authenticatedActionClient
|
||||
});
|
||||
|
||||
const ZCopySurveyToOtherEnvironmentAction = z.object({
|
||||
surveyId: z.string().cuid2(),
|
||||
targetEnvironmentId: z.string().cuid2(),
|
||||
surveyId: z.cuid2(),
|
||||
targetEnvironmentId: z.cuid2(),
|
||||
});
|
||||
|
||||
export const copySurveyToOtherEnvironmentAction = authenticatedActionClient
|
||||
@@ -141,7 +141,7 @@ export const copySurveyToOtherEnvironmentAction = authenticatedActionClient
|
||||
);
|
||||
|
||||
const ZGetProjectsByEnvironmentIdAction = z.object({
|
||||
environmentId: z.string().cuid2(),
|
||||
environmentId: z.cuid2(),
|
||||
});
|
||||
|
||||
export const getProjectsByEnvironmentIdAction = authenticatedActionClient
|
||||
@@ -168,7 +168,7 @@ export const getProjectsByEnvironmentIdAction = authenticatedActionClient
|
||||
});
|
||||
|
||||
const ZDeleteSurveyAction = z.object({
|
||||
surveyId: z.string().cuid2(),
|
||||
surveyId: z.cuid2(),
|
||||
});
|
||||
|
||||
export const deleteSurveyAction = authenticatedActionClient.schema(ZDeleteSurveyAction).action(
|
||||
@@ -201,9 +201,9 @@ export const deleteSurveyAction = authenticatedActionClient.schema(ZDeleteSurvey
|
||||
);
|
||||
|
||||
const ZGenerateSingleUseIdAction = z.object({
|
||||
surveyId: z.string().cuid2(),
|
||||
surveyId: z.cuid2(),
|
||||
isEncrypted: z.boolean(),
|
||||
count: z.number().min(1).max(5000).default(1),
|
||||
count: z.number().min(1).max(5000).prefault(1),
|
||||
});
|
||||
|
||||
export const generateSingleUseIdsAction = authenticatedActionClient
|
||||
@@ -229,7 +229,7 @@ export const generateSingleUseIdsAction = authenticatedActionClient
|
||||
});
|
||||
|
||||
const ZGetSurveysAction = z.object({
|
||||
environmentId: z.string().cuid2(),
|
||||
environmentId: z.cuid2(),
|
||||
limit: z.number().optional(),
|
||||
offset: z.number().optional(),
|
||||
filterCriteria: ZSurveyFilterCriteria.optional(),
|
||||
|
||||
@@ -45,7 +45,7 @@ export const getProjectIdIfEnvironmentExists = reactCache(
|
||||
|
||||
export const getEnvironment = reactCache(
|
||||
async (environmentId: string): Promise<Pick<Environment, "id" | "type"> | null> => {
|
||||
validateInputs([environmentId, z.string().cuid2()]);
|
||||
validateInputs([environmentId, z.cuid2()]);
|
||||
|
||||
try {
|
||||
const environment = await prisma.environment.findUnique({
|
||||
|
||||
@@ -603,7 +603,7 @@ export const copySurveyToOtherEnvironment = async (
|
||||
};
|
||||
|
||||
export const getSurveyCount = reactCache(async (environmentId: string): Promise<number> => {
|
||||
validateInputs([environmentId, z.string().cuid2()]);
|
||||
validateInputs([environmentId, z.cuid2()]);
|
||||
try {
|
||||
const surveyCount = await prisma.survey.count({
|
||||
where: {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { getOrganizationIdFromSurveyId, getProjectIdFromSurveyId } from "@/lib/u
|
||||
import { updateSurveySlug } from "@/modules/survey/lib/slug";
|
||||
|
||||
const ZUpdateSurveySlugAction = z.object({
|
||||
surveyId: z.string().cuid2(),
|
||||
surveyId: z.cuid2(),
|
||||
slug: ZSurveySlug,
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@ export const updateSurveySlugAction = authenticatedActionClient
|
||||
});
|
||||
|
||||
const ZRemoveSurveySlugAction = z.object({
|
||||
surveyId: z.string().cuid2(),
|
||||
surveyId: z.cuid2(),
|
||||
});
|
||||
|
||||
export const removeSurveySlugAction = authenticatedActionClient
|
||||
|
||||
@@ -42,18 +42,18 @@
|
||||
"@lexical/react": "0.41.0",
|
||||
"@lexical/rich-text": "0.41.0",
|
||||
"@lexical/table": "0.41.0",
|
||||
"@opentelemetry/auto-instrumentations-node": "0.70.1",
|
||||
"@opentelemetry/exporter-metrics-otlp-http": "0.212.0",
|
||||
"@opentelemetry/exporter-prometheus": "0.212.0",
|
||||
"@opentelemetry/exporter-trace-otlp-http": "0.212.0",
|
||||
"@opentelemetry/resources": "2.5.1",
|
||||
"@opentelemetry/sdk-metrics": "2.5.1",
|
||||
"@opentelemetry/sdk-node": "0.212.0",
|
||||
"@opentelemetry/sdk-trace-base": "2.5.1",
|
||||
"@opentelemetry/auto-instrumentations-node": "0.71.0",
|
||||
"@opentelemetry/exporter-metrics-otlp-http": "0.213.0",
|
||||
"@opentelemetry/exporter-prometheus": "0.213.0",
|
||||
"@opentelemetry/exporter-trace-otlp-http": "0.213.0",
|
||||
"@opentelemetry/resources": "2.6.0",
|
||||
"@opentelemetry/sdk-metrics": "2.6.0",
|
||||
"@opentelemetry/sdk-node": "0.213.0",
|
||||
"@opentelemetry/sdk-trace-base": "2.6.0",
|
||||
"@opentelemetry/semantic-conventions": "1.40.0",
|
||||
"@paralleldrive/cuid2": "2.3.1",
|
||||
"@prisma/client": "6.19.2",
|
||||
"@prisma/instrumentation": "6.19.2",
|
||||
"@paralleldrive/cuid2": "3.3.0",
|
||||
"@prisma/client": "7.4.2",
|
||||
"@prisma/instrumentation": "7.4.2",
|
||||
"@radix-ui/react-checkbox": "1.3.3",
|
||||
"@radix-ui/react-collapsible": "1.1.12",
|
||||
"@radix-ui/react-dialog": "1.1.15",
|
||||
@@ -79,55 +79,55 @@
|
||||
"class-variance-authority": "0.7.1",
|
||||
"clsx": "2.1.1",
|
||||
"cmdk": "1.1.1",
|
||||
"csv-parse": "5.6.0",
|
||||
"csv-parse": "6.1.0",
|
||||
"date-fns": "4.1.0",
|
||||
"file-loader": "6.2.0",
|
||||
"framer-motion": "12.34.4",
|
||||
"googleapis": "148.0.0",
|
||||
"framer-motion": "12.35.0",
|
||||
"googleapis": "171.4.0",
|
||||
"heic-convert": "2.1.0",
|
||||
"https-proxy-agent": "7.0.6",
|
||||
"i18next": "25.8.13",
|
||||
"i18next": "25.8.14",
|
||||
"i18next-icu": "2.4.3",
|
||||
"i18next-resources-to-backend": "1.2.1",
|
||||
"jiti": "2.6.1",
|
||||
"jsonwebtoken": "9.0.3",
|
||||
"lexical": "0.41.0",
|
||||
"lodash": "4.17.23",
|
||||
"lucide-react": "0.576.0",
|
||||
"lucide-react": "0.577.0",
|
||||
"markdown-it": "14.1.1",
|
||||
"next": "16.1.6",
|
||||
"next-auth": "4.24.13",
|
||||
"next-safe-action": "7.10.8",
|
||||
"next-safe-action": "8.1.5",
|
||||
"node-fetch": "3.3.2",
|
||||
"nodemailer": "7.0.13",
|
||||
"otplib": "12.0.1",
|
||||
"nodemailer": "8.0.1",
|
||||
"otplib": "13.3.0",
|
||||
"papaparse": "5.5.3",
|
||||
"prismjs": "1.30.0",
|
||||
"qr-code-styling": "1.9.2",
|
||||
"qrcode": "1.5.4",
|
||||
"react": "19.2.4",
|
||||
"react-calendar": "5.1.0",
|
||||
"react-calendar": "6.0.0",
|
||||
"react-colorful": "5.6.1",
|
||||
"react-confetti": "6.4.0",
|
||||
"react-day-picker": "9.14.0",
|
||||
"react-dom": "19.2.4",
|
||||
"react-hook-form": "7.71.2",
|
||||
"react-hot-toast": "2.6.0",
|
||||
"react-i18next": "15.7.4",
|
||||
"react-i18next": "16.5.4",
|
||||
"react-turnstile": "1.1.5",
|
||||
"react-use": "17.6.0",
|
||||
"sanitize-html": "2.17.1",
|
||||
"server-only": "0.0.1",
|
||||
"sharp": "0.34.5",
|
||||
"stripe": "16.12.0",
|
||||
"stripe": "20.4.0",
|
||||
"tailwind-merge": "3.5.0",
|
||||
"tailwindcss": "3.4.19",
|
||||
"ua-parser-js": "2.0.9",
|
||||
"uuid": "11.1.0",
|
||||
"webpack": "5.105.3",
|
||||
"uuid": "13.0.0",
|
||||
"webpack": "5.105.4",
|
||||
"xlsx": "file:vendor/xlsx-0.20.3.tgz",
|
||||
"zod": "3.25.76",
|
||||
"zod-openapi": "4.2.4"
|
||||
"zod": "4.3.6",
|
||||
"zod-openapi": "5.4.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formbricks/config-typescript": "workspace:*",
|
||||
@@ -143,15 +143,15 @@
|
||||
"@types/qrcode": "1.5.6",
|
||||
"@types/sanitize-html": "2.16.0",
|
||||
"@types/ungap__structured-clone": "1.2.0",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"@vitest/coverage-v8": "4.0.18",
|
||||
"autoprefixer": "10.4.27",
|
||||
"cross-env": "10.1.0",
|
||||
"dotenv": "16.6.1",
|
||||
"dotenv": "17.3.1",
|
||||
"postcss": "8.5.8",
|
||||
"resize-observer-polyfill": "1.5.1",
|
||||
"vite": "6.4.1",
|
||||
"vite-tsconfig-paths": "5.1.4",
|
||||
"vitest": "3.2.4",
|
||||
"vite": "7.3.1",
|
||||
"vite-tsconfig-paths": "6.1.1",
|
||||
"vitest": "4.0.18",
|
||||
"vitest-mock-extended": "3.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
"apps/*",
|
||||
"packages/*"
|
||||
],
|
||||
"prisma": {
|
||||
"schema": "packages/database/schema.prisma"
|
||||
},
|
||||
"scripts": {
|
||||
"agents:update": "npx @next/codemod@canary agents-md --output AGENTS.md",
|
||||
"clean:all": "turbo run clean && rimraf node_modules pnpm-lock.yaml .turbo coverage out",
|
||||
@@ -54,10 +51,10 @@
|
||||
"@playwright/test": "1.58.2",
|
||||
"eslint": "8.57.1",
|
||||
"husky": "9.1.7",
|
||||
"lint-staged": "16.3.1",
|
||||
"lint-staged": "16.3.2",
|
||||
"rimraf": "6.1.3",
|
||||
"tsx": "4.21.0",
|
||||
"turbo": "2.8.12"
|
||||
"turbo": "2.8.13"
|
||||
},
|
||||
"lint-staged": {
|
||||
"(apps|packages)/**/*.{js,ts,jsx,tsx}": [
|
||||
|
||||
8
packages/cache/package.json
vendored
8
packages/cache/package.json
vendored
@@ -39,13 +39,13 @@
|
||||
"dependencies": {
|
||||
"@formbricks/logger": "workspace:*",
|
||||
"redis": "5.11.0",
|
||||
"zod": "3.25.76"
|
||||
"zod": "4.3.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formbricks/config-typescript": "workspace:*",
|
||||
"@formbricks/eslint-config": "workspace:*",
|
||||
"vite": "6.4.1",
|
||||
"vitest": "3.2.4",
|
||||
"@vitest/coverage-v8": "3.2.4"
|
||||
"vite": "7.3.1",
|
||||
"vitest": "4.0.18",
|
||||
"@vitest/coverage-v8": "4.0.18"
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user