---
# System prepended metadata

title: Capabilities for w3up Metrics/Blocking

---

# Capabilities for w3up Metrics/Blocking

Before we can bring w3up to a wider audience we need better administrative tools. This document proposes a set of UCAN capabilities that will underlie a minimum-viable set of these tools. 

A prototype implementation of these tools has been created in the https://github.com/web3-storage/w3admin repository, and is deployed at https://w3admin.vercel.app

Mock implementations of these capabilities have been created as part of the [`w3admin`](https://github.com/web3-storage/w3admin) prototype. 

Capability specifications can be found in https://github.com/web3-storage/w3admin/tree/main/src/capabilities

In-memory providers for these capabilities can be found in https://github.com/web3-storage/w3admin/blob/main/src/hooks/service.ts#L155

The remainder of this document will summarize the implementations linked above.

## User Needs

The burden of finding and blocking problematic users mostly falls on David Choi so `w3admin` was built to meet the needs he has identified.

1. `w3admin` users need to be able to search for spaces by space DID and search for customers by email address. 
2. `w3admin` users need to be able to see a space's total possible storage, allocated storage, block status and attached subscriptions as well as block or unblock a space.
3. `w3admin` users need to be able to see the customer who pays for a subscription and the space a subscription is attached to.
4. `w3admin` users need to be able to see a customer's subscriptions and whether a customer's email address or email address domain is blocked. They need to be able to block a customer's email or domain.

These needs are not exhaustive and this list is expected to grow.

## Capabilities



| Capability        | New?   | Resource   | Inputs (nb)          |
| --------          | ------ | --------   | --------             |
| customer/get      | No     | Provider   | `customer: DIDMailto`  |
| consumer/get      | Yes    | Provider   | `consumer: DIDKey` |
| subscription/get  | Yes    | Provider   | `subscription: string` |
| rate-limit/add    | Yes    | Provider   | `subject: string`, `rate: number` |
| rate-limit/remove | Yes    | Provider   | `id: string` |
| rate-limit/list   | Yes    | Provider   | `subject: string` |

### customer/get

Given a customer's `did:mailto`, return information about that customer of the given Provider.

#### inputs

`customer: DIDMailto`

#### returns

```typescript
{
  did: DIDMailto
}
```

#### errors

`CustomerNotFound`

#### capability definition

```javascript=
export const get = capability({
  can: 'customer/get',
  with: ProviderDID,
  nb: struct({
    customer: AccountDID,
  }),
  derives: (child, parent) => {
    return (
      and(equalWith(child, parent)) ||
      and(equal(child.nb.customer, parent.nb.customer, 'customer')) ||
      ok({})
    )
  },
})
```

### consumer/get

Return information about the consumer (ie, space) identified by `consumer`.

#### inputs

`consumer: DIDKey`

#### returns

```typescript
{
  did: DIDKey
  allocated: number
  total: number
  subscription: string
}
```

#### errors 

`ConsumerNotFound`

#### capability definition

```typescript=
export const get = capability({
  can: 'consumer/get',
  with: ProviderDID,
  nb: struct({
    consumer: Schema.string()
  }),
  derives: (child, parent) => {
    return (
      and(equalWith(child, parent)) ||
      and(equal(child.nb.consumer, parent.nb.consumer, 'consumer')) ||
      ok({})
    )
  },
})
```

### subscription/get

Given a subscription ID, return information about the identified subscription.

#### inputs

`subscription: string` 

#### returns

```typescript=
{
  customer: DIDMailto
  consumer: DIDKey
}
```

#### errors

`SubscriptionNotFound`

#### capability definition

```javascript=
export const get = capability({
  can: 'subscription/get',
  with: ProviderDID,
  nb: struct({
    subscription: Schema.string()
  }),
  derives: (child, parent) => {
    return (
      and(equalWith(child, parent)) ||
      and(equal(child.nb.subscription, parent.nb.subscription, 'subscription')) ||
      ok({})
    )
  },
})
```


### rate-limit/add

Given a subject ID (eg, a`did:mailto`, a URL, a domain name, etc), set a rate limit for the entity represented by that ID. The semantics of both the subject and rate are intentionally abstract, and the service is expected to record them without much processing.

Consumers of rate limits are expected to query the underlying datastore where they are stored for the subjects they care about and interpret the `rate` value in a way that makes sense for their usecase.

Returns an ID that can be used to remove this limit later.

#### inputs
`subject: string`
`rate: number`

#### returns

```typescript
{
    id: string
}
```

#### errors

#### capability definition

```javascript=
export const add = capability({
  can: 'rate-limit/add',
  with: ProviderDID,
  nb: struct({
    subject: Schema.string(),
    rate: Schema.number()
  }),
  derives: (child, parent) => {
    return (
      and(equalWith(child, parent)) ||
      and(equal(child.nb.subject, parent.nb.subject, 'subject')) ||
      and(equal(child.nb.rate, parent.nb.rate, 'rate')) ||
      ok({})
    )
  },
})
```

### rate-limit/list

Given a subject ID (eg, a`did:mailto`, a URL, a domain name, etc), list all rate limits that apply to the given subject.

#### inputs
`subject: string`

#### returns

```typescript
{
    limits: [
        {
            id: '123',
            limit: 0
        },
        {
            id: '456',
            limit: 2
        }
    ]
}
```

#### errors

#### capability definition

```javascript=
export const remove = capability({
  can: 'rate-limit/list',
  with: ProviderDID,
  nb: struct({
    subject: Schema.string()
  }),
  derives: (child, parent) => {
    return (
      and(equalWith(child, parent)) ||
      and(equal(child.nb.subject, parent.nb.subject, 'subject')) ||
      ok({})
    )
  },
})
```

### rate-limit/remove

Given a rate limit ID (returned from `rate-limit/add` or `rate-limit/list`), remove the identified rate limit.

#### inputs
`id: string`

#### returns

```typescript
{}
```

#### errors

`RateLimitsNotFound`

#### capability definition

```javascript=
export const remove = capability({
  can: 'rate-limit/remove',
  with: ProviderDID,
  nb: struct({
    ids: Schema.string().array()
  }),
  derives: (child, parent) => {
    return (
      and(equalWith(child, parent)) ||
      and(equal(child.nb.id, parent.nb.id, 'id')) ||
      ok({})
    )
  },
})
```