@dxos/random-access-storage 0.8.4-main.1f223c7 → 0.8.4-main.21d9917

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.
@@ -0,0 +1,807 @@
1
+ import "@dxos/node-std/globals";
2
+ import import$d$random_access_storage from 'random-access-storage';
3
+ import import$d$inherits from 'inherits';
4
+ import import$d$next_tick from 'next-tick';
5
+ import import$d$once from 'once';
6
+ import import$d$buffer_from from 'buffer-from';
7
+ import import$d$buffer_alloc from 'buffer-alloc';
8
+ import {
9
+ AbstractStorage,
10
+ Directory,
11
+ MemoryStorage,
12
+ StorageType,
13
+ __commonJS,
14
+ __require,
15
+ __toESM,
16
+ getFullPath,
17
+ stringDiff,
18
+ wrapFile
19
+ } from "../chunk-QQKT3REB.mjs";
20
+
21
+ // ../../../node_modules/.pnpm/random-access-idb@1.2.2_patch_hash=207ec2404ef8b5e9e6d9de8ce83586d215ef77b94a7d0cadced03125874a1d9e/node_modules/random-access-idb/lib/blocks.js
22
+ var require_blocks = __commonJS({
23
+ "../../../node_modules/.pnpm/random-access-idb@1.2.2_patch_hash=207ec2404ef8b5e9e6d9de8ce83586d215ef77b94a7d0cadced03125874a1d9e/node_modules/random-access-idb/lib/blocks.js"(exports, module) {
24
+ module.exports = function(size, start, end) {
25
+ var result = [];
26
+ for (var n = Math.floor(start / size) * size; n < end; n += size) {
27
+ result.push({
28
+ block: Math.floor(n / size),
29
+ start: Math.max(n, start) % size,
30
+ end: Math.min(n + size, end) % size || size
31
+ });
32
+ }
33
+ return result;
34
+ };
35
+ }
36
+ });
37
+
38
+ // ../../../node_modules/.pnpm/random-access-idb@1.2.2_patch_hash=207ec2404ef8b5e9e6d9de8ce83586d215ef77b94a7d0cadced03125874a1d9e/node_modules/random-access-idb/index.js
39
+ var require_random_access_idb = __commonJS({
40
+ "../../../node_modules/.pnpm/random-access-idb@1.2.2_patch_hash=207ec2404ef8b5e9e6d9de8ce83586d215ef77b94a7d0cadced03125874a1d9e/node_modules/random-access-idb/index.js"(exports, module) {
41
+ var RandomAccess = import$d$random_access_storage;
42
+ var inherits = import$d$inherits;
43
+ var nextTick = import$d$next_tick;
44
+ var once = import$d$once;
45
+ var blocks = require_blocks();
46
+ var bufferFrom = import$d$buffer_from;
47
+ var bufferAlloc = import$d$buffer_alloc;
48
+ var DELIM2 = "\0";
49
+ var win = typeof window !== "undefined" ? window : typeof self !== "undefined" ? self : {};
50
+ module.exports = function(dbname, xopts) {
51
+ if (!xopts) xopts = {};
52
+ var idb2 = xopts.idb || (typeof win !== "undefined" ? win.indexedDB || win.mozIndexedDB || win.webkitIndexedDB || win.msIndexedDB : null);
53
+ if (!idb2) throw new Error("indexedDB not present and not given");
54
+ var db = null, dbqueue = [];
55
+ if (typeof idb2.open === "function") {
56
+ var req = idb2.open(dbname);
57
+ req.addEventListener("upgradeneeded", function() {
58
+ db = req.result;
59
+ db.createObjectStore("data");
60
+ });
61
+ req.addEventListener("success", function() {
62
+ db = req.result;
63
+ dbqueue.forEach(function(cb) {
64
+ cb(db);
65
+ });
66
+ dbqueue = null;
67
+ });
68
+ } else {
69
+ db = idb2;
70
+ }
71
+ function getdb(cb) {
72
+ if (db) nextTick(function() {
73
+ cb(db);
74
+ });
75
+ else dbqueue.push(cb);
76
+ }
77
+ return {
78
+ create: function(name, opts) {
79
+ if (typeof name === "object") {
80
+ opts = name;
81
+ name = opts.name;
82
+ }
83
+ if (!opts) opts = {};
84
+ opts.name = name;
85
+ return new Store(Object.assign({ db: getdb }, xopts, opts));
86
+ },
87
+ getdb
88
+ };
89
+ };
90
+ function Store(opts) {
91
+ if (!(this instanceof Store)) return new Store(opts);
92
+ RandomAccess.call(this);
93
+ if (!opts) opts = {};
94
+ if (typeof opts === "string") opts = { name: opts };
95
+ this.size = opts.size || 4096;
96
+ this.name = opts.name;
97
+ this.length = opts.length || 0;
98
+ this._getdb = opts.db;
99
+ }
100
+ inherits(Store, RandomAccess);
101
+ Store.prototype._blocks = function(i, j) {
102
+ return blocks(this.size, i, j);
103
+ };
104
+ Store.prototype._read = function(req) {
105
+ var self2 = this;
106
+ var buffers = [];
107
+ self2._store("readonly", function(err, store) {
108
+ if ((self2.length || 0) < req.offset + req.size) {
109
+ return req.callback(new Error("Could not satisfy length"));
110
+ }
111
+ if (err) return req.callback(err);
112
+ var offsets = self2._blocks(req.offset, req.offset + req.size);
113
+ var pending = offsets.length + 1;
114
+ var firstBlock = offsets.length > 0 ? offsets[0].block : 0;
115
+ var j = 0;
116
+ for (var i = 0; i < offsets.length; i++) (function(o) {
117
+ var key = self2.name + DELIM2 + o.block;
118
+ backify(store.get(key), function(err2, ev) {
119
+ if (err2) return req.callback(err2);
120
+ buffers[o.block - firstBlock] = ev.target.result ? bufferFrom(ev.target.result.subarray(o.start, o.end)) : bufferAlloc(o.end - o.start);
121
+ if (--pending === 0) req.callback(null, Buffer.concat(buffers));
122
+ });
123
+ })(offsets[i]);
124
+ if (--pending === 0) req.callback(null, Buffer.concat(buffers));
125
+ });
126
+ };
127
+ Store.prototype._write = function(req) {
128
+ var self2 = this;
129
+ self2._store("readwrite", function(err, store) {
130
+ if (err) return req.callback(err);
131
+ var offsets = self2._blocks(req.offset, req.offset + req.data.length);
132
+ var pending = 1;
133
+ var buffers = {};
134
+ for (var i = 0; i < offsets.length; i++) (function(o, i2) {
135
+ if (o.end - o.start === self2.size) return;
136
+ pending++;
137
+ var key = self2.name + DELIM2 + o.block;
138
+ backify(store.get(key), function(err2, ev) {
139
+ if (err2) return req.callback(err2);
140
+ buffers[i2] = bufferFrom(ev.target.result || bufferAlloc(self2.size));
141
+ if (--pending === 0) write(store, offsets, buffers);
142
+ });
143
+ })(offsets[i], i);
144
+ if (--pending === 0) write(store, offsets, buffers);
145
+ });
146
+ function write(store, offsets, buffers) {
147
+ var block;
148
+ for (var i = 0, j = 0; i < offsets.length; i++) {
149
+ var o = offsets[i];
150
+ var len = o.end - o.start;
151
+ if (len === self2.size) {
152
+ block = bufferFrom(req.data.slice(j, j + len));
153
+ } else {
154
+ block = buffers[i];
155
+ req.data.copy(block, o.start, j, j + len);
156
+ }
157
+ store.put(block, self2.name + DELIM2 + o.block);
158
+ j += len;
159
+ }
160
+ var length = Math.max(self2.length || 0, req.offset + req.data.length);
161
+ store.put(length, self2.name + DELIM2 + "length");
162
+ store.transaction.addEventListener("complete", function() {
163
+ self2.length = length;
164
+ req.callback(null);
165
+ });
166
+ store.transaction.addEventListener("error", function(err) {
167
+ req.callback(err);
168
+ });
169
+ }
170
+ };
171
+ Store.prototype._store = function(mode, cb) {
172
+ cb = once(cb);
173
+ var self2 = this;
174
+ self2._getdb(function(db) {
175
+ var tx = db.transaction(["data"], mode);
176
+ var store = tx.objectStore("data");
177
+ tx.addEventListener("error", cb);
178
+ cb(null, store);
179
+ });
180
+ };
181
+ Store.prototype._open = function(req) {
182
+ var self2 = this;
183
+ this._getdb(function(db) {
184
+ self2._store("readonly", function(err, store) {
185
+ backify(store.get(self2.name + DELIM2 + "length"), function(err2, ev) {
186
+ self2.length = ev.target.result || 0;
187
+ req.callback(null);
188
+ });
189
+ });
190
+ });
191
+ };
192
+ Store.prototype._close = function(req) {
193
+ this._getdb(function(db) {
194
+ req.callback();
195
+ });
196
+ };
197
+ Store.prototype._stat = function(req) {
198
+ var self2 = this;
199
+ nextTick(function() {
200
+ req.callback(null, { size: self2.length });
201
+ });
202
+ };
203
+ function backify(r, cb) {
204
+ r.addEventListener("success", function(ev) {
205
+ cb(null, ev);
206
+ });
207
+ r.addEventListener("error", cb);
208
+ }
209
+ }
210
+ });
211
+
212
+ // src/browser/idb-storage.ts
213
+ var import_random_access_idb = __toESM(require_random_access_idb(), 1);
214
+ import { invariant } from "@dxos/invariant";
215
+ var __dxlog_file = "/__w/dxos/dxos/packages/common/random-access-storage/src/browser/idb-storage.ts";
216
+ var DELIM = "\0";
217
+ var IDbStorage = class extends AbstractStorage {
218
+ type = StorageType.IDB;
219
+ _db;
220
+ _store = "data";
221
+ _initialized = false;
222
+ _fileStorage;
223
+ constructor(path) {
224
+ super(path);
225
+ this._fileStorage = this._createFileStorage(path);
226
+ }
227
+ _createFileStorage(path) {
228
+ const database = (0, import_random_access_idb.default)(path);
229
+ let res;
230
+ this._db = new Promise((resolve) => {
231
+ res = resolve;
232
+ });
233
+ database.getdb(res);
234
+ return database.create;
235
+ }
236
+ async close() {
237
+ await this._closeFilesInPath("");
238
+ }
239
+ async reset() {
240
+ await this._closeFilesInPath("");
241
+ await this._remove("");
242
+ }
243
+ async _destroy() {
244
+ throw new Error("Unreachable");
245
+ }
246
+ _createFile(path, filename) {
247
+ const file = this._fileStorage(getFullPath(path, filename));
248
+ file.destroy = (cb) => {
249
+ void this._db.then((db) => {
250
+ const lowerBound = getFullPath(path, filename);
251
+ const upperBound = `${lowerBound}\uFFFF`;
252
+ const range = IDBKeyRange.bound(lowerBound, upperBound);
253
+ const transaction = db.transaction(this._store, "readwrite");
254
+ const objectStore = transaction.objectStore(this._store);
255
+ objectStore.delete(range);
256
+ transaction.oncomplete = () => {
257
+ file.destroyed = true;
258
+ file.unlinked = true;
259
+ file.closed = true;
260
+ cb(null);
261
+ };
262
+ transaction.onerror = () => cb(transaction.error);
263
+ });
264
+ };
265
+ file.deletable = true;
266
+ return file;
267
+ }
268
+ async _loadFiles(path) {
269
+ const db = await this._db;
270
+ invariant(db, "Database is not initialized.", {
271
+ F: __dxlog_file,
272
+ L: 85,
273
+ S: this,
274
+ A: [
275
+ "db",
276
+ "'Database is not initialized.'"
277
+ ]
278
+ });
279
+ const lowerBound = path;
280
+ const upperBound = `${path}\uFFFF`;
281
+ const range = IDBKeyRange.bound(lowerBound, upperBound);
282
+ const transaction = db.transaction(this._store);
283
+ const objectStore = transaction.objectStore(this._store);
284
+ const request = objectStore.openCursor(range);
285
+ return new Promise((resolve, reject) => {
286
+ transaction.onerror = () => {
287
+ reject(request.error);
288
+ };
289
+ request.onsuccess = (event) => {
290
+ const cursor = event.target.result;
291
+ if (cursor) {
292
+ const filename = String(cursor.key).split(DELIM)[0];
293
+ if (filename && !this._files.has(getFullPath(this.path, filename))) {
294
+ const file = this._createFile(path, filename);
295
+ this._files.set(getFullPath(this.path, filename), wrapFile(file, this.type));
296
+ }
297
+ cursor.continue();
298
+ } else {
299
+ resolve();
300
+ }
301
+ };
302
+ });
303
+ }
304
+ async _getFiles(path) {
305
+ if (!this._initialized) {
306
+ await this._loadFiles(this.path);
307
+ this._initialized = true;
308
+ }
309
+ return super._getFiles(path);
310
+ }
311
+ };
312
+
313
+ // src/browser/web-fs.ts
314
+ import { EventEmitter } from "@dxos/node-std/events";
315
+ import { callbackify } from "@dxos/node-std/util";
316
+ import { synchronized } from "@dxos/async";
317
+ import { invariant as invariant2 } from "@dxos/invariant";
318
+ import { log } from "@dxos/log";
319
+ import { TimeSeriesCounter, trace } from "@dxos/tracing";
320
+ function _ts_decorate(decorators, target, key, desc) {
321
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
322
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
323
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
324
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
325
+ }
326
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/common/random-access-storage/src/browser/web-fs.ts";
327
+ var WebFS = class {
328
+ path;
329
+ _files = /* @__PURE__ */ new Map();
330
+ type = StorageType.WEBFS;
331
+ _root;
332
+ constructor(path) {
333
+ this.path = path;
334
+ }
335
+ get size() {
336
+ return this._files.size;
337
+ }
338
+ _getFiles(path) {
339
+ const fullName = this._getFullFilename(this.path, path);
340
+ return new Map([
341
+ ...this._files.entries()
342
+ ].filter(([path2, file]) => {
343
+ return path2.includes(fullName) && !file.destroyed;
344
+ }));
345
+ }
346
+ async _list(path) {
347
+ const fullName = this._getFullFilename(path);
348
+ const root = await this._initialize();
349
+ const entries = [];
350
+ for await (const entry of root.keys()) {
351
+ if (entry.startsWith(fullName + "_") && !entry.endsWith(".crswap")) {
352
+ entries.push(entry.slice(fullName.length + 1));
353
+ }
354
+ }
355
+ return entries;
356
+ }
357
+ async _initialize() {
358
+ if (this._root) {
359
+ return this._root;
360
+ }
361
+ this._root = await navigator.storage.getDirectory();
362
+ invariant2(this._root, "Root is undefined", {
363
+ F: __dxlog_file2,
364
+ L: 74,
365
+ S: this,
366
+ A: [
367
+ "this._root",
368
+ "'Root is undefined'"
369
+ ]
370
+ });
371
+ return this._root;
372
+ }
373
+ createDirectory(sub = "") {
374
+ return new Directory({
375
+ type: this.type,
376
+ path: getFullPath(this.path, sub),
377
+ list: (path) => this._list(path),
378
+ getOrCreateFile: (...args) => this.getOrCreateFile(...args),
379
+ remove: () => this._delete(sub),
380
+ onFlush: async () => {
381
+ await Promise.all(Array.from(this._getFiles(sub)).map(([_, file]) => file.flush()));
382
+ }
383
+ });
384
+ }
385
+ getOrCreateFile(path, filename, opts) {
386
+ const fullName = this._getFullFilename(path, filename);
387
+ const existingFile = this._files.get(fullName);
388
+ if (existingFile) {
389
+ return existingFile;
390
+ }
391
+ const file = this._createFile(fullName);
392
+ this._files.set(fullName, file);
393
+ return file;
394
+ }
395
+ _createFile(fullName) {
396
+ return new WebFile({
397
+ fileName: fullName,
398
+ file: this._initialize().then((root) => root.getFileHandle(fullName, {
399
+ create: true
400
+ })),
401
+ destroy: async () => {
402
+ this._files.delete(fullName);
403
+ const root = await this._initialize();
404
+ return root.removeEntry(fullName);
405
+ }
406
+ });
407
+ }
408
+ async _delete(path) {
409
+ await Promise.all(Array.from(this._getFiles(path)).map(async ([path2, file]) => {
410
+ await file.destroy().catch((err) => log.warn(err, void 0, {
411
+ F: __dxlog_file2,
412
+ L: 117,
413
+ S: this,
414
+ C: (f, a) => f(...a)
415
+ }));
416
+ this._files.delete(path2);
417
+ }));
418
+ }
419
+ async reset() {
420
+ await this._initialize();
421
+ for await (const filename of await this._root.keys()) {
422
+ await this._root.removeEntry(filename, {
423
+ recursive: true
424
+ }).catch((err) => log.warn("failed to remove an entry", {
425
+ filename,
426
+ err
427
+ }, {
428
+ F: __dxlog_file2,
429
+ L: 127,
430
+ S: this,
431
+ C: (f, a) => f(...a)
432
+ }));
433
+ this._files.delete(filename);
434
+ }
435
+ this._root = void 0;
436
+ }
437
+ async close() {
438
+ await Promise.all(Array.from(this._files.values()).map((file) => {
439
+ return file.close().catch((e) => log.warn("failed to close a file", {
440
+ file: file.fileName,
441
+ e
442
+ }, {
443
+ F: __dxlog_file2,
444
+ L: 137,
445
+ S: this,
446
+ C: (f, a) => f(...a)
447
+ }));
448
+ }));
449
+ }
450
+ _getFullFilename(path, filename) {
451
+ if (filename) {
452
+ return getFullPath(path, filename).replace(/\//g, "_");
453
+ } else {
454
+ return path.replace(/\//g, "_");
455
+ }
456
+ }
457
+ async getDiskInfo() {
458
+ let used = 0;
459
+ const recurse = async (handle) => {
460
+ const promises = [];
461
+ for await (const entry of handle.values()) {
462
+ promises.push((async () => {
463
+ switch (entry.kind) {
464
+ case "file":
465
+ used += await entry.getFile().then((f) => f.size);
466
+ break;
467
+ case "directory":
468
+ await recurse(entry);
469
+ break;
470
+ }
471
+ })());
472
+ }
473
+ await Promise.all(promises);
474
+ };
475
+ await recurse(this._root);
476
+ return {
477
+ used
478
+ };
479
+ }
480
+ };
481
+ _ts_decorate([
482
+ synchronized
483
+ ], WebFS.prototype, "_initialize", null);
484
+ var WebFile = class extends EventEmitter {
485
+ fileName;
486
+ _fileHandle;
487
+ _destroy;
488
+ /**
489
+ * Current view of the file contents.
490
+ */
491
+ _buffer = null;
492
+ _loadBufferPromise = null;
493
+ _flushScheduled = false;
494
+ _flushPromise = Promise.resolve();
495
+ /**
496
+ * Used to discard unnecessary scheduled flushes.
497
+ * If _flushNow() is called with a lower sequence number it should early exit.
498
+ */
499
+ _flushSequence = 0;
500
+ //
501
+ // Metrics
502
+ //
503
+ _flushes = new TimeSeriesCounter();
504
+ _operations = new TimeSeriesCounter();
505
+ _reads = new TimeSeriesCounter();
506
+ _readBytes = new TimeSeriesCounter();
507
+ _writes = new TimeSeriesCounter();
508
+ _writeBytes = new TimeSeriesCounter();
509
+ get _bufferSize() {
510
+ return this._buffer?.length;
511
+ }
512
+ constructor({ fileName, file, destroy }) {
513
+ super();
514
+ this.fileName = fileName;
515
+ this._fileHandle = file;
516
+ this._destroy = destroy;
517
+ void this._loadBufferGuarded();
518
+ }
519
+ type = StorageType.WEBFS;
520
+ //
521
+ // random-access-storage library compatibility
522
+ //
523
+ // TODO(dmaretskyi): Are those all needed?
524
+ opened = true;
525
+ suspended = false;
526
+ closed = false;
527
+ unlinked = false;
528
+ writing = false;
529
+ readable = true;
530
+ writable = true;
531
+ deletable = true;
532
+ truncatable = true;
533
+ statable = true;
534
+ destroyed = false;
535
+ directory = "";
536
+ // TODO(dmaretskyi): is this used?
537
+ filename = "";
538
+ native = {
539
+ write: callbackify(this.write.bind(this)),
540
+ read: callbackify(this.read.bind(this)),
541
+ del: callbackify(this.del.bind(this)),
542
+ stat: callbackify(this.stat.bind(this)),
543
+ destroy: callbackify(this.destroy.bind(this)),
544
+ truncate: callbackify(this.truncate?.bind(this))
545
+ };
546
+ async _loadBuffer() {
547
+ const fileHandle = await this._fileHandle;
548
+ const file = await fileHandle.getFile();
549
+ this._buffer = new Uint8Array(await file.arrayBuffer());
550
+ }
551
+ async _loadBufferGuarded() {
552
+ await (this._loadBufferPromise ??= this._loadBuffer());
553
+ }
554
+ // Do not call directly, use _flushLater or _flushNow.
555
+ async _flushCache(sequence) {
556
+ if (this.destroyed || sequence < this._flushSequence) {
557
+ return;
558
+ }
559
+ this._flushSequence = sequence + 1;
560
+ this._flushes.inc();
561
+ await this._loadBufferGuarded();
562
+ invariant2(this._buffer, void 0, {
563
+ F: __dxlog_file2,
564
+ L: 301,
565
+ S: this,
566
+ A: [
567
+ "this._buffer",
568
+ ""
569
+ ]
570
+ });
571
+ const fileHandle = await this._fileHandle;
572
+ const writable = await fileHandle.createWritable({
573
+ keepExistingData: true
574
+ });
575
+ await writable.write({
576
+ type: "write",
577
+ data: this._buffer,
578
+ position: 0
579
+ });
580
+ await writable.close();
581
+ }
582
+ _flushLater() {
583
+ if (this._flushScheduled) {
584
+ return;
585
+ }
586
+ const sequence = this._flushSequence;
587
+ setTimeout(async () => {
588
+ await this._flushPromise;
589
+ this._flushScheduled = false;
590
+ this._flushPromise = this._flushCache(sequence).catch((err) => log.warn(err, void 0, {
591
+ F: __dxlog_file2,
592
+ L: 319,
593
+ S: this,
594
+ C: (f, a) => f(...a)
595
+ }));
596
+ });
597
+ this._flushScheduled = true;
598
+ }
599
+ async _flushNow() {
600
+ await this._flushPromise;
601
+ this._flushPromise = this._flushCache(this._flushSequence).catch((err) => log.warn(err, void 0, {
602
+ F: __dxlog_file2,
603
+ L: 327,
604
+ S: this,
605
+ C: (f, a) => f(...a)
606
+ }));
607
+ await this._flushPromise;
608
+ }
609
+ async read(offset, size) {
610
+ this.assertNotDestroyed("Read");
611
+ this._operations.inc();
612
+ this._reads.inc();
613
+ this._readBytes.inc(size);
614
+ if (!this._buffer) {
615
+ await this._loadBufferGuarded();
616
+ invariant2(this._buffer, void 0, {
617
+ F: __dxlog_file2,
618
+ L: 340,
619
+ S: this,
620
+ A: [
621
+ "this._buffer",
622
+ ""
623
+ ]
624
+ });
625
+ }
626
+ if (offset + size > this._buffer.length) {
627
+ throw new Error("Read out of bounds");
628
+ }
629
+ return Buffer.from(this._buffer.slice(offset, offset + size));
630
+ }
631
+ async write(offset, data) {
632
+ this.assertNotDestroyed("Write");
633
+ this._operations.inc();
634
+ this._writes.inc();
635
+ this._writeBytes.inc(data.length);
636
+ if (!this._buffer) {
637
+ await this._loadBufferGuarded();
638
+ invariant2(this._buffer, void 0, {
639
+ F: __dxlog_file2,
640
+ L: 360,
641
+ S: this,
642
+ A: [
643
+ "this._buffer",
644
+ ""
645
+ ]
646
+ });
647
+ }
648
+ if (offset + data.length <= this._buffer.length) {
649
+ this._buffer.set(data, offset);
650
+ } else {
651
+ const newCache = new Uint8Array(offset + data.length);
652
+ newCache.set(this._buffer);
653
+ newCache.set(data, offset);
654
+ this._buffer = newCache;
655
+ }
656
+ this._flushLater();
657
+ }
658
+ async del(offset, size) {
659
+ this.assertNotDestroyed("Del");
660
+ this._operations.inc();
661
+ if (offset < 0 || size <= 0) {
662
+ return;
663
+ }
664
+ if (!this._buffer) {
665
+ await this._loadBufferGuarded();
666
+ invariant2(this._buffer, void 0, {
667
+ F: __dxlog_file2,
668
+ L: 387,
669
+ S: this,
670
+ A: [
671
+ "this._buffer",
672
+ ""
673
+ ]
674
+ });
675
+ }
676
+ let leftoverSize = 0;
677
+ if (offset + size < this._buffer.length) {
678
+ leftoverSize = this._buffer.length - (offset + size);
679
+ this._buffer.set(this._buffer.slice(offset + size, offset + size + leftoverSize), offset);
680
+ }
681
+ this._buffer = this._buffer.slice(0, offset + leftoverSize);
682
+ this._flushLater();
683
+ }
684
+ async stat() {
685
+ this.assertNotDestroyed("Truncate");
686
+ this._operations.inc();
687
+ if (!this._buffer) {
688
+ await this._loadBufferGuarded();
689
+ invariant2(this._buffer, void 0, {
690
+ F: __dxlog_file2,
691
+ L: 409,
692
+ S: this,
693
+ A: [
694
+ "this._buffer",
695
+ ""
696
+ ]
697
+ });
698
+ }
699
+ return {
700
+ size: this._buffer.length
701
+ };
702
+ }
703
+ async truncate(offset) {
704
+ this.assertNotDestroyed("Truncate");
705
+ this._operations.inc();
706
+ if (!this._buffer) {
707
+ await this._loadBufferGuarded();
708
+ invariant2(this._buffer, void 0, {
709
+ F: __dxlog_file2,
710
+ L: 424,
711
+ S: this,
712
+ A: [
713
+ "this._buffer",
714
+ ""
715
+ ]
716
+ });
717
+ }
718
+ this._buffer = this._buffer.slice(0, offset);
719
+ this._flushLater();
720
+ }
721
+ async flush() {
722
+ this.assertNotDestroyed("Flush");
723
+ await this._flushNow();
724
+ }
725
+ /**
726
+ * It's best to avoid using this method as it doesn't really close a file.
727
+ * We could update the _opened flag and add a guard like for destroyed, but this would break
728
+ * the FileSystemFileHandle sharing required for browser tests to run, where writes are
729
+ * not immediately visible if using different file handles.
730
+ */
731
+ async close() {
732
+ await this._flushNow();
733
+ }
734
+ async destroy() {
735
+ if (!this.destroyed) {
736
+ await this._flushNow();
737
+ this.destroyed = true;
738
+ return await this._destroy();
739
+ }
740
+ }
741
+ assertNotDestroyed(operation) {
742
+ if (this.destroyed) {
743
+ throw new Error(`${operation} on a destroyed or closed file`);
744
+ }
745
+ }
746
+ };
747
+ _ts_decorate([
748
+ trace.info()
749
+ ], WebFile.prototype, "fileName", void 0);
750
+ _ts_decorate([
751
+ trace.metricsCounter()
752
+ ], WebFile.prototype, "_flushes", void 0);
753
+ _ts_decorate([
754
+ trace.metricsCounter()
755
+ ], WebFile.prototype, "_operations", void 0);
756
+ _ts_decorate([
757
+ trace.metricsCounter()
758
+ ], WebFile.prototype, "_reads", void 0);
759
+ _ts_decorate([
760
+ trace.metricsCounter()
761
+ ], WebFile.prototype, "_readBytes", void 0);
762
+ _ts_decorate([
763
+ trace.metricsCounter()
764
+ ], WebFile.prototype, "_writes", void 0);
765
+ _ts_decorate([
766
+ trace.metricsCounter()
767
+ ], WebFile.prototype, "_writeBytes", void 0);
768
+ _ts_decorate([
769
+ trace.info()
770
+ ], WebFile.prototype, "_bufferSize", null);
771
+ _ts_decorate([
772
+ synchronized
773
+ ], WebFile.prototype, "destroy", null);
774
+
775
+ // src/browser/storage.ts
776
+ var createStorage = ({ type, root = "" } = {}) => {
777
+ if (type === void 0) {
778
+ return new IDbStorage(root);
779
+ }
780
+ switch (type) {
781
+ case StorageType.RAM: {
782
+ return new MemoryStorage(root);
783
+ }
784
+ case StorageType.IDB:
785
+ case StorageType.CHROME:
786
+ case StorageType.FIREFOX: {
787
+ return new IDbStorage(root);
788
+ }
789
+ case StorageType.WEBFS: {
790
+ return new WebFS(root);
791
+ }
792
+ default: {
793
+ throw new Error(`Invalid type: ${type}`);
794
+ }
795
+ }
796
+ };
797
+ export {
798
+ AbstractStorage,
799
+ Directory,
800
+ MemoryStorage,
801
+ StorageType,
802
+ createStorage,
803
+ getFullPath,
804
+ stringDiff,
805
+ wrapFile
806
+ };
807
+ //# sourceMappingURL=index.mjs.map