Skip to content

Commit

Permalink
feat!: consume access and upload client (#159)
Browse files Browse the repository at this point in the history
This PR makes breaking changes to core and framework components to
integrate the access agent (+ucanto 0.9) and the new upload client.

resolves #127

BREAKING CHANGE: core and framework components have changed
considerably. Please read the updated doucmentation.

Co-authored-by: Yusef Napora <yusef@napora.org>
Co-authored-by: Travis Vachon <travis.vachon@gmail.com>
  • Loading branch information
3 people authored Dec 14, 2022
1 parent fdb917f commit e36d842
Show file tree
Hide file tree
Showing 81 changed files with 14,605 additions and 8,314 deletions.
192 changes: 107 additions & 85 deletions docs/keyring-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
```sh
npm install @w3ui/keyring-core
```

## Usage

```js
Expand All @@ -14,138 +13,161 @@ import * as KeyringCore from '@w3ui/keyring-core'

## Exports

* [`loadDefaultIdentity`](#loaddefaultidentity)
* [`loadIdentity`](#loadidentity)
* [`createIdentity`](#createidentity)
* [`sendVerificationEmail`](#sendverificationemail)
* [`waitIdentityVerification`](#waitidentityverification)
* [`registerIdentity`](#registeridentity)
* [`removeIdentity`](#removeidentity)
* [`storeIdentity`](#storeidentity)
**Interfaces**

---
- [`KeyringContextState`](#keyringcontextstate)
- [`KeyringContextActions`](#keyringcontextactions)

### `loadDefaultIdentity`
**Classes**

```ts
loadDefaultIdentity (): Promise<Identity | undefined>
```
- [`Space`](#space)
- [`name`](#name)
- [`did`](#did)
- [`registered`](#registered)
- [`meta`](#meta)

Load the default identity on this device, returning `undefined` if none exist.
**Functions**

Example:
- [`createAgent`](#createagent)
- [`getCurrentSpace`](#getcurrentspace)
- [`getSpaces`](#getspaces)

```js
const identity = await loadDefaultIdentity()
if (identity) {
console.log(`DID: ${identity.signingPrincipal.did()}`)
} else {
console.log('No identity registered')
}
```
---

### `KeyringContextState`

### `loadIdentity`
Interface for keyring state. Implementations are framework-specific and found in each framework's `-keyring` module (e.g. `@w3ui/react-keyring`).

```ts
loadIdentity ({ email: string }): Promise<Identity | undefined>
export interface KeyringContextState {
/**
* The current space.
*/
space?: Space
/**
* Spaces available to this agent.
*/
spaces: Space[]
/**
* The current user agent (this device).
*/
agent?: Signer
}
```

Load an identity matching the passed argument from secure storage, returning `undefined` if not found.
### `KeyringContextActions`

Example:
Interface for keyring actions. Implementations are framework-specific and found in each framework's `-keyring` module (e.g. `@w3ui/react-keyring`).

```js
const identity = await loadIdentity('test@example.com')
if (identity) {
console.log(`DID: ${identity.signingPrincipal.did()}`)
} else {
console.log('Not found')
```ts
export interface KeyringContextActions {
/**
* Load the user agent and all stored data from secure storage.
*/
loadAgent: () => Promise<void>
/**
* Unload the user agent and all stored data from secure storage. Note: this
* does not remove data, use `resetAgent` if that is desired.
*/
unloadAgent: () => Promise<void>
/**
* Unload the current space and agent from memory and remove from secure
* storage. Note: this removes all data and is unrecoverable.
*/
resetAgent: () => Promise<void>
/**
* Create a new space with the passed name and set it as the current space.
*/
createSpace: (name?: string) => Promise<DID>
/**
* Use a specific space.
*/
setCurrentSpace: (did: DID) => Promise<void>
/**
* Register the current space, verify the email address and store in secure
* storage. Use cancelRegisterSpace to abort. Automatically sets the
* newly registered space as the current space.
*/
registerSpace: (email: string) => Promise<void>
/**
* Abort an ongoing account registration.
*/
cancelRegisterSpace: () => void,
/**
* Get all the proofs matching the capabilities. Proofs are delegations with
* an audience matching the agent DID.
*/
getProofs: (caps: Capability[]) => Promise<Proof[]>
}
```

### `createIdentity`
### `Space`

```ts
createIdentity ({ email: string }): Promise<UnverifiedIdentity>
```
A subclass of ucanto's `Principal` type that represents a storage location uniquely identified by its DID.

Create a new identity.
A `Space` has the following methods:

Example:
#### `name`

```js
const unverifiedIdentity = await createIdentity('test@example.com')
console.log(`DID: ${unverifiedIdentity.signingPrincipal.did()}`)
```ts
name(): String
```

### `sendVerificationEmail`
Returns the "friendly" name for the space, or the space DID if no name is set.

#### `did`

```ts
function sendVerificationEmail (identity: UnverifiedIdentity): Promise<void>
did(): DID
```

Example:
Returns the DID string for the space.

```js
const unverifiedIdentity = await createIdentity('test@example.com')
console.log(`DID: ${unverifiedIdentity.signingPrincipal.did()}`)
await sendVerificationEmail(unverifiedIdentity)
```

### `waitIdentityVerification`
#### `registered`

```ts
function waitIdentityVerification (identity: UnverifiedIdentity, options?: { signal: AbortSignal }): Promise<{ identity: VerifiedIdentity, proof: Delegation<[IdentityRegister]> }>
registered(): Boolean
```

Wait for identity verification to complete (user must click link in email).
Returns `true` if the space has been registered with the service.

Example:
#### `meta`

```js
const unverifiedIdentity = await createIdentity('test@example.com')
console.log(`DID: ${unverifiedIdentity.signingPrincipal.did()}`)
await sendVerificationEmail(unverifiedIdentity)
const controller = new AbortController()
const { identity, proof } = await waitIdentityVerification(unverifiedIdentity, {
signal: controller.signal
})
```ts
meta(): Record<string, any>
```

### `registerIdentity`
Returns user-defined metadata attached to the space.

### `createAgent`

```ts
registerIdentity (identity: VerifiedIdentity, proof: Delegation<[IdentityRegister]>): Promise<void>
createAgent (options: CreateAgentOptions = {}): Promise<Agent>
```

Register a verified identity with the service, passing the proof of verification (a delegation allowing registration).
Create the user agent and load account information from secure storage.

Example:
`CreateAgentOptions` accepts the following fields:

```js
const unverifiedIdentity = await createIdentity('test@example.com')
console.log(`DID: ${unverifiedIdentity.signingPrincipal.did()}`)
await sendVerificationEmail(unverifiedIdentity)
const controller = new AbortController()
const { identity, proof } = await waitIdentityVerification(unverifiedIdentity, {
signal: controller.signal
})
await registerIdentity(identity, proof)
```
| field | type | description |
| ------------------ | ----------------------- | ---------------------------------------------------- |
| `servicePrincipal` | ucanto `Principal` | contains the DID & public key for the access service |
| `connection` | ucanto `ConnectionView` | a connection to the access service |

If `servicePrincipal` or `connection` are not provided, defaults to the production service.

### `removeIdentity`
### `getCurrentSpace`

```ts
removeIdentity (identity: Identity): Promise<void>
getCurrentSpace(agent: Agent): Space | undefined
```

Remove the passed identity from secure storage.

Returns the given `agent`'s current space, or `undefined` if the agent has no current space set.

# `storeIdentity`
### `getSpaces`

```ts
storeIdentity (identity: Identity): Promise<void>
getSpaces(agent: Agent): Space[]
```

Store identity locally in secure storage and set the default.
Returns an array of all spaces that the agent has access to.
59 changes: 18 additions & 41 deletions docs/react-keyring.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,67 +14,44 @@ import * as ReactKeyring from '@w3ui/react-keyring'

## Exports

* [`AuthProvider`](#authprovider)
* [`useAuth`](#useauth)
* [`KeyringProvider`](#keyringprovider)
* [`useKeyring`](#usekeyring)

---

### `AuthProvider`
### `KeyringProvider`

Provider for authentication with the service.
Provider for managing agent creation, key management, and space registration with the service.

Example:

```jsx
import { AuthProvider } from '@w3ui/react-keyring'
import { KeyringProvider } from '@w3ui/react-keyring'

function App () {
return (
<AuthProvider>
<KeyringProvider>
{/* Application pages/components */}
</AuthProvider>
</KeyringProvider>
)
}
```

### `useAuth`
You can optionally target a non-production instance of the access service by setting the `servicePrincipal` and `connection` props on `KeyringProvider`. The `servicePrincipal` should be set to the service's DID, and `connection` should be a ucanto `ConnectionView` to the service instance.

### `useKeyring`

```ts
const auth = useAuth()
const [keyringState, keyringActions] = useKeyring()
```

Hook to allow use of the [`AuthProvider`](#authprovider) value. The value returned is an `AuthContextValue`:
Hook to allow use of the [`KeyringProvider`](#keyringprovider) value. The value returned is a `KeyringContextValue`:

```ts
interface AuthContextValue {
/**
* The current identity
*/
identity?: Identity
/**
* Load the default identity from secure storage.
*/
loadDefaultIdentity: () => Promise<void>
/**
* Unload the current identity from memory.
*/
unloadIdentity: () => Promise<void>
/**
* Unload the current identity from memory and remove from secure storage.
*/
unloadAndRemoveIdentity: () => Promise<void>
/**
* Register a new identity, verify the email address and store in secure
* storage. Use cancelRegisterAndStoreIdentity to abort.
*/
registerAndStoreIdentity: (email: string) => Promise<void>
/**
* Abort an ongoing identity registration.
*/
cancelRegisterAndStoreIdentity: () => void
/**
* Authentication status of the current identity.
*/
authStatus: AuthStatus
}
export type KeyringContextValue = [
state: KeyringContextState,
actions: KeyringContextActions
]
```
See [keyring-core.md](./keyring-core.md) for the definitions for [`KeyringContextState`](./keyring-core.md#keyringcontextstate) and [`KeyringContextActions`](./keyring-core.md#keyringcontextactions).
26 changes: 5 additions & 21 deletions docs/react-uploader.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import * as ReactUploader from '@w3ui/react-uploader'

### `UploaderProvider`

Provider for an `Uploader` which allows uploads to the service. Note that this provider uses [`useAuth`](./react-keyring#useauth) and provides an `uploader` only when a current identity is loaded.
Provider for an `Uploader` which allows uploads to the service. Note that this provider uses [`useKeyring`](./react-keyring#usekeyring) and provides an `uploader` only when an Agent with a registered space is loaded.

Example:

Expand All @@ -37,10 +37,12 @@ function App () {
}
```

You can optionally target a non-production instance of the upload service by setting the `servicePrincipal` and `connection` props on `UploaderProvider`. The `servicePrincipal` should be set to the service's DID, and `connection` should be a ucanto `ConnectionView` to the service instance.

### `useUploader`

```ts
const [progress, uploader] = useUploader()
const [uploaderState, uploaderActions] = useUploader()
```

Hook to allow use of the [`UploaderProvider`](#uploaderprovider) value. The value returned is an `UploaderContextValue`:
Expand All @@ -50,24 +52,6 @@ type UploaderContextValue = [
state: UploaderContextState,
actions: UploaderContextActions
]

interface UploaderContextState {
uploadedCarChunks: CarChunkMeta[]
}

interface UploaderContextActions {
/**
* Upload a single file to the service.
*/
uploadFile: (file: Blob) => Promise<CID>
/**
* Upload a directory of files to the service.
*/
uploadDirectory: (files: File[]) => Promise<CID>
/**
* Upload CAR bytes to the service.
*/
uploadCarChunks: (chunks: AsyncIterable<CarData>) => Promise<void>
}
```
See [uploader-core.md](./uploader-core.md) for the definitions for [`UploaderContextState`](./uploader-core.md#uploadercontextstate) and [`UploaderContextActions`](./uploader-core.md#uploadercontextactions).
Loading

0 comments on commit e36d842

Please sign in to comment.