diff --git a/lib/shared/config-manager/src/CDNConfigSource.ts b/lib/shared/config-manager/src/CDNConfigSource.ts index 8a95ee74f..d93c1f5e6 100644 --- a/lib/shared/config-manager/src/CDNConfigSource.ts +++ b/lib/shared/config-manager/src/CDNConfigSource.ts @@ -1,7 +1,6 @@ -import { ConfigBody, DVCLogger } from '@devcycle/types' -import { ConfigSource } from './ConfigSource' +import { ConfigBody, DVCLogger, ConfigSource, UserError } from '@devcycle/types' import { getEnvironmentConfig } from './request' -import { ResponseError, UserError } from '@devcycle/server-request' +import { ResponseError } from '@devcycle/server-request' export class CDNConfigSource extends ConfigSource { constructor( @@ -12,13 +11,14 @@ export class CDNConfigSource extends ConfigSource { super() } - async getConfig( + // type generic to make typescript happy. It's always false in this implementation + async getConfig( sdkKey: string, kind: 'server' | 'bootstrap', obfuscated: boolean, lastModifiedThreshold?: string, ): Promise<{ - config: ConfigBody | null + config: T extends true ? ConfigBody : ConfigBody | null metaData: Record lastModified: string | null }> { @@ -66,7 +66,9 @@ export class CDNConfigSource extends ConfigSource { 'Skipping saving config, existing last modified date is newer.', ) return { - config: null, + config: null as T extends true + ? ConfigBody + : ConfigBody | null, metaData: metadata, lastModified: lastModifiedHeader, } @@ -80,7 +82,7 @@ export class CDNConfigSource extends ConfigSource { } } return { - config: null, + config: null as T extends true ? ConfigBody : ConfigBody | null, metaData: metadata, lastModified: null, } diff --git a/lib/shared/config-manager/src/index.ts b/lib/shared/config-manager/src/index.ts index 476bf15b6..cd0bca2c7 100644 --- a/lib/shared/config-manager/src/index.ts +++ b/lib/shared/config-manager/src/index.ts @@ -1,11 +1,8 @@ -import { ConfigBody, DVCLogger } from '@devcycle/types' -import { ResponseError, UserError } from '@devcycle/server-request' +import { ConfigBody, DVCLogger, ConfigSource, UserError } from '@devcycle/types' +import { ResponseError } from '@devcycle/server-request' import { SSEConnection } from '@devcycle/sse-connection' import { CDNConfigSource } from './CDNConfigSource' import { isValidDate } from './request' -import { ConfigSource } from './ConfigSource' - -export * from './ConfigSource' type ConfigPollingOptions = { configPollingIntervalMS?: number diff --git a/lib/shared/server-request/src/index.ts b/lib/shared/server-request/src/index.ts index 05fb21655..582b1a31e 100644 --- a/lib/shared/server-request/src/index.ts +++ b/lib/shared/server-request/src/index.ts @@ -1,2 +1 @@ export * from './request' -export * from './userError' diff --git a/lib/shared/types/src/index.ts b/lib/shared/types/src/index.ts index be4d775f2..6d4e99b02 100644 --- a/lib/shared/types/src/index.ts +++ b/lib/shared/types/src/index.ts @@ -8,3 +8,5 @@ export * from './types/validators/dvcCustomDataJSON' export * from './types/apis/events/eventsAPI' export * from './types/config/models' export * from './utils' +export * from './types/ConfigSource' +export * from './types/UserError' diff --git a/lib/shared/config-manager/src/ConfigSource.ts b/lib/shared/types/src/types/ConfigSource.ts similarity index 77% rename from lib/shared/config-manager/src/ConfigSource.ts rename to lib/shared/types/src/types/ConfigSource.ts index a66294181..b6b63712f 100644 --- a/lib/shared/config-manager/src/ConfigSource.ts +++ b/lib/shared/types/src/types/ConfigSource.ts @@ -1,6 +1,11 @@ -import { ConfigBody } from '@devcycle/types' -import { isValidDate } from './request' +import { ConfigBody } from './config/configBody' +export const isValidDate = (date: Date | null): date is Date => + date instanceof Date && !isNaN(date.getTime()) + +/** + * Interface representing a source to pull config data from. Used by the Node and Next SDKs + */ export abstract class ConfigSource { configEtag?: string configLastModified?: string @@ -12,16 +17,18 @@ export abstract class ConfigSource { * @param kind * @param obfuscated * @param lastModifiedThreshold + * @param skipLastModified */ - abstract getConfig( + abstract getConfig( sdkKey: string, kind: 'server' | 'bootstrap', obfuscated: boolean, lastModifiedThreshold?: string, + skipLastModified?: T, ): Promise<{ - config: ConfigBody | null - metaData: Record + config: T extends true ? ConfigBody : ConfigBody | null lastModified: string | null + metaData: Record }> /** diff --git a/lib/shared/server-request/src/userError.ts b/lib/shared/types/src/types/UserError.ts similarity index 68% rename from lib/shared/server-request/src/userError.ts rename to lib/shared/types/src/types/UserError.ts index b769fb700..21d7f4c88 100644 --- a/lib/shared/server-request/src/userError.ts +++ b/lib/shared/types/src/types/UserError.ts @@ -2,6 +2,8 @@ export class UserError extends Error { constructor(error: Error | string) { super(error instanceof Error ? error.message : error) this.name = 'UserError' - this.stack = error instanceof Error ? error.stack : undefined + if (error instanceof Error) { + this.stack = error.stack + } } } diff --git a/lib/shared/vercel-edge-config/package.json b/lib/shared/vercel-edge-config/package.json index 66234d42b..054e4f6b8 100644 --- a/lib/shared/vercel-edge-config/package.json +++ b/lib/shared/vercel-edge-config/package.json @@ -2,7 +2,6 @@ "name": "@devcycle/vercel-edge-config", "version": "0.1.5", "peerDependencies": { - "@devcycle/nodejs-server-sdk": "*", "@devcycle/types": "*", "@vercel/edge-config": "^1.2.0" }, diff --git a/lib/shared/vercel-edge-config/src/edge-config.ts b/lib/shared/vercel-edge-config/src/edge-config.ts index 5e8e71021..41ae740fe 100644 --- a/lib/shared/vercel-edge-config/src/edge-config.ts +++ b/lib/shared/vercel-edge-config/src/edge-config.ts @@ -1,6 +1,5 @@ -import { ConfigSource, UserError } from '@devcycle/nodejs-server-sdk' import { EdgeConfigClient, EdgeConfigValue } from '@vercel/edge-config' -import { ConfigBody } from '@devcycle/types' +import { ConfigBody, ConfigSource, UserError } from '@devcycle/types' export class EdgeConfigSource extends ConfigSource { constructor(private edgeConfigClient: EdgeConfigClient) { diff --git a/sdk/nextjs/src/common/ConfigSource.ts b/sdk/nextjs/src/common/ConfigSource.ts deleted file mode 100644 index 6326eab7f..000000000 --- a/sdk/nextjs/src/common/ConfigSource.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ConfigBody } from '@devcycle/types' - -export abstract class ConfigSource { - /** - * Method to get the config from the source. - * Should return null if the config has not changed, and throw an error if it could not be retrieved. - * @param sdkKey - * @param kind - * @param obfuscated - * @param lastModifiedThreshold - * @param skipLastModified - */ - abstract getConfig( - sdkKey: string, - kind: 'server' | 'bootstrap', - obfuscated: boolean, - lastModifiedThreshold?: string, - skipLastModified?: T, - ): Promise<{ - config: T extends true ? ConfigBody : ConfigBody | null - lastModified: string | null - }> -} diff --git a/sdk/nextjs/src/common/types.ts b/sdk/nextjs/src/common/types.ts index b03426d14..c9735c0de 100644 --- a/sdk/nextjs/src/common/types.ts +++ b/sdk/nextjs/src/common/types.ts @@ -1,6 +1,5 @@ import { DevCycleOptions, DevCycleUser } from '@devcycle/js-client-sdk' -import { BucketedUserConfig } from '@devcycle/types' -import { ConfigSource } from './ConfigSource' +import { BucketedUserConfig, ConfigSource } from '@devcycle/types' export type DevCycleNextOptions = Pick< DevCycleOptions, diff --git a/sdk/nextjs/src/pages/appWithDevCycle.tsx b/sdk/nextjs/src/pages/appWithDevCycle.tsx index 616ce6efe..fc2da84bb 100644 --- a/sdk/nextjs/src/pages/appWithDevCycle.tsx +++ b/sdk/nextjs/src/pages/appWithDevCycle.tsx @@ -4,7 +4,7 @@ import { SSRProps } from './types' import { DevCycleProvider } from '@devcycle/react-client-sdk' import React from 'react' import { DevCycleOptions } from '@devcycle/js-client-sdk' -import { ConfigSource } from '../common/ConfigSource.js' +import { ConfigSource } from '@devcycle/types' type DevCycleNextOptions = Pick< DevCycleOptions, diff --git a/sdk/nextjs/src/pages/bucketing.ts b/sdk/nextjs/src/pages/bucketing.ts index 221e78ef6..a89199886 100644 --- a/sdk/nextjs/src/pages/bucketing.ts +++ b/sdk/nextjs/src/pages/bucketing.ts @@ -1,7 +1,6 @@ import { DevCycleUser, DVCPopulatedUser } from '@devcycle/js-client-sdk' import { generateBucketedConfig } from '@devcycle/bucketing' -import { BucketedUserConfig, ConfigBody } from '@devcycle/types' -import { ConfigSource } from '../common/ConfigSource.js' +import { BucketedUserConfig, ConfigBody, ConfigSource } from '@devcycle/types' const getFetchUrl = (sdkKey: string, obfuscated: boolean) => `https://config-cdn.devcycle.com/config/v1/server/bootstrap/${ @@ -23,6 +22,7 @@ class CDNConfigSource extends ConfigSource { ): Promise<{ config: ConfigBody lastModified: string | null + metaData: Record }> { const configResponse = await fetchCDNConfig(sdkKey, obfuscated) if (!configResponse.ok) { @@ -31,8 +31,18 @@ class CDNConfigSource extends ConfigSource { return { config: await configResponse.json(), lastModified: configResponse.headers.get('last-modified'), + metaData: {}, } } + + // implement a dummy version of this to satisfy shared type definition. Next does not use this method + getConfigURL( + sdkKey: string, + kind: 'server' | 'bootstrap', + obfuscated: boolean, + ): string { + return '' + } } const cdnConfigSource = new CDNConfigSource() diff --git a/sdk/nextjs/src/pages/getServerSideDevCycle.ts b/sdk/nextjs/src/pages/getServerSideDevCycle.ts index 3cfe7639f..12593fdbe 100644 --- a/sdk/nextjs/src/pages/getServerSideDevCycle.ts +++ b/sdk/nextjs/src/pages/getServerSideDevCycle.ts @@ -2,8 +2,7 @@ import { SSRProps } from './types' import { DevCycleOptions, DevCycleUser } from '@devcycle/js-client-sdk' import { getBucketedConfig } from './bucketing.js' import { GetServerSidePropsContext } from 'next' -import { BucketedUserConfig } from '@devcycle/types' -import { ConfigSource } from '../common/ConfigSource.js' +import { BucketedUserConfig, ConfigSource } from '@devcycle/types' type IdentifiedUser = Omit & { user_id: string diff --git a/sdk/nextjs/src/server/bucketing.ts b/sdk/nextjs/src/server/bucketing.ts index ec69bf38e..05d83fb4f 100644 --- a/sdk/nextjs/src/server/bucketing.ts +++ b/sdk/nextjs/src/server/bucketing.ts @@ -6,8 +6,7 @@ import { BucketedConfigWithAdditionalFields, DevCycleNextOptions, } from '../common/types' -import { ConfigSource } from '../common/ConfigSource' -import { ConfigBody } from '@devcycle/types' +import { ConfigBody, ConfigSource } from '@devcycle/types' // wrap this function in react cache to avoid redoing work for the same user and config const generateBucketedConfigCached = cache( @@ -59,8 +58,14 @@ class CDNConfigSource extends ConfigSource { return { config: (await cdnConfig.json()) as ConfigBody, lastModified: cdnConfig.headers.get('last-modified'), + metaData: {}, } } + + // dummy implementation to make types happy, this method isn't used in Next + getConfigURL(): string { + return '' + } } /** diff --git a/sdk/nodejs/src/client.ts b/sdk/nodejs/src/client.ts index 9a5f71952..1825c436e 100644 --- a/sdk/nodejs/src/client.ts +++ b/sdk/nodejs/src/client.ts @@ -1,5 +1,5 @@ import { EnvironmentConfigManager } from '@devcycle/config-manager' -import { ResponseError, UserError } from '@devcycle/server-request' +import { ResponseError } from '@devcycle/server-request' import { bucketUserForConfig, getSDKKeyFromConfig, @@ -16,6 +16,7 @@ import { getVariableTypeFromValue, VariableTypeAlias, type VariableValue, + UserError, } from '@devcycle/types' import os from 'os' import { diff --git a/sdk/nodejs/src/index.ts b/sdk/nodejs/src/index.ts index 863f59711..57e865487 100644 --- a/sdk/nodejs/src/index.ts +++ b/sdk/nodejs/src/index.ts @@ -101,11 +101,11 @@ export type DVCEvent = DevCycleEvent */ export type DVCOptions = DevCycleServerSDKOptions -import { ConfigSource } from '@devcycle/config-manager' +import { ConfigSource } from '@devcycle/types' export { ConfigSource } -export { UserError } from '@devcycle/server-request' +export { UserError } from '@devcycle/types' type DevCycleOptionsCloudEnabled = DevCycleServerSDKOptions & { enableCloudBucketing: true diff --git a/yarn.lock b/yarn.lock index db3b3bea7..e4602f4e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4845,7 +4845,6 @@ __metadata: version: 0.0.0-use.local resolution: "@devcycle/vercel-edge-config@workspace:lib/shared/vercel-edge-config" peerDependencies: - "@devcycle/nodejs-server-sdk": "*" "@devcycle/types": "*" "@vercel/edge-config": ^1.2.0 languageName: unknown