@zenfs/core 0.9.7 → 0.11.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.
Files changed (90) hide show
  1. package/dist/backends/Index.d.ts +3 -3
  2. package/dist/backends/Index.js +23 -23
  3. package/dist/backends/backend.js +6 -5
  4. package/dist/backends/fetch.d.ts +84 -0
  5. package/dist/backends/fetch.js +170 -0
  6. package/dist/backends/{Locked.d.ts → locked.d.ts} +13 -13
  7. package/dist/backends/{Locked.js → locked.js} +54 -54
  8. package/dist/backends/{InMemory.d.ts → memory.d.ts} +7 -9
  9. package/dist/backends/memory.js +38 -0
  10. package/dist/backends/{Overlay.d.ts → overlay.d.ts} +12 -13
  11. package/dist/backends/{Overlay.js → overlay.js} +105 -110
  12. package/dist/backends/port/fs.d.ts +123 -0
  13. package/dist/backends/port/fs.js +239 -0
  14. package/dist/backends/port/rpc.d.ts +60 -0
  15. package/dist/backends/port/rpc.js +71 -0
  16. package/dist/backends/store/fs.d.ts +169 -0
  17. package/dist/backends/store/fs.js +743 -0
  18. package/dist/backends/store/simple.d.ts +64 -0
  19. package/dist/backends/store/simple.js +111 -0
  20. package/dist/backends/store/store.d.ts +111 -0
  21. package/dist/backends/store/store.js +62 -0
  22. package/dist/browser.min.js +4 -4
  23. package/dist/browser.min.js.map +4 -4
  24. package/dist/config.d.ts +8 -10
  25. package/dist/config.js +11 -11
  26. package/dist/emulation/async.js +6 -6
  27. package/dist/emulation/dir.js +2 -2
  28. package/dist/emulation/index.d.ts +1 -1
  29. package/dist/emulation/index.js +1 -1
  30. package/dist/emulation/path.d.ts +3 -2
  31. package/dist/emulation/path.js +19 -45
  32. package/dist/emulation/promises.d.ts +7 -12
  33. package/dist/emulation/promises.js +144 -146
  34. package/dist/emulation/shared.d.ts +5 -10
  35. package/dist/emulation/shared.js +9 -9
  36. package/dist/emulation/streams.js +3 -3
  37. package/dist/emulation/sync.js +25 -25
  38. package/dist/{ApiError.d.ts → error.d.ts} +13 -15
  39. package/dist/error.js +291 -0
  40. package/dist/file.d.ts +2 -0
  41. package/dist/file.js +11 -5
  42. package/dist/filesystem.d.ts +3 -3
  43. package/dist/filesystem.js +41 -44
  44. package/dist/index.d.ts +7 -6
  45. package/dist/index.js +7 -6
  46. package/dist/inode.d.ts +1 -1
  47. package/dist/mutex.js +2 -1
  48. package/dist/utils.d.ts +8 -7
  49. package/dist/utils.js +11 -12
  50. package/package.json +3 -3
  51. package/readme.md +17 -9
  52. package/src/backends/Index.ts +23 -23
  53. package/src/backends/backend.ts +8 -7
  54. package/src/backends/fetch.ts +229 -0
  55. package/src/backends/{Locked.ts → locked.ts} +55 -55
  56. package/src/backends/memory.ts +44 -0
  57. package/src/backends/{Overlay.ts → overlay.ts} +108 -114
  58. package/src/backends/port/fs.ts +306 -0
  59. package/src/backends/port/readme.md +59 -0
  60. package/src/backends/port/rpc.ts +144 -0
  61. package/src/backends/store/fs.ts +881 -0
  62. package/src/backends/store/readme.md +9 -0
  63. package/src/backends/store/simple.ts +144 -0
  64. package/src/backends/store/store.ts +164 -0
  65. package/src/config.ts +21 -25
  66. package/src/emulation/async.ts +6 -6
  67. package/src/emulation/dir.ts +2 -2
  68. package/src/emulation/index.ts +1 -1
  69. package/src/emulation/path.ts +25 -49
  70. package/src/emulation/promises.ts +150 -159
  71. package/src/emulation/shared.ts +13 -15
  72. package/src/emulation/streams.ts +3 -3
  73. package/src/emulation/sync.ts +28 -28
  74. package/src/{ApiError.ts → error.ts} +89 -90
  75. package/src/file.ts +13 -5
  76. package/src/filesystem.ts +44 -47
  77. package/src/index.ts +7 -6
  78. package/src/inode.ts +1 -1
  79. package/src/mutex.ts +3 -1
  80. package/src/utils.ts +16 -18
  81. package/tsconfig.json +2 -2
  82. package/dist/ApiError.js +0 -292
  83. package/dist/backends/AsyncStore.d.ts +0 -204
  84. package/dist/backends/AsyncStore.js +0 -509
  85. package/dist/backends/InMemory.js +0 -49
  86. package/dist/backends/SyncStore.d.ts +0 -213
  87. package/dist/backends/SyncStore.js +0 -445
  88. package/src/backends/AsyncStore.ts +0 -655
  89. package/src/backends/InMemory.ts +0 -56
  90. package/src/backends/SyncStore.ts +0 -589
@@ -1,509 +0,0 @@
1
- import { dirname, basename, join, resolve } from '../emulation/path.js';
2
- import { ApiError, ErrorCode } from '../ApiError.js';
3
- import { W_OK, R_OK } from '../emulation/constants.js';
4
- import { PreloadFile, flagToMode } from '../file.js';
5
- import { Async, FileSystem } from '../filesystem.js';
6
- import { randomIno, Inode } from '../inode.js';
7
- import { FileType } from '../stats.js';
8
- import { encode, decodeDirListing, encodeDirListing } from '../utils.js';
9
- import { rootIno } from '../inode.js';
10
- import { InMemory } from './InMemory.js';
11
- /**
12
- * Last Recently Used cache
13
- */
14
- class LRUCache {
15
- constructor(limit) {
16
- this.limit = limit;
17
- this.cache = [];
18
- }
19
- set(key, value) {
20
- const existingIndex = this.cache.findIndex(node => node.key === key);
21
- if (existingIndex != -1) {
22
- this.cache.splice(existingIndex, 1);
23
- }
24
- else if (this.cache.length >= this.limit) {
25
- this.cache.shift();
26
- }
27
- this.cache.push({ key, value });
28
- }
29
- get(key) {
30
- const node = this.cache.find(n => n.key === key);
31
- if (!node) {
32
- return;
33
- }
34
- // Move the accessed item to the end of the cache (most recently used)
35
- this.set(key, node.value);
36
- return node.value;
37
- }
38
- remove(key) {
39
- const index = this.cache.findIndex(node => node.key === key);
40
- if (index !== -1) {
41
- this.cache.splice(index, 1);
42
- }
43
- }
44
- reset() {
45
- this.cache = [];
46
- }
47
- }
48
- /**
49
- * An asynchronous file system which uses an async store to store its data.
50
- * @see AsyncStore
51
- * @internal
52
- */
53
- export class AsyncStoreFS extends Async(FileSystem) {
54
- get store() {
55
- if (!this._store) {
56
- throw new ReferenceError('AsyncStoreFS not attached to a store');
57
- }
58
- return this._store;
59
- }
60
- async ready() {
61
- if (this._initialized) {
62
- return this;
63
- }
64
- this._initialized = true;
65
- if (this._options.lruCacheSize) {
66
- this._cache = new LRUCache(this._options.lruCacheSize);
67
- }
68
- this._store = await this._options.store;
69
- this._sync = this._options.sync || this._sync;
70
- await this.makeRootDirectory();
71
- await super.ready();
72
- return this;
73
- }
74
- metadata() {
75
- return {
76
- ...super.metadata(),
77
- name: this.store.name,
78
- };
79
- }
80
- constructor(_options) {
81
- super();
82
- this._options = _options;
83
- this._initialized = false;
84
- this._sync = InMemory.create({ name: 'test' });
85
- }
86
- /**
87
- * Delete all contents stored in the file system.
88
- */
89
- async empty() {
90
- if (this._cache) {
91
- this._cache.reset();
92
- }
93
- await this.store.clear();
94
- // Root always exists.
95
- await this.makeRootDirectory();
96
- }
97
- /**
98
- * @todo Make rename compatible with the cache.
99
- */
100
- async rename(oldPath, newPath, cred) {
101
- await this.queueDone();
102
- const c = this._cache;
103
- if (this._cache) {
104
- // Clear and disable cache during renaming process.
105
- delete this._cache;
106
- c?.reset();
107
- }
108
- try {
109
- const tx = this.store.beginTransaction(), oldParent = dirname(oldPath), oldName = basename(oldPath), newParent = dirname(newPath), newName = basename(newPath),
110
- // Remove oldPath from parent's directory listing.
111
- oldDirNode = await this.findINode(tx, oldParent), oldDirList = await this.getDirListing(tx, oldDirNode, oldParent);
112
- if (!oldDirNode.toStats().hasAccess(W_OK, cred)) {
113
- throw ApiError.With('EACCES', oldPath, 'rename');
114
- }
115
- if (!oldDirList[oldName]) {
116
- throw ApiError.With('ENOENT', oldPath, 'rename');
117
- }
118
- const nodeId = oldDirList[oldName];
119
- delete oldDirList[oldName];
120
- // Invariant: Can't move a folder inside itself.
121
- // This funny little hack ensures that the check passes only if oldPath
122
- // is a subpath of newParent. We append '/' to avoid matching folders that
123
- // are a substring of the bottom-most folder in the path.
124
- if ((newParent + '/').indexOf(oldPath + '/') === 0) {
125
- throw new ApiError(ErrorCode.EBUSY, oldParent);
126
- }
127
- // Add newPath to parent's directory listing.
128
- let newDirNode, newDirList;
129
- if (newParent === oldParent) {
130
- // Prevent us from re-grabbing the same directory listing, which still
131
- // contains oldName.
132
- newDirNode = oldDirNode;
133
- newDirList = oldDirList;
134
- }
135
- else {
136
- newDirNode = await this.findINode(tx, newParent);
137
- newDirList = await this.getDirListing(tx, newDirNode, newParent);
138
- }
139
- if (newDirList[newName]) {
140
- // If it's a file, delete it.
141
- const newNameNode = await this.getINode(tx, newDirList[newName], newPath);
142
- if (newNameNode.toStats().isFile()) {
143
- try {
144
- await tx.remove(newNameNode.ino);
145
- await tx.remove(newDirList[newName]);
146
- }
147
- catch (e) {
148
- await tx.abort();
149
- throw e;
150
- }
151
- }
152
- else {
153
- // If it's a directory, throw a permissions error.
154
- throw ApiError.With('EPERM', newPath, 'rename');
155
- }
156
- }
157
- newDirList[newName] = nodeId;
158
- // Commit the two changed directory listings.
159
- try {
160
- await tx.put(oldDirNode.ino, encodeDirListing(oldDirList), true);
161
- await tx.put(newDirNode.ino, encodeDirListing(newDirList), true);
162
- }
163
- catch (e) {
164
- await tx.abort();
165
- throw e;
166
- }
167
- await tx.commit();
168
- }
169
- finally {
170
- if (c) {
171
- this._cache = c;
172
- }
173
- }
174
- }
175
- async stat(p, cred) {
176
- await this.queueDone();
177
- const tx = this.store.beginTransaction();
178
- const inode = await this.findINode(tx, p);
179
- if (!inode) {
180
- throw ApiError.With('ENOENT', p, 'stat');
181
- }
182
- const stats = inode.toStats();
183
- if (!stats.hasAccess(R_OK, cred)) {
184
- throw ApiError.With('EACCES', p, 'stat');
185
- }
186
- return stats;
187
- }
188
- async createFile(p, flag, mode, cred) {
189
- await this.queueDone();
190
- const tx = this.store.beginTransaction(), data = new Uint8Array(0), newFile = await this.commitNewFile(tx, p, FileType.FILE, mode, cred, data);
191
- // Open the file.
192
- return new PreloadFile(this, p, flag, newFile.toStats(), data);
193
- }
194
- async openFile(p, flag, cred) {
195
- await this.queueDone();
196
- const tx = this.store.beginTransaction(), node = await this.findINode(tx, p), data = await tx.get(node.ino);
197
- if (!node.toStats().hasAccess(flagToMode(flag), cred)) {
198
- throw ApiError.With('EACCES', p, 'openFile');
199
- }
200
- if (!data) {
201
- throw ApiError.With('ENOENT', p, 'openFile');
202
- }
203
- return new PreloadFile(this, p, flag, node.toStats(), data);
204
- }
205
- async unlink(p, cred) {
206
- await this.queueDone();
207
- return this.removeEntry(p, false, cred);
208
- }
209
- async rmdir(p, cred) {
210
- await this.queueDone();
211
- // Check first if directory is empty.
212
- const list = await this.readdir(p, cred);
213
- if (list.length > 0) {
214
- throw ApiError.With('ENOTEMPTY', p, 'rmdir');
215
- }
216
- await this.removeEntry(p, true, cred);
217
- }
218
- async mkdir(p, mode, cred) {
219
- await this.queueDone();
220
- const tx = this.store.beginTransaction(), data = encode('{}');
221
- await this.commitNewFile(tx, p, FileType.DIRECTORY, mode, cred, data);
222
- }
223
- async readdir(p, cred) {
224
- await this.queueDone();
225
- const tx = this.store.beginTransaction();
226
- const node = await this.findINode(tx, p);
227
- if (!node.toStats().hasAccess(R_OK, cred)) {
228
- throw ApiError.With('EACCES', p, 'readdur');
229
- }
230
- return Object.keys(await this.getDirListing(tx, node, p));
231
- }
232
- /**
233
- * Updated the inode and data node at the given path
234
- * @todo Ensure mtime updates properly, and use that to determine if a data update is required.
235
- */
236
- async sync(p, data, stats) {
237
- await this.queueDone();
238
- const tx = this.store.beginTransaction(),
239
- // We use the _findInode helper because we actually need the INode id.
240
- fileInodeId = await this._findINode(tx, dirname(p), basename(p)), fileInode = await this.getINode(tx, fileInodeId, p), inodeChanged = fileInode.update(stats);
241
- try {
242
- // Sync data.
243
- await tx.put(fileInode.ino, data, true);
244
- // Sync metadata.
245
- if (inodeChanged) {
246
- await tx.put(fileInodeId, fileInode.data, true);
247
- }
248
- }
249
- catch (e) {
250
- await tx.abort();
251
- throw e;
252
- }
253
- await tx.commit();
254
- }
255
- async link(existing, newpath, cred) {
256
- await this.queueDone();
257
- const tx = this.store.beginTransaction(), existingDir = dirname(existing), existingDirNode = await this.findINode(tx, existingDir);
258
- if (!existingDirNode.toStats().hasAccess(R_OK, cred)) {
259
- throw ApiError.With('EACCES', existingDir, 'link');
260
- }
261
- const newDir = dirname(newpath), newDirNode = await this.findINode(tx, newDir), newListing = await this.getDirListing(tx, newDirNode, newDir);
262
- if (!newDirNode.toStats().hasAccess(W_OK, cred)) {
263
- throw ApiError.With('EACCES', newDir, 'link');
264
- }
265
- const ino = await this._findINode(tx, existingDir, basename(existing));
266
- const node = await this.getINode(tx, ino, existing);
267
- if (!node.toStats().hasAccess(W_OK, cred)) {
268
- throw ApiError.With('EACCES', newpath, 'link');
269
- }
270
- node.nlink++;
271
- newListing[basename(newpath)] = ino;
272
- try {
273
- tx.put(ino, node.data, true);
274
- tx.put(newDirNode.ino, encodeDirListing(newListing), true);
275
- }
276
- catch (e) {
277
- tx.abort();
278
- throw e;
279
- }
280
- tx.commit();
281
- }
282
- /**
283
- * Checks if the root directory exists. Creates it if it doesn't.
284
- */
285
- async makeRootDirectory() {
286
- const tx = this.store.beginTransaction();
287
- if (!(await tx.get(rootIno))) {
288
- // Create new inode. o777, owned by root:root
289
- const inode = new Inode();
290
- inode.mode = 0o777 | FileType.DIRECTORY;
291
- // If the root doesn't exist, the first random ID shouldn't exist either.
292
- await tx.put(inode.ino, encode('{}'), false);
293
- await tx.put(rootIno, inode.data, false);
294
- await tx.commit();
295
- }
296
- }
297
- /**
298
- * Helper function for findINode.
299
- * @param parent The parent directory of the file we are attempting to find.
300
- * @param filename The filename of the inode we are attempting to find, minus
301
- * the parent.
302
- */
303
- async _findINode(tx, parent, filename, visited = new Set()) {
304
- const currentPath = join(parent, filename);
305
- if (visited.has(currentPath)) {
306
- throw new ApiError(ErrorCode.EIO, 'Infinite loop detected while finding inode', currentPath);
307
- }
308
- visited.add(currentPath);
309
- if (this._cache) {
310
- const id = this._cache.get(currentPath);
311
- if (id) {
312
- return id;
313
- }
314
- }
315
- if (parent === '/') {
316
- if (filename === '') {
317
- // BASE CASE #1: Return the root's ID.
318
- if (this._cache) {
319
- this._cache.set(currentPath, rootIno);
320
- }
321
- return rootIno;
322
- }
323
- else {
324
- // BASE CASE #2: Find the item in the root node.
325
- const inode = await this.getINode(tx, rootIno, parent);
326
- const dirList = await this.getDirListing(tx, inode, parent);
327
- if (dirList[filename]) {
328
- const id = dirList[filename];
329
- if (this._cache) {
330
- this._cache.set(currentPath, id);
331
- }
332
- return id;
333
- }
334
- else {
335
- throw ApiError.With('ENOENT', resolve(parent, filename), '_findINode');
336
- }
337
- }
338
- }
339
- else {
340
- // Get the parent directory's INode, and find the file in its directory
341
- // listing.
342
- const inode = await this.findINode(tx, parent, visited);
343
- const dirList = await this.getDirListing(tx, inode, parent);
344
- if (dirList[filename]) {
345
- const id = dirList[filename];
346
- if (this._cache) {
347
- this._cache.set(currentPath, id);
348
- }
349
- return id;
350
- }
351
- else {
352
- throw ApiError.With('ENOENT', resolve(parent, filename), '_findINode');
353
- }
354
- }
355
- }
356
- /**
357
- * Finds the Inode of the given path.
358
- * @param p The path to look up.
359
- * @todo memoize/cache
360
- */
361
- async findINode(tx, p, visited = new Set()) {
362
- const id = await this._findINode(tx, dirname(p), basename(p), visited);
363
- return this.getINode(tx, id, p);
364
- }
365
- /**
366
- * Given the ID of a node, retrieves the corresponding Inode.
367
- * @param tx The transaction to use.
368
- * @param p The corresponding path to the file (used for error messages).
369
- * @param id The ID to look up.
370
- */
371
- async getINode(tx, id, p) {
372
- const data = await tx.get(id);
373
- if (!data) {
374
- throw ApiError.With('ENOENT', p, 'getINode');
375
- }
376
- return new Inode(data.buffer);
377
- }
378
- /**
379
- * Given the Inode of a directory, retrieves the corresponding directory
380
- * listing.
381
- */
382
- async getDirListing(tx, inode, p) {
383
- if (!inode.toStats().isDirectory()) {
384
- throw ApiError.With('ENOTDIR', p, 'getDirListing');
385
- }
386
- const data = await tx.get(inode.ino);
387
- if (!data) {
388
- /*
389
- Occurs when data is undefined, or corresponds to something other
390
- than a directory listing. The latter should never occur unless
391
- the file system is corrupted.
392
- */
393
- throw ApiError.With('ENOENT', p, 'getDirListing');
394
- }
395
- return decodeDirListing(data);
396
- }
397
- /**
398
- * Adds a new node under a random ID. Retries 5 times before giving up in
399
- * the exceedingly unlikely chance that we try to reuse a random ino.
400
- */
401
- async addNewNode(tx, data, _maxAttempts = 5) {
402
- if (_maxAttempts <= 0) {
403
- // Max retries hit. Return with an error.
404
- throw new ApiError(ErrorCode.EIO, 'Unable to commit data to key-value store.');
405
- }
406
- // Make an attempt
407
- const ino = randomIno();
408
- const isCommited = await tx.put(ino, data, false);
409
- if (!isCommited) {
410
- return await this.addNewNode(tx, data, --_maxAttempts);
411
- }
412
- return ino;
413
- }
414
- /**
415
- * Commits a new file (well, a FILE or a DIRECTORY) to the file system with
416
- * the given mode.
417
- * Note: This will commit the transaction.
418
- * @param p The path to the new file.
419
- * @param type The type of the new file.
420
- * @param mode The mode to create the new file with.
421
- * @param cred The UID/GID to create the file with
422
- * @param data The data to store at the file's data node.
423
- */
424
- async commitNewFile(tx, p, type, mode, cred, data) {
425
- const parentDir = dirname(p), fname = basename(p), parentNode = await this.findINode(tx, parentDir), dirListing = await this.getDirListing(tx, parentNode, parentDir);
426
- //Check that the creater has correct access
427
- if (!parentNode.toStats().hasAccess(W_OK, cred)) {
428
- throw ApiError.With('EACCES', p, 'commitNewFile');
429
- }
430
- // Invariant: The root always exists.
431
- // If we don't check this prior to taking steps below, we will create a
432
- // file with name '' in root should p == '/'.
433
- if (p === '/') {
434
- throw ApiError.With('EEXIST', p, 'commitNewFile');
435
- }
436
- // Check if file already exists.
437
- if (dirListing[fname]) {
438
- await tx.abort();
439
- throw ApiError.With('EEXIST', p, 'commitNewFile');
440
- }
441
- try {
442
- // Commit data.
443
- const inode = new Inode();
444
- inode.ino = await this.addNewNode(tx, data);
445
- inode.mode = mode | type;
446
- inode.uid = cred.uid;
447
- inode.gid = cred.gid;
448
- inode.size = data.length;
449
- // Update and commit parent directory listing.
450
- dirListing[fname] = await this.addNewNode(tx, inode.data);
451
- await tx.put(parentNode.ino, encodeDirListing(dirListing), true);
452
- await tx.commit();
453
- return inode;
454
- }
455
- catch (e) {
456
- tx.abort();
457
- throw e;
458
- }
459
- }
460
- /**
461
- * Remove all traces of the given path from the file system.
462
- * @param p The path to remove from the file system.
463
- * @param isDir Does the path belong to a directory, or a file?
464
- * @todo Update mtime.
465
- */
466
- /**
467
- * Remove all traces of the given path from the file system.
468
- * @param p The path to remove from the file system.
469
- * @param isDir Does the path belong to a directory, or a file?
470
- * @todo Update mtime.
471
- */
472
- async removeEntry(p, isDir, cred) {
473
- if (this._cache) {
474
- this._cache.remove(p);
475
- }
476
- const tx = this.store.beginTransaction(), parent = dirname(p), parentNode = await this.findINode(tx, parent), parentListing = await this.getDirListing(tx, parentNode, parent), fileName = basename(p);
477
- if (!parentListing[fileName]) {
478
- throw ApiError.With('ENOENT', p, 'removeEntry');
479
- }
480
- const fileIno = parentListing[fileName];
481
- // Get file inode.
482
- const fileNode = await this.getINode(tx, fileIno, p);
483
- if (!fileNode.toStats().hasAccess(W_OK, cred)) {
484
- throw ApiError.With('EACCES', p, 'removeEntry');
485
- }
486
- // Remove from directory listing of parent.
487
- delete parentListing[fileName];
488
- if (!isDir && fileNode.toStats().isDirectory()) {
489
- throw ApiError.With('EISDIR', p, 'removeEntry');
490
- }
491
- if (isDir && !fileNode.toStats().isDirectory()) {
492
- throw ApiError.With('ENOTDIR', p, 'removeEntry');
493
- }
494
- try {
495
- await tx.put(parentNode.ino, encodeDirListing(parentListing), true);
496
- if (--fileNode.nlink < 1) {
497
- // remove file
498
- await tx.remove(fileNode.ino);
499
- await tx.remove(fileIno);
500
- }
501
- }
502
- catch (e) {
503
- await tx.abort();
504
- throw e;
505
- }
506
- // Success.
507
- await tx.commit();
508
- }
509
- }
@@ -1,49 +0,0 @@
1
- import { SimpleSyncTransaction, SyncStoreFS } from './SyncStore.js';
2
- /**
3
- * A simple in-memory store
4
- */
5
- export class InMemoryStore {
6
- constructor(name = 'tmp') {
7
- this.name = name;
8
- this.store = new Map();
9
- }
10
- clear() {
11
- this.store.clear();
12
- }
13
- beginTransaction() {
14
- return new SimpleSyncTransaction(this);
15
- }
16
- get(key) {
17
- return this.store.get(key);
18
- }
19
- put(key, data, overwrite) {
20
- if (!overwrite && this.store.has(key)) {
21
- return false;
22
- }
23
- this.store.set(key, data);
24
- return true;
25
- }
26
- remove(key) {
27
- this.store.delete(key);
28
- }
29
- }
30
- /**
31
- * A simple in-memory file system backed by an InMemoryStore.
32
- * Files are not persisted across page loads.
33
- */
34
- export const InMemory = {
35
- name: 'InMemory',
36
- isAvailable() {
37
- return true;
38
- },
39
- options: {
40
- name: {
41
- type: 'string',
42
- required: false,
43
- description: 'The name of the store',
44
- },
45
- },
46
- create({ name }) {
47
- return new SyncStoreFS({ store: new InMemoryStore(name) });
48
- },
49
- };