@depup/launchdarkly-node-server-sdk 7.0.4-depup.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.
Files changed (107) hide show
  1. package/.babelrc +16 -0
  2. package/.circleci/config.yml +89 -0
  3. package/.eslintignore +5 -0
  4. package/.eslintrc.yaml +114 -0
  5. package/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
  6. package/.github/ISSUE_TEMPLATE/config.yml +5 -0
  7. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  8. package/.github/pull_request_template.md +21 -0
  9. package/.github/workflows/stale.yml +8 -0
  10. package/.hound.yml +33 -0
  11. package/.ldrelease/config.yml +28 -0
  12. package/.prettierrc +6 -0
  13. package/CHANGELOG.md +603 -0
  14. package/CODEOWNERS +2 -0
  15. package/CONTRIBUTING.md +55 -0
  16. package/LICENSE.txt +13 -0
  17. package/README.md +36 -0
  18. package/SECURITY.md +5 -0
  19. package/attribute_reference.js +217 -0
  20. package/big_segments.js +117 -0
  21. package/caching_store_wrapper.js +240 -0
  22. package/changes.json +30 -0
  23. package/configuration.js +235 -0
  24. package/context.js +98 -0
  25. package/context_filter.js +137 -0
  26. package/contract-tests/README.md +7 -0
  27. package/contract-tests/index.js +109 -0
  28. package/contract-tests/log.js +23 -0
  29. package/contract-tests/package.json +15 -0
  30. package/contract-tests/sdkClientEntity.js +110 -0
  31. package/contract-tests/testharness-suppressions.txt +2 -0
  32. package/diagnostic_events.js +151 -0
  33. package/docs/typedoc.js +10 -0
  34. package/errors.js +26 -0
  35. package/evaluator.js +822 -0
  36. package/event_factory.js +121 -0
  37. package/event_processor.js +320 -0
  38. package/event_summarizer.js +101 -0
  39. package/feature_store.js +120 -0
  40. package/feature_store_event_wrapper.js +258 -0
  41. package/file_data_source.js +192 -0
  42. package/flags_state.js +46 -0
  43. package/index.d.ts +2426 -0
  44. package/index.js +452 -0
  45. package/integrations.js +7 -0
  46. package/interfaces.js +2 -0
  47. package/loggers.js +125 -0
  48. package/messages.js +31 -0
  49. package/operators.js +106 -0
  50. package/package.json +105 -0
  51. package/polling.js +70 -0
  52. package/requestor.js +62 -0
  53. package/scripts/better-audit.sh +76 -0
  54. package/sharedtest/big_segment_store_tests.js +86 -0
  55. package/sharedtest/feature_store_tests.js +177 -0
  56. package/sharedtest/persistent_feature_store_tests.js +183 -0
  57. package/sharedtest/store_tests.js +7 -0
  58. package/streaming.js +179 -0
  59. package/test/LDClient-big-segments-test.js +92 -0
  60. package/test/LDClient-end-to-end-test.js +218 -0
  61. package/test/LDClient-evaluation-all-flags-test.js +226 -0
  62. package/test/LDClient-evaluation-test.js +204 -0
  63. package/test/LDClient-events-test.js +502 -0
  64. package/test/LDClient-listeners-test.js +180 -0
  65. package/test/LDClient-test.js +96 -0
  66. package/test/LDClient-tls-test.js +110 -0
  67. package/test/attribute_reference-test.js +494 -0
  68. package/test/big_segments-test.js +182 -0
  69. package/test/caching_store_wrapper-test.js +434 -0
  70. package/test/configuration-test.js +249 -0
  71. package/test/context-test.js +93 -0
  72. package/test/context_filter-test.js +424 -0
  73. package/test/diagnostic_events-test.js +152 -0
  74. package/test/evaluator-big-segments-test.js +301 -0
  75. package/test/evaluator-bucketing-test.js +333 -0
  76. package/test/evaluator-clause-test.js +277 -0
  77. package/test/evaluator-flag-test.js +452 -0
  78. package/test/evaluator-pre-conditions-test.js +105 -0
  79. package/test/evaluator-rule-test.js +131 -0
  80. package/test/evaluator-segment-match-test.js +310 -0
  81. package/test/evaluator_helpers.js +106 -0
  82. package/test/event_processor-test.js +680 -0
  83. package/test/event_summarizer-test.js +146 -0
  84. package/test/feature_store-test.js +42 -0
  85. package/test/feature_store_event_wrapper-test.js +182 -0
  86. package/test/feature_store_test_base.js +60 -0
  87. package/test/file_data_source-test.js +255 -0
  88. package/test/loggers-test.js +126 -0
  89. package/test/operators-test.js +102 -0
  90. package/test/polling-test.js +158 -0
  91. package/test/requestor-test.js +60 -0
  92. package/test/store_tests_big_segments-test.js +61 -0
  93. package/test/streaming-test.js +323 -0
  94. package/test/stubs.js +107 -0
  95. package/test/test_data-test.js +341 -0
  96. package/test/update_queue-test.js +61 -0
  97. package/test-types.ts +210 -0
  98. package/test_data.js +323 -0
  99. package/tsconfig.json +14 -0
  100. package/update_queue.js +28 -0
  101. package/utils/__tests__/httpUtils-test.js +39 -0
  102. package/utils/__tests__/wrapPromiseCallback-test.js +33 -0
  103. package/utils/asyncUtils.js +32 -0
  104. package/utils/httpUtils.js +105 -0
  105. package/utils/stringifyAttrs.js +14 -0
  106. package/utils/wrapPromiseCallback.js +36 -0
  107. package/versioned_data_kind.js +34 -0
@@ -0,0 +1,110 @@
1
+ const ld = require('launchdarkly-node-server-sdk');
2
+
3
+ const { Log, sdkLogger } = require('./log');
4
+
5
+ const badCommandError = new Error('unsupported command');
6
+
7
+ function makeSdkConfig(options, tag) {
8
+ const cf = {
9
+ logger: sdkLogger(tag),
10
+ };
11
+ const maybeTime = seconds => (seconds === undefined || seconds === null ? undefined : seconds / 1000);
12
+ if (options.streaming) {
13
+ cf.streamUri = options.streaming.baseUri;
14
+ cf.streamInitialReconnectDelay = maybeTime(options.streaming.initialRetryDelayMs);
15
+ }
16
+ if (options.events) {
17
+ cf.allAttributesPrivate = options.events.allAttributesPrivate;
18
+ cf.eventsUri = options.events.baseUri;
19
+ cf.capacity = options.events.capacity;
20
+ cf.diagnosticOptOut = !options.events.enableDiagnostics;
21
+ cf.flushInterval = maybeTime(options.events.flushIntervalMs);
22
+ cf.privateAttributes = options.events.globalPrivateAttributes;
23
+ }
24
+ if (options.tags) {
25
+ cf.application = {
26
+ id: options.tags.applicationId,
27
+ version: options.tags.applicationVersion,
28
+ };
29
+ }
30
+ return cf;
31
+ }
32
+
33
+ async function newSdkClientEntity(options) {
34
+ const c = {};
35
+ const log = Log(options.tag);
36
+
37
+ log.info('Creating client with configuration: ' + JSON.stringify(options.configuration));
38
+ const timeout =
39
+ options.configuration.startWaitTimeMs !== null && options.configuration.startWaitTimeMs !== undefined
40
+ ? options.configuration.startWaitTimeMs
41
+ : 5000;
42
+ const client = ld.init(
43
+ options.configuration.credential || 'unknown-sdk-key',
44
+ makeSdkConfig(options.configuration, options.tag)
45
+ );
46
+ try {
47
+ await Promise.race([client.waitForInitialization(), new Promise(resolve => setTimeout(resolve, timeout))]);
48
+ } catch (_) {
49
+ // if waitForInitialization() rejects, the client failed to initialize, see next line
50
+ }
51
+ if (!client.initialized() && !options.configuration.initCanFail) {
52
+ client.close();
53
+ throw new Error('client initialization failed');
54
+ }
55
+
56
+ c.close = () => {
57
+ client.close();
58
+ log.info('Test ended');
59
+ };
60
+
61
+ c.doCommand = async params => {
62
+ log.info('Received command: ' + params.command);
63
+ switch (params.command) {
64
+ case 'evaluate': {
65
+ const pe = params.evaluate;
66
+ if (pe.detail) {
67
+ return await client.variationDetail(pe.flagKey, pe.context || pe.user, pe.defaultValue);
68
+ } else {
69
+ const value = await client.variation(pe.flagKey, pe.context || pe.user, pe.defaultValue);
70
+ return { value };
71
+ }
72
+ }
73
+
74
+ case 'evaluateAll': {
75
+ const pea = params.evaluateAll;
76
+ const eao = {
77
+ clientSideOnly: pea.clientSideOnly,
78
+ detailsOnlyForTrackedFlags: pea.detailsOnlyForTrackedFlags,
79
+ withReasons: pea.withReasons,
80
+ };
81
+ return { state: await client.allFlagsState(pea.context || pea.user, eao) };
82
+ }
83
+
84
+ case 'identifyEvent':
85
+ client.identify(params.identifyEvent.context || params.identifyEvent.user);
86
+ return undefined;
87
+
88
+ case 'customEvent': {
89
+ const pce = params.customEvent;
90
+ client.track(pce.eventKey, pce.context || pce.user, pce.data, pce.metricValue);
91
+ return undefined;
92
+ }
93
+
94
+ case 'flushEvents':
95
+ client.flush();
96
+ return undefined;
97
+
98
+ case 'getBigSegmentStoreStatus':
99
+ return undefined;
100
+
101
+ default:
102
+ throw badCommandError;
103
+ }
104
+ };
105
+
106
+ return c;
107
+ }
108
+
109
+ module.exports.newSdkClientEntity = newSdkClientEntity;
110
+ module.exports.badCommandError = badCommandError;
@@ -0,0 +1,2 @@
1
+ streaming/validation/drop and reconnect if stream event has malformed JSON
2
+ streaming/validation/drop and reconnect if stream event has well-formed JSON not matching schema
@@ -0,0 +1,151 @@
1
+ const os = require('os');
2
+ const { v4: uuidv4 } = require('uuid');
3
+ const configuration = require('./configuration');
4
+ const packageJson = require('./package.json');
5
+
6
+ // An object that maintains information that will go into diagnostic events, and knows how to format
7
+ // those events. It is instantiated by the SDK client, and shared with the event processor.
8
+ function DiagnosticsManager(config, diagnosticId, startTime) {
9
+ let dataSinceDate = startTime;
10
+ let streamInits = [];
11
+ const acc = {};
12
+
13
+ // Creates the initial event that is sent by the event processor when the SDK starts up. This will not
14
+ // be repeated during the lifetime of the SDK client.
15
+ acc.createInitEvent = () => ({
16
+ kind: 'diagnostic-init',
17
+ id: diagnosticId,
18
+ creationDate: startTime,
19
+ sdk: makeSdkData(config),
20
+ configuration: makeConfigData(config),
21
+ platform: makePlatformData(),
22
+ });
23
+
24
+ // Records a stream connection attempt (called by the stream processor).
25
+ // timestamp: Time of the *beginning* of the connection attempt.
26
+ // failed: True if the connection failed, or we got a read timeout before receiving a "put".
27
+ // durationMillis: Elapsed time between starting timestamp and when we either gave up/lost the
28
+ // connection or received a successful "put".
29
+ acc.recordStreamInit = (timestamp, failed, durationMillis) => {
30
+ const item = { timestamp, failed, durationMillis };
31
+ streamInits.push(item);
32
+ };
33
+
34
+ // Creates a periodic event containing time-dependent stats, and resets the state of the manager with
35
+ // regard to those stats.
36
+ // Note: the reason droppedEvents, deduplicatedUsers, and eventsInLastBatch are passed into this function,
37
+ // instead of being properties of the DiagnosticsManager, is that the event processor is the one who's
38
+ // calling this function and is also the one who's tracking those stats.
39
+ acc.createStatsEventAndReset = (droppedEvents, deduplicatedUsers, eventsInLastBatch) => {
40
+ const currentTime = new Date().getTime();
41
+ const ret = {
42
+ kind: 'diagnostic',
43
+ id: diagnosticId,
44
+ creationDate: currentTime,
45
+ dataSinceDate,
46
+ droppedEvents,
47
+ deduplicatedUsers,
48
+ eventsInLastBatch,
49
+ streamInits,
50
+ };
51
+ dataSinceDate = currentTime;
52
+ streamInits = [];
53
+ return ret;
54
+ };
55
+
56
+ return acc;
57
+ }
58
+
59
+ function DiagnosticId(sdkKey) {
60
+ const ret = {
61
+ diagnosticId: uuidv4(),
62
+ };
63
+ if (sdkKey) {
64
+ ret.sdkKeySuffix = sdkKey.length > 6 ? sdkKey.substring(sdkKey.length - 6) : sdkKey;
65
+ }
66
+ return ret;
67
+ }
68
+
69
+ function makeSdkData(config) {
70
+ const sdkData = {
71
+ name: 'node-server-sdk',
72
+ version: packageJson.version,
73
+ };
74
+ if (config.wrapperName) {
75
+ sdkData.wrapperName = config.wrapperName;
76
+ }
77
+ if (config.wrapperVersion) {
78
+ sdkData.wrapperVersion = config.wrapperVersion;
79
+ }
80
+ return sdkData;
81
+ }
82
+
83
+ function makeConfigData(config) {
84
+ const defaults = configuration.defaults();
85
+ const secondsToMillis = sec => Math.trunc(sec * 1000);
86
+
87
+ function getComponentDescription(component, defaultName) {
88
+ if (component) {
89
+ return component.description || 'custom';
90
+ }
91
+ return defaultName;
92
+ }
93
+
94
+ const configData = {
95
+ customBaseURI: config.baseUri !== defaults.baseUri,
96
+ customStreamURI: config.streamUri !== defaults.streamUri,
97
+ customEventsURI: config.eventsUri !== defaults.eventsUri,
98
+ eventsCapacity: config.capacity,
99
+ connectTimeoutMillis: secondsToMillis(config.timeout),
100
+ socketTimeoutMillis: secondsToMillis(config.timeout), // Node doesn't distinguish between these two kinds of timeouts
101
+ eventsFlushIntervalMillis: secondsToMillis(config.flushInterval),
102
+ pollingIntervalMillis: secondsToMillis(config.pollInterval),
103
+ // startWaitMillis: n/a (Node SDK does not have this feature)
104
+ // samplingInterval: n/a (Node SDK does not have this feature)
105
+ reconnectTimeMillis: secondsToMillis(config.streamInitialReconnectDelay),
106
+ streamingDisabled: !config.stream,
107
+ usingRelayDaemon: !!config.useLdd,
108
+ offline: !!config.offline,
109
+ allAttributesPrivate: !!config.allAttributesPrivate,
110
+ contextKeysCapacity: config.contextKeysCapacity,
111
+ contextKeysFlushIntervalMillis: secondsToMillis(config.contextKeysFlushInterval),
112
+ usingProxy: !!(config.proxyAgent || config.proxyHost),
113
+ usingProxyAuthenticator: !!config.proxyAuth,
114
+ diagnosticRecordingIntervalMillis: secondsToMillis(config.diagnosticRecordingInterval),
115
+ dataStoreType: getComponentDescription(config.featureStore, 'memory'),
116
+ };
117
+
118
+ return configData;
119
+ }
120
+
121
+ function makePlatformData() {
122
+ return {
123
+ name: 'Node',
124
+ osArch: os.arch(),
125
+ osName: normalizePlatformName(os.platform()),
126
+ osVersion: os.release(),
127
+ // Note that os.release() is not the same OS version string that would be reported by other languages.
128
+ // It's defined as being the value returned by "uname -r" (e.g. on Mac OS 10.14, this is "18.7.0"; on
129
+ // Ubuntu 16.04, it is "4.4.0-1095-aws"), or GetVersionExW in Windows.
130
+ nodeVersion: process.versions.node,
131
+ };
132
+ }
133
+
134
+ function normalizePlatformName(platformName) {
135
+ // The following logic is based on how Node.js reports the platform name
136
+ switch (platformName) {
137
+ case 'darwin':
138
+ return 'MacOS';
139
+ case 'win32':
140
+ return 'Windows';
141
+ case 'linux':
142
+ return 'Linux';
143
+ default:
144
+ return platformName;
145
+ }
146
+ }
147
+
148
+ module.exports = {
149
+ DiagnosticsManager,
150
+ DiagnosticId,
151
+ };
@@ -0,0 +1,10 @@
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 Server-Side Node SDK (7.0.0)",
8
+ readme: 'none', // don't add a home page with a copy of README.md
9
+ entryPoints: "/tmp/project-releaser/project/index.d.ts"
10
+ };
package/errors.js ADDED
@@ -0,0 +1,26 @@
1
+ function createCustomError(name) {
2
+ function CustomError(message, code) {
3
+ Error.captureStackTrace && Error.captureStackTrace(this, this.constructor);
4
+ this.message = message;
5
+ this.code = code;
6
+ }
7
+
8
+ CustomError.prototype = new Error();
9
+ CustomError.prototype.name = name;
10
+ CustomError.prototype.constructor = CustomError;
11
+
12
+ return CustomError;
13
+ }
14
+
15
+ exports.LDPollingError = createCustomError('LaunchDarklyPollingError');
16
+ exports.LDStreamingError = createCustomError('LaunchDarklyStreamingError');
17
+ exports.LDUnexpectedResponseError = createCustomError('LaunchDarklyUnexpectedResponseError');
18
+ exports.LDInvalidSDKKeyError = createCustomError('LaunchDarklyInvalidSDKKeyError');
19
+ exports.LDClientError = createCustomError('LaunchDarklyClientError');
20
+
21
+ exports.isHttpErrorRecoverable = function (status) {
22
+ if (status >= 400 && status < 500) {
23
+ return status === 400 || status === 408 || status === 429;
24
+ }
25
+ return true;
26
+ };