From a45715c80afef266a34c4a5ed8106ef056e4b5e6 Mon Sep 17 00:00:00 2001
From: Adam Wootton <adam@taplytics.com>
Date: Wed, 23 Oct 2024 12:12:10 -0400
Subject: [PATCH] disable next events serverside in the ClientSide provider

---
 sdk/js/src/Client.ts                          | 27 +++++++++++++------
 sdk/js/src/EventQueue.ts                      |  2 ++
 .../InternalDevCycleClientsideProvider.tsx    | 16 ++++++++---
 sdk/nextjs/src/client/internal/context.ts     | 19 +++++++++++--
 .../src/client/internal/useDevCycleClient.ts  |  5 ++--
 sdk/nextjs/src/client/useDevCycleClient.ts    |  4 +--
 6 files changed, 55 insertions(+), 18 deletions(-)

diff --git a/sdk/js/src/Client.ts b/sdk/js/src/Client.ts
index 1f82464f8..4923b1c79 100644
--- a/sdk/js/src/Client.ts
+++ b/sdk/js/src/Client.ts
@@ -82,7 +82,7 @@ export class DevCycleClient<
         [key: string]: { [key: string]: DVCVariable<any> }
     }
     private store: CacheStore
-    private eventQueue: EventQueue<Variables, CustomData>
+    private eventQueue?: EventQueue<Variables, CustomData>
     private requestConsolidator: ConfigRequestConsolidator
     eventEmitter: EventEmitter
     private streamingConnection?: StreamingConnection
@@ -125,7 +125,15 @@ export class DevCycleClient<
 
         this.sdkKey = sdkKey
         this.variableDefaultMap = {}
-        this.eventQueue = new EventQueue(sdkKey, this, options)
+
+        if (
+            !(
+                this.options.disableAutomaticEventLogging &&
+                this.options.disableCustomEventLogging
+            )
+        ) {
+            this.eventQueue = new EventQueue(sdkKey, this, options)
+        }
 
         this.eventEmitter = new EventEmitter()
         if (!this.options.disableRealtimeUpdates) {
@@ -359,7 +367,7 @@ export class DevCycleClient<
 
         try {
             const variableFromConfig = this.config?.variables?.[variable.key]
-            this.eventQueue.queueAggregateEvent({
+            this.eventQueue?.queueAggregateEvent({
                 type: variable.isDefaulted
                     ? EventTypes.variableDefaulted
                     : EventTypes.variableEvaluated,
@@ -439,7 +447,7 @@ export class DevCycleClient<
             return this.config?.variables || {}
         }
 
-        void this.eventQueue.flushEvents()
+        void this.eventQueue?.flushEvents()
 
         try {
             await this.onInitialized
@@ -489,7 +497,7 @@ export class DevCycleClient<
             this.options,
         )
         const promise = new Promise<DVCVariableSet>((resolve, reject) => {
-            this.eventQueue.flushEvents()
+            this.eventQueue?.flushEvents()
 
             this.onInitialized
                 .then(() => this.store.loadAnonUserId())
@@ -598,7 +606,7 @@ export class DevCycleClient<
 
         checkParamDefined('type', event.type)
         this.onInitialized.then(() => {
-            this.eventQueue.queueEvent(event)
+            this.eventQueue?.queueEvent(event)
         })
     }
 
@@ -608,7 +616,10 @@ export class DevCycleClient<
      * @param callback
      */
     flushEvents(callback?: () => void): Promise<void> {
-        return this.eventQueue.flushEvents().then(() => callback?.())
+        return (
+            this.eventQueue?.flushEvents().then(() => callback?.()) ??
+            Promise.resolve().then(() => callback?.())
+        )
     }
 
     /**
@@ -637,7 +648,7 @@ export class DevCycleClient<
 
         this.streamingConnection?.close()
 
-        await this.eventQueue.close()
+        await this.eventQueue?.close()
     }
 
     /**
diff --git a/sdk/js/src/EventQueue.ts b/sdk/js/src/EventQueue.ts
index 77b44a821..e1145dc37 100644
--- a/sdk/js/src/EventQueue.ts
+++ b/sdk/js/src/EventQueue.ts
@@ -156,6 +156,7 @@ export class EventQueue<
             )
             return
         }
+        console.log('queueEvent', event)
         this.eventQueue.push(event)
     }
 
@@ -170,6 +171,7 @@ export class EventQueue<
             )
             return
         }
+        console.log('queueAggregateEvent', event)
 
         checkParamDefined('type', event.type)
         checkParamDefined('target', event.target)
diff --git a/sdk/nextjs/src/client/internal/InternalDevCycleClientsideProvider.tsx b/sdk/nextjs/src/client/internal/InternalDevCycleClientsideProvider.tsx
index 91092731e..061da4e78 100644
--- a/sdk/nextjs/src/client/internal/InternalDevCycleClientsideProvider.tsx
+++ b/sdk/nextjs/src/client/internal/InternalDevCycleClientsideProvider.tsx
@@ -22,6 +22,8 @@ type DevCycleClientsideProviderProps = {
     children: React.ReactNode
 }
 
+const isServer = typeof window === 'undefined'
+
 /**
  * Component which renders nothing, but runs code to keep client state in sync with server
  * Also waits for the server's data promise with the `use` hook. This triggers the nearest suspense boundary,
@@ -36,7 +38,7 @@ export const SuspendedProviderInitialization = ({
 }: Pick<
     DevCycleClientContext,
     'serverDataPromise' | 'userAgent'
->): React.ReactElement => {
+>): React.ReactNode => {
     const serverData = use(serverDataPromise)
     const [previousContext, setPreviousContext] = useState<
         DevCycleServerData | undefined
@@ -45,14 +47,16 @@ export const SuspendedProviderInitialization = ({
     if (previousContext !== serverData) {
         // change user and config data to match latest server data
         // if the data has changed since the last invocation
-        context.client.synchronizeBootstrapData(
+        // assert this is a DevCycleClient, not a DevCycleNextClient, because it is. We expose a more limited type
+        // to the end user 
+        (context.client as DevCycleClient).synchronizeBootstrapData(
             serverData.config,
             serverData.user,
             userAgent,
         )
         setPreviousContext(serverData)
     }
-    return <></>
+    return null
 }
 
 export const InternalDevCycleClientsideProvider = ({
@@ -102,6 +106,12 @@ export const InternalDevCycleClientsideProvider = ({
             sdkPlatform: 'nextjs',
             deferInitialization: true,
             disableConfigCache: true,
+            ...(isServer
+                ? {
+                      disableAutomaticEventLogging: true,
+                      disableCustomEventLogging: true,
+                  }
+                : {}),
             next: {
                 configRefreshHandler: revalidateConfig,
             },
diff --git a/sdk/nextjs/src/client/internal/context.ts b/sdk/nextjs/src/client/internal/context.ts
index 24ff9b052..20e2109ab 100644
--- a/sdk/nextjs/src/client/internal/context.ts
+++ b/sdk/nextjs/src/client/internal/context.ts
@@ -1,9 +1,24 @@
 'use client'
-import { DevCycleClient } from '@devcycle/js-client-sdk'
+import {
+    DevCycleClient,
+    DVCCustomDataJSON,
+    VariableDefinitions,
+} from '@devcycle/js-client-sdk'
 import React from 'react'
 
+export type DevCycleNextClient<
+    Variables extends VariableDefinitions = VariableDefinitions,
+    CustomData extends DVCCustomDataJSON = DVCCustomDataJSON,
+> = Omit<
+    DevCycleClient<Variables, CustomData>,
+    | 'onClientInitialized'
+    | 'identifyUser'
+    | 'resetUser'
+    | 'synchronizeBootstrapData'
+>
+
 type ClientProviderContext = {
-    client: DevCycleClient
+    client: DevCycleNextClient
     clientSDKKey: string
     enableStreaming: boolean
     serverDataPromise: Promise<unknown>
diff --git a/sdk/nextjs/src/client/internal/useDevCycleClient.ts b/sdk/nextjs/src/client/internal/useDevCycleClient.ts
index 07de42357..34ce0cd2e 100644
--- a/sdk/nextjs/src/client/internal/useDevCycleClient.ts
+++ b/sdk/nextjs/src/client/internal/useDevCycleClient.ts
@@ -1,7 +1,6 @@
 import { useContext } from 'react'
-import { DevCycleProviderContext } from './context'
-import { DevCycleClient } from '@devcycle/js-client-sdk'
+import { DevCycleNextClient, DevCycleProviderContext } from './context'
 
-export const useDevCycleClient = (): DevCycleClient => {
+export const useDevCycleClient = (): DevCycleNextClient => {
     return useContext(DevCycleProviderContext).client
 }
diff --git a/sdk/nextjs/src/client/useDevCycleClient.ts b/sdk/nextjs/src/client/useDevCycleClient.ts
index 4e287720b..1f0da1f90 100644
--- a/sdk/nextjs/src/client/useDevCycleClient.ts
+++ b/sdk/nextjs/src/client/useDevCycleClient.ts
@@ -1,6 +1,6 @@
+import { DevCycleNextClient } from './internal/context'
 import { useDevCycleClient as internalUseClient } from './internal/useDevCycleClient'
-import { DevCycleClient } from '@devcycle/js-client-sdk'
 
-export const useDevCycleClient = (): DevCycleClient => {
+export const useDevCycleClient = (): DevCycleNextClient => {
     return internalUseClient()
 }