Giter Club home page Giter Club logo

js-sdks's Introduction

JS SDK Monorepo

This is the DevCycle JS SDK Monorepo which contains all the Javascript-based SDKs and public shared packages used by DevCycle products.

To view the README for a specific SDK, navigate to that SDK inside the sdk directory.

Javascript Client SDK

React Client SDK

Node.js Server SDK

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

Setup

Ensure you have Node 20.x installed.

  1. Clone this repo
  2. Run yarn from the root directory. SDKs and examples should now be set up to run via Nx.
  3. Run aws configure sso
  4. Run aws sso login

Directory Structure

examples/
    - contains example applications using each SDK
lib/
    - contains shared Javascript libraries
scripts/
    - contains all scripts that are not service or task specific
sdk/
    - contains all SDKs

Running an example

To run an example, use the yarn start command with the name of the example you want to run: yarn start example-react-with-provider

The names of the examples are listed in the workspace.json file at the root of the repository. All examples are located in the root-level examples/ directory.

Development

The repo is managed using Nx, a monorepo management tool. It's worth reading their docs here: https://nx.dev/l/n/getting-started/intro

Every project in the repo is listed in the workspace.json file. Each of these projects will let you run common Nx commands against them. For example, to test the "nodejs" project, run:

nx test nodejs

These commands can be run from the root directory, but should work in any directory.

The full list of relevant Nx commands is below:

build - build the compiled Webpack output of the project
serve - build and then run the compiled project
test  - run the tests using jest
lint  - run linting
format:write - run prettier against the project and write all formatting changes

There are also several root-level yarn commands for running services:

yarn start                - start all services in the repo
yarn start:partial        - start the services you specify (eg. yarn start:partial api,config)
yarn test                 - run all tests in the repo
yarn lint                 - lint all projects in the repo

Running a local npm server to publish to and pull from

This will update your yarn and npm configs to point to the new registry, and start up the new registry locally.

yarn local-registry enable
yarn local-registry start

The first time you run this, you'll need to add your user:

npm adduser --registry http://localhost:4873

The username is test, and the password is test.

To disable the server, just exit the process. Then run:

yarn local-registry disable

Keeping the server active may interfere with normal npm and npx activities, so if anything's acting strange, just kill the server and disable the registry updates.

โš ๏ธ The npm-safe-publish.sh script will not use the locally running server!

Linting and Running Tests

You can run commands in every javascript project using Nx: nx run-many --target test --all

This allows you to lint and/or test all projects at once.

Publishing a Release

Note: You need admin privileges to publish a release. If you don't have them, ask someone who does to do the release for you.

Setup:

  • run aws sso login
  • run ./scripts/brew-install.sh
  • ensure you're on the main branch with the latest code

Then use lerna to create new versions of all changed packages (ensure you do this on the main branch) yarn lerna:version

This will automatically push the latest tags and version updates to github.

To publish the versions to npm, you need a one-time password from our NPM account.

To publish, run: yarn npm-publish --otp=<one-time password>

This will publish all the new versions to npm.

js.devcycle.com/devcycle.min.js

The last step is to upload the umd version of the SDK to our S3 bucket.

To build it, run:

nx build:cdn js

This will create three files in the dist/sdk/js folder:

- devcycle.min.js
- devcycle.min.js.map
- devcycle.min.js.LICENSE.txt

Upload them all to S3. Ensure that their access controls allow public access.

js-sdks's People

Contributors

ajwootto avatar chantalchung avatar chris-hoefgen avatar cristinataplytics avatar dependabot[bot] avatar elliotcamblor avatar emmawillis avatar jamiesinn avatar jonathannorris avatar jsalaber avatar kaushalkapasi avatar l-joli avatar nikolasleblanc avatar nsalamad avatar rabiaq123 avatar rob-odwyer avatar squarepegg avatar suthar26 avatar taplytics-robot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

js-sdks's Issues

Expo: Unable to resolve "class-validator"

Sometime after version 1.14, something changed that broke the package.
I get this error during bundling:

Unable to resolve "class-validator" from "node_modules\@devcycle\react-native-expo-client-sdk\node_modules\@devcycle\types\index.cjs.js"

If I downgrade to 1.14, I no longer get the error.
I'm using Expo SDK 50.

Error initializing DevCycle: TypeError: Converting circular structure to JSON

I'm seeing Error initializing DevCycle: TypeError: Converting circular structure to JSON error when attempting to provide a custom logger to the initializeDevCycle function. This error is seemingly related to winston as swapping winston with a custom logger that uses console.log does not throw this error.

Package versions

@devcycle/nodejs-server-sdk: 1.33.2
@devcycle/types: 1.16.0
winston: 3.13.1

Test code

import { DVCVariable, initializeDevCycle } from '@devcycle/nodejs-server-sdk';
import { DVCLogger } from '@devcycle/types';
import winston, { Logger } from 'winston';

export const logger: winston.Logger = winston.createLogger({
  format: winston.format.combine(
    winston.format.metadata(),
    winston.format.errors({ stack: true }),
    winston.format.timestamp(),
    winston.format.json()
  ),
  transports: [
    new winston.transports.Console({
      handleExceptions: true,
      level: 'debug'
    })
  ],
  exitOnError: false
});

export class CustomLogger implements DVCLogger {
  constructor(private logger: Logger) {}

  error(message: string, error?: unknown): void {
    this.logger.error(message, {
      error
    });
  }
  warn(message: string): void {
    this.logger.warn(message);
  }
  info(message: string): void {
    this.logger.info(message);
  }
  debug(message: string): void {
    this.logger.debug(message);
  }
}

(async () => {
  await initializeDevCycle('dvc_server_fake-key', {
    logLevel: 'debug',
    logger: new CustomLogger(logger)
  }).onClientInitialized();
})();

Error stack trace

{
  "level":"error",
  "message":"Error initializing DevCycle: TypeError: Converting circular structure to JSON\n    --> starting at object with constructor 'DerivedLogger'\n    |     property '_readableState' -> object with constructor 'ReadableState'\n    |     property 'pipes' -> object with constructor 'Console'\n    --- property 'parent' closes the circle",
  "metadata":{},
  "timestamp":"2024-08-09T13:41:27.906Z"
}

memory access out of bounds issues with the nodejs-server-sdk

Hi! It's me again! haha

This time I bring up something more critical, we deployed the solution to stage, then production we saw a sudden increase of memory from the pods, and then the pods started crashing due to the memory access out of bounds error.

The error started occurring more frequently, and we rolled it back.
We are using the same stack, just updated the library as you recommended.
Node: v16.20.2 (npm v8.19.4)
@devcycle/nodejs-server-sdk: ^1.30.1

RuntimeError: memory access out of bounds\n
at wasm://wasm/000c6366:wasm-function[5]:0xd06\n 
at wasm://wasm/000c6366:wasm-function[6]:0xd45\n
at wasm://wasm/000c6366:wasm-function[499]:0x2b403\n
at wasm://wasm/000c6366:wasm-function[12]:0x1308\n
at wasm://wasm/000c6366:wasm-function[15]:0x1661\n
at __lowerTypedArray (/app/dist/node_modules/@devcycle/bucketing-assembly-script/build/bucketing-lib.release.js:573:38)\n
at Object.variableForUser_PB (/app/dist/node_modules/@devcycle/bucketing-assembly-script/build/bucketing-lib.release.js:100:18)\n 
at variableForUser_PB (/app/dist/node_modules/@devcycle/nodejs-server-sdk/src/utils/userBucketingHelper.js:52:65)\n
at DevCycleClient.variable (/app/dist/node_modules/@devcycle/nodejs-server-sdk/src/client.js:159:77)\n
at DevCycleClient.variableValue (/app/dist/node_modules/@devcycle/nodejs-server-sdk/src/client.js:177:21)\n

Could someone help with this issue?

Intermittent issue with `initializeDevCycle` function

Hi! I've been implementing the @devcycle/nodejs-server-sdk in my node backend code, and I am facing some issues with initializing the SDK incorrectly. The configuration looks right, but I noticed that the SDK fails to initialize (a few times)

The application I am integrating it is using:
Node: v16.20.2 (npm v8.19.4)
@devcycle/nodejs-server-sdk: ^1.30.0

Init code snippet:

const DEVCYCLE_SERVER_SDK_KEY = process.env.DEVCYCLE_SERVER_SDK_KEY ?? '';
let devcycleClient: DevCycleClient;

export const initDevCycle = async () => {
    devcycleClient = await initializeDevCycle(DEVCYCLE_SERVER_SDK_KEY, {
        logger: logger,
        logLevel: 'debug',
        enableCloudBucketing: false,
        configPollingIntervalMS: 10 * 1000,
    }).onClientInitialized((err) => {
        logger.error(`Fail to initialize DevCycle: ${err}`);
    });
    devcycleClient.isInitialized && logger.info('Initialized DevCycle');
};

Looking at the logs using the debug mode, I can see:

DEBUG: Requesting new config for https://config-cdn.devcycle.com/config/v1/server/dvc_server_xxx.json, etag: undefined, last-modified: undefined
ERROR: Error initializing DevCycle: Error: Config data is not set. in assembly/managers/configDataManager.ts:11:9
ERROR: Fail to initialize DevCycle: undefined

What is wrong with this configuration? I see that theconfigDataManager is validating the sdk value. However, after digging my code I noticed that the SDK value is being inserted correctly. I tried to remove all extra configuration values too, with no difference in the outcome. As mentioned at the top, it worked a few times and stopped working.

withDevCycleProvider not forwarding ref

Hello! I am currently working with DVC's @devcycle/devcycle-react-sdk package and am using the withDevCycleProvider HOC. The component I am passing to the HOC requires a React ref be forwarded and so, that component is wrapped in forwardRef from React. withDevCycleProvider does not return WrappedComponent wrapped in forwardRef. This is causing the ref to be lost.

const Component = forwardRef((props, ref) => { ....... });

export default withDevCycleProvider(configObject)(Component);  <-- returns a WrappedComponent with no forwarded ref

Environment
@devcycle/devcycle-react-sdk: ^1.11.5
node: 18.18.0
npm: 9.8.1

SSE provider not disconnected when window loses focus

Hi,

more or less related to #468, when playing around with js-sdk for Angular, I noticed that sometimes in contrast to what is described here, the SSE connection is not dropped when the user de-focuses the current page and a new one is created when returning to the page resulting in two open connections.

On other hand, in another situation the connection was open all the time regardless of whether the page is focused or not.

Are you able to somehow reproduce this on your side? Or put differently, what would be the expected behavior?

Best regards,
Alex

@devcycle/js-client-sdk depends on window object

JS SDK depends on window object being present, which does not exist in browser extensions built on manifest v3. NodeJS SDK on the other hand, depends on packages specific to NodeJS, which leaves no options to use in extension service workers.

From looking at the code, usages of window.localStorage, window.navigator.userAgent and window.addEventListener are the only instances where a window is needed. Hovewer, it is assumed that if window.addEventListener does not exist, this must be a react native app.

NodeJS SDK: Promises created as per `pollingInterval` can reject and crash the process

See line 44 of environmentConfigManager.ts - whilst the initial fetchConfigPromise is exposed to consumers so that they can handle any rejections accordingly, the subsequent fetch promises that are created per line 44 according to the polling interval are not exposed to consumer land and therefore if any of them fail, they can result in an unhandled rejections (line 82). This could potentially stop our node server process from being able to start (during autoscaling for instance) if there was an issue downloading dev cycle config.

Note: this would only happen if both the initial dev cycle config failed as well as subsequent polls. In other words, if the initial dev cycle config download success, consumers wont run into this issue.

Event queue not fully cleaned up on close

I'm integrating our backend with @devcycle/nodejs-server-sdk and having a very particular issue related to hot reloading and needing to initialize the lib multiple times by calling initializeDevCycle.

We have a custom hot reload mechanism that does not shut down the process. To summarize, it simply rebuilds, clears caches, and restarts the express app on the fly. Thus, imported packages (node_modules) are not reloaded after changing a file, making it very fast. However, when the app restarts and calls the initializeDevCycle for the second time, we get this error:

Event Queue already exists for sdkKey: ${sdkKey} you can only initialize the DevCycle SDK once per sdkKey

We're calling devCycleClient.close() when the app shuts down but that doesn't solve the problem. Looking at the code, I can see that the close() method on the DevCycleClient calls the cleanup method on the EventQueue but that's not enough. I believe that a potential solution is to also call the cleanupEventQueue(sdkKey) method when closing the client, but I'm not sure if that has any drawbacks.

That's what I'm doing to workaround the problem for now, essentially this:

import { getBucketingLib } from '@devcycle/nodejs-server-sdk/src/bucketing';

export const closeFeatureFlagsClient = async () => {
  if (devCycleClient) {
    await devCycleClient.close();
  }
  
  getBucketingLib().cleanupEventQueue(DEV_CYCLE_SERVER_KEY);
};

It works, but I believe the cleanupEventQueue method was only intended to be used internally.

Another solution I can see is to add an option to the initializeDevCycle method that would allow us to continue normally even if the queue was already created, or something like that.

`initializeDevCycle.onClientInitialized()` does not throw error when connection to DVC APIs fail

I have recently included DevCycle in my application and experienced unexpected behavior.
My expectation is that the client should not initialize if DVC cannot be reached or an invalid client SDK key is provided.

Reproduce steps

Scenario 1

An invalid SDK key is provided to the client.

Scenario 2

The DVC server cannot be reached. I was able to reproduce this by blocking network requests to DVC servers in Chrome devtools.

Example code

try {
  const client = await initializeDevCycle('invalid-client-id', {}).onClientInitialized();
  console.log('Is client initialized: ' + client.isInitialized);
} catch (error) {
  console.log('An error occurred');
}

Expected output:

'An error occurred' // console.log

Actual output:

'Is client initialized: true' // console.log
Further more, because the client initializes successfully, when await client.identifyUser(user) is invoked, an unhandled exception occurs -- seemingly in the background? -- and my application hangs.

I've been able to temporarily workaround the issue by pairing disabling of the config cache as well as verifying the client.config.project object is undefined, but this is certainly hacky.

That code looks something like

const client = await initializeDevCycle('invalid-client-id', { disableConfigCache: true }).onClientInitialized();

// only identify the user when project is truthy
if (client.config?.project) {
  await client.identifyUser(user);
}

Unable to update node sdk to v12.4

You might have leaked a private NPM package or forgot to publish something?

This error happened while installing the dependencies of @devcycle/[email protected]
@devcycle/bucketing-test-data is not in the npm registry, or you have no permission to fetch it.

Client does not remove pagehide event listener when closed

Hey DevCycle team,

This is not affecting me in any way, but I wanted to point it out as it may result in a tricky-to-debug problem for someone else.

In initializeDevCycle an event handler is registered for the pagehide event (source). As far as I can tell this event handler is never removed when a client is closed. There is also an event handler registration for the visibilitychange event when the client is created but this handler appears to be being cleaned up properly as part of the client's close method.

Provide option to disable real-time updates

Hi,

after successfully using Node.js SDK, I wanted to try integrating your library in an Angular app. It works as expected, so thanks for that.

What I realized though is that there are 3 types of requests:

In the end, my motivation is to hide these calls behind my custom domain as explained here, but since I assume that this will only work for *.devcycle.com domains & because I don't need real-time updates, I wanted to know if it is possible to completely disable that feature.

If not yet possible to disable via configuration, is this something you'd expect to be implemented in the near future?

Best regards,
Alex

initialize client with flags from server

It would be great if I could initialize the client client (haha don't know what else to call it) with flag values that I got from the server.

FWIW, the launch darkly sdk allows you to pass in an option called "bootstrap" which is a list of all flags.

Is there any ability to switch Env Key?

My app has one entry point structure and environment is related to the info which passed in token. Can I reinstantiate the initialization of connection with correct env key?
I'm working with @devcycle/react-client-sdk

Axios error when starting in Angular project

I'm having a particular problem with a angular legacy project, in angular 1.5.x and node lts/fermium (14.20.22). I'm trying to initialize the with my credentials. In node SDK works, but in js SDK get this strange error on axios.

This occurs when I import the initialize:
import { initialize } from '@devcycle/devcycle-js-sdk'

image

Realtime updates not working with next js

I have a next js app using the app router. I have added the devcycle provider following these instructions. However, after changing a flag, the page never updates. It is only after waiting a bit and doing a hard refresh that the new value for the flag is available for both client and server components. The eventstream does immediately show a change but no update is triggered on the feature flags. What am I doing wrong? I have a minimum reproduction here

@devcycle/devcycle-js-sdk shows "Failed to parse source map" warnings in the console

I used "@devcycle/devcycle-react-sdk": "^1.9.1" and started my test app, but got those "Failed to parse source map" warnings from @devcycle/devcycle-js-sdk

WARNING in ./node_modules/@devcycle/devcycle-js-sdk/src/utils.js
Module Warning (from ./node_modules/source-map-loader/dist/cjs.js):
Failed to parse source map from '/Users/test/sdk/js/src/utils.ts' file: Error: ENOENT: no such file or directory, open '/Users/test/sdk/js/src/utils.ts'

It tried to find those source files from my test project.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.