FileDB is a simple Node.js tool for working with a File-based Database, allowing secure storage and retrieval of JSON data in encrypted files using AES encryption.
npm install @randajan/file-db 
FileDB is a minimalistic file-based adapter for storing and retrieving records using append-only logs. It is not a database. It is a thin and efficient layer for handling records in plain files ā optimized for performance, clarity, and simplicity.
---
FileDB is not a database. It does not manage schemas, indexes, or validation. Instead, it provides:
- Raw access to record-based file logs
- Encryption support via user-defined encrypt/decrypt
- Per-record identification for deduplication and optimization
- Thread-safe writes using @randajan/treelock
You are responsible for data shape and logic. FileDB focuses solely on reliable, structured persistence.
---
``js
import createFileDB from "@randajan/file-db";
import CryptoJS from "crypto-js";
const fdb = createFileDB({
dir: "./data",
extension: "fdb",
encrypt:(json, key) => {
if (!key) return json;
return CryptoJS.AES.encrypt(json, key).toString();
},
decrypt:(raw, key) => {
if (!key) return raw;
const bytes = CryptoJS.AES.decrypt(raw, key);
return bytes.toString(CryptoJS.enc.Utf8);
},
on: ({ name, ram }, state) => {
console.log(${name} changed state to, state, (${ram} in queue));
}
});
const users = fdb.link("users");
await fdb.unlock("secret-key");
await users.write("john", { role: "admin" });
console.log(await users.index());
await fdb.optimize();
`
---
All options are passed to FilesDB on creation.
| Option | Type | Description |
|------------|------------|-------------|
| dir | string | Root directory path |extension
| | string | File extension (without .) |encoding
| | string | File encoding |encrypt(json, key)
| | function | Must return string |decrypt(raw, key)
| | function | Must return JSON string |timeout
| | number | Option will be passed as __ttl__ to @randajan/treelock |
| on(thread, state) | function | Hook from " class="text-primary hover:underline" target="_blank" rel="noopener noreferrer">@randajan/treelock |
š Hooks must not be asynchronous.
---
Options passed to FilesDB are inherited by default in FileDB. However, each file can override them individually when calling .link(name, options).
---
| Property | Type | Description |
|--------------|----------|-------------|
| dir | string | Root path |extension
| | string | File extension |encoding
| | string | File encoding |thread
| | TreeLock | See @randajan/treelock |
---
| Property | Type | Description |
|--------------|----------|-------------|
| name | string | File name |fullname
| | string | Namespaced name (e.g. MyDB.users) |pathname
| | string | Full path to the file |isReadable
| | boolean| Whether file is readable |error
| | Error? | Last read-related error |thread
| | TreeLock | See @randajan/treelock |
---
This section provides a detailed explanation of all public methods of FilesDB and FileDB.
---
#### link(name: string, options?: object, throwError?: boolean): FileDB FileDB
Synchronous
Links a file by name and returns its instance. Throws if already linked (unless throwError is false).
#### unlink(name: string, throwError?: boolean): boolean throwError
Synchronous
Unlinks a file. Throws if not linked (unless is false).
#### get(name: string, throwError?: boolean): FileDB FileDB
Synchronous
Returns the instance for a linked file. Throws if not linked (unless throwError is false).
#### map(fn: (file: FileDB, name: string) => any): Promise
Asynchronous
Runs the provided function on all linked files in parallel.
#### collect(obj: object, fn: (collector: object, file: FileDB, name: string) => void): Promise
#### reduce(initialValue: any, fn: (result: any, file: FileDB) => any): Promise
Asynchronous
Applies a reducer over all files.
#### values(): Promise map(file => file)
Alias for
#### keys(): Promise map((file, name) => name)
Alias for
#### entries(): Promise map((file, name) => [name, file])
Alias for
#### index(): Promise
Collects all files into a dictionary.
#### verify(): Promise<{ isOk: boolean, errors?: [string, Error][] }>
Async & Treelock protected
Checks readability of all linked files.
#### unlock(key: string): Promise<{ isOk: boolean, errors?: [string, Error][] }>
Async & Treelock protected
Attempts to decrypt and verify all linked files with the provided key.
#### optimize(): Promise<{ isOk: boolean, errors?: [string, Error][] }>
Async & Treelock protected
Regenerates all files to a compact form.
#### rekey(newKey: string, currentKey: string): Promise<{ isOk: boolean, errors?: [string, Error][] }>
Async & Treelock protected
Regenerates and re-encrypts all files using a new key.
Requires currentKey to be provided because of security.
---
#### write(id:string, body: object): Promise
Async & Treelock protected
Appends a single record. Requires the file to be readable.
_To delete record simple provide its id and no body (body==null)_
#### writeSync(id:string, body: object): voidwrite
Synchronous
Synchronous version of .
#### map(fn: (body: object, id: string) => any): Promise
Async & Treelock protected
Iterates over all records, giving only the latest per ID.
#### collect(obj: object, fn: (collector: object, body: object, id: string) => void): Promise
#### reduce(initialValue: any, fn: (result: any, body: object, id: string) => any): Promise
Async & Treelock protected
Reduces over all unique records.
#### values(): Promise map(body => body)
Alias for
#### keys(): Promise map((body, id) => id)
Alias for
#### entries(): Promise map((body, id) => [id, body])
Alias for
#### index(): Promise
Collects records by ID.
#### verify(): Promise
Async & Treelock protected
Validates the file can be read and parsed. Throws if unreadable.
#### unlock(key: string): Promise
Async & Treelock protected
Attempts to decrypt and verify the file with the provided key.
#### optimize(): Promise
Async & Treelock protected
Compacts the file to remove duplicate entries.
#### rekey(newKey: string, currentKey: string): Promise
Async & Treelock protected
Regenerates the file using a new key.
Requires currentKey to be provided because of security.
---
- isReadable is false until at least one successful verify, map, or unlock.error
- Errors during reading are stored in and prevent writes.
---
MIT License ⢠Made with ā by Jan / @randajan`