UNPKG

@launchdarkly/js-server-sdk-common

Version:
123 lines 7.04 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const js_sdk_common_1 = require("@launchdarkly/js-sdk-common"); const serialization_1 = require("../store/serialization"); /** * @internal */ class OneShotInitializerFDv2 { constructor(_requestor, _logger) { this._requestor = _requestor; this._logger = _logger; this._stopped = false; } start(dataCallback, statusCallback) { var _a; statusCallback(js_sdk_common_1.subsystem.DataSourceState.Initializing); (_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug('Performing initialization request to LaunchDarkly for feature flag data.'); this._requestor.requestAllData((err, body, headers, fallbackToFDv1) => { var _a, _b, _c; if (this._stopped) { return; } // Helper used to emit the FDv1 fallback signal once any accompanying payload has been // applied. Callers should `return` immediately after invoking it. const emitFallback = () => { var _a; const status = err === null || err === void 0 ? void 0 : err.status; const message = err ? (0, js_sdk_common_1.httpErrorMessage)(err, 'initializer', 'falling back to FDv1') : `Response header indicates to fallback to FDv1`; (_a = this._logger) === null || _a === void 0 ? void 0 : _a.warn(message); statusCallback(js_sdk_common_1.subsystem.DataSourceState.Closed, new js_sdk_common_1.LDFlagDeliveryFallbackError(js_sdk_common_1.DataSourceErrorKind.ErrorResponse, message, status)); }; if (err) { // An error response can still carry the fallback directive. Emit the directive in // that case so the CompositeDataSource can hand off to the FDv1 synchronizer. if (fallbackToFDv1) { emitFallback(); return; } const { status } = err; const message = (0, js_sdk_common_1.httpErrorMessage)(err, 'initializer', 'initializer does not retry'); (_a = this._logger) === null || _a === void 0 ? void 0 : _a.error(message); statusCallback(js_sdk_common_1.subsystem.DataSourceState.Closed, new js_sdk_common_1.LDPollingError(js_sdk_common_1.DataSourceErrorKind.ErrorResponse, message, status)); return; } if (!body) { if (fallbackToFDv1) { emitFallback(); return; } statusCallback(js_sdk_common_1.subsystem.DataSourceState.Closed, new js_sdk_common_1.LDPollingError(js_sdk_common_1.DataSourceErrorKind.InvalidData, 'One shot initializer response missing body.')); return; } const initMetadata = js_sdk_common_1.internal.initMetadataFromHeaders(headers); try { const parsed = JSON.parse(body); const payloadProcessor = new js_sdk_common_1.internal.PayloadProcessor({ flag: (flag) => { (0, serialization_1.processFlag)(flag); return flag; }, segment: (segment) => { (0, serialization_1.processSegment)(segment); return segment; }, }, (errorKind, message) => { // If a per-event error fires while the fallback directive is in flight, route it // through the LDFlagDeliveryFallbackError path so CompositeDataSource still // engages FDv1. Otherwise the directive would be lost: the composite's status // handler would treat the LDPollingError as an ordinary failure and fall through // to the next FDv2 source. if (fallbackToFDv1) { emitFallback(); return; } statusCallback(js_sdk_common_1.subsystem.DataSourceState.Interrupted, new js_sdk_common_1.LDPollingError(errorKind, message)); }, this._logger); statusCallback(js_sdk_common_1.subsystem.DataSourceState.Valid); // When the fallback directive rides along on a 200 response with a valid payload, // the directive must be applied atomically with the data callback. CompositeData- // Source disables its callback handler as soon as basis-during-init arrives, so a // separate status callback emitted afterwards would be silently dropped. Instead, // attach a fallbackToFDv1 marker to the data object: CompositeDataSource will swap // its synchronizer list to FDv1 before resolving the switchToSync transition. payloadProcessor.addPayloadListener((payload) => { var _a; const data = { initMetadata, payload, }; if (fallbackToFDv1) { data.fallbackToFDv1 = true; (_a = this._logger) === null || _a === void 0 ? void 0 : _a.warn(`Response header indicates to fallback to FDv1`); } dataCallback(payload.type === 'full', data); }); payloadProcessor.processEvents(parsed.events); // The fallback directive (if any) was already attached to the data callback above, // so CompositeDataSource has already taken over the transition. Just close out. statusCallback(js_sdk_common_1.subsystem.DataSourceState.Closed); } catch (parseError) { // We could not parse this JSON. Report the problem. (_b = this._logger) === null || _b === void 0 ? void 0 : _b.error('Response contained invalid data'); (_c = this._logger) === null || _c === void 0 ? void 0 : _c.debug(`${parseError} - Body follows: ${body}`); if (fallbackToFDv1) { // Even when the accompanying body could not be parsed, the directive must still // be honored so we don't get stuck retrying FDv2 indefinitely. No payload was // applied here so we can use the status callback path safely. emitFallback(); return; } statusCallback(js_sdk_common_1.subsystem.DataSourceState.Closed, new js_sdk_common_1.LDPollingError(js_sdk_common_1.DataSourceErrorKind.InvalidData, 'Malformed data in polling response')); } }); } stop() { this._stopped = true; } } exports.default = OneShotInitializerFDv2; //# sourceMappingURL=OneShotInitializerFDv2.js.map