# Actors
## Query Service
Query service implements [upload protocol][] and is basically a request router responsible for decoding requests _(that arrive in [CAR][] format)_ into [UCAN invocation][]s and route enclosed operations to a relevant subservice.
:::info
CAR payload MAY contain multiple UCANs, which in turn MAY contain multiple [operations][] defined by a protocol
:::
:::warning
💠I wonder we should limit one UCAN per one operation instead, we still can deduplicate using [CID][]s and share blocks by including them in the same [CAR][].
:::
Additionally service is also responsible for awaiting / listening on all operations to combine them back into a response _(which can be in form of event)_.
:::info
It is similar to [GraphQL][] intreface except queries are sent as [IPLD][] encoded [UCAN][]s in [CAR][] format. And responses are associated with queries by their [CID][].
:::
```ts
interface Writer<T> {
add(T): Promise<void>
}
// UCAN represents
interface UCAN<
Capabilities extends Array<{can:string, with:string}> = {can:string, with:string}[],
To extends DID = DID,
From extends = DID,
Proofs = UCAN<Capabilities, From, DID>[]
> {
issuer: From
audience: To
expiry: Time
notBefore?: Time
capabilities: Capabilities
proofs: Proofs
}
interface Revoke<ID extends CID<UCAN>> {
issuer: DID
revoke: ID
challenge: Signature<PrivateKey<DID>, `REVOKE:${ID}`>
}
type Signature <PirvateKey, Message> = Uint8Array & Phantom
interface QueryService {
query(query:CAR<Query>):unknown
}
type Query =
| UCAN<[Identify]>
| UCAN<[Authorize], DID, DID, [UCAN<[Identify]>]>
|
/**
* Incoming requests are CAR encoded set of queries that
* client may pack together for deduplication pursposes.
*/
export interface Request {
cid: CID<CAR>
body: CAR
}
/**
* Queries are represented as IPLD encoded UCANs. Each
* query may contain multiple operations encoded as
* capabilities.
*/
export interface Query {
cid: CID<UCAN>
query: UCAN
}
/**
*
*/
export type Capability =
| Identify
| Authorize
| Revoke
| Add
| Remove
export interface Identify {
can: "access/identify"
with: DID
as: Email
}
type DID = string
type Email = string
export interface Authorize {
can: "access/authorize"
with: DID
capabilities?: Capability[]
}
export interface Revoke {
can: "access/revoke"
with: DID
access:
}
// Service saves every incoming (CAR encoded)
// request keyed by it's CID.
export type Requests = StoreWriter<{
cid: CID<CAR>
car: CAR
}>
// Service saves each (UCAN encoded) query from
// the car keyed by it's CID
export type Queries extends Writer<{
cid: CID<UCAN>
query: UCAN
group: CID<CAR>
}>
export type Operations extends Writer<{
cid: CID<Operation>
// Operation Add / Remove MAY depend on
// Identify
requires?: CID<Identify>
query: UCAN
}>
interface IO {
/**
* Stores incoming (CAR encoded) request and returns correspnoding CID.
*/
storeCAR(request:CAR): Promise<void>
/**
*
*/
storeUCAN(request: UCAN): Promise<void>
}
```
## Store service
Store service is responsible for handling `{ can: "store/*" }"` capabilities of [upload protocol] service.
## Access service
Access service is responsible for handling `{ can: "access/*" }` capabilities of [upload protocol] service.
[upload protocol]:https://hackmd.io/@gozala/upload-protocol
[UCAN]:https://whitepaper.fission.codes/access-control/ucan
[did:key]:https://w3c-ccg.github.io/did-method-key/
[CAR]:https://ipld.io/specs/transport/car/carv1/
[UCAN invocation]:https://github.com/ucan-wg/spec#521-invocation-recipient-validation
[operations]:https://hackmd.io/@gozala/upload-protocol
[CID]:https://docs.ipfs.io/concepts/content-addressing/
[GraphQL]:https://graphql.org/
[IPLD]:https://ipld.io/