From 52be680541b2e3a2bba86e81763cb037b3b82121 Mon Sep 17 00:00:00 2001 From: Parth Suthar Date: Fri, 9 May 2025 10:04:16 -0400 Subject: [PATCH] feat: add optIn support for nextjs sdk --- sdk/nextjs/src/server/bucketing.ts | 14 ++++++++++++-- sdk/nextjs/src/server/requests.ts | 29 +++++++++++++++++++---------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/sdk/nextjs/src/server/bucketing.ts b/sdk/nextjs/src/server/bucketing.ts index a666c430a..c62507783 100644 --- a/sdk/nextjs/src/server/bucketing.ts +++ b/sdk/nextjs/src/server/bucketing.ts @@ -1,4 +1,8 @@ -import { fetchCDNConfig, sdkConfigAPI } from './requests' +import { + fetchCDNConfig, + getOptInUsersFromConfigApi, + sdkConfigAPI, +} from './requests' import { generateBucketedConfig } from '@devcycle/bucketing' import { cache } from 'react' import { DevCycleUser, DVCPopulatedUser } from '@devcycle/js-client-sdk' @@ -31,7 +35,13 @@ const generateBucketedConfigCached = cache( // clientSDKKey is always defined for bootstrap config // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const clientSDKKey = config.clientSDKKey! - if (config.debugUsers?.includes(user.user_id ?? '')) { + const optInUsers = config.project.settings.optIn?.enabled + ? await getOptInUsersFromConfigApi(clientSDKKey) + : [] + if ( + config.debugUsers?.includes(user.user_id ?? '') || + optInUsers.includes(user.user_id ?? '') + ) { const bucketedConfigResponse = await sdkConfigAPI( clientSDKKey, obfuscated, diff --git a/sdk/nextjs/src/server/requests.ts b/sdk/nextjs/src/server/requests.ts index 853d580a7..dbf160ebf 100644 --- a/sdk/nextjs/src/server/requests.ts +++ b/sdk/nextjs/src/server/requests.ts @@ -15,16 +15,13 @@ export const fetchCDNConfig = cache( clientSDKKey: string, obfuscated: boolean, ): Promise<{ config: ConfigBody; headers: Headers }> => { - const response = await fetch( - getFetchUrl(sdkKey, obfuscated), - // only store for 60 seconds - { - next: { - revalidate: 60, - tags: [sdkKey, clientSDKKey], - }, + const url = getFetchUrl(sdkKey, obfuscated) + const response = await fetch(url, { + next: { + revalidate: 60, + tags: [sdkKey, clientSDKKey], }, - ) + }) if (!response.ok) { const responseText = await response.text() @@ -37,6 +34,8 @@ export const fetchCDNConfig = cache( }, ) +const getAPIUrl = (path: string) => `https://sdk-api.devcycle.com/v1/${path}` + const getSDKAPIUrl = ( sdkKey: string, obfuscated: boolean, @@ -50,7 +49,7 @@ const getSDKAPIUrl = ( } searchParams.set('sdkPlatform', 'nextjs') searchParams.set('sse', '1') - return `https://sdk-api.devcycle.com/v1/sdkConfig?${searchParams.toString()}` + return getAPIUrl(`sdkConfig?${searchParams.toString()}`) } export const sdkConfigAPI = cache( @@ -69,3 +68,13 @@ export const sdkConfigAPI = cache( return (await response.json()) as BucketedUserConfig }, ) + +export const getOptInUsersFromConfigApi = cache( + async (sdkKey: string): Promise => { + const response = await fetch(getAPIUrl(`optIns/users?sdkKey=${sdkKey}`)) + if (!response.ok) { + return [] + } + return (await response.json()).users + }, +)