From 54b2811d2723988bb3030897eaa0fe38bf96fb92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jimmy=20Wa=CC=88rting?= Date: Fri, 24 Jul 2020 16:56:54 +0200 Subject: [PATCH 1/9] create a blob backed up by filesystem --- README.md | 18 +++++++++++++++++ from.js | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 +++ test.js | 7 +++++++ 4 files changed, 84 insertions(+) create mode 100644 from.js diff --git a/README.md b/README.md index 1286c25..a03cbbf 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,24 @@ fetch('https://httpbin.org/post', { .then(json => console.log(json)); ``` +### Blob part backed up by filesystem +you need to install optional domexception too + +```sh +npm install fetch-blob domexception +``` + +```js +const blobFrom = require('fetch-blob/from.js'); +const blob1 = blobFrom('./2-GiB-file.bin'); +const blob2 = blobFrom('./2-GiB-file.bin'); + +// Not a 4 GiB memory snapshot, just holds 3 references +// points to where data is located on the disk +const blob = new Blob([blob1, blob2]); +console.log(blob.size) // 4 GiB +``` + See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/Blob) and [tests](https://github.com/node-fetch/fetch-blob/blob/master/test.js) for more details. [npm-image]: https://flat.badgen.net/npm/v/fetch-blob diff --git a/from.js b/from.js new file mode 100644 index 0000000..fb34cfe --- /dev/null +++ b/from.js @@ -0,0 +1,56 @@ +const {statSync, createReadStream} = require('fs'); +const Blob = require('.'); +const DOMException = require('domexception'); + +/** + * @param {string} path filepath on the disk + */ +function blobFrom(path) { + const {size, mtime} = statSync(path); + const blob = new BlobDataItem({path, size, mtime}); + + return new Blob([blob]); +} + +/** + * This is a blob backed up by a file on the disk + * with minium requirement + * + * @private + */ +class BlobDataItem { + constructor(options) { + this.size = options.size; + this.path = options.path; + this.start = options.start; + this.mtime = options.mtime; + } + + // Slicing arguments is validated and formated + // by Blob.prototype.slice + slice(start, end) { + return new BlobDataItem({ + path: this.path, + start, + mtime: this.mtime, + size: end - start + }); + } + + stream() { + if (statSync(this.path).mtime > this.mtime) { + throw new DOMException('The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.', 'NotReadableError'); + } + + return createReadStream(this.path, { + start: this.start, + end: this.start + this.size - 1 + }); + } + + get [Symbol.toStringTag]() { + return 'Blob'; + } +} + +module.exports = blobFrom; diff --git a/package.json b/package.json index 68a848c..affcd1a 100644 --- a/package.json +++ b/package.json @@ -49,4 +49,7 @@ ] }, "dependencies": {} + "optionalDependencies": { + "domexception": "^2.0.1" + } } diff --git a/test.js b/test.js index ae73beb..fed05e8 100644 --- a/test.js +++ b/test.js @@ -1,5 +1,6 @@ const test = require('ava'); const Blob = require('.'); +const blobFrom = require('./from'); const getStream = require('get-stream'); const {Response} = require('node-fetch'); const {TextDecoder} = require('util'); @@ -142,3 +143,9 @@ test('Blob works with node-fetch Response.text()', async t => { const text = await response.text(); t.is(text, data); }); + +test('blob part backed up by filesystem', async t => { + const blob = blobFrom('./LICENSE'); + t.is(await blob.slice(0, 3).text(), 'MIT'); + t.is(await blob.slice(4, 11).text(), 'License'); +}); From 74cee5a1e325ab2b870fdccf5a159b476c68453b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jimmy=20Wa=CC=88rting?= Date: Fri, 24 Jul 2020 16:58:59 +0200 Subject: [PATCH 2/9] typo --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index affcd1a..3487d9e 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ } ] }, - "dependencies": {} + "dependencies": {}, "optionalDependencies": { "domexception": "^2.0.1" } From d853409523196b3f5efed75530024bf4964a6626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jimmy=20Wa=CC=88rting?= Date: Sat, 25 Jul 2020 17:08:04 +0200 Subject: [PATCH 3/9] Changed to peer dependency --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 3487d9e..9e3c583 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,7 @@ } ] }, - "dependencies": {}, - "optionalDependencies": { + "peerDependencies": { "domexception": "^2.0.1" } } From 5d84a6285cc71cc3ba7ace3578b1ca5863336c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jimmy=20Wa=CC=88rting?= Date: Sat, 25 Jul 2020 17:08:26 +0200 Subject: [PATCH 4/9] added code coverage test for modification --- test.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test.js b/test.js index fed05e8..14447a2 100644 --- a/test.js +++ b/test.js @@ -1,3 +1,4 @@ +const fs = require('fs'); const test = require('ava'); const Blob = require('.'); const blobFrom = require('./from'); @@ -149,3 +150,13 @@ test('blob part backed up by filesystem', async t => { t.is(await blob.slice(0, 3).text(), 'MIT'); t.is(await blob.slice(4, 11).text(), 'License'); }); + +test('Reading after modified should fail', async t => { + const blob = blobFrom('./LICENSE'); + await new Promise(rs => setTimeout(rs, 100)) + const now = new Date(); + // Change modified time + fs.utimesSync('./LICENSE', now, now); + const error = await blob.text().catch(e => e); + t.is(error.name, 'NotReadableError'); +}); From 82d9be0943ebf956071c2c16269d46c8fbbffce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jimmy=20Wa=CC=88rting?= Date: Sat, 25 Jul 2020 17:09:50 +0200 Subject: [PATCH 5/9] updated domexception sentences --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a03cbbf..53c81f5 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ fetch('https://httpbin.org/post', { ``` ### Blob part backed up by filesystem -you need to install optional domexception too +To use, install [domexception](https://github.com/jsdom/domexception). ```sh npm install fetch-blob domexception From e79992ca5c266bcedd83aff45330c7b89dc6d2c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jimmy=20Wa=CC=88rting?= Date: Sat, 25 Jul 2020 17:15:24 +0200 Subject: [PATCH 6/9] lint fix --- test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.js b/test.js index 14447a2..3a7b23b 100644 --- a/test.js +++ b/test.js @@ -153,10 +153,10 @@ test('blob part backed up by filesystem', async t => { test('Reading after modified should fail', async t => { const blob = blobFrom('./LICENSE'); - await new Promise(rs => setTimeout(rs, 100)) + await new Promise(resolve => setTimeout(resolve, 100)); const now = new Date(); // Change modified time fs.utimesSync('./LICENSE', now, now); - const error = await blob.text().catch(e => e); + const error = await blob.text().catch(error => error); t.is(error.name, 'NotReadableError'); }); From 21a126f0abc1013f4936188e023e22566bfc0947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jimmy=20Wa=CC=88rting?= Date: Sat, 25 Jul 2020 17:22:18 +0200 Subject: [PATCH 7/9] install peer dep --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c117b61..eb011f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,6 +47,7 @@ jobs: node-version: ${{steps.get-version.outputs.node}} - run: npm install + - run: npm install domexception - run: npm run report -- --colors From 31648c653897cec9278e92951c3e012a26bc3434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jimmy=20Wa=CC=88rting?= Date: Sat, 25 Jul 2020 17:54:25 +0200 Subject: [PATCH 8/9] jsdoc return --- from.js | 1 + 1 file changed, 1 insertion(+) diff --git a/from.js b/from.js index fb34cfe..8d60de8 100644 --- a/from.js +++ b/from.js @@ -4,6 +4,7 @@ const DOMException = require('domexception'); /** * @param {string} path filepath on the disk + * @returns {Blob} */ function blobFrom(path) { const {size, mtime} = statSync(path); From cffb0be52fab142b700d13cba6faf4cf33800994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jimmy=20Wa=CC=88rting?= Date: Mon, 27 Jul 2020 12:44:18 +0200 Subject: [PATCH 9/9] added from to files array --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 9e3c583..9a7e74c 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "A Blob implementation in Node.js, originally from node-fetch.", "main": "index.js", "files": [ + "from.js", "index.js", "index.d.ts" ],