Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

feat: add typeScript support #3236

Merged
merged 21 commits into from
Sep 3, 2020
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions docs/core-api/FILES.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ One of `path` or `content` _must_ be passed.
`FileContent` is one of the following types:

```js
Uint8Array | Blob | String | Iterable<Uint8Array|Number> | AsyncIterable<Uint8Array> | ReadableStream<Uint8Array>
Uint8Array | Blob | String | Iterable<Uint8Array> | Iterable<number> | AsyncIterable<Uint8Array> | ReadableStream<Uint8Array>
```

`UnixTime` is one of the following types:
Expand All @@ -162,7 +162,7 @@ An optional object which may have the following keys:

| Name | Type | Default | Description |
| ---- | ---- | ------- | ----------- |
| chunker | `String` | `'size-262144` | chunking algorithm used to build ipfs DAGs |
| chunker | `String` | `'size-262144'` | chunking algorithm used to build ipfs DAGs |
| cidVersion | `Number` | `0` | the CID version to use when storing the data |
| hashAlg | `String` | `'sha2-256'` | multihash hashing algorithm to use |
| onlyHash | `boolean` | `false` | If true, will not add blocks to the blockstore |
Expand All @@ -178,7 +178,7 @@ An optional object which may have the following keys:

| Type | Description |
| -------- | -------- |
| `UnixFSEntry` | A object describing the added data |
| `Promise<UnixFSEntry>` | A object describing the added data |

Each yielded object is of the form:

Expand Down Expand Up @@ -226,7 +226,7 @@ Now [ipfs.io/ipfs/Qm..pg/myfile.txt](https://ipfs.io/ipfs/QmWXdjNC362aPDtwHPUE9o

| Name | Type | Description |
| ---- | ---- | ----------- |
| source | [FileStream<FileContent|FileObject>](#filestream) | Data to import (see below) |
| source | [FileStream<FileContent\|FileObject>](#filestream) | Data to import (see below) |

##### FileStream

Expand All @@ -242,7 +242,7 @@ An optional object which may have the following keys:

| Name | Type | Default | Description |
| ---- | ---- | ------- | ----------- |
| chunker | `String` | `'size-262144` | chunking algorithm used to build ipfs DAGs |
| chunker | `String` | `'size-262144'` | chunking algorithm used to build ipfs DAGs |
| cidVersion | `Number` | `0` | the CID version to use when storing the data |
| enableShardingExperiment | `boolean` | `false` | allows to create directories with an unlimited number of entries currently size of unixfs directories is limited by the maximum block size. Note that this is an experimental feature |
| hashAlg | `String` | `'sha2-256'` | multihash hashing algorithm to use |
Expand Down
2 changes: 1 addition & 1 deletion docs/core-api/REPO.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ An optional object which may have the following keys:

| Name | Type | Default | Description |
| ---- | ---- | ------- | ----------- |
| options | `boolean` | `false` | Return storage numbers in `MiB` |
| human | `boolean` | `false` | Return storage numbers in `MiB` |
| timeout | `Number` | `undefined` | A timeout in ms |
| signal | [AbortSignal][] | `undefined` | Can be used to cancel any long running requests started as a result of this call |

Expand Down
3 changes: 2 additions & 1 deletion packages/ipfs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@
"tcme <hi@this-connect.me>",
"victorbjelkholm <victorbjelkholm@gmail.com>",
"Łukasz Magiera <magik6k@users.noreply.github.com>",
"Максим Ильин <negamaxi@gmail.com>"
"Максим Ильин <negamaxi@gmail.com>",
"Xmader <xmader@outlook.com>"
]
}
24 changes: 22 additions & 2 deletions packages/ipfs/src/core/api-manager.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
'use strict'

module.exports = class ApiManager {
/**
* @callback UndefFn
* @param {PropertyKey} prop
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why to note add @return type here and do it on line 18 instead ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eslint valid-jsdoc requires an @return on line 18, and the default return type for @callback definition is any

*/

/**
* @template API
* @typedef {{ cancel(): any; api: API; }} Updated
*/

constructor () {
this._api = {}
/**
* @type {UndefFn}
* @returns {any}
*/
this._onUndef = () => undefined
this.api = new Proxy(this._api, {
get: (_, prop) => {
Expand All @@ -12,12 +26,18 @@ module.exports = class ApiManager {
})
}

/**
* @template A
* @param {A} nextApi
* @param {UndefFn} [onUndef]
* @returns {Updated<A>}
*/
update (nextApi, onUndef) {
const prevApi = { ...this._api }
const prevUndef = this._onUndef
Object.keys(this._api).forEach(k => { delete this._api[k] })
Object.assign(this._api, nextApi)
const api = Object.assign(this._api, nextApi)
if (onUndef) this._onUndef = onUndef
return { cancel: () => this.update(prevApi, prevUndef), api: this.api }
return { cancel: () => this.update(prevApi, prevUndef), api }
}
}
59 changes: 56 additions & 3 deletions packages/ipfs/src/core/components/add-all/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,64 @@
const importer = require('ipfs-unixfs-importer')
const normaliseAddInput = require('ipfs-core-utils/src/files/normalise-input')
const { parseChunkerString } = require('./utils')
const pipe = require('it-pipe')
const { pipe } = require('it-pipe')
const { withTimeoutOption } = require('../../utils')

/**
* @typedef {Uint8Array | Blob | String | Iterable<Uint8Array> | Iterable<number> | AsyncIterable<Uint8Array> | ReadableStream<Uint8Array>} FileContent
*
* @typedef {object} FileObject
* - If no path is specified, then the item will be added to the root level and will be given a name according to it's CID.
* - If no content is passed, then the item is treated as an empty directory.
* - One of path or content must be passed.
* @property {string} [path] - The path you want to the file to be accessible at from the root CID _after_ it has been added
* @property {FileContent} [content] - The contents of the file
* @property {number | string} [mode] - File mode to store the entry with (see https://en.wikipedia.org/wiki/File_system_permissions#Numeric_notation)
* @property {UnixTime} [mtime] - The modification time of the entry
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 If you want to be more precise (not asking you to, I have taken same shortcuts myself) FileObject would be:

type FileObject =
  | { path: string, mode?: Mode, mtime?: UnixTime } // Directory
  | { path?: string, content: FileContent, mtime?: UnixTime } // File

That is to say it must have path or a content or both.

*
* @typedef {FileContent | FileObject} Source
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 I think it would be better to call this something like FileSource or FileImport so it's little bit more meaningful out of context.

* @typedef {Iterable<Source> | AsyncIterable<Source> | ReadableStream<Source>} FileStream
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@achingbrain now that I'm looking at it, I find FileStream to be misleading, as I expect stream of representing file contents not the stream of files. Can we rename to ImportStream or something along those lines instead ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I'm all for making it more straightforward.

Input streams are largely called source throughout the codebase, though I see Source here is being used for the stream contents?

*
* @typedef {Date | UnixTimeObj | [number, number]} UnixTime - As an array of numbers, it must have two elements, as per the output of [`process.hrtime()`](https://nodejs.org/dist/latest/docs/api/process.html#process_process_hrtime_time).
*
* @typedef {object} UnixTimeObj
* @property {number} secs - the number of seconds since (positive) or before (negative) the Unix Epoch began
* @property {number} [nsecs] - the number of nanoseconds since the last full second.
*
* @typedef {object} UnixFSEntry
* @property {string} path
* @property {import('cids')} cid
* @property {number} mode
* @property {UnixTimeObj} mtime
* @property {number} size
*/

module.exports = ({ block, gcLock, preload, pin, options: constructorOptions }) => {
const isShardingEnabled = constructorOptions.EXPERIMENTAL && constructorOptions.EXPERIMENTAL.sharding

return withTimeoutOption(async function * addAll (source, options) {
/**
* Import multiple files and data into IPFS.
*
* @param {FileStream} source
*
* @param {object} [options]
* @param {string} [options.chunker] - chunking algorithm used to build ipfs DAGs (default: `'size-262144'`)
* @param {Number} [options.cidVersion] - the CID version to use when storing the data (default: `0`)
* @param {boolean} [options.enableShardingExperiment] - allows to create directories with an unlimited number of entries currently size of unixfs directories is limited by the maximum block size. Note that this is an experimental feature (default: `false`)
* @param {String} [options.hashAlg] - multihash hashing algorithm to use (default: `'sha2-256'`)
* @param {boolean} [options.onlyHash] - If true, will not add blocks to the blockstore (default: `false`)
* @param {boolean} [options.pin] - pin this object when adding (default: `true`)
* @param {function} [options.progress] - a function that will be called with the byte length of chunks as a file is added to ipfs (default: `undefined`)
* @param {boolean} [options.rawLeaves] - if true, DAG leaves will contain raw file data and not be wrapped in a protobuf (default: `false`)
* @param {Number} [options.shardSplitThreshold] - Directories with more than this number of files will be created as HAMT-sharded directories (default: `1000`)
* @param {boolean} [options.trickle] - if true will use the [trickle DAG](https://godoc.org/github.com/ipsn/go-ipfs/gxlibs/github.com/ipfs/go-unixfs/importer/trickle) format for DAG generation (default: `false`)
* @param {boolean} [options.wrapWithDirectory] - Adds a wrapping node around the content (default: `false`)
* @param {Number} [options.timeout] - A timeout in ms (default: `undefined`)
* @param {AbortSignal} [options.signal] - Can be used to cancel any long running requests started as a result of this call (default: `undefined`)

* @returns {AsyncIterable<UnixFSEntry>}
*/
async function * addAll (source, options) {
options = options || {}

const opts = {
Expand Down Expand Up @@ -58,7 +109,9 @@ module.exports = ({ block, gcLock, preload, pin, options: constructorOptions })
} finally {
releaseLock()
}
})
}

return withTimeoutOption(addAll)
}

function transformFile (opts) {
Expand Down
28 changes: 27 additions & 1 deletion packages/ipfs/src/core/components/add.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,34 @@

const last = require('it-last')

/**
* @typedef {import('./add-all').Source} Source
* @typedef {import('./add-all').UnixFSEntry} UnixFSEntry
*/

module.exports = ({ addAll }) => {
return async function add (source, options) { // eslint-disable-line require-await
/**
* Import a file or data into IPFS.
*
* @param {Source} source - Data to import
*
* @param {object} [options]
* @param {String} [options.chunker] - chunking algorithm used to build ipfs DAGs (default: `'size-262144'`)
* @param {Number} [options.cidVersion] - the CID version to use when storing the data (default: `0`)
* @param {String} [options.hashAlg] - multihash hashing algorithm to use (default: `'sha2-256'`)
* @param {boolean} [options.onlyHash] - If true, will not add blocks to the blockstore (default: `false`)
* @param {boolean} [options.pin] - pin this object when adding (default: `true`)
* @param {function} [options.progress] - a function that will be called with the byte length of chunks as a file is added to ipfs (default: `undefined`)
* @param {boolean} [options.rawLeaves] - if true, DAG leaves will contain raw file data and not be wrapped in a protobuf (default: `false`)
* @param {boolean} [options.trickle] - if true will use the [trickle DAG](https://godoc.org/github.com/ipsn/go-ipfs/gxlibs/github.com/ipfs/go-unixfs/importer/trickle) format for DAG generation (default: `false`)
* @param {boolean} [options.wrapWithDirectory] - Adds a wrapping node around the content (default: `false`)
* @param {Number} [options.timeout] - A timeout in ms (default: `undefined`)
* @param {AbortSignal} [options.signal] - Can be used to cancel any long running requests started as a result of this call (default: `undefined`)
*
* @returns {Promise<UnixFSEntry>}
*/
async function add (source, options) { // eslint-disable-line require-await
return last(addAll(source, options))
}
return add
}
30 changes: 27 additions & 3 deletions packages/ipfs/src/core/components/bitswap/stat.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,33 @@
'use strict'

const Big = require('bignumber.js')
const Big = require('bignumber.js').default
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change necessary ? From their website this is how they suggest to import

const BigNumber = require('bignumber.js');

So I would much rather keep it as it was, unless absolutely necessary. Otherwise it's fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make the typings work, the export signature in its .d.ts file

export default BigNumber;
export declare class BigNumber ...

is either require('bignumber.js').default or require('bignumber.js').BigNumber in CommonJS

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think when namespace and class name do collide in definitions TS does know to not require default, but I could be wrong and it might be behind some config flag. I think I'd still prefer const { BigNumber: Big } = require('bignumber.js') over current version, but I'm ok with current version too.

const CID = require('cids')
const { withTimeoutOption } = require('../../utils')

/**
* @typedef {object} BitswapStats - An object that contains information about the bitswap agent
* @property {number} provideBufLen - an integer
* @property {import('cids')[]} wantlist
* @property {string[]} peers - array of peer IDs as Strings
* @property {Big} blocksReceived
* @property {Big} dataReceived
* @property {Big} blocksSent
* @property {Big} dataSent
* @property {Big} dupBlksReceived
* @property {Big} dupDataReceived
*/

module.exports = ({ bitswap }) => {
return withTimeoutOption(async function stat () { // eslint-disable-line require-await
/**
* Show diagnostic information on the bitswap agent.
*
* @param {object} [options]
* @param {Number} [options.timeout] - A timeout in ms (default: `undefined`)
* @param {AbortSignal} [options.signal] - Can be used to cancel any long running requests started as a result of this call (default: `undefined`)
*
* @returns {Promise<BitswapStats>}
*/
async function stat (options) { // eslint-disable-line require-await, @typescript-eslint/no-unused-vars
const snapshot = bitswap.stat().snapshot

return {
Expand All @@ -19,5 +41,7 @@ module.exports = ({ bitswap }) => {
blocksSent: new Big(snapshot.blocksSent),
dataSent: new Big(snapshot.dataSent)
}
})
}

return withTimeoutOption(stat)
}
28 changes: 22 additions & 6 deletions packages/ipfs/src/core/components/bitswap/unwant.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,33 @@ const errCode = require('err-code')
const { withTimeoutOption } = require('../../utils')

module.exports = ({ bitswap }) => {
return withTimeoutOption(async function unwant (keys, options) { // eslint-disable-line require-await
if (!Array.isArray(keys)) {
keys = [keys]
/**
* @typedef {import('cids')} CID
*/

/**
* Removes one or more CIDs from the wantlist
*
* @param {CID | CID[]} cids - The CIDs to remove from the wantlist
* @param {object} [options]
* @param {Number} [options.timeout] - A timeout in ms (default: `undefined`)
* @param {AbortSignal} [options.signal] - Can be used to cancel any long running requests started as a result of this call (default: `undefined`)
*
* @returns {Promise<void>} - A promise that resolves once the request is complete
*/
async function unwant (cids, options) { // eslint-disable-line require-await
if (!Array.isArray(cids)) {
cids = [cids]
}

try {
keys = keys.map((key) => new CID(key))
cids = cids.map((cid) => new CID(cid))
} catch (err) {
throw errCode(err, 'ERR_INVALID_CID')
}

return bitswap.unwant(keys, options)
})
return bitswap.unwant(cids, options)
}

return withTimeoutOption(unwant)
}
21 changes: 19 additions & 2 deletions packages/ipfs/src/core/components/bitswap/wantlist-for-peer.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,26 @@ const PeerId = require('peer-id')
const { withTimeoutOption } = require('../../utils')

module.exports = ({ bitswap }) => {
return withTimeoutOption(async function wantlistForPeer (peerId, options = {}) { // eslint-disable-line require-await
/**
* @typedef {import('cids')} CID
* @typedef {import('peer-id')} PeerId
*/

/**
* Returns the wantlist for a connected peer
*
* @param {PeerId | CID | string | Buffer} peerId - A peer ID to return the wantlist for
* @param {object} [options]
* @param {Number} [options.timeout] - A timeout in ms (default: `undefined`)
* @param {AbortSignal} [options.signal] - Can be used to cancel any long running requests started as a result of this call (default: `undefined`)
*
* @returns {Promise<CID[]>} - An array of CIDs currently in the wantlist
*/
async function wantlistForPeer (peerId, options = {}) { // eslint-disable-line require-await
const list = bitswap.wantlistForPeer(PeerId.createFromCID(peerId), options)

return Array.from(list).map(e => e[1].cid)
})
}

return withTimeoutOption(wantlistForPeer)
}
19 changes: 17 additions & 2 deletions packages/ipfs/src/core/components/bitswap/wantlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,24 @@
const { withTimeoutOption } = require('../../utils')

module.exports = ({ bitswap }) => {
return withTimeoutOption(async function wantlist (options = {}) { // eslint-disable-line require-await
/**
* @typedef {import('cids')} CID
*/

/**
* Returns the wantlist for your node
*
* @param {object} [options]
* @param {Number} [options.timeout] - A timeout in ms (default: `undefined`)
* @param {AbortSignal} [options.signal] - Can be used to cancel any long running requests started as a result of this call (default: `undefined`)
*
* @returns {Promise<CID[]>} - An array of CIDs currently in the wantlist
*/
async function wantlist (options = {}) { // eslint-disable-line require-await
const list = bitswap.getWantlist(options)

return Array.from(list).map(e => e[1].cid)
})
}

return withTimeoutOption(wantlist)
}
22 changes: 20 additions & 2 deletions packages/ipfs/src/core/components/block/get.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,23 @@ const { cleanCid } = require('./utils')
const { withTimeoutOption } = require('../../utils')

module.exports = ({ blockService, preload }) => {
return withTimeoutOption(async function get (cid, options) { // eslint-disable-line require-await
/**
* @typedef {import('cids')} CID
* @typedef {import('ipld-block')} Block
*/

/**
* Get a raw IPFS block.
*
* @param {CID | string | Buffer} cid - A CID that corresponds to the desired block
* @param {object} [options]
* @param {boolean} [options.preload] - (default: `true`)
* @param {Number} [options.timeout] - A timeout in ms (default: `undefined`)
* @param {AbortSignal} [options.signal] - Can be used to cancel any long running requests started as a result of this call (default: `undefined`)
*
* @returns {Promise<Block>} - A Block type object, containing both the data and the hash of the block
*/
async function get (cid, options) { // eslint-disable-line require-await
options = options || {}
cid = cleanCid(cid)

Expand All @@ -13,5 +29,7 @@ module.exports = ({ blockService, preload }) => {
}

return blockService.get(cid, options)
})
}

return withTimeoutOption(get)
}
Loading