This repository has been archived by the owner on Feb 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: do not accept single items for ipfs.add (#3900)
The types allow passing single items to `ipfs.addAll` and multiple items to `ipfs.add`. Instead, only accept single items to `ipfs.add` and streams of item to `ipfs.addAll` and fail with a more helpful error message if you do not do this. BREAKING CHANGE: errors will now be thrown if multiple items are passed to `ipfs.add` or single items to `ipfs.addAll` (n.b. you can still pass a list of a single item to `ipfs.addAll`)
- Loading branch information
1 parent
5ddd0c5
commit 04e3cf3
Showing
36 changed files
with
688 additions
and
146 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 111 additions & 0 deletions
111
packages/ipfs-core-utils/src/files/normalise-candidate-single.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import errCode from 'err-code' | ||
import browserStreamToIt from 'browser-readablestream-to-it' | ||
import itPeekable from 'it-peekable' | ||
import { | ||
isBytes, | ||
isBlob, | ||
isReadableStream, | ||
isFileObject | ||
} from './utils.js' | ||
import { | ||
parseMtime, | ||
parseMode | ||
} from 'ipfs-unixfs' | ||
|
||
/** | ||
* @typedef {import('ipfs-core-types/src/utils').ToContent} ToContent | ||
* @typedef {import('ipfs-unixfs-importer').ImportCandidate} ImporterImportCandidate | ||
* @typedef {import('ipfs-core-types/src/utils').ImportCandidate} ImportCandidate | ||
* @typedef {import('ipfs-core-types/src/utils').ImportCandidateStream} ImportCandidateStream | ||
*/ | ||
|
||
/** | ||
* @param {ImportCandidate} input | ||
* @param {(content:ToContent) => Promise<AsyncIterable<Uint8Array>>} normaliseContent | ||
*/ | ||
// eslint-disable-next-line complexity | ||
export async function * normaliseCandidateSingle (input, normaliseContent) { | ||
if (input === null || input === undefined) { | ||
throw errCode(new Error(`Unexpected input: ${input}`), 'ERR_UNEXPECTED_INPUT') | ||
} | ||
|
||
// String | ||
if (typeof input === 'string' || input instanceof String) { | ||
yield toFileObject(input.toString(), normaliseContent) | ||
return | ||
} | ||
|
||
// Uint8Array|ArrayBuffer|TypedArray | ||
// Blob|File | ||
if (isBytes(input) || isBlob(input)) { | ||
yield toFileObject(input, normaliseContent) | ||
return | ||
} | ||
|
||
// Browser ReadableStream | ||
if (isReadableStream(input)) { | ||
input = browserStreamToIt(input) | ||
} | ||
|
||
// Iterable<?> | ||
if (Symbol.iterator in input || Symbol.asyncIterator in input) { | ||
// @ts-ignore it's (async)iterable | ||
const peekable = itPeekable(input) | ||
|
||
/** @type {any} value **/ | ||
const { value, done } = await peekable.peek() | ||
|
||
if (done) { | ||
// make sure empty iterators result in empty files | ||
yield { content: [] } | ||
return | ||
} | ||
|
||
peekable.push(value) | ||
|
||
// (Async)Iterable<Number> | ||
// (Async)Iterable<Bytes> | ||
// (Async)Iterable<String> | ||
if (Number.isInteger(value) || isBytes(value) || typeof value === 'string' || value instanceof String) { | ||
yield toFileObject(peekable, normaliseContent) | ||
return | ||
} | ||
|
||
throw errCode(new Error('Unexpected input: multiple items passed - if you are using ipfs.add, please use ipfs.addAll instead'), 'ERR_UNEXPECTED_INPUT') | ||
} | ||
|
||
// { path, content: ? } | ||
// Note: Detected _after_ (Async)Iterable<?> because Node.js fs.ReadStreams have a | ||
// `path` property that passes this check. | ||
if (isFileObject(input)) { | ||
yield toFileObject(input, normaliseContent) | ||
return | ||
} | ||
|
||
throw errCode(new Error('Unexpected input: cannot convert "' + typeof input + '" into ImportCandidate'), 'ERR_UNEXPECTED_INPUT') | ||
} | ||
|
||
/** | ||
* @param {ImportCandidate} input | ||
* @param {(content:ToContent) => Promise<AsyncIterable<Uint8Array>>} normaliseContent | ||
*/ | ||
async function toFileObject (input, normaliseContent) { | ||
// @ts-ignore - Those properties don't exist on most input types | ||
const { path, mode, mtime, content } = input | ||
|
||
/** @type {ImporterImportCandidate} */ | ||
const file = { | ||
path: path || '', | ||
mode: parseMode(mode), | ||
mtime: parseMtime(mtime) | ||
} | ||
|
||
if (content) { | ||
file.content = await normaliseContent(content) | ||
} else if (!path) { // Not already a file object with path or content prop | ||
// @ts-ignore - input still can be different ToContent | ||
file.content = await normaliseContent(input) | ||
} | ||
|
||
return file | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 5 additions & 6 deletions
11
...tils/src/files/normalise-input.browser.js → ...files/normalise-input-multiple.browser.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,24 @@ | ||
import { normaliseContent } from './normalise-content.browser.js' | ||
import { normalise } from './normalise.js' | ||
import { normaliseCandidateMultiple } from './normalise-candidate-multiple.js' | ||
|
||
/** | ||
* @typedef {import('ipfs-core-types/src/utils').ImportCandidateStream} ImportCandidateStream | ||
* @typedef {import('ipfs-core-types/src/utils').ImportCandidate} ImportCandidate | ||
* @typedef {import('ipfs-core-types/src/utils').BrowserImportCandidate} BrowserImportCandidate | ||
*/ | ||
|
||
/** | ||
* Transforms any of the `ipfs.add` input types into | ||
* Transforms any of the `ipfs.addAll` input types into | ||
* | ||
* ``` | ||
* AsyncIterable<{ path, mode, mtime, content: Blob }> | ||
* ``` | ||
* | ||
* See https://github.com/ipfs/js-ipfs/blob/master/docs/core-api/FILES.md#ipfsadddata-options | ||
* | ||
* @param {ImportCandidate | ImportCandidateStream} input | ||
* @param {ImportCandidateStream} input | ||
* @returns {AsyncGenerator<BrowserImportCandidate, void, undefined>} | ||
*/ | ||
export function normaliseInput (input) { | ||
// @ts-ignore normaliseContent returns Blob and not AsyncIterator | ||
return normalise(input, normaliseContent) | ||
// @ts-expect-error browser normaliseContent returns a Blob not an AsyncIterable<Uint8Array> | ||
return normaliseCandidateMultiple(input, normaliseContent, true) | ||
} |
Oops, something went wrong.