@furystack/core
Advanced tools
Comparing version 2.0.0 to 4.0.0
/// <reference types="node" /> | ||
import { Constructable } from '@furystack/inject'; | ||
import { ILogger } from '@furystack/logging'; | ||
import { readFile as nodeReadFile, writeFile as nodeWriteFile } from 'fs'; | ||
import { LoggerCollection } from './Loggers'; | ||
import { IPhysicalStore } from './Models/IPhysicalStore'; | ||
import { DefaultFilter, IPhysicalStore } from './Models/IPhysicalStore'; | ||
/** | ||
* Store implementation that stores info in a simple JSON file | ||
*/ | ||
export declare class FileStore<T, K extends keyof T = keyof T> implements IPhysicalStore<T, K> { | ||
private readonly fileName; | ||
readonly primaryKey: K; | ||
readonly tickMs: number; | ||
private readFile; | ||
private writeFile; | ||
logger: LoggerCollection; | ||
export declare class FileStore<T> implements IPhysicalStore<T, DefaultFilter<T>> { | ||
private readonly options; | ||
private readonly watcher?; | ||
readonly model: Constructable<T>; | ||
readonly primaryKey: keyof T; | ||
remove(key: T[this['primaryKey']]): Promise<void>; | ||
@@ -23,3 +21,3 @@ readonly logScope: string; | ||
add(data: T): Promise<T>; | ||
filter: (filter: Partial<T>) => Promise<T[]>; | ||
filter: (filter: DefaultFilter<T>) => Promise<T[]>; | ||
count(): Promise<number>; | ||
@@ -31,4 +29,14 @@ private fileLock; | ||
update(id: T[this['primaryKey']], data: T): Promise<void>; | ||
constructor(fileName: string, primaryKey: K, tickMs?: number, readFile?: typeof nodeReadFile, writeFile?: typeof nodeWriteFile, logger?: LoggerCollection); | ||
private readFile; | ||
private writeFile; | ||
constructor(options: { | ||
fileName: string; | ||
primaryKey: keyof T; | ||
tickMs?: number; | ||
logger: ILogger; | ||
model: Constructable<T>; | ||
readFile?: typeof nodeReadFile; | ||
writeFile?: typeof nodeWriteFile; | ||
}); | ||
} | ||
//# sourceMappingURL=FileStore.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const tslib_1 = require("tslib"); | ||
const fs_1 = require("fs"); | ||
const semaphore_async_await_1 = require("semaphore-async-await"); | ||
const Loggers_1 = require("./Loggers"); | ||
const semaphore_async_await_1 = tslib_1.__importDefault(require("semaphore-async-await")); | ||
/** | ||
@@ -10,12 +10,7 @@ * Store implementation that stores info in a simple JSON file | ||
class FileStore { | ||
constructor(fileName, primaryKey, tickMs = 10000, readFile = fs_1.readFile, writeFile = fs_1.writeFile, logger = new Loggers_1.LoggerCollection()) { | ||
this.fileName = fileName; | ||
this.primaryKey = primaryKey; | ||
this.tickMs = tickMs; | ||
this.readFile = readFile; | ||
this.writeFile = writeFile; | ||
this.logger = logger; | ||
constructor(options) { | ||
this.options = options; | ||
this.logScope = '@furystack/core/' + this.constructor.name; | ||
this.cache = new Map(); | ||
this.tick = setInterval(() => this.saveChanges(), this.tickMs); | ||
this.tick = setInterval(() => this.saveChanges(), this.options.tickMs || 5000); | ||
this.hasChanges = false; | ||
@@ -28,16 +23,24 @@ this.get = async (key) => { | ||
this.filter = async (filter) => { | ||
return await this.fileLock.execute(async () => { | ||
return [...this.cache.values()].filter(item => { | ||
for (const key in filter) { | ||
if (filter[key] !== item[key]) { | ||
return false; | ||
} | ||
return [...this.cache.values()].filter(item => { | ||
for (const key in filter.filter) { | ||
if (filter.filter[key] !== item[key]) { | ||
return false; | ||
} | ||
return true; | ||
}); | ||
} | ||
return true; | ||
}); | ||
}; | ||
this.fileLock = new semaphore_async_await_1.default(1); | ||
this.readFile = fs_1.readFile; | ||
this.writeFile = fs_1.writeFile; | ||
this.primaryKey = options.primaryKey; | ||
this.model = options.model; | ||
options.readFile && (this.readFile = options.readFile); | ||
options.writeFile && (this.writeFile = options.writeFile); | ||
try { | ||
this.watcher = fs_1.watch(this.fileName, { encoding: 'buffer' }, () => { | ||
this.watcher = fs_1.watch(this.options.fileName, { encoding: 'buffer' }, () => { | ||
this.options.logger.verbose({ | ||
scope: this.logScope, | ||
message: `The file '${this.options.fileName}' has been changed, reloading data...`, | ||
}); | ||
this.reloadData(); | ||
@@ -47,7 +50,3 @@ }); | ||
catch (error) { | ||
this.logger.warning({ | ||
scope: this.logScope, | ||
data: error, | ||
message: `Error registering file watcher for store. External updates won't be updated.`, | ||
}); | ||
// Error registering file watcher for store. External updates won't be updated. | ||
} | ||
@@ -84,3 +83,3 @@ } | ||
await new Promise((resolve, reject) => { | ||
this.writeFile(this.fileName, JSON.stringify(values), error => { | ||
this.writeFile(this.options.fileName, JSON.stringify(values), error => { | ||
if (!error) { | ||
@@ -90,7 +89,2 @@ resolve(); | ||
else { | ||
this.logger.error({ | ||
scope: this.logScope, | ||
message: 'Error when saving store data to file:', | ||
data: { error }, | ||
}); | ||
reject(error); | ||
@@ -101,3 +95,15 @@ } | ||
this.hasChanges = false; | ||
this.options.logger.information({ | ||
scope: this.logScope, | ||
message: `Store '${this.options.fileName}' has been updated with the latest changes.`, | ||
data: { values }, | ||
}); | ||
} | ||
catch (e) { | ||
this.options.logger.error({ | ||
scope: this.logScope, | ||
message: `Error saving changed data to '${this.options.fileName}'.`, | ||
data: { error: e }, | ||
}); | ||
} | ||
finally { | ||
@@ -108,2 +114,6 @@ this.fileLock.release(); | ||
async dispose() { | ||
this.options.logger.information({ | ||
scope: this.logScope, | ||
message: `Disposing FileStore: '${this.options.fileName}'`, | ||
}); | ||
await this.saveChanges(); | ||
@@ -117,9 +127,4 @@ this.watcher && this.watcher.close(); | ||
await new Promise((resolve, reject) => { | ||
this.readFile(this.fileName, (error, data) => { | ||
this.readFile(this.options.fileName, (error, data) => { | ||
if (error) { | ||
this.logger.error({ | ||
scope: this.logScope, | ||
message: 'Error when loading store data from file:', | ||
data: { error }, | ||
}); | ||
reject(error); | ||
@@ -138,2 +143,9 @@ } | ||
} | ||
catch (e) { | ||
this.options.logger.error({ | ||
scope: this.logScope, | ||
message: `Error loading data into store from '${this.options.fileName}'.`, | ||
data: e, | ||
}); | ||
} | ||
finally { | ||
@@ -140,0 +152,0 @@ this.fileLock.release(); |
export * from './SystemRoles'; | ||
export * from './Loggers'; | ||
export * from './Models/IActivateable'; | ||
export * from './Models/IApi'; | ||
export * from './Models/IFuryStackOptions'; | ||
export * from './Models/ILogEntries'; | ||
export * from './Models/ILogger'; | ||
export * from './InjectorExtension'; | ||
export * from './ServerManager'; | ||
export * from './Models/IPhysicalStore'; | ||
export * from './Models/IRole'; | ||
export * from './Models/IUser'; | ||
export * from './Models/User'; | ||
export * from './FileStore'; | ||
export * from './FuryStack'; | ||
export * from './InMemoryStore'; | ||
export * from './UserContext'; | ||
export * from './StoreManager'; | ||
import './InjectorExtension'; | ||
//# sourceMappingURL=index.d.ts.map |
"use strict"; | ||
function __export(m) { | ||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__export(require("./SystemRoles")); | ||
__export(require("./Loggers")); | ||
__export(require("./Models/ILogEntries")); | ||
__export(require("./Models/IUser")); | ||
__export(require("./FileStore")); | ||
__export(require("./FuryStack")); | ||
__export(require("./InMemoryStore")); | ||
__export(require("./UserContext")); | ||
const tslib_1 = require("tslib"); | ||
tslib_1.__exportStar(require("./SystemRoles"), exports); | ||
tslib_1.__exportStar(require("./ServerManager"), exports); | ||
tslib_1.__exportStar(require("./Models/User"), exports); | ||
tslib_1.__exportStar(require("./FileStore"), exports); | ||
tslib_1.__exportStar(require("./InMemoryStore"), exports); | ||
tslib_1.__exportStar(require("./StoreManager"), exports); | ||
require("./InjectorExtension"); | ||
//# sourceMappingURL=index.js.map |
@@ -1,10 +0,7 @@ | ||
import { LoggerCollection } from './Loggers'; | ||
import { IPhysicalStore } from './Models/IPhysicalStore'; | ||
import { Constructable } from '@furystack/inject'; | ||
import { DefaultFilter, IPhysicalStore } from './Models/IPhysicalStore'; | ||
/** | ||
* Store implementation that stores data in an in-memory cache | ||
*/ | ||
export declare class InMemoryStore<T, K extends keyof T = keyof T> implements IPhysicalStore<T, K> { | ||
readonly primaryKey: K; | ||
readonly tickMs: number; | ||
logger: LoggerCollection; | ||
export declare class InMemoryStore<T> implements IPhysicalStore<T, Partial<T>> { | ||
remove(key: T[this['primaryKey']]): Promise<void>; | ||
@@ -14,8 +11,15 @@ add(data: T): Promise<T>; | ||
get: (key: T[this["primaryKey"]]) => Promise<T | undefined>; | ||
filter: (filter: Partial<T>) => Promise<T[]>; | ||
filter: (filter: DefaultFilter<T>) => Promise<T[]>; | ||
count(): Promise<number>; | ||
update(id: T[this['primaryKey']], data: T): Promise<void>; | ||
dispose(): void; | ||
constructor(primaryKey: K, tickMs?: number, logger?: LoggerCollection); | ||
readonly primaryKey: keyof T; | ||
tickMs: number; | ||
readonly model: Constructable<T>; | ||
constructor(options: { | ||
primaryKey: keyof T; | ||
tickMs?: number; | ||
model: Constructable<T>; | ||
}); | ||
} | ||
//# sourceMappingURL=InMemoryStore.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const Loggers_1 = require("./Loggers"); | ||
/** | ||
@@ -8,16 +7,19 @@ * Store implementation that stores data in an in-memory cache | ||
class InMemoryStore { | ||
constructor(primaryKey, tickMs = 10000, logger = new Loggers_1.LoggerCollection()) { | ||
this.primaryKey = primaryKey; | ||
this.tickMs = tickMs; | ||
this.logger = logger; | ||
constructor(options) { | ||
this.cache = new Map(); | ||
this.get = async (key) => this.cache.get(key); | ||
this.filter = async (filter) => [...this.cache.values()].filter(item => { | ||
for (const key in filter) { | ||
if (filter[key] !== item[key]) { | ||
return false; | ||
this.filter = async (filter) => { | ||
return [...this.cache.values()].filter(item => { | ||
for (const key in filter.filter) { | ||
if (filter.filter[key] !== item[key]) { | ||
return false; | ||
} | ||
} | ||
} | ||
return true; | ||
}); | ||
return true; | ||
}); | ||
}; | ||
this.tickMs = 10000; | ||
this.primaryKey = options.primaryKey; | ||
options.tickMs && (this.tickMs = options.tickMs); | ||
this.model = options.model; | ||
} | ||
@@ -24,0 +26,0 @@ async remove(key) { |
@@ -0,12 +1,21 @@ | ||
import { Constructable } from '@furystack/inject'; | ||
import { Disposable } from '@sensenet/client-utils'; | ||
import { ILogger } from './ILogger'; | ||
/** | ||
* Interface that defines a physical store implementation | ||
* Type for default filtering model | ||
*/ | ||
export interface IPhysicalStore<T, K extends keyof T = keyof T, TFilter = Partial<T> & { | ||
export interface DefaultFilter<T> { | ||
top?: number; | ||
skip?: number; | ||
}> extends Disposable { | ||
readonly primaryKey: K; | ||
logger: ILogger; | ||
order?: { | ||
[P in keyof T]?: 'ASC' | 'DESC'; | ||
}; | ||
select?: Array<keyof T>; | ||
filter?: Partial<T>; | ||
} | ||
/** | ||
* Interface that defines a physical store implementation | ||
*/ | ||
export interface IPhysicalStore<T, TFilter = DefaultFilter<T>> extends Disposable { | ||
readonly primaryKey: keyof T; | ||
readonly model: Constructable<T>; | ||
add(data: T): Promise<T>; | ||
@@ -13,0 +22,0 @@ update(id: T[this['primaryKey']], data: T): Promise<void>; |
{ | ||
"name": "@furystack/core", | ||
"version": "2.0.0", | ||
"version": "4.0.0", | ||
"description": "Core FuryStack package", | ||
@@ -58,13 +58,14 @@ "main": "dist/index.js", | ||
"dependencies": { | ||
"@furystack/inject": "^2.0.0", | ||
"@sensenet/client-utils": "^1.2.1", | ||
"semaphore-async-await": "^1.5.1" | ||
"@furystack/inject": "^3.0.1", | ||
"@furystack/logging": "^1.0.0", | ||
"@sensenet/client-utils": "^1.5.1", | ||
"semaphore-async-await": "1.5.1" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^23.3.11", | ||
"jest": "^23.6.0", | ||
"rimraf": "^2.6.1", | ||
"ts-jest": "^23.10.4", | ||
"tslint": "^5.11.0", | ||
"typescript": "^3.1.6" | ||
"@types/jest": "24.0.9", | ||
"jest": "24.1.0", | ||
"rimraf": "2.6.3", | ||
"ts-jest": "24.0.0", | ||
"tslint": "5.13.0", | ||
"typescript": "^3.4.3" | ||
}, | ||
@@ -77,3 +78,3 @@ "config": { | ||
"typings": "./dist/index.d.ts", | ||
"gitHead": "d0452632dfb2b8de2dcb1c47d88fff62997c738d" | ||
"gitHead": "2fa8429190fca702d037ea9da26cdc9ded16a8de" | ||
} |
@@ -0,5 +1,6 @@ | ||
import { Constructable } from '@furystack/inject' | ||
import { ILogger } from '@furystack/logging' | ||
import { FSWatcher, readFile as nodeReadFile, watch, writeFile as nodeWriteFile } from 'fs' | ||
import Semaphore from 'semaphore-async-await' | ||
import { LoggerCollection } from './Loggers' | ||
import { IPhysicalStore } from './Models/IPhysicalStore' | ||
import { DefaultFilter, IPhysicalStore } from './Models/IPhysicalStore' | ||
@@ -9,4 +10,8 @@ /** | ||
*/ | ||
export class FileStore<T, K extends keyof T = keyof T> implements IPhysicalStore<T, K> { | ||
export class FileStore<T> implements IPhysicalStore<T, DefaultFilter<T>> { | ||
private readonly watcher?: FSWatcher | ||
public readonly model: Constructable<T> | ||
public readonly primaryKey: keyof T | ||
public async remove(key: T[this['primaryKey']]): Promise<void> { | ||
@@ -18,3 +23,3 @@ this.cache.delete(key) | ||
private cache: Map<T[this['primaryKey']], T> = new Map() | ||
public tick = setInterval(() => this.saveChanges(), this.tickMs) | ||
public tick = setInterval(() => this.saveChanges(), this.options.tickMs || 5000) | ||
private hasChanges: boolean = false | ||
@@ -37,12 +42,10 @@ public get = async (key: T[this['primaryKey']]) => { | ||
public filter = async (filter: Partial<T>) => { | ||
return await this.fileLock.execute(async () => { | ||
return [...this.cache.values()].filter(item => { | ||
for (const key in filter) { | ||
if (filter[key] !== (item as any)[key]) { | ||
return false | ||
} | ||
public filter = async (filter: DefaultFilter<T>) => { | ||
return [...this.cache.values()].filter(item => { | ||
for (const key in filter.filter) { | ||
if ((filter.filter as any)[key] !== (item as any)[key]) { | ||
return false | ||
} | ||
return true | ||
}) | ||
} | ||
return true | ||
}) | ||
@@ -69,11 +72,6 @@ } | ||
await new Promise((resolve, reject) => { | ||
this.writeFile(this.fileName, JSON.stringify(values), error => { | ||
this.writeFile(this.options.fileName, JSON.stringify(values), error => { | ||
if (!error) { | ||
resolve() | ||
} else { | ||
this.logger.error({ | ||
scope: this.logScope, | ||
message: 'Error when saving store data to file:', | ||
data: { error }, | ||
}) | ||
reject(error) | ||
@@ -84,2 +82,13 @@ } | ||
this.hasChanges = false | ||
this.options.logger.information({ | ||
scope: this.logScope, | ||
message: `Store '${this.options.fileName}' has been updated with the latest changes.`, | ||
data: { values }, | ||
}) | ||
} catch (e) { | ||
this.options.logger.error({ | ||
scope: this.logScope, | ||
message: `Error saving changed data to '${this.options.fileName}'.`, | ||
data: { error: e }, | ||
}) | ||
} finally { | ||
@@ -91,2 +100,6 @@ this.fileLock.release() | ||
public async dispose() { | ||
this.options.logger.information({ | ||
scope: this.logScope, | ||
message: `Disposing FileStore: '${this.options.fileName}'`, | ||
}) | ||
await this.saveChanges() | ||
@@ -101,9 +114,4 @@ this.watcher && this.watcher.close() | ||
await new Promise((resolve, reject) => { | ||
this.readFile(this.fileName, (error, data) => { | ||
this.readFile(this.options.fileName, (error, data) => { | ||
if (error) { | ||
this.logger.error({ | ||
scope: this.logScope, | ||
message: 'Error when loading store data from file:', | ||
data: { error }, | ||
}) | ||
reject(error) | ||
@@ -120,2 +128,8 @@ } else { | ||
}) | ||
} catch (e) { | ||
this.options.logger.error({ | ||
scope: this.logScope, | ||
message: `Error loading data into store from '${this.options.fileName}'.`, | ||
data: e, | ||
}) | ||
} finally { | ||
@@ -131,22 +145,33 @@ this.fileLock.release() | ||
private readFile = nodeReadFile | ||
private writeFile = nodeWriteFile | ||
constructor( | ||
private readonly fileName: string, | ||
public readonly primaryKey: K, | ||
public readonly tickMs = 10000, | ||
private readFile = nodeReadFile, | ||
private writeFile = nodeWriteFile, | ||
public logger = new LoggerCollection(), | ||
private readonly options: { | ||
fileName: string | ||
primaryKey: keyof T | ||
tickMs?: number | ||
logger: ILogger | ||
model: Constructable<T> | ||
readFile?: typeof nodeReadFile | ||
writeFile?: typeof nodeWriteFile | ||
}, | ||
) { | ||
this.primaryKey = options.primaryKey | ||
this.model = options.model | ||
options.readFile && (this.readFile = options.readFile) | ||
options.writeFile && (this.writeFile = options.writeFile) | ||
try { | ||
this.watcher = watch(this.fileName, { encoding: 'buffer' }, () => { | ||
this.watcher = watch(this.options.fileName, { encoding: 'buffer' }, () => { | ||
this.options.logger.verbose({ | ||
scope: this.logScope, | ||
message: `The file '${this.options.fileName}' has been changed, reloading data...`, | ||
}) | ||
this.reloadData() | ||
}) | ||
} catch (error) { | ||
this.logger.warning({ | ||
scope: this.logScope, | ||
data: error, | ||
message: `Error registering file watcher for store. External updates won't be updated.`, | ||
}) | ||
// Error registering file watcher for store. External updates won't be updated. | ||
} | ||
} | ||
} |
export * from './SystemRoles' | ||
export * from './Loggers' | ||
export * from './Models/IActivateable' | ||
export * from './Models/IApi' | ||
export * from './Models/IFuryStackOptions' | ||
export * from './Models/ILogEntries' | ||
export * from './Models/ILogger' | ||
export * from './InjectorExtension' | ||
export * from './ServerManager' | ||
export * from './Models/IPhysicalStore' | ||
export * from './Models/IRole' | ||
export * from './Models/IUser' | ||
export * from './Models/User' | ||
export * from './FileStore' | ||
export * from './FuryStack' | ||
export * from './InMemoryStore' | ||
export * from './UserContext' | ||
export * from './StoreManager' | ||
import './InjectorExtension' |
@@ -1,3 +0,3 @@ | ||
import { LoggerCollection } from './Loggers' | ||
import { IPhysicalStore } from './Models/IPhysicalStore' | ||
import { Constructable } from '@furystack/inject' | ||
import { DefaultFilter, IPhysicalStore } from './Models/IPhysicalStore' | ||
@@ -7,3 +7,3 @@ /** | ||
*/ | ||
export class InMemoryStore<T, K extends keyof T = keyof T> implements IPhysicalStore<T, K> { | ||
export class InMemoryStore<T> implements IPhysicalStore<T, Partial<T>> { | ||
public async remove(key: T[this['primaryKey']]): Promise<void> { | ||
@@ -24,6 +24,6 @@ this.cache.delete(key) | ||
public filter = async (filter: Partial<T>) => | ||
[...this.cache.values()].filter(item => { | ||
for (const key in filter) { | ||
if (filter[key] !== (item as any)[key]) { | ||
public filter = async (filter: DefaultFilter<T>) => { | ||
return [...this.cache.values()].filter(item => { | ||
for (const key in filter.filter) { | ||
if ((filter.filter as any)[key] !== (item as any)[key]) { | ||
return false | ||
@@ -34,2 +34,3 @@ } | ||
}) | ||
} | ||
@@ -48,3 +49,11 @@ public async count() { | ||
constructor(public readonly primaryKey: K, public readonly tickMs = 10000, public logger = new LoggerCollection()) {} | ||
public readonly primaryKey: keyof T | ||
public tickMs = 10000 | ||
public readonly model: Constructable<T> | ||
constructor(options: { primaryKey: keyof T; tickMs?: number; model: Constructable<T> }) { | ||
this.primaryKey = options.primaryKey | ||
options.tickMs && (this.tickMs = options.tickMs) | ||
this.model = options.model | ||
} | ||
} |
@@ -0,11 +1,21 @@ | ||
import { Constructable } from '@furystack/inject' | ||
import { Disposable } from '@sensenet/client-utils' | ||
import { ILogger } from './ILogger' | ||
/** | ||
* Type for default filtering model | ||
*/ | ||
export interface DefaultFilter<T> { | ||
top?: number | ||
skip?: number | ||
order?: { [P in keyof T]?: 'ASC' | 'DESC' } | ||
select?: Array<keyof T> | ||
filter?: Partial<T> | ||
} | ||
/** | ||
* Interface that defines a physical store implementation | ||
*/ | ||
export interface IPhysicalStore<T, K extends keyof T = keyof T, TFilter = Partial<T> & { top?: number; skip?: number }> | ||
extends Disposable { | ||
readonly primaryKey: K | ||
logger: ILogger | ||
export interface IPhysicalStore<T, TFilter = DefaultFilter<T>> extends Disposable { | ||
readonly primaryKey: keyof T | ||
readonly model: Constructable<T> | ||
add(data: T): Promise<T> | ||
@@ -12,0 +22,0 @@ update(id: T[this['primaryKey']], data: T): Promise<void> |
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
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
62656
4
53
814
1
+ Added@furystack/logging@^1.0.0
+ Added@furystack/inject@3.0.8(transitive)
+ Added@furystack/logging@1.1.7(transitive)
- Removed@furystack/inject@2.0.0(transitive)
Updated@furystack/inject@^3.0.1
Updatedsemaphore-async-await@1.5.1