@chriscdn/file-cache 0.0.11 → 0.0.13

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.
@@ -10,9 +10,9 @@ const pause = async (ms) => new Promise((resolve) => setTimeout(resolve, ms));
10
10
  const testPDFFile = "./__tests__/pdfs/lorem.pdf";
11
11
 
12
12
  describe("Cache Expiration", async () => {
13
- const cache = new FileCache({
13
+ const cache = new FileCache<{ a: number }>({
14
14
  cachePath: await temp.mkdir("file-cache-test"),
15
- cb: async (filePath, { a }: { a: number }) => {
15
+ cb: async (filePath, { a }) => {
16
16
  await fs.copyFile(
17
17
  testPDFFile,
18
18
  filePath,
@@ -25,7 +25,7 @@ describe("Cache Expiration", async () => {
25
25
 
26
26
  it("sync", async () => {
27
27
  //
28
- const filePath3 = await cache.getFile({ a: 3 });
28
+ const filePath3 = await cache.getFile({ a: 1 });
29
29
 
30
30
  // test if filePath exists
31
31
  expect(await pathExists(filePath3)).toBe(true);
package/lib/index.d.ts CHANGED
@@ -7,7 +7,7 @@ export type FileCacheOptions<T extends Record<string, any>> = {
7
7
  autoCreateCachePath?: boolean;
8
8
  cb: (filePath: FilePath, args: T, cache: FileCache<T>) => Promise<void>;
9
9
  ext: (args: T) => string | Promise<string>;
10
- resolveCacheFileKey?: (args: T) => string | Promise<string>;
10
+ resolveCacheKey?: (args: T) => string | Promise<string>;
11
11
  ttl: Milliseconds;
12
12
  cleanupInterval?: Milliseconds;
13
13
  };
@@ -16,17 +16,19 @@ declare class FileCache<T extends Record<string, any>> {
16
16
  private _cb;
17
17
  private _ttl;
18
18
  private _cleanupInterval;
19
- private _resolveCacheFileKey;
19
+ private _resolveCacheKey;
20
20
  private _ext;
21
21
  private _intervalId;
22
22
  private _semaphore;
23
23
  private _cleanupGroupSemaphore;
24
- constructor({ cachePath, autoCreateCachePath, cb, ext, ttl, cleanupInterval, resolveCacheFileKey, }: FileCacheOptions<T>);
24
+ constructor({ cachePath, autoCreateCachePath, cb, ext, ttl, cleanupInterval, resolveCacheKey, }: FileCacheOptions<T>);
25
25
  /**
26
- * Runs a cleanup pass to remove files older than 1 day from the cache.
27
- * This is called periodically, but can be triggered manually.
26
+ * Resolves the filename for the cache based on the provided arguments.
27
+ *
28
+ * Uses the provided `resolveFileName` function if available, or falls back to
29
+ * generating a hash from the arguments to create a unique file name.
28
30
  */
29
- cleanup(): Promise<void>;
31
+ private resolveFileName;
30
32
  /**
31
33
  * Retrieves a cached file for the given arguments.
32
34
  * If the file doesn't exist, it is generated by the callback and stored.
@@ -38,31 +40,22 @@ declare class FileCache<T extends Record<string, any>> {
38
40
  * @returns The path to the cached or newly created file
39
41
  */
40
42
  getFile(args: T): Promise<FilePath>;
41
- has(args: T): Promise<boolean>;
42
43
  /**
43
- * Deletes a file from the cache if it exists.
44
+ * Resolves the full file path for the cached file based on the provided arguments.
44
45
  *
45
- * @param args The arguments used to determine the file's identity
46
- * @returns True if the file was deleted, false if it didn't exist
46
+ * @param args The arguments used to resolve the file path
47
+ * @returns The full path to the cached file
47
48
  */
48
- expire(args: T): Promise<boolean>;
49
+ resolveFilePath(args: T): Promise<FilePath>;
49
50
  /**
50
51
  * Stops the background cleanup process, but does not delete any cached files.
51
52
  */
52
53
  destroy(): void;
54
+ has(args: T): Promise<boolean>;
53
55
  /**
54
- * Resolves the filename for the cache based on the provided arguments.
55
- *
56
- * Uses the provided `resolveFileName` function if available, or falls back to
57
- * generating a hash from the arguments to create a unique file name.
58
- */
59
- private resolveFileName;
60
- /**
61
- * Resolves the full file path for the cached file based on the provided arguments.
62
- *
63
- * @param args The arguments used to resolve the file path
64
- * @returns The full path to the cached file
56
+ * Runs a cleanup pass to remove files older than 1 day from the cache.
57
+ * This is called periodically, but can be triggered manually.
65
58
  */
66
- resolveFilePath(args: T): Promise<FilePath>;
59
+ cleanup(): Promise<void>;
67
60
  }
68
61
  export { type DirectoryPath, FileCache, type FileName, type FilePath };
package/lib/index.js CHANGED
@@ -6,29 +6,26 @@ import { GroupSemaphore, Semaphore } from "@chriscdn/promise-semaphore";
6
6
  import touch from "touch";
7
7
  import { findNuke } from "@chriscdn/find-nuke";
8
8
  import { Duration } from "@chriscdn/duration";
9
- // import { Memoize } from "@chriscdn/memoize";
10
- const fsp = fs.promises;
11
- const deleteFile = async (filepath) => await fs.promises.unlink(filepath);
12
9
  class FileCache {
13
10
  _cachePath;
14
11
  _cb;
15
12
  _ttl;
16
13
  _cleanupInterval;
17
- _resolveCacheFileKey;
14
+ _resolveCacheKey;
18
15
  _ext;
19
16
  _intervalId = null;
20
17
  _semaphore = new Semaphore();
21
18
  _cleanupGroupSemaphore = new GroupSemaphore();
22
- // private _fileNameResover(args:T) =>
23
- constructor({ cachePath, autoCreateCachePath, cb, ext, ttl, cleanupInterval, resolveCacheFileKey, }) {
19
+ constructor({ cachePath, autoCreateCachePath, cb, ext, ttl, cleanupInterval, resolveCacheKey, }) {
24
20
  this._cachePath = cachePath;
25
21
  this._cb = cb;
26
22
  this._ext = ext;
27
23
  this._ttl = ttl;
28
24
  this._cleanupInterval = cleanupInterval ??
29
25
  Duration.toMilliseconds({ days: 1 });
30
- this._resolveCacheFileKey = resolveCacheFileKey ??
31
- ((args) => sha1(JSON.stringify(args)));
26
+ this._resolveCacheKey = resolveCacheKey ??
27
+ ((args) => (JSON.stringify(args)));
28
+ // Startup code
32
29
  if ((pathExistsSync(cachePath))) {
33
30
  // we're good
34
31
  }
@@ -41,25 +38,23 @@ class FileCache {
41
38
  // fire and forget
42
39
  this.cleanup();
43
40
  this._intervalId = setInterval(this.cleanup.bind(this), this._cleanupInterval);
44
- // this.resolveFileName = Memoize(this.resolveFileName.bind(this));
45
- // this.resolveFilePath = Memoize(this.resolveFilePath.bind(this));
46
41
  }
47
42
  /**
48
- * Runs a cleanup pass to remove files older than 1 day from the cache.
49
- * This is called periodically, but can be triggered manually.
43
+ * Resolves the filename for the cache based on the provided arguments.
44
+ *
45
+ * Uses the provided `resolveFileName` function if available, or falls back to
46
+ * generating a hash from the arguments to create a unique file name.
50
47
  */
51
- async cleanup() {
52
- try {
53
- await this._cleanupGroupSemaphore.acquire("cleanup");
54
- await findNuke(this._cachePath, {
55
- olderThan: this._ttl,
56
- verbose: true,
57
- deleteEmptyDirectories: true,
58
- });
59
- }
60
- finally {
61
- this._cleanupGroupSemaphore.release("cleanup");
62
- }
48
+ async resolveFileName(args) {
49
+ const [name, ext] = await Promise.all([
50
+ this._resolveCacheKey(args),
51
+ this._ext(args),
52
+ ]);
53
+ const resolvedFileName = sha1(JSON.stringify([name, ext]));
54
+ return path.format({
55
+ name: resolvedFileName,
56
+ ext,
57
+ });
63
58
  }
64
59
  /**
65
60
  * Retrieves a cached file for the given arguments.
@@ -83,7 +78,7 @@ class FileCache {
83
78
  touch(filePath);
84
79
  }
85
80
  else {
86
- await fsp.mkdir(path.dirname(filePath), { recursive: true });
81
+ await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
87
82
  await this._cb(filePath, args, this);
88
83
  }
89
84
  }
@@ -93,35 +88,16 @@ class FileCache {
93
88
  }
94
89
  return filePath;
95
90
  }
96
- async has(args) {
97
- const filePath = await this.resolveFilePath(args);
98
- return await pathExists(filePath);
99
- }
100
91
  /**
101
- * Deletes a file from the cache if it exists.
92
+ * Resolves the full file path for the cached file based on the provided arguments.
102
93
  *
103
- * @param args The arguments used to determine the file's identity
104
- * @returns True if the file was deleted, false if it didn't exist
94
+ * @param args The arguments used to resolve the file path
95
+ * @returns The full path to the cached file
105
96
  */
106
- async expire(args) {
107
- const filePath = await this.resolveFilePath(args);
108
- try {
109
- await Promise.all([
110
- this._cleanupGroupSemaphore.acquire("expire"),
111
- this._semaphore.acquire(filePath),
112
- ]);
113
- if (await pathExists(filePath)) {
114
- await deleteFile(filePath);
115
- return true;
116
- }
117
- else {
118
- return false;
119
- }
120
- }
121
- finally {
122
- this._semaphore.release(filePath);
123
- this._cleanupGroupSemaphore.release("expire");
124
- }
97
+ async resolveFilePath(args) {
98
+ const fileName = await this.resolveFileName(args);
99
+ const filePath = path.resolve(this._cachePath, fileName[0], fileName[1], fileName[2], fileName);
100
+ return filePath;
125
101
  }
126
102
  /**
127
103
  * Stops the background cleanup process, but does not delete any cached files.
@@ -132,32 +108,26 @@ class FileCache {
132
108
  this._intervalId = null;
133
109
  }
134
110
  }
135
- /**
136
- * Resolves the filename for the cache based on the provided arguments.
137
- *
138
- * Uses the provided `resolveFileName` function if available, or falls back to
139
- * generating a hash from the arguments to create a unique file name.
140
- */
141
- async resolveFileName(args) {
142
- const [name, ext] = await Promise.all([
143
- this._resolveCacheFileKey(args),
144
- this._ext(args),
145
- ]);
146
- return path.format({
147
- name,
148
- ext,
149
- });
111
+ async has(args) {
112
+ const filePath = await this.resolveFilePath(args);
113
+ return await pathExists(filePath);
150
114
  }
151
115
  /**
152
- * Resolves the full file path for the cached file based on the provided arguments.
153
- *
154
- * @param args The arguments used to resolve the file path
155
- * @returns The full path to the cached file
116
+ * Runs a cleanup pass to remove files older than 1 day from the cache.
117
+ * This is called periodically, but can be triggered manually.
156
118
  */
157
- async resolveFilePath(args) {
158
- const fileName = await this.resolveFileName(args);
159
- const filePath = path.resolve(this._cachePath, fileName[0], fileName[1], fileName[2], fileName);
160
- return filePath;
119
+ async cleanup() {
120
+ try {
121
+ await this._cleanupGroupSemaphore.acquire("cleanup");
122
+ await findNuke(this._cachePath, {
123
+ olderThan: this._ttl,
124
+ verbose: true,
125
+ deleteEmptyDirectories: true,
126
+ });
127
+ }
128
+ finally {
129
+ this._cleanupGroupSemaphore.release("cleanup");
130
+ }
161
131
  }
162
132
  }
163
133
  export { FileCache };
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chriscdn/file-cache",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "description": "File cache ",
5
5
  "repository": "https://github.com/chriscdn/file-cache",
6
6
  "author": "Christopher Meyer <chris@schwiiz.org>",
package/src/index.ts CHANGED
@@ -7,48 +7,34 @@ import touch from "touch";
7
7
  import { findNuke } from "@chriscdn/find-nuke";
8
8
  import { Duration } from "@chriscdn/duration";
9
9
 
10
- // import { Memoize } from "@chriscdn/memoize";
11
-
12
- const fsp = fs.promises;
13
-
14
10
  type DirectoryPath = string;
15
11
  type FileName = string;
16
12
  type FilePath = string;
17
13
  type Milliseconds = number;
18
14
 
19
- const deleteFile = async (filepath: FilePath) =>
20
- await fs.promises.unlink(filepath);
21
-
22
15
  export type FileCacheOptions<T extends Record<string, any>> = {
23
16
  cachePath: DirectoryPath;
24
17
  autoCreateCachePath?: boolean;
25
18
  cb: (filePath: FilePath, args: T, cache: FileCache<T>) => Promise<void>;
26
19
  ext: (args: T) => string | Promise<string>;
27
- resolveCacheFileKey?: (args: T) => string | Promise<string>;
20
+ resolveCacheKey?: (args: T) => string | Promise<string>;
28
21
  ttl: Milliseconds;
29
22
  cleanupInterval?: Milliseconds;
30
23
  };
31
24
 
32
25
  class FileCache<T extends Record<string, any>> {
33
26
  private _cachePath: FileCacheOptions<T>["cachePath"];
34
-
35
27
  private _cb: FileCacheOptions<T>["cb"];
36
-
37
28
  private _ttl: FileCacheOptions<T>["ttl"];
38
29
  private _cleanupInterval: FileCacheOptions<T>["cleanupInterval"];
39
-
40
- private _resolveCacheFileKey: Required<
30
+ private _resolveCacheKey: Required<
41
31
  FileCacheOptions<T>
42
- >["resolveCacheFileKey"];
32
+ >["resolveCacheKey"];
43
33
  private _ext: FileCacheOptions<T>["ext"];
44
-
45
34
  private _intervalId: ReturnType<typeof setInterval> | null = null;
46
-
47
35
  private _semaphore: Semaphore = new Semaphore();
48
36
  private _cleanupGroupSemaphore: GroupSemaphore = new GroupSemaphore();
49
37
 
50
- // private _fileNameResover(args:T) =>
51
-
52
38
  constructor(
53
39
  {
54
40
  cachePath,
@@ -57,7 +43,7 @@ class FileCache<T extends Record<string, any>> {
57
43
  ext,
58
44
  ttl,
59
45
  cleanupInterval,
60
- resolveCacheFileKey,
46
+ resolveCacheKey,
61
47
  }: FileCacheOptions<T>,
62
48
  ) {
63
49
  this._cachePath = cachePath;
@@ -67,9 +53,10 @@ class FileCache<T extends Record<string, any>> {
67
53
  this._cleanupInterval = cleanupInterval ??
68
54
  Duration.toMilliseconds({ days: 1 });
69
55
 
70
- this._resolveCacheFileKey = resolveCacheFileKey ??
71
- ((args: T) => sha1(JSON.stringify(args)));
56
+ this._resolveCacheKey = resolveCacheKey ??
57
+ ((args: T) => (JSON.stringify(args)));
72
58
 
59
+ // Startup code
73
60
  if ((pathExistsSync(cachePath))) {
74
61
  // we're good
75
62
  } else if (autoCreateCachePath) {
@@ -85,26 +72,26 @@ class FileCache<T extends Record<string, any>> {
85
72
  this.cleanup.bind(this),
86
73
  this._cleanupInterval,
87
74
  );
88
-
89
- // this.resolveFileName = Memoize(this.resolveFileName.bind(this));
90
- // this.resolveFilePath = Memoize(this.resolveFilePath.bind(this));
91
75
  }
92
76
 
93
77
  /**
94
- * Runs a cleanup pass to remove files older than 1 day from the cache.
95
- * This is called periodically, but can be triggered manually.
78
+ * Resolves the filename for the cache based on the provided arguments.
79
+ *
80
+ * Uses the provided `resolveFileName` function if available, or falls back to
81
+ * generating a hash from the arguments to create a unique file name.
96
82
  */
97
- async cleanup() {
98
- try {
99
- await this._cleanupGroupSemaphore.acquire("cleanup");
100
- await findNuke(this._cachePath, {
101
- olderThan: this._ttl,
102
- verbose: true,
103
- deleteEmptyDirectories: true,
104
- });
105
- } finally {
106
- this._cleanupGroupSemaphore.release("cleanup");
107
- }
83
+ private async resolveFileName(args: T): Promise<FileName> {
84
+ const [name, ext] = await Promise.all([
85
+ this._resolveCacheKey(args),
86
+ this._ext(args),
87
+ ]);
88
+
89
+ const resolvedFileName = sha1(JSON.stringify([name, ext]));
90
+
91
+ return path.format({
92
+ name: resolvedFileName,
93
+ ext,
94
+ }) as FileName;
108
95
  }
109
96
 
110
97
  /**
@@ -130,7 +117,7 @@ class FileCache<T extends Record<string, any>> {
130
117
  // fire and forget
131
118
  touch(filePath);
132
119
  } else {
133
- await fsp.mkdir(path.dirname(filePath), { recursive: true });
120
+ await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
134
121
  await this._cb(filePath, args, this);
135
122
  }
136
123
  } finally {
@@ -141,36 +128,24 @@ class FileCache<T extends Record<string, any>> {
141
128
  return filePath;
142
129
  }
143
130
 
144
- async has(args: T): Promise<boolean> {
145
- const filePath = await this.resolveFilePath(args);
146
- return await pathExists(filePath);
147
- }
148
-
149
131
  /**
150
- * Deletes a file from the cache if it exists.
132
+ * Resolves the full file path for the cached file based on the provided arguments.
151
133
  *
152
- * @param args The arguments used to determine the file's identity
153
- * @returns True if the file was deleted, false if it didn't exist
134
+ * @param args The arguments used to resolve the file path
135
+ * @returns The full path to the cached file
154
136
  */
155
- async expire(args: T): Promise<boolean> {
156
- const filePath = await this.resolveFilePath(args);
137
+ async resolveFilePath(args: T): Promise<FilePath> {
138
+ const fileName = await this.resolveFileName(args);
157
139
 
158
- try {
159
- await Promise.all([
160
- this._cleanupGroupSemaphore.acquire("expire"),
161
- this._semaphore.acquire(filePath),
162
- ]);
140
+ const filePath = path.resolve(
141
+ this._cachePath,
142
+ fileName[0],
143
+ fileName[1],
144
+ fileName[2],
145
+ fileName,
146
+ );
163
147
 
164
- if (await pathExists(filePath)) {
165
- await deleteFile(filePath);
166
- return true;
167
- } else {
168
- return false;
169
- }
170
- } finally {
171
- this._semaphore.release(filePath);
172
- this._cleanupGroupSemaphore.release("expire");
173
- }
148
+ return filePath;
174
149
  }
175
150
 
176
151
  /**
@@ -183,42 +158,26 @@ class FileCache<T extends Record<string, any>> {
183
158
  }
184
159
  }
185
160
 
186
- /**
187
- * Resolves the filename for the cache based on the provided arguments.
188
- *
189
- * Uses the provided `resolveFileName` function if available, or falls back to
190
- * generating a hash from the arguments to create a unique file name.
191
- */
192
- private async resolveFileName(args: T): Promise<FileName> {
193
- const [name, ext] = await Promise.all([
194
- this._resolveCacheFileKey(args),
195
- this._ext(args),
196
- ]);
197
-
198
- return path.format({
199
- name,
200
- ext,
201
- }) as FileName;
161
+ async has(args: T): Promise<boolean> {
162
+ const filePath = await this.resolveFilePath(args);
163
+ return await pathExists(filePath);
202
164
  }
203
165
 
204
166
  /**
205
- * Resolves the full file path for the cached file based on the provided arguments.
206
- *
207
- * @param args The arguments used to resolve the file path
208
- * @returns The full path to the cached file
167
+ * Runs a cleanup pass to remove files older than 1 day from the cache.
168
+ * This is called periodically, but can be triggered manually.
209
169
  */
210
- async resolveFilePath(args: T): Promise<FilePath> {
211
- const fileName = await this.resolveFileName(args);
212
-
213
- const filePath = path.resolve(
214
- this._cachePath,
215
- fileName[0],
216
- fileName[1],
217
- fileName[2],
218
- fileName,
219
- );
220
-
221
- return filePath;
170
+ async cleanup() {
171
+ try {
172
+ await this._cleanupGroupSemaphore.acquire("cleanup");
173
+ await findNuke(this._cachePath, {
174
+ olderThan: this._ttl,
175
+ verbose: true,
176
+ deleteEmptyDirectories: true,
177
+ });
178
+ } finally {
179
+ this._cleanupGroupSemaphore.release("cleanup");
180
+ }
222
181
  }
223
182
  }
224
183