85 lines
3.1 KiB
Markdown

# PouchDB Attachment Proxy
PouchDB Attachment Proxy is a PouchDB plugin that intercepts and allows you to redirect document
attachments in a PouchDB database. The intention is to use the PouchDB API to manage all attachment
metadata without having the raw data bogging down your PouchDB database.
## Overview
Attachment Proxy works by intercepting attachments bound for the pouchdb backend and passing them to
a custom `save` function that will return a blob to be saved in the pouchdb document. The returned
blob should be a smaller _sentry_ blob with just enough information needed to fetch the full version
that is being proxied. `stringToBlob` is provided to make this process easier for simple string
identifier cases. Alternatively, you can pass the original attachment through if you do not want it
to be proxied.
When an attachment is requested, the document attached blob (returned from `save`) will be provided
to a custom `getFn` function to be converted into desired document. `blobToString` is provided to
make this easier for simple string identifier cases.
Similar to `getFn`, the sentry blob is provided to `remove` when an attachment or its containing
document is deleted.
Each function is expected to be asynchronous and the database will not continue its operation until
the proxy function completes to ensure data integrity. It may be desirable to for the `remove`
function to delay attachment cleanup. In this case, the document blob will be removed from document
(effectively orphaning the proxied attachment until it is cleaned asynchronously).
## Example
To create an attachment proxy, supply an object to the proxy wrapper with the three handler
functions.
```js
import {
PouchDBAttachmentProxy,
SENTRY_MIMETYPE,
blobToString,
stringToBlob
} from 'pouchdb-attachmentproxy';
const dataUrlToBlob = data => {
const [header, b64str] = data.split(';base64,');
const byteCharacters = atob(b64str);
const byteNumbers = new Array(byteCharacters.length);
for (var i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
return new Blob([byteArray], { type: header.substr(5) });
};
const LocalStorageExampleAdapter = PouchDBAttachmentProxy({
getFn: async function getAttachment(blob) {
const id = await blobToString(blob);
return dataUrlToBlob(localStorage[id]);
},
remove: async function removeAttachment(blob) {
const id = await blobToString(blob);
delete localStorage[id];
},
save: async function saveAttachment(blob) {
let id;
while (!id || localStorage[id] !== undefined) {
id = '' + Math.ceil(Math.random() * 100000);
}
// placeholder to prevent a race condition
localStorage[id] = true;
return new Promise(resolve => {
const reader = new FileReader();
reader.onloadend = function() {
localStorage[id] = reader.result;
// The returned blob must have the SENTRY_MIMETYPE mime_type in
// order to be proxied to `getFn` and `remove`.
resolve(stringToBlob(id, SENTRY_MIMETYPE));
};
reader.readAsDataURL(blob);
});
}
});
const ProxiedPouch = PouchDB.plugin(LocalStorageExampleAdapter);
```