mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-31 05:19:53 +00:00
feat: decouple auth and telemetry with event hooks
- Create authEventBus.ts with typed event hooks - Create authTracking.ts to subscribe telemetry to auth events - Remove direct telemetry imports from firebaseAuthStore - Remove useCurrentUser import from MixpanelTelemetryProvider - Breaks ~600 circular dependency cycles Amp-Thread-ID: https://ampcode.com/threads/T-019bfe73-6a29-7638-8160-8de515af8707 Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
26
src/platform/telemetry/authTracking.ts
Normal file
26
src/platform/telemetry/authTracking.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { authEventHook, userResolvedHook } from '@/stores/authEventBus'
|
||||
|
||||
import type { TelemetryProvider } from './types'
|
||||
|
||||
export function initAuthTracking(
|
||||
getTelemetry: () => TelemetryProvider | null
|
||||
): void {
|
||||
authEventHook.on((event) => {
|
||||
const telemetry = getTelemetry()
|
||||
if (!telemetry) return
|
||||
|
||||
if (event.type === 'login' || event.type === 'register') {
|
||||
telemetry.trackAuth({
|
||||
method: event.method,
|
||||
is_new_user: event.is_new_user
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
userResolvedHook.on((event) => {
|
||||
const telemetry = getTelemetry()
|
||||
if (!telemetry) return
|
||||
|
||||
telemetry.identify?.(event.userId)
|
||||
})
|
||||
}
|
||||
@@ -16,11 +16,13 @@
|
||||
*/
|
||||
import { isCloud } from '@/platform/distribution/types'
|
||||
|
||||
import { initAuthTracking } from './authTracking'
|
||||
import { MixpanelTelemetryProvider } from './providers/cloud/MixpanelTelemetryProvider'
|
||||
import type { TelemetryProvider } from './types'
|
||||
|
||||
// Singleton instance
|
||||
let _telemetryProvider: TelemetryProvider | null = null
|
||||
let _authTrackingInitialized = false
|
||||
|
||||
/**
|
||||
* Telemetry factory - conditionally creates provider based on distribution
|
||||
@@ -34,6 +36,11 @@ export function useTelemetry(): TelemetryProvider | null {
|
||||
// Use distribution check for tree-shaking
|
||||
if (isCloud) {
|
||||
_telemetryProvider = new MixpanelTelemetryProvider()
|
||||
|
||||
if (!_authTrackingInitialized) {
|
||||
initAuthTracking(() => _telemetryProvider)
|
||||
_authTrackingInitialized = true
|
||||
}
|
||||
}
|
||||
// For OSS builds, _telemetryProvider stays null
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { OverridedMixpanel } from 'mixpanel-browser'
|
||||
import { watch } from 'vue'
|
||||
|
||||
import { useCurrentUser } from '@/composables/auth/useCurrentUser'
|
||||
import {
|
||||
checkForCompletedTopup as checkTopupUtil,
|
||||
clearTopupTracking as clearTopupUtil,
|
||||
@@ -120,11 +119,6 @@ export class MixpanelTelemetryProvider implements TelemetryProvider {
|
||||
loaded: () => {
|
||||
this.isInitialized = true
|
||||
this.flushEventQueue() // flush events that were queued while initializing
|
||||
useCurrentUser().onUserResolved((user) => {
|
||||
if (this.mixpanel && user.id) {
|
||||
this.mixpanel.identify(user.id)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -205,6 +199,12 @@ export class MixpanelTelemetryProvider implements TelemetryProvider {
|
||||
)
|
||||
}
|
||||
|
||||
identify(userId: string): void {
|
||||
if (this.mixpanel) {
|
||||
this.mixpanel.identify(userId)
|
||||
}
|
||||
}
|
||||
|
||||
trackSignupOpened(): void {
|
||||
this.trackEvent(TelemetryEvents.USER_SIGN_UP_OPENED)
|
||||
}
|
||||
|
||||
@@ -272,6 +272,9 @@ export interface WorkflowCreatedMetadata {
|
||||
* Core telemetry provider interface
|
||||
*/
|
||||
export interface TelemetryProvider {
|
||||
// User identification (called by auth event hooks)
|
||||
identify?(userId: string): void
|
||||
|
||||
// Authentication flow events
|
||||
trackSignupOpened(): void
|
||||
trackAuth(metadata: AuthMetadata): void
|
||||
|
||||
16
src/stores/authEventBus.ts
Normal file
16
src/stores/authEventBus.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { createEventHook } from '@vueuse/core'
|
||||
|
||||
import type { AuthMetadata } from '@/platform/telemetry/types'
|
||||
|
||||
export interface AuthEvent extends AuthMetadata {
|
||||
type: 'login' | 'register' | 'logout' | 'password_reset'
|
||||
}
|
||||
|
||||
export interface UserResolvedEvent {
|
||||
userId: string
|
||||
email?: string | null
|
||||
displayName?: string | null
|
||||
}
|
||||
|
||||
export const authEventHook = createEventHook<AuthEvent>()
|
||||
export const userResolvedHook = createEventHook<UserResolvedEvent>()
|
||||
@@ -25,8 +25,8 @@ import { getComfyApiBaseUrl } from '@/config/comfyApi'
|
||||
import { t } from '@/i18n'
|
||||
import { WORKSPACE_STORAGE_KEYS } from '@/platform/auth/workspace/workspaceConstants'
|
||||
import { isCloud } from '@/platform/distribution/types'
|
||||
import { useTelemetry } from '@/platform/telemetry'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { authEventHook, userResolvedHook } from '@/stores/authEventBus'
|
||||
import { useApiKeyAuthStore } from '@/stores/apiKeyAuthStore'
|
||||
import type { AuthHeader } from '@/types/authTypes'
|
||||
import type { operations } from '@/types/comfyRegistryTypes'
|
||||
@@ -323,10 +323,16 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
)
|
||||
|
||||
if (isCloud) {
|
||||
useTelemetry()?.trackAuth({
|
||||
authEventHook.trigger({
|
||||
type: 'login',
|
||||
method: 'email',
|
||||
is_new_user: false
|
||||
})
|
||||
userResolvedHook.trigger({
|
||||
userId: result.user.uid,
|
||||
email: result.user.email,
|
||||
displayName: result.user.displayName
|
||||
})
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -343,10 +349,16 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
)
|
||||
|
||||
if (isCloud) {
|
||||
useTelemetry()?.trackAuth({
|
||||
authEventHook.trigger({
|
||||
type: 'register',
|
||||
method: 'email',
|
||||
is_new_user: true
|
||||
})
|
||||
userResolvedHook.trigger({
|
||||
userId: result.user.uid,
|
||||
email: result.user.email,
|
||||
displayName: result.user.displayName
|
||||
})
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -361,10 +373,16 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
if (isCloud) {
|
||||
const additionalUserInfo = getAdditionalUserInfo(result)
|
||||
const isNewUser = additionalUserInfo?.isNewUser ?? false
|
||||
useTelemetry()?.trackAuth({
|
||||
authEventHook.trigger({
|
||||
type: isNewUser ? 'register' : 'login',
|
||||
method: 'google',
|
||||
is_new_user: isNewUser
|
||||
})
|
||||
userResolvedHook.trigger({
|
||||
userId: result.user.uid,
|
||||
email: result.user.email,
|
||||
displayName: result.user.displayName
|
||||
})
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -379,10 +397,16 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
if (isCloud) {
|
||||
const additionalUserInfo = getAdditionalUserInfo(result)
|
||||
const isNewUser = additionalUserInfo?.isNewUser ?? false
|
||||
useTelemetry()?.trackAuth({
|
||||
authEventHook.trigger({
|
||||
type: isNewUser ? 'register' : 'login',
|
||||
method: 'github',
|
||||
is_new_user: isNewUser
|
||||
})
|
||||
userResolvedHook.trigger({
|
||||
userId: result.user.uid,
|
||||
email: result.user.email,
|
||||
displayName: result.user.displayName
|
||||
})
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user