First pass at a PosthogAnalytics class
This commit is contained in:
parent
48817499e4
commit
2a48d3c9bc
4 changed files with 179 additions and 0 deletions
|
@ -86,6 +86,7 @@
|
||||||
"pako": "^2.0.3",
|
"pako": "^2.0.3",
|
||||||
"parse5": "^6.0.1",
|
"parse5": "^6.0.1",
|
||||||
"png-chunks-extract": "^1.0.0",
|
"png-chunks-extract": "^1.0.0",
|
||||||
|
"posthog-js": "^1.12.1",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"qrcode": "^1.4.4",
|
"qrcode": "^1.4.4",
|
||||||
"re-resizable": "^6.9.0",
|
"re-resizable": "^6.9.0",
|
||||||
|
|
82
src/PosthogAnalytics.ts
Normal file
82
src/PosthogAnalytics.ts
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
import posthog from 'posthog-js';
|
||||||
|
import SdkConfig from './SdkConfig';
|
||||||
|
|
||||||
|
export interface IEvent {
|
||||||
|
key: string;
|
||||||
|
properties: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IOnboardingLoginBegin extends IEvent {
|
||||||
|
key: "onboarding_login_begin",
|
||||||
|
}
|
||||||
|
|
||||||
|
const hashHex = async (input: string): Promise<string> => {
|
||||||
|
const buf = new TextEncoder().encode(input);
|
||||||
|
const digestBuf = await window.crypto.subtle.digest("sha-256", buf);
|
||||||
|
return [...new Uint8Array(digestBuf)].map((b: number) => b.toString(16).padStart(2, "0")).join("");
|
||||||
|
};
|
||||||
|
|
||||||
|
export class PosthogAnalytics {
|
||||||
|
private onlyTrackAnonymousEvents = false;
|
||||||
|
private initialised = false;
|
||||||
|
private posthog = null;
|
||||||
|
|
||||||
|
private static _instance = null;
|
||||||
|
|
||||||
|
public static instance(): PosthogAnalytics {
|
||||||
|
if (!this.instance) {
|
||||||
|
this._instance = new PosthogAnalytics(posthog);
|
||||||
|
}
|
||||||
|
return this._instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(posthog) {
|
||||||
|
this.posthog = posthog;
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(onlyTrackAnonymousEvents: boolean) {
|
||||||
|
if (Boolean(navigator.doNotTrack === "1")) {
|
||||||
|
this.initialised = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.onlyTrackAnonymousEvents = onlyTrackAnonymousEvents;
|
||||||
|
const posthogConfig = SdkConfig.get()["posthog"];
|
||||||
|
if (posthogConfig) {
|
||||||
|
console.log(`Initialising Posthog for ${posthogConfig.apiHost}`);
|
||||||
|
this.posthog.init(posthogConfig.projectApiKey, { api_host: posthogConfig.apiHost });
|
||||||
|
this.initialised = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public isInitialised(): boolean {
|
||||||
|
return this.initialised;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setOnlyTrackAnonymousEvents(enabled: boolean) {
|
||||||
|
this.onlyTrackAnonymousEvents = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public track<E extends IEvent>(
|
||||||
|
key: E["key"],
|
||||||
|
properties: E["properties"],
|
||||||
|
anonymous = false,
|
||||||
|
) {
|
||||||
|
if (!this.initialised) return;
|
||||||
|
if (this.onlyTrackAnonymousEvents && !anonymous) return;
|
||||||
|
|
||||||
|
this.posthog.capture(key, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async trackRoomEvent<E extends IEvent>(
|
||||||
|
key: E["key"],
|
||||||
|
roomId: string,
|
||||||
|
properties: E["properties"],
|
||||||
|
...args
|
||||||
|
) {
|
||||||
|
const updatedProperties = {
|
||||||
|
...properties,
|
||||||
|
hashedRoomId: roomId ? await hashHex(roomId) : null,
|
||||||
|
};
|
||||||
|
this.track(key, updatedProperties, ...args);
|
||||||
|
}
|
||||||
|
}
|
84
test/PosthogAnalytics-test.ts
Normal file
84
test/PosthogAnalytics-test.ts
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
import { IEvent, PosthogAnalytics } from '../src/PosthogAnalytics';
|
||||||
|
import SdkConfig from '../src/SdkConfig';
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
class FakePosthog {
|
||||||
|
public capture;
|
||||||
|
public init;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.capture = jest.fn();
|
||||||
|
this.init = jest.fn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ITestEvent extends IEvent {
|
||||||
|
key: "jest_test_event",
|
||||||
|
properties: {
|
||||||
|
foo: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("PosthogAnalytics", () => {
|
||||||
|
let analytics: PosthogAnalytics;
|
||||||
|
let fakePosthog: FakePosthog;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fakePosthog = new FakePosthog();
|
||||||
|
analytics = new PosthogAnalytics(fakePosthog);
|
||||||
|
window.crypto = {
|
||||||
|
subtle: crypto.webcrypto.subtle,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
navigator.doNotTrack = null;
|
||||||
|
window.crypto = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not initialise if DNT is enabled", () => {
|
||||||
|
navigator.doNotTrack = "1";
|
||||||
|
analytics.init(false);
|
||||||
|
expect(analytics.isInitialised()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not initialise if config is not set", () => {
|
||||||
|
jest.spyOn(SdkConfig, "get").mockReturnValue({});
|
||||||
|
analytics.init(false);
|
||||||
|
expect(analytics.isInitialised()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should initialise if config is set", () => {
|
||||||
|
jest.spyOn(SdkConfig, "get").mockReturnValue({
|
||||||
|
posthog: {
|
||||||
|
projectApiKey: "foo",
|
||||||
|
apiHost: "bar",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
analytics.init(false);
|
||||||
|
expect(analytics.isInitialised()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should pass track() to posthog", () => {
|
||||||
|
analytics.init(false);
|
||||||
|
analytics.track<ITestEvent>("jest_test_event", {
|
||||||
|
foo: "bar",
|
||||||
|
});
|
||||||
|
expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_event");
|
||||||
|
expect(fakePosthog.capture.mock.calls[0][1]).toEqual({ foo: "bar" });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should pass trackRoomEvent to posthog", () => {
|
||||||
|
analytics.init(false);
|
||||||
|
const roomId = "42";
|
||||||
|
return analytics.trackRoomEvent<ITestEvent>("jest_test_event", roomId, {
|
||||||
|
foo: "bar",
|
||||||
|
}).then(() => {
|
||||||
|
expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_event");
|
||||||
|
expect(fakePosthog.capture.mock.calls[0][1]).toEqual({
|
||||||
|
foo: "bar",
|
||||||
|
hashedRoomId: "73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
12
yarn.lock
12
yarn.lock
|
@ -3601,6 +3601,11 @@ fbjs@^0.8.4:
|
||||||
setimmediate "^1.0.5"
|
setimmediate "^1.0.5"
|
||||||
ua-parser-js "^0.7.18"
|
ua-parser-js "^0.7.18"
|
||||||
|
|
||||||
|
fflate@^0.4.1:
|
||||||
|
version "0.4.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae"
|
||||||
|
integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==
|
||||||
|
|
||||||
file-entry-cache@^6.0.0:
|
file-entry-cache@^6.0.0:
|
||||||
version "6.0.0"
|
version "6.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.0.tgz#7921a89c391c6d93efec2169ac6bf300c527ea0a"
|
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.0.tgz#7921a89c391c6d93efec2169ac6bf300c527ea0a"
|
||||||
|
@ -6287,6 +6292,13 @@ postcss@^8.0.2:
|
||||||
nanoid "^3.1.20"
|
nanoid "^3.1.20"
|
||||||
source-map "^0.6.1"
|
source-map "^0.6.1"
|
||||||
|
|
||||||
|
posthog-js@^1.12.1:
|
||||||
|
version "1.12.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.12.1.tgz#97834ee2574f34ffb5db2f5b07452c847e3c4d27"
|
||||||
|
integrity sha512-Y3lzcWkS8xFY6Ryj3I4ees7qWP2WGkLw0Arcbk5xaT0+5YlA6UC2jlL/+fN9bz/Bl62EoN3BML901Cuot/QNjg==
|
||||||
|
dependencies:
|
||||||
|
fflate "^0.4.1"
|
||||||
|
|
||||||
prelude-ls@^1.2.1:
|
prelude-ls@^1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
||||||
|
|
Loading…
Reference in a new issue