react-native-nitro-filetoolkit
v0.1.0
Published
Fast, type-safe native filesystem APIs for React Native powered by Nitro Modules
Maintainers
Readme
React Native Nitro File Toolkit
Fast, type-safe native filesystem APIs for React Native, powered by Nitro Modules.
Why use it?
- Swift and Kotlin filesystem operations outside the JS thread
- Validated app-owned paths and absolute
file://URIs - Read-only external sources, including Android
content://URIs - Bounded, staged imports into app-owned storage
- Bounded text reads and staged binary streaming
- Explicit collision, missing-file, write, and atomicity policies
- Paginated listing, metadata, hashing, disk-space, and cleanup APIs
- Native 64-bit byte counts exposed as TypeScript
bigint
This IAUTI Labs package is a clean successor to rn-file-toolkit; it is not
API-compatible with that library.
Requirements
- React Native New Architecture
react-native-nitro-modules >=0.37.1 <0.38.0- iOS or Android
- Expo development build for Expo projects; Expo Go is not supported
Install
npm install react-native-nitro-filetoolkit react-native-nitro-modulesbun add react-native-nitro-filetoolkit react-native-nitro-modulesBare React Native iOS projects must run pod install. Expo projects should
generate and run a development build:
npx expo install react-native-nitro-filetoolkit react-native-nitro-modules
npx expo prebuild
npx expo run:ios
# or: npx expo run:androidQuick start
import { FileToolkit } from 'react-native-nitro-filetoolkit'
const files = FileToolkit.getFileSystem()
const report = files.location('documents', 'reports/annual.txt')
await files.writeText({
destination: report,
text: 'Annual report',
encoding: 'utf-8',
mode: 'replace',
atomicity: 'preferred',
createParentDirectories: true,
})
const contents = await files.readText({
source: report,
encoding: 'utf-8',
maxByteCount: 1_048_576n,
})
const info = await files.stat(report)
const digest = await files.hash({ source: report, algorithm: 'sha-256' })Import a picker result
Treat picker/share URIs as read-only capabilities, not writable filesystem
locations. Android supports content:// and file:// sources; iOS supports
file:// sources:
const source = files.sourceFromUri(pickerUri)
const sourceInfo = await files.inspectSource(source)
if (sourceInfo === undefined) throw new Error('The selected file is unavailable')
const imported = await files.importFile({
source,
destination: files.location('documents', 'imports/report.pdf'),
collision: 'replace',
atomicity: 'preferred',
})
console.log(imported.byteCount)sourceInfo.byteCount may be undefined when a provider does not report a
size. The returned local FileInfo describes the completed import. The toolkit
does not persist or renew Android content:// grants.
Common operations
const archive = files.location('documents', 'archive')
await files.createDirectory({
location: archive,
createParentDirectories: true,
})
const page = await files.list({
directory: archive,
maxEntryCount: 100n,
recursive: false,
})
const copy = files.location('documents', 'archive/report-copy.txt')
await files.copy({
source: report,
destination: copy,
collision: 'replace',
atomicity: 'preferred',
followSymbolicLinks: false,
})
await files.remove({
location: copy,
recursive: false,
missing: 'ignore',
})Streaming
Readers and writers own native resources. Always close them. A writer uses a
staging file and updates its destination only after commit() succeeds.
const reader = await files.openReader(report)
const destination = files.location('cache', 'report-copy.bin')
const writer = await files.openWriter({
destination,
mode: 'replace',
atomicity: 'preferred',
createParentDirectories: true,
})
try {
while (true) {
const chunk = await reader.read(64n * 1024n)
if (chunk.data.byteLength > 0) await writer.write(chunk.data)
if (chunk.isEndOfFile) break
}
await writer.commit()
} catch (error) {
await writer.abort()
throw error
} finally {
reader.close()
writer.close()
}Behavior to know
UInt64values arebigintin TypeScript; use64n, not64.readText()rejects files larger thanmaxByteCountbefore decoding.location()rejects empty paths, absolute paths, backslashes, NUL bytes, empty segments,.segments, and..segments.fromUri()currently accepts absolutefile://URIs only.root()returns a managed root;FileLocation.originismanagedoruri.- Use
sourceFromUri()andimportFile()for picker/share URIs. - Directory-list cursors are opaque. Pass
nextCursorback unchanged. atomicity: 'required'fails if the platform cannot guarantee the requested operation atomically;'preferred'may fall back where supported.
Full documentation and runnable examples: github.com/iauti/react-native-nitro-filetoolkit.
Roadmap
- [x] Filesystem locations, text and binary I/O, metadata, and mutations
- [x] Hashing, disk-space reporting, and managed-directory cleanup
- [x] Android content-source inspection and staged local imports
- [ ] Durable downloads and uploads
- [ ] Safe archive creation and extraction
- [ ] Sharing, external opening, Photos, and MediaStore
- [ ] Transfer and WebView cookie stores
- [ ] React task hooks
Unchecked domains are not placeholder exports; they will enter the public API only after both native implementations and behavior tests are complete.
License
MIT © IAUTI Labs
