├── .eslintignore ├── .eslintrc.yaml ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md ├── actions │ ├── publish-docs │ │ └── action.yml │ └── publish-npm │ │ └── action.yml ├── pull_request_template.md └── workflows │ ├── ci.yml │ ├── lint-pr-title.yml │ ├── manual-publish.yml │ ├── release-please.yml │ └── stale.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .release-please-manifest.json ├── .sdk_metadata.json ├── CHANGELOG.md ├── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── SECURITY.md ├── azure-pipelines.yml ├── babel.config.js ├── example ├── README.md ├── example.css ├── example.js └── index.html ├── jest.config.js ├── package.json ├── release-please-config.json ├── rollup.config.js ├── scripts ├── better-audit.sh ├── publish-npm.sh ├── release-docs.sh └── release.sh ├── src ├── GoalManager.js ├── GoalTracker.js ├── __tests__ │ ├── LDClient-events-test.js │ ├── LDClient-test.js │ ├── browserPlatform-test.js │ └── internal-test.js ├── basicLogger.js ├── browserPlatform.js ├── httpRequest.js ├── index.js └── jest.setup.js ├── test-types.ts ├── tsconfig.json ├── typedoc.json └── typings.d.ts /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | dist/ 4 | eventsource.js 5 | example/example.js 6 | -------------------------------------------------------------------------------- /.eslintrc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | parser: "@babel/eslint-parser" 3 | root: true 4 | extends: 5 | - prettier 6 | - eslint:recommended # https://eslint.org/docs/rules/ 7 | env: 8 | es6: true 9 | node: true 10 | plugins: 11 | - babel 12 | - prettier 13 | globals: 14 | VERSION: true 15 | describe: true 16 | it: true 17 | expect: true 18 | jest: true 19 | beforeAll: true 20 | afterAll: true 21 | beforeEach: true 22 | afterEach: true 23 | window: true # we *do* want to allow "window" and "document" in the browser JS SDK 24 | document: true 25 | rules: 26 | # https://eslint.org/docs/rules/array-callback-return 27 | array-callback-return: error 28 | 29 | # https://eslint.org/docs/rules/arrow-body-style 30 | arrow-body-style: 31 | - error 32 | - as-needed 33 | 34 | # https://github.com/babel/eslint-plugin-babel 35 | babel/semi: error 36 | 37 | # Deprecations are required to turn enforce this 38 | camelcase: warn 39 | 40 | # https://eslint.org/docs/rules/curly 41 | curly: 42 | - error 43 | - all 44 | 45 | # https://eslint.org/docs/rules/eqeqeq 46 | eqeqeq: error 47 | 48 | # https://eslint.org/docs/rules/no-array-constructor 49 | no-array-constructor: error 50 | 51 | # https://eslint.org/docs/rules/no-eval 52 | no-eval: error 53 | 54 | # https://eslint.org/docs/rules/no-implicit-coercion 55 | no-implicit-coercion: 56 | - 'off' 57 | - boolean: false 58 | number: true 59 | string: true 60 | allow: [] 61 | 62 | # https://eslint.org/docs/rules/no-implied-eval 63 | no-implied-eval: error 64 | 65 | # https://eslint.org/docs/rules/no-nested-ternary 66 | no-nested-ternary: error 67 | 68 | # https://eslint.org/docs/rules/no-new-object 69 | no-new-object: error 70 | 71 | # https://eslint.org/docs/rules/no-new-wrappers 72 | no-new-wrappers: error 73 | 74 | # https://eslint.org/docs/rules/no-param-reassign 75 | no-param-reassign: 76 | - error 77 | - props: true 78 | 79 | # https://eslint.org/docs/rules/no-return-assign 80 | no-return-assign: error 81 | 82 | # https://eslint.org/docs/rules/no-self-compare 83 | no-self-compare: error 84 | 85 | # https://eslint.org/docs/rules/no-use-before-define 86 | no-use-before-define: 87 | - error 88 | - functions: false 89 | 90 | # https://eslint.org/docs/rules/no-var 91 | no-var: error 92 | 93 | # https://eslint.org/docs/rules/prefer-arrow-callback 94 | prefer-arrow-callback: error 95 | 96 | # https://eslint.org/docs/rules/prefer-const 97 | prefer-const: error 98 | 99 | # https://github.com/prettier/eslint-plugin-prettier 100 | prettier/prettier: 101 | - error 102 | 103 | # https://eslint.org/docs/rules/radix 104 | radix: error -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is this a support request?** 11 | This issue tracker is maintained by LaunchDarkly SDK developers and is intended for feedback on the SDK code. If you're not sure whether the problem you are having is specifically related to the SDK, or to the LaunchDarkly service overall, it may be more appropriate to contact the LaunchDarkly support team; they can help to investigate the problem and will consult the SDK team if necessary. You can submit a support request by going [here](https://support.launchdarkly.com/hc/en-us/requests/new) or by emailing support@launchdarkly.com. 12 | 13 | Note that issues filed on this issue tracker are publicly accessible. Do not provide any private account information on your issues. If your problem is specific to your account, you should submit a support request as described above. 14 | 15 | **Describe the bug** 16 | A clear and concise description of what the bug is. 17 | 18 | **To reproduce** 19 | Steps to reproduce the behavior. 20 | 21 | **Expected behavior** 22 | A clear and concise description of what you expected to happen. 23 | 24 | **Logs** 25 | If applicable, add any log output related to your problem. 26 | 27 | **SDK version** 28 | The version of this SDK that you are using. 29 | 30 | **Language version, developer tools** 31 | For instance, Go 1.11 or Ruby 2.5.3. If you are using a language that requires a separate compiler, such as C, please include the name and version of the compiler too. 32 | 33 | **OS/platform** 34 | For instance, Ubuntu 16.04, Windows 10, or Android 4.0.3. If your code is running in a browser, please also include the browser type and version. 35 | 36 | **Additional context** 37 | Add any other context about the problem here. 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Support request 4 | url: https://support.launchdarkly.com/hc/en-us/requests/new 5 | about: File your support requests with LaunchDarkly's support team 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I would love to see the SDK [...does something new...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/actions/publish-docs/action.yml: -------------------------------------------------------------------------------- 1 | name: Publish Documentation 2 | description: 'Publish documentation to github pages.' 3 | 4 | inputs: 5 | github_token: 6 | description: 'The github token to use for committing' 7 | required: true 8 | 9 | runs: 10 | using: composite 11 | steps: 12 | - uses: launchdarkly/gh-actions/actions/publish-pages@publish-pages-v1.0.2 13 | name: 'Publish to Github pages' 14 | with: 15 | docs_path: docs 16 | github_token: ${{ inputs.github_token }} 17 | -------------------------------------------------------------------------------- /.github/actions/publish-npm/action.yml: -------------------------------------------------------------------------------- 1 | name: Publish to NPM 2 | description: Publish an npm package. 3 | inputs: 4 | prerelease: 5 | description: 'Is this a prerelease. If so, then the latest tag will not be updated in npm.' 6 | required: false 7 | dry-run: 8 | description: 'Is this a dry run. If so no package will be published.' 9 | required: false 10 | 11 | runs: 12 | using: composite 13 | steps: 14 | - name: Publish 15 | shell: bash 16 | run: | 17 | ./scripts/publish-npm.sh 18 | env: 19 | LD_RELEASE_IS_PRERELEASE: ${{ inputs.prerelease }} 20 | LD_RELEASE_IS_DRYRUN: ${{ inputs.dry-run }} 21 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | **Requirements** 2 | 3 | - [ ] I have added test coverage for new or changed functionality 4 | - [ ] I have followed the repository's [pull request submission guidelines](../blob/master/CONTRIBUTING.md#submitting-pull-requests) 5 | - [ ] I have validated my changes against all supported platform versions 6 | 7 | **Related issues** 8 | 9 | Provide links to any issues in this repository or elsewhere relating to this pull request. 10 | 11 | **Describe the solution you've provided** 12 | 13 | Provide a clear and concise description of what you expect to happen. 14 | 15 | **Describe alternatives you've considered** 16 | 17 | Provide a clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | 21 | Add any other context about the pull request here. 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | paths-ignore: 7 | - '**.md' #Do not need to run CI for markdown changes. 8 | pull_request: 9 | branches: [main] 10 | paths-ignore: 11 | - '**.md' 12 | 13 | jobs: 14 | build-test: 15 | strategy: 16 | matrix: 17 | variations: [ 18 | {os: ubuntu-latest, node: latest}, 19 | {os: ubuntu-latest, node: 18} 20 | ] 21 | 22 | runs-on: ${{ matrix.variations.os }} 23 | env: 24 | TEST_SERVICE_PORT: 8000 25 | 26 | steps: 27 | - uses: actions/checkout@v4 28 | - uses: actions/setup-node@v4 29 | with: 30 | node-version: ${{ matrix.variations.node }} 31 | registry-url: 'https://registry.npmjs.org' 32 | - name: Install 33 | run: npm install 34 | - name: Test 35 | run: npm test 36 | - name: Lint 37 | run: npm run lint:all 38 | - name: Check typescript 39 | run: npm run check-typescript 40 | - name: Build Docs 41 | run: npm run doc 42 | -------------------------------------------------------------------------------- /.github/workflows/lint-pr-title.yml: -------------------------------------------------------------------------------- 1 | name: Lint PR title 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | jobs: 11 | lint-pr-title: 12 | uses: launchdarkly/gh-actions/.github/workflows/lint-pr-title.yml@main 13 | -------------------------------------------------------------------------------- /.github/workflows/manual-publish.yml: -------------------------------------------------------------------------------- 1 | name: Manual Publish Package 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | dry-run: 6 | description: 'Is this a dry run. If so no package will be published.' 7 | type: boolean 8 | required: true 9 | prerelease: 10 | description: 'Is this a prerelease. If so, then the latest tag will not be updated in npm.' 11 | type: boolean 12 | required: true 13 | 14 | jobs: 15 | publish-package: 16 | runs-on: ubuntu-latest 17 | permissions: 18 | id-token: write 19 | contents: write 20 | steps: 21 | - uses: actions/checkout@v4 22 | 23 | - uses: actions/setup-node@v4 24 | with: 25 | node-version: 20.x 26 | registry-url: 'https://registry.npmjs.org' 27 | 28 | - uses: launchdarkly/gh-actions/actions/release-secrets@release-secrets-v1.2.0 29 | name: 'Get NPM token' 30 | with: 31 | aws_assume_role: ${{ vars.AWS_ROLE_ARN }} 32 | ssm_parameter_pairs: '/production/common/releasing/npm/token = NODE_AUTH_TOKEN' 33 | 34 | - name: Install Dependencies 35 | run: npm install 36 | 37 | - id: publish-npm 38 | name: Publish NPM Package 39 | uses: ./.github/actions/publish-npm 40 | with: 41 | dry-run: ${{ inputs.dry-run }} 42 | prerelease: ${{ inputs.prerelease }} 43 | -------------------------------------------------------------------------------- /.github/workflows/release-please.yml: -------------------------------------------------------------------------------- 1 | name: Release Please 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | release-please: 10 | runs-on: ubuntu-latest 11 | outputs: 12 | release_created: ${{ steps.release.outputs.release_created }} 13 | steps: 14 | - uses: googleapis/release-please-action@v4 15 | id: release 16 | with: 17 | token: ${{secrets.GITHUB_TOKEN}} 18 | 19 | publish-package: 20 | runs-on: ubuntu-latest 21 | needs: ['release-please'] 22 | permissions: 23 | id-token: write 24 | contents: write 25 | if: ${{ needs.release-please.outputs.release_created == 'true' }} 26 | steps: 27 | - uses: actions/checkout@v4 28 | 29 | - uses: actions/setup-node@v4 30 | with: 31 | node-version: 20.x 32 | registry-url: 'https://registry.npmjs.org' 33 | 34 | - uses: launchdarkly/gh-actions/actions/release-secrets@release-secrets-v1.2.0 35 | name: 'Get NPM token' 36 | with: 37 | aws_assume_role: ${{ vars.AWS_ROLE_ARN }} 38 | ssm_parameter_pairs: '/production/common/releasing/npm/token = NODE_AUTH_TOKEN' 39 | 40 | - name: Install Dependencies 41 | run: npm install 42 | 43 | - id: publish-npm 44 | name: Publish NPM Package 45 | uses: ./.github/actions/publish-npm 46 | with: 47 | dry-run: 'false' 48 | prerelease: 'false' 49 | 50 | - name: Build Documentation 51 | run: npm run doc 52 | 53 | - id: publish-docs 54 | name: Publish Documentation 55 | uses: ./.github/actions/publish-docs 56 | with: 57 | github_token: ${{ secrets.GITHUB_TOKEN }} 58 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues and PRs' 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | # Happen once per day at 1:30 AM 6 | - cron: '30 1 * * *' 7 | 8 | jobs: 9 | sdk-close-stale: 10 | uses: launchdarkly/gh-actions/.github/workflows/sdk-stale.yml@main 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | **/junit.xml 3 | npm-debug.log 4 | yarn-error.log 5 | node_modules 6 | dist 7 | lib 8 | .idea 9 | .vscode/ 10 | test-types.js 11 | docs/build/ 12 | package-lock.json 13 | docs/ 14 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package.json 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "singleQuote": true, 4 | "printWidth": 120 5 | } 6 | -------------------------------------------------------------------------------- /.release-please-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | ".": "3.8.1" 3 | } 4 | -------------------------------------------------------------------------------- /.sdk_metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "sdks": { 4 | "js-client-sdk": { 5 | "name": "JavaScript Client SDK", 6 | "type": "client-side", 7 | "languages": [ 8 | "JavaScript", "TypeScript" 9 | ], 10 | "userAgents": ["JSClient"] 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change log 2 | 3 | All notable changes to the LaunchDarkly client-side JavaScript SDKs will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org). 4 | 5 | ## [3.8.1](https://github.com/launchdarkly/js-client-sdk/compare/3.8.0...3.8.1) (2025-05-30) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * Update to js-sdk-common 5.7.1 for updated docs ([#324](https://github.com/launchdarkly/js-client-sdk/issues/324)) ([5be94b1](https://github.com/launchdarkly/js-client-sdk/commit/5be94b1591b2595c2c06e8fc887f6e59790e498b)) 11 | 12 | ## [3.8.0](https://github.com/launchdarkly/js-client-sdk/compare/3.7.0...3.8.0) (2025-05-23) 13 | 14 | 15 | ### Features 16 | 17 | * Add support for per-context summary events. ([#321](https://github.com/launchdarkly/js-client-sdk/issues/321)) ([f5a1f80](https://github.com/launchdarkly/js-client-sdk/commit/f5a1f800920cd2667bb0f4cdee6d52a380c20ae5)) 18 | 19 | ## [3.7.0](https://github.com/launchdarkly/js-client-sdk/compare/3.6.1...3.7.0) (2025-04-29) 20 | 21 | 22 | ### Features 23 | 24 | * Add plugin support. ([3e3b7cc](https://github.com/launchdarkly/js-client-sdk/commit/3e3b7ccaea67e2d6f44a086179a272cc9e0a7c0d)) 25 | * Add support for the afterTrack stage for hooks. ([3e3b7cc](https://github.com/launchdarkly/js-client-sdk/commit/3e3b7ccaea67e2d6f44a086179a272cc9e0a7c0d)) 26 | 27 | ## [3.6.1](https://github.com/launchdarkly/js-client-sdk/compare/3.6.0...3.6.1) (2025-04-25) 28 | 29 | 30 | ### Bug Fixes 31 | 32 | * Update configuration to expect `hooks`. ([#317](https://github.com/launchdarkly/js-client-sdk/issues/317)) ([574dec8](https://github.com/launchdarkly/js-client-sdk/commit/574dec8a9fc7c7bf1f327f3e058724f0c8483c8d)) 33 | 34 | ## [3.6.0](https://github.com/launchdarkly/js-client-sdk/compare/3.5.0...3.6.0) (2025-04-21) 35 | 36 | 37 | ### Features 38 | 39 | * Add hooks support. ([46f4571](https://github.com/launchdarkly/js-client-sdk/commit/46f4571922eff6e68f66bcc35ea2b03b57da6b2c)) 40 | * Inline contexts in custom events. ([46f4571](https://github.com/launchdarkly/js-client-sdk/commit/46f4571922eff6e68f66bcc35ea2b03b57da6b2c)) 41 | 42 | ## [3.5.0](https://github.com/launchdarkly/js-client-sdk/compare/3.4.0...3.5.0) (2024-10-18) 43 | 44 | 45 | ### Features 46 | 47 | * Add support for client-side prerequisite events. ([#306](https://github.com/launchdarkly/js-client-sdk/issues/306)) ([fe51da0](https://github.com/launchdarkly/js-client-sdk/commit/fe51da0c2b974fb9b4d5fe99ad46cea35993a704)) 48 | 49 | ## [3.4.0] - 2024-06-20 50 | ### Changed: 51 | - Updated to launchdarkly-js-sdk-common 5.3.0 which supports synchronous inspectors. 52 | 53 | ## [3.3.0] - 2024-05-01 54 | ### Added: 55 | - Added an optional timeout to the `waitForInitialization` method. When a timeout is specified the returned promise will be rejected after the timeout elapses if the client has not finished initializing within that time. When no timeout is specified the returned promise will not be resolved or rejected until the initialization either completes or fails. 56 | 57 | ### Changed: 58 | - The track method now validates that the provided metricValue is a number. If a metric value is provided, and it is not a number, then a warning will be logged. 59 | 60 | ### Fixed: 61 | - Fixed the documentation for `evaluationReasons` for the `identify` method. 62 | 63 | ## [3.2.0] - 2024-03-19 64 | ### Changed: 65 | - Redact anonymous attributes within feature events 66 | - Always inline contexts for feature events 67 | 68 | ## [3.1.4] - 2023-09-06 69 | ### Fixed: 70 | - #283 Catch xhr errors on page close and ignore them to reduce noise. 71 | 72 | ## [3.1.3] - 2023-04-12 73 | ### Fixed: 74 | - Fixed an issue that was preventing page view/click events from being sent. (Thanks, [seanr-cardless](https://github.com/launchdarkly/js-client-sdk/pull/276)!) 75 | 76 | ## [3.1.2] - 2023-03-21 77 | ### Changed: 78 | - Update `LDContext` to allow for key to be optional. This is used when making an anonymous context with a generated key. 79 | 80 | ## [3.1.1] - 2023-02-15 81 | ### Changed: 82 | - Upgrade to `js-sdk-common` version `5.0.2`. This removes usage of optional chaining (`?.`) to allow for use with older transpilers. 83 | 84 | ## [3.1.0] - 2023-01-18 85 | ### Changed: 86 | - Changed event flushing on page close to be based on page visibility. This should increase compatibility with the bfcache. 87 | - Updated `launchdarkly-js-sdk-common` to version 5.0.1 for improved documentation generation. 88 | 89 | ## [3.0.0] - 2022-12-07 90 | The latest version of this SDK supports LaunchDarkly's new custom contexts feature. Contexts are an evolution of a previously-existing concept, "users." Contexts let you create targeting rules for feature flags based on a variety of different information, including attributes pertaining to users, organizations, devices, and more. You can even combine contexts to create "multi-contexts." 91 | 92 | For detailed information about this version, please refer to the list below. For information on how to upgrade from the previous version, please read the [migration guide](https://docs.launchdarkly.com/sdk/client-side/javascript/migration-2-to-3). 93 | 94 | ### Added: 95 | - The types `LDContext`, `LDSingleKindContext`, and `LDMultiKindContext` define the new "context" model. 96 | - All SDK methods that took an `LDUser` parameter now take an `LDContext`. `LDUser` is now a subset of `LDContext`, so existing code based on users will still work. 97 | 98 | ### Changed _(breaking changes from 3.x)_: 99 | - There is no longer such a thing as a `secondary` meta-attribute that affects percentage rollouts. If you set an attribute with that name in `LDContext`, it will simply be a custom attribute like any other. 100 | - Evaluations now treat the `anonymous` attribute as a simple boolean, with no distinction between a false state and an undefined state. 101 | - `LDClient.getUser` has been replaced with `LDClient.getContext`. 102 | - `privateAttributeNames` has been replaced with `privateAttributes` in `LDOptions`. Private attributes now allow using attribute references. 103 | 104 | 105 | ### Changed (behavioral changes): 106 | - Analytics event data now uses a new JSON schema due to differences between the context model and the old user model. 107 | 108 | ### Removed: 109 | - Removed all types, fields, and methods that were deprecated as of the most recent 3.x release. 110 | - Removed the `secondary` meta-attribute in `LDUser`. 111 | - The `alias` method no longer exists because alias events are not needed in the new context model. 112 | - The `autoAliasingOptOut` and `inlineUsersInEvents` options no longer exist because they are not relevant in the new context model. 113 | 114 | ### Deprecated: 115 | - The `LDUser` object has been deprecated. Support for `LDUser` is maintained to simplify the upgrade process, but it is recommended to use `LDContext` in the shape of either `LDSingleKindContext` or `LDMultiKindContext`. 116 | 117 | ## [2.24.2] - 2022-10-20 118 | ### Changed: 119 | - Updated to `js-sdk-common` `3.8.2` which includes jitter and backoff for re-connection attempts for streaming connections. 120 | 121 | ## [2.24.0] - 2022-10-18 122 | ### Changed: 123 | - Upgrade to `js-sdk-common` `3.8.1` which added support for `Inspectors` that can be used for collecting information for monitoring, analytics, and debugging. 124 | 125 | ## [2.23.0] - 2022-10-05 126 | ### Changed: 127 | - Updated `js-sdk-common` version which removed event de-duplication functionality which was made redundant by support of summary events. This will improve the default event behavior when using experimentation. 128 | 129 | - Updated `escape-string-regexp` to version 4. 130 | 131 | - Updated development dependencies to recent versions. 132 | 133 | ### Deprecated: 134 | - Deprecated the `allowFrequentDuplicateEvents` configuration option. Setting the option will no longer have any effect, and it will be removed in a future version. 135 | 136 | ## [2.22.1] - 2022-04-27 137 | This release is functionally identical to the 2.22.0 release. Due to an oversight the release process re-introduced the `package-lock.json`. 138 | 139 | ### Removed: 140 | - The `package-lock.json` file is no longer in source control. As this is a library project, the lockfile never affected application code that used the SDK, but only affected the SDK's CI build. It is preferable for the CI build to refer only to package.json so that it resolves dependencies the same way an application using the SDK would, rather than using pinned dependencies that an application would not use. 141 | 142 | ## [2.22.0] - 2022-04-26 143 | ### Added: 144 | - `LDOptions.application`, for configuration of application metadata that may be used in LaunchDarkly analytics or other product features. This does not affect feature flag evaluations. 145 | 146 | ### Fixed: 147 | - The `baseUrl`, `streamUrl`, and `eventsUrl` properties now work properly regardless of whether the URL string has a trailing slash. Previously, a trailing slash would cause request URL paths to have double slashes. 148 | 149 | ### Removed: 150 | - The `package-lock.json` file is no longer in source control. As this is a library project, the lockfile never affected application code that used the SDK, but only affected the SDK's CI build. It is preferable for the CI build to refer only to `package.json` so that it resolves dependencies the same way an application using the SDK would, rather than using pinned dependencies that an application would not use. 151 | 152 | ## [2.21.0] - 2022-03-21 153 | ### Added: 154 | - Added `basicLogger`, a replacement for the deprecated `createConsoleLogger`. 155 | 156 | ## [2.20.2] - 2022-02-18 157 | ### Fixed: 158 | - If the SDK receives invalid JSON data from a streaming connection (possibly as a result of the connection being cut off), it now uses its regular error-handling logic: the error is emitted as an `error` event or, if there are no `error` event listeners, it is logged. Previously, the error would be thrown as an unhandled exception. 159 | 160 | ## [2.20.1] - 2022-02-02 161 | ### Fixed: 162 | - If the browser local storage mechanism throws an exception (for instance, if it is disabled or if storage is full), the SDK now correctly catches the exception and logs a message about the failure. It will only log this message once during the lifetime of the SDK client. ([#54](https://github.com/launchdarkly/js-sdk-common/issues/54)) 163 | 164 | ## [2.20.0] - 2021-10-15 165 | ### Added: 166 | - New property `LDOptions.requestHeaderTransform` allows custom headers to be added to all HTTP requests. This may be necessary if you have an Internet gateway that uses a custom header for authentication. Note that custom headers may cause cross-origin browser requests to be rejected unless you have a way to ensure that the header name also appears in `Access-Control-Allow-Headers` for CORS preflight responses; if you are connecting to the LaunchDarkly Relay Proxy, it has a way to configure this. 167 | 168 | ## [2.19.4] - 2021-10-12 169 | ### Fixed: 170 | - Removed an obsolete warning that would appear in the browser console after calling `track`: `Custom event "_____" does not exist`. Originally, the SDK had an expectation that `track` would be used only for event keys that had been previously defined as custom goals in the LaunchDarkly dashboard. That is still often the case, but it is not required and LaunchDarkly no longer sends custom goal names to the SDK, so the warning was happening even if such a goal did exist. 171 | 172 | ## [2.19.3] - 2021-06-08 173 | _This release is broken and cannot be used._ 174 | 175 | ## [2.19.2] - 2021-06-08 176 | ### Fixed: 177 | - Events for the [LaunchDarkly debugger](https://docs.launchdarkly.com/home/flags/debugger) are now properly pre-processed to omit private user attributes, as well as enforce only expected top level attributes are sent. 178 | - Events for the [LaunchDarkly debugger](https://docs.launchdarkly.com/home/flags/debugger) now include the index of the variation responsible for the evaluation result. 179 | 180 | 181 | ## [2.19.1] - 2021-04-01 182 | ### Fixed: 183 | - The property `LDOptions.inlineUsersInEvents` was not included in the TypeScript definitions. 184 | 185 | ## [2.19.0] - 2021-01-27 186 | ### Added: 187 | - Added the `alias` method. This method can be used to associate two user objects for analytics purposes. When invoked, this method will queue a new alias event to be sent to LaunchDarkly. 188 | - Added the `autoAliasingOptOut` configuration option. This can be used to control the new automatic aliasing behavior of the `identify` method; by passing `autoAliasingOptOut: true`, `identify` will not automatically generate alias events. 189 | 190 | ### Changed: 191 | - The `identify` method will now automatically generate an alias event when switching from an anonymous to a known user. This event associates the two users for analytics purposes as they most likely represent a single person. 192 | 193 | ## [2.18.3] - 2020-11-17 194 | ### Fixed: 195 | - Updated the `LDEvaluationDetail.reason` type definition to be nullable. This value will be `null` when `LDOptions.evaluationReasons` is `false`. 196 | 197 | 198 | ## [2.18.2] - 2020-10-19 199 | ### Changed: 200 | - With goals that use substring or regex mode for URL matching, the SDK previously was not able to match anything in a URL's hash fragment. Since some applications use path-like hash fragments (`http://example.com/url/path#/additional/path`), the SDK now considers any hash string that contains a slash to be part of the URL for matching purposes, _if_ the matching mode is substring or regex. Hash strings that do not contain a slash are assumed to be simple HTML anchors and are not included in matching. 201 | 202 | ## [2.18.1] - 2020-09-14 203 | ### Fixed: 204 | - In streaming mode, when connecting to the Relay Proxy rather than directly to the LaunchDarkly streaming service, if the current user was changed twice within a short time it was possible for the SDK to revert to flag values from the previous user. 205 | 206 | ## [2.18.0] - 2020-07-16 207 | ### Added: 208 | - Configuration option `disableSyncEventPost`, for preventing the SDK from trying to do a synchronous HTTP request to deliver analytics events while the page is closing. Such requests are not supported in current versions of Chrome, and although the SDK uses browser detection to avoid doing them if they are not supported, the browser detection mechanism does not work in some test environments. 209 | 210 | ## [2.17.6] - 2020-07-13 211 | ### Fixed: 212 | - Removed uses of `String.startsWith` that caused errors in Internet Explorer unless a polyfill for that function was present. 213 | 214 | ## [2.17.5] - 2020-05-13 215 | ### Fixed: 216 | - The TypeScript declaration for `track()` was missing the optional `metricValue` parameter. 217 | 218 | ## [2.17.4] - 2020-04-30 219 | ### Fixed: 220 | - Some diagnostic event data was being sent twice, resulting in extra HTTP requests. This did not affect analytics events, so customer data on the dashboard and in data export would still be correct. 221 | 222 | ## [2.17.3] - 2020-03-31 223 | ### Fixed: 224 | - The default logging implementation (`createConsoleLogger`) could throw errors in Internet Explorer 11 if log output (of an enabled level) happened while the developer tools were _not_ open. This is because in IE 11, the `console` object [does not exist](https://www.beyondjava.net/console-log-surprises-with-internet-explorer-11-and-edge) unless the tools are open. This has been fixed so the logger does not try to use `console` unless it currently has a value. 225 | - Updated some dependency versions to resolve a security vulnerability in the transitive `acorn` dependency. This dependency is only used for development and as a result the security vulnerability did not affect customers. 226 | 227 | ## [2.17.2] - 2020-03-18 228 | ### Fixed: 229 | - Some users reported an error where the SDK said that the content type of a response was `application/json, application/json; charset=utf8`. It is invalid to have multiple Content-Type values in a response and the LaunchDarkly service does not do this, but an improperly configured proxy/gateway might add such a header. Now the SDK will tolerate a value like this as long as it starts with `application/json`. ([#205](https://github.com/launchdarkly/js-client-sdk/issues/205)) 230 | - Fixed incorrect usage of `Object.hasOwnProperty` which could have caused an error if a feature flag had `hasOwnProperty` as its flag key. 231 | 232 | ## [2.17.1] - 2020-03-06 233 | ### Fixed: 234 | - At client initialization time, if the initial flag polling request failed, it would cause an unhandled promise rejection unless the application had called `waitForInitialization()` and provided an error handler for the promise that was returned by that method. While that is correct behavior if the application did call `waitForInitialization()` (any promise that might be rejected should have an error handler attached), it is inappropriate if the application did not call `waitForInitialization()` at all-- which is not mandatory, since the application could use events instead, or `waitUntilReady()`, or might simply not care about waiting for initialization. This has been fixed so that no such promise is created until the first time the application calls `waitForInitialization()`; subsequent calls to the same method will return the same promise (since initialization can only happen once). 235 | - A bug in the event emitter made its behavior unpredictable if an event handler called `on` or `off` while handling an event. This has been fixed so that all event handlers that were defined _at the time the event was fired_ will be called; any changes made will not take effect until the next event. 236 | 237 | ## [2.17.0] - 2020-02-14 238 | Note: if you are using the LaunchDarkly Relay Proxy to forward events, update the Relay to version 5.10.0 or later before updating to this Node SDK version. 239 | 240 | ### Added: 241 | - The SDK now periodically sends diagnostic data to LaunchDarkly, describing the version and configuration of the SDK, the architecture and version of the runtime platform, and performance statistics. No credentials, hostnames, or other identifiable values are included. This behavior can be disabled with the `diagnosticOptOut` option, or configured with `diagnosticRecordingInterval`. 242 | 243 | ### Fixed: 244 | - When using secure mode in conjunction with streaming mode, if an application specified a new `hash` parameter while changing the current user with `identify()`, the SDK was not using the new `hash` value when recomputing the stream URL, causing the stream to fail. (Thanks, [andrao](https://github.com/launchdarkly/js-sdk-common/issues/13)!) 245 | - The `LICENSE.txt` file was accidentally replaced with an incomplete license in an earlier release. The standard Apache 2.0 license file has been restored. ([#202](https://github.com/launchdarkly/js-client-sdk/issues/202)) 246 | 247 | ## [2.16.3] - 2020-02-05 248 | ### Fixed: 249 | - Changed some exact version dependencies to "highest compatible" dependencies, to avoid having modules that are also used by the host application loaded twice by NPM. The dependency on `js-sdk-common` is still an exact version dependency so that each release of `js-client-sdk` has well-defined behavior for that internal code. 250 | 251 | ### Removed: 252 | - Removed an unused transitive dependency on `@babel/polyfill`. (Thanks, [bdwain](https://github.com/launchdarkly/js-sdk-common/pull/7)!) 253 | 254 | 255 | ## [2.16.2] - 2020-01-27 256 | ### Fixed: 257 | - If the user started to navigate away from the page, but then did not actually do so (for instance, if the application cancelled the `beforeunload` event, or if a nonstandard URL scheme caused the browser to launch an external app), the SDK could be left in a state where all of its HTTP requests would be made synchronously. This has been fixed so the only synchronous request the SDK makes is when it needs to flush events during a `beforeunload`. (Thanks, [edvinerikson](https://github.com/launchdarkly/js-client-sdk/pull/199)!) 258 | 259 | ## [2.16.1] - 2020-01-15 260 | **Note:** If you use the Relay Proxy, and have configured it to forward events, please update it to version 5.9.4 or later before using this version of the browser SDK. Otherwise you may encounter CORS errors in the browser. 261 | 262 | ### Fixed: 263 | - The SDK now specifies a uniquely identifiable request header when sending events to LaunchDarkly to ensure that events are only processed once, even if the SDK sends them two times due to a failed initial attempt. 264 | 265 | ## [2.16.0] - 2019-12-16 266 | ### Added: 267 | - Configuration property `eventCapacity`: the maximum number of analytics events (not counting evaluation counters) that can be held at once, to prevent the SDK from consuming unexpected amounts of memory in case an application generates events unusually rapidly. In JavaScript code this would not normally be an issue, since the SDK flushes events every two seconds by default, but you may wish to increase this value if you will intentionally be generating a high volume of custom or identify events. The default value is 100. 268 | - Configuration properties `wrapperName` and `wrapperVersion`: used by the React SDK, and potentially by third-party libraries, to identify a JS SDK instance that is being used with a wrapper API. 269 | 270 | ### Changed: 271 | - The SDK now logs a warning if any configuration property has an inappropriate type, such as `baseUri:3` or `sendEvents:"no"`. For boolean properties, the SDK will still interpret the value in terms of truthiness, which was the previous behavior. For all other types, since there's no such commonly accepted way to coerce the type, it will fall back to the default setting for that property; previously, the behavior was undefined but most such mistakes would have caused the SDK to throw an exception at some later point. 272 | - Removed or updated some development dependencies that were causing vulnerability warnings. 273 | 274 | ### Fixed: 275 | - When calling `identify`, the current user (as reported by `getUser()`) was being updated before the SDK had received the new flag values for that user, causing the client to be temporarily in an inconsistent state where flag evaluations would be associated with the wrong user in analytics events. Now, the current-user state will stay in sync with the flags and change only when they have finished changing. (Thanks, [edvinerikson](https://github.com/launchdarkly/js-sdk-common/pull/3)!) 276 | 277 | ### Deprecated: 278 | - The `samplingInterval` configuration property was deprecated in the code in the previous minor version release, and in the changelog, but the deprecation notice was accidentally omitted from the documentation comments. It is hereby deprecated again. 279 | 280 | ## [2.15.2] - 2019-11-15 281 | ### Fixed: 282 | - Releases after 2.14.1 were continuing to report the `version` property as "2.14.1". This property will now once again be consistent with the actual release version. 283 | 284 | ## [2.15.1] - 2019-11-06 285 | ### Fixed: 286 | - A runtime dependency on `typedoc` was mistakenly added in the 2.15.0 release. This has been removed. 287 | 288 | 289 | ## [2.15.0] - 2019-11-05 290 | ### Changed: 291 | - Changed the behavior of the warning message that is logged on failing to establish a streaming connection. Rather than the current behavior where the warning message appears upon each failed attempt, it will now only appear on the first failure in each series of attempts. Also, the message has been changed to mention that retries will occur. ([#182](https://github.com/launchdarkly/js-client-sdk/issues/182)) 292 | - The source code for the `launchdarkly-js-sdk-common` package has been moved out of this repository into [`js-sdk-common`](https://github.org/launchdarkly-js-sdk-common), and will now be versioned separately. Applications should never refer to the common package directly; it is brought in automatically by `launchdarkly-js-client-sdk`. Changes made in the common code that affect JS SDK functionality will be noted in the main changelog here. 293 | - There is a new, much fuller-featured demo application in the `example` directory, which may be useful for testing not only of the JS SDK but of feature flag evaluation in general. 294 | 295 | ### Fixed: 296 | - The `beforeunload` event handler no longer calls `close` on the client, which was causing the SDK to become unusable if the page did not actually close after this event fired (for instance if the browser navigated to a URL that launched an external application, or if another `beforeunload` handler cancelled leaving the page). Instead, it now only flushes events. There is also an `unload` handler that flushes any additional events that might have been created by any code that ran during the `beforeunload` stage. ([#181](https://github.com/launchdarkly/js-client-sdk/issues/181)) 297 | - Removed uses of `Object.assign` that caused errors in Internet Explorer unless a polyfill for that function was present. These were removed earlier in the 2.1.1 release, but had been mistakenly added again. 298 | 299 | ### Deprecated: 300 | - The `samplingInterval` configuration property is deprecated and will be removed in a future version. The intended use case for the `samplingInterval` feature was to reduce analytics event network usage in high-traffic applications. This feature is being deprecated in favor of summary counters, which are meant to track all events. 301 | 302 | 303 | ## [2.14.0] - 2019-10-10 304 | ### Added: 305 | - Added support for upcoming LaunchDarkly experimentation features. See `LDClient.track()`. 306 | - The `createConsoleLogger()` function now has an optional second parameter for customizing the log prefix. 307 | 308 | ### Changed: 309 | - Log messages now include the level ("[warn]", "[error]", etc.) and have a prefix of "LD:" by default. 310 | 311 | ### Removed: 312 | - The source code for the `launchdarkly-react-client-sdk` package is no longer part of this monorepo. It is now in its own repository, [`react-client-sdk`](https://github.com/launchdarkly/react-client-sdk). Future updates to the LaunchDarkly React interface will be tracked there. 313 | 314 | Note that the React SDK code has moved to its own repository, [`react-client-sdk`](https://github.com/launchdarkly/react-client-sdk). The 2.13.0 release was the last one that had the React wrapper code in the same repository, and from this point on the React package will be versioned separately. 315 | 316 | ## [2.13.0] - 2019-08-15 317 | ### Added: 318 | - A `jsdelivr` entry to `package.json` to specify the primary build artifact and simplify the jsDelivr snippet URL. 319 | - In the React SDK, the new `reactOptions` parameter to `withLDProvider` provides React-specific options that do not affect the underlying JavaScript SDK. Currently, the only such option is `useCamelCaseFlagKeys`, which is true by default but can be set to false to disable the automatic camel-casing of flag keys. 320 | 321 | ### Changed: 322 | - In the React SDK, when omitting the `user` parameter to `withLDProvider`, an anonymous user will be created. This user will remain constant across browser sessions. Previously a new user was generated on each page load. 323 | 324 | ## [2.12.5] - 2019-07-29 325 | ### Changed: 326 | - The error messages logged upon having an invalid environment/client-side ID have been updated to better clarify what went wrong. ([#165](https://github.com/launchdarkly/js-client-sdk/issues/165)) 327 | 328 | ### Fixed: 329 | - The React SDK was incompatible with Internet Explorer 11 due to using `String.startsWith()`. (Thanks, [cvetanov](https://github.com/launchdarkly/js-client-sdk/pull/169)!) 330 | - There was a broken documentation link in the error message logged when initially sending an event without identifying a user. The broken link has been fixed. 331 | 332 | ## [2.12.4] - 2019-07-10 333 | ### Changed: 334 | - The `useReport` property, which tells the SDK to use the REPORT method for HTTP requests so that user data will not appear in the URL path, was only actually using REPORT for requesting all flags at once— not for streaming updates, because streaming uses the EventSource API which normally can only use the GET method; so, to avoid exposing user data in the URL for the streaming connection, the SDK had to use a different and slower mechanism (in which all of the flags are reloaded whenever there is a change) if `useReport` was true. That is still the case by default; but, if you load the specific EventSource [polyfill implementation](https://docs.launchdarkly.com/sdk/client-side/javascript/requirements-polyfills) [`launchdarkly-eventsource`](https://github.com/launchdarkly/js-eventsource) (v1.1.0 or later), the SDK _can_ now use REPORT for streaming connections. 335 | 336 | ### Fixed: 337 | - The `homepage` attribute in the `launchdarkly-react-client-sdk` and `launchdarkly-react-client-sdk-example` packages has been updated to the correct value. 338 | 339 | ## [2.12.3] - 2019-07-08 340 | ### Added: 341 | - The SDK now logs a message at `info` level when the stream connection is started or stopped. It also logs a message at `warn` level if it detects that the stream had to be restarted due to a connection failure; however, in browsers that have native support for EventSource, connection restarts may be handled internally by the browser in which case there will be no log message. 342 | 343 | ### Changed: 344 | - When providing precomputed flag values to the SDK via the `bootstrap` option, these values will now be immediately available as soon as `initialize()` returns. That was already the behavior in earlier versions of the SDK, but ever since version 2.10.0 the values only became available once the client was officially ready (i.e. the `ready` event had fired or the `waitUntilInitialized()` promise had resolved), so they could not be used in non-asynchronous application code. The correct behavior had never been explicitly defined, so this had not been documented as a change. The behavior is now as it was prior to 2.10.0, and is now documented as such. ([#162](https://github.com/launchdarkly/js-client-sdk/issues/162)) 345 | 346 | ### Fixed: 347 | - Under some circumstances, the SDK would fail to restart a streaming connection if it had already been dropped and restarted before. This normally would not happen when using a built-in browser implementation of EventSource, but could happen with some EventSource polyfills. 348 | - Fixed a broken link in the project README. 349 | 350 | ## [2.1.2] - 2019-06-28 351 | ### Fixed: 352 | - The `eventUrlTransformer` property that was added in 2.12.0 had no effect. It now works. 353 | 354 | 355 | ## [2.12.1] - 2019-06-28 356 | ### Added: 357 | - The SDK now logs a message at `info` level when the stream connection is started or stopped. It also logs a message at `warn` level if it detects that the stream had to be restarted due to a connection failure; however, in browsers that have native support for EventSource, connection restarts may be handled internally by the browser in which case there will be no log message. 358 | 359 | ### Fixed: 360 | - Under some circumstances, the SDK would fail to restart a streaming connection if it had already been dropped and restarted before. This normally would not happen when using a built-in browser implementation of EventSource, but could happen with some EventSource polyfills. 361 | - Fixed a broken link in the project README. 362 | 363 | ## [2.12.0] - 2019-06-18 364 | ### Added: 365 | - Configuration property `eventUrlTransformer` allows application code to modify the URL that is sent in analytics events. 366 | ### Fixed: 367 | - If the SDK receives data from the service that does not have the expected JSON content type, it will now log an appropriate error message, rather than "Error fetching flags: 200". 368 | 369 | ## [2.11.0] - 2019-06-06 370 | ### Added: 371 | - Added support for hooks to the React SDK. 372 | 373 | ## [2.10.4] - 2019-05-22 374 | ### Added: 375 | - `unpkg` entry to `package.json` to specify primary build artifact to simplify the unpkg snippet URL. 376 | ### Fixed: 377 | - Streaming updates did not work if `useReport` was enabled, or if the SDK was connecting through the LaunchDarkly relay proxy. This bug was introduced in version 2.10.0. 378 | 379 | ## [2.10.3] - 2019-05-08 380 | ### Changed: 381 | - Changed the package names from `ldclient-js`, `ldclient-react`, and `ldclient-js-common` to `launchdarkly-js-client-sdk`, `launchdarkly-react-client-sdk`, and `launchdarkly-js-sdk-common`, respectively. 382 | 383 | There are no other changes in this release. Substituting `ldclient-js`, `ldclient-react`, and `ldclient-js-common` version 2.10.2 with `launchdarkly-js-client-sdk`, `launchdarkly-react-client-sdk`, and `launchdarkly-js-sdk-common` version 2.10.3 will not affect functionality. 384 | 385 | ### Fixed: 386 | - Fixed some broken links in the package READMEs. 387 | 388 | ## [2.10.2] - 2019-05-01 389 | ### Fixed: 390 | - Fixed a problem that prevented the Electron and client-side Node SDKs from reporting their own version strings correctly. This fix does not affect the browser JS SDK, so there is no need to upgrade if you are using that. 391 | 392 | ### Note on future releases: 393 | 394 | The LaunchDarkly SDK repositories are being renamed for consistency. This repository is now `js-client-sdk` rather than `js-client`. 395 | 396 | The package names will also change. In the 2.10.2 release, there were packages for `ldclient-js`, `ldclient-react` and `ldclient-js-common`; in all future releases, they will be `launchdarkly-js-client-sdk`, `launchdarkly-react-client-sdk`, and `launchdarkly-js-sdk-common`, respectively. 397 | 398 | ## [2.10.1] - 2019-04-23 399 | ### Fixed: 400 | - The 2.10.0 release added a usage of the `Promise.finally()` method, which made it incompatible with some older browsers. This has been removed. ([#151](https://github.com/launchdarkly/js-client/issues/151)) 401 | 402 | ## [2.10.0] - 2019-04-19 403 | ### Added: 404 | - Generated TypeDoc documentation for all types, properties, and methods is now available online at [https://launchdarkly.github.io/js-client/](https://launchdarkly.github.io/js-client/). Currently this will only be for the latest released version. 405 | - The SDK now allows you to specify an anonymous user without a key (i.e. the `anonymous` property is `true`, and there is no `key` property). In that case, the SDK will generate a UUID and send that as the user key. It will also cache this generated key in local storage (if local storage is available) so that anonymous users in the same browser will always get the same key. 406 | 407 | ### Fixed: 408 | - Setting user attributes to non-string values when a string was expected would prevent evaluations and analytics events from working. The SDK will now convert attribute values to strings as needed. 409 | 410 | ## [2.9.7] - 2019-04-16 411 | ### Fixed: 412 | - If there are pending analytics events when the page is being closed, the SDK normally attempts to deliver them by making a synchronous HTTP request. Chrome, as of version 73, does not allow this and logs an error. An upcoming release will change how events are sent, but as a temporary measure to avoid these errors, the SDK will now simply discard any pending events when the page is being closed _if_ the browser is Chrome version 73 or higher. In other browsers, there is no change. Note that this means that in Chrome 73, some events may be lost; that was already the case. The purpose of this patch is simply to avoid triggering errors. ([#178](https://github.com/launchdarkly/js-client-private/pull/178)) 413 | 414 | ## [2.9.6] - 2019-04-16 415 | 416 | This release was an error and has been removed. 417 | 418 | ## [2.9.5] - 2019-03-12 419 | ### Fixed: 420 | - In React, when using the `bootstrap` property to preload the SDK client with flag values, the client will now become ready immediately and make the flags available to other components as soon as it is initialized; previously this did not happen until after `componentDidMount`. 421 | - The user attribute `secondary` was not included in the TypeScript declarations and therefore could not be used from TypeScript code. 422 | 423 | ## [2.9.4] - 2019-02-22 424 | ### Fixed: 425 | - Running inside an iframe on Chrome with third-party cookies disabled-- which also disables HTML5 local storage-- would cause a security exception (due to the SDK attempting to check whether `window.localStorage` exists). This was a long-standing problem, but became worse in the 2.9.0 release since the SDK now checks for browser capabilities like this regardless of whether you've attempted to use them yet. It should now simply log a warning if you try to use `bootstrap: "localstorage"` when local storage is disabled. ([#138](https://github.com/launchdarkly/js-client/issues/138)) 426 | - If the SDK received streaming updates out of order (rare, but possible) such that it received "flag X was deleted" prior to "flag X was created", an uncaught exception would be logged in the browser console (but would not otherwise affect anything). 427 | - A supported user property, `privateAttributeNames`, was not usable from TypeScript because it was omitted from the TypeScript declarations. 428 | - Several TypeScript declarations had been changed from `interface` to `type`. They all now use `interface`, except for `LDFlagValue` which is a type alias. This should not affect regular usage of the SDK in TypeScript, but it is easier to extend an `interface` than a `type` if desired. 429 | - Removed a window message listener that was previously used for integration with the LaunchDarkly dashboard, but is no longer used. 430 | 431 | ## [2.9.3] - 2019-02-12 432 | ### Fixed: 433 | - The React SDK was pulling in the entire `lodash` package. This has been improved to only require the much smaller `camelcase` tool from `lodash`. 434 | - The React SDK now lists React itself as a peer dependency rather than a regular dependency, so it will not included twice in an application that already requires React. 435 | - Corrected the TypeScript declaration for the `identify` method to indicate that its asynchronous result type is `LDFlagSet`, not `void`. (Thanks, [impressiver](https://github.com/launchdarkly/js-client/pull/135)!) 436 | - Corrected and expanded many documentation comments in the TypeScript declarations. 437 | 438 | (The 2.9.2 release was broken and has been removed.) 439 | 440 | ## [2.9.1] - 2019-02-08 441 | ### Fixed: 442 | - The previous release of `ldclient-react` was broken: the package did not contain the actual files. The packaging script has been fixed. There are no other changes. 443 | 444 | ## [2.9.0] - 2019-02-01 445 | ### Added: 446 | - The new [`ldclient-react`](packages/ldclient-react/README.md) package provides a convenient mechanism for using the LaunchDarkly SDK within the React framework. 447 | - The new `getUser()` method returns the current user object. 448 | - The client options can now have a `logger` property that defines a custom logging mechanism. The default is still to use `console.warn` and `console.error`; you could override this to send log messages to another destination or to suppress them. See `LDLogger` and `createConsoleLogger` in the [TypeScript definitions](packages/ldclient-js-common/typings.d.ts). 449 | 450 | ### Changed: 451 | - The SDK now uses an additional package, `ldclient-js-common`, consisting of code that is also used by other LaunchDarkly SDKs. This is automatically loaded as a dependency of `ldclient-js` so you should notice any difference. However, the source code has been reorganized so that this project is now a monorepo containing multiple packages. 452 | 453 | ## [2.8.0] - 2018-12-03 454 | ### Added: 455 | - The use of a streaming connection to LaunchDarkly for receiving live updates can now be controlled with the new `client.setStreaming()` method, or the equivalent boolean `streaming` property in the client configuration. If you set this to `false`, the client will not open a streaming connection even if you subscribe to change events (you might want to do this if, for instance, you just want to be notified when the client gets new flag values due to having switched users). If you set it to `true`, the client will open a streaming connection regardless of whether you subscribe to change events or not (the flag values will simply be updated in the background). If you don't set it either way then the default behavior still applies, i.e. the client opens a streaming connection if and only if you subscribe to change events. 456 | 457 | ### Fixed: 458 | - If the client opened a streaming connection because you called `on('change', ...)` one or more times, it will not close the connection until you call `off()` for _all_ of your event listeners. Previously, it was closing the connection whenever `off('change')` was called, even if you still had a listener for `'change:specific-flag-key'`. 459 | - The client's logic for signaling a `change` event was using a regular Javascript `===` comparison, so it could incorrectly decide that a flag had changed if its value was a JSON object or an array. This has been fixed to use deep equality checking for object and array values. 460 | 461 | ## [2.7.5] - 2018-11-21 462 | ### Fixed: 463 | - When using the [`event-source-polyfill`](https://github.com/Yaffle/EventSource) package to allow streaming mode in browsers with no native EventSource support, the polyfill was using a default read timeout of 45 seconds, so if no updates arrived within 45 seconds it would log an error and reconnect the stream. The SDK now sets its own timeout (5 minutes) which will be used if this particular polyfill is active. LaunchDarkly normally sends a heartbeat every 3 minutes, so you should not see a timeout happen unless the connection has been lost. 464 | - The SDK's use of the "Base64" package caused problems for build tools that strictly enforce the lowercase package name rule. It now uses the "base64-js" package instead. ([#124](https://github.com/launchdarkly/js-client/issues/124)) 465 | 466 | ## [2.7.4] - 2018-11-21 467 | (This version was skipped due to a release problem.) 468 | 469 | ## [2.7.3] - 2018-11-09 470 | ### Fixed: 471 | - The TypeScript definitions were incorrectly restricting the possible values for event types in `on()` and `off()`. Also, added documentation for event types which were not documented before. ([#122](https://github.com/launchdarkly/js-client/issues/122)) 472 | 473 | ## [2.7.2] - 2018-10-17 474 | ### Fixed: 475 | - Disconnecting from the stream does not close the browser tab anymore. 476 | (Thanks, [Sawtaytoes](https://github.com/launchdarkly/js-client/issues/119).) 477 | - The configuration property `evaluationReasons` was misnamed as `evaluationExplanations` in the TypeScript definitions. 478 | 479 | ## [2.7.1] - 2018-09-27 480 | ### Fixed: 481 | - Event posts did not include the HTTP header that specifies the SDK version. They now do again. Note that the `sendLDHeaders` option does not affect this; if the header is turned off for flag requests, it should still be sent in events, since events always require a CORS preflight check anyway (and are delivered asynchronously, so the OPTIONS request does not slow down page loads). 482 | 483 | ## [2.7.0] - 2018-09-26 484 | ### Added: 485 | - New client method `waitForInitialization` returns a Promise, like `waitUntilReady`; but while `waitUntilReady` will be resolved as soon as client initialization either succeeds or fails, `waitForInitialization` will be resolved only if initialization succeeds, and will be rejected (with an error object) if it fails. 486 | - New config option `fetchGoals` (default: true) allows you to control whether the client will request A/B testing parameters from LaunchDarkly. If you do not use A/B testing, you may wish to disable this to reduce the number of HTTP requests. 487 | - New config option `sendLDHeaders` (default: true) allows you to control whether the client will add a custom HTTP header to LaunchDarkly flag requests (to indicate the SDK version). You may wish to disable this behavior if you have performance concerns, as it causes browsers to make an additional CORS preflight check (since it is no longer a [simple request](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)). 488 | 489 | ## [2.6.0] - 2018-09-07 490 | ### Added: 491 | - The new configuration option `evaluationReasons` causes LaunchDarkly to report information about how each feature flag value was determined; you can access this information with the new client method `variationDetail`. The new method returns an object that contains both the flag value and a "reason" object which will tell you, for instance, if the user was individually targeted for the flag or was matched by one of the flag's rules, or if the flag returned the default value due to an error. 492 | 493 | ### Changed: 494 | - In streaming mode, the client will attempt to reconnect if it receives an HTTP error status from LaunchDarkly. Previously, it would only retry if the connection was lost. 495 | 496 | ## [2.5.0] - 2018-08-27 497 | ### Changed: 498 | - Starting in version 2.0.0, there was a problem where analytics events would not be generated correctly if you initialized the client with bootstrap data, because the bootstrap data did not include some flag metadata that the front end uses for events. The client now supports an extended format for bootstrap data that fixes this problem; this is generated by calling a new method that has been added to the server-side SDKs, `allFlagsState`/`all_flags_state` (previously `allFlags`/`all_flags`). Therefore, if you want analytics event data and you are using bootstrap data from the back end, you should upgrade both your JavaScript SDK and your server-side SDK, and use `allFlagsState` on the back end. This does not require any changes in your JavaScript code. If you use bootstrap data in the old format, the SDK will still be usable but events will not work correctly. 499 | - When posting events to LaunchDarkly, if a request fails, it will be retried once. 500 | - The TypeScript mappings for the SDK were omitted from the distribution in the previous release. They are now in the distribution again, in the root folder instead of in `src`, and have been renamed from `index.d.ts` to `typings.d.ts`. 501 | 502 | ## [2.4.1] - 2018-08-14 503 | ### Fixed: 504 | - The result value of `identify()` (provided by either a promise or a callback, once the flag values for the new user have been retrieved) used to be a simple map of flag keys to values, until it was accidentally changed to an internal data structure in version 2.0.0. It is now a map of flag keys to values again, consistent with what is returned by `allFlags()`. 505 | - Added TypeScript definitions for the result values of `identify()`. (Thanks, [1999](https://github.com/launchdarkly/js-client/pull/102)!) 506 | - Documented all optional compatibility polyfills in `README.md`. 507 | 508 | ## [2.4.0] - 2018-07-12 509 | ### Added: 510 | - Named exports for the `initialize` method and `version` number exports. 511 | 512 | ### Deprecated: 513 | - Default exports, use named exports instead. 514 | 515 | ### Changed: 516 | - Updated `package.json` to only export minified files. 517 | 518 | ## [2.3.1] - 2018-06-29 519 | ### Fixed: 520 | - If a polling request has failed due to an invalid environment key, calling `variation` now returns the default value; previously, it sometimes caused a null reference error. 521 | 522 | ## [2.3.0] - 2018-06-26 523 | ### Changed: 524 | - The client will now stop trying to send analytics events if it receives almost any HTTP 4xx error from LaunchDarkly; such errors indicate either a configuration problem (invalid SDK key) or a bug, which is not likely to resolve without a restart or an upgrade. This does not apply if the error is 400, 408, or 429. 525 | 526 | ## [2.2.0] - 2018-06-22 527 | ### Added: 528 | - New event `goalsReady` (and new method `waitUntilGoalsReady`, which returns a Promise based on that event) indicates when the client has loaded goals-- i.e. when it is possible for pageview events and click events to be triggered. 529 | 530 | ### Fixed: 531 | - Fixed a bug where calling `variation` would throw an error if the client was bootstrapped from local storage and there were no flags in local storage yet, and the initial HTTP request for flags from LaunchDarkly had not yet completed. (thanks, [mpcowan](https://github.com/launchdarkly/js-client/pull/97)!) 532 | 533 | ## [2.1.2] - 2018-06-08 534 | ### Fixed: 535 | - Fix the TypeScript definitions to properly support the ES default export. 536 | 537 | ## [2.1.1] - 2018-06-05 538 | ### Fixed: 539 | - Removed two function calls that are not supported in Internet Explorer: `string.startsWith()` and `Object.assign()`. 540 | 541 | ## [2.1.0] - 2018-05-31 542 | ### Added: 543 | - The client now sends the current SDK version to LaunchDarkly in an HTTP header. This information will be visible in a future version of the LaunchDarkly UI. 544 | 545 | ### Fixed: 546 | - Fixed a bug that caused summary events to combine the counts for flag evaluations that produced the flag's first variation (variation index 0) with the counts for flag evaluations that fell through to the default value. 547 | 548 | ## [2.0.0] - 2018-05-25 549 | ### Changed 550 | - To reduce the network bandwidth used for analytics events, feature request events are now sent as counters rather than individual events, and user details are now sent only at intervals rather than in each event. These behaviors can be modified through the LaunchDarkly UI and with the new configuration option `inlineUsersInEvents`. For more details, see [Data Export](https://docs.launchdarkly.com/home/data-export). 551 | - In every function that takes an optional callback parameter, if you provide a callback, the function will not return a promise; a promise will be returned only if you omit the callback. Previously, it would always return a promise which would be resolved/rejected at the same time that the callback (if any) was called; this caused problems if you had not registered an error handler for the promise. 552 | - When sending analytics events, if there is a connection error or an HTTP 5xx response, the client will try to send the events again one more time after a one-second delay. 553 | - Analytics are now sent with an HTTP `POST` request if the browser supports CORS, or via image loading if it does not. Previously, they were always sent via image loading. 554 | 555 | ### Added 556 | - The new configuration option `sendEventsOnlyForVariation`, if set to `true`, causes analytics events for feature flags to be sent only when you call `variation`. Otherwise, the default behavior is to also send events when you call `allFlags`, and whenever a changed flag value is detected in streaming mode. 557 | - The new configuration option `allowFrequentDuplicateEvents`, if set to `true`, turns off throttling for feature flag events. Otherwise, the default behavior is to block the sending of an analytics event if another event with the same flag key, flag value, and user key was generated within the last five minutes. 558 | 559 | ### Fixed 560 | - If `identify` is called with a null user, or a user with no key, the function no longer tries to do an HTTP request to the server (which would always fail); instead, it just returns an error. 561 | 562 | ### Deprecated 563 | - The configuration options `all_attributes_private` and `private_attribute_names` are deprecated. Use `allAttributesPrivate` and `privateAttributeNames` instead. 564 | 565 | ## [1.7.4] - 2018-05-23 566 | ### Fixed 567 | - Fixed a bug that caused events _not_ to be sent if `options.sendEvents` was explicitly set to `true`. 568 | - HTTP requests will no longer fail if there is a `charset` specified in the response's `Content-Type` header. ([#87](https://github.com/launchdarkly/js-client/issues/87)) 569 | 570 | ## [1.7.3] - 2018-05-08 571 | ### Fixed 572 | - The client no longer creates an empty `XMLHttpRequest` at startup time (which could interfere with unit tests). 573 | 574 | ## [1.7.2] - 2018-05-07 575 | _This release was broken and should not be used._ 576 | 577 | ## [1.7.1] - 2018-05-07 578 | _This release was broken and should not be used._ 579 | 580 | ## [1.7.0] - 2018-04-27 581 | ### Changed 582 | - The build now uses Rollup, Babel and Jest. 583 | ### Fixed 584 | - Fixed a bug that caused a syntax error when running in Internet Explorer 11. 585 | - Fixed an IE 11 incompatibility in the example page index.html. 586 | - Fixed a bug that caused the SDK to send events on beforeunload even if it should not send events. 587 | 588 | 589 | ## [1.6.2] - 2018-04-05 590 | 591 | ### Fixed 592 | 593 | * `LDClient.track` properly sets the user for custom events. 594 | 595 | ## [1.6.1] - 2018-03-30 596 | 597 | ### Fixed 598 | 599 | * The SDK now polls the URL for changes if (and only if) there are page view goals,to ensure it is accurately reporting page views. 600 | 601 | ## [1.6.0] - 2018-03-28 602 | 603 | ### Changed 604 | 605 | * Added support for a future update to LaunchDarkly that will deliver individual feature flag changes over the streaming connection as they occur, rather than requiring the client to re-request all flags for each change. 606 | 607 | ## [1.5.2] - 2018-03-28 608 | 609 | ### Added 610 | 611 | * The new flush method on the client object tells the client to deliver any stored analytics events as soon as possible, rather than waiting for the regularly scheduled event-flushing interval. 612 | ### Fixed 613 | * Fixed a bug that could prevent events from being generated for page view goals. 614 | 615 | ## [1.5.1] - 2018-03-07 616 | 617 | ### Fixed 618 | 619 | * Removed usage of the `const` keyword, to maintain IE10 compatibility. (Thanks, [turnerniles](https://github.com/launchdarkly/js-client/pull/68)!) 620 | 621 | ## [1.5.0] - 2018-03-05 622 | 623 | ### Added 624 | 625 | * The `options` object now supports a `samplingInterval` property. If greater than zero, this causes a fraction of analytics events to be sent to LaunchDarkly: one per that number of events (pseudo-randomly). For instance, setting it to 5 would cause 20% of events to be sent on average. 626 | 627 | ## [1.4.0] - 2018-02-07 628 | 629 | ### Added 630 | 631 | * The SDK now supports multiple environments. Calling `initialize` returns a new client each time. 632 | ### Fixed 633 | * The `waitUntilReady` `Promise` will now resolve even after the `ready` event was emitted — thanks @rmanalan! 634 | 635 | ## [1.3.1] - 2018-01-23 636 | 637 | ### Fixed 638 | 639 | * Methods that expose a `Promise` interface now properly return the resolution or rejection value to the caller. 640 | 641 | ## [1.3.0] - 2018-01-22 642 | 643 | ### Added 644 | 645 | * Support for [private user attributes](https://docs.launchdarkly.com/home/users/attributes#creating-private-user-attributes). 646 | * New `sendEvents` option to control whether the SDK should send events back to LaunchDarkly or not. Defaults to `true`. 647 | * It is now possible to wait for SDK readiness using `waitUntilReady` which returns a `Promise`. `identify` also returns a `Promise` (while still supporting the callback argument), which should make 648 | it easier to integrate into code that relies heavily on `Promise`'s for asynchronous code. 649 | ### Changed 650 | * The SDK now respects the user's [do-not-track setting](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/doNotTrack) 651 | 652 | ## [1.2.0] - 2017-12-15 653 | 654 | ### Added 655 | 656 | * Added `useReport` initialization option to use `REPORT` instead of `GET` when communicating with LaunchDarkly. 657 | ### Fixed 658 | * Authentication errors will now be logged — the root cause for these errors is usually an invalid 659 | client-side ID. 660 | 661 | ## [1.1.13] - 2017-12-12 662 | 663 | ### Changed 664 | 665 | * Emit an `error` event — separately from the `ready` event — in case fetching initial data fails. This allows consumers to respond accordingly. 666 | 667 | ## [1.1.12] - 2017-06-09 668 | 669 | ### Changed 670 | 671 | * Improve error handling 672 | 673 | ## [1.1.11] - 2017-05-16 674 | 675 | ### Added 676 | 677 | * Add typescript definitions 678 | 679 | ## [1.1.10] - 2017-05-04 680 | 681 | ### Added 682 | 683 | * Add a warning when tracking unknown custom goal events 684 | 685 | ## [1.1.9] - 2017-04-07 686 | 687 | ### Fixed 688 | 689 | * Changed default stream url 690 | 691 | ## [1.1.8] - 2017-02-02 692 | 693 | ### Fixed 694 | 695 | * Cached `localStorage` copy is not overwritten anymore when connection to LD 696 | fails 697 | 698 | ## [1.1.7] - 2017-01-27 699 | 700 | ### Changed 701 | 702 | * `onDone` argument to `identify` method is now optional 703 | 704 | ## [1.1.6] - 2017-01-16 705 | 706 | ### Changed 707 | 708 | * Removed dependency on Sizzle and direct to polyfill for older browser support 709 | 710 | ## [1.1.5] - 2016-12-07 711 | 712 | ### Changed 713 | 714 | * Fix bug in `Emitter.off()` 715 | 716 | ## [1.1.4] - 2016-10-26 717 | 718 | ### Changed 719 | 720 | * Fix bug caused by accessing `undefined` flags 721 | 722 | ## [1.1.3] - 2016-10-14 723 | 724 | ### Changed 725 | 726 | * Fix bug caused by accessing `undefined` settings 727 | 728 | ## [1.1.2] - 2016-09-21 729 | 730 | ### Changed 731 | 732 | * Ensure callbacks only ever get called once 733 | 734 | ## [1.1.1] - 2016-09-20 735 | 736 | ### Changed 737 | 738 | * Fix flag setting request cancellation logic 739 | 740 | ## [1.1.0] - 2016-09-14 741 | 742 | ### Added 743 | 744 | * Add a new `allFlags` method that returns a map of all feature flag keys and 745 | their values for a user 746 | 747 | ## [1.0.8] - 2016-09-09 748 | 749 | ### Changed 750 | 751 | * Added 'undefined' check on VERSION otherwise unbundled usage from npm fails 752 | 753 | ## [1.0.7] - 2016-09-06 754 | 755 | ### Changed 756 | 757 | * Expose SDK version at `LDClient.version` 758 | 759 | ## [1.0.6] - 2016-08-23 760 | 761 | ### Changed 762 | 763 | * Added check for EventSource before trying to connect Stream. 764 | 765 | ## [1.0.5] - 2016-08-22 766 | 767 | ### Changed 768 | 769 | * Fixed an error that occurred on `hashchage`/`popstate` if the account had no 770 | goals. 771 | 772 | ## [1.0.4] - 2016-08-12 773 | 774 | ### Changed 775 | 776 | * Added window check for server side rendering compatibility before loading 777 | Sizzle. 778 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Repository Maintainers 2 | * @launchdarkly/team-sdk-js 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to LaunchDarkly SDK for Browser JavaScript 2 | 3 | LaunchDarkly has published an [SDK contributor's guide](https://docs.launchdarkly.com/sdk/concepts/contributors-guide) that provides a detailed explanation of how our SDKs work. See below for additional information on how to contribute to this SDK. 4 | 5 | ## Submitting bug reports and feature requests 6 | 7 | The LaunchDarkly SDK team monitors the [issue tracker](https://github.com/launchdarkly/js-client-sdk/issues) in the SDK repository. Bug reports and feature requests specific to this SDK should be filed in this issue tracker. The SDK team will respond to all newly filed issues within two business days. 8 | 9 | ## Submitting pull requests 10 | 11 | We encourage pull requests and other contributions from the community. Before submitting pull requests, ensure that all temporary or unintended code is removed. Don't worry about adding reviewers to the pull request; the LaunchDarkly SDK team will add themselves. The SDK team will acknowledge all pull requests within two business days. 12 | 13 | ## Build instructions 14 | 15 | ### Prerequisites 16 | 17 | Note that much of the basic SDK logic, which is common to all of the LaunchDarkly client-side JavaScript-based SDKs, is in the `launchdarkly-js-sdk-common` package in the [js-sdk-common](https://github.com/launchdarkly/js-sdk-common) repository. This is pulled in automatically by `npm` when you build the SDK, but if you are planning to make changes that affect the common code, you will need to check out that repository as well. 18 | 19 | ### Setup 20 | 21 | To install project dependencies, from the project root directory: 22 | 23 | ``` 24 | npm install 25 | ``` 26 | 27 | ### Testing 28 | 29 | To run all unit tests: 30 | 31 | ``` 32 | npm test 33 | ``` 34 | 35 | To verify that the TypeScript declarations compile correctly (this involves compiling the file `test-types.ts`, so if you have changed any types or interfaces, you will want to update that code): 36 | 37 | ``` 38 | npm run check-typescript 39 | ``` 40 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2016 Catamorphic, Co. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LaunchDarkly SDK for Browser JavaScript 2 | 3 | [](https://github.com/launchdarkly/js-client-sdk/actions/workflows/ci.yml) 4 | 5 | ## LaunchDarkly overview 6 | 7 | [LaunchDarkly](https://www.launchdarkly.com) is a feature management platform that serves trillions of feature flags daily to help teams build better software, faster. [Get started](https://docs.launchdarkly.com/home/getting-started) using LaunchDarkly today! 8 | 9 | [](https://twitter.com/intent/follow?screen_name=launchdarkly) 10 | 11 | ## Getting started 12 | 13 | Refer to the [SDK documentation](https://docs.launchdarkly.com/sdk/client-side/javascript#getting-started) for instructions on getting started with using the SDK. 14 | 15 | Note: _If you are using JavaScript in a non-browser environment,_ please see our [server-side Node.js SDK](https://github.com/launchdarkly/node-server-sdk), [client-side Node.js SDK](https://github.com/launchdarkly/node-client-sdk), and [Electron SDK](https://github.com/launchdarkly/electron-client-sdk). 16 | 17 | Please note that the JavaScript SDK has two special requirements in terms of your LaunchDarkly environment. First, in terms of the credentials for your environment that appear on your [Account Settings](https://app.launchdarkly.com/settings/projects) dashboard, the JavaScript SDK uses the "Client-side ID"-- not the "SDK key" or the "Mobile key". Second, for any feature flag that you will be using in JavaScript code, you must check the "Make this flag available to client-side SDKs" box on that flag's Settings page. 18 | 19 | ## ReactJS 20 | 21 | The SDK does not require any particular JavaScript framework. However, if you are using [React](https://reactjs.org/), there is an add-on to simplify use of the SDK. See [`react-client-sdk`](https://github.com/launchdarkly/react-client-sdk). 22 | 23 | ## Browser compatibility 24 | 25 | The LaunchDarkly SDK can be used in all major browsers. However, web browsers vary widely in their support of specific features and standards. Three features that are used by the LaunchDarkly SDK that may not be available on every browser are `Promise`, `EventSource`, and `document.querySelectorAll()`. For more information on whether you may need to use a polyfill to ensure compatibility, and how to do so, see ["JS SDK requirements and polyfills"](https://docs.launchdarkly.com/sdk/client-side/javascript/requirements-polyfills). 26 | 27 | ## Logging 28 | 29 | By default, the SDK sends log output to the browser console. There are four logging levels: `debug`, `info`, `warn`, and `error`; by default, `debug` and `info` messages are hidden. See [`LDOptions.logger`](https://launchdarkly.github.io/js-client-sdk/interfaces/LDOptions.html#logger) and [`basicLogger`](https://launchdarkly.github.io/js-client-sdk/functions/basicLogger.html) for more details. 30 | 31 | ## Learn more 32 | 33 | Read our [documentation](https://docs.launchdarkly.com) for in-depth instructions on configuring and using LaunchDarkly. You can also head straight to the [complete reference guide for this SDK](https://docs.launchdarkly.com/sdk/client-side/javascript). Additionally, the authoritative full description of all properties, types, and methods is the [online TypeScript documentation](https://launchdarkly.github.io/js-client-sdk/). If you are not using TypeScript, then the types are only for your information and are not enforced, although the properties and methods are still the same as described in the documentation. 34 | 35 | For examples of using the SDK in a simple JavaScript application, see [`hello-js`](https://github.com/launchdarkly/hello-js) and [`hello-bootstrap`](https://github.com/launchdarkly/hello-bootstrap). 36 | 37 | ## Testing 38 | 39 | We run integration tests for all our SDKs using a centralized test harness. This approach gives us the ability to test for consistency across SDKs, as well as test networking behavior in a long-running application. These tests cover each method in the SDK, and verify that event sending, flag evaluation, stream reconnection, and other aspects of the SDK all behave correctly. 40 | 41 | ## Contributing 42 | 43 | We encourage pull requests and other contributions from the community. Check out our [contributing guidelines](CONTRIBUTING.md) for instructions on how to contribute to this SDK. 44 | 45 | ## About LaunchDarkly 46 | 47 | * LaunchDarkly is a continuous delivery platform that provides feature flags as a service and allows developers to iterate quickly and safely. We allow you to easily flag your features and manage them from the LaunchDarkly dashboard. With LaunchDarkly, you can: 48 | * Roll out a new feature to a subset of your users (like a group of users who opt-in to a beta tester group), gathering feedback and bug reports from real-world use cases. 49 | * Gradually roll out a feature to an increasing percentage of users, and track the effect that the feature has on key metrics (for instance, how likely is a user to complete a purchase if they have feature A versus feature B?). 50 | * Turn off a feature that you realize is causing performance problems in production, without needing to re-deploy, or even restart the application with a changed configuration file. 51 | * Grant access to certain features based on user attributes, like payment plan (eg: users on the ‘gold’ plan get access to more features than users in the ‘silver’ plan). Disable parts of your application to facilitate maintenance, without taking everything offline. 52 | * LaunchDarkly provides feature flag SDKs for a wide variety of languages and technologies. Check out [our documentation](https://docs.launchdarkly.com/sdk) for a complete list. 53 | * Explore LaunchDarkly 54 | * [launchdarkly.com](https://www.launchdarkly.com/ "LaunchDarkly Main Website") for more information 55 | * [docs.launchdarkly.com](https://docs.launchdarkly.com/ "LaunchDarkly Documentation") for our documentation and SDK reference guides 56 | * [apidocs.launchdarkly.com](https://apidocs.launchdarkly.com/ "LaunchDarkly API Documentation") for our API documentation 57 | * [blog.launchdarkly.com](https://blog.launchdarkly.com/ "LaunchDarkly Blog Documentation") for the latest product updates 58 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting and Fixing Security Issues 2 | 3 | Please report all security issues to the LaunchDarkly security team by submitting a bug bounty report to our [HackerOne program](https://hackerone.com/launchdarkly?type=team). LaunchDarkly will triage and address all valid security issues following the response targets defined in our program policy. Valid security issues may be eligible for a bounty. 4 | 5 | Please do not open issues or pull requests for security issues. This makes the problem immediately visible to everyone, including potentially malicious actors. 6 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: build 3 | pool: 4 | vmImage: 'vs2017-win2016' 5 | steps: 6 | - task: PowerShell@2 7 | displayName: 'install dependencies' 8 | inputs: 9 | targetType: inline 10 | script: | 11 | node --version 12 | npm install 13 | - task: PowerShell@2 14 | displayName: 'build' 15 | inputs: 16 | targetType: inline 17 | script: npm run build 18 | - task: PowerShell@2 19 | displayName: 'test' 20 | inputs: 21 | targetType: inline 22 | script: npm test 23 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@babel/env', 5 | { 6 | targets: ["last 2 versions", "ie >= 10"], 7 | }, 8 | ], 9 | ], 10 | env: { 11 | test: { 12 | plugins: [ 13 | '@babel/plugin-transform-regenerator', 14 | '@babel/plugin-transform-runtime', 15 | ], 16 | }, 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # SDK Browser Demo Page 2 | 3 | This is a simple front-end-only JavaScript application that exercises much of the functionality of the LaunchDarkly SDK for browser JavaScript. It is not meant to be an example of how to write a LaunchDarkly application, since most of its logic is devoted to implementing a testing UI that a real application would not have. Instead, it is meant to show the SDK in action and to verify that feature flags work as expected in a given environment. 4 | 5 | For a more realistic example of a LaunchDarkly-enabled application with both a front end and a back end, see [`hello-bootstrap`](https://github.com/launchdarkly/hello-bootstrap). 6 | 7 | ## Running the demo 8 | 9 | Most of the demo can be used without a real HTTP server; just start your browser and tell it to open the `index.html` file in this directory. The only thing that will not work in that mode is the "Set URL" feature under Navigation/Events. 10 | 11 | To access the demo via a basic HTTP server, there are several ways but the simplest-- if you have npx-- is to run `npx http-server` from a command line at this directory, and then browse http://127.0.0.1:8080. 12 | 13 | Note that by default, the demo uses the latest release of the JS SDK script that is hosted on `app.launchdarkly.com`. However, if it detects that you have built the SDK locally, it will use the local SDK code instead. Therefore, it can be used for testing changes to the SDK. To build from the SDK root directory, run `npm run build`. 14 | 15 | ## Selecting an environment 16 | 17 | By default, the demo uses a simple environment that LaunchDarkly has created for this purpose, containing a few feature flags as follows-- two that do not change, and two that change in response to a user property: 18 | 19 | * `client-side-flag-1-always-true`: Always returns the boolean value `true`. 20 | * `client-side-flag-2-always-green`: Always returns the string value `"green"`. 21 | * `client-side-flag-3-does-name-start-with-b`: Returns `true` if the user's `name` property starts with the letter B, otherwise `false`. 22 | * `client-side-flag-4-has-valid-email`: Returns `true` if the user's `email` property matches a simple regex for validating emails, otherwise `false`. 23 | 24 | You can instead use your own environment, by copying the environment ID from [your dashboard](https://app.launchdarkly.com/settings/projects) into the Environment ID field and clicking "Update Configuration, Reconnect". You should now see all feature flags from your environment that have the "Make this flag available to client-side SDKs" option checked. If you also clicked the "Live updates (streaming)" box, you should also see any changes you make to your flags reflected on the page in real time. 25 | -------------------------------------------------------------------------------- /example/example.css: -------------------------------------------------------------------------------- 1 | 2 | #logPanel { 3 | border: 1px solid #888; 4 | font-family: monospace; 5 | font-size: 9pt; 6 | height: 140px; 7 | overflow: scroll; 8 | white-space: pre; 9 | } 10 | 11 | code { 12 | font-size: 9pt; 13 | } 14 | 15 | .error { 16 | color: red; 17 | } 18 | 19 | #usingWhichScript, #usingWhichScript .local, #usingWhichScript .hosted { 20 | display: none; 21 | } 22 | 23 | #usingWhichScript.local, #usingWhichScript.hosted, #usingWhichScript.local .local, #usingWhichScript.hosted .hosted { 24 | display: inline; 25 | } 26 | -------------------------------------------------------------------------------- /example/example.js: -------------------------------------------------------------------------------- 1 | 2 | // Note that this example does not use a module loader; instead it assumes that the page has loaded the 3 | // default web distribution of ldclient.js (or ldclient.min.js), which sets the global variable "LDClient". 4 | 5 | $(function() { 6 | var defaultEnvId = '5cc8a87be4b564081fd2fd70'; 7 | var $flagsContainer = $('#flagsContainer'); 8 | var $logContainer = $('#logPanel'); 9 | 10 | var client; 11 | var clientConfig; 12 | var flagsShown = false; 13 | 14 | // These functions are for redirecting log output from the SDK so we can see it on the page for debugging. 15 | 16 | function writeLogLine(message) { 17 | if ($logContainer.html() != '') { 18 | message = "\n" + message; 19 | } 20 | $logContainer.append(message); 21 | var height = $logContainer[0].scrollHeight; 22 | $logContainer.scrollTop(height); 23 | } 24 | 25 | function logWriter(level) { 26 | return function(message) { 27 | if (level === 'error') { 28 | message = '' + message + ''; 29 | } 30 | writeLogLine('[' + level.toUpperCase() + '] ' + message); 31 | } 32 | } 33 | 34 | var logger = { 35 | debug: logWriter('debug'), 36 | info: logWriter('info'), 37 | warn: logWriter('warn'), 38 | error: logWriter('error') 39 | }; 40 | 41 | // Here we build a user object from the form fields. 42 | 43 | function makeUserObject() { 44 | var user = {}; 45 | var fields = [ 'key', 'email', 'name', 'firstName', 'lastName', 'avatar', 'ip', 'country' ]; 46 | for (var i in fields) { 47 | var val = $('#' + fields[i] + 'Field').val(); 48 | if (val) { 49 | user[fields[i]] = val; 50 | } 51 | } 52 | 53 | $customNames = $('#customFieldsContainer .customFieldName'); 54 | $customValues = $('#customFieldsContainer .customFieldValue'); 55 | for (var c in $customNames) { 56 | if (c < $customValues.length) { 57 | var name = $($customNames[c]).val(); 58 | var value = $($customValues[c]).val(); 59 | if (name) { 60 | user.custom = user.custom || {}; 61 | user.custom[name] = getJsonValue(value); 62 | } 63 | } 64 | } 65 | 66 | if ($('#userAnonymousCheck').prop('checked')) { 67 | user.anonymous = true; 68 | } 69 | return user; 70 | } 71 | 72 | function getJsonValue(s) { 73 | if (s === '' || s === null || s === undefined) { 74 | return null; 75 | } 76 | if (/^\d+$/.test(s)) { 77 | return parseInt(s, 10); 78 | } 79 | if (/^\d+\.\d+$/.test(s)) { 80 | return parseFloat(s); 81 | } 82 | if (s.startsWith('{') || s.startsWith('[')) { 83 | try { 84 | return JSON.parse(s); 85 | } catch (e) {} 86 | } 87 | return s; 88 | } 89 | 90 | // Here we initialize the LaunchDarkly client connection. 91 | 92 | function reconnect() { 93 | if (client) { 94 | client.close(); 95 | } 96 | 97 | var envId = $('#envIdField').val() || defaultEnvId; 98 | var streaming = $('#streamingCheck').prop('checked'); 99 | clientConfig = { 100 | streaming: streaming || undefined, 101 | evaluationReasons: $('#reasonsCheck').prop('checked') || undefined, 102 | useReport: $('#useReportCheck').prop('checked') || undefined, 103 | flushInterval: $('#flushIntervalField').val() ? parseInt($('#flushIntervalField').val(), 10) : undefined, 104 | privateAttributeNames: $('#privateAttributeNamesField').val() ? $('#privateAttributeNamesField').val().split(',') : undefined, 105 | allAttributesPrivate: $('#allAttributesPrivateCheck').prop('checked') || undefined 106 | }; 107 | logger.debug('test app is using config: ' + JSON.stringify(clientConfig)); 108 | clientConfig.logger = logger; 109 | var user = makeUserObject(); 110 | 111 | showFlagsPlaceholder('
').text(' ' + contextJson)).append('
').text(reasonJson)));
174 | }
175 | $tbody.append($tbr);
176 | }
177 | $table.append($tbody);
178 |
179 | $content.append($table);
180 |
181 | $flagsContainer.empty().append($content);
182 |
183 | flagsShown = true;
184 | }
185 |
186 | function handleBeforeUnload(e) {
187 | return 'Are you sure you want to leave this page?';
188 | }
189 |
190 | $('#reconnectButton').on('click', function(e) {
191 | e.preventDefault();
192 | reconnect();
193 | });
194 |
195 | $('#identifyButton').on('click', function(e) {
196 | e.preventDefault();
197 | identifyUser();
198 | });
199 |
200 | $('#pushUrlButton').on('click', function(e) {
201 | e.preventDefault();
202 | var url = $('#urlField').val();
203 | if (url) {
204 | history.pushState(null, null, url);
205 | }
206 | });
207 |
208 | $('#pushRandomUrlButton').on('click', function(e) {
209 | e.preventDefault();
210 | history.pushState(null, null, new Date().getTime().toString());
211 | });
212 |
213 | $('#pushRandomHashButton').on('click', function(e) {
214 | e.preventDefault();
215 | location.hash = new Date().getTime().toString();
216 | });
217 |
218 | $('#backButton').on('click', function(e) {
219 | e.preventDefault();
220 | window.history.back();
221 | });
222 |
223 | $('#customEventButton').on('click', function(e) {
224 | e.preventDefault();
225 | var eventName = $('#eventNameField').val();
226 | var eventData = $('#eventDataField').val();
227 | if (eventName) {
228 | $('#eventNameField').removeClass('is-invalid');
229 | client.track(eventName, getJsonValue(eventData));
230 | } else {
231 | $('#eventNameField').addClass('is-invalid');
232 | }
233 | });
234 |
235 | $('a.special').on('click', function(e) { e.preventDefault(); }); // these have no purpose except for click goals
236 |
237 | $('#addCustomFieldButton').on('click', function(e) {
238 | e.preventDefault();
239 | var $row = $('#customFieldTemplate').find('form').clone();
240 | $('#customFieldsContainer').append($row);
241 | });
242 |
243 | $('#customFieldsContainer').on('click', '.removeCustomFieldButton', function(e) {
244 | e.preventDefault();
245 | $(e.target).closest('form').remove();
246 | });
247 |
248 | $('#interceptBeforeUnloadCheck').on('change', function(e) {
249 | if ($('#interceptBeforeUnloadCheck').prop('checked')) {
250 | $(window).on('beforeunload', handleBeforeUnload);
251 | } else {
252 | $(window).off('beforeunload');
253 | }
254 | });
255 |
256 | // For this demo, we can use either a local build of the SDK (which is what index.html references), or the current
257 | // release from app.launchdarkly.com. If we detect that the former is not available, we'll switch to the latter. This
258 | // is to make the page useful for both users and SDK developers. A real application would just use one or the other.
259 |
260 | function startDemo() {
261 | $('#sdkVersion').text(LDClient.version);
262 | reconnect();
263 | }
264 |
265 | if (window.LDClient) { // we successfully loaded the script from a local copy
266 | $('#usingWhichScript').addClass('local');
267 | startDemo();
268 | } else {
269 | var hostedScriptUrl = 'https://unpkg.com/launchdarkly-js-client-sdk@3';
270 | var script = document.createElement('script');
271 | script.src = hostedScriptUrl;
272 | script.crossOrigin = 'anonymous';
273 | script.onload = function() {
274 | $('#usingWhichScript').addClass('hosted');
275 | startDemo();
276 | };
277 | document.head.append(script);
278 | }
279 | });
280 |
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 37 | This is a simple front-end-only application using LaunchDarkly. 38 | (Using the hosted SDK script a local SDK build - version ) Learn more 39 |
40 | 41 |