Storage adapters
EscoDB provides a number of storage adapters that can be passed to the Store
class to handle persistence. Two such adapters are included in the
@escodb/core package:
-
FileAdapter: Stores content on the local filesystem. Most current applications will use this adapter. -
MemoryAdapter: Stores content in memory and does not write to any persistent store. This adapter is mainly used for testing; if your application uses a remote storage backend, it can be swapped out for this adapter and it will work identically.
Several other adapters are available via other packages:
-
@escodb/couchdb-adapter: Adapter for storing content in CouchDB. -
@escodb/s3-adapter: Adapter for storing content in Amazon S3.
Custom adapters
Support for any other storage system can be accomplished by implementing the Storage Adapter API, which consists of the following methods:
-
read(id): ReturnsPromise<{ value, rev }>wherevalueis a string representing the current content of the file or object namedid.revis a revision token that identifies the current version of the file, and can be any type of value that thewrite()method knows how to handle. If the file does not currently exist, returnsPromise<null>. -
write(id, value, rev): Ifrevmatches the current revision of the file namedid, then it writes the stringvalueto the file and returnsPromise<{ rev }>whererevis the new revision token. Otherwise, it returns aPromiserejected with an error withcode = 'ERR_CONFLICT'. If the inputrevisnullthen the write must only succeed if the file does not currently exist.
Any object implementing these two methods can be used as a storage adapter. To make sure that EscoDB’s concurrency control works correctly, these methods must obey the following constraints:
-
The first
write(id, value, rev)call to succeed for a givenidmust haverev = null. That is, the client must believe it is creating the file for the first time. If the file does not exist then any non-nullrevinput should be rejected. -
Any subsequent
write(id, value, rev)call for thatidmust succeed only ifrevis a revision token that has previously been returned byread(id)orwrite(id, ...). That is, some client must previously have been told thatrevwas the current revision token. -
write(id, value, rev)must succeed at most once for each unique combination ofidandrev, i.e. only onevalueis accepted for each version of a file. -
The
revreturned by a successful call towrite(id, value, rev)must be different from any previously returnedrev. EscoDB includes a small amount of random content each time it updates a file, so this requirement can be met by using a collision-resistant content hash. -
After a
write(id, value, rev)call succeeds, all subsequent calls toread(id)must returnvalueuntil the next successful call towrite(id, ...). -
write(id, value, rev)must appear to be atomic to any external observer. That is, calls toread(id)must only ever return avaluethat was passed in some prior successfulwrite(id, value, rev)call and must never return any intermediate or incomplete value.
Security considerations
The storage layer in EscoDB is deliberately minimal. It does not have any awareness of the data model built on top of it, the data access execution planner, or any of the cryptographic techniques used to secure the data. It is simply a place where blobs of data can be stored and retrieved.
Being an end-to-end encryption system, EscoDB places minimal trust in the storage layer and tries to guard against an attacker who has access to the storage server or to the communication channel between the client and the server.
That being said, it is still a good idea to secure the storage backend as much as you are able. The storage system should be protected by strong credentials that grant access only to authorised users, it should be logically or physically isolated from systems that do not require access to it, and all communication with it should use an encrypted and authenticated transport mechanism such as TLS or SSH.