Skip to content

Commit 5c50bec

Browse files
committed
refactor: move PostHog singleton to utils/posthog.ts
Extracts getPostHogClient() into a dedicated module so it can be reused for feature flags and other PostHog features beyond the mirror middleware.
1 parent e453214 commit 5c50bec

3 files changed

Lines changed: 22 additions & 19 deletions

File tree

apps/backend/middleware/legacy/mirror.middleware.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,6 @@
11
import { NextFunction, Request, Response } from 'express';
22
import { MirrorCommandQueue } from './commandqueue.mirror';
3-
4-
import { PostHog } from 'posthog-node';
5-
6-
let postHogClient: PostHog | null = null;
7-
function getPostHogClient(): PostHog {
8-
if (!postHogClient) {
9-
postHogClient = new PostHog(process.env.POSTHOG_API_KEY ?? '', {
10-
host: 'https://us.i.posthog.com',
11-
});
12-
}
13-
return postHogClient;
14-
}
3+
import { getPostHogClient } from '../../utils/posthog.js';
154

165
export const createBackendMirrorMiddleware =
176
<T>(createCommand: (req: Request, data: T) => Promise<string[]>) =>

apps/backend/utils/posthog.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { PostHog } from 'posthog-node';
2+
3+
let postHogClient: PostHog | null = null;
4+
5+
export function getPostHogClient(): PostHog {
6+
if (!postHogClient) {
7+
postHogClient = new PostHog(process.env.POSTHOG_API_KEY ?? '', {
8+
host: 'https://us.i.posthog.com',
9+
});
10+
}
11+
return postHogClient;
12+
}

tests/unit/middleware/legacy/mirror.posthog.test.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ const mockPostHogInstance = {
33
shutdown: jest.fn().mockResolvedValue(undefined),
44
};
55

6-
const PostHogConstructor = jest.fn(() => mockPostHogInstance);
6+
const mockGetPostHogClient = jest.fn(() => mockPostHogInstance);
77

8-
jest.mock('posthog-node', () => ({
9-
PostHog: PostHogConstructor,
8+
jest.mock('../../../../apps/backend/utils/posthog', () => ({
9+
getPostHogClient: mockGetPostHogClient,
1010
}));
1111

1212
jest.mock('../../../../apps/backend/middleware/legacy/commandqueue.mirror', () => ({
@@ -34,14 +34,14 @@ function createMockReqRes() {
3434
return { req, res };
3535
}
3636

37-
describe('PostHog client instantiation', () => {
37+
describe('PostHog client usage', () => {
3838
beforeEach(() => {
39-
PostHogConstructor.mockClear();
39+
mockGetPostHogClient.mockClear();
4040
mockPostHogInstance.isFeatureEnabled.mockClear();
4141
mockPostHogInstance.shutdown.mockClear();
4242
});
4343

44-
it('creates PostHog at most once across multiple requests', async () => {
44+
it('uses the shared PostHog singleton from utils/posthog', async () => {
4545
const createCommand = jest.fn().mockResolvedValue(['SQL1']);
4646
const middleware = createBackendMirrorMiddleware(createCommand);
4747

@@ -63,6 +63,8 @@ describe('PostHog client instantiation', () => {
6363
// Allow async callbacks to settle
6464
await new Promise((r) => setTimeout(r, 50));
6565

66-
expect(PostHogConstructor).toHaveBeenCalledTimes(1);
66+
// getPostHogClient is called per-request, but it returns the same singleton
67+
expect(mockGetPostHogClient).toHaveBeenCalled();
68+
expect(mockPostHogInstance.isFeatureEnabled).toHaveBeenCalledTimes(2);
6769
});
6870
});

0 commit comments

Comments
 (0)