From c2349b34668b2c76798632e4d6d1ad7738002c0f Mon Sep 17 00:00:00 2001 From: Richard Poelderl Date: Thu, 11 May 2023 17:14:24 +0200 Subject: [PATCH] refactor(lib): turn constants.ts & telemetry.ts into next.config.js compatible .JS --- packages/lib/constants.js | 98 +++++++++++++++++++++ packages/lib/constants.ts | 66 -------------- packages/lib/{telemetry.ts => telemetry.js} | 87 +++++++++++++----- 3 files changed, 164 insertions(+), 87 deletions(-) create mode 100644 packages/lib/constants.js delete mode 100644 packages/lib/constants.ts rename packages/lib/{telemetry.ts => telemetry.js} (60%) diff --git a/packages/lib/constants.js b/packages/lib/constants.js new file mode 100644 index 00000000000000..0d462ce362e394 --- /dev/null +++ b/packages/lib/constants.js @@ -0,0 +1,98 @@ +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 WEBAPP_URL = + process.env.NEXT_PUBLIC_WEBAPP_URL || + VERCEL_URL || + RAILWAY_STATIC_URL || + HEROKU_URL || + RENDER_URL || + "http://localhost:3000"; +/** @deprecated use `WEBAPP_URL` */ +const BASE_URL = WEBAPP_URL; +const WEBSITE_URL = process.env.NEXT_PUBLIC_WEBSITE_URL || "https://cal.com"; +const APP_NAME = process.env.NEXT_PUBLIC_APP_NAME || "Cal.com"; +const SUPPORT_MAIL_ADDRESS = process.env.NEXT_PUBLIC_SUPPORT_MAIL_ADDRESS || "help@cal.com"; +const COMPANY_NAME = process.env.NEXT_PUBLIC_COMPANY_NAME || "Cal.com, Inc."; +const SENDER_ID = process.env.NEXT_PUBLIC_SENDER_ID || "Cal"; +const SENDER_NAME = process.env.NEXT_PUBLIC_SENDGRID_SENDER_NAME || "Cal.com"; + +// This is the URL from which all Cal Links and their assets are served. +// Use website URL to make links shorter(cal.com and not app.cal.com) +// As website isn't setup for preview environments, use the webapp url instead +const CAL_URL = new URL(WEBAPP_URL).hostname.endsWith(".vercel.app") ? WEBAPP_URL : WEBSITE_URL; + +const CONSOLE_URL = + new URL(WEBAPP_URL).hostname.endsWith(".cal.dev") || process.env.NODE_ENV !== "production" + ? `https://console.cal.dev` + : `https://console.cal.com`; +const IS_SELF_HOSTED = !( + new URL(WEBAPP_URL).hostname.endsWith(".cal.dev") || new URL(WEBAPP_URL).hostname.endsWith(".cal.com") +); +const EMBED_LIB_URL = process.env.NEXT_PUBLIC_EMBED_LIB_URL || `${WEBAPP_URL}/embed/embed.js`; +const IS_PRODUCTION = process.env.NODE_ENV === "production"; +const TRIAL_LIMIT_DAYS = 14; + +const HOSTED_CAL_FEATURES = process.env.NEXT_PUBLIC_HOSTED_CAL_FEATURES || !IS_SELF_HOSTED; + +/** @deprecated use `WEBAPP_URL` */ +const NEXT_PUBLIC_BASE_URL = process.env.NEXT_PUBLIC_WEBAPP_URL || `https://${process.env.VERCEL_URL}`; +const LOGO = "/calcom-logo-white-word.svg"; +const LOGO_ICON = "/cal-com-icon-white.svg"; +const ROADMAP = "https://cal.com/roadmap"; +const DESKTOP_APP_LINK = "https://cal.com/download"; +const JOIN_SLACK = "https://cal.com/slack"; +const POWERED_BY_URL = `${WEBSITE_URL}/?utm_source=embed&utm_medium=powered-by-button`; +const DOCS_URL = "https://cal.com/docs"; +const DEVELOPER_DOCS = "https://developer.cal.com"; +const SEO_IMG_DEFAULT = `${WEBSITE_URL}/og-image.png`; +// The Dynamic OG Image is passed through Next's Image API to further optimize it. +// This results in a 80% smaller image 🤯. It is however important that for the query +// parameters you pass to the /api/social/og/image endpoint, you wrap them in encodeURIComponent +// as well, otherwise the URL won't be valid. +const SEO_IMG_OGIMG = `${CAL_URL}/_next/image?w=1200&q=100&url=${encodeURIComponent("/api/social/og/image")}`; +const SEO_IMG_OGIMG_VIDEO = `${WEBSITE_URL}/video-og-image.png`; +const IS_STRIPE_ENABLED = !!( + process.env.STRIPE_CLIENT_ID && + process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY && + process.env.STRIPE_PRIVATE_KEY +); +/** Self hosted shouldn't checkout when creating teams unless required */ +const IS_TEAM_BILLING_ENABLED = IS_STRIPE_ENABLED && (!IS_SELF_HOSTED || HOSTED_CAL_FEATURES); +const FULL_NAME_LENGTH_MAX_LIMIT = 50; +const MINUTES_TO_BOOK = process.env.NEXT_PUBLIC_MINUTES_TO_BOOK || "5"; + +module.exports = { + WEBAPP_URL, + BASE_URL, + WEBSITE_URL, + APP_NAME, + SUPPORT_MAIL_ADDRESS, + COMPANY_NAME, + SENDER_ID, + SENDER_NAME, + CAL_URL, + CONSOLE_URL, + IS_SELF_HOSTED, + EMBED_LIB_URL, + IS_PRODUCTION, + TRIAL_LIMIT_DAYS, + HOSTED_CAL_FEATURES, + NEXT_PUBLIC_BASE_URL, + LOGO, + LOGO_ICON, + ROADMAP, + DESKTOP_APP_LINK, + JOIN_SLACK, + POWERED_BY_URL, + DOCS_URL, + DEVELOPER_DOCS, + SEO_IMG_DEFAULT, + SEO_IMG_OGIMG, + SEO_IMG_OGIMG_VIDEO, + IS_STRIPE_ENABLED, + IS_TEAM_BILLING_ENABLED, + FULL_NAME_LENGTH_MAX_LIMIT, + MINUTES_TO_BOOK, +}; diff --git a/packages/lib/constants.ts b/packages/lib/constants.ts deleted file mode 100644 index 19b47fb76272e4..00000000000000 --- a/packages/lib/constants.ts +++ /dev/null @@ -1,66 +0,0 @@ -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 WEBAPP_URL = - process.env.NEXT_PUBLIC_WEBAPP_URL || - VERCEL_URL || - RAILWAY_STATIC_URL || - HEROKU_URL || - RENDER_URL || - "http://localhost:3000"; -/** @deprecated use `WEBAPP_URL` */ -export const BASE_URL = WEBAPP_URL; -export const WEBSITE_URL = 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 SENDER_ID = process.env.NEXT_PUBLIC_SENDER_ID || "Cal"; -export const SENDER_NAME = process.env.NEXT_PUBLIC_SENDGRID_SENDER_NAME || "Cal.com"; - -// This is the URL from which all Cal Links and their assets are served. -// Use website URL to make links shorter(cal.com and not app.cal.com) -// As website isn't setup for preview environments, use the webapp url instead -export const CAL_URL = new URL(WEBAPP_URL).hostname.endsWith(".vercel.app") ? WEBAPP_URL : WEBSITE_URL; - -export const CONSOLE_URL = - new URL(WEBAPP_URL).hostname.endsWith(".cal.dev") || process.env.NODE_ENV !== "production" - ? `https://console.cal.dev` - : `https://console.cal.com`; -export const IS_SELF_HOSTED = !( - new URL(WEBAPP_URL).hostname.endsWith(".cal.dev") || new URL(WEBAPP_URL).hostname.endsWith(".cal.com") -); -export const EMBED_LIB_URL = process.env.NEXT_PUBLIC_EMBED_LIB_URL || `${WEBAPP_URL}/embed/embed.js`; -export const IS_PRODUCTION = process.env.NODE_ENV === "production"; -export const TRIAL_LIMIT_DAYS = 14; - -export const HOSTED_CAL_FEATURES = process.env.NEXT_PUBLIC_HOSTED_CAL_FEATURES || !IS_SELF_HOSTED; - -/** @deprecated use `WEBAPP_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_ICON = "/cal-com-icon-white.svg"; -export const ROADMAP = "https://cal.com/roadmap"; -export const DESKTOP_APP_LINK = "https://cal.com/download"; -export const JOIN_SLACK = "https://cal.com/slack"; -export const POWERED_BY_URL = `${WEBSITE_URL}/?utm_source=embed&utm_medium=powered-by-button`; -export const DOCS_URL = "https://cal.com/docs"; -export const DEVELOPER_DOCS = "https://developer.cal.com"; -export const SEO_IMG_DEFAULT = `${WEBSITE_URL}/og-image.png`; -// The Dynamic OG Image is passed through Next's Image API to further optimize it. -// This results in a 80% smaller image 🤯. It is however important that for the query -// parameters you pass to the /api/social/og/image endpoint, you wrap them in encodeURIComponent -// as well, otherwise the URL won't be valid. -export const SEO_IMG_OGIMG = `${CAL_URL}/_next/image?w=1200&q=100&url=${encodeURIComponent( - "/api/social/og/image" -)}`; -export const SEO_IMG_OGIMG_VIDEO = `${WEBSITE_URL}/video-og-image.png`; -export const IS_STRIPE_ENABLED = !!( - process.env.STRIPE_CLIENT_ID && - process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY && - process.env.STRIPE_PRIVATE_KEY -); -/** Self hosted shouldn't checkout when creating teams unless required */ -export const IS_TEAM_BILLING_ENABLED = IS_STRIPE_ENABLED && (!IS_SELF_HOSTED || HOSTED_CAL_FEATURES); -export const FULL_NAME_LENGTH_MAX_LIMIT = 50; -export const MINUTES_TO_BOOK = process.env.NEXT_PUBLIC_MINUTES_TO_BOOK || "5"; diff --git a/packages/lib/telemetry.ts b/packages/lib/telemetry.js similarity index 60% rename from packages/lib/telemetry.ts rename to packages/lib/telemetry.js index fab7f8a9fcd7e1..3eb09fadb423a7 100644 --- a/packages/lib/telemetry.ts +++ b/packages/lib/telemetry.js @@ -1,12 +1,36 @@ -import type { NextApiRequest, NextApiResponse } from "next"; -import type { CollectOpts, EventHandler } from "next-collect"; -import { useCollector } from "next-collect/client"; -// Importing types so we're not directly importing next/server -import type { NextRequest, NextResponse } from "next/server"; +/** + * @typedef {import("next").NextApiRequest} NextApiRequest + * @typedef {import("next").NextApiResponse} NextApiResponse + * @typedef {import("next-collect").CollectOpts} CollectOpts + * @typedef {import("next-collect").EventHandler} EventHandler + * @typedef {import("next/server").NextRequest} NextRequest + * @typedef {import("next/server").NextResponse} NextResponse + */ +const useCollector = require("next-collect/client"); -import { CONSOLE_URL } from "./constants"; +const CONSOLE_URL = require("./constants"); -export const telemetryEventTypes = { +/** + * @type {{ + * pageView: string; + * apiCall: string; + * bookingConfirmed: string; + * bookingCancelled: string; + * importSubmitted: string; + * login: string; + * embedView: string; + * embedBookingConfirmed: string; + * onboardingFinished: string; + * onboardingStarted: string; + * signup: string; + * team_created: string; + * website: { + * pageView: string; + * }; + * slugReplacementAction: string; + * }} + */ +const telemetryEventTypes = { pageView: "page_view", apiCall: "api_call", bookingConfirmed: "booking_confirmed", @@ -25,10 +49,12 @@ export const telemetryEventTypes = { slugReplacementAction: "slug_replacement_action", }; -export function collectPageParameters( - route?: string, - extraData: Record = {} -): Record { +/** + * @param {string} [route] + * @param {Record} [extraData] + * @returns {Record} + */ +function collectPageParameters(route, extraData = {}) { const host = document.location.host; const docPath = route ?? ""; return { @@ -39,7 +65,10 @@ export function collectPageParameters( }; } -const reportUsage: EventHandler = async (event, { fetch }) => { +/** + * @type {EventHandler} + */ +const reportUsage = async (event, { fetch }) => { const ets = telemetryEventTypes; if ([ets.bookingConfirmed, ets.embedBookingConfirmed].includes(event.eventType)) { const key = process.env.CALCOM_LICENSE_KEY; @@ -55,7 +84,10 @@ const reportUsage: EventHandler = async (event, { fetch }) => { } }; -export const nextCollectBasicSettings: CollectOpts = { +/** + * @type {CollectOpts} + */ +const nextCollectBasicSettings = { drivers: [ process.env.CALCOM_LICENSE_KEY && process.env.NEXT_PUBLIC_IS_E2E !== "1" ? reportUsage : undefined, process.env.CALCOM_TELEMETRY_DISABLED === "1" || process.env.NEXT_PUBLIC_IS_E2E === "1" @@ -85,17 +117,19 @@ export const nextCollectBasicSettings: CollectOpts = { ], }; -export const extendEventData = ( - req: NextRequest | NextApiRequest, - res: NextResponse | NextApiResponse, - original: any -) => { +/** + * @param {NextRequest | NextApiRequest} req + * @param {NextResponse | NextApiResponse} res + * @param {any} original + * @returns {Record} + */ +const extendEventData = (req, res, original) => { const onVercel = typeof req.headers?.get === "function" ? !!req.headers.get("x-vercel-id") - : !!(req.headers as any)?.["x-vercel-id"]; + : !!req.headers?.["x-vercel-id"]; const pageUrl = original?.page_url || req.url || undefined; - const cookies = req.cookies as { [key: string]: any }; + const cookies = req.cookies; return { title: "", ipAddress: "", @@ -113,4 +147,15 @@ export const extendEventData = ( }; }; -export const useTelemetry = useCollector; +/** + * @type {typeof useCollector} + */ +const useTelemetry = useCollector; + +module.exports = { + telemetryEventTypes, + collectPageParameters, + nextCollectBasicSettings, + extendEventData, + useTelemetry, +};