Store a file
Publish a file's bytes with its name and content type, optionally signed and encrypted, then recover the file from the record.
A file output publishes the file itself, so the record carries the document rather than a pointer to a document that somebody has to keep hosting.
What a file output takes
The shape as @mintblue/sdk 9.6.0 declares it, verbatim:
export interface FileOutput {
type: 'file';
/** File to publish */
value: {
fileName: string;
contentType: string;
content: Buffer;
};
/** Set to true to add digital signature */
sign?: boolean;
/** Set to true to encrypt value */
encrypt?: boolean;
}Three things about value are worth stating plainly, because each one is a way
the call goes wrong:
- All three fields are required.
fileNameis not optional. Avaluewith onlycontentTypeandcontentdoes not satisfy the declared type. contentis aBuffer. Reading a file with an encoding argument, as infs.readFileSync(path, 'base64'), returns a string, not a buffer. Read it without an encoding.contentTypeis a MIME type, the same string a web server would send:application/pdf,image/png,text/plain. The list is at MDN.
The maximum file size is 50MB per transaction.
Read the file and submit it
const fs = require('node:fs');
const path = require('node:path');
const filePath = path.join(__dirname, 'invoice.pdf');
const outputs = [
{
type: 'file',
value: {
fileName: path.basename(filePath),
contentType: 'application/pdf',
content: fs.readFileSync(filePath),
},
sign: true,
encrypt: true,
},
];
const { txid } = await client.createTransaction({
project_id: process.env.MINTBLUE_PROJECT_ID,
outputs,
});sign and encrypt behave as they do for a data output: the signature is made
with your key, and the encryption happens on your machine before anything is
submitted. Both default to off.
Check it worked
Fetch the transaction with parse: true, find the file output, and write the
bytes back to disk. If the recovered file opens and matches the original, the
whole path worked.
const transaction = await client.getTransaction({ txid, parse: true });
const file = transaction.outputs.find((output) => output.type === 'file');
fs.writeFileSync(`recovered-${file.value.fileName}`, file.value.content);A stricter check, if the file matters: compare digests rather than eyeballing the result.
const { utils } = require('@mintblue/sdk');
const original = await utils.sha256s(fs.readFileSync(filePath));
const recovered = await utils.sha256s(file.value.content);
console.log(original === recovered ? 'identical' : 'different');When a digest is enough
Publishing the whole file is not always what you want. If the point is to be
able to prove later that a document has not been altered, the hash output type
publishes a digest of the file and leaves the file with you. It takes the raw
contents as data and an algorithm, either SHA-256 or SHA-512, and
computes the digest for you. The format it writes is documented at
hash.