@dynlabs/react-native-immutable-file-cache 1.0.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 (113) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +415 -0
  3. package/lib/commonjs/adapters/memoryAdapter.js +266 -0
  4. package/lib/commonjs/adapters/memoryAdapter.js.map +1 -0
  5. package/lib/commonjs/adapters/rnfsAdapter.js +259 -0
  6. package/lib/commonjs/adapters/rnfsAdapter.js.map +1 -0
  7. package/lib/commonjs/adapters/webAdapter.js +432 -0
  8. package/lib/commonjs/adapters/webAdapter.js.map +1 -0
  9. package/lib/commonjs/core/adapter.js +2 -0
  10. package/lib/commonjs/core/adapter.js.map +1 -0
  11. package/lib/commonjs/core/cacheEngine.js +578 -0
  12. package/lib/commonjs/core/cacheEngine.js.map +1 -0
  13. package/lib/commonjs/core/errors.js +83 -0
  14. package/lib/commonjs/core/errors.js.map +1 -0
  15. package/lib/commonjs/core/hash.js +83 -0
  16. package/lib/commonjs/core/hash.js.map +1 -0
  17. package/lib/commonjs/core/indexStore.js +175 -0
  18. package/lib/commonjs/core/indexStore.js.map +1 -0
  19. package/lib/commonjs/core/mutex.js +143 -0
  20. package/lib/commonjs/core/mutex.js.map +1 -0
  21. package/lib/commonjs/core/prune.js +127 -0
  22. package/lib/commonjs/core/prune.js.map +1 -0
  23. package/lib/commonjs/core/types.js +6 -0
  24. package/lib/commonjs/core/types.js.map +1 -0
  25. package/lib/commonjs/factory.js +56 -0
  26. package/lib/commonjs/factory.js.map +1 -0
  27. package/lib/commonjs/index.js +110 -0
  28. package/lib/commonjs/index.js.map +1 -0
  29. package/lib/commonjs/index.native.js +74 -0
  30. package/lib/commonjs/index.native.js.map +1 -0
  31. package/lib/commonjs/index.web.js +75 -0
  32. package/lib/commonjs/index.web.js.map +1 -0
  33. package/lib/commonjs/types/react-native-fs.d.js +2 -0
  34. package/lib/commonjs/types/react-native-fs.d.js.map +1 -0
  35. package/lib/module/adapters/memoryAdapter.js +261 -0
  36. package/lib/module/adapters/memoryAdapter.js.map +1 -0
  37. package/lib/module/adapters/rnfsAdapter.js +251 -0
  38. package/lib/module/adapters/rnfsAdapter.js.map +1 -0
  39. package/lib/module/adapters/webAdapter.js +426 -0
  40. package/lib/module/adapters/webAdapter.js.map +1 -0
  41. package/lib/module/core/adapter.js +2 -0
  42. package/lib/module/core/adapter.js.map +1 -0
  43. package/lib/module/core/cacheEngine.js +571 -0
  44. package/lib/module/core/cacheEngine.js.map +1 -0
  45. package/lib/module/core/errors.js +71 -0
  46. package/lib/module/core/errors.js.map +1 -0
  47. package/lib/module/core/hash.js +76 -0
  48. package/lib/module/core/hash.js.map +1 -0
  49. package/lib/module/core/indexStore.js +168 -0
  50. package/lib/module/core/indexStore.js.map +1 -0
  51. package/lib/module/core/mutex.js +135 -0
  52. package/lib/module/core/mutex.js.map +1 -0
  53. package/lib/module/core/prune.js +116 -0
  54. package/lib/module/core/prune.js.map +1 -0
  55. package/lib/module/core/types.js +2 -0
  56. package/lib/module/core/types.js.map +1 -0
  57. package/lib/module/factory.js +49 -0
  58. package/lib/module/factory.js.map +1 -0
  59. package/lib/module/index.js +41 -0
  60. package/lib/module/index.js.map +1 -0
  61. package/lib/module/index.native.js +54 -0
  62. package/lib/module/index.native.js.map +1 -0
  63. package/lib/module/index.web.js +55 -0
  64. package/lib/module/index.web.js.map +1 -0
  65. package/lib/module/types/react-native-fs.d.js +2 -0
  66. package/lib/module/types/react-native-fs.d.js.map +1 -0
  67. package/lib/typescript/src/adapters/memoryAdapter.d.ts +23 -0
  68. package/lib/typescript/src/adapters/memoryAdapter.d.ts.map +1 -0
  69. package/lib/typescript/src/adapters/rnfsAdapter.d.ts +18 -0
  70. package/lib/typescript/src/adapters/rnfsAdapter.d.ts.map +1 -0
  71. package/lib/typescript/src/adapters/webAdapter.d.ts +30 -0
  72. package/lib/typescript/src/adapters/webAdapter.d.ts.map +1 -0
  73. package/lib/typescript/src/core/adapter.d.ts +105 -0
  74. package/lib/typescript/src/core/adapter.d.ts.map +1 -0
  75. package/lib/typescript/src/core/cacheEngine.d.ts +99 -0
  76. package/lib/typescript/src/core/cacheEngine.d.ts.map +1 -0
  77. package/lib/typescript/src/core/errors.d.ts +54 -0
  78. package/lib/typescript/src/core/errors.d.ts.map +1 -0
  79. package/lib/typescript/src/core/hash.d.ts +20 -0
  80. package/lib/typescript/src/core/hash.d.ts.map +1 -0
  81. package/lib/typescript/src/core/indexStore.d.ts +34 -0
  82. package/lib/typescript/src/core/indexStore.d.ts.map +1 -0
  83. package/lib/typescript/src/core/mutex.d.ts +49 -0
  84. package/lib/typescript/src/core/mutex.d.ts.map +1 -0
  85. package/lib/typescript/src/core/prune.d.ts +39 -0
  86. package/lib/typescript/src/core/prune.d.ts.map +1 -0
  87. package/lib/typescript/src/core/types.d.ts +109 -0
  88. package/lib/typescript/src/core/types.d.ts.map +1 -0
  89. package/lib/typescript/src/factory.d.ts +46 -0
  90. package/lib/typescript/src/factory.d.ts.map +1 -0
  91. package/lib/typescript/src/index.d.ts +20 -0
  92. package/lib/typescript/src/index.d.ts.map +1 -0
  93. package/lib/typescript/src/index.native.d.ts +37 -0
  94. package/lib/typescript/src/index.native.d.ts.map +1 -0
  95. package/lib/typescript/src/index.web.d.ts +38 -0
  96. package/lib/typescript/src/index.web.d.ts.map +1 -0
  97. package/package.json +125 -0
  98. package/src/adapters/memoryAdapter.ts +307 -0
  99. package/src/adapters/rnfsAdapter.ts +283 -0
  100. package/src/adapters/webAdapter.ts +480 -0
  101. package/src/core/adapter.ts +128 -0
  102. package/src/core/cacheEngine.ts +634 -0
  103. package/src/core/errors.ts +82 -0
  104. package/src/core/hash.ts +78 -0
  105. package/src/core/indexStore.ts +184 -0
  106. package/src/core/mutex.ts +134 -0
  107. package/src/core/prune.ts +145 -0
  108. package/src/core/types.ts +165 -0
  109. package/src/factory.ts +60 -0
  110. package/src/index.native.ts +58 -0
  111. package/src/index.ts +82 -0
  112. package/src/index.web.ts +59 -0
  113. package/src/types/react-native-fs.d.ts +75 -0
@@ -0,0 +1 @@
1
+ {"version":3,"names":["CacheError","Error","constructor","message","name","Object","setPrototypeOf","new","target","prototype","exports","UnsupportedSourceError","code","sourceType","adapterKind","AdapterIOError","operation","path","cause","CorruptIndexError","reason","ImmutableConflictError","key","EntryNotFoundError"],"sourceRoot":"../../../src","sources":["core/errors.ts"],"mappings":";;;;;;AAEA;AACA;AACA;AACO,MAAeA,UAAU,SAASC,KAAK,CAAC;EAG7CC,WAAWA,CAACC,OAAe,EAAE;IAC3B,KAAK,CAACA,OAAO,CAAC;IACd,IAAI,CAACC,IAAI,GAAG,IAAI,CAACF,WAAW,CAACE,IAAI;IACjCC,MAAM,CAACC,cAAc,CAAC,IAAI,EAAEC,GAAG,CAACC,MAAM,CAACC,SAAS,CAAC;EACnD;AACF;;AAEA;AACA;AACA;AAFAC,OAAA,CAAAV,UAAA,GAAAA,UAAA;AAGO,MAAMW,sBAAsB,SAASX,UAAU,CAAC;EAC5CY,IAAI,GAAG,oBAAoB;EAEpCV,WAAWA,CACOW,UAAiC,EACjCC,WAAmB,EACnC;IACA,KAAK,CAAC,YAAYA,WAAW,mCAAmCD,UAAU,GAAG,CAAC;IAAC,KAH/DA,UAAiC,GAAjCA,UAAiC;IAAA,KACjCC,WAAmB,GAAnBA,WAAmB;EAGrC;AACF;;AAEA;AACA;AACA;AAFAJ,OAAA,CAAAC,sBAAA,GAAAA,sBAAA;AAGO,MAAMI,cAAc,SAASf,UAAU,CAAC;EACpCY,IAAI,GAAG,kBAAkB;EAElCV,WAAWA,CACOc,SAAiB,EACjBC,IAAY,EACZC,KAAa,EAC7B;IACA,KAAK,CACH,6BAA6BF,SAAS,cAAcC,IAAI,MAAMC,KAAK,EAAEf,OAAO,IAAI,SAAS,EAC3F,CAAC;IAAC,KANca,SAAiB,GAAjBA,SAAiB;IAAA,KACjBC,IAAY,GAAZA,IAAY;IAAA,KACZC,KAAa,GAAbA,KAAa;EAK/B;AACF;;AAEA;AACA;AACA;AAFAR,OAAA,CAAAK,cAAA,GAAAA,cAAA;AAGO,MAAMI,iBAAiB,SAASnB,UAAU,CAAC;EACvCY,IAAI,GAAG,eAAe;EAE/BV,WAAWA,CACOkB,MAAc,EACdF,KAAa,EAC7B;IACA,KAAK,CAAC,2BAA2BE,MAAM,EAAE,CAAC;IAAC,KAH3BA,MAAc,GAAdA,MAAc;IAAA,KACdF,KAAa,GAAbA,KAAa;EAG/B;AACF;;AAEA;AACA;AACA;AACA;AAHAR,OAAA,CAAAS,iBAAA,GAAAA,iBAAA;AAIO,MAAME,sBAAsB,SAASrB,UAAU,CAAC;EAC5CY,IAAI,GAAG,oBAAoB;EAEpCV,WAAWA,CAAiBoB,GAAW,EAAE;IACvC,KAAK,CAAC,8CAA8CA,GAAG,GAAG,CAAC;IAAC,KADlCA,GAAW,GAAXA,GAAW;EAEvC;AACF;;AAEA;AACA;AACA;AAFAZ,OAAA,CAAAW,sBAAA,GAAAA,sBAAA;AAGO,MAAME,kBAAkB,SAASvB,UAAU,CAAC;EACxCY,IAAI,GAAG,iBAAiB;EAEjCV,WAAWA,CAAiBoB,GAAW,EAAE;IACvC,KAAK,CAAC,kCAAkCA,GAAG,GAAG,CAAC;IAAC,KADtBA,GAAW,GAAXA,GAAW;EAEvC;AACF;AAACZ,OAAA,CAAAa,kBAAA,GAAAA,kBAAA","ignoreList":[]}
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.hash = hash;
7
+ exports.hashSync = hashSync;
8
+ /**
9
+ * Cross-platform SHA-256 hashing utility.
10
+ * Uses SubtleCrypto on web and native platforms that support it.
11
+ */
12
+
13
+ /**
14
+ * Converts an ArrayBuffer to a lowercase hex string.
15
+ */
16
+ function arrayBufferToHex(buffer) {
17
+ const bytes = new Uint8Array(buffer);
18
+ let hex = "";
19
+ for (let i = 0; i < bytes.length; i++) {
20
+ hex += bytes[i].toString(16).padStart(2, "0");
21
+ }
22
+ return hex;
23
+ }
24
+
25
+ /**
26
+ * Converts a string to a Uint8Array using UTF-8 encoding.
27
+ */
28
+ function stringToUint8Array(str) {
29
+ const encoder = new TextEncoder();
30
+ return encoder.encode(str);
31
+ }
32
+
33
+ /**
34
+ * Computes SHA-256 hash of the input string.
35
+ * Returns lowercase hex string.
36
+ *
37
+ * Uses SubtleCrypto API which is available in:
38
+ * - Modern browsers
39
+ * - React Native (via Hermes or polyfill)
40
+ * - Node.js 15+
41
+ */
42
+ async function hash(input) {
43
+ // Use SubtleCrypto (available in browsers and modern RN)
44
+ if (typeof globalThis.crypto?.subtle?.digest === "function") {
45
+ const data = stringToUint8Array(input);
46
+ const hashBuffer = await globalThis.crypto.subtle.digest("SHA-256", data.buffer);
47
+ return arrayBufferToHex(hashBuffer);
48
+ }
49
+
50
+ // Fallback: Simple hash for environments without crypto
51
+ // This is a basic djb2-based hash - NOT cryptographically secure
52
+ // Should only be used as last resort fallback
53
+ return fallbackHash(input);
54
+ }
55
+
56
+ /**
57
+ * Simple non-cryptographic hash fallback.
58
+ * Used only when SubtleCrypto is unavailable.
59
+ */
60
+ function fallbackHash(input) {
61
+ let h1 = 0xdeadbeef;
62
+ let h2 = 0x41c6ce57;
63
+ for (let i = 0; i < input.length; i++) {
64
+ const ch = input.charCodeAt(i);
65
+ h1 = Math.imul(h1 ^ ch, 2654435761);
66
+ h2 = Math.imul(h2 ^ ch, 1597334677);
67
+ }
68
+ h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507);
69
+ h1 ^= Math.imul(h2 ^ h2 >>> 13, 3266489909);
70
+ h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507);
71
+ h2 ^= Math.imul(h1 ^ h1 >>> 13, 3266489909);
72
+ const result = 4294967296 * (2097151 & h2) + (h1 >>> 0);
73
+ return result.toString(16).padStart(16, "0");
74
+ }
75
+
76
+ /**
77
+ * Synchronous hash for cases where async is not possible.
78
+ * Uses fallback algorithm - prefer async hash() when possible.
79
+ */
80
+ function hashSync(input) {
81
+ return fallbackHash(input);
82
+ }
83
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["arrayBufferToHex","buffer","bytes","Uint8Array","hex","i","length","toString","padStart","stringToUint8Array","str","encoder","TextEncoder","encode","hash","input","globalThis","crypto","subtle","digest","data","hashBuffer","fallbackHash","h1","h2","ch","charCodeAt","Math","imul","result","hashSync"],"sourceRoot":"../../../src","sources":["core/hash.ts"],"mappings":";;;;;;;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,SAASA,gBAAgBA,CAACC,MAAmB,EAAU;EACrD,MAAMC,KAAK,GAAG,IAAIC,UAAU,CAACF,MAAM,CAAC;EACpC,IAAIG,GAAG,GAAG,EAAE;EACZ,KAAK,IAAIC,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGH,KAAK,CAACI,MAAM,EAAED,CAAC,EAAE,EAAE;IACrCD,GAAG,IAAIF,KAAK,CAACG,CAAC,CAAC,CAACE,QAAQ,CAAC,EAAE,CAAC,CAACC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC;EAC/C;EACA,OAAOJ,GAAG;AACZ;;AAEA;AACA;AACA;AACA,SAASK,kBAAkBA,CAACC,GAAW,EAAc;EACnD,MAAMC,OAAO,GAAG,IAAIC,WAAW,CAAC,CAAC;EACjC,OAAOD,OAAO,CAACE,MAAM,CAACH,GAAG,CAAC;AAC5B;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,eAAeI,IAAIA,CAACC,KAAa,EAAmB;EACzD;EACA,IAAI,OAAOC,UAAU,CAACC,MAAM,EAAEC,MAAM,EAAEC,MAAM,KAAK,UAAU,EAAE;IAC3D,MAAMC,IAAI,GAAGX,kBAAkB,CAACM,KAAK,CAAC;IACtC,MAAMM,UAAU,GAAG,MAAML,UAAU,CAACC,MAAM,CAACC,MAAM,CAACC,MAAM,CAAC,SAAS,EAAEC,IAAI,CAACnB,MAAqB,CAAC;IAC/F,OAAOD,gBAAgB,CAACqB,UAAU,CAAC;EACrC;;EAEA;EACA;EACA;EACA,OAAOC,YAAY,CAACP,KAAK,CAAC;AAC5B;;AAEA;AACA;AACA;AACA;AACA,SAASO,YAAYA,CAACP,KAAa,EAAU;EAC3C,IAAIQ,EAAE,GAAG,UAAU;EACnB,IAAIC,EAAE,GAAG,UAAU;EAEnB,KAAK,IAAInB,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGU,KAAK,CAACT,MAAM,EAAED,CAAC,EAAE,EAAE;IACrC,MAAMoB,EAAE,GAAGV,KAAK,CAACW,UAAU,CAACrB,CAAC,CAAC;IAC9BkB,EAAE,GAAGI,IAAI,CAACC,IAAI,CAACL,EAAE,GAAGE,EAAE,EAAE,UAAU,CAAC;IACnCD,EAAE,GAAGG,IAAI,CAACC,IAAI,CAACJ,EAAE,GAAGC,EAAE,EAAE,UAAU,CAAC;EACrC;EAEAF,EAAE,GAAGI,IAAI,CAACC,IAAI,CAACL,EAAE,GAAIA,EAAE,KAAK,EAAG,EAAE,UAAU,CAAC;EAC5CA,EAAE,IAAII,IAAI,CAACC,IAAI,CAACJ,EAAE,GAAIA,EAAE,KAAK,EAAG,EAAE,UAAU,CAAC;EAC7CA,EAAE,GAAGG,IAAI,CAACC,IAAI,CAACJ,EAAE,GAAIA,EAAE,KAAK,EAAG,EAAE,UAAU,CAAC;EAC5CA,EAAE,IAAIG,IAAI,CAACC,IAAI,CAACL,EAAE,GAAIA,EAAE,KAAK,EAAG,EAAE,UAAU,CAAC;EAE7C,MAAMM,MAAM,GAAG,UAAU,IAAI,OAAO,GAAGL,EAAE,CAAC,IAAID,EAAE,KAAK,CAAC,CAAC;EACvD,OAAOM,MAAM,CAACtB,QAAQ,CAAC,EAAE,CAAC,CAACC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC;AAC9C;;AAEA;AACA;AACA;AACA;AACO,SAASsB,QAAQA,CAACf,KAAa,EAAU;EAC9C,OAAOO,YAAY,CAACP,KAAK,CAAC;AAC5B","ignoreList":[]}
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.IndexStore = void 0;
7
+ var _errors = require("./errors");
8
+ var _prune = require("./prune");
9
+ const INDEX_VERSION = 1;
10
+
11
+ /**
12
+ * Manages persistence of the cache index via the storage adapter.
13
+ */
14
+ class IndexStore {
15
+ constructor(adapter, indexPath) {
16
+ this._adapter = adapter;
17
+ this._indexPath = indexPath;
18
+ }
19
+
20
+ /**
21
+ * Load index from storage.
22
+ * Returns empty index if file doesn't exist.
23
+ * Throws CorruptIndexError if index is malformed.
24
+ */
25
+ async load() {
26
+ try {
27
+ const exists = await this._adapter.exists(this._indexPath);
28
+ if (!exists) {
29
+ return (0, _prune.createEmptyIndex)();
30
+ }
31
+ const content = await this._adapter.readText(this._indexPath, "utf8");
32
+ const parsed = JSON.parse(content);
33
+ return this._validateIndex(parsed);
34
+ } catch (error) {
35
+ if (error instanceof _errors.CorruptIndexError) {
36
+ throw error;
37
+ }
38
+ if (error instanceof SyntaxError) {
39
+ throw new _errors.CorruptIndexError("Invalid JSON", error);
40
+ }
41
+ // File doesn't exist or other read error - return empty
42
+ if (error instanceof _errors.AdapterIOError) {
43
+ return (0, _prune.createEmptyIndex)();
44
+ }
45
+ throw error;
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Save index atomically via the adapter.
51
+ */
52
+ async save(index) {
53
+ const content = JSON.stringify(index, null, 2);
54
+ await this._adapter.writeTextAtomic(this._indexPath, content, "utf8");
55
+ }
56
+
57
+ /**
58
+ * Validate and rebuild index from filesystem if corrupt.
59
+ * Scans the entries directory and reconstructs metadata.
60
+ */
61
+ async rebuild(entriesDir) {
62
+ const entries = {};
63
+ let totalSizeBytes = 0;
64
+ try {
65
+ const files = await this._adapter.listDir(entriesDir);
66
+ for (const file of files) {
67
+ try {
68
+ const filePath = `${entriesDir}/${file}`;
69
+ const stat = await this._adapter.stat(filePath);
70
+
71
+ // Extract hash and extension from filename
72
+ const lastDot = file.lastIndexOf(".");
73
+ const hash = lastDot > 0 ? file.substring(0, lastDot) : file;
74
+ const ext = lastDot > 0 ? file.substring(lastDot) : "";
75
+
76
+ // Create minimal entry metadata
77
+ // Note: We lose the original key during rebuild
78
+ const entry = {
79
+ key: hash,
80
+ // Use hash as key since original is lost
81
+ hash,
82
+ ext,
83
+ sizeBytes: stat.sizeBytes,
84
+ createdAt: stat.mtimeMs,
85
+ lastAccessedAt: stat.mtimeMs
86
+ };
87
+ entries[hash] = entry;
88
+ totalSizeBytes += stat.sizeBytes;
89
+ } catch {
90
+ // Skip files that can't be stat'd
91
+ continue;
92
+ }
93
+ }
94
+ } catch {
95
+ // If we can't list the directory, return empty index
96
+ return (0, _prune.createEmptyIndex)();
97
+ }
98
+ const rebuiltIndex = {
99
+ version: INDEX_VERSION,
100
+ entries,
101
+ totalSizeBytes,
102
+ lastModifiedAt: Date.now()
103
+ };
104
+
105
+ // Save the rebuilt index
106
+ await this.save(rebuiltIndex);
107
+ return rebuiltIndex;
108
+ }
109
+
110
+ /**
111
+ * Validates that the parsed object is a valid ICacheIndex.
112
+ */
113
+ _validateIndex(parsed) {
114
+ if (typeof parsed !== "object" || parsed === null) {
115
+ throw new _errors.CorruptIndexError("Index is not an object");
116
+ }
117
+ const obj = parsed;
118
+
119
+ // Check version
120
+ if (obj.version !== INDEX_VERSION) {
121
+ throw new _errors.CorruptIndexError(`Unsupported version: ${String(obj.version)}`);
122
+ }
123
+
124
+ // Check entries
125
+ if (typeof obj.entries !== "object" || obj.entries === null) {
126
+ throw new _errors.CorruptIndexError("Entries is not an object");
127
+ }
128
+
129
+ // Validate each entry has required fields
130
+ const entries = obj.entries;
131
+ for (const [key, entry] of Object.entries(entries)) {
132
+ this._validateEntry(key, entry);
133
+ }
134
+
135
+ // Check totalSizeBytes
136
+ if (typeof obj.totalSizeBytes !== "number" || obj.totalSizeBytes < 0) {
137
+ throw new _errors.CorruptIndexError("Invalid totalSizeBytes");
138
+ }
139
+
140
+ // Check lastModifiedAt
141
+ if (typeof obj.lastModifiedAt !== "number") {
142
+ throw new _errors.CorruptIndexError("Invalid lastModifiedAt");
143
+ }
144
+ return {
145
+ version: INDEX_VERSION,
146
+ entries: entries,
147
+ totalSizeBytes: obj.totalSizeBytes,
148
+ lastModifiedAt: obj.lastModifiedAt
149
+ };
150
+ }
151
+
152
+ /**
153
+ * Validates that an entry has all required fields.
154
+ */
155
+ _validateEntry(key, entry) {
156
+ if (typeof entry !== "object" || entry === null) {
157
+ throw new _errors.CorruptIndexError(`Entry "${key}" is not an object`);
158
+ }
159
+ const obj = entry;
160
+ const requiredStrings = ["key", "hash", "ext"];
161
+ const requiredNumbers = ["sizeBytes", "createdAt", "lastAccessedAt"];
162
+ for (const field of requiredStrings) {
163
+ if (typeof obj[field] !== "string") {
164
+ throw new _errors.CorruptIndexError(`Entry "${key}" missing string field "${field}"`);
165
+ }
166
+ }
167
+ for (const field of requiredNumbers) {
168
+ if (typeof obj[field] !== "number") {
169
+ throw new _errors.CorruptIndexError(`Entry "${key}" missing number field "${field}"`);
170
+ }
171
+ }
172
+ }
173
+ }
174
+ exports.IndexStore = IndexStore;
175
+ //# sourceMappingURL=indexStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_errors","require","_prune","INDEX_VERSION","IndexStore","constructor","adapter","indexPath","_adapter","_indexPath","load","exists","createEmptyIndex","content","readText","parsed","JSON","parse","_validateIndex","error","CorruptIndexError","SyntaxError","AdapterIOError","save","index","stringify","writeTextAtomic","rebuild","entriesDir","entries","totalSizeBytes","files","listDir","file","filePath","stat","lastDot","lastIndexOf","hash","substring","ext","entry","key","sizeBytes","createdAt","mtimeMs","lastAccessedAt","rebuiltIndex","version","lastModifiedAt","Date","now","obj","String","Object","_validateEntry","requiredStrings","requiredNumbers","field","exports"],"sourceRoot":"../../../src","sources":["core/indexStore.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.Mutex = exports.KeyedMutex = void 0;
7
+ /**
8
+ * Async mutex for serializing critical sections.
9
+ * Ensures only one operation runs at a time within a critical section.
10
+ */
11
+ class Mutex {
12
+ _queue = [];
13
+ _locked = false;
14
+
15
+ /**
16
+ * Acquires the mutex lock.
17
+ * Returns a release function that must be called when done.
18
+ */
19
+ async acquire() {
20
+ return new Promise(resolve => {
21
+ const tryAcquire = () => {
22
+ if (!this._locked) {
23
+ this._locked = true;
24
+ resolve(this._createRelease());
25
+ } else {
26
+ this._queue.push(tryAcquire);
27
+ }
28
+ };
29
+ tryAcquire();
30
+ });
31
+ }
32
+
33
+ /**
34
+ * Creates a release function for the current lock holder.
35
+ */
36
+ _createRelease() {
37
+ let released = false;
38
+ return () => {
39
+ if (released) {
40
+ return; // Prevent double-release
41
+ }
42
+ released = true;
43
+ this._locked = false;
44
+ const next = this._queue.shift();
45
+ if (next) {
46
+ next();
47
+ }
48
+ };
49
+ }
50
+
51
+ /**
52
+ * Returns whether the mutex is currently locked.
53
+ */
54
+ get isLocked() {
55
+ return this._locked;
56
+ }
57
+
58
+ /**
59
+ * Executes a function with the mutex held.
60
+ * Automatically releases the mutex when done.
61
+ */
62
+ async runExclusive(fn) {
63
+ const release = await this.acquire();
64
+ try {
65
+ return await fn();
66
+ } finally {
67
+ release();
68
+ }
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Keyed mutex for per-key locking.
74
+ * Allows concurrent operations on different keys while serializing same-key operations.
75
+ */
76
+ exports.Mutex = Mutex;
77
+ class KeyedMutex {
78
+ _mutexes = new Map();
79
+ _refCounts = new Map();
80
+
81
+ /**
82
+ * Acquires lock for a specific key.
83
+ * Returns a release function that must be called when done.
84
+ */
85
+ async acquire(key) {
86
+ // Get or create mutex for this key
87
+ let mutex = this._mutexes.get(key);
88
+ if (!mutex) {
89
+ mutex = new Mutex();
90
+ this._mutexes.set(key, mutex);
91
+ this._refCounts.set(key, 0);
92
+ }
93
+
94
+ // Increment ref count
95
+ this._refCounts.set(key, (this._refCounts.get(key) ?? 0) + 1);
96
+
97
+ // Acquire the mutex
98
+ const innerRelease = await mutex.acquire();
99
+
100
+ // Return wrapped release that cleans up when ref count hits 0
101
+ let released = false;
102
+ return () => {
103
+ if (released) {
104
+ return;
105
+ }
106
+ released = true;
107
+
108
+ // Release the inner mutex
109
+ innerRelease();
110
+
111
+ // Decrement ref count and clean up if zero
112
+ const count = (this._refCounts.get(key) ?? 1) - 1;
113
+ if (count <= 0) {
114
+ this._mutexes.delete(key);
115
+ this._refCounts.delete(key);
116
+ } else {
117
+ this._refCounts.set(key, count);
118
+ }
119
+ };
120
+ }
121
+
122
+ /**
123
+ * Executes a function with the keyed mutex held.
124
+ * Automatically releases the mutex when done.
125
+ */
126
+ async runExclusive(key, fn) {
127
+ const release = await this.acquire(key);
128
+ try {
129
+ return await fn();
130
+ } finally {
131
+ release();
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Returns the number of active keys with pending operations.
137
+ */
138
+ get activeKeyCount() {
139
+ return this._mutexes.size;
140
+ }
141
+ }
142
+ exports.KeyedMutex = KeyedMutex;
143
+ //# sourceMappingURL=mutex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Mutex","_queue","_locked","acquire","Promise","resolve","tryAcquire","_createRelease","push","released","next","shift","isLocked","runExclusive","fn","release","exports","KeyedMutex","_mutexes","Map","_refCounts","key","mutex","get","set","innerRelease","count","delete","activeKeyCount","size"],"sourceRoot":"../../../src","sources":["core/mutex.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.addEntryToIndex = addEntryToIndex;
7
+ exports.createEmptyIndex = createEmptyIndex;
8
+ exports.getExpiredEntries = getExpiredEntries;
9
+ exports.getLruPruneTargets = getLruPruneTargets;
10
+ exports.removeEntriesFromIndex = removeEntriesFromIndex;
11
+ exports.touchEntry = touchEntry;
12
+ /**
13
+ * Options for pruning operations.
14
+ */
15
+
16
+ /**
17
+ * Identifies entries to remove based on TTL expiration.
18
+ * Returns entries that have expired (expiresAt < now).
19
+ */
20
+ function getExpiredEntries(index, now = Date.now()) {
21
+ const expired = [];
22
+ for (const entry of Object.values(index.entries)) {
23
+ if (entry.expiresAt !== undefined && entry.expiresAt < now) {
24
+ expired.push(entry);
25
+ }
26
+ }
27
+ return expired;
28
+ }
29
+
30
+ /**
31
+ * Identifies entries to remove based on LRU policy to meet size limit.
32
+ * Sorts entries by lastAccessedAt (oldest first) and returns entries
33
+ * that need to be removed to get under maxSizeBytes.
34
+ */
35
+ function getLruPruneTargets(index, maxSizeBytes) {
36
+ if (index.totalSizeBytes <= maxSizeBytes) {
37
+ return [];
38
+ }
39
+
40
+ // Sort entries by lastAccessedAt ascending (oldest first = LRU candidates)
41
+ const sortedEntries = Object.values(index.entries).sort((a, b) => a.lastAccessedAt - b.lastAccessedAt);
42
+ const toRemove = [];
43
+ let currentSize = index.totalSizeBytes;
44
+ for (const entry of sortedEntries) {
45
+ if (currentSize <= maxSizeBytes) {
46
+ break;
47
+ }
48
+ toRemove.push(entry);
49
+ currentSize -= entry.sizeBytes;
50
+ }
51
+ return toRemove;
52
+ }
53
+
54
+ /**
55
+ * Creates a new index with the specified entries removed.
56
+ * Returns a new ICacheIndex without mutating the original.
57
+ */
58
+ function removeEntriesFromIndex(index, keysToRemove) {
59
+ const keySet = new Set(keysToRemove);
60
+ const newEntries = {};
61
+ let newTotalSize = 0;
62
+ for (const [key, entry] of Object.entries(index.entries)) {
63
+ if (!keySet.has(key)) {
64
+ newEntries[key] = entry;
65
+ newTotalSize += entry.sizeBytes;
66
+ }
67
+ }
68
+ return {
69
+ version: 1,
70
+ entries: newEntries,
71
+ totalSizeBytes: newTotalSize,
72
+ lastModifiedAt: Date.now()
73
+ };
74
+ }
75
+
76
+ /**
77
+ * Adds or updates an entry in the index.
78
+ * Returns a new ICacheIndex without mutating the original.
79
+ */
80
+ function addEntryToIndex(index, entry) {
81
+ const existingEntry = index.entries[entry.key];
82
+ const sizeDelta = entry.sizeBytes - (existingEntry?.sizeBytes ?? 0);
83
+ return {
84
+ version: 1,
85
+ entries: {
86
+ ...index.entries,
87
+ [entry.key]: entry
88
+ },
89
+ totalSizeBytes: index.totalSizeBytes + sizeDelta,
90
+ lastModifiedAt: Date.now()
91
+ };
92
+ }
93
+
94
+ /**
95
+ * Updates the lastAccessedAt timestamp for an entry.
96
+ * Returns a new ICacheIndex without mutating the original.
97
+ */
98
+ function touchEntry(index, key, accessedAt = Date.now()) {
99
+ const entry = index.entries[key];
100
+ if (!entry) {
101
+ return index;
102
+ }
103
+ return {
104
+ ...index,
105
+ entries: {
106
+ ...index.entries,
107
+ [key]: {
108
+ ...entry,
109
+ lastAccessedAt: accessedAt
110
+ }
111
+ },
112
+ lastModifiedAt: accessedAt
113
+ };
114
+ }
115
+
116
+ /**
117
+ * Creates an empty cache index.
118
+ */
119
+ function createEmptyIndex() {
120
+ return {
121
+ version: 1,
122
+ entries: {},
123
+ totalSizeBytes: 0,
124
+ lastModifiedAt: Date.now()
125
+ };
126
+ }
127
+ //# sourceMappingURL=prune.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["getExpiredEntries","index","now","Date","expired","entry","Object","values","entries","expiresAt","undefined","push","getLruPruneTargets","maxSizeBytes","totalSizeBytes","sortedEntries","sort","a","b","lastAccessedAt","toRemove","currentSize","sizeBytes","removeEntriesFromIndex","keysToRemove","keySet","Set","newEntries","newTotalSize","key","has","version","lastModifiedAt","addEntryToIndex","existingEntry","sizeDelta","touchEntry","accessedAt","createEmptyIndex"],"sourceRoot":"../../../src","sources":["core/prune.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["core/types.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createCacheEngineSync = createCacheEngineSync;
7
+ exports.createImmutableFileCache = createImmutableFileCache;
8
+ var _cacheEngine = require("./core/cacheEngine");
9
+ /**
10
+ * Creates an immutable file cache instance.
11
+ *
12
+ * This is the base factory function. Platform-specific entrypoints
13
+ * (index.native.ts, index.web.ts) wrap this to auto-select the appropriate adapter.
14
+ *
15
+ * @param options - Cache configuration options
16
+ * @param adapter - Storage adapter (required in base factory)
17
+ * @returns Initialized CacheEngine instance
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * import { createImmutableFileCache } from "react-native-immutable-file-cache";
22
+ *
23
+ * const cache = await createImmutableFileCache({
24
+ * namespace: "images",
25
+ * defaultTtlMs: 7 * 24 * 60 * 60 * 1000, // 7 days
26
+ * });
27
+ * ```
28
+ */
29
+ async function createImmutableFileCache(options) {
30
+ const {
31
+ autoInit = true,
32
+ adapter,
33
+ ...config
34
+ } = options;
35
+ const engine = new _cacheEngine.CacheEngine(config, adapter);
36
+ if (autoInit) {
37
+ await engine.init();
38
+ }
39
+ return engine;
40
+ }
41
+
42
+ /**
43
+ * Creates a cache engine without auto-initialization.
44
+ * Useful when you need to control initialization timing.
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * const engine = createCacheEngineSync({ namespace: "images" }, adapter);
49
+ * // Later...
50
+ * await engine.init();
51
+ * ```
52
+ */
53
+ function createCacheEngineSync(config, adapter) {
54
+ return new _cacheEngine.CacheEngine(config, adapter);
55
+ }
56
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_cacheEngine","require","createImmutableFileCache","options","autoInit","adapter","config","engine","CacheEngine","init","createCacheEngineSync"],"sourceRoot":"../../src","sources":["factory.ts"],"mappings":";;;;;;;AAEA,IAAAA,YAAA,GAAAC,OAAA;AAUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,eAAeC,wBAAwBA,CAC5CC,OAA2D,EACrC;EACtB,MAAM;IAAEC,QAAQ,GAAG,IAAI;IAAEC,OAAO;IAAE,GAAGC;EAAO,CAAC,GAAGH,OAAO;EAEvD,MAAMI,MAAM,GAAG,IAAIC,wBAAW,CAACF,MAAM,EAAED,OAAO,CAAC;EAE/C,IAAID,QAAQ,EAAE;IACZ,MAAMG,MAAM,CAACE,IAAI,CAAC,CAAC;EACrB;EAEA,OAAOF,MAAM;AACf;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASG,qBAAqBA,CAACJ,MAAoB,EAAED,OAAwB,EAAe;EACjG,OAAO,IAAIG,wBAAW,CAACF,MAAM,EAAED,OAAO,CAAC;AACzC","ignoreList":[]}