Skip to content

Commit d3613f3

Browse files
committed
fix!: simplify the codec interface, remove helper methods & classes
BREAKING CHANGE: * Removes the codecs/codec export - there is no longer a helper function to building codecs, they should instead assert that they conform to the `BlockCodec` type, see json and raw examples. The `codec()` helper and `Encoder` and `Decoder` classes have been removed. Use type assertions to conform to simple signatures for now. In the future we may introduce more composable codec functionality which may require codecs to lean on additional helpers and classes. * Fix bases/base64 type export to be usable
1 parent 6d3bb8a commit d3613f3

11 files changed

+68
-175
lines changed

README.md

+12-32
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
# multiformats
22

3-
This library defines common interfaces and low level building blocks for varios inter-related multiformat technologies (multicodec, multihash, multibase,
4-
and CID). They can be used to implement custom custom base
5-
encoders / decoders / codecs, codec encoders /decoders and multihash hashers that comply to the interface that layers above assume.
3+
This library defines common interfaces and low level building blocks for varios inter-related multiformat technologies (multicodec, multihash, multibase, and CID). They can be used to implement custom custom base encoders / decoders / codecs, codec encoders /decoders and multihash hashers that comply to the interface that layers above assume.
64

7-
Library provides implementations for most basics and many others can be found in linked repositories.
5+
This library provides implementations for most basics and many others can be found in linked repositories.
86

97
## Interfaces
108

@@ -45,19 +43,15 @@ block = await Block.create({ bytes: block.bytes, cid: block.cid, codec, hasher }
4543

4644
### Multibase Encoders / Decoders / Codecs
4745

48-
CIDs can be serialized to string representation using multibase encoders that
49-
implement [`MultibaseEncoder`](https://github.com/multiformats/js-multiformats/blob/master/src/bases/interface.ts) interface. Library
50-
provides quite a few implementations that can be imported:
46+
CIDs can be serialized to string representation using multibase encoders that implement [`MultibaseEncoder`](https://github.com/multiformats/js-multiformats/blob/master/src/bases/interface.ts) interface. This library provides quite a few implementations that can be imported:
5147

5248
```js
5349
import { base64 } from "multiformats/bases/base64"
5450
cid.toString(base64.encoder)
5551
//> 'mAYAEEiCTojlxqRTl6svwqNJRVM2jCcPBxy+7mRTUfGDzy2gViA'
5652
```
5753

58-
Parsing CID string serialized CIDs requires multibase decoder that implements
59-
[`MultibaseDecoder`](https://github.com/multiformats/js-multiformats/blob/master/src/bases/interface.ts) interface. Library provides a
60-
decoder for every encoder it provides:
54+
Parsing CID string serialized CIDs requires multibase decoder that implements [`MultibaseDecoder`](https://github.com/multiformats/js-multiformats/blob/master/src/bases/interface.ts) interface. This library provides a decoder for every encoder it provides:
6155

6256
```js
6357
CID.parse('mAYAEEiCTojlxqRTl6svwqNJRVM2jCcPBxy+7mRTUfGDzy2gViA', base64.decoder)
@@ -93,35 +87,24 @@ v0.toV1().toString()
9387

9488
### Multicodec Encoders / Decoders / Codecs
9589

96-
Library defines [`BlockEncoder`, `BlockDecoder` and `BlockCodec` interfaces](https://github.com/multiformats/js-multiformats/blob/master/src/codecs/interface.ts)
97-
and utility function to take care of the boilerplate when implementing them:
90+
This library defines [`BlockEncoder`, `BlockDecoder` and `BlockCodec` interfaces](https://github.com/multiformats/js-multiformats/blob/master/src/codecs/interface.ts). Codec implementations should conform to the `BlockCodec` interface which implements both `BlockEncoder` and `BlockDecoder`.
9891

9992
```js
100-
import { codec } from 'multiformats/codecs/codec'
101-
102-
const json = codec({
93+
/**
94+
* @template T
95+
* @type {BlockCodec<0x0200, T>}
96+
*/
97+
export const { name, code, encode, decode } = {
10398
name: 'json',
104-
// As per multiformats table
105-
// https://github.com/multiformats/multicodec/blob/master/table.csv#L113
10699
code: 0x0200,
107100
encode: json => new TextEncoder().encode(JSON.stringify(json)),
108101
decode: bytes => JSON.parse(new TextDecoder().decode(bytes))
109-
})
110-
```
111-
112-
Just like with multibase, here codecs are duals of `encoder` and `decoder` parts,
113-
but they also implement both interfaces for convenience:
114-
115-
```js
116-
const hello = json.encoder.encode({ hello: 'world' })
117-
json.decode(b1)
118-
//> { hello: 'world' }
102+
}
119103
```
120104

121105
### Multihash Hashers
122106

123-
This library defines [`MultihashHasher` and `MultihashDigest` interfaces](https://github.com/multiformats/js-multiformats/blob/master/src/hashes/interface.ts)
124-
and convinient function for implementing them:
107+
This library defines [`MultihashHasher` and `MultihashDigest` interfaces](https://github.com/multiformats/js-multiformats/blob/master/src/hashes/interface.ts) and convinient function for implementing them:
125108

126109
```js
127110
import * as hasher from 'multiformats/hashes/hasher')
@@ -141,8 +124,6 @@ CID.create(1, json.code, hash)
141124
//> CID(bagaaierasords4njcts6vs7qvdjfcvgnume4hqohf65zsfguprqphs3icwea)
142125
```
143126

144-
145-
146127
# Implementations
147128

148129
By default, no base encodings (other than base32 & base58btc), hash functions,
@@ -179,7 +160,6 @@ import the ones you need yourself.
179160
| `dag-pb` | `@ipld/dag-pb` | [ipld/js-dag-pb](https://github.com/ipld/js-dag-pb) |
180161
| `dag-jose` | `dag-jose`| [ceramicnetwork/js-dag-jose](https://github.com/ceramicnetwork/js-dag-jose) |
181162

182-
183163
## TypeScript support
184164

185165
This project is distributed with type definitions for TypeScript.

package.json

+12-13
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@
77
"type": "module",
88
"scripts": {
99
"build": "npm run build:js && npm run build:types",
10-
"build:js": "npm_config_yes=true ipjs build --tests --main && npm run build:copy",
10+
"build:js": "ipjs build --tests --main && npm run build:copy",
1111
"build:copy": "cp -a tsconfig.json src vendor test dist/ && rm -rf dist/test/ts-use",
1212
"build:types": "npm run build:copy && cd dist && tsc --build",
1313
"build:vendor": "npm run build:vendor:varint && npm run build:vendor:base-x",
14-
"build:vendor:varint": "npx brrp -x varint > vendor/varint.js",
15-
"build:vendor:base-x": "npx brrp -x @multiformats/base-x > vendor/base-x.js",
16-
"publish": "npm_config_yes=true ipjs publish",
14+
"build:vendor:varint": "npm_config_yes=true npx brrp -x varint > vendor/varint.js",
15+
"build:vendor:base-x": "npm_config_yes=true npx brrp -x @multiformats/base-x > vendor/base-x.js",
16+
"publish": "ipjs publish",
1717
"lint": "standard",
18-
"check": "tsc --build --noErrorTruncation",
1918
"test:cjs": "npm run build:js && mocha dist/cjs/node-test/test-*.js && npm run test:cjs:browser",
2019
"test:node": "hundreds mocha test/test-*.js",
2120
"test:cjs:browser": "polendina --page --worker --serviceworker --cleanup dist/cjs/browser-test/test-*.js",
@@ -75,9 +74,6 @@
7574
"./hashes/identity": {
7675
"import": "./src/hashes/identity.js"
7776
},
78-
"./codecs/codec": {
79-
"import": "./src/codecs/codec.js"
80-
},
8177
"./codecs/json": {
8278
"import": "./src/codecs/json.js"
8379
},
@@ -86,16 +82,16 @@
8682
}
8783
},
8884
"devDependencies": {
89-
"@types/node": "^14.14.37",
90-
"@typescript-eslint/eslint-plugin": "^4.20.0",
91-
"@typescript-eslint/parser": "^4.20.0",
92-
"c8": "^7.6.0",
85+
"@types/node": "^14.14.41",
86+
"@typescript-eslint/eslint-plugin": "^4.22.0",
87+
"@typescript-eslint/parser": "^4.22.0",
88+
"c8": "^7.7.1",
9389
"hundreds": "0.0.9",
9490
"ipjs": "^5.0.0",
9591
"mocha": "^8.3.2",
9692
"polendina": "^1.1.0",
9793
"standard": "^16.0.3",
98-
"typescript": "^4.2.3"
94+
"typescript": "^4.2.4"
9995
},
10096
"standard": {
10197
"ignore": [
@@ -120,6 +116,9 @@
120116
"homepage": "https://github.com/multiformats/js-multiformats#readme",
121117
"typesVersions": {
122118
"*": {
119+
"bases/base64": [
120+
"types/bases/base64-import.d.ts"
121+
],
123122
"*": [
124123
"types/*"
125124
],

src/codecs/codec.js

-71
This file was deleted.

src/codecs/interface.ts

+4-10
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,12 @@ export interface BlockDecoder<Code extends number, T> {
1616
}
1717

1818
/**
19-
* IPLD codec that is just Encoder + Decoder however it is
20-
* separate those capabilties as sender requires encoder and receiver
21-
* requires decoder.
19+
* An IPLD codec is a combination of both encoder and decoder.
2220
*/
23-
export interface BlockCodec<Code extends number, T> extends BlockEncoder<Code, T>, BlockDecoder<Code, T> {
24-
encoder: BlockEncoder<Code, T>,
25-
decoder: BlockDecoder<Code, T>
26-
}
27-
21+
export interface BlockCodec<Code extends number, T> extends BlockEncoder<Code, T>, BlockDecoder<Code, T> {}
2822

29-
// This just a hack to retain type information abouth the data that
30-
// is incoded `T` Because it's a union `data` field is never going
23+
// This just a hack to retain type information about the data that
24+
// is encoded `T` Because it's a union `data` field is never going
3125
// to be usable anyway.
3226
export type ByteView<T> =
3327
| Uint8Array

src/codecs/json.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
// @ts-check
22

3-
import { codec } from './codec.js'
3+
/**
4+
* @template {number} Code
5+
* @template T
6+
* @typedef {import('./interface').BlockCodec<Code, T>} BlockCodec
7+
*/
48

5-
export const { name, code, decode, encode, decoder, encoder } = codec({
9+
/**
10+
* @template T
11+
* @type {BlockCodec<0x0200, T>}
12+
*/
13+
export const { name, code, encode, decode } = {
614
name: 'json',
715
code: 0x0200,
816
encode: json => new TextEncoder().encode(JSON.stringify(json)),
917
decode: bytes => JSON.parse(new TextDecoder().decode(bytes))
10-
})
18+
}

src/codecs/raw.js

+21-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,26 @@
11
// @ts-check
22

33
import { coerce } from '../bytes.js'
4-
import { codec } from './codec.js'
54

6-
export const { name, code, decode, encode, decoder, encoder } = codec({
5+
/**
6+
* @template {number} Code
7+
* @template T
8+
* @typedef {import('./interface').BlockCodec<Code, T>} BlockCodec
9+
*/
10+
11+
/**
12+
* @param {Uint8Array} bytes
13+
* @returns {Uint8Array}
14+
*/
15+
const raw = (bytes) => coerce(bytes)
16+
17+
/**
18+
* @template T
19+
* @type {BlockCodec<0x55, Uint8Array>}
20+
*/
21+
export const { name, code, encode, decode } = {
722
name: 'raw',
8-
code: 85,
9-
decode: coerce,
10-
encode: coerce
11-
})
23+
code: 0x55,
24+
decode: raw,
25+
encode: raw
26+
}

src/index.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,5 @@ import * as varint from './varint.js'
33
import * as bytes from './bytes.js'
44
import * as hasher from './hashes/hasher.js'
55
import * as digest from './hashes/digest.js'
6-
import * as codec from './codecs/codec.js'
76

8-
export { CID, hasher, digest, varint, bytes, codec }
7+
export { CID, hasher, digest, varint, bytes }

test/test-legacy.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { legacy } from 'multiformats/legacy'
55
import * as rawCodec from 'multiformats/codecs/raw'
66
import * as jsonCodec from 'multiformats/codecs/json'
77
import { sha256, sha512 } from 'multiformats/hashes/sha2'
8-
import { codec } from 'multiformats/codecs/codec'
98
import { CID } from 'multiformats/cid'
109

1110
const same = assert.deepStrictEqual
@@ -36,7 +35,7 @@ describe('multicodec', () => {
3635
raw = legacy(rawCodec, { hashes })
3736
json = legacy(jsonCodec, { hashes })
3837
link = await raw.util.cid(Buffer.from('test'))
39-
custom = legacy(codec({
38+
custom = legacy({
4039
name: 'custom',
4140
code: 6787678,
4241
encode: o => {
@@ -52,7 +51,7 @@ describe('multicodec', () => {
5251
if (obj.o.link) obj.link = CID.asCID(link)
5352
return obj
5453
}
55-
}), { hashes })
54+
}, { hashes })
5655
})
5756
test('encode/decode raw', () => {
5857
const buff = raw.util.serialize(Buffer.from('test'))

test/test-multicodec.js

+1-31
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as bytes from '../src/bytes.js'
33
import assert from 'assert'
44
import * as raw from 'multiformats/codecs/raw'
55
import * as json from 'multiformats/codecs/json'
6-
import { codec } from 'multiformats/codecs/codec'
6+
77
const same = assert.deepStrictEqual
88
const test = it
99

@@ -31,37 +31,7 @@ describe('multicodec', () => {
3131
same(json.decode(buff), { hello: 'world' })
3232
})
3333

34-
test('json.encoder', () => {
35-
const { encoder } = json
36-
same(encoder === json.encoder, true, 'getter cached decoder')
37-
38-
const buff = encoder.encode({ hello: 'world' })
39-
same(buff, bytes.fromString(JSON.stringify({ hello: 'world' })))
40-
})
41-
42-
test('json.decoder', () => {
43-
const { decoder } = json
44-
same(decoder === json.decoder, true, 'getter cached encoder')
45-
46-
const buff = json.encode({ hello: 'world' })
47-
same(decoder.decode(buff), { hello: 'world' })
48-
})
49-
5034
test('raw cannot encode string', async () => {
5135
await testThrow(() => raw.encode('asdf'), 'Unknown type, must be binary type')
5236
})
53-
54-
test('add with function', () => {
55-
const blip = codec({
56-
code: 200,
57-
name: 'blip',
58-
encode: (a) => a[1],
59-
decode: (a) => a
60-
})
61-
62-
const two = bytes.fromString('two')
63-
const three = bytes.fromString('three')
64-
same(blip.encode(['one', two, three]), two)
65-
same(blip.decode(three, 200), three)
66-
})
6737
})

test/ts-use/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
"multiformats": "file:../../dist/"
66
},
77
"scripts": {
8-
"test": "npm install && npx -p typescript tsc --noEmit"
8+
"test": "npm install && npm_config_yes=true npx -p typescript tsc --noEmit"
99
}
1010
}

0 commit comments

Comments
 (0)