Update: The examples in this post were updated in January 2023 to reflect the changes we've made during the beta development process. Check out our announcement post for more details!

When we launched Web3.Storage in August 2021, we knew we were onto something great, and our users have reflected that back to us. By making a simple "on-ramp" to IPFS and Filecoin, web3.storage has enabled traditional web developers to tap into the decentralized ecosystem without having to run their own storage infrastructure or learn the nuances of decentralized storage protocols.

Since then, we've been hard at work building a new application platform with content addressing at its heart, with a powerful new authorization protocol powered by UCAN, or User Controlled Authorization Networks.

Today we're announcing the first component of the new Web3.Storage platform, a file upload service called w3up. w3up is a complete reimagining of the Web3.Storage API that leverages the strengths of UCAN authorization and our cloud-native Elastic IPFS stack.

Yes, UCAN!

UCAN is a central component of our new platform, and we think it unlocks some pretty amazing super powers. But what is a UCAN, and why should you care about it?

UCANs are a relatively new authorization protocol developed by Fission that allows you to build fine-grained permission and authorization systems without requiring a single "issuer" or central authority.

In a traditional authorization system, you sign up for an account from some provider, and they'll create an entry for you in their database using whatever ID fits their internal models. In some cases, you might be able to sign in with some other ID ("Sign in with Google", etc.), but that's just passing the buck to another third party who controls your identity.

With UCAN, you hold the keys, in a very literal sense. Your UCAN identity is based on a public key, the private half of which is only known to you. When you register your UCAN identity with w3up, you tell us who you are, not the other way around. There's no way for us or anyone else to impersonate your account without your private key.

That's already pretty cool, but what makes UCAN truly special is that we as the service provider are not the only ones that can issue UCAN tokens - you can too! Once you've created a w3up account and registered your UCAN identity, you can issue your own UCAN tokens and delegate some or all of your permissions to another UCAN identity. This might be another device like your phone, or it could be a user on a platform that you manage.

Using w3up-client

w3up is our first service built from the ground up on our new platform. It offers UCAN-based identity and a streamlined upload experience based on Elastic IPFS.

In this post we'll take a look at the JavaScript client library w3up-client. If you're more into the command line, check out the w3cli project, and stay tuned for a post that explores it in detail!

Below we'll look at a few examples of using w3up-client to register a UCAN identity and upload files.

You can add the w3up-client package to your JavaScript or TypeScript project with npm:

npm install w3up-client

Creating a client object

The create function in the w3up-client package creates and returns a client object you can use to interact with the w3up service.

import { create } from 'w3up-client'

const client = await create()

Creating and registering a space

Content you store with w3up is organized into "spaces," which act like folders or namespaces to group uploads together. You'll need at least one space to store data with w3up, and the space needs to be registered with the service by providing an email address.

The createSpace method will create a space on your local machine. Once it's created, call client.setCurrentSpace to set the client's active space, passing in the DID (decentralized identifier) of the new space.

Giving your space a human-readable name is optional but recommended, as it's a bit easier to keep track of than the full DID of the space.

const space = await client.createSpace('my-awesome-space')
await client.setCurrentSpace(space.did())

Before you can use the space for uploads, you need to register it by providing an email address:

try {
  await client.registerSpace('you@email.host')
  console.log('Space successfully registered!')
} catch (err) {
  console.error(`Registration error: ${err}`)
}

The registerSpace method will complete when the confirmation link in the email is clicked and the space is successfully registered.

Uploading data

Now that you have a registered space, it's time to upload!

The uploadFile method takes a File or Blob object and uploads it to the w3up service. You can also use uploadDirectory to upload a collection of files at once.

In web browsers, the File and Blob objects are part of the standard DOM API, and you can use the target.files property of a file input element to get a File to pass in to the upload methods.

On node.js, you can use any object that satisfies this interface as a "File-like" input:

interface FileLike {
  stream: () => ReadableStream
  name: string
}

To easily create FileLike objects from local files, check out the files-from-path package, which can load files and directories from the filesystem in the correct format.

Below is a little snippet that uses files-from-path to load a file named hello.txt from the current directory and upload it:

import { getFilesFromPath } from 'files-from-path'

const files = await getFilesFromPath('hello.txt')

// getFilesFromPath returns an array, since it can also dive into directories.
// If we wanted to upload multiple files, we could call uploadDirectory
// and pass in the whole files array.
const cid = await client.uploadFile(files[0])

Next steps

Hopefully this post has piqued your interest in w3up. We're excited to put it into your hands and eager to see what you'll build.

If you want to dig deeper, make sure to check out w3cli, our fully-featured command line tool.

If you have any issues using w3up, we want to know all about it. Please feel free to reach out early and often with any feedback!