Skip to content

Commit

Permalink
feat: update getOpenFeatureProvider() to dynamically import OpenFeatu…
Browse files Browse the repository at this point in the history
…re peer dependencies (#732)
  • Loading branch information
jonathannorris authored Feb 9, 2024
1 parent 9d3051f commit eaddb57
Show file tree
Hide file tree
Showing 19 changed files with 77 additions and 30 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ To view the README for a specific SDK, navigate to that SDK inside the `sdk` dir

[React Client SDK](sdk/react)

[NodeJS Server SDK](sdk/nodejs)
[Node.js Server SDK](sdk/nodejs)

There are several examples included in this repository for various SDKs. If you want to run them, proceed to setup:

Expand Down
4 changes: 2 additions & 2 deletions examples/nodejs-cloud/js/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# DevCycle NodeJS Cloud Server SDK - Javascript Example App
# DevCycle Node.js Cloud Server SDK - Javascript Example App

Example app for using the DevCycle NodeJS Server SDK with nodeJS and javascript.
Example app for using the DevCycle Node.js Server SDK with node.js and javascript.

### Run

Expand Down
4 changes: 2 additions & 2 deletions examples/nodejs-cloud/typescript/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# DevCycle NodeJS Cloud Server SDK - Typescript Example App
# DevCycle Node.js Cloud Server SDK - Typescript Example App

Example app for using the DevCycle NodeJS Server SDK with nodeJS and typescript.
Example app for using the DevCycle Node.js Server SDK with node.js and typescript.

### Build and Run

Expand Down
4 changes: 2 additions & 2 deletions examples/nodejs-local/js/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# DevCycle NodeJS Local Server SDK - Typescript Example App
# DevCycle Node.js Local Server SDK - Typescript Example App

Example app for using the DevCycle NodeJS Server SDK with nodeJS and javascript.
Example app for using the DevCycle Node.js Server SDK with node.js and javascript.

### Run

Expand Down
4 changes: 2 additions & 2 deletions examples/nodejs-local/typescript/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# DevCycle NodeJS Local Server SDK - Typescript Example App
# DevCycle Node.js Local Server SDK - Typescript Example App

Example app for using the DevCycle NodeJS Server SDK with nodeJS and typescript.
Example app for using the DevCycle Node.js Server SDK with node.js and typescript.

### Build and Run

Expand Down
4 changes: 3 additions & 1 deletion examples/openfeature-nodejs/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# OpenFeature DevCycle Provider Example App

Example app for using the OpenFeature NodeJS SDK with the DevCycle Provider.


Example app for using the OpenFeature Node.js SDK with the DevCycle Provider.

### Build and Run

Expand Down
6 changes: 5 additions & 1 deletion examples/openfeature-nodejs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,9 @@
"name": "@devcycle/openfeature-nodejs-example",
"version": "1.7.1",
"description": "DevCycle OpenFeature NodeJS Example App",
"license": "MIT"
"license": "MIT",
"dependencies": {
"@openfeature/core": "^0.0.25",
"@openfeature/server-sdk": "^1.11.0"
}
}
4 changes: 3 additions & 1 deletion examples/openfeature-nodejs/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ let openFeatureClient: Client

async function startDevCycle() {
await OpenFeature.setProviderAndWait(
initializeDevCycle(DEVCYCLE_SERVER_SDK_KEY).getOpenFeatureProvider(),
await initializeDevCycle(
DEVCYCLE_SERVER_SDK_KEY,
).getOpenFeatureProvider(),
)
openFeatureClient = OpenFeature.getClient()

Expand Down
2 changes: 1 addition & 1 deletion lib/shared/config-manager/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# config-manager

This library extracts the `EnvironmentConfigManager` Server SDK logic to be used across the NodeJS SDK
This library extracts the `EnvironmentConfigManager` Server SDK logic to be used across the Node.js SDK
and Edge Worker SDKs.

## Building
Expand Down
2 changes: 1 addition & 1 deletion sdk/js-cloud-server/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# DevCycle Javascript Cloud Bucketing Server SDK

This SDK is used to integrate DevCycle with your Javascript server-side application, where a NodeJS runtime isn't available.
This SDK is used to integrate DevCycle with your Javascript server-side application, where a Node.js runtime isn't available.
Example use-cases would be Cloudflare Workers and other edge-worker runtimes.

This SDK makes API requests to DevCycle's [Bucketing API](https://docs.devcycle.com/bucketing-api/) to perform bucketing.
Expand Down
1 change: 1 addition & 0 deletions sdk/nodejs/.test.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NODE_OPTIONS=--experimental-vm-modules
4 changes: 2 additions & 2 deletions sdk/nodejs/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# DevCycle NodeJS Server SDK
# DevCycle Node.js Server SDK

The NodeJS Server SDK for DevCycle.
The Node.js Server SDK for DevCycle.

This SDK uses local bucketing to perform all user segmentation and bucketing locally in the SDK,
providing immediate responses to variable and feature requests for a user.
Expand Down
8 changes: 4 additions & 4 deletions sdk/nodejs/__tests__/initialize.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ describe('NodeJS SDK Initialize', () => {
})

it('successfully creates a OpenFeature provider - local', async () => {
const provider =
initializeDevCycle('dvc_server_token').getOpenFeatureProvider()
const provider = await initializeDevCycle(
'dvc_server_token',
).getOpenFeatureProvider()
expect(provider).toBeDefined()
expect(provider.status).toBe('NOT_READY')
await OpenFeature.setProviderAndWait(provider)
expect(provider.status).toBe('READY')
const client = OpenFeature.getClient()
expect(client).toBeDefined()
})

it('successfully creates a OpenFeature provider - cloud', async () => {
const provider = initializeDevCycle('dvc_server_token', {
const provider = await initializeDevCycle('dvc_server_token', {
enableCloudBucketing: true,
}).getOpenFeatureProvider()
expect(provider).toBeDefined()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe.each(['DevCycleClient', 'DevCycleCloudClient'])(
},
)
await OpenFeature.setProviderAndWait(
dvcClient.getOpenFeatureProvider(),
await dvcClient.getOpenFeatureProvider(),
)
const ofClient = OpenFeature.getClient()
ofClient.setContext({ targetingKey: 'node_sdk_test' })
Expand Down
2 changes: 1 addition & 1 deletion sdk/nodejs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@openfeature/server-sdk": "^1.11.0"
},
"engines": {
"node": ">=14.0.0"
"node": ">=16.0.0"
},
"main": "src/index.js",
"types": "src/index.d.ts"
Expand Down
24 changes: 21 additions & 3 deletions sdk/nodejs/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import {
DevCycleEvent,
} from '@devcycle/js-cloud-server-sdk'
import { DVCPopulatedUserFromDevCycleUser } from './models/populatedUserHelpers'
import DevCycleProvider from './open-feature-provider/DevCycleProvider'

interface IPlatformData {
platform: string
Expand All @@ -48,6 +47,11 @@ const castIncomingUser = (user: DevCycleUser) => {
return user
}

// Dynamically import the OpenFeature Provider, as it's an optional peer dependency
type DevCycleProviderConstructor =
typeof import('./open-feature-provider/DevCycleProvider').DevCycleProvider
type DevCycleProvider = InstanceType<DevCycleProviderConstructor>

export class DevCycleClient {
private sdkKey: string
private configHelper: EnvironmentConfigManager
Expand Down Expand Up @@ -125,10 +129,24 @@ export class DevCycleClient {
})
}

getOpenFeatureProvider(): DevCycleProvider {
async getOpenFeatureProvider(): Promise<DevCycleProvider> {
let DevCycleProviderClass

try {
const importedModule = await import(
'./open-feature-provider/DevCycleProvider.js'
)
DevCycleProviderClass = importedModule.DevCycleProvider
} catch (error) {
throw new Error(
'Missing "@openfeature/server-sdk" and/or "@openfeature/core" ' +
'peer dependencies to get OpenFeature Provider',
)
}

if (this.openFeatureProvider) return this.openFeatureProvider

this.openFeatureProvider = new DevCycleProvider(this, {
this.openFeatureProvider = new DevCycleProviderClass(this, {
logger: this.logger,
})
return this.openFeatureProvider
Expand Down
25 changes: 21 additions & 4 deletions sdk/nodejs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ import {
} from '@devcycle/js-cloud-server-sdk'
import { DevCycleServerSDKOptions } from '@devcycle/types'
import { getNodeJSPlatformDetails } from './utils/platformDetails'
import DevCycleProvider from './open-feature-provider/DevCycleProvider'

// Dynamically import the OpenFeature Provider, as it's an optional peer dependency
type DevCycleProviderConstructor =
typeof import('./open-feature-provider/DevCycleProvider').DevCycleProvider
type DevCycleProvider = InstanceType<DevCycleProviderConstructor>

class DevCycleCloudClient extends InternalDevCycleCloudClient {
private openFeatureProvider: DevCycleProvider
Expand All @@ -31,10 +35,24 @@ class DevCycleCloudClient extends InternalDevCycleCloudClient {
super(sdkKey, options, platformDetails)
}

getOpenFeatureProvider(): DevCycleProvider {
async getOpenFeatureProvider(): Promise<DevCycleProvider> {
let DevCycleProviderClass

try {
const importedModule = await import(
'./open-feature-provider/DevCycleProvider.js'
)
DevCycleProviderClass = importedModule.DevCycleProvider
} catch (error) {
throw new Error(
'Missing "@openfeature/server-sdk" and/or "@openfeature/core" ' +
'peer dependencies to get OpenFeature Provider',
)
}

if (this.openFeatureProvider) return this.openFeatureProvider

this.openFeatureProvider = new DevCycleProvider(this, {
this.openFeatureProvider = new DevCycleProviderClass(this, {
logger: this.logger,
})
return this.openFeatureProvider
Expand All @@ -47,7 +65,6 @@ export {
DevCycleUser,
DevCycleServerSDKOptions as DevCycleOptions,
DevCycleEvent,
DevCycleProvider,
DVCVariableValue,
JSON,
DVCJSON,
Expand Down
2 changes: 1 addition & 1 deletion sdk/nodejs/src/open-feature-provider/DevCycleProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type EvaluationContextObject = {
[key: string]: EvaluationContextValue
}

export default class DevCycleProvider implements Provider {
export class DevCycleProvider implements Provider {
readonly metadata: ProviderMetadata = {
name: 'devcycle-nodejs-provider',
} as const
Expand Down
3 changes: 3 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5210,6 +5210,9 @@ __metadata:
"@devcycle/openfeature-nodejs-example@workspace:examples/openfeature-nodejs":
version: 0.0.0-use.local
resolution: "@devcycle/openfeature-nodejs-example@workspace:examples/openfeature-nodejs"
dependencies:
"@openfeature/core": ^0.0.25
"@openfeature/server-sdk": ^1.11.0
languageName: unknown
linkType: soft

Expand Down

0 comments on commit eaddb57

Please sign in to comment.