feat: bee-js revamp (#690)
* chore: initial commit * refactor: remove unnecessary wrappers * style: add missing newline * chore: bump bee-js * chore: ignore any cast in fdp * fix: remove cid import * fix: make TextEncoder and TextDecoder available in jest * refactor: dedupe stamp ttl second conversion * refactor: use convenience methods from bee-js * feat: update to bee-js for restored ens support * fix: bump bee-js to get download fix * fix: resolve feed before downloading reference * fix: fix token displays * fix: fix token input modal error message * refactor: remove wallet balance provider * chore: remove dead code * refactor: upcoming bee js 0.15.0 (#692) * chore: initial commit * fix: do not break page when duration seconds is 0 * ci: remove cache * chore: upgrade bee-js * feat: bee-js and bee v2.6 compatibility * chore: switch upcoming/bee-js to ethersphere/bee-js
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Utils } from '@ethersphere/bee-js'
|
||||
import { Box } from '@material-ui/core'
|
||||
import { Reference } from '@ethersphere/bee-js'
|
||||
import { ReactElement } from 'react'
|
||||
import { DocumentationText } from '../../components/DocumentationText'
|
||||
import ExpandableListItemKey from '../../components/ExpandableListItemKey'
|
||||
@@ -11,7 +11,7 @@ interface Props {
|
||||
}
|
||||
|
||||
export function AssetSummary({ isWebsite, reference }: Props): ReactElement {
|
||||
const isHash = Utils.isHexString(reference) && reference.length === 64
|
||||
const isHash = Reference.isValid(reference)
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Context as SettingsContext } from '../../providers/Settings'
|
||||
import { Box } from '@material-ui/core'
|
||||
import { Tag } from '@ethersphere/bee-js'
|
||||
import { ReactElement, useContext, useEffect, useRef, useState } from 'react'
|
||||
import { DocumentationText } from '../../components/DocumentationText'
|
||||
import { LinearProgressWithLabel } from '../../components/ProgressBar'
|
||||
import { Tag } from '@ethersphere/bee-js'
|
||||
import { Context as SettingsContext } from '../../providers/Settings'
|
||||
|
||||
interface Props {
|
||||
reference: string
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BeeModes, Utils } from '@ethersphere/bee-js'
|
||||
import { BeeModes, MantarayNode, NULL_ADDRESS, Reference } from '@ethersphere/bee-js'
|
||||
import { useSnackbar } from 'notistack'
|
||||
import { ReactElement, useContext, useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
@@ -11,7 +11,6 @@ import { Context as SettingsContext } from '../../providers/Settings'
|
||||
import { ROUTES } from '../../routes'
|
||||
import { recognizeEnsOrSwarmHash, regexpEns } from '../../utils'
|
||||
import { HISTORY_KEYS, determineHistoryName, putHistory } from '../../utils/local-storage'
|
||||
import { ManifestJs } from '../../utils/manifest'
|
||||
import { FileNavigation } from './FileNavigation'
|
||||
|
||||
export function Download(): ReactElement {
|
||||
@@ -26,41 +25,43 @@ export function Download(): ReactElement {
|
||||
const navigate = useNavigate()
|
||||
|
||||
const validateChange = (value: string) => {
|
||||
if (
|
||||
Utils.isHexString(value, 64) ||
|
||||
Utils.isHexString(value, 128) ||
|
||||
!value.trim().length ||
|
||||
regexpEns.test(value)
|
||||
) {
|
||||
if (Reference.isValid(value) || regexpEns.test(value)) {
|
||||
setReferenceError(undefined)
|
||||
} else {
|
||||
setReferenceError('Incorrect format of swarm hash. Expected 64 or 128 hexstring characters or ENS domain.')
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Test this for feeds, bzz, and bytes
|
||||
async function onSwarmIdentifier(identifier: string) {
|
||||
setLoading(true)
|
||||
|
||||
if (!beeApi) {
|
||||
setLoading(false)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
const manifestJs = new ManifestJs(beeApi)
|
||||
const feedIdentifier = await manifestJs.resolveFeedManifest(identifier)
|
||||
let manifest = await MantarayNode.unmarshal(beeApi, identifier)
|
||||
await manifest.loadRecursively(beeApi)
|
||||
|
||||
if (feedIdentifier) {
|
||||
identifier = feedIdentifier
|
||||
}
|
||||
const isManifest = await manifestJs.isManifest(identifier)
|
||||
// If the manifest is a feed, resolve it and overwrite the manifest
|
||||
await manifest.resolveFeed(beeApi).then(
|
||||
async feed =>
|
||||
await feed.ifPresentAsync(async feedUpdate => {
|
||||
manifest = MantarayNode.unmarshalFromData(feedUpdate.payload.toUint8Array(), NULL_ADDRESS)
|
||||
await manifest.loadRecursively(beeApi)
|
||||
}),
|
||||
)
|
||||
|
||||
if (!isManifest) {
|
||||
throw Error('The specified hash does not contain valid content.')
|
||||
}
|
||||
const indexDocument = await manifestJs.getIndexDocumentPath(identifier)
|
||||
putHistory(HISTORY_KEYS.DOWNLOAD_HISTORY, identifier, determineHistoryName(identifier, indexDocument))
|
||||
const rootMetadata = manifest.getDocsMetadata()
|
||||
|
||||
putHistory(
|
||||
HISTORY_KEYS.DOWNLOAD_HISTORY,
|
||||
identifier,
|
||||
determineHistoryName(identifier, rootMetadata.indexDocument),
|
||||
)
|
||||
setUploadOrigin(defaultUploadOrigin)
|
||||
navigate(ROUTES.HASH.replace(':hash', identifier))
|
||||
} catch (error: unknown) {
|
||||
|
||||
@@ -27,7 +27,7 @@ export default function SimpleMenu({ stamps, selectedStamp, setSelected }: Props
|
||||
<Menu anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose}>
|
||||
{stamps.map(stamp => (
|
||||
<MenuItem
|
||||
key={stamp.batchID}
|
||||
key={stamp.batchID.toHex()}
|
||||
onClick={() => {
|
||||
setSelected(stamp)
|
||||
handleClose()
|
||||
@@ -35,7 +35,7 @@ export default function SimpleMenu({ stamps, selectedStamp, setSelected }: Props
|
||||
selected={stamp.batchID === selectedStamp?.batchID}
|
||||
>
|
||||
<ListItemIcon>{stamp.usageText}</ListItemIcon>
|
||||
<Typography variant="body2">{stamp.batchID.slice(0, 8)}[…]</Typography>
|
||||
<Typography variant="body2">{stamp.batchID.toHex().slice(0, 8)}[…]</Typography>
|
||||
</MenuItem>
|
||||
))}
|
||||
</Menu>
|
||||
|
||||
+48
-35
@@ -1,4 +1,5 @@
|
||||
import { Box, Typography } from '@material-ui/core'
|
||||
import { MantarayNode, NULL_ADDRESS } from '@ethersphere/bee-js'
|
||||
import { saveAs } from 'file-saver'
|
||||
import JSZip from 'jszip'
|
||||
import { useSnackbar } from 'notistack'
|
||||
@@ -12,11 +13,10 @@ import { Context as BeeContext } from '../../providers/Bee'
|
||||
import { Context as SettingsContext } from '../../providers/Settings'
|
||||
import { ROUTES } from '../../routes'
|
||||
import { determineHistoryName, HISTORY_KEYS, putHistory } from '../../utils/local-storage'
|
||||
import { ManifestJs } from '../../utils/manifest'
|
||||
import { AssetPreview } from './AssetPreview'
|
||||
import { AssetSummary } from './AssetSummary'
|
||||
import { DownloadActionBar } from './DownloadActionBar'
|
||||
import { AssetSyncing } from './AssetSyncing'
|
||||
import { DownloadActionBar } from './DownloadActionBar'
|
||||
|
||||
export function Share(): ReactElement {
|
||||
const { apiUrl, beeApi } = useContext(SettingsContext)
|
||||
@@ -41,44 +41,57 @@ export function Share(): ReactElement {
|
||||
return
|
||||
}
|
||||
|
||||
const manifestJs = new ManifestJs(beeApi)
|
||||
const isManifest = await manifestJs.isManifest(reference)
|
||||
try {
|
||||
let manifest = await MantarayNode.unmarshal(beeApi, reference)
|
||||
await manifest.loadRecursively(beeApi)
|
||||
|
||||
if (!isManifest) {
|
||||
// If the manifest is a feed, resolve it and overwrite the manifest
|
||||
await manifest.resolveFeed(beeApi).then(
|
||||
async feed =>
|
||||
await feed.ifPresentAsync(async feedUpdate => {
|
||||
manifest = MantarayNode.unmarshalFromData(feedUpdate.payload.toUint8Array(), NULL_ADDRESS)
|
||||
await manifest.loadRecursively(beeApi)
|
||||
}),
|
||||
)
|
||||
|
||||
const entries = manifest.collectAndMap()
|
||||
delete entries[META_FILE_NAME]
|
||||
setSwarmEntries(entries)
|
||||
|
||||
const docsMetadata = manifest.getDocsMetadata()
|
||||
|
||||
// needed in catch block, shadows the outer variable
|
||||
const indexDocument = docsMetadata.indexDocument
|
||||
setIndexDocument(indexDocument)
|
||||
|
||||
try {
|
||||
const remoteMetadata = await beeApi.downloadFile(reference, META_FILE_NAME)
|
||||
const formattedMetadata = remoteMetadata.data.toJSON() as Metadata
|
||||
|
||||
if (formattedMetadata.isVideo || formattedMetadata.isImage) {
|
||||
setPreview(`${apiUrl}/bzz/${reference}`)
|
||||
}
|
||||
setMetadata({ ...formattedMetadata, hash })
|
||||
} catch (e) {
|
||||
// if metadata is not available or invalid go with the default one
|
||||
const count = Object.keys(entries).length
|
||||
setMetadata({
|
||||
hash,
|
||||
type: count > 1 ? 'folder' : 'unknown',
|
||||
name: reference,
|
||||
count,
|
||||
isWebsite: Boolean(indexDocument && /.*\.html?$/i.test(indexDocument)),
|
||||
isVideo: Boolean(indexDocument && /.*\.(mp4|webm|ogg|mp3|ogg|wav)$/i.test(indexDocument)),
|
||||
isImage: Boolean(indexDocument && /.*\.(jpg|jpeg|png|gif|webp|svg)$/i.test(indexDocument)),
|
||||
// naive assumption based on indexDocument, we don't want to download the whole manifest
|
||||
})
|
||||
}
|
||||
} catch {
|
||||
setNotFound(true)
|
||||
enqueueSnackbar('The specified hash does not contain valid content.', { variant: 'error' })
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const entries = await manifestJs.getHashes(reference, { exclude: [META_FILE_NAME] })
|
||||
setSwarmEntries(entries)
|
||||
|
||||
const indexDocument = await manifestJs.getIndexDocumentPath(reference)
|
||||
setIndexDocument(indexDocument)
|
||||
|
||||
try {
|
||||
const remoteMetadata = await beeApi.downloadFile(reference, META_FILE_NAME)
|
||||
const formattedMetadata = JSON.parse(remoteMetadata.data.text()) as Metadata
|
||||
|
||||
if (formattedMetadata.isVideo || formattedMetadata.isImage) {
|
||||
setPreview(`${apiUrl}/bzz/${reference}`)
|
||||
}
|
||||
setMetadata({ ...formattedMetadata, hash })
|
||||
} catch (e) {
|
||||
// if metadata is not available or invalid go with the default one
|
||||
const count = Object.keys(entries).length
|
||||
setMetadata({
|
||||
hash,
|
||||
type: count > 1 ? 'folder' : 'unknown',
|
||||
name: reference,
|
||||
count,
|
||||
isWebsite: Boolean(indexDocument && /.*\.html?$/i.test(indexDocument)),
|
||||
isVideo: Boolean(indexDocument && /.*\.(mp4|webm|ogg|mp3|ogg|wav)$/i.test(indexDocument)),
|
||||
isImage: Boolean(indexDocument && /.*\.(jpg|jpeg|png|gif|webp|svg)$/i.test(indexDocument)),
|
||||
// naive assumption based on indexDocument, we don't want to donwload the whole manifest
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function onOpen() {
|
||||
@@ -119,7 +132,7 @@ export function Share(): ReactElement {
|
||||
} else {
|
||||
const zip = new JSZip()
|
||||
for (const [path, hash] of Object.entries(swarmEntries)) {
|
||||
zip.file(path, await beeApi.downloadData(hash))
|
||||
zip.file(path, (await beeApi.downloadData(hash)).toUint8Array())
|
||||
}
|
||||
const content = await zip.generateAsync({ type: 'blob' })
|
||||
saveAs(content, reference + '.zip')
|
||||
|
||||
@@ -114,10 +114,10 @@ export function Upload(): ReactElement {
|
||||
beeApi
|
||||
.uploadFiles(stamp.batchID, fls, { indexDocument, deferred: true })
|
||||
.then(hash => {
|
||||
putHistory(HISTORY_KEYS.UPLOAD_HISTORY, hash.reference, getAssetNameFromFiles(files))
|
||||
putHistory(HISTORY_KEYS.UPLOAD_HISTORY, hash.reference.toHex(), getAssetNameFromFiles(files))
|
||||
|
||||
if (uploadOrigin.origin === 'UPLOAD') {
|
||||
navigate(ROUTES.HASH.replace(':hash', hash.reference), { replace: true })
|
||||
navigate(ROUTES.HASH.replace(':hash', hash.reference.toHex()), { replace: true })
|
||||
} else {
|
||||
updateFeed(beeApi, identity as Identity, hash.reference, stamp.batchID, password as string).then(() => {
|
||||
persistIdentity(identities, identity as Identity)
|
||||
@@ -164,7 +164,7 @@ export function Upload(): ReactElement {
|
||||
<>
|
||||
<Box mb={2}>
|
||||
{hasAnyStamps && stampMode === 'SELECT' ? (
|
||||
<PostageStampSelector onSelect={stamp => setStamp(stamp)} defaultValue={stamp?.batchID} />
|
||||
<PostageStampSelector onSelect={stamp => setStamp(stamp)} defaultValue={stamp?.batchID.toHex()} />
|
||||
) : (
|
||||
<PostageStampAdvancedCreation onFinished={() => setStampMode('SELECT')} />
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user