diff --git a/apps/native-component-list/src/screens/FileSystemScreen.tsx b/apps/native-component-list/src/screens/FileSystemScreen.tsx
index eff226476bef50..5f082abbecbe36 100644
--- a/apps/native-component-list/src/screens/FileSystemScreen.tsx
+++ b/apps/native-component-list/src/screens/FileSystemScreen.tsx
@@ -8,6 +8,8 @@ import type {
DownloadPauseState,
DownloadTaskState,
UploadTaskState,
+ WatchSubscription,
+ WatchEvent,
} from 'expo-file-system';
import * as IntentLauncher from 'expo-intent-launcher';
import * as MediaLibrary from 'expo-media-library';
@@ -72,6 +74,7 @@ export default function FileSystemScreen() {
+
(null);
+ const [watchTarget, setWatchTarget] = useState(null);
+ const [watchLog, setWatchLog] = useState([]);
+
+ useEffect(() => {
+ return () => {
+ subscriptionRef.current?.remove();
+ subscriptionRef.current = null;
+ };
+ }, []);
+
+ function appendLog(line: string) {
+ const timestamp = new Date().toLocaleTimeString();
+ setWatchLog((prev) => [`[${timestamp}] ${line}`, ...prev].slice(0, 50));
+ }
+
+ function stopWatching() {
+ if (subscriptionRef.current) {
+ subscriptionRef.current.remove();
+ subscriptionRef.current = null;
+ appendLog('Stopped watching');
+ setWatchTarget(null);
+ }
+ }
+
+ function watchFile(file: File) {
+ stopWatching();
+ try {
+ const subscription = file.watch((event: WatchEvent) => {
+ appendLog(`${event.type.toUpperCase()}: ${event.target.name}`);
+ });
+ subscriptionRef.current = subscription;
+ setWatchTarget(`File: ${file.name}`);
+ appendLog(`Started watching file: ${file.name}`);
+ } catch (e: any) {
+ Alert.alert('Error', e.message);
+ }
+ }
+
+ function watchDirectory(dir: Directory) {
+ stopWatching();
+ try {
+ const subscription = dir.watch((event: WatchEvent) => {
+ const targetType = event.target instanceof Directory ? 'dir' : 'file';
+ appendLog(`${event.type.toUpperCase()} (${targetType}): ${event.target.name}`);
+ });
+ subscriptionRef.current = subscription;
+ setWatchTarget(`Directory: ${dir.name}`);
+ appendLog(`Started watching directory: ${dir.name}`);
+ } catch (e: any) {
+ Alert.alert('Error', e.message);
+ }
+ }
+
+ return (
+ <>
+ File System Watcher
+ Watch files or directories for changes
+
+ watchFile(currentFile!)}
+ />
+ {
+ const cacheDir = new Directory(Paths.cache, 'test_sandbox');
+ cacheDir.create({ intermediates: true, idempotent: true });
+ watchDirectory(cacheDir);
+ }}
+ />
+ watchDirectory(Paths.document)} />
+
+
+ {watchTarget && (
+
+ Watching: {watchTarget}
+
+ )}
+
+ {watchLog.length > 0 && (
+ <>
+
+ Event Log
+ setWatchLog([])}>
+ Clear
+
+
+
+ {watchLog.map((line, index) => (
+
+ {line}
+
+ ))}
+
+ >
+ )}
+ >
+ );
+}
+
// ===== Section: Copy & Move =====
function CopyMoveSection({
@@ -1273,4 +1383,44 @@ const styles = StyleSheet.create({
color: '#888',
marginBottom: 4,
},
+ watchStatusBar: {
+ backgroundColor: '#e8f5e9',
+ padding: 8,
+ borderRadius: 4,
+ marginTop: 8,
+ },
+ watchStatusText: {
+ fontSize: 12,
+ color: '#2e7d32',
+ fontWeight: '500',
+ },
+ watchLogHeader: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ marginTop: 8,
+ paddingHorizontal: 4,
+ },
+ watchLogTitle: {
+ fontSize: 13,
+ fontWeight: '600',
+ color: '#333',
+ },
+ clearLogButton: {
+ fontSize: 12,
+ color: '#4630eb',
+ },
+ watchLogContainer: {
+ maxHeight: 150,
+ backgroundColor: '#f5f5f5',
+ borderRadius: 4,
+ padding: 8,
+ marginTop: 4,
+ },
+ watchLogLine: {
+ fontSize: 11,
+ fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace',
+ color: '#333',
+ paddingVertical: 2,
+ },
});
diff --git a/apps/test-suite/tests/FileSystem.ts b/apps/test-suite/tests/FileSystem.ts
index bde6d1e2bbfc76..9c3eb73dc2c166 100644
--- a/apps/test-suite/tests/FileSystem.ts
+++ b/apps/test-suite/tests/FileSystem.ts
@@ -9,19 +9,28 @@ import { Platform } from 'react-native';
export const name = 'FileSystem';
const shouldSkipTestsRequiringPermissions = true;
+function delay(ms: number): Promise {
+ return new Promise((resolve) => setTimeout(resolve, ms));
+}
+
export async function test({ describe, expect, it, ...t }) {
const describeWithPermissions = shouldSkipTestsRequiringPermissions ? t.xdescribe : describe;
const testDirectory = FS.documentDirectory + 'tests/';
+ const watcherDirectory = new Directory(Paths.cache, 'watcher-tests');
t.beforeEach(async () => {
try {
await FS.makeDirectoryAsync(testDirectory);
} catch {}
+ watcherDirectory.create({ idempotent: true, intermediates: true });
});
t.afterEach(async () => {
try {
await FS.deleteAsync(testDirectory);
} catch {}
+ if (watcherDirectory.exists) {
+ watcherDirectory.delete();
+ }
});
describe('FileSystem', () => {
if (Constants.appOwnership === 'expo') {
@@ -215,6 +224,111 @@ export async function test({ describe, expect, it, ...t }) {
}
});
+ describe('watching files and directories', () => {
+ let originalTimeout;
+
+ t.beforeAll(() => {
+ originalTimeout = t.jasmine.DEFAULT_TIMEOUT_INTERVAL;
+ t.jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout * 4;
+ });
+
+ t.afterAll(() => {
+ t.jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
+ });
+
+ it('returns an idempotent subscription', () => {
+ const file = new File(watcherDirectory, 'subscription.txt');
+ file.create();
+
+ const subscription = file.watch(() => {});
+ subscription.remove();
+
+ expect(() => subscription.remove()).not.toThrow();
+ });
+
+ it('emits a modified event when a watched file is written', async () => {
+ const file = new File(watcherDirectory, 'modified.txt');
+ file.create();
+ file.write('before');
+
+ const events: { type: string }[] = [];
+ const subscription = file.watch((event) => events.push(event));
+
+ try {
+ file.write('after');
+ await delay(300);
+
+ expect(events.some((event) => event.type === 'modified')).toBe(true);
+ } finally {
+ subscription.remove();
+ }
+ });
+
+ it('emits a deleted event when a watched file is deleted', async () => {
+ const file = new File(watcherDirectory, 'deleted.txt');
+ file.create();
+
+ const events: { type: string }[] = [];
+ const subscription = file.watch((event) => events.push(event));
+
+ try {
+ file.delete();
+ await delay(300);
+
+ expect(events.some((event) => event.type === 'deleted')).toBe(true);
+ } finally {
+ subscription.remove();
+ }
+ });
+
+ it('filters events by requested types', async () => {
+ const file = new File(watcherDirectory, 'filter.txt');
+ file.create();
+ file.write('before');
+
+ const events: { type: string }[] = [];
+ const subscription = file.watch((event) => events.push(event), {
+ events: ['deleted'],
+ });
+
+ try {
+ file.write('after');
+ await delay(300);
+
+ expect(events.length).toBe(0);
+ } finally {
+ subscription.remove();
+ }
+ });
+
+ it('emits an event when a child file is created in a watched directory', async () => {
+ const directory = new Directory(watcherDirectory, 'children');
+ directory.create();
+
+ const events: { type: string; target: File | Directory }[] = [];
+ const subscription = directory.watch((event) => events.push(event));
+
+ try {
+ const childFile = new File(directory, 'child.txt');
+ childFile.create();
+ await delay(300);
+
+ expect(events.length).toBeGreaterThan(0);
+
+ if (Platform.OS === 'ios') {
+ expect(events[0]?.type).toBe('modified');
+ expect(events[0]?.target instanceof Directory).toBe(true);
+ expect(events[0]?.target.uri).toBe(directory.uri);
+ } else {
+ expect(events.some((event) => event.type === 'created')).toBe(true);
+ expect(events.some((event) => event.target instanceof File)).toBe(true);
+ }
+ } finally {
+ subscription.remove();
+ }
+ });
+ });
+
if (Platform.OS === 'android') {
describe('Android bundle directory listing', () => {
it('returns correct names for files in bundle directory', () => {
diff --git a/packages/expo-file-system/CHANGELOG.md b/packages/expo-file-system/CHANGELOG.md
index 3342943cd4abb0..8fd4aa8f0adfec 100644
--- a/packages/expo-file-system/CHANGELOG.md
+++ b/packages/expo-file-system/CHANGELOG.md
@@ -17,6 +17,7 @@
- Add `onProgress` callback and `AbortSignal` support to `File.downloadFileAsync()`. ([#43053](https://github.com/expo/expo/pull/43053) by [@aleqsio](https://github.com/aleqsio))
- Add `file.createUploadTask()` and `File.createDownloadTask()` APIs ([#44055](https://github.com/expo/expo/pull/44055) by [@barthap](https://github.com/barthap))
- Add `File.upload()` with legacy-compatible upload semantics, progress callbacks, and `AbortSignal` support. ([#45033](https://github.com/expo/expo/pull/45033) by [@barthap](https://github.com/barthap))
+- Add support for watching file/directory events. ([#44986](https://github.com/expo/expo/pull/44986) by [@barthap](https://github.com/barthap))
### 🐛 Bug fixes
diff --git a/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemExceptions.kt b/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemExceptions.kt
index 7d28fc958fa08e..554b6adbe57698 100644
--- a/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemExceptions.kt
+++ b/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemExceptions.kt
@@ -58,3 +58,15 @@ internal class InvalidResumeDataException :
internal class DownloadCancelledException :
CodedException("Download was cancelled")
+
+internal class WatcherSetupException(path: String) :
+ CodedException("Cannot start watching path '$path'")
+
+internal class WatcherPermissionException(path: String) :
+ CodedException("No permission to watch path '$path'")
+
+internal class WatcherPathNotFoundException(path: String) :
+ CodedException("Path does not exist: '$path'")
+
+internal class WatcherUnsupportedPathException(path: String) :
+ CodedException("Cannot watch path '$path'. Only local file:// paths are supported.")
diff --git a/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemModule.kt b/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemModule.kt
index d004a9c52dd9ba..9e0ad9b0fd3e77 100644
--- a/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemModule.kt
+++ b/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemModule.kt
@@ -386,5 +386,21 @@ class FileSystemModule : Module() {
task.cancel()
}
}
+
+ Class(FileSystemWatcher::class) {
+ Events("change")
+
+ Constructor { uri: Uri, options: WatchOptions? ->
+ FileSystemWatcher(appContext, uri, options)
+ }
+
+ Function("start") { watcher: FileSystemWatcher ->
+ watcher.start()
+ }
+
+ Function("stop") { watcher: FileSystemWatcher ->
+ watcher.stop()
+ }
+ }
}
}
diff --git a/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemWatcher.kt b/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemWatcher.kt
new file mode 100644
index 00000000000000..04385d06ea27df
--- /dev/null
+++ b/packages/expo-file-system/android/src/main/java/expo/modules/filesystem/FileSystemWatcher.kt
@@ -0,0 +1,354 @@
+package expo.modules.filesystem
+
+import android.net.Uri
+import android.os.FileObserver
+import androidx.core.net.toUri
+import expo.modules.kotlin.AppContext
+import expo.modules.kotlin.records.Field
+import expo.modules.kotlin.records.Record
+import expo.modules.kotlin.types.Enumerable
+import expo.modules.kotlin.sharedobjects.SharedObject
+import expo.modules.kotlin.types.OptimizedRecord
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import java.io.File
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.milliseconds
+
+private val DEFAULT_DEBOUNCE = 100.milliseconds
+
+// Android's FileObserver does not expose the inotify IN_ISDIR bit.
+private const val IN_ISDIR = 0x40000000
+private const val WATCH_MASK = FileObserver.CREATE or
+ FileObserver.MODIFY or
+ FileObserver.DELETE or
+ FileObserver.DELETE_SELF or
+ FileObserver.MOVED_FROM or
+ FileObserver.MOVED_TO or
+ FileObserver.MOVE_SELF
+
+internal enum class WatchEventType(val value: String) : Enumerable {
+ CREATED("created"),
+ MODIFIED("modified"),
+ DELETED("deleted"),
+ RENAMED("renamed")
+}
+
+@OptimizedRecord
+internal data class WatchOptions(
+ @Field val debounce: Long = DEFAULT_DEBOUNCE.inWholeMilliseconds,
+ @Field val events: List? = null
+) : Record
+
+@OptimizedRecord
+internal data class WatchEventPayload(
+ @Field val type: WatchEventType,
+ @Field val path: String,
+ @Field val isDirectory: Boolean,
+ @Field val nativeEventFlags: Int,
+ @Field val newPath: String? = null,
+ @Field val newPathIsDirectory: Boolean? = null
+) : Record
+
+internal class FileSystemWatcher(
+ appContext: AppContext,
+ uri: Uri,
+ options: WatchOptions?
+) : SharedObject(appContext) {
+ private val backgroundCoroutineScope = appContext.backgroundCoroutineScope
+ private val watchedFile: File
+ private val watchedUri: Uri
+ private val debounceDuration: Duration = options?.debounce?.milliseconds ?: DEFAULT_DEBOUNCE
+ private val isWatchingDirectory: Boolean
+
+ private val lock = Any()
+ private var observer: FileObserver? = null
+ private var debounceJob: Job? = null
+ private val pendingEvents = linkedMapOf>()
+ private val pendingMoveFrom = mutableListOf()
+
+ init {
+ if (uri.scheme != "file") {
+ throw WatcherUnsupportedPathException(uri.toString())
+ }
+
+ val path = uri.path ?: throw WatcherSetupException(uri.toString())
+ watchedFile = File(path)
+ if (!watchedFile.exists()) {
+ throw WatcherPathNotFoundException(path)
+ }
+ if (!watchedFile.canRead()) {
+ throw WatcherPermissionException(path)
+ }
+
+ watchedUri = watchedFile.toUri()
+ isWatchingDirectory = watchedFile.isDirectory
+ }
+
+ fun start() {
+ if (observer != null) {
+ return
+ }
+
+ observer = object : FileObserver(watchedFile.path, WATCH_MASK) {
+ override fun onEvent(event: Int, path: String?) {
+ handleEvent(RawWatchEvent(WatchEventFlags(event), path))
+ }
+ }.also {
+ it.startWatching()
+ }
+ }
+
+ fun stop() {
+ observer?.stopWatching()
+ observer = null
+
+ synchronized(lock) {
+ debounceJob?.cancel()
+ debounceJob = null
+ pendingEvents.clear()
+ pendingMoveFrom.clear()
+ }
+ }
+
+ private fun handleEvent(event: RawWatchEvent) {
+ if (event.isEmpty) {
+ return
+ }
+
+ if (event.isSelfEvent) {
+ emitEvent(
+ type = event.selfEventType,
+ path = watchedUri.toString(),
+ isDirectory = isWatchingDirectory,
+ flags = event.flags
+ )
+ stop()
+ return
+ }
+
+ val isDirectory = event.resolveIsDirectory(watchedFile, isWatchingDirectory)
+
+ synchronized(lock) {
+ if (event.flags.isMoveFrom && event.changedPath != null) {
+ pendingMoveFrom.add(PendingMove(event.changedPath, isDirectory))
+ }
+
+ pendingEvents.getOrPut(event.changedPath) { mutableListOf() }.add(PendingEvent(event, isDirectory))
+
+ debounceJob?.cancel()
+ debounceJob = backgroundCoroutineScope.launch {
+ delay(debounceDuration.inWholeMilliseconds)
+ flushPendingEvents()
+ }
+ }
+ }
+
+ private fun flushPendingEvents() {
+ val eventsSnapshot: Map>
+ val moveFromEvents: List
+
+ synchronized(lock) {
+ eventsSnapshot = pendingEvents.mapValues { it.value.toList() }
+ moveFromEvents = pendingMoveFrom.toList()
+ pendingEvents.clear()
+ pendingMoveFrom.clear()
+ debounceJob = null
+ }
+
+ val mergedEvents = mergeEvents(eventsSnapshot)
+ val pairedMoves = emitPairedMoveEvents(moveFromEvents, mergedEvents)
+ emitUnpairedEvents(mergedEvents, pairedMoves)
+ }
+
+ private fun mergeEvents(eventsSnapshot: Map>): List {
+ return eventsSnapshot.map { (changedPath, events) ->
+ MergedEvent(
+ changedPath = changedPath,
+ flags = events.fold(WatchEventFlags.NONE) { flags, pendingEvent -> flags or pendingEvent.flags },
+ isDirectory = events.any { it.isDirectory }
+ )
+ }
+ }
+
+ private fun emitPairedMoveEvents(
+ moveFromEvents: List,
+ mergedEvents: List
+ ): PairedMoves {
+ val movedToEvents = mergedEvents
+ .mapNotNull { event ->
+ event.changedPath
+ ?.takeIf { event.flags.isMoveTo }
+ ?.let { PendingMove(it, event.isDirectory) }
+ }
+ val pairedMoves = PairedMoves()
+ val pairedMoveCount = minOf(moveFromEvents.size, movedToEvents.size)
+
+ for (index in 0 until pairedMoveCount) {
+ val moveFrom = moveFromEvents[index]
+ val moveTo = movedToEvents[index]
+ val moveFlags = mergedEvents.flagsFor(moveFrom.path) or mergedEvents.flagsFor(moveTo.path)
+
+ emitEvent(
+ type = WatchEventType.RENAMED,
+ path = childUri(moveFrom.path),
+ isDirectory = moveFrom.isDirectory,
+ flags = moveFlags,
+ newPath = childUri(moveTo.path),
+ newPathIsDirectory = moveTo.isDirectory
+ )
+
+ pairedMoves.sources.add(moveFrom.path)
+ pairedMoves.destinations.add(moveTo.path)
+ }
+
+ return pairedMoves
+ }
+
+ private fun emitUnpairedEvents(mergedEvents: List, pairedMoves: PairedMoves) {
+ for (event in mergedEvents) {
+ if (event.isPairedMove(pairedMoves)) {
+ continue
+ }
+
+ for (eventType in event.flags.toUnifiedTypes()) {
+ emitEvent(
+ type = eventType,
+ path = childUri(event.changedPath),
+ isDirectory = event.isDirectory,
+ flags = event.flags
+ )
+ }
+ }
+ }
+
+ private fun emitEvent(
+ type: WatchEventType,
+ path: String,
+ isDirectory: Boolean,
+ flags: WatchEventFlags,
+ newPath: String? = null,
+ newPathIsDirectory: Boolean? = null
+ ) {
+ emit(
+ "change",
+ WatchEventPayload(
+ type = type,
+ path = path,
+ isDirectory = isDirectory,
+ nativeEventFlags = flags.rawValue,
+ newPath = newPath,
+ newPathIsDirectory = if (newPath != null) newPathIsDirectory ?: isDirectory else null
+ )
+ )
+ }
+
+ private fun childUri(changedPath: String?): String {
+ if (changedPath == null) {
+ return watchedUri.toString()
+ }
+ return File(watchedFile, changedPath).toUri().toString()
+ }
+
+ private data class PendingEvent(val event: RawWatchEvent, val isDirectory: Boolean) {
+ val flags: WatchEventFlags
+ get() = event.flags
+ }
+
+ private data class PendingMove(val path: String, val isDirectory: Boolean)
+
+ private data class MergedEvent(
+ val changedPath: String?,
+ val flags: WatchEventFlags,
+ val isDirectory: Boolean
+ ) {
+ fun isPairedMove(pairedMoves: PairedMoves): Boolean {
+ return changedPath != null &&
+ (pairedMoves.sources.contains(changedPath) || pairedMoves.destinations.contains(changedPath))
+ }
+ }
+
+ private data class PairedMoves(
+ val sources: MutableSet = mutableSetOf(),
+ val destinations: MutableSet = mutableSetOf()
+ )
+
+ private data class RawWatchEvent(val flags: WatchEventFlags, val changedPath: String?) {
+ val isEmpty: Boolean
+ get() = flags.isEmpty
+
+ val isSelfEvent: Boolean
+ get() = flags.isSelfEvent
+
+ val selfEventType: WatchEventType
+ get() = if (flags.isSelfDelete) WatchEventType.DELETED else WatchEventType.RENAMED
+
+ fun resolveIsDirectory(watchedFile: File, defaultValue: Boolean): Boolean {
+ return when {
+ flags.isDirectory -> true
+ changedPath != null -> File(watchedFile, changedPath).isDirectory
+ else -> defaultValue
+ }
+ }
+ }
+
+ @JvmInline
+ private value class WatchEventFlags(val rawValue: Int) {
+ val isEmpty: Boolean
+ get() = rawValue == 0
+
+ val isDirectory: Boolean
+ get() = contains(IN_ISDIR)
+
+ val isMoveFrom: Boolean
+ get() = contains(FileObserver.MOVED_FROM)
+
+ val isMoveTo: Boolean
+ get() = contains(FileObserver.MOVED_TO)
+
+ val isSelfDelete: Boolean
+ get() = contains(FileObserver.DELETE_SELF)
+
+ val isSelfMove: Boolean
+ get() = contains(FileObserver.MOVE_SELF)
+
+ val isSelfEvent: Boolean
+ get() = isSelfDelete || isSelfMove
+
+ operator fun contains(flag: Int): Boolean {
+ return rawValue and flag != 0
+ }
+
+ infix fun or(other: WatchEventFlags): WatchEventFlags {
+ return WatchEventFlags(rawValue or other.rawValue)
+ }
+
+ fun toUnifiedTypes(): List {
+ val types = mutableListOf()
+
+ if (contains(FileObserver.CREATE)) {
+ types.add(WatchEventType.CREATED)
+ }
+ if (contains(FileObserver.MODIFY)) {
+ types.add(WatchEventType.MODIFIED)
+ }
+ if (contains(FileObserver.DELETE)) {
+ types.add(WatchEventType.DELETED)
+ }
+ if (isMoveFrom || isMoveTo) {
+ types.add(WatchEventType.RENAMED)
+ }
+
+ return types.ifEmpty { listOf(WatchEventType.MODIFIED) }
+ }
+
+ companion object {
+ val NONE = WatchEventFlags(0)
+ }
+ }
+
+ private fun List.flagsFor(path: String): WatchEventFlags {
+ return firstOrNull { it.changedPath == path }?.flags ?: WatchEventFlags.NONE
+ }
+}
diff --git a/packages/expo-file-system/build/ExpoFileSystem.d.ts b/packages/expo-file-system/build/ExpoFileSystem.d.ts
index 1127bd3d5f8ac6..c3c8e9f0bd9ef5 100644
--- a/packages/expo-file-system/build/ExpoFileSystem.d.ts
+++ b/packages/expo-file-system/build/ExpoFileSystem.d.ts
@@ -1,5 +1,5 @@
-import { NativeModule, SharedObject } from 'expo-modules-core';
-import type { Directory, File, DownloadOptions, DownloadProgress, PathInfo, PickSingleFileOptions, PickMultipleFilesOptions, UploadProgress, UploadResult } from './ExpoFileSystem.types';
+import { NativeModule, type SharedObject } from 'expo-modules-core';
+import type { Directory, File, DownloadOptions, DownloadProgress, PathInfo, WatchEventType, WatchOptions, PickSingleFileOptions, PickMultipleFilesOptions, UploadProgress, UploadResult } from './ExpoFileSystem.types';
type FileSystemEvents = {
downloadProgress: (data: {
uuid: string;
@@ -22,11 +22,28 @@ declare class FileSystemDownloadTask extends SharedObject {
resume(url: string, to: File | Directory, resumeData: string, options?: Record): Promise;
cancel(): void;
}
+type FileSystemWatcherEvent = {
+ type: WatchEventType;
+ path: string;
+ isDirectory: boolean;
+ nativeEventFlags?: number;
+ newPath?: string;
+ newPathIsDirectory?: boolean;
+};
+type FileSystemWatcherEvents = {
+ change: (event: FileSystemWatcherEvent) => void;
+};
+declare class NativeFileSystemWatcher extends SharedObject {
+ constructor(path: string, options?: WatchOptions);
+ start(): void;
+ stop(): void;
+}
declare class ExpoFileSystemModule extends NativeModule {
FileSystemDirectory: typeof Directory;
FileSystemFile: typeof File;
FileSystemUploadTask: typeof FileSystemUploadTask;
FileSystemDownloadTask: typeof FileSystemDownloadTask;
+ FileSystemWatcher: typeof NativeFileSystemWatcher;
downloadFileAsync(url: string, destination: File | Directory, options?: DownloadOptions, uuid?: string): Promise;
cancelDownloadAsync(uuid: string): void;
pickDirectoryAsync(initialUri?: string): Promise;
diff --git a/packages/expo-file-system/build/ExpoFileSystem.d.ts.map b/packages/expo-file-system/build/ExpoFileSystem.d.ts.map
index d620e5d1489c2f..811f0f98bc11cd 100644
--- a/packages/expo-file-system/build/ExpoFileSystem.d.ts.map
+++ b/packages/expo-file-system/build/ExpoFileSystem.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"ExpoFileSystem.d.ts","sourceRoot":"","sources":["../src/ExpoFileSystem.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAuB,MAAM,mBAAmB,CAAC;AAEpF,OAAO,KAAK,EACV,SAAS,EACT,IAAI,EACJ,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACR,qBAAqB,EACrB,wBAAwB,EACxB,cAAc,EACd,YAAY,EACb,MAAM,wBAAwB,CAAC;AAEhC,KAAK,gBAAgB,GAAG;IACtB,gBAAgB,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,gBAAgB,CAAA;KAAE,KAAK,IAAI,CAAC;CAC5E,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,QAAQ,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;CAC1C,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,QAAQ,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;CAC5C,CAAC;AAEF,OAAO,OAAO,oBAAqB,SAAQ,YAAY,CAAC,gBAAgB,CAAC;IACvE,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC;IACnF,MAAM,IAAI,IAAI;CACf;AAED,OAAO,OAAO,sBAAuB,SAAQ,YAAY,CAAC,kBAAkB,CAAC;IAC3E,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAC/F,KAAK,IAAI,GAAG;IACZ,MAAM,CACJ,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,IAAI,GAAG,SAAS,EACpB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,IAAI,IAAI;CACf;AAED,OAAO,OAAO,oBAAqB,SAAQ,YAAY,CAAC,gBAAgB,CAAC;IACvE,mBAAmB,EAAE,OAAO,SAAS,CAAC;IACtC,cAAc,EAAE,OAAO,IAAI,CAAC;IAC5B,oBAAoB,EAAE,OAAO,oBAAoB,CAAC;IAClD,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,iBAAiB,CACf,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,IAAI,GAAG,SAAS,EAC7B,OAAO,CAAC,EAAE,eAAe,EACzB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC;IAClB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IACvC,kBAAkB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAC3D,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAC5D,aAAa,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IACjE,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChD;;AAED,wBAAuE"}
\ No newline at end of file
+{"version":3,"file":"ExpoFileSystem.d.ts","sourceRoot":"","sources":["../src/ExpoFileSystem.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/packages/expo-file-system/build/ExpoFileSystem.types.d.ts b/packages/expo-file-system/build/ExpoFileSystem.types.d.ts
index f06805d57f739a..609d89a8323466 100644
--- a/packages/expo-file-system/build/ExpoFileSystem.types.d.ts
+++ b/packages/expo-file-system/build/ExpoFileSystem.types.d.ts
@@ -39,6 +39,70 @@ export type FileWriteOptions = {
*/
append?: boolean;
};
+/**
+ * The default debounce time for file system watcher events in milliseconds.
+ */
+export declare const DEFAULT_DEBOUNCE_MS = 100;
+/**
+ * The type of change that triggered a watcher event.
+ * - `created` — a new file or directory was created
+ * - `modified` — the file contents or metadata changed
+ * - `deleted` — the file or directory was removed
+ * - `renamed` — the file or directory was renamed or moved
+ */
+export type WatchEventType = 'created' | 'modified' | 'deleted' | 'renamed';
+/**
+ * Describes a change detected by a file system watcher.
+ */
+export type WatchEvent = {
+ /**
+ * The kind of change that occurred.
+ */
+ type: WatchEventType;
+ /**
+ * The file or directory that changed. For `renamed` events, this is the original path before the rename.
+ */
+ target: T;
+ /**
+ * Raw platform-specific event flags for advanced use cases.
+ * On Android: FileObserver event flags.
+ * On iOS: DispatchSource.FileSystemEvent flags.
+ */
+ nativeEventFlags?: number;
+ /**
+ * For rename events, the new path after rename.
+ * Populated when MOVED_FROM and MOVED_TO events are correlated within the debounce window.
+ * @platform android
+ */
+ newTarget?: T;
+};
+/**
+ * Options for configuring a file system watcher.
+ */
+export type WatchOptions = {
+ /**
+ * The debounce interval in milliseconds for coalescing rapid successive events into a single callback.
+ * @default DEFAULT_DEBOUNCE_MS
+ */
+ debounce?: number;
+ /**
+ * Limits which event types trigger the callback. If omitted, all event types are observed.
+ *
+ * On iOS, directory watchers only provide coarse-grained notifications that the directory itself
+ * changed, so filtering for child-level `created`, `deleted`, or `renamed` events is not reliable.
+ */
+ events?: WatchEventType[];
+};
+/**
+ * A handle to an active file system watcher. Call `remove()` to stop watching and release resources.
+ */
+export type WatchSubscription = {
+ /**
+ * Stops watching for changes and releases native resources.
+ * After calling this method, the callback will no longer be invoked.
+ */
+ remove(): void;
+};
export type DirectoryCreateOptions = {
/**
* Whether to create intermediate directories if they do not exist.
@@ -132,6 +196,17 @@ export declare class Directory {
create(options?: DirectoryCreateOptions): void;
createFile(name: string, mimeType: string | null): File;
createDirectory(name: string): Directory;
+ /**
+ * Watches this directory for changes to its contents.
+ *
+ * On iOS, DispatchSource can only detect that the directory changed,
+ * not which specific child was affected. The `target` will always be
+ * the directory itself, and content changes are reported as `modified`.
+ * Call `directory.list()` to determine what changed.
+ *
+ * On Android, FileObserver provides granular child-level events.
+ */
+ watch(callback: (event: WatchEvent) => void, options?: WatchOptions): WatchSubscription;
/**
* Copies a directory.
*/
@@ -464,6 +539,10 @@ export declare class File {
* @platform android
*/
contentUri: string;
+ /**
+ * Watches for changes affecting this file.
+ */
+ watch(callback: (event: WatchEvent) => void, options?: WatchOptions): WatchSubscription;
}
export declare class FileHandle {
close(): void;
diff --git a/packages/expo-file-system/build/ExpoFileSystem.types.d.ts.map b/packages/expo-file-system/build/ExpoFileSystem.types.d.ts.map
index be2fa0f8e4c2fd..f574e6b39950f7 100644
--- a/packages/expo-file-system/build/ExpoFileSystem.types.d.ts.map
+++ b/packages/expo-file-system/build/ExpoFileSystem.types.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"ExpoFileSystem.types.d.ts","sourceRoot":"","sources":["../src/ExpoFileSystem.types.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"ExpoFileSystem.types.d.ts","sourceRoot":"","sources":["../src/ExpoFileSystem.types.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/packages/expo-file-system/build/FileSystem.d.ts b/packages/expo-file-system/build/FileSystem.d.ts
index 66110b8ee003f8..7d5701cc957951 100644
--- a/packages/expo-file-system/build/FileSystem.d.ts
+++ b/packages/expo-file-system/build/FileSystem.d.ts
@@ -1,5 +1,5 @@
import ExpoFileSystem from './ExpoFileSystem';
-import { type DownloadOptions, type PathInfo, type UploadOptions, type UploadResult, type DownloadTaskOptions, type DownloadPauseState, type UploadTaskState, type DownloadTaskState } from './ExpoFileSystem.types';
+import { type DownloadOptions, type PathInfo, type UploadOptions, type UploadResult, type DownloadTaskOptions, type DownloadPauseState, type UploadTaskState, type DownloadTaskState, type WatchEvent, type WatchOptions, type WatchSubscription } from './ExpoFileSystem.types';
import { PathUtilities } from './pathUtilities';
export declare class Paths extends PathUtilities {
/**
@@ -70,6 +70,28 @@ export declare class File extends ExpoFileSystem.FileSystemFile implements Blob
upload(url: string, options?: UploadOptions): Promise;
createUploadTask(url: string, options?: UploadOptions): UploadTask;
static createDownloadTask(url: string, destination: File | Directory, options?: DownloadTaskOptions): DownloadTask;
+ /**
+ * Watches this file for changes on the filesystem.
+ *
+ * The watcher automatically stops when the file is deleted or renamed. To stop watching manually,
+ * call `remove()` on the returned subscription.
+ *
+ * @param callback Invoked when a change is detected. Receives a `WatchEvent` describing what changed.
+ * @param options Configuration for debouncing and filtering events.
+ * @return A subscription handle. Call `remove()` to stop watching.
+ *
+ * @example
+ * ```ts
+ * const file = new File(Paths.cache, 'data.json');
+ * const subscription = file.watch((event) => {
+ * console.log(`File ${event.type}`);
+ * });
+ *
+ * // Later, stop watching:
+ * subscription.remove();
+ * ```
+ */
+ watch(callback: (event: WatchEvent) => void, options?: WatchOptions): WatchSubscription;
}
/**
* Represents a directory on the filesystem.
@@ -108,6 +130,31 @@ export declare class Directory extends ExpoFileSystem.FileSystemDirectory {
get name(): string;
createFile(name: string, mimeType: string | null): File;
createDirectory(name: string): Directory;
+ /**
+ * Watches this directory for changes to its contents or the directory itself.
+ *
+ * Events are emitted when files or subdirectories are created, modified, deleted, or renamed
+ * within this directory. On iOS, child changes are surfaced as a coarse-grained `modified` event
+ * on the directory itself, so filtering for child-level `created`, `deleted`, or `renamed` events
+ * is not reliable. The watcher automatically stops when the directory is deleted or renamed.
+ * To stop watching manually, call `remove()` on the returned subscription.
+ *
+ * @param callback Invoked when a change is detected. Receives a `WatchEvent` describing what changed.
+ * @param options Configuration for debouncing and filtering events.
+ * @return A subscription handle. Call `remove()` to stop watching.
+ *
+ * @example
+ * ```ts
+ * const cacheDir = new Directory(Paths.cache);
+ * const subscription = cacheDir.watch((event) => {
+ * console.log(`${event.type}: ${event.target.uri}`);
+ * });
+ *
+ * // Later, stop watching:
+ * subscription.remove();
+ * ```
+ */
+ watch(callback: (event: WatchEvent) => void, options?: WatchOptions): WatchSubscription;
}
/**
* Represents an upload task with progress tracking and cancellation support.
diff --git a/packages/expo-file-system/build/FileSystem.d.ts.map b/packages/expo-file-system/build/FileSystem.d.ts.map
index 28da378f94ff1a..2dd2ca6a59068d 100644
--- a/packages/expo-file-system/build/FileSystem.d.ts.map
+++ b/packages/expo-file-system/build/FileSystem.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"FileSystem.d.ts","sourceRoot":"","sources":["../src/FileSystem.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"FileSystem.d.ts","sourceRoot":"","sources":["../src/FileSystem.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/packages/expo-file-system/build/FileSystemWatcher.d.ts b/packages/expo-file-system/build/FileSystemWatcher.d.ts
new file mode 100644
index 00000000000000..69f7629953b69e
--- /dev/null
+++ b/packages/expo-file-system/build/FileSystemWatcher.d.ts
@@ -0,0 +1,19 @@
+import { type WatchEvent, type WatchOptions, type WatchSubscription } from './ExpoFileSystem.types';
+import type { Directory, File } from './FileSystem';
+type TargetFactory = (uri: string, isDirectory: boolean) => T;
+/**
+ * @hidden
+ * Internal implementation of file system watching. Use `File.watch()` or `Directory.watch()` instead.
+ */
+export declare class FileSystemWatcher implements WatchSubscription {
+ private readonly targetFactory;
+ private nativeWatcher;
+ private subscription;
+ private removed;
+ private readonly normalizedWatchedPath;
+ constructor(path: string, callback: (event: WatchEvent) => void, options: WatchOptions | undefined, targetFactory: TargetFactory);
+ private mapEvent;
+ remove(): void;
+}
+export {};
+//# sourceMappingURL=FileSystemWatcher.d.ts.map
\ No newline at end of file
diff --git a/packages/expo-file-system/build/FileSystemWatcher.d.ts.map b/packages/expo-file-system/build/FileSystemWatcher.d.ts.map
new file mode 100644
index 00000000000000..aab552811fa4e7
--- /dev/null
+++ b/packages/expo-file-system/build/FileSystemWatcher.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"FileSystemWatcher.d.ts","sourceRoot":"","sources":["../src/FileSystemWatcher.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,UAAU,EAEf,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEpD,KAAK,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,KAAK,CAAC,CAAC;AAejE;;;GAGG;AACH,qBAAa,iBAAiB,CAAC,CAAC,SAAS,IAAI,GAAG,SAAS,CAAE,YAAW,iBAAiB;IAUnF,OAAO,CAAC,QAAQ,CAAC,aAAa;IAThC,OAAO,CAAC,aAAa,CAA+D;IACpF,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAS;gBAG7C,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,EACxC,OAAO,EAAE,YAAY,YAAK,EACT,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC;IA+BlD,OAAO,CAAC,QAAQ;IAWhB,MAAM,IAAI,IAAI;CAYf"}
\ No newline at end of file
diff --git a/packages/expo-file-system/build/FileSystemWatcher.web.d.ts b/packages/expo-file-system/build/FileSystemWatcher.web.d.ts
new file mode 100644
index 00000000000000..6089710a515f2b
--- /dev/null
+++ b/packages/expo-file-system/build/FileSystemWatcher.web.d.ts
@@ -0,0 +1,9 @@
+import type { WatchEvent, WatchOptions, WatchSubscription } from './ExpoFileSystem.types';
+import type { Directory, File } from './FileSystem';
+type TargetFactory = (uri: string, isDirectory: boolean) => T;
+export declare class FileSystemWatcher implements WatchSubscription {
+ constructor(_path: string, _callback: (event: WatchEvent) => void, _options: WatchOptions | undefined, _targetFactory: TargetFactory);
+ remove(): void;
+}
+export {};
+//# sourceMappingURL=FileSystemWatcher.web.d.ts.map
\ No newline at end of file
diff --git a/packages/expo-file-system/build/FileSystemWatcher.web.d.ts.map b/packages/expo-file-system/build/FileSystemWatcher.web.d.ts.map
new file mode 100644
index 00000000000000..03f2a7175a4c63
--- /dev/null
+++ b/packages/expo-file-system/build/FileSystemWatcher.web.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"FileSystemWatcher.web.d.ts","sourceRoot":"","sources":["../src/FileSystemWatcher.web.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEpD,KAAK,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,KAAK,CAAC,CAAC;AAEjE,qBAAa,iBAAiB,CAAC,CAAC,SAAS,IAAI,GAAG,SAAS,CAAE,YAAW,iBAAiB;gBAEnF,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,EACzC,QAAQ,EAAE,YAAY,YAAK,EAC3B,cAAc,EAAE,aAAa,CAAC,CAAC,CAAC;IAKlC,MAAM,IAAI,IAAI;CAGf"}
\ No newline at end of file
diff --git a/packages/expo-file-system/build/index.d.ts b/packages/expo-file-system/build/index.d.ts
index df1e7e6b40fb7c..561b9127607655 100644
--- a/packages/expo-file-system/build/index.d.ts
+++ b/packages/expo-file-system/build/index.d.ts
@@ -1,4 +1,4 @@
export * from './FileSystem';
-export { type FileCreateOptions, type DirectoryCreateOptions, type FileHandle, type FileInfo, type FileWriteOptions, type InfoOptions, type PathInfo, type DirectoryInfo, type DownloadOptions, type DownloadProgress, FileMode, EncodingType, UploadType, type PickFileOptions, type PickSingleFileOptions, type PickMultipleFilesOptions, type PickFileGeneralOptions, type PickSingleFileSuccessResult, type PickSingleFileResult, type PickMultipleFilesResult, type PickMultipleFilesSuccessResult, type PickFileCanceledResult, type UploadOptions, type UploadProgress, type UploadResult, type DownloadTaskOptions, type NetworkTaskSessionType, type DownloadPauseState, type UploadTaskState, type DownloadTaskState, } from './ExpoFileSystem.types';
+export { DEFAULT_DEBOUNCE_MS, type FileCreateOptions, type DirectoryCreateOptions, type FileHandle, type FileInfo, type FileWriteOptions, type InfoOptions, type PathInfo, type DirectoryInfo, type DownloadOptions, type DownloadProgress, FileMode, EncodingType, UploadType, type PickFileOptions, type PickSingleFileOptions, type PickMultipleFilesOptions, type PickFileGeneralOptions, type PickSingleFileSuccessResult, type PickSingleFileResult, type PickMultipleFilesResult, type PickMultipleFilesSuccessResult, type PickFileCanceledResult, type UploadOptions, type UploadProgress, type UploadResult, type DownloadTaskOptions, type NetworkTaskSessionType, type DownloadPauseState, type UploadTaskState, type DownloadTaskState, type WatchEventType, type WatchEvent, type WatchOptions, type WatchSubscription, } from './ExpoFileSystem.types';
export * from './legacyWarnings';
//# sourceMappingURL=index.d.ts.map
\ No newline at end of file
diff --git a/packages/expo-file-system/build/index.d.ts.map b/packages/expo-file-system/build/index.d.ts.map
index 6bc56739439b61..999fcd2b109d5b 100644
--- a/packages/expo-file-system/build/index.d.ts.map
+++ b/packages/expo-file-system/build/index.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAE7B,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,2BAA2B,EAChC,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,8BAA8B,EACnC,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,wBAAwB,CAAC;AAEhC,cAAc,kBAAkB,CAAC"}
\ No newline at end of file
+{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAE7B,OAAO,EACL,mBAAmB,EACnB,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,2BAA2B,EAChC,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,8BAA8B,EACnC,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,iBAAiB,GACvB,MAAM,wBAAwB,CAAC;AAEhC,cAAc,kBAAkB,CAAC"}
\ No newline at end of file
diff --git a/packages/expo-file-system/ios/FileSystemExceptions.swift b/packages/expo-file-system/ios/FileSystemExceptions.swift
index b2eaaf4c44030f..b4db9d398e12a8 100644
--- a/packages/expo-file-system/ios/FileSystemExceptions.swift
+++ b/packages/expo-file-system/ios/FileSystemExceptions.swift
@@ -156,3 +156,27 @@ internal final class UploadFailedToAccessCacheException: Exception {
"Failed to access cache directory for upload temp file"
}
}
+
+internal final class WatcherSetupException: GenericException {
+ override var reason: String {
+ "Cannot start watching path '\(param)'"
+ }
+}
+
+internal final class WatcherPermissionException: GenericException {
+ override var reason: String {
+ "No permission to watch path '\(param)'"
+ }
+}
+
+internal final class WatcherPathNotFoundException: GenericException {
+ override var reason: String {
+ "Path does not exist: '\(param)'"
+ }
+}
+
+internal final class WatcherUnsupportedPathException: GenericException {
+ override var reason: String {
+ "Cannot watch path '\(param)'. Only local file:// paths are supported."
+ }
+}
diff --git a/packages/expo-file-system/ios/FileSystemModule.swift b/packages/expo-file-system/ios/FileSystemModule.swift
index 6f65cd6b57bd44..7af943c7823e2d 100644
--- a/packages/expo-file-system/ios/FileSystemModule.swift
+++ b/packages/expo-file-system/ios/FileSystemModule.swift
@@ -386,6 +386,20 @@ public final class FileSystemModule: Module {
task.cancel()
}
}
+
+ Class(FileSystemWatcher.self) {
+ Constructor { (path: URL, options: WatchOptions?) in
+ try FileSystemWatcher(path: path, options: options)
+ }
+
+ Function("start") { watcher in
+ watcher.start()
+ }
+
+ Function("stop") { watcher in
+ watcher.stop()
+ }
+ }
}
private func getAppleSharedContainers() -> [String: String] {
diff --git a/packages/expo-file-system/ios/FileSystemWatcher.swift b/packages/expo-file-system/ios/FileSystemWatcher.swift
new file mode 100644
index 00000000000000..13a97c4cf45b57
--- /dev/null
+++ b/packages/expo-file-system/ios/FileSystemWatcher.swift
@@ -0,0 +1,178 @@
+// Copyright 2024-present 650 Industries. All rights reserved.
+
+import Darwin
+import ExpoModulesCore
+import Foundation
+
+internal struct WatchOptions: Record {
+ @Field var debounce: Int = 100
+ @Field var events: [String]?
+}
+
+internal struct WatchEventPayload: Record {
+ @Field var type: String = "modified"
+ @Field var path: String = ""
+ @Field var isDirectory: Bool = false
+ @Field var nativeEventFlags: Int = 0
+ @Field var newPath: String?
+ @Field var newPathIsDirectory: Bool?
+}
+
+internal final class FileSystemWatcher: SharedObject {
+ private static let eventQueueKey = DispatchSpecificKey()
+
+ private let path: URL
+ private let fileDescriptor: Int32
+ private let debounceInterval: TimeInterval
+ private let isWatchingDirectory: Bool
+ private let eventQueue = DispatchQueue(label: "expo.filesystem.watcher")
+
+ private var source: DispatchSourceFileSystemObject?
+ private var debounceWorkItem: DispatchWorkItem?
+ private var pendingEvents: DispatchSource.FileSystemEvent = []
+ private var fileDescriptorClosed = false
+
+ init(path: URL, options: WatchOptions?) throws {
+ let standardizedPath = path.standardizedFileURL
+
+ guard standardizedPath.isFileURL else {
+ throw WatcherUnsupportedPathException(path.absoluteString)
+ }
+
+ var isDirectory: ObjCBool = false
+ guard FileManager.default.fileExists(atPath: standardizedPath.path, isDirectory: &isDirectory) else {
+ throw WatcherPathNotFoundException(standardizedPath.path)
+ }
+
+ guard FileManager.default.isReadableFile(atPath: standardizedPath.path) else {
+ throw WatcherPermissionException(standardizedPath.path)
+ }
+
+ let descriptor = open(standardizedPath.path, O_EVTONLY)
+ guard descriptor >= 0 else {
+ throw WatcherSetupException(standardizedPath.path)
+ }
+
+ self.path = standardizedPath
+ self.fileDescriptor = descriptor
+ self.debounceInterval = TimeInterval(options?.debounce ?? 100) / 1000
+ self.isWatchingDirectory = isDirectory.boolValue
+ eventQueue.setSpecific(key: Self.eventQueueKey, value: ())
+ }
+
+ deinit {
+ closeFileDescriptor()
+ }
+
+ func start() {
+ withEventQueue {
+ guard source == nil else {
+ return
+ }
+
+ let source = DispatchSource.makeFileSystemObjectSource(
+ fileDescriptor: fileDescriptor,
+ eventMask: [.write, .delete, .rename, .extend],
+ queue: eventQueue
+ )
+
+ source.setEventHandler { [weak self, weak source] in
+ self?.handleEvent(flags: source?.data ?? [])
+ }
+ source.setCancelHandler { [weak self] in
+ self?.closeFileDescriptor()
+ }
+ self.source = source
+ source.activate()
+ }
+ }
+
+ func stop() {
+ withEventQueue {
+ stopLocked()
+ }
+ }
+
+ private func withEventQueue(_ block: () -> Void) {
+ if DispatchQueue.getSpecific(key: Self.eventQueueKey) != nil {
+ block()
+ } else {
+ eventQueue.sync(execute: block)
+ }
+ }
+
+ private func stopLocked() {
+ debounceWorkItem?.cancel()
+ debounceWorkItem = nil
+ pendingEvents = []
+ let source = self.source
+ self.source = nil
+ source?.cancel()
+ }
+
+ private func handleEvent(flags: DispatchSource.FileSystemEvent) {
+ if flags.contains(.delete) || flags.contains(.rename) {
+ emitEvent(flags: flags)
+ stopLocked()
+ return
+ }
+
+ pendingEvents.formUnion(flags)
+ debounceWorkItem?.cancel()
+
+ let workItem = DispatchWorkItem { [weak self] in
+ self?.flushPendingEvents()
+ }
+
+ debounceWorkItem = workItem
+ eventQueue.asyncAfter(deadline: .now() + debounceInterval, execute: workItem)
+ }
+
+ private func flushPendingEvents() {
+ guard !pendingEvents.isEmpty else {
+ return
+ }
+
+ let flags = pendingEvents
+ pendingEvents = []
+ emitEvent(flags: flags)
+ }
+
+ private func emitEvent(flags: DispatchSource.FileSystemEvent) {
+ for eventType in mapToUnifiedTypes(flags) {
+ emit(
+ event: "change",
+ arguments: WatchEventPayload(
+ type: eventType,
+ path: path.absoluteString,
+ isDirectory: isWatchingDirectory,
+ nativeEventFlags: Int(flags.rawValue)
+ )
+ )
+ }
+ }
+
+ private func mapToUnifiedTypes(_ flags: DispatchSource.FileSystemEvent) -> [String] {
+ var types: [String] = []
+
+ if flags.contains(.write) || flags.contains(.extend) {
+ types.append("modified")
+ }
+ if flags.contains(.delete) {
+ types.append("deleted")
+ }
+ if flags.contains(.rename) {
+ types.append("renamed")
+ }
+
+ return types.isEmpty ? ["modified"] : types
+ }
+
+ private func closeFileDescriptor() {
+ guard !fileDescriptorClosed else {
+ return
+ }
+ fileDescriptorClosed = true
+ close(fileDescriptor)
+ }
+}
diff --git a/packages/expo-file-system/mocks/FileSystem.ts b/packages/expo-file-system/mocks/FileSystem.ts
index ed1a50123cc0ad..9bdda19c7c35e3 100644
--- a/packages/expo-file-system/mocks/FileSystem.ts
+++ b/packages/expo-file-system/mocks/FileSystem.ts
@@ -53,6 +53,9 @@ export class FileSystemFile {
async text(): Promise {}
async base64(): Promise {}
async bytes(): Promise {}
+ watch(_callback: any, _options?: any): { remove: () => void } {
+ return { remove: () => {} };
+ }
}
export class FileSystemFileHandle {
@@ -79,6 +82,18 @@ export class FileSystemDirectory {
listAsRecords(): any {}
createFile(name: string, mimeType: string | null): any {}
createDirectory(name: string): any {}
+ watch(_callback: any, _options?: any): { remove: () => void } {
+ return { remove: () => {} };
+ }
+}
+
+export class FileSystemWatcher {
+ constructor(_path: string, _options?: { debounce?: number; events?: string[] }) {}
+ addListener(_event: string, _callback: (data: any) => void): { remove: () => void } {
+ return { remove: () => {} };
+ }
+ start(): void {}
+ stop(): void {}
}
// SharedObject-based task classes.
diff --git a/packages/expo-file-system/src/ExpoFileSystem.ts b/packages/expo-file-system/src/ExpoFileSystem.ts
index b276660049af21..a04110352ac219 100644
--- a/packages/expo-file-system/src/ExpoFileSystem.ts
+++ b/packages/expo-file-system/src/ExpoFileSystem.ts
@@ -1,4 +1,4 @@
-import { NativeModule, SharedObject, requireNativeModule } from 'expo-modules-core';
+import { NativeModule, requireNativeModule, type SharedObject } from 'expo-modules-core';
import type {
Directory,
@@ -6,6 +6,8 @@ import type {
DownloadOptions,
DownloadProgress,
PathInfo,
+ WatchEventType,
+ WatchOptions,
PickSingleFileOptions,
PickMultipleFilesOptions,
UploadProgress,
@@ -41,11 +43,31 @@ declare class FileSystemDownloadTask extends SharedObject {
cancel(): void;
}
+type FileSystemWatcherEvent = {
+ type: WatchEventType;
+ path: string;
+ isDirectory: boolean;
+ nativeEventFlags?: number;
+ newPath?: string;
+ newPathIsDirectory?: boolean;
+};
+
+type FileSystemWatcherEvents = {
+ change: (event: FileSystemWatcherEvent) => void;
+};
+
+declare class NativeFileSystemWatcher extends SharedObject {
+ constructor(path: string, options?: WatchOptions);
+ start(): void;
+ stop(): void;
+}
+
declare class ExpoFileSystemModule extends NativeModule {
FileSystemDirectory: typeof Directory;
FileSystemFile: typeof File;
FileSystemUploadTask: typeof FileSystemUploadTask;
FileSystemDownloadTask: typeof FileSystemDownloadTask;
+ FileSystemWatcher: typeof NativeFileSystemWatcher;
downloadFileAsync(
url: string,
destination: File | Directory,
diff --git a/packages/expo-file-system/src/ExpoFileSystem.types.ts b/packages/expo-file-system/src/ExpoFileSystem.types.ts
index e5508eb9e7d923..b377c918a515e3 100644
--- a/packages/expo-file-system/src/ExpoFileSystem.types.ts
+++ b/packages/expo-file-system/src/ExpoFileSystem.types.ts
@@ -43,6 +43,75 @@ export type FileWriteOptions = {
append?: boolean;
};
+/**
+ * The default debounce time for file system watcher events in milliseconds.
+ */
+export const DEFAULT_DEBOUNCE_MS = 100;
+
+/**
+ * The type of change that triggered a watcher event.
+ * - `created` — a new file or directory was created
+ * - `modified` — the file contents or metadata changed
+ * - `deleted` — the file or directory was removed
+ * - `renamed` — the file or directory was renamed or moved
+ */
+export type WatchEventType = 'created' | 'modified' | 'deleted' | 'renamed';
+
+/**
+ * Describes a change detected by a file system watcher.
+ */
+export type WatchEvent = {
+ /**
+ * The kind of change that occurred.
+ */
+ type: WatchEventType;
+ /**
+ * The file or directory that changed. For `renamed` events, this is the original path before the rename.
+ */
+ target: T;
+ /**
+ * Raw platform-specific event flags for advanced use cases.
+ * On Android: FileObserver event flags.
+ * On iOS: DispatchSource.FileSystemEvent flags.
+ */
+ nativeEventFlags?: number;
+ /**
+ * For rename events, the new path after rename.
+ * Populated when MOVED_FROM and MOVED_TO events are correlated within the debounce window.
+ * @platform android
+ */
+ newTarget?: T;
+};
+
+/**
+ * Options for configuring a file system watcher.
+ */
+export type WatchOptions = {
+ /**
+ * The debounce interval in milliseconds for coalescing rapid successive events into a single callback.
+ * @default DEFAULT_DEBOUNCE_MS
+ */
+ debounce?: number;
+ /**
+ * Limits which event types trigger the callback. If omitted, all event types are observed.
+ *
+ * On iOS, directory watchers only provide coarse-grained notifications that the directory itself
+ * changed, so filtering for child-level `created`, `deleted`, or `renamed` events is not reliable.
+ */
+ events?: WatchEventType[];
+};
+
+/**
+ * A handle to an active file system watcher. Call `remove()` to stop watching and release resources.
+ */
+export type WatchSubscription = {
+ /**
+ * Stops watching for changes and releases native resources.
+ * After calling this method, the callback will no longer be invoked.
+ */
+ remove(): void;
+};
+
export type DirectoryCreateOptions = {
/**
* Whether to create intermediate directories if they do not exist.
@@ -150,6 +219,21 @@ export declare class Directory {
createDirectory(name: string): Directory;
+ /**
+ * Watches this directory for changes to its contents.
+ *
+ * On iOS, DispatchSource can only detect that the directory changed,
+ * not which specific child was affected. The `target` will always be
+ * the directory itself, and content changes are reported as `modified`.
+ * Call `directory.list()` to determine what changed.
+ *
+ * On Android, FileObserver provides granular child-level events.
+ */
+ watch(
+ callback: (event: WatchEvent) => void,
+ options?: WatchOptions
+ ): WatchSubscription;
+
/**
* Copies a directory.
*/
@@ -530,6 +614,11 @@ export declare class File {
* @platform android
*/
contentUri: string;
+
+ /**
+ * Watches for changes affecting this file.
+ */
+ watch(callback: (event: WatchEvent) => void, options?: WatchOptions): WatchSubscription;
}
export declare class FileHandle {
diff --git a/packages/expo-file-system/src/FileSystem.ts b/packages/expo-file-system/src/FileSystem.ts
index c7212e6478bb5f..2deec813098c23 100644
--- a/packages/expo-file-system/src/FileSystem.ts
+++ b/packages/expo-file-system/src/FileSystem.ts
@@ -15,7 +15,11 @@ import {
type DownloadPauseState,
type UploadTaskState,
type DownloadTaskState,
+ type WatchEvent,
+ type WatchOptions,
+ type WatchSubscription,
} from './ExpoFileSystem.types';
+import { FileSystemWatcher } from './FileSystemWatcher';
import { PathUtilities } from './pathUtilities';
import { FileSystemReadableStreamSource, FileSystemWritableSink } from './streams';
@@ -166,6 +170,31 @@ export class File extends ExpoFileSystem.FileSystemFile implements Blob {
): DownloadTask {
return new DownloadTask(url, destination, options);
}
+
+ /**
+ * Watches this file for changes on the filesystem.
+ *
+ * The watcher automatically stops when the file is deleted or renamed. To stop watching manually,
+ * call `remove()` on the returned subscription.
+ *
+ * @param callback Invoked when a change is detected. Receives a `WatchEvent` describing what changed.
+ * @param options Configuration for debouncing and filtering events.
+ * @return A subscription handle. Call `remove()` to stop watching.
+ *
+ * @example
+ * ```ts
+ * const file = new File(Paths.cache, 'data.json');
+ * const subscription = file.watch((event) => {
+ * console.log(`File ${event.type}`);
+ * });
+ *
+ * // Later, stop watching:
+ * subscription.remove();
+ * ```
+ */
+ watch(callback: (event: WatchEvent) => void, options?: WatchOptions): WatchSubscription {
+ return new FileSystemWatcher(this.uri, callback, options, (uri) => new File(uri));
+ }
}
function createAbortError(reason?: string): Error {
@@ -353,6 +382,42 @@ export class Directory extends ExpoFileSystem.FileSystemDirectory {
createDirectory(name: string): Directory {
return new Directory(super.createDirectory(name).uri);
}
+
+ /**
+ * Watches this directory for changes to its contents or the directory itself.
+ *
+ * Events are emitted when files or subdirectories are created, modified, deleted, or renamed
+ * within this directory. On iOS, child changes are surfaced as a coarse-grained `modified` event
+ * on the directory itself, so filtering for child-level `created`, `deleted`, or `renamed` events
+ * is not reliable. The watcher automatically stops when the directory is deleted or renamed.
+ * To stop watching manually, call `remove()` on the returned subscription.
+ *
+ * @param callback Invoked when a change is detected. Receives a `WatchEvent` describing what changed.
+ * @param options Configuration for debouncing and filtering events.
+ * @return A subscription handle. Call `remove()` to stop watching.
+ *
+ * @example
+ * ```ts
+ * const cacheDir = new Directory(Paths.cache);
+ * const subscription = cacheDir.watch((event) => {
+ * console.log(`${event.type}: ${event.target.uri}`);
+ * });
+ *
+ * // Later, stop watching:
+ * subscription.remove();
+ * ```
+ */
+ watch(
+ callback: (event: WatchEvent) => void,
+ options?: WatchOptions
+ ): WatchSubscription {
+ return new FileSystemWatcher(
+ this.uri,
+ callback,
+ options,
+ (uri, isDirectory) => (isDirectory ? new Directory(uri) : new File(uri))
+ );
+ }
}
Directory.pickDirectoryAsync = async function (initialUri?: string) {
diff --git a/packages/expo-file-system/src/FileSystemWatcher.ts b/packages/expo-file-system/src/FileSystemWatcher.ts
new file mode 100644
index 00000000000000..c49340e99d569c
--- /dev/null
+++ b/packages/expo-file-system/src/FileSystemWatcher.ts
@@ -0,0 +1,96 @@
+import type { EventSubscription } from 'expo-modules-core';
+
+import ExpoFileSystem from './ExpoFileSystem';
+import {
+ DEFAULT_DEBOUNCE_MS,
+ type WatchEvent,
+ type WatchEventType,
+ type WatchOptions,
+ type WatchSubscription,
+} from './ExpoFileSystem.types';
+import type { Directory, File } from './FileSystem';
+
+type TargetFactory = (uri: string, isDirectory: boolean) => T;
+
+interface NativeWatchEvent {
+ type: WatchEventType;
+ path: string;
+ isDirectory: boolean;
+ nativeEventFlags?: number;
+ newPath?: string;
+ newPathIsDirectory?: boolean;
+}
+
+function normalizePath(path: string): string {
+ return path.replace(/\/+$/, '');
+}
+
+/**
+ * @hidden
+ * Internal implementation of file system watching. Use `File.watch()` or `Directory.watch()` instead.
+ */
+export class FileSystemWatcher implements WatchSubscription {
+ private nativeWatcher: InstanceType | null;
+ private subscription: EventSubscription | null = null;
+ private removed = false;
+ private readonly normalizedWatchedPath: string;
+
+ constructor(
+ path: string,
+ callback: (event: WatchEvent) => void,
+ options: WatchOptions = {},
+ private readonly targetFactory: TargetFactory
+ ) {
+ this.normalizedWatchedPath = normalizePath(path);
+ this.nativeWatcher = new ExpoFileSystem.FileSystemWatcher(path, {
+ debounce: options.debounce ?? DEFAULT_DEBOUNCE_MS,
+ events: options.events,
+ });
+
+ this.subscription = this.nativeWatcher.addListener('change', (raw: NativeWatchEvent) => {
+ const event = this.mapEvent(raw);
+ const isWatchedTarget = normalizePath(raw.path) === this.normalizedWatchedPath;
+
+ if (!options.events || options.events.includes(event.type)) {
+ callback(event);
+ }
+
+ if ((event.type === 'deleted' || event.type === 'renamed') && isWatchedTarget) {
+ this.remove();
+ }
+ });
+
+ try {
+ this.nativeWatcher.start();
+ } catch (error) {
+ this.subscription.remove();
+ this.subscription = null;
+ this.nativeWatcher = null;
+ throw error;
+ }
+ }
+
+ private mapEvent(raw: NativeWatchEvent): WatchEvent {
+ return {
+ type: raw.type,
+ target: this.targetFactory(raw.path, raw.isDirectory),
+ newTarget: raw.newPath
+ ? this.targetFactory(raw.newPath, raw.newPathIsDirectory ?? raw.isDirectory)
+ : undefined,
+ nativeEventFlags: raw.nativeEventFlags,
+ };
+ }
+
+ remove(): void {
+ if (this.removed) {
+ return;
+ }
+ this.removed = true;
+
+ this.subscription?.remove();
+ this.subscription = null;
+
+ this.nativeWatcher?.stop();
+ this.nativeWatcher = null;
+ }
+}
diff --git a/packages/expo-file-system/src/FileSystemWatcher.web.ts b/packages/expo-file-system/src/FileSystemWatcher.web.ts
new file mode 100644
index 00000000000000..f2498631f49410
--- /dev/null
+++ b/packages/expo-file-system/src/FileSystemWatcher.web.ts
@@ -0,0 +1,19 @@
+import type { WatchEvent, WatchOptions, WatchSubscription } from './ExpoFileSystem.types';
+import type { Directory, File } from './FileSystem';
+
+type TargetFactory = (uri: string, isDirectory: boolean) => T;
+
+export class FileSystemWatcher implements WatchSubscription {
+ constructor(
+ _path: string,
+ _callback: (event: WatchEvent) => void,
+ _options: WatchOptions = {},
+ _targetFactory: TargetFactory
+ ) {
+ console.warn('FileSystemWatcher is not supported on web');
+ }
+
+ remove(): void {
+ // No-op on web.
+ }
+}
diff --git a/packages/expo-file-system/src/__tests__/FileSystemWatcher-test.ts b/packages/expo-file-system/src/__tests__/FileSystemWatcher-test.ts
new file mode 100644
index 00000000000000..8d603b1f93b4fb
--- /dev/null
+++ b/packages/expo-file-system/src/__tests__/FileSystemWatcher-test.ts
@@ -0,0 +1,257 @@
+import { Platform } from 'expo-modules-core';
+
+import { DEFAULT_DEBOUNCE_MS, Directory, File } from '../..';
+import { FileSystemWatcher } from '../FileSystemWatcher';
+
+jest.mock('../ExpoFileSystem', () => {
+ const mock = require('../../mocks/FileSystem');
+
+ return {
+ __esModule: true,
+ default: {
+ ...mock,
+ },
+ };
+});
+
+const isNativePlatform = Platform.OS === 'android' || Platform.OS === 'ios';
+const describeNative = isNativePlatform ? describe : describe.skip;
+const describeWebLike = isNativePlatform ? describe.skip : describe;
+
+describeNative('FileSystemWatcher', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('constructs the native watcher with the default debounce and starts after listening', () => {
+ const native = require('../ExpoFileSystem').default;
+ const order: string[] = [];
+ const remove = jest.fn();
+ const stop = jest.fn();
+
+ native.FileSystemWatcher = jest.fn().mockImplementation(() => ({
+ addListener: jest.fn(() => {
+ order.push('listen');
+ return { remove };
+ }),
+ start: jest.fn(() => {
+ order.push('start');
+ }),
+ stop,
+ }));
+
+ const subscription = new FileSystemWatcher(
+ 'file:///test.txt',
+ () => {},
+ {},
+ (uri) => ({ uri }) as any
+ );
+
+ expect(native.FileSystemWatcher).toHaveBeenCalledWith('file:///test.txt', {
+ debounce: DEFAULT_DEBOUNCE_MS,
+ events: undefined,
+ });
+ expect(order).toEqual(['listen', 'start']);
+ expect(typeof subscription.remove).toBe('function');
+ });
+
+ it('maps native events and filters requested event types', () => {
+ const native = require('../ExpoFileSystem').default;
+ let listener: ((event: any) => void) | undefined;
+
+ native.FileSystemWatcher = jest.fn().mockImplementation(() => ({
+ addListener: jest.fn((_event: string, callback: (event: any) => void) => {
+ listener = callback;
+ return { remove: jest.fn() };
+ }),
+ start: jest.fn(),
+ stop: jest.fn(),
+ }));
+
+ const callback = jest.fn();
+ const _watcher = new FileSystemWatcher(
+ 'file:///project',
+ callback,
+ { events: ['renamed'] },
+ (uri, isDirectory) => (isDirectory ? new Directory(uri) : new File(uri))
+ );
+
+ listener?.({
+ type: 'modified',
+ path: 'file:///project/a.txt',
+ isDirectory: false,
+ });
+ expect(callback).not.toHaveBeenCalled();
+
+ listener?.({
+ type: 'renamed',
+ path: 'file:///project/a.txt',
+ isDirectory: false,
+ newPath: 'file:///project/b.txt',
+ newPathIsDirectory: false,
+ nativeEventFlags: 42,
+ });
+
+ expect(callback).toHaveBeenCalledTimes(1);
+ const [event] = callback.mock.calls[0];
+ expect(event.type).toBe('renamed');
+ expect(event.target).toBeInstanceOf(File);
+ expect(event.newTarget).toBeInstanceOf(File);
+ expect(event.target.uri).toBe('file:///project/a.txt');
+ expect(event.newTarget.uri).toBe('file:///project/b.txt');
+ expect(event.nativeEventFlags).toBe(42);
+ });
+
+ it('auto-removes when the watched target is deleted or renamed', () => {
+ const native = require('../ExpoFileSystem').default;
+ let listener: ((event: any) => void) | undefined;
+ const remove = jest.fn();
+ const stop = jest.fn();
+
+ native.FileSystemWatcher = jest.fn().mockImplementation(() => ({
+ addListener: jest.fn((_event: string, callback: (event: any) => void) => {
+ listener = callback;
+ return { remove };
+ }),
+ start: jest.fn(),
+ stop,
+ }));
+
+ const subscription = new FileSystemWatcher(
+ 'file:///project/',
+ () => {},
+ {},
+ (uri) => ({ uri }) as any
+ );
+
+ listener?.({
+ type: 'deleted',
+ path: 'file:///project',
+ isDirectory: true,
+ });
+
+ expect(remove).toHaveBeenCalledTimes(1);
+ expect(stop).toHaveBeenCalledTimes(1);
+
+ subscription.remove();
+ expect(remove).toHaveBeenCalledTimes(1);
+ expect(stop).toHaveBeenCalledTimes(1);
+ });
+
+ it('auto-removes even when deleted events are filtered out', () => {
+ const native = require('../ExpoFileSystem').default;
+ let listener: ((event: any) => void) | undefined;
+ const remove = jest.fn();
+ const stop = jest.fn();
+ const callback = jest.fn();
+
+ native.FileSystemWatcher = jest.fn().mockImplementation(() => ({
+ addListener: jest.fn((_event: string, receivedListener: (event: any) => void) => {
+ listener = receivedListener;
+ return { remove };
+ }),
+ start: jest.fn(),
+ stop,
+ }));
+
+ const _watcher = new FileSystemWatcher(
+ 'file:///project/file.txt',
+ callback,
+ { events: ['modified'] },
+ (uri) =>
+ ({
+ uri,
+ }) as any
+ );
+
+ listener?.({
+ type: 'deleted',
+ path: 'file:///project/file.txt',
+ isDirectory: false,
+ });
+
+ expect(callback).not.toHaveBeenCalled();
+ expect(remove).toHaveBeenCalledTimes(1);
+ expect(stop).toHaveBeenCalledTimes(1);
+ });
+});
+
+describeNative('File.watch and Directory.watch', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('File.watch produces File targets', () => {
+ const native = require('../ExpoFileSystem').default;
+ let listener: ((event: any) => void) | undefined;
+
+ native.FileSystemWatcher = jest.fn().mockImplementation(() => ({
+ addListener: jest.fn((_event: string, callback: (event: any) => void) => {
+ listener = callback;
+ return { remove: jest.fn() };
+ }),
+ start: jest.fn(),
+ stop: jest.fn(),
+ }));
+
+ const file = new File('file:///mock/cache/test.txt');
+ const callback = jest.fn();
+
+ file.watch(callback);
+ listener?.({
+ type: 'modified',
+ path: 'file:///mock/cache/test.txt',
+ isDirectory: false,
+ });
+
+ expect(callback).toHaveBeenCalledTimes(1);
+ expect(callback.mock.calls[0][0].target).toBeInstanceOf(File);
+ });
+
+ it('Directory.watch creates Directory targets for directory events', () => {
+ const native = require('../ExpoFileSystem').default;
+ let listener: ((event: any) => void) | undefined;
+
+ native.FileSystemWatcher = jest.fn().mockImplementation(() => ({
+ addListener: jest.fn((_event: string, callback: (event: any) => void) => {
+ listener = callback;
+ return { remove: jest.fn() };
+ }),
+ start: jest.fn(),
+ stop: jest.fn(),
+ }));
+
+ const directory = new Directory('file:///mock/cache/project');
+ const callback = jest.fn();
+
+ directory.watch(callback);
+ listener?.({
+ type: 'modified',
+ path: 'file:///mock/cache/project/',
+ isDirectory: true,
+ });
+
+ expect(callback).toHaveBeenCalledTimes(1);
+ expect(callback.mock.calls[0][0].target).toBeInstanceOf(Directory);
+ });
+});
+
+describeWebLike('FileSystemWatcher web fallback', () => {
+ it('warns and returns a no-op subscription', () => {
+ const warn = jest.spyOn(console, 'warn').mockImplementation(() => {});
+ const { FileSystemWatcher: WebFileSystemWatcher } = require('../FileSystemWatcher.web');
+
+ const subscription = new WebFileSystemWatcher(
+ 'file:///mock/cache/web.txt',
+ () => {},
+ {},
+ (uri: string) => new File(uri)
+ );
+
+ expect(warn).toHaveBeenCalledWith('FileSystemWatcher is not supported on web');
+ expect(typeof subscription.remove).toBe('function');
+ subscription.remove();
+
+ warn.mockRestore();
+ });
+});
diff --git a/packages/expo-file-system/src/index.ts b/packages/expo-file-system/src/index.ts
index 795d36ac0ed7eb..0ed923dd8fb10b 100644
--- a/packages/expo-file-system/src/index.ts
+++ b/packages/expo-file-system/src/index.ts
@@ -1,6 +1,7 @@
export * from './FileSystem';
export {
+ DEFAULT_DEBOUNCE_MS,
type FileCreateOptions,
type DirectoryCreateOptions,
type FileHandle,
@@ -31,6 +32,10 @@ export {
type DownloadPauseState,
type UploadTaskState,
type DownloadTaskState,
+ type WatchEventType,
+ type WatchEvent,
+ type WatchOptions,
+ type WatchSubscription,
} from './ExpoFileSystem.types';
export * from './legacyWarnings';