255 lines
5.9 KiB
TypeScript
255 lines
5.9 KiB
TypeScript
import { PostHog } from "posthog-node";
|
|
import { env } from "~/env.server";
|
|
import type { MatchedOrganization } from "~/hooks/useOrganizations";
|
|
import type { Organization } from "~/models/organization.server";
|
|
import type { Project } from "~/models/project.server";
|
|
import type { User } from "~/models/user.server";
|
|
import { singleton } from "~/utils/singleton";
|
|
import { enqueueAttioUserSync } from "./attio.server";
|
|
import { loopsClient } from "./loops.server";
|
|
|
|
type Options = {
|
|
postHogApiKey?: string;
|
|
};
|
|
|
|
class Telemetry {
|
|
#posthogClient: PostHog | undefined = undefined;
|
|
|
|
constructor({ postHogApiKey }: Options) {
|
|
if (env.TRIGGER_TELEMETRY_DISABLED !== undefined) {
|
|
console.log("📉 Telemetry disabled");
|
|
return;
|
|
}
|
|
|
|
if (postHogApiKey) {
|
|
this.#posthogClient = new PostHog(postHogApiKey, { host: env.POSTHOG_HOST });
|
|
} else {
|
|
console.log("No PostHog API key, so analytics won't track");
|
|
}
|
|
}
|
|
|
|
user = {
|
|
identify: ({
|
|
user,
|
|
isNewUser,
|
|
referralSource,
|
|
}: {
|
|
user: User;
|
|
isNewUser: boolean;
|
|
referralSource?: string;
|
|
}) => {
|
|
if (this.#posthogClient) {
|
|
const properties: Record<string, any> = {
|
|
email: user.email,
|
|
name: user.name,
|
|
authenticationMethod: user.authenticationMethod,
|
|
admin: user.admin,
|
|
createdAt: user.createdAt,
|
|
isNewUser,
|
|
};
|
|
|
|
if (referralSource) {
|
|
properties.referralSource = referralSource;
|
|
}
|
|
|
|
this.#posthogClient.identify({
|
|
distinctId: user.id,
|
|
properties,
|
|
});
|
|
}
|
|
if (isNewUser) {
|
|
this.#capture({
|
|
userId: user.id,
|
|
event: "user created",
|
|
eventProperties: {
|
|
email: user.email,
|
|
name: user.name,
|
|
authenticationMethod: user.authenticationMethod,
|
|
admin: user.admin,
|
|
createdAt: user.createdAt,
|
|
},
|
|
});
|
|
|
|
loopsClient?.userCreated({
|
|
userId: user.id,
|
|
email: user.email,
|
|
name: user.name,
|
|
});
|
|
|
|
enqueueAttioUserSync({
|
|
userId: user.id,
|
|
email: user.email,
|
|
referralSource: referralSource ?? user.referralSource,
|
|
marketingEmails: user.marketingEmails,
|
|
createdAt: user.createdAt,
|
|
});
|
|
}
|
|
},
|
|
};
|
|
|
|
organization = {
|
|
identify: ({ organization }: { organization: MatchedOrganization }) => {
|
|
if (this.#posthogClient === undefined) return;
|
|
this.#posthogClient.groupIdentify({
|
|
groupType: "organization",
|
|
groupKey: organization.id,
|
|
properties: {
|
|
name: organization.title,
|
|
slug: organization.slug,
|
|
},
|
|
});
|
|
},
|
|
new: ({
|
|
userId,
|
|
organization,
|
|
organizationCount,
|
|
}: {
|
|
userId: string;
|
|
organization: Organization;
|
|
organizationCount: number;
|
|
}) => {
|
|
if (this.#posthogClient === undefined) return;
|
|
this.#capture({
|
|
userId,
|
|
event: "organization created",
|
|
organizationId: organization.id,
|
|
eventProperties: {
|
|
id: organization.id,
|
|
slug: organization.slug,
|
|
title: organization.title,
|
|
createdAt: organization.createdAt,
|
|
updatedAt: organization.updatedAt,
|
|
},
|
|
userProperties: {
|
|
organizationCount: organizationCount,
|
|
},
|
|
});
|
|
},
|
|
};
|
|
|
|
project = {
|
|
identify: ({
|
|
project,
|
|
}: {
|
|
project: Pick<Project, "id" | "name" | "createdAt" | "updatedAt">;
|
|
}) => {
|
|
if (this.#posthogClient === undefined) return;
|
|
this.#posthogClient.groupIdentify({
|
|
groupType: "project",
|
|
groupKey: project.id,
|
|
properties: {
|
|
name: project.name,
|
|
createdAt: project.createdAt,
|
|
updatedAt: project.updatedAt,
|
|
},
|
|
});
|
|
},
|
|
new: ({
|
|
userId,
|
|
organizationId,
|
|
project,
|
|
}: {
|
|
userId: string;
|
|
organizationId: string;
|
|
project: Project;
|
|
}) => {
|
|
if (this.#posthogClient === undefined) return;
|
|
this.#capture({
|
|
userId,
|
|
event: "project created",
|
|
organizationId,
|
|
eventProperties: {
|
|
id: project.id,
|
|
|
|
title: project.name,
|
|
createdAt: project.createdAt,
|
|
updatedAt: project.updatedAt,
|
|
},
|
|
});
|
|
},
|
|
};
|
|
|
|
#capture(event: CaptureEvent) {
|
|
if (this.#posthogClient === undefined) return;
|
|
let groups: Record<string, string> = {};
|
|
|
|
if (event.organizationId) {
|
|
groups = {
|
|
...groups,
|
|
organization: event.organizationId,
|
|
};
|
|
}
|
|
|
|
if (event.projectId) {
|
|
groups = {
|
|
...groups,
|
|
project: event.projectId,
|
|
};
|
|
}
|
|
|
|
if (event.jobId) {
|
|
groups = {
|
|
...groups,
|
|
workflow: event.jobId,
|
|
};
|
|
}
|
|
|
|
if (event.environmentId) {
|
|
groups = {
|
|
...groups,
|
|
environment: event.environmentId,
|
|
};
|
|
}
|
|
|
|
let properties: Record<string, any> = {};
|
|
if (event.eventProperties) {
|
|
properties = {
|
|
...properties,
|
|
...event.eventProperties,
|
|
};
|
|
}
|
|
|
|
if (event.userProperties) {
|
|
properties = {
|
|
...properties,
|
|
$set: event.userProperties,
|
|
};
|
|
}
|
|
|
|
if (event.userOnceProperties) {
|
|
properties = {
|
|
...properties,
|
|
$set_once: event.userOnceProperties,
|
|
};
|
|
}
|
|
|
|
const eventData = {
|
|
distinctId: event.userId,
|
|
event: event.event,
|
|
properties,
|
|
groups,
|
|
};
|
|
this.#posthogClient.capture(eventData);
|
|
}
|
|
}
|
|
|
|
type CaptureEvent = {
|
|
userId: string;
|
|
event: string;
|
|
organizationId?: string;
|
|
projectId?: string;
|
|
jobId?: string;
|
|
environmentId?: string;
|
|
eventProperties?: Record<string, any>;
|
|
userProperties?: Record<string, any>;
|
|
userOnceProperties?: Record<string, any>;
|
|
};
|
|
|
|
export const telemetry = singleton(
|
|
"telemetry",
|
|
() =>
|
|
new Telemetry({
|
|
postHogApiKey: env.POSTHOG_PROJECT_KEY,
|
|
})
|
|
);
|