dbas_filesystem 3.1.4
dbas_filesystem: ^3.1.4 copied to clipboard
Flutter plugin for cross-platform file system operations with streaming, byte array, and directory support across Android, iOS, macOS, Linux, Windows, and Web (OPFS).
3.1.4 #
Security #
- Pinned third-party CI action:
subosito/flutter-actionis now pinned to a commit SHA instead of the floatingv2tag, so the public repo can't run an unverified upstream action update on PRs from forks. First-partyactions/*stay on their major tags.
Documentation #
- License footer aligned with Apache 2.0: replaced the README "All rights reserved" line with "Licensed under the Apache License, Version 2.0" to match the actual
LICENSEfile.
3.1.3 #
Documentation #
- Install instructions for pub.dev: README now installs
dbas_filesystemfrom pub.dev (flutter pub add dbas_filesystem) instead of the previous git URL.
3.1.2 #
Improvements #
- Public release: relicensed under Apache License 2.0 and prepared the repo for public distribution (new CI/release/publish pipeline,
.pubignore,CODEOWNERS). - SDK / Flutter floor: bumped to
sdk: ^3.12.0andflutter: '>=3.44.0'. - Dependencies: refreshed
webto^1.1.1.
3.1.1 #
Improvements #
- Reduced lock contention for read-only operations:
fileExists,getFileSize, andgetLastModifiednow acquire a shared lock instead of an exclusive lock. Multiple concurrent reads on the same path no longer serialize behind each other. This also reduces contention whenonFileChangedis enabled, since every mutation performs an extrafileExistscheck before writing.
3.1.0 #
Breaking changes #
overwritedefaults tofalse:writeFile,writeFileStream,copyFile,moveFile,renameFile, andcopyDirectorynow default tooverwrite: false. Existing files are preserved unless you explicitly passoverwrite: true. This prevents silent data loss from accidental overwrites.- Atomic bulk writes (default):
writeFilesandwriteFilesStreamare now atomic by default — if any write fails, all successfully written files are rolled back to their original state. Setatomic: falseto restore the previous non-atomic behavior withonErrorsupport. readFileswithoutonErrorthrowsMultiException: WhenonErroris not provided,readFilesnow collects all errors and throwsMultiExceptioninstead of propagating only the first error. PassonErrorto get the previous partial-results behavior.
New features #
- Atomic bulk operations with rollback:
writeFilesandwriteFilesStreamaccept{bool atomic = true}. In atomic mode, existing files are snapshotted before writing. On failure, all changes are rolled back andAtomicOperationExceptionis thrown (with an optionalsecondaryErrorif rollback itself partially failed). moveDirectory: Moves a directory tree. On native, attempts atomicrename()first, falling back to copy+delete across filesystems. On web, performs copy+delete via OPFS.- File change notifications:
getInstanceacceptsonFileChangedcallback (also settable as a property). Fires after every successful mutation with aMap<String, FileChange>describing old/new state of each affected entry. Directory operations fire one notification with all affected entries. - Progress callbacks: All operations accept
onProgresswithOperationProgresscontainingcurrent(entry + progress) andoverall(0.0-1.0). Bulk ops report per-file completion; copy operations report byte-level progress on native. - Configurable dispose timeout:
dispose({Duration timeout})replaces the hard-coded 30-second timeout. - Hierarchical per-path locking: File operations acquire a shared lock on the parent directory and an exclusive lock on the file. Directory-destructive operations (delete, rename, move) acquire exclusive locks that block concurrent file operations in that directory. Non-destructive directory operations (list, exists, create) use shared locks.
- Symlink resolution in
listDirectory: Symlinks on native platforms are now resolved to their target type instead of being misidentified as directories. MultiException: Collects all errors from parallel operations with path context. Immutable error list.AtomicOperationException: Contains the primaryerrorand an optionalsecondaryErrorfrom rollback.FileChangetype: Describes a single change witholdEntry/newEntryand derivedtype(created/modified/deleted). Named factories:FileChange.created(),.deleted(),.modified().OperationProgress/CurrentEntryProgress: Progress reporting types with range-validated fields.- Web worker orphaned stream cleanup: On worker restart, orphaned writable streams from a previous crash are aborted during initialization.
- Web
moveDirectorydestination guard: Web now checks that the destination doesn't already exist before moving, matching nativeDirectory.rename()behavior.
Fixes #
- Callback safety:
onFileChangedandonProgresscallbacks are wrapped in try-catch — a bug in user code never masks a successful filesystem operation. PathLock.disposeno longer orphans waiters: On timeout, pending lock waiters receiveStateErrorinstead of hanging forever.- Cancellation token respected in snapshot phase:
writeFiles/writeFilesStreamnow check the cancellation token during the snapshot phase, not just the write phase. _RWLockdefensive assertions:releaseShared/releaseExclusiveassert correct pairing to prevent silent lock corruption.
Improvements #
- Singleton documented as intentional: Class-level documentation explains why the singleton pattern is used (coordinating per-path locks, worker pools, and change notifications).
- Web worker double-copy overhead documented: The
Uint8List→List<int>conversion in_sanitizeArgsis documented as a known Dart JS interop limitation. readFileStreamlock behavior documented: Doc comment explains that the file path lock is held for the entire stream lifetime.- JS worker cleanup logging: Silent
catch (_) {}blocks in worker cleanup (orphaned streams, move/rename rollback) now useconsole.warnfor debuggability. _rollbackreturn clarity: Usesreturn _rollback(...)for explicit non-return semantics.- JS worker minification: Source moved to
web/libs/src/. CI automatically minifies via esbuild and commits the built output toweb/libs/. Local scripts available atscripts/minify-js-worker.shand.ps1.
Tests #
- 129 tests (up from 92). New coverage:
- Atomic rollback (success + failure paths)
writeFilesStream(happy path + atomic rollback)moveDirectory(happy path + missing source)- File change notifications (writeFile create/modify, deleteFile, moveFile, renameFile, copyDirectory, moveDirectory, writeFiles)
- Progress callbacks (writeFile, writeFiles)
- Callback safety (throwing onFileChanged, throwing onProgress)
PathLock.withLocks(sorted acquisition, exclusive-overrides-shared)- PathLock writer-priority
- Mid-flight cancellation
onErrorwithatomic: false(non-atomic write + read)MultiExceptionimmutability and error detailsFileChangefactories and equality- Configurable dispose timeout
createDirectory(recursive: false)error path- Empty bulk operation edge cases
3.0.0 #
Breaking changes #
listDirectoryreturns typed entries:listDirectorynow returnsList<FileSystemEntry>instead ofList<String>. EachFileSystemEntryhas apath(normalized forward-slash string) and atype(FileSystemEntityType.fileorFileSystemEntityType.directory). Update call sites fromentrytoentry.pathfor path access.
New features #
appendFileandappendFileStream: Append bytes to existing files, or create them if they don't exist. Parent directories are created automatically, consistent withwriteFile.copyDirectory: Copies a directory tree with merge semantics — files at matching paths in the destination are overwritten (or throwFileAlreadyExistsExceptionwithoverwrite: false), while non-conflicting destination files are preserved.isDisposedgetter: Returnstrueafterdispose()has been called. All subsequent operations on a disposed instance throwStateError.CancellationTokenlistener API:addListener/removeListenerfor reactive cancellation. Listeners registered after cancellation are called immediately. Listeners are invoked synchronously incancel()exactly once.- Web worker auto-restart: Crashed workers are automatically restarted with exponential backoff (first 3 retries immediate, then 1s, 2s, 4s... capped at 60s, max 5 retries per slot). Previously, a crashed worker was permanently removed from the pool.
Fixes #
- Unified error handling: Replaced
_throwIfNotFound/_throwIfDirNotFoundwith a singlehandleErrormethod. All native methods now catchFileSystemExceptionand map to typed exceptions. Added ENOTDIR (20), EISDIR (21), and Windows ERROR_PATH_NOT_FOUND (3) mappings. - Web
PermissionDeniedException: OPFSNotAllowedErrornow maps toPermissionDeniedExceptioninstead of a genericDbasFileSystemException. - Native
moveFilerollback safety: Cross-device move fallback no longer deletes the destination when source deletion fails. Matches web behaviour — data at the destination (which was successfully copied) is preserved. - Dispose race condition:
getInstance()anddispose()now use a static mutex to prevent overlapping execution. Previously, a concurrentgetInstance()duringdispose()could receive a being-disposed native interface. - Graceful dispose with timeout:
dispose()gives in-flight operations up to 30 seconds to complete before forcing teardown, instead of waiting indefinitely.
Improvements #
- Documentation:
getAppFilePathdoc comment clarifies it is side-effect free (no directory creation). README explains OPFS-only web strategy (no IndexedDB/LocalStorage fallback). Worker crash troubleshooting updated for auto-restart behaviour. _assertNotDisposedguard: Every public method onDbasFileSystemchecksisDisposedbefore delegating, providing immediateStateErrorinstead of relying on thePathLockdisposed check.
Tests #
- 20+ new tests:
appendFile/appendFileStream(6 tests),copyDirectory(5 tests),listDirectorytyped entries (2 tests),CancellationTokenlisteners (5 tests),isDisposedlifecycle (3 tests),FileSystemEntrymodel (1 test). - Updated all existing
listDirectorytests for the newFileSystemEntryreturn type.
2.3.0 #
New features #
overwriteparameter oncopyFile,moveFile,renameFile: All three methods now accept{bool overwrite = true}. Whenoverwrite: falseand the destination already exists, throwsFileAlreadyExistsException. Default behavior (overwrite: true) is unchanged — fully backwards compatible.- Recursive
listDirectory:listDirectorynow accepts{bool recursive = false}. Whentrue, returns all entries in subdirectories as well. Default behavior is unchanged.
Fixes #
- Web
readFileStreambackpressure: AddedonPause/onResumehandlers withpauseCompleterpattern (matching native implementation). Slow consumers on web no longer cause unbounded memory growth. Also added a missingcancelledcheck after worker round-trip to prevent adding chunks to a cancelled stream. - Web
moveFilerollback safety: Previously, if source deletion failed after a successful copy, the worker would delete the destination — destroying the user's data whenoverwrite: truehad replaced a pre-existing file. Now the destination (with correct data) is preserved and the error propagates. EPERMerror mapping: LinuxEPERM(error code 1, "Operation not permitted") now maps toPermissionDeniedException, alongside the existingEACCES(13) and WindowsERROR_ACCESS_DENIED(5) mappings.- CI: test discovery: Changed
flutter test test/dbas_filesystem_test.darttoflutter test test/so new test files are automatically picked up.
Improvements #
getAppFilePathis now side-effect free: No longer creates the application data directory on every call. Write operations (writeFile,writeFileStream) already create parent directories, so this was redundant. Callers that relied on the implicit directory creation should usecreateDirectoryexplicitly.isTest()cached at startup: TheFLUTTER_TESTenvironment variable check is now evaluated once at library load time instead of on everygetAppFilePathcall.- DRY bulk operations: The
onErrorbranching logic duplicated acrosswriteFiles,writeFilesStream, andreadFileshas been extracted into a shared_withErrorHandlerhelper.
Tests #
- 7 new tests:
copyFile/moveFile/renameFilewithoverwrite: false(3 tests + 1 success case), recursivelistDirectory, strengthenedwriteFilesonErrorcallback with a real failure trigger.
2.2.2 #
Fixes #
- CI: web integration tests use WebDriver protocol: Switched from
-d chrome(dwds) to-d web-server --browser-name=chrome(WebDriver via ChromeDriver). FixesAppConnectionException/ dwds connection failures on headless CI runners. Chrome runs headless natively viaintegrationDriver()— noxvfb-runneeded.
2.2.1 #
Fixes #
- CI: web integration tests on headless runners: Fixed
Missing X server or $DISPLAYerror by wrappingflutter drivewithxvfb-runfor headless Chrome support on Ubuntu CI. - CI: ChromeDriver cleanup: Added a
Stop ChromeDriverstep (if: always()) to kill the backgrounded process after tests complete. - CI: example dependencies: Added
flutter pub getfor theexample/project before running integration tests.
2.2.0 #
New features #
onErrorcallback for bulk operations:readFiles,writeFiles, andwriteFilesStreamnow accept an optionalonErrorcallback. When provided, individual failures invoke the callback instead of throwing — successful results are still returned.OperationCancelledExceptionalways propagates regardless ofonError.PermissionDeniedException: New typed exception for permission-denied errors. MapsEACCES(13) on Linux/macOS andERROR_ACCESS_DENIED(5) on Windows to a typed exception instead of surfacing rawFileSystemException.chunkSizehonored on native:readFileStreamnow respects thechunkSizeparameter on all platforms (previously only affected web). UsesRandomAccessFilefor precise chunk-level control with backpressure support — slow consumers no longer cause unbounded memory growth.
Fixes #
copyFilerobustness: Replaced fragilepipe()with a manual read/write loop andtry/finallypattern. The writer is always closed, and partial destination files are cleaned up on failure (including on Windows where file handles must be released before deletion).getInstance()hardening: The_initCompleteris now captured into a local variable before accessing.future, eliminating a theoretical race ifdispose()clears it between the null-check and usage. Error cleanup usesidentical()to avoid stomping a concurrent re-initialization.
Improvements #
- Memory guidance:
readFiles,writeFiles, andwriteFilesStreamdoc comments now document memory implications. README adds guidance on when to use bulk APIs vs streaming. - Removed unused dependency:
plugin_platform_interfacewas listed inpubspec.yamlbut never imported. Removed.
Tests #
- 12 new tests:
chunkSizehonoring (3 tests),PermissionDeniedExceptionhierarchy,copyFilepartial cleanup,onErrorcallback (4 tests),getInstancehardening, backwards compatibility.
2.1.0 #
New features #
- Cancellation tokens: Bulk operations (
writeFiles,readFiles,writeFilesStream) now accept an optionalCancellationToken. When cancelled, tasks not yet started throwOperationCancelledException; in-flight tasks run to completion. isPersistentStoragegetter: Reports whether the underlying storage is persistent. Alwaystrueon native platforms. On web, reflects whether the browser granted persistent OPFS storage vianavigator.storage.persist().OperationCancelledException: New typed exception for cancelled operations, extendsDbasFileSystemException.
Improvements #
- Bulk operation docs:
writeFiles,readFiles, andwriteFilesStreamdoc comments now explicitly state that operations are not atomic — no rollback on partial failure. - Web worker error messages: Crash errors now include recovery instructions ("Call dispose() and re-initialize.").
- Web persistence visibility: Worker returns persistence grant status to Dart instead of only logging to
console.warn. Apps can checkisPersistentStorageand warn users. - README: Added migration guide (v1.x → v2.x), performance tuning table, bulk operation semantics, troubleshooting section, cancellation examples, and storage persistence examples.
- pubspec.yaml: Added
repositoryandissue_trackerfields.
Tests #
- 16 new edge case tests: cancellation tokens,
isPersistentStorage, concurrentdispose()+getInstance()race, duplicate paths in bulk ops, bulk partial failure,ConcurrencyPooledge cases, stream cancellation, and exception hierarchy completeness.
2.0.1 #
- Updated README to reflect all 2.0.0 changes:
Uint8ListAPI in examples,dispose()lifecycle section,writeFileStreamoverwrite parameter, directory locking in thread safety docs, path normalization, and updated API reference table.
2.0.0 #
Breaking changes #
Uint8ListAPI: All byte parameters and return types changed fromList<int>toUint8Listfor proper binary semantics and memory efficiency.- Bulk operations removed from native interface:
writeFiles,readFiles, andwriteFilesStreamare now handled exclusively by the platform layer, eliminating duplication and ensuring all bulk calls route throughPathLock. - Removed
ffiPlugindeclarations: No native FFI code exists; the misleadingffiPlugin: trueentries have been removed frompubspec.yaml.
New features #
writeFileStreamoverwrite protection: Addedoverwriteparameter (defaulttrue) to matchwriteFilebehavior.dispose()method: Releases all resources (terminates web workers, resets singleton). Allows re-initialization viagetInstance(). Callers holding old references getStateError.- Use-after-dispose guard: All platform methods throw
StateErrorif called afterdispose(). - Directory locking: Directory operations now acquire
PathLock, consistent with file operations.renameDirectorylocks both paths in sorted order. - Path normalization:
listDirectoryandgetAppFilePathreturn forward-slash paths on all platforms.
Fixes #
- Web binary transfer: Worker returns data via reliable
Array.from()conversion for correctdartify()interop. Bytes sent to the worker are sanitized to plainList<int>for safejsify()conversion. moveFilepartial cleanup: Failed cross-device moves (native) and copy+delete moves (web) now clean up partial destination files. Source delete failure also rolls back the destination.createDirectoryrecursive parameter on web: Non-recursive mode now correctly fails if parent directory does not exist.renameDirectoryon web: Cleans up partial destination on failure instead of leaving orphaned directories.readFileStreamcancellation:onCancelnow always returns a validFuture(viaCompleter) ensuring the path lock is properly released on cancel. Web implementation no longerawaitscontroller.close()infinally.- Dispose race condition: Singleton
_instanceis nulled before awaiting async teardown, preventing concurrentgetInstance()from returning a being-disposed instance.
Internal improvements #
- Removed
DbasFileSystemPlatformsingleton: Platform is now constructed directly byDbasFileSystem.getInstance(), eliminating duplicate singleton boilerplate. - Consolidated stub files: Two identical 77-line stubs replaced with a shared
DbasFileSystemNativeStubbase class. - JS Worker DRY cleanup: Extracted
getFileObject(),assertNotExists(), andwriteFileChunked()helpers.renameFiledelegates tomoveFileinstead of duplicating logic.
1.1.0 #
- File metadata:
getFileSizeandgetLastModified. writeFileoverwriteparameter to prevent accidental overwrites.- Parallel bulk operations with configurable
maxConcurrency(default 10). - Rename support for files and directories (atomic on native, copy+delete on web).
- Per-file thread safety via
PathLock— same-file operations serialized, different files parallel. - Multi-path operations (
copyFile,moveFile,renameFile) lock both paths in sorted order to prevent deadlocks. - Bulk operations route through locked single-file methods with bounded concurrency via
ConcurrencyPool. - Typed exception hierarchy:
FileNotFoundException,FileAlreadyExistsException,DirectoryNotFoundException,DirectoryNotEmptyException. - Web Worker pool (default 4 workers) with least-pending dispatch for true parallel I/O.
- Worker pool crash recovery — crashed workers are removed from pool automatically.
readFileStreamerror mapping for consistentFileNotFoundExceptionacross all methods.
1.0.0 #
- Initial stable release.
- File operations: read, write, copy, move, delete, and existence check.
- Stream-based read and write for memory-efficient large file handling.
- Directory operations: create, list, delete, and existence check.
- Cross-device move with automatic copy+delete fallback.
- Web support via OPFS with background Web Worker.
- Configurable chunk size for streamed reads (default 64 KB).
- Platform-aware path resolution via
getAppFilePath. - Thread-safe singleton initialization.