Comparing version 0.3.3 to 5.0.0
@@ -1,48 +0,36 @@ | ||
export interface Data<V> { | ||
expire?: number; | ||
value: V; | ||
} | ||
export declare const defaultOpts: { | ||
import EventEmitter from 'events'; | ||
import type { KeyvStoreAdapter, StoredData } from 'keyv'; | ||
export interface Options { | ||
deserialize: (val: any) => any; | ||
dialect: string; | ||
expiredCheckDelay: number; | ||
filename: string; | ||
expiredCheckDelay: number; | ||
serialize: (val: any) => any; | ||
writeDelay: number; | ||
encode: (val: any) => any; | ||
decode: (val: any) => any; | ||
}; | ||
export declare class Field<T, D extends T | void = T | void> { | ||
protected kv: KeyvFile; | ||
protected key: string; | ||
protected defaults?: D | undefined; | ||
constructor(kv: KeyvFile, key: string, defaults?: D | undefined); | ||
get(): D; | ||
get(def: D): D; | ||
set(val: T, ttl?: number): Promise<any>; | ||
delete(): boolean; | ||
} | ||
export declare function makeField<T = any, D extends T | void = T | void>(kv: KeyvFile, key: string, defaults?: D): Field<T, D>; | ||
export declare class KeyvFile<V = any> { | ||
export declare const defaultOpts: Options; | ||
export declare class KeyvFile extends EventEmitter implements KeyvStoreAdapter { | ||
ttlSupport: boolean; | ||
private _opts; | ||
namespace?: string; | ||
opts: Options; | ||
private _cache; | ||
private _lastExpire; | ||
constructor(opts?: Partial<typeof defaultOpts>); | ||
isExpired(data: Data<V>): boolean; | ||
get<T = V>(key: string, defaults: T): T; | ||
get<T = V>(key: string): T | void; | ||
has(key: string): boolean; | ||
keys(): string[]; | ||
/** | ||
* | ||
* @param key | ||
* @param value | ||
* @param ttl time-to-live, seconds | ||
*/ | ||
set<T = V>(key: string, value: T, ttl?: number): Promise<any>; | ||
delete(key: string): boolean; | ||
constructor(options?: Options); | ||
private _getKeyName; | ||
private _removeNamespaceFromKey; | ||
get<Value>(key: string): Promise<StoredData<Value> | undefined>; | ||
getMany<Value>(keys: string[]): Promise<Array<StoredData<Value | undefined>>>; | ||
set(key: string, value: any, ttl?: number): Promise<any>; | ||
delete(key: string): Promise<boolean>; | ||
deleteMany(keys: string[]): Promise<boolean>; | ||
clear(): Promise<any>; | ||
clearExpire(): void; | ||
saveToDisk(): Promise<void>; | ||
iterator(namespace?: string): AsyncGenerator<any[], void, unknown>; | ||
has(key: string): Promise<boolean>; | ||
private isExpired; | ||
private clearExpire; | ||
private saveToDisk; | ||
private _savePromise?; | ||
save(): Promise<any>; | ||
private save; | ||
disconnect(): Promise<void>; | ||
} | ||
export default KeyvFile; |
204
lib/index.js
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.KeyvFile = exports.Field = exports.defaultOpts = void 0; | ||
exports.makeField = makeField; | ||
exports.KeyvFile = exports.defaultOpts = void 0; | ||
const tslib_1 = require("tslib"); | ||
const os = tslib_1.__importStar(require("os")); | ||
const fs = tslib_1.__importStar(require("fs-extra")); | ||
const debug_1 = tslib_1.__importDefault(require("debug")); | ||
const debug = (0, debug_1.default)('keyv-file'); | ||
function isNumber(val) { | ||
return typeof val === 'number'; | ||
} | ||
const events_1 = tslib_1.__importDefault(require("events")); | ||
exports.defaultOpts = { | ||
deserialize: JSON.parse, | ||
dialect: 'redis', | ||
expiredCheckDelay: 24 * 3600 * 1000, // ms | ||
filename: `${os.tmpdir()}/keyv-file/default-rnd-${Math.random().toString(36).slice(2)}.json`, | ||
expiredCheckDelay: 24 * 3600 * 1000, // ms | ||
serialize: JSON.stringify, | ||
writeDelay: 100, // ms | ||
encode: JSON.stringify, | ||
decode: JSON.parse, | ||
}; | ||
class Field { | ||
constructor(kv, key, defaults) { | ||
this.kv = kv; | ||
this.key = key; | ||
this.defaults = defaults; | ||
} | ||
get(def = this.defaults) { | ||
return this.kv.get(this.key, def); | ||
} | ||
set(val, ttl) { | ||
return this.kv.set(this.key, val, ttl); | ||
} | ||
delete() { | ||
return this.kv.delete(this.key); | ||
} | ||
function isNumber(val) { | ||
return typeof val === 'number'; | ||
} | ||
exports.Field = Field; | ||
function makeField(kv, key, defaults) { | ||
return new Field(kv, key, defaults); | ||
} | ||
class KeyvFile { | ||
constructor(opts) { | ||
class KeyvFile extends events_1.default { | ||
constructor(options) { | ||
super(); | ||
this.ttlSupport = true; | ||
this._opts = exports.defaultOpts; | ||
this._opts = Object.assign(Object.assign({}, this._opts), opts); | ||
this._getKeyName = (key) => { | ||
if (this.namespace) { | ||
return `${this.namespace}:${key}`; | ||
} | ||
return key; | ||
}; | ||
this._removeNamespaceFromKey = (key) => { | ||
if (this.namespace) { | ||
return key.replace(`${this.namespace}:`, ''); | ||
} | ||
return key; | ||
}; | ||
this.opts = Object.assign({}, exports.defaultOpts, options); | ||
try { | ||
const data = this._opts.decode(fs.readFileSync(this._opts.filename, 'utf8')); | ||
const data = this.opts.deserialize(fs.readFileSync(this.opts.filename, 'utf8')); | ||
if (!Array.isArray(data.cache)) { | ||
@@ -51,3 +42,5 @@ const _cache = data.cache; | ||
for (const key in _cache) { | ||
data.cache.push([key, _cache[key]]); | ||
if (_cache.hasOwnProperty(key)) { | ||
data.cache.push([key, _cache[key]]); | ||
} | ||
} | ||
@@ -59,3 +52,2 @@ } | ||
catch (e) { | ||
debug(e); | ||
this._cache = new Map(); | ||
@@ -65,66 +57,91 @@ this._lastExpire = Date.now(); | ||
} | ||
isExpired(data) { | ||
return isNumber(data.expire) && data.expire <= Date.now(); | ||
} | ||
get(key, defaults) { | ||
try { | ||
const data = this._cache.get(key); | ||
if (!data) { | ||
return defaults; | ||
get(key) { | ||
return tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
try { | ||
const data = this._cache.get(this._getKeyName(key)); | ||
if (!data) { | ||
return undefined; | ||
} | ||
else if (this.isExpired(data)) { | ||
yield this.delete(this._getKeyName(key)); | ||
return undefined; | ||
} | ||
else { | ||
return data.value; | ||
} | ||
} | ||
else if (this.isExpired(data)) { | ||
this.delete(key); | ||
return defaults; | ||
catch (error) { | ||
// do nothing; | ||
} | ||
else { | ||
return data.value; | ||
} | ||
} | ||
catch (error) { | ||
console.error(error); | ||
} | ||
}); | ||
} | ||
has(key) { | ||
return typeof this.get(key) !== 'undefined'; | ||
getMany(keys) { | ||
return tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
const results = yield Promise.all(keys.map((key) => tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
const value = yield this.get(key); | ||
return value; | ||
}))); | ||
return results; | ||
}); | ||
} | ||
keys() { | ||
let keys = []; | ||
for (const key of this._cache.keys()) { | ||
if (!this.isExpired(this._cache.get(key))) { | ||
keys.push(key); | ||
set(key, value, ttl) { | ||
return tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
if (ttl === 0) { | ||
ttl = undefined; | ||
} | ||
} | ||
return keys; | ||
} | ||
/** | ||
* | ||
* @param key | ||
* @param value | ||
* @param ttl time-to-live, seconds | ||
*/ | ||
set(key, value, ttl) { | ||
if (ttl === 0) { | ||
ttl = undefined; | ||
} | ||
this._cache.set(key, { | ||
value: value, | ||
expire: isNumber(ttl) | ||
? Date.now() + ttl | ||
: undefined | ||
this._cache.set(this._getKeyName(key), { | ||
expire: isNumber(ttl) | ||
? Date.now() + ttl | ||
: undefined, | ||
value: value | ||
}); | ||
return this.save(); | ||
}); | ||
return this.save(); | ||
} | ||
delete(key) { | ||
let ret = this._cache.delete(key); | ||
this.save(); | ||
return ret; | ||
return tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
const ret = this._cache.delete(this._getKeyName(key)); | ||
yield this.save(); | ||
return ret; | ||
}); | ||
} | ||
deleteMany(keys) { | ||
return tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
const deletePromises = keys.map((key) => this.delete(key)); | ||
const results = yield Promise.all(deletePromises); | ||
return results.every((result) => result); | ||
}); | ||
} | ||
clear() { | ||
this._cache = new Map(); | ||
this._lastExpire = Date.now(); | ||
return this.save(); | ||
return tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
this._cache = new Map(); | ||
this._lastExpire = Date.now(); | ||
return this.save(); | ||
}); | ||
} | ||
iterator(namespace) { | ||
return tslib_1.__asyncGenerator(this, arguments, function* iterator_1() { | ||
for (const [key, data] of this._cache) { | ||
// Filter by namespace if provided | ||
if (key === undefined) { | ||
continue; | ||
} | ||
if (!namespace || key.includes(namespace)) { | ||
const resolvedValue = data.value; | ||
yield yield tslib_1.__await([this._removeNamespaceFromKey(key), resolvedValue]); | ||
} | ||
} | ||
}); | ||
} | ||
has(key) { | ||
return tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
return this._cache.has(this._getKeyName(key)); | ||
}); | ||
} | ||
isExpired(data) { | ||
return isNumber(data.expire) && data.expire <= Date.now(); | ||
} | ||
clearExpire() { | ||
const now = Date.now(); | ||
if (now - this._lastExpire <= this._opts.expiredCheckDelay) { | ||
if (now - this._lastExpire <= this.opts.expiredCheckDelay) { | ||
return; | ||
@@ -145,3 +162,3 @@ } | ||
} | ||
const data = this._opts.encode({ | ||
const data = this.opts.serialize({ | ||
cache, | ||
@@ -151,3 +168,3 @@ lastExpire: this._lastExpire, | ||
return new Promise((resolve, reject) => { | ||
fs.outputFile(this._opts.filename, data, err => { | ||
fs.outputFile(this.opts.filename, data, (err) => { | ||
if (err) { | ||
@@ -169,11 +186,14 @@ reject(err); | ||
setTimeout(() => { | ||
this.saveToDisk().then(() => { | ||
this.saveToDisk().then(resolve, reject).finally(() => { | ||
this._savePromise = void 0; | ||
}).then(resolve, reject); | ||
}, this._opts.writeDelay); | ||
}); | ||
}, this.opts.writeDelay); | ||
}); | ||
return this._savePromise; | ||
} | ||
disconnect() { | ||
return Promise.resolve(); | ||
} | ||
} | ||
exports.KeyvFile = KeyvFile; | ||
exports.default = KeyvFile; |
{ | ||
"name": "keyv-file", | ||
"version": "0.3.3", | ||
"version": "5.0.0", | ||
"description": "File storage adapter for Keyv, using msgpack to serialize data fast and small.", | ||
@@ -10,3 +10,3 @@ "main": "lib/index.js", | ||
"build": "tsc", | ||
"test": "tsc && ava", | ||
"test": "tsc && vitest run", | ||
"preversion": "pnpm test", | ||
@@ -36,17 +36,16 @@ "postversion": "git add -A && git push origin master --tags" | ||
"devDependencies": { | ||
"@keyv/test-suite": "^2.0.1", | ||
"@types/debug": "^0.0.31", | ||
"@types/fs-extra": "^5.0.4", | ||
"@types/node": "^22.2.0", | ||
"ava": "^0.21.0", | ||
"benchmark": "^2.1.4", | ||
"keyv": "^1.0.4", | ||
"keyv-test-suite": "^1.5.0" | ||
"keyv": "^5.0.1", | ||
"typescript": "^5.5.4", | ||
"vitest": "^2.0.5" | ||
}, | ||
"dependencies": { | ||
"debug": "^4.1.1", | ||
"fs-extra": "^4.0.1", | ||
"tslib": "^1.14.1", | ||
"typescript": "^5.5.4" | ||
"tslib": "^1.14.1" | ||
}, | ||
"packageManager": "pnpm@9.6.0+sha512.38dc6fba8dba35b39340b9700112c2fe1e12f10b17134715a4aa98ccf7bb035e76fd981cf0bb384dfa98f8d6af5481c2bef2f4266a24bfa20c34eb7147ce0b5e" | ||
} |
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
11756
2
229
0
8
1
- Removeddebug@^4.1.1
- Removedtypescript@^5.5.4
- Removeddebug@4.3.7(transitive)
- Removedms@2.1.3(transitive)
- Removedtypescript@5.6.3(transitive)