@ogxjs/core 0.1.2 → 0.2.0-alpha.1

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.
Files changed (59) hide show
  1. package/dist/cache/hash.d.ts +66 -0
  2. package/dist/cache/hash.d.ts.map +1 -0
  3. package/dist/cache/hash.js +161 -0
  4. package/dist/cache/index.d.ts +10 -0
  5. package/dist/cache/index.d.ts.map +1 -0
  6. package/dist/cache/index.js +12 -0
  7. package/dist/cache/lru.d.ts +122 -0
  8. package/dist/cache/lru.d.ts.map +1 -0
  9. package/dist/cache/lru.js +269 -0
  10. package/dist/cache/snapshot.d.ts +116 -0
  11. package/dist/cache/snapshot.d.ts.map +1 -0
  12. package/dist/cache/snapshot.js +204 -0
  13. package/dist/cache.d.ts +2 -2
  14. package/dist/cache.js +2 -2
  15. package/dist/css.d.ts +19 -6
  16. package/dist/css.d.ts.map +1 -1
  17. package/dist/index.d.ts +17 -3
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +40 -9
  20. package/dist/ogx.js +2 -2
  21. package/dist/perf/index.d.ts +8 -0
  22. package/dist/perf/index.d.ts.map +1 -0
  23. package/dist/perf/index.js +7 -0
  24. package/dist/perf/timing.d.ts +160 -0
  25. package/dist/perf/timing.d.ts.map +1 -0
  26. package/dist/perf/timing.js +305 -0
  27. package/dist/presets/blog.js +1 -1
  28. package/dist/presets/docs.d.ts +2 -0
  29. package/dist/presets/docs.d.ts.map +1 -1
  30. package/dist/presets/docs.js +26 -23
  31. package/dist/presets/minimal.d.ts +2 -0
  32. package/dist/presets/minimal.d.ts.map +1 -1
  33. package/dist/presets/minimal.js +8 -16
  34. package/dist/presets/social.d.ts +2 -0
  35. package/dist/presets/social.d.ts.map +1 -1
  36. package/dist/presets/social.js +28 -18
  37. package/dist/render-png.d.ts.map +1 -1
  38. package/dist/render-png.js +9 -1
  39. package/dist/render-svg.d.ts.map +1 -1
  40. package/dist/render-svg.js +11 -1
  41. package/dist/tailwind/class-cache.d.ts +141 -0
  42. package/dist/tailwind/class-cache.d.ts.map +1 -0
  43. package/dist/tailwind/class-cache.js +212 -0
  44. package/dist/tailwind/index.d.ts +14 -1
  45. package/dist/tailwind/index.d.ts.map +1 -1
  46. package/dist/tailwind/index.js +15 -1
  47. package/dist/tailwind/lookup-tables.d.ts +30 -0
  48. package/dist/tailwind/lookup-tables.d.ts.map +1 -0
  49. package/dist/tailwind/lookup-tables.js +427 -0
  50. package/dist/tailwind/parser-v2.d.ts +54 -0
  51. package/dist/tailwind/parser-v2.d.ts.map +1 -0
  52. package/dist/tailwind/parser-v2.js +250 -0
  53. package/dist/tailwind/parser.d.ts +1 -0
  54. package/dist/tailwind/parser.d.ts.map +1 -1
  55. package/dist/tailwind/parser.js +1 -0
  56. package/dist/tailwind/prefix-handlers.d.ts +68 -0
  57. package/dist/tailwind/prefix-handlers.d.ts.map +1 -0
  58. package/dist/tailwind/prefix-handlers.js +931 -0
  59. package/package.json +17 -2
@@ -0,0 +1,66 @@
1
+ /**
2
+ * @ogxjs/core - Fast Hash Functions
3
+ * High-performance sync hashing for cache keys
4
+ *
5
+ * @description
6
+ * SHA-256 is secure but slow (~200μs per hash).
7
+ * For cache keys where collision resistance is less critical,
8
+ * we use faster algorithms:
9
+ * - FNV-1a: ~10μs per hash (20x faster)
10
+ * - xxHash-inspired: ~5μs per hash (40x faster)
11
+ *
12
+ * @version 0.2.0 "Turbo"
13
+ */
14
+ /**
15
+ * FNV-1a hash algorithm (32-bit)
16
+ *
17
+ * Fast, simple, good distribution for short strings.
18
+ * Collision probability: ~1 in 4 billion for random inputs.
19
+ *
20
+ * @param str - String to hash
21
+ * @returns 32-bit hash as unsigned integer
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * fnv1a("hello") // → 1335831723
26
+ * fnv1a("hello world") // → 3582672807
27
+ * ```
28
+ */
29
+ export declare function fnv1a(str: string): number;
30
+ /**
31
+ * FNV-1a hash with hex string output
32
+ *
33
+ * @param str - String to hash
34
+ * @returns Hash as 8-character hex string
35
+ */
36
+ export declare function fnv1aHex(str: string): string;
37
+ /**
38
+ * xxHash-inspired fast hash (32-bit)
39
+ *
40
+ * Even faster than FNV-1a for longer strings.
41
+ * Processes 4 bytes at a time when possible.
42
+ *
43
+ * @param str - String to hash
44
+ * @param seed - Optional seed value (default: 0)
45
+ * @returns 32-bit hash as unsigned integer
46
+ */
47
+ export declare function fastHash(str: string, seed?: number): number;
48
+ /**
49
+ * Fast hash with hex string output
50
+ */
51
+ export declare function fastHashHex(str: string, seed?: number): string;
52
+ /**
53
+ * Hash a configuration object
54
+ *
55
+ * Serializes the object to JSON and hashes it.
56
+ * Excludes functions and debug flags.
57
+ *
58
+ * @param obj - Object to hash
59
+ * @returns Hash string
60
+ */
61
+ export declare function hashObject(obj: unknown): string;
62
+ /**
63
+ * Create a composite hash from multiple values
64
+ */
65
+ export declare function hashComposite(...values: unknown[]): string;
66
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/cache/hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUzC;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5C;AAID;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,SAAI,GAAG,MAAM,CA8DtD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,SAAI,GAAG,MAAM,CAEzD;AA2BD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAQ/C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAM1D"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * @ogxjs/core - Fast Hash Functions
3
+ * High-performance sync hashing for cache keys
4
+ *
5
+ * @description
6
+ * SHA-256 is secure but slow (~200μs per hash).
7
+ * For cache keys where collision resistance is less critical,
8
+ * we use faster algorithms:
9
+ * - FNV-1a: ~10μs per hash (20x faster)
10
+ * - xxHash-inspired: ~5μs per hash (40x faster)
11
+ *
12
+ * @version 0.2.0 "Turbo"
13
+ */
14
+ // FNV-1A HASH
15
+ /**
16
+ * FNV-1a hash algorithm (32-bit)
17
+ *
18
+ * Fast, simple, good distribution for short strings.
19
+ * Collision probability: ~1 in 4 billion for random inputs.
20
+ *
21
+ * @param str - String to hash
22
+ * @returns 32-bit hash as unsigned integer
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * fnv1a("hello") // → 1335831723
27
+ * fnv1a("hello world") // → 3582672807
28
+ * ```
29
+ */
30
+ export function fnv1a(str) {
31
+ let hash = 2166136261; // FNV offset basis
32
+ for (let i = 0; i < str.length; i++) {
33
+ hash ^= str.charCodeAt(i);
34
+ // FNV prime multiplication (using Math.imul for 32-bit overflow)
35
+ hash = Math.imul(hash, 16777619);
36
+ }
37
+ return hash >>> 0; // Ensure unsigned
38
+ }
39
+ /**
40
+ * FNV-1a hash with hex string output
41
+ *
42
+ * @param str - String to hash
43
+ * @returns Hash as 8-character hex string
44
+ */
45
+ export function fnv1aHex(str) {
46
+ return fnv1a(str).toString(16).padStart(8, "0");
47
+ }
48
+ // XXHASH-INSPIRED HASH
49
+ /**
50
+ * xxHash-inspired fast hash (32-bit)
51
+ *
52
+ * Even faster than FNV-1a for longer strings.
53
+ * Processes 4 bytes at a time when possible.
54
+ *
55
+ * @param str - String to hash
56
+ * @param seed - Optional seed value (default: 0)
57
+ * @returns 32-bit hash as unsigned integer
58
+ */
59
+ export function fastHash(str, seed = 0) {
60
+ const PRIME1 = 2654435761;
61
+ const PRIME2 = 2246822519;
62
+ const PRIME3 = 3266489917;
63
+ const PRIME4 = 668265263;
64
+ const PRIME5 = 374761393;
65
+ let h32;
66
+ const len = str.length;
67
+ if (len >= 16) {
68
+ // Process in 16-byte blocks
69
+ let v1 = (seed + PRIME1 + PRIME2) | 0;
70
+ let v2 = (seed + PRIME2) | 0;
71
+ let v3 = seed | 0;
72
+ let v4 = (seed - PRIME1) | 0;
73
+ let i = 0;
74
+ const limit = len - 16;
75
+ while (i <= limit) {
76
+ v1 = Math.imul(rotl(v1 + Math.imul(read32(str, i), PRIME2), 13), PRIME1);
77
+ i += 4;
78
+ v2 = Math.imul(rotl(v2 + Math.imul(read32(str, i), PRIME2), 13), PRIME1);
79
+ i += 4;
80
+ v3 = Math.imul(rotl(v3 + Math.imul(read32(str, i), PRIME2), 13), PRIME1);
81
+ i += 4;
82
+ v4 = Math.imul(rotl(v4 + Math.imul(read32(str, i), PRIME2), 13), PRIME1);
83
+ i += 4;
84
+ }
85
+ h32 = rotl(v1, 1) + rotl(v2, 7) + rotl(v3, 12) + rotl(v4, 18);
86
+ }
87
+ else {
88
+ h32 = seed + PRIME5;
89
+ }
90
+ h32 += len;
91
+ // Process remaining bytes
92
+ let i = len >= 16 ? len - (len % 16) : 0;
93
+ while (i <= len - 4) {
94
+ h32 = Math.imul(rotl(h32 + Math.imul(read32(str, i), PRIME3), 17), PRIME4);
95
+ i += 4;
96
+ }
97
+ while (i < len) {
98
+ h32 = Math.imul(rotl(h32 + Math.imul(str.charCodeAt(i), PRIME5), 11), PRIME1);
99
+ i++;
100
+ }
101
+ // Final mix
102
+ h32 ^= h32 >>> 15;
103
+ h32 = Math.imul(h32, PRIME2);
104
+ h32 ^= h32 >>> 13;
105
+ h32 = Math.imul(h32, PRIME3);
106
+ h32 ^= h32 >>> 16;
107
+ return h32 >>> 0;
108
+ }
109
+ /**
110
+ * Fast hash with hex string output
111
+ */
112
+ export function fastHashHex(str, seed = 0) {
113
+ return fastHash(str, seed).toString(16).padStart(8, "0");
114
+ }
115
+ // HELPERS
116
+ /**
117
+ * Rotate left (32-bit)
118
+ */
119
+ function rotl(x, r) {
120
+ return (x << r) | (x >>> (32 - r));
121
+ }
122
+ /**
123
+ * Read 4 characters as a 32-bit value
124
+ * Safely handles bounds by returning 0 for out-of-bounds indices
125
+ */
126
+ function read32(str, i) {
127
+ const len = str.length;
128
+ return ((i < len ? str.charCodeAt(i) : 0) |
129
+ ((i + 1 < len ? str.charCodeAt(i + 1) : 0) << 8) |
130
+ ((i + 2 < len ? str.charCodeAt(i + 2) : 0) << 16) |
131
+ ((i + 3 < len ? str.charCodeAt(i + 3) : 0) << 24));
132
+ }
133
+ // OBJECT HASHING
134
+ /**
135
+ * Hash a configuration object
136
+ *
137
+ * Serializes the object to JSON and hashes it.
138
+ * Excludes functions and debug flags.
139
+ *
140
+ * @param obj - Object to hash
141
+ * @returns Hash string
142
+ */
143
+ export function hashObject(obj) {
144
+ const str = JSON.stringify(obj, (key, value) => {
145
+ if (typeof value === "function")
146
+ return undefined;
147
+ if (key === "debug")
148
+ return undefined;
149
+ return value;
150
+ });
151
+ return fastHashHex(str);
152
+ }
153
+ /**
154
+ * Create a composite hash from multiple values
155
+ */
156
+ export function hashComposite(...values) {
157
+ const combined = values
158
+ .map((v) => (typeof v === "string" ? v : JSON.stringify(v)))
159
+ .join("|");
160
+ return fastHashHex(combined);
161
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @ogxjs/core - Cache Module
3
+ * High-performance caching system
4
+ *
5
+ * @version 0.2.0 "Turbo"
6
+ */
7
+ export { fastHash, fastHashHex, fnv1a, fnv1aHex, hashComposite, hashObject, } from "./hash";
8
+ export { createLargeCache, createMediumCache, createSmallCache, LRUCache, type LRUCacheOptions, type LRUCacheStats, } from "./lru";
9
+ export { configureSnapshotCache, getSnapshotCache, type SnapshotCacheOptions, type SnapshotCacheStats, SnapshotCacheV2, snapshotCache, } from "./snapshot";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACN,QAAQ,EACR,WAAW,EACX,KAAK,EACL,QAAQ,EACR,aAAa,EACb,UAAU,GACV,MAAM,QAAQ,CAAC;AAGhB,OAAO,EACN,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,QAAQ,EACR,KAAK,eAAe,EACpB,KAAK,aAAa,GAClB,MAAM,OAAO,CAAC;AAGf,OAAO,EACN,sBAAsB,EACtB,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,eAAe,EACf,aAAa,GACb,MAAM,YAAY,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @ogxjs/core - Cache Module
3
+ * High-performance caching system
4
+ *
5
+ * @version 0.2.0 "Turbo"
6
+ */
7
+ // Hash functions
8
+ export { fastHash, fastHashHex, fnv1a, fnv1aHex, hashComposite, hashObject, } from "./hash";
9
+ // LRU Cache
10
+ export { createLargeCache, createMediumCache, createSmallCache, LRUCache, } from "./lru";
11
+ // Snapshot Cache
12
+ export { configureSnapshotCache, getSnapshotCache, SnapshotCacheV2, snapshotCache, } from "./snapshot";
@@ -0,0 +1,122 @@
1
+ /**
2
+ * @ogxjs/core - LRU Cache Implementation
3
+ * Least Recently Used cache with O(1) operations
4
+ *
5
+ * @description
6
+ * High-performance LRU cache using Map + doubly-linked list.
7
+ * - O(1) get, set, delete
8
+ * - Automatic eviction when max size reached
9
+ * - Optional TTL (time-to-live) support
10
+ * - Memory-bounded
11
+ *
12
+ * @version 0.2.0 "Turbo"
13
+ */
14
+ export interface LRUCacheOptions<K = unknown, V = unknown> {
15
+ /** Maximum number of items in cache */
16
+ maxSize?: number;
17
+ /** Time-to-live in milliseconds (0 = no expiration) */
18
+ ttl?: number;
19
+ /** Callback when an item is evicted */
20
+ onEvict?: (key: K, value: V) => void;
21
+ }
22
+ export interface LRUCacheStats {
23
+ size: number;
24
+ maxSize: number;
25
+ hits: number;
26
+ misses: number;
27
+ hitRate: number;
28
+ evictions: number;
29
+ }
30
+ /**
31
+ * LRU Cache with O(1) operations
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const cache = new LRUCache<string, Buffer>({ maxSize: 100, ttl: 60000 });
36
+ *
37
+ * cache.set("image-1", buffer);
38
+ * const result = cache.get("image-1"); // → buffer
39
+ *
40
+ * console.log(cache.stats); // { size: 1, hits: 1, ... }
41
+ * ```
42
+ */
43
+ export declare class LRUCache<K, V> {
44
+ private cache;
45
+ private head;
46
+ private tail;
47
+ private readonly maxSize;
48
+ private readonly ttl;
49
+ private readonly onEvict?;
50
+ private _hits;
51
+ private _misses;
52
+ private _evictions;
53
+ constructor(options?: LRUCacheOptions<K, V>);
54
+ /**
55
+ * Get a value from the cache
56
+ * Moves the item to the front (most recently used)
57
+ */
58
+ get(key: K): V | undefined;
59
+ /**
60
+ * Set a value in the cache
61
+ * Evicts least recently used item if at capacity
62
+ */
63
+ set(key: K, value: V): void;
64
+ /**
65
+ * Check if a key exists (without updating LRU order)
66
+ */
67
+ has(key: K): boolean;
68
+ /**
69
+ * Delete a key from the cache
70
+ */
71
+ delete(key: K): boolean;
72
+ /**
73
+ * Clear the entire cache
74
+ */
75
+ clear(): void;
76
+ /**
77
+ * Get cache size
78
+ */
79
+ get size(): number;
80
+ /**
81
+ * Get cache statistics
82
+ */
83
+ get stats(): LRUCacheStats;
84
+ /**
85
+ * Get all keys (in LRU order, most recent first)
86
+ */
87
+ keys(): K[];
88
+ /**
89
+ * Iterate over entries (in LRU order)
90
+ */
91
+ entries(): Generator<[K, V]>;
92
+ /**
93
+ * Prune expired entries (if TTL is set)
94
+ * Call periodically for long-running processes
95
+ */
96
+ prune(): number;
97
+ /**
98
+ * Move a node to the front (most recently used)
99
+ */
100
+ private moveToFront;
101
+ /**
102
+ * Remove a node from the linked list (but not from Map)
103
+ */
104
+ private removeNode;
105
+ /**
106
+ * Evict the least recently used item
107
+ */
108
+ private evictLRU;
109
+ }
110
+ /**
111
+ * Create a small LRU cache (100 items)
112
+ */
113
+ export declare function createSmallCache<K, V>(ttl?: number): LRUCache<K, V>;
114
+ /**
115
+ * Create a medium LRU cache (1000 items)
116
+ */
117
+ export declare function createMediumCache<K, V>(ttl?: number): LRUCache<K, V>;
118
+ /**
119
+ * Create a large LRU cache (10000 items)
120
+ */
121
+ export declare function createLargeCache<K, V>(ttl?: number): LRUCache<K, V>;
122
+ //# sourceMappingURL=lru.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lru.d.ts","sourceRoot":"","sources":["../../src/cache/lru.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAYH,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO;IACxD,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;CACrC;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CAClB;AAID;;;;;;;;;;;;GAYG;AACH,qBAAa,QAAQ,CAAC,CAAC,EAAE,CAAC;IACzB,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,IAAI,CAAgC;IAC5C,OAAO,CAAC,IAAI,CAAgC;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAA6B;IAGtD,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,UAAU,CAAK;gBAEX,OAAO,GAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAM;IAM/C;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IAsB1B;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAsC3B;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAapB;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAUvB;;OAEG;IACH,KAAK,IAAI,IAAI;IASb;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACH,IAAI,KAAK,IAAI,aAAa,CAUzB;IAED;;OAEG;IACH,IAAI,IAAI,CAAC,EAAE;IAUX;;OAEG;IACF,OAAO,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAQ7B;;;OAGG;IACH,KAAK,IAAI,MAAM;IAoBf;;OAEG;IACH,OAAO,CAAC,WAAW;IAoBnB;;OAEG;IACH,OAAO,CAAC,UAAU;IAclB;;OAEG;IACH,OAAO,CAAC,QAAQ;CAehB;AAID;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,SAAI,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAE9D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,SAAI,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAE/D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,SAAI,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAE9D"}
@@ -0,0 +1,269 @@
1
+ /**
2
+ * @ogxjs/core - LRU Cache Implementation
3
+ * Least Recently Used cache with O(1) operations
4
+ *
5
+ * @description
6
+ * High-performance LRU cache using Map + doubly-linked list.
7
+ * - O(1) get, set, delete
8
+ * - Automatic eviction when max size reached
9
+ * - Optional TTL (time-to-live) support
10
+ * - Memory-bounded
11
+ *
12
+ * @version 0.2.0 "Turbo"
13
+ */
14
+ // LRU CACHE CLASS
15
+ /**
16
+ * LRU Cache with O(1) operations
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const cache = new LRUCache<string, Buffer>({ maxSize: 100, ttl: 60000 });
21
+ *
22
+ * cache.set("image-1", buffer);
23
+ * const result = cache.get("image-1"); // → buffer
24
+ *
25
+ * console.log(cache.stats); // { size: 1, hits: 1, ... }
26
+ * ```
27
+ */
28
+ export class LRUCache {
29
+ cache = new Map();
30
+ head = null;
31
+ tail = null;
32
+ maxSize;
33
+ ttl;
34
+ onEvict;
35
+ // Stats
36
+ _hits = 0;
37
+ _misses = 0;
38
+ _evictions = 0;
39
+ constructor(options = {}) {
40
+ this.maxSize = options.maxSize ?? 1000;
41
+ this.ttl = options.ttl ?? 0;
42
+ this.onEvict = options.onEvict;
43
+ }
44
+ /**
45
+ * Get a value from the cache
46
+ * Moves the item to the front (most recently used)
47
+ */
48
+ get(key) {
49
+ const node = this.cache.get(key);
50
+ if (!node) {
51
+ this._misses++;
52
+ return undefined;
53
+ }
54
+ // Check TTL
55
+ if (this.ttl > 0 && Date.now() - node.timestamp > this.ttl) {
56
+ this.delete(key);
57
+ this._misses++;
58
+ return undefined;
59
+ }
60
+ // Move to front
61
+ this.moveToFront(node);
62
+ this._hits++;
63
+ return node.value;
64
+ }
65
+ /**
66
+ * Set a value in the cache
67
+ * Evicts least recently used item if at capacity
68
+ */
69
+ set(key, value) {
70
+ const existing = this.cache.get(key);
71
+ if (existing) {
72
+ // Update existing
73
+ existing.value = value;
74
+ existing.timestamp = Date.now();
75
+ this.moveToFront(existing);
76
+ return;
77
+ }
78
+ // Evict if at capacity
79
+ if (this.cache.size >= this.maxSize) {
80
+ this.evictLRU();
81
+ }
82
+ // Create new node
83
+ const node = {
84
+ key,
85
+ value,
86
+ timestamp: Date.now(),
87
+ prev: null,
88
+ next: this.head,
89
+ };
90
+ // Update links
91
+ if (this.head) {
92
+ this.head.prev = node;
93
+ }
94
+ this.head = node;
95
+ if (!this.tail) {
96
+ this.tail = node;
97
+ }
98
+ this.cache.set(key, node);
99
+ }
100
+ /**
101
+ * Check if a key exists (without updating LRU order)
102
+ */
103
+ has(key) {
104
+ const node = this.cache.get(key);
105
+ if (!node)
106
+ return false;
107
+ // Check TTL
108
+ if (this.ttl > 0 && Date.now() - node.timestamp > this.ttl) {
109
+ this.delete(key);
110
+ return false;
111
+ }
112
+ return true;
113
+ }
114
+ /**
115
+ * Delete a key from the cache
116
+ */
117
+ delete(key) {
118
+ const node = this.cache.get(key);
119
+ if (!node)
120
+ return false;
121
+ this.removeNode(node);
122
+ this.cache.delete(key);
123
+ return true;
124
+ }
125
+ /**
126
+ * Clear the entire cache
127
+ */
128
+ clear() {
129
+ this.cache.clear();
130
+ this.head = null;
131
+ this.tail = null;
132
+ this._hits = 0;
133
+ this._misses = 0;
134
+ this._evictions = 0;
135
+ }
136
+ /**
137
+ * Get cache size
138
+ */
139
+ get size() {
140
+ return this.cache.size;
141
+ }
142
+ /**
143
+ * Get cache statistics
144
+ */
145
+ get stats() {
146
+ const total = this._hits + this._misses;
147
+ return {
148
+ size: this.cache.size,
149
+ maxSize: this.maxSize,
150
+ hits: this._hits,
151
+ misses: this._misses,
152
+ hitRate: total > 0 ? this._hits / total : 0,
153
+ evictions: this._evictions,
154
+ };
155
+ }
156
+ /**
157
+ * Get all keys (in LRU order, most recent first)
158
+ */
159
+ keys() {
160
+ const result = [];
161
+ let node = this.head;
162
+ while (node) {
163
+ result.push(node.key);
164
+ node = node.next;
165
+ }
166
+ return result;
167
+ }
168
+ /**
169
+ * Iterate over entries (in LRU order)
170
+ */
171
+ *entries() {
172
+ let node = this.head;
173
+ while (node) {
174
+ yield [node.key, node.value];
175
+ node = node.next;
176
+ }
177
+ }
178
+ /**
179
+ * Prune expired entries (if TTL is set)
180
+ * Call periodically for long-running processes
181
+ */
182
+ prune() {
183
+ if (this.ttl === 0)
184
+ return 0;
185
+ const now = Date.now();
186
+ let pruned = 0;
187
+ for (const [key, node] of this.cache) {
188
+ if (now - node.timestamp > this.ttl) {
189
+ this.delete(key);
190
+ pruned++;
191
+ }
192
+ }
193
+ return pruned;
194
+ }
195
+ // ═══════════════════════════════════════════════════════════════════════
196
+ // PRIVATE METHODS
197
+ // ═══════════════════════════════════════════════════════════════════════
198
+ /**
199
+ * Move a node to the front (most recently used)
200
+ */
201
+ moveToFront(node) {
202
+ if (node === this.head)
203
+ return;
204
+ // Remove from current position
205
+ this.removeNode(node);
206
+ // Add to front
207
+ node.prev = null;
208
+ node.next = this.head;
209
+ if (this.head) {
210
+ this.head.prev = node;
211
+ }
212
+ this.head = node;
213
+ if (!this.tail) {
214
+ this.tail = node;
215
+ }
216
+ }
217
+ /**
218
+ * Remove a node from the linked list (but not from Map)
219
+ */
220
+ removeNode(node) {
221
+ if (node.prev) {
222
+ node.prev.next = node.next;
223
+ }
224
+ else {
225
+ this.head = node.next;
226
+ }
227
+ if (node.next) {
228
+ node.next.prev = node.prev;
229
+ }
230
+ else {
231
+ this.tail = node.prev;
232
+ }
233
+ }
234
+ /**
235
+ * Evict the least recently used item
236
+ */
237
+ evictLRU() {
238
+ if (!this.tail)
239
+ return;
240
+ const evicted = this.tail;
241
+ // Call eviction callback
242
+ if (this.onEvict) {
243
+ this.onEvict(evicted.key, evicted.value);
244
+ }
245
+ // Remove from list
246
+ this.removeNode(evicted);
247
+ this.cache.delete(evicted.key);
248
+ this._evictions++;
249
+ }
250
+ }
251
+ // CONVENIENCE FACTORIES
252
+ /**
253
+ * Create a small LRU cache (100 items)
254
+ */
255
+ export function createSmallCache(ttl = 0) {
256
+ return new LRUCache({ maxSize: 100, ttl });
257
+ }
258
+ /**
259
+ * Create a medium LRU cache (1000 items)
260
+ */
261
+ export function createMediumCache(ttl = 0) {
262
+ return new LRUCache({ maxSize: 1000, ttl });
263
+ }
264
+ /**
265
+ * Create a large LRU cache (10000 items)
266
+ */
267
+ export function createLargeCache(ttl = 0) {
268
+ return new LRUCache({ maxSize: 10000, ttl });
269
+ }