@cyberalien/redundancy
Advanced tools
Comparing version 1.0.0 to 1.1.0
/** | ||
* Callback for "timeout" configuration property. | ||
* "timeout" is used for timeout when all resources have been queried and loop must start again | ||
* | ||
* Function should return number in milliseconds, 0 to abort | ||
* Returns number of milliseconds to wait before failing query, while there are pending resources. | ||
*/ | ||
export interface TimeoutCallback { | ||
(retries: number, // Number of retries so far | ||
nextIndex: number, // Resource index for next query | ||
startTime: number): number; | ||
(startTime: number): number; | ||
} | ||
/** | ||
* Callback for "rotate" configuration property. | ||
* "rotate" is used for timeout when switching to next resource within same loop. | ||
* | ||
* Function should return number in milliseconds, 0 to abort | ||
* Returns number of milliseconds to wait before trying next resource. | ||
*/ | ||
export interface RotationTimeoutCallback { | ||
(queriesSent: number, // Number of queries sent so far, starts with 0 for first callback | ||
retry: number, // Retry counter, starts with 1 for first callback | ||
nextIndex: number, // Resource index for next query | ||
(queriesSent: number, // Number of queries sent, starts with 1 for timeout after first resource | ||
startTime: number): number; | ||
} | ||
/** | ||
* Callback for "limit" configuration property. | ||
* | ||
* Function should return number (at least "retries" + 1), 0 to abort (different from default value 0 that means no limit) | ||
* Resource to rotate (usually hostname or partial URL) | ||
*/ | ||
export interface LimitCallback { | ||
(retry: number, // Retry counter, starts with 1 for first callback | ||
startTime: number): number; | ||
} | ||
export declare type RedundancyResource = unknown; | ||
/** | ||
@@ -37,3 +24,3 @@ * Configuration object | ||
export interface RedundancyConfig { | ||
resources: Array<any>; | ||
resources: RedundancyResource[]; | ||
index: number; | ||
@@ -43,3 +30,3 @@ timeout: number | TimeoutCallback; | ||
random: boolean; | ||
limit: number | LimitCallback; | ||
dataAfterTimeout: boolean; | ||
} | ||
@@ -50,2 +37,1 @@ /** | ||
export declare const defaultConfig: RedundancyConfig; | ||
//# sourceMappingURL=config.d.ts.map |
"use strict"; | ||
// Allow <any> type because resource can be anything | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.defaultConfig = void 0; | ||
/** | ||
@@ -14,4 +13,3 @@ * Default RedundancyConfig for API calls | ||
random: false, | ||
limit: 2, | ||
dataAfterTimeout: false, | ||
}; | ||
//# sourceMappingURL=config.js.map |
@@ -1,67 +0,58 @@ | ||
import { RedundancyConfig } from './config'; | ||
import { Redundancy } from './redundancy'; | ||
import type { RedundancyConfig, RedundancyResource } from './config'; | ||
/** | ||
* Execution status | ||
*/ | ||
declare type ExecStatus = 'pending' | 'completed' | 'aborted'; | ||
declare type QueryItemStatus = 'pending' | 'completed' | 'aborted' | 'failed'; | ||
/** | ||
* Status for query | ||
* Custom payload | ||
*/ | ||
export interface QueryStatus { | ||
done: (data: unknown) => void; | ||
abort: () => void; | ||
subscribe: (callback: OptionalDoneCallback, overwrite?: boolean) => void; | ||
payload: unknown; | ||
startTime: number; | ||
loop: number; | ||
attempt: number; | ||
startIndex: number; | ||
index: number; | ||
maxIndex: number; | ||
status: ExecStatus; | ||
} | ||
declare type QueryPayload = unknown; | ||
/** | ||
* Callback to track status | ||
* Callback | ||
* | ||
* If error is present, something went wrong and data is undefined. If error is undefined, data is set. | ||
*/ | ||
export declare type GetQueryStatus = () => QueryStatus; | ||
export declare type QueryDoneCallback = (data?: unknown, error?: unknown) => void; | ||
/** | ||
* Callback for "done" pending item. | ||
* Callback for "abort" pending item. | ||
*/ | ||
export interface QueryDoneCallback { | ||
(data?: unknown): void; | ||
} | ||
export declare type QueryAbortCallback = () => void; | ||
/** | ||
* Callback for "abort" pending item. | ||
* Callback to call to update last successful resource index. Used by Resundancy class to automatically update config. | ||
*/ | ||
export interface QueryAbortCallback { | ||
(): void; | ||
} | ||
export declare type QueryUpdateIndexCallback = (index: number) => void; | ||
/** | ||
* Function to send to item to send query | ||
* Status for query | ||
*/ | ||
export interface QueryCallback { | ||
(resource: unknown, payload: unknown, status: PendingItem): void; | ||
export interface QueryStatus { | ||
readonly abort: () => void; | ||
readonly subscribe: (callback?: QueryDoneCallback, overwrite?: boolean) => void; | ||
readonly payload: QueryPayload; | ||
status: QueryItemStatus; | ||
startTime: number; | ||
queriesSent: number; | ||
queriesPending: number; | ||
} | ||
/** | ||
* Function to send to item on completion | ||
* Callback to track status | ||
*/ | ||
export interface DoneCallback { | ||
(data: unknown, payload: unknown, getStatus: GetQueryStatus): void; | ||
} | ||
export declare type OptionalDoneCallback = DoneCallback | null; | ||
export declare type GetQueryStatus = () => QueryStatus; | ||
/** | ||
* Item in pending items list | ||
*/ | ||
export interface PendingItem { | ||
readonly getStatus: GetQueryStatus; | ||
status: ExecStatus; | ||
readonly attempt: number; | ||
export interface PendingQueryItem { | ||
readonly getQueryStatus: GetQueryStatus; | ||
status: QueryItemStatus; | ||
readonly resource: RedundancyResource; | ||
readonly done: QueryDoneCallback; | ||
abort: QueryAbortCallback | null; | ||
abort?: QueryAbortCallback; | ||
} | ||
/** | ||
* Function to send to item to send query | ||
*/ | ||
export declare type QueryModuleCallback = (resource: RedundancyResource, payload: QueryPayload, queryItem: PendingQueryItem) => void; | ||
/** | ||
* Send query | ||
*/ | ||
export declare function sendQuery(parent: Redundancy | null, config: RedundancyConfig, payload: unknown, queryCallback: QueryCallback, doneCallback?: OptionalDoneCallback): GetQueryStatus; | ||
export declare function sendQuery(config: RedundancyConfig, payload: unknown, query: QueryModuleCallback, done?: QueryDoneCallback, success?: QueryUpdateIndexCallback): GetQueryStatus; | ||
export {}; | ||
//# sourceMappingURL=query.d.ts.map |
406
lib/query.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.sendQuery = void 0; | ||
/** | ||
* Send query | ||
*/ | ||
function sendQuery(parent, config, payload, queryCallback, doneCallback = null) { | ||
// Optional callbacks to call when query is complete | ||
let doneCallbacks = []; | ||
if (typeof doneCallback === 'function') { | ||
doneCallbacks.push(doneCallback); | ||
function sendQuery(config, payload, query, done, success) { | ||
// Get number of resources | ||
const resourcesCount = config.resources.length; | ||
// Save start index | ||
const startIndex = config.random | ||
? Math.floor(Math.random() * resourcesCount) | ||
: config.index; | ||
// Get resources | ||
let resources; | ||
if (config.random) { | ||
// Randomise array | ||
let list = config.resources.slice(0); | ||
resources = []; | ||
while (list.length > 1) { | ||
const nextIndex = Math.floor(Math.random() * list.length); | ||
resources.push(list[nextIndex]); | ||
list = list.slice(0, nextIndex).concat(list.slice(nextIndex + 1)); | ||
} | ||
resources = resources.concat(list); | ||
} | ||
// Start time | ||
else { | ||
// Rearrange resources to start with startIndex | ||
resources = config.resources | ||
.slice(startIndex) | ||
.concat(config.resources.slice(0, startIndex)); | ||
} | ||
// Counters, status | ||
const startTime = Date.now(); | ||
// Current loop number (increased once per full loop of available resources) | ||
let loop = 0; | ||
// Current attempt number (increased on every query) | ||
let attempt = 0; | ||
// Max index (config.resources.length - 1) | ||
const maxIndex = config.resources.length - 1; | ||
// Resource start index | ||
let startIndex = config.index ? config.index : 0; | ||
if (config.random && config.resources.length > 1) { | ||
startIndex = Math.floor(Math.random() * config.resources.length); | ||
} | ||
startIndex = Math.min(startIndex, maxIndex); | ||
// Last index | ||
let index = startIndex; | ||
// List of pending items | ||
let pending = []; | ||
// Query status | ||
let status = 'pending'; | ||
let queriesSent = 0; | ||
let lastError = void 0; | ||
// Timer | ||
let timer = 0; | ||
let timer = null; | ||
// Execution queue | ||
let queue = []; | ||
// Callbacks to call when query is complete | ||
let doneCallbacks = []; | ||
if (typeof done === 'function') { | ||
doneCallbacks.push(done); | ||
} | ||
/** | ||
* Reset timer | ||
*/ | ||
function resetTimer() { | ||
if (timer) { | ||
clearTimeout(timer); | ||
timer = null; | ||
} | ||
} | ||
/** | ||
* Abort everything | ||
*/ | ||
function abort() { | ||
// Change status | ||
if (status === 'pending') { | ||
status = 'aborted'; | ||
} | ||
// Reset timer | ||
resetTimer(); | ||
// Abort all queued items | ||
queue.forEach((item) => { | ||
if (item.abort) { | ||
item.abort(); | ||
} | ||
if (item.status === 'pending') { | ||
item.status = 'aborted'; | ||
} | ||
}); | ||
queue = []; | ||
} | ||
/** | ||
* Add / replace callback to call when execution is complete. | ||
* This can be used to abort pending query implementations when query is complete or aborted. | ||
*/ | ||
function subscribe(callback, overwrite = false) { | ||
function subscribe(callback, overwrite) { | ||
if (overwrite) { | ||
@@ -49,225 +92,156 @@ doneCallbacks = []; | ||
*/ | ||
function getStatus() { | ||
function getQueryStatus() { | ||
return { | ||
// eslint-disable-next-line @typescript-eslint/no-use-before-define | ||
done, | ||
// eslint-disable-next-line @typescript-eslint/no-use-before-define | ||
abort, | ||
subscribe, | ||
startTime, | ||
payload, | ||
startTime, | ||
loop, | ||
attempt, | ||
startIndex, | ||
index, | ||
maxIndex, | ||
status, | ||
queriesSent, | ||
queriesPending: queue.length, | ||
subscribe, | ||
abort, | ||
}; | ||
} | ||
/** | ||
* Stop timer | ||
* Fail query | ||
*/ | ||
function stopTimer() { | ||
if (timer) { | ||
clearTimeout(timer); | ||
} | ||
timer = 0; | ||
} | ||
/** | ||
* Abort pending item | ||
*/ | ||
function abortPendingItem(item) { | ||
if (item.abort && item.status === 'pending') { | ||
item.status = 'aborted'; | ||
item.abort(); | ||
} | ||
} | ||
/** | ||
* Stop everything | ||
*/ | ||
function stopQuery() { | ||
stopTimer(); | ||
// Stop all pending queries that have abort() callback | ||
pending.forEach(abortPendingItem); | ||
pending = []; | ||
// Cleanup parent | ||
if (parent !== null) { | ||
parent.cleanup(); | ||
} | ||
} | ||
/** | ||
* Send retrieved data to doneCallbacks | ||
*/ | ||
function sendRetrievedData(data) { | ||
doneCallbacks.forEach(callback => { | ||
callback(data, payload, getStatus); | ||
function failQuery() { | ||
status = 'failed'; | ||
// Send notice to all callbacks | ||
doneCallbacks.forEach((callback) => { | ||
callback(void 0, lastError); | ||
}); | ||
} | ||
/** | ||
* Complete stuff | ||
* Clear queue | ||
*/ | ||
function done(data = void 0) { | ||
// Stop timer | ||
stopTimer(); | ||
// Complete query | ||
if (status === 'pending') { | ||
status = 'completed'; | ||
stopQuery(); | ||
if (data !== void 0) { | ||
sendRetrievedData(data); | ||
function clearQueue() { | ||
queue = queue.filter((item) => { | ||
if (item.status === 'pending') { | ||
item.status = 'aborted'; | ||
} | ||
} | ||
} | ||
/** | ||
* Check if next run is new loop | ||
* | ||
* Returns true on new loop or next index number | ||
*/ | ||
function isNewLoop() { | ||
if (maxIndex < 1) { | ||
return true; | ||
} | ||
let nextIndex = index + 1; | ||
if (nextIndex > maxIndex) { | ||
nextIndex = 0; | ||
} | ||
if (nextIndex === startIndex) { | ||
return true; | ||
} | ||
return nextIndex; | ||
} | ||
/** | ||
* Done, called by pendingItem | ||
*/ | ||
function completePendingItem(pendingItem, index, data = void 0) { | ||
if (pendingItem.status === 'pending') { | ||
pendingItem.status = 'completed'; | ||
// Complete query | ||
done(data); | ||
// Change parent index | ||
if (parent !== null && !config.random && index !== startIndex) { | ||
// Tell Redundancy instance to change start index | ||
parent.setIndex(index); | ||
if (item.abort) { | ||
item.abort(); | ||
} | ||
} | ||
return false; | ||
}); | ||
} | ||
/** | ||
* Send query | ||
* Got response from module | ||
*/ | ||
function sendQuery() { | ||
const queryIndex = index; | ||
const queryResource = config.resources[queryIndex]; | ||
const pendingItem = { | ||
getStatus, | ||
attempt: attempt + 1, | ||
status: 'pending', | ||
done: (data = void 0) => { | ||
completePendingItem(pendingItem, queryIndex, data); | ||
}, | ||
abort: null, | ||
}; | ||
// Clean up old pending queries | ||
if (pending.length > Math.max(maxIndex * 2, 5)) { | ||
// Array is not empty, so first shift() will always return item | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
abortPendingItem(pending.shift()); | ||
function moduleResponse(item, data, error) { | ||
const isError = data === void 0; | ||
// Remove item from queue | ||
queue = queue.filter((queued) => queued !== item); | ||
// Check status | ||
switch (status) { | ||
case 'pending': | ||
// Pending | ||
break; | ||
case 'failed': | ||
if (isError || !config.dataAfterTimeout) { | ||
// Query has already timed out or dataAfterTimeout is disabled | ||
return; | ||
} | ||
// Success after failure | ||
break; | ||
default: | ||
// Aborted or completed | ||
return; | ||
} | ||
// Add pending query and call callback | ||
pending.push(pendingItem); | ||
queryCallback(queryResource, payload, pendingItem); | ||
} | ||
/** | ||
* Start timer for next query | ||
*/ | ||
function startTimer() { | ||
if (status !== 'pending') { | ||
return; | ||
} | ||
const nextIndex = isNewLoop(); | ||
let timeout; | ||
if (typeof nextIndex === 'boolean') { | ||
// New loop | ||
const nextLoop = loop + 1; | ||
// Check limit | ||
let limit; | ||
if (typeof config.limit === 'function') { | ||
limit = config.limit(nextLoop, startTime); | ||
// Error | ||
if (isError) { | ||
if (error !== void 0) { | ||
lastError = error; | ||
} | ||
else { | ||
limit = config.limit; | ||
if (!queue.length) { | ||
if (!resources.length) { | ||
// Nothing else queued, nothing can be queued | ||
failQuery(); | ||
} | ||
else { | ||
// Queue is empty: run next item immediately | ||
// eslint-disable-next-line @typescript-eslint/no-use-before-define | ||
execNext(); | ||
} | ||
} | ||
if (limit > 0 && limit <= nextLoop) { | ||
// Attempts limit was hit | ||
stopTimer(); | ||
return; | ||
} | ||
if (typeof config.timeout === 'function') { | ||
timeout = config.timeout(nextLoop, startIndex, startTime); | ||
} | ||
else { | ||
timeout = config.timeout; | ||
} | ||
return; | ||
} | ||
else { | ||
// Next index | ||
if (typeof config.rotate === 'function') { | ||
const queriesSent = nextIndex < startIndex | ||
? maxIndex - startIndex + nextIndex | ||
: nextIndex - startIndex; | ||
timeout = config.rotate(queriesSent, loop, nextIndex, startTime); | ||
// Reset timers, abort pending queries | ||
resetTimer(); | ||
clearQueue(); | ||
// Update index in Redundancy | ||
if (success && !config.random) { | ||
const index = config.resources.indexOf(item.resource); | ||
if (index !== -1 && index !== config.index) { | ||
success(index); | ||
} | ||
else { | ||
timeout = config.rotate; | ||
} | ||
} | ||
if (typeof timeout !== 'number' || timeout < 1) { | ||
// Stop sending queries | ||
stopTimer(); | ||
return; | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-use-before-define | ||
timer = setTimeout(nextTimer, timeout); | ||
// Mark as completed and call callbacks | ||
status = 'completed'; | ||
doneCallbacks.forEach((callback) => { | ||
callback(data); | ||
}); | ||
} | ||
/** | ||
* Next attempt | ||
* Execute next query | ||
*/ | ||
function next() { | ||
function execNext() { | ||
// Check status | ||
if (status !== 'pending') { | ||
return; | ||
} | ||
// Send query | ||
sendQuery(); | ||
// Start timer on next tick | ||
setTimeout(startTimer); | ||
} | ||
/** | ||
* Next attempt on timer | ||
*/ | ||
function nextTimer() { | ||
// Increase index | ||
index = isNewLoop(); | ||
if (typeof index === 'boolean') { | ||
loop++; | ||
index = startIndex; | ||
} | ||
attempt++; | ||
// Start next attempt | ||
next(); | ||
} | ||
/** | ||
* Abort all queries | ||
*/ | ||
function abort() { | ||
if (status !== 'pending') { | ||
// Reset timer | ||
resetTimer(); | ||
// Get resource | ||
const resource = resources.shift(); | ||
if (resource === void 0) { | ||
// Nothing to execute: wait for final timeout before failing | ||
if (queue.length) { | ||
const timeout = typeof config.timeout === 'function' | ||
? config.timeout(startTime) | ||
: config.timeout; | ||
if (timeout) { | ||
// Last timeout before failing to allow late response | ||
timer = setTimeout(() => { | ||
resetTimer(); | ||
if (status === 'pending') { | ||
// Clear queue | ||
clearQueue(); | ||
failQuery(); | ||
} | ||
}, timeout); | ||
return; | ||
} | ||
} | ||
// Fail | ||
failQuery(); | ||
return; | ||
} | ||
status = 'aborted'; | ||
stopQuery(); | ||
// Create new item | ||
const item = { | ||
getQueryStatus, | ||
status: 'pending', | ||
resource, | ||
done: (data, error) => { | ||
moduleResponse(item, data, error); | ||
}, | ||
}; | ||
// Add to queue | ||
queue.push(item); | ||
// Bump next index | ||
queriesSent++; | ||
// Get timeout for next item | ||
const timeout = typeof config.rotate === 'function' | ||
? config.rotate(queriesSent, startTime) | ||
: config.rotate; | ||
// Create timer | ||
timer = setTimeout(execNext, timeout); | ||
// Execute it | ||
query(resource, payload, item); | ||
} | ||
// Run next attempt on next tick | ||
setTimeout(next); | ||
// Return function that can check status | ||
return getStatus; | ||
// Execute first query on next tick | ||
setTimeout(execNext); | ||
// Return getQueryStatus() | ||
return getQueryStatus; | ||
} | ||
exports.sendQuery = sendQuery; | ||
//# sourceMappingURL=query.js.map |
@@ -1,4 +0,13 @@ | ||
import { RedundancyConfig } from './config'; | ||
import { GetQueryStatus, QueryCallback, OptionalDoneCallback } from './query'; | ||
import type { RedundancyConfig } from './config'; | ||
import type { GetQueryStatus, QueryModuleCallback, QueryDoneCallback } from './query'; | ||
/** | ||
* Export types from query.ts | ||
*/ | ||
export { GetQueryStatus, QueryModuleCallback, QueryDoneCallback }; | ||
export type { QueryAbortCallback, QueryUpdateIndexCallback, QueryStatus, PendingQueryItem, } from './query'; | ||
/** | ||
* Export types from config.ts | ||
*/ | ||
export type { RedundancyConfig, RedundancyResource } from './config'; | ||
/** | ||
* Function to filter item | ||
@@ -13,3 +22,3 @@ */ | ||
export interface Redundancy { | ||
query: (payload: unknown, queryCallback: QueryCallback, doneCallback?: OptionalDoneCallback) => GetQueryStatus; | ||
query: (payload: unknown, queryCallback: QueryModuleCallback, doneCallback?: QueryDoneCallback) => GetQueryStatus; | ||
find: (callback: FilterCallback) => GetQueryStatus | null; | ||
@@ -24,2 +33,1 @@ setIndex: (index: number) => void; | ||
export declare function initRedundancy(cfg: Partial<RedundancyConfig>): Redundancy; | ||
//# sourceMappingURL=redundancy.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.initRedundancy = void 0; | ||
const config_1 = require("./config"); | ||
@@ -36,8 +37,22 @@ const query_1 = require("./query"); | ||
/** | ||
* Remove aborted and completed queries | ||
*/ | ||
function cleanup() { | ||
queries = queries.filter((item) => item().status === 'pending'); | ||
} | ||
/** | ||
* Send query | ||
*/ | ||
function query(payload, queryCallback, doneCallback = null) { | ||
const query = query_1.sendQuery( | ||
// eslint-disable-next-line @typescript-eslint/no-use-before-define | ||
instance, config, payload, queryCallback, doneCallback); | ||
function query(payload, queryCallback, doneCallback) { | ||
const query = query_1.sendQuery(config, payload, queryCallback, (data, error) => { | ||
// Remove query from list | ||
cleanup(); | ||
// Call callback | ||
if (doneCallback) { | ||
doneCallback(data, error); | ||
} | ||
}, (newIndex) => { | ||
// Update start index | ||
config.index = newIndex; | ||
}); | ||
queries.push(query); | ||
@@ -50,3 +65,3 @@ return query; | ||
function find(callback) { | ||
const result = queries.find(value => { | ||
const result = queries.find((value) => { | ||
return callback(value); | ||
@@ -56,8 +71,2 @@ }); | ||
} | ||
/** | ||
* Remove aborted and completed queries | ||
*/ | ||
function cleanup() { | ||
queries = queries.filter(item => item().status === 'pending'); | ||
} | ||
// Create and return functions | ||
@@ -76,2 +85,1 @@ const instance = { | ||
exports.initRedundancy = initRedundancy; | ||
//# sourceMappingURL=redundancy.js.map |
{ | ||
"name": "@cyberalien/redundancy", | ||
"description": "Reusable redundancy library for API queries", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"author": "Vjacheslav Trushkin", | ||
"license": "(Apache-2.0 OR GPL-2.0)", | ||
"main": "lib/redundancy.js", | ||
"types": "lib/types.d.ts", | ||
"types": "lib/redundancy.d.ts", | ||
"scripts": { | ||
@@ -26,13 +26,12 @@ "clean": "rm -rf lib compiled-tests", | ||
"devDependencies": { | ||
"@types/chai": "^4.2.11", | ||
"@types/mocha": "^5.2.7", | ||
"@types/node": "^12.12.37", | ||
"@typescript-eslint/eslint-plugin": "^2.30.0", | ||
"@typescript-eslint/parser": "^2.30.0", | ||
"@types/chai": "^4.2.14", | ||
"@types/mocha": "^8.2.0", | ||
"@types/node": "^14.14.13", | ||
"@typescript-eslint/eslint-plugin": "^4.10.0", | ||
"@typescript-eslint/parser": "^4.10.0", | ||
"chai": "^4.2.0", | ||
"eslint": "^6.8.0", | ||
"mocha": "^6.2.3", | ||
"typescript": "^3.8.3" | ||
}, | ||
"dependencies": {} | ||
"mocha": "^8.2.1", | ||
"typescript": "^4.1.3" | ||
} | ||
} |
@@ -6,4 +6,4 @@ { | ||
"declaration": true, | ||
"declarationMap": true, | ||
"sourceMap": true, | ||
"declarationMap": false, | ||
"sourceMap": false, | ||
"composite": true, | ||
@@ -13,4 +13,6 @@ "strict": true, | ||
"esModuleInterop": true, | ||
"forceConsistentCasingInFileNames": true | ||
"allowSyntheticDefaultImports": true, | ||
"forceConsistentCasingInFileNames": true, | ||
"importsNotUsedAsValues": "error" | ||
} | ||
} |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
87596
17
522
1