Skip to content
This repository has been archived by the owner on Aug 24, 2021. It is now read-only.

Commit

Permalink
feat: add ts types (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
hugomrdias committed Nov 24, 2020
1 parent 167eae7 commit 5a1e7d7
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 55 deletions.
9 changes: 8 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
name: ci
on: [push, pull_request]
on:
push:
branches:
- master
pull_request:
branches:
- master

jobs:
check:
Expand All @@ -8,6 +14,7 @@ jobs:
- uses: actions/checkout@v2
- run: yarn
- run: yarn lint
- uses: gozala/typescript-error-reporter-action@v1.0.4
- run: yarn aegir dep-check -- -i aegir
- uses: ipfs/aegir/actions/bundle-size@master
name: size
Expand Down
19 changes: 4 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io)
[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats)
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs)
[![Coverage Status](https://coveralls.io/repos/github/multiformats/js-multihash/badge.svg?branch=master)](https://coveralls.io/github/multiformats/js-multihash?branch=master)
[![Travis CI](https://img.shields.io/travis/multiformats/js-multihash.svg?style=flat-square&branch=master)](https://travis-ci.org/multiformats/js-multihash)
[![Dependency Status](https://david-dm.org/multiformats/js-multihash.svg?style=flat-square)](https://david-dm.org/multiformats/js-multihash)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard)
[![](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
[![codecov](https://img.shields.io/codecov/c/github/multiformats/js-multihash.svg?style=flat-square)](https://codecov.io/gh/multiformats/js-multihash)
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/multiformats/js-multihash/ci?label=ci&style=flat-square)](https://github.com/multiformats/js-multihash/actions?query=branch%3Amaster+workflow%3Aci+)

> multihash implementation in node.js
Expand Down Expand Up @@ -36,20 +33,12 @@ so give those a look as well.
### Using npm

```bash
> npm install multihashes # node the name of the module is multihashes
> npm install multihashes # NOTE: The name of the module is multihashes!
```

Once the install is complete, you can require it as a normal dependency

```js
const multihashes = require('multihashes')
```

You can require it and use with your favourite bundler to bundle this package in a browser compatible code.

### Using a `<script>` tag

Loading this module through a script tag will make the ```Multihashes``` obj available in the global namespace.
Loading this module through a script tag will make the `Multihashes` obj available in the global namespace.

```html
<script src="https://unpkg.com/multihashes/dist/index.min.js"></script>
Expand Down
20 changes: 16 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,27 @@
"update-constants": "node update-constants.js"
},
"main": "src/index.js",
"types": "dist/src/index.d.ts",
"typesVersions": {
"*": {
"src/*": [
"dist/src/*",
"dist/src/*/index"
]
}
},
"repository": "github:multiformats/js-multihash",
"dependencies": {
"multibase": "^3.0.0",
"multibase": "^3.1.0",
"uint8arrays": "^1.0.0",
"varint": "^5.0.0"
"varint": "^6.0.0"
},
"devDependencies": {
"aegir": "^25.0.0",
"ipfs-utils": "^2.3.1"
"aegir": "^29.0.1",
"ipfs-utils": "^5.0.0"
},
"eslintConfig": {
"extends": "ipfs"
},
"contributors": [
"David Dias <daviddias.p@gmail.com>",
Expand Down
15 changes: 15 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
/* eslint quote-props: off */
'use strict'

/**
* Names for all available hashes
*
* @typedef { "identity" | "sha1" | "sha2-256" | "sha2-512" | "sha3-512" | "sha3-384" | "sha3-256" | "sha3-224" | "shake-128" | "shake-256" | "keccak-224" | "keccak-256" | "keccak-384" | "keccak-512" | "blake3" | "murmur3-128" | "murmur3-32" | "dbl-sha2-256" | "md4" | "md5" | "bmt" | "sha2-256-trunc254-padded" | "ripemd-128" | "ripemd-160" | "ripemd-256" | "ripemd-320" | "x11" | "kangarootwelve" | "sm3-256" | "blake2b-8" | "blake2b-16" | "blake2b-24" | "blake2b-32" | "blake2b-40" | "blake2b-48" | "blake2b-56" | "blake2b-64" | "blake2b-72" | "blake2b-80" | "blake2b-88" | "blake2b-96" | "blake2b-104" | "blake2b-112" | "blake2b-120" | "blake2b-128" | "blake2b-136" | "blake2b-144" | "blake2b-152" | "blake2b-160" | "blake2b-168" | "blake2b-176" | "blake2b-184" | "blake2b-192" | "blake2b-200" | "blake2b-208" | "blake2b-216" | "blake2b-224" | "blake2b-232" | "blake2b-240" | "blake2b-248" | "blake2b-256" | "blake2b-264" | "blake2b-272" | "blake2b-280" | "blake2b-288" | "blake2b-296" | "blake2b-304" | "blake2b-312" | "blake2b-320" | "blake2b-328" | "blake2b-336" | "blake2b-344" | "blake2b-352" | "blake2b-360" | "blake2b-368" | "blake2b-376" | "blake2b-384" | "blake2b-392" | "blake2b-400" | "blake2b-408" | "blake2b-416" | "blake2b-424" | "blake2b-432" | "blake2b-440" | "blake2b-448" | "blake2b-456" | "blake2b-464" | "blake2b-472" | "blake2b-480" | "blake2b-488" | "blake2b-496" | "blake2b-504" | "blake2b-512" | "blake2s-8" | "blake2s-16" | "blake2s-24" | "blake2s-32" | "blake2s-40" | "blake2s-48" | "blake2s-56" | "blake2s-64" | "blake2s-72" | "blake2s-80" | "blake2s-88" | "blake2s-96" | "blake2s-104" | "blake2s-112" | "blake2s-120" | "blake2s-128" | "blake2s-136" | "blake2s-144" | "blake2s-152" | "blake2s-160" | "blake2s-168" | "blake2s-176" | "blake2s-184" | "blake2s-192" | "blake2s-200" | "blake2s-208" | "blake2s-216" | "blake2s-224" | "blake2s-232" | "blake2s-240" | "blake2s-248" | "blake2s-256" | "skein256-8" | "skein256-16" | "skein256-24" | "skein256-32" | "skein256-40" | "skein256-48" | "skein256-56" | "skein256-64" | "skein256-72" | "skein256-80" | "skein256-88" | "skein256-96" | "skein256-104" | "skein256-112" | "skein256-120" | "skein256-128" | "skein256-136" | "skein256-144" | "skein256-152" | "skein256-160" | "skein256-168" | "skein256-176" | "skein256-184" | "skein256-192" | "skein256-200" | "skein256-208" | "skein256-216" | "skein256-224" | "skein256-232" | "skein256-240" | "skein256-248" | "skein256-256" | "skein512-8" | "skein512-16" | "skein512-24" | "skein512-32" | "skein512-40" | "skein512-48" | "skein512-56" | "skein512-64" | "skein512-72" | "skein512-80" | "skein512-88" | "skein512-96" | "skein512-104" | "skein512-112" | "skein512-120" | "skein512-128" | "skein512-136" | "skein512-144" | "skein512-152" | "skein512-160" | "skein512-168" | "skein512-176" | "skein512-184" | "skein512-192" | "skein512-200" | "skein512-208" | "skein512-216" | "skein512-224" | "skein512-232" | "skein512-240" | "skein512-248" | "skein512-256" | "skein512-264" | "skein512-272" | "skein512-280" | "skein512-288" | "skein512-296" | "skein512-304" | "skein512-312" | "skein512-320" | "skein512-328" | "skein512-336" | "skein512-344" | "skein512-352" | "skein512-360" | "skein512-368" | "skein512-376" | "skein512-384" | "skein512-392" | "skein512-400" | "skein512-408" | "skein512-416" | "skein512-424" | "skein512-432" | "skein512-440" | "skein512-448" | "skein512-456" | "skein512-464" | "skein512-472" | "skein512-480" | "skein512-488" | "skein512-496" | "skein512-504" | "skein512-512" | "skein1024-8" | "skein1024-16" | "skein1024-24" | "skein1024-32" | "skein1024-40" | "skein1024-48" | "skein1024-56" | "skein1024-64" | "skein1024-72" | "skein1024-80" | "skein1024-88" | "skein1024-96" | "skein1024-104" | "skein1024-112" | "skein1024-120" | "skein1024-128" | "skein1024-136" | "skein1024-144" | "skein1024-152" | "skein1024-160" | "skein1024-168" | "skein1024-176" | "skein1024-184" | "skein1024-192" | "skein1024-200" | "skein1024-208" | "skein1024-216" | "skein1024-224" | "skein1024-232" | "skein1024-240" | "skein1024-248" | "skein1024-256" | "skein1024-264" | "skein1024-272" | "skein1024-280" | "skein1024-288" | "skein1024-296" | "skein1024-304" | "skein1024-312" | "skein1024-320" | "skein1024-328" | "skein1024-336" | "skein1024-344" | "skein1024-352" | "skein1024-360" | "skein1024-368" | "skein1024-376" | "skein1024-384" | "skein1024-392" | "skein1024-400" | "skein1024-408" | "skein1024-416" | "skein1024-424" | "skein1024-432" | "skein1024-440" | "skein1024-448" | "skein1024-456" | "skein1024-464" | "skein1024-472" | "skein1024-480" | "skein1024-488" | "skein1024-496" | "skein1024-504" | "skein1024-512" | "skein1024-520" | "skein1024-528" | "skein1024-536" | "skein1024-544" | "skein1024-552" | "skein1024-560" | "skein1024-568" | "skein1024-576" | "skein1024-584" | "skein1024-592" | "skein1024-600" | "skein1024-608" | "skein1024-616" | "skein1024-624" | "skein1024-632" | "skein1024-640" | "skein1024-648" | "skein1024-656" | "skein1024-664" | "skein1024-672" | "skein1024-680" | "skein1024-688" | "skein1024-696" | "skein1024-704" | "skein1024-712" | "skein1024-720" | "skein1024-728" | "skein1024-736" | "skein1024-744" | "skein1024-752" | "skein1024-760" | "skein1024-768" | "skein1024-776" | "skein1024-784" | "skein1024-792" | "skein1024-800" | "skein1024-808" | "skein1024-816" | "skein1024-824" | "skein1024-832" | "skein1024-840" | "skein1024-848" | "skein1024-856" | "skein1024-864" | "skein1024-872" | "skein1024-880" | "skein1024-888" | "skein1024-896" | "skein1024-904" | "skein1024-912" | "skein1024-920" | "skein1024-928" | "skein1024-936" | "skein1024-944" | "skein1024-952" | "skein1024-960" | "skein1024-968" | "skein1024-976" | "skein1024-984" | "skein1024-992" | "skein1024-1000" | "skein1024-1008" | "skein1024-1016" | "skein1024-1024" | "poseidon-bls12_381-a2-fc1" | "poseidon-bls12_381-a2-fc1-sc" } HashName
*/
/**
* Codes for all available hashes
*
* @typedef { 0x00 | 0x11 | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1a | 0x1b | 0x1c | 0x1d | 0x1e | 0x22 | 0x23 | 0x56 | 0xd4 | 0xd5 | 0xd6 | 0x1012 | 0x1052 | 0x1053 | 0x1054 | 0x1055 | 0x1100 | 0x1d01 | 0x534d | 0xb201 | 0xb202 | 0xb203 | 0xb204 | 0xb205 | 0xb206 | 0xb207 | 0xb208 | 0xb209 | 0xb20a | 0xb20b | 0xb20c | 0xb20d | 0xb20e | 0xb20f | 0xb210 | 0xb211 | 0xb212 | 0xb213 | 0xb214 | 0xb215 | 0xb216 | 0xb217 | 0xb218 | 0xb219 | 0xb21a | 0xb21b | 0xb21c | 0xb21d | 0xb21e | 0xb21f | 0xb220 | 0xb221 | 0xb222 | 0xb223 | 0xb224 | 0xb225 | 0xb226 | 0xb227 | 0xb228 | 0xb229 | 0xb22a | 0xb22b | 0xb22c | 0xb22d | 0xb22e | 0xb22f | 0xb230 | 0xb231 | 0xb232 | 0xb233 | 0xb234 | 0xb235 | 0xb236 | 0xb237 | 0xb238 | 0xb239 | 0xb23a | 0xb23b | 0xb23c | 0xb23d | 0xb23e | 0xb23f | 0xb240 | 0xb241 | 0xb242 | 0xb243 | 0xb244 | 0xb245 | 0xb246 | 0xb247 | 0xb248 | 0xb249 | 0xb24a | 0xb24b | 0xb24c | 0xb24d | 0xb24e | 0xb24f | 0xb250 | 0xb251 | 0xb252 | 0xb253 | 0xb254 | 0xb255 | 0xb256 | 0xb257 | 0xb258 | 0xb259 | 0xb25a | 0xb25b | 0xb25c | 0xb25d | 0xb25e | 0xb25f | 0xb260 | 0xb301 | 0xb302 | 0xb303 | 0xb304 | 0xb305 | 0xb306 | 0xb307 | 0xb308 | 0xb309 | 0xb30a | 0xb30b | 0xb30c | 0xb30d | 0xb30e | 0xb30f | 0xb310 | 0xb311 | 0xb312 | 0xb313 | 0xb314 | 0xb315 | 0xb316 | 0xb317 | 0xb318 | 0xb319 | 0xb31a | 0xb31b | 0xb31c | 0xb31d | 0xb31e | 0xb31f | 0xb320 | 0xb321 | 0xb322 | 0xb323 | 0xb324 | 0xb325 | 0xb326 | 0xb327 | 0xb328 | 0xb329 | 0xb32a | 0xb32b | 0xb32c | 0xb32d | 0xb32e | 0xb32f | 0xb330 | 0xb331 | 0xb332 | 0xb333 | 0xb334 | 0xb335 | 0xb336 | 0xb337 | 0xb338 | 0xb339 | 0xb33a | 0xb33b | 0xb33c | 0xb33d | 0xb33e | 0xb33f | 0xb340 | 0xb341 | 0xb342 | 0xb343 | 0xb344 | 0xb345 | 0xb346 | 0xb347 | 0xb348 | 0xb349 | 0xb34a | 0xb34b | 0xb34c | 0xb34d | 0xb34e | 0xb34f | 0xb350 | 0xb351 | 0xb352 | 0xb353 | 0xb354 | 0xb355 | 0xb356 | 0xb357 | 0xb358 | 0xb359 | 0xb35a | 0xb35b | 0xb35c | 0xb35d | 0xb35e | 0xb35f | 0xb360 | 0xb361 | 0xb362 | 0xb363 | 0xb364 | 0xb365 | 0xb366 | 0xb367 | 0xb368 | 0xb369 | 0xb36a | 0xb36b | 0xb36c | 0xb36d | 0xb36e | 0xb36f | 0xb370 | 0xb371 | 0xb372 | 0xb373 | 0xb374 | 0xb375 | 0xb376 | 0xb377 | 0xb378 | 0xb379 | 0xb37a | 0xb37b | 0xb37c | 0xb37d | 0xb37e | 0xb37f | 0xb380 | 0xb381 | 0xb382 | 0xb383 | 0xb384 | 0xb385 | 0xb386 | 0xb387 | 0xb388 | 0xb389 | 0xb38a | 0xb38b | 0xb38c | 0xb38d | 0xb38e | 0xb38f | 0xb390 | 0xb391 | 0xb392 | 0xb393 | 0xb394 | 0xb395 | 0xb396 | 0xb397 | 0xb398 | 0xb399 | 0xb39a | 0xb39b | 0xb39c | 0xb39d | 0xb39e | 0xb39f | 0xb3a0 | 0xb3a1 | 0xb3a2 | 0xb3a3 | 0xb3a4 | 0xb3a5 | 0xb3a6 | 0xb3a7 | 0xb3a8 | 0xb3a9 | 0xb3aa | 0xb3ab | 0xb3ac | 0xb3ad | 0xb3ae | 0xb3af | 0xb3b0 | 0xb3b1 | 0xb3b2 | 0xb3b3 | 0xb3b4 | 0xb3b5 | 0xb3b6 | 0xb3b7 | 0xb3b8 | 0xb3b9 | 0xb3ba | 0xb3bb | 0xb3bc | 0xb3bd | 0xb3be | 0xb3bf | 0xb3c0 | 0xb3c1 | 0xb3c2 | 0xb3c3 | 0xb3c4 | 0xb3c5 | 0xb3c6 | 0xb3c7 | 0xb3c8 | 0xb3c9 | 0xb3ca | 0xb3cb | 0xb3cc | 0xb3cd | 0xb3ce | 0xb3cf | 0xb3d0 | 0xb3d1 | 0xb3d2 | 0xb3d3 | 0xb3d4 | 0xb3d5 | 0xb3d6 | 0xb3d7 | 0xb3d8 | 0xb3d9 | 0xb3da | 0xb3db | 0xb3dc | 0xb3dd | 0xb3de | 0xb3df | 0xb3e0 | 0xb401 | 0xb402 } HashCode
*/

/**
* @type { Object<HashName,HashCode> }
*/
const names = Object.freeze({
'identity': 0x00,
'sha1': 0x11,
Expand Down Expand Up @@ -29,6 +43,7 @@ const names = Object.freeze({
'ripemd-256': 0x1054,
'ripemd-320': 0x1055,
'x11': 0x1100,
'kangarootwelve': 0x1d01,
'sm3-256': 0x534d,
'blake2b-8': 0xb201,
'blake2b-16': 0xb202,
Expand Down
72 changes: 45 additions & 27 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @ts-check
/* eslint-disable guard-for-in */
/**
* Multihash implementation in JavaScript.
*
Expand All @@ -14,21 +12,20 @@ const uint8ArrayToString = require('uint8arrays/to-string')
const uint8ArrayFromString = require('uint8arrays/from-string')
const uint8ArrayConcat = require('uint8arrays/concat')

const codes = {}
const codes = /** @type {import('./types').CodeNameMap} */({})

// eslint-disable-next-line guard-for-in
for (const key in names) {
codes[names[key]] = key
}
exports.names = names
exports.codes = Object.freeze(codes)

/**
* Convert the given multihash to a hex encoded string.
*
* @param {Uint8Array} hash
* @returns {string}
*/
exports.toHexString = function toHexString (hash) {
function toHexString (hash) {
if (!(hash instanceof Uint8Array)) {
throw new Error('must be passed a Uint8Array')
}
Expand All @@ -42,7 +39,7 @@ exports.toHexString = function toHexString (hash) {
* @param {string} hash
* @returns {Uint8Array}
*/
exports.fromHexString = function fromHexString (hash) {
function fromHexString (hash) {
return uint8ArrayFromString(hash, 'base16')
}

Expand All @@ -52,7 +49,7 @@ exports.fromHexString = function fromHexString (hash) {
* @param {Uint8Array} hash
* @returns {string}
*/
exports.toB58String = function toB58String (hash) {
function toB58String (hash) {
if (!(hash instanceof Uint8Array)) {
throw new Error('must be passed a Uint8Array')
}
Expand All @@ -66,7 +63,7 @@ exports.toB58String = function toB58String (hash) {
* @param {string|Uint8Array} hash
* @returns {Uint8Array}
*/
exports.fromB58String = function fromB58String (hash) {
function fromB58String (hash) {
const encoded = hash instanceof Uint8Array
? uint8ArrayToString(hash)
: hash
Expand All @@ -78,9 +75,9 @@ exports.fromB58String = function fromB58String (hash) {
* Decode a hash from the given multihash.
*
* @param {Uint8Array} bytes
* @returns {{code: number, name: string, length: number, digest: Uint8Array}} result
* @returns {{code: HashCode, name: HashName, length: number, digest: Uint8Array}} result
*/
exports.decode = function decode (bytes) {
function decode (bytes) {
if (!(bytes instanceof Uint8Array)) {
throw new Error('multihash must be a Uint8Array')
}
Expand All @@ -90,7 +87,7 @@ exports.decode = function decode (bytes) {
}

const code = varint.decode(bytes)
if (!exports.isValidCode(code)) {
if (!isValidCode(code)) {
throw new Error(`multihash unknown function code: 0x${code.toString(16)}`)
}
bytes = bytes.slice(varint.decode.bytes)
Expand All @@ -114,22 +111,22 @@ exports.decode = function decode (bytes) {
}

/**
* Encode a hash digest along with the specified function code.
* Encode a hash digest along with the specified function code.
*
* > **Note:** the length is derived from the length of the digest itself.
*
* @param {Uint8Array} digest
* @param {string|number} code
* @param {HashName | HashCode} code
* @param {number} [length]
* @returns {Uint8Array}
*/
exports.encode = function encode (digest, code, length) {
function encode (digest, code, length) {
if (!digest || code === undefined) {
throw new Error('multihash encode requires at least two args: digest, code')
}

// ensure it's a hashfunction code.
const hashfn = exports.coerceCode(code)
const hashfn = coerceCode(code)

if (!(digest instanceof Uint8Array)) {
throw new Error('digest should be a Uint8Array')
Expand All @@ -151,10 +148,11 @@ exports.encode = function encode (digest, code, length) {
/**
* Converts a hash function name into the matching code.
* If passed a number it will return the number if it's a valid code.
* @param {string|number} name
*
* @param {HashName | number} name
* @returns {number}
*/
exports.coerceCode = function coerceCode (name) {
function coerceCode (name) {
let code = name

if (typeof name === 'string') {
Expand All @@ -168,31 +166,31 @@ exports.coerceCode = function coerceCode (name) {
throw new Error(`Hash function code should be a number. Got: ${code}`)
}

if (codes[code] === undefined && !exports.isAppCode(code)) {
if (codes[code] === undefined && !isAppCode(code)) {
throw new Error(`Unrecognized function code: ${code}`)
}

return code
}

/**
* Checks wether a code is part of the app range
* Checks if a code is part of the app range
*
* @param {number} code
* @returns {boolean}
*/
exports.isAppCode = function appCode (code) {
function isAppCode (code) {
return code > 0 && code < 0x10
}

/**
* Checks whether a multihash code is valid.
*
* @param {number} code
* @param {HashCode} code
* @returns {boolean}
*/
exports.isValidCode = function validCode (code) {
if (exports.isAppCode(code)) {
function isValidCode (code) {
if (isAppCode(code)) {
return true
}

Expand All @@ -211,9 +209,8 @@ exports.isValidCode = function validCode (code) {
* @throws {Error}
*/
function validate (multihash) {
exports.decode(multihash) // throws if bad.
decode(multihash) // throws if bad.
}
exports.validate = validate

/**
* Returns a prefix from a valid multihash. Throws an error if it is not valid.
Expand All @@ -222,8 +219,29 @@ exports.validate = validate
* @returns {Uint8Array}
* @throws {Error}
*/
exports.prefix = function prefix (multihash) {
function prefix (multihash) {
validate(multihash)

return multihash.subarray(0, 2)
}

module.exports = {
names,
codes: Object.freeze(codes),
toHexString,
fromHexString,
toB58String,
fromB58String,
decode,
encode,
coerceCode,
isAppCode,
validate,
prefix,
isValidCode
}

/**
* @typedef { import("./constants").HashCode } HashCode
* @typedef { import("./constants").HashName } HashName
*/
4 changes: 4 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { HashCode, HashName } from './constants.js'

export type CodeNameMap = Record<HashCode, HashName>
export type NameCodeMap = Record<HashName, HashCode>

0 comments on commit 5a1e7d7

Please sign in to comment.