@neezco/cache 0.2.0 → 0.3.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 +14 -0
- package/dist/browser/index.d.ts +47 -10
- package/dist/browser/index.js +70 -37
- package/dist/browser/index.js.map +1 -1
- package/dist/node/index.cjs +70 -37
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.cts +47 -10
- package/dist/node/index.d.mts +47 -10
- package/dist/node/index.mjs +70 -37
- package/dist/node/index.mjs.map +1 -1
- package/docs/api-reference.md +33 -3
- package/package.json +3 -3
package/dist/node/index.d.cts
CHANGED
|
@@ -100,6 +100,34 @@ interface InvalidateTagOptions {
|
|
|
100
100
|
asStale?: boolean;
|
|
101
101
|
[key: string]: unknown;
|
|
102
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Status of a cache entry.
|
|
105
|
+
*/
|
|
106
|
+
declare enum ENTRY_STATUS {
|
|
107
|
+
/** The entry is fresh and valid. */
|
|
108
|
+
FRESH = "fresh",
|
|
109
|
+
/** The entry is stale but can still be served. */
|
|
110
|
+
STALE = "stale",
|
|
111
|
+
/** The entry has expired and is no longer valid. */
|
|
112
|
+
EXPIRED = "expired",
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Metadata returned when includeMetadata is enabled in get().
|
|
116
|
+
* Contains complete information about a cache entry including
|
|
117
|
+
* timing, status, and associated tags.
|
|
118
|
+
*/
|
|
119
|
+
interface EntryMetadata<T = unknown> {
|
|
120
|
+
/** The cached value. */
|
|
121
|
+
data: T;
|
|
122
|
+
/** Absolute timestamp when this entry becomes fully expired (in milliseconds). */
|
|
123
|
+
expirationTime: number;
|
|
124
|
+
/** Absolute timestamp when the stale window expires (in milliseconds). */
|
|
125
|
+
staleWindowExpiration: number;
|
|
126
|
+
/** Current status of the entry (fresh, stale, or expired). */
|
|
127
|
+
status: ENTRY_STATUS;
|
|
128
|
+
/** Tags associated with this entry, or null if no tags are set. */
|
|
129
|
+
tags: string[] | null;
|
|
130
|
+
}
|
|
103
131
|
//#endregion
|
|
104
132
|
//#region src/index.d.ts
|
|
105
133
|
/**
|
|
@@ -156,22 +184,31 @@ declare class LocalTtlCache {
|
|
|
156
184
|
* Returns the value if it exists and is not fully expired. If an entry is in the
|
|
157
185
|
* stale window (expired but still within staleWindow), the stale value is returned.
|
|
158
186
|
*
|
|
159
|
-
|
|
160
187
|
* @param key - The key to retrieve
|
|
161
|
-
* @
|
|
188
|
+
* @param options - Optional configuration object
|
|
189
|
+
* @param options.includeMetadata - If true, returns entry metadata (data, status, expirationTime, staleWindowExpiration, tags). Defaults to false
|
|
190
|
+
* @returns The cached value, or entry metadata if includeMetadata is true. Returns undefined if not found or expired
|
|
162
191
|
*
|
|
163
192
|
* @example
|
|
164
193
|
* ```typescript
|
|
165
|
-
*
|
|
194
|
+
* // Get value
|
|
195
|
+
* const user = cache.get("user:123");
|
|
196
|
+
*
|
|
197
|
+
* // Get with metadata
|
|
198
|
+
* const entry = cache.get("user:123", { includeMetadata: true });
|
|
199
|
+
* if (entry) {
|
|
200
|
+
* console.log(entry.data);
|
|
201
|
+
* console.log(entry.status);
|
|
202
|
+
* }
|
|
166
203
|
* ```
|
|
167
|
-
*
|
|
168
|
-
* @edge-cases
|
|
169
|
-
* - Returns `undefined` if the key doesn't exist
|
|
170
|
-
* - Returns `undefined` if the key has expired beyond the stale window
|
|
171
|
-
* - Returns the stale value if within the stale window
|
|
172
|
-
* - If `purgeStaleOnGet` is enabled, stale entries are deleted after being returned
|
|
173
204
|
*/
|
|
174
205
|
get<T = unknown>(key: string): T | undefined;
|
|
206
|
+
get<T = unknown>(key: string, options: {
|
|
207
|
+
includeMetadata: true;
|
|
208
|
+
}): EntryMetadata<T> | undefined;
|
|
209
|
+
get<T = unknown>(key: string, options: {
|
|
210
|
+
includeMetadata: false;
|
|
211
|
+
}): T | undefined;
|
|
175
212
|
/**
|
|
176
213
|
* Sets or updates a value in the cache.
|
|
177
214
|
*
|
|
@@ -296,5 +333,5 @@ declare class LocalTtlCache {
|
|
|
296
333
|
invalidateTag(tags: string | string[], options?: InvalidateTagOptions): void;
|
|
297
334
|
}
|
|
298
335
|
//#endregion
|
|
299
|
-
export { type CacheOptions, type InvalidateTagOptions, LocalTtlCache };
|
|
336
|
+
export { type CacheOptions, type EntryMetadata, type InvalidateTagOptions, LocalTtlCache };
|
|
300
337
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/node/index.d.mts
CHANGED
|
@@ -100,6 +100,34 @@ interface InvalidateTagOptions {
|
|
|
100
100
|
asStale?: boolean;
|
|
101
101
|
[key: string]: unknown;
|
|
102
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Status of a cache entry.
|
|
105
|
+
*/
|
|
106
|
+
declare enum ENTRY_STATUS {
|
|
107
|
+
/** The entry is fresh and valid. */
|
|
108
|
+
FRESH = "fresh",
|
|
109
|
+
/** The entry is stale but can still be served. */
|
|
110
|
+
STALE = "stale",
|
|
111
|
+
/** The entry has expired and is no longer valid. */
|
|
112
|
+
EXPIRED = "expired",
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Metadata returned when includeMetadata is enabled in get().
|
|
116
|
+
* Contains complete information about a cache entry including
|
|
117
|
+
* timing, status, and associated tags.
|
|
118
|
+
*/
|
|
119
|
+
interface EntryMetadata<T = unknown> {
|
|
120
|
+
/** The cached value. */
|
|
121
|
+
data: T;
|
|
122
|
+
/** Absolute timestamp when this entry becomes fully expired (in milliseconds). */
|
|
123
|
+
expirationTime: number;
|
|
124
|
+
/** Absolute timestamp when the stale window expires (in milliseconds). */
|
|
125
|
+
staleWindowExpiration: number;
|
|
126
|
+
/** Current status of the entry (fresh, stale, or expired). */
|
|
127
|
+
status: ENTRY_STATUS;
|
|
128
|
+
/** Tags associated with this entry, or null if no tags are set. */
|
|
129
|
+
tags: string[] | null;
|
|
130
|
+
}
|
|
103
131
|
//#endregion
|
|
104
132
|
//#region src/index.d.ts
|
|
105
133
|
/**
|
|
@@ -156,22 +184,31 @@ declare class LocalTtlCache {
|
|
|
156
184
|
* Returns the value if it exists and is not fully expired. If an entry is in the
|
|
157
185
|
* stale window (expired but still within staleWindow), the stale value is returned.
|
|
158
186
|
*
|
|
159
|
-
|
|
160
187
|
* @param key - The key to retrieve
|
|
161
|
-
* @
|
|
188
|
+
* @param options - Optional configuration object
|
|
189
|
+
* @param options.includeMetadata - If true, returns entry metadata (data, status, expirationTime, staleWindowExpiration, tags). Defaults to false
|
|
190
|
+
* @returns The cached value, or entry metadata if includeMetadata is true. Returns undefined if not found or expired
|
|
162
191
|
*
|
|
163
192
|
* @example
|
|
164
193
|
* ```typescript
|
|
165
|
-
*
|
|
194
|
+
* // Get value
|
|
195
|
+
* const user = cache.get("user:123");
|
|
196
|
+
*
|
|
197
|
+
* // Get with metadata
|
|
198
|
+
* const entry = cache.get("user:123", { includeMetadata: true });
|
|
199
|
+
* if (entry) {
|
|
200
|
+
* console.log(entry.data);
|
|
201
|
+
* console.log(entry.status);
|
|
202
|
+
* }
|
|
166
203
|
* ```
|
|
167
|
-
*
|
|
168
|
-
* @edge-cases
|
|
169
|
-
* - Returns `undefined` if the key doesn't exist
|
|
170
|
-
* - Returns `undefined` if the key has expired beyond the stale window
|
|
171
|
-
* - Returns the stale value if within the stale window
|
|
172
|
-
* - If `purgeStaleOnGet` is enabled, stale entries are deleted after being returned
|
|
173
204
|
*/
|
|
174
205
|
get<T = unknown>(key: string): T | undefined;
|
|
206
|
+
get<T = unknown>(key: string, options: {
|
|
207
|
+
includeMetadata: true;
|
|
208
|
+
}): EntryMetadata<T> | undefined;
|
|
209
|
+
get<T = unknown>(key: string, options: {
|
|
210
|
+
includeMetadata: false;
|
|
211
|
+
}): T | undefined;
|
|
175
212
|
/**
|
|
176
213
|
* Sets or updates a value in the cache.
|
|
177
214
|
*
|
|
@@ -296,5 +333,5 @@ declare class LocalTtlCache {
|
|
|
296
333
|
invalidateTag(tags: string | string[], options?: InvalidateTagOptions): void;
|
|
297
334
|
}
|
|
298
335
|
//#endregion
|
|
299
|
-
export { type CacheOptions, type InvalidateTagOptions, LocalTtlCache };
|
|
336
|
+
export { type CacheOptions, type EntryMetadata, type InvalidateTagOptions, LocalTtlCache };
|
|
300
337
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/node/index.mjs
CHANGED
|
@@ -566,11 +566,18 @@ function computeEntryStatus(state, entry, now) {
|
|
|
566
566
|
* - It has not expired according to its own timestamps, and
|
|
567
567
|
* - No associated tag imposes a stricter stale or expired rule.
|
|
568
568
|
*
|
|
569
|
+
* `entry` can be either a {@link CacheEntry} or a pre-computed {@link ENTRY_STATUS}.
|
|
570
|
+
* Passing a pre-computed status avoids recalculating the entry status.
|
|
571
|
+
*
|
|
569
572
|
* @param state - The cache state containing tag metadata.
|
|
570
|
-
* @param entry - The cache entry being evaluated.
|
|
573
|
+
* @param entry - The cache entry or pre-computed status being evaluated.
|
|
574
|
+
* @param now - The current timestamp.
|
|
571
575
|
* @returns True if the entry is fresh.
|
|
572
576
|
*/
|
|
573
|
-
const isFresh = (state, entry, now) =>
|
|
577
|
+
const isFresh = (state, entry, now) => {
|
|
578
|
+
if (typeof entry === "string") return entry === ENTRY_STATUS.FRESH;
|
|
579
|
+
return computeEntryStatus(state, entry, now) === ENTRY_STATUS.FRESH;
|
|
580
|
+
};
|
|
574
581
|
/**
|
|
575
582
|
* Determines whether a cache entry is stale.
|
|
576
583
|
*
|
|
@@ -578,11 +585,18 @@ const isFresh = (state, entry, now) => computeEntryStatus(state, entry, now) ===
|
|
|
578
585
|
* - It has passed its TTL but is still within its stale window, or
|
|
579
586
|
* - A tag imposes a stale rule that applies to this entry.
|
|
580
587
|
*
|
|
588
|
+
* `entry` can be either a {@link CacheEntry} or a pre-computed {@link ENTRY_STATUS}.
|
|
589
|
+
* Passing a pre-computed status avoids recalculating the entry status.
|
|
590
|
+
*
|
|
581
591
|
* @param state - The cache state containing tag metadata.
|
|
582
|
-
* @param entry - The cache entry being evaluated.
|
|
592
|
+
* @param entry - The cache entry or pre-computed status being evaluated.
|
|
593
|
+
* @param now - The current timestamp.
|
|
583
594
|
* @returns True if the entry is stale.
|
|
584
595
|
*/
|
|
585
|
-
const isStale = (state, entry, now) =>
|
|
596
|
+
const isStale = (state, entry, now) => {
|
|
597
|
+
if (typeof entry === "string") return entry === ENTRY_STATUS.STALE;
|
|
598
|
+
return computeEntryStatus(state, entry, now) === ENTRY_STATUS.STALE;
|
|
599
|
+
};
|
|
586
600
|
/**
|
|
587
601
|
* Determines whether a cache entry is expired.
|
|
588
602
|
*
|
|
@@ -590,11 +604,18 @@ const isStale = (state, entry, now) => computeEntryStatus(state, entry, now) ===
|
|
|
590
604
|
* - It has exceeded both its TTL and stale TTL, or
|
|
591
605
|
* - A tag imposes an expiration rule that applies to this entry.
|
|
592
606
|
*
|
|
607
|
+
* `entry` can be either a {@link CacheEntry} or a pre-computed {@link ENTRY_STATUS}.
|
|
608
|
+
* Passing a pre-computed status avoids recalculating the entry status.
|
|
609
|
+
*
|
|
593
610
|
* @param state - The cache state containing tag metadata.
|
|
594
|
-
* @param entry - The cache entry being evaluated.
|
|
611
|
+
* @param entry - The cache entry or pre-computed status being evaluated.
|
|
612
|
+
* @param now - The current timestamp.
|
|
595
613
|
* @returns True if the entry is expired.
|
|
596
614
|
*/
|
|
597
|
-
const isExpired = (state, entry, now) =>
|
|
615
|
+
const isExpired = (state, entry, now) => {
|
|
616
|
+
if (typeof entry === "string") return entry === ENTRY_STATUS.EXPIRED;
|
|
617
|
+
return computeEntryStatus(state, entry, now) === ENTRY_STATUS.EXPIRED;
|
|
618
|
+
};
|
|
598
619
|
|
|
599
620
|
//#endregion
|
|
600
621
|
//#region src/sweep/sweep-once.ts
|
|
@@ -619,10 +640,11 @@ function _sweepOnce(state, _maxKeysPerBatch = MAX_KEYS_PER_BATCH) {
|
|
|
619
640
|
processed += 1;
|
|
620
641
|
const [key, entry] = next.value;
|
|
621
642
|
const now = Date.now();
|
|
622
|
-
|
|
643
|
+
const status = computeEntryStatus(state, entry, now);
|
|
644
|
+
if (isExpired(state, status, now)) {
|
|
623
645
|
deleteKey(state, key, DELETE_REASON.EXPIRED);
|
|
624
646
|
expiredCount += 1;
|
|
625
|
-
} else if (isStale(state,
|
|
647
|
+
} else if (isStale(state, status, now)) {
|
|
626
648
|
staleCount += 1;
|
|
627
649
|
if (state.purgeStaleOnSweep) deleteKey(state, key, DELETE_REASON.STALE);
|
|
628
650
|
}
|
|
@@ -819,21 +841,40 @@ const createCache = (options = {}) => {
|
|
|
819
841
|
//#endregion
|
|
820
842
|
//#region src/cache/get.ts
|
|
821
843
|
/**
|
|
822
|
-
*
|
|
844
|
+
* Internal function that retrieves a value from the cache with its status information.
|
|
845
|
+
* Returns a tuple containing the entry status and the complete cache entry.
|
|
846
|
+
*
|
|
823
847
|
* @param state - The cache state.
|
|
824
848
|
* @param key - The key to retrieve.
|
|
825
849
|
* @param now - Optional timestamp override (defaults to Date.now()).
|
|
826
|
-
* @returns
|
|
850
|
+
* @returns A tuple of [status, entry] if the entry is valid, or [null, undefined] if not found or expired.
|
|
851
|
+
*
|
|
852
|
+
* @internal
|
|
827
853
|
*/
|
|
828
|
-
const
|
|
854
|
+
const getWithStatus = (state, key, now = Date.now()) => {
|
|
829
855
|
const entry = state.store.get(key);
|
|
830
|
-
if (!entry) return void 0;
|
|
831
|
-
|
|
832
|
-
if (
|
|
856
|
+
if (!entry) return [null, void 0];
|
|
857
|
+
const status = computeEntryStatus(state, entry, now);
|
|
858
|
+
if (isFresh(state, status, now)) return [status, entry];
|
|
859
|
+
if (isStale(state, status, now)) {
|
|
833
860
|
if (state.purgeStaleOnGet) deleteKey(state, key, DELETE_REASON.STALE);
|
|
834
|
-
return entry
|
|
861
|
+
return [status, entry];
|
|
835
862
|
}
|
|
836
863
|
deleteKey(state, key, DELETE_REASON.EXPIRED);
|
|
864
|
+
return [status, void 0];
|
|
865
|
+
};
|
|
866
|
+
/**
|
|
867
|
+
* Retrieves a value from the cache if the entry is valid.
|
|
868
|
+
* @param state - The cache state.
|
|
869
|
+
* @param key - The key to retrieve.
|
|
870
|
+
* @param now - Optional timestamp override (defaults to Date.now()).
|
|
871
|
+
* @returns The cached value if valid, undefined otherwise.
|
|
872
|
+
*
|
|
873
|
+
* @internal
|
|
874
|
+
*/
|
|
875
|
+
const get = (state, key, now = Date.now()) => {
|
|
876
|
+
const [, entry] = getWithStatus(state, key, now);
|
|
877
|
+
return entry ? entry[1] : void 0;
|
|
837
878
|
};
|
|
838
879
|
|
|
839
880
|
//#endregion
|
|
@@ -982,28 +1023,20 @@ var LocalTtlCache = class {
|
|
|
982
1023
|
get size() {
|
|
983
1024
|
return this.state.size;
|
|
984
1025
|
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
*
|
|
1000
|
-
* @edge-cases
|
|
1001
|
-
* - Returns `undefined` if the key doesn't exist
|
|
1002
|
-
* - Returns `undefined` if the key has expired beyond the stale window
|
|
1003
|
-
* - Returns the stale value if within the stale window
|
|
1004
|
-
* - If `purgeStaleOnGet` is enabled, stale entries are deleted after being returned
|
|
1005
|
-
*/
|
|
1006
|
-
get(key) {
|
|
1026
|
+
get(key, options) {
|
|
1027
|
+
if (options?.includeMetadata) {
|
|
1028
|
+
const [status, entry] = getWithStatus(this.state, key);
|
|
1029
|
+
if (!entry) return void 0;
|
|
1030
|
+
const [timestamps, value, tags] = entry;
|
|
1031
|
+
const [, expiresAt, staleExpiresAt] = timestamps;
|
|
1032
|
+
return {
|
|
1033
|
+
data: value,
|
|
1034
|
+
expirationTime: expiresAt,
|
|
1035
|
+
staleWindowExpiration: staleExpiresAt,
|
|
1036
|
+
status,
|
|
1037
|
+
tags
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1007
1040
|
return get(this.state, key);
|
|
1008
1041
|
}
|
|
1009
1042
|
/**
|