I'm using js-interop to use the File System Access API with Dart in a web environment.
I would like to store a FileSystemDirectoryHandle in IndexedDB to reuse it later.
When storing an instance of FileSystemDirectoryHandle in IndexedDB, the data is a Dart object (Symbol when exploring the value in DevTools). When I read back, value is not a FileSystemDirectoryHandle and all informations of the object is lost and useless.
I did not find a way to store a handle into IndexedDB and read it back as a FileSystemDirectoryHandle.
Below is parts of the code I declare with js-interop:
// Only to keep track of API's types definitions.
typedef Promise<T> = dynamic;
// FileSystemHandle and *Options are declared in the same way.
@JS()
class FileSystemDirectoryHandle extends FileSystemHandle {
external Promise<FileSystemFileHandle> getFileHandle(String name, [FileSystemGetFileOptions? options]);
external Promise<FileSystemDirectoryHandle> getDirectoryHandle(String name, [FileSystemGetDirectoryOptions? options]);
external Promise<void> removeEntry(String name, [FileSystemRemoveOptions? options]);
external Promise<List<String>?> resolve(FileSystemHandle possibleDescendant);
}
Here is what I'm trying to achieve:
final handle = await js.promiseToFuture(window.showDirectoryPicker());
// Storage use dart:indexed_db in a homebrew implementation (tested and works fine with
// primitive types).
await storage.set("dir", handle);
// Reload page...
// Dynamic only
final directory = await storage.get("dir");
print(directory.name);
// Typed
FileSystemDirectoryHandle dirHandle = directory as FileSystemDirectoryHandle;
print(dirHandle.name);
Calling dynamic directory.name throws a NoSuchMethodError:
Uncaught (in promise) Error: NoSuchMethodError: 'name'
method not found
Receiver: Instance of 'LinkedMap<dynamic, dynamic>'
Calling typed dirHandle.name throws an Error:
Error: Expected a value of type 'FileSystemDirectoryHandle', but got one of type 'LinkedMap<dynamic, dynamic>'
Screenshot of IndexedDB in DevTools, when storing from Dart, and storing from JavaScript
My understanding of js-interop is that it translates JavaScript object into a Dart proxy. As I'm sending a Dart object, it does not serialize the JavaScript object, but the Dart proxy object. Therefore the JavaScript object is lost in the process.
Is there a way to pass the JavaScript object to IndexedDB from Dart? Or at least serialize the native JavaScript object from Dart proxy and then send it into IndexedDB?
Any guidance would be much appreciated.
Issue on dart-lang/sdk repository #50621
More on this repository, usage in example here, and js-interop here.
A workaround is available in issue linked in original post. Problem comes from
dart:indexed_dbpackage.