diff --git a/packages/emails/billing-email-service.ts b/packages/emails/billing-email-service.ts index f6f76f9c34..49dbc29d06 100644 --- a/packages/emails/billing-email-service.ts +++ b/packages/emails/billing-email-service.ts @@ -25,21 +25,13 @@ const eventTypeDisableAttendeeEmail = (metadata?: EventTypeMetadata) => { return !!metadata?.disableStandardEmails?.all?.attendee; }; -export const sendOrganizerPaymentRefundFailedEmail = async ( - calEvent: CalendarEvent -) => { +export const sendOrganizerPaymentRefundFailedEmail = async (calEvent: CalendarEvent) => { const emailsToSend: Promise[] = []; - emailsToSend.push( - sendEmail(() => new OrganizerPaymentRefundFailedEmail({ calEvent })) - ); + emailsToSend.push(sendEmail(() => new OrganizerPaymentRefundFailedEmail({ calEvent }))); if (calEvent.team?.members) { for (const teamMember of calEvent.team.members) { - emailsToSend.push( - sendEmail( - () => new OrganizerPaymentRefundFailedEmail({ calEvent, teamMember }) - ) - ); + emailsToSend.push(sendEmail(() => new OrganizerPaymentRefundFailedEmail({ calEvent, teamMember }))); } } @@ -99,9 +91,7 @@ export const sendCreditBalanceLowWarningEmails = async (input: { } if (user) { - await sendEmail( - () => new CreditBalanceLowWarningEmail({ user, balance, creditFor }) - ); + await sendEmail(() => new CreditBalanceLowWarningEmail({ user, balance, creditFor })); } }; @@ -135,19 +125,14 @@ export const sendCreditBalanceLimitReachedEmails = async ({ for (const admin of team.adminAndOwners) { emailsToSend.push( - sendEmail( - () => - new CreditBalanceLimitReachedEmail({ user: admin, team, creditFor }) - ) + sendEmail(() => new CreditBalanceLimitReachedEmail({ user: admin, team, creditFor })) ); } await Promise.all(emailsToSend); } if (user) { - await sendEmail( - () => new CreditBalanceLimitReachedEmail({ user, creditFor }) - ); + await sendEmail(() => new CreditBalanceLimitReachedEmail({ user, creditFor })); } }; diff --git a/packages/emails/email-manager.test.ts b/packages/emails/email-manager.test.ts index b5b6e4255a..ef5bd37d6d 100644 --- a/packages/emails/email-manager.test.ts +++ b/packages/emails/email-manager.test.ts @@ -9,9 +9,11 @@ import AttendeeScheduledEmail from "./templates/attendee-scheduled-email"; const mockGetEmailSettings = vi.fn(); vi.mock("@calcom/features/organizations/repositories/OrganizationSettingsRepository", () => ({ - OrganizationSettingsRepository: vi.fn().mockImplementation(function() { return { - getEmailSettings: mockGetEmailSettings, - }; }), + OrganizationSettingsRepository: vi.fn().mockImplementation(function () { + return { + getEmailSettings: mockGetEmailSettings, + }; + }), })); vi.mock("@calcom/prisma", () => ({ @@ -184,7 +186,6 @@ describe("shouldSkipAttendeeEmailWithSettings", () => { }); describe("AttendeeScheduledEmail - Privacy fix for seated events", () => { - const createMockPerson = (name: string, email: string): Person => ({ name, email, diff --git a/packages/emails/oauth-email-service.ts b/packages/emails/oauth-email-service.ts index ef94c2ce34..51cff62dbe 100644 --- a/packages/emails/oauth-email-service.ts +++ b/packages/emails/oauth-email-service.ts @@ -15,7 +15,10 @@ const sendEmail = async (prepare: () => BaseEmail) => { return await email.sendEmail(); } catch (e) { const errorName = e instanceof Error ? e.name : "UnknownError"; - console.error(`${email?.constructor?.name ?? "Email"}.sendEmail oauth-email-service failed (${errorName})`, e); + console.error( + `${email?.constructor?.name ?? "Email"}.sendEmail oauth-email-service failed (${errorName})`, + e + ); throw e; } }; diff --git a/packages/emails/src/templates/BaseScheduledEmail.tsx b/packages/emails/src/templates/BaseScheduledEmail.tsx index 306481e4a1..691f6ef8c0 100644 --- a/packages/emails/src/templates/BaseScheduledEmail.tsx +++ b/packages/emails/src/templates/BaseScheduledEmail.tsx @@ -72,8 +72,8 @@ export const BaseScheduledEmail = ( props.title ? props.title : props.calEvent.recurringEvent?.count - ? "your_event_has_been_scheduled_recurring" - : "your_event_has_been_scheduled" + ? "your_event_has_been_scheduled_recurring" + : "your_event_has_been_scheduled" )} callToAction={ props.callToAction === null diff --git a/packages/emails/src/templates/CreditBalanceLimitReachedEmail.tsx b/packages/emails/src/templates/CreditBalanceLimitReachedEmail.tsx index 6b68131ee6..47f851706c 100644 --- a/packages/emails/src/templates/CreditBalanceLimitReachedEmail.tsx +++ b/packages/emails/src/templates/CreditBalanceLimitReachedEmail.tsx @@ -26,15 +26,25 @@ export const CreditBalanceLimitReachedEmail = ( if (team) { return ( - +

<> {user.t("hi_user_name", { name: user.name, interpolation: { escapeValue: false } })},

<> {isCalAi - ? user.t("cal_ai_credit_limit_reached_message", { teamName: team.name, interpolation: { escapeValue: false } }) - : user.t("credit_limit_reached_message", { teamName: team.name, interpolation: { escapeValue: false } })} + ? user.t("cal_ai_credit_limit_reached_message", { + teamName: team.name, + interpolation: { escapeValue: false }, + }) + : user.t("credit_limit_reached_message", { + teamName: team.name, + interpolation: { escapeValue: false }, + })}

diff --git a/packages/emails/src/templates/CreditBalanceLowWarningEmail.tsx b/packages/emails/src/templates/CreditBalanceLowWarningEmail.tsx index 0dca552772..807c87e0ab 100644 --- a/packages/emails/src/templates/CreditBalanceLowWarningEmail.tsx +++ b/packages/emails/src/templates/CreditBalanceLowWarningEmail.tsx @@ -27,15 +27,25 @@ export const CreditBalanceLowWarningEmail = ( if (team) { return ( - +

<> {user.t("hi_user_name", { name: user.name, interpolation: { escapeValue: false } })},

<> {isCalAi - ? user.t("cal_ai_low_credits_warning_message", { teamName: team.name, interpolation: { escapeValue: false } }) - : user.t("low_credits_warning_message", { teamName: team.name, interpolation: { escapeValue: false } })} + ? user.t("cal_ai_low_credits_warning_message", { + teamName: team.name, + interpolation: { escapeValue: false }, + }) + : user.t("low_credits_warning_message", { + teamName: team.name, + interpolation: { escapeValue: false }, + })}

{language("oauth_client_approved_email_title", { clientName })}

-

- {language("hi_user", { name: userName || language("there") })}! -

+

{language("hi_user", { name: userName || language("there") })}!

{language("oauth_client_approved_email_body")}

{props.attendeeCancelled - ? t("attendee_no_longer_attending_subtitle", { name: props.attendee.name, interpolation: { escapeValue: false } }) + ? t("attendee_no_longer_attending_subtitle", { + name: props.attendee.name, + interpolation: { escapeValue: false }, + }) : ""} ) diff --git a/packages/emails/src/templates/TeamInviteEmail.tsx b/packages/emails/src/templates/TeamInviteEmail.tsx index f3a560aa02..51aa9d407b 100644 --- a/packages/emails/src/templates/TeamInviteEmail.tsx +++ b/packages/emails/src/templates/TeamInviteEmail.tsx @@ -136,7 +136,7 @@ export const TeamInviteEmail = ( parentTeamName: props.parentTeamName, prevLink: props.prevLink, newLink: props.newLink, - orgName: props.parentTeamName ?? props.isOrg ? props.teamName : "", + orgName: (props.parentTeamName ?? props.isOrg) ? props.teamName : "", prevLinkWithoutProtocol: props.prevLink?.replace(/https?:\/\//, ""), newLinkWithoutProtocol: props.newLink?.replace(/https?:\/\//, ""), }; diff --git a/packages/emails/templates/attendee-was-requested-to-reschedule-email.ts b/packages/emails/templates/attendee-was-requested-to-reschedule-email.ts index 33337ff810..f0f6384a4b 100644 --- a/packages/emails/templates/attendee-was-requested-to-reschedule-email.ts +++ b/packages/emails/templates/attendee-was-requested-to-reschedule-email.ts @@ -45,10 +45,10 @@ export default class AttendeeWasRequestedToRescheduleEmail extends OrganizerSche

${this.t("when")}

${this.t(this.getOrganizerStart("dddd").toLowerCase())}, ${this.t( - this.getOrganizerStart("MMMM").toLowerCase() - )} ${this.getOrganizerStart("D")}, ${this.getOrganizerStart("YYYY")} | ${this.getOrganizerStart( - "h:mma" - )} - ${this.getOrganizerEnd("h:mma")} (${this.getTimezone()}) + this.getOrganizerStart("MMMM").toLowerCase() + )} ${this.getOrganizerStart("D")}, ${this.getOrganizerStart("YYYY")} | ${this.getOrganizerStart( + "h:mma" + )} - ${this.getOrganizerEnd("h:mma")} (${this.getTimezone()})

`; } diff --git a/packages/emails/templates/disabled-app-email.ts b/packages/emails/templates/disabled-app-email.ts index 1df6a6fde2..c015a9c462 100644 --- a/packages/emails/templates/disabled-app-email.ts +++ b/packages/emails/templates/disabled-app-email.ts @@ -53,7 +53,7 @@ export default class DisabledAppEmail extends BaseEmail { return this.appType.some((type) => type === "payment") ? this.t("disable_payment_app", { appName: this.appName, title: this.title }) : this.appType.some((type) => type === "video") - ? this.t("app_disabled_video", { appName: this.appName }) - : this.t("app_disabled", { appName: this.appName }); + ? this.t("app_disabled_video", { appName: this.appName }) + : this.t("app_disabled", { appName: this.appName }); } } diff --git a/packages/emails/templates/organizer-scheduled-email.ts b/packages/emails/templates/organizer-scheduled-email.ts index 8a67638c7e..f9aacfa215 100644 --- a/packages/emails/templates/organizer-scheduled-email.ts +++ b/packages/emails/templates/organizer-scheduled-email.ts @@ -94,8 +94,8 @@ ${this.t( title ? title : this.calEvent.recurringEvent?.count - ? "new_event_scheduled_recurring" - : "new_event_scheduled" + ? "new_event_scheduled_recurring" + : "new_event_scheduled" )} ${this.t(subtitle)} ${extraInfo} diff --git a/packages/lib/CalEventParser.ts b/packages/lib/CalEventParser.ts index e3564ae936..dce0ea2d5e 100644 --- a/packages/lib/CalEventParser.ts +++ b/packages/lib/CalEventParser.ts @@ -467,7 +467,7 @@ type RichDescriptionCalEvent = { additionalInformation?: AdditionalInformation; location?: string | null; uid?: string | null; -} +}; export const getRichDescriptionHTML = ( calEvent: RichDescriptionCalEvent, @@ -649,5 +649,5 @@ export const getVideoCallUrlFromCalEvent = (calEvent: { }; export const getVideoCallPassword = (videoCallData?: VideoCallData): string => { - return isDailyVideoCall(videoCallData) ? "" : videoCallData?.password ?? ""; + return isDailyVideoCall(videoCallData) ? "" : (videoCallData?.password ?? ""); }; diff --git a/packages/lib/CalendarService.ts b/packages/lib/CalendarService.ts index b36253d201..1dbd875235 100644 --- a/packages/lib/CalendarService.ts +++ b/packages/lib/CalendarService.ts @@ -243,8 +243,8 @@ export default abstract class BaseCalendarService implements Calendar { throw new Error(`Error creating iCalString:=> ${error?.message} : ${error?.name} `); const mainHostDestinationCalendar = event.destinationCalendar - ? event.destinationCalendar.find((cal) => cal.credentialId === credentialId) ?? - event.destinationCalendar[0] + ? (event.destinationCalendar.find((cal) => cal.credentialId === credentialId) ?? + event.destinationCalendar[0]) : undefined; // We create the event directly on iCal diff --git a/packages/lib/OgImages.test.ts b/packages/lib/OgImages.test.ts index 677504d9c0..e68d901435 100644 --- a/packages/lib/OgImages.test.ts +++ b/packages/lib/OgImages.test.ts @@ -1,6 +1,11 @@ import { describe, expect, it } from "vitest"; -import { getOGImageVersion, constructMeetingImage, constructAppImage, constructGenericImage } from "./OgImages"; +import { + getOGImageVersion, + constructMeetingImage, + constructAppImage, + constructGenericImage, +} from "./OgImages"; describe("OgImages", () => { describe("getOGImageVersion", () => { diff --git a/packages/lib/OgImages.tsx b/packages/lib/OgImages.tsx index 137419995d..6491dc409b 100644 --- a/packages/lib/OgImages.tsx +++ b/packages/lib/OgImages.tsx @@ -47,8 +47,7 @@ const joinMultipleNames = (names: string[] = []) => { return `${names.length > 0 ? `${names.join(", ")} & ${lastName}` : lastName}`; }; -const makeAbsoluteUrl = (url: string) => - /^https?:\/\//.test(url) ? url : `${CAL_URL}${url}`; +const makeAbsoluteUrl = (url: string) => (/^https?:\/\//.test(url) ? url : `${CAL_URL}${url}`); const OG_ASSETS = { meeting: { @@ -82,20 +81,12 @@ export const getOGImageVersion = async ( ...(additionalInputs ?? {}), }; - const content = JSON.stringify( - versionInputs, - Object.keys(versionInputs).sort() - ); + const content = JSON.stringify(versionInputs, Object.keys(versionInputs).sort()); // Use Web Crypto API instead of Node.js crypto for Edge Runtime compatibility (`/api/social/og/image` is an Edge Runtime route) - const hashBuffer = await crypto.subtle.digest( - "SHA-256", - new TextEncoder().encode(content) - ); + const hashBuffer = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(content)); const hashArray = Array.from(new Uint8Array(hashBuffer)); - const hashHex = hashArray - .map((b) => b.toString(16).padStart(2, "0")) - .join(""); + const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join(""); return hashHex.substring(0, 8); }; @@ -156,10 +147,7 @@ export const constructAppImage = async ({ return encodeURIComponent(`/api/social/og/image?${params.toString()}`); }; -export const constructGenericImage = async ({ - title, - description, -}: GenericImageProps): Promise => { +export const constructGenericImage = async ({ title, description }: GenericImageProps): Promise => { const params = new URLSearchParams({ type: "generic", title, @@ -171,11 +159,7 @@ export const constructGenericImage = async ({ return encodeURIComponent(`/api/social/og/image?${params.toString()}`); }; -const Wrapper = ({ - children, - variant = "light", - rotateBackground, -}: WrapperProps) => ( +const Wrapper = ({ children, variant = "light", rotateBackground }: WrapperProps) => (
-
- {children} -
+
{children}
); @@ -204,8 +186,7 @@ export const Meeting = ({ title, users = [], profile }: MeetingImageProps) => { // any non existing images for dynamic collectives, while at the same time removing them from // the names list, because the profile name of that event is a concatenation of all names. const attendees = (profile.image ? [profile, ...users] : users).filter( - (value, index, self) => - self.findIndex((v) => v.name === value.name) === index + (value, index, self) => self.findIndex((v) => v.name === value.name) === index ); // Construct list of avatar urls, removes duplicates and empty profile images @@ -218,26 +199,15 @@ export const Meeting = ({ title, users = [], profile }: MeetingImageProps) => { // In case there is NO other attendee than the single meeting profile without an image, we add // that name back in here, since the event probably is a round robin event. - const names = - attendees.length > 0 ? attendees.map((user) => user.name) : [profile.name]; + const names = attendees.length > 0 ? attendees.map((user) => user.name) : [profile.name]; return (
-
- Logo +
+ Logo {avatars.length > 0 && ( -
+
/
)} @@ -254,27 +224,20 @@ export const Meeting = ({ title, users = [], profile }: MeetingImageProps) => { ))} {avatars.length > 3 && (
- - +{avatars.length - 3} - + tw={`flex items-center justify-center w-[${config.avatarSize}px] h-[${config.avatarSize}px] rounded-full bg-black text-inverted text-[54px] font-bold`}> + +{avatars.length - 3}
)}
-
+
+ }}> Meet {joinMultipleNames(names)}
{ whiteSpace: "nowrap", fontFamily: "inter", textOverflow: "ellipsis", - }} - > + }}> {title}
@@ -355,10 +317,7 @@ export const App = ({ name, description, logoUrl }: AppImageProps) => {
-
+
{name}
@@ -380,21 +339,11 @@ export const Generic = ({ title, description }: GenericImageProps) => { return (
-
- Logo +
+ Logo
-
+
{title}
diff --git a/packages/lib/apps/getAppOnboardingUrl.ts b/packages/lib/apps/getAppOnboardingUrl.ts index c58496cb26..49014ad5fd 100644 --- a/packages/lib/apps/getAppOnboardingUrl.ts +++ b/packages/lib/apps/getAppOnboardingUrl.ts @@ -1,4 +1,4 @@ -import type { AppOnboardingSteps } from "@calcom/lib/apps/appOnboardingSteps" +import type { AppOnboardingSteps } from "@calcom/lib/apps/appOnboardingSteps"; // biome-ignore lint/style/useNodejsImportProtocol: Vite env import { stringify } from "querystring"; diff --git a/packages/lib/apps/getInstallCountPerApp.ts b/packages/lib/apps/getInstallCountPerApp.ts index 482313e7ab..ed95234875 100644 --- a/packages/lib/apps/getInstallCountPerApp.ts +++ b/packages/lib/apps/getInstallCountPerApp.ts @@ -19,10 +19,13 @@ const computeInstallCountsFromDB = async (): Promise> => "installCount" DESC ` ); - return mostPopularApps.reduce((acc, { appId, installCount }) => { - acc[appId] = installCount; - return acc; - }, {} as Record); + return mostPopularApps.reduce( + (acc, { appId, installCount }) => { + acc[appId] = installCount; + return acc; + }, + {} as Record + ); }; const getInstallCountPerApp = async (): Promise> => { diff --git a/packages/lib/availability.ts b/packages/lib/availability.ts index 78254b1e3b..84aff7e85a 100644 --- a/packages/lib/availability.ts +++ b/packages/lib/availability.ts @@ -28,7 +28,7 @@ export function getAvailabilityFromSchedule(schedule: Schedule): Availability[] days: [day], startTime: time.start, endTime: time.end, - } as Availability); + }) as Availability; const filteredTimes = times.filter((time) => { let idx: number; diff --git a/packages/lib/buildCalEventFromBooking.ts b/packages/lib/buildCalEventFromBooking.ts index 34c2d82eb4..eaad3386b0 100644 --- a/packages/lib/buildCalEventFromBooking.ts +++ b/packages/lib/buildCalEventFromBooking.ts @@ -109,8 +109,8 @@ export const buildCalEventFromBooking = async ({ destinationCalendar: booking.destinationCalendar ? [booking.destinationCalendar] : booking.user?.destinationCalendar - ? [booking.user?.destinationCalendar] - : [], + ? [booking.user?.destinationCalendar] + : [], seatsPerTimeSlot: booking.eventType?.seatsPerTimeSlot, seatsShowAttendees: booking.eventType?.seatsShowAttendees, customReplyToEmail: booking.eventType?.customReplyToEmail, diff --git a/packages/lib/constants.ts b/packages/lib/constants.ts index 8c67cfa020..84856a4bfe 100644 --- a/packages/lib/constants.ts +++ b/packages/lib/constants.ts @@ -9,23 +9,14 @@ function ensureProtocol(url: string | undefined): string { return `https://${url}`; } -const VERCEL_URL = process.env.NEXT_PUBLIC_VERCEL_URL - ? `https://${process.env.NEXT_PUBLIC_VERCEL_URL}` - : ""; -const RAILWAY_STATIC_URL = process.env.RAILWAY_STATIC_URL - ? `https://${process.env.RAILWAY_STATIC_URL}` - : ""; -const HEROKU_URL = process.env.HEROKU_APP_NAME - ? `https://${process.env.HEROKU_APP_NAME}.herokuapp.com` - : ""; -const RENDER_URL = process.env.RENDER_EXTERNAL_URL - ? `https://${process.env.RENDER_EXTERNAL_URL}` - : ""; +const VERCEL_URL = process.env.NEXT_PUBLIC_VERCEL_URL ? `https://${process.env.NEXT_PUBLIC_VERCEL_URL}` : ""; +const RAILWAY_STATIC_URL = process.env.RAILWAY_STATIC_URL ? `https://${process.env.RAILWAY_STATIC_URL}` : ""; +const HEROKU_URL = process.env.HEROKU_APP_NAME ? `https://${process.env.HEROKU_APP_NAME}.herokuapp.com` : ""; +const RENDER_URL = process.env.RENDER_EXTERNAL_URL ? `https://${process.env.RENDER_EXTERNAL_URL}` : ""; export const CALCOM_ENV = process.env.CALCOM_ENV || process.env.NODE_ENV; export const IS_PRODUCTION = CALCOM_ENV === "production"; export const IS_PRODUCTION_BUILD = process.env.NODE_ENV === "production"; -export const ORGANIZER_EMAIL_EXEMPT_DOMAINS = - process.env.ORGANIZER_EMAIL_EXEMPT_DOMAINS || ""; +export const ORGANIZER_EMAIL_EXEMPT_DOMAINS = process.env.ORGANIZER_EMAIL_EXEMPT_DOMAINS || ""; const IS_DEV = CALCOM_ENV === "development"; export const SINGLE_ORG_SLUG = process.env.NEXT_PUBLIC_SINGLE_ORG_SLUG; /** https://app.cal.com */ @@ -39,21 +30,16 @@ export const WEBAPP_URL = // OAuth needs to have HTTPS(which is not generally setup locally) and a valid tld(*.local isn't a valid tld) // So for development purpose, we would stick to localhost only -export const WEBAPP_URL_FOR_OAUTH = - IS_PRODUCTION || IS_DEV ? WEBAPP_URL : "http://localhost:3000"; +export const WEBAPP_URL_FOR_OAUTH = IS_PRODUCTION || IS_DEV ? WEBAPP_URL : "http://localhost:3000"; /** @deprecated use `WEBAPP_URL` */ export const BASE_URL = WEBAPP_URL; -export const WEBSITE_URL = - ensureProtocol(process.env.NEXT_PUBLIC_WEBSITE_URL) || "https://cal.com"; +export const WEBSITE_URL = ensureProtocol(process.env.NEXT_PUBLIC_WEBSITE_URL) || "https://cal.com"; export const APP_NAME = process.env.NEXT_PUBLIC_APP_NAME || "Cal.com"; -export const SUPPORT_MAIL_ADDRESS = - process.env.NEXT_PUBLIC_SUPPORT_MAIL_ADDRESS || "help@cal.com"; -export const COMPANY_NAME = - process.env.NEXT_PUBLIC_COMPANY_NAME || "Cal.com, Inc."; +export const SUPPORT_MAIL_ADDRESS = process.env.NEXT_PUBLIC_SUPPORT_MAIL_ADDRESS || "help@cal.com"; +export const COMPANY_NAME = process.env.NEXT_PUBLIC_COMPANY_NAME || "Cal.com, Inc."; export const SENDER_ID = process.env.NEXT_PUBLIC_SENDER_ID || "Cal"; -export const SENDER_NAME = - process.env.NEXT_PUBLIC_SENDGRID_SENDER_NAME || "Cal.com"; +export const SENDER_NAME = process.env.NEXT_PUBLIC_SENDGRID_SENDER_NAME || "Cal.com"; export const EMAIL_FROM_NAME = process.env.EMAIL_FROM_NAME || APP_NAME; // This is the URL from which all Cal Links and their assets are served. @@ -82,11 +68,8 @@ export const CONSOLE_URL = : `https://console.cal.com`; const CAL_DOMAINS = [".cal.com", ".cal.dev", ".cal.eu", ".cal.qa"]; const WEBAPP_HOSTNAME = new URL(WEBAPP_URL).hostname; -export const IS_SELF_HOSTED = !CAL_DOMAINS.some((domain) => - WEBAPP_HOSTNAME.endsWith(domain) -); -export const EMBED_LIB_URL = - process.env.NEXT_PUBLIC_EMBED_LIB_URL || `${WEBAPP_URL}/embed/embed.js`; +export const IS_SELF_HOSTED = !CAL_DOMAINS.some((domain) => WEBAPP_HOSTNAME.endsWith(domain)); +export const EMBED_LIB_URL = process.env.NEXT_PUBLIC_EMBED_LIB_URL || `${WEBAPP_URL}/embed/embed.js`; export const TRIAL_LIMIT_DAYS = 14; export const MAX_SEATS_PER_TIME_SLOT = 1000; @@ -96,26 +79,16 @@ export const MAX_EVENT_DURATION_MINUTES = 1440; /** Minimum duration allowed for an event in minutes */ export const MIN_EVENT_DURATION_MINUTES = 1; -export const HOSTED_CAL_FEATURES = - process.env.NEXT_PUBLIC_HOSTED_CAL_FEATURES || !IS_SELF_HOSTED; +export const HOSTED_CAL_FEATURES = process.env.NEXT_PUBLIC_HOSTED_CAL_FEATURES || !IS_SELF_HOSTED; export const PUBLIC_QUERY_RESERVATION_INTERVAL_SECONDS = - parseInt( - process.env.NEXT_PUBLIC_QUERY_RESERVATION_INTERVAL_SECONDS ?? "", - 10 - ) || 30; + parseInt(process.env.NEXT_PUBLIC_QUERY_RESERVATION_INTERVAL_SECONDS ?? "", 10) || 30; // Must be lower than PUBLIC_QUERY_RESERVATION_INTERVAL_SECONDS export const PUBLIC_QUERY_RESERVATION_STALE_TIME_SECONDS = - parseInt( - process.env.NEXT_PUBLIC_QUERY_RESERVATION_STALE_TIME_SECONDS ?? "", - 10 - ) || 20; + parseInt(process.env.NEXT_PUBLIC_QUERY_RESERVATION_STALE_TIME_SECONDS ?? "", 10) || 20; export const PUBLIC_QUERY_AVAILABLE_SLOTS_INTERVAL_SECONDS = - parseInt( - process.env.NEXT_PUBLIC_QUERY_AVAILABLE_SLOTS_INTERVAL_SECONDS ?? "", - 10 - ) || 5 * 60; + parseInt(process.env.NEXT_PUBLIC_QUERY_AVAILABLE_SLOTS_INTERVAL_SECONDS ?? "", 10) || 5 * 60; export const PUBLIC_INVALIDATE_AVAILABLE_SLOTS_ON_BOOKING_FORM = process.env.NEXT_PUBLIC_INVALIDATE_AVAILABLE_SLOTS_ON_BOOKING_FORM === "1"; @@ -124,8 +97,7 @@ export const PUBLIC_QUICK_AVAILABILITY_ROLLOUT = parseInt(process.env.NEXT_PUBLIC_QUICK_AVAILABILITY_ROLLOUT ?? "", 10) || 0; /** @deprecated use `WEBAPP_URL` */ -export const NEXT_PUBLIC_BASE_URL = - process.env.NEXT_PUBLIC_WEBAPP_URL || `https://${process.env.VERCEL_URL}`; +export const NEXT_PUBLIC_BASE_URL = process.env.NEXT_PUBLIC_WEBAPP_URL || `https://${process.env.VERCEL_URL}`; export const LOGO = "/calcom-logo-white-word.svg"; export const LOGO_DARK = "/cal-logo-word-black.svg"; export const LOGO_ICON = "/cal-com-icon-white.svg"; @@ -163,15 +135,10 @@ export const IS_TEAM_BILLING_ENABLED_CLIENT = export const FULL_NAME_LENGTH_MAX_LIMIT = 50; export const API_NAME_LENGTH_MAX_LIMIT = 80; export const MINUTES_TO_BOOK = process.env.NEXT_PUBLIC_MINUTES_TO_BOOK || "5"; -export const ENABLE_PROFILE_SWITCHER = - process.env.NEXT_PUBLIC_ENABLE_PROFILE_SWITCHER === "1"; +export const ENABLE_PROFILE_SWITCHER = process.env.NEXT_PUBLIC_ENABLE_PROFILE_SWITCHER === "1"; // Needed for orgs -export const ALLOWED_HOSTNAMES = JSON.parse( - `[${process.env.ALLOWED_HOSTNAMES || ""}]` -) as string[]; -export const RESERVED_SUBDOMAINS = JSON.parse( - `[${process.env.RESERVED_SUBDOMAINS || ""}]` -) as string[]; +export const ALLOWED_HOSTNAMES = JSON.parse(`[${process.env.ALLOWED_HOSTNAMES || ""}]`) as string[]; +export const RESERVED_SUBDOMAINS = JSON.parse(`[${process.env.RESERVED_SUBDOMAINS || ""}]`) as string[]; export const ORGANIZATION_SELF_SERVE_PRICE = parseFloat( process.env.NEXT_PUBLIC_ORGANIZATIONS_SELF_SERVE_PRICE_NEW || "37" @@ -182,19 +149,15 @@ export const IS_MAILHOG_ENABLED = process.env.E2E_TEST_MAILHOG_ENABLED === "1"; export const CALCOM_VERSION = process.env.NEXT_PUBLIC_CALCOM_VERSION as string; export const APP_CREDENTIAL_SHARING_ENABLED = - !!process.env.CALCOM_CREDENTIAL_SYNC_SECRET && - !!process.env.CALCOM_APP_CREDENTIAL_ENCRYPTION_KEY; + !!process.env.CALCOM_CREDENTIAL_SYNC_SECRET && !!process.env.CALCOM_APP_CREDENTIAL_ENCRYPTION_KEY; export const CREDENTIAL_SYNC_SECRET = process.env.CALCOM_CREDENTIAL_SYNC_SECRET; export const CREDENTIAL_SYNC_SECRET_HEADER_NAME = - process.env.CALCOM_CREDENTIAL_SYNC_HEADER_NAME || - "calcom-credential-sync-secret"; + process.env.CALCOM_CREDENTIAL_SYNC_HEADER_NAME || "calcom-credential-sync-secret"; -export const CREDENTIAL_SYNC_ENDPOINT = - process.env.CALCOM_CREDENTIAL_SYNC_ENDPOINT; +export const CREDENTIAL_SYNC_ENDPOINT = process.env.CALCOM_CREDENTIAL_SYNC_ENDPOINT; // Service Account Encryption Key for encrypting/decrypting service account keys -export const SERVICE_ACCOUNT_ENCRYPTION_KEY = - process.env.CALCOM_SERVICE_ACCOUNT_ENCRYPTION_KEY; +export const SERVICE_ACCOUNT_ENCRYPTION_KEY = process.env.CALCOM_SERVICE_ACCOUNT_ENCRYPTION_KEY; export const DEFAULT_LIGHT_BRAND_COLOR = "#292929"; export const DEFAULT_DARK_BRAND_COLOR = "#fafafa"; @@ -210,9 +173,7 @@ export const MAX_NB_INVITES = 100; export const URL_PROTOCOL_REGEX = /(^\w+:|^)\/\//; -export const IS_VISUAL_REGRESSION_TESTING = Boolean( - globalThis.window?.Meticulous?.isRunningAsTest -); +export const IS_VISUAL_REGRESSION_TESTING = Boolean(globalThis.window?.Meticulous?.isRunningAsTest); export const BOOKER_NUMBER_OF_DAYS_TO_LOAD = parseInt( process.env.NEXT_PUBLIC_BOOKER_NUMBER_OF_DAYS_TO_LOAD ?? "0", @@ -220,20 +181,15 @@ export const BOOKER_NUMBER_OF_DAYS_TO_LOAD = parseInt( ); export const CLOUDFLARE_SITE_ID = process.env.NEXT_PUBLIC_CLOUDFLARE_SITEKEY; -export const CLOUDFLARE_USE_TURNSTILE_IN_BOOKER = - process.env.NEXT_PUBLIC_CLOUDFLARE_USE_TURNSTILE_IN_BOOKER; -export const ORG_SELF_SERVE_ENABLED = - process.env.NEXT_PUBLIC_ORG_SELF_SERVE_ENABLED === "1"; +export const CLOUDFLARE_USE_TURNSTILE_IN_BOOKER = process.env.NEXT_PUBLIC_CLOUDFLARE_USE_TURNSTILE_IN_BOOKER; +export const ORG_SELF_SERVE_ENABLED = process.env.NEXT_PUBLIC_ORG_SELF_SERVE_ENABLED === "1"; export const ORG_MINIMUM_PUBLISHED_TEAMS_SELF_SERVE = 0; export const ORG_MINIMUM_PUBLISHED_TEAMS_SELF_SERVE_HELPER_DIALOGUE = 1; -export const CALCOM_PRIVATE_API_ROUTE = - process.env.CALCOM_PRIVATE_API_ROUTE || "https://goblin.cal.com"; +export const CALCOM_PRIVATE_API_ROUTE = process.env.CALCOM_PRIVATE_API_ROUTE || "https://goblin.cal.com"; export const WEBSITE_PRIVACY_POLICY_URL = - process.env.NEXT_PUBLIC_WEBSITE_PRIVACY_POLICY_URL || - "https://cal.com/privacy"; -export const WEBSITE_TERMS_URL = - process.env.NEXT_PUBLIC_WEBSITE_TERMS_URL || "https://cal.com/terms"; + process.env.NEXT_PUBLIC_WEBSITE_PRIVACY_POLICY_URL || "https://cal.com/privacy"; +export const WEBSITE_TERMS_URL = process.env.NEXT_PUBLIC_WEBSITE_TERMS_URL || "https://cal.com/terms"; export const LINGO_DOT_DEV_API_KEY = process.env.LINGO_DOT_DEV_API_KEY; /** @@ -258,55 +214,36 @@ export const RECORDING_IN_PROGRESS_ICON = IS_PRODUCTION ? `${WEBAPP_URL}/stop-recording.svg` : `https://app.cal.com/stop-recording.svg`; -export const SCOPE_USERINFO_PROFILE = - "https://www.googleapis.com/auth/userinfo.profile"; -export const SCOPE_USERINFO_EMAIL = - "https://www.googleapis.com/auth/userinfo.email"; -export const GOOGLE_OAUTH_SCOPES = [ - SCOPE_USERINFO_PROFILE, - SCOPE_USERINFO_EMAIL, -]; +export const SCOPE_USERINFO_PROFILE = "https://www.googleapis.com/auth/userinfo.profile"; +export const SCOPE_USERINFO_EMAIL = "https://www.googleapis.com/auth/userinfo.email"; +export const GOOGLE_OAUTH_SCOPES = [SCOPE_USERINFO_PROFILE, SCOPE_USERINFO_EMAIL]; export const GOOGLE_CALENDAR_SCOPES = [ "https://www.googleapis.com/auth/calendar.events", "https://www.googleapis.com/auth/calendar.readonly", ]; -export const DIRECTORY_IDS_TO_LOG = - process.env.DIRECTORY_IDS_TO_LOG?.split(",") || []; -export const SCANNING_WORKFLOW_STEPS = !!( - !IS_SELF_HOSTED && process.env.IFFY_API_KEY -); +export const DIRECTORY_IDS_TO_LOG = process.env.DIRECTORY_IDS_TO_LOG?.split(",") || []; +export const SCANNING_WORKFLOW_STEPS = !!(!IS_SELF_HOSTED && process.env.IFFY_API_KEY); // Cloudflare URL Scanner - checks URLs for malicious content in workflows and event types export const URL_SCANNING_ENABLED = - !!process.env.CLOUDFLARE_URL_SCANNER_API_TOKEN && - !!process.env.CLOUDFLARE_ACCOUNT_ID; + !!process.env.CLOUDFLARE_URL_SCANNER_API_TOKEN && !!process.env.CLOUDFLARE_ACCOUNT_ID; export const IS_DUB_REFERRALS_ENABLED = - !!process.env.NEXT_PUBLIC_DUB_PROGRAM_ID && - process.env.NEXT_PUBLIC_DUB_PROGRAM_ID !== ""; + !!process.env.NEXT_PUBLIC_DUB_PROGRAM_ID && process.env.NEXT_PUBLIC_DUB_PROGRAM_ID !== ""; -export const CAL_VIDEO_MEETING_LINK_FOR_TESTING = - process.env.CAL_VIDEO_MEETING_LINK_FOR_TESTING; +export const CAL_VIDEO_MEETING_LINK_FOR_TESTING = process.env.CAL_VIDEO_MEETING_LINK_FOR_TESTING; export const IS_SMS_CREDITS_ENABLED = - !!process.env.NEXT_PUBLIC_STRIPE_CREDITS_PRICE_ID || - !!process.env.NEXT_PUBLIC_IS_E2E; -export const DATABASE_CHUNK_SIZE = parseInt( - process.env.DATABASE_CHUNK_SIZE || "25", - 10 -); + !!process.env.NEXT_PUBLIC_STRIPE_CREDITS_PRICE_ID || !!process.env.NEXT_PUBLIC_IS_E2E; +export const DATABASE_CHUNK_SIZE = parseInt(process.env.DATABASE_CHUNK_SIZE || "25", 10); export const NEXTJS_CACHE_TTL = 3600; // 1 hour export const DEFAULT_GROUP_ID = "default_group_id"; -const _rawCalAiPrice = - process.env.NEXT_PUBLIC_CAL_AI_PHONE_NUMBER_MONTHLY_PRICE; +const _rawCalAiPrice = process.env.NEXT_PUBLIC_CAL_AI_PHONE_NUMBER_MONTHLY_PRICE; export const CAL_AI_PHONE_NUMBER_MONTHLY_PRICE = (() => { - const parsed = - _rawCalAiPrice && _rawCalAiPrice.trim() !== "" - ? Number(_rawCalAiPrice) - : NaN; + const parsed = _rawCalAiPrice && _rawCalAiPrice.trim() !== "" ? Number(_rawCalAiPrice) : NaN; return Number.isFinite(parsed) ? parsed : 5; })(); @@ -338,6 +275,4 @@ export const ORG_TRIAL_DAYS = process.env.STRIPE_ORG_TRIAL_DAYS export const IS_API_V2_E2E = process.env.IS_E2E === "true"; export const ENABLE_ASYNC_TASKER = - process.env.ENABLE_ASYNC_TASKER === "true" && - !process.env.NEXT_PUBLIC_IS_E2E && - !IS_API_V2_E2E; + process.env.ENABLE_ASYNC_TASKER === "true" && !process.env.NEXT_PUBLIC_IS_E2E && !IS_API_V2_E2E; diff --git a/packages/lib/csvUtils.ts b/packages/lib/csvUtils.ts index a99c3daeb9..5746c433b3 100644 --- a/packages/lib/csvUtils.ts +++ b/packages/lib/csvUtils.ts @@ -29,7 +29,9 @@ export const objectsToCsv = (data: Record[]): string => { // Create CSV rows const csvRows = [ // Header row - headers.map((header) => sanitizeValue(header)).join(","), + headers + .map((header) => sanitizeValue(header)) + .join(","), // Data rows ...data.map((row) => headers diff --git a/packages/lib/domainManager/deploymentServices/vercel.ts b/packages/lib/domainManager/deploymentServices/vercel.ts index 27ff4b1311..5360b633c7 100644 --- a/packages/lib/domainManager/deploymentServices/vercel.ts +++ b/packages/lib/domainManager/deploymentServices/vercel.ts @@ -81,7 +81,7 @@ function handleDomainCreationError(error: { domain?: string | null; message?: string | null; invalidToken?: boolean | null; -}){ +}) { // Vercel returns "forbidden" for various permission issues, not just domain ownership if (error.code === "forbidden") { const errorMessage = @@ -130,7 +130,7 @@ function handleDomainDeletionError(error: { domain?: string | null; message?: string | null; invalidToken?: boolean | null; -}){ +}) { if (error.code === "not_found") { // Domain is already deleted return true; diff --git a/packages/lib/errors.ts b/packages/lib/errors.ts index 689ea4d107..29613e129b 100644 --- a/packages/lib/errors.ts +++ b/packages/lib/errors.ts @@ -26,18 +26,18 @@ export class ErrorWithCode extends Error { /** * Converts unknown error types to Error objects. - * + * * @deprecated For server-side code, use `getServerErrorFromUnknown` from `@calcom/lib/server/getServerErrorFromUnknown` instead. * This function should only be used in client-side or isomorphic code (React components, shared utilities). - * + * * Use this function when: * - You're in a React component that runs on the client * - You're in shared/isomorphic code that cannot import server-only dependencies * - You only need a basic Error object without HTTP status code mapping - * + * * For server-side error handling (API routes, tRPC handlers, webhooks), use `getServerErrorFromUnknown` * which provides proper HTTP status code mapping, error redaction, and handles Zod/Prisma/Stripe errors. - * + * * @param cause - The unknown error to convert * @returns An Error object with optional statusCode and code properties */ diff --git a/packages/lib/getBooking.tsx b/packages/lib/getBooking.tsx index 014ea210ea..d16dadb679 100644 --- a/packages/lib/getBooking.tsx +++ b/packages/lib/getBooking.tsx @@ -92,7 +92,7 @@ export const getBookingWithResponses = < select: BookingSelect & { responses: true; }; - }> + }>, >( booking: T ) => { diff --git a/packages/lib/getSafeRedirectUrl.ts b/packages/lib/getSafeRedirectUrl.ts index 67332eb921..fb58fd308d 100644 --- a/packages/lib/getSafeRedirectUrl.ts +++ b/packages/lib/getSafeRedirectUrl.ts @@ -48,4 +48,3 @@ export function isSafeUrlToLoadResourceFrom(urlString: string) { return false; } } - diff --git a/packages/lib/hashedLinksUtils.ts b/packages/lib/hashedLinksUtils.ts index 2a93780240..7aae1d3d1d 100644 --- a/packages/lib/hashedLinksUtils.ts +++ b/packages/lib/hashedLinksUtils.ts @@ -139,7 +139,7 @@ export function filterActiveLinks< expiresAt?: Date | null; maxUsageCount?: number | null; usageCount?: number | null; - } + }, >(links: T[], timezone?: string | null): T[] { return links.filter((link) => !isLinkExpired(link, timezone)); } diff --git a/packages/lib/holidays/GoogleCalendarClient.ts b/packages/lib/holidays/GoogleCalendarClient.ts index e4c6e098fa..5250c3292d 100644 --- a/packages/lib/holidays/GoogleCalendarClient.ts +++ b/packages/lib/holidays/GoogleCalendarClient.ts @@ -93,4 +93,3 @@ export function getGoogleCalendarClient(): GoogleCalendarClient { } return defaultClient; } - diff --git a/packages/lib/holidays/HolidayServiceCachingProxy.ts b/packages/lib/holidays/HolidayServiceCachingProxy.ts index 87370b7ba4..fe3dc36802 100644 --- a/packages/lib/holidays/HolidayServiceCachingProxy.ts +++ b/packages/lib/holidays/HolidayServiceCachingProxy.ts @@ -2,7 +2,11 @@ import dayjs from "@calcom/dayjs"; import { HolidayRepository } from "@calcom/features/holidays/repositories/HolidayRepository"; import { GOOGLE_HOLIDAY_CALENDARS, HOLIDAY_CACHE_DAYS } from "./constants"; -import { getGoogleCalendarClient, type GoogleCalendarClient, type GoogleCalendarHoliday } from "./GoogleCalendarClient"; +import { + getGoogleCalendarClient, + type GoogleCalendarClient, + type GoogleCalendarHoliday, +} from "./GoogleCalendarClient"; export interface CachedHoliday { id: string; @@ -67,14 +71,16 @@ export class HolidayServiceCachingProxy { const cached = await HolidayRepository.findManyCachedHolidays({ countryCode, year }); - return cached.map((h): CachedHoliday => ({ - id: h.id, - countryCode: h.countryCode, - eventId: h.eventId, - name: h.name, - date: h.date, - year: h.year, - })); + return cached.map( + (h): CachedHoliday => ({ + id: h.id, + countryCode: h.countryCode, + eventId: h.eventId, + name: h.name, + date: h.date, + year: h.year, + }) + ); } async getHolidaysInRange(countryCode: string, startDate: Date, endDate: Date): Promise { @@ -94,14 +100,16 @@ export class HolidayServiceCachingProxy { endDate, }); - return cached.map((h): CachedHoliday => ({ - id: h.id, - countryCode: h.countryCode, - eventId: h.eventId, - name: h.name, - date: h.date, - year: h.year, - })); + return cached.map( + (h): CachedHoliday => ({ + id: h.id, + countryCode: h.countryCode, + eventId: h.eventId, + name: h.name, + date: h.date, + year: h.year, + }) + ); } } @@ -113,4 +121,3 @@ export function getHolidayServiceCachingProxy(): HolidayServiceCachingProxy { } return defaultProxy; } - diff --git a/packages/lib/holidays/constants.ts b/packages/lib/holidays/constants.ts index caf12c3584..0d5c150559 100644 --- a/packages/lib/holidays/constants.ts +++ b/packages/lib/holidays/constants.ts @@ -13,7 +13,10 @@ export const GOOGLE_RELIGIOUS_HOLIDAY_CALENDARS: Record = [ { keywords: ["revolution", "revolución"], emoji: "✊" }, { keywords: ["unity", "unification", "einheit", "german unity"], emoji: "🤝" }, { keywords: ["flag day", "día de la bandera"], emoji: "🚩" }, - { keywords: ["labor", "labour", "workers", "trabajo", "travail", "may day", "tag der arbeit"], emoji: "👷" }, + { + keywords: ["labor", "labour", "workers", "trabajo", "travail", "may day", "tag der arbeit"], + emoji: "👷", + }, { keywords: ["diwali", "deepavali", "dipavali"], emoji: "🪔" }, { keywords: ["holi"], emoji: "🎨" }, { keywords: ["dussehra", "dasara", "vijayadashami"], emoji: "🏹" }, diff --git a/packages/lib/hooks/useCompatSearchParams.test.ts b/packages/lib/hooks/useCompatSearchParams.test.ts index 4839dd6a8d..b465cd7ff7 100644 --- a/packages/lib/hooks/useCompatSearchParams.test.ts +++ b/packages/lib/hooks/useCompatSearchParams.test.ts @@ -5,7 +5,9 @@ import { describe, expect, it } from "vitest"; import { useCompatSearchParams } from "./useCompatSearchParams"; vi.mock("next/navigation", () => ({ - ReadonlyURLSearchParams: vi.fn().mockImplementation(function(a) { return a; }), + ReadonlyURLSearchParams: vi.fn().mockImplementation(function (a) { + return a; + }), })); describe("useCompatSearchParams hook", () => { diff --git a/packages/lib/intervalLimits/utils/getPeriodStartDatesBetween.ts b/packages/lib/intervalLimits/utils/getPeriodStartDatesBetween.ts index 9c60a8bf89..af8844ddd9 100644 --- a/packages/lib/intervalLimits/utils/getPeriodStartDatesBetween.ts +++ b/packages/lib/intervalLimits/utils/getPeriodStartDatesBetween.ts @@ -21,4 +21,7 @@ function _getPeriodStartDatesBetween( return dates; } -export const getPeriodStartDatesBetween = withReporting(_getPeriodStartDatesBetween, "getPeriodStartDatesBetween"); +export const getPeriodStartDatesBetween = withReporting( + _getPeriodStartDatesBetween, + "getPeriodStartDatesBetween" +); diff --git a/packages/lib/logger.server.ts b/packages/lib/logger.server.ts index 4c401205f3..f457700d74 100644 --- a/packages/lib/logger.server.ts +++ b/packages/lib/logger.server.ts @@ -1,4 +1,4 @@ -import fs from "node:fs" +import fs from "node:fs"; import logger from "./logger"; diff --git a/packages/lib/raqb/utils.ts b/packages/lib/raqb/utils.ts index 6a6438871f..c9cd7e54d4 100644 --- a/packages/lib/raqb/utils.ts +++ b/packages/lib/raqb/utils.ts @@ -6,4 +6,4 @@ export function caseInsensitive( ? stringOrStringArray.map((string) => string.toLowerCase()) : stringOrStringArray.toLowerCase() ) as T extends string[] ? string[] : string; -} \ No newline at end of file +} diff --git a/packages/lib/rateLimit.ts b/packages/lib/rateLimit.ts index ebdc90460a..ed109bc0f1 100644 --- a/packages/lib/rateLimit.ts +++ b/packages/lib/rateLimit.ts @@ -38,7 +38,7 @@ export function rateLimiter() { log.warn("Disabled because the UNKEY_ROOT_KEY environment variable was not found."); warned = true; } - return () => ({ success: true, limit: 10, remaining: 999, reset: 0 } as RatelimitResponse); + return () => ({ success: true, limit: 10, remaining: 999, reset: 0 }) as RatelimitResponse; } const timeout = { fallback: { success: true, limit: 10, remaining: 999, reset: 0 }, diff --git a/packages/lib/schedules/transformers/for-atom.ts b/packages/lib/schedules/transformers/for-atom.ts index 933fedabb7..7eb99ecb94 100644 --- a/packages/lib/schedules/transformers/for-atom.ts +++ b/packages/lib/schedules/transformers/for-atom.ts @@ -30,37 +30,40 @@ export function transformDateOverridesForAtom( schedule: { availability: ScheduleOverride }, timeZone: string ) { - const acc = schedule.availability.reduce((acc, override) => { - // only if future date override - const currentUtcOffset = dayjs().tz(timeZone).utcOffset(); - const currentTimeInTz = dayjs().utc().add(currentUtcOffset, "minute"); + const acc = schedule.availability.reduce( + (acc, override) => { + // only if future date override + const currentUtcOffset = dayjs().tz(timeZone).utcOffset(); + const currentTimeInTz = dayjs().utc().add(currentUtcOffset, "minute"); - if (!override.date || dayjs(override.date).isBefore(currentTimeInTz, "day")) { + if (!override.date || dayjs(override.date).isBefore(currentTimeInTz, "day")) { + return acc; + } + const newValue = { + start: dayjs + .utc(override.date) + .hour(override.startTime.getUTCHours()) + .minute(override.startTime.getUTCMinutes()) + .toDate(), + end: dayjs + .utc(override.date) + .hour(override.endTime.getUTCHours()) + .minute(override.endTime.getUTCMinutes()) + .toDate(), + }; + const dayRangeIndex = acc.findIndex( + // early return prevents override.date from ever being empty. + (item) => override.date && yyyymmdd(item.ranges[0].start) === yyyymmdd(override.date) + ); + if (dayRangeIndex === -1) { + acc.push({ ranges: [newValue] }); + return acc; + } + acc[dayRangeIndex].ranges.push(newValue); return acc; - } - const newValue = { - start: dayjs - .utc(override.date) - .hour(override.startTime.getUTCHours()) - .minute(override.startTime.getUTCMinutes()) - .toDate(), - end: dayjs - .utc(override.date) - .hour(override.endTime.getUTCHours()) - .minute(override.endTime.getUTCMinutes()) - .toDate(), - }; - const dayRangeIndex = acc.findIndex( - // early return prevents override.date from ever being empty. - (item) => override.date && yyyymmdd(item.ranges[0].start) === yyyymmdd(override.date) - ); - if (dayRangeIndex === -1) { - acc.push({ ranges: [newValue] }); - return acc; - } - acc[dayRangeIndex].ranges.push(newValue); - return acc; - }, [] as { ranges: TimeRange[] }[]); + }, + [] as { ranges: TimeRange[] }[] + ); acc.sort((a, b) => { const aTime = a.ranges?.[0]?.start?.getTime?.() ?? 0; diff --git a/packages/lib/sentryWrapper.ts b/packages/lib/sentryWrapper.ts index 8cb3afaa32..c6d88b0512 100644 --- a/packages/lib/sentryWrapper.ts +++ b/packages/lib/sentryWrapper.ts @@ -138,9 +138,10 @@ const noOpSpan: TelemetrySpan = { * Creates a console-logging span for local development when Sentry is not configured. * Tracks attributes and logs them with duration when the span completes. */ -function createConsoleSpan( - options: TelemetrySpanOptions -): { span: TelemetrySpan; logCompletion: (durationMs: number, error?: unknown) => void } { +function createConsoleSpan(options: TelemetrySpanOptions): { + span: TelemetrySpan; + logCompletion: (durationMs: number, error?: unknown) => void; +} { const attributes: Record = { ...options.attributes }; const span: TelemetrySpan = { diff --git a/packages/lib/server/PiiHasher.test.ts b/packages/lib/server/PiiHasher.test.ts index 7e7e45d594..aa0afb508b 100644 --- a/packages/lib/server/PiiHasher.test.ts +++ b/packages/lib/server/PiiHasher.test.ts @@ -2,7 +2,6 @@ import { describe, it, expect } from "vitest"; import { hashEmail, Md5PiiHasher } from "./PiiHasher"; describe("PII Hasher Test Suite", () => { - const hasher = new Md5PiiHasher("test-salt"); it("can hash email addresses deterministically and preserve domain", async () => { diff --git a/packages/lib/server/getServerErrorFromUnknown.ts b/packages/lib/server/getServerErrorFromUnknown.ts index 723d9d5836..0ae304a86e 100644 --- a/packages/lib/server/getServerErrorFromUnknown.ts +++ b/packages/lib/server/getServerErrorFromUnknown.ts @@ -22,7 +22,10 @@ function isZodError(cause: unknown): cause is ZodError { function isPrismaError(cause: unknown): cause is Prisma.PrismaClientKnownRequestError { return ( cause instanceof Prisma.PrismaClientKnownRequestError || - (cause instanceof Error && "code" in cause && typeof cause.code === "string" && cause.code.startsWith("P")) + (cause instanceof Error && + "code" in cause && + typeof cause.code === "string" && + cause.code.startsWith("P")) ); } @@ -32,8 +35,8 @@ function parseZodErrorIssues(issues: ZodIssue[]): string { i.code === "invalid_union" ? i.unionErrors.map((ue) => parseZodErrorIssues(ue.issues)).join("; ") : i.code === "unrecognized_keys" - ? i.message - : `${i.path.length ? `${i.code} in '${i.path}': ` : ""}${i.message}` + ? i.message + : `${i.path.length ? `${i.code} in '${i.path}': ` : ""}${i.message}` ) .join("; "); } diff --git a/packages/lib/server/withSelectedCalendars.ts b/packages/lib/server/withSelectedCalendars.ts index 4410d8615e..49904ad532 100644 --- a/packages/lib/server/withSelectedCalendars.ts +++ b/packages/lib/server/withSelectedCalendars.ts @@ -13,7 +13,7 @@ export function withSelectedCalendars< }, TUser extends { selectedCalendars: TCalendar[]; - } + }, >(user: UserWithLegacySelectedCalendars): UserWithSelectedCalendars { // We are renaming selectedCalendars to allSelectedCalendars to make it clear that it contains all the calendars including eventType calendars const { selectedCalendars, ...restUser } = user; diff --git a/packages/lib/ssrfProtection.test.ts b/packages/lib/ssrfProtection.test.ts index 7af4f20346..d65dfd5c81 100644 --- a/packages/lib/ssrfProtection.test.ts +++ b/packages/lib/ssrfProtection.test.ts @@ -81,16 +81,12 @@ describe("validateUrlForSSRFSync", () => { }); it("allows /api/avatar/{uuid}.png only", () => { - expect(validateUrlForSSRFSync("/api/avatar/ba0fa3a6-2aac-4032-8230-3789f5752e5a.png").isValid).toBe( - true - ); + expect(validateUrlForSSRFSync("/api/avatar/ba0fa3a6-2aac-4032-8230-3789f5752e5a.png").isValid).toBe(true); expect(validateUrlForSSRFSync("/api/avatar/any-value.png").isValid).toBe(true); }); it("rejects /api/avatar/ path without .png extension", () => { - expect(validateUrlForSSRFSync("/api/avatar/ba0fa3a6-2aac-4032-8230-3789f5752e5a").isValid).toBe( - false - ); + expect(validateUrlForSSRFSync("/api/avatar/ba0fa3a6-2aac-4032-8230-3789f5752e5a").isValid).toBe(false); expect(validateUrlForSSRFSync("/api/avatar/foo.jpg").isValid).toBe(false); }); @@ -213,4 +209,4 @@ describe("Self-hosted environment behavior", () => { expect(validateSelfHosted("ftp://internal-server/file").isValid).toBe(false); expect(validateSelfHosted("javascript:alert(1)").isValid).toBe(false); }); -}); \ No newline at end of file +}); diff --git a/packages/lib/tasker/Tasker.ts b/packages/lib/tasker/Tasker.ts index b8cf6e082c..74f09e4a83 100644 --- a/packages/lib/tasker/Tasker.ts +++ b/packages/lib/tasker/Tasker.ts @@ -7,9 +7,7 @@ import { redactError } from "../redactError"; import type { ILogger } from "./types"; const isAsyncTaskerEnabled = - ENABLE_ASYNC_TASKER && - process.env.TRIGGER_SECRET_KEY && - process.env.TRIGGER_API_URL; + ENABLE_ASYNC_TASKER && process.env.TRIGGER_SECRET_KEY && process.env.TRIGGER_API_URL; export abstract class Tasker { protected readonly asyncTasker: T; @@ -24,10 +22,7 @@ export abstract class Tasker { this.logger = dependencies.logger; if (!isAsyncTaskerEnabled) { - if ( - ENABLE_ASYNC_TASKER && - (!process.env.TRIGGER_SECRET_KEY || !process.env.TRIGGER_API_URL) - ) { + if (ENABLE_ASYNC_TASKER && (!process.env.TRIGGER_SECRET_KEY || !process.env.TRIGGER_API_URL)) { this.logger.info( "Missing env variables TRIGGER_SECRET_KEY or TRIGGER_API_URL, falling back to Sync tasker." ); @@ -41,18 +36,14 @@ export abstract class Tasker { }); } - this.asyncTasker = isAsyncTaskerEnabled - ? dependencies.asyncTasker - : dependencies.syncTasker; + this.asyncTasker = isAsyncTaskerEnabled ? dependencies.asyncTasker : dependencies.syncTasker; this.syncTasker = dependencies.syncTasker; } public async dispatch( taskName: K, ...args: T[K] extends (...args: any[]) => any ? Parameters : never - ): Promise< - T[K] extends (...args: any[]) => any ? Awaited> : never - > { + ): Promise any ? Awaited> : never> { this.logger.info(`Safely Dispatching task '${String(taskName)}'`, { args }); return this._safeDispatch(taskName, ...args); } @@ -60,14 +51,10 @@ export abstract class Tasker { private async _safeDispatch( taskName: K, ...args: T[K] extends (...args: any[]) => any ? Parameters : never - ): Promise< - T[K] extends (...args: any[]) => any ? Awaited> : never - > { + ): Promise any ? Awaited> : never> { try { this.logger.info( - `${isAsyncTaskerEnabled ? "AsyncTasker" : "SyncTasker"} '${String( - taskName - )}' dispatched.` + `${isAsyncTaskerEnabled ? "AsyncTasker" : "SyncTasker"} '${String(taskName)}' dispatched.` ); const method = this.asyncTasker[taskName] as (...args: any[]) => any; return await method.apply(this.asyncTasker, args); @@ -85,20 +72,13 @@ export abstract class Tasker { throw err; } - this.logger.warn( - `Trying again with SyncTasker for '${String(taskName)}'.` - ); + this.logger.warn(`Trying again with SyncTasker for '${String(taskName)}'.`); try { - const fallbackMethod = this.syncTasker[taskName] as ( - ...args: any[] - ) => any; + const fallbackMethod = this.syncTasker[taskName] as (...args: any[]) => any; return await fallbackMethod.apply(this.syncTasker, args); } catch (err) { - this.logger.error( - `SyncTasker failed for '${String(taskName)}'.`, - this.getErrorDetails(err) - ); + this.logger.error(`SyncTasker failed for '${String(taskName)}'.`, this.getErrorDetails(err)); throw err; } } diff --git a/packages/lib/tracing/index.test.ts b/packages/lib/tracing/index.test.ts index 16c097622f..f84afbc10c 100644 --- a/packages/lib/tracing/index.test.ts +++ b/packages/lib/tracing/index.test.ts @@ -269,7 +269,13 @@ describe("DistributedTracing", () => { tracing.getTracingLogger(context); expect(mockLogger.getSubLogger).toHaveBeenCalledWith({ - prefix: ["distributed-trace", "trace:trace_123", "span:span_456", "op:test_operation", "userId:user_789"], + prefix: [ + "distributed-trace", + "trace:trace_123", + "span:span_456", + "op:test_operation", + "userId:user_789", + ], }); }); @@ -287,7 +293,13 @@ describe("DistributedTracing", () => { tracing.getTracingLogger(context); expect(mockLogger.getSubLogger).toHaveBeenCalledWith({ - prefix: ["distributed-trace", "trace:trace_123", "span:span_456", "op:test_operation", "userId:user_789"], + prefix: [ + "distributed-trace", + "trace:trace_123", + "span:span_456", + "op:test_operation", + "userId:user_789", + ], }); }); }); diff --git a/packages/lib/tracing/index.ts b/packages/lib/tracing/index.ts index b5431252e6..9037176fda 100644 --- a/packages/lib/tracing/index.ts +++ b/packages/lib/tracing/index.ts @@ -14,7 +14,10 @@ export interface IdGenerator { } export class DistributedTracing { - constructor(private idGenerator: IdGenerator, private loggerInstance: Logger) {} + constructor( + private idGenerator: IdGenerator, + private loggerInstance: Logger + ) {} createTrace(operation: string, context?: Partial): TraceContext { const { traceId, spanId, meta, ...otherContext } = context || {}; diff --git a/packages/lib/tracking/index.ts b/packages/lib/tracking/index.ts index b01b1fabdf..8a8f860fa5 100644 --- a/packages/lib/tracking/index.ts +++ b/packages/lib/tracking/index.ts @@ -4,4 +4,3 @@ export { type GoogleAdsTrackingData, type LinkedInAdsTrackingData, } from "./server"; - diff --git a/packages/lib/videoTokens.ts b/packages/lib/videoTokens.ts index 43ea2865b3..ad487f5613 100644 --- a/packages/lib/videoTokens.ts +++ b/packages/lib/videoTokens.ts @@ -1,12 +1,8 @@ import { createHmac } from "node:crypto"; // 262992 minutes is 6 months -export function generateVideoToken( - recordingId: string, - expiresInMinutes = 262992 -) { - const secret = - process.env.CAL_VIDEO_RECORDING_TOKEN_SECRET || "default-secret-change-me"; +export function generateVideoToken(recordingId: string, expiresInMinutes = 262992) { + const secret = process.env.CAL_VIDEO_RECORDING_TOKEN_SECRET || "default-secret-change-me"; const expires = Date.now() + expiresInMinutes * 60 * 1000; const payload = `${recordingId}:${expires}`; @@ -21,9 +17,7 @@ export function verifyVideoToken(token: string): { } { try { const [recordingId, expires, receivedHmac] = token.split(":"); - const secret = - process.env.CAL_VIDEO_RECORDING_TOKEN_SECRET || - "default-secret-change-me"; + const secret = process.env.CAL_VIDEO_RECORDING_TOKEN_SECRET || "default-secret-change-me"; if (Date.now() > parseInt(expires, 10)) { return { valid: false }; @@ -31,9 +25,7 @@ export function verifyVideoToken(token: string): { // Verify HMAC const payload = `${recordingId}:${expires}`; - const expectedHmac = createHmac("sha256", secret) - .update(payload) - .digest("hex"); + const expectedHmac = createHmac("sha256", secret).update(payload).digest("hex"); if (receivedHmac !== expectedHmac) { return { valid: false }; diff --git a/packages/lib/zod/ssrfSafeUrl.ts b/packages/lib/zod/ssrfSafeUrl.ts index 4cd45968b7..444dd21ca4 100644 --- a/packages/lib/zod/ssrfSafeUrl.ts +++ b/packages/lib/zod/ssrfSafeUrl.ts @@ -12,7 +12,6 @@ const validateSsrfUrl = (url: string | null | undefined): boolean => { return validateUrlForSSRFSync(url).isValid; }; - /** * Zod schema for validating user-provided URLs before server-side fetching * Applies synchronous SSRF checks only (no DNS resolution) diff --git a/packages/prisma/zod-utils.test.ts b/packages/prisma/zod-utils.test.ts index fd2b0383ba..455496a1ea 100644 --- a/packages/prisma/zod-utils.test.ts +++ b/packages/prisma/zod-utils.test.ts @@ -63,7 +63,6 @@ describe("excludeOrRequireEmailSchema", () => { }); describe("invalid inputs", () => { - it("rejects invalid TLD lengths", () => { expect(parse("example.c").success).toBe(false); }); diff --git a/packages/prisma/zod-utils.ts b/packages/prisma/zod-utils.ts index e817ad7f68..316f0905d6 100644 --- a/packages/prisma/zod-utils.ts +++ b/packages/prisma/zod-utils.ts @@ -357,9 +357,14 @@ export const stringOrNumber = z.union([ export const requiredCustomInputSchema = z.union([ // string must be given & nonempty - z.string().trim().min(1), + z + .string() + .trim() + .min(1), // boolean must be true if set. - z.boolean().refine((v) => v === true), + z + .boolean() + .refine((v) => v === true), ]); const PlatformClientParamsSchema = z.object({ @@ -643,7 +648,7 @@ export function denullishShape< UnknownKeys extends UnknownKeysParam = "strip", Catchall extends ZodTypeAny = ZodTypeAny, Output = objectOutputType, - Input = objectInputType + Input = objectInputType, >( obj: ZodObject ): ZodObject, UnknownKeys, Catchall> { @@ -675,13 +680,14 @@ export const entries = >( /** * Returns a type with all readonly notations removed (traverses recursively on an object) */ -type DeepWriteable = T extends Readonly<{ - -readonly [K in keyof T]: T[K]; -}> - ? { - -readonly [K in keyof T]: DeepWriteable; - } - : T; /* Make it work with readonly types (this is not strictly necessary) */ +type DeepWriteable = + T extends Readonly<{ + -readonly [K in keyof T]: T[K]; + }> + ? { + -readonly [K in keyof T]: DeepWriteable; + } + : T; /* Make it work with readonly types (this is not strictly necessary) */ type FromEntries = T extends [infer Keys, unknown][] ? { [K in Keys & PropertyKey]: Extract[1] } @@ -694,7 +700,7 @@ type FromEntries = T extends [infer Keys, unknown][] * @see https://github.com/3x071c/lsg-remix/blob/e2a9592ba3ec5103556f2cf307c32f08aeaee32d/app/lib/util/fromEntries.ts */ export const fromEntries = < - E extends [PropertyKey, unknown][] | ReadonlyArray + E extends [PropertyKey, unknown][] | ReadonlyArray, >( entries: E ): FromEntries> => { diff --git a/packages/sms/attendee/event-cancelled-sms.ts b/packages/sms/attendee/event-cancelled-sms.ts index 917eac6936..d0aa0517b6 100644 --- a/packages/sms/attendee/event-cancelled-sms.ts +++ b/packages/sms/attendee/event-cancelled-sms.ts @@ -15,7 +15,7 @@ export default class EventCancelledSMS extends SMSManager { const messageText = `${t("hey_there")} ${attendee.name}, ${t("event_request_cancelled")}\n\n${t( "event_cancelled_subject", { - title: typeof this.calEvent.title === 'string' ? this.calEvent.title : 'Untitled Event', + title: typeof this.calEvent.title === "string" ? this.calEvent.title : "Untitled Event", date: this.getFormattedDate(attendee.timeZone, attendee.language.locale), interpolation: { escapeValue: false }, } diff --git a/packages/sms/sms-manager.ts b/packages/sms/sms-manager.ts index aea61317a9..6e19c77155 100644 --- a/packages/sms/sms-manager.ts +++ b/packages/sms/sms-manager.ts @@ -33,8 +33,8 @@ const handleSendingSMS = async ({ identifier: teamId ? `handleSendingSMS:team-${teamId}` : organizerUserId - ? `handleSendingSMS:org-user-${organizerUserId}` - : `handleSendingSMS:user-${piiHasher.hash(reminderPhone)}`, + ? `handleSendingSMS:org-user-${organizerUserId}` + : `handleSendingSMS:user-${piiHasher.hash(reminderPhone)}`, rateLimitingType: "sms", });