diff --git a/apps/code/src/main/posthog-session-arg.test.ts b/apps/code/src/main/posthog-session-arg.test.ts new file mode 100644 index 0000000000..a45c458fe6 --- /dev/null +++ b/apps/code/src/main/posthog-session-arg.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, it } from "vitest"; +import { parseSessionIdArg } from "./posthog-session-arg"; + +describe("parseSessionIdArg", () => { + it("returns the value when the flag is present", () => { + expect(parseSessionIdArg(["--posthog-session-id=abc-123"])).toBe("abc-123"); + }); + + it("finds the flag among other arguments", () => { + expect( + parseSessionIdArg(["--foo", "--posthog-session-id=xyz", "--bar"]), + ).toBe("xyz"); + }); + + it("returns null when the flag is absent", () => { + expect(parseSessionIdArg(["--type=renderer", "--no-sandbox"])).toBeNull(); + }); + + it("ignores arguments that only share the prefix", () => { + expect(parseSessionIdArg(["--posthog-session-id-extra=foo"])).toBeNull(); + }); + + it("returns an empty string when the flag has no value", () => { + expect(parseSessionIdArg(["--posthog-session-id="])).toBe(""); + }); +}); diff --git a/apps/code/src/main/posthog-session-arg.ts b/apps/code/src/main/posthog-session-arg.ts new file mode 100644 index 0000000000..e11002aa45 --- /dev/null +++ b/apps/code/src/main/posthog-session-arg.ts @@ -0,0 +1,9 @@ +export const POSTHOG_SESSION_ID_ARG = "--posthog-session-id="; + +export function parseSessionIdArg(argv: string[]): string | null { + return ( + argv + .find((arg) => arg.startsWith(POSTHOG_SESSION_ID_ARG)) + ?.slice(POSTHOG_SESSION_ID_ARG.length) ?? null + ); +} diff --git a/apps/code/src/main/preload.ts b/apps/code/src/main/preload.ts index b90c21f89e..a78c4f20d2 100644 --- a/apps/code/src/main/preload.ts +++ b/apps/code/src/main/preload.ts @@ -1,11 +1,16 @@ import { exposeElectronTRPC } from "@posthog/electron-trpc/main"; import { contextBridge, webUtils } from "electron"; import "electron-log/preload"; +import { parseSessionIdArg } from "./posthog-session-arg"; contextBridge.exposeInMainWorld("electronUtils", { getPathForFile: (file: File) => webUtils.getPathForFile(file), }); +contextBridge.exposeInMainWorld("__posthogBootstrap", { + sessionId: parseSessionIdArg(process.argv), +}); + if (process.argv.includes("--posthog-code-dev")) { contextBridge.exposeInMainWorld("__posthogCodeTest", { crash: () => { diff --git a/apps/code/src/main/window.ts b/apps/code/src/main/window.ts index e9df218cc4..530cf95fbc 100644 --- a/apps/code/src/main/window.ts +++ b/apps/code/src/main/window.ts @@ -13,6 +13,8 @@ import { import { container } from "./di/container"; import { buildApplicationMenu } from "./menu"; import type { ElectronMainWindow } from "./platform-adapters/electron-main-window"; +import { posthogNodeAnalytics } from "./platform-adapters/posthog-analytics"; +import { POSTHOG_SESSION_ID_ARG } from "./posthog-session-arg"; import { trpcRouter } from "./trpc/router"; import { collectMemorySnapshot } from "./utils/crash-diagnostics"; import { isDevBuild } from "./utils/env"; @@ -203,7 +205,10 @@ export function createWindow(): void { preload: path.join(__dirname, "preload.js"), enableBlinkFeatures: "GetDisplayMedia", partition: "persist:main", - additionalArguments: isDev ? ["--posthog-code-dev"] : [], + additionalArguments: [ + ...(isDev ? ["--posthog-code-dev"] : []), + `${POSTHOG_SESSION_ID_ARG}${posthogNodeAnalytics.getOrCreateSessionId()}`, + ], ...(isDev && { webSecurity: false }), }, }); diff --git a/apps/code/src/renderer/contributions/app-boot.contributions.ts b/apps/code/src/renderer/contributions/app-boot.contributions.ts index 040573f6ea..d3ef4a3f0c 100644 --- a/apps/code/src/renderer/contributions/app-boot.contributions.ts +++ b/apps/code/src/renderer/contributions/app-boot.contributions.ts @@ -13,13 +13,15 @@ const log = logger.scope("app-boot"); export class AnalyticsBootContribution implements Contribution { start(): void { void (async () => { - let sessionId: string | undefined; - try { - ({ sessionId } = await trpcClient.analytics.getSessionId.query()); - } catch (error) { - log.warn("Failed to fetch session id from main", { error }); + if (!window.__posthogBootstrap?.sessionId) { + let sessionId: string | undefined; + try { + ({ sessionId } = await trpcClient.analytics.getSessionId.query()); + } catch (error) { + log.warn("Failed to fetch session id from main", { error }); + } + initializePostHog(sessionId); } - initializePostHog(sessionId); trpcClient.os.getAppVersion .query() .then(registerAppVersion) diff --git a/apps/code/src/renderer/main.tsx b/apps/code/src/renderer/main.tsx index da12c700cb..dfd059c3d5 100644 --- a/apps/code/src/renderer/main.tsx +++ b/apps/code/src/renderer/main.tsx @@ -16,6 +16,7 @@ import { preloadHighlighter } from "@pierre/diffs"; import { boot } from "@posthog/di/contribution"; import { ServiceProvider } from "@posthog/di/react"; import App from "@posthog/ui/shell/App"; +import { initializePostHog } from "@posthog/ui/shell/posthogAnalyticsImpl"; import { registerDesktopContributions } from "@renderer/desktop-contributions"; import { container } from "@renderer/di/container"; import "@renderer/desktop-services"; @@ -74,6 +75,11 @@ document.title = import.meta.env.DEV ? "PostHog Code (Development)" : "PostHog Code"; +const bootstrapSessionId = window.__posthogBootstrap?.sessionId; +if (bootstrapSessionId) { + initializePostHog(bootstrapSessionId); +} + registerDesktopContributions(); void boot(container); diff --git a/apps/code/src/renderer/types/electron.d.ts b/apps/code/src/renderer/types/electron.d.ts index 0da53ae4a1..a67719c0b2 100644 --- a/apps/code/src/renderer/types/electron.d.ts +++ b/apps/code/src/renderer/types/electron.d.ts @@ -5,5 +5,8 @@ declare global { electronUtils?: { getPathForFile: (file: File) => string; }; + __posthogBootstrap?: { + sessionId: string | null; + }; } }