@launchdarkly/js-sdk-common
Advanced tools
Comparing version 2.1.0 to 2.1.1
@@ -5,2 +5,10 @@ # Changelog | ||
## [2.1.1](https://github.com/launchdarkly/js-core/compare/js-sdk-common-v2.1.0...js-sdk-common-v2.1.1) (2024-01-16) | ||
### Bug Fixes | ||
* remove type modifiers on imports for better TS compatibility ([#346](https://github.com/launchdarkly/js-core/issues/346)) ([3506349](https://github.com/launchdarkly/js-core/commit/3506349512f2288ba9bc2b2bd79d6ed38fd3684c)) | ||
* Treat 413 HTTP status as recoverable for events. ([#348](https://github.com/launchdarkly/js-core/issues/348)) ([4a6d4c3](https://github.com/launchdarkly/js-core/commit/4a6d4c3cae25e4993a798d0fd315b51ef607d727)) | ||
## [2.1.0](https://github.com/launchdarkly/js-core/compare/js-sdk-common-v2.0.0...js-sdk-common-v2.1.0) (2023-11-14) | ||
@@ -7,0 +15,0 @@ |
@@ -0,1 +1,2 @@ | ||
import type { HttpErrorResponse } from './Requests'; | ||
export type EventName = 'delete' | 'patch' | 'ping' | 'put'; | ||
@@ -11,3 +12,3 @@ export type EventListener = (event?: { | ||
onclose: (() => void) | undefined; | ||
onerror: (() => void) | undefined; | ||
onerror: ((err?: HttpErrorResponse) => void) | undefined; | ||
onopen: (() => void) | undefined; | ||
@@ -21,6 +22,3 @@ onretrying: ((e: { | ||
export interface EventSourceInitDict { | ||
errorFilter: (err: { | ||
status: number; | ||
message: string; | ||
}) => boolean; | ||
errorFilter: (err: HttpErrorResponse) => boolean; | ||
headers: { | ||
@@ -27,0 +25,0 @@ [key: string]: string | string[]; |
@@ -8,2 +8,3 @@ export * from './Encoding'; | ||
export * from './EventSource'; | ||
export * from './Storage'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -24,2 +24,3 @@ "use strict"; | ||
__exportStar(require("./EventSource"), exports); | ||
__exportStar(require("./Storage"), exports); | ||
//# sourceMappingURL=index.js.map |
@@ -6,2 +6,3 @@ import { Crypto } from './Crypto'; | ||
import { Requests } from './Requests'; | ||
import { Storage } from './Storage'; | ||
export interface Platform { | ||
@@ -30,3 +31,8 @@ /** | ||
requests: Requests; | ||
/** | ||
* The interface for session specific storage object. If the platform does not | ||
* support local storage access, this may be undefined. | ||
*/ | ||
storage?: Storage; | ||
} | ||
//# sourceMappingURL=Platform.d.ts.map |
@@ -1,2 +0,2 @@ | ||
import { EventSource, EventSourceInitDict } from './EventSource'; | ||
import type { EventSource, EventSourceInitDict } from './EventSource'; | ||
/** | ||
@@ -75,2 +75,6 @@ * Interface for headers that are part of a fetch response. | ||
} | ||
export interface HttpErrorResponse { | ||
message: string; | ||
status?: number; | ||
} | ||
//# sourceMappingURL=Requests.d.ts.map |
@@ -18,3 +18,17 @@ export declare class LDFileDataSourceError extends Error { | ||
} | ||
/** | ||
* Check if the HTTP error is recoverable. This will return false if a request | ||
* made with any payload could not recover. If the reason for the failure | ||
* is payload specific, for instance a payload that is too large, then | ||
* it could recover with a different payload. | ||
*/ | ||
export declare function isHttpRecoverable(status: number): boolean; | ||
/** | ||
* Returns true if the status could recover for a different payload. | ||
* | ||
* When used with event processing this indicates that we should discard | ||
* the payload, but that a subsequent payload may succeed. Therefore we should | ||
* not stop event processing. | ||
*/ | ||
export declare function isHttpLocallyRecoverable(status: number): boolean; | ||
//# sourceMappingURL=errors.d.ts.map |
@@ -6,3 +6,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isHttpRecoverable = exports.LDClientError = exports.LDUnexpectedResponseError = exports.LDStreamingError = exports.LDPollingError = exports.LDFileDataSourceError = void 0; | ||
exports.isHttpLocallyRecoverable = exports.isHttpRecoverable = exports.LDClientError = exports.LDUnexpectedResponseError = exports.LDStreamingError = exports.LDPollingError = exports.LDFileDataSourceError = void 0; | ||
class LDFileDataSourceError extends Error { | ||
@@ -45,2 +45,8 @@ constructor(message) { | ||
exports.LDClientError = LDClientError; | ||
/** | ||
* Check if the HTTP error is recoverable. This will return false if a request | ||
* made with any payload could not recover. If the reason for the failure | ||
* is payload specific, for instance a payload that is too large, then | ||
* it could recover with a different payload. | ||
*/ | ||
function isHttpRecoverable(status) { | ||
@@ -53,2 +59,16 @@ if (status >= 400 && status < 500) { | ||
exports.isHttpRecoverable = isHttpRecoverable; | ||
/** | ||
* Returns true if the status could recover for a different payload. | ||
* | ||
* When used with event processing this indicates that we should discard | ||
* the payload, but that a subsequent payload may succeed. Therefore we should | ||
* not stop event processing. | ||
*/ | ||
function isHttpLocallyRecoverable(status) { | ||
if (status === 413) { | ||
return true; | ||
} | ||
return isHttpRecoverable(status); | ||
} | ||
exports.isHttpLocallyRecoverable = isHttpLocallyRecoverable; | ||
//# sourceMappingURL=errors.js.map |
@@ -71,3 +71,5 @@ "use strict"; | ||
if (this.shutdown) { | ||
throw new LDInvalidSDKKeyError_1.default('Events cannot be posted because SDK key is invalid'); | ||
throw new LDInvalidSDKKeyError_1.default('Events cannot be posted because a permanent error has been encountered. ' + | ||
'This is most likely an invalid SDK key. The specific error information ' + | ||
'is logged independently.'); | ||
} | ||
@@ -74,0 +76,0 @@ const eventsToFlush = this.queue; |
@@ -42,3 +42,12 @@ "use strict"; | ||
if (!(0, errors_1.isHttpRecoverable)(status)) { | ||
tryRes.status = subsystem_1.LDDeliveryStatus.FailedAndMustShutDown; | ||
// If the HTTP request isn't recoverable. Meaning if we made the same request it | ||
// would not recover, then we check if a different request could recover. | ||
// If a different request could not recover, then we shutdown. If a different request could | ||
// recover, then we just don't retry this specific request. | ||
if (!(0, errors_1.isHttpLocallyRecoverable)(status)) { | ||
tryRes.status = subsystem_1.LDDeliveryStatus.FailedAndMustShutDown; | ||
} | ||
else { | ||
tryRes.status = subsystem_1.LDDeliveryStatus.Failed; | ||
} | ||
tryRes.error = error; | ||
@@ -45,0 +54,0 @@ return tryRes; |
import StreamingProcessor from './StreamingProcessor'; | ||
import { type StreamingErrorHandler } from './types'; | ||
export { StreamingProcessor, type StreamingErrorHandler }; | ||
import type { StreamingErrorHandler } from './types'; | ||
export { StreamingProcessor }; | ||
export type { StreamingErrorHandler }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -20,2 +20,12 @@ import { EventName, ProcessStreamResponse } from '../../api'; | ||
private logConnectionResult; | ||
/** | ||
* This is a wrapper around the passed errorHandler which adds additional | ||
* diagnostics and logging logic. | ||
* | ||
* @param err The error to be logged and handled. | ||
* @return boolean whether to retry the connection. | ||
* | ||
* @private | ||
*/ | ||
private retryAndHandleError; | ||
start(): void; | ||
@@ -22,0 +32,0 @@ stop(): void; |
@@ -5,4 +5,2 @@ "use strict"; | ||
const utils_1 = require("../../utils"); | ||
const STREAM_READ_TIMEOUT_MS = 5 * 60 * 1000; | ||
const RETRY_RESET_INTERVAL_MS = 60 * 1000; | ||
const reportJsonError = (type, data, logger, errorHandler) => { | ||
@@ -36,24 +34,33 @@ logger === null || logger === void 0 ? void 0 : logger.error(`Stream received invalid data in "${type}" message`); | ||
} | ||
/** | ||
* This is a wrapper around the passed errorHandler which adds additional | ||
* diagnostics and logging logic. | ||
* | ||
* @param err The error to be logged and handled. | ||
* @return boolean whether to retry the connection. | ||
* | ||
* @private | ||
*/ | ||
retryAndHandleError(err) { | ||
var _a, _b, _c; | ||
if (!(0, utils_1.shouldRetry)(err)) { | ||
this.logConnectionResult(false); | ||
(_a = this.errorHandler) === null || _a === void 0 ? void 0 : _a.call(this, new errors_1.LDStreamingError(err.message, err.status)); | ||
(_b = this.logger) === null || _b === void 0 ? void 0 : _b.error((0, utils_1.httpErrorMessage)(err, 'streaming request')); | ||
return false; | ||
} | ||
(_c = this.logger) === null || _c === void 0 ? void 0 : _c.warn((0, utils_1.httpErrorMessage)(err, 'streaming request', 'will retry')); | ||
this.logConnectionResult(false); | ||
this.logConnectionStarted(); | ||
return true; | ||
} | ||
start() { | ||
this.logConnectionStarted(); | ||
const errorFilter = (err) => { | ||
var _a, _b, _c; | ||
if (err.status && !(0, errors_1.isHttpRecoverable)(err.status)) { | ||
this.logConnectionResult(false); | ||
(_a = this.errorHandler) === null || _a === void 0 ? void 0 : _a.call(this, new errors_1.LDStreamingError(err.message, err.status)); | ||
(_b = this.logger) === null || _b === void 0 ? void 0 : _b.error((0, utils_1.httpErrorMessage)(err, 'streaming request')); | ||
return false; | ||
} | ||
(_c = this.logger) === null || _c === void 0 ? void 0 : _c.warn((0, utils_1.httpErrorMessage)(err, 'streaming request', 'will retry')); | ||
this.logConnectionResult(false); | ||
this.logConnectionStarted(); | ||
return true; | ||
}; | ||
// TLS is handled by the platform implementation. | ||
const eventSource = this.requests.createEventSource(this.streamUri, { | ||
headers: this.headers, | ||
errorFilter, | ||
errorFilter: (error) => this.retryAndHandleError(error), | ||
initialRetryDelayMillis: 1000 * this.streamInitialReconnectDelay, | ||
readTimeoutMillis: STREAM_READ_TIMEOUT_MS, | ||
retryResetIntervalMillis: RETRY_RESET_INTERVAL_MS, | ||
readTimeoutMillis: 5 * 60 * 1000, | ||
retryResetIntervalMillis: 60 * 1000, | ||
}); | ||
@@ -60,0 +67,0 @@ this.eventSource = eventSource; |
@@ -1,2 +0,2 @@ | ||
export default function clone(obj: any): any; | ||
export default function clone<T>(obj: any): T; | ||
//# sourceMappingURL=clone.d.ts.map |
@@ -1,2 +0,2 @@ | ||
import { Info } from '../api'; | ||
import { Encoding, HttpErrorResponse, Info } from '../api'; | ||
import { ApplicationTags } from '../options'; | ||
@@ -10,6 +10,14 @@ export type LDHeaders = { | ||
export declare function defaultHeaders(sdkKey: string, info: Info, tags?: ApplicationTags, includeAuthorizationHeader?: boolean): LDHeaders; | ||
export declare function httpErrorMessage(err: { | ||
status: number; | ||
message: string; | ||
}, context: string, retryMessage?: string): string; | ||
export declare function httpErrorMessage(err: HttpErrorResponse, context: string, retryMessage?: string): string; | ||
export declare function shouldRetry({ status }: HttpErrorResponse): boolean; | ||
/** | ||
* In react-native use base64-js to polyfill btoa. This is safe | ||
* because the react-native repo uses it too. Set the global.btoa to the encode | ||
* function of base64-js. | ||
* https://github.com/beatgammit/base64-js | ||
* https://github.com/axios/axios/issues/2235#issuecomment-512204616 | ||
* | ||
* Ripped from https://thewoods.blog/base64url/ | ||
*/ | ||
export declare const base64UrlEncode: (s: string, encoding: Encoding) => string; | ||
//# sourceMappingURL=http.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.httpErrorMessage = exports.defaultHeaders = void 0; | ||
exports.base64UrlEncode = exports.shouldRetry = exports.httpErrorMessage = exports.defaultHeaders = void 0; | ||
const errors_1 = require("../errors"); | ||
function defaultHeaders(sdkKey, info, tags, includeAuthorizationHeader = true) { | ||
@@ -37,2 +38,17 @@ const { userAgentBase, version, wrapperName, wrapperVersion } = info.sdkData(); | ||
exports.httpErrorMessage = httpErrorMessage; | ||
function shouldRetry({ status }) { | ||
return status ? (0, errors_1.isHttpRecoverable)(status) : true; | ||
} | ||
exports.shouldRetry = shouldRetry; | ||
/** | ||
* In react-native use base64-js to polyfill btoa. This is safe | ||
* because the react-native repo uses it too. Set the global.btoa to the encode | ||
* function of base64-js. | ||
* https://github.com/beatgammit/base64-js | ||
* https://github.com/axios/axios/issues/2235#issuecomment-512204616 | ||
* | ||
* Ripped from https://thewoods.blog/base64url/ | ||
*/ | ||
const base64UrlEncode = (s, encoding) => encoding.btoa(s).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); | ||
exports.base64UrlEncode = base64UrlEncode; | ||
//# sourceMappingURL=http.js.map |
import clone from './clone'; | ||
import { secondsToMillis } from './date'; | ||
import { defaultHeaders, httpErrorMessage, LDHeaders } from './http'; | ||
import fastDeepEqual from './fast-deep-equal'; | ||
import { base64UrlEncode, defaultHeaders, httpErrorMessage, LDHeaders, shouldRetry } from './http'; | ||
import noop from './noop'; | ||
import sleep from './sleep'; | ||
import { VoidFunction } from './VoidFunction'; | ||
export { clone, defaultHeaders, httpErrorMessage, noop, LDHeaders, secondsToMillis, sleep, VoidFunction, }; | ||
export { base64UrlEncode, clone, defaultHeaders, fastDeepEqual, httpErrorMessage, noop, LDHeaders, shouldRetry, secondsToMillis, sleep, VoidFunction, }; | ||
//# sourceMappingURL=index.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.sleep = exports.secondsToMillis = exports.noop = exports.httpErrorMessage = exports.defaultHeaders = exports.clone = void 0; | ||
exports.sleep = exports.secondsToMillis = exports.shouldRetry = exports.noop = exports.httpErrorMessage = exports.fastDeepEqual = exports.defaultHeaders = exports.clone = exports.base64UrlEncode = void 0; | ||
const clone_1 = require("./clone"); | ||
@@ -8,5 +8,9 @@ exports.clone = clone_1.default; | ||
Object.defineProperty(exports, "secondsToMillis", { enumerable: true, get: function () { return date_1.secondsToMillis; } }); | ||
const fast_deep_equal_1 = require("./fast-deep-equal"); | ||
exports.fastDeepEqual = fast_deep_equal_1.default; | ||
const http_1 = require("./http"); | ||
Object.defineProperty(exports, "base64UrlEncode", { enumerable: true, get: function () { return http_1.base64UrlEncode; } }); | ||
Object.defineProperty(exports, "defaultHeaders", { enumerable: true, get: function () { return http_1.defaultHeaders; } }); | ||
Object.defineProperty(exports, "httpErrorMessage", { enumerable: true, get: function () { return http_1.httpErrorMessage; } }); | ||
Object.defineProperty(exports, "shouldRetry", { enumerable: true, get: function () { return http_1.shouldRetry; } }); | ||
const noop_1 = require("./noop"); | ||
@@ -13,0 +17,0 @@ exports.noop = noop_1.default; |
{ | ||
"name": "@launchdarkly/js-sdk-common", | ||
"version": "2.1.0", | ||
"version": "2.1.1", | ||
"type": "commonjs", | ||
@@ -5,0 +5,0 @@ "main": "./dist/index.js", |
@@ -15,2 +15,6 @@ # LaunchDarkly SDK JavaScript Common Code | ||
## Verifying SDK build provenance with the SLSA framework | ||
LaunchDarkly uses the [SLSA framework](https://slsa.dev/spec/v1.0/about) (Supply-chain Levels for Software Artifacts) to help developers make their supply chain more secure by ensuring the authenticity and build integrity of our published SDK packages. To learn more, see the [provenance guide](PROVENANCE.md). | ||
## About LaunchDarkly | ||
@@ -17,0 +21,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
290247
344
4314
37
3