Skip to content

Commit

Permalink
feat: diagrams in readme, delegated example (#909)
Browse files Browse the repository at this point in the history
Co-authored-by: Travis Vachon <[email protected]>
  • Loading branch information
dchoi27 and travis authored Sep 19, 2023
1 parent 54c1a78 commit 329354d
Showing 1 changed file with 139 additions and 18 deletions.
157 changes: 139 additions & 18 deletions packages/w3up-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,19 @@ This library is the user-facing "porcelain" client for interacting with w3up ser
- [Install](#install)
- [Usage](#usage)
- [Core concepts](#core-concepts)
- [Basic usage](#basic-usage)
- [How w3up and w3up-client use UCANs](#how-w3up-and-w3up-client-use-ucans)
- [Space](#space)
- [Agent](#agent)
- [Basic usage with web3.storage](#basic-usage-with-web3-storage)
- [Creating a client object](#creating-a-client-object)
- [Creating and registering Spaces](#creating-and-registering-spaces)
- [Delegating from Space to Agent](#delegating-from-space-to-agent)
- [Bringing your own Agent and delegation](#bringing-your-own-agent-and-delegation)
- [Uploading data](#uploading-data)
- [Alternate implementation options](#alternate-implementation-options) - _Coming soon!_
- [Integration options](#integration-options)
- [Client-server](#client-server)
- [Delegated](#delegated)
- [User owned](#user-owned)
- [API](#api)
- [Contributing](#contributing)
- [License](#license)
Expand Down Expand Up @@ -79,7 +86,15 @@ The delegation from a Space to your Agent that `w3up-client` needs can be passed

### Basic usage with web3.storage

This section shows the basic flows to start storing data using the `w3up-client` package with web3.storage. For more complex integration options, check out the [integration options][integration options] docs. For reference, check out the [API reference docs][docs] or the source code of the [`w3up-cli` package][w3up-cli-github], which uses `w3up-client` throughout.
```mermaid
flowchart TD
A[w3up-client instance] -->|Automatic if specific Agent is not passed when client object created|B(Create local Agent DID and key)
B --> |If Space has not yet been created|S(Create local Space and register it)
S --> C(Get UCAN delegation from Space to Agent)
C --> D(Upload to Space using Agent)
```

All uses of `w3up-client` to upload with web3.storage follow the flow above. This section shows the basic flows to start storing data. For more complex integration options, check out the [integration options][#integration-options] docs. For reference, check out the [API reference docs][docs] or the source code of the [`w3up-cli` package][w3up-cli-github], which uses `w3up-client` throughout.

> By you or your users registering a w3up beta Space via email confirmation with [web3.storage](http://web3.storage), you agree to the beta [Terms of Service](https://console.web3.storage/terms). Uploads to w3up will not appear in your web3.storage account (and vice versa).
Expand Down Expand Up @@ -148,6 +163,14 @@ In order to store data with w3up, your Agent will need a delegation from a Space
await client.authorize('[email protected]')
```

```mermaid
sequenceDiagram
Client->>web3.storage w3up service: Here is my email address and Agent DID
web3.storage w3up service-->>Client: Please click the link to validate
Client-->>web3.storage w3up service: Email address validated
web3.storage w3up service->>Client: Here is a UCAN delegating permission from Space DID to Agent DID
```

Calling `authorize` will cause an email to be sent to the given address. Once a user clicks the confirmation link in the email, the `authorize` method will resolve. Make sure to check for errors, as `authorize` will fail if the email is not confirmed within the expiration timeout.

##### Bringing your own Agent and delegation
Expand Down Expand Up @@ -227,25 +250,122 @@ As mentioned, UCAN opens up a number of options in how to integrate with w3up: S

You can implement each of these in a number of ways, but we talk through some considerations when implementing a given option.

1. Client-server
#### Client-server
```mermaid
sequenceDiagram
participant User
w3up-client in backend->>w3up-client in backend: Client set with Agent with delegation from Space
User->>w3up-client in backend: Upload data
w3up-client in backend->>web3.storage w3up service: Upload data
```
- For your backend to be scalable, you might consider using serverless workers or a queue in front of a server
- In either case, it's likely easiest to create and register your Space using [w3cli](https://github.com/web3-storage/w3cli) rather than using `w3up-client` to do so
- You can then generate your own Agent and delegate the ability to upload to your Space using something like [this example](#bringing-your-own-agent-and-delegation)
- Once your user uploads data to your backend, you can run any of the `upload` methods

2. Delegated
- In either case, you'll need a registered Space, and your client instance in your backend to have an Agent with a delegation from this Space
- (Recommended) It's likely easiest to create and register your Space using [w3cli](https://github.com/web3-storage/w3cli) rather than using `w3up-client` to do so (especially if your backend isn't persistent); you can then generate your own Agent and delegate the ability to upload to your Space using something like [this example](#bringing-your-own-agent-and-delegation)
- If your backend is persistent, you can do this or do everything in the client directly ([create Space](#creating-and-registering-spaces) and [get delegation](#delegating-from-space-to-agent))
- After this, once your user uploads data to your backend, you can run any of the `upload` methods

#### Delegated
```mermaid
sequenceDiagram
participant w3up-client in user
participant w3up-client in backend
participant web3.storage w3up service
w3up-client in backend->>w3up-client in backend: Client created with Agent and delegation from Space
w3up-client in user->>w3up-client in user: Client instantiated with default Agent
w3up-client in user->>w3up-client in backend: Request delegation with user's Agent DID
w3up-client in backend->>w3up-client in user: Send delegation from Space to user's Agent DID
w3up-client in user->>web3.storage w3up service: Upload data
```
- You will likely have `w3up-client` running in your end-user's client code, as well as backend code that's able to generate UCANs that delegate the ability to upload and pass them to your users (e.g., `w3up-client` running in a serverless worker)
- As the developer, you should create and register a Space; it's likely easiest to create and register your Space using [w3cli](https://github.com/web3-storage/w3cli) rather than using `w3up-client` to do so
- `w3up-client` in the end user environment should have a unique Agent for each user, which should happen by default (since when `w3up-client` is instantiated it creates a new Agent anyway, or uses the one in local Store)
- From there, when your end user is ready to upload, they should request from your backend a delegation from your developer-owned Space to their Agent (which can be derived via [`client.agent()`](#agent))
- If you are running `w3up-client` in your backend should follow the instructions in the "Client-server" section to set it up
- From there, you can call [`client.createDelegation()`](#createDelegation) passing in the Agent object from `client.agent()` in your end user's instance, and passing through `options?` params to limit the scope of the delegation (__todo: documentation on options for delegations__)
- For your backend to be scalable, you might consider using serverless workers or a queue in front of a server
- As the developer, you'll need a registered Space, and your client instance in your backend to have an Agent with a delegation from this Space
- (Recommended) It's likely easiest to create and register your Space using [w3cli](https://github.com/web3-storage/w3cli) rather than using `w3up-client` to do so (especially if your backend isn't persistent); you can then generate your own Agent and delegate the ability to upload to your Space using something like [this example](#bringing-your-own-agent-and-delegation)
- If your backend is persistent, you can do this or do everything in the client directly ([create Space](#creating-and-registering-spaces) and [get delegation](#delegating-from-space-to-agent))
- Your user does not need a registered Space - just an Agent with a delegation from your Space
- `w3up-client` in the end user environment should have a unique Agent for each user, which should happen by default (since when `w3up-client` is instantiated it creates a new Agent anyway, or uses the one in local Store)
- From there, when your end user is ready to upload, they should request from your backend a delegation from your developer-owned Space to their Agent (which can be derived via [`client.agent()`](docs-Client#agent))
- In your backend, you can call [`client.createDelegation()`](docs-Client#createDelegation) passing in the Agent object from `client.agent()` in your end user's instance, and passing through `options?` params to limit the scope of the delegation (e.g., `store/add`, `upload/add`, expiration time)
- You can serialize this using `delegation.archive()` and send it to your user
- The end user instance of the client should not need to call `client.authorize(email)`, as it is not claiming any delegations via email address (but rather getting the delegation directly from your backend)
- Once your user receives the delegation, they can pass it in using `client.addSpace()`, and from there they can run any of the `upload` methods
- Once your user receives the delegation, they can deserialize it using [`ucanto.Delegation.extract()`](https://github.com/web3-storage/ucanto/blob/c8999a59852b61549d163532a83bac62290b629d/packages/core/src/delegation.js#L399) and pass it in using `client.addSpace()`, and from there they can run any of the `upload` methods
- Note that this alone does not give visibility into which of your end users are uploading what; to track this, you'll probably need them to send you that information separately (e.g., once they've run `upload` and get back a content CID, you can have them send that CID to you for tracking)
- If you have code snippet(s) that works for you, please share them in a PR or [Github issue](https://github.com/web3-storage/w3up/issues) and we'll link them here!
- A code example that does this can be found below

3. User-owned
```js
import { CarReader } from '@ipld/car';
import * as DID from '@ipld/dag-ucan/did';
import * as Delegation from '@ucanto/core/delegation';
import { importDAG } from '@ucanto/core/delegation';
import * as Signer from '@ucanto/principal/ed25519';
import * as Client from '@web3-storage/w3up-client';

async function backend(did: string) {
// Load client with specific private key
const principal = Signer.parse(process.env.KEY);
const client = await Client.create({ principal });

// Add proof that this agent has been delegated capabilities on the space
const proof = await parseProof(process.env.PROOF);
const space = await client.addSpace(proof);
await client.setCurrentSpace(space.did());

// Create a delegation for a specific DID
const audience = DID.parse(did);
const abilities = ['store/add', 'upload/add'];
const expiration = Math.floor(Date.now() / 1000) + 60 * 60 * 24; // 24 hours from now
const delegation = await client.createDelegation(audience, abilities, {
expiration,
});

// Serialize the delegation and send it to the client
const archive = await delegation.archive();
return archive.ok;
}

/** @param {string} data Base64 encoded CAR file */
async function parseProof(data) {
const blocks = [];
const reader = await CarReader.fromBytes(Buffer.from(data, 'base64'));
for await (const block of reader.blocks()) {
blocks.push(block);
}
return importDAG(blocks);
}

async function frontend() {
// Create a new client
const client = await Client.create();

// Fetch the delegation from the backend
const apiUrl = `/api/w3up-delegation/${client.agent().did()}`;
const response = await fetch(apiUrl);
const data = await response.arrayBuffer();

// Deserialize the delegation
const delegation = await Delegation.extract(new Uint8Array(data));
if (!delegation.ok) {
throw new Error('Failed to extract delegation');
}

// Add proof that this agent has been delegated capabilities on the space
const space = await client.addSpace(delegation.ok);
client.setCurrentSpace(space.did());

// READY to go!
}
```

#### User-owned
```mermaid
sequenceDiagram
participant User
participant Application backend
participant web3.storage w3up service
Application backend->>User: Front end code that includes w3up-client
User->>web3.storage w3up service: (If needed) Create Space and register it
User->>web3.storage w3up service: (If needed) Use Agent email verification to "log in" to Space
User->>web3.storage w3up service: Upload data using w3up-client
```
- If you want your user to own their own Space, you'll likely be relying on the `w3up-client` methods to create a Space, authorize the Space, and authorize the Agent on the end user-side; from there they can run any of the `upload` methods
- Doing this does take some of the UX out of your control; for instance, when web3.storage fully launches with w3up, your users will have to set up their payment methods with web3.storage
- Note that this alone does not give visibility into which of your end users are uploading what; to track this, you'll probably need them to send you that information separately (e.g., once they've run `upload` and get back a content CID, you can have them send that CID to you for tracking)
Expand Down Expand Up @@ -784,6 +904,7 @@ Dual-licensed under [MIT + Apache 2.0](https://github.com/web3-storage/w3up-clie
[docs]: https://web3-storage.github.io/w3up-client
[docs-Client]: https://web3-storage.github.io/w3up-client/classes/client.Client.html
[docs-Client#agent]: https://web3-storage.github.io/w3up-client/classes/client.Client.html#agent
[docs-Client#createDelegation]: https://web3-storage.github.io/w3up-client/classes/client.Client.html#createDelegation
[docs-Client#createSpace]: https://web3-storage.github.io/w3up-client/classes/client.Client.html#createSpace
[docs-Client#setCurrentSpace]: https://web3-storage.github.io/w3up-client/classes/client.Client.html#setCurrentSpace
[docs-Client#registerSpace]: https://web3-storage.github.io/w3up-client/classes/client.Client.html#registerSpace
Expand Down

0 comments on commit 329354d

Please sign in to comment.