# 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/