diff --git a/.changeset/wrapper-build-send.md b/.changeset/wrapper-build-send.md new file mode 100644 index 000000000..7a7fd89e5 --- /dev/null +++ b/.changeset/wrapper-build-send.md @@ -0,0 +1,5 @@ +--- +'posthog': patch +--- + +Add internal APIs so wrapper SDKs can run their own `beforeSend` on the fully built event before it's sent diff --git a/build.gradle.kts b/build.gradle.kts index 2d3d940ef..b44efdd53 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -66,6 +66,8 @@ apiValidation { ignoredProjects.add("posthog-android-sample") // Pre-1.0 (0.x) module — public surface may change between minor versions until 1.0.0. ignoredProjects.add("posthog-android-surveys-compose") + // APIs only wrapper SDKs and the SDK's own modules may call; not part of the public API. + nonPublicMarkers.add("com.posthog.PostHogInternal") } nexusPublishing.postHogConfig() diff --git a/posthog-android/api/posthog-android.api b/posthog-android/api/posthog-android.api index 1749b4128..59262210a 100644 --- a/posthog-android/api/posthog-android.api +++ b/posthog-android/api/posthog-android.api @@ -58,20 +58,6 @@ public final class com/posthog/android/errortracking/PostHogNativeCrashIntegrati public fun uninstall ()V } -public final class com/posthog/android/internal/MainHandler { - public fun ()V - public fun (Landroid/os/Looper;)V - public synthetic fun (Landroid/os/Looper;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getHandler ()Landroid/os/Handler; - public final fun getMainLooper ()Landroid/os/Looper; -} - -public final class com/posthog/android/internal/PostHogAndroidUtilsKt { - public static final fun base64 (Landroid/graphics/Bitmap;Landroid/graphics/Bitmap$CompressFormat;I)Ljava/lang/String; - public static synthetic fun base64$default (Landroid/graphics/Bitmap;Landroid/graphics/Bitmap$CompressFormat;IILjava/lang/Object;)Ljava/lang/String; - public static final fun getApplicationInfo (Landroid/content/Context;)Landroid/content/pm/ApplicationInfo; -} - public abstract interface class com/posthog/android/replay/PostHogDrawableConverter { public abstract fun convert (Landroid/graphics/drawable/Drawable;)Landroid/graphics/Bitmap; } diff --git a/posthog/api/posthog.api b/posthog/api/posthog.api index dd1ef6174..389bcc9e9 100644 --- a/posthog/api/posthog.api +++ b/posthog/api/posthog.api @@ -166,17 +166,13 @@ public class com/posthog/PostHogConfig { public synthetic fun (Ljava/lang/String;Ljava/lang/String;ZZZIZLjava/util/List;ZIIIIIILcom/posthog/PostHogEncryption;Lcom/posthog/PostHogFeatureFlagsCallback;ZLkotlin/jvm/functions/Function1;ZLcom/posthog/PersonProfiles;ZLjava/net/Proxy;Lcom/posthog/surveys/PostHogSurveysConfig;Lcom/posthog/logs/PostHogLogsConfig;Lkotlin/jvm/functions/Function6;Lkotlin/jvm/functions/Function5;Lcom/posthog/errortracking/PostHogErrorTrackingConfig;Ljava/lang/String;Lcom/posthog/PostHogBootstrapConfig;Lkotlin/jvm/functions/Function3;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun addBeforeSend (Lcom/posthog/PostHogBeforeSend;)V public final fun addIntegration (Lcom/posthog/PostHogIntegration;)V - public final fun getAiStoragePrefix ()Ljava/lang/String; public final fun getBeforeSendList ()Ljava/util/List; public final fun getBootstrap ()Lcom/posthog/PostHogBootstrapConfig; - public final fun getCachePreferences ()Lcom/posthog/internal/PostHogPreferences; public final fun getCaptureAiCompression ()Lcom/posthog/PostHogCompression; public final fun getCaptureAiMaxEventBytes ()I public final fun getCaptureAiMaxQueueSize ()I public final fun getCaptureAiTimeout ()I public final fun getCompression ()Lcom/posthog/PostHogCompression; - public final fun getContext ()Lcom/posthog/internal/PostHogContext; - public final fun getDateProvider ()Lcom/posthog/internal/PostHogDateProvider; public final fun getDebug ()Z public final fun getEncryption ()Lcom/posthog/PostHogEncryption; public final fun getErrorTrackingConfig ()Lcom/posthog/errortracking/PostHogErrorTrackingConfig; @@ -187,55 +183,36 @@ public class com/posthog/PostHogConfig { public final fun getFlushIntervalSeconds ()I public final fun getGetAnonymousId ()Lkotlin/jvm/functions/Function1; public final fun getHost ()Ljava/lang/String; - public final fun getHttpClient ()Lokhttp3/OkHttpClient; public final fun getIntegrations ()Ljava/util/List; - public final fun getLegacyStoragePrefix ()Ljava/lang/String; - public final fun getLogger ()Lcom/posthog/internal/PostHogLogger; public final fun getLogs ()Lcom/posthog/logs/PostHogLogsConfig; - public final fun getLogsStoragePrefix ()Ljava/lang/String; public final fun getMaxBatchSize ()I public final fun getMaxQueueSize ()I - public final fun getNetworkStatus ()Lcom/posthog/internal/PostHogNetworkStatus; public final fun getOnFeatureFlags ()Lcom/posthog/PostHogFeatureFlagsCallback; public final fun getOptOut ()Z - public final fun getPersistOptOut ()Z public final fun getPersonProfiles ()Lcom/posthog/PersonProfiles; public final fun getPreloadFeatureFlags ()Z public final fun getProjectToken ()Ljava/lang/String; public final fun getProxy ()Ljava/net/Proxy; public final fun getPushIdentityProvider ()Lkotlin/jvm/functions/Function3; public final fun getPushNotificationSubscriptionMaxRetries ()I - public final fun getQueueProvider ()Lkotlin/jvm/functions/Function5; public final fun getReleaseIdentifier ()Ljava/lang/String; - public final fun getRemoteConfigHolder ()Lcom/posthog/internal/PostHogRemoteConfig; public final fun getRemoteConfigProvider ()Lkotlin/jvm/functions/Function6; - public final fun getReplayStoragePrefix ()Ljava/lang/String; public final fun getRequestHeaders ()Ljava/util/Map; public final fun getReuseAnonymousId ()Z - public final fun getSampleRateProvider ()Lkotlin/jvm/functions/Function0; - public final fun getSdkName ()Ljava/lang/String; - public final fun getSdkVersion ()Ljava/lang/String; public final fun getSendFeatureFlagEvent ()Z - public final fun getSerializer ()Lcom/posthog/internal/PostHogSerializer; public final fun getSessionReplay ()Z public final fun getSetDefaultPersonProperties ()Z - public final fun getSnapshotEndpoint ()Ljava/lang/String; - public final fun getStoragePrefix ()Ljava/lang/String; public final fun getSurveys ()Z public final fun getSurveysConfig ()Lcom/posthog/surveys/PostHogSurveysConfig; public final synthetic fun getTracingHeaders ()Ljava/util/List; public final fun removeBeforeSend (Lcom/posthog/PostHogBeforeSend;)V public final fun removeIntegration (Lcom/posthog/PostHogIntegration;)V - public final fun setAiStoragePrefix (Ljava/lang/String;)V public final fun setBootstrap (Lcom/posthog/PostHogBootstrapConfig;)V - public final fun setCachePreferences (Lcom/posthog/internal/PostHogPreferences;)V public final fun setCaptureAiCompression (Lcom/posthog/PostHogCompression;)V public final fun setCaptureAiMaxEventBytes (I)V public final fun setCaptureAiMaxQueueSize (I)V public final fun setCaptureAiTimeout (I)V public final fun setCompression (Lcom/posthog/PostHogCompression;)V - public final fun setContext (Lcom/posthog/internal/PostHogContext;)V - public final fun setDateProvider (Lcom/posthog/internal/PostHogDateProvider;)V public final fun setDebug (Z)V public final fun setEncryption (Lcom/posthog/PostHogEncryption;)V public final fun setEvaluationContexts (Ljava/util/List;)V @@ -244,35 +221,22 @@ public class com/posthog/PostHogConfig { public final fun setFlushAt (I)V public final fun setFlushIntervalSeconds (I)V public final fun setGetAnonymousId (Lkotlin/jvm/functions/Function1;)V - public final fun setHttpClient (Lokhttp3/OkHttpClient;)V - public final fun setLegacyStoragePrefix (Ljava/lang/String;)V - public final fun setLogger (Lcom/posthog/internal/PostHogLogger;)V public final fun setLogs (Lcom/posthog/logs/PostHogLogsConfig;)V - public final fun setLogsStoragePrefix (Ljava/lang/String;)V public final fun setMaxBatchSize (I)V public final fun setMaxQueueSize (I)V - public final fun setNetworkStatus (Lcom/posthog/internal/PostHogNetworkStatus;)V public final fun setOnFeatureFlags (Lcom/posthog/PostHogFeatureFlagsCallback;)V public final fun setOptOut (Z)V - public final fun setPersistOptOut (Z)V public final fun setPersonProfiles (Lcom/posthog/PersonProfiles;)V public final fun setPreloadFeatureFlags (Z)V public final fun setProxy (Ljava/net/Proxy;)V public final fun setPushIdentityProvider (Lkotlin/jvm/functions/Function3;)V public final fun setPushNotificationSubscriptionMaxRetries (I)V public final fun setReleaseIdentifier (Ljava/lang/String;)V - public final fun setRemoteConfigHolder (Lcom/posthog/internal/PostHogRemoteConfig;)V - public final fun setReplayStoragePrefix (Ljava/lang/String;)V public final fun setRequestHeaders (Ljava/util/Map;)V public final fun setReuseAnonymousId (Z)V - public final fun setSampleRateProvider (Lkotlin/jvm/functions/Function0;)V - public final fun setSdkName (Ljava/lang/String;)V - public final fun setSdkVersion (Ljava/lang/String;)V public final fun setSendFeatureFlagEvent (Z)V public final fun setSessionReplay (Z)V public final fun setSetDefaultPersonProperties (Z)V - public final fun setSnapshotEndpoint (Ljava/lang/String;)V - public final fun setStoragePrefix (Ljava/lang/String;)V public final fun setSurveys (Z)V public final fun setSurveysConfig (Lcom/posthog/surveys/PostHogSurveysConfig;)V public final fun setTracingHeaders (Ljava/util/List;)V @@ -365,7 +329,6 @@ public abstract interface class com/posthog/PostHogFeatureFlagsCallback { } public final class com/posthog/PostHogFeatureFlagsLoaded { - public fun (Ljava/util/Map;Z)V public final fun getErrorsLoading ()Z public final fun getFlags ()Ljava/util/List; public final fun getVariants ()Ljava/util/Map; @@ -410,7 +373,6 @@ public abstract interface class com/posthog/PostHogInterface : com/posthog/PostH public abstract fun endSession ()V public abstract fun getAllFeatureFlags ()Ljava/util/List; public abstract fun getAnonymousId ()Ljava/lang/String; - public abstract fun getConfig ()Lcom/posthog/PostHogConfig; public abstract fun getDeviceId ()Ljava/lang/String; public abstract fun getFeatureFlag (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Boolean;)Ljava/lang/Object; public static synthetic fun getFeatureFlag$default (Lcom/posthog/PostHogInterface;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Boolean;ILjava/lang/Object;)Ljava/lang/Object; @@ -501,11 +463,7 @@ public class com/posthog/PostHogStateless : com/posthog/PostHogStatelessInterfac public fun aliasStateless (Ljava/lang/String;Ljava/lang/String;)V protected final fun buildEvent (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Date;Ljava/util/Map;Ljava/util/UUID;)Lcom/posthog/PostHogEvent; public static synthetic fun buildEvent$default (Lcom/posthog/PostHogStateless;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Date;Ljava/util/Map;Ljava/util/UUID;ILjava/lang/Object;)Lcom/posthog/PostHogEvent; - protected final fun captureExceptionEvent (Ljava/lang/Throwable;Ljava/lang/String;Ljava/util/Map;Ljava/util/Date;Lkotlin/jvm/functions/Function0;)V public fun captureExceptionStateless (Ljava/lang/Throwable;Ljava/lang/String;Ljava/util/Map;)V - protected final fun captureFeatureFlagCalledEvent (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;Ljava/util/Map;)V - protected final fun captureFeatureFlagCalledEvent (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;Ljava/util/Map;Ljava/util/Map;)V - public static synthetic fun captureFeatureFlagCalledEvent$default (Lcom/posthog/PostHogStateless;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)V public fun captureStateless (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Date;)V public fun close ()V public fun debug (Z)V @@ -597,19 +555,12 @@ public abstract interface annotation class com/posthog/PostHogVisibleForTesting public final class com/posthog/errortracking/PostHogErrorTrackingAutoCaptureIntegration : com/posthog/PostHogIntegration, java/lang/Thread$UncaughtExceptionHandler { public fun (Lcom/posthog/PostHogConfig;)V - public fun (Lcom/posthog/PostHogConfig;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;)V public fun install (Lcom/posthog/PostHogInterface;)V - public final fun installWith (Lcom/posthog/errortracking/PostHogErrorTrackingAutoCaptureIntegration$CaptureTarget;)V public fun onRemoteConfig (Z)V public fun uncaughtException (Ljava/lang/Thread;Ljava/lang/Throwable;)V public fun uninstall ()V } -public abstract interface class com/posthog/errortracking/PostHogErrorTrackingAutoCaptureIntegration$CaptureTarget { - public abstract fun capture (Ljava/lang/Throwable;)V - public abstract fun flush ()V -} - public final class com/posthog/errortracking/PostHogErrorTrackingConfig { public fun ()V public fun (Z)V @@ -638,14 +589,6 @@ public final class com/posthog/errortracking/PostHogExceptionStepsConfig { public final fun setMaxBytes (I)V } -public final class com/posthog/internal/EndpointSpec { - public static final field Companion Lcom/posthog/internal/EndpointSpec$Companion; - public static final fun ai (Lcom/posthog/PostHogConfig;Lcom/posthog/internal/PostHogApi;Ljava/lang/String;)Lcom/posthog/internal/EndpointSpec; - public static final fun batch (Lcom/posthog/PostHogConfig;Lcom/posthog/internal/PostHogApi;Ljava/lang/String;)Lcom/posthog/internal/EndpointSpec; - public static final fun logs (Lcom/posthog/PostHogConfig;Lcom/posthog/internal/PostHogApi;Ljava/lang/String;)Lcom/posthog/internal/EndpointSpec; - public static final fun snapshot (Lcom/posthog/PostHogConfig;Lcom/posthog/internal/PostHogApi;Ljava/lang/String;)Lcom/posthog/internal/EndpointSpec; -} - public final class com/posthog/internal/EndpointSpec$Companion { public final fun ai (Lcom/posthog/PostHogConfig;Lcom/posthog/internal/PostHogApi;Ljava/lang/String;)Lcom/posthog/internal/EndpointSpec; public final fun batch (Lcom/posthog/PostHogConfig;Lcom/posthog/internal/PostHogApi;Ljava/lang/String;)Lcom/posthog/internal/EndpointSpec; @@ -653,304 +596,11 @@ public final class com/posthog/internal/EndpointSpec$Companion { public final fun snapshot (Lcom/posthog/PostHogConfig;Lcom/posthog/internal/PostHogApi;Ljava/lang/String;)Lcom/posthog/internal/EndpointSpec; } -public final class com/posthog/internal/EvaluationReason { - public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;)V - public final fun component1 ()Ljava/lang/String; - public final fun component2 ()Ljava/lang/String; - public final fun component3 ()Ljava/lang/Integer; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;)Lcom/posthog/internal/EvaluationReason; - public static synthetic fun copy$default (Lcom/posthog/internal/EvaluationReason;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;ILjava/lang/Object;)Lcom/posthog/internal/EvaluationReason; - public fun equals (Ljava/lang/Object;)Z - public final fun getCode ()Ljava/lang/String; - public final fun getCondition_index ()Ljava/lang/Integer; - public final fun getDescription ()Ljava/lang/String; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class com/posthog/internal/FeatureFlag { - public fun (Ljava/lang/String;ZLjava/lang/String;Lcom/posthog/internal/FeatureFlagMetadata;Lcom/posthog/internal/EvaluationReason;Ljava/lang/Boolean;)V - public synthetic fun (Ljava/lang/String;ZLjava/lang/String;Lcom/posthog/internal/FeatureFlagMetadata;Lcom/posthog/internal/EvaluationReason;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun component1 ()Ljava/lang/String; - public final fun component2 ()Z - public final fun component3 ()Ljava/lang/String; - public final fun component4 ()Lcom/posthog/internal/FeatureFlagMetadata; - public final fun component5 ()Lcom/posthog/internal/EvaluationReason; - public final fun component6 ()Ljava/lang/Boolean; - public final fun copy (Ljava/lang/String;ZLjava/lang/String;Lcom/posthog/internal/FeatureFlagMetadata;Lcom/posthog/internal/EvaluationReason;Ljava/lang/Boolean;)Lcom/posthog/internal/FeatureFlag; - public static synthetic fun copy$default (Lcom/posthog/internal/FeatureFlag;Ljava/lang/String;ZLjava/lang/String;Lcom/posthog/internal/FeatureFlagMetadata;Lcom/posthog/internal/EvaluationReason;Ljava/lang/Boolean;ILjava/lang/Object;)Lcom/posthog/internal/FeatureFlag; - public fun equals (Ljava/lang/Object;)Z - public final fun getEnabled ()Z - public final fun getFailed ()Ljava/lang/Boolean; - public final fun getKey ()Ljava/lang/String; - public final fun getMetadata ()Lcom/posthog/internal/FeatureFlagMetadata; - public final fun getReason ()Lcom/posthog/internal/EvaluationReason; - public final fun getVariant ()Ljava/lang/String; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class com/posthog/internal/FeatureFlagMetadata { - public fun (ILjava/lang/String;ILjava/lang/Boolean;Ljava/lang/String;)V - public synthetic fun (ILjava/lang/String;ILjava/lang/Boolean;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun component1 ()I - public final fun component2 ()Ljava/lang/String; - public final fun component3 ()I - public final fun component4 ()Ljava/lang/Boolean; - public final fun component5 ()Ljava/lang/String; - public final fun copy (ILjava/lang/String;ILjava/lang/Boolean;Ljava/lang/String;)Lcom/posthog/internal/FeatureFlagMetadata; - public static synthetic fun copy$default (Lcom/posthog/internal/FeatureFlagMetadata;ILjava/lang/String;ILjava/lang/Boolean;Ljava/lang/String;ILjava/lang/Object;)Lcom/posthog/internal/FeatureFlagMetadata; - public fun equals (Ljava/lang/Object;)Z - public final fun getEvaluationRuntime ()Ljava/lang/String; - public final fun getHasExperiment ()Ljava/lang/Boolean; - public final fun getId ()I - public final fun getPayload ()Ljava/lang/String; - public final fun getVersion ()I - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class com/posthog/internal/FlagConditionGroup { - public fun (Ljava/util/List;Ljava/lang/Double;Ljava/lang/String;)V - public final fun getProperties ()Ljava/util/List; - public final fun getRolloutPercentage ()Ljava/lang/Double; - public final fun getVariant ()Ljava/lang/String; -} - -public final class com/posthog/internal/FlagDefinition { - public fun (ILjava/lang/String;Ljava/lang/String;ZLcom/posthog/internal/FlagFilters;IZLjava/lang/Boolean;Ljava/lang/String;)V - public synthetic fun (ILjava/lang/String;Ljava/lang/String;ZLcom/posthog/internal/FlagFilters;IZLjava/lang/Boolean;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getActive ()Z - public final fun getEnsureExperienceContinuity ()Z - public final fun getEvaluationRuntime ()Ljava/lang/String; - public final fun getFilters ()Lcom/posthog/internal/FlagFilters; - public final fun getHasExperiment ()Ljava/lang/Boolean; - public final fun getId ()I - public final fun getKey ()Ljava/lang/String; - public final fun getName ()Ljava/lang/String; - public final fun getVersion ()I -} - -public final class com/posthog/internal/FlagFilters { - public fun (Ljava/util/List;Lcom/posthog/internal/MultiVariateConfig;Ljava/util/Map;Ljava/lang/Integer;)V - public final fun getAggregationGroupTypeIndex ()Ljava/lang/Integer; - public final fun getGroups ()Ljava/util/List; - public final fun getMultivariate ()Lcom/posthog/internal/MultiVariateConfig; - public final fun getPayloads ()Ljava/util/Map; -} - -public final class com/posthog/internal/FlagProperty { - public fun (Ljava/lang/String;Ljava/lang/Object;Lcom/posthog/internal/PropertyOperator;Lcom/posthog/internal/PropertyType;Ljava/lang/Boolean;Ljava/util/List;)V - public final fun component1 ()Ljava/lang/String; - public final fun component2 ()Ljava/lang/Object; - public final fun component3 ()Lcom/posthog/internal/PropertyOperator; - public final fun component4 ()Lcom/posthog/internal/PropertyType; - public final fun component5 ()Ljava/lang/Boolean; - public final fun component6 ()Ljava/util/List; - public final fun copy (Ljava/lang/String;Ljava/lang/Object;Lcom/posthog/internal/PropertyOperator;Lcom/posthog/internal/PropertyType;Ljava/lang/Boolean;Ljava/util/List;)Lcom/posthog/internal/FlagProperty; - public static synthetic fun copy$default (Lcom/posthog/internal/FlagProperty;Ljava/lang/String;Ljava/lang/Object;Lcom/posthog/internal/PropertyOperator;Lcom/posthog/internal/PropertyType;Ljava/lang/Boolean;Ljava/util/List;ILjava/lang/Object;)Lcom/posthog/internal/FlagProperty; - public fun equals (Ljava/lang/Object;)Z - public final fun getDependencyChain ()Ljava/util/List; - public final fun getKey ()Ljava/lang/String; - public final fun getNegation ()Ljava/lang/Boolean; - public final fun getPropertyOperator ()Lcom/posthog/internal/PropertyOperator; - public final fun getPropertyValue ()Ljava/lang/Object; - public final fun getType ()Lcom/posthog/internal/PropertyType; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class com/posthog/internal/GzipRequestInterceptor : okhttp3/Interceptor { - public fun (Lcom/posthog/PostHogConfig;)V - public fun (Lcom/posthog/PostHogConfig;Lkotlin/jvm/functions/Function0;)V - public synthetic fun (Lcom/posthog/PostHogConfig;Lkotlin/jvm/functions/Function0;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun intercept (Lokhttp3/Interceptor$Chain;)Lokhttp3/Response; -} - -public final class com/posthog/internal/LocalEvaluationApiResponse { - public static final field Companion Lcom/posthog/internal/LocalEvaluationApiResponse$Companion; - public synthetic fun (Lcom/posthog/internal/LocalEvaluationResponse;Ljava/lang/String;ZLkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getEtag ()Ljava/lang/String; - public final fun getResult ()Lcom/posthog/internal/LocalEvaluationResponse; - public final fun getWasModified ()Z -} - public final class com/posthog/internal/LocalEvaluationApiResponse$Companion { public final fun notModified (Ljava/lang/String;)Lcom/posthog/internal/LocalEvaluationApiResponse; public final fun success (Lcom/posthog/internal/LocalEvaluationResponse;Ljava/lang/String;)Lcom/posthog/internal/LocalEvaluationApiResponse; } -public final class com/posthog/internal/LocalEvaluationResponse { - public fun (Ljava/util/List;Ljava/util/Map;Ljava/util/Map;)V - public fun (Ljava/util/List;Ljava/util/Map;Ljava/util/Map;Ljava/lang/Integer;)V - public synthetic fun (Ljava/util/List;Ljava/util/Map;Ljava/util/Map;Ljava/lang/Integer;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun component1 ()Ljava/util/List; - public final fun component2 ()Ljava/util/Map; - public final fun component3 ()Ljava/util/Map; - public final fun component4 ()Ljava/lang/Integer; - public final fun copy (Ljava/util/List;Ljava/util/Map;Ljava/util/Map;Ljava/lang/Integer;)Lcom/posthog/internal/LocalEvaluationResponse; - public static synthetic fun copy$default (Lcom/posthog/internal/LocalEvaluationResponse;Ljava/util/List;Ljava/util/Map;Ljava/util/Map;Ljava/lang/Integer;ILjava/lang/Object;)Lcom/posthog/internal/LocalEvaluationResponse; - public fun equals (Ljava/lang/Object;)Z - public final fun getCohorts ()Ljava/util/Map; - public final fun getFlags ()Ljava/util/List; - public final fun getGroupTypeMapping ()Ljava/util/Map; - public final fun getPropertyMatchingVersion ()Ljava/lang/Integer; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class com/posthog/internal/LogicalOperator : java/lang/Enum { - public static final field AND Lcom/posthog/internal/LogicalOperator; - public static final field OR Lcom/posthog/internal/LogicalOperator; - public static fun getEntries ()Lkotlin/enums/EnumEntries; - public static fun valueOf (Ljava/lang/String;)Lcom/posthog/internal/LogicalOperator; - public static fun values ()[Lcom/posthog/internal/LogicalOperator; -} - -public final class com/posthog/internal/MultiVariateConfig { - public fun (Ljava/util/List;)V - public final fun component1 ()Ljava/util/List; - public final fun copy (Ljava/util/List;)Lcom/posthog/internal/MultiVariateConfig; - public static synthetic fun copy$default (Lcom/posthog/internal/MultiVariateConfig;Ljava/util/List;ILjava/lang/Object;)Lcom/posthog/internal/MultiVariateConfig; - public fun equals (Ljava/lang/Object;)Z - public final fun getVariants ()Ljava/util/List; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class com/posthog/internal/PostHogApi { - public fun (Lcom/posthog/PostHogConfig;)V - public final fun batch (Ljava/util/List;)V - public final fun flags (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/List;Z)Lcom/posthog/internal/PostHogFlagsResponse; - public static synthetic fun flags$default (Lcom/posthog/internal/PostHogApi;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/List;ZILjava/lang/Object;)Lcom/posthog/internal/PostHogFlagsResponse; - public final fun localEvaluation (Ljava/lang/String;Ljava/lang/String;)Lcom/posthog/internal/LocalEvaluationApiResponse; - public static synthetic fun localEvaluation$default (Lcom/posthog/internal/PostHogApi;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/posthog/internal/LocalEvaluationApiResponse; - public final fun pushSubscription (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V - public static synthetic fun pushSubscription$default (Lcom/posthog/internal/PostHogApi;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)V - public final fun pushUnsubscription (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V - public static synthetic fun pushUnsubscription$default (Lcom/posthog/internal/PostHogApi;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)V - public final fun remoteConfig ()Lcom/posthog/internal/PostHogRemoteConfigResponse; - public final fun snapshot (Ljava/util/List;)V -} - -public final class com/posthog/internal/PostHogApiEndpoint : java/lang/Enum { - public static final field BATCH Lcom/posthog/internal/PostHogApiEndpoint; - public static final field SNAPSHOT Lcom/posthog/internal/PostHogApiEndpoint; - public static fun getEntries ()Lkotlin/enums/EnumEntries; - public static fun valueOf (Ljava/lang/String;)Lcom/posthog/internal/PostHogApiEndpoint; - public static fun values ()[Lcom/posthog/internal/PostHogApiEndpoint; -} - -public final class com/posthog/internal/PostHogApiError : java/lang/RuntimeException { - public fun (ILjava/lang/String;Lokhttp3/ResponseBody;Ljava/lang/Integer;Ljava/lang/String;)V - public synthetic fun (ILjava/lang/String;Lokhttp3/ResponseBody;Ljava/lang/Integer;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getBody ()Lokhttp3/ResponseBody; - public final fun getErrorCode ()Ljava/lang/String; - public fun getMessage ()Ljava/lang/String; - public final fun getRetryAfterSeconds ()Ljava/lang/Integer; - public final fun getStatusCode ()I - public fun toString ()Ljava/lang/String; -} - -public abstract interface class com/posthog/internal/PostHogContext { - public abstract fun getDynamicContext ()Ljava/util/Map; - public abstract fun getSdkInfo ()Ljava/util/Map; - public abstract fun getStaticContext ()Ljava/util/Map; -} - -public abstract interface class com/posthog/internal/PostHogDateProvider { - public abstract fun addSecondsToCurrentDate (I)Ljava/util/Date; - public abstract fun currentDate ()Ljava/util/Date; - public abstract fun currentTimeMillis ()J - public abstract fun nanoTime ()J -} - -public final class com/posthog/internal/PostHogDateUtilsKt { - public static final fun formatISO8601Date (Ljava/util/Date;)Ljava/lang/String; - public static final fun parseISO8601Date (Ljava/lang/String;)Ljava/util/Date; -} - -public abstract interface class com/posthog/internal/PostHogDefaultPersonPropertiesProvider { - public abstract fun getDefaultPersonProperties ()Ljava/util/Map; -} - -public final class com/posthog/internal/PostHogDeviceDateProvider : com/posthog/internal/PostHogDateProvider { - public fun ()V - public fun addSecondsToCurrentDate (I)Ljava/util/Date; - public fun currentDate ()Ljava/util/Date; - public fun currentTimeMillis ()J - public fun nanoTime ()J -} - -public abstract interface class com/posthog/internal/PostHogFeatureFlagCalledProvider { - public abstract fun onFeatureFlagCalled (Ljava/lang/String;Ljava/lang/Object;)V -} - -public abstract interface class com/posthog/internal/PostHogFeatureFlagsInterface { - public abstract fun clear ()V - public abstract fun getEvaluatedAt (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)Ljava/lang/Long; - public static synthetic fun getEvaluatedAt$default (Lcom/posthog/internal/PostHogFeatureFlagsInterface;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Ljava/lang/Long; - public fun getFeatureFlagDetails (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)Lcom/posthog/internal/FeatureFlag; - public static synthetic fun getFeatureFlagDetails$default (Lcom/posthog/internal/PostHogFeatureFlagsInterface;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Lcom/posthog/internal/FeatureFlag; - public fun getFeatureFlagError (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)Ljava/lang/String; - public static synthetic fun getFeatureFlagError$default (Lcom/posthog/internal/PostHogFeatureFlagsInterface;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Ljava/lang/String; - public abstract fun getFeatureFlagResult (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)Lcom/posthog/FeatureFlagResult; - public static synthetic fun getFeatureFlagResult$default (Lcom/posthog/internal/PostHogFeatureFlagsInterface;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Lcom/posthog/FeatureFlagResult; - public abstract fun getFeatureFlags (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)Ljava/util/Map; - public static synthetic fun getFeatureFlags$default (Lcom/posthog/internal/PostHogFeatureFlagsInterface;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Ljava/util/Map; - public abstract fun getRequestId (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)Ljava/lang/String; - public static synthetic fun getRequestId$default (Lcom/posthog/internal/PostHogFeatureFlagsInterface;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Ljava/lang/String; - public fun isMinimalFlagCalledEventsEnabled ()Z - public fun shutDown ()V -} - -public final class com/posthog/internal/PostHogFeatureFlagsInterface$DefaultImpls { - public static synthetic fun getEvaluatedAt$default (Lcom/posthog/internal/PostHogFeatureFlagsInterface;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Ljava/lang/Long; - public static fun getFeatureFlagDetails (Lcom/posthog/internal/PostHogFeatureFlagsInterface;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)Lcom/posthog/internal/FeatureFlag; - public static synthetic fun getFeatureFlagDetails$default (Lcom/posthog/internal/PostHogFeatureFlagsInterface;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Lcom/posthog/internal/FeatureFlag; - public static fun getFeatureFlagError (Lcom/posthog/internal/PostHogFeatureFlagsInterface;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)Ljava/lang/String; - public static synthetic fun getFeatureFlagError$default (Lcom/posthog/internal/PostHogFeatureFlagsInterface;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Ljava/lang/String; - public static synthetic fun getFeatureFlagResult$default (Lcom/posthog/internal/PostHogFeatureFlagsInterface;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Lcom/posthog/FeatureFlagResult; - public static synthetic fun getFeatureFlags$default (Lcom/posthog/internal/PostHogFeatureFlagsInterface;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Ljava/util/Map; - public static synthetic fun getRequestId$default (Lcom/posthog/internal/PostHogFeatureFlagsInterface;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Ljava/lang/String; - public static fun isMinimalFlagCalledEventsEnabled (Lcom/posthog/internal/PostHogFeatureFlagsInterface;)Z - public static fun shutDown (Lcom/posthog/internal/PostHogFeatureFlagsInterface;)V -} - -public final class com/posthog/internal/PostHogFlagsResponse : com/posthog/internal/PostHogRemoteConfigResponse { - public fun (ZLjava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/Long;Ljava/lang/Boolean;)V - public synthetic fun (ZLjava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/Long;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun component1 ()Z - public final fun component2 ()Ljava/util/Map; - public final fun component3 ()Ljava/util/Map; - public final fun component4 ()Ljava/util/Map; - public final fun component5 ()Ljava/lang/String; - public final fun component6 ()Ljava/lang/Long; - public final fun component7 ()Ljava/lang/Boolean; - public final fun copy (ZLjava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/Long;Ljava/lang/Boolean;)Lcom/posthog/internal/PostHogFlagsResponse; - public static synthetic fun copy$default (Lcom/posthog/internal/PostHogFlagsResponse;ZLjava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/Long;Ljava/lang/Boolean;ILjava/lang/Object;)Lcom/posthog/internal/PostHogFlagsResponse; - public fun equals (Ljava/lang/Object;)Z - public final fun getErrorsWhileComputingFlags ()Z - public final fun getEvaluatedAt ()Ljava/lang/Long; - public final fun getFeatureFlagPayloads ()Ljava/util/Map; - public final fun getFeatureFlags ()Ljava/util/Map; - public final fun getFlags ()Ljava/util/Map; - public final fun getMinimalFlagCalledEvents ()Ljava/lang/Boolean; - public final fun getRequestId ()Ljava/lang/String; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public abstract interface class com/posthog/internal/PostHogLogger { - public abstract fun isEnabled ()Z - public abstract fun log (Ljava/lang/String;)V - public fun logWarning (Ljava/lang/String;)V -} - -public final class com/posthog/internal/PostHogLogger$DefaultImpls { - public static fun logWarning (Lcom/posthog/internal/PostHogLogger;Ljava/lang/String;)V -} - public final class com/posthog/internal/PostHogMemoryPreferences : com/posthog/internal/PostHogPreferences { public fun ()V public fun clear (Ljava/util/List;)V @@ -960,50 +610,6 @@ public final class com/posthog/internal/PostHogMemoryPreferences : com/posthog/i public fun setValue (Ljava/lang/String;Ljava/lang/Object;)V } -public abstract interface class com/posthog/internal/PostHogNetworkStatus { - public abstract fun isConnected ()Z - public fun register (Lkotlin/jvm/functions/Function0;)V - public fun unregister ()V -} - -public final class com/posthog/internal/PostHogNetworkStatus$DefaultImpls { - public static fun register (Lcom/posthog/internal/PostHogNetworkStatus;Lkotlin/jvm/functions/Function0;)V - public static fun unregister (Lcom/posthog/internal/PostHogNetworkStatus;)V -} - -public final class com/posthog/internal/PostHogNoOpLogger : com/posthog/internal/PostHogLogger { - public fun ()V - public fun isEnabled ()Z - public fun log (Ljava/lang/String;)V -} - -public abstract interface class com/posthog/internal/PostHogOnRemoteConfigLoaded { - public abstract fun loaded ()V -} - -public abstract interface class com/posthog/internal/PostHogPreferences { - public static final field ANONYMOUS_ID Ljava/lang/String; - public static final field BUILD Ljava/lang/String; - public static final field Companion Lcom/posthog/internal/PostHogPreferences$Companion; - public static final field DEVICE_ID Ljava/lang/String; - public static final field DISTINCT_ID Ljava/lang/String; - public static final field GROUPS Ljava/lang/String; - public static final field LAST_SEEN_SURVEY_DATE Ljava/lang/String; - public static final field PUSH_OPENED_MESSAGE_IDS Ljava/lang/String; - public static final field STRINGIFIED_KEYS Ljava/lang/String; - public static final field SURVEY_PROGRESS Ljava/lang/String; - public static final field SURVEY_SEEN Ljava/lang/String; - public static final field VERSION Ljava/lang/String; - public abstract fun clear (Ljava/util/List;)V - public static synthetic fun clear$default (Lcom/posthog/internal/PostHogPreferences;Ljava/util/List;ILjava/lang/Object;)V - public abstract fun getAll ()Ljava/util/Map; - public abstract fun getValue (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object; - public static synthetic fun getValue$default (Lcom/posthog/internal/PostHogPreferences;Ljava/lang/String;Ljava/lang/Object;ILjava/lang/Object;)Ljava/lang/Object; - public fun isAvailable ()Z - public abstract fun remove (Ljava/lang/String;)V - public abstract fun setValue (Ljava/lang/String;Ljava/lang/Object;)V -} - public final class com/posthog/internal/PostHogPreferences$Companion { public static final field ANONYMOUS_ID Ljava/lang/String; public static final field BUILD Ljava/lang/String; @@ -1011,7 +617,6 @@ public final class com/posthog/internal/PostHogPreferences$Companion { public static final field DISTINCT_ID Ljava/lang/String; public static final field GROUPS Ljava/lang/String; public static final field LAST_SEEN_SURVEY_DATE Ljava/lang/String; - public static final field PUSH_OPENED_MESSAGE_IDS Ljava/lang/String; public static final field STRINGIFIED_KEYS Ljava/lang/String; public static final field SURVEY_PROGRESS Ljava/lang/String; public static final field SURVEY_SEEN Ljava/lang/String; @@ -1019,81 +624,6 @@ public final class com/posthog/internal/PostHogPreferences$Companion { public final fun getALL_INTERNAL_KEYS ()Ljava/util/Set; } -public final class com/posthog/internal/PostHogPreferences$DefaultImpls { - public static synthetic fun clear$default (Lcom/posthog/internal/PostHogPreferences;Ljava/util/List;ILjava/lang/Object;)V - public static synthetic fun getValue$default (Lcom/posthog/internal/PostHogPreferences;Ljava/lang/String;Ljava/lang/Object;ILjava/lang/Object;)Ljava/lang/Object; - public static fun isAvailable (Lcom/posthog/internal/PostHogPreferences;)Z -} - -public final class com/posthog/internal/PostHogQueue : com/posthog/internal/PostHogQueueInterface { - public fun (Lcom/posthog/PostHogConfig;Lcom/posthog/internal/EndpointSpec;Ljava/util/concurrent/ExecutorService;)V - public fun add (Ljava/lang/Object;)V - public fun clear ()V - public fun flush ()V - public final fun getQueueDirectory ()Ljava/io/File; - public fun getSize ()I - public final fun reloadFromDisk ()V - public fun start ()V - public fun stop ()V -} - -public abstract interface class com/posthog/internal/PostHogQueueInterface { - public abstract fun add (Ljava/lang/Object;)V - public abstract fun clear ()V - public abstract fun flush ()V - public fun flushForShutdown ()V - public abstract fun getSize ()I - public abstract fun start ()V - public abstract fun stop ()V -} - -public final class com/posthog/internal/PostHogQueueInterface$DefaultImpls { - public static fun flushForShutdown (Lcom/posthog/internal/PostHogQueueInterface;)V -} - -public final class com/posthog/internal/PostHogRemoteConfig : com/posthog/internal/PostHogFeatureFlagsInterface { - public fun (Lcom/posthog/PostHogConfig;Lcom/posthog/internal/PostHogApi;Ljava/util/concurrent/ExecutorService;Lcom/posthog/internal/PostHogDefaultPersonPropertiesProvider;Lcom/posthog/internal/PostHogFeatureFlagCalledProvider;Lcom/posthog/internal/PostHogOnRemoteConfigLoaded;)V - public synthetic fun (Lcom/posthog/PostHogConfig;Lcom/posthog/internal/PostHogApi;Ljava/util/concurrent/ExecutorService;Lcom/posthog/internal/PostHogDefaultPersonPropertiesProvider;Lcom/posthog/internal/PostHogFeatureFlagCalledProvider;Lcom/posthog/internal/PostHogOnRemoteConfigLoaded;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun clear ()V - public final fun consumeNewlyRegisterablePushAppIds ()Ljava/util/Set; - public final fun getActiveFeatureFlagKeys ()Ljava/util/List; - public fun getEvaluatedAt (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)Ljava/lang/Long; - public final fun getEventTriggers ()Ljava/util/Set; - public final fun getFeatureFlag (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)Ljava/lang/Object; - public static synthetic fun getFeatureFlag$default (Lcom/posthog/internal/PostHogRemoteConfig;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Ljava/lang/Object; - public final fun getFeatureFlagPayload (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)Ljava/lang/Object; - public static synthetic fun getFeatureFlagPayload$default (Lcom/posthog/internal/PostHogRemoteConfig;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Ljava/lang/Object; - public fun getFeatureFlagResult (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)Lcom/posthog/FeatureFlagResult; - public fun getFeatureFlags (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)Ljava/util/Map; - public final fun getFlagDetails (Ljava/lang/String;)Lcom/posthog/internal/FeatureFlag; - public final fun getPersonPropertiesForFlags ()Ljava/util/Map; - public final fun getPushAppIds ()Ljava/util/List; - public final fun getRecordingMinimumDurationMs ()Ljava/lang/Long; - public fun getRequestId (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)Ljava/lang/String; - public final fun getSessionRecordingSampleRate ()Ljava/lang/Double; - public final fun getSurveys ()Ljava/util/List; - public final fun hasCachedErrorTrackingConfig ()Z - public final fun hasRemoteConfigFetched ()Z - public final fun isAutocaptureExceptionsEnabled ()Z - public final fun isCaptureNetworkTimingEnabled ()Z - public final fun isConsoleLogRecordingEnabled ()Z - public fun isMinimalFlagCalledEventsEnabled ()Z - public final fun isNativeCrashCaptureEnabled ()Z - public final fun isSessionReplayFlagActive ()Z - public final fun loadFeatureFlags (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function0;Lcom/posthog/PostHogFeatureFlagsCallback;)V - public static synthetic fun loadFeatureFlags$default (Lcom/posthog/internal/PostHogRemoteConfig;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function0;Lcom/posthog/PostHogFeatureFlagsCallback;ILjava/lang/Object;)V - public final fun loadRemoteConfig (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function0;Lcom/posthog/PostHogFeatureFlagsCallback;)V - public static synthetic fun loadRemoteConfig$default (Lcom/posthog/internal/PostHogRemoteConfig;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function0;Lcom/posthog/PostHogFeatureFlagsCallback;ILjava/lang/Object;)V - public final fun makeSamplingDecision (Ljava/lang/String;)Z - public final fun persistPushConfigCache ()V - public final fun resetGroupPropertiesForFlags (Ljava/lang/String;)V - public static synthetic fun resetGroupPropertiesForFlags$default (Lcom/posthog/internal/PostHogRemoteConfig;Ljava/lang/String;ILjava/lang/Object;)V - public final fun resetPersonPropertiesForFlags ()V - public final fun sessionReplayLinkedFlagSnapshot ()Lcom/posthog/internal/PostHogRemoteConfig$SessionReplayLinkedFlagSnapshot; - public final fun setGroupPropertiesForFlags (Ljava/lang/String;Ljava/util/Map;)V - public final fun setPersonPropertiesForFlags (Ljava/util/Map;)V -} - public final class com/posthog/internal/PostHogRemoteConfig$SessionReplayLinkedFlagSnapshot { public fun (ZZ)V public final fun component1 ()Z @@ -1107,129 +637,16 @@ public final class com/posthog/internal/PostHogRemoteConfig$SessionReplayLinkedF public fun toString ()Ljava/lang/String; } -public class com/posthog/internal/PostHogRemoteConfigResponse { - public fun ()V - public fun (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Boolean;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/util/List;)V - public synthetic fun (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Boolean;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getCapturePerformance ()Ljava/lang/Object; - public final fun getErrorTracking ()Ljava/lang/Object; - public final fun getHasFeatureFlags ()Ljava/lang/Boolean; - public final fun getPush ()Ljava/lang/Object; - public final fun getQuotaLimited ()Ljava/util/List; - public final fun getSessionRecording ()Ljava/lang/Object; - public final fun getSurveys ()Ljava/lang/Object; -} - -public final class com/posthog/internal/PostHogSerializer { - public fun (Lcom/posthog/PostHogConfig;)V - public final fun deserializeString (Ljava/lang/String;)Ljava/lang/Object; - public final fun getGson ()Lcom/google/gson/Gson; - public final fun serializeObject (Ljava/lang/Object;)Ljava/lang/String; -} - -public final class com/posthog/internal/PostHogSessionManager { - public static final field INSTANCE Lcom/posthog/internal/PostHogSessionManager; - public final fun endSession ()V - public final fun getActiveSessionId ()Ljava/util/UUID; - public final fun isReactNative ()Z - public final fun isSessionActive ()Z - public final fun isSessionExceedingMaxDuration (J)Z - public final fun peekSessionId ()Ljava/util/UUID; - public final fun setAppInBackground (Z)V - public final fun setDateProvider (Lcom/posthog/internal/PostHogDateProvider;)V - public final fun setReactNative (Z)V - public final fun setSessionId (Ljava/util/UUID;)V - public final fun startSession ()V - public final fun touchSession ()V -} - -public final class com/posthog/internal/PostHogThreadFactory : java/util/concurrent/ThreadFactory { - public fun (Ljava/lang/String;)V - public fun newThread (Ljava/lang/Runnable;)Ljava/lang/Thread; -} - -public final class com/posthog/internal/PostHogUtilsKt { - public static final fun executeSafely (Ljava/util/concurrent/Executor;Ljava/lang/Runnable;)V - public static final fun interruptSafely (Ljava/lang/Thread;)V - public static final fun isNetworkingError (Ljava/lang/Throwable;)Z - public static final fun logIntegrationFailure (Lcom/posthog/PostHogConfig;Ljava/lang/String;Ljava/lang/Throwable;)V - public static final fun submitSyncSafely (Ljava/util/concurrent/ExecutorService;Ljava/lang/Runnable;)V -} - -public final class com/posthog/internal/PropertyGroup { - public fun (Lcom/posthog/internal/LogicalOperator;Lcom/posthog/internal/PropertyValue;)V - public final fun component1 ()Lcom/posthog/internal/LogicalOperator; - public final fun component2 ()Lcom/posthog/internal/PropertyValue; - public final fun copy (Lcom/posthog/internal/LogicalOperator;Lcom/posthog/internal/PropertyValue;)Lcom/posthog/internal/PropertyGroup; - public static synthetic fun copy$default (Lcom/posthog/internal/PropertyGroup;Lcom/posthog/internal/LogicalOperator;Lcom/posthog/internal/PropertyValue;ILjava/lang/Object;)Lcom/posthog/internal/PropertyGroup; - public fun equals (Ljava/lang/Object;)Z - public final fun getType ()Lcom/posthog/internal/LogicalOperator; - public final fun getValues ()Lcom/posthog/internal/PropertyValue; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class com/posthog/internal/PropertyOperator : java/lang/Enum { - public static final field Companion Lcom/posthog/internal/PropertyOperator$Companion; - public static final field ENDS_WITH Lcom/posthog/internal/PropertyOperator; - public static final field EXACT Lcom/posthog/internal/PropertyOperator; - public static final field FLAG_EVALUATES_TO Lcom/posthog/internal/PropertyOperator; - public static final field GT Lcom/posthog/internal/PropertyOperator; - public static final field GTE Lcom/posthog/internal/PropertyOperator; - public static final field ICONTAINS Lcom/posthog/internal/PropertyOperator; - public static final field IN Lcom/posthog/internal/PropertyOperator; - public static final field IS_DATE_AFTER Lcom/posthog/internal/PropertyOperator; - public static final field IS_DATE_BEFORE Lcom/posthog/internal/PropertyOperator; - public static final field IS_NOT Lcom/posthog/internal/PropertyOperator; - public static final field IS_NOT_SET Lcom/posthog/internal/PropertyOperator; - public static final field IS_SET Lcom/posthog/internal/PropertyOperator; - public static final field LT Lcom/posthog/internal/PropertyOperator; - public static final field LTE Lcom/posthog/internal/PropertyOperator; - public static final field NOT_ENDS_WITH Lcom/posthog/internal/PropertyOperator; - public static final field NOT_ICONTAINS Lcom/posthog/internal/PropertyOperator; - public static final field NOT_REGEX Lcom/posthog/internal/PropertyOperator; - public static final field NOT_STARTS_WITH Lcom/posthog/internal/PropertyOperator; - public static final field REGEX Lcom/posthog/internal/PropertyOperator; - public static final field SEMVER_CARET Lcom/posthog/internal/PropertyOperator; - public static final field SEMVER_EQ Lcom/posthog/internal/PropertyOperator; - public static final field SEMVER_GT Lcom/posthog/internal/PropertyOperator; - public static final field SEMVER_GTE Lcom/posthog/internal/PropertyOperator; - public static final field SEMVER_LT Lcom/posthog/internal/PropertyOperator; - public static final field SEMVER_LTE Lcom/posthog/internal/PropertyOperator; - public static final field SEMVER_NEQ Lcom/posthog/internal/PropertyOperator; - public static final field SEMVER_TILDE Lcom/posthog/internal/PropertyOperator; - public static final field SEMVER_WILDCARD Lcom/posthog/internal/PropertyOperator; - public static final field STARTS_WITH Lcom/posthog/internal/PropertyOperator; - public static final field UNKNOWN Lcom/posthog/internal/PropertyOperator; - public static fun getEntries ()Lkotlin/enums/EnumEntries; - public static fun valueOf (Ljava/lang/String;)Lcom/posthog/internal/PropertyOperator; - public static fun values ()[Lcom/posthog/internal/PropertyOperator; -} - public final class com/posthog/internal/PropertyOperator$Companion { public final fun fromString (Ljava/lang/String;)Lcom/posthog/internal/PropertyOperator; public final fun fromStringOrNull (Ljava/lang/String;)Lcom/posthog/internal/PropertyOperator; } -public final class com/posthog/internal/PropertyType : java/lang/Enum { - public static final field COHORT Lcom/posthog/internal/PropertyType; - public static final field Companion Lcom/posthog/internal/PropertyType$Companion; - public static final field FLAG Lcom/posthog/internal/PropertyType; - public static final field PERSON Lcom/posthog/internal/PropertyType; - public static fun getEntries ()Lkotlin/enums/EnumEntries; - public static fun valueOf (Ljava/lang/String;)Lcom/posthog/internal/PropertyType; - public static fun values ()[Lcom/posthog/internal/PropertyType; -} - public final class com/posthog/internal/PropertyType$Companion { public final fun fromString (Ljava/lang/String;)Lcom/posthog/internal/PropertyType; public final fun fromStringOrNull (Ljava/lang/String;)Lcom/posthog/internal/PropertyType; } -public abstract interface class com/posthog/internal/PropertyValue { - public abstract fun isEmpty ()Z -} - public final class com/posthog/internal/PropertyValue$FlagProperties : com/posthog/internal/PropertyValue { public fun (Ljava/util/List;)V public final fun component1 ()Ljava/util/List; @@ -1254,153 +671,14 @@ public final class com/posthog/internal/PropertyValue$PropertyGroups : com/posth public fun toString ()Ljava/lang/String; } -public final class com/posthog/internal/VariantDefinition { - public fun (Ljava/lang/String;D)V - public final fun getKey ()Ljava/lang/String; - public final fun getRolloutPercentage ()D -} - -public final class com/posthog/internal/errortracking/ThrowableCoercer { - public static final field EXCEPTION_LEVEL_ATTRIBUTE Ljava/lang/String; - public static final field EXCEPTION_LEVEL_FATAL Ljava/lang/String; - public static final field MAX_EXCEPTION_LIST_SIZE I - public static final field MAX_FRAMES_PER_STACKTRACE I - public fun ()V -} - -public abstract interface class com/posthog/internal/replay/PostHogSessionReplayHandler { - public abstract fun debugProperties ()Ljava/util/Map; - public abstract fun isActive ()Z - public abstract fun onEvent (Ljava/lang/String;Ljava/util/Map;)V - public static synthetic fun onEvent$default (Lcom/posthog/internal/replay/PostHogSessionReplayHandler;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)V - public abstract fun onSessionIdChanged ()V - public abstract fun start (Z)V - public abstract fun stop ()V -} - -public final class com/posthog/internal/replay/PostHogSessionReplayHandler$DefaultImpls { - public static synthetic fun onEvent$default (Lcom/posthog/internal/replay/PostHogSessionReplayHandler;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)V -} - -public final class com/posthog/internal/replay/RRCustomEvent : com/posthog/internal/replay/RREvent { - public fun (Ljava/lang/String;Ljava/lang/Object;J)V -} - -public class com/posthog/internal/replay/RREvent { - public fun (Lcom/posthog/internal/replay/RREventType;JLjava/lang/Object;)V - public synthetic fun (Lcom/posthog/internal/replay/RREventType;JLjava/lang/Object;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getData ()Ljava/lang/Object; - public final fun getTimestamp ()J - public final fun getType ()Lcom/posthog/internal/replay/RREventType; -} - -public final class com/posthog/internal/replay/RREventType : java/lang/Enum { - public static final field Companion Lcom/posthog/internal/replay/RREventType$Companion; - public static final field Custom Lcom/posthog/internal/replay/RREventType; - public static final field DomContentLoaded Lcom/posthog/internal/replay/RREventType; - public static final field FullSnapshot Lcom/posthog/internal/replay/RREventType; - public static final field IncrementalSnapshot Lcom/posthog/internal/replay/RREventType; - public static final field Load Lcom/posthog/internal/replay/RREventType; - public static final field Meta Lcom/posthog/internal/replay/RREventType; - public static final field Plugin Lcom/posthog/internal/replay/RREventType; - public static fun getEntries ()Lkotlin/enums/EnumEntries; - public final fun getValue ()I - public static fun valueOf (Ljava/lang/String;)Lcom/posthog/internal/replay/RREventType; - public static fun values ()[Lcom/posthog/internal/replay/RREventType; -} - public final class com/posthog/internal/replay/RREventType$Companion { public final fun fromValue (I)Lcom/posthog/internal/replay/RREventType; } -public final class com/posthog/internal/replay/RRFullSnapshotEvent : com/posthog/internal/replay/RREvent { - public fun (Ljava/util/List;IIJ)V -} - -public final class com/posthog/internal/replay/RRIncrementalMouseInteractionData { - public fun (ILcom/posthog/internal/replay/RRMouseInteraction;IILcom/posthog/internal/replay/RRIncrementalSource;ILjava/util/List;)V - public synthetic fun (ILcom/posthog/internal/replay/RRMouseInteraction;IILcom/posthog/internal/replay/RRIncrementalSource;ILjava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getId ()I - public final fun getPointerType ()I - public final fun getPositions ()Ljava/util/List; - public final fun getSource ()Lcom/posthog/internal/replay/RRIncrementalSource; - public final fun getType ()Lcom/posthog/internal/replay/RRMouseInteraction; - public final fun getX ()I - public final fun getY ()I -} - -public final class com/posthog/internal/replay/RRIncrementalMouseInteractionEvent : com/posthog/internal/replay/RREvent { - public fun (Lcom/posthog/internal/replay/RRIncrementalMouseInteractionData;J)V - public synthetic fun (Lcom/posthog/internal/replay/RRIncrementalMouseInteractionData;JILkotlin/jvm/internal/DefaultConstructorMarker;)V -} - -public final class com/posthog/internal/replay/RRIncrementalMutationData { - public fun ()V - public fun (Ljava/util/List;Ljava/util/List;Ljava/util/List;Lcom/posthog/internal/replay/RRIncrementalSource;)V - public synthetic fun (Ljava/util/List;Ljava/util/List;Ljava/util/List;Lcom/posthog/internal/replay/RRIncrementalSource;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getAdds ()Ljava/util/List; - public final fun getRemoves ()Ljava/util/List; - public final fun getSource ()Lcom/posthog/internal/replay/RRIncrementalSource; - public final fun getUpdates ()Ljava/util/List; -} - -public final class com/posthog/internal/replay/RRIncrementalSnapshotEvent : com/posthog/internal/replay/RREvent { - public fun (Lcom/posthog/internal/replay/RRIncrementalMutationData;J)V - public synthetic fun (Lcom/posthog/internal/replay/RRIncrementalMutationData;JILkotlin/jvm/internal/DefaultConstructorMarker;)V -} - -public final class com/posthog/internal/replay/RRIncrementalSource : java/lang/Enum { - public static final field AdoptedStyleSheet Lcom/posthog/internal/replay/RRIncrementalSource; - public static final field CanvasMutation Lcom/posthog/internal/replay/RRIncrementalSource; - public static final field Companion Lcom/posthog/internal/replay/RRIncrementalSource$Companion; - public static final field CustomElement Lcom/posthog/internal/replay/RRIncrementalSource; - public static final field Drag Lcom/posthog/internal/replay/RRIncrementalSource; - public static final field Font Lcom/posthog/internal/replay/RRIncrementalSource; - public static final field Input Lcom/posthog/internal/replay/RRIncrementalSource; - public static final field Log Lcom/posthog/internal/replay/RRIncrementalSource; - public static final field MediaInteraction Lcom/posthog/internal/replay/RRIncrementalSource; - public static final field MouseInteraction Lcom/posthog/internal/replay/RRIncrementalSource; - public static final field MouseMove Lcom/posthog/internal/replay/RRIncrementalSource; - public static final field Mutation Lcom/posthog/internal/replay/RRIncrementalSource; - public static final field Scroll Lcom/posthog/internal/replay/RRIncrementalSource; - public static final field Selection Lcom/posthog/internal/replay/RRIncrementalSource; - public static final field StyleDeclaration Lcom/posthog/internal/replay/RRIncrementalSource; - public static final field StyleSheetRule Lcom/posthog/internal/replay/RRIncrementalSource; - public static final field TouchMove Lcom/posthog/internal/replay/RRIncrementalSource; - public static final field ViewportResize Lcom/posthog/internal/replay/RRIncrementalSource; - public static fun getEntries ()Lkotlin/enums/EnumEntries; - public final fun getValue ()I - public static fun valueOf (Ljava/lang/String;)Lcom/posthog/internal/replay/RRIncrementalSource; - public static fun values ()[Lcom/posthog/internal/replay/RRIncrementalSource; -} - public final class com/posthog/internal/replay/RRIncrementalSource$Companion { public final fun fromValue (I)Lcom/posthog/internal/replay/RRIncrementalSource; } -public final class com/posthog/internal/replay/RRMetaEvent : com/posthog/internal/replay/RREvent { - public fun (IIJLjava/lang/String;)V -} - -public final class com/posthog/internal/replay/RRMouseInteraction : java/lang/Enum { - public static final field Blur Lcom/posthog/internal/replay/RRMouseInteraction; - public static final field Click Lcom/posthog/internal/replay/RRMouseInteraction; - public static final field Companion Lcom/posthog/internal/replay/RRMouseInteraction$Companion; - public static final field ContextMenu Lcom/posthog/internal/replay/RRMouseInteraction; - public static final field DblClick Lcom/posthog/internal/replay/RRMouseInteraction; - public static final field Focus Lcom/posthog/internal/replay/RRMouseInteraction; - public static final field MouseDown Lcom/posthog/internal/replay/RRMouseInteraction; - public static final field MouseUp Lcom/posthog/internal/replay/RRMouseInteraction; - public static final field TouchCancel Lcom/posthog/internal/replay/RRMouseInteraction; - public static final field TouchEnd Lcom/posthog/internal/replay/RRMouseInteraction; - public static final field TouchMoveDeparted Lcom/posthog/internal/replay/RRMouseInteraction; - public static final field TouchStart Lcom/posthog/internal/replay/RRMouseInteraction; - public static fun getEntries ()Lkotlin/enums/EnumEntries; - public final fun getValue ()I - public static fun valueOf (Ljava/lang/String;)Lcom/posthog/internal/replay/RRMouseInteraction; - public static fun values ()[Lcom/posthog/internal/replay/RRMouseInteraction; -} - public final class com/posthog/internal/replay/RRMouseInteraction$Companion { public final fun fromValue (I)Lcom/posthog/internal/replay/RRMouseInteraction; } @@ -1414,178 +692,6 @@ public final class com/posthog/internal/replay/RRMousePosition { public final fun getY ()I } -public final class com/posthog/internal/replay/RRMutatedNode { - public fun (Lcom/posthog/internal/replay/RRWireframe;Ljava/lang/Integer;)V - public synthetic fun (Lcom/posthog/internal/replay/RRWireframe;Ljava/lang/Integer;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getParentId ()Ljava/lang/Integer; - public final fun getWireframe ()Lcom/posthog/internal/replay/RRWireframe; -} - -public final class com/posthog/internal/replay/RRPluginEvent : com/posthog/internal/replay/RREvent { - public fun (Ljava/lang/String;Ljava/util/Map;J)V -} - -public final class com/posthog/internal/replay/RRRemovedNode { - public fun (ILjava/lang/Integer;)V - public synthetic fun (ILjava/lang/Integer;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getId ()I - public final fun getParentId ()Ljava/lang/Integer; -} - -public final class com/posthog/internal/replay/RRStyle { - public fun ()V - public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun component1 ()Ljava/lang/String; - public final fun component10 ()Ljava/lang/String; - public final fun component11 ()Ljava/lang/Integer; - public final fun component12 ()Ljava/lang/Integer; - public final fun component13 ()Ljava/lang/Integer; - public final fun component14 ()Ljava/lang/Integer; - public final fun component15 ()Ljava/lang/String; - public final fun component16 ()Ljava/lang/String; - public final fun component17 ()Ljava/lang/String; - public final fun component2 ()Ljava/lang/String; - public final fun component3 ()Ljava/lang/String; - public final fun component4 ()Ljava/lang/Integer; - public final fun component5 ()Ljava/lang/Integer; - public final fun component6 ()Ljava/lang/String; - public final fun component7 ()Ljava/lang/Integer; - public final fun component8 ()Ljava/lang/String; - public final fun component9 ()Ljava/lang/String; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lcom/posthog/internal/replay/RRStyle; - public static synthetic fun copy$default (Lcom/posthog/internal/replay/RRStyle;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/posthog/internal/replay/RRStyle; - public fun equals (Ljava/lang/Object;)Z - public final fun getBackgroundColor ()Ljava/lang/String; - public final fun getBackgroundImage ()Ljava/lang/String; - public final fun getBar ()Ljava/lang/String; - public final fun getBorderColor ()Ljava/lang/String; - public final fun getBorderRadius ()Ljava/lang/Integer; - public final fun getBorderWidth ()Ljava/lang/Integer; - public final fun getColor ()Ljava/lang/String; - public final fun getFontFamily ()Ljava/lang/String; - public final fun getFontSize ()Ljava/lang/Integer; - public final fun getHorizontalAlign ()Ljava/lang/String; - public final fun getIconLeft ()Ljava/lang/String; - public final fun getIconRight ()Ljava/lang/String; - public final fun getPaddingBottom ()Ljava/lang/Integer; - public final fun getPaddingLeft ()Ljava/lang/Integer; - public final fun getPaddingRight ()Ljava/lang/Integer; - public final fun getPaddingTop ()Ljava/lang/Integer; - public final fun getVerticalAlign ()Ljava/lang/String; - public fun hashCode ()I - public final fun setBackgroundColor (Ljava/lang/String;)V - public final fun setBackgroundImage (Ljava/lang/String;)V - public final fun setBar (Ljava/lang/String;)V - public final fun setBorderColor (Ljava/lang/String;)V - public final fun setBorderRadius (Ljava/lang/Integer;)V - public final fun setBorderWidth (Ljava/lang/Integer;)V - public final fun setColor (Ljava/lang/String;)V - public final fun setFontFamily (Ljava/lang/String;)V - public final fun setFontSize (Ljava/lang/Integer;)V - public final fun setHorizontalAlign (Ljava/lang/String;)V - public final fun setIconLeft (Ljava/lang/String;)V - public final fun setIconRight (Ljava/lang/String;)V - public final fun setPaddingBottom (Ljava/lang/Integer;)V - public final fun setPaddingLeft (Ljava/lang/Integer;)V - public final fun setPaddingRight (Ljava/lang/Integer;)V - public final fun setPaddingTop (Ljava/lang/Integer;)V - public final fun setVerticalAlign (Ljava/lang/String;)V - public fun toString ()Ljava/lang/String; -} - -public final class com/posthog/internal/replay/RRUtilsKt { - public static final fun capture (Ljava/util/List;)V - public static final fun capture (Ljava/util/List;Lcom/posthog/PostHogInterface;)V - public static synthetic fun capture$default (Ljava/util/List;Lcom/posthog/PostHogInterface;ILjava/lang/Object;)V -} - -public final class com/posthog/internal/replay/RRWireframe { - public fun (IIIIILjava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;Lcom/posthog/internal/replay/RRStyle;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/Integer;Ljava/lang/Integer;)V - public synthetic fun (IIIIILjava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;Lcom/posthog/internal/replay/RRStyle;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/Integer;Ljava/lang/Integer;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun component1 ()I - public final fun component10 ()Ljava/lang/String; - public final fun component11 ()Ljava/lang/Object; - public final fun component12 ()Ljava/lang/String; - public final fun component13 ()Lcom/posthog/internal/replay/RRStyle; - public final fun component14 ()Ljava/lang/Boolean; - public final fun component15 ()Ljava/lang/Boolean; - public final fun component16 ()Ljava/util/List; - public final fun component17 ()Ljava/lang/Integer; - public final fun component18 ()Ljava/lang/Integer; - public final fun component2 ()I - public final fun component3 ()I - public final fun component4 ()I - public final fun component5 ()I - public final fun component6 ()Ljava/util/List; - public final fun component7 ()Ljava/lang/String; - public final fun component8 ()Ljava/lang/String; - public final fun component9 ()Ljava/lang/String; - public final fun copy (IIIIILjava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;Lcom/posthog/internal/replay/RRStyle;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/Integer;Ljava/lang/Integer;)Lcom/posthog/internal/replay/RRWireframe; - public static synthetic fun copy$default (Lcom/posthog/internal/replay/RRWireframe;IIIIILjava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;Lcom/posthog/internal/replay/RRStyle;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/Integer;Ljava/lang/Integer;ILjava/lang/Object;)Lcom/posthog/internal/replay/RRWireframe; - public fun equals (Ljava/lang/Object;)Z - public final fun getBase64 ()Ljava/lang/String; - public final fun getChecked ()Ljava/lang/Boolean; - public final fun getChildWireframes ()Ljava/util/List; - public final fun getDisabled ()Ljava/lang/Boolean; - public final fun getHeight ()I - public final fun getId ()I - public final fun getInputType ()Ljava/lang/String; - public final fun getLabel ()Ljava/lang/String; - public final fun getMax ()Ljava/lang/Integer; - public final fun getOptions ()Ljava/util/List; - public final fun getParentId ()Ljava/lang/Integer; - public final fun getStyle ()Lcom/posthog/internal/replay/RRStyle; - public final fun getText ()Ljava/lang/String; - public final fun getType ()Ljava/lang/String; - public final fun getValue ()Ljava/lang/Object; - public final fun getWidth ()I - public final fun getX ()I - public final fun getY ()I - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public abstract interface class com/posthog/internal/surveys/PostHogSurveysHandler { - public abstract fun onEvent (Ljava/lang/String;Ljava/util/Map;)V - public static synthetic fun onEvent$default (Lcom/posthog/internal/surveys/PostHogSurveysHandler;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)V - public abstract fun onReset ()V - public abstract fun onSurveysLoaded (Ljava/util/List;)V -} - -public final class com/posthog/internal/surveys/PostHogSurveysHandler$DefaultImpls { - public static synthetic fun onEvent$default (Lcom/posthog/internal/surveys/PostHogSurveysHandler;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)V -} - -public final class com/posthog/internal/surveys/ResolvedSurveyTranslations { - public fun (Ljava/lang/String;Lcom/posthog/surveys/SurveyTranslation;Ljava/util/List;)V - public final fun component1 ()Ljava/lang/String; - public final fun component2 ()Lcom/posthog/surveys/SurveyTranslation; - public final fun component3 ()Ljava/util/List; - public final fun copy (Ljava/lang/String;Lcom/posthog/surveys/SurveyTranslation;Ljava/util/List;)Lcom/posthog/internal/surveys/ResolvedSurveyTranslations; - public static synthetic fun copy$default (Lcom/posthog/internal/surveys/ResolvedSurveyTranslations;Ljava/lang/String;Lcom/posthog/surveys/SurveyTranslation;Ljava/util/List;ILjava/lang/Object;)Lcom/posthog/internal/surveys/ResolvedSurveyTranslations; - public fun equals (Ljava/lang/Object;)Z - public final fun getMatchedKey ()Ljava/lang/String; - public final fun getQuestions ()Ljava/util/List; - public final fun getSurvey ()Lcom/posthog/surveys/SurveyTranslation; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class com/posthog/internal/surveys/SurveyLanguageDetectionKt { - public static final fun detectSurveyLanguage (Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;)Ljava/lang/String; -} - -public final class com/posthog/internal/surveys/SurveyTranslationApplierKt { - public static final fun resolveSurveyTranslations (Lcom/posthog/surveys/Survey;Ljava/lang/String;)Lcom/posthog/internal/surveys/ResolvedSurveyTranslations; -} - -public final class com/posthog/internal/surveys/SurveyUtilsKt { - public static final fun canActivateRepeatedly (Lcom/posthog/surveys/Survey;)Z - public static final fun hasEvents (Lcom/posthog/surveys/Survey;)Z - public static final fun hasWaitPeriodPassed (Lcom/posthog/surveys/Survey;Ljava/util/Date;Ljava/util/Date;)Z -} - public abstract interface class com/posthog/logs/PostHogBeforeSendLog { public abstract fun run (Lcom/posthog/logs/PostHogLogRecord;)Lcom/posthog/logs/PostHogLogRecord; } @@ -2418,9 +1524,3 @@ public final class com/posthog/surveys/SurveyType$Companion { public final fun fromValue (Ljava/lang/String;)Lcom/posthog/surveys/SurveyType; } -public final class com/posthog/vendor/uuid/TimeBasedEpochGenerator { - public static final field INSTANCE Lcom/posthog/vendor/uuid/TimeBasedEpochGenerator; - public final fun generate ()Ljava/util/UUID; - public final fun setDateProvider (Lcom/posthog/internal/PostHogDateProvider;)V -} - diff --git a/posthog/src/main/java/com/posthog/PostHog.kt b/posthog/src/main/java/com/posthog/PostHog.kt index ea0a756d9..58aeb49cb 100644 --- a/posthog/src/main/java/com/posthog/PostHog.kt +++ b/posthog/src/main/java/com/posthog/PostHog.kt @@ -65,6 +65,20 @@ private val REQUIRED_REPLAY_DEBUG_PROPERTY_KEYS = "\$sdk_debug_replay_internal_buffer_length", ) +// On every event whether or not the bundle is claimed; the rest of the bundle needs the claim. +private val UNTHROTTLED_DEBUG_PROPERTY_KEYS = + REQUIRED_REPLAY_DEBUG_PROPERTY_KEYS + setOf("\$sdk_debug_pending_queue_size", "\$sdk_debug_error_capturing_properties") + +// Wrapper builds waiting for their send, and recent sends. A build the wrapper drops is evicted by +// newer ones; an evicted build can no longer be sent. +private const val MAX_TRACKED_WRAPPER_EVENTS = 1000 + +private fun requiresPersonProcessing( + userProperties: Map?, + userPropertiesSetOnce: Map?, + groups: Map?, +): Boolean = userProperties?.isEmpty() == false || userPropertiesSetOnce?.isEmpty() == false || groups?.isEmpty() == false + private fun isReplayDebugEvent(event: String): Boolean = event.startsWith("\$") && event != PostHogEventName.FEATURE_FLAG_CALLED.event && @@ -129,6 +143,15 @@ public class PostHog private constructor( private var lastReplayDebugPropertiesAt: Long? = null private var replayDebugClaimOutstanding = false + // Keyed by event uuid in build order. Both guarded by pendingWrapperBuilds. + private val pendingWrapperBuilds = LinkedHashMap() + private val sentWrapperEvents = LinkedHashSet() + + // Incremented by reset(), so a send can tell the user changed since the build even when + // reuseAnonymousId keeps the distinct id the same. + @Volatile + private var resetGeneration = 0L + private var replayQueue: PostHogQueueInterface? = null private var logsQueue: PostHogQueueInterface? = null @@ -388,6 +411,7 @@ public class PostHog private constructor( applyBootstrapIfNeeded(config) + clearWrapperBuilds() super.enabled = true // Initialize device_id if not already set. getDeviceId() handles lazy init @@ -667,6 +691,7 @@ public class PostHog private constructor( featureFlagsCalled.clear() lastScreenName = null + clearWrapperBuilds() synchronized(replayDebugPropertiesLock) { lastReplayDebugPropertiesAt = null replayDebugClaimOutstanding = false @@ -771,6 +796,7 @@ public class PostHog private constructor( appendGroups: Boolean = true, timestamp: Date? = null, claimReplayDebugBundle: () -> Boolean = { false }, + readReplayDebugProperties: () -> Map = ::readReplayDebugProperties, ): MutableMap { val props = mutableMapOf() @@ -839,7 +865,7 @@ public class PostHog private constructor( if (appendSharedProps) { // After session resolution so the debug snapshot never precedes a rotation triggered by // getActiveSessionId() above. - props.putAll(sdkDebugProperties(sessionIdString, timestamp, claimReplayDebugBundle)) + props.putAll(sdkDebugProperties(sessionIdString, timestamp, claimReplayDebugBundle, readReplayDebugProperties)) // Registered super properties win over everything the SDK set above. val registeredPrefs = getPreferences().getAll() @@ -880,10 +906,14 @@ public class PostHog private constructor( return props } + private fun readReplayDebugProperties(): Map = + sessionReplayHandler?.debugProperties() ?: mapOf("\$recording_status" to "disabled") + private fun sdkDebugProperties( sessionId: String?, timestamp: Date?, claimReplayDebugBundle: () -> Boolean, + readReplayDebugProperties: () -> Map = ::readReplayDebugProperties, ): Map { val props = mutableMapOf() val managerStart = PostHogSessionManager.getSessionStartedAt() @@ -896,7 +926,7 @@ public class PostHog private constructor( // Guarded separately from the session and queue keys below: those come from the session // manager and the queue, not from replay, so a handler that throws must not suppress them. try { - val replayProps = sessionReplayHandler?.debugProperties() ?: mapOf("\$recording_status" to "disabled") + val replayProps = readReplayDebugProperties() if (claimed) { props.putAll(replayProps) } else { @@ -976,15 +1006,20 @@ public class PostHog private constructor( * Adds `process_person_profile: false` when the SDK doesn't process person profiles for this * event, unless the caller set that option or [properties] carry a non-null legacy * `$process_person_profile` property (per call or registered). Nothing is added otherwise: - * PostHog processes person profiles by default. Returns a copy, so `beforeSend` edits never - * reach the caller's map. + * PostHog processes person profiles by default. [personProcessingPending] counts a person + * processing change a wrapper build defers to its send. Returns a copy, so `beforeSend` edits + * never reach the caller's map. */ private fun personProcessingOptions( options: Map?, properties: Map, + personProcessingPending: Boolean = false, ): MutableMap? { val eventOptions = options?.toMutableMap() - if (hasPersonProcessing() || properties["\$process_person_profile"] != null) { + if ((personProcessingPending && config?.personProfiles != PersonProfiles.NEVER) || + hasPersonProcessing() || + properties["\$process_person_profile"] != null + ) { return eventOptions } val result = eventOptions ?: mutableMapOf() @@ -1104,132 +1139,398 @@ public class PostHog private constructor( // or replacing the event. var claimedReplayDebugBundle = false try { - if (!isEnabled()) { + val prepared = + prepareEvent( + event, + distinctId, + properties, + userProperties, + userPropertiesSetOnce, + groups, + timestamp, + options, + aiLane, + claimReplayDebugBundle = { claimReplayDebugPropertiesWindow().also { claimedReplayDebugBundle = it } }, + ) ?: return null + val postHogEvent = runBeforeSend(prepared.event, prepared.event.uuid) + if (postHogEvent == null) { + logDroppedEvent(event) return null } - if (isOptedOut()) { - config?.logger?.log("PostHog is in OptOut state.") - return null + return enqueueEvent(postHogEvent, event, prepared.mergedProperties, aiLane) { + if (claimedReplayDebugBundle) { + commitReplayDebugPropertiesWindow() + } + } + } catch (e: Throwable) { + config?.logger?.log("Capture failed: $e.") + return null + } finally { + if (claimedReplayDebugBundle) { + releaseReplayDebugPropertiesClaim() } + } + } - // A blank distinct ID falls back to the current one, like null, instead of PostHog dropping the event. - val newDistinctId = distinctId?.takeIf { it.isNotBlank() } ?: this.distinctId + /** + * An event enriched for capture, before the `beforeSend` chain runs. + * + * @property mergedProperties the enriched properties before the `$feature_flag_called` + * minimization, which the surveys and replay handlers read. + */ + private class PreparedEvent( + val event: PostHogEvent, + val mergedProperties: Map, + ) - // if the user isn't identified but passed userProperties, userPropertiesSetOnce or groups, - // we should still enable person processing since this is intentional - if (userProperties?.isEmpty() == false || userPropertiesSetOnce?.isEmpty() == false || groups?.isEmpty() == false) { - requirePersonProcessing("capture", ignoreMessage = true) - } + /** + * What [buildEventForWrapper] decided from the call, read back by [sendBuiltEventForWrapper]: + * the wrapper's hook can rename the event, and a build changes no SDK state. + * [deferredReplayDebug] holds the replay debug values from the build, sent only if the send + * claims the window; null when the event can't carry them. + */ + private class WrapperBuild( + val deferredReplayDebug: Map?, + val requiresPersonProcessing: Boolean, + val sdkDistinctId: String, + val resetGeneration: Long, + ) - // Automatically set person properties for feature flags during capture event + /** + * Checks and enriches one event without running `beforeSend` or queueing it. Returns null when + * the SDK wouldn't capture it. [claimReplayDebugBundle] is called only for events that may carry + * the replay debug bundle. + */ + private fun prepareEvent( + event: String, + distinctId: String?, + properties: Map?, + userProperties: Map?, + userPropertiesSetOnce: Map?, + groups: Map?, + timestamp: Date?, + options: Map?, + aiLane: Boolean, + claimReplayDebugBundle: () -> Boolean, + readReplayDebugProperties: () -> Map = ::readReplayDebugProperties, + setFlagPersonProperties: Boolean = true, + deferPersonProcessing: Boolean = false, + ): PreparedEvent? { + if (!isEnabled()) { + return null + } + if (isOptedOut()) { + config?.logger?.log("PostHog is in OptOut state.") + return null + } + + // A blank distinct ID falls back to the current one, like null, instead of PostHog dropping the event. + val newDistinctId = distinctId?.takeIf { it.isNotBlank() } ?: this.distinctId + + // if the user isn't identified but passed userProperties, userPropertiesSetOnce or groups, + // we should still enable person processing since this is intentional + val requiresPersonProcessing = requiresPersonProcessing(userProperties, userPropertiesSetOnce, groups) + if (requiresPersonProcessing && !deferPersonProcessing) { + requirePersonProcessing("capture", ignoreMessage = true) + } + + // Automatically set person properties for feature flags during capture event + if (setFlagPersonProperties) { setPersonPropertiesForFlagsIfNeeded(userProperties, userPropertiesSetOnce) + } - if (newDistinctId.isBlank()) { - config?.logger?.log("capture call not allowed, distinctId is invalid: $newDistinctId.") - return null + if (newDistinctId.isBlank()) { + config?.logger?.log("capture call not allowed, distinctId is invalid: $newDistinctId.") + return null + } + + // The AI lane always uses its own queue. + val isSnapshotEvent = !aiLane && event == PostHogEventName.SNAPSHOT.event + var groupIdentify = false + if (event == PostHogEventName.GROUP_IDENTIFY.event) { + groupIdentify = true + } + + // Externally-built $exception events (e.g. the Flutter/RN bridge) carry only + // serialized class names, so they are matched by name instead of isInstance. + val ignored = config?.errorTrackingConfig?.ignoredExceptionTypes + if (!ignored.isNullOrEmpty() && + event == PostHogEventName.EXCEPTION.event && + hasIgnoredTypeInExceptionList(properties, ignored) + ) { + config?.logger?.log( + "Skipping \$exception: an entry in \$exception_list matches ignoredExceptionTypes", + ) + return null + } + + // Attach the buffered exception steps to any $exception event (unless the caller + // already supplied them), so externally-built exceptions (e.g. from the Flutter/RN + // bridge) carry steps too, not only those captured via captureException(throwable). + val stepsBuffer = exceptionStepsBuffer + val effectiveProperties = + if (event == PostHogEventName.EXCEPTION.event && stepsBuffer != null) { + val mutableProperties = properties?.toMutableMap() ?: mutableMapOf() + stepsBuffer.attachTo(mutableProperties) + mutableProperties + } else { + properties } - // The AI lane always uses its own queue. - var isSnapshotEvent = !aiLane && event == PostHogEventName.SNAPSHOT.event - var groupIdentify = false - if (event == PostHogEventName.GROUP_IDENTIFY.event) { - groupIdentify = true + val mergedProperties = + buildProperties( + newDistinctId, + properties = effectiveProperties, + userProperties = userProperties, + userPropertiesSetOnce = userPropertiesSetOnce, + groups = groups, + // only append shared props if not a snapshot event + appendSharedProps = !isSnapshotEvent, + // only append groups if not a group identify event and not a snapshot + appendGroups = !groupIdentify, + timestamp = timestamp, + claimReplayDebugBundle = { isReplayDebugEvent(event) && claimReplayDebugBundle() }, + readReplayDebugProperties = readReplayDebugProperties, + ) + + val eventProperties = minimizeIfFeatureFlagCalled(event, mergedProperties) + + // Snapshots don't carry the SDK's person-processing option. + val eventOptions = + if (isSnapshotEvent) { + options?.toMutableMap() + } else { + personProcessingOptions(options, mergedProperties, deferPersonProcessing && requiresPersonProcessing) } - // Externally-built $exception events (e.g. the Flutter/RN bridge) carry only - // serialized class names, so they are matched by name instead of isInstance. - val ignored = config?.errorTrackingConfig?.ignoredExceptionTypes - if (!ignored.isNullOrEmpty() && - event == PostHogEventName.EXCEPTION.event && - hasIgnoredTypeInExceptionList(properties, ignored) - ) { - config?.logger?.log( - "Skipping \$exception: an entry in \$exception_list matches ignoredExceptionTypes", - ) - return null + // This capture's identity, kept through beforeSend. + val uuid = TimeBasedEpochGenerator.generate() + return PreparedEvent(newEvent(event, newDistinctId, eventProperties, timestamp, eventOptions, uuid), mergedProperties) + } + + private fun logDroppedEvent(event: String) { + val originalMessage = "PostHog event $event was dropped" + val message = + if (PostHogEventName.isUnsafeEditable(event)) { + "$originalMessage. This can cause unexpected behavior." + } else { + originalMessage } + config?.logger?.log(message) + } - // Attach the buffered exception steps to any $exception event (unless the caller - // already supplied them), so externally-built exceptions (e.g. from the Flutter/RN - // bridge) carry steps too, not only those captured via captureException(throwable). - val stepsBuffer = exceptionStepsBuffer - val effectiveProperties = - if (event == PostHogEventName.EXCEPTION.event && stepsBuffer != null) { - val mutableProperties = properties?.toMutableMap() ?: mutableMapOf() - stepsBuffer.attachTo(mutableProperties) - mutableProperties + /** + * Queues [postHogEvent], already through `beforeSend`, on its lane and notifies the surveys and + * replay handlers with [event] and [mergedProperties] from before the hook. Returns the event's + * uuid when it's queued. [onQueued] runs right after the event is added to the analytics or AI + * queue. + */ + private fun enqueueEvent( + postHogEvent: PostHogEvent, + event: String, + mergedProperties: Map, + aiLane: Boolean, + onQueued: () -> Unit = {}, + ): UUID? { + // Reevaluate if this is a snapshot event because the event might have been updated by the beforeSend hook + val isSnapshotEvent = !aiLane && postHogEvent.event == PostHogEventName.SNAPSHOT.event + // if this is a $snapshot event and $session_id is missing, don't process then event + if (isSnapshotEvent && postHogEvent.properties?.get("\$session_id") == null) { + config?.logger?.log("${postHogEvent.event} event dropped, because the \$session_id property is missing") + return null + } + // Replay has its own queue + if (isSnapshotEvent) { + replayQueue?.add(postHogEvent) + return postHogEvent.uuid + } + val targetQueue = if (aiLane) aiQueue ?: return null else queue + var queued = false + // beforeSend may have opted out + if (isOptedOut()) { + config?.logger?.log("PostHog is in OptOut state.") + } else if (aiLane && isOverAiEventLimit(postHogEvent)) { + // dropped here rather than in the queue, so captureAi returns null + } else if (targetQueue != null) { + targetQueue.add(postHogEvent) + queued = true + onQueued() + } + // Notify surveys integration about the event + surveysHandler?.onEvent(event, mergedProperties) + // Notify session replay handler about the event for event triggers + sessionReplayHandler?.onEvent(event, mergedProperties) + return if (queued) postHogEvent.uuid else null + } + + @PostHogInternal + override fun buildEventForWrapper( + event: String, + distinctId: String?, + properties: Map?, + userProperties: Map?, + userPropertiesSetOnce: Map?, + groups: Map?, + options: Map?, + ai: Boolean, + timestamp: Date?, + ): PostHogEvent? { + try { + if (!isEnabled()) { + return null + } + // The wrapper may drop the event after this, so state changes wait for the send. + val eventProperties = + if (!ai && event == PostHogEventName.SCREEN.event) { + val screenTitle = properties?.get("\$screen_name") as? String ?: return null + screenProperties(screenTitle, properties, cacheScreenName = false) ?: return null } else { properties } + // One replay read for the build's required keys and the deferred bundle, so a replay + // transition between them can't pair keys from two different states. + val replayDebugSnapshot by lazy { runCatching { readReplayDebugProperties() } } + val readReplayDebugSnapshot = { replayDebugSnapshot.getOrThrow() } + val built = + prepareEvent( + event, + distinctId, + eventProperties, + userProperties, + userPropertiesSetOnce, + groups, + timestamp, + options, + ai, + claimReplayDebugBundle = { false }, + readReplayDebugProperties = readReplayDebugSnapshot, + setFlagPersonProperties = false, + deferPersonProcessing = true, + )?.event ?: return null + built.uuid?.let { uuid -> + // Snapshotted now, so a new session during the round trip doesn't change them. + val deferredReplayDebug = + if (isReplayDebugEvent(event)) { + sdkDebugProperties( + built.properties?.get("\$session_id") as? String, + built.timestamp, + claimReplayDebugBundle = { true }, + readReplayDebugProperties = readReplayDebugSnapshot, + ) + .filterKeys { it !in UNTHROTTLED_DEBUG_PROPERTY_KEYS } + .takeIf { it.isNotEmpty() } + } else { + null + } + val build = + WrapperBuild( + deferredReplayDebug = deferredReplayDebug, + requiresPersonProcessing = requiresPersonProcessing(userProperties, userPropertiesSetOnce, groups), + sdkDistinctId = this.distinctId, + resetGeneration = resetGeneration, + ) + synchronized(pendingWrapperBuilds) { + pendingWrapperBuilds[uuid] = build + if (pendingWrapperBuilds.size > MAX_TRACKED_WRAPPER_EVENTS) { + pendingWrapperBuilds.remove(pendingWrapperBuilds.keys.first()) + } + } + } + return built + } catch (e: Throwable) { + config?.logger?.log("Capture failed: $e.") + return null + } + } - val mergedProperties = - buildProperties( - newDistinctId, - properties = effectiveProperties, - userProperties = userProperties, - userPropertiesSetOnce = userPropertiesSetOnce, - groups = groups, - // only append shared props if not a snapshot event - appendSharedProps = !isSnapshotEvent, - // only append groups if not a group identify event and not a snapshot - appendGroups = !groupIdentify, - timestamp = timestamp, - claimReplayDebugBundle = { - isReplayDebugEvent(event) && claimReplayDebugPropertiesWindow().also { claimedReplayDebugBundle = it } - }, - ) - - val eventProperties = minimizeIfFeatureFlagCalled(event, mergedProperties) - - // Snapshots don't carry the SDK's person-processing option. - val eventOptions = - if (isSnapshotEvent) options?.toMutableMap() else personProcessingOptions(options, mergedProperties) + private fun clearWrapperBuilds() { + synchronized(pendingWrapperBuilds) { + pendingWrapperBuilds.clear() + } + } - // This capture's identity, kept through beforeSend. - val uuid = TimeBasedEpochGenerator.generate() - val postHogEvent = buildEvent(event, newDistinctId, eventProperties, timestamp, eventOptions, uuid) - if (postHogEvent == null) { - val originalMessage = "PostHog event $event was dropped" - val message = - if (PostHogEventName.isUnsafeEditable(event)) { - "$originalMessage. This can cause unexpected behavior." - } else { - originalMessage + @PostHogInternal + override fun sendBuiltEventForWrapper( + event: PostHogEvent, + ai: Boolean, + ): UUID? { + var claimedReplayDebugBundle = false + try { + var alreadySent = false + val build = + event.uuid?.let { uuid -> + synchronized(pendingWrapperBuilds) { + // Checked and recorded together, so two concurrent sends can't both queue it. + alreadySent = !sentWrapperEvents.add(uuid) + if (sentWrapperEvents.size > MAX_TRACKED_WRAPPER_EVENTS) { + sentWrapperEvents.remove(sentWrapperEvents.first()) + } + pendingWrapperBuilds.remove(uuid) } - config?.logger?.log(message) + } + if (alreadySent) { + config?.logger?.log("Event ${event.uuid} was already sent.") return null } - // Reevaluate if this is a snapshot event because the event might have been updated by the beforeSend hook - isSnapshotEvent = !aiLane && postHogEvent.event == PostHogEventName.SNAPSHOT.event - // if this is a $snapshot event and $session_id is missing, don't process then event - if (isSnapshotEvent && postHogEvent.properties?.get("\$session_id") == null) { - config?.logger?.log("${postHogEvent.event} event dropped, because the \$session_id property is missing") + // Builds are cleared on setup() and close() and kept per instance, so this also drops an + // event built by another instance or before a reconfigure. + if (build == null) { + config?.logger?.log("Event ${event.event} wasn't built by buildEventForWrapper on this setup, so it was dropped.") return null } - // Replay has its own queue - if (isSnapshotEvent) { - replayQueue?.add(postHogEvent) - return uuid + if (!isEnabled()) { + return null } - val targetQueue = if (aiLane) aiQueue ?: return null else queue - var queued = false - // beforeSend may have opted out if (isOptedOut()) { config?.logger?.log("PostHog is in OptOut state.") - } else if (aiLane && isOverAiEventLimit(postHogEvent)) { - // dropped here rather than in the queue, so captureAi returns null - } else if (targetQueue != null) { - targetQueue.add(postHogEvent) - queued = true + return null + } + // Person processing and flag person properties apply only while the SDK still has the + // identity the event was built for: after a reset() or identify(), it belongs to the previous one. + val sameIdentity = build.sdkDistinctId == this.distinctId && build.resetGeneration == resetGeneration + if (sameIdentity && build.requiresPersonProcessing) { + requirePersonProcessing("capture", ignoreMessage = true) + } + val uuid = event.uuid + val properties = event.properties ?: mutableMapOf() + if (sameIdentity) { + @Suppress("UNCHECKED_CAST") + setPersonPropertiesForFlagsIfNeeded( + properties["\$set"] as? Map, + properties["\$set_once"] as? Map, + ) + } + // A reset() since the build cleared the screen name, so the old one isn't restored. + if (!ai && build.resetGeneration == resetGeneration && event.event == PostHogEventName.SCREEN.event) { + (properties["\$screen_name"] as? String)?.trim()?.takeIf { it.isNotEmpty() }?.let { cacheScreenName(it) } + } + // The build added only the required replay debug keys. The window is claimed here, so a + // built event the wrapper drops never holds or starts it. Eligibility and values come from + // the build, since the wrapper's hook can rename the event and the session can change. + val deferredReplayDebug = build.deferredReplayDebug + if (deferredReplayDebug != null && claimReplayDebugPropertiesWindow()) { + claimedReplayDebugBundle = true + // Only keys the event lacks, so the wrapper's values win. + deferredReplayDebug.forEach { (key, value) -> + if (!properties.containsKey(key)) { + properties[key] = value + } + } + } + val builtEvent = if (event.properties == null) event.copy(properties = properties) else event + // Copied before the hooks run, which can change the map in place. + val handlerProperties = + if (surveysHandler != null || sessionReplayHandler != null) properties.toMap() else emptyMap() + val postHogEvent = runBeforeSend(builtEvent, uuid) + if (postHogEvent == null) { + logDroppedEvent(builtEvent.event) + return null + } + return enqueueEvent(postHogEvent, builtEvent.event, handlerProperties, ai) { if (claimedReplayDebugBundle) { commitReplayDebugPropertiesWindow() } } - // Notify surveys integration about the event - surveysHandler?.onEvent(event, mergedProperties) - // Notify session replay handler about the event for event triggers - sessionReplayHandler?.onEvent(event, mergedProperties) - return if (queued) uuid else null } catch (e: Throwable) { config?.logger?.log("Capture failed: $e.") return null @@ -1602,16 +1903,28 @@ public class PostHog private constructor( return } + val props = screenProperties(screenTitle, properties) ?: return + + capture(PostHogEventName.SCREEN.event, properties = props, options = options) + } + + /** + * Caches [screenTitle], trimmed, as the current screen and returns [properties] with it as + * `$screen_name`. Returns null for a blank title. + */ + private fun screenProperties( + screenTitle: String, + properties: Map?, + cacheScreenName: Boolean = true, + ): MutableMap? { val trimmedTitle = screenTitle.trim() if (trimmedTitle.isEmpty()) { - return + return null } - if (lastScreenName != trimmedTitle) config.notifyIntegrationsChanged() - - // Cache for capture-time context snapshot on log records and for the - // $screen_name auto-attach on subsequent events (see buildProperties). - this.lastScreenName = trimmedTitle + if (cacheScreenName) { + cacheScreenName(trimmedTitle) + } val props = mutableMapOf() properties?.let { @@ -1620,8 +1933,14 @@ public class PostHog private constructor( // The title wins over a caller-supplied $screen_name, matching the cached value. props["\$screen_name"] = trimmedTitle + return props + } - capture(PostHogEventName.SCREEN.event, properties = props, options = options) + // Cache for capture-time context snapshot on log records and for the + // $screen_name auto-attach on subsequent events (see buildProperties). + private fun cacheScreenName(screenName: String) { + if (lastScreenName != screenName) config.notifyIntegrationsChanged() + this.lastScreenName = screenName } public override fun alias( @@ -2368,6 +2687,7 @@ public class PostHog private constructor( } config.notifyIntegrationsChanged() + resetGeneration++ // Capture the logging-out identity before preferences are cleared, so the push token can be // unregistered for it and re-registered under the new anonymous id (decision 5/6). val previousDistinctId = distinctId @@ -3078,6 +3398,36 @@ public class PostHog private constructor( return shared.getConfig() } + @PostHogInternal + override fun buildEventForWrapper( + event: String, + distinctId: String?, + properties: Map?, + userProperties: Map?, + userPropertiesSetOnce: Map?, + groups: Map?, + options: Map?, + ai: Boolean, + timestamp: Date?, + ): PostHogEvent? = + shared.buildEventForWrapper( + event, + distinctId = distinctId, + properties = properties, + userProperties = userProperties, + userPropertiesSetOnce = userPropertiesSetOnce, + groups = groups, + options = options, + ai = ai, + timestamp = timestamp, + ) + + @PostHogInternal + override fun sendBuiltEventForWrapper( + event: PostHogEvent, + ai: Boolean, + ): UUID? = shared.sendBuiltEventForWrapper(event, ai) + override fun isSessionActive(): Boolean { return shared.isSessionActive() } diff --git a/posthog/src/main/java/com/posthog/PostHogInterface.kt b/posthog/src/main/java/com/posthog/PostHogInterface.kt index 108335003..9d116baca 100644 --- a/posthog/src/main/java/com/posthog/PostHogInterface.kt +++ b/posthog/src/main/java/com/posthog/PostHogInterface.kt @@ -577,4 +577,68 @@ public interface PostHogInterface : PostHogCoreInterface { @PostHogInternal public fun getConfig(): T? + + /** + * For wrapper SDKs only (Flutter, React Native); apps use [capture] and [captureAi]. + * + * Builds the event that [capture] (or [captureAi] when [ai] is true) would send: the same + * checks, SDK and registered properties, per-call values, session, screen and options, with a + * new uuid and timestamp. It doesn't run `beforeSend` and doesn't queue the event, so a wrapper + * can run its own hook on the full event, then pass the result to [sendBuiltEventForWrapper]. + * It changes no SDK state, so a wrapper can drop the event: the current screen, the person + * properties used for flags, person processing turned on by [userProperties], + * [userPropertiesSetOnce] or [groups], and the replay debug window are updated by + * [sendBuiltEventForWrapper]. That send uses the event name passed here to decide whether the + * replay debug bundle applies, even if the wrapper's hook renamed the event. + * + * Returns null when the SDK wouldn't capture the event: disabled, opted out, an ignored + * exception type, or a `$screen` event (not on the AI lane) without a non-blank `$screen_name`. Defaults to null. + * + * ```kotlin + * val event = PostHog.buildEventForWrapper("purchase", properties = mapOf("plan" to "pro")) + * ?: return + * PostHog.sendBuiltEventForWrapper(wrapperBeforeSend(event) ?: return) + * ``` + * + * @suppress + */ + @PostHogInternal + public fun buildEventForWrapper( + event: String, + distinctId: String? = null, + properties: Map? = null, + userProperties: Map? = null, + userPropertiesSetOnce: Map? = null, + groups: Map? = null, + options: Map? = null, + ai: Boolean = false, + timestamp: Date? = null, + ): PostHogEvent? = null + + /** + * For wrapper SDKs only (Flutter, React Native); apps use [capture] and [captureAi]. + * + * Sends an event from [buildEventForWrapper] without adding properties again: runs the native + * `beforeSend` chain, then queues it on the analytics lane, or the AI lane when [ai] is true. + * The event keeps its uuid and timestamp. Legacy option properties are moved into options when + * the event is sent, as for [capture]. + * Surveys and session replay event triggers see [event] as passed in, after the wrapper's hook. + * Like [capture], it updates the person properties used for flags from `$set` and `$set_once`, + * caches a `$screen` event's `$screen_name` as the current screen, turns person processing on + * when the build had user properties or groups, and may add the replay debug values snapshotted + * at build that the event lacks. Keys the wrapper's hook removed aren't added back. + * + * Person processing and the person properties for flags are skipped when `reset()` or + * `identify()` changed the user since the build. The event is dropped when this instance didn't + * build it, when `setup()` or `close()` ran since the build, or when it was already sent. + * + * Returns the event's uuid once it's queued, or null when it's dropped. Defaults to null. + * + * @suppress + */ + @PostHogInternal + public fun sendBuiltEventForWrapper( + event: PostHogEvent, + ai: Boolean = false, + ): UUID? = null } diff --git a/posthog/src/main/java/com/posthog/PostHogStateless.kt b/posthog/src/main/java/com/posthog/PostHogStateless.kt index 104829ce5..eb5673141 100644 --- a/posthog/src/main/java/com/posthog/PostHogStateless.kt +++ b/posthog/src/main/java/com/posthog/PostHogStateless.kt @@ -308,16 +308,37 @@ public open class PostHogStateless protected constructor( timestamp: Date? = null, options: MutableMap? = null, uuid: UUID? = null, + ): PostHogEvent? = runBeforeSend(newEvent(event, distinctId, properties, timestamp, options, uuid), uuid) + + /** + * Creates the event, without running `beforeSend`. A null [timestamp] means now, and a null + * [uuid] gets a new UUID v7. + */ + internal fun newEvent( + event: String, + distinctId: String, + properties: MutableMap, + timestamp: Date? = null, + options: MutableMap? = null, + uuid: UUID? = null, + ): PostHogEvent = + PostHogEvent( + event, + distinctId, + properties = properties, + timestamp = timestamp ?: config?.dateProvider?.currentDate() ?: Date(), + uuid = uuid ?: TimeBasedEpochGenerator.generate(), + options = options, + ) + + /** + * Runs the `beforeSend` chain on [postHogEvent]. Returns null when a hook drops the event or + * throws. When [uuid] is given, the result keeps it. + */ + internal fun runBeforeSend( + postHogEvent: PostHogEvent, + uuid: UUID?, ): PostHogEvent? { - val postHogEvent = - PostHogEvent( - event, - distinctId, - properties = properties, - timestamp = timestamp ?: config?.dateProvider?.currentDate() ?: Date(), - uuid = uuid ?: TimeBasedEpochGenerator.generate(), - options = options, - ) var eventChecked: PostHogEvent = postHogEvent val beforeSendList = config?.beforeSendList ?: emptyList() @@ -326,7 +347,7 @@ public open class PostHogStateless protected constructor( try { val result = beforeSend.run(eventChecked) if (result == null) { - config?.logger?.log("Event $event was rejected in beforeSend function") + config?.logger?.log("Event ${postHogEvent.event} was rejected in beforeSend function") return null } eventChecked = result diff --git a/posthog/src/test/java/com/posthog/PostHogSessionReplayHandlerFake.kt b/posthog/src/test/java/com/posthog/PostHogSessionReplayHandlerFake.kt index 060ab3854..117e5ac59 100644 --- a/posthog/src/test/java/com/posthog/PostHogSessionReplayHandlerFake.kt +++ b/posthog/src/test/java/com/posthog/PostHogSessionReplayHandlerFake.kt @@ -49,11 +49,14 @@ public class PostHogSessionReplayHandlerFake(private var isActive: Boolean) : Po return isActive } + // runs after each debugProperties() read, so a test can change the state between reads + public var onDebugProperties: (() -> Unit)? = null + override fun debugProperties(): Map { if (throwOnDebugProperties) { throw RuntimeException("debugProperties failed") } - return debugProperties + return debugProperties.also { onDebugProperties?.invoke() } } override fun onEvent( diff --git a/posthog/src/test/java/com/posthog/PostHogWrapperEventTest.kt b/posthog/src/test/java/com/posthog/PostHogWrapperEventTest.kt new file mode 100644 index 000000000..00ca720c9 --- /dev/null +++ b/posthog/src/test/java/com/posthog/PostHogWrapperEventTest.kt @@ -0,0 +1,429 @@ +package com.posthog + +import com.posthog.internal.PostHogMemoryPreferences +import com.posthog.internal.PostHogPreferences.Companion.PERSON_PROPERTIES_FOR_FLAGS +import com.posthog.internal.PostHogThreadFactory +import okhttp3.mockwebserver.MockWebServer +import okhttp3.mockwebserver.RecordedRequest +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import java.io.File +import java.util.Date +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit +import kotlin.test.AfterTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +internal class PostHogWrapperEventTest { + @get:Rule + val tmpDir = TemporaryFolder() + + @get:Rule + val httpServers = TestHttpServers() + + private val queueExecutor = Executors.newSingleThreadScheduledExecutor(PostHogThreadFactory("TestQueue")) + private val replayQueueExecutor = Executors.newSingleThreadScheduledExecutor(PostHogThreadFactory("TestReplayQueue")) + private val logsExecutor = Executors.newSingleThreadScheduledExecutor(PostHogThreadFactory("TestLogsQueue")) + private val aiExecutor = Executors.newSingleThreadScheduledExecutor(PostHogThreadFactory("TestAiQueue")) + private val remoteConfigExecutor = Executors.newSingleThreadScheduledExecutor(PostHogThreadFactory("TestRemoteConfig")) + private val cachedEventsExecutor = Executors.newSingleThreadScheduledExecutor(PostHogThreadFactory("TestCachedEvents")) + private val clients = mutableListOf() + + private fun getSut( + http: MockWebServer, + configure: PostHogConfig.() -> Unit = {}, + ): PostHogInterface { + val storage = tmpDir.newFolder().absolutePath + val config = + PostHogConfig(PROJECT_TOKEN, http.url("/").toString()).apply { + storagePrefix = File(storage, "events").absolutePath + replayStoragePrefix = File(storage, "snapshots").absolutePath + logsStoragePrefix = File(storage, "logs").absolutePath + aiStoragePrefix = File(storage, "ai").absolutePath + flushAt = 1 + preloadFeatureFlags = false + sendFeatureFlagEvent = false + cachePreferences = PostHogMemoryPreferences() + context = TestPostHogContext() + configure() + } + return PostHog.withInternal( + config, + queueExecutor, + replayQueueExecutor, + remoteConfigExecutor, + cachedEventsExecutor, + reloadFeatureFlags = false, + logsExecutor = logsExecutor, + aiExecutor = aiExecutor, + ).also { clients.add(it) } + } + + @AfterTest + fun cleanup() { + clients.forEach { it.close() } + listOf(queueExecutor, replayQueueExecutor, logsExecutor, aiExecutor, remoteConfigExecutor, cachedEventsExecutor).forEach { + it.shutdownAndAwaitTermination() + } + tmpDir.root.deleteRecursively() + } + + private fun takeRequest(http: MockWebServer): RecordedRequest = assertNotNull(http.takeRequest(5, TimeUnit.SECONDS)) + + private fun events(request: RecordedRequest): List> = captureV1Events(request.body.unGzip()) + + @Suppress("UNCHECKED_CAST") + private fun Map.properties(): Map = this["properties"] as Map + + @Test + fun `build fills the event without running beforeSend or queueing it`() { + val http = httpServers.mockHttp() + var hookCalls = 0 + val sut = + getSut(http) { + addBeforeSend { event -> + hookCalls++ + event + } + } + sut.register("plan", "free") + + val event = + assertNotNull( + sut.buildEventForWrapper( + "purchase", + properties = mapOf("plan" to "pro"), + userProperties = mapOf("email" to "a@b.c"), + options = mapOf("cookieless_mode" to true), + ), + ) + + queueExecutor.awaitExecution() + assertEquals(0, http.requestCount) + assertEquals(0, hookCalls) + assertEquals("purchase", event.event) + assertEquals(sut.distinctId(), event.distinctId) + assertNotNull(event.uuid) + assertEquals("pro", event.properties?.get("plan")) + assertEquals("Android", event.properties?.get("\$os_name")) + assertEquals(mapOf("email" to "a@b.c"), event.properties?.get("\$set")) + assertEquals(true, event.options?.get("cookieless_mode")) + } + + @Test + fun `send keeps the built event's identity and properties, then runs beforeSend`() { + val http = httpServers.mockHttp() + val sut = + getSut(http) { + addBeforeSend { event -> + event.properties?.put("hooked", true) + event + } + } + val timestamp = Date(1_700_000_000_000) + val built = assertNotNull(sut.buildEventForWrapper("purchase", timestamp = timestamp)) + built.properties?.remove("\$os_name") + sut.register("late", "value") + + val uuid = sut.sendBuiltEventForWrapper(built) + + queueExecutor.awaitExecution() + val sent = events(takeRequest(http)).single() + assertEquals(built.uuid, uuid) + assertEquals(built.uuid.toString(), sent["uuid"]) + assertEquals("2023-11-14T22:13:20.000Z", sent["timestamp"]) + assertEquals(true, sent.properties()["hooked"]) + assertFalse(sent.properties().containsKey("\$os_name")) + assertFalse(sent.properties().containsKey("late")) + } + + @Test + fun `send on the AI lane posts to the AI endpoint`() { + val http = httpServers.mockHttp() + val sut = getSut(http) + sut.startSession() + val built = assertNotNull(sut.buildEventForWrapper("\$ai_generation", ai = true)) + + assertEquals(built.uuid, sut.sendBuiltEventForWrapper(built, ai = true)) + + aiExecutor.awaitExecution() + val request = takeRequest(http) + assertEquals("/i/v1/ai/events", request.path) + assertNotNull(events(request).single().properties()["\$sdk_debug_session_start"]) + } + + @Test + fun `send returns null when beforeSend drops the event`() { + val http = httpServers.mockHttp() + val sut = getSut(http) { addBeforeSend { null } } + val built = assertNotNull(sut.buildEventForWrapper("purchase")) + + assertNull(sut.sendBuiltEventForWrapper(built)) + + queueExecutor.awaitExecution() + assertEquals(0, http.requestCount) + } + + @Test + fun `send returns null after an opt-out since the build`() { + val http = httpServers.mockHttp() + val sut = getSut(http) + val built = assertNotNull(sut.buildEventForWrapper("purchase")) + sut.optOut() + + assertNull(sut.sendBuiltEventForWrapper(built)) + + queueExecutor.awaitExecution() + assertEquals(0, http.requestCount) + } + + @Test + fun `build returns null when opted out`() { + val sut = getSut(httpServers.mockHttp()) + sut.optOut() + + assertNull(sut.buildEventForWrapper("purchase")) + } + + @Test + fun `build of a screen event without a screen name returns null`() { + val sut = getSut(httpServers.mockHttp()) + + assertNull(sut.buildEventForWrapper("\$screen", properties = mapOf("\$screen_name" to " "))) + assertNull(sut.buildEventForWrapper("\$screen")) + } + + @Test + fun `a built event the wrapper drops leaves no state behind`() { + val prefs = PostHogMemoryPreferences() + val sut = getSut(httpServers.mockHttp()) { cachePreferences = prefs } + + assertNotNull( + sut.buildEventForWrapper( + "\$screen", + properties = mapOf("\$screen_name" to "Home"), + userProperties = mapOf("plan" to "pro"), + ), + ) + val next = assertNotNull(sut.buildEventForWrapper("tap")) + + assertFalse(next.properties!!.containsKey("\$screen_name")) + assertNull(prefs.getValue(PERSON_PROPERTIES_FOR_FLAGS)) + assertEquals(false, next.options?.get("process_person_profile")) + } + + @Test + fun `send turns on person processing for a build with user properties`() { + val sut = getSut(httpServers.mockHttp()) + val identified = assertNotNull(sut.buildEventForWrapper("signup", userProperties = mapOf("plan" to "pro"))) + + assertNotNull(sut.sendBuiltEventForWrapper(identified)) + val next = assertNotNull(sut.buildEventForWrapper("tap")) + + assertNull(identified.options?.get("process_person_profile")) + assertNull(next.options?.get("process_person_profile")) + } + + @Test + fun `send caches the screen name and the person properties for flags`() { + val prefs = PostHogMemoryPreferences() + val sut = getSut(httpServers.mockHttp()) { cachePreferences = prefs } + val screen = + assertNotNull( + sut.buildEventForWrapper( + "\$screen", + properties = mapOf("\$screen_name" to " Home "), + userProperties = mapOf("plan" to "pro"), + ), + ) + + assertNotNull(sut.sendBuiltEventForWrapper(screen)) + val next = assertNotNull(sut.buildEventForWrapper("tap")) + + assertEquals("Home", screen.properties?.get("\$screen_name")) + assertEquals("Home", next.properties?.get("\$screen_name")) + assertEquals(mapOf("plan" to "pro"), prefs.getValue(PERSON_PROPERTIES_FOR_FLAGS)) + } + + @Test + fun `send after a reset delivers the screen without restoring its name`() { + val sut = getSut(httpServers.mockHttp()) + val screen = assertNotNull(sut.buildEventForWrapper("\$screen", properties = mapOf("\$screen_name" to "Home"))) + + sut.reset() + assertNotNull(sut.sendBuiltEventForWrapper(screen)) + val next = assertNotNull(sut.buildEventForWrapper("tap")) + + assertNull(next.properties?.get("\$screen_name")) + } + + @Test + fun `the replay debug bundle is claimed at send`() { + val http = httpServers.mockHttp() + val sut = getSut(http) { flushAt = 2 } + sut.startSession() + val first = assertNotNull(sut.buildEventForWrapper("\$first")) + val second = assertNotNull(sut.buildEventForWrapper("\$second")) + + assertNotNull(sut.sendBuiltEventForWrapper(first)) + assertNotNull(sut.sendBuiltEventForWrapper(second)) + + queueExecutor.awaitExecution() + val (sentFirst, sentSecond) = events(takeRequest(http)) + assertNotNull(sentFirst.properties()["\$sdk_debug_session_start"]) + assertFalse(sentSecond.properties().containsKey("\$sdk_debug_session_start")) + } + + @Test + fun `replay debug eligibility follows the built name across a rename`() { + val http = httpServers.mockHttp() + val sut = getSut(http) { flushAt = 2 } + sut.startSession() + val renamedAway = assertNotNull(sut.buildEventForWrapper("\$first")) + val renamedTo = assertNotNull(sut.buildEventForWrapper("tap")) + + assertNotNull(sut.sendBuiltEventForWrapper(renamedTo.copy(event = "\$second"))) + assertNotNull(sut.sendBuiltEventForWrapper(renamedAway.copy(event = "custom"))) + + queueExecutor.awaitExecution() + val (sentTo, sentAway) = events(takeRequest(http)) + assertNotNull(sentAway.properties()["\$sdk_debug_session_start"]) + assertFalse(sentTo.properties().containsKey("\$sdk_debug_session_start")) + } + + @Test + fun `send keeps a replay debug key the wrapper removed`() { + val http = httpServers.mockHttp() + val sut = getSut(http) + sut.startSession() + val event = assertNotNull(sut.buildEventForWrapper("\$first")) + event.properties?.remove("\$recording_status") + + assertNotNull(sut.sendBuiltEventForWrapper(event)) + + queueExecutor.awaitExecution() + val sent = events(takeRequest(http)).single().properties() + assertNotNull(sent["\$sdk_debug_session_start"]) + assertFalse(sent.containsKey("\$recording_status")) + } + + @Test + fun `a second send of the same built event is a no-op`() { + val http = httpServers.mockHttp() + val sut = getSut(http) { flushAt = 2 } + val event = assertNotNull(sut.buildEventForWrapper("tap")) + + assertNotNull(sut.sendBuiltEventForWrapper(event)) + assertNull(sut.sendBuiltEventForWrapper(event)) + assertNotNull(sut.sendBuiltEventForWrapper(assertNotNull(sut.buildEventForWrapper("next")))) + + queueExecutor.awaitExecution() + assertEquals(listOf("tap", "next"), events(takeRequest(http)).map { it["event"] }) + } + + @Test + fun `send skips the person properties for flags after the user changed`() { + val prefs = PostHogMemoryPreferences() + val sut = getSut(httpServers.mockHttp()) { cachePreferences = prefs } + val event = assertNotNull(sut.buildEventForWrapper("signup", userProperties = mapOf("plan" to "pro"))) + + sut.reset() + assertNotNull(sut.sendBuiltEventForWrapper(event)) + + assertNull(prefs.getValue(PERSON_PROPERTIES_FOR_FLAGS)) + } + + @Test + fun `send skips the person properties for flags after a reset that kept the anonymous id`() { + val prefs = PostHogMemoryPreferences() + val sut = + getSut(httpServers.mockHttp()) { + cachePreferences = prefs + reuseAnonymousId = true + } + val event = assertNotNull(sut.buildEventForWrapper("signup", userProperties = mapOf("plan" to "pro"))) + + sut.reset() + assertNotNull(sut.sendBuiltEventForWrapper(event)) + + assertNull(prefs.getValue(PERSON_PROPERTIES_FOR_FLAGS)) + } + + @Test + fun `send drops an event built by another instance`() { + val built = assertNotNull(getSut(httpServers.mockHttp()).buildEventForWrapper("tap")) + val other = getSut(httpServers.mockHttp()) + + assertNull(other.sendBuiltEventForWrapper(built)) + } + + @Test + fun `send drops an event built before the SDK was set up again`() { + val http = httpServers.mockHttp() + var setupConfig: PostHogConfig? = null + val sut = getSut(http) { setupConfig = this } + val built = assertNotNull(sut.buildEventForWrapper("tap")) + + sut.close() + sut.setup(assertNotNull(setupConfig)) + + assertNull(sut.sendBuiltEventForWrapper(built)) + } + + @Test + fun `send keeps the replay debug values from the build`() { + val http = httpServers.mockHttp() + val sut = getSut(http) + sut.startSession() + val built = assertNotNull(sut.buildEventForWrapper("\$first")) + sut.endSession() + Thread.sleep(5) + sut.startSession() + + assertNotNull(sut.sendBuiltEventForWrapper(built)) + + queueExecutor.awaitExecution() + val sent = events(takeRequest(http)).single().properties() + assertNotNull(sent["\$sdk_debug_session_start"]) + } + + @Test + fun `build reads the replay debug state once for the required and deferred keys`() { + val http = httpServers.mockHttp() + val replay = + PostHogSessionReplayHandlerFake(true).apply { + debugProperties = + mapOf( + "\$recording_status" to "buffering", + "\$sdk_debug_replay_flush_hold_reason" to "below_minimum_duration", + ) + // A replay stop between two reads would pair buffering with no hold reason. + onDebugProperties = { debugProperties = mapOf("\$recording_status" to "disabled") } + } + val sut = getSut(http) { addIntegration(replay) } + sut.startSession() + + val screen = assertNotNull(sut.buildEventForWrapper("\$screen", properties = mapOf("\$screen_name" to "Home"))) + assertNotNull(sut.sendBuiltEventForWrapper(screen)) + + queueExecutor.awaitExecution() + val sent = events(takeRequest(http)).single().properties() + assertEquals("buffering", sent["\$recording_status"]) + assertEquals("below_minimum_duration", sent["\$sdk_debug_replay_flush_hold_reason"]) + } + + @Test + fun `send skips person processing after the user changed`() { + val sut = getSut(httpServers.mockHttp()) + val identified = assertNotNull(sut.buildEventForWrapper("signup", userProperties = mapOf("plan" to "pro"))) + + sut.reset() + assertNotNull(sut.sendBuiltEventForWrapper(identified)) + + assertEquals(false, assertNotNull(sut.buildEventForWrapper("tap")).options?.get("process_person_profile")) + } +}