@launchdarkly/js-server-sdk-common
Version:
LaunchDarkly Server SDK for JavaScript - common code
127 lines • 5.34 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const serialization_1 = require("../store/serialization");
const VersionedDataKinds_1 = require("../store/VersionedDataKinds");
const FileLoader_1 = require("./FileLoader");
function makeFlagWithValue(key, value, version) {
return {
key,
on: true,
fallthrough: { variation: 0 },
variations: [value],
version,
};
}
class FileDataSource {
/**
* This is internal because we want instances to only be created with the
* factory.
* @internal
*/
constructor(options, filesystem, _featureStore, _initSuccessHandler = () => { }, _errorHandler) {
var _a;
this._featureStore = _featureStore;
this._initSuccessHandler = _initSuccessHandler;
this._errorHandler = _errorHandler;
this._allData = {};
this._fileLoader = new FileLoader_1.default(filesystem, options.paths, (_a = options.autoUpdate) !== null && _a !== void 0 ? _a : false, (results) => {
var _a, _b;
// Whenever changes are detected we re-process all of the data.
// The FileLoader will have handled debouncing for us.
try {
this._processFileData(results);
}
catch (err) {
// If this was during start, then the initCallback will be present.
(_a = this._errorHandler) === null || _a === void 0 ? void 0 : _a.call(this, err);
(_b = this._logger) === null || _b === void 0 ? void 0 : _b.error(`Error processing files: ${err}`);
}
});
this._logger = options.logger;
this._yamlParser = options.yamlParser;
}
start() {
// Use an immediately invoked function expression to allow handling of the
// async loading without making start async itself.
(async () => {
var _a;
try {
await this._fileLoader.loadAndWatch();
}
catch (err) {
// There was an issue loading/watching the files.
// Report back to the caller.
(_a = this._errorHandler) === null || _a === void 0 ? void 0 : _a.call(this, err);
}
})();
}
stop() {
this._fileLoader.close();
}
close() {
this.stop();
}
_addItem(kind, item) {
if (!this._allData[kind.namespace]) {
this._allData[kind.namespace] = {};
}
if (this._allData[kind.namespace][item.key]) {
throw new Error(`found duplicate key: "${item.key}"`);
}
else {
this._allData[kind.namespace][item.key] = item;
}
}
_processFileData(fileData) {
// Clear any existing data before re-populating it.
const oldData = this._allData;
this._allData = {};
// We let the parsers throw, and the caller can handle the rejection.
fileData.forEach((fd) => {
let parsed;
if (fd.path.endsWith('.yml') || fd.path.endsWith('.yaml')) {
if (this._yamlParser) {
parsed = this._yamlParser(fd.data);
}
else {
throw new Error(`Attempted to parse yaml file (${fd.path}) without parser.`);
}
}
else {
parsed = JSON.parse(fd.data);
}
this._processParsedData(parsed, oldData);
});
this._featureStore.init(this._allData, () => {
// Call the init callback if present.
// Then clear the callback so we cannot call it again.
this._initSuccessHandler();
this._initSuccessHandler = () => { };
});
}
_processParsedData(parsed, oldData) {
Object.keys(parsed.flags || {}).forEach((key) => {
(0, serialization_1.processFlag)(parsed.flags[key]);
this._addItem(VersionedDataKinds_1.default.Features, parsed.flags[key]);
});
Object.keys(parsed.flagValues || {}).forEach((key) => {
var _a, _b;
const previousInstance = (_a = oldData[VersionedDataKinds_1.default.Features.namespace]) === null || _a === void 0 ? void 0 : _a[key];
let { version } = previousInstance !== null && previousInstance !== void 0 ? previousInstance : { version: 1 };
// If the data is different, then we want to increment the version.
if (previousInstance &&
JSON.stringify(parsed.flagValues[key]) !== JSON.stringify((_b = previousInstance === null || previousInstance === void 0 ? void 0 : previousInstance.variations) === null || _b === void 0 ? void 0 : _b[0])) {
version += 1;
}
const flag = makeFlagWithValue(key, parsed.flagValues[key], version);
(0, serialization_1.processFlag)(flag);
this._addItem(VersionedDataKinds_1.default.Features, flag);
});
Object.keys(parsed.segments || {}).forEach((key) => {
(0, serialization_1.processSegment)(parsed.segments[key]);
this._addItem(VersionedDataKinds_1.default.Segments, parsed.segments[key]);
});
}
}
exports.default = FileDataSource;
//# sourceMappingURL=FileDataSource.js.map