@componentor/fs 1.2.4 → 1.2.5

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.
@@ -145,6 +145,52 @@ function segments(path) {
145
145
  // src/handle-manager.ts
146
146
  var FILE_HANDLE_POOL_SIZE = 50;
147
147
  var DIR_CACHE_MAX_SIZE = 200;
148
+ var FileLockManager = class {
149
+ locks = /* @__PURE__ */ new Map();
150
+ lockResolvers = /* @__PURE__ */ new Map();
151
+ waitQueues = /* @__PURE__ */ new Map();
152
+ /**
153
+ * Acquire an exclusive lock on a file path.
154
+ * If the file is already locked, waits until it's released.
155
+ * Returns a release function that MUST be called when done.
156
+ */
157
+ async acquire(path) {
158
+ const normalizedPath = normalize(path);
159
+ while (this.locks.has(normalizedPath)) {
160
+ await this.locks.get(normalizedPath);
161
+ }
162
+ let resolve;
163
+ const lockPromise = new Promise((r) => {
164
+ resolve = r;
165
+ });
166
+ this.locks.set(normalizedPath, lockPromise);
167
+ this.lockResolvers.set(normalizedPath, resolve);
168
+ return () => {
169
+ const resolver = this.lockResolvers.get(normalizedPath);
170
+ this.locks.delete(normalizedPath);
171
+ this.lockResolvers.delete(normalizedPath);
172
+ if (resolver) resolver();
173
+ };
174
+ }
175
+ /**
176
+ * Check if a file is currently locked
177
+ */
178
+ isLocked(path) {
179
+ return this.locks.has(normalize(path));
180
+ }
181
+ /**
182
+ * Clear all locks (use with caution, mainly for cleanup)
183
+ */
184
+ clearAll() {
185
+ for (const resolver of this.lockResolvers.values()) {
186
+ resolver();
187
+ }
188
+ this.locks.clear();
189
+ this.lockResolvers.clear();
190
+ this.waitQueues.clear();
191
+ }
192
+ };
193
+ var fileLockManager = new FileLockManager();
148
194
  var HandleManager = class {
149
195
  rootPromise;
150
196
  dirCache = /* @__PURE__ */ new Map();
@@ -402,13 +448,21 @@ var SymlinkManager = class {
402
448
  if (!fileHandle) return;
403
449
  const buffer = new TextEncoder().encode(data);
404
450
  if (this.useSync) {
405
- const access = await fileHandle.createSyncAccessHandle();
406
- access.truncate(0);
407
- let written = 0;
408
- while (written < buffer.length) {
409
- written += access.write(buffer.subarray(written), { at: written });
451
+ const releaseLock = await fileLockManager.acquire(SYMLINK_FILE);
452
+ try {
453
+ const access = await fileHandle.createSyncAccessHandle();
454
+ try {
455
+ access.truncate(0);
456
+ let written = 0;
457
+ while (written < buffer.length) {
458
+ written += access.write(buffer.subarray(written), { at: written });
459
+ }
460
+ } finally {
461
+ access.close();
462
+ }
463
+ } finally {
464
+ releaseLock();
410
465
  }
411
- access.close();
412
466
  } else {
413
467
  const writable = await fileHandle.createWritable();
414
468
  await writable.write(buffer);
@@ -653,29 +707,12 @@ var PackedStorage = class {
653
707
  useChecksum;
654
708
  index = null;
655
709
  indexLoaded = false;
656
- lockPromise = null;
657
710
  constructor(handleManager, useSync, useCompression = false, useChecksum = true) {
658
711
  this.handleManager = handleManager;
659
712
  this.useSync = useSync;
660
713
  this.useCompression = useCompression && typeof CompressionStream !== "undefined";
661
714
  this.useChecksum = useChecksum;
662
715
  }
663
- /**
664
- * Acquire lock for pack file access (prevents concurrent handle conflicts)
665
- */
666
- async acquireLock() {
667
- while (this.lockPromise) {
668
- await this.lockPromise;
669
- }
670
- let release;
671
- this.lockPromise = new Promise((resolve) => {
672
- release = () => {
673
- this.lockPromise = null;
674
- resolve();
675
- };
676
- });
677
- return release;
678
- }
679
716
  /**
680
717
  * Reset pack storage state (memory only)
681
718
  */
@@ -707,30 +744,35 @@ var PackedStorage = class {
707
744
  return {};
708
745
  }
709
746
  if (this.useSync) {
710
- const access = await fileHandle.createSyncAccessHandle();
747
+ const releaseLock = await fileLockManager.acquire(PACK_FILE);
711
748
  try {
712
- const size = access.getSize();
713
- if (size < 8) {
714
- return {};
715
- }
716
- const header = new Uint8Array(8);
717
- access.read(header, { at: 0 });
718
- const view = new DataView(header.buffer);
719
- const indexLen = view.getUint32(0, true);
720
- const storedCrc = view.getUint32(4, true);
721
- const contentSize = size - 8;
722
- const content = new Uint8Array(contentSize);
723
- access.read(content, { at: 8 });
724
- if (this.useChecksum && storedCrc !== 0) {
725
- const calculatedCrc = crc32(content);
726
- if (calculatedCrc !== storedCrc) {
727
- throw createECORRUPTED(PACK_FILE);
749
+ const access = await fileHandle.createSyncAccessHandle();
750
+ try {
751
+ const size = access.getSize();
752
+ if (size < 8) {
753
+ return {};
754
+ }
755
+ const header = new Uint8Array(8);
756
+ access.read(header, { at: 0 });
757
+ const view = new DataView(header.buffer);
758
+ const indexLen = view.getUint32(0, true);
759
+ const storedCrc = view.getUint32(4, true);
760
+ const contentSize = size - 8;
761
+ const content = new Uint8Array(contentSize);
762
+ access.read(content, { at: 8 });
763
+ if (this.useChecksum && storedCrc !== 0) {
764
+ const calculatedCrc = crc32(content);
765
+ if (calculatedCrc !== storedCrc) {
766
+ throw createECORRUPTED(PACK_FILE);
767
+ }
728
768
  }
769
+ const indexJson = new TextDecoder().decode(content.subarray(0, indexLen));
770
+ return JSON.parse(indexJson);
771
+ } finally {
772
+ access.close();
729
773
  }
730
- const indexJson = new TextDecoder().decode(content.subarray(0, indexLen));
731
- return JSON.parse(indexJson);
732
774
  } finally {
733
- access.close();
775
+ releaseLock();
734
776
  }
735
777
  } else {
736
778
  const file = await fileHandle.getFile();
@@ -759,43 +801,33 @@ var PackedStorage = class {
759
801
  * Check if a path exists in the pack
760
802
  */
761
803
  async has(path) {
762
- const release = await this.acquireLock();
763
- try {
764
- const index = await this.loadIndex();
765
- return path in index;
766
- } finally {
767
- release();
768
- }
804
+ const index = await this.loadIndex();
805
+ return path in index;
769
806
  }
770
807
  /**
771
808
  * Get file size from pack (for stat)
772
809
  * Returns originalSize if compressed, otherwise size
773
810
  */
774
811
  async getSize(path) {
775
- const release = await this.acquireLock();
776
- try {
777
- const index = await this.loadIndex();
778
- const entry = index[path];
779
- if (!entry) return null;
780
- return entry.originalSize ?? entry.size;
781
- } finally {
782
- release();
783
- }
812
+ const index = await this.loadIndex();
813
+ const entry = index[path];
814
+ if (!entry) return null;
815
+ return entry.originalSize ?? entry.size;
784
816
  }
785
817
  /**
786
818
  * Read a file from the pack
787
819
  * Handles decompression if file was stored compressed
788
820
  */
789
821
  async read(path) {
790
- const release = await this.acquireLock();
791
- try {
792
- const index = await this.loadIndex();
793
- const entry = index[path];
794
- if (!entry) return null;
795
- const { fileHandle } = await this.handleManager.getHandle(PACK_FILE);
796
- if (!fileHandle) return null;
797
- let buffer;
798
- if (this.useSync) {
822
+ const index = await this.loadIndex();
823
+ const entry = index[path];
824
+ if (!entry) return null;
825
+ const { fileHandle } = await this.handleManager.getHandle(PACK_FILE);
826
+ if (!fileHandle) return null;
827
+ let buffer;
828
+ if (this.useSync) {
829
+ const releaseLock = await fileLockManager.acquire(PACK_FILE);
830
+ try {
799
831
  const access = await fileHandle.createSyncAccessHandle();
800
832
  try {
801
833
  buffer = new Uint8Array(entry.size);
@@ -803,18 +835,18 @@ var PackedStorage = class {
803
835
  } finally {
804
836
  access.close();
805
837
  }
806
- } else {
807
- const file = await fileHandle.getFile();
808
- const data = new Uint8Array(await file.arrayBuffer());
809
- buffer = data.slice(entry.offset, entry.offset + entry.size);
810
- }
811
- if (entry.originalSize !== void 0) {
812
- return decompress(buffer);
838
+ } finally {
839
+ releaseLock();
813
840
  }
814
- return buffer;
815
- } finally {
816
- release();
841
+ } else {
842
+ const file = await fileHandle.getFile();
843
+ const data = new Uint8Array(await file.arrayBuffer());
844
+ buffer = data.slice(entry.offset, entry.offset + entry.size);
845
+ }
846
+ if (entry.originalSize !== void 0) {
847
+ return decompress(buffer);
817
848
  }
849
+ return buffer;
818
850
  }
819
851
  /**
820
852
  * Read multiple files from the pack in a single operation
@@ -824,28 +856,28 @@ var PackedStorage = class {
824
856
  async readBatch(paths) {
825
857
  const results = /* @__PURE__ */ new Map();
826
858
  if (paths.length === 0) return results;
827
- const release = await this.acquireLock();
828
- try {
829
- const index = await this.loadIndex();
830
- const toRead = [];
831
- for (const path of paths) {
832
- const entry = index[path];
833
- if (entry) {
834
- toRead.push({ path, offset: entry.offset, size: entry.size, originalSize: entry.originalSize });
835
- } else {
836
- results.set(path, null);
837
- }
859
+ const index = await this.loadIndex();
860
+ const toRead = [];
861
+ for (const path of paths) {
862
+ const entry = index[path];
863
+ if (entry) {
864
+ toRead.push({ path, offset: entry.offset, size: entry.size, originalSize: entry.originalSize });
865
+ } else {
866
+ results.set(path, null);
838
867
  }
839
- if (toRead.length === 0) return results;
840
- const { fileHandle } = await this.handleManager.getHandle(PACK_FILE);
841
- if (!fileHandle) {
842
- for (const { path } of toRead) {
843
- results.set(path, null);
844
- }
845
- return results;
868
+ }
869
+ if (toRead.length === 0) return results;
870
+ const { fileHandle } = await this.handleManager.getHandle(PACK_FILE);
871
+ if (!fileHandle) {
872
+ for (const { path } of toRead) {
873
+ results.set(path, null);
846
874
  }
847
- const decompressPromises = [];
848
- if (this.useSync) {
875
+ return results;
876
+ }
877
+ const decompressPromises = [];
878
+ if (this.useSync) {
879
+ const releaseLock = await fileLockManager.acquire(PACK_FILE);
880
+ try {
849
881
  const access = await fileHandle.createSyncAccessHandle();
850
882
  try {
851
883
  for (const { path, offset, size, originalSize } of toRead) {
@@ -860,25 +892,25 @@ var PackedStorage = class {
860
892
  } finally {
861
893
  access.close();
862
894
  }
863
- } else {
864
- const file = await fileHandle.getFile();
865
- const data = new Uint8Array(await file.arrayBuffer());
866
- for (const { path, offset, size, originalSize } of toRead) {
867
- const buffer = data.slice(offset, offset + size);
868
- if (originalSize !== void 0) {
869
- decompressPromises.push({ path, promise: decompress(buffer) });
870
- } else {
871
- results.set(path, buffer);
872
- }
873
- }
895
+ } finally {
896
+ releaseLock();
874
897
  }
875
- for (const { path, promise } of decompressPromises) {
876
- results.set(path, await promise);
898
+ } else {
899
+ const file = await fileHandle.getFile();
900
+ const data = new Uint8Array(await file.arrayBuffer());
901
+ for (const { path, offset, size, originalSize } of toRead) {
902
+ const buffer = data.slice(offset, offset + size);
903
+ if (originalSize !== void 0) {
904
+ decompressPromises.push({ path, promise: decompress(buffer) });
905
+ } else {
906
+ results.set(path, buffer);
907
+ }
877
908
  }
878
- return results;
879
- } finally {
880
- release();
881
909
  }
910
+ for (const { path, promise } of decompressPromises) {
911
+ results.set(path, await promise);
912
+ }
913
+ return results;
882
914
  }
883
915
  /**
884
916
  * Write multiple files to the pack in a single operation
@@ -889,62 +921,57 @@ var PackedStorage = class {
889
921
  */
890
922
  async writeBatch(entries) {
891
923
  if (entries.length === 0) return;
892
- const release = await this.acquireLock();
893
- try {
894
- const encoder = new TextEncoder();
895
- let processedEntries;
896
- if (this.useCompression) {
897
- processedEntries = await Promise.all(
898
- entries.map(async ({ path, data }) => {
899
- const compressed = await compress(data);
900
- if (compressed.length < data.length) {
901
- return { path, data: compressed, originalSize: data.length };
902
- }
903
- return { path, data };
904
- })
905
- );
906
- } else {
907
- processedEntries = entries;
908
- }
909
- let totalDataSize = 0;
910
- for (const { data } of processedEntries) {
911
- totalDataSize += data.length;
912
- }
913
- const newIndex = {};
914
- let headerSize = 8;
915
- let prevHeaderSize = 0;
916
- while (headerSize !== prevHeaderSize) {
917
- prevHeaderSize = headerSize;
918
- let currentOffset = headerSize;
919
- for (const { path, data, originalSize } of processedEntries) {
920
- const entry = { offset: currentOffset, size: data.length };
921
- if (originalSize !== void 0) {
922
- entry.originalSize = originalSize;
924
+ const encoder = new TextEncoder();
925
+ let processedEntries;
926
+ if (this.useCompression) {
927
+ processedEntries = await Promise.all(
928
+ entries.map(async ({ path, data }) => {
929
+ const compressed = await compress(data);
930
+ if (compressed.length < data.length) {
931
+ return { path, data: compressed, originalSize: data.length };
923
932
  }
924
- newIndex[path] = entry;
925
- currentOffset += data.length;
933
+ return { path, data };
934
+ })
935
+ );
936
+ } else {
937
+ processedEntries = entries;
938
+ }
939
+ let totalDataSize = 0;
940
+ for (const { data } of processedEntries) {
941
+ totalDataSize += data.length;
942
+ }
943
+ const newIndex = {};
944
+ let headerSize = 8;
945
+ let prevHeaderSize = 0;
946
+ while (headerSize !== prevHeaderSize) {
947
+ prevHeaderSize = headerSize;
948
+ let currentOffset = headerSize;
949
+ for (const { path, data, originalSize } of processedEntries) {
950
+ const entry = { offset: currentOffset, size: data.length };
951
+ if (originalSize !== void 0) {
952
+ entry.originalSize = originalSize;
926
953
  }
927
- const indexBuf = encoder.encode(JSON.stringify(newIndex));
928
- headerSize = 8 + indexBuf.length;
929
- }
930
- const finalIndexBuf = encoder.encode(JSON.stringify(newIndex));
931
- const totalSize = headerSize + totalDataSize;
932
- const packBuffer = new Uint8Array(totalSize);
933
- const view = new DataView(packBuffer.buffer);
934
- packBuffer.set(finalIndexBuf, 8);
935
- for (const { path, data } of processedEntries) {
936
- const entry = newIndex[path];
937
- packBuffer.set(data, entry.offset);
938
- }
939
- const content = packBuffer.subarray(8);
940
- const checksum = this.useChecksum ? crc32(content) : 0;
941
- view.setUint32(0, finalIndexBuf.length, true);
942
- view.setUint32(4, checksum, true);
943
- await this.writePackFile(packBuffer);
944
- this.index = newIndex;
945
- } finally {
946
- release();
954
+ newIndex[path] = entry;
955
+ currentOffset += data.length;
956
+ }
957
+ const indexBuf = encoder.encode(JSON.stringify(newIndex));
958
+ headerSize = 8 + indexBuf.length;
947
959
  }
960
+ const finalIndexBuf = encoder.encode(JSON.stringify(newIndex));
961
+ const totalSize = headerSize + totalDataSize;
962
+ const packBuffer = new Uint8Array(totalSize);
963
+ const view = new DataView(packBuffer.buffer);
964
+ packBuffer.set(finalIndexBuf, 8);
965
+ for (const { path, data } of processedEntries) {
966
+ const entry = newIndex[path];
967
+ packBuffer.set(data, entry.offset);
968
+ }
969
+ const content = packBuffer.subarray(8);
970
+ const checksum = this.useChecksum ? crc32(content) : 0;
971
+ view.setUint32(0, finalIndexBuf.length, true);
972
+ view.setUint32(4, checksum, true);
973
+ await this.writePackFile(packBuffer);
974
+ this.index = newIndex;
948
975
  }
949
976
  /**
950
977
  * Write the pack file to OPFS
@@ -954,12 +981,17 @@ var PackedStorage = class {
954
981
  const { fileHandle } = await this.handleManager.getHandle(PACK_FILE, { create: true });
955
982
  if (!fileHandle) return;
956
983
  if (this.useSync) {
957
- const access = await fileHandle.createSyncAccessHandle();
984
+ const releaseLock = await fileLockManager.acquire(PACK_FILE);
958
985
  try {
959
- access.truncate(data.length);
960
- access.write(data, { at: 0 });
986
+ const access = await fileHandle.createSyncAccessHandle();
987
+ try {
988
+ access.truncate(data.length);
989
+ access.write(data, { at: 0 });
990
+ } finally {
991
+ access.close();
992
+ }
961
993
  } finally {
962
- access.close();
994
+ releaseLock();
963
995
  }
964
996
  } else {
965
997
  const writable = await fileHandle.createWritable();
@@ -972,16 +1004,16 @@ var PackedStorage = class {
972
1004
  * Note: Doesn't reclaim space, just removes from index and recalculates CRC32
973
1005
  */
974
1006
  async remove(path) {
975
- const release = await this.acquireLock();
976
- try {
977
- const index = await this.loadIndex();
978
- if (!(path in index)) return false;
979
- delete index[path];
980
- const { fileHandle } = await this.handleManager.getHandle(PACK_FILE);
981
- if (!fileHandle) return true;
982
- const encoder = new TextEncoder();
983
- const newIndexBuf = encoder.encode(JSON.stringify(index));
984
- if (this.useSync) {
1007
+ const index = await this.loadIndex();
1008
+ if (!(path in index)) return false;
1009
+ delete index[path];
1010
+ const { fileHandle } = await this.handleManager.getHandle(PACK_FILE);
1011
+ if (!fileHandle) return true;
1012
+ const encoder = new TextEncoder();
1013
+ const newIndexBuf = encoder.encode(JSON.stringify(index));
1014
+ if (this.useSync) {
1015
+ const releaseLock = await fileLockManager.acquire(PACK_FILE);
1016
+ try {
985
1017
  const access = await fileHandle.createSyncAccessHandle();
986
1018
  try {
987
1019
  const size = access.getSize();
@@ -1012,42 +1044,37 @@ var PackedStorage = class {
1012
1044
  } finally {
1013
1045
  access.close();
1014
1046
  }
1015
- } else {
1016
- const file = await fileHandle.getFile();
1017
- const oldData = new Uint8Array(await file.arrayBuffer());
1018
- if (oldData.length < 8) return true;
1019
- const oldIndexLen = new DataView(oldData.buffer).getUint32(0, true);
1020
- const dataStart = 8 + oldIndexLen;
1021
- const dataPortion = oldData.subarray(dataStart);
1022
- const newContent = new Uint8Array(newIndexBuf.length + dataPortion.length);
1023
- newContent.set(newIndexBuf, 0);
1024
- newContent.set(dataPortion, newIndexBuf.length);
1025
- const checksum = this.useChecksum ? crc32(newContent) : 0;
1026
- const newFile = new Uint8Array(8 + newContent.length);
1027
- const view = new DataView(newFile.buffer);
1028
- view.setUint32(0, newIndexBuf.length, true);
1029
- view.setUint32(4, checksum, true);
1030
- newFile.set(newContent, 8);
1031
- const writable = await fileHandle.createWritable();
1032
- await writable.write(newFile);
1033
- await writable.close();
1047
+ } finally {
1048
+ releaseLock();
1034
1049
  }
1035
- return true;
1036
- } finally {
1037
- release();
1050
+ } else {
1051
+ const file = await fileHandle.getFile();
1052
+ const oldData = new Uint8Array(await file.arrayBuffer());
1053
+ if (oldData.length < 8) return true;
1054
+ const oldIndexLen = new DataView(oldData.buffer).getUint32(0, true);
1055
+ const dataStart = 8 + oldIndexLen;
1056
+ const dataPortion = oldData.subarray(dataStart);
1057
+ const newContent = new Uint8Array(newIndexBuf.length + dataPortion.length);
1058
+ newContent.set(newIndexBuf, 0);
1059
+ newContent.set(dataPortion, newIndexBuf.length);
1060
+ const checksum = this.useChecksum ? crc32(newContent) : 0;
1061
+ const newFile = new Uint8Array(8 + newContent.length);
1062
+ const view = new DataView(newFile.buffer);
1063
+ view.setUint32(0, newIndexBuf.length, true);
1064
+ view.setUint32(4, checksum, true);
1065
+ newFile.set(newContent, 8);
1066
+ const writable = await fileHandle.createWritable();
1067
+ await writable.write(newFile);
1068
+ await writable.close();
1038
1069
  }
1070
+ return true;
1039
1071
  }
1040
1072
  /**
1041
1073
  * Check if pack file is being used (has entries)
1042
1074
  */
1043
1075
  async isEmpty() {
1044
- const release = await this.acquireLock();
1045
- try {
1046
- const index = await this.loadIndex();
1047
- return Object.keys(index).length === 0;
1048
- } finally {
1049
- release();
1050
- }
1076
+ const index = await this.loadIndex();
1077
+ return Object.keys(index).length === 0;
1051
1078
  }
1052
1079
  };
1053
1080
 
@@ -1689,11 +1716,19 @@ var OPFS = class {
1689
1716
  if (fileHandle) {
1690
1717
  let buffer;
1691
1718
  if (this.useSync) {
1692
- const access = await fileHandle.createSyncAccessHandle();
1693
- const size = access.getSize();
1694
- buffer = new Uint8Array(size);
1695
- access.read(buffer);
1696
- access.close();
1719
+ const releaseLock = await fileLockManager.acquire(resolvedPath);
1720
+ try {
1721
+ const access = await fileHandle.createSyncAccessHandle();
1722
+ try {
1723
+ const size = access.getSize();
1724
+ buffer = new Uint8Array(size);
1725
+ access.read(buffer);
1726
+ } finally {
1727
+ access.close();
1728
+ }
1729
+ } finally {
1730
+ releaseLock();
1731
+ }
1697
1732
  } else {
1698
1733
  const file = await fileHandle.getFile();
1699
1734
  buffer = new Uint8Array(await file.arrayBuffer());
@@ -1750,11 +1785,19 @@ var OPFS = class {
1750
1785
  }
1751
1786
  let buffer;
1752
1787
  if (this.useSync) {
1753
- const access = await fileHandle.createSyncAccessHandle();
1754
- const size = access.getSize();
1755
- buffer = new Uint8Array(size);
1756
- access.read(buffer);
1757
- access.close();
1788
+ const releaseLock = await fileLockManager.acquire(resolvedPath);
1789
+ try {
1790
+ const access = await fileHandle.createSyncAccessHandle();
1791
+ try {
1792
+ const size = access.getSize();
1793
+ buffer = new Uint8Array(size);
1794
+ access.read(buffer);
1795
+ } finally {
1796
+ access.close();
1797
+ }
1798
+ } finally {
1799
+ releaseLock();
1800
+ }
1758
1801
  } else {
1759
1802
  const file = await fileHandle.getFile();
1760
1803
  buffer = new Uint8Array(await file.arrayBuffer());
@@ -1786,10 +1829,18 @@ var OPFS = class {
1786
1829
  const { fileHandle } = await this.handleManager.getHandle(resolvedPath, { create: true });
1787
1830
  const buffer = typeof data === "string" ? new TextEncoder().encode(data) : data;
1788
1831
  if (this.useSync) {
1789
- const access = await fileHandle.createSyncAccessHandle();
1790
- access.truncate(buffer.length);
1791
- access.write(buffer, { at: 0 });
1792
- access.close();
1832
+ const releaseLock = await fileLockManager.acquire(resolvedPath);
1833
+ try {
1834
+ const access = await fileHandle.createSyncAccessHandle();
1835
+ try {
1836
+ access.truncate(buffer.length);
1837
+ access.write(buffer, { at: 0 });
1838
+ } finally {
1839
+ access.close();
1840
+ }
1841
+ } finally {
1842
+ releaseLock();
1843
+ }
1793
1844
  } else {
1794
1845
  const writable = await fileHandle.createWritable();
1795
1846
  await writable.write(buffer);
@@ -2402,9 +2453,17 @@ var OPFS = class {
2402
2453
  const { fileHandle } = await this.handleManager.getHandle(resolvedPath);
2403
2454
  if (!fileHandle) throw createENOENT(path);
2404
2455
  if (this.useSync) {
2405
- const access = await fileHandle.createSyncAccessHandle();
2406
- access.truncate(len);
2407
- access.close();
2456
+ const releaseLock = await fileLockManager.acquire(resolvedPath);
2457
+ try {
2458
+ const access = await fileHandle.createSyncAccessHandle();
2459
+ try {
2460
+ access.truncate(len);
2461
+ } finally {
2462
+ access.close();
2463
+ }
2464
+ } finally {
2465
+ releaseLock();
2466
+ }
2408
2467
  } else {
2409
2468
  const file = await fileHandle.getFile();
2410
2469
  const data = new Uint8Array(await file.arrayBuffer());