chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:32:57 +08:00
commit cd420f9332
4811 changed files with 884702 additions and 0 deletions
@@ -0,0 +1,254 @@
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,
})
);