import { loadRequiredWebConfig } from "@toolctrl/config"; import { getAuthUserWithoutPasswordById as getUser, getTenantById as getTenant, getTenantByIdOrSlug } from "@toolctrl/db/auth-boundary.server"; import { Params } from "react-router"; import { AnalyticsInfoDto } from "~/application/dtos/marketing/AnalyticsInfoDto"; import { ImpersonatingSessionDto } from "~/application/dtos/session/ImpersonatingSessionDto"; import { CookieCategory } from "~/application/cookies/CookieCategory"; import { remixI18Next, i18nCookie } from "~/locale/i18next.server"; import { getCurrentEnabledFlagNames } from "~/utils/services/.server/featureFlagsRequest.server"; import { createMetrics } from "~/modules/metrics/services/.server/MetricTracker"; import { getAnalyticsSession, generateAnalyticsUserId, commitAnalyticsSession, destroyAnalyticsSession } from "~/utils/analyticsCookie.server"; import { getAppConfiguration } from "~/utils/db/appConfiguration.db.server"; import AnalyticsService from "~/utils/helpers/.server/AnalyticsService"; import CookieHelper from "~/utils/helpers/CookieHelper"; import { promiseHash } from "~/utils/promises/promiseHash"; import { getUserInfo, getUserSession, setCSRFToken, createUserSession, commitSession } from "~/utils/session.server"; import { getAbsoluteApiUrl, getAbsoluteUrl, getBaseURL, getDomainName } from "~/utils/url.server"; import { AppRootData } from "../useRootData"; export async function loadRootData({ request, params }: { request: Request; params: Params }) { const { time, getServerTimingHeader } = await createMetrics({ request, params }, "root"); const { userInfo, session, analyticsSession } = await time( promiseHash({ userInfo: getUserInfo(request), session: getUserSession(request), analyticsSession: getAnalyticsSession(request), }), "loadRootData.session" ); const user = userInfo.userId ? await getUser(userInfo.userId) : null; const currentTenant = params.tenant ? await getTenantByIdOrSlug(params.tenant) : user?.defaultTenantId ? await getTenant(user.defaultTenantId) : null; const existingCsrf = session.get("csrf"); const csrf = typeof existingCsrf === "string" && existingCsrf.length > 0 ? existingCsrf : setCSRFToken(session); let analytics: AnalyticsInfoDto | undefined = undefined; const appConfiguration = await time(getAppConfiguration({ request }), "getAppConfiguration"); const hasAnalyticsConsent = CookieHelper.hasConsent(userInfo, CookieCategory.ANALYTICS); if (appConfiguration.analytics.enabled && hasAnalyticsConsent) { try { analytics = await AnalyticsService.getFromRequest({ appConfiguration, request, userId: userInfo.userId ?? null }); } catch (e: any) { // eslint-disable-next-line no-console console.error(e.message); } } const headers = new Headers(); let userAnalyticsId = analyticsSession.get("userAnalyticsId"); headers.append("Set-Cookie", await commitSession(session)); if (hasAnalyticsConsent) { if (!userAnalyticsId) { userAnalyticsId = generateAnalyticsUserId(); analyticsSession.set("userAnalyticsId", userAnalyticsId); } if (analytics) { analytics = { ...analytics, userAnalyticsId }; } headers.append("Set-Cookie", await commitAnalyticsSession(analyticsSession)); } else { userAnalyticsId = undefined; headers.append("Set-Cookie", await destroyAnalyticsSession(analyticsSession)); } let impersonatingSession: ImpersonatingSessionDto | null = null; if (userInfo.impersonatingFromUserId && userInfo.userId?.length > 0) { const fromUser = await getUser(userInfo.impersonatingFromUserId); const toUser = await getUser(userInfo.userId); if (fromUser && toUser) { impersonatingSession = { fromUser, toUser }; } } const locale = await remixI18Next.getLocale(request); const webConfig = loadRequiredWebConfig(); const data: AppRootData = { metatags: [{ title: webConfig.appName }], user, currentTenant, locale, theme: userInfo.theme || appConfiguration.app.theme, serverUrl: getBaseURL(request), publicBaseUrl: getAbsoluteUrl(request, "/"), apiBaseUrl: getAbsoluteApiUrl(request, "/"), routing: webConfig.routing, domainName: getDomainName(request), userSession: userInfo, authenticated: userInfo.userId?.length > 0, debug: webConfig.nodeEnv === "development", isStripeTest: webConfig.stripe.secretKey?.startsWith("sk_test_") ?? true, chatWebsiteId: webConfig.crisp.chatWebsiteId, appConfiguration, csrf, analytics, analyticsToken: appConfiguration.analytics.enabled && hasAnalyticsConsent ? webConfig.analytics.token : undefined, featureFlags: appConfiguration.featureFlags.enabled ? await getCurrentEnabledFlagNames({ request, params }) : [], impersonatingSession, }; const updateMetrics = userInfo.userId?.length > 0 && appConfiguration.metrics.enabled !== userInfo.metrics?.enabled; const needsToUpdateSession = updateMetrics; if (needsToUpdateSession) { return createUserSession( { ...userInfo, metrics: appConfiguration.metrics, }, new URL(request.url).pathname + new URL(request.url).search ); } headers.append("Server-Timing", getServerTimingHeader()["Server-Timing"]); headers.append("Set-Cookie", await i18nCookie.serialize(locale)); return Response.json(data, { headers }); }