From 252d3118781f0df1067d9cabf67f1ae1b3490479 Mon Sep 17 00:00:00 2001 From: elliotCamblor Date: Wed, 24 Jul 2024 12:39:31 -0400 Subject: [PATCH] feat: enable generated variable types for nodejs sdk (#901) --- sdk/js-cloud-server/src/cloudClient.ts | 25 ++++++++++++++------- sdk/js/src/Client.ts | 1 + sdk/nodejs/src/client.ts | 31 +++++++++++++++----------- sdk/nodejs/src/index.ts | 29 ++++++++++++++++-------- 4 files changed, 56 insertions(+), 30 deletions(-) diff --git a/sdk/js-cloud-server/src/cloudClient.ts b/sdk/js-cloud-server/src/cloudClient.ts index a4420d0cc..94ae5023b 100644 --- a/sdk/js-cloud-server/src/cloudClient.ts +++ b/sdk/js-cloud-server/src/cloudClient.ts @@ -16,6 +16,7 @@ import { DVCLogger, getVariableTypeFromValue, VariableTypeAlias, + type VariableValue, } from '@devcycle/types' import { getAllFeatures, @@ -67,7 +68,13 @@ const throwIfUserError = (err: unknown) => { throw err } -export class DevCycleCloudClient { +export interface VariableDefinitions { + [key: string]: VariableValue +} + +export class DevCycleCloudClient< + Variables extends VariableDefinitions = VariableDefinitions, +> { private sdkKey: string protected logger: DVCLogger private options: DevCycleServerSDKOptions @@ -94,11 +101,10 @@ export class DevCycleCloudClient { return true } - async variable( - user: DevCycleUser, - key: string, - defaultValue: T, - ): Promise> { + async variable< + K extends string & keyof Variables, + T extends DVCVariableValue & Variables[K], + >(user: DevCycleUser, key: K, defaultValue: T): Promise> { const incomingUser = castIncomingUser(user) const populatedUser = DVCPopulatedUser.fromDVCUser( incomingUser, @@ -148,9 +154,12 @@ export class DevCycleCloudClient { } } - async variableValue( + async variableValue< + K extends string & keyof Variables, + T extends DVCVariableValue & Variables[K], + >( user: DevCycleUser, - key: string, + key: K, defaultValue: T, ): Promise> { return (await this.variable(user, key, defaultValue)).value diff --git a/sdk/js/src/Client.ts b/sdk/js/src/Client.ts index 0f627e223..df361da0c 100644 --- a/sdk/js/src/Client.ts +++ b/sdk/js/src/Client.ts @@ -9,6 +9,7 @@ import { DVCFeature, VariableDefinitions, } from './types' + import { DVCVariable, DVCVariableOptions } from './Variable' import { getConfigJson, saveEntity } from './Request' import CacheStore from './CacheStore' diff --git a/sdk/nodejs/src/client.ts b/sdk/nodejs/src/client.ts index 701c0da03..9a5f71952 100644 --- a/sdk/nodejs/src/client.ts +++ b/sdk/nodejs/src/client.ts @@ -15,6 +15,7 @@ import { DVCLogger, getVariableTypeFromValue, VariableTypeAlias, + type VariableValue, } from '@devcycle/types' import os from 'os' import { @@ -54,14 +55,20 @@ type DevCycleProviderConstructor = typeof import('./open-feature/DevCycleProvider').DevCycleProvider type DevCycleProvider = InstanceType -export class DevCycleClient { +export interface VariableDefinitions { + [key: string]: VariableValue +} + +export class DevCycleClient< + Variables extends VariableDefinitions = VariableDefinitions, +> { private clientUUID: string private hostname: string private sdkKey: string private configHelper?: EnvironmentConfigManager private clientConfigHelper?: EnvironmentConfigManager private eventQueue: EventQueue - private onInitialized: Promise + private onInitialized: Promise> private logger: DVCLogger private _isInitialized = false private openFeatureProvider: DevCycleProvider @@ -212,7 +219,7 @@ export class DevCycleClient { */ async onClientInitialized( onInitialized?: (err?: Error) => void, - ): Promise { + ): Promise> { if (onInitialized && typeof onInitialized === 'function') { this.onInitialized .then(() => onInitialized()) @@ -221,11 +228,10 @@ export class DevCycleClient { return this.onInitialized } - variable( - user: DevCycleUser, - key: string, - defaultValue: T, - ): DVCVariable { + variable< + K extends string & keyof Variables, + T extends DVCVariableValue & Variables[K], + >(user: DevCycleUser, key: K, defaultValue: T): DVCVariable { const incomingUser = castIncomingUser(user) // this will throw if type is invalid const type = getVariableTypeFromValue( @@ -280,11 +286,10 @@ export class DevCycleClient { return new DVCVariable(options) } - variableValue( - user: DevCycleUser, - key: string, - defaultValue: T, - ): VariableTypeAlias { + variableValue< + K extends string & keyof Variables, + T extends DVCVariableValue & Variables[K], + >(user: DevCycleUser, key: K, defaultValue: T): VariableTypeAlias { return this.variable(user, key, defaultValue).value } diff --git a/sdk/nodejs/src/index.ts b/sdk/nodejs/src/index.ts index 9ea98ed3f..5c9a278ac 100644 --- a/sdk/nodejs/src/index.ts +++ b/sdk/nodejs/src/index.ts @@ -16,6 +16,7 @@ import { DVCFeatureSet, DevCyclePlatformDetails, } from '@devcycle/js-cloud-server-sdk' +import { VariableDefinitions } from '@devcycle/js-client-sdk' import { DevCycleServerSDKOptions } from '@devcycle/types' import { getNodeJSPlatformDetails } from './utils/platformDetails' @@ -24,7 +25,9 @@ type DevCycleProviderConstructor = typeof import('./open-feature/DevCycleProvider').DevCycleProvider type DevCycleProvider = InstanceType -class DevCycleCloudClient extends InternalDevCycleCloudClient { +class DevCycleCloudClient< + Variables extends VariableDefinitions = VariableDefinitions, +> extends InternalDevCycleCloudClient { private openFeatureProvider: DevCycleProvider constructor( @@ -117,22 +120,30 @@ export type DevCycleOptionsLocalEnabled = DevCycleServerSDKOptions & { configSource?: ConfigSource } -export function initializeDevCycle( +export function initializeDevCycle< + Variables extends VariableDefinitions = VariableDefinitions, +>( sdkKey: string, options?: DevCycleOptionsLocalEnabled, -): DevCycleClient -export function initializeDevCycle( +): DevCycleClient +export function initializeDevCycle< + Variables extends VariableDefinitions = VariableDefinitions, +>( sdkKey: string, options: DevCycleOptionsCloudEnabled, -): DevCycleCloudClient -export function initializeDevCycle( +): DevCycleCloudClient +export function initializeDevCycle< + Variables extends VariableDefinitions = VariableDefinitions, +>( sdkKey: string, options?: DevCycleServerSDKOptions, -): DevCycleClient | DevCycleCloudClient -export function initializeDevCycle( +): DevCycleClient | DevCycleCloudClient +export function initializeDevCycle< + Variables extends VariableDefinitions = VariableDefinitions, +>( sdkKey: string, options: DevCycleServerSDKOptions = {}, -): DevCycleClient | DevCycleCloudClient { +): DevCycleClient | DevCycleCloudClient { if (!sdkKey) { throw new Error('Missing SDK key! Call initialize with a valid SDK key') } else if (!isValidServerSDKKey(sdkKey)) {