mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-01 21:22:38 -05:00
Compare commits
1 Commits
feat/custo
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c34c316d0 |
35
README.md
35
README.md
@@ -127,34 +127,10 @@ Formbricks has a hosted cloud offering with a generous free plan to get you up a
|
||||
|
||||
Formbricks is available Open-Source under AGPLv3 license. You can host Formbricks on your own servers using Docker without a subscription.
|
||||
|
||||
If you opt for self-hosting Formbricks, here are a few options to consider:
|
||||
|
||||
#### Docker
|
||||
|
||||
To get started with self-hosting with Docker, take a look at our [self-hosting docs](https://formbricks.com/docs/self-hosting/deployment).
|
||||
|
||||
#### Community-managed One Click Hosting
|
||||
|
||||
##### Railway
|
||||
|
||||
You can deploy Formbricks on [Railway](https://railway.app) using the button below.
|
||||
|
||||
[](https://railway.app/new/template/PPDzCd)
|
||||
|
||||
##### RepoCloud
|
||||
|
||||
Or you can also deploy Formbricks on [RepoCloud](https://repocloud.io) using the button below.
|
||||
|
||||
[](https://repocloud.io/details/?app_id=254)
|
||||
|
||||
##### Zeabur
|
||||
|
||||
Or you can also deploy Formbricks on [Zeabur](https://zeabur.com) using the button below.
|
||||
|
||||
[](https://zeabur.com/templates/G4TUJL)
|
||||
|
||||
<a id="development"></a>
|
||||
|
||||
## 👨💻 Development
|
||||
|
||||
### Prerequisites
|
||||
@@ -248,14 +224,3 @@ We currently do not offer Formbricks white-labeled. That means that we don't sel
|
||||
The Enterprise Edition allows us to fund the development of Formbricks sustainably. It guarantees that the free and open-source surveying infrastructure we're building will be around for decades to come.
|
||||
|
||||
<a id="readme-de"></a>
|
||||
|
||||
## Deutsch
|
||||
|
||||
Formbricks ist eine freie, quelloffene und datenschutzorientierte Plattform für Surveys und Experience Management. Mit In-App-, Website-, Link- und E-Mail-Umfragen sammelt ihr Feedback entlang der gesamten User Journey.
|
||||
|
||||
- Website & Cloud: [formbricks.com](https://formbricks.com/) und [Cloud starten](https://app.formbricks.com/auth/signup)
|
||||
- Self-Hosting: [Deployment-Dokumentation](https://formbricks.com/docs/self-hosting/deployment)
|
||||
- Beitrag & Community: [Beitragen](https://formbricks.com/docs/developer-docs/contributing/get-started), [GitHub Discussions](https://github.com/formbricks/formbricks/discussions) und [Issues](https://github.com/formbricks/formbricks/issues)
|
||||
- Sicherheit & Lizenz: [`SECURITY.md`](./SECURITY.md) und [AGPLv3](https://github.com/formbricks/formbricks/blob/main/LICENSE)
|
||||
|
||||
<p align="right"><a href="#top">🔼 Back to top</a></p>
|
||||
|
||||
@@ -4,7 +4,6 @@ import { z } from "zod";
|
||||
import { ZId } from "@formbricks/types/common";
|
||||
import { ResourceNotFoundError } from "@formbricks/types/errors";
|
||||
import { ZResponseFilterCriteria } from "@formbricks/types/responses";
|
||||
import { capturePostHogEvent } from "@/lib/posthog";
|
||||
import { getResponseDownloadFile, getResponseFilteringValues } from "@/lib/response/service";
|
||||
import { getSurvey } from "@/lib/survey/service";
|
||||
import { getTagsByEnvironmentId } from "@/lib/tag/service";
|
||||
@@ -24,11 +23,9 @@ const ZGetResponsesDownloadUrlAction = z.object({
|
||||
export const getResponsesDownloadUrlAction = authenticatedActionClient
|
||||
.inputSchema(ZGetResponsesDownloadUrlAction)
|
||||
.action(async ({ ctx, parsedInput }) => {
|
||||
const organizationId = await getOrganizationIdFromSurveyId(parsedInput.surveyId);
|
||||
|
||||
await checkAuthorizationUpdated({
|
||||
userId: ctx.user.id,
|
||||
organizationId,
|
||||
organizationId: await getOrganizationIdFromSurveyId(parsedInput.surveyId),
|
||||
access: [
|
||||
{
|
||||
type: "organization",
|
||||
@@ -42,20 +39,11 @@ export const getResponsesDownloadUrlAction = authenticatedActionClient
|
||||
],
|
||||
});
|
||||
|
||||
const result = await getResponseDownloadFile(
|
||||
return await getResponseDownloadFile(
|
||||
parsedInput.surveyId,
|
||||
parsedInput.format,
|
||||
parsedInput.filterCriteria
|
||||
);
|
||||
|
||||
capturePostHogEvent(ctx.user.id, "responses_exported", {
|
||||
survey_id: parsedInput.surveyId,
|
||||
format: parsedInput.format,
|
||||
filter_applied: Object.keys(parsedInput.filterCriteria ?? {}).length > 0,
|
||||
organization_id: organizationId,
|
||||
});
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
const ZGetSurveyFilterDataAction = z.object({
|
||||
|
||||
@@ -4,7 +4,6 @@ import { z } from "zod";
|
||||
import { ZId } from "@formbricks/types/common";
|
||||
import { ZIntegrationInput } from "@formbricks/types/integration";
|
||||
import { createOrUpdateIntegration, deleteIntegration } from "@/lib/integration/service";
|
||||
import { capturePostHogEvent } from "@/lib/posthog";
|
||||
import { authenticatedActionClient } from "@/lib/utils/action-client";
|
||||
import { checkAuthorizationUpdated } from "@/lib/utils/action-client/action-client-middleware";
|
||||
import {
|
||||
@@ -46,12 +45,6 @@ export const createOrUpdateIntegrationAction = authenticatedActionClient
|
||||
const result = await createOrUpdateIntegration(parsedInput.environmentId, parsedInput.integrationData);
|
||||
ctx.auditLoggingCtx.integrationId = result.id;
|
||||
ctx.auditLoggingCtx.newObject = result;
|
||||
|
||||
capturePostHogEvent(ctx.user.id, "integration_connected", {
|
||||
integration_type: parsedInput.integrationData.type,
|
||||
organization_id: organizationId,
|
||||
});
|
||||
|
||||
return result;
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { PipelineTriggers, Webhook } from "@prisma/client";
|
||||
import { headers } from "next/headers";
|
||||
import { v7 as uuidv7 } from "uuid";
|
||||
import { createCacheKey } from "@formbricks/cache";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { logger } from "@formbricks/logger";
|
||||
import { ResourceNotFoundError } from "@formbricks/types/errors";
|
||||
@@ -9,12 +8,10 @@ import { sendTelemetryEvents } from "@/app/api/(internal)/pipeline/lib/telemetry
|
||||
import { ZPipelineInput } from "@/app/api/(internal)/pipeline/types/pipelines";
|
||||
import { responses } from "@/app/lib/api/response";
|
||||
import { transformErrorToDetails } from "@/app/lib/api/validator";
|
||||
import { cache } from "@/lib/cache";
|
||||
import { CRON_SECRET } from "@/lib/constants";
|
||||
import { generateStandardWebhookSignature } from "@/lib/crypto";
|
||||
import { getIntegrations } from "@/lib/integration/service";
|
||||
import { getOrganizationByEnvironmentId } from "@/lib/organization/service";
|
||||
import { capturePostHogEvent } from "@/lib/posthog";
|
||||
import { getResponseCountBySurveyId } from "@/lib/response/service";
|
||||
import { getSurvey, updateSurvey } from "@/lib/survey/service";
|
||||
import { convertDatesInObject } from "@/lib/time";
|
||||
@@ -302,25 +299,6 @@ export const POST = async (request: Request) => {
|
||||
logger.error({ error, responseId: response.id }, "Failed to record response meter event");
|
||||
});
|
||||
|
||||
// Sampled PostHog tracking: first response + every 100th
|
||||
const responseCount = await cache.withCache(
|
||||
() => getResponseCountBySurveyId(surveyId),
|
||||
createCacheKey.response.countBySurveyId(surveyId),
|
||||
60 * 1000
|
||||
);
|
||||
|
||||
if (responseCount === 1 || responseCount % 100 === 0) {
|
||||
capturePostHogEvent(organization.id, "survey_response_received", {
|
||||
survey_id: surveyId,
|
||||
survey_type: survey.type,
|
||||
organization_id: organization.id,
|
||||
environment_id: environmentId,
|
||||
response_count: responseCount,
|
||||
is_first_response: responseCount === 1,
|
||||
milestone: responseCount === 1 ? "first" : String(responseCount),
|
||||
});
|
||||
}
|
||||
|
||||
// Send telemetry events
|
||||
await sendTelemetryEvents();
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import { IS_FORMBRICKS_CLOUD } from "@/lib/constants";
|
||||
import { gethasNoOrganizations } from "@/lib/instance/service";
|
||||
import { createMembership } from "@/lib/membership/service";
|
||||
import { createOrganization } from "@/lib/organization/service";
|
||||
import { capturePostHogEvent } from "@/lib/posthog";
|
||||
import { authenticatedActionClient } from "@/lib/utils/action-client";
|
||||
import { withAuditLogging } from "@/modules/ee/audit-logs/lib/handler";
|
||||
import { ensureCloudStripeSetupForOrganization } from "@/modules/ee/billing/lib/organization-billing";
|
||||
@@ -50,12 +49,6 @@ export const createOrganizationAction = authenticatedActionClient
|
||||
ctx.auditLoggingCtx.organizationId = newOrganization.id;
|
||||
ctx.auditLoggingCtx.newObject = newOrganization;
|
||||
|
||||
capturePostHogEvent(ctx.user.id, "organization_created", {
|
||||
organization_id: newOrganization.id,
|
||||
is_first_org: hasNoOrganizations,
|
||||
user_id: ctx.user.id,
|
||||
});
|
||||
|
||||
return newOrganization;
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import "server-only";
|
||||
import { logger } from "@formbricks/logger";
|
||||
import { posthogServerClient } from "./server";
|
||||
|
||||
type PostHogEventProperties = Record<string, string | number | boolean | null | undefined>;
|
||||
|
||||
export function capturePostHogEvent(
|
||||
distinctId: string,
|
||||
eventName: string,
|
||||
properties?: PostHogEventProperties
|
||||
): void {
|
||||
if (!posthogServerClient) return;
|
||||
|
||||
try {
|
||||
posthogServerClient.capture({
|
||||
distinctId,
|
||||
event: eventName,
|
||||
properties: {
|
||||
...properties,
|
||||
$lib: "posthog-node",
|
||||
source: "server",
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
logger.warn({ error, eventName }, "Failed to capture PostHog event");
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { capturePostHogEvent } from "./capture";
|
||||
@@ -1,37 +0,0 @@
|
||||
import "server-only";
|
||||
import { PostHog } from "posthog-node";
|
||||
import { logger } from "@formbricks/logger";
|
||||
import { POSTHOG_KEY } from "@/lib/constants";
|
||||
|
||||
const POSTHOG_HOST = "https://eu.i.posthog.com";
|
||||
|
||||
const globalForPostHog = globalThis as unknown as {
|
||||
posthogServerClient: PostHog | undefined;
|
||||
};
|
||||
|
||||
function createPostHogClient(): PostHog | null {
|
||||
if (!POSTHOG_KEY) return null;
|
||||
|
||||
return new PostHog(POSTHOG_KEY, {
|
||||
host: POSTHOG_HOST,
|
||||
flushAt: 1,
|
||||
flushInterval: 0,
|
||||
});
|
||||
}
|
||||
|
||||
export const posthogServerClient: PostHog | null =
|
||||
globalForPostHog.posthogServerClient ?? createPostHogClient();
|
||||
|
||||
if (process.env.NODE_ENV !== "production" && posthogServerClient) {
|
||||
globalForPostHog.posthogServerClient = posthogServerClient;
|
||||
}
|
||||
|
||||
if (process.env.NEXT_RUNTIME === "nodejs" && posthogServerClient) {
|
||||
const shutdownPostHog = () => {
|
||||
posthogServerClient?.shutdown().catch((err) => {
|
||||
logger.error(err, "Error shutting down PostHog server client");
|
||||
});
|
||||
};
|
||||
process.on("SIGTERM", shutdownPostHog);
|
||||
process.on("SIGINT", shutdownPostHog);
|
||||
}
|
||||
@@ -10,12 +10,10 @@ import {
|
||||
EMAIL_VERIFICATION_DISABLED,
|
||||
ENCRYPTION_KEY,
|
||||
ENTERPRISE_LICENSE_KEY,
|
||||
POSTHOG_KEY,
|
||||
SESSION_MAX_AGE,
|
||||
} from "@/lib/constants";
|
||||
import { symmetricDecrypt, symmetricEncrypt } from "@/lib/crypto";
|
||||
import { verifyToken } from "@/lib/jwt";
|
||||
import { capturePostHogEvent } from "@/lib/posthog";
|
||||
import { updateUser, updateUserLastLoginAt } from "@/modules/auth/lib/user";
|
||||
import {
|
||||
logAuthAttempt,
|
||||
@@ -337,25 +335,6 @@ export const authOptions: NextAuthOptions = {
|
||||
"";
|
||||
|
||||
const userEmail = user.email ?? "";
|
||||
const userId = user.id as string;
|
||||
|
||||
// Capture sign-in event for PostHog (query BEFORE updating lastLoginAt)
|
||||
const captureSignIn = async (provider: string) => {
|
||||
if (!POSTHOG_KEY) return;
|
||||
|
||||
const [membershipCount, userData] = await Promise.all([
|
||||
prisma.membership.count({ where: { userId } }),
|
||||
prisma.user.findUnique({ where: { id: userId }, select: { lastLoginAt: true } }),
|
||||
]);
|
||||
const isFirstLoginToday =
|
||||
!userData?.lastLoginAt || userData.lastLoginAt.toDateString() !== new Date().toDateString();
|
||||
|
||||
capturePostHogEvent(userId, "user_signed_in", {
|
||||
auth_provider: provider,
|
||||
organization_count: membershipCount,
|
||||
is_first_login_today: isFirstLoginToday,
|
||||
});
|
||||
};
|
||||
|
||||
if (account?.provider === "credentials" || account?.provider === "token") {
|
||||
// check if user's email is verified or not
|
||||
@@ -363,7 +342,6 @@ export const authOptions: NextAuthOptions = {
|
||||
logger.error("Email Verification is Pending");
|
||||
throw new Error("Email Verification is Pending");
|
||||
}
|
||||
await captureSignIn(account.provider);
|
||||
await updateUserLastLoginAt(userEmail);
|
||||
return true;
|
||||
}
|
||||
@@ -375,12 +353,10 @@ export const authOptions: NextAuthOptions = {
|
||||
});
|
||||
|
||||
if (result) {
|
||||
await captureSignIn(account.provider);
|
||||
await updateUserLastLoginAt(userEmail);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
await captureSignIn(account?.provider ?? "unknown");
|
||||
await updateUserLastLoginAt(userEmail);
|
||||
return true;
|
||||
},
|
||||
|
||||
@@ -9,7 +9,6 @@ import { IS_FORMBRICKS_CLOUD, IS_TURNSTILE_CONFIGURED, TURNSTILE_SECRET_KEY } fr
|
||||
import { verifyInviteToken } from "@/lib/jwt";
|
||||
import { createMembership } from "@/lib/membership/service";
|
||||
import { createOrganization } from "@/lib/organization/service";
|
||||
import { capturePostHogEvent } from "@/lib/posthog";
|
||||
import { actionClient } from "@/lib/utils/action-client";
|
||||
import { ActionClientCtx } from "@/lib/utils/action-client/types/context";
|
||||
import { createUser, updateUser } from "@/modules/auth/lib/user";
|
||||
@@ -212,13 +211,6 @@ export const createUserAction = actionClient.inputSchema(ZCreateUserAction).acti
|
||||
subscribeToSecurityUpdates: parsedInput.subscribeToSecurityUpdates,
|
||||
subscribeToProductUpdates: parsedInput.subscribeToProductUpdates,
|
||||
});
|
||||
|
||||
capturePostHogEvent(user.id, "user_signed_up", {
|
||||
auth_provider: "credentials",
|
||||
email_domain: user.email.split("@")[1],
|
||||
signup_source: parsedInput.inviteToken ? "invite" : "direct",
|
||||
invite_organization_id: ctx.auditLoggingCtx.organizationId ?? null,
|
||||
});
|
||||
}
|
||||
|
||||
if (user) {
|
||||
|
||||
@@ -6,7 +6,6 @@ import { OperationNotAllowedError, ResourceNotFoundError } from "@formbricks/typ
|
||||
import { ZCloudBillingInterval } from "@formbricks/types/organizations";
|
||||
import { WEBAPP_URL } from "@/lib/constants";
|
||||
import { getOrganization } from "@/lib/organization/service";
|
||||
import { capturePostHogEvent } from "@/lib/posthog";
|
||||
import { authenticatedActionClient } from "@/lib/utils/action-client";
|
||||
import { checkAuthorizationUpdated } from "@/lib/utils/action-client/action-client-middleware";
|
||||
import { getOrganizationIdFromEnvironmentId } from "@/lib/utils/helper";
|
||||
@@ -251,13 +250,6 @@ export const startProTrialAction = authenticatedActionClient
|
||||
await createProTrialSubscription(parsedInput.organizationId, customerId);
|
||||
await reconcileCloudStripeSubscriptionsForOrganization(parsedInput.organizationId);
|
||||
await syncOrganizationBillingFromStripe(parsedInput.organizationId);
|
||||
|
||||
capturePostHogEvent(ctx.user.id, "free_trial_started", {
|
||||
plan: "pro",
|
||||
organization_id: parsedInput.organizationId,
|
||||
trial_duration_days: 14,
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
});
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import { DEFAULT_TEAM_ID, SKIP_INVITE_FOR_SSO } from "@/lib/constants";
|
||||
import { getIsFreshInstance } from "@/lib/instance/service";
|
||||
import { verifyInviteToken } from "@/lib/jwt";
|
||||
import { createMembership } from "@/lib/membership/service";
|
||||
import { capturePostHogEvent } from "@/lib/posthog";
|
||||
import { findMatchingLocale } from "@/lib/utils/locale";
|
||||
import { redactPII } from "@/lib/utils/logger-helpers";
|
||||
import { createBrevoCustomer } from "@/modules/auth/lib/brevo";
|
||||
@@ -361,14 +360,6 @@ export const handleSsoCallback = async ({
|
||||
|
||||
// send new user to brevo
|
||||
createBrevoCustomer({ id: userProfile.id, email: userProfile.email });
|
||||
|
||||
capturePostHogEvent(userProfile.id, "user_signed_up", {
|
||||
auth_provider: provider,
|
||||
email_domain: userProfile.email.split("@")[1],
|
||||
signup_source: callbackUrl?.includes("token=") ? "invite" : "direct",
|
||||
invite_organization_id: organization?.id ?? null,
|
||||
});
|
||||
|
||||
await syncSsoAccount(userProfile.id, account);
|
||||
|
||||
if (isMultiOrgEnabled) {
|
||||
|
||||
@@ -10,7 +10,6 @@ import { INVITE_DISABLED, IS_FORMBRICKS_CLOUD } from "@/lib/constants";
|
||||
import { createInviteToken } from "@/lib/jwt";
|
||||
import { getMembershipByUserIdOrganizationId } from "@/lib/membership/service";
|
||||
import { getAccessFlags } from "@/lib/membership/utils";
|
||||
import { capturePostHogEvent } from "@/lib/posthog";
|
||||
import { authenticatedActionClient } from "@/lib/utils/action-client";
|
||||
import { checkAuthorizationUpdated } from "@/lib/utils/action-client/action-client-middleware";
|
||||
import { getOrganizationIdFromInviteId } from "@/lib/utils/helper";
|
||||
@@ -328,11 +327,6 @@ export const inviteUserAction = authenticatedActionClient.inputSchema(ZInviteUse
|
||||
await sendInviteMemberEmail(inviteId, parsedInput.email, ctx.user.name ?? "", parsedInput.name ?? "");
|
||||
}
|
||||
|
||||
capturePostHogEvent(ctx.user.id, "team_member_invited", {
|
||||
organization_id: parsedInput.organizationId,
|
||||
invitee_role: parsedInput.role,
|
||||
});
|
||||
|
||||
return inviteId;
|
||||
})
|
||||
);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import { z } from "zod";
|
||||
import { OperationNotAllowedError, ResourceNotFoundError } from "@formbricks/types/errors";
|
||||
import { ZSurveyCreateInput } from "@formbricks/types/surveys/types";
|
||||
import { capturePostHogEvent } from "@/lib/posthog";
|
||||
import { authenticatedActionClient } from "@/lib/utils/action-client";
|
||||
import { checkAuthorizationUpdated } from "@/lib/utils/action-client/action-client-middleware";
|
||||
import { getOrganizationIdFromEnvironmentId, getProjectIdFromEnvironmentId } from "@/lib/utils/helper";
|
||||
@@ -16,7 +15,6 @@ import { getOrganizationBilling } from "@/modules/survey/lib/survey";
|
||||
const ZCreateSurveyAction = z.object({
|
||||
environmentId: z.cuid2(),
|
||||
surveyBody: ZSurveyCreateInput,
|
||||
createdFrom: z.enum(["blank", "template"]).optional(),
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -70,15 +68,6 @@ export const createSurveyAction = authenticatedActionClient.inputSchema(ZCreateS
|
||||
ctx.auditLoggingCtx.organizationId = organizationId;
|
||||
ctx.auditLoggingCtx.surveyId = result.id;
|
||||
ctx.auditLoggingCtx.newObject = result;
|
||||
|
||||
capturePostHogEvent(ctx.user.id, "survey_created", {
|
||||
survey_id: result.id,
|
||||
survey_type: result.type,
|
||||
organization_id: organizationId,
|
||||
question_count: result.questions?.length ?? 0,
|
||||
created_from: parsedInput.createdFrom ?? "template",
|
||||
});
|
||||
|
||||
return result;
|
||||
})
|
||||
);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { ZProjectConfigChannel, ZProjectConfigIndustry } from "@formbricks/types/project";
|
||||
import { TSurveyCreateInput, TSurveyType } from "@formbricks/types/surveys/types";
|
||||
import { TTemplate, TTemplateFilter, ZTemplateRole } from "@formbricks/types/templates";
|
||||
import { customSurveyTemplate, templates } from "@/app/lib/templates";
|
||||
import { templates } from "@/app/lib/templates";
|
||||
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||
import { createSurveyAction } from "./actions";
|
||||
import { StartFromScratchTemplate } from "./components/start-from-scratch-template";
|
||||
@@ -58,11 +58,9 @@ export const TemplateList = ({
|
||||
type: surveyType,
|
||||
createdBy: userId,
|
||||
};
|
||||
const isBlank = activeTemplate.name === customSurveyTemplate(t).name;
|
||||
const createSurveyResponse = await createSurveyAction({
|
||||
environmentId: environmentId,
|
||||
surveyBody: augmentedTemplate,
|
||||
createdFrom: isBlank ? "blank" : "template",
|
||||
});
|
||||
|
||||
if (createSurveyResponse?.data) {
|
||||
|
||||
@@ -6,7 +6,6 @@ import { ZActionClassInput } from "@formbricks/types/action-classes";
|
||||
import { OperationNotAllowedError, ResourceNotFoundError } from "@formbricks/types/errors";
|
||||
import { TSurvey, ZSurvey } from "@formbricks/types/surveys/types";
|
||||
import { UNSPLASH_ACCESS_KEY, UNSPLASH_ALLOWED_DOMAINS } from "@/lib/constants";
|
||||
import { capturePostHogEvent } from "@/lib/posthog";
|
||||
import { actionClient, authenticatedActionClient } from "@/lib/utils/action-client";
|
||||
import { checkAuthorizationUpdated } from "@/lib/utils/action-client/action-client-middleware";
|
||||
import {
|
||||
@@ -146,17 +145,6 @@ export const updateSurveyAction = authenticatedActionClient.inputSchema(ZSurvey)
|
||||
ctx.auditLoggingCtx.oldObject = oldObject;
|
||||
ctx.auditLoggingCtx.newObject = result;
|
||||
|
||||
if (oldObject?.status !== "inProgress" && result.status === "inProgress") {
|
||||
capturePostHogEvent(ctx.user.id, "survey_published", {
|
||||
survey_id: result.id,
|
||||
survey_type: result.type,
|
||||
question_count: result.questions?.length ?? 0,
|
||||
organization_id: organizationId,
|
||||
has_targeting: result.segment ? !result.segment.isPrivate : false,
|
||||
language_count: result.languages?.length ?? 0,
|
||||
});
|
||||
}
|
||||
|
||||
revalidatePath(`/environments/${result.environmentId}/surveys/${result.id}`);
|
||||
|
||||
return result;
|
||||
|
||||
@@ -33,7 +33,6 @@ const nextConfig = {
|
||||
"pino",
|
||||
"pino-pretty",
|
||||
"pino-opentelemetry-transport",
|
||||
"posthog-node",
|
||||
],
|
||||
outputFileTracingIncludes: {
|
||||
"/api/auth/**/*": ["../../node_modules/jose/**/*"],
|
||||
|
||||
@@ -104,7 +104,6 @@
|
||||
"otplib": "12.0.1",
|
||||
"papaparse": "5.5.3",
|
||||
"posthog-js": "1.360.0",
|
||||
"posthog-node": "5.28.9",
|
||||
"prismjs": "1.30.0",
|
||||
"qr-code-styling": "1.9.2",
|
||||
"qrcode": "1.5.4",
|
||||
|
||||
5
packages/cache/src/cache-keys.ts
vendored
5
packages/cache/src/cache-keys.ts
vendored
@@ -35,11 +35,6 @@ export const createCacheKey = {
|
||||
fetch_lock: (organizationId: string): CacheKey => makeCacheKey("license", organizationId, "fetch_lock"),
|
||||
},
|
||||
|
||||
// Response-related keys
|
||||
response: {
|
||||
countBySurveyId: (surveyId: string): CacheKey => makeCacheKey("response", surveyId, "count"),
|
||||
},
|
||||
|
||||
// Rate limiting and security
|
||||
rateLimit: {
|
||||
core: (namespace: string, identifier: string, windowStart: number): CacheKey =>
|
||||
|
||||
25
pnpm-lock.yaml
generated
25
pnpm-lock.yaml
generated
@@ -369,9 +369,6 @@ importers:
|
||||
posthog-js:
|
||||
specifier: 1.360.0
|
||||
version: 1.360.0
|
||||
posthog-node:
|
||||
specifier: 5.28.9
|
||||
version: 5.28.9(rxjs@7.8.2)
|
||||
prismjs:
|
||||
specifier: 1.30.0
|
||||
version: 1.30.0
|
||||
@@ -3315,9 +3312,6 @@ packages:
|
||||
'@posthog/core@1.23.2':
|
||||
resolution: {integrity: sha512-zTDdda9NuSHrnwSOfFMxX/pyXiycF4jtU1kTr8DL61dHhV+7LF6XF1ndRZZTuaGGbfbb/GJYkEsjEX9SXfNZeQ==}
|
||||
|
||||
'@posthog/core@1.24.4':
|
||||
resolution: {integrity: sha512-S+TolwBHSSJz7WWtgaELQWQqXviSm3uf1e+qorWUts0bZcgPwWzhnmhCUZAhvn0NVpTQHDJ3epv+hHbPLl5dHg==}
|
||||
|
||||
'@posthog/types@1.360.0':
|
||||
resolution: {integrity: sha512-roypbiJ49V3jWlV/lzhXGf0cKLLRj69L4H4ZHW6YsITHlnjQ12cgdPhPS88Bb9nW9xZTVSGWWDjfNGsdgAxsNg==}
|
||||
|
||||
@@ -9121,15 +9115,6 @@ packages:
|
||||
posthog-js@1.360.0:
|
||||
resolution: {integrity: sha512-jkyO+T97yi6RuiexOaXC7AnEGiC+yIfGU5DIUzI5rqBH6MltmtJw/ve2Oxc4jeua2WDr5sXMzo+SS+acbpueAA==}
|
||||
|
||||
posthog-node@5.28.9:
|
||||
resolution: {integrity: sha512-iZWyAYkIAq5QqcYz4q2nXOX+Ivn04Yh8AuKqfFVw0SvBpfli49bNAjyE97qbRTLr+irrzRUELgGIkDC14NgugA==}
|
||||
engines: {node: ^20.20.0 || >=22.22.0}
|
||||
peerDependencies:
|
||||
rxjs: ^7.0.0
|
||||
peerDependenciesMeta:
|
||||
rxjs:
|
||||
optional: true
|
||||
|
||||
powershell-utils@0.1.0:
|
||||
resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==}
|
||||
engines: {node: '>=20'}
|
||||
@@ -14489,10 +14474,6 @@ snapshots:
|
||||
dependencies:
|
||||
cross-spawn: 7.0.6
|
||||
|
||||
'@posthog/core@1.24.4':
|
||||
dependencies:
|
||||
cross-spawn: 7.0.6
|
||||
|
||||
'@posthog/types@1.360.0': {}
|
||||
|
||||
'@preact/preset-vite@2.10.3(@babel/core@7.29.0)(preact@10.29.0)(rollup@4.59.0)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))':
|
||||
@@ -21022,12 +21003,6 @@ snapshots:
|
||||
query-selector-shadow-dom: 1.0.1
|
||||
web-vitals: 5.1.0
|
||||
|
||||
posthog-node@5.28.9(rxjs@7.8.2):
|
||||
dependencies:
|
||||
'@posthog/core': 1.24.4
|
||||
optionalDependencies:
|
||||
rxjs: 7.8.2
|
||||
|
||||
powershell-utils@0.1.0: {}
|
||||
|
||||
preact-render-to-string@5.2.6(preact@10.28.2):
|
||||
|
||||
Reference in New Issue
Block a user