npm.io
13.1.0 • Published 1 week agoCLI

@ethersphere/bee-js

Licence
BSD-3-Clause
Version
13.1.0
Deps
7
Size
2.3 MB
Vulns
0
Weekly
0
Stars
67

Bee-JS

FOSSA Status standard-readme compliant js-standard-style

JavaScript SDK for the Swarm decentralised storage.

Supports Node.js 18+, Vite and Webpack.

Write your code in CJS, MJS or TypeScript.

Intended to be used with Bee version 2.8.1.

Quick start

Start a Swarm project using TypeScript:

npm init swarm-app@latest my-dapp node-ts

or using Vite and TypeScript:

npm init swarm-app@latest my-dapp vite-tsx

Supported types are node, node-esm, node-ts and vite-tsx. Replace my-dapp with your project name.

Install

npm install @ethersphere/bee-js

Import

CJS
const { Bee } = require('@ethersphere/bee-js')
MJS and TypeScript
import { Bee } from '@ethersphere/bee-js'
Script tag

Loading this module through a script tag will make the BeeJs object available in the global namespace.

<script src="https://unpkg.com/@ethersphere/bee-js/dist/index.browser.min.js"></script>

Overview

Type interfaces

NumberString is a branded type for marking strings that represent numbers. It interops with string and bigint types. Where NumberString is present, number is disallowed in order to avoid pitfalls with unsafe large values.

Byte primitives

All the classes below extend Bytes, therefore the following methods are available on all of them: toUint8Array, toHex, toBase64, toBase32, toUtf8, toJSON, static keccak256, static fromUtf8.

The toString method uses toHex.

Bytes and its subclasses may be constructed with new from Uint8Array or hex string.

Elliptic
Name Description Methods
PrivateKey 32 bytes private key publicKey, sign
PublicKey 64 bytes public key address, toCompressedUint8Array, toCompressedHex
EthAddress 20 bytes Ethereum address toChecksum
Signature 65 bytes signature recoverPublicKey
Swarm
Name Description Methods
Reference 32/64 bytes reference (chunk, feed) toCid
Identifier 32 bytes identifier (SOC, Feed) -
TransactionId 32 bytes transaction ID -
FeedIndex 8 bytes feed index (BE) static fromBigInt, toBigInt
Topic 32 bytes topic static fromString
PeerAddress 32 bytes peer address -
BatchId 32 bytes batch ID -
Span 8 bytes span (LE) static fromBigInt, toBigInt
Tokens
Name Description Methods
DAI ERC20 DAI token (18 digits) static fromDecimalString, static fromWei, toWeiString, toWeiBigInt, toDecimalString
BZZ ERC20 BZZ token (16 digits) static fromDecimalString, static fromPLUR, toPLURString, toPLURBigInt, toDecimalString
Swarm chunks
Name Description Creation
Chunk Span, max. 4096 bytes payload; address derived from content makeContentAddressedChunk
SingleOwnerChunk Identifier, signature, span, max. 4096 bytes payload; address derived from identifier and owner makeSingleOwnerChunk
Swarm primitives
Name Description Methods
MantarayNode Compact trie with reference values and JSON metadata addFork, removeFork, calculateSelfAddress, find, findClosest, collect, marshal, unmarshal, saveRecursively, loadRecursively
ChunkSplitter Streaming BMT chunk-tree builder append, finalize, static root
ChunkJoiner Reconstructs data from a chunk tree join, static collect
Swarm objects
Name Description Creation
SOCWriter SingleOwnerChunk writer bee.soc.makeWriter
SOCReader SingleOwnerChunk reader bee.soc.makeReader
FeedWriter Feed writer bee.feed.makeWriter
FeedReader Feed reader bee.feed.makeReader
RollingFeedWriter Rolling feed writer bee.rollingFeed.makeWriter
RollingFeedReader Rolling feed reader bee.rollingFeed.makeReader
Bee API
  • - Full node only
  • - Light node and full node
  • - Ultra-light node, light node and full node
JS Call Bee Endpoint Bee Mode
file.upload POST /bzz
collection.uploadFromDirectory Node.js POST /bzz
collection.uploadFromFileList POST /bzz
collection.upload POST /bzz
data.upload POST /bytes
chunk.upload POST /chunks
collection.streamFromDirectory Node.js POST /chunks
collection.stream Browser POST /chunks
SOCWriter.upload POST /soc/:owner/:identifier
FeedReader.download GET /feeds/:owner/:topic
FeedWriter.uploadReference POST /soc/:owner/:identifier
file.download GET /bzz/:reference
file.download GET /bzz/:reference/:path
file.downloadReadable GET /bzz/:reference
data.download GET /bytes/:reference
data.downloadReadable GET /bytes/:reference
chunk.download GET /chunks/:reference
feed.createManifest POST /feeds/:owner/:topic
connectivity.isConnected GET /
status.getHealth GET /health
status.getReadiness GET /readiness
status.getNodeInfo GET /node
status.getChainState GET /chainstate
stake.getRedistributionState GET /redistributionstate
status.getReserveState GET /reservestate
status.get GET /status
wallet.getBalance GET /wallet
connectivity.getTopology GET /topology
connectivity.getNodeAddresses GET /addresses
connectivity.getPeers GET /peers
balance.getAll GET /balances
balance.getPeer GET /balances/:peer
balance.getAllPastDueConsumption GET /consumed
balance.getAllPastDueConsumptionForPeer GET /consumed/:peer
settlement.getAll GET /settlements
settlement.get GET /settlements/:peer
chequebook.getAddress GET /chequebook/address
chequebook.getBalance GET /chequebook/balance
cheque.getAllLatest GET /chequebook/cheque
cheque.getAllLatestForPeer GET /chequebook/cheque/:peer
cheque.getLastCashoutAction GET /chequebook/cashout/:peer
cheque.cashoutLast POST /chequebook/cashout/:peer
chequebook.deposit POST /chequebook/deposit
chequebook.withdraw POST /chequebook/withdraw
transaction.getAll GET /transactions
transaction.get GET /transactions/:id
transaction.rebroadcast POST /transactions/:id
transaction.cancel DELETE /transactions/:id
tag.create POST /tags
tag.get GET /tags/:id
tag.getAll GET /tags
tag.delete DELETE /tags/:id
tag.update PATCH /tags/:id
pin.add POST /pins/:reference
pin.getAll GET /pins
pin.get GET /pins/:reference
data.isRetrievable GET /stewardship/:reference
pin.reuploadData PUT /stewardship/:reference
pin.remove DELETE /pins/:reference
grantee.get GET /grantee/:reference
grantee.create POST /grantee
grantee.patch PATCH /grantee/:reference
messaging.pssSend POST /pss/send/:topic/:target
messaging.pssSubscribe Websocket GET /pss/subscribe/:topic
messaging.pssReceive GET /pss/subscribe/:topic
stamp.getAll GET /stamps
stamp.getAllGlobal GET /batches
stamp.get GET /stamps/:batchId
stamp.getBuckets GET /stamps/:batchId/buckets
stamp.create POST /stamps/:amount/:depth
stamp.topUp PATCH /stamps/topup/:batchId/:amount
stamp.dilute PATCH /stamps/dilute/:batchId/:depth
createEnvelope POST /envelope/:reference
stake.get GET /stake
stake.deposit POST /stake
Utils
General
  • getCollectionSize
  • getFolderSize
PSS
  • makeMaxTarget
Erasure Coding
  • approximateOverheadForRedundancyLevel
  • getRedundancyStat
  • getRedundancyStats
Stamps
  • getAmountForDuration
  • getDepthForSize
  • getStampCost
  • getStampEffectiveBytes
  • getStampTheoreticalBytes
  • getStampDuration
  • getStampUsage

Usage

Upload via Swarm Gateway
import { Bee, NULL_STAMP, SWARM_GATEWAY_URL } from '@ethersphere/bee-js'

main()

async function main() {
  const bee = new Bee(SWARM_GATEWAY_URL)
  const { reference } = await bee.data.upload(NULL_STAMP, 'Hello, World!')
  console.log(reference.toHex())
}
Create or select an existing postage batch

Swarm incentivizes nodes in the network to store content, therefore all uploads require a paid postage batch.

import { Bee } from '@ethersphere/bee-js'

async function getOrCreatePostageBatch() {
  const bee = new Bee('http://localhost:1633')
  let batchId

  const batches = await bee.stamp.getAll()
  const usable = batches.find(x => x.usable)

  if (usable) {
    batchId = usable.batchID
  } else {
    batchId = await bee.storage.buy(Size.fromGigabytes(1), Duration.fromDays(7))
  }
}

The following examples all assume an existing batchId.

Upload simple data (Browser + Node.js)
import { Bee } from '@ethersphere/bee-js'

const bee = new Bee('http://localhost:1633')

const uploadResult = await bee.data.upload(batchId, 'Bee is awesome!')
const data = await bee.data.download(uploadResult.reference)

console.log(data.toUtf8()) // prints 'Bee is awesome!'
Upload data from a file input (React)
import { Bee } from '@ethersphere/bee-js'

const bee = new Bee('http://localhost:1633')
const result = await bee.file.upload(batchId, file)
Upload multiple files or a directory (React)
import { Bee } from '@ethersphere/bee-js'

const bee = new Bee('http://localhost:1633')
const result = await bee.collection.uploadFromFileList(batchId, fileList)
Upload arbitrary large file (Node.js)
import { Bee } from '@ethersphere/bee-js'
import { createReadStream } from 'fs'

const bee = new Bee('http://localhost:1633')
const readable = createReadStream('./path/to/large.bin')
const uploadResult = await bee.file.upload(batchId, readable)
Upload arbitrary large directories (Node.js)
import { Bee } from '@ethersphere/bee-js'
import { createReadStream } from 'fs'

const bee = new Bee('http://localhost:1633')
const uploadResult = await bee.collection.uploadFromDirectory(batchId, './path/to/gallery/')
Rolling feed (periodically-restarting sequential feed)

A rolling feed avoids the unbounded growth of a plain sequential feed by restarting it every periodLength seconds, so old postage-batch eviction never breaks the latest update. See ROLLING_FEED.md for the full design.

A rolling feed only stays readable while the writer keeps publishing. Keeping it alive is the application's job, not the SDK's, so a writer belongs on a timer — republish on every tick, even when the data has not changed.

Writer
import { Bee, PrivateKey, Topic } from '@ethersphere/bee-js'

const bee = new Bee('http://localhost:1633')
const topic = Topic.fromString('my-feed')
const signer = new PrivateKey('...')
const periodLength = 600 // 10 minutes

const writer = bee.rollingFeed.makeWriter(topic, signer, periodLength)

let latest = 'Hello, World!'
await writer.uploadPayload(batchId, latest)

// tick twice per period so a slow or delayed write still lands inside its own period
const handle = setInterval(async () => {
  try {
    await writer.uploadPayload(batchId, latest)
  } catch (error) {
    console.error('rolling feed heartbeat failed', error)
  }
}, (periodLength / 2) * 1000)

process.on('SIGTERM', () => clearInterval(handle))

If the writer was down long enough to leave gaps behind, call writer.catchUp(batchId) before resuming the timer to backfill the missed periods. It throws when no populated period is found within maxBackfill, so it is for restarts, not for the very first run.

Reader
import { Bee, EthAddress, Topic } from '@ethersphere/bee-js'

const bee = new Bee('http://localhost:1633')
const topic = Topic.fromString('my-feed')
const owner = new EthAddress('...')
const periodLength = 600 // must match the writer

const reader = bee.rollingFeed.makeReader(topic, owner, periodLength)
const result = await reader.downloadPayload()
console.log(result.payload.toUtf8()) // prints 'Hello, World!'
Customize http/https agent and headers
const bee = new Bee('http://localhost:1633', {
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),
  headers: {
    Authorization: 'Basic ' + Buffer.from('username:password').toString('base64'),
  },
})

Contribute

Stay up to date by joining the official Discord and by keeping an eye on the releases tab.

We are using Conventional Commits for our commit messages and pull requests, following the Semantic Versioning rules.

There are some ways you can make this module better:

  • Consult our open issues and take on one of them
  • Help our tests reach 100% coverage!
  • Join us in our Discord chat in the #develop-on-swarm channel if you have questions or want to give feedback
Setup

Install project dependencies:

npm install

Build the project:

npm run build

After making changes, link the package to your project by running npm link in the Bee-JS project root, and npm link @ethersphere/bee-js in your project root.

Test

Code coverage

Tests are currently run against a mainnet Bee node. This is temporary and this section will be revised in the future.

License

BSD-3-Clause

FOSSA Status

Keywords