Compare commits

..

16 Commits

Author SHA1 Message Date
Dhruwang a4469dbb46 Merge branch 'main' of https://github.com/formbricks/formbricks into fix-delete-dialog-title 2026-03-02 11:56:57 +05:30
Johannes 6dd2e707fe feat: display Formbricks version alongside organization ID in settings (#7363) 2026-03-02 05:54:23 +00:00
Matti Nannt 58d5de7d45 fix: resolve Dependabot Next.js deserialization alert (#7393) 2026-02-27 22:18:38 +01:00
Dhruwang Jariwala 7c3fa8b5ea fix: restore bullet points in survey preview and public survey (#7356) (#7360)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-27 18:24:15 +00:00
Harsh Bhat 2601169877 docs: add advanced CSS variable updates (#7389)
Co-authored-by: Johannes <johannes@formbricks.com>
2026-02-27 17:19:22 +00:00
bharath kumar aecf85815a fix(js-core): use closest() fallback for nested click target matching (#7327)
Co-authored-by: Dhruwang <dhruwangjariwala18@gmail.com>
2026-02-27 06:24:58 +00:00
Bhagya Amarasinghe c6ebaea989 fix: set success_action_status on S3 presigned POST to fix CORS on Ceph-based providers (#7362) 2026-02-26 10:26:49 +00:00
Bhagya Amarasinghe 68c1422733 fix: copy database package.json to Docker runner stage (#7371) 2026-02-26 10:25:28 +00:00
Dhruwang Jariwala 6942502baf fix: slack missing redirect uri (#7372) 2026-02-26 10:01:25 +00:00
Theodór Tómas a4bd217761 chore: update to zod 3.25.76 (#7366) 2026-02-26 05:17:20 +00:00
Bhagya Amarasinghe fee770358c perf(contacts): build segment WHERE clauses sequentially to prevent pool saturation (#7354)
Co-authored-by: pandeymangg <anshuman.pandey9999@gmail.com>
2026-02-25 15:25:32 +00:00
Dhruwang Jariwala 44f8f80cac docs: clarify startAt is block-based, not question-based (#1404) (#7352)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-25 13:19:30 +00:00
Balázs Úr 207d044707 fix: delete confirmation dialog title translation 2026-02-25 13:29:17 +01:00
Chowdhury Tafsir Ahmed Siddiki 858a7f7aa9 fix: replace toSorted in breadcrumb switchers for compatibility (#7325)
Co-authored-by: Dhruwang <dhruwangjariwala18@gmail.com>
2026-02-25 06:29:31 +00:00
Gulshan ac40b90e81 fix: made "Filter" string translatable (#7301)
Signed-off-by: gulshank0 <gulshanbahadur002@gmail.com>
Co-authored-by: Dhruwang <dhruwangjariwala18@gmail.com>
2026-02-25 06:28:51 +00:00
Balázs Úr aa21b4e442 fix: made Contact's page titles and table headers translatable (#7313)
Co-authored-by: Dhruwang <dhruwangjariwala18@gmail.com>
2026-02-24 14:07:05 +00:00
62 changed files with 794 additions and 669 deletions
-50
View File
@@ -1,50 +0,0 @@
# Fix Summary: Custom Script Error Handling (FORMBRICKS-P5)
## Problem
User-provided custom scripts injected via `customHeadScripts` were calling deprecated MetaMask internal APIs (`window.ethereum._handleChainChanged`), causing unhandled TypeErrors that:
- Were reported to Sentry as production errors
- Could potentially break the survey experience for users
- Occurred when the survey page loaded with certain browser extensions (MetaMask)
## Root Cause
The `CustomScriptsInjector` component was correctly injecting user-provided scripts, but had no protection against runtime errors that occurred *after* the scripts were executed. The existing try-catch block only caught errors during the injection process itself, not runtime errors from the injected code.
## Solution
Enhanced error handling in the `CustomScriptsInjector` component to wrap all user-provided scripts in defensive error handling:
### Changes Made
1. **Inline Script Wrapping** (lines 64-72):
- All inline script content is now wrapped in try-catch blocks
- Runtime errors are caught and logged to console with `[Formbricks]` prefix
- Errors don't break the survey or propagate to error tracking
2. **External Script Error Handling** (lines 75-77):
- Added `onerror` event handlers to all external scripts loaded via `src` attribute
- Loading errors are logged to console but don't break functionality
3. **Documentation**:
- Updated JSDoc to clearly state that user scripts are error-isolated
- Added inline comments explaining the defensive programming approach
## Benefits
- ✅ Prevents third-party script errors from breaking surveys
- ✅ Reduces noise in error tracking (Sentry)
- ✅ Maintains debuggability via console warnings
- ✅ No breaking changes to existing functionality
- ✅ Works for both inline and external scripts
## Testing Considerations
- User scripts with errors will execute up to the point of failure, then stop gracefully
- Error messages are visible in browser console for debugging by self-hosted admins
- Survey functionality remains intact even if custom scripts fail completely
## Example
**Before**: User script calling `window.ethereum._handleChainChanged()` would throw an unhandled TypeError
**After**: The error is caught, logged to console as a warning, and the survey continues to function normally
## Files Modified
- `apps/web/modules/survey/link/components/custom-scripts-injector.tsx`
## Commit
- `fix: wrap custom scripts in try-catch to prevent runtime errors` (Fixes FORMBRICKS-P5)
+3
View File
@@ -101,6 +101,9 @@ RUN chown -R nextjs:nextjs ./apps/web/public && chmod -R 755 ./apps/web/public
# Create packages/database directory structure with proper ownership for runtime migrations
RUN mkdir -p ./packages/database/migrations && chown -R nextjs:nextjs ./packages/database
COPY --from=installer /app/packages/database/package.json ./packages/database/package.json
RUN chown nextjs:nextjs ./packages/database/package.json && chmod 644 ./packages/database/package.json
COPY --from=installer /app/packages/database/schema.prisma ./packages/database/schema.prisma
RUN chown nextjs:nextjs ./packages/database/schema.prisma && chmod 644 ./packages/database/schema.prisma
@@ -81,7 +81,7 @@ export const OrganizationBreadcrumb = ({
getOrganizationsForSwitcherAction({ organizationId: currentOrganizationId }).then((result) => {
if (result?.data) {
// Sort organizations by name
const sorted = result.data.toSorted((a, b) => a.name.localeCompare(b.name));
const sorted = [...result.data].sort((a, b) => a.name.localeCompare(b.name));
setOrganizations(sorted);
} else {
// Handle server errors or validation errors
@@ -82,7 +82,7 @@ export const ProjectBreadcrumb = ({
getProjectsForSwitcherAction({ organizationId: currentOrganizationId }).then((result) => {
if (result?.data) {
// Sort projects by name
const sorted = result.data.toSorted((a, b) => a.name.localeCompare(b.name));
const sorted = [...result.data].sort((a, b) => a.name.localeCompare(b.name));
setProjects(sorted);
} else {
// Handle server errors or validation errors
@@ -9,6 +9,7 @@ import { Alert, AlertDescription } from "@/modules/ui/components/alert";
import { IdBadge } from "@/modules/ui/components/id-badge";
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
import { PageHeader } from "@/modules/ui/components/page-header";
import packageJson from "@/package.json";
import { SettingsCard } from "../../components/SettingsCard";
import { DeleteOrganization } from "./components/DeleteOrganization";
import { EditOrganizationNameForm } from "./components/EditOrganizationNameForm";
@@ -81,7 +82,10 @@ const Page = async (props: { params: Promise<{ environmentId: string }> }) => {
</SettingsCard>
)}
<IdBadge id={organization.id} label={t("common.organization_id")} variant="column" />
<div className="space-y-2">
<IdBadge id={organization.id} label={t("common.organization_id")} variant="column" />
<IdBadge id={packageJson.version} label={t("common.formbricks_version")} variant="column" />
</div>
</PageContentWrapper>
);
};
@@ -352,7 +352,7 @@ export const AnonymousLinksTab = ({
},
{
title: t("environments.surveys.share.anonymous_links.custom_start_point"),
href: "https://formbricks.com/docs/xm-and-surveys/surveys/link-surveys/start-at-question",
href: "https://formbricks.com/docs/xm-and-surveys/surveys/link-surveys/start-at-block",
},
]}
/>
@@ -241,7 +241,7 @@ export const ResponseFilter = ({ survey }: ResponseFilterProps) => {
<Popover open={isOpen} onOpenChange={handleOpenChange}>
<PopoverTrigger asChild>
<PopoverTriggerButton isOpen={isOpen}>
Filter <b>{activeFilterCount > 0 && `(${activeFilterCount})`}</b>
{t("common.filter")} <b>{activeFilterCount > 0 && `(${activeFilterCount})`}</b>
</PopoverTriggerButton>
</PopoverTrigger>
<PopoverContent
@@ -329,7 +329,7 @@ export const ResponseFilter = ({ survey }: ResponseFilterProps) => {
</div>
{i !== filterValue.filter.length - 1 && (
<div className="my-4 flex items-center">
<p className="mr-4 font-semibold text-slate-800">and</p>
<p className="mr-4 font-semibold text-slate-800">{t("common.and")}</p>
<hr className="w-full text-slate-600" />
</div>
)}
@@ -6,7 +6,7 @@ import {
} from "@formbricks/types/integration/slack";
import { responses } from "@/app/lib/api/response";
import { TSessionAuthentication, withV1ApiWrapper } from "@/app/lib/api/with-api-logging";
import { SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, WEBAPP_URL } from "@/lib/constants";
import { SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, SLACK_REDIRECT_URI, WEBAPP_URL } from "@/lib/constants";
import { hasUserEnvironmentAccess } from "@/lib/environment/auth";
import { createOrUpdateIntegration, getIntegrationByType } from "@/lib/integration/service";
@@ -56,6 +56,7 @@ export const GET = withV1ApiWrapper({
code,
client_id: SLACK_CLIENT_ID,
client_secret: SLACK_CLIENT_SECRET,
redirect_uri: SLACK_REDIRECT_URI,
};
const formBody: string[] = [];
for (const property in formData) {
+7 -2
View File
@@ -164,6 +164,7 @@ checksums:
common/days: c95fe8aedde21a0b5653dbd0b3c58b48
common/default: d9c6dc5c412fe94143dfd1d332ec81d4
common/delete: 8bcf303dd10a645b5baacb02b47d72c9
common/delete_what: 718ddfcc1dec7f3e8b67856fba838267
common/description: e17686a22ffad04cc7bb70524ed4478b
common/dev_env: e650911d5e19ba256358e0cda154c005
common/development: 85211dbb918bda7a6e87649dcfc1b17a
@@ -198,7 +199,9 @@ checksums:
common/failed_to_copy_to_clipboard: de836a7d628d36c832809252f188f784
common/failed_to_load_organizations: 512808a2b674c7c28bca73f8f91fd87e
common/failed_to_load_workspaces: 6ee3448097394517dc605074cd4e6ea4
common/filter: 626325a05e4c8800f7ede7012b0cadaf
common/finish: ffa7a10f71182b48fefed7135bee24fa
common/first_name: cf040a5d6a9fd696be400380cc99f54b
common/follow_these: 3a730b242bb17a3f95e01bf0dae86885
common/formbricks_version: d9967c797f3e49ca0cae78bc0ebd19cb
common/full_name: f45991923345e8322c9ff8cd6b7e2b16
@@ -211,6 +214,7 @@ checksums:
common/hidden_field: 3ed5c58d0ed359e558cdf7bd33606d2d
common/hidden_fields: 3de6cfd308293a826cb8679fd1d49972
common/hide_column: 23ce94db148f2d8e4a0923defead6cf1
common/id: c8886d38aeea2ed5f785aba4fc96784b
common/image: 048ba7a239de0fbd883ade8558415830
common/images: 9305827c28694866f49db42b4c51831f
common/import: 348b8ab981de5b7f1fca6d7302263bbd
@@ -228,6 +232,7 @@ checksums:
common/key: 3d1065ab98a1c2f1210507fd5c7bf515
common/label: a5c71bf158481233f8215dbd38cc196b
common/language: 277fd1a41cc237a437cd1d5e4a80463b
common/last_name: 2c9a7de7738ca007ba9023c385149c26
common/learn_more: e598091d132f890c37a6d4ed94f6d794
common/license_expired: 7af13535e320e4197989472c01387d2c
common/light_overlay: 0499907ea7b8405f4267b117998b5a78
@@ -1016,7 +1021,7 @@ checksums:
environments/settings/general/email_customization_preview_email_heading: 8b798cb8438b3dd356c02dab33b4c897
environments/settings/general/email_customization_preview_email_text: fa6ae92403cc8f3c35c03e6c94cbde51
environments/settings/general/error_deleting_organization_please_try_again: 7f0fe257d4a0b40bff025408a7766706
environments/settings/general/from_your_organization: 4b7970431edb3d0f13c394dbd755a055
environments/settings/general/from_your_organization: 9ebd6dcd79f7bfad3fea46ed2e3133d2
environments/settings/general/invitation_sent_once_more: e6e5ea066810f9dcb65788aa4f05d6e2
environments/settings/general/invite_deleted_successfully: 1c7dca6d0f6870d945288e38cfd2f943
environments/settings/general/invite_expires_on: 6fd2356ad91a5f189070c43855904bb4
@@ -1369,7 +1374,6 @@ checksums:
environments/surveys/edit/follow_ups_modal_updated_successfull_toast: 61204fada3231f4f1fe3866e87e1130a
environments/surveys/edit/follow_ups_new: 224c779d252b3e75086e4ed456ba2548
environments/surveys/edit/follow_ups_upgrade_button_text: 4cd167527fc6cdb5b0bfc9b486b142a8
environments/surveys/edit/form_styling: 1278a2db4257b5500474161133acc857
environments/surveys/edit/formbricks_sdk_is_not_connected: 35165b0cac182a98408007a378cc677e
environments/surveys/edit/four_points: b289628a6b8a6cd0f7d17a14ca6cd7bf
environments/surveys/edit/heading: 79e9dfa461f38a239d34b9833ca103f1
@@ -1586,6 +1590,7 @@ checksums:
environments/surveys/edit/survey_completed_subheading: db537c356c3ab6564d24de0d11a0fee2
environments/surveys/edit/survey_display_settings: 8ed19e6a8e1376f7a1ba037d82c4ae11
environments/surveys/edit/survey_placement: 083c10f257337f9648bf9d435b18ec2c
environments/surveys/edit/survey_styling: 7f96d6563e934e65687b74374a33b1dc
environments/surveys/edit/survey_trigger: f0c7014a684ca566698b87074fad5579
environments/surveys/edit/switch_multi_language_on_to_get_started: cca0ef91ee49095da30cd1e3f26c406f
environments/surveys/edit/target_block_not_found: 0a0c401017ab32364fec2fcbf815d832
+2 -1
View File
@@ -63,7 +63,8 @@ export const INVITE_DISABLED = env.INVITE_DISABLED === "1";
export const SLACK_CLIENT_SECRET = env.SLACK_CLIENT_SECRET;
export const SLACK_CLIENT_ID = env.SLACK_CLIENT_ID;
export const SLACK_AUTH_URL = `https://slack.com/oauth/v2/authorize?client_id=${env.SLACK_CLIENT_ID}&scope=channels:read,chat:write,chat:write.public,chat:write.customize,groups:read`;
export const SLACK_REDIRECT_URI = `${WEBAPP_URL}/api/v1/integrations/slack/callback`;
export const SLACK_AUTH_URL = `https://slack.com/oauth/v2/authorize?client_id=${env.SLACK_CLIENT_ID}&scope=channels:read,chat:write,chat:write.public,chat:write.customize,groups:read&redirect_uri=${SLACK_REDIRECT_URI}`;
export const GOOGLE_SHEETS_CLIENT_ID = env.GOOGLE_SHEETS_CLIENT_ID;
export const GOOGLE_SHEETS_CLIENT_SECRET = env.GOOGLE_SHEETS_CLIENT_SECRET;
+7 -2
View File
@@ -191,6 +191,7 @@
"days": "Tage",
"default": "Standard",
"delete": "Löschen",
"delete_what": "{deleteWhat} löschen",
"description": "Beschreibung",
"dev_env": "Entwicklungsumgebung",
"development": "Entwicklung",
@@ -225,7 +226,9 @@
"failed_to_copy_to_clipboard": "Fehler beim Kopieren in die Zwischenablage",
"failed_to_load_organizations": "Fehler beim Laden der Organisationen",
"failed_to_load_workspaces": "Projekte konnten nicht geladen werden",
"filter": "Filter",
"finish": "Fertigstellen",
"first_name": "Vorname",
"follow_these": "Folge diesen",
"formbricks_version": "Formbricks Version",
"full_name": "Name",
@@ -238,6 +241,7 @@
"hidden_field": "Verstecktes Feld",
"hidden_fields": "Versteckte Felder",
"hide_column": "Spalte ausblenden",
"id": "ID",
"image": "Bild",
"images": "Bilder",
"import": "Importieren",
@@ -255,6 +259,7 @@
"key": "Schlüssel",
"label": "Bezeichnung",
"language": "Sprache",
"last_name": "Nachname",
"learn_more": "Mehr erfahren",
"license_expired": "License Expired",
"light_overlay": "Helle Überlagerung",
@@ -1077,7 +1082,7 @@
"email_customization_preview_email_heading": "Hey {userName}",
"email_customization_preview_email_text": "Dies ist eine E-Mail-Vorschau, um dir zu zeigen, welches Logo in den E-Mails gerendert wird.",
"error_deleting_organization_please_try_again": "Fehler beim Löschen der Organisation. Bitte versuche es erneut.",
"from_your_organization": "von deiner Organisation",
"from_your_organization": "{memberName} aus Ihrer Organisation",
"invitation_sent_once_more": "Einladung nochmal gesendet.",
"invite_deleted_successfully": "Einladung erfolgreich gelöscht",
"invite_expires_on": "Einladung läuft ab am {date}",
@@ -1440,7 +1445,6 @@
"follow_ups_modal_updated_successfull_toast": "Nachverfolgung aktualisiert und wird gespeichert, sobald du die Umfrage speicherst.",
"follow_ups_new": "Neues Follow-up",
"follow_ups_upgrade_button_text": "Upgrade, um Follow-ups zu aktivieren",
"form_styling": "Umfrage Styling",
"formbricks_sdk_is_not_connected": "Formbricks SDK ist nicht verbunden",
"four_points": "4 Punkte",
"heading": "Überschrift",
@@ -1659,6 +1663,7 @@
"survey_completed_subheading": "Diese kostenlose und quelloffene Umfrage wurde geschlossen",
"survey_display_settings": "Einstellungen zur Anzeige der Umfrage",
"survey_placement": "Platzierung der Umfrage",
"survey_styling": "Umfrage Styling",
"survey_trigger": "Auslöser der Umfrage",
"switch_multi_language_on_to_get_started": "Aktiviere Mehrsprachigkeit, um loszulegen 👉",
"target_block_not_found": "Zielblock nicht gefunden",
+7 -2
View File
@@ -191,6 +191,7 @@
"days": "days",
"default": "Default",
"delete": "Delete",
"delete_what": "Delete {deleteWhat}",
"description": "Description",
"dev_env": "Dev Environment",
"development": "Development",
@@ -225,7 +226,9 @@
"failed_to_copy_to_clipboard": "Failed to copy to clipboard",
"failed_to_load_organizations": "Failed to load organizations",
"failed_to_load_workspaces": "Failed to load workspaces",
"filter": "Filter",
"finish": "Finish",
"first_name": "First Name",
"follow_these": "Follow these",
"formbricks_version": "Formbricks Version",
"full_name": "Full name",
@@ -238,6 +241,7 @@
"hidden_field": "Hidden field",
"hidden_fields": "Hidden fields",
"hide_column": "Hide column",
"id": "ID",
"image": "Image",
"images": "Images",
"import": "Import",
@@ -255,6 +259,7 @@
"key": "Key",
"label": "Label",
"language": "Language",
"last_name": "Last Name",
"learn_more": "Learn more",
"license_expired": "License Expired",
"light_overlay": "Light overlay",
@@ -1077,7 +1082,7 @@
"email_customization_preview_email_heading": "Hey {userName}",
"email_customization_preview_email_text": "This is an email preview to show you which logo will be rendered in the emails.",
"error_deleting_organization_please_try_again": "Error deleting organization. Please try again.",
"from_your_organization": "from your organization",
"from_your_organization": "{memberName} from your organization",
"invitation_sent_once_more": "Invitation sent once more.",
"invite_deleted_successfully": "Invite deleted successfully",
"invite_expires_on": "Invite expires on {date}",
@@ -1440,7 +1445,6 @@
"follow_ups_modal_updated_successfull_toast": "Follow-up updated and will be saved once you save the survey.",
"follow_ups_new": "New follow-up",
"follow_ups_upgrade_button_text": "Upgrade to enable follow-ups",
"form_styling": "Form styling",
"formbricks_sdk_is_not_connected": "Formbricks SDK is not connected",
"four_points": "4 points",
"heading": "Heading",
@@ -1659,6 +1663,7 @@
"survey_completed_subheading": "This free & open-source survey has been closed",
"survey_display_settings": "Survey Display Settings",
"survey_placement": "Survey Placement",
"survey_styling": "Survey styling",
"survey_trigger": "Survey Trigger",
"switch_multi_language_on_to_get_started": "Switch multi-language on to get started 👉",
"target_block_not_found": "Target block not found",
+7 -2
View File
@@ -191,6 +191,7 @@
"days": "días",
"default": "Predeterminado",
"delete": "Eliminar",
"delete_what": "Eliminar {deleteWhat}",
"description": "Descripción",
"dev_env": "Entorno de desarrollo",
"development": "Desarrollo",
@@ -225,7 +226,9 @@
"failed_to_copy_to_clipboard": "Error al copiar al portapapeles",
"failed_to_load_organizations": "Error al cargar organizaciones",
"failed_to_load_workspaces": "Error al cargar los proyectos",
"filter": "Filtro",
"finish": "Finalizar",
"first_name": "Nombre",
"follow_these": "Sigue estos",
"formbricks_version": "Versión de Formbricks",
"full_name": "Nombre completo",
@@ -238,6 +241,7 @@
"hidden_field": "Campo oculto",
"hidden_fields": "Campos ocultos",
"hide_column": "Ocultar columna",
"id": "ID",
"image": "Imagen",
"images": "Imágenes",
"import": "Importar",
@@ -255,6 +259,7 @@
"key": "Clave",
"label": "Etiqueta",
"language": "Idioma",
"last_name": "Apellido",
"learn_more": "Saber más",
"license_expired": "License Expired",
"light_overlay": "Superposición clara",
@@ -1077,7 +1082,7 @@
"email_customization_preview_email_heading": "Hola {userName}",
"email_customization_preview_email_text": "Este es un correo electrónico de vista previa para mostrarte qué logotipo se mostrará en los correos electrónicos.",
"error_deleting_organization_please_try_again": "Error al eliminar la organización. Por favor, inténtalo de nuevo.",
"from_your_organization": "de tu organización",
"from_your_organization": "{memberName} de tu organización",
"invitation_sent_once_more": "Invitación enviada una vez más.",
"invite_deleted_successfully": "Invitación eliminada correctamente",
"invite_expires_on": "La invitación expira el {date}",
@@ -1440,7 +1445,6 @@
"follow_ups_modal_updated_successfull_toast": "Seguimiento actualizado y se guardará cuando guardes la encuesta.",
"follow_ups_new": "Nuevo seguimiento",
"follow_ups_upgrade_button_text": "Actualiza para habilitar seguimientos",
"form_styling": "Estilo del formulario",
"formbricks_sdk_is_not_connected": "El SDK de Formbricks no está conectado",
"four_points": "4 puntos",
"heading": "Encabezado",
@@ -1659,6 +1663,7 @@
"survey_completed_subheading": "Esta encuesta gratuita y de código abierto ha sido cerrada",
"survey_display_settings": "Ajustes de visualización de la encuesta",
"survey_placement": "Ubicación de la encuesta",
"survey_styling": "Estilo del formulario",
"survey_trigger": "Activador de la encuesta",
"switch_multi_language_on_to_get_started": "Activa el modo multiidioma para comenzar 👉",
"target_block_not_found": "Bloque objetivo no encontrado",
+7 -2
View File
@@ -191,6 +191,7 @@
"days": "jours",
"default": "Par défaut",
"delete": "Supprimer",
"delete_what": "Supprimer {deleteWhat}",
"description": "Description",
"dev_env": "Environnement de développement",
"development": "Développement",
@@ -225,7 +226,9 @@
"failed_to_copy_to_clipboard": "Échec de la copie dans le presse-papiers",
"failed_to_load_organizations": "Échec du chargement des organisations",
"failed_to_load_workspaces": "Échec du chargement des projets",
"filter": "Filtre",
"finish": "Terminer",
"first_name": "Prénom",
"follow_these": "Suivez ceci",
"formbricks_version": "Version de Formbricks",
"full_name": "Nom complet",
@@ -238,6 +241,7 @@
"hidden_field": "Champ caché",
"hidden_fields": "Champs cachés",
"hide_column": "Cacher la colonne",
"id": "ID",
"image": "Image",
"images": "Images",
"import": "Importer",
@@ -255,6 +259,7 @@
"key": "Clé",
"label": "Étiquette",
"language": "Langue",
"last_name": "Nom de famille",
"learn_more": "En savoir plus",
"license_expired": "License Expired",
"light_overlay": "Claire",
@@ -1077,7 +1082,7 @@
"email_customization_preview_email_heading": "Salut {userName}",
"email_customization_preview_email_text": "Cette est une prévisualisation d'e-mail pour vous montrer quel logo sera rendu dans les e-mails.",
"error_deleting_organization_please_try_again": "Erreur lors de la suppression de l'organisation. Veuillez réessayer.",
"from_your_organization": "de votre organisation",
"from_your_organization": "{memberName} de votre organisation",
"invitation_sent_once_more": "Invitation envoyée une fois de plus.",
"invite_deleted_successfully": "Invitation supprimée avec succès",
"invite_expires_on": "L'invitation expire le {date}",
@@ -1440,7 +1445,6 @@
"follow_ups_modal_updated_successfull_toast": "\"Suivi mis à jour et sera enregistré une fois que vous sauvegarderez le sondage.\"",
"follow_ups_new": "Nouveau suivi",
"follow_ups_upgrade_button_text": "Passez à la version supérieure pour activer les relances",
"form_styling": "Style de formulaire",
"formbricks_sdk_is_not_connected": "Le SDK Formbricks n'est pas connecté",
"four_points": "4 points",
"heading": "En-tête",
@@ -1659,6 +1663,7 @@
"survey_completed_subheading": "Cette enquête gratuite et open-source a été fermée",
"survey_display_settings": "Paramètres d'affichage de l'enquête",
"survey_placement": "Placement de l'enquête",
"survey_styling": "Style de formulaire",
"survey_trigger": "Déclencheur d'enquête",
"switch_multi_language_on_to_get_started": "Activez le mode multilingue pour commencer 👉",
"target_block_not_found": "Bloc cible non trouvé",
+7 -2
View File
@@ -191,6 +191,7 @@
"days": "napok",
"default": "Alapértelmezett",
"delete": "Törlés",
"delete_what": "{deleteWhat} törlése",
"description": "Leírás",
"dev_env": "Fejlesztői környezet",
"development": "Fejlesztés",
@@ -225,7 +226,9 @@
"failed_to_copy_to_clipboard": "Nem sikerült másolni a vágólapra",
"failed_to_load_organizations": "Nem sikerült betölteni a szervezeteket",
"failed_to_load_workspaces": "Nem sikerült a munkaterületek betöltése",
"filter": "Szűrő",
"finish": "Befejezés",
"first_name": "Keresztnév",
"follow_these": "Ezek követése",
"formbricks_version": "Formbricks verziója",
"full_name": "Teljes név",
@@ -238,6 +241,7 @@
"hidden_field": "Rejtett mező",
"hidden_fields": "Rejtett mezők",
"hide_column": "Oszlop elrejtése",
"id": "ID",
"image": "Kép",
"images": "Képek",
"import": "Importálás",
@@ -255,6 +259,7 @@
"key": "Kulcs",
"label": "Címke",
"language": "Nyelv",
"last_name": "Vezetéknév",
"learn_more": "Tudjon meg többet",
"license_expired": "A licenc lejárt",
"light_overlay": "Világos rávetítés",
@@ -1077,7 +1082,7 @@
"email_customization_preview_email_heading": "Helló {userName}",
"email_customization_preview_email_text": "Ez egy e-mail előnézet, amely azt mutatja meg, hogy melyik logó fog megjelenni az e-mailekben.",
"error_deleting_organization_please_try_again": "Hiba a szervezet törlésekor. Próbálja meg újra.",
"from_your_organization": "a szervezetétől",
"from_your_organization": "{memberName} a szervezetből",
"invitation_sent_once_more": "A meghívó még egyszer elküldve.",
"invite_deleted_successfully": "A meghívó sikeresen törölve",
"invite_expires_on": "A meghívó lejár ekkor: {date}",
@@ -1440,7 +1445,6 @@
"follow_ups_modal_updated_successfull_toast": "A követés frissítve, és akkor lesz elmentve, ha elmenti a kérdőívet.",
"follow_ups_new": "Új követés",
"follow_ups_upgrade_button_text": "Magasabb csomagra váltás a követések engedélyezéséhez",
"form_styling": "Űrlap stílusának beállítása",
"formbricks_sdk_is_not_connected": "A Formbricks SDK nincs csatlakoztatva",
"four_points": "4 pont",
"heading": "Címsor",
@@ -1659,6 +1663,7 @@
"survey_completed_subheading": "Ez a szabad és nyílt forráskódú kérdőív le lett zárva",
"survey_display_settings": "Kérdőív megjelenítésének beállításai",
"survey_placement": "Kérdőív elhelyezése",
"survey_styling": "Űrlap stílusának beállítása",
"survey_trigger": "Kérdőív aktiválója",
"switch_multi_language_on_to_get_started": "Kapcsolja be a többnyelvűséget a kezdéshez 👉",
"target_block_not_found": "A célblokk nem található",
+7 -2
View File
@@ -191,6 +191,7 @@
"days": "日",
"default": "デフォルト",
"delete": "削除",
"delete_what": "{deleteWhat}を削除",
"description": "説明",
"dev_env": "開発環境",
"development": "開発",
@@ -225,7 +226,9 @@
"failed_to_copy_to_clipboard": "クリップボードへのコピーに失敗しました",
"failed_to_load_organizations": "組織の読み込みに失敗しました",
"failed_to_load_workspaces": "ワークスペースの読み込みに失敗しました",
"filter": "フィルター",
"finish": "完了",
"first_name": "名",
"follow_these": "こちらの手順に従って",
"formbricks_version": "Formbricksバージョン",
"full_name": "氏名",
@@ -238,6 +241,7 @@
"hidden_field": "非表示フィールド",
"hidden_fields": "非表示フィールド",
"hide_column": "列を非表示",
"id": "ID",
"image": "画像",
"images": "画像",
"import": "インポート",
@@ -255,6 +259,7 @@
"key": "キー",
"label": "ラベル",
"language": "言語",
"last_name": "姓",
"learn_more": "詳細を見る",
"license_expired": "License Expired",
"light_overlay": "明るいオーバーレイ",
@@ -1077,7 +1082,7 @@
"email_customization_preview_email_heading": "こんにちは、{userName}さん",
"email_customization_preview_email_text": "これは、メールに表示されるロゴを確認するためのプレビューメールです。",
"error_deleting_organization_please_try_again": "組織の削除中にエラーが発生しました。もう一度お試しください。",
"from_your_organization": "あなたの組織から",
"from_your_organization": "組織から{memberName}を削除",
"invitation_sent_once_more": "招待状を再度送信しました。",
"invite_deleted_successfully": "招待を正常に削除しました",
"invite_expires_on": "招待は{date}に期限切れ",
@@ -1440,7 +1445,6 @@
"follow_ups_modal_updated_successfull_toast": "フォローアップ が 更新され、 アンケートを 保存すると保存されます。",
"follow_ups_new": "新しいフォローアップ",
"follow_ups_upgrade_button_text": "フォローアップを有効にするためにアップグレード",
"form_styling": "フォームのスタイル",
"formbricks_sdk_is_not_connected": "Formbricks SDKが接続されていません",
"four_points": "4点",
"heading": "見出し",
@@ -1659,6 +1663,7 @@
"survey_completed_subheading": "この無料のオープンソースフォームは閉鎖されました",
"survey_display_settings": "フォーム表示設定",
"survey_placement": "フォームの配置",
"survey_styling": "フォームのスタイル",
"survey_trigger": "フォームのトリガー",
"switch_multi_language_on_to_get_started": "多言語機能をオンにして開始 👉",
"target_block_not_found": "対象ブロックが見つかりません",
+7 -2
View File
@@ -191,6 +191,7 @@
"days": "dagen",
"default": "Standaard",
"delete": "Verwijderen",
"delete_what": "Verwijder {deleteWhat}",
"description": "Beschrijving",
"dev_env": "Ontwikkelomgeving",
"development": "Ontwikkeling",
@@ -225,7 +226,9 @@
"failed_to_copy_to_clipboard": "Kopiëren naar klembord mislukt",
"failed_to_load_organizations": "Laden van organisaties mislukt",
"failed_to_load_workspaces": "Laden van werkruimtes mislukt",
"filter": "Filter",
"finish": "Finish",
"first_name": "Voornaam",
"follow_these": "Volg deze",
"formbricks_version": "Formbricks-versie",
"full_name": "Volledige naam",
@@ -238,6 +241,7 @@
"hidden_field": "Verborgen veld",
"hidden_fields": "Verborgen velden",
"hide_column": "Kolom verbergen",
"id": "ID",
"image": "Afbeelding",
"images": "Afbeeldingen",
"import": "Importeren",
@@ -255,6 +259,7 @@
"key": "Sleutel",
"label": "Label",
"language": "Taal",
"last_name": "Achternaam",
"learn_more": "Meer informatie",
"license_expired": "License Expired",
"light_overlay": "Lichte overlay",
@@ -1077,7 +1082,7 @@
"email_customization_preview_email_heading": "Hé {userName}",
"email_customization_preview_email_text": "Dit is een e-mailvoorbeeld om u te laten zien welk logo in de e-mails wordt weergegeven.",
"error_deleting_organization_please_try_again": "Fout bij verwijderen van organisatie. Probeer het opnieuw.",
"from_your_organization": "vanuit uw organisatie",
"from_your_organization": "{memberName} uit je organisatie",
"invitation_sent_once_more": "Uitnodiging nogmaals verzonden.",
"invite_deleted_successfully": "Uitnodiging succesvol verwijderd",
"invite_expires_on": "Uitnodiging verloopt op {date}",
@@ -1440,7 +1445,6 @@
"follow_ups_modal_updated_successfull_toast": "Follow-up bijgewerkt en wordt opgeslagen zodra u de enquête opslaat.",
"follow_ups_new": "Nieuw vervolg",
"follow_ups_upgrade_button_text": "Upgrade om follow-ups mogelijk te maken",
"form_styling": "Vorm styling",
"formbricks_sdk_is_not_connected": "Formbricks SDK is niet verbonden",
"four_points": "4 punten",
"heading": "Rubriek",
@@ -1659,6 +1663,7 @@
"survey_completed_subheading": "Deze gratis en open source-enquête is gesloten",
"survey_display_settings": "Enquêteweergave-instellingen",
"survey_placement": "Enquête plaatsing",
"survey_styling": "Vorm styling",
"survey_trigger": "Enquêtetrigger",
"switch_multi_language_on_to_get_started": "Schakel meertaligheid in om te beginnen 👉",
"target_block_not_found": "Doelblok niet gevonden",
+7 -2
View File
@@ -191,6 +191,7 @@
"days": "dias",
"default": "Padrão",
"delete": "Apagar",
"delete_what": "Excluir {deleteWhat}",
"description": "Descrição",
"dev_env": "Ambiente de Desenvolvimento",
"development": "Desenvolvimento",
@@ -225,7 +226,9 @@
"failed_to_copy_to_clipboard": "Falha ao copiar para a área de transferência",
"failed_to_load_organizations": "Falha ao carregar organizações",
"failed_to_load_workspaces": "Falha ao carregar projetos",
"filter": "Filtro",
"finish": "Terminar",
"first_name": "Primeiro nome",
"follow_these": "Siga esses",
"formbricks_version": "Versão do Formbricks",
"full_name": "Nome completo",
@@ -238,6 +241,7 @@
"hidden_field": "Campo oculto",
"hidden_fields": "Campos ocultos",
"hide_column": "Ocultar coluna",
"id": "ID",
"image": "imagem",
"images": "Imagens",
"import": "importar",
@@ -255,6 +259,7 @@
"key": "Chave",
"label": "Etiqueta",
"language": "Língua",
"last_name": "Sobrenome",
"learn_more": "Saiba mais",
"license_expired": "License Expired",
"light_overlay": "sobreposição leve",
@@ -1077,7 +1082,7 @@
"email_customization_preview_email_heading": "Oi {userName}",
"email_customization_preview_email_text": "Esta é uma pré-visualização de e-mail para mostrar qual logo será renderizado nos e-mails.",
"error_deleting_organization_please_try_again": "Erro ao deletar a organização. Por favor, tente novamente.",
"from_your_organization": "da sua organização",
"from_your_organization": "{memberName} da sua organização",
"invitation_sent_once_more": "Convite enviado de novo.",
"invite_deleted_successfully": "Convite deletado com sucesso",
"invite_expires_on": "O convite expira em {date}",
@@ -1440,7 +1445,6 @@
"follow_ups_modal_updated_successfull_toast": "Acompanhamento atualizado e será salvo assim que você salvar a pesquisa.",
"follow_ups_new": "Novo acompanhamento",
"follow_ups_upgrade_button_text": "Atualize para habilitar os Acompanhamentos",
"form_styling": "Estilização de Formulários",
"formbricks_sdk_is_not_connected": "O SDK do Formbricks não está conectado",
"four_points": "4 pontos",
"heading": "Título",
@@ -1659,6 +1663,7 @@
"survey_completed_subheading": "Essa pesquisa gratuita e de código aberto foi encerrada",
"survey_display_settings": "Configurações de Exibição da Pesquisa",
"survey_placement": "Posicionamento da Pesquisa",
"survey_styling": "Estilização de Formulários",
"survey_trigger": "Gatilho de Pesquisa",
"switch_multi_language_on_to_get_started": "Ative o modo multilíngue para começar 👉",
"target_block_not_found": "Bloco de destino não encontrado",
+7 -2
View File
@@ -191,6 +191,7 @@
"days": "dias",
"default": "Padrão",
"delete": "Eliminar",
"delete_what": "Eliminar {deleteWhat}",
"description": "Descrição",
"dev_env": "Ambiente de Desenvolvimento",
"development": "Desenvolvimento",
@@ -225,7 +226,9 @@
"failed_to_copy_to_clipboard": "Falha ao copiar para a área de transferência",
"failed_to_load_organizations": "Falha ao carregar organizações",
"failed_to_load_workspaces": "Falha ao carregar projetos",
"filter": "Filtro",
"finish": "Concluir",
"first_name": "Primeiro nome",
"follow_these": "Siga estes",
"formbricks_version": "Versão do Formbricks",
"full_name": "Nome completo",
@@ -238,6 +241,7 @@
"hidden_field": "Campo oculto",
"hidden_fields": "Campos ocultos",
"hide_column": "Ocultar coluna",
"id": "ID",
"image": "Imagem",
"images": "Imagens",
"import": "Importar",
@@ -255,6 +259,7 @@
"key": "Chave",
"label": "Etiqueta",
"language": "Idioma",
"last_name": "Apelido",
"learn_more": "Saiba mais",
"license_expired": "License Expired",
"light_overlay": "Sobreposição leve",
@@ -1077,7 +1082,7 @@
"email_customization_preview_email_heading": "Olá {userName}",
"email_customization_preview_email_text": "Esta é uma pré-visualização de email para mostrar qual logotipo será exibido nos emails.",
"error_deleting_organization_please_try_again": "Erro ao eliminar a organização. Por favor, tente novamente.",
"from_your_organization": "da sua organização",
"from_your_organization": "{memberName} da sua organização",
"invitation_sent_once_more": "Convite enviado mais uma vez.",
"invite_deleted_successfully": "Convite eliminado com sucesso",
"invite_expires_on": "O convite expira em {date}",
@@ -1440,7 +1445,6 @@
"follow_ups_modal_updated_successfull_toast": "Seguimento atualizado e será guardado assim que guardar o questionário.",
"follow_ups_new": "Novo acompanhamento",
"follow_ups_upgrade_button_text": "Atualize para ativar os acompanhamentos",
"form_styling": "Estilo do formulário",
"formbricks_sdk_is_not_connected": "O SDK do Formbricks não está conectado",
"four_points": "4 pontos",
"heading": "Cabeçalho",
@@ -1659,6 +1663,7 @@
"survey_completed_subheading": "Este inquérito gratuito e de código aberto foi encerrado",
"survey_display_settings": "Configurações de Exibição do Inquérito",
"survey_placement": "Colocação do Inquérito",
"survey_styling": "Estilo do formulário",
"survey_trigger": "Desencadeador de Inquérito",
"switch_multi_language_on_to_get_started": "Ative o modo multilingue para começar 👉",
"target_block_not_found": "Bloco de destino não encontrado",
+7 -2
View File
@@ -191,6 +191,7 @@
"days": "zile",
"default": "Implicit",
"delete": "Șterge",
"delete_what": "Șterge {deleteWhat}",
"description": "Descriere",
"dev_env": "Mediu de dezvoltare",
"development": "Dezvoltare",
@@ -225,7 +226,9 @@
"failed_to_copy_to_clipboard": "Nu s-a reușit copierea în clipboard",
"failed_to_load_organizations": "Nu s-a reușit încărcarea organizațiilor",
"failed_to_load_workspaces": "Nu s-au putut încărca workspaces",
"filter": "Filtru",
"finish": "Finalizează",
"first_name": "Prenume",
"follow_these": "Urmați acestea",
"formbricks_version": "Versiunea Formbricks",
"full_name": "Nume complet",
@@ -238,6 +241,7 @@
"hidden_field": "Câmp ascuns",
"hidden_fields": "Câmpuri ascunse",
"hide_column": "Ascunde coloana",
"id": "ID",
"image": "Imagine",
"images": "Imagini",
"import": "Import",
@@ -255,6 +259,7 @@
"key": "Cheie",
"label": "Etichetă",
"language": "Limba",
"last_name": "Nume de familie",
"learn_more": "Află mai multe",
"license_expired": "License Expired",
"light_overlay": "Suprapunere ușoară",
@@ -1077,7 +1082,7 @@
"email_customization_preview_email_heading": "Salut {userName}",
"email_customization_preview_email_text": "Acesta este o previzualizare a e-mailului pentru a vă arăta ce logo va fi afișat în e-mailurile.",
"error_deleting_organization_please_try_again": "Eroare la ștergerea organizației. Vă rugăm să încercați din nou.",
"from_your_organization": "din organizația ta",
"from_your_organization": "{memberName} din organizația ta",
"invitation_sent_once_more": "Invitație trimisă din nou.",
"invite_deleted_successfully": "Invitație ștearsă cu succes",
"invite_expires_on": "Invitația expiră pe {date}",
@@ -1440,7 +1445,6 @@
"follow_ups_modal_updated_successfull_toast": "Urmărirea a fost actualizată și va fi salvată odată ce salvați sondajul.",
"follow_ups_new": "Follow-up nou",
"follow_ups_upgrade_button_text": "Actualizați pentru a activa urmărările",
"form_styling": "Stilizare formular",
"formbricks_sdk_is_not_connected": "SDK Formbricks nu este conectat",
"four_points": "4 puncte",
"heading": "Titlu",
@@ -1659,6 +1663,7 @@
"survey_completed_subheading": "Acest sondaj gratuit și open-source a fost închis",
"survey_display_settings": "Setări de afișare a sondajului",
"survey_placement": "Amplasarea sondajului",
"survey_styling": "Stilizare formular",
"survey_trigger": "Declanșator sondaj",
"switch_multi_language_on_to_get_started": "Activați opțiunea multi-limbă pentru a începe 👉",
"target_block_not_found": "Blocul țintă nu a fost găsit",
+7 -2
View File
@@ -191,6 +191,7 @@
"days": "дни",
"default": "По умолчанию",
"delete": "Удалить",
"delete_what": "Удалить {deleteWhat}",
"description": "Описание",
"dev_env": "Dev Environment",
"development": "Разработка",
@@ -225,7 +226,9 @@
"failed_to_copy_to_clipboard": "Не удалось скопировать в буфер обмена",
"failed_to_load_organizations": "Не удалось загрузить организации",
"failed_to_load_workspaces": "Не удалось загрузить рабочие пространства",
"filter": "Фильтр",
"finish": "Завершить",
"first_name": "Имя",
"follow_these": "Выполните следующие действия",
"formbricks_version": "Версия Formbricks",
"full_name": "Полное имя",
@@ -238,6 +241,7 @@
"hidden_field": "Скрытое поле",
"hidden_fields": "Скрытые поля",
"hide_column": "Скрыть столбец",
"id": "ID",
"image": "Изображение",
"images": "Изображения",
"import": "Импорт",
@@ -255,6 +259,7 @@
"key": "Ключ",
"label": "Метка",
"language": "Язык",
"last_name": "Фамилия",
"learn_more": "Подробнее",
"license_expired": "License Expired",
"light_overlay": "Светлый оверлей",
@@ -1077,7 +1082,7 @@
"email_customization_preview_email_heading": "Привет, {userName}",
"email_customization_preview_email_text": "Это предварительный просмотр письма, чтобы показать, какой логотип будет отображаться в письмах.",
"error_deleting_organization_please_try_again": "Ошибка при удалении организации. Пожалуйста, попробуйте ещё раз.",
"from_your_organization": "из вашей организации",
"from_your_organization": "{memberName} из вашей организации",
"invitation_sent_once_more": "Приглашение отправлено ещё раз.",
"invite_deleted_successfully": "Приглашение успешно удалено",
"invite_expires_on": "Приглашение истекает {date}",
@@ -1440,7 +1445,6 @@
"follow_ups_modal_updated_successfull_toast": "Фоллоу-ап обновлён и будет сохранён после сохранения опроса.",
"follow_ups_new": "Новый фоллоу-ап",
"follow_ups_upgrade_button_text": "Обновите тариф для активации фоллоу-апов",
"form_styling": "Оформление формы",
"formbricks_sdk_is_not_connected": "Formbricks SDK не подключён",
"four_points": "4 балла",
"heading": "Заголовок",
@@ -1659,6 +1663,7 @@
"survey_completed_subheading": "Этот бесплатный и открытый опрос был закрыт",
"survey_display_settings": "Настройки отображения опроса",
"survey_placement": "Размещение опроса",
"survey_styling": "Оформление формы",
"survey_trigger": "Триггер опроса",
"switch_multi_language_on_to_get_started": "Включите многоязычный режим, чтобы начать 👉",
"target_block_not_found": "Целевой блок не найден",
+6 -1
View File
@@ -191,6 +191,7 @@
"days": "dagar",
"default": "Standard",
"delete": "Ta bort",
"delete_what": "Ta bort {deleteWhat}",
"description": "Beskrivning",
"dev_env": "Utvecklingsmiljö",
"development": "Utveckling",
@@ -225,7 +226,9 @@
"failed_to_copy_to_clipboard": "Misslyckades att kopiera till urklipp",
"failed_to_load_organizations": "Misslyckades att ladda organisationer",
"failed_to_load_workspaces": "Det gick inte att ladda arbetsytor",
"filter": "Filter",
"finish": "Slutför",
"first_name": "Förnamn",
"follow_these": "Följ dessa",
"formbricks_version": "Formbricks-version",
"full_name": "Fullständigt namn",
@@ -238,6 +241,7 @@
"hidden_field": "Dolt fält",
"hidden_fields": "Dolda fält",
"hide_column": "Dölj kolumn",
"id": "ID",
"image": "Bild",
"images": "Bilder",
"import": "Importera",
@@ -255,6 +259,7 @@
"key": "Nyckel",
"label": "Etikett",
"language": "Språk",
"last_name": "Efternamn",
"learn_more": "Läs mer",
"license_expired": "License Expired",
"light_overlay": "Ljust överlägg",
@@ -1440,7 +1445,6 @@
"follow_ups_modal_updated_successfull_toast": "Uppföljning uppdaterad och sparas när du sparar enkäten.",
"follow_ups_new": "Ny uppföljning",
"follow_ups_upgrade_button_text": "Uppgradera för att aktivera uppföljningar",
"form_styling": "Formulärstil",
"formbricks_sdk_is_not_connected": "Formbricks SDK är inte anslutet",
"four_points": "4 poäng",
"heading": "Rubrik",
@@ -1659,6 +1663,7 @@
"survey_completed_subheading": "Denna gratis och öppenkällkodsenkät har stängts",
"survey_display_settings": "Visningsinställningar för enkät",
"survey_placement": "Enkätplacering",
"survey_styling": "Formulärstil",
"survey_trigger": "Enkätutlösare",
"switch_multi_language_on_to_get_started": "Slå på flerspråkighet för att komma igång 👉",
"target_block_not_found": "Målblock hittades inte",
+7 -2
View File
@@ -191,6 +191,7 @@
"days": "天",
"default": "默认",
"delete": "删除",
"delete_what": "删除{deleteWhat}",
"description": "描述",
"dev_env": "开发 环境",
"development": "开发环境",
@@ -225,7 +226,9 @@
"failed_to_copy_to_clipboard": "复制到剪贴板失败",
"failed_to_load_organizations": "加载组织失败",
"failed_to_load_workspaces": "加载工作区失败",
"filter": "筛选",
"finish": "完成",
"first_name": "名字",
"follow_these": "遵循 这些",
"formbricks_version": "Formbricks 版本",
"full_name": "全名",
@@ -238,6 +241,7 @@
"hidden_field": "隐藏 字段",
"hidden_fields": "隐藏 字段",
"hide_column": "隐藏 列",
"id": "ID",
"image": "图片",
"images": "图片",
"import": "导入",
@@ -255,6 +259,7 @@
"key": "键",
"label": "标签",
"language": "语言",
"last_name": "姓",
"learn_more": "了解 更多",
"license_expired": "License Expired",
"light_overlay": "浅色遮罩层",
@@ -1077,7 +1082,7 @@
"email_customization_preview_email_heading": "嘿 {userName}",
"email_customization_preview_email_text": "这 是 一封 电子邮件 预览,展示 哪个 徽标 将在 电子邮件 中 渲染。",
"error_deleting_organization_please_try_again": "删除 组织时 出错 。 请重试 。",
"from_your_organization": "来自你的组织",
"from_your_organization": "来自您组织的{memberName}",
"invitation_sent_once_more": "再次发送邀请。",
"invite_deleted_successfully": "邀请 删除 成功",
"invite_expires_on": "邀请将于 {date} 过期",
@@ -1440,7 +1445,6 @@
"follow_ups_modal_updated_successfull_toast": "后续 操作 已 更新, 并且 在 你 保存 调查 后 将 被 保存。",
"follow_ups_new": "新的跟进",
"follow_ups_upgrade_button_text": "升级 以启用 跟进",
"form_styling": "表单 样式",
"formbricks_sdk_is_not_connected": "Formbricks SDK 未连接",
"four_points": "4 分",
"heading": "标题",
@@ -1659,6 +1663,7 @@
"survey_completed_subheading": "此 免费 & 开源 调查 已 关闭",
"survey_display_settings": "调查显示设置",
"survey_placement": "调查 放置",
"survey_styling": "表单 样式",
"survey_trigger": "调查 触发",
"switch_multi_language_on_to_get_started": "开启多语言以开始使用 👉",
"target_block_not_found": "未找到目标区块",
+6 -1
View File
@@ -191,6 +191,7 @@
"days": "天",
"default": "預設",
"delete": "刪除",
"delete_what": "刪除{deleteWhat}",
"description": "描述",
"dev_env": "開發環境",
"development": "開發",
@@ -225,7 +226,9 @@
"failed_to_copy_to_clipboard": "無法複製到剪貼簿",
"failed_to_load_organizations": "無法載入組織",
"failed_to_load_workspaces": "載入工作區失敗",
"filter": "篩選",
"finish": "完成",
"first_name": "名字",
"follow_these": "按照這些步驟",
"formbricks_version": "Formbricks 版本",
"full_name": "全名",
@@ -238,6 +241,7 @@
"hidden_field": "隱藏欄位",
"hidden_fields": "隱藏欄位",
"hide_column": "隱藏欄位",
"id": "ID",
"image": "圖片",
"images": "圖片",
"import": "匯入",
@@ -255,6 +259,7 @@
"key": "金鑰",
"label": "標籤",
"language": "語言",
"last_name": "姓氏",
"learn_more": "瞭解更多",
"license_expired": "License Expired",
"light_overlay": "淺色覆蓋",
@@ -1440,7 +1445,6 @@
"follow_ups_modal_updated_successfull_toast": "後續 動作 已 更新 並 將 在 你 儲存 調查 後 儲存",
"follow_ups_new": "新增後續追蹤",
"follow_ups_upgrade_button_text": "升級以啟用後續追蹤",
"form_styling": "表單樣式設定",
"formbricks_sdk_is_not_connected": "Formbricks SDK 未連線",
"four_points": "4 分",
"heading": "標題",
@@ -1659,6 +1663,7 @@
"survey_completed_subheading": "此免費且開源的問卷已關閉",
"survey_display_settings": "問卷顯示設定",
"survey_placement": "問卷位置",
"survey_styling": "表單樣式設定",
"survey_trigger": "問卷觸發器",
"switch_multi_language_on_to_get_started": "請開啟多語言功能以開始使用 👉",
"target_block_not_found": "找不到目標區塊",
@@ -99,7 +99,7 @@ export const ContactControlBar = ({
<DeleteDialog
open={deleteDialogOpen}
setOpen={setDeleteDialogOpen}
deleteWhat="person"
deleteWhat={t("common.person")}
onDelete={handleDeletePerson}
isDeleting={isDeletingPerson}
text={
@@ -66,7 +66,7 @@ export const DeleteContactButton = ({
<DeleteDialog
open={deleteDialogOpen}
setOpen={setDeleteDialogOpen}
deleteWhat="person"
deleteWhat={t("common.person")}
onDelete={handleDeletePerson}
isDeleting={isDeletingPerson}
text={
@@ -52,54 +52,41 @@ export const getPersonSegmentIds = async (
return [];
}
// Phase 1: Build all Prisma where clauses concurrently.
// This converts segment filters into where clauses without per-contact DB queries.
const segmentWithClauses = await Promise.all(
segments.map(async (segment) => {
const filters = segment.filters as TBaseFilters | null;
if (!filters || filters.length === 0) {
return { segmentId: segment.id, whereClause: {} as Prisma.ContactWhereInput };
}
const queryResult = await segmentFilterToPrismaQuery(segment.id, filters, environmentId, deviceType);
if (!queryResult.ok) {
logger.warn(
{ segmentId: segment.id, environmentId, error: queryResult.error },
"Failed to build Prisma query for segment"
);
return { segmentId: segment.id, whereClause: null };
}
return { segmentId: segment.id, whereClause: queryResult.data.whereClause };
})
);
// Separate segments into: always-match (no filters), needs-DB-check, and failed-to-build
// Phase 1: Build WHERE clauses sequentially to avoid connection pool contention.
// segmentFilterToPrismaQuery can itself hit the DB (e.g. unmigrated-row checks),
// so running all builds concurrently would saturate the pool.
const alwaysMatchIds: string[] = [];
const toCheck: { segmentId: string; whereClause: Prisma.ContactWhereInput }[] = [];
const dbChecks: { segmentId: string; whereClause: Prisma.ContactWhereInput }[] = [];
for (const item of segmentWithClauses) {
if (item.whereClause === null) {
for (const segment of segments) {
const filters = segment.filters as TBaseFilters;
if (!filters?.length) {
alwaysMatchIds.push(segment.id);
continue;
}
if (Object.keys(item.whereClause).length === 0) {
alwaysMatchIds.push(item.segmentId);
} else {
toCheck.push({ segmentId: item.segmentId, whereClause: item.whereClause });
const queryResult = await segmentFilterToPrismaQuery(segment.id, filters, environmentId, deviceType);
if (!queryResult.ok) {
logger.warn(
{ segmentId: segment.id, environmentId, error: queryResult.error },
"Failed to build Prisma query for segment, skipping"
);
continue;
}
dbChecks.push({ segmentId: segment.id, whereClause: queryResult.data.whereClause });
}
if (toCheck.length === 0) {
if (dbChecks.length === 0) {
return alwaysMatchIds;
}
// Phase 2: Batch all contact-match checks into a single DB transaction.
// Replaces N individual findFirst queries with one batched round-trip.
const batchResults = await prisma.$transaction(
toCheck.map(({ whereClause }) =>
// Phase 2: Execute all membership checks in a single transaction.
// Uses one connection instead of N concurrent ones, eliminating pool contention.
const txResults = await prisma.$transaction(
dbChecks.map(({ whereClause }) =>
prisma.contact.findFirst({
where: { id: contactId, ...whereClause },
select: { id: true },
@@ -107,17 +94,12 @@ export const getPersonSegmentIds = async (
)
);
// Phase 3: Collect matching segment IDs
const dbMatchIds = toCheck.filter((_, i) => batchResults[i] !== null).map(({ segmentId }) => segmentId);
const matchedIds = dbChecks.filter((_, i) => txResults[i] !== null).map(({ segmentId }) => segmentId);
return [...alwaysMatchIds, ...dbMatchIds];
return [...alwaysMatchIds, ...matchedIds];
} catch (error) {
logger.warn(
{
environmentId,
contactId,
error,
},
{ environmentId, contactId, error },
"Failed to get person segment IDs, returning empty array"
);
return [];
@@ -1,139 +0,0 @@
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
import { prisma } from "@formbricks/database";
import { TJsPersonState } from "@formbricks/types/js";
import { getPersonSegmentIds } from "./segments";
import { getUserState } from "./user-state";
vi.mock("@formbricks/database", () => ({
prisma: {
contact: {
findUniqueOrThrow: vi.fn(),
},
},
}));
vi.mock("./segments", () => ({
getPersonSegmentIds: vi.fn(),
}));
const mockEnvironmentId = "test-environment-id";
const mockUserId = "test-user-id";
const mockContactId = "test-contact-id";
const mockDevice = "desktop";
describe("getUserState", () => {
beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
vi.clearAllMocks();
});
test("should return user state with empty responses and displays", async () => {
const mockContactData = {
id: mockContactId,
responses: [],
displays: [],
};
vi.mocked(prisma.contact.findUniqueOrThrow).mockResolvedValue(mockContactData as any);
vi.mocked(getPersonSegmentIds).mockResolvedValue(["segment1"]);
const result = await getUserState({
environmentId: mockEnvironmentId,
userId: mockUserId,
contactId: mockContactId,
device: mockDevice,
});
expect(prisma.contact.findUniqueOrThrow).toHaveBeenCalledWith({
where: { id: mockContactId },
select: {
id: true,
responses: {
select: { surveyId: true },
},
displays: {
select: { surveyId: true, createdAt: true },
orderBy: { createdAt: "desc" },
},
},
});
expect(getPersonSegmentIds).toHaveBeenCalledWith(
mockEnvironmentId,
mockContactId,
mockUserId,
mockDevice
);
expect(result).toEqual<TJsPersonState["data"]>({
contactId: mockContactId,
userId: mockUserId,
segments: ["segment1"],
displays: [],
responses: [],
lastDisplayAt: null,
});
});
test("should return user state with responses and displays, and sort displays by createdAt", async () => {
const mockDate1 = new Date("2023-01-01T00:00:00.000Z");
const mockDate2 = new Date("2023-01-02T00:00:00.000Z");
const mockContactData = {
id: mockContactId,
responses: [{ surveyId: "survey1" }, { surveyId: "survey2" }],
displays: [
{ surveyId: "survey4", createdAt: mockDate2 }, // most recent (already sorted by desc)
{ surveyId: "survey3", createdAt: mockDate1 },
],
};
vi.mocked(prisma.contact.findUniqueOrThrow).mockResolvedValue(mockContactData as any);
vi.mocked(getPersonSegmentIds).mockResolvedValue(["segment2", "segment3"]);
const result = await getUserState({
environmentId: mockEnvironmentId,
userId: mockUserId,
contactId: mockContactId,
device: mockDevice,
});
expect(result).toEqual<TJsPersonState["data"]>({
contactId: mockContactId,
userId: mockUserId,
segments: ["segment2", "segment3"],
displays: [
{ surveyId: "survey4", createdAt: mockDate2 },
{ surveyId: "survey3", createdAt: mockDate1 },
],
responses: ["survey1", "survey2"],
lastDisplayAt: mockDate2,
});
});
test("should handle empty arrays from prisma", async () => {
// This case tests with proper empty arrays instead of null
const mockContactData = {
id: mockContactId,
responses: [],
displays: [],
};
vi.mocked(prisma.contact.findUniqueOrThrow).mockResolvedValue(mockContactData as any);
vi.mocked(getPersonSegmentIds).mockResolvedValue([]);
const result = await getUserState({
environmentId: mockEnvironmentId,
userId: mockUserId,
contactId: mockContactId,
device: mockDevice,
});
expect(result).toEqual<TJsPersonState["data"]>({
contactId: mockContactId,
userId: mockUserId,
segments: [],
displays: [],
responses: [],
lastDisplayAt: null,
});
});
});
@@ -1,80 +0,0 @@
import { prisma } from "@formbricks/database";
import { TJsPersonState } from "@formbricks/types/js";
import { getPersonSegmentIds } from "./segments";
/**
* Optimized single query to get all user state data
* Replaces multiple separate queries with one efficient query
*/
const getUserStateDataOptimized = async (contactId: string) => {
return prisma.contact.findUniqueOrThrow({
where: { id: contactId },
select: {
id: true,
responses: {
select: { surveyId: true },
},
displays: {
select: {
surveyId: true,
createdAt: true,
},
orderBy: { createdAt: "desc" },
},
},
});
};
/**
* Optimized user state fetcher without caching
* Uses single database query and efficient data processing
* NO CACHING - user state changes frequently with contact updates
*
* @param environmentId - The environment id
* @param userId - The user id
* @param device - The device type
* @returns The person state
* @throws {ValidationError} - If the input is invalid
* @throws {ResourceNotFoundError} - If the environment or organization is not found
*/
export const getUserState = async ({
environmentId,
userId,
contactId,
device,
}: {
environmentId: string;
userId: string;
contactId: string;
device: "phone" | "desktop";
}): Promise<TJsPersonState["data"]> => {
// Single optimized query for all contact data
const contactData = await getUserStateDataOptimized(contactId);
// Get segments using Prisma-based evaluation (no attributes needed - fetched from DB)
const segments = await getPersonSegmentIds(environmentId, contactId, userId, device);
// Process displays efficiently
const displays = (contactData.displays ?? []).map((display) => ({
surveyId: display.surveyId,
createdAt: display.createdAt,
}));
// Get latest display date
const lastDisplayAt =
contactData.displays && contactData.displays.length > 0 ? contactData.displays[0].createdAt : null;
// Process responses efficiently
const responses = (contactData.responses ?? []).map((response) => response.surveyId);
const userState: TJsPersonState["data"] = {
contactId,
userId,
segments,
displays,
responses,
lastDisplayAt,
};
return userState;
};
@@ -1,4 +1,5 @@
import { getLocale } from "@/lingodotdev/language";
import { getTranslate } from "@/lingodotdev/server";
import { ContactsPageLayout } from "@/modules/ee/contacts/components/contacts-page-layout";
import { getContactAttributeKeys } from "@/modules/ee/contacts/lib/contact-attribute-keys";
import { getIsContactsEnabled } from "@/modules/ee/license-check/lib/utils";
@@ -13,7 +14,7 @@ export const AttributesPage = async ({
}) => {
const params = await paramsProps;
const locale = await getLocale();
const t = await getTranslate();
const [{ isReadOnly }, contactAttributeKeys] = await Promise.all([
getEnvironmentAuth(params.environmentId),
getContactAttributeKeys(params.environmentId),
@@ -23,7 +24,7 @@ export const AttributesPage = async ({
return (
<ContactsPageLayout
pageTitle="Contacts"
pageTitle={t("common.contacts")}
activeId="attributes"
environmentId={params.environmentId}
isContactsEnabled={isContactsEnabled}
@@ -1,6 +1,7 @@
"use client";
import { ColumnDef } from "@tanstack/react-table";
import { TFunction } from "i18next";
import { formatAttributeValue } from "@/modules/ee/contacts/lib/format-attribute-value";
import { getSelectionColumn } from "@/modules/ui/components/data-table";
import { HighlightedText } from "@/modules/ui/components/highlighted-text";
@@ -10,12 +11,13 @@ import { TContactTableData } from "../types/contact";
export const generateContactTableColumns = (
searchValue: string,
data: TContactTableData[],
isReadOnly: boolean
isReadOnly: boolean,
t: TFunction
): ColumnDef<TContactTableData>[] => {
const userColumn: ColumnDef<TContactTableData> = {
id: "contactsTableUser",
accessorKey: "contactsTableUser",
header: "ID",
header: t("common.id"),
cell: ({ row }) => {
const contactId = row.original.id;
return <HighlightedText value={contactId} searchValue={searchValue} />;
@@ -25,7 +27,7 @@ export const generateContactTableColumns = (
const userIdColumn: ColumnDef<TContactTableData> = {
id: "userId",
accessorKey: "userId",
header: "User ID",
header: t("common.user_id"),
cell: ({ row }) => {
const userId = row.original.userId;
return <IdBadge id={userId} />;
@@ -35,7 +37,7 @@ export const generateContactTableColumns = (
const emailColumn: ColumnDef<TContactTableData> = {
id: "email",
accessorKey: "email",
header: "Email",
header: t("common.email"),
cell: ({ row }) => {
const email = row.original.email;
if (email) {
@@ -47,7 +49,7 @@ export const generateContactTableColumns = (
const firstNameColumn: ColumnDef<TContactTableData> = {
id: "firstName",
accessorKey: "firstName",
header: "First Name",
header: t("common.first_name"),
cell: ({ row }) => {
const firstName = row.original.firstName;
return <HighlightedText value={firstName} searchValue={searchValue} />;
@@ -57,7 +59,7 @@ export const generateContactTableColumns = (
const lastNameColumn: ColumnDef<TContactTableData> = {
id: "lastName",
accessorKey: "lastName",
header: "Last Name",
header: t("common.last_name"),
cell: ({ row }) => {
const lastName = row.original.lastName;
return <HighlightedText value={lastName} searchValue={searchValue} />;
@@ -71,7 +71,7 @@ export const ContactsTable = ({
// Generate columns
const columns = useMemo(() => {
return generateContactTableColumns(searchValue, data, isReadOnly);
return generateContactTableColumns(searchValue, data, isReadOnly, t);
}, [searchValue, data, isReadOnly]);
// Load saved settings from localStorage
@@ -2,14 +2,15 @@
import { ColumnDef } from "@tanstack/react-table";
import { format, formatDistanceToNow } from "date-fns";
import { TFunction } from "i18next";
import { UsersIcon } from "lucide-react";
import { TSegmentWithSurveyNames } from "@formbricks/types/segment";
export const generateSegmentTableColumns = (): ColumnDef<TSegmentWithSurveyNames>[] => {
export const generateSegmentTableColumns = (t: TFunction): ColumnDef<TSegmentWithSurveyNames>[] => {
const titleColumn: ColumnDef<TSegmentWithSurveyNames> = {
id: "title",
accessorKey: "title",
header: "Title",
header: t("common.title"),
cell: ({ row }) => {
return (
<div className="flex items-center gap-4">
@@ -30,7 +31,7 @@ export const generateSegmentTableColumns = (): ColumnDef<TSegmentWithSurveyNames
const updatedAtColumn: ColumnDef<TSegmentWithSurveyNames> = {
id: "updatedAt",
accessorKey: "updatedAt",
header: "Updated",
header: t("common.updated_at"),
cell: ({ row }) => {
return (
<span className="text-sm text-slate-900">
@@ -43,7 +44,7 @@ export const generateSegmentTableColumns = (): ColumnDef<TSegmentWithSurveyNames
const createdAtColumn: ColumnDef<TSegmentWithSurveyNames> = {
id: "createdAt",
accessorKey: "createdAt",
header: "Created",
header: t("common.created_at"),
cell: ({ row }) => {
return (
<span className="text-sm text-slate-900">{format(row.original.createdAt, "do 'of' MMMM, yyyy")}</span>
@@ -26,7 +26,7 @@ export function SegmentTable({
const [editingSegment, setEditingSegment] = useState<TSegmentWithSurveyNames | null>(null);
const columns = useMemo(() => {
return generateSegmentTableColumns();
return generateSegmentTableColumns(t);
}, []);
const table = useReactTable({
@@ -32,7 +32,7 @@ export const SegmentsPage = async ({
return (
<ContactsPageLayout
pageTitle="Contacts"
pageTitle={t("common.contacts")}
activeId="segments"
environmentId={params.environmentId}
isContactsEnabled={isContactsEnabled}
@@ -168,7 +168,7 @@ export const MemberActions = ({ organization, member, invite, showDeleteButton }
<DeleteDialog
open={isDeleteMemberModalOpen}
setOpen={setDeleteMemberModalOpen}
deleteWhat={`${memberName} ${t("environments.settings.general.from_your_organization")}`}
deleteWhat={t("environments.settings.general.from_your_organization", { memberName })}
onDelete={handleDeleteMember}
isDeleting={isDeleting}
text={t("environments.settings.general.delete_member_confirmation")}
@@ -89,7 +89,7 @@ export const DeleteProjectRender = ({
)}
<DeleteDialog
deleteWhat="Workspace"
deleteWhat={t("environments.settings.domain.workspace")}
open={isDeleteDialogOpen}
setOpen={setIsDeleteDialogOpen}
onDelete={handleDeleteProject}
@@ -1,5 +1,5 @@
import { SettingsCard } from "@/app/(app)/environments/[environmentId]/settings/components/SettingsCard";
import { IS_DEVELOPMENT, IS_FORMBRICKS_CLOUD } from "@/lib/constants";
import { IS_FORMBRICKS_CLOUD } from "@/lib/constants";
import { getProjects } from "@/lib/project/service";
import { getTranslate } from "@/lingodotdev/server";
import { getEnvironmentAuth } from "@/modules/environments/lib/utils";
@@ -7,7 +7,6 @@ import { ProjectConfigNavigation } from "@/modules/projects/settings/components/
import { IdBadge } from "@/modules/ui/components/id-badge";
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
import { PageHeader } from "@/modules/ui/components/page-header";
import packageJson from "@/package.json";
import { CustomScriptsForm } from "./components/custom-scripts-form";
import { DeleteProject } from "./components/delete-project";
import { EditProjectNameForm } from "./components/edit-project-name-form";
@@ -59,9 +58,6 @@ export const GeneralSettingsPage = async (props: { params: Promise<{ environment
</SettingsCard>
<div className="space-y-2">
<IdBadge id={project.id} label={t("common.workspace_id")} variant="column" />
{!IS_FORMBRICKS_CLOUD && !IS_DEVELOPMENT && (
<IdBadge id={packageJson.version} label={t("common.formbricks_version")} variant="column" />
)}
</div>
</PageContentWrapper>
);
@@ -52,7 +52,7 @@ export const ProjectLookSettingsLoading = () => {
<div className="w-full rounded-lg border border-slate-300 bg-white">
<div className="flex flex-col p-4">
<h2 className="text-sm font-semibold text-slate-700">
{t("environments.surveys.edit.form_styling")}
{t("environments.surveys.edit.survey_styling")}
</h2>
<p className="mt-1 text-xs text-slate-500">
{t("environments.surveys.edit.style_the_question_texts_descriptions_and_input_fields")}
@@ -149,7 +149,7 @@ export const ProjectLookSettingsLoading = () => {
<div className={cn("absolute bottom-3 h-16 w-16 rounded bg-slate-700 sm:right-3")}></div>
</div>
</div>
<Button className="pointer-events-none mt-4 animate-pulse cursor-not-allowed bg-slate-200 select-none">
<Button className="pointer-events-none mt-4 animate-pulse cursor-not-allowed select-none bg-slate-200">
{t("common.loading")}
</Button>
</div>
@@ -159,7 +159,7 @@ export const ProjectLookSettingsLoading = () => {
title="Formbricks Signature"
description="We love your support but understand if you toggle it off.">
<div className="w-full items-center">
<div className="pointer-events-none flex cursor-not-allowed items-center space-x-2 select-none">
<div className="pointer-events-none flex cursor-not-allowed select-none items-center space-x-2">
<Switch id="signature" checked={false} />
<Label htmlFor="signature">{t("environments.workspace.look.show_powered_by_formbricks")}</Label>
</div>
@@ -67,7 +67,7 @@ export const FormStylingSettings = ({
<div>
<p className={cn("font-semibold text-slate-800", isSettingsPage ? "text-sm" : "text-base")}>
{t("environments.surveys.edit.form_styling")}
{t("environments.surveys.edit.survey_styling")}
</p>
<p className={cn("mt-1 text-slate-500", isSettingsPage ? "text-xs" : "text-sm")}>
{t("environments.surveys.edit.style_the_question_texts_descriptions_and_input_fields")}
@@ -13,9 +13,6 @@ interface CustomScriptsInjectorProps {
* Injects custom HTML scripts into the document head for link surveys.
* Supports merging project and survey scripts or replacing project scripts with survey scripts.
*
* User-provided scripts are wrapped in try-catch blocks to prevent runtime errors
* (e.g., calls to deprecated browser APIs) from breaking the survey experience.
*
* @param projectScripts - Scripts configured at the workspace/project level
* @param surveyScripts - Scripts configured at the survey level
* @param scriptsMode - "add" merges both, "replace" uses only survey scripts
@@ -61,21 +58,9 @@ export const CustomScriptsInjector = ({
// Copy inline script content
if (script.textContent) {
// Wrap inline scripts in try-catch to prevent user script errors from breaking the survey
newScript.textContent = `
try {
${script.textContent}
} catch (error) {
console.warn('[Formbricks] Error in custom script:', error);
}
`;
newScript.textContent = script.textContent;
}
// Add error handler for external scripts loaded via src
newScript.onerror = (error) => {
console.warn("[Formbricks] Error loading external script:", error);
};
document.head.appendChild(newScript);
});
@@ -246,7 +246,7 @@ export const SurveyDropDownMenu = ({
{!isSurveyCreationDeletionDisabled && (
<DeleteDialog
deleteWhat="Survey"
deleteWhat={t("common.survey")}
open={isDeleteDialogOpen}
setOpen={setDeleteDialogOpen}
onDelete={() => handleDeleteSurvey(survey.id)}
@@ -48,7 +48,7 @@ export const DeleteDialog = ({
<div className="flex items-center gap-2">
<CircleAlert className="h-4 w-4" />
<div>
<DialogTitle>{`${t("common.delete")} ${deleteWhat}`}</DialogTitle>
<DialogTitle>{t("common.delete_what", { deleteWhat })}</DialogTitle>
<DialogDescription>
{t("environments.workspace.general.this_action_cannot_be_undone")}
</DialogDescription>
+5 -5
View File
@@ -54,9 +54,9 @@
"@opentelemetry/sdk-node": "0.211.0",
"@opentelemetry/sdk-trace-base": "2.5.0",
"@opentelemetry/semantic-conventions": "1.38.0",
"@prisma/instrumentation": "6.14.0",
"@paralleldrive/cuid2": "2.2.2",
"@prisma/client": "6.14.0",
"@prisma/instrumentation": "6.14.0",
"@radix-ui/react-accordion": "1.2.10",
"@radix-ui/react-checkbox": "1.3.1",
"@radix-ui/react-collapsible": "1.1.10",
@@ -114,10 +114,12 @@
"prismjs": "1.30.0",
"qr-code-styling": "1.9.2",
"qrcode": "1.5.4",
"react": "19.2.3",
"react-calendar": "5.1.0",
"react-colorful": "5.6.1",
"react-confetti": "6.4.0",
"react-day-picker": "9.6.7",
"react-dom": "19.2.3",
"react-hook-form": "7.56.2",
"react-hot-toast": "2.5.2",
"react-i18next": "15.7.3",
@@ -135,10 +137,8 @@
"uuid": "11.1.0",
"webpack": "5.99.8",
"xlsx": "file:vendor/xlsx-0.20.3.tgz",
"zod": "3.24.4",
"zod-openapi": "4.2.4",
"react": "19.2.3",
"react-dom": "19.2.3"
"zod": "3.25.76",
"zod-openapi": "4.2.4"
},
"devDependencies": {
"@formbricks/config-typescript": "workspace:*",
+4 -4
View File
@@ -50,8 +50,8 @@ test.describe("Survey Styling", async () => {
await addCustomStyles.click();
}
// --- Form styling ---
await openAccordion(page, "Form styling");
// --- Survey styling ---
await openAccordion(page, "Survey styling");
// 1. Headlines & Descriptions
await openAccordion(page, "Headlines & Descriptions");
@@ -182,7 +182,7 @@ test.describe("Survey Styling", async () => {
}
// Set some non-color properties BEFORE suggesting colors, so we can verify they aren't overwritten
await openAccordion(page, "Form styling");
await openAccordion(page, "Survey styling");
await openAccordion(page, "Inputs");
await setDimension(page, "Border Radius", "12");
await setDimension(page, "Padding Y", "20");
@@ -341,7 +341,7 @@ test.describe("Survey Styling", async () => {
}
// Apply Overrides
await openAccordion(page, "Form styling");
await openAccordion(page, "Survey styling");
await openAccordion(page, "Headlines & Descriptions");
// Override Headline Color (Blue)
+6 -2
View File
@@ -99,7 +99,7 @@
"xm-and-surveys/surveys/link-surveys/personal-links",
"xm-and-surveys/surveys/link-surveys/single-use-links",
"xm-and-surveys/surveys/link-surveys/source-tracking",
"xm-and-surveys/surveys/link-surveys/start-at-question",
"xm-and-surveys/surveys/link-surveys/start-at-block",
"xm-and-surveys/surveys/link-surveys/verify-email-before-survey",
"xm-and-surveys/surveys/link-surveys/market-research-panel",
"xm-and-surveys/surveys/link-surveys/pin-protected-surveys",
@@ -516,9 +516,13 @@
"source": "/docs/link-surveys/global/schedule-start-end-dates"
},
{
"destination": "/docs/xm-and-surveys/surveys/link-surveys/start-at-question",
"destination": "/docs/xm-and-surveys/surveys/link-surveys/start-at-block",
"source": "/docs/link-surveys/start-at-question"
},
{
"destination": "/docs/xm-and-surveys/surveys/link-surveys/start-at-block",
"source": "/docs/xm-and-surveys/surveys/link-surveys/start-at-question"
},
{
"destination": "/docs/xm-and-surveys/surveys/general-features/metadata",
"source": "/docs/link-surveys/global/metadata"
Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

@@ -1,6 +1,6 @@
---
title: "Styling Theme"
description: "Keep the survey styling consistent over all surveys with a Styling Theme. Customize the colors, fonts, and other styling options to match your brand's aesthetic."
description: "Keep the survey styling consistent over all surveys with a Styling Theme. Customize colors, fonts, buttons, inputs, and more to match your brand."
icon: "palette"
---
@@ -10,48 +10,114 @@ icon: "palette"
uploads](/self-hosting/configuration/file-uploads) before using these features.
</Note>
Keep the survey styling consistent over all surveys with a Styling Theme. Customize the colors, fonts, and other styling options to match your brand's aesthetic.
Keep the survey styling consistent over all surveys with a Styling Theme. Customize colors, fonts, buttons, inputs, and other styling options to match your brand's aesthetic.
## Configuration
In the left side bar, you find the `Configuration` page. On this page you find the `Look & Feel` section:
![Look & Feel](/images/xm-and-surveys/core-features/styling-theme/look-and-feel.webp)
/>
![Look & Feel](/images/xm-and-surveys/core-features/styling-theme/form-css-styling.webp)
## **Styling Options**
## Survey styling
1. **Form Styling:** Customize the survey card using the following settings
The Survey styling section gives you granular control over every text and input element in your survey. Expand the **Survey styling** panel to find collapsible sub-sections for Headlines & Descriptions, Inputs, Buttons, and Options.
![Form styling options UI](/images/xm-and-surveys/core-features/styling-theme/form-settings.webp)
### Headlines & Descriptions
- **Brand Color**: Sets the primary color tone of the survey.
- **Text Color**: This is a single color scheme that will be used across to display all the text on your survey. Ensures all text is readable against the background.
- **Input Color:** Alters the border color of input fields.
- **Input Border Color**: This is the color of the border of the form input field.
Fine-tune how question headlines, descriptions, and upper labels appear:
2. **Card Styling:** Adjust the look of the survey card
| Property | Description |
|---|---|
| **Headline Color** | Color of the question headline text |
| **Description Color** | Color of the question description text |
| **Headline Font Size** | Font size for headlines (in `px` or any CSS unit) |
| **Description Font Size** | Font size for descriptions |
| **Headline Font Weight** | Numeric font weight for headlines (e.g. `400`, `600`, `700`) |
| **Description Font Weight** | Numeric font weight for descriptions |
| **Upper Label Color** | Color of the small labels above input fields |
| **Upper Label Font Size** | Font size for upper labels |
| **Upper Label Font Weight** | Numeric font weight for upper labels |
![Card styling options UI](/images/xm-and-surveys/core-features/styling-theme/card-settings.webp)
### Inputs
- **Roundness**: Adjusts the corner roundness of the survey card and its components (including input boxes, buttons).
- **Card Background Color**: Sets the card's main background color.
- **Card Border Color**: Changes the border color of the card
Control the appearance of text inputs, textareas, and other form fields:
- **Hide Progress Bar**: Optionally remove the progress bar to simplify the survey experience
- **Add Highlight Border**: Adds a distinct border for emphasis.
| Property | Description |
|---|---|
| **Input Color** | Background color of input fields |
| **Input Border Color** | Border color of input fields |
| **Input Text Color** | Color of text typed into inputs |
| **Border Radius** | Corner roundness of input fields (in `px` or any CSS unit) |
| **Height** | Height of input fields |
| **Font Size** | Font size of text inside inputs |
| **Padding X** | Horizontal padding inside inputs |
| **Padding Y** | Vertical padding inside inputs |
| **Placeholder Opacity** | Opacity of placeholder text (`0` to `1`) |
| **Shadow** | CSS box-shadow value for inputs (e.g. `0 1px 2px rgba(0,0,0,0.1)`) |
3. **Background Styling**: Customize the survey background with static colors, animations, or images (upload your own or get from Unsplash)
### Buttons
<Note>This is only available for Link Surveys</Note>
Customize the submit and navigation buttons:
![Background styling options UI](/images/xm-and-surveys/core-features/styling-theme/background-settings.webp)
| Property | Description |
|---|---|
| **Button Background** | Background color of buttons |
| **Button Text** | Text color of buttons |
| **Border Radius** | Corner roundness of buttons |
| **Height** | Height of buttons |
| **Font Size** | Font size of button text |
| **Font Weight** | Numeric font weight for button text |
| **Padding X** | Horizontal padding inside buttons |
| **Padding Y** | Vertical padding inside buttons |
- **Color**: Pick any color for the background
- **Animation**: Add dynamic animations to enhance user experience..
- **Upload**: Use a custom uploaded image for a personalized touch. Images must be 5 MB or less.
- Image: Choose from Unsplash's extensive gallery. Note that these images will have a link and mention of the author & Unsplash on the bottom right to give them the credit for their awesome work!
- **Background Overlay**: Adjust the background's opacity
### Options
Style the select options in single-select, multi-select, and similar question types:
| Property | Description |
|---|---|
| **Option Background** | Background color of option items |
| **Option Label Color** | Text color of option labels |
| **Border Radius** | Corner roundness of option items |
| **Padding X** | Horizontal padding inside options |
| **Padding Y** | Vertical padding inside options |
| **Font Size** | Font size of option text |
## Card Styling
Adjust the look of the survey card container:
| Property | Description |
|---|---|
| **Roundness** | Corner roundness of the survey card (in `px` or any CSS unit) |
| **Card Background Color** | Background color of the survey card |
| **Card Border Color** | Border color of the survey card |
| **Add Highlight Border** | Adds a distinct colored border for emphasis (app surveys only) |
| **Card Arrangement** | Layout mode for stacking cards: **Simple**, **Straight**, or **Casual** |
### Progress Bar
When the progress bar is visible (toggle **Hide Progress Bar** to control it), you can customize:
| Property | Description |
|---|---|
| **Track Background** | Background color of the progress track |
| **Indicator Background** | Fill color of the progress indicator |
| **Track Height** | Height of the progress bar track |
## Background Styling
Customize the survey background with static colors, animations, or images (upload your own or pick from Unsplash).
<Note>Background styling is only available for Link Surveys.</Note>
| Property | Description |
|---|---|
| **Color** | Pick any color for the background |
| **Animation** | Add dynamic animations to enhance user experience |
| **Upload** | Use a custom uploaded image (5 MB max) |
| **Image** | Choose from Unsplash's gallery (attribution shown automatically) |
| **Background Overlay** | Adjust the background's opacity / brightness |
## Add Brand Logo
@@ -59,30 +125,44 @@ Customize your survey with your brand's logo.
<Note>Brand logos are only visible on Link Survey pages.</Note>
1. In the Look & Feel page itself in Project settings, scroll down to see the Logo Upload box.
<Steps>
<Step title="Open Logo Settings">
In the **Look & Feel** page in Project settings, scroll down to the **Logo Upload** box.
![Choose a link survey template](/images/xm-and-surveys/core-features/styling-theme/step-four.webp)
![Logo upload box](/images/xm-and-surveys/core-features/styling-theme/step-four.webp)
</Step>
2. Upload your logo. Logos must be 5 MB or less.
<Step title="Upload Your Logo">
Upload your logo. Logos must be 5 MB or less.
![Choose a link survey template](/images/xm-and-surveys/core-features/styling-theme/step-five.webp)
![Upload logo](/images/xm-and-surveys/core-features/styling-theme/step-five.webp)
</Step>
3. Add a background color: If youve uploaded a transparent image and want to add background to it, enable this toggle and select the color of your choice.
<Step title="Add Background Color (Optional)">
If you've uploaded a transparent image and want to add a background to it, enable the toggle and select a color.
![Choose a link survey template](/images/xm-and-surveys/core-features/styling-theme/step-six.webp)
![Logo background color](/images/xm-and-surveys/core-features/styling-theme/step-six.webp)
</Step>
4. Remember to save your changes!
<Step title="Save">
Remember to save your changes!
![Choose a link survey template](/images/xm-and-surveys/core-features/styling-theme/step-seven.webp)
![Save changes](/images/xm-and-surveys/core-features/styling-theme/step-seven.webp)
</Step>
</Steps>
<Note>The logo settings apply across all Link Surveys pages.</Note>
<Note>The logo settings apply across all Link Survey pages.</Note>
## Overwrite Styling Theme
You can allow to overwrite the styling theme for individual surveys to create unique styles for each survey:
You can allow overwriting the styling theme for individual surveys to create unique styles per survey:
![Choose a link survey template](/images/xm-and-surveys/core-features/styling-theme/allow-overwrite.webp)
![Allow overwrite toggle](/images/xm-and-surveys/core-features/styling-theme/allow-overwrite.webp)
In the survey editor, a tab called `Styling` will appear. Here you can overwrite the default styling theme.
In the survey editor, a **Styling** tab will appear where you can overwrite the default styling theme. See the [Custom Styling](/xm-and-surveys/surveys/general-features/overwrite-styling) guide for details.
---
## CSS Variables Reference
Under the hood, every styling property maps to a CSS variable prefixed with `--fb-`. For App & Website Surveys, you can override these directly in your global CSS file (e.g., `globals.css`) by targeting the `#fbjs` selector.
See the full [CSS Variables Reference](/xm-and-surveys/surveys/general-features/overwrite-styling#overwrite-css-styles-for-app--website-surveys) in the Custom Styling guide.
@@ -76,12 +76,4 @@ Windows XP
Who's a Good Boy?
"Things you've likely said to your dog."
![Dog-themed survey example](/images/xm-and-surveys/surveys/general-features/overwrite-styling/doggo.webp)
### Fixes & Improvements:
- **Numbered list formatting**: Fixed numbering issues.
- **Consistent image alt text**: Updated descriptions for clarity.
- **CSS syntax correction**: Removed unnecessary text before code block.
- **Grammar & punctuation fixes**: Ensured clarity and smooth readability.
This should now display correctly on Mintlify! Let me know if you need further tweaks.
![Dog-themed survey example](/images/xm-and-surveys/surveys/general-features/overwrite-styling/doggo.webp)
@@ -0,0 +1,42 @@
---
title: "Start At Specific Block"
description:
"Start a survey at a specific block using the URL to skip earlier blocks."
icon: "arrow-right"
---
The `startAt` URL parameter lets you open a Link Survey at a specific **block** instead of from the beginning. This is useful when you want to link to a specific part of the survey from external sources or reuse the same survey at different points in the user journey.
## How it works
The survey navigation is block-based: each block can contain one or more questions. When you pass `startAt` with a Question ID, the survey finds the **block** that contains that question and opens at that block. All questions in that block are shown together.
<Note>
**Multi-question blocks:** When a block has multiple questions, `startAt` opens at the block—you will see all questions in that block, not only the question whose ID you used. For precise "start at this exact question" behavior, use one question per block.
</Note>
## How to use it
1. In the Survey Editor, open the Questions Tab and ensure the survey is set as a **Link Survey**.
2. Find the question (or block) you want to start at, click on **Show Advanced Settings**, and copy the **Question ID** of any question in that block.
<Note>
Each question has a unique Question ID. Since `startAt` resolves to the block containing the question, you can use any question ID from the target block—typically the first question in that block.
</Note>
3. Append `?startAt=question_id` to your survey's URL, replacing `question_id` with the copied Question ID.
4. Share this modified URL with your users to start the survey at the specified block.
### Sample Link Survey URL with `startAt`
```sh Example Link Survey URL with startAt configured
https://formbricks.com/clny997dj087ho30fdzyf4nkl?startAt=bqd29m94l9k0hnc3azbrexl8
```
## Use cases
- **Link to a specific block from an external source:** Direct users to a specific block in your survey from emails, chatbots, or web pages.
- **Use the same survey in different parts of the user journey:** Reuse the survey at different stages, starting at different blocks to gather insights.
- **Create a personalized survey experience:** Tailor the survey by starting at a particular block based on the user's past interactions or preferences.
@@ -1,36 +0,0 @@
---
title: "Start At Specific Question"
description:
"Start a survey at a specific question using the URL to skip the initial questions."
icon: "arrow-right"
---
You can start a survey at a specific question from the survey using the URL to skip the initial questions. This is useful when you want to link to a specific question from an external source or want to use the same survey in different parts of the user journey.
## How to Use it?
1. In the Survey Editor, open the Questions Tab and ensure the survey is set as a **Link Survey**.
2. Find the question you want to start at, click on **Show Advanced Settings**, and copy the **Question ID**.
<Note>
Each question has a unique Question ID, which is used to identify it in the
survey. You can use different Question IDs for multiple **startAt** points in
the URL.
</Note>
3. Append `?startAt=question_id` to your survey's URL, replacing `question_id` with the copied Question ID.
4. Share this modified URL with your users to start the survey at the specified question.
### Sample Link Survey URL with `startAt`
```sh Example Link Survey URL with startAt configured
https://formbricks.com/clny997dj087ho30fdzyf4nkl?startAt=bqd29m94l9k0hnc3azbrexl8
```
## Use Cases
- **Link to a specific question from an external source:** Use this feature to direct users to a specific question in your survey from emails, chatbots, or web pages, providing a seamless experience.
- **Use the same survey in different parts of the user journey:** Employ the same survey at various stages of the user journey, starting at different questions to gather comprehensive insights.
- **Create a personalized survey experience:** Tailor the survey experience by starting at a particular question based on the user's past interactions or preferences, enhancing engagement.
+1 -1
View File
@@ -39,7 +39,7 @@
"dependencies": {
"@formbricks/logger": "workspace:*",
"redis": "5.8.1",
"zod": "3.24.4"
"zod": "3.25.76"
},
"devDependencies": {
"@formbricks/config-typescript": "workspace:*",
+1 -1
View File
@@ -52,7 +52,7 @@
"@prisma/client": "6.14.0",
"bcryptjs": "2.4.3",
"uuid": "11.1.0",
"zod": "3.24.4",
"zod": "3.25.76",
"zod-openapi": "4.2.4"
},
"devDependencies": {
+1 -1
View File
@@ -20,7 +20,7 @@
"@formbricks/config-typescript": "workspace:*",
"@formbricks/eslint-config": "workspace:*",
"@formbricks/types": "workspace:*",
"@react-email/preview-server": "5.2.5",
"@react-email/preview-server": "5.2.8",
"autoprefixer": "10.4.21",
"clsx": "2.1.1",
"postcss": "8.5.3",
@@ -887,6 +887,7 @@ describe("utils.ts", () => {
targetElement.className = "other";
targetElement.matches = vi.fn(() => false);
targetElement.closest = vi.fn(() => null); // no ancestor matches either
const action: TEnvironmentStateActionClass = {
id: "clabc123abc",
@@ -993,13 +994,93 @@ describe("utils.ts", () => {
expect(result).toBe(true);
});
// --- Regression tests for nested child click target (issue #7314) ---
// In this test environment document.createElement() returns a plain mock object,
// so we set .matches and .closest as vi.fn() — the same pattern used by existing tests.
// This exercises the exact code path of the fix: matches() fails → closest() succeeds.
test("returns true when clicking a child element inside a button matched by cssSelector", () => {
const button = document.createElement("button");
const icon = document.createElement("span");
// Simulate: icon does NOT directly match ".my-btn", but its closest ancestor does
(icon as unknown as { matches: ReturnType<typeof vi.fn> }).matches = vi.fn(() => false);
(icon as unknown as { closest: ReturnType<typeof vi.fn> }).closest = vi.fn(() => button);
const action: TEnvironmentStateActionClass = {
id: "clabc123abc",
name: "Test Action",
type: "noCode",
key: null,
noCodeConfig: {
type: "click",
urlFilters: [],
elementSelector: { cssSelector: ".my-btn" },
},
};
// Before fix: matches() → false → returns false (bug)
// After fix: matches() → false → closest() → button → returns true (correct)
const result = evaluateNoCodeConfigClick(icon as unknown as HTMLElement, action);
expect(result).toBe(true);
});
test("returns false when clicking a child element with no matching ancestor", () => {
const other = document.createElement("div");
// Simulate: element doesn't match, and no ancestor matches either
(other as unknown as { matches: ReturnType<typeof vi.fn> }).matches = vi.fn(() => false);
(other as unknown as { closest: ReturnType<typeof vi.fn> }).closest = vi.fn(() => null);
const action: TEnvironmentStateActionClass = {
id: "clabc123abc",
name: "Test Action",
type: "noCode",
key: null,
noCodeConfig: {
type: "click",
urlFilters: [],
elementSelector: { cssSelector: ".my-btn" },
},
};
const result = evaluateNoCodeConfigClick(other as unknown as HTMLElement, action);
expect(result).toBe(false);
});
test("uses direct target (not closest) when target directly matches cssSelector", () => {
const button = document.createElement("button");
// Simulate: click on the button itself — matches() succeeds, closest() should NOT be called
(button as unknown as { matches: ReturnType<typeof vi.fn> }).matches = vi.fn(() => true);
const closestSpy = vi.fn();
(button as unknown as { closest: ReturnType<typeof vi.fn> }).closest = closestSpy;
const action: TEnvironmentStateActionClass = {
id: "clabc123abc",
name: "Test Action",
type: "noCode",
key: null,
noCodeConfig: {
type: "click",
urlFilters: [],
elementSelector: { cssSelector: ".my-btn" },
},
};
const result = evaluateNoCodeConfigClick(button as unknown as HTMLElement, action);
expect(result).toBe(true);
expect(closestSpy).not.toHaveBeenCalled(); // closest() is only a fallback
});
test("handles multiple cssSelectors correctly", () => {
const targetElement = document.createElement("div");
targetElement.className = "test other";
targetElement.matches = vi.fn((selector) => {
return selector === ".test" || selector === ".other";
return selector === ".test" || selector === ".other" || selector === ".test .other";
});
targetElement.closest = vi.fn(() => null); // not needed but consistent with mock environment
const action: TEnvironmentStateActionClass = {
id: "clabc123abc",
+17 -9
View File
@@ -304,20 +304,28 @@ export const evaluateNoCodeConfigClick = (
if (!innerHtml && !cssSelector) return false;
if (innerHtml && targetElement.innerHTML !== innerHtml) return false;
// Resolve the element to test: prefer the direct click target, but walk up to
// the nearest ancestor that matches the CSS selector (event delegation for nested markup,
// e.g. <svg> or <span> inside a <button class="my-btn">).
let matchedElement: HTMLElement = targetElement;
if (cssSelector) {
// Split selectors that start with a . or # including the . or #
const individualSelectors = cssSelector
.split(/(?=[.#])/) // split before each . or #
.map((sel) => sel.trim()); // remove leftover whitespace
for (const selector of individualSelectors) {
if (!targetElement.matches(selector)) {
return false;
}
let matchesDirectly = false;
try {
matchesDirectly = targetElement.matches(cssSelector);
} catch {
matchesDirectly = false;
}
if (!matchesDirectly) {
const ancestor = targetElement.closest(cssSelector);
if (!ancestor) return false;
matchedElement = ancestor as HTMLElement;
}
}
// Check innerHtml against the resolved element, not the raw click target
if (innerHtml && matchedElement.innerHTML !== innerHtml) return false;
const connector = action.noCodeConfig.urlFiltersConnector ?? "or";
const isValidUrl = handleUrlFilters(urlFilters, connector);
+1 -1
View File
@@ -35,7 +35,7 @@
},
"author": "Formbricks <hola@formbricks.com>",
"dependencies": {
"zod": "3.24.4",
"zod": "3.25.76",
"pino": "10.0.0",
"pino-opentelemetry-transport": "2.0.0",
"pino-pretty": "13.1.1"
+2 -2
View File
@@ -80,7 +80,7 @@ describe("service.ts", () => {
Key: "uploads/images/test-file.jpg",
Fields: {
"Content-Type": "image/jpeg",
// "Content-Encoding": "base64",
success_action_status: "201",
},
Conditions: [["content-length-range", 0, mockMaxSize]],
});
@@ -175,7 +175,7 @@ describe("service.ts", () => {
Key: "uploads/images/test-file.jpg",
Fields: {
"Content-Type": "image/jpeg",
// "Content-Encoding": "base64",
success_action_status: "201",
},
Conditions: [["content-length-range", 0, mockMaxSize]],
});
+1 -1
View File
@@ -66,7 +66,7 @@ export const getSignedUploadUrl = async (
Key: `${filePath}/${fileName}`,
Fields: {
"Content-Type": contentType,
// "Content-Encoding": "base64",
success_action_status: "201",
},
Conditions: postConditions,
});
+30
View File
@@ -57,6 +57,36 @@
color: var(--fb-subheading-color) !important;
}
/*
* Restore list styling for rich text (questions/descriptions).
* Preflight resets ul/ol with list-style:none; these overrides restore bullets/numbers.
*/
#fbjs .htmlbody ul,
#fbjs .htmlbody ol,
#fbjs [data-variant="headline"] ul,
#fbjs [data-variant="headline"] ol,
#fbjs [data-variant="description"] ul,
#fbjs [data-variant="description"] ol {
list-style-position: outside;
margin: 0.5em 0;
padding-left: 1.5em;
}
#fbjs .htmlbody ul,
#fbjs [data-variant="headline"] ul,
#fbjs [data-variant="description"] ul {
list-style-type: disc;
}
#fbjs .htmlbody ol,
#fbjs [data-variant="headline"] ol,
#fbjs [data-variant="description"] ol {
list-style-type: decimal;
}
#fbjs .htmlbody li,
#fbjs [data-variant="headline"] li,
#fbjs [data-variant="description"] li {
margin: 0.25em 0;
}
/* without this, it wont override the color */
#fbjs p.editor-paragraph {
overflow-wrap: break-word;
+1 -1
View File
@@ -10,7 +10,7 @@
},
"dependencies": {
"@prisma/client": "6.14.0",
"zod": "3.24.4",
"zod": "3.25.76",
"zod-openapi": "4.2.4",
"node-html-parser": "7.0.1"
},
+302 -160
View File
@@ -297,7 +297,7 @@ importers:
version: 10.5.0(@opentelemetry/context-async-hooks@2.5.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.5.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.0(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@16.1.6(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(webpack@5.99.8(esbuild@0.25.12))
'@t3-oss/env-nextjs':
specifier: 0.13.4
version: 0.13.4(arktype@2.1.29)(typescript@5.8.3)(zod@3.24.4)
version: 0.13.4(arktype@2.1.29)(typescript@5.8.3)(zod@3.25.76)
'@tailwindcss/forms':
specifier: 0.5.10
version: 0.5.10(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.15.18)(typescript@5.8.3)))
@@ -390,7 +390,7 @@ importers:
version: 4.24.12(patch_hash=7ac5717a8d7d2049442182b5d83ab492d33fe774ff51ff5ea3884628b77df87b)(next@16.1.6(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(nodemailer@7.0.11)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
next-safe-action:
specifier: 7.10.8
version: 7.10.8(next@16.1.6(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@3.24.4)
version: 7.10.8(next@16.1.6(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@3.25.76)
node-fetch:
specifier: 3.3.2
version: 3.3.2
@@ -482,11 +482,11 @@ importers:
specifier: file:vendor/xlsx-0.20.3.tgz
version: file:apps/web/vendor/xlsx-0.20.3.tgz
zod:
specifier: 3.24.4
version: 3.24.4
specifier: 3.25.76
version: 3.25.76
zod-openapi:
specifier: 4.2.4
version: 4.2.4(zod@3.24.4)
version: 4.2.4(zod@3.25.76)
devDependencies:
'@formbricks/config-typescript':
specifier: workspace:*
@@ -582,8 +582,8 @@ importers:
specifier: 5.8.1
version: 5.8.1
zod:
specifier: 3.24.4
version: 3.24.4
specifier: 3.25.76
version: 3.25.76
devDependencies:
'@formbricks/config-typescript':
specifier: workspace:*
@@ -685,11 +685,11 @@ importers:
specifier: 11.1.0
version: 11.1.0
zod:
specifier: 3.24.4
version: 3.24.4
specifier: 3.25.76
version: 3.25.76
zod-openapi:
specifier: 4.2.4
version: 4.2.4(zod@3.24.4)
version: 4.2.4(zod@3.25.76)
devDependencies:
'@formbricks/config-typescript':
specifier: workspace:*
@@ -744,8 +744,8 @@ importers:
specifier: workspace:*
version: link:../types
'@react-email/preview-server':
specifier: 5.2.5
version: 5.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
specifier: 5.2.8
version: 5.2.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
autoprefixer:
specifier: 10.4.21
version: 10.4.21(postcss@8.5.3)
@@ -829,8 +829,8 @@ importers:
specifier: 13.1.1
version: 13.1.1
zod:
specifier: 3.24.4
version: 3.24.4
specifier: 3.25.76
version: 3.25.76
devDependencies:
'@formbricks/config-typescript':
specifier: workspace:*
@@ -1067,11 +1067,11 @@ importers:
specifier: 7.0.1
version: 7.0.1
zod:
specifier: 3.24.4
version: 3.24.4
specifier: 3.25.76
version: 3.25.76
zod-openapi:
specifier: 4.2.4
version: 4.2.4(zod@3.24.4)
version: 4.2.4(zod@3.25.76)
devDependencies:
'@formbricks/config-typescript':
specifier: workspace:*
@@ -1827,6 +1827,12 @@ packages:
cpu: [ppc64]
os: [aix]
'@esbuild/aix-ppc64@0.25.10':
resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
'@esbuild/aix-ppc64@0.25.12':
resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
engines: {node: '>=18'}
@@ -1845,6 +1851,12 @@ packages:
cpu: [arm64]
os: [android]
'@esbuild/android-arm64@0.25.10':
resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm64@0.25.12':
resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
engines: {node: '>=18'}
@@ -1863,6 +1875,12 @@ packages:
cpu: [arm]
os: [android]
'@esbuild/android-arm@0.25.10':
resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
'@esbuild/android-arm@0.25.12':
resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
engines: {node: '>=18'}
@@ -1881,6 +1899,12 @@ packages:
cpu: [x64]
os: [android]
'@esbuild/android-x64@0.25.10':
resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
'@esbuild/android-x64@0.25.12':
resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
engines: {node: '>=18'}
@@ -1899,6 +1923,12 @@ packages:
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-arm64@0.25.10':
resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-arm64@0.25.12':
resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
engines: {node: '>=18'}
@@ -1917,6 +1947,12 @@ packages:
cpu: [x64]
os: [darwin]
'@esbuild/darwin-x64@0.25.10':
resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
'@esbuild/darwin-x64@0.25.12':
resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
engines: {node: '>=18'}
@@ -1935,6 +1971,12 @@ packages:
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-arm64@0.25.10':
resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-arm64@0.25.12':
resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
engines: {node: '>=18'}
@@ -1953,6 +1995,12 @@ packages:
cpu: [x64]
os: [freebsd]
'@esbuild/freebsd-x64@0.25.10':
resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
'@esbuild/freebsd-x64@0.25.12':
resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
engines: {node: '>=18'}
@@ -1971,6 +2019,12 @@ packages:
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm64@0.25.10':
resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm64@0.25.12':
resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
engines: {node: '>=18'}
@@ -1989,6 +2043,12 @@ packages:
cpu: [arm]
os: [linux]
'@esbuild/linux-arm@0.25.10':
resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
'@esbuild/linux-arm@0.25.12':
resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
engines: {node: '>=18'}
@@ -2007,6 +2067,12 @@ packages:
cpu: [ia32]
os: [linux]
'@esbuild/linux-ia32@0.25.10':
resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-ia32@0.25.12':
resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
engines: {node: '>=18'}
@@ -2025,6 +2091,12 @@ packages:
cpu: [loong64]
os: [linux]
'@esbuild/linux-loong64@0.25.10':
resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-loong64@0.25.12':
resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
engines: {node: '>=18'}
@@ -2043,6 +2115,12 @@ packages:
cpu: [mips64el]
os: [linux]
'@esbuild/linux-mips64el@0.25.10':
resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-mips64el@0.25.12':
resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
engines: {node: '>=18'}
@@ -2061,6 +2139,12 @@ packages:
cpu: [ppc64]
os: [linux]
'@esbuild/linux-ppc64@0.25.10':
resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-ppc64@0.25.12':
resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
engines: {node: '>=18'}
@@ -2079,6 +2163,12 @@ packages:
cpu: [riscv64]
os: [linux]
'@esbuild/linux-riscv64@0.25.10':
resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-riscv64@0.25.12':
resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
engines: {node: '>=18'}
@@ -2097,6 +2187,12 @@ packages:
cpu: [s390x]
os: [linux]
'@esbuild/linux-s390x@0.25.10':
resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-s390x@0.25.12':
resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
engines: {node: '>=18'}
@@ -2115,6 +2211,12 @@ packages:
cpu: [x64]
os: [linux]
'@esbuild/linux-x64@0.25.10':
resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
'@esbuild/linux-x64@0.25.12':
resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
engines: {node: '>=18'}
@@ -2127,6 +2229,12 @@ packages:
cpu: [x64]
os: [linux]
'@esbuild/netbsd-arm64@0.25.10':
resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
'@esbuild/netbsd-arm64@0.25.12':
resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
engines: {node: '>=18'}
@@ -2145,6 +2253,12 @@ packages:
cpu: [x64]
os: [netbsd]
'@esbuild/netbsd-x64@0.25.10':
resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
'@esbuild/netbsd-x64@0.25.12':
resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
engines: {node: '>=18'}
@@ -2163,6 +2277,12 @@ packages:
cpu: [arm64]
os: [openbsd]
'@esbuild/openbsd-arm64@0.25.10':
resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
'@esbuild/openbsd-arm64@0.25.12':
resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
engines: {node: '>=18'}
@@ -2181,6 +2301,12 @@ packages:
cpu: [x64]
os: [openbsd]
'@esbuild/openbsd-x64@0.25.10':
resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
'@esbuild/openbsd-x64@0.25.12':
resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
engines: {node: '>=18'}
@@ -2193,6 +2319,12 @@ packages:
cpu: [x64]
os: [openbsd]
'@esbuild/openharmony-arm64@0.25.10':
resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
'@esbuild/openharmony-arm64@0.25.12':
resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
engines: {node: '>=18'}
@@ -2211,6 +2343,12 @@ packages:
cpu: [x64]
os: [sunos]
'@esbuild/sunos-x64@0.25.10':
resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
'@esbuild/sunos-x64@0.25.12':
resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
engines: {node: '>=18'}
@@ -2229,6 +2367,12 @@ packages:
cpu: [arm64]
os: [win32]
'@esbuild/win32-arm64@0.25.10':
resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-arm64@0.25.12':
resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
engines: {node: '>=18'}
@@ -2247,6 +2391,12 @@ packages:
cpu: [ia32]
os: [win32]
'@esbuild/win32-ia32@0.25.10':
resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-ia32@0.25.12':
resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
engines: {node: '>=18'}
@@ -2265,6 +2415,12 @@ packages:
cpu: [x64]
os: [win32]
'@esbuild/win32-x64@0.25.10':
resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
'@esbuild/win32-x64@0.25.12':
resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
engines: {node: '>=18'}
@@ -2845,46 +3001,24 @@ packages:
'@neoconfetti/react@1.0.0':
resolution: {integrity: sha512-klcSooChXXOzIm+SE5IISIAn3bYzYfPjbX7D7HoqZL84oAfgREeSg5vSIaSFH+DaGzzvImTyWe1OyrJ67vik4A==}
'@next/env@16.0.10':
resolution: {integrity: sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang==}
'@next/env@16.1.6':
resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==}
'@next/eslint-plugin-next@15.3.2':
resolution: {integrity: sha512-ijVRTXBgnHT33aWnDtmlG+LJD+5vhc9AKTJPquGG5NKXjpKNjc62woIhFtrAcWdBobt8kqjCoaJ0q6sDQoX7aQ==}
'@next/swc-darwin-arm64@16.0.10':
resolution: {integrity: sha512-4XgdKtdVsaflErz+B5XeG0T5PeXKDdruDf3CRpnhN+8UebNa5N2H58+3GDgpn/9GBurrQ1uWW768FfscwYkJRg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
'@next/swc-darwin-arm64@16.1.6':
resolution: {integrity: sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
'@next/swc-darwin-x64@16.0.10':
resolution: {integrity: sha512-spbEObMvRKkQ3CkYVOME+ocPDFo5UqHb8EMTS78/0mQ+O1nqE8toHJVioZo4TvebATxgA8XMTHHrScPrn68OGw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
'@next/swc-darwin-x64@16.1.6':
resolution: {integrity: sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
'@next/swc-linux-arm64-gnu@16.0.10':
resolution: {integrity: sha512-uQtWE3X0iGB8apTIskOMi2w/MKONrPOUCi5yLO+v3O8Mb5c7K4Q5KD1jvTpTF5gJKa3VH/ijKjKUq9O9UhwOYw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@next/swc-linux-arm64-gnu@16.1.6':
resolution: {integrity: sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==}
engines: {node: '>= 10'}
@@ -2892,13 +3026,6 @@ packages:
os: [linux]
libc: [glibc]
'@next/swc-linux-arm64-musl@16.0.10':
resolution: {integrity: sha512-llA+hiDTrYvyWI21Z0L1GiXwjQaanPVQQwru5peOgtooeJ8qx3tlqRV2P7uH2pKQaUfHxI/WVarvI5oYgGxaTw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@next/swc-linux-arm64-musl@16.1.6':
resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==}
engines: {node: '>= 10'}
@@ -2906,13 +3033,6 @@ packages:
os: [linux]
libc: [musl]
'@next/swc-linux-x64-gnu@16.0.10':
resolution: {integrity: sha512-AK2q5H0+a9nsXbeZ3FZdMtbtu9jxW4R/NgzZ6+lrTm3d6Zb7jYrWcgjcpM1k8uuqlSy4xIyPR2YiuUr+wXsavA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@next/swc-linux-x64-gnu@16.1.6':
resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==}
engines: {node: '>= 10'}
@@ -2920,13 +3040,6 @@ packages:
os: [linux]
libc: [glibc]
'@next/swc-linux-x64-musl@16.0.10':
resolution: {integrity: sha512-1TDG9PDKivNw5550S111gsO4RGennLVl9cipPhtkXIFVwo31YZ73nEbLjNC8qG3SgTz/QZyYyaFYMeY4BKZR/g==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [musl]
'@next/swc-linux-x64-musl@16.1.6':
resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==}
engines: {node: '>= 10'}
@@ -2934,24 +3047,12 @@ packages:
os: [linux]
libc: [musl]
'@next/swc-win32-arm64-msvc@16.0.10':
resolution: {integrity: sha512-aEZIS4Hh32xdJQbHz121pyuVZniSNoqDVx1yIr2hy+ZwJGipeqnMZBJHyMxv2tiuAXGx6/xpTcQJ6btIiBjgmg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
'@next/swc-win32-arm64-msvc@16.1.6':
resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
'@next/swc-win32-x64-msvc@16.0.10':
resolution: {integrity: sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
'@next/swc-win32-x64-msvc@16.1.6':
resolution: {integrity: sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==}
engines: {node: '>= 10'}
@@ -4521,8 +4622,8 @@ packages:
peerDependencies:
react: ^18.0 || ^19.0 || ^19.0.0-rc
'@react-email/preview-server@5.2.5':
resolution: {integrity: sha512-YERhEKl0Dz2qNbHTzdSwnsK15gipEqonKMPEbsoE8C+ACiHIm/f/d1UzQVmhrsN6PW7L+JhAuzcdIX1H3pLmFg==}
'@react-email/preview-server@5.2.8':
resolution: {integrity: sha512-drQ0C7vi7P0uE7Ox1Cyiujsx0oqp2RbIscOdSBR5qvzw3EKjlGbW2pWjQ000cjxTq3Si7lqlRKhOIF8MzOnqHw==}
'@react-email/preview@0.0.14':
resolution: {integrity: sha512-aYK8q0IPkBXyMsbpMXgxazwHxYJxTrXrV95GFuu2HbEiIToMwSyUgb8HDFYwPqqfV03/jbwqlsXmFxsOd+VNaw==}
@@ -7602,6 +7703,11 @@ packages:
engines: {node: '>=18'}
hasBin: true
esbuild@0.25.10:
resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==}
engines: {node: '>=18'}
hasBin: true
esbuild@0.25.12:
resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
engines: {node: '>=18'}
@@ -9326,27 +9432,6 @@ packages:
zod:
optional: true
next@16.0.10:
resolution: {integrity: sha512-RtWh5PUgI+vxlV3HdR+IfWA1UUHu0+Ram/JBO4vWB54cVPentCD0e+lxyAYEsDTqGGMg7qpjhKh6dc6aW7W/sA==}
engines: {node: '>=20.9.0'}
hasBin: true
peerDependencies:
'@opentelemetry/api': ^1.1.0
'@playwright/test': ^1.51.1
babel-plugin-react-compiler: '*'
react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
sass: ^1.3.0
peerDependenciesMeta:
'@opentelemetry/api':
optional: true
'@playwright/test':
optional: true
babel-plugin-react-compiler:
optional: true
sass:
optional: true
next@16.1.6:
resolution: {integrity: sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==}
engines: {node: '>=20.9.0'}
@@ -11758,8 +11843,8 @@ packages:
peerDependencies:
zod: ^3.21.4
zod@3.24.4:
resolution: {integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==}
zod@3.25.76:
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
snapshots:
@@ -13575,6 +13660,9 @@ snapshots:
'@esbuild/aix-ppc64@0.23.1':
optional: true
'@esbuild/aix-ppc64@0.25.10':
optional: true
'@esbuild/aix-ppc64@0.25.12':
optional: true
@@ -13584,6 +13672,9 @@ snapshots:
'@esbuild/android-arm64@0.23.1':
optional: true
'@esbuild/android-arm64@0.25.10':
optional: true
'@esbuild/android-arm64@0.25.12':
optional: true
@@ -13593,6 +13684,9 @@ snapshots:
'@esbuild/android-arm@0.23.1':
optional: true
'@esbuild/android-arm@0.25.10':
optional: true
'@esbuild/android-arm@0.25.12':
optional: true
@@ -13602,6 +13696,9 @@ snapshots:
'@esbuild/android-x64@0.23.1':
optional: true
'@esbuild/android-x64@0.25.10':
optional: true
'@esbuild/android-x64@0.25.12':
optional: true
@@ -13611,6 +13708,9 @@ snapshots:
'@esbuild/darwin-arm64@0.23.1':
optional: true
'@esbuild/darwin-arm64@0.25.10':
optional: true
'@esbuild/darwin-arm64@0.25.12':
optional: true
@@ -13620,6 +13720,9 @@ snapshots:
'@esbuild/darwin-x64@0.23.1':
optional: true
'@esbuild/darwin-x64@0.25.10':
optional: true
'@esbuild/darwin-x64@0.25.12':
optional: true
@@ -13629,6 +13732,9 @@ snapshots:
'@esbuild/freebsd-arm64@0.23.1':
optional: true
'@esbuild/freebsd-arm64@0.25.10':
optional: true
'@esbuild/freebsd-arm64@0.25.12':
optional: true
@@ -13638,6 +13744,9 @@ snapshots:
'@esbuild/freebsd-x64@0.23.1':
optional: true
'@esbuild/freebsd-x64@0.25.10':
optional: true
'@esbuild/freebsd-x64@0.25.12':
optional: true
@@ -13647,6 +13756,9 @@ snapshots:
'@esbuild/linux-arm64@0.23.1':
optional: true
'@esbuild/linux-arm64@0.25.10':
optional: true
'@esbuild/linux-arm64@0.25.12':
optional: true
@@ -13656,6 +13768,9 @@ snapshots:
'@esbuild/linux-arm@0.23.1':
optional: true
'@esbuild/linux-arm@0.25.10':
optional: true
'@esbuild/linux-arm@0.25.12':
optional: true
@@ -13665,6 +13780,9 @@ snapshots:
'@esbuild/linux-ia32@0.23.1':
optional: true
'@esbuild/linux-ia32@0.25.10':
optional: true
'@esbuild/linux-ia32@0.25.12':
optional: true
@@ -13674,6 +13792,9 @@ snapshots:
'@esbuild/linux-loong64@0.23.1':
optional: true
'@esbuild/linux-loong64@0.25.10':
optional: true
'@esbuild/linux-loong64@0.25.12':
optional: true
@@ -13683,6 +13804,9 @@ snapshots:
'@esbuild/linux-mips64el@0.23.1':
optional: true
'@esbuild/linux-mips64el@0.25.10':
optional: true
'@esbuild/linux-mips64el@0.25.12':
optional: true
@@ -13692,6 +13816,9 @@ snapshots:
'@esbuild/linux-ppc64@0.23.1':
optional: true
'@esbuild/linux-ppc64@0.25.10':
optional: true
'@esbuild/linux-ppc64@0.25.12':
optional: true
@@ -13701,6 +13828,9 @@ snapshots:
'@esbuild/linux-riscv64@0.23.1':
optional: true
'@esbuild/linux-riscv64@0.25.10':
optional: true
'@esbuild/linux-riscv64@0.25.12':
optional: true
@@ -13710,6 +13840,9 @@ snapshots:
'@esbuild/linux-s390x@0.23.1':
optional: true
'@esbuild/linux-s390x@0.25.10':
optional: true
'@esbuild/linux-s390x@0.25.12':
optional: true
@@ -13719,12 +13852,18 @@ snapshots:
'@esbuild/linux-x64@0.23.1':
optional: true
'@esbuild/linux-x64@0.25.10':
optional: true
'@esbuild/linux-x64@0.25.12':
optional: true
'@esbuild/linux-x64@0.27.2':
optional: true
'@esbuild/netbsd-arm64@0.25.10':
optional: true
'@esbuild/netbsd-arm64@0.25.12':
optional: true
@@ -13734,6 +13873,9 @@ snapshots:
'@esbuild/netbsd-x64@0.23.1':
optional: true
'@esbuild/netbsd-x64@0.25.10':
optional: true
'@esbuild/netbsd-x64@0.25.12':
optional: true
@@ -13743,6 +13885,9 @@ snapshots:
'@esbuild/openbsd-arm64@0.23.1':
optional: true
'@esbuild/openbsd-arm64@0.25.10':
optional: true
'@esbuild/openbsd-arm64@0.25.12':
optional: true
@@ -13752,12 +13897,18 @@ snapshots:
'@esbuild/openbsd-x64@0.23.1':
optional: true
'@esbuild/openbsd-x64@0.25.10':
optional: true
'@esbuild/openbsd-x64@0.25.12':
optional: true
'@esbuild/openbsd-x64@0.27.2':
optional: true
'@esbuild/openharmony-arm64@0.25.10':
optional: true
'@esbuild/openharmony-arm64@0.25.12':
optional: true
@@ -13767,6 +13918,9 @@ snapshots:
'@esbuild/sunos-x64@0.23.1':
optional: true
'@esbuild/sunos-x64@0.25.10':
optional: true
'@esbuild/sunos-x64@0.25.12':
optional: true
@@ -13776,6 +13930,9 @@ snapshots:
'@esbuild/win32-arm64@0.23.1':
optional: true
'@esbuild/win32-arm64@0.25.10':
optional: true
'@esbuild/win32-arm64@0.25.12':
optional: true
@@ -13785,6 +13942,9 @@ snapshots:
'@esbuild/win32-ia32@0.23.1':
optional: true
'@esbuild/win32-ia32@0.25.10':
optional: true
'@esbuild/win32-ia32@0.25.12':
optional: true
@@ -13794,6 +13954,9 @@ snapshots:
'@esbuild/win32-x64@0.23.1':
optional: true
'@esbuild/win32-x64@0.25.10':
optional: true
'@esbuild/win32-x64@0.25.12':
optional: true
@@ -14441,59 +14604,33 @@ snapshots:
'@neoconfetti/react@1.0.0': {}
'@next/env@16.0.10': {}
'@next/env@16.1.6': {}
'@next/eslint-plugin-next@15.3.2':
dependencies:
fast-glob: 3.3.1
'@next/swc-darwin-arm64@16.0.10':
optional: true
'@next/swc-darwin-arm64@16.1.6':
optional: true
'@next/swc-darwin-x64@16.0.10':
optional: true
'@next/swc-darwin-x64@16.1.6':
optional: true
'@next/swc-linux-arm64-gnu@16.0.10':
optional: true
'@next/swc-linux-arm64-gnu@16.1.6':
optional: true
'@next/swc-linux-arm64-musl@16.0.10':
optional: true
'@next/swc-linux-arm64-musl@16.1.6':
optional: true
'@next/swc-linux-x64-gnu@16.0.10':
optional: true
'@next/swc-linux-x64-gnu@16.1.6':
optional: true
'@next/swc-linux-x64-musl@16.0.10':
optional: true
'@next/swc-linux-x64-musl@16.1.6':
optional: true
'@next/swc-win32-arm64-msvc@16.0.10':
optional: true
'@next/swc-win32-arm64-msvc@16.1.6':
optional: true
'@next/swc-win32-x64-msvc@16.0.10':
optional: true
'@next/swc-win32-x64-msvc@16.1.6':
optional: true
@@ -16719,9 +16856,10 @@ snapshots:
marked: 15.0.12
react: 19.2.3
'@react-email/preview-server@5.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
'@react-email/preview-server@5.2.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
dependencies:
next: 16.0.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
esbuild: 0.25.10
next: 16.1.6(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
transitivePeerDependencies:
- '@babel/core'
- '@opentelemetry/api'
@@ -17928,19 +18066,19 @@ snapshots:
dependencies:
tslib: 2.8.1
'@t3-oss/env-core@0.13.4(arktype@2.1.29)(typescript@5.8.3)(zod@3.24.4)':
'@t3-oss/env-core@0.13.4(arktype@2.1.29)(typescript@5.8.3)(zod@3.25.76)':
dependencies:
arktype: 2.1.29
optionalDependencies:
typescript: 5.8.3
zod: 3.24.4
zod: 3.25.76
'@t3-oss/env-nextjs@0.13.4(arktype@2.1.29)(typescript@5.8.3)(zod@3.24.4)':
'@t3-oss/env-nextjs@0.13.4(arktype@2.1.29)(typescript@5.8.3)(zod@3.25.76)':
dependencies:
'@t3-oss/env-core': 0.13.4(arktype@2.1.29)(typescript@5.8.3)(zod@3.24.4)
'@t3-oss/env-core': 0.13.4(arktype@2.1.29)(typescript@5.8.3)(zod@3.25.76)
optionalDependencies:
typescript: 5.8.3
zod: 3.24.4
zod: 3.25.76
transitivePeerDependencies:
- arktype
@@ -20291,6 +20429,35 @@ snapshots:
'@esbuild/win32-ia32': 0.23.1
'@esbuild/win32-x64': 0.23.1
esbuild@0.25.10:
optionalDependencies:
'@esbuild/aix-ppc64': 0.25.10
'@esbuild/android-arm': 0.25.10
'@esbuild/android-arm64': 0.25.10
'@esbuild/android-x64': 0.25.10
'@esbuild/darwin-arm64': 0.25.10
'@esbuild/darwin-x64': 0.25.10
'@esbuild/freebsd-arm64': 0.25.10
'@esbuild/freebsd-x64': 0.25.10
'@esbuild/linux-arm': 0.25.10
'@esbuild/linux-arm64': 0.25.10
'@esbuild/linux-ia32': 0.25.10
'@esbuild/linux-loong64': 0.25.10
'@esbuild/linux-mips64el': 0.25.10
'@esbuild/linux-ppc64': 0.25.10
'@esbuild/linux-riscv64': 0.25.10
'@esbuild/linux-s390x': 0.25.10
'@esbuild/linux-x64': 0.25.10
'@esbuild/netbsd-arm64': 0.25.10
'@esbuild/netbsd-x64': 0.25.10
'@esbuild/openbsd-arm64': 0.25.10
'@esbuild/openbsd-x64': 0.25.10
'@esbuild/openharmony-arm64': 0.25.10
'@esbuild/sunos-x64': 0.25.10
'@esbuild/win32-arm64': 0.25.10
'@esbuild/win32-ia32': 0.25.10
'@esbuild/win32-x64': 0.25.10
esbuild@0.25.12:
optionalDependencies:
'@esbuild/aix-ppc64': 0.25.12
@@ -22203,38 +22370,13 @@ snapshots:
optionalDependencies:
nodemailer: 7.0.11
next-safe-action@7.10.8(next@16.1.6(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@3.24.4):
next-safe-action@7.10.8(next@16.1.6(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@3.25.76):
dependencies:
next: 16.1.6(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
optionalDependencies:
zod: 3.24.4
next@16.0.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
dependencies:
'@next/env': 16.0.10
'@swc/helpers': 0.5.15
caniuse-lite: 1.0.30001762
postcss: 8.4.31
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
styled-jsx: 5.1.6(@babel/core@7.28.5)(react@19.2.3)
optionalDependencies:
'@next/swc-darwin-arm64': 16.0.10
'@next/swc-darwin-x64': 16.0.10
'@next/swc-linux-arm64-gnu': 16.0.10
'@next/swc-linux-arm64-musl': 16.0.10
'@next/swc-linux-x64-gnu': 16.0.10
'@next/swc-linux-x64-musl': 16.0.10
'@next/swc-win32-arm64-msvc': 16.0.10
'@next/swc-win32-x64-msvc': 16.0.10
'@opentelemetry/api': 1.9.0
'@playwright/test': 1.56.1
sharp: 0.34.5
transitivePeerDependencies:
- '@babel/core'
- babel-plugin-macros
zod: 3.25.76
next@16.1.6(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
dependencies:
@@ -25089,8 +25231,8 @@ snapshots:
yoga-layout@3.2.1: {}
zod-openapi@4.2.4(zod@3.24.4):
zod-openapi@4.2.4(zod@3.25.76):
dependencies:
zod: 3.24.4
zod: 3.25.76
zod@3.24.4: {}
zod@3.25.76: {}