launchdarkly-js-sdk-common 5.2.0 → 5.4.0
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/actions/publish-docs/action.yml +16 -0
- package/.github/actions/publish-npm/action.yml +20 -0
- package/.github/workflows/ci.yml +41 -0
- package/.github/workflows/lint-pr-title.yml +12 -0
- package/.github/workflows/release-please.yml +57 -0
- package/.release-please-manifest.json +3 -0
- package/CHANGELOG.md +25 -0
- package/README.md +4 -1
- package/package.json +5 -3
- package/release-please-config.json +10 -0
- package/scripts/publish-npm.sh +11 -0
- package/src/InspectorManager.js +47 -10
- package/src/SafeInspector.js +1 -0
- package/src/__tests__/InspectorManager-test.js +7 -1
- package/src/__tests__/LDClient-events-test.js +92 -0
- package/src/__tests__/LDClient-inspectors-test.js +112 -3
- package/src/index.js +22 -7
- package/src/messages.js +1 -1
- package/typedoc.json +8 -0
- package/typings.d.ts +31 -1
- package/.circleci/config.yml +0 -22
- package/.ldrelease/config.yml +0 -25
- package/docs/typedoc.js +0 -11
|
@@ -0,0 +1,16 @@
|
|
|
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 }}
|
|
@@ -0,0 +1,20 @@
|
|
|
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 }}
|
|
@@ -0,0 +1,41 @@
|
|
|
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
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
- uses: actions/setup-node@v4
|
|
27
|
+
with:
|
|
28
|
+
node-version: ${{ matrix.variations.node }}
|
|
29
|
+
registry-url: 'https://registry.npmjs.org'
|
|
30
|
+
- name: Install
|
|
31
|
+
run: npm install
|
|
32
|
+
- name: Test
|
|
33
|
+
run: npm test
|
|
34
|
+
env:
|
|
35
|
+
JEST_JUNIT_OUTPUT_FILE: "reports/junit/js-test-results.xml"
|
|
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
|
|
@@ -0,0 +1,57 @@
|
|
|
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 }}
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
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.4.0](https://github.com/launchdarkly/js-sdk-common/compare/5.3.0...5.4.0) (2024-10-18)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* Add support for client-side prerequisite events. ([#112](https://github.com/launchdarkly/js-sdk-common/issues/112)) ([9d1708b](https://github.com/launchdarkly/js-sdk-common/commit/9d1708b212246c5650794af99f79cd6a95cfbcd1))
|
|
11
|
+
|
|
12
|
+
## [5.3.0](https://github.com/launchdarkly/js-sdk-common/compare/launchdarkly-js-sdk-common-v5.2.0...launchdarkly-js-sdk-common-v5.3.0) (2024-06-18)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* Add inExperiment to evaluation reason. ([#105](https://github.com/launchdarkly/js-sdk-common/issues/105)) ([cf69770](https://github.com/launchdarkly/js-sdk-common/commit/cf6977080e67e4e54f773df410a671764dbcb304))
|
|
18
|
+
* Allow for synchronous inspectors. ([#103](https://github.com/launchdarkly/js-sdk-common/issues/103)) ([7e490f4](https://github.com/launchdarkly/js-sdk-common/commit/7e490f479299f772a9db78efd1c2235645785250))
|
|
19
|
+
|
|
20
|
+
## [5.2.0] - 2024-05-01
|
|
21
|
+
### Added:
|
|
22
|
+
- 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.
|
|
23
|
+
|
|
24
|
+
### Changed:
|
|
25
|
+
- 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.
|
|
26
|
+
|
|
27
|
+
### Fixed:
|
|
28
|
+
- Fixed the documentation for `evaluationReasons` for the `identify` method.
|
|
29
|
+
|
|
5
30
|
## [5.1.0] - 2024-03-19
|
|
6
31
|
### Changed:
|
|
7
32
|
- Redact anonymous attributes within feature events
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# LaunchDarkly Javascript SDK Core Components
|
|
2
2
|
|
|
3
|
-
[![
|
|
3
|
+
[![Actions Status][ci-badge]][ci]
|
|
4
4
|
|
|
5
5
|
## LaunchDarkly overview
|
|
6
6
|
|
|
@@ -33,3 +33,6 @@ We encourage pull requests and other contributions from the community. Check out
|
|
|
33
33
|
* [docs.launchdarkly.com](https://docs.launchdarkly.com/ "LaunchDarkly Documentation") for our documentation and SDK reference guides
|
|
34
34
|
* [apidocs.launchdarkly.com](https://apidocs.launchdarkly.com/ "LaunchDarkly API Documentation") for our API documentation
|
|
35
35
|
* [blog.launchdarkly.com](https://blog.launchdarkly.com/ "LaunchDarkly Blog Documentation") for the latest product updates
|
|
36
|
+
|
|
37
|
+
[ci-badge]: https://github.com/launchdarkly/js-sdk-common/actions/workflows/ci.yml/badge.svg
|
|
38
|
+
[ci]: https://github.com/launchdarkly/js-sdk-common/actions/workflows/ci.yml
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "launchdarkly-js-sdk-common",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.4.0",
|
|
4
4
|
"description": "LaunchDarkly SDK for JavaScript - common code",
|
|
5
5
|
"author": "LaunchDarkly <team@launchdarkly.com>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"format:test:md": "prettier --parser markdown --ignore-path .prettierignore --list-different '*.md'",
|
|
18
18
|
"format:test:js": "prettier --ignore-path .prettierignore --list-different 'src/**/*.js'",
|
|
19
19
|
"test": "cross-env NODE_ENV=test jest",
|
|
20
|
-
"check-typescript": "
|
|
20
|
+
"check-typescript": "tsc",
|
|
21
|
+
"doc": "typedoc"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
23
24
|
"@babel/cli": "^7.8.4",
|
|
@@ -43,7 +44,8 @@
|
|
|
43
44
|
"launchdarkly-js-test-helpers": "1.1.0",
|
|
44
45
|
"prettier": "1.19.1",
|
|
45
46
|
"readline-sync": "^1.4.9",
|
|
46
|
-
"typescript": "~
|
|
47
|
+
"typescript": "~5.4.5",
|
|
48
|
+
"typedoc": "^0.25.13"
|
|
47
49
|
},
|
|
48
50
|
"dependencies": {
|
|
49
51
|
"base64-js": "^1.3.0",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
if $LD_RELEASE_IS_DRYRUN ; then
|
|
3
|
+
echo "Doing a dry run of publishing."
|
|
4
|
+
else
|
|
5
|
+
if $LD_RELEASE_IS_PRERELEASE ; then
|
|
6
|
+
echo "Publishing with prerelease tag."
|
|
7
|
+
npm publish --tag prerelease --provenance --access public || { echo "npm publish failed" >&2; exit 1; }
|
|
8
|
+
else
|
|
9
|
+
npm publish --provenance --access public || { echo "npm publish failed" >&2; exit 1; }
|
|
10
|
+
fi
|
|
11
|
+
fi
|
package/src/InspectorManager.js
CHANGED
|
@@ -22,6 +22,9 @@ function InspectorManager(inspectors, logger) {
|
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Collection of inspectors keyed by type.
|
|
25
|
+
*
|
|
26
|
+
* Inspectors are async by default.
|
|
27
|
+
*
|
|
25
28
|
* @type {{[type: string]: object[]}}
|
|
26
29
|
*/
|
|
27
30
|
const inspectorsByType = {
|
|
@@ -30,14 +33,30 @@ function InspectorManager(inspectors, logger) {
|
|
|
30
33
|
[InspectorTypes.flagDetailChanged]: [],
|
|
31
34
|
[InspectorTypes.clientIdentityChanged]: [],
|
|
32
35
|
};
|
|
36
|
+
/**
|
|
37
|
+
* Collection synchronous of inspectors keyed by type.
|
|
38
|
+
*
|
|
39
|
+
* @type {{[type: string]: object[]}}
|
|
40
|
+
*/
|
|
41
|
+
const synchronousInspectorsByType = {
|
|
42
|
+
[InspectorTypes.flagUsed]: [],
|
|
43
|
+
[InspectorTypes.flagDetailsChanged]: [],
|
|
44
|
+
[InspectorTypes.flagDetailChanged]: [],
|
|
45
|
+
[InspectorTypes.clientIdentityChanged]: [],
|
|
46
|
+
};
|
|
33
47
|
|
|
34
48
|
const safeInspectors = inspectors && inspectors.map(inspector => SafeInspector(inspector, logger));
|
|
35
49
|
|
|
36
50
|
safeInspectors &&
|
|
37
51
|
safeInspectors.forEach(safeInspector => {
|
|
38
52
|
// Only add inspectors of supported types.
|
|
39
|
-
if (Object.prototype.hasOwnProperty.call(inspectorsByType, safeInspector.type)) {
|
|
53
|
+
if (Object.prototype.hasOwnProperty.call(inspectorsByType, safeInspector.type) && !safeInspector.synchronous) {
|
|
40
54
|
inspectorsByType[safeInspector.type].push(safeInspector);
|
|
55
|
+
} else if (
|
|
56
|
+
Object.prototype.hasOwnProperty.call(synchronousInspectorsByType, safeInspector.type) &&
|
|
57
|
+
safeInspector.synchronous
|
|
58
|
+
) {
|
|
59
|
+
synchronousInspectorsByType[safeInspector.type].push(safeInspector);
|
|
41
60
|
} else {
|
|
42
61
|
logger.warn(messages.invalidInspector(safeInspector.type, safeInspector.name));
|
|
43
62
|
}
|
|
@@ -49,7 +68,9 @@ function InspectorManager(inspectors, logger) {
|
|
|
49
68
|
* @param {string} type The type of the inspector to check.
|
|
50
69
|
* @returns True if there are any inspectors of that type registered.
|
|
51
70
|
*/
|
|
52
|
-
manager.hasListeners = type =>
|
|
71
|
+
manager.hasListeners = type =>
|
|
72
|
+
(inspectorsByType[type] && inspectorsByType[type].length) ||
|
|
73
|
+
(synchronousInspectorsByType[type] && synchronousInspectorsByType[type].length);
|
|
53
74
|
|
|
54
75
|
/**
|
|
55
76
|
* Notify registered inspectors of a flag being used.
|
|
@@ -61,9 +82,13 @@ function InspectorManager(inspectors, logger) {
|
|
|
61
82
|
* @param {Object} context The LDContext for the flag.
|
|
62
83
|
*/
|
|
63
84
|
manager.onFlagUsed = (flagKey, detail, context) => {
|
|
64
|
-
|
|
85
|
+
const type = InspectorTypes.flagUsed;
|
|
86
|
+
if (synchronousInspectorsByType[type].length) {
|
|
87
|
+
synchronousInspectorsByType[type].forEach(inspector => inspector.method(flagKey, detail, context));
|
|
88
|
+
}
|
|
89
|
+
if (inspectorsByType[type].length) {
|
|
65
90
|
onNextTick(() => {
|
|
66
|
-
inspectorsByType[
|
|
91
|
+
inspectorsByType[type].forEach(inspector => inspector.method(flagKey, detail, context));
|
|
67
92
|
});
|
|
68
93
|
}
|
|
69
94
|
};
|
|
@@ -76,9 +101,13 @@ function InspectorManager(inspectors, logger) {
|
|
|
76
101
|
* @param {Record<string, Object>} flags The current flags as a Record<string, LDEvaluationDetail>.
|
|
77
102
|
*/
|
|
78
103
|
manager.onFlags = flags => {
|
|
79
|
-
|
|
104
|
+
const type = InspectorTypes.flagDetailsChanged;
|
|
105
|
+
if (synchronousInspectorsByType[type].length) {
|
|
106
|
+
synchronousInspectorsByType[type].forEach(inspector => inspector.method(flags));
|
|
107
|
+
}
|
|
108
|
+
if (inspectorsByType[type].length) {
|
|
80
109
|
onNextTick(() => {
|
|
81
|
-
inspectorsByType[
|
|
110
|
+
inspectorsByType[type].forEach(inspector => inspector.method(flags));
|
|
82
111
|
});
|
|
83
112
|
}
|
|
84
113
|
};
|
|
@@ -92,9 +121,13 @@ function InspectorManager(inspectors, logger) {
|
|
|
92
121
|
* @param {Object} flag An `LDEvaluationDetail` for the flag.
|
|
93
122
|
*/
|
|
94
123
|
manager.onFlagChanged = (flagKey, flag) => {
|
|
95
|
-
|
|
124
|
+
const type = InspectorTypes.flagDetailChanged;
|
|
125
|
+
if (synchronousInspectorsByType[type].length) {
|
|
126
|
+
synchronousInspectorsByType[type].forEach(inspector => inspector.method(flagKey, flag));
|
|
127
|
+
}
|
|
128
|
+
if (inspectorsByType[type].length) {
|
|
96
129
|
onNextTick(() => {
|
|
97
|
-
inspectorsByType[
|
|
130
|
+
inspectorsByType[type].forEach(inspector => inspector.method(flagKey, flag));
|
|
98
131
|
});
|
|
99
132
|
}
|
|
100
133
|
};
|
|
@@ -107,9 +140,13 @@ function InspectorManager(inspectors, logger) {
|
|
|
107
140
|
* @param {Object} context The `LDContext` which is now identified.
|
|
108
141
|
*/
|
|
109
142
|
manager.onIdentityChanged = context => {
|
|
110
|
-
|
|
143
|
+
const type = InspectorTypes.clientIdentityChanged;
|
|
144
|
+
if (synchronousInspectorsByType[type].length) {
|
|
145
|
+
synchronousInspectorsByType[type].forEach(inspector => inspector.method(context));
|
|
146
|
+
}
|
|
147
|
+
if (inspectorsByType[type].length) {
|
|
111
148
|
onNextTick(() => {
|
|
112
|
-
inspectorsByType[
|
|
149
|
+
inspectorsByType[type].forEach(inspector => inspector.method(context));
|
|
113
150
|
});
|
|
114
151
|
}
|
|
115
152
|
};
|
package/src/SafeInspector.js
CHANGED
|
@@ -28,7 +28,7 @@ describe('given an inspector manager with no registered inspectors', () => {
|
|
|
28
28
|
});
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
describe('given an inspector with callbacks of every type',
|
|
31
|
+
describe.each([true, false])('given an inspector with callbacks of every type: synchronous: %p', synchronous => {
|
|
32
32
|
/**
|
|
33
33
|
* @type {AsyncQueue}
|
|
34
34
|
*/
|
|
@@ -39,6 +39,7 @@ describe('given an inspector with callbacks of every type', () => {
|
|
|
39
39
|
{
|
|
40
40
|
type: 'flag-used',
|
|
41
41
|
name: 'my-flag-used-inspector',
|
|
42
|
+
synchronous,
|
|
42
43
|
method: (flagKey, flagDetail, context) => {
|
|
43
44
|
eventQueue.add({ type: 'flag-used', flagKey, flagDetail, context });
|
|
44
45
|
},
|
|
@@ -47,6 +48,7 @@ describe('given an inspector with callbacks of every type', () => {
|
|
|
47
48
|
{
|
|
48
49
|
type: 'flag-used',
|
|
49
50
|
name: 'my-other-flag-used-inspector',
|
|
51
|
+
synchronous,
|
|
50
52
|
method: (flagKey, flagDetail, context) => {
|
|
51
53
|
eventQueue.add({ type: 'flag-used', flagKey, flagDetail, context });
|
|
52
54
|
},
|
|
@@ -54,6 +56,7 @@ describe('given an inspector with callbacks of every type', () => {
|
|
|
54
56
|
{
|
|
55
57
|
type: 'flag-details-changed',
|
|
56
58
|
name: 'my-flag-details-inspector',
|
|
59
|
+
synchronous,
|
|
57
60
|
method: details => {
|
|
58
61
|
eventQueue.add({
|
|
59
62
|
type: 'flag-details-changed',
|
|
@@ -64,6 +67,7 @@ describe('given an inspector with callbacks of every type', () => {
|
|
|
64
67
|
{
|
|
65
68
|
type: 'flag-detail-changed',
|
|
66
69
|
name: 'my-flag-detail-inspector',
|
|
70
|
+
synchronous,
|
|
67
71
|
method: (flagKey, flagDetail) => {
|
|
68
72
|
eventQueue.add({
|
|
69
73
|
type: 'flag-detail-changed',
|
|
@@ -75,6 +79,7 @@ describe('given an inspector with callbacks of every type', () => {
|
|
|
75
79
|
{
|
|
76
80
|
type: 'client-identity-changed',
|
|
77
81
|
name: 'my-identity-inspector',
|
|
82
|
+
synchronous,
|
|
78
83
|
method: context => {
|
|
79
84
|
eventQueue.add({
|
|
80
85
|
type: 'client-identity-changed',
|
|
@@ -85,6 +90,7 @@ describe('given an inspector with callbacks of every type', () => {
|
|
|
85
90
|
// Invalid inspector shouldn't have an effect.
|
|
86
91
|
{
|
|
87
92
|
type: 'potato',
|
|
93
|
+
synchronous,
|
|
88
94
|
name: 'my-potato-inspector',
|
|
89
95
|
method: () => {},
|
|
90
96
|
},
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
1
2
|
import * as messages from '../messages';
|
|
2
3
|
|
|
3
4
|
import { withCloseable, sleepAsync } from 'launchdarkly-js-test-helpers';
|
|
@@ -253,6 +254,81 @@ describe('LDClient events', () => {
|
|
|
253
254
|
});
|
|
254
255
|
});
|
|
255
256
|
|
|
257
|
+
it('sends events for prerequisites', async () => {
|
|
258
|
+
const initData = makeBootstrap({
|
|
259
|
+
'is-prereq': {
|
|
260
|
+
value: true,
|
|
261
|
+
variation: 1,
|
|
262
|
+
reason: {
|
|
263
|
+
kind: 'FALLTHROUGH',
|
|
264
|
+
},
|
|
265
|
+
version: 1,
|
|
266
|
+
trackEvents: true,
|
|
267
|
+
trackReason: true,
|
|
268
|
+
},
|
|
269
|
+
'has-prereq-depth-1': {
|
|
270
|
+
value: true,
|
|
271
|
+
variation: 0,
|
|
272
|
+
prerequisites: ['is-prereq'],
|
|
273
|
+
reason: {
|
|
274
|
+
kind: 'FALLTHROUGH',
|
|
275
|
+
},
|
|
276
|
+
version: 4,
|
|
277
|
+
trackEvents: true,
|
|
278
|
+
trackReason: true,
|
|
279
|
+
},
|
|
280
|
+
'has-prereq-depth-2': {
|
|
281
|
+
value: true,
|
|
282
|
+
variation: 0,
|
|
283
|
+
prerequisites: ['has-prereq-depth-1'],
|
|
284
|
+
reason: {
|
|
285
|
+
kind: 'FALLTHROUGH',
|
|
286
|
+
},
|
|
287
|
+
version: 5,
|
|
288
|
+
trackEvents: true,
|
|
289
|
+
trackReason: true,
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
await withClientAndEventProcessor(user, { bootstrap: initData }, async (client, ep) => {
|
|
293
|
+
await client.waitForInitialization(5);
|
|
294
|
+
client.variation('has-prereq-depth-2', false);
|
|
295
|
+
|
|
296
|
+
// An identify event and 3 feature events.
|
|
297
|
+
expect(ep.events.length).toEqual(4);
|
|
298
|
+
expectIdentifyEvent(ep.events[0], user);
|
|
299
|
+
expect(ep.events[1]).toMatchObject({
|
|
300
|
+
kind: 'feature',
|
|
301
|
+
key: 'is-prereq',
|
|
302
|
+
variation: 1,
|
|
303
|
+
value: true,
|
|
304
|
+
version: 1,
|
|
305
|
+
reason: {
|
|
306
|
+
kind: 'FALLTHROUGH',
|
|
307
|
+
},
|
|
308
|
+
});
|
|
309
|
+
expect(ep.events[2]).toMatchObject({
|
|
310
|
+
kind: 'feature',
|
|
311
|
+
key: 'has-prereq-depth-1',
|
|
312
|
+
variation: 0,
|
|
313
|
+
value: true,
|
|
314
|
+
version: 4,
|
|
315
|
+
reason: {
|
|
316
|
+
kind: 'FALLTHROUGH',
|
|
317
|
+
},
|
|
318
|
+
});
|
|
319
|
+
expect(ep.events[3]).toMatchObject({
|
|
320
|
+
kind: 'feature',
|
|
321
|
+
key: 'has-prereq-depth-2',
|
|
322
|
+
variation: 0,
|
|
323
|
+
value: true,
|
|
324
|
+
version: 5,
|
|
325
|
+
reason: {
|
|
326
|
+
kind: 'FALLTHROUGH',
|
|
327
|
+
},
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
|
|
256
332
|
it('sends a feature event on receiving a new flag value', async () => {
|
|
257
333
|
const oldFlags = { foo: { value: 'a', variation: 1, version: 2, flagVersion: 2000 } };
|
|
258
334
|
const newFlags = { foo: { value: 'b', variation: 2, version: 3, flagVersion: 2001 } };
|
|
@@ -327,6 +403,22 @@ describe('LDClient events', () => {
|
|
|
327
403
|
});
|
|
328
404
|
});
|
|
329
405
|
|
|
406
|
+
it('does not send duplicate events for prerequisites with all flags.', async () => {
|
|
407
|
+
const initData = makeBootstrap({
|
|
408
|
+
foo: { value: 'a', variation: 1, version: 2 },
|
|
409
|
+
bar: { value: 'b', variation: 1, version: 3, prerequisites: ['foo'] },
|
|
410
|
+
});
|
|
411
|
+
await withClientAndEventProcessor(user, { bootstrap: initData }, async (client, ep) => {
|
|
412
|
+
await client.waitForInitialization(5);
|
|
413
|
+
client.allFlags();
|
|
414
|
+
|
|
415
|
+
expect(ep.events.length).toEqual(3);
|
|
416
|
+
expectIdentifyEvent(ep.events[0], user);
|
|
417
|
+
expectFeatureEvent({ e: ep.events[1], key: 'foo', user, value: 'a', variation: 1, version: 2, defaultVal: null });
|
|
418
|
+
expectFeatureEvent({ e: ep.events[2], key: 'bar', user, value: 'b', variation: 1, version: 3, defaultVal: null });
|
|
419
|
+
});
|
|
420
|
+
});
|
|
421
|
+
|
|
330
422
|
it('does not send feature events for allFlags() if sendEventsOnlyForVariation is set', async () => {
|
|
331
423
|
const initData = makeBootstrap({
|
|
332
424
|
foo: { value: 'a', variation: 1, version: 2 },
|
|
@@ -5,12 +5,48 @@ const stubPlatform = require('./stubPlatform');
|
|
|
5
5
|
const envName = 'UNKNOWN_ENVIRONMENT_ID';
|
|
6
6
|
const context = { key: 'context-key' };
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const flagPayload = {
|
|
9
|
+
'is-prereq': {
|
|
10
|
+
value: true,
|
|
11
|
+
variation: 1,
|
|
12
|
+
reason: {
|
|
13
|
+
kind: 'FALLTHROUGH',
|
|
14
|
+
},
|
|
15
|
+
version: 1,
|
|
16
|
+
trackEvents: true,
|
|
17
|
+
trackReason: true,
|
|
18
|
+
},
|
|
19
|
+
'has-prereq-depth-1': {
|
|
20
|
+
value: true,
|
|
21
|
+
variation: 0,
|
|
22
|
+
prerequisites: ['is-prereq'],
|
|
23
|
+
reason: {
|
|
24
|
+
kind: 'FALLTHROUGH',
|
|
25
|
+
},
|
|
26
|
+
version: 4,
|
|
27
|
+
trackEvents: true,
|
|
28
|
+
trackReason: true,
|
|
29
|
+
},
|
|
30
|
+
'has-prereq-depth-2': {
|
|
31
|
+
value: true,
|
|
32
|
+
variation: 0,
|
|
33
|
+
prerequisites: ['has-prereq-depth-1'],
|
|
34
|
+
reason: {
|
|
35
|
+
kind: 'FALLTHROUGH',
|
|
36
|
+
},
|
|
37
|
+
version: 5,
|
|
38
|
+
trackEvents: true,
|
|
39
|
+
trackReason: true,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
describe.each([true, false])('given a streaming client with registered inspectors, synchronous: %p', synchronous => {
|
|
9
44
|
const eventQueue = new AsyncQueue();
|
|
10
45
|
|
|
11
46
|
const inspectors = [
|
|
12
47
|
{
|
|
13
48
|
type: 'flag-used',
|
|
49
|
+
synchronous,
|
|
14
50
|
method: (flagKey, flagDetail, context) => {
|
|
15
51
|
eventQueue.add({ type: 'flag-used', flagKey, flagDetail, context });
|
|
16
52
|
},
|
|
@@ -18,12 +54,14 @@ describe('given a streaming client with registered inspectors', () => {
|
|
|
18
54
|
// 'flag-used registered twice.
|
|
19
55
|
{
|
|
20
56
|
type: 'flag-used',
|
|
57
|
+
synchronous,
|
|
21
58
|
method: (flagKey, flagDetail, context) => {
|
|
22
59
|
eventQueue.add({ type: 'flag-used', flagKey, flagDetail, context });
|
|
23
60
|
},
|
|
24
61
|
},
|
|
25
62
|
{
|
|
26
63
|
type: 'flag-details-changed',
|
|
64
|
+
synchronous,
|
|
27
65
|
method: details => {
|
|
28
66
|
eventQueue.add({
|
|
29
67
|
type: 'flag-details-changed',
|
|
@@ -33,6 +71,7 @@ describe('given a streaming client with registered inspectors', () => {
|
|
|
33
71
|
},
|
|
34
72
|
{
|
|
35
73
|
type: 'flag-detail-changed',
|
|
74
|
+
synchronous,
|
|
36
75
|
method: (flagKey, flagDetail) => {
|
|
37
76
|
eventQueue.add({
|
|
38
77
|
type: 'flag-detail-changed',
|
|
@@ -43,6 +82,7 @@ describe('given a streaming client with registered inspectors', () => {
|
|
|
43
82
|
},
|
|
44
83
|
{
|
|
45
84
|
type: 'client-identity-changed',
|
|
85
|
+
synchronous,
|
|
46
86
|
method: context => {
|
|
47
87
|
eventQueue.add({
|
|
48
88
|
type: 'client-identity-changed',
|
|
@@ -58,7 +98,7 @@ describe('given a streaming client with registered inspectors', () => {
|
|
|
58
98
|
beforeEach(async () => {
|
|
59
99
|
platform = stubPlatform.defaults();
|
|
60
100
|
const server = platform.testing.http.newServer();
|
|
61
|
-
server.byDefault(respondJson(
|
|
101
|
+
server.byDefault(respondJson(flagPayload));
|
|
62
102
|
const config = { streaming: true, baseUrl: server.url, inspectors, sendEvents: false };
|
|
63
103
|
client = platform.testing.makeClient(envName, context, config);
|
|
64
104
|
await client.waitUntilReady();
|
|
@@ -86,7 +126,29 @@ describe('given a streaming client with registered inspectors', () => {
|
|
|
86
126
|
const flagsEvent = await eventQueue.take();
|
|
87
127
|
expect(flagsEvent).toMatchObject({
|
|
88
128
|
type: 'flag-details-changed',
|
|
89
|
-
details: {
|
|
129
|
+
details: {
|
|
130
|
+
'is-prereq': {
|
|
131
|
+
value: true,
|
|
132
|
+
variationIndex: 1,
|
|
133
|
+
reason: {
|
|
134
|
+
kind: 'FALLTHROUGH',
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
'has-prereq-depth-1': {
|
|
138
|
+
value: true,
|
|
139
|
+
variationIndex: 0,
|
|
140
|
+
reason: {
|
|
141
|
+
kind: 'FALLTHROUGH',
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
'has-prereq-depth-2': {
|
|
145
|
+
value: true,
|
|
146
|
+
variationIndex: 0,
|
|
147
|
+
reason: {
|
|
148
|
+
kind: 'FALLTHROUGH',
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
},
|
|
90
152
|
});
|
|
91
153
|
});
|
|
92
154
|
|
|
@@ -124,4 +186,51 @@ describe('given a streaming client with registered inspectors', () => {
|
|
|
124
186
|
flagDetail: { value: false },
|
|
125
187
|
});
|
|
126
188
|
});
|
|
189
|
+
|
|
190
|
+
it('emits an event when a flag is used', async () => {
|
|
191
|
+
// Take initial events.
|
|
192
|
+
eventQueue.take();
|
|
193
|
+
eventQueue.take();
|
|
194
|
+
|
|
195
|
+
await platform.testing.eventSourcesCreated.take();
|
|
196
|
+
client.variation('is-prereq', false);
|
|
197
|
+
const updateEvent = await eventQueue.take();
|
|
198
|
+
expect(updateEvent).toMatchObject({
|
|
199
|
+
type: 'flag-used',
|
|
200
|
+
flagKey: 'is-prereq',
|
|
201
|
+
flagDetail: { value: true },
|
|
202
|
+
});
|
|
203
|
+
// Two inspectors are handling this
|
|
204
|
+
const updateEvent2 = await eventQueue.take();
|
|
205
|
+
expect(updateEvent2).toMatchObject({
|
|
206
|
+
type: 'flag-used',
|
|
207
|
+
flagKey: 'is-prereq',
|
|
208
|
+
flagDetail: { value: true },
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('does not execute flag-used for prerequisites', async () => {
|
|
213
|
+
// Take initial events.
|
|
214
|
+
eventQueue.take();
|
|
215
|
+
eventQueue.take();
|
|
216
|
+
|
|
217
|
+
await platform.testing.eventSourcesCreated.take();
|
|
218
|
+
client.variation('has-prereq-depth-2', false);
|
|
219
|
+
// There would be many more than 2 events if prerequisites were inspected.
|
|
220
|
+
const updateEvent = await eventQueue.take();
|
|
221
|
+
expect(updateEvent).toMatchObject({
|
|
222
|
+
type: 'flag-used',
|
|
223
|
+
flagKey: 'has-prereq-depth-2',
|
|
224
|
+
flagDetail: { value: true },
|
|
225
|
+
});
|
|
226
|
+
// Two inspectors are handling this
|
|
227
|
+
const updateEvent2 = await eventQueue.take();
|
|
228
|
+
expect(updateEvent2).toMatchObject({
|
|
229
|
+
type: 'flag-used',
|
|
230
|
+
flagKey: 'has-prereq-depth-2',
|
|
231
|
+
flagDetail: { value: true },
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
expect(eventQueue.length()).toEqual(0);
|
|
235
|
+
});
|
|
127
236
|
});
|
package/src/index.js
CHANGED
|
@@ -299,18 +299,19 @@ function initialize(env, context, specifiedOptions, platform, extraOptionDefs) {
|
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
function variation(key, defaultValue) {
|
|
302
|
-
return variationDetailInternal(key, defaultValue, true, false, false).value;
|
|
302
|
+
return variationDetailInternal(key, defaultValue, true, false, false, true).value;
|
|
303
303
|
}
|
|
304
304
|
|
|
305
305
|
function variationDetail(key, defaultValue) {
|
|
306
|
-
return variationDetailInternal(key, defaultValue, true, true, false);
|
|
306
|
+
return variationDetailInternal(key, defaultValue, true, true, false, true);
|
|
307
307
|
}
|
|
308
308
|
|
|
309
|
-
function variationDetailInternal(key, defaultValue, sendEvent, includeReasonInEvent, isAllFlags) {
|
|
309
|
+
function variationDetailInternal(key, defaultValue, sendEvent, includeReasonInEvent, isAllFlags, notifyInspection) {
|
|
310
310
|
let detail;
|
|
311
|
+
let flag;
|
|
311
312
|
|
|
312
313
|
if (flags && utils.objectHasOwnProperty(flags, key) && flags[key] && !flags[key].deleted) {
|
|
313
|
-
|
|
314
|
+
flag = flags[key];
|
|
314
315
|
detail = getFlagDetail(flag);
|
|
315
316
|
if (flag.value === null || flag.value === undefined) {
|
|
316
317
|
detail.value = defaultValue;
|
|
@@ -320,11 +321,18 @@ function initialize(env, context, specifiedOptions, platform, extraOptionDefs) {
|
|
|
320
321
|
}
|
|
321
322
|
|
|
322
323
|
if (sendEvent) {
|
|
324
|
+
// For an all-flags evaluation, with events enabled, each flag will get an event, so we do not
|
|
325
|
+
// need to duplicate the prerequisites.
|
|
326
|
+
if (!isAllFlags) {
|
|
327
|
+
flag?.prerequisites?.forEach(key => {
|
|
328
|
+
variationDetailInternal(key, undefined, sendEvent, false, false, false);
|
|
329
|
+
});
|
|
330
|
+
}
|
|
323
331
|
sendFlagEvent(key, detail, defaultValue, includeReasonInEvent);
|
|
324
332
|
}
|
|
325
333
|
|
|
326
334
|
// For the all flags case `onFlags` will be called instead.
|
|
327
|
-
if (!isAllFlags) {
|
|
335
|
+
if (!isAllFlags && notifyInspection) {
|
|
328
336
|
notifyInspectionFlagUsed(key, detail);
|
|
329
337
|
}
|
|
330
338
|
|
|
@@ -351,7 +359,14 @@ function initialize(env, context, specifiedOptions, platform, extraOptionDefs) {
|
|
|
351
359
|
|
|
352
360
|
for (const key in flags) {
|
|
353
361
|
if (utils.objectHasOwnProperty(flags, key) && !flags[key].deleted) {
|
|
354
|
-
results[key] = variationDetailInternal(
|
|
362
|
+
results[key] = variationDetailInternal(
|
|
363
|
+
key,
|
|
364
|
+
null,
|
|
365
|
+
!options.sendEventsOnlyForVariation,
|
|
366
|
+
false,
|
|
367
|
+
true,
|
|
368
|
+
false
|
|
369
|
+
).value;
|
|
355
370
|
}
|
|
356
371
|
}
|
|
357
372
|
|
|
@@ -462,8 +477,8 @@ function initialize(env, context, specifiedOptions, platform, extraOptionDefs) {
|
|
|
462
477
|
} else {
|
|
463
478
|
mods[data.key] = { current: newDetail };
|
|
464
479
|
}
|
|
465
|
-
handleFlagChanges(mods); // don't wait for this Promise to be resolved
|
|
466
480
|
notifyInspectionFlagChanged(data, newFlag);
|
|
481
|
+
handleFlagChanges(mods); // don't wait for this Promise to be resolved
|
|
467
482
|
} else {
|
|
468
483
|
logger.debug(messages.debugStreamPatchIgnored(data.key));
|
|
469
484
|
}
|
package/src/messages.js
CHANGED
|
@@ -15,7 +15,7 @@ const clientInitialized = function() {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
const docLink =
|
|
18
|
-
' Please see https://docs.launchdarkly.com/sdk/client-side/javascript#
|
|
18
|
+
' Please see https://docs.launchdarkly.com/sdk/client-side/javascript#initialize-the-client for instructions on SDK initialization.';
|
|
19
19
|
|
|
20
20
|
const clientNotReady = function() {
|
|
21
21
|
return 'LaunchDarkly client is not ready';
|
package/typedoc.json
ADDED
package/typings.d.ts
CHANGED
|
@@ -552,7 +552,7 @@ declare module 'launchdarkly-js-sdk-common' {
|
|
|
552
552
|
|
|
553
553
|
/**
|
|
554
554
|
* Describes the reason that a flag evaluation produced a particular value. This is
|
|
555
|
-
* part of the {@link LDEvaluationDetail} object returned by {@link LDClient.variationDetail
|
|
555
|
+
* part of the {@link LDEvaluationDetail} object returned by {@link LDClient.variationDetail}.
|
|
556
556
|
*/
|
|
557
557
|
export interface LDEvaluationReason {
|
|
558
558
|
/**
|
|
@@ -588,6 +588,14 @@ declare module 'launchdarkly-js-sdk-common' {
|
|
|
588
588
|
* The key of the failed prerequisite flag, if the kind was `'PREREQUISITE_FAILED'`.
|
|
589
589
|
*/
|
|
590
590
|
prerequisiteKey?: string;
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Whether the evaluation was part of an experiment.
|
|
594
|
+
*
|
|
595
|
+
* This is true if the evaluation resulted in an experiment rollout and served one of
|
|
596
|
+
* the variations in the experiment. Otherwise it is false or undefined.
|
|
597
|
+
*/
|
|
598
|
+
inExperiment?: boolean;
|
|
591
599
|
}
|
|
592
600
|
|
|
593
601
|
/**
|
|
@@ -1013,6 +1021,13 @@ declare module 'launchdarkly-js-sdk-common' {
|
|
|
1013
1021
|
*/
|
|
1014
1022
|
name: string;
|
|
1015
1023
|
|
|
1024
|
+
/**
|
|
1025
|
+
* If `true`, then the inspector will be ran synchronously with evaluation.
|
|
1026
|
+
* Synchronous inspectors execute inline with evaluation and care should be taken to ensure
|
|
1027
|
+
* they have minimal performance overhead.
|
|
1028
|
+
*/
|
|
1029
|
+
synchronous?: boolean,
|
|
1030
|
+
|
|
1016
1031
|
/**
|
|
1017
1032
|
* This method is called when a flag is accessed via a variation method, or it can be called based on actions in
|
|
1018
1033
|
* wrapper SDKs which have different methods of tracking when a flag was accessed. It is not called when a call is made
|
|
@@ -1040,6 +1055,11 @@ declare module 'launchdarkly-js-sdk-common' {
|
|
|
1040
1055
|
*/
|
|
1041
1056
|
name: string;
|
|
1042
1057
|
|
|
1058
|
+
/**
|
|
1059
|
+
* If `true`, then the inspector will be ran synchronously with flag updates.
|
|
1060
|
+
*/
|
|
1061
|
+
synchronous?: boolean,
|
|
1062
|
+
|
|
1043
1063
|
/**
|
|
1044
1064
|
* This method is called when the flags in the store are replaced with new flags. It will contain all flags
|
|
1045
1065
|
* regardless of if they have been evaluated.
|
|
@@ -1065,6 +1085,11 @@ declare module 'launchdarkly-js-sdk-common' {
|
|
|
1065
1085
|
*/
|
|
1066
1086
|
name: string;
|
|
1067
1087
|
|
|
1088
|
+
/**
|
|
1089
|
+
* If `true`, then the inspector will be ran synchronously with flag updates.
|
|
1090
|
+
*/
|
|
1091
|
+
synchronous?: boolean,
|
|
1092
|
+
|
|
1068
1093
|
/**
|
|
1069
1094
|
* This method is called when a flag is updated. It will not be called
|
|
1070
1095
|
* when all flags are updated.
|
|
@@ -1088,6 +1113,11 @@ declare module 'launchdarkly-js-sdk-common' {
|
|
|
1088
1113
|
*/
|
|
1089
1114
|
name: string;
|
|
1090
1115
|
|
|
1116
|
+
/**
|
|
1117
|
+
* If `true`, then the inspector will be ran synchronously with identification.
|
|
1118
|
+
*/
|
|
1119
|
+
synchronous?: boolean,
|
|
1120
|
+
|
|
1091
1121
|
/**
|
|
1092
1122
|
* This method will be called when an identify operation completes.
|
|
1093
1123
|
*/
|
package/.circleci/config.yml
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
version: 2
|
|
2
|
-
jobs:
|
|
3
|
-
build:
|
|
4
|
-
docker:
|
|
5
|
-
- image: cimg/node:12.22
|
|
6
|
-
steps:
|
|
7
|
-
- checkout
|
|
8
|
-
|
|
9
|
-
- run: npm install
|
|
10
|
-
- run: npm run lint:all
|
|
11
|
-
- run:
|
|
12
|
-
command: npm test
|
|
13
|
-
environment:
|
|
14
|
-
JEST_JUNIT_OUTPUT: "reports/junit/js-test-results.xml"
|
|
15
|
-
- run: npm run check-typescript
|
|
16
|
-
- run:
|
|
17
|
-
name: dependency audit
|
|
18
|
-
command: ./scripts/better-audit.sh
|
|
19
|
-
- store_test_results:
|
|
20
|
-
path: reports/junit/
|
|
21
|
-
- store_artifacts:
|
|
22
|
-
path: reports/junit/
|
package/.ldrelease/config.yml
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
version: 2
|
|
2
|
-
|
|
3
|
-
repo:
|
|
4
|
-
public: js-sdk-common
|
|
5
|
-
private: js-sdk-common-private
|
|
6
|
-
|
|
7
|
-
branches:
|
|
8
|
-
- name: main
|
|
9
|
-
description: 5.x
|
|
10
|
-
- name: 4.x
|
|
11
|
-
- name: 3.x
|
|
12
|
-
|
|
13
|
-
publications:
|
|
14
|
-
- url: https://www.npmjs.com/package/launchdarkly-js-sdk-common
|
|
15
|
-
description: npm
|
|
16
|
-
|
|
17
|
-
jobs:
|
|
18
|
-
- docker:
|
|
19
|
-
image: node:12-buster
|
|
20
|
-
template:
|
|
21
|
-
name: npm
|
|
22
|
-
|
|
23
|
-
documentation:
|
|
24
|
-
gitHubPages: true
|
|
25
|
-
title: LaunchDarkly Javascript SDK Core Components
|
package/docs/typedoc.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
out: '/tmp/project-releaser/project/docs/build/html',
|
|
3
|
-
exclude: [
|
|
4
|
-
'**/node_modules/**',
|
|
5
|
-
'test-types.ts'
|
|
6
|
-
],
|
|
7
|
-
name: "LaunchDarkly Javascript SDK Core Components (4.0.2)",
|
|
8
|
-
readme: 'none', // don't add a home page with a copy of README.md
|
|
9
|
-
entryPoints: "/tmp/project-releaser/project/typings.d.ts",
|
|
10
|
-
entryPointStrategy: "expand"
|
|
11
|
-
};
|