Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions .github/workflows/posthog-types.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
name: posthog-types

on:
push:
branches: [master]
pull_request:
branches: [master]

defaults:
run:
shell: bash
working-directory: .

jobs:
build:
runs-on: ubicloud
timeout-minutes: 10
defaults:
run:
working-directory: ./posthog-types
steps:
- uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '24.x.x'
registry-url: 'https://registry.npmjs.org'

- name: Setup bun
uses: oven-sh/setup-bun@v1
with:
bun-version: 1.2.15

- name: Install dependencies
run: bun install

- name: Build
run: bun run build

check-for-posthog-types-changes:
runs-on: ubicloud
outputs:
posthog-types: ${{ steps.filter.outputs.posthog-types }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
posthog-types:
- 'posthog-types/**'

release:
runs-on: ubicloud
needs: [build, check-for-posthog-types-changes]
if: ${{ github.ref == 'refs/heads/master' && needs.check-for-posthog-types-changes.outputs.posthog-types == 'true' }}
defaults:
run:
working-directory: ./posthog-types
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GH_PAT }}

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '24.x.x'
registry-url: 'https://registry.npmjs.org'

- name: Setup bun
uses: oven-sh/setup-bun@v1
with:
bun-version: 1.2.15

- name: Install dependencies
run: bun install

- name: Build
run: bun run build

- name: Update package version
run: |
VERSION=$(node -e "console.log(require('./package.json').version);")
npm version patch
echo "PACKAGE_VERSION=$(node -e "console.log(require('./package.json').version);")" >> $GITHUB_ENV

- name: Git commit
id: git-commit
run: |
git config user.name "GitHub Actions"
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
git add ..
git commit -a -m "posthog-types: release v$PACKAGE_VERSION [skip ci]"
git pull --rebase origin master
git push origin HEAD || {
echo "Push failed. Retrying after pulling latest changes..."
git pull --rebase origin master
git push origin HEAD
}
echo "version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT

- name: Publish to npm
run: npm publish --access=public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Notify Slack on failure
if: failure()
uses: slackapi/[email protected]
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
with:
channel-id: '#code-review'
slack-message: '<!here> ❌ posthog-types deployment failed! Check the logs: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
26 changes: 26 additions & 0 deletions posthog-types/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "@drift-labs/posthog-types",
"version": "0.0.1",
"description": "Shared PostHog event type definitions for Drift",
"types": "./lib/index.d.ts",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/drift-labs/drift-common/tree/master/posthog-types"
},
"author": "Drift Labs",
"scripts": {
"build": "bun run clean && tsc",
"clean": "rm -rf lib",
"prepublishOnly": "bun run build"
},
"files": [
"lib"
],
"publishConfig": {
"access": "public"
},
"devDependencies": {
"typescript": "5.4.5"
}
}
77 changes: 77 additions & 0 deletions posthog-types/src/eventMap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import type { CollateralEvents } from './events/collateral';
import type { TradeEvents } from './events/trade';
import type { VaultEvents } from './events/vault';
import type { IfStakingEvents } from './events/ifStaking';
import type { EarnEvents } from './events/earn';
import type { AmplifyEvents } from './events/amplify';
import type { OnboardingEvents } from './events/onboarding';
import type { SurveyEvents } from './events/survey';
import type { PnlEvents } from './events/pnl';
import type { SystemEvents } from './events/system';

/**
* Marker type for events that require no properties.
* We use {} rather than Record<string, never> because Record<string, never>
* collapses optional fields to never under intersection with platform extensions.
*/
// eslint-disable-next-line @typescript-eslint/ban-types
export type NoProperties = {};

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface PostHogEventMap
extends CollateralEvents,
TradeEvents,
VaultEvents,
IfStakingEvents,
EarnEvents,
AmplifyEvents,
OnboardingEvents,
SurveyEvents,
PnlEvents,
SystemEvents {}

export type PostHogEvent = keyof PostHogEventMap;

/**
* Extracts event names whose property type has no required keys (i.e., empty `{}`).
* These events can be captured without passing a properties argument.
*/
type EmptyEventsOf<TMap extends PostHogEventMap> = {
[K in keyof TMap]: keyof TMap[K] extends never ? K : never;
}[keyof TMap];

/**
* Typed capture function. Overloads are ordered so that:
* 1. Events with no properties can be called with just the event name
* 2. Events with properties require the properties argument
*
* TypeScript resolves overloads top-to-bottom — the zero-argument overload
* must come first, otherwise it would never match.
*/
export type CaptureEvent<TMap extends PostHogEventMap = PostHogEventMap> = {
<E extends EmptyEventsOf<TMap> & string>(event: E): void;
<E extends keyof TMap & string>(event: E, properties: TMap[E]): void;
};

/**
* Extend the shared event map with platform-specific overrides and new events.
*
* @typeParam TOverrides - Properties to intersect onto existing events (use optional fields)
* @typeParam TNew - Entirely new platform-specific events
*
* @example
* ```ts
* type WebEventMap = ExtendEventMap<
* { collateral_deposit_submitted: { source?: string } },
* { web_only_event: { detail: string } }
* >;
* ```
*/
export type ExtendEventMap<
TOverrides extends Partial<Record<PostHogEvent, object>> = NoProperties,
TNew extends Record<string, object> = NoProperties
> = {
[K in PostHogEvent]: K extends keyof TOverrides
? PostHogEventMap[K] & TOverrides[K]
: PostHogEventMap[K];
} & TNew;
13 changes: 13 additions & 0 deletions posthog-types/src/events/amplify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
type AmplifyDepositProperties = {
amplify_deposit_amount: number;
amplify_deposit_leverage: number;
amplify_deposit_asset: string;
amplify_deposit_pair: string;
};

export type AmplifyEvents = {
amplify_deposit_cta_clicked: AmplifyDepositProperties;
amplify_deposit_succeeded: AmplifyDepositProperties & {
amplify_last_withdrawal_quote_30_mins: number;
};
};
30 changes: 30 additions & 0 deletions posthog-types/src/events/collateral.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { NoProperties } from '../eventMap';

export type CollateralEvents = {
collateral_deposit_submitted: {
spot_market_symbol?: string;
newAccount: boolean;
depositAmount: number;
};
collateral_withdrawal_submitted: {
spot_market_symbol: string;
withdrawal_amount: string;
};
collateral_borrow_submitted: {
spot_market_symbol: string;
borrow_amount: string;
};
collateral_transfer_submitted: NoProperties;
collateral_deposit_modal_opened: {
cta: string;
from: string;
};
collateral_funxyz_address_copied: {
from_chain_id: number | string | null;
from_chain_name?: string | null;
from_asset_symbol: string | null;
to_chain: string;
to_asset_symbol: string;
receiving_address: string;
};
};
8 changes: 8 additions & 0 deletions posthog-types/src/events/earn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { NoProperties } from '../eventMap';

export type EarnEvents = {
earn_if_stake_clicked: NoProperties;
earn_vaults_clicked: NoProperties;
earn_dsol_staking_clicked: NoProperties;
earn_amplify_clicked: NoProperties;
};
14 changes: 14 additions & 0 deletions posthog-types/src/events/ifStaking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export type IfStakingEvents = {
if_staking_stake_submitted: {
spot_market_symbol: string;
};
if_staking_unstake_submitted: {
spot_market_symbol: string;
};
if_staking_unstake_canceled: {
spot_market_symbol: string;
};
if_staking_unstaked_assets_withdrawn: {
spot_market_symbol: string;
};
};
10 changes: 10 additions & 0 deletions posthog-types/src/events/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export type { CollateralEvents } from './collateral';
export type { TradeEvents } from './trade';
export type { VaultEvents } from './vault';
export type { IfStakingEvents } from './ifStaking';
export type { EarnEvents } from './earn';
export type { AmplifyEvents } from './amplify';
export type { OnboardingEvents } from './onboarding';
export type { SurveyEvents } from './survey';
export type { PnlEvents } from './pnl';
export type { SystemEvents } from './system';
40 changes: 40 additions & 0 deletions posthog-types/src/events/onboarding.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { NoProperties } from '../eventMap';

type PrivyErrorProperties = {
error_message: string;
error_stack?: string;
error_name?: string;
error_raw: string;
env: string;
wallet_address: string;
use_fee_payer: boolean;
};

export type OnboardingEvents = {
onboarding_wallet_connected: {
name: string;
};
onboarding_magic_auth_login: {
auth_type: 'email' | 'other';
success: boolean;
};
onboarding_subaccount_created: NoProperties;
onboarding_signless_modal_opened: NoProperties;
onboarding_signless_delegated_confirmed: {
success: boolean;
delegated_selected_option: string;
};
onboarding_signless_setup_succeeded: {
is_ledger: boolean;
};
onboarding_wallet_connection_error: {
provider: string;
error: unknown;
};
onboarding_referral_creation_error: {
error: unknown;
};
onboarding_privy_sign_send_error: PrivyErrorProperties;
onboarding_privy_build_sign_error: PrivyErrorProperties;
onboarding_account_deleted: NoProperties;
};
10 changes: 10 additions & 0 deletions posthog-types/src/events/pnl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export type PnlEvents = {
pnl_action_performed: {
action: 'download' | 'copy' | 'share_on_x';
};
pnl_history_exported: {
statement_type: string;
date_from: string;
date_to: string;
};
};
18 changes: 18 additions & 0 deletions posthog-types/src/events/survey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Survey events use PostHog-reserved names with spaces (not snake_case).
* These exact strings are required for PostHog's Surveys UI, response rate
* tracking, and analytics to work. Do NOT rename them.
* See: https://posthog.com/docs/surveys/implementing-custom-surveys
*/
export type SurveyEvents = {
'survey shown': {
$survey_id: string;
};
'survey dismissed': {
$survey_id: string;
};
'survey sent': {
$survey_id: string;
[key: string]: unknown;
};
};
Loading
Loading