Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: rewrite in typescript #128

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 3 additions & 3 deletions .aegir.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import EchoServer from 'aegir/echo-server'
* @typedef {object} BeforeType
* @property {import('ipfsd-ctl').Controller} server
* @property {EchoServer} echoServer
* @property {typeof import('./test/utils/mock-pinning-service.js')} pinningService
* @property {typeof import('./dist/test/utils/mock-pinning-service.js')} pinningService
* @property {Record<string, string>} env
*/
/** @type {import('aegir').PartialOptions} */
Expand All @@ -21,13 +21,13 @@ export default {
* @returns {Promise<BeforeType>}
*/
async before (options) {
const { PinningService } = await import('./test/utils/mock-pinning-service.js')
const { PinningService } = await import('./dist/test/utils/mock-pinning-service.js')
const pinningService = await PinningService.start()
const server = createServer({
port: 0
}, {
type: 'go',
kuboRpcModule: await import('./src/index.js'),
kuboRpcModule: await import('./dist/src/index.js'),
ipfsBin: (await import('go-ipfs')).default.path()
})

Expand Down
20 changes: 2 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,6 @@
},
"type": "module",
"types": "./dist/src/index.d.ts",
"typesVersions": {
"*": {
"*": [
"*",
"dist/*",
"dist/src/*",
"dist/src/*/index"
],
"src/*": [
"*",
"dist/*",
"dist/src/*",
"dist/src/*/index"
]
}
},
"files": [
"src",
"dist",
Expand All @@ -50,8 +34,8 @@
"exports": {
".": {
"types": "./dist/src/index.d.ts",
"import": "./src/index.js",
"require": "./dist/src/index.js"
"require": "./dist/src/index.js",
"import": "./dist/src/index.js"
}
},
"eslintConfig": {
Expand Down
63 changes: 24 additions & 39 deletions src/add-all.js → src/add-all.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
import { CID } from 'multiformats/cid'
import { objectToCamel } from './lib/object-to-camel.js'
import { configure } from './lib/configure.js'
import { multipartRequest } from 'ipfs-core-utils/multipart-request'
import { toUrlSearchParams } from './lib/to-url-search-params.js'
import { abortSignal } from './lib/abort-signal.js'
import type { AddAllOptions, AddProgressFn, AddResult } from './root.js'
import type { Client } from './lib/core.js'
import type { ImportCandidateStream, IPFSUtilsHttpUploadProgressFn } from './index.js'

export const createAddAll = configure((api) => {
/**
* @type {import('./types.js').RootAPI["addAll"]}
*/
async function * addAll (source, options = {}) {
export function createAddAll (client: Client) {
async function * addAll (source: ImportCandidateStream, options?: AddAllOptions): AsyncIterable<AddResult> {
// allow aborting requests on body errors
const controller = new AbortController()
const signal = abortSignal(controller.signal, options.signal)
const signal = abortSignal(controller.signal, options?.signal)
const { headers, body, total, parts } =
await multipartRequest(source, controller, options.headers)
await multipartRequest(source, controller, options?.headers)

// In browser response body only starts streaming once upload is
// complete, at which point all the progress updates are invalid. If
// length of the content is computable we can interpret progress from
// `{ total, loaded}` passed to `onUploadProgress` and `multipart.total`
// in which case we disable progress updates to be written out.
const [progressFn, onUploadProgress] = typeof options.progress === 'function'
const [progressFn, onUploadProgress] = typeof options?.progress === 'function'
? createProgressHandler(total, parts, options.progress)
: [undefined, undefined]

const res = await api.post('add', {
const res = await client.post('add', {
searchParams: toUrlSearchParams({
'stream-channels': true,
...options,
Expand All @@ -42,36 +41,32 @@

if (file.hash !== undefined) {
yield toCoreInterface(file)
} else if (progressFn) {
progressFn(file.bytes || 0, file.name)
} else if (progressFn != null) {
progressFn(file.bytes ?? 0, file.name)
}
}
}
return addAll
})
}

interface ProgressPart {
name: string
start: number
end: number
}

/**
* Returns simple progress callback when content length isn't computable or a
* progress event handler that calculates progress from upload progress events.
*
* @param {number} total
* @param {{name:string, start:number, end:number}[]|null} parts
* @param {import('./types.js').IPFSCoreAddProgressFn} progress
* @returns {[import('./types.js').IPFSCoreAddProgressFn|undefined, import('./types.js').IPFSUtilsHttpUploadProgressFn|undefined]}
*/
const createProgressHandler = (total, parts, progress) =>
parts ? [undefined, createOnUploadProgress(total, parts, progress)] : [progress, undefined]
const createProgressHandler = (total: number, parts: ProgressPart[]|null, progress: AddProgressFn): [AddProgressFn|undefined, IPFSUtilsHttpUploadProgressFn|undefined] =>
parts != null ? [undefined, createOnUploadProgress(total, parts, progress)] : [progress, undefined]

/**
* Creates a progress handler that interpolates progress from upload progress
* events and total size of the content that is added.
*
* @param {number} size - actual content size
* @param {{name:string, start:number, end:number}[]} parts
* @param {import('./types.js').IPFSCoreAddProgressFn} progress
* @returns {import('./types.js').IPFSUtilsHttpUploadProgressFn}
*/
const createOnUploadProgress = (size, parts, progress) => {
const createOnUploadProgress = (size: number, parts: ProgressPart[], progress: AddProgressFn): IPFSUtilsHttpUploadProgressFn => {
let index = 0
const count = parts.length
return ({ loaded, total }) => {
Expand All @@ -93,18 +88,8 @@
}
}

/**
* @param {object} input
* @param {string} input.name
* @param {string} input.hash
* @param {string} input.size
* @param {string} [input.mode]
* @param {number} [input.mtime]
* @param {number} [input.mtimeNsecs]
*/
function toCoreInterface ({ name, hash, size, mode, mtime, mtimeNsecs }) {
/** @type {import('./types.js').AddResult} */
const output = {
function toCoreInterface ({ name, hash, size, mode, mtime, mtimeNsecs }: any) {
const output: AddResult = {
path: name,
cid: CID.parse(hash),
size: parseInt(size)
Expand All @@ -117,7 +102,7 @@
if (mtime != null) {
output.mtime = {
secs: mtime,
nsecs: mtimeNsecs || 0
nsecs: mtimeNsecs ?? 0

Check warning on line 105 in src/add-all.ts

View check run for this annotation

Codecov / codecov/patch

src/add-all.ts#L105

Added line #L105 was not covered by tests
}
}

Expand Down
24 changes: 0 additions & 24 deletions src/add.js

This file was deleted.

18 changes: 18 additions & 0 deletions src/add.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import last from 'it-last'
import { normaliseInput } from 'ipfs-core-utils/files/normalise-input-single'
import { createAddAll } from './add-all.js'
import type { Client } from './lib/core.js'
import type { AddOptions, AddResult } from './root.js'
import type { ImportCandidate } from './index.js'

export function createAdd (client: Client) {
const all = createAddAll(client)
async function add (input: ImportCandidate, options?: AddOptions): Promise<AddResult> {
const source = normaliseInput(input)
// @ts-expect-error - all may return undefined if source is empty
const addAllPromise = all(source, options)
// @ts-expect-error - last may return undefined if source is empty
return await last(addAllPromise)
}
return add
}
17 changes: 0 additions & 17 deletions src/bitswap/index.js

This file was deleted.

56 changes: 56 additions & 0 deletions src/bitswap/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { createWantlist } from './wantlist.js'
import { createStat } from './stat.js'
import type { PeerId } from '@libp2p/interface-peer-id'
import type { CID } from 'multiformats'
import type { Client } from '../lib/core.js'
import type { ClientOptions } from '../index.js'

export function createBitswap (client: Client): BitswapAPI {
// TODO: https://github.com/ipfs/js-kubo-rpc-client/issues/99
return {
wantlist: createWantlist(client),
stat: createStat(client)
}
}

export interface WantlistOptions extends ClientOptions {
peer: PeerId
}

export interface BitswapAPI {
/**
* Returns the wantlist for your node
*
* @example
* ```js
* const list = await ipfs.bitswap.wantlist()
* console.log(list)
* // [ CID('QmHash') ]
* ```
*/
wantlist: (options?: WantlistOptions) => Promise<CID[]>

/**
* Show diagnostic information on the bitswap agent.
* Note: `bitswap.stat` and `stats.bitswap` can be used interchangeably.
*
* @example
* ```js
* const stats = await ipfs.bitswap.stat()
* console.log(stats)
* ```
*/
stat: (options?: ClientOptions) => Promise<Stats>
}

export interface Stats {
provideBufLen: number
wantlist: CID[]
peers: PeerId[]
blocksReceived: bigint
dataReceived: bigint
blocksSent: bigint
dataSent: bigint
dupBlksReceived: bigint
dupDataReceived: bigint
}
29 changes: 13 additions & 16 deletions src/bitswap/stat.js → src/bitswap/stat.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,29 @@
import { CID } from 'multiformats/cid'
import { configure } from '../lib/configure.js'
import { toUrlSearchParams } from '../lib/to-url-search-params.js'
import { peerIdFromString } from '@libp2p/peer-id'
import type { Stats } from './index.js'
import type { Client } from '../lib/core.js'
import type { ClientOptions } from '../index.js'

export const createStat = configure(api => {
/**
* @type {import('../types').BitswapAPI["stat"]}
*/
async function stat (options = {}) {
const res = await api.post('bitswap/stat', {
export function createStat (client: Client) {
async function stat (options?: ClientOptions): Promise<Stats> {
const res = await client.post('bitswap/stat', {
searchParams: toUrlSearchParams(options),
signal: options.signal,
headers: options.headers
signal: options?.signal,
headers: options?.headers
})

return toCoreInterface(await res.json())
}

return stat
})
}

/**
* @param {any} res
*/
function toCoreInterface (res) {
function toCoreInterface (res: any): Stats {
return {
provideBufLen: res.ProvideBufLen,
wantlist: (res.Wantlist || []).map((/** @type {{ '/': string }} */ k) => CID.parse(k['/'])),
peers: (res.Peers || []).map((/** @type {string} */ str) => peerIdFromString(str)),
wantlist: (res.Wantlist ?? []).map((k: Record<string, any>) => CID.parse(k['/'])),
peers: (res.Peers ?? []).map((str: string) => peerIdFromString(str)),
blocksReceived: BigInt(res.BlocksReceived),
dataReceived: BigInt(res.DataReceived),
blocksSent: BigInt(res.BlocksSent),
Expand Down
22 changes: 0 additions & 22 deletions src/bitswap/wantlist-for-peer.js

This file was deleted.

19 changes: 0 additions & 19 deletions src/bitswap/wantlist.js

This file was deleted.

Loading
Loading