From 3d4eaf8995ec4fef1899da62e7025d5fe5eaecbc Mon Sep 17 00:00:00 2001 From: Alex Potsides Date: Fri, 16 Feb 2024 11:01:57 +0000 Subject: [PATCH] feat: support decoding ArrayBuffers (#95) Expands supported input types to include `ArrayBuffer`s to make it easiser for users to use modules like `fetch` that don't return `Uint8Array`s. --- package.json | 2 +- src/index.js | 12 +++++++++--- src/util.js | 23 +++++++++++++++++++++++ test/test-basics.spec.js | 11 +++++++++++ test/ts-use/src/main.ts | 9 +++++++++ 5 files changed, 53 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 49a8c08..e04ec1a 100644 --- a/package.json +++ b/package.json @@ -163,7 +163,7 @@ "dep-check": "aegir dep-check -i @ipld/dag-pb" }, "dependencies": { - "multiformats": "^13.0.0" + "multiformats": "^13.1.0" }, "devDependencies": { "aegir": "^42.1.0" diff --git a/src/index.js b/src/index.js index 77e009f..ccd5b4d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,13 +1,18 @@ import { CID } from 'multiformats/cid' import { decodeNode } from './pb-decode.js' import { encodeNode } from './pb-encode.js' -import { prepare, validate, createNode, createLink } from './util.js' +import { prepare, validate, createNode, createLink, toByteView } from './util.js' /** * @template T * @typedef {import('multiformats/codecs/interface').ByteView} ByteView */ +/** + * @template T + * @typedef {import('multiformats/codecs/interface').ArrayBufferView} ArrayBufferView + */ + /** * @typedef {import('./interface.js').PBLink} PBLink * @typedef {import('./interface.js').PBNode} PBNode @@ -47,11 +52,12 @@ export function encode (node) { } /** - * @param {ByteView} bytes + * @param {ByteView | ArrayBufferView} bytes * @returns {PBNode} */ export function decode (bytes) { - const pbn = decodeNode(bytes) + const buf = toByteView(bytes) + const pbn = decodeNode(buf) const node = {} diff --git a/src/util.js b/src/util.js index 113826f..f581942 100644 --- a/src/util.js +++ b/src/util.js @@ -5,6 +5,16 @@ import { CID } from 'multiformats/cid' * @typedef {import('./interface.js').PBNode} PBNode */ +/** + * @template T + * @typedef {import('multiformats/codecs/interface').ByteView} ByteView + */ + +/** + * @template T + * @typedef {import('multiformats/codecs/interface').ArrayBufferView} ArrayBufferView + */ + const pbNodeProperties = ['Data', 'Links'] const pbLinkProperties = ['Hash', 'Name', 'Tsize'] @@ -231,3 +241,16 @@ export function createNode (data, links = []) { export function createLink (name, size, cid) { return asLink({ Hash: cid, Name: name, Tsize: size }) } + +/** + * @template T + * @param {ByteView | ArrayBufferView} buf + * @returns {ByteView} + */ +export function toByteView (buf) { + if (buf instanceof ArrayBuffer) { + return new Uint8Array(buf, 0, buf.byteLength) + } + + return buf +} diff --git a/test/test-basics.spec.js b/test/test-basics.spec.js index 2601b9e..ce3e397 100644 --- a/test/test-basics.spec.js +++ b/test/test-basics.spec.js @@ -44,6 +44,17 @@ describe('Basics', () => { assert.deepEqual(node.Data, data) }) + it('prepare & encode a node with data using an ArrayBuffer', () => { + const data = Uint8Array.from([0, 1, 2, 3, 4]) + const prepared = prepare({ Data: data }) + assert.deepEqual(prepared, { Data: data, Links: [] }) + const result = encode(prepared) + assert.instanceOf(result, Uint8Array) + + const node = decode(result.buffer) + assert.deepEqual(node.Data, data) + }) + it('prepare & encode a node with links', () => { const links = [ { Hash: CID.parse('QmWDtUQj38YLW8v3q4A6LwPn4vYKEbuKWpgSm6bjKW6Xfe') } diff --git a/test/ts-use/src/main.ts b/test/ts-use/src/main.ts index 1b4674d..ccf363a 100644 --- a/test/ts-use/src/main.ts +++ b/test/ts-use/src/main.ts @@ -19,6 +19,9 @@ function useCodec (codec: BlockCodec<0x70, any>) { // use only as a BlockDecoder useDecoder(codec) + // use with ArrayBuffer input type + useDecoderWithArrayBuffer(codec) + // use as a full BlockCodec which does both BlockEncoder & BlockDecoder useBlockCodec(codec) } @@ -36,6 +39,12 @@ function useDecoder (decoder: BlockDecoder (decoder: BlockDecoder) { + deepStrictEqual(decoder.code, 0x70) + deepStrictEqual(decoder.decode(Uint8Array.from(exampleBytes).buffer), exampleNode) + console.log('[TS] ✓ { decoder: BlockDecoder }') +} + function useBlockCodec (blockCodec: BlockCodec) { deepStrictEqual(blockCodec.code, 0x70) deepStrictEqual(blockCodec.name, 'dag-pb')