UNPKG

@launchdarkly/js-server-sdk-common

Version:
278 lines 14.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.defaultValues = exports.DEFAULT_POLL_INTERVAL = void 0; const js_sdk_common_1 = require("@launchdarkly/js-sdk-common"); const LDDataSystemOptions_1 = require("../api/options/LDDataSystemOptions"); 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, dataSystem: js_sdk_common_1.TypeValidators.Object, 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, dataSourceOptionsType: js_sdk_common_1.TypeValidators.String, }; exports.DEFAULT_POLL_INTERVAL = 30; const DEFAULT_STREAM_RECONNECT_DELAY = 1; const defaultStandardDataSourceOptions = { dataSourceOptionsType: 'standard', streamInitialReconnectDelay: DEFAULT_STREAM_RECONNECT_DELAY, pollInterval: exports.DEFAULT_POLL_INTERVAL, }; const defaultStreamingDataSourceOptions = { dataSourceOptionsType: 'streamingOnly', streamInitialReconnectDelay: DEFAULT_STREAM_RECONNECT_DELAY, }; const defaultPollingDataSourceOptions = { dataSourceOptionsType: 'pollingOnly', pollInterval: exports.DEFAULT_POLL_INTERVAL, }; const defaultDataSystemOptions = { dataSource: defaultStandardDataSourceOptions, }; /** * @internal */ exports.defaultValues = { baseUri: 'https://sdk.launchdarkly.com', streamUri: 'https://stream.launchdarkly.com', eventsUri: js_sdk_common_1.ServiceEndpoints.DEFAULT_EVENTS, stream: true, streamInitialReconnectDelay: DEFAULT_STREAM_RECONNECT_DELAY, sendEvents: true, timeout: 5, capacity: 10000, flushInterval: 5, pollInterval: exports.DEFAULT_POLL_INTERVAL, offline: false, useLdd: false, allAttributesPrivate: false, privateAttributes: [], contextKeysCapacity: 1000, contextKeysFlushInterval: 300, diagnosticOptOut: false, diagnosticRecordingInterval: 900, featureStore: () => new InMemoryFeatureStore_1.default(), enableEventCompression: false, dataSystem: defaultDataSystemOptions, }; function validateTypesAndNames(options, defaults) { const errors = []; const validatedOptions = Object.assign({}, defaults); 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')); } } function validateDataSystemOptions(options) { const allErrors = []; const validatedOptions = Object.assign({}, options); if (options.persistentStore && !js_sdk_common_1.TypeValidators.ObjectOrFactory.is(options.persistentStore)) { validatedOptions.persistentStore = undefined; // default is to not use this allErrors.push(js_sdk_common_1.OptionMessages.wrongOptionType('persistentStore', 'LDFeatureStore', typeof options.persistentStore)); } if (options.dataSource) { let errors; let validatedDataSourceOptions; if ((0, LDDataSystemOptions_1.isStandardOptions)(options.dataSource)) { ({ errors, validatedOptions: validatedDataSourceOptions } = validateTypesAndNames(options.dataSource, defaultStandardDataSourceOptions)); } else if ((0, LDDataSystemOptions_1.isStreamingOnlyOptions)(options.dataSource)) { ({ errors, validatedOptions: validatedDataSourceOptions } = validateTypesAndNames(options.dataSource, defaultStreamingDataSourceOptions)); } else if ((0, LDDataSystemOptions_1.isPollingOnlyOptions)(options.dataSource)) { ({ errors, validatedOptions: validatedDataSourceOptions } = validateTypesAndNames(options.dataSource, defaultPollingDataSourceOptions)); } else { // provided datasource options don't fit any expected form, drop them and use defaults validatedDataSourceOptions = defaultStandardDataSourceOptions; errors = [ js_sdk_common_1.OptionMessages.wrongOptionType('dataSource', 'DataSourceOptions', typeof options.dataSource), ]; } validatedOptions.dataSource = validatedDataSourceOptions; allErrors.push(...errors); } else { // use default datasource options if no datasource was specified validatedOptions.dataSource = defaultStandardDataSourceOptions; } return { errors: allErrors, validatedOptions }; } /** * Configuration options for the LDClient. * * @internal */ class Configuration { constructor(options = {}, internalOptions = {}) { var _a; // 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: topLevelResult } = validateTypesAndNames(options, exports.defaultValues); const validatedOptions = topLevelResult; errors.forEach((error) => { var _a; (_a = this.logger) === null || _a === void 0 ? void 0 : _a.warn(error); }); validateEndpoints(options, validatedOptions); if (options.dataSystem) { // validate the data system options, this will also apply reasonable defaults const { errors: dsErrors, validatedOptions: dsResult } = validateDataSystemOptions(options.dataSystem); const validatedDSOptions = dsResult; this.dataSystem = { dataSource: validatedDSOptions.dataSource, useLdd: validatedDSOptions.useLdd, // @ts-ignore featureStoreFactory: (clientContext) => { if (validatedDSOptions.persistentStore === undefined) { // the persistent store provided was either undefined or invalid, default to memory store return new InMemoryFeatureStore_1.default(); } if (js_sdk_common_1.TypeValidators.Function.is(validatedDSOptions.persistentStore)) { return validatedDSOptions.persistentStore(clientContext); } return validatedDSOptions.persistentStore; }, }; dsErrors.forEach((error) => { var _a; (_a = this.logger) === null || _a === void 0 ? void 0 : _a.warn(error); }); } 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; this.getImplementationHooks = (_a = internalOptions.getImplementationHooks) !== null && _a !== void 0 ? _a : (() => []); this.applicationInfo = validatedOptions.application; } } exports.default = Configuration; //# sourceMappingURL=Configuration.js.map