@launchdarkly/js-server-sdk-common
Version:
LaunchDarkly Server SDK for JavaScript - common code
193 lines • 9.72 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultValues = void 0;
const js_sdk_common_1 = require("@launchdarkly/js-sdk-common");
const InMemoryFeatureStore_1 = require("../store/InMemoryFeatureStore");
// Once things are internal to the implementation of the SDK we can depend on
// types. Calls to the SDK could contain anything without any regard to typing.
// So, data we take from external sources must be normalized into something
// that can be trusted.
/**
* These perform cursory validations. Complex objects are implemented with classes
* and these should allow for conditional construction.
*/
const validations = {
baseUri: js_sdk_common_1.TypeValidators.String,
streamUri: js_sdk_common_1.TypeValidators.String,
eventsUri: js_sdk_common_1.TypeValidators.String,
timeout: js_sdk_common_1.TypeValidators.Number,
capacity: js_sdk_common_1.TypeValidators.Number,
logger: js_sdk_common_1.TypeValidators.Object,
featureStore: js_sdk_common_1.TypeValidators.ObjectOrFactory,
bigSegments: js_sdk_common_1.TypeValidators.Object,
updateProcessor: js_sdk_common_1.TypeValidators.ObjectOrFactory,
flushInterval: js_sdk_common_1.TypeValidators.Number,
pollInterval: js_sdk_common_1.TypeValidators.numberWithMin(30),
proxyOptions: js_sdk_common_1.TypeValidators.Object,
offline: js_sdk_common_1.TypeValidators.Boolean,
stream: js_sdk_common_1.TypeValidators.Boolean,
streamInitialReconnectDelay: js_sdk_common_1.TypeValidators.Number,
useLdd: js_sdk_common_1.TypeValidators.Boolean,
sendEvents: js_sdk_common_1.TypeValidators.Boolean,
allAttributesPrivate: js_sdk_common_1.TypeValidators.Boolean,
privateAttributes: js_sdk_common_1.TypeValidators.StringArray,
contextKeysCapacity: js_sdk_common_1.TypeValidators.Number,
contextKeysFlushInterval: js_sdk_common_1.TypeValidators.Number,
tlsParams: js_sdk_common_1.TypeValidators.Object,
diagnosticOptOut: js_sdk_common_1.TypeValidators.Boolean,
diagnosticRecordingInterval: js_sdk_common_1.TypeValidators.numberWithMin(60),
wrapperName: js_sdk_common_1.TypeValidators.String,
wrapperVersion: js_sdk_common_1.TypeValidators.String,
application: js_sdk_common_1.TypeValidators.Object,
payloadFilterKey: js_sdk_common_1.TypeValidators.stringMatchingRegex(/^[a-zA-Z0-9](\w|\.|-)*$/),
hooks: js_sdk_common_1.TypeValidators.createTypeArray('Hook[]', {}),
enableEventCompression: js_sdk_common_1.TypeValidators.Boolean,
};
/**
* @internal
*/
exports.defaultValues = {
baseUri: 'https://sdk.launchdarkly.com',
streamUri: 'https://stream.launchdarkly.com',
eventsUri: js_sdk_common_1.ServiceEndpoints.DEFAULT_EVENTS,
stream: true,
streamInitialReconnectDelay: 1,
sendEvents: true,
timeout: 5,
capacity: 10000,
flushInterval: 5,
pollInterval: 30,
offline: false,
useLdd: false,
allAttributesPrivate: false,
privateAttributes: [],
contextKeysCapacity: 1000,
contextKeysFlushInterval: 300,
diagnosticOptOut: false,
diagnosticRecordingInterval: 900,
featureStore: () => new InMemoryFeatureStore_1.default(),
enableEventCompression: false,
};
function validateTypesAndNames(options) {
const errors = [];
const validatedOptions = Object.assign({}, exports.defaultValues);
Object.keys(options).forEach((optionName) => {
var _a;
// We need to tell typescript it doesn't actually know what options are.
// If we don't then it complains we are doing crazy things with it.
const optionValue = options[optionName];
const validator = validations[optionName];
if (validator) {
if (!validator.is(optionValue)) {
if (validator.getType() === 'boolean') {
errors.push(js_sdk_common_1.OptionMessages.wrongOptionTypeBoolean(optionName, typeof optionValue));
validatedOptions[optionName] = !!optionValue;
}
else if (validator instanceof js_sdk_common_1.NumberWithMinimum &&
js_sdk_common_1.TypeValidators.Number.is(optionValue)) {
const { min } = validator;
errors.push(js_sdk_common_1.OptionMessages.optionBelowMinimum(optionName, optionValue, min));
validatedOptions[optionName] = min;
}
else {
errors.push(js_sdk_common_1.OptionMessages.wrongOptionType(optionName, validator.getType(), typeof optionValue));
validatedOptions[optionName] = exports.defaultValues[optionName];
}
}
else {
validatedOptions[optionName] = optionValue;
}
}
else {
(_a = options.logger) === null || _a === void 0 ? void 0 : _a.warn(js_sdk_common_1.OptionMessages.unknownOption(optionName));
}
});
return { errors, validatedOptions };
}
function validateEndpoints(options, validatedOptions) {
var _a, _b, _c;
const { baseUri, streamUri, eventsUri } = options;
const streamingEndpointSpecified = streamUri !== undefined && streamUri !== null;
const pollingEndpointSpecified = baseUri !== undefined && baseUri !== null;
const eventEndpointSpecified = eventsUri !== undefined && eventsUri !== null;
if (streamingEndpointSpecified === pollingEndpointSpecified &&
streamingEndpointSpecified === eventEndpointSpecified) {
// Either everything is default, or everything is set.
return;
}
if (!streamingEndpointSpecified && validatedOptions.stream) {
(_a = validatedOptions.logger) === null || _a === void 0 ? void 0 : _a.warn(js_sdk_common_1.OptionMessages.partialEndpoint('streamUri'));
}
if (!pollingEndpointSpecified) {
(_b = validatedOptions.logger) === null || _b === void 0 ? void 0 : _b.warn(js_sdk_common_1.OptionMessages.partialEndpoint('baseUri'));
}
if (!eventEndpointSpecified && validatedOptions.sendEvents) {
(_c = validatedOptions.logger) === null || _c === void 0 ? void 0 : _c.warn(js_sdk_common_1.OptionMessages.partialEndpoint('eventsUri'));
}
}
/**
* Configuration options for the LDClient.
*
* @internal
*/
class Configuration {
constructor(options = {}, internalOptions = {}) {
// The default will handle undefined, but not null.
// Because we can be called from JS we need to be extra defensive.
// eslint-disable-next-line no-param-reassign
options = options || {};
// If there isn't a valid logger from the platform, then logs would go nowhere.
this.logger = options.logger;
const { errors, validatedOptions } = validateTypesAndNames(options);
errors.forEach((error) => {
var _a;
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.warn(error);
});
validateEndpoints(options, validatedOptions);
this.serviceEndpoints = new js_sdk_common_1.ServiceEndpoints(validatedOptions.streamUri, validatedOptions.baseUri, validatedOptions.eventsUri, internalOptions.analyticsEventPath, internalOptions.diagnosticEventPath, internalOptions.includeAuthorizationHeader, validatedOptions.payloadFilterKey);
this.eventsCapacity = validatedOptions.capacity;
this.timeout = validatedOptions.timeout;
this.bigSegments = validatedOptions.bigSegments;
this.flushInterval = validatedOptions.flushInterval;
this.pollInterval = validatedOptions.pollInterval;
this.proxyOptions = validatedOptions.proxyOptions;
this.offline = validatedOptions.offline;
this.stream = validatedOptions.stream;
this.streamInitialReconnectDelay = validatedOptions.streamInitialReconnectDelay;
this.useLdd = validatedOptions.useLdd;
this.sendEvents = validatedOptions.sendEvents;
this.allAttributesPrivate = validatedOptions.allAttributesPrivate;
this.privateAttributes = validatedOptions.privateAttributes;
this.contextKeysCapacity = validatedOptions.contextKeysCapacity;
this.contextKeysFlushInterval = validatedOptions.contextKeysFlushInterval;
this.tlsParams = validatedOptions.tlsParams;
this.diagnosticOptOut = validatedOptions.diagnosticOptOut;
this.wrapperName = validatedOptions.wrapperName;
this.payloadFilterKey = validatedOptions.payloadFilterKey;
this.wrapperVersion = validatedOptions.wrapperVersion;
this.tags = new js_sdk_common_1.ApplicationTags(validatedOptions);
this.diagnosticRecordingInterval = validatedOptions.diagnosticRecordingInterval;
if (js_sdk_common_1.TypeValidators.Function.is(validatedOptions.updateProcessor)) {
// @ts-ignore
this.updateProcessorFactory = validatedOptions.updateProcessor;
}
else {
// The processor is already created, just have the method return it.
// @ts-ignore
this.updateProcessorFactory = () => validatedOptions.updateProcessor;
}
if (js_sdk_common_1.TypeValidators.Function.is(validatedOptions.featureStore)) {
// @ts-ignore
this.featureStoreFactory = validatedOptions.featureStore;
}
else {
// The store is already created, just have the method return it.
// @ts-ignore
this.featureStoreFactory = () => validatedOptions.featureStore;
}
this.hooks = validatedOptions.hooks;
this.enableEventCompression = validatedOptions.enableEventCompression;
}
}
exports.default = Configuration;
//# sourceMappingURL=Configuration.js.map