launchdarkly-js-sdk-common 5.7.1 → 5.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/dependency-scan.yml +30 -0
- package/.github/workflows/lint-pr-title.yml +3 -0
- package/.github/workflows/release-please.yml +49 -7
- package/.github/workflows/stale.yml +14 -0
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +14 -0
- package/package.json +4 -5
- package/src/AnonymousContextProcessor.js +2 -2
- package/src/EventSender.js +2 -2
- package/src/FlagStore.js +144 -0
- package/src/__tests__/LDClient-debugOverride-test.js +342 -0
- package/src/__tests__/LDClient-plugins-test.js +63 -5
- package/src/__tests__/diagnosticEvents-test.js +6 -0
- package/src/diagnosticEvents.js +2 -5
- package/src/index.js +127 -31
- package/src/plugins.js +17 -0
- package/src/uuid.js +70 -0
- package/test-types.ts +1 -1
- package/typings.d.ts +55 -3
- package/.github/workflows/manual-publish.yml +0 -42
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Dependency Scan
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
generate-nodejs-sbom:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
|
|
14
|
+
|
|
15
|
+
- name: Generate SBOM
|
|
16
|
+
uses: launchdarkly/gh-actions/actions/dependency-scan/generate-sbom@main
|
|
17
|
+
with:
|
|
18
|
+
types: 'nodejs'
|
|
19
|
+
|
|
20
|
+
evaluate-policy:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
needs:
|
|
23
|
+
- generate-nodejs-sbom
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
|
|
26
|
+
|
|
27
|
+
- name: Evaluate SBOM Policy
|
|
28
|
+
uses: launchdarkly/gh-actions/actions/dependency-scan/evaluate-policy@main
|
|
29
|
+
with:
|
|
30
|
+
artifacts-pattern: bom-*
|
|
@@ -4,14 +4,28 @@ on:
|
|
|
4
4
|
push:
|
|
5
5
|
branches:
|
|
6
6
|
- main
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
dry-run:
|
|
10
|
+
description: 'Is this a dry run. If so no package will be published.'
|
|
11
|
+
type: boolean
|
|
12
|
+
required: true
|
|
13
|
+
prerelease:
|
|
14
|
+
description: 'Is this a prerelease. If so, then the latest tag will not be updated in npm.'
|
|
15
|
+
type: boolean
|
|
16
|
+
required: true
|
|
7
17
|
|
|
8
18
|
jobs:
|
|
9
19
|
release-please:
|
|
10
20
|
runs-on: ubuntu-latest
|
|
21
|
+
permissions:
|
|
22
|
+
contents: write
|
|
23
|
+
pull-requests: write
|
|
24
|
+
if: github.event_name == 'push'
|
|
11
25
|
outputs:
|
|
12
26
|
release_created: ${{ steps.release.outputs.release_created }}
|
|
13
27
|
steps:
|
|
14
|
-
- uses: googleapis/release-please-action@
|
|
28
|
+
- uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0
|
|
15
29
|
id: release
|
|
16
30
|
with:
|
|
17
31
|
token: ${{secrets.GITHUB_TOKEN}}
|
|
@@ -28,14 +42,13 @@ jobs:
|
|
|
28
42
|
|
|
29
43
|
- uses: actions/setup-node@v4
|
|
30
44
|
with:
|
|
31
|
-
node-version:
|
|
45
|
+
node-version: 24.x
|
|
32
46
|
registry-url: 'https://registry.npmjs.org'
|
|
33
47
|
|
|
34
|
-
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
ssm_parameter_pairs: '/production/common/releasing/npm/token = NODE_AUTH_TOKEN'
|
|
48
|
+
- name: Update NPM
|
|
49
|
+
shell: bash
|
|
50
|
+
# Must be greater than 11.5.1 for OIDC.
|
|
51
|
+
run: npm install -g npm@11.6.2
|
|
39
52
|
|
|
40
53
|
- name: Install Dependencies
|
|
41
54
|
run: npm install
|
|
@@ -55,3 +68,32 @@ jobs:
|
|
|
55
68
|
uses: ./.github/actions/publish-docs
|
|
56
69
|
with:
|
|
57
70
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
71
|
+
|
|
72
|
+
manual-publish-package:
|
|
73
|
+
runs-on: ubuntu-latest
|
|
74
|
+
if: github.event_name == 'workflow_dispatch'
|
|
75
|
+
permissions:
|
|
76
|
+
id-token: write
|
|
77
|
+
contents: write
|
|
78
|
+
steps:
|
|
79
|
+
- uses: actions/checkout@v4
|
|
80
|
+
|
|
81
|
+
- uses: actions/setup-node@v4
|
|
82
|
+
with:
|
|
83
|
+
node-version: 24.x
|
|
84
|
+
registry-url: 'https://registry.npmjs.org'
|
|
85
|
+
|
|
86
|
+
- name: Update NPM
|
|
87
|
+
shell: bash
|
|
88
|
+
# Must be greater than 11.5.1 for OIDC.
|
|
89
|
+
run: npm install -g npm@11.6.2
|
|
90
|
+
|
|
91
|
+
- name: Install Dependencies
|
|
92
|
+
run: npm install
|
|
93
|
+
|
|
94
|
+
- id: publish-npm
|
|
95
|
+
name: Publish NPM Package
|
|
96
|
+
uses: ./.github/actions/publish-npm
|
|
97
|
+
with:
|
|
98
|
+
dry-run: ${{ inputs.dry-run }}
|
|
99
|
+
prerelease: ${{ inputs.prerelease }}
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
permissions:
|
|
9
|
+
issues: write
|
|
10
|
+
pull-requests: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
sdk-close-stale:
|
|
14
|
+
uses: launchdarkly/gh-actions/.github/workflows/sdk-stale.yml@main
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the `launchdarkly-js-sdk-common` package will be documented in this file. Changes that affect the dependent SDKs such as `launchdarkly-js-client-sdk` should also be logged in those projects, in the next release that uses the updated version of this package. This project adheres to [Semantic Versioning](http://semver.org).
|
|
4
4
|
|
|
5
|
+
## [5.8.1](https://github.com/launchdarkly/js-sdk-common/compare/5.8.0...5.8.1) (2026-05-21)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* remove uuid dependency, replace with inline implementation ([#146](https://github.com/launchdarkly/js-sdk-common/issues/146)) ([98c87d0](https://github.com/launchdarkly/js-sdk-common/commit/98c87d02a6c58b336bbb40b7a80f9bb3489bbed9))
|
|
11
|
+
|
|
12
|
+
## [5.8.0](https://github.com/launchdarkly/js-sdk-common/compare/5.7.1...5.8.0) (2025-09-05)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* Add experimental debug override functionality. ([#132](https://github.com/launchdarkly/js-sdk-common/issues/132)) ([8b2f757](https://github.com/launchdarkly/js-sdk-common/commit/8b2f757e9e070226a10f32dcf943501a8f8f1e4a))
|
|
18
|
+
|
|
5
19
|
## [5.7.1](https://github.com/launchdarkly/js-sdk-common/compare/5.7.0...5.7.1) (2025-05-30)
|
|
6
20
|
|
|
7
21
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "launchdarkly-js-sdk-common",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.8.1",
|
|
4
4
|
"description": "LaunchDarkly SDK for JavaScript - common code",
|
|
5
5
|
"author": "LaunchDarkly <team@launchdarkly.com>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -44,13 +44,12 @@
|
|
|
44
44
|
"launchdarkly-js-test-helpers": "1.1.0",
|
|
45
45
|
"prettier": "1.19.1",
|
|
46
46
|
"readline-sync": "^1.4.9",
|
|
47
|
-
"
|
|
48
|
-
"
|
|
47
|
+
"typedoc": "^0.25.13",
|
|
48
|
+
"typescript": "~5.4.5"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"base64-js": "^1.3.0",
|
|
52
|
-
"fast-deep-equal": "^2.0.1"
|
|
53
|
-
"uuid": "^8.0.0"
|
|
52
|
+
"fast-deep-equal": "^2.0.1"
|
|
54
53
|
},
|
|
55
54
|
"repository": {
|
|
56
55
|
"type": "git",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { randomUuidV4 } = require('./uuid');
|
|
2
2
|
const { getContextKinds } = require('./context');
|
|
3
3
|
|
|
4
4
|
const errors = require('./errors');
|
|
@@ -57,7 +57,7 @@ function AnonymousContextProcessor(persistentStorage) {
|
|
|
57
57
|
context.key = cachedId;
|
|
58
58
|
return context;
|
|
59
59
|
} else {
|
|
60
|
-
const id =
|
|
60
|
+
const id = randomUuidV4();
|
|
61
61
|
context.key = id;
|
|
62
62
|
return setCachedContextKey(id, kind).then(() => context);
|
|
63
63
|
}
|
package/src/EventSender.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const errors = require('./errors');
|
|
2
2
|
const utils = require('./utils');
|
|
3
|
-
const {
|
|
3
|
+
const { randomUuidV4 } = require('./uuid');
|
|
4
4
|
const { getLDHeaders, transformHeaders } = require('./headers');
|
|
5
5
|
|
|
6
6
|
function EventSender(platform, environmentId, options) {
|
|
@@ -25,7 +25,7 @@ function EventSender(platform, environmentId, options) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const jsonBody = JSON.stringify(events);
|
|
28
|
-
const payloadId = isDiagnostic ? null :
|
|
28
|
+
const payloadId = isDiagnostic ? null : randomUuidV4();
|
|
29
29
|
|
|
30
30
|
function doPostRequest(canRetry) {
|
|
31
31
|
const headers = isDiagnostic
|
package/src/FlagStore.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
const utils = require('./utils');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* FlagStore - Centralized flag store and access point for all feature flags
|
|
5
|
+
*
|
|
6
|
+
* This module manages two types of feature flags:
|
|
7
|
+
* 1. Regular flags - Retrieved from LaunchDarkly servers or bootstrap data
|
|
8
|
+
* 2. Override flags - Local overrides for debugging/testing
|
|
9
|
+
*
|
|
10
|
+
* When a flag is requested:
|
|
11
|
+
* - If an override exists for that flag, the override value is returned
|
|
12
|
+
* - Otherwise, the regular flag value is returned
|
|
13
|
+
*/
|
|
14
|
+
function FlagStore() {
|
|
15
|
+
let flags = {};
|
|
16
|
+
// The flag overrides are set lazily to allow bypassing property checks when no overrides are present.
|
|
17
|
+
let flagOverrides;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Gets a single flag by key, with overrides taking precedence over regular flags
|
|
21
|
+
* @param {string} key The flag key to retrieve
|
|
22
|
+
* @returns {Object|null} The flag object or null if not found
|
|
23
|
+
*/
|
|
24
|
+
function get(key) {
|
|
25
|
+
// Check overrides first, then real flags
|
|
26
|
+
if (flagOverrides && utils.objectHasOwnProperty(flagOverrides, key) && flagOverrides[key]) {
|
|
27
|
+
return flagOverrides[key];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (flags && utils.objectHasOwnProperty(flags, key) && flags[key] && !flags[key].deleted) {
|
|
31
|
+
return flags[key];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Gets all flags with overrides applied
|
|
39
|
+
* @returns {Object} Object containing all flags with any overrides applied
|
|
40
|
+
*/
|
|
41
|
+
function getFlagsWithOverrides() {
|
|
42
|
+
const result = {};
|
|
43
|
+
|
|
44
|
+
// Add all flags first
|
|
45
|
+
for (const key in flags) {
|
|
46
|
+
const flag = get(key);
|
|
47
|
+
if (flag) {
|
|
48
|
+
result[key] = flag;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Override with any flagOverrides (they take precedence)
|
|
53
|
+
if (flagOverrides) {
|
|
54
|
+
for (const key in flagOverrides) {
|
|
55
|
+
const override = get(key);
|
|
56
|
+
if (override) {
|
|
57
|
+
result[key] = override;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Replaces all flags with new flag data
|
|
67
|
+
* @param {Object} newFlags - Object containing the new flag data
|
|
68
|
+
*/
|
|
69
|
+
function setFlags(newFlags) {
|
|
70
|
+
flags = { ...newFlags };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Sets an override value for a specific flag
|
|
75
|
+
* @param {string} key The flag key to override
|
|
76
|
+
* @param {*} value The override value for the flag
|
|
77
|
+
*/
|
|
78
|
+
function setOverride(key, value) {
|
|
79
|
+
if (!flagOverrides) {
|
|
80
|
+
flagOverrides = {};
|
|
81
|
+
}
|
|
82
|
+
flagOverrides[key] = { value };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Removes an override for a specific flag
|
|
87
|
+
* @param {string} key The flag key to remove the override for
|
|
88
|
+
*/
|
|
89
|
+
function removeOverride(key) {
|
|
90
|
+
if (!flagOverrides || !flagOverrides[key]) {
|
|
91
|
+
return; // No override to remove
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
delete flagOverrides[key];
|
|
95
|
+
|
|
96
|
+
// If no more overrides, reset to undefined for performance
|
|
97
|
+
if (Object.keys(flagOverrides).length === 0) {
|
|
98
|
+
flagOverrides = undefined;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Clears all flag overrides and returns the cleared overrides
|
|
104
|
+
* @returns {Object} The overrides that were cleared, useful for tracking what was removed
|
|
105
|
+
*/
|
|
106
|
+
function clearAllOverrides() {
|
|
107
|
+
if (!flagOverrides) {
|
|
108
|
+
return {}; // No overrides to clear, return empty object for consistency
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const clearedOverrides = { ...flagOverrides };
|
|
112
|
+
flagOverrides = undefined; // Reset to undefined
|
|
113
|
+
return clearedOverrides;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Gets the internal flag state without overrides applied
|
|
118
|
+
* @returns {Object} The internal flag data structure
|
|
119
|
+
*/
|
|
120
|
+
function getFlags() {
|
|
121
|
+
return flags;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Gets the flag overrides data
|
|
126
|
+
* @returns {Object} The flag overrides object, or empty object if no overrides exist
|
|
127
|
+
*/
|
|
128
|
+
function getFlagOverrides() {
|
|
129
|
+
return flagOverrides || {};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
clearAllOverrides,
|
|
134
|
+
get,
|
|
135
|
+
getFlagOverrides,
|
|
136
|
+
getFlags,
|
|
137
|
+
getFlagsWithOverrides,
|
|
138
|
+
removeOverride,
|
|
139
|
+
setFlags,
|
|
140
|
+
setOverride,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
module.exports = FlagStore;
|