limited-cache 2.3.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +4 -3
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/index.d.cts +1 -8
- package/dist/cjs/index.d.cts.map +1 -1
- package/dist/esm/index.d.ts +1 -8
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/lowLevelFunctions.ts +3 -2
- package/src/types.ts +2 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- Update CJS build settings and raise to ES2022 ([#90](https://github.com/spautz/limited-cache/issues/90)) ([4428c27](https://github.com/spautz/limited-cache/commit/4428c276d5208a50dbcd495bcc7a0fd7aa3047ea))
|
|
8
|
+
- Change default ItemType from `any` to `unknown` ([#90](https://github.com/spautz/limited-cache/issues/90)) ([4428c27](https://github.com/spautz/limited-cache/commit/4428c276d5208a50dbcd495bcc7a0fd7aa3047ea))
|
|
9
|
+
|
|
10
|
+
## 2.3.1
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Revert an accidental type change for process.env ([#88](https://github.com/spautz/limited-cache/issues/88)) ([1a82894](https://github.com/spautz/limited-cache/commit/1a82894b2a4287ea379019a72e7b74328790cf59))
|
|
15
|
+
|
|
3
16
|
## 2.3.0
|
|
4
17
|
|
|
5
18
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
A minimal JS cache. Like using an object to store keys and values, except it won't grow forever
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/limited-cache)
|
|
6
|
-
[](https://github.com/spautz/limited-cache/blob/main/packages/limited-cache/README.md)
|
|
7
|
+
[](https://github.com/spautz/limited-cache/actions)
|
|
7
8
|
[](https://coveralls.io/github/spautz/limited-cache?branch=main)
|
|
8
|
-
[](https://snyk.io/test/github/spautz/limited-cache)
|
|
9
10
|
[](https://bundlephobia.com/package/limited-cache@latest)
|
|
10
11
|
|
|
11
12
|
## Motivation
|
|
@@ -114,7 +115,7 @@ on the higher-level LimitedCache and LimitedCacheObject is available as a low-le
|
|
|
114
115
|
- `lowLevelReset(cacheMeta)`
|
|
115
116
|
- `lowLevelSetOptions(cacheMeta, options)` - you can update options anytime
|
|
116
117
|
|
|
117
|
-
These functions are also grouped together as [limitedCacheUtil](https://github.com/spautz/limited-cache/blob/main/src/core/limitedCacheUtil.ts#
|
|
118
|
+
These functions are also grouped together as [limitedCacheUtil](https://github.com/spautz/limited-cache/blob/main/packages/limited-cache/src/core/limitedCacheUtil.ts#L25-L35) --
|
|
118
119
|
but minimization and tree-shaking will be slightly better if you import each individually.
|
|
119
120
|
|
|
120
121
|
## FAQ
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -134,7 +134,7 @@ const _removeItemsToMakeRoom = (cacheMeta, now) => {
|
|
|
134
134
|
const lowLevelHas = (cacheMeta, cacheKey) => {
|
|
135
135
|
upgradeCacheMeta(cacheMeta);
|
|
136
136
|
const { cache } = cacheMeta;
|
|
137
|
-
if (Object.
|
|
137
|
+
if (Object.hasOwn(cache, cacheKey) && cache[cacheKey] !== void 0) {
|
|
138
138
|
if (!_cacheKeyHasExpired(cacheMeta, cacheKey, Date.now())) return true;
|
|
139
139
|
cache[cacheKey] = void 0;
|
|
140
140
|
}
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
//#region src/types.d.ts
|
|
2
|
-
|
|
3
|
-
namespace NodeJS {
|
|
4
|
-
interface ProcessEnv {
|
|
5
|
-
NODE_ENV?: "development" | "production" | "test";
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
type DefaultItemType = any;
|
|
2
|
+
type DefaultItemType = unknown;
|
|
10
3
|
interface LimitedCacheOptionsFull {
|
|
11
4
|
/** Items will be removed to keep the cache within the maxCacheSize limit */
|
|
12
5
|
maxCacheSize: number;
|
package/dist/cjs/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/types.ts","../../src/core/defaultOptions.ts","../../src/core/LimitedCache.ts","../../src/core/LimitedCacheObject.ts","../../src/core/lowLevelFunctions.ts","../../src/core/limitedCacheUtil.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/types.ts","../../src/core/defaultOptions.ts","../../src/core/LimitedCache.ts","../../src/core/LimitedCacheObject.ts","../../src/core/lowLevelFunctions.ts","../../src/core/limitedCacheUtil.ts"],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
//#region src/types.d.ts
|
|
2
|
-
|
|
3
|
-
namespace NodeJS {
|
|
4
|
-
interface ProcessEnv {
|
|
5
|
-
NODE_ENV?: "development" | "production" | "test";
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
type DefaultItemType = any;
|
|
2
|
+
type DefaultItemType = unknown;
|
|
10
3
|
interface LimitedCacheOptionsFull {
|
|
11
4
|
/** Items will be removed to keep the cache within the maxCacheSize limit */
|
|
12
5
|
maxCacheSize: number;
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/types.ts","../../src/core/defaultOptions.ts","../../src/core/LimitedCache.ts","../../src/core/LimitedCacheObject.ts","../../src/core/lowLevelFunctions.ts","../../src/core/limitedCacheUtil.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/types.ts","../../src/core/defaultOptions.ts","../../src/core/LimitedCache.ts","../../src/core/LimitedCacheObject.ts","../../src/core/lowLevelFunctions.ts","../../src/core/limitedCacheUtil.ts"],"mappings":"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"}
|
package/dist/esm/index.js
CHANGED
|
@@ -133,7 +133,7 @@ const _removeItemsToMakeRoom = (cacheMeta, now) => {
|
|
|
133
133
|
const lowLevelHas = (cacheMeta, cacheKey) => {
|
|
134
134
|
upgradeCacheMeta(cacheMeta);
|
|
135
135
|
const { cache } = cacheMeta;
|
|
136
|
-
if (Object.
|
|
136
|
+
if (Object.hasOwn(cache, cacheKey) && cache[cacheKey] !== void 0) {
|
|
137
137
|
if (!_cacheKeyHasExpired(cacheMeta, cacheKey, Date.now())) return true;
|
|
138
138
|
cache[cacheKey] = void 0;
|
|
139
139
|
}
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/core/defaultOptions.ts","../../src/core/lowLevelFunctions.ts","../../src/core/LimitedCache.ts","../../src/core/LimitedCacheObject.ts","../../src/core/limitedCacheUtil.ts"],"sourcesContent":["import type { LimitedCacheOptionsReadonly } from '../types.js';\n\nconst CURRENT_META_VERSION = 2 as const;\n// Default = 1 year\nconst MAXIMUM_CACHE_TIME: number = 365 * 86400 * 1000;\n\nconst defaultOptions: LimitedCacheOptionsReadonly = {\n // Public\n maxCacheSize: 100,\n maxCacheTime: 86400 * 1000,\n // Development-only\n warnIfItemPurgedBeforeTime: 5000,\n // Private\n opLimit: 200,\n scanLimit: 50,\n};\n\nexport { CURRENT_META_VERSION, defaultOptions, MAXIMUM_CACHE_TIME };\n","import type {\n DefaultItemType,\n LimitedCacheMeta,\n LimitedCacheOptions,\n LimitedCacheOptionsFull,\n LimitedCacheOptionsReadonly,\n} from '../types.js';\nimport { CURRENT_META_VERSION, defaultOptions, MAXIMUM_CACHE_TIME } from './defaultOptions.js';\n\n/* Initialization and options */\n\nconst positiveNumberOrZero = (value: number): number => Math.max(value, 0) || 0;\n\nconst normalizeOptions = (cacheMetaOptions: LimitedCacheOptionsFull): LimitedCacheOptionsFull => {\n Object.assign(cacheMetaOptions, {\n maxCacheSize: positiveNumberOrZero(cacheMetaOptions.maxCacheSize),\n maxCacheTime: positiveNumberOrZero(cacheMetaOptions.maxCacheTime),\n opLimit: positiveNumberOrZero(cacheMetaOptions.opLimit),\n });\n\n if (process.env.NODE_ENV !== 'production') {\n cacheMetaOptions.warnIfItemPurgedBeforeTime = positiveNumberOrZero(\n cacheMetaOptions.warnIfItemPurgedBeforeTime,\n );\n }\n return cacheMetaOptions;\n};\n\nconst isCacheMeta = (cacheMeta: unknown): cacheMeta is LimitedCacheMeta => {\n // @ts-expect-error Duck-typing the unknown value\n return !!cacheMeta?.limitedCacheMetaVersion;\n};\n\nconst upgradeCacheMeta = (cacheMeta: LimitedCacheMeta): void => {\n if (!isCacheMeta(cacheMeta)) {\n throw new Error('Limited-cache metadata is missing: please check your usage');\n }\n if (cacheMeta.limitedCacheMetaVersion !== CURRENT_META_VERSION) {\n // Version is out of date! (Today the only prior version is 1)\n // Version 1: Cache meta cannot be migrated because timestamps and keys are incompatible\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn('Limited-cache metadata is from an incompatible version (1). It must be reset.');\n cacheMeta.limitedCacheMetaVersion = CURRENT_META_VERSION;\n lowLevelReset(cacheMeta);\n }\n};\n\nconst lowLevelSetOptions = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n options: LimitedCacheOptions,\n): LimitedCacheOptionsReadonly => {\n upgradeCacheMeta(cacheMeta);\n return normalizeOptions(Object.assign(cacheMeta.options, options));\n};\n\nconst lowLevelInit = <ItemType = DefaultItemType>(\n optionsOrCacheMeta?: LimitedCacheOptions | LimitedCacheMeta<ItemType>,\n): LimitedCacheMeta<ItemType> => {\n if (isCacheMeta(optionsOrCacheMeta)) {\n const existingCacheMeta = optionsOrCacheMeta;\n upgradeCacheMeta(existingCacheMeta);\n return existingCacheMeta;\n }\n // Else: it's options\n const fullOptions = normalizeOptions({\n ...defaultOptions,\n ...optionsOrCacheMeta,\n });\n\n // The cacheMeta is created once, and persists per instance\n const newCacheMeta = lowLevelReset({\n limitedCacheMetaVersion: CURRENT_META_VERSION,\n options: fullOptions,\n } as LimitedCacheMeta<ItemType>);\n\n return newCacheMeta;\n};\n\n/* Internal cache manipulation */\n\nconst _getExpireTime = (cacheMeta: LimitedCacheMeta, cacheKey: string): number => {\n const {\n options: { maxCacheTime },\n keyInfo: { [cacheKey]: keyInfo },\n } = cacheMeta;\n if (!keyInfo) {\n // A missing record is always treated as expired\n return 0;\n }\n // If we have an exact expireTime then honor it. Otherwise it'll depend on the current maxCacheTime.\n const [setTime, expireTime] = keyInfo;\n return expireTime || setTime + (maxCacheTime || MAXIMUM_CACHE_TIME);\n};\n\nconst _cacheKeyHasExpired = (\n cacheMeta: LimitedCacheMeta,\n cacheKey: string,\n now: number,\n): boolean => {\n return _getExpireTime(cacheMeta, cacheKey) < now;\n};\n\nconst lowLevelDoMaintenance = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n): LimitedCacheMeta<ItemType> => {\n upgradeCacheMeta(cacheMeta);\n const { cache, keyList, keyInfo } = cacheMeta;\n const now = Date.now();\n\n // Rebuild cache from keyList only, checking timestamps to auto-remove expired\n const [newCache, newKeyList, newKeyInfo] = keyList.reduce(\n (acc, cacheKey) => {\n const [accCache, accKeyList, accKeyInfo] = acc;\n if (!_cacheKeyHasExpired(cacheMeta, cacheKey, now)) {\n accCache[cacheKey] = cache[cacheKey];\n accKeyList.push(cacheKey);\n accKeyInfo[cacheKey] = keyInfo[cacheKey];\n }\n return acc;\n },\n [\n // This manual assertion is required because TypeScript doesn't know that the initial value is of the same type as the accumulator.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n {} as (typeof cacheMeta)['cache'],\n [] as (typeof cacheMeta)['keyList'],\n Object.create(null) as (typeof cacheMeta)['keyInfo'],\n ],\n );\n\n return Object.assign(cacheMeta, {\n cache: newCache,\n keyList: newKeyList,\n keyInfo: newKeyInfo,\n opsLeft: cacheMeta.options.opLimit,\n });\n};\n\nconst _removeFromIndex = (cacheMeta: LimitedCacheMeta, startIndex: number, now: number): void => {\n const { cache, keyList, keyInfo } = cacheMeta;\n\n // Always remove the item requested, and also remove any neighbors who have expired\n let nextIndex = startIndex;\n let nextCacheKey = keyList[startIndex] as string;\n const keyListLength = keyList.length;\n do {\n // Remove the 'next' item\n\n cache[nextCacheKey] = keyInfo[nextCacheKey] = undefined;\n\n // Now advance and decide whether to keep going\n nextIndex++;\n nextCacheKey = keyList[nextIndex] as string;\n } while (nextIndex < keyListLength && _cacheKeyHasExpired(cacheMeta, nextCacheKey, now));\n\n // Remove the index for everything from the startIndex until we stopped\n keyList.splice(startIndex, nextIndex - startIndex);\n};\n\nconst _removeItemsToMakeRoom = (cacheMeta: LimitedCacheMeta, now: number): void => {\n const {\n options: { scanLimit, warnIfItemPurgedBeforeTime },\n cache,\n keyList,\n keyInfo,\n } = cacheMeta;\n\n // These track the soonest-to-expire thing we've found. It may not actually be \"oldest\".\n // By default we'll remove the item at the head of the queue, unless we find something better.\n let oldestItemIndex = 0;\n let oldestExpireTime = _getExpireTime(cacheMeta, keyList[0] as string);\n\n if (oldestExpireTime > now) {\n // The head of the list hasn't yet expired: scan for a better candidate to remove\n let indexToCheck = 0;\n const maxIndexToCheck = Math.min(keyList.length, scanLimit);\n while (indexToCheck < maxIndexToCheck) {\n const cacheKeyForIndex = keyList[indexToCheck] as string;\n const expireTimeForIndex = _getExpireTime(cacheMeta, cacheKeyForIndex);\n\n // We only consider it if it's eligible for expiration: otherwise it can't be a better option\n // than the default head-of-queue\n if (expireTimeForIndex < now) {\n // We found an expired item! This wins automatically\n oldestItemIndex = indexToCheck;\n oldestExpireTime = 0;\n break;\n }\n if (expireTimeForIndex < oldestExpireTime) {\n // We have a new leader\n oldestItemIndex = indexToCheck;\n oldestExpireTime = expireTimeForIndex;\n }\n indexToCheck += 1;\n }\n }\n\n // Warn if the 'oldest' item is more recent than we'd like: this means it cycled into and out of\n // cache too quickly for the cache to be useful.\n if (\n process.env.NODE_ENV !== 'production' &&\n warnIfItemPurgedBeforeTime &&\n oldestExpireTime > now\n ) {\n const oldestItemKey = keyList[oldestItemIndex] as string;\n const [oldestItemSetTime, oldestItemExpireTime] = keyInfo[oldestItemKey] as [number, number];\n\n if (now - oldestItemSetTime < warnIfItemPurgedBeforeTime) {\n // biome-ignore lint/suspicious/noConsole: Dev-only code\n console.warn(\n 'Purged an item from cache while it was still fresh: you may want to increase maxCacheSize',\n {\n currentTime: now,\n key: oldestItemKey,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n item: cache[oldestItemKey],\n setTime: oldestItemSetTime,\n expireTime: oldestItemExpireTime,\n timeInCache: now - oldestItemSetTime,\n },\n );\n }\n }\n\n // Remove the oldest item we found, plus any expired neighbors\n _removeFromIndex(cacheMeta, oldestItemIndex, now);\n};\n\n/* Accessors */\n\nconst lowLevelHas = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n cacheKey: string,\n): boolean => {\n upgradeCacheMeta(cacheMeta);\n const { cache } = cacheMeta;\n // biome-ignore lint/suspicious/noPrototypeBuiltins: Keeping the legacy hasOwnProperty to avoid a breaking change\n if (Object.prototype.hasOwnProperty.call(cache, cacheKey) && cache[cacheKey] !== undefined) {\n if (!_cacheKeyHasExpired(cacheMeta, cacheKey, Date.now())) {\n return true;\n }\n // If it's expired, clear the value so that we can short-circuit future lookups\n cache[cacheKey] = undefined;\n }\n return false;\n};\n\nconst lowLevelGetOne = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n cacheKey: string,\n): ItemType | undefined => {\n upgradeCacheMeta(cacheMeta);\n if (lowLevelHas(cacheMeta, cacheKey)) {\n return cacheMeta.cache[cacheKey];\n }\n return;\n};\n\nconst lowLevelGetAll = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n): Record<string, ItemType> => {\n upgradeCacheMeta(cacheMeta);\n // Remove all expired values, and return whatever's left\n lowLevelDoMaintenance(cacheMeta);\n // Retype because there won't be any `undefined` values after doMaintenance\n return cacheMeta.cache as Record<string, ItemType>;\n};\n\nconst lowLevelSet = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n cacheKey: string,\n item: ItemType,\n): LimitedCacheMeta<ItemType> => {\n upgradeCacheMeta(cacheMeta);\n\n const {\n options: { maxCacheSize },\n keyList,\n keyInfo,\n } = cacheMeta;\n\n const now = Date.now();\n const isNew = !keyInfo[cacheKey];\n\n if (cacheMeta.cache[cacheKey] !== item) {\n // The cache itself is immutable (but the rest of cacheMeta is not)\n cacheMeta.cache = {\n ...cacheMeta.cache,\n [cacheKey]: item,\n };\n }\n // We've now set or updated it. Regardless of whether it's new, bump its set time\n // @TODO: expireTime override\n keyInfo[cacheKey] = [now, 0];\n\n if (isNew) {\n // It's a new key: grow the cache, then shrink it if we can\n keyList.push(cacheKey);\n\n cacheMeta.opsLeft--;\n if (cacheMeta.opsLeft <= 0) {\n // Time for an oil change\n lowLevelDoMaintenance(cacheMeta);\n }\n\n if (maxCacheSize && cacheMeta.keyList.length > maxCacheSize) {\n // We're still over the limit: drop at least one item\n _removeItemsToMakeRoom(cacheMeta, now);\n }\n }\n\n if (_cacheKeyHasExpired(cacheMeta, keyList[0] as string, now)) {\n // While we're here, if we need to expire the head of the queue then drop it\n _removeFromIndex(cacheMeta, 0, now);\n }\n\n return cacheMeta;\n};\n\nconst lowLevelRemove = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n cacheKey: string,\n): LimitedCacheMeta<ItemType> => {\n upgradeCacheMeta(cacheMeta);\n const { cache, keyInfo } = cacheMeta;\n\n if (keyInfo[cacheKey]) {\n if (cache[cacheKey] !== undefined) {\n cacheMeta.cache = {\n ...cache,\n [cacheKey]: undefined,\n };\n }\n keyInfo[cacheKey] = undefined;\n }\n\n return cacheMeta;\n};\n\nconst lowLevelReset = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n): LimitedCacheMeta<ItemType> => {\n upgradeCacheMeta(cacheMeta);\n return Object.assign(cacheMeta, {\n cache: {},\n keyList: [],\n keyInfo: Object.create(null) as Record<string, ItemType>,\n opsLeft: cacheMeta.options.opLimit,\n });\n};\n\nexport {\n isCacheMeta,\n lowLevelDoMaintenance,\n lowLevelGetAll,\n lowLevelGetOne,\n lowLevelHas,\n lowLevelInit,\n lowLevelRemove,\n lowLevelReset,\n lowLevelSet,\n lowLevelSetOptions,\n upgradeCacheMeta,\n};\n","import type {\n DefaultItemType,\n LimitedCacheInstance,\n LimitedCacheMeta,\n LimitedCacheOptions,\n LimitedCacheOptionsReadonly,\n} from '../types.js';\nimport {\n lowLevelDoMaintenance,\n lowLevelGetAll,\n lowLevelGetOne,\n lowLevelHas,\n lowLevelInit,\n lowLevelRemove,\n lowLevelReset,\n lowLevelSet,\n lowLevelSetOptions,\n} from './lowLevelFunctions.js';\n\n// Most public functions just call a low-level function directly, passing the cacheMeta.\n// Doing this via a helper function makes the typeChecks easier, and minifies better.\nconst bindFunctionToCacheMeta = <ItemType, OtherArgs extends unknown[], ReturnValue>(\n fn: (cacheMeta: LimitedCacheMeta<ItemType>, ...otherArgs: OtherArgs) => ReturnValue,\n cacheMeta: LimitedCacheMeta<ItemType>,\n): ((...otherArgs: OtherArgs) => ReturnValue) => fn.bind(null, cacheMeta);\n\nconst LimitedCache = <ItemType = DefaultItemType>(\n options?: LimitedCacheOptions,\n): LimitedCacheInstance<ItemType> => {\n const cacheMeta = lowLevelInit<ItemType>(options);\n\n return {\n get: bindFunctionToCacheMeta(lowLevelGetOne, cacheMeta),\n getAll: bindFunctionToCacheMeta(lowLevelGetAll, cacheMeta),\n has: bindFunctionToCacheMeta(lowLevelHas, cacheMeta),\n set: (cacheKey, item): ItemType => {\n lowLevelSet(cacheMeta, cacheKey, item);\n return item;\n },\n remove: (cacheKey): true => {\n lowLevelRemove(cacheMeta, cacheKey);\n return true;\n },\n reset: bindFunctionToCacheMeta(lowLevelReset, cacheMeta),\n getCacheMeta: (): LimitedCacheMeta<ItemType> => cacheMeta,\n getOptions: (): LimitedCacheOptionsReadonly => cacheMeta.options,\n setOptions: bindFunctionToCacheMeta(lowLevelSetOptions, cacheMeta),\n doMaintenance: bindFunctionToCacheMeta(lowLevelDoMaintenance, cacheMeta),\n };\n};\n\nexport { LimitedCache };\n","import type {\n DefaultItemType,\n LimitedCacheMeta,\n LimitedCacheObjectInstance,\n LimitedCacheOptions,\n} from '../types.js';\nimport {\n lowLevelGetAll,\n lowLevelGetOne,\n lowLevelHas,\n lowLevelInit,\n lowLevelRemove,\n lowLevelSet,\n} from './lowLevelFunctions.js';\n\nconst proxyHandler: ProxyHandler<LimitedCacheMeta> = {\n get: (cacheMeta: LimitedCacheMeta, cacheKey: string) => {\n if (cacheKey === 'hasOwnProperty') {\n return Object.prototype.hasOwnProperty;\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return lowLevelGetOne(cacheMeta, cacheKey);\n },\n getOwnPropertyDescriptor: (cacheMeta: LimitedCacheMeta, cacheKey: string) => {\n const hasResult = lowLevelHas(cacheMeta, cacheKey);\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const getResult = lowLevelGetOne(cacheMeta, cacheKey);\n\n if (hasResult) {\n return {\n configurable: true,\n enumerable: hasResult,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n value: getResult,\n writable: true,\n };\n }\n return;\n },\n has: lowLevelHas,\n set: <T>(cacheMeta: LimitedCacheMeta, cacheKey: string, item: T): T => {\n lowLevelSet(cacheMeta, cacheKey, item);\n return item;\n },\n deleteProperty: (cacheMeta: LimitedCacheMeta, cacheKey: string): true => {\n lowLevelRemove(cacheMeta, cacheKey);\n return true;\n },\n ownKeys: (cacheMeta: LimitedCacheMeta) => Object.keys(lowLevelGetAll(cacheMeta)),\n};\n\n/**\n * TypeScript's Proxy type models the runtime target, but LimitedCacheObject intentionally returns\n * a facade with a different surface from the internal cache metadata target.\n */\nconst internal_createLimitedCacheObjectProxy = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n): LimitedCacheObjectInstance<ItemType> => {\n return new Proxy(cacheMeta, proxyHandler) as unknown as LimitedCacheObjectInstance<ItemType>;\n};\n\n/**\n * So that we can retrieve the cacheMeta for a LimitedCacheObject, without polluting its properties, each proxy\n * is associated back to its internal cacheMeta here.\n */\nconst cacheMetasForProxies = new WeakMap();\n\nconst LimitedCacheObject = <ItemType = DefaultItemType>(\n options?: LimitedCacheOptions,\n): LimitedCacheObjectInstance<ItemType> => {\n const cacheMeta = lowLevelInit<ItemType>(options);\n const limitedCacheObject = internal_createLimitedCacheObjectProxy(cacheMeta);\n\n cacheMetasForProxies.set(limitedCacheObject, cacheMeta);\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return limitedCacheObject;\n};\n\nconst getCacheMetaFromObject = (instance: LimitedCacheObjectInstance): LimitedCacheMeta => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return cacheMetasForProxies.get(instance);\n};\n\nexport { getCacheMetaFromObject, LimitedCacheObject };\n","import {\n lowLevelDoMaintenance,\n lowLevelGetAll,\n lowLevelGetOne,\n lowLevelHas,\n lowLevelInit,\n lowLevelRemove,\n lowLevelReset,\n lowLevelSet,\n lowLevelSetOptions,\n} from './lowLevelFunctions.js';\n\ntype LimitedCacheUtil = {\n init: typeof lowLevelInit;\n get: typeof lowLevelGetOne;\n getAll: typeof lowLevelGetAll;\n has: typeof lowLevelHas;\n set: typeof lowLevelSet;\n remove: typeof lowLevelRemove;\n reset: typeof lowLevelReset;\n doMaintenance: typeof lowLevelDoMaintenance;\n setOptions: typeof lowLevelSetOptions;\n};\n\nconst limitedCacheUtil: LimitedCacheUtil = {\n init: lowLevelInit,\n get: lowLevelGetOne,\n getAll: lowLevelGetAll,\n has: lowLevelHas,\n set: lowLevelSet,\n remove: lowLevelRemove,\n reset: lowLevelReset,\n doMaintenance: lowLevelDoMaintenance,\n setOptions: lowLevelSetOptions,\n};\n\nexport { limitedCacheUtil };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/core/defaultOptions.ts","../../src/core/lowLevelFunctions.ts","../../src/core/LimitedCache.ts","../../src/core/LimitedCacheObject.ts","../../src/core/limitedCacheUtil.ts"],"sourcesContent":["import type { LimitedCacheOptionsReadonly } from '../types.js';\n\nconst CURRENT_META_VERSION = 2 as const;\n// Default = 1 year\nconst MAXIMUM_CACHE_TIME: number = 365 * 86400 * 1000;\n\nconst defaultOptions: LimitedCacheOptionsReadonly = {\n // Public\n maxCacheSize: 100,\n maxCacheTime: 86400 * 1000,\n // Development-only\n warnIfItemPurgedBeforeTime: 5000,\n // Private\n opLimit: 200,\n scanLimit: 50,\n};\n\nexport { CURRENT_META_VERSION, defaultOptions, MAXIMUM_CACHE_TIME };\n","import type {\n DefaultItemType,\n LimitedCacheMeta,\n LimitedCacheOptions,\n LimitedCacheOptionsFull,\n LimitedCacheOptionsReadonly,\n} from '../types.js';\nimport { CURRENT_META_VERSION, defaultOptions, MAXIMUM_CACHE_TIME } from './defaultOptions.js';\n\n/* Initialization and options */\n\nconst positiveNumberOrZero = (value: number): number => Math.max(value, 0) || 0;\n\nconst normalizeOptions = (cacheMetaOptions: LimitedCacheOptionsFull): LimitedCacheOptionsFull => {\n Object.assign(cacheMetaOptions, {\n maxCacheSize: positiveNumberOrZero(cacheMetaOptions.maxCacheSize),\n maxCacheTime: positiveNumberOrZero(cacheMetaOptions.maxCacheTime),\n opLimit: positiveNumberOrZero(cacheMetaOptions.opLimit),\n });\n\n // @ts-expect-error `process.env.NODE_ENV` left intact and not added to global typings\n if (process.env.NODE_ENV !== 'production') {\n cacheMetaOptions.warnIfItemPurgedBeforeTime = positiveNumberOrZero(\n cacheMetaOptions.warnIfItemPurgedBeforeTime,\n );\n }\n return cacheMetaOptions;\n};\n\nconst isCacheMeta = (cacheMeta: unknown): cacheMeta is LimitedCacheMeta => {\n // @ts-expect-error Duck-typing the unknown value\n return !!cacheMeta?.limitedCacheMetaVersion;\n};\n\nconst upgradeCacheMeta = (cacheMeta: LimitedCacheMeta): void => {\n if (!isCacheMeta(cacheMeta)) {\n throw new Error('Limited-cache metadata is missing: please check your usage');\n }\n if (cacheMeta.limitedCacheMetaVersion !== CURRENT_META_VERSION) {\n // Version is out of date! (Today the only prior version is 1)\n // Version 1: Cache meta cannot be migrated because timestamps and keys are incompatible\n // biome-ignore lint/suspicious/noConsole: Intentional warning\n console.warn('Limited-cache metadata is from an incompatible version (1). It must be reset.');\n cacheMeta.limitedCacheMetaVersion = CURRENT_META_VERSION;\n lowLevelReset(cacheMeta);\n }\n};\n\nconst lowLevelSetOptions = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n options: LimitedCacheOptions,\n): LimitedCacheOptionsReadonly => {\n upgradeCacheMeta(cacheMeta);\n return normalizeOptions(Object.assign(cacheMeta.options, options));\n};\n\nconst lowLevelInit = <ItemType = DefaultItemType>(\n optionsOrCacheMeta?: LimitedCacheOptions | LimitedCacheMeta<ItemType>,\n): LimitedCacheMeta<ItemType> => {\n if (isCacheMeta(optionsOrCacheMeta)) {\n const existingCacheMeta = optionsOrCacheMeta;\n upgradeCacheMeta(existingCacheMeta);\n return existingCacheMeta;\n }\n // Else: it's options\n const fullOptions = normalizeOptions({\n ...defaultOptions,\n ...optionsOrCacheMeta,\n });\n\n // The cacheMeta is created once, and persists per instance\n const newCacheMeta = lowLevelReset({\n limitedCacheMetaVersion: CURRENT_META_VERSION,\n options: fullOptions,\n } as LimitedCacheMeta<ItemType>);\n\n return newCacheMeta;\n};\n\n/* Internal cache manipulation */\n\nconst _getExpireTime = (cacheMeta: LimitedCacheMeta, cacheKey: string): number => {\n const {\n options: { maxCacheTime },\n keyInfo: { [cacheKey]: keyInfo },\n } = cacheMeta;\n if (!keyInfo) {\n // A missing record is always treated as expired\n return 0;\n }\n // If we have an exact expireTime then honor it. Otherwise it'll depend on the current maxCacheTime.\n const [setTime, expireTime] = keyInfo;\n return expireTime || setTime + (maxCacheTime || MAXIMUM_CACHE_TIME);\n};\n\nconst _cacheKeyHasExpired = (\n cacheMeta: LimitedCacheMeta,\n cacheKey: string,\n now: number,\n): boolean => {\n return _getExpireTime(cacheMeta, cacheKey) < now;\n};\n\nconst lowLevelDoMaintenance = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n): LimitedCacheMeta<ItemType> => {\n upgradeCacheMeta(cacheMeta);\n const { cache, keyList, keyInfo } = cacheMeta;\n const now = Date.now();\n\n // Rebuild cache from keyList only, checking timestamps to auto-remove expired\n const [newCache, newKeyList, newKeyInfo] = keyList.reduce(\n (acc, cacheKey) => {\n const [accCache, accKeyList, accKeyInfo] = acc;\n if (!_cacheKeyHasExpired(cacheMeta, cacheKey, now)) {\n accCache[cacheKey] = cache[cacheKey];\n accKeyList.push(cacheKey);\n accKeyInfo[cacheKey] = keyInfo[cacheKey];\n }\n return acc;\n },\n [\n // This manual assertion is required because TypeScript doesn't know that the initial value is of the same type as the accumulator.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n {} as (typeof cacheMeta)['cache'],\n [] as (typeof cacheMeta)['keyList'],\n Object.create(null) as (typeof cacheMeta)['keyInfo'],\n ],\n );\n\n return Object.assign(cacheMeta, {\n cache: newCache,\n keyList: newKeyList,\n keyInfo: newKeyInfo,\n opsLeft: cacheMeta.options.opLimit,\n });\n};\n\nconst _removeFromIndex = (cacheMeta: LimitedCacheMeta, startIndex: number, now: number): void => {\n const { cache, keyList, keyInfo } = cacheMeta;\n\n // Always remove the item requested, and also remove any neighbors who have expired\n let nextIndex = startIndex;\n let nextCacheKey = keyList[startIndex] as string;\n const keyListLength = keyList.length;\n do {\n // Remove the 'next' item\n\n cache[nextCacheKey] = keyInfo[nextCacheKey] = undefined;\n\n // Now advance and decide whether to keep going\n nextIndex++;\n nextCacheKey = keyList[nextIndex] as string;\n } while (nextIndex < keyListLength && _cacheKeyHasExpired(cacheMeta, nextCacheKey, now));\n\n // Remove the index for everything from the startIndex until we stopped\n keyList.splice(startIndex, nextIndex - startIndex);\n};\n\nconst _removeItemsToMakeRoom = (cacheMeta: LimitedCacheMeta, now: number): void => {\n const {\n options: { scanLimit, warnIfItemPurgedBeforeTime },\n cache,\n keyList,\n keyInfo,\n } = cacheMeta;\n\n // These track the soonest-to-expire thing we've found. It may not actually be \"oldest\".\n // By default we'll remove the item at the head of the queue, unless we find something better.\n let oldestItemIndex = 0;\n let oldestExpireTime = _getExpireTime(cacheMeta, keyList[0] as string);\n\n if (oldestExpireTime > now) {\n // The head of the list hasn't yet expired: scan for a better candidate to remove\n let indexToCheck = 0;\n const maxIndexToCheck = Math.min(keyList.length, scanLimit);\n while (indexToCheck < maxIndexToCheck) {\n const cacheKeyForIndex = keyList[indexToCheck] as string;\n const expireTimeForIndex = _getExpireTime(cacheMeta, cacheKeyForIndex);\n\n // We only consider it if it's eligible for expiration: otherwise it can't be a better option\n // than the default head-of-queue\n if (expireTimeForIndex < now) {\n // We found an expired item! This wins automatically\n oldestItemIndex = indexToCheck;\n oldestExpireTime = 0;\n break;\n }\n if (expireTimeForIndex < oldestExpireTime) {\n // We have a new leader\n oldestItemIndex = indexToCheck;\n oldestExpireTime = expireTimeForIndex;\n }\n indexToCheck += 1;\n }\n }\n\n // Warn if the 'oldest' item is more recent than we'd like: this means it cycled into and out of\n // cache too quickly for the cache to be useful.\n if (\n // @ts-expect-error `process.env.NODE_ENV` left intact and not added to global typings\n process.env.NODE_ENV !== 'production' &&\n warnIfItemPurgedBeforeTime &&\n oldestExpireTime > now\n ) {\n const oldestItemKey = keyList[oldestItemIndex] as string;\n const [oldestItemSetTime, oldestItemExpireTime] = keyInfo[oldestItemKey] as [number, number];\n\n if (now - oldestItemSetTime < warnIfItemPurgedBeforeTime) {\n // biome-ignore lint/suspicious/noConsole: Dev-only code\n console.warn(\n 'Purged an item from cache while it was still fresh: you may want to increase maxCacheSize',\n {\n currentTime: now,\n key: oldestItemKey,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n item: cache[oldestItemKey],\n setTime: oldestItemSetTime,\n expireTime: oldestItemExpireTime,\n timeInCache: now - oldestItemSetTime,\n },\n );\n }\n }\n\n // Remove the oldest item we found, plus any expired neighbors\n _removeFromIndex(cacheMeta, oldestItemIndex, now);\n};\n\n/* Accessors */\n\nconst lowLevelHas = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n cacheKey: string,\n): boolean => {\n upgradeCacheMeta(cacheMeta);\n const { cache } = cacheMeta;\n if (Object.hasOwn(cache, cacheKey) && cache[cacheKey] !== undefined) {\n if (!_cacheKeyHasExpired(cacheMeta, cacheKey, Date.now())) {\n return true;\n }\n // If it's expired, clear the value so that we can short-circuit future lookups\n cache[cacheKey] = undefined;\n }\n return false;\n};\n\nconst lowLevelGetOne = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n cacheKey: string,\n): ItemType | undefined => {\n upgradeCacheMeta(cacheMeta);\n if (lowLevelHas(cacheMeta, cacheKey)) {\n return cacheMeta.cache[cacheKey];\n }\n return;\n};\n\nconst lowLevelGetAll = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n): Record<string, ItemType> => {\n upgradeCacheMeta(cacheMeta);\n // Remove all expired values, and return whatever's left\n lowLevelDoMaintenance(cacheMeta);\n // Retype because there won't be any `undefined` values after doMaintenance\n return cacheMeta.cache as Record<string, ItemType>;\n};\n\nconst lowLevelSet = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n cacheKey: string,\n item: ItemType,\n): LimitedCacheMeta<ItemType> => {\n upgradeCacheMeta(cacheMeta);\n\n const {\n options: { maxCacheSize },\n keyList,\n keyInfo,\n } = cacheMeta;\n\n const now = Date.now();\n const isNew = !keyInfo[cacheKey];\n\n if (cacheMeta.cache[cacheKey] !== item) {\n // The cache itself is immutable (but the rest of cacheMeta is not)\n cacheMeta.cache = {\n ...cacheMeta.cache,\n [cacheKey]: item,\n };\n }\n // We've now set or updated it. Regardless of whether it's new, bump its set time\n // @TODO: expireTime override\n keyInfo[cacheKey] = [now, 0];\n\n if (isNew) {\n // It's a new key: grow the cache, then shrink it if we can\n keyList.push(cacheKey);\n\n cacheMeta.opsLeft--;\n if (cacheMeta.opsLeft <= 0) {\n // Time for an oil change\n lowLevelDoMaintenance(cacheMeta);\n }\n\n if (maxCacheSize && cacheMeta.keyList.length > maxCacheSize) {\n // We're still over the limit: drop at least one item\n _removeItemsToMakeRoom(cacheMeta, now);\n }\n }\n\n if (_cacheKeyHasExpired(cacheMeta, keyList[0] as string, now)) {\n // While we're here, if we need to expire the head of the queue then drop it\n _removeFromIndex(cacheMeta, 0, now);\n }\n\n return cacheMeta;\n};\n\nconst lowLevelRemove = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n cacheKey: string,\n): LimitedCacheMeta<ItemType> => {\n upgradeCacheMeta(cacheMeta);\n const { cache, keyInfo } = cacheMeta;\n\n if (keyInfo[cacheKey]) {\n if (cache[cacheKey] !== undefined) {\n cacheMeta.cache = {\n ...cache,\n [cacheKey]: undefined,\n };\n }\n keyInfo[cacheKey] = undefined;\n }\n\n return cacheMeta;\n};\n\nconst lowLevelReset = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n): LimitedCacheMeta<ItemType> => {\n upgradeCacheMeta(cacheMeta);\n return Object.assign(cacheMeta, {\n cache: {},\n keyList: [],\n keyInfo: Object.create(null) as Record<string, ItemType>,\n opsLeft: cacheMeta.options.opLimit,\n });\n};\n\nexport {\n isCacheMeta,\n lowLevelDoMaintenance,\n lowLevelGetAll,\n lowLevelGetOne,\n lowLevelHas,\n lowLevelInit,\n lowLevelRemove,\n lowLevelReset,\n lowLevelSet,\n lowLevelSetOptions,\n upgradeCacheMeta,\n};\n","import type {\n DefaultItemType,\n LimitedCacheInstance,\n LimitedCacheMeta,\n LimitedCacheOptions,\n LimitedCacheOptionsReadonly,\n} from '../types.js';\nimport {\n lowLevelDoMaintenance,\n lowLevelGetAll,\n lowLevelGetOne,\n lowLevelHas,\n lowLevelInit,\n lowLevelRemove,\n lowLevelReset,\n lowLevelSet,\n lowLevelSetOptions,\n} from './lowLevelFunctions.js';\n\n// Most public functions just call a low-level function directly, passing the cacheMeta.\n// Doing this via a helper function makes the typeChecks easier, and minifies better.\nconst bindFunctionToCacheMeta = <ItemType, OtherArgs extends unknown[], ReturnValue>(\n fn: (cacheMeta: LimitedCacheMeta<ItemType>, ...otherArgs: OtherArgs) => ReturnValue,\n cacheMeta: LimitedCacheMeta<ItemType>,\n): ((...otherArgs: OtherArgs) => ReturnValue) => fn.bind(null, cacheMeta);\n\nconst LimitedCache = <ItemType = DefaultItemType>(\n options?: LimitedCacheOptions,\n): LimitedCacheInstance<ItemType> => {\n const cacheMeta = lowLevelInit<ItemType>(options);\n\n return {\n get: bindFunctionToCacheMeta(lowLevelGetOne, cacheMeta),\n getAll: bindFunctionToCacheMeta(lowLevelGetAll, cacheMeta),\n has: bindFunctionToCacheMeta(lowLevelHas, cacheMeta),\n set: (cacheKey, item): ItemType => {\n lowLevelSet(cacheMeta, cacheKey, item);\n return item;\n },\n remove: (cacheKey): true => {\n lowLevelRemove(cacheMeta, cacheKey);\n return true;\n },\n reset: bindFunctionToCacheMeta(lowLevelReset, cacheMeta),\n getCacheMeta: (): LimitedCacheMeta<ItemType> => cacheMeta,\n getOptions: (): LimitedCacheOptionsReadonly => cacheMeta.options,\n setOptions: bindFunctionToCacheMeta(lowLevelSetOptions, cacheMeta),\n doMaintenance: bindFunctionToCacheMeta(lowLevelDoMaintenance, cacheMeta),\n };\n};\n\nexport { LimitedCache };\n","import type {\n DefaultItemType,\n LimitedCacheMeta,\n LimitedCacheObjectInstance,\n LimitedCacheOptions,\n} from '../types.js';\nimport {\n lowLevelGetAll,\n lowLevelGetOne,\n lowLevelHas,\n lowLevelInit,\n lowLevelRemove,\n lowLevelSet,\n} from './lowLevelFunctions.js';\n\nconst proxyHandler: ProxyHandler<LimitedCacheMeta> = {\n get: (cacheMeta: LimitedCacheMeta, cacheKey: string) => {\n if (cacheKey === 'hasOwnProperty') {\n return Object.prototype.hasOwnProperty;\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return lowLevelGetOne(cacheMeta, cacheKey);\n },\n getOwnPropertyDescriptor: (cacheMeta: LimitedCacheMeta, cacheKey: string) => {\n const hasResult = lowLevelHas(cacheMeta, cacheKey);\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const getResult = lowLevelGetOne(cacheMeta, cacheKey);\n\n if (hasResult) {\n return {\n configurable: true,\n enumerable: hasResult,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n value: getResult,\n writable: true,\n };\n }\n return;\n },\n has: lowLevelHas,\n set: <T>(cacheMeta: LimitedCacheMeta, cacheKey: string, item: T): T => {\n lowLevelSet(cacheMeta, cacheKey, item);\n return item;\n },\n deleteProperty: (cacheMeta: LimitedCacheMeta, cacheKey: string): true => {\n lowLevelRemove(cacheMeta, cacheKey);\n return true;\n },\n ownKeys: (cacheMeta: LimitedCacheMeta) => Object.keys(lowLevelGetAll(cacheMeta)),\n};\n\n/**\n * TypeScript's Proxy type models the runtime target, but LimitedCacheObject intentionally returns\n * a facade with a different surface from the internal cache metadata target.\n */\nconst internal_createLimitedCacheObjectProxy = <ItemType = DefaultItemType>(\n cacheMeta: LimitedCacheMeta<ItemType>,\n): LimitedCacheObjectInstance<ItemType> => {\n return new Proxy(cacheMeta, proxyHandler) as unknown as LimitedCacheObjectInstance<ItemType>;\n};\n\n/**\n * So that we can retrieve the cacheMeta for a LimitedCacheObject, without polluting its properties, each proxy\n * is associated back to its internal cacheMeta here.\n */\nconst cacheMetasForProxies = new WeakMap();\n\nconst LimitedCacheObject = <ItemType = DefaultItemType>(\n options?: LimitedCacheOptions,\n): LimitedCacheObjectInstance<ItemType> => {\n const cacheMeta = lowLevelInit<ItemType>(options);\n const limitedCacheObject = internal_createLimitedCacheObjectProxy(cacheMeta);\n\n cacheMetasForProxies.set(limitedCacheObject, cacheMeta);\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return limitedCacheObject;\n};\n\nconst getCacheMetaFromObject = (instance: LimitedCacheObjectInstance): LimitedCacheMeta => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return cacheMetasForProxies.get(instance);\n};\n\nexport { getCacheMetaFromObject, LimitedCacheObject };\n","import {\n lowLevelDoMaintenance,\n lowLevelGetAll,\n lowLevelGetOne,\n lowLevelHas,\n lowLevelInit,\n lowLevelRemove,\n lowLevelReset,\n lowLevelSet,\n lowLevelSetOptions,\n} from './lowLevelFunctions.js';\n\ntype LimitedCacheUtil = {\n init: typeof lowLevelInit;\n get: typeof lowLevelGetOne;\n getAll: typeof lowLevelGetAll;\n has: typeof lowLevelHas;\n set: typeof lowLevelSet;\n remove: typeof lowLevelRemove;\n reset: typeof lowLevelReset;\n doMaintenance: typeof lowLevelDoMaintenance;\n setOptions: typeof lowLevelSetOptions;\n};\n\nconst limitedCacheUtil: LimitedCacheUtil = {\n init: lowLevelInit,\n get: lowLevelGetOne,\n getAll: lowLevelGetAll,\n has: lowLevelHas,\n set: lowLevelSet,\n remove: lowLevelRemove,\n reset: lowLevelReset,\n doMaintenance: lowLevelDoMaintenance,\n setOptions: lowLevelSetOptions,\n};\n\nexport { limitedCacheUtil };\n"],"mappings":";AAEA,MAAM,uBAAuB;AAE7B,MAAM,qBAA6B,MAAM,QAAQ;AAEjD,MAAM,iBAA8C;CAElD,cAAc;CACd,cAAc,QAAQ;CAEtB,4BAA4B;CAE5B,SAAS;CACT,WAAW;AACb;;;ACJA,MAAM,wBAAwB,UAA0B,KAAK,IAAI,OAAO,CAAC,KAAK;AAE9E,MAAM,oBAAoB,qBAAuE;CAC/F,OAAO,OAAO,kBAAkB;EAC9B,cAAc,qBAAqB,iBAAiB,YAAY;EAChE,cAAc,qBAAqB,iBAAiB,YAAY;EAChE,SAAS,qBAAqB,iBAAiB,OAAO;CACxD,CAAC;CAGD,IAAI,QAAQ,IAAI,aAAa,cAC3B,iBAAiB,6BAA6B,qBAC5C,iBAAiB,0BACnB;CAEF,OAAO;AACT;AAEA,MAAM,eAAe,cAAsD;CAEzE,OAAO,CAAC,CAAC,WAAW;AACtB;AAEA,MAAM,oBAAoB,cAAsC;CAC9D,IAAI,CAAC,YAAY,SAAS,GACxB,MAAM,IAAI,MAAM,4DAA4D;CAE9E,IAAI,UAAU,4BAAA,GAAkD;EAI9D,QAAQ,KAAK,+EAA+E;EAC5F,UAAU,0BAAA;EACV,cAAc,SAAS;CACzB;AACF;AAEA,MAAM,sBACJ,WACA,YACgC;CAChC,iBAAiB,SAAS;CAC1B,OAAO,iBAAiB,OAAO,OAAO,UAAU,SAAS,OAAO,CAAC;AACnE;AAEA,MAAM,gBACJ,uBAC+B;CAC/B,IAAI,YAAY,kBAAkB,GAAG;EACnC,MAAM,oBAAoB;EAC1B,iBAAiB,iBAAiB;EAClC,OAAO;CACT;CAaA,OALqB,cAAc;EACjC,yBAAA;EACA,SARkB,iBAAiB;GACnC,GAAG;GACH,GAAG;EACL,CAKqB;CACrB,CAEkB;AACpB;AAIA,MAAM,kBAAkB,WAA6B,aAA6B;CAChF,MAAM,EACJ,SAAS,EAAE,gBACX,SAAS,GAAG,WAAW,cACrB;CACJ,IAAI,CAAC,SAEH,OAAO;CAGT,MAAM,CAAC,SAAS,cAAc;CAC9B,OAAO,cAAc,WAAW,gBAAA;AAClC;AAEA,MAAM,uBACJ,WACA,UACA,QACY;CACZ,OAAO,eAAe,WAAW,QAAQ,IAAI;AAC/C;AAEA,MAAM,yBACJ,cAC+B;CAC/B,iBAAiB,SAAS;CAC1B,MAAM,EAAE,OAAO,SAAS,YAAY;CACpC,MAAM,MAAM,KAAK,IAAI;CAGrB,MAAM,CAAC,UAAU,YAAY,cAAc,QAAQ,QAChD,KAAK,aAAa;EACjB,MAAM,CAAC,UAAU,YAAY,cAAc;EAC3C,IAAI,CAAC,oBAAoB,WAAW,UAAU,GAAG,GAAG;GAClD,SAAS,YAAY,MAAM;GAC3B,WAAW,KAAK,QAAQ;GACxB,WAAW,YAAY,QAAQ;EACjC;EACA,OAAO;CACT,GACA;EAGE,CAAC;EACD,CAAC;EACD,OAAO,OAAO,IAAI;CACpB,CACF;CAEA,OAAO,OAAO,OAAO,WAAW;EAC9B,OAAO;EACP,SAAS;EACT,SAAS;EACT,SAAS,UAAU,QAAQ;CAC7B,CAAC;AACH;AAEA,MAAM,oBAAoB,WAA6B,YAAoB,QAAsB;CAC/F,MAAM,EAAE,OAAO,SAAS,YAAY;CAGpC,IAAI,YAAY;CAChB,IAAI,eAAe,QAAQ;CAC3B,MAAM,gBAAgB,QAAQ;CAC9B,GAAG;EAGD,MAAM,gBAAgB,QAAQ,gBAAgB,KAAA;EAG9C;EACA,eAAe,QAAQ;CACzB,SAAS,YAAY,iBAAiB,oBAAoB,WAAW,cAAc,GAAG;CAGtF,QAAQ,OAAO,YAAY,YAAY,UAAU;AACnD;AAEA,MAAM,0BAA0B,WAA6B,QAAsB;CACjF,MAAM,EACJ,SAAS,EAAE,WAAW,8BACtB,OACA,SACA,YACE;CAIJ,IAAI,kBAAkB;CACtB,IAAI,mBAAmB,eAAe,WAAW,QAAQ,EAAY;CAErE,IAAI,mBAAmB,KAAK;EAE1B,IAAI,eAAe;EACnB,MAAM,kBAAkB,KAAK,IAAI,QAAQ,QAAQ,SAAS;EAC1D,OAAO,eAAe,iBAAiB;GACrC,MAAM,mBAAmB,QAAQ;GACjC,MAAM,qBAAqB,eAAe,WAAW,gBAAgB;GAIrE,IAAI,qBAAqB,KAAK;IAE5B,kBAAkB;IAClB,mBAAmB;IACnB;GACF;GACA,IAAI,qBAAqB,kBAAkB;IAEzC,kBAAkB;IAClB,mBAAmB;GACrB;GACA,gBAAgB;EAClB;CACF;CAIA,IAEE,QAAQ,IAAI,aAAa,gBACzB,8BACA,mBAAmB,KACnB;EACA,MAAM,gBAAgB,QAAQ;EAC9B,MAAM,CAAC,mBAAmB,wBAAwB,QAAQ;EAE1D,IAAI,MAAM,oBAAoB,4BAE5B,QAAQ,KACN,6FACA;GACE,aAAa;GACb,KAAK;GAEL,MAAM,MAAM;GACZ,SAAS;GACT,YAAY;GACZ,aAAa,MAAM;EACrB,CACF;CAEJ;CAGA,iBAAiB,WAAW,iBAAiB,GAAG;AAClD;AAIA,MAAM,eACJ,WACA,aACY;CACZ,iBAAiB,SAAS;CAC1B,MAAM,EAAE,UAAU;CAClB,IAAI,OAAO,OAAO,OAAO,QAAQ,KAAK,MAAM,cAAc,KAAA,GAAW;EACnE,IAAI,CAAC,oBAAoB,WAAW,UAAU,KAAK,IAAI,CAAC,GACtD,OAAO;EAGT,MAAM,YAAY,KAAA;CACpB;CACA,OAAO;AACT;AAEA,MAAM,kBACJ,WACA,aACyB;CACzB,iBAAiB,SAAS;CAC1B,IAAI,YAAY,WAAW,QAAQ,GACjC,OAAO,UAAU,MAAM;AAG3B;AAEA,MAAM,kBACJ,cAC6B;CAC7B,iBAAiB,SAAS;CAE1B,sBAAsB,SAAS;CAE/B,OAAO,UAAU;AACnB;AAEA,MAAM,eACJ,WACA,UACA,SAC+B;CAC/B,iBAAiB,SAAS;CAE1B,MAAM,EACJ,SAAS,EAAE,gBACX,SACA,YACE;CAEJ,MAAM,MAAM,KAAK,IAAI;CACrB,MAAM,QAAQ,CAAC,QAAQ;CAEvB,IAAI,UAAU,MAAM,cAAc,MAEhC,UAAU,QAAQ;EAChB,GAAG,UAAU;GACZ,WAAW;CACd;CAIF,QAAQ,YAAY,CAAC,KAAK,CAAC;CAE3B,IAAI,OAAO;EAET,QAAQ,KAAK,QAAQ;EAErB,UAAU;EACV,IAAI,UAAU,WAAW,GAEvB,sBAAsB,SAAS;EAGjC,IAAI,gBAAgB,UAAU,QAAQ,SAAS,cAE7C,uBAAuB,WAAW,GAAG;CAEzC;CAEA,IAAI,oBAAoB,WAAW,QAAQ,IAAc,GAAG,GAE1D,iBAAiB,WAAW,GAAG,GAAG;CAGpC,OAAO;AACT;AAEA,MAAM,kBACJ,WACA,aAC+B;CAC/B,iBAAiB,SAAS;CAC1B,MAAM,EAAE,OAAO,YAAY;CAE3B,IAAI,QAAQ,WAAW;EACrB,IAAI,MAAM,cAAc,KAAA,GACtB,UAAU,QAAQ;GAChB,GAAG;IACF,WAAW,KAAA;EACd;EAEF,QAAQ,YAAY,KAAA;CACtB;CAEA,OAAO;AACT;AAEA,MAAM,iBACJ,cAC+B;CAC/B,iBAAiB,SAAS;CAC1B,OAAO,OAAO,OAAO,WAAW;EAC9B,OAAO,CAAC;EACR,SAAS,CAAC;EACV,SAAS,OAAO,OAAO,IAAI;EAC3B,SAAS,UAAU,QAAQ;CAC7B,CAAC;AACH;;;ACxUA,MAAM,2BACJ,IACA,cAC+C,GAAG,KAAK,MAAM,SAAS;AAExE,MAAM,gBACJ,YACmC;CACnC,MAAM,YAAY,aAAuB,OAAO;CAEhD,OAAO;EACL,KAAK,wBAAwB,gBAAgB,SAAS;EACtD,QAAQ,wBAAwB,gBAAgB,SAAS;EACzD,KAAK,wBAAwB,aAAa,SAAS;EACnD,MAAM,UAAU,SAAmB;GACjC,YAAY,WAAW,UAAU,IAAI;GACrC,OAAO;EACT;EACA,SAAS,aAAmB;GAC1B,eAAe,WAAW,QAAQ;GAClC,OAAO;EACT;EACA,OAAO,wBAAwB,eAAe,SAAS;EACvD,oBAAgD;EAChD,kBAA+C,UAAU;EACzD,YAAY,wBAAwB,oBAAoB,SAAS;EACjE,eAAe,wBAAwB,uBAAuB,SAAS;CACzE;AACF;;;AClCA,MAAM,eAA+C;CACnD,MAAM,WAA6B,aAAqB;EACtD,IAAI,aAAa,kBACf,OAAO,OAAO,UAAU;EAG1B,OAAO,eAAe,WAAW,QAAQ;CAC3C;CACA,2BAA2B,WAA6B,aAAqB;EAC3E,MAAM,YAAY,YAAY,WAAW,QAAQ;EAEjD,MAAM,YAAY,eAAe,WAAW,QAAQ;EAEpD,IAAI,WACF,OAAO;GACL,cAAc;GACd,YAAY;GAEZ,OAAO;GACP,UAAU;EACZ;CAGJ;CACA,KAAK;CACL,MAAS,WAA6B,UAAkB,SAAe;EACrE,YAAY,WAAW,UAAU,IAAI;EACrC,OAAO;CACT;CACA,iBAAiB,WAA6B,aAA2B;EACvE,eAAe,WAAW,QAAQ;EAClC,OAAO;CACT;CACA,UAAU,cAAgC,OAAO,KAAK,eAAe,SAAS,CAAC;AACjF;;;;;AAMA,MAAM,0CACJ,cACyC;CACzC,OAAO,IAAI,MAAM,WAAW,YAAY;AAC1C;;;;;AAMA,MAAM,uCAAuB,IAAI,QAAQ;AAEzC,MAAM,sBACJ,YACyC;CACzC,MAAM,YAAY,aAAuB,OAAO;CAChD,MAAM,qBAAqB,uCAAuC,SAAS;CAE3E,qBAAqB,IAAI,oBAAoB,SAAS;CAEtD,OAAO;AACT;AAEA,MAAM,0BAA0B,aAA2D;CAEzF,OAAO,qBAAqB,IAAI,QAAQ;AAC1C;;;ACzDA,MAAM,mBAAqC;CACzC,MAAM;CACN,KAAK;CACL,QAAQ;CACR,KAAK;CACL,KAAK;CACL,QAAQ;CACR,OAAO;CACP,eAAe;CACf,YAAY;AACd"}
|
package/package.json
CHANGED
|
@@ -18,6 +18,7 @@ const normalizeOptions = (cacheMetaOptions: LimitedCacheOptionsFull): LimitedCac
|
|
|
18
18
|
opLimit: positiveNumberOrZero(cacheMetaOptions.opLimit),
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
+
// @ts-expect-error `process.env.NODE_ENV` left intact and not added to global typings
|
|
21
22
|
if (process.env.NODE_ENV !== 'production') {
|
|
22
23
|
cacheMetaOptions.warnIfItemPurgedBeforeTime = positiveNumberOrZero(
|
|
23
24
|
cacheMetaOptions.warnIfItemPurgedBeforeTime,
|
|
@@ -197,6 +198,7 @@ const _removeItemsToMakeRoom = (cacheMeta: LimitedCacheMeta, now: number): void
|
|
|
197
198
|
// Warn if the 'oldest' item is more recent than we'd like: this means it cycled into and out of
|
|
198
199
|
// cache too quickly for the cache to be useful.
|
|
199
200
|
if (
|
|
201
|
+
// @ts-expect-error `process.env.NODE_ENV` left intact and not added to global typings
|
|
200
202
|
process.env.NODE_ENV !== 'production' &&
|
|
201
203
|
warnIfItemPurgedBeforeTime &&
|
|
202
204
|
oldestExpireTime > now
|
|
@@ -233,8 +235,7 @@ const lowLevelHas = <ItemType = DefaultItemType>(
|
|
|
233
235
|
): boolean => {
|
|
234
236
|
upgradeCacheMeta(cacheMeta);
|
|
235
237
|
const { cache } = cacheMeta;
|
|
236
|
-
|
|
237
|
-
if (Object.prototype.hasOwnProperty.call(cache, cacheKey) && cache[cacheKey] !== undefined) {
|
|
238
|
+
if (Object.hasOwn(cache, cacheKey) && cache[cacheKey] !== undefined) {
|
|
238
239
|
if (!_cacheKeyHasExpired(cacheMeta, cacheKey, Date.now())) {
|
|
239
240
|
return true;
|
|
240
241
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,21 +1,8 @@
|
|
|
1
|
-
declare global {
|
|
2
|
-
// We only want the exact `process.env.NODE_ENV` (and not all Node typings) since that's handled by bundlers
|
|
3
|
-
// even in ESM.
|
|
4
|
-
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
5
|
-
namespace NodeJS {
|
|
6
|
-
interface ProcessEnv {
|
|
7
|
-
// Usually optional because env vars may be missing at runtime
|
|
8
|
-
NODE_ENV?: 'development' | 'production' | 'test';
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
1
|
// This makes it easy to ensure that ItemType gets passed to any nested generics:
|
|
14
2
|
// * Using `unknown` helps catch errors during development but is a pain for consumers.
|
|
15
3
|
// * Using `any` is nicer for consumers, but errors could slip through during development.
|
|
16
|
-
// In v3.0.0 the default
|
|
17
|
-
|
|
18
|
-
export type DefaultItemType = any;
|
|
4
|
+
// In v3.0.0 the default was changed from `any` to `unknown`
|
|
5
|
+
export type DefaultItemType = unknown;
|
|
19
6
|
|
|
20
7
|
export interface LimitedCacheOptionsFull {
|
|
21
8
|
/** Items will be removed to keep the cache within the maxCacheSize limit */
|