Skip to content

Commit

Permalink
feat: implement main service logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Gozala committed Apr 22, 2022
1 parent 866052c commit abca293
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 115 deletions.
49 changes: 15 additions & 34 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,6 @@ export type Proof<C extends UCAN.Capability = UCAN.Capability> =
| UCAN.Proof<C>
| Delegation<C>

export interface Instruction<T extends UCAN.Capability = UCAN.Capability> {
issuer: UCAN.DID
audience: UCAN.DID
capabilities: [T]

proofs?: Proof[]
}

export interface Invocation<
Capability extends UCAN.Capability = UCAN.Capability
> {
Expand Down Expand Up @@ -136,7 +128,7 @@ export type ServiceInvocations<T> = Invocation &

type SubServiceInvocations<T, Path extends string> = {
[Key in keyof T]: T[Key] extends (
input: Instruction<infer Capability>
input: Invocation<infer Capability>
) => Await<Result<any, any>>
? Invocation<Capability>
: SubServiceInvocations<Path, Key & string>
Expand All @@ -157,7 +149,7 @@ export type InvocationService<
? { [Key in Base]: InvocationService<Capability, Path> }
: {
[Key in Ability]: (
input: Instruction<Capability>
input: Invocation<Capability>
) => Await<Result<any, any>>
}

Expand All @@ -167,7 +159,7 @@ export type ExecuteInvocation<
Ability extends string = Capability["can"]
> = Ability extends `${infer Base}/${infer Path}`
? ExecuteInvocation<Capability, T[Base], Path>
: T[Ability] extends (input: Instruction<Capability>) => infer Out
: T[Ability] extends (input: Invocation<Capability>) => infer Out
? Out
: never

Expand All @@ -176,14 +168,14 @@ export type Result<T, E extends Error = Error> =
| (E & { ok?: false })

type StoreAdd = (
input: Instruction<{ can: "store/add"; with: UCAN.DID; link: UCAN.Link }>
input: Invocation<{ can: "store/add"; with: UCAN.DID; link: UCAN.Link }>
) => Result<
| { status: "done"; with: UCAN.DID; link: UCAN.Link }
| { status: "pending"; with: UCAN.DID; link: UCAN.Link; url: string }
>

type StoreRemove = (
input: Instruction<{ can: "store/remove"; with: UCAN.DID; link: UCAN.Link }>
input: Invocation<{ can: "store/remove"; with: UCAN.DID; link: UCAN.Link }>
) => Result<boolean>

type Store = {
Expand Down Expand Up @@ -232,20 +224,11 @@ export declare function connection<T>(): Connection<T>

export type Service = Record<
string,
(input: Instruction<any>) => Promise<Result<any, any>>
(input: Invocation<any>) => Promise<Result<any, any>>
>

export type Await<T> = T | PromiseLike<T> | Promise<T>

// export declare function invoke<In extends Invoke, T extends Service>(
// connection: Connection<T>,
// input: In
// ): {
// [Key in keyof T]: T[Key] extends (input: ToInstruction<In>) => infer Out
// ? Out
// : never
// }[keyof T]

export declare function invoke<Capability extends UCAN.Capability>(
input: IssuedInvocation<Capability>
): IssuedInvocationView<Capability>
Expand Down Expand Up @@ -332,7 +315,7 @@ export type InstructionHandler<
In extends Input = Input,
T = unknown,
X extends Error = Error
> = (instruction: Instruction<In & { can: Ability }>) => Result<T, X>
> = (instruction: Invocation<In & { can: Ability }>) => Result<T, X>

export declare function query<In extends QueryInput>(query: In): Query<In>

Expand All @@ -347,7 +330,7 @@ export declare function select<In extends Input, S extends Selector = true>(
selector?: S
): S extends true ? Select<In, true> : Select<In, S>

type Match<In extends Instruction, T extends Service> = {
type Match<In extends Invocation, T extends Service> = {
[Key in keyof T]: T[Key] extends (input: In) => infer Out ? Out : never
}[keyof T]

Expand Down Expand Up @@ -432,15 +415,13 @@ const q = query({
})

const r2 = q.queryService().store.remove({
issuer: alice.did(),
audience: bob.did(),
capabilities: [
{
can: "store/remove",
with: alice.did(),
link: car,
},
],
issuer: alice,
audience: bob,
capability: {
can: "store/remove",
with: alice.did(),
link: car,
},
})

const r3 = q.execute(host)
Expand Down
22 changes: 22 additions & 0 deletions src/claim/access.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as API from "./api.js"
import { ok, the } from "../../test/services/util.js"
export * from "./api.js"

/**
* @template {API.CapabilityView} C
* @param {API.Capability} capability
* @param {API.UCANView<C>} ucan
* @returns {API.Result<API.Access<C>, API.InvalidClaim<C>>}
*/
export const access = (capability, ucan) => {
return ok({
ok: the(true),
capability: ucan.capabilities[0],
to: ucan.ucan.audience,
proof: {
by: ucan.ucan.issuer,
granted: [],
proof: null,
},
})
}
45 changes: 27 additions & 18 deletions src/claim/api.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as UCAN from '@ipld/dag-ucan'
import type { Result } from '../api.js'
import * as UCAN from "@ipld/dag-ucan"
import type { Result } from "../api.js"

export type { Result }
export * from '@ipld/dag-ucan'
export * from "@ipld/dag-ucan"

/**
* Function checks if the claimed capability is met by given set of capaibilites. Note that function takes capability
Expand All @@ -24,7 +24,7 @@ export * from '@ipld/dag-ucan'
export declare function claim<C extends CapabilityView>(
capability: C,
given: C[]
): Result<IterableIterator<Evidence<C>>, EscalationError<C>[]>
): Result<IterableIterator<Evidence<C>>, ClaimError<C>>

/**
* Represents succesfully parsed capability. Idea is that user could provide capability parser that UCAN
Expand All @@ -44,13 +44,17 @@ interface Evidence<C> {
capaibilites: C[]
}

export interface ClaimError<C> extends Error {
esclacations: EscalationError<C>[]
}

/**
* Represents capability escalation and contains non empty set of
* contstraint violations.
*/

export interface EscalationError<C> extends RangeError {
readonly name: 'EscalationError'
readonly name: "EscalationError"

/**
* claimed capability
Expand All @@ -72,7 +76,7 @@ export interface EscalationError<C> extends RangeError {
* Represents specific constraint violation by the claimed capability.
*/
export interface ConstraintViolationError<C> extends RangeError {
readonly name: 'ConstraintViolationError'
readonly name: "ConstraintViolationError"
/**
* Constraint that was violated.
*/
Expand Down Expand Up @@ -101,13 +105,14 @@ export interface Constraint<C> {
* Access internally utilized `claim` function and walks up the proof chain until it is able to proove that claim is unfounded.
*/

declare function access<C extends CapabilityView>(
export declare function access<C extends CapabilityView>(
capability: UCAN.Capability,
ucan: UCANView<C>
): Result<Access<C>, InvalidClaim<C>>

interface InvalidClaim<C> {
readonly name: 'InvalidClaim'
export interface InvalidClaim<C extends CapabilityView = CapabilityView>
extends Error {
readonly name: "InvalidClaim"
readonly claim: C
readonly by: UCAN.DID
// I know to is broken english but "from" is too ambigius as it can be "claim from gozala" or "gozala claimed car from robox"
Expand All @@ -122,7 +127,7 @@ interface InvalidClaim<C> {
}

interface ExpriedClaim<C> {
readonly name: 'ExpriedClaim'
readonly name: "ExpriedClaim"
readonly by: UCAN.DID
readonly to: UCAN.DID

Expand All @@ -132,7 +137,7 @@ interface ExpriedClaim<C> {
}

interface InactiveClaim<C> {
readonly name: 'InactiveClaim'
readonly name: "InactiveClaim"
readonly from: UCAN.DID
readonly to: UCAN.DID

Expand All @@ -142,31 +147,31 @@ interface InactiveClaim<C> {
}

interface UnfundedClaim<C> {
readonly name: 'UnfundedClaim'
readonly name: "UnfundedClaim"
readonly claim: C

readonly by: UCAN.DID
readonly to: UCAN.DID
}

interface ViolatingClaim<C> {
readonly name: 'ViolatingClaim'
readonly name: "ViolatingClaim"
readonly from: UCAN.DID
readonly to: UCAN.DID

readonly claim: C
readonly escalates: EscalationError<C>[]
}

interface Access<C> {
export interface Access<C> {
ok: true
capability: C
to: UCAN.DID
to: UCAN.DIDView
proof: Authorization<C>
}

interface Authorization<C> {
by: UCAN.DID
export interface Authorization<C> {
by: UCAN.DIDView
granted: C[]

proof: Authorization<C> | null
Expand All @@ -185,7 +190,11 @@ export interface CapabilityParser<C> {
/**
* Returns either succesfully parsed capability or unknown capability back
*/
parse(capability: UCAN.Capability): Result<C, UCAN.Capability>
parse(capability: UCAN.Capability): Result<C, UnknownCapability>
}

interface UnknownCapability extends Error {
capability: UCAN.Capability
}

type Time = number
5 changes: 5 additions & 0 deletions test/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,8 @@ export interface DoesNotHasError extends RangeError {
export interface UnknownDIDError extends RangeError {
name: "UnknownDIDError"
}

export interface InvalidInvocation extends Error {
name: "InvalidInvocation"
link: Link
}
16 changes: 8 additions & 8 deletions test/server.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,34 +38,34 @@ describe("server", () => {
const service = {
store: {
/**
* @param {Client.Instruction<Add>} ucan
* @param {Client.Invocation<Add>} ucan
* @returns {Promise<Client.Result<Added|Upload, string>>}
*/
async add(ucan) {
const [action] = ucan.capabilities
if (action.with === ucan.issuer) {
const { capability } = ucan
if (capability.with === ucan.issuer.did()) {
// can do it
} else {
}
return {
ok: true,
value: {
with: action.with,
link: action.link,
with: capability.with,
link: capability.link,
status: "upload",
url: "http://localhost:9090/",
},
}
},
/**
* @param {Client.Instruction<Remove>} ucan
* @param {Client.Invocation<Remove>} ucan
* @returns {Promise<Client.Result<Remove, string>>}
*/
async remove(ucan) {
const [action] = ucan.capabilities
const { capability } = ucan
return {
ok: true,
value: action,
value: capability,
}
},
},
Expand Down
Loading

0 comments on commit abca293

Please sign in to comment.