Skip to content

Commit

Permalink
feat: support execution of materialized invocations (#199)
Browse files Browse the repository at this point in the history
* feat: support execution of delegations

* chore: add one more test
  • Loading branch information
Gozala committed Jan 20, 2023
1 parent 42a5a55 commit 275bc24
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 88 deletions.
39 changes: 38 additions & 1 deletion packages/client/test/client.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as Service from './service.js'
import { alice, bob, mallory, service as w3 } from './fixtures.js'
import fetch from '@web-std/fetch'

test('encode inovocation', async () => {
test('encode invocation', async () => {
/** @type {Client.ConnectionView<Service.Service>} */
const connection = Client.connect({
id: w3,
Expand Down Expand Up @@ -225,3 +225,40 @@ test('execute', async () => {
url: 'http://localhost:9090/',
})
})

test('execute with delegations', async () => {
const car = await CAR.codec.write({
roots: [await CBOR.codec.write({ hello: 'world ' })],
})

const add = Client.invoke({
issuer: bob,
audience: w3,
capability: {
can: 'store/add',
with: bob.did(),
nb: { link: car.cid },
},
proofs: [],
})

const [e1] = await connection.execute(await add.delegate())

assert.deepEqual(e1, {
error: true,
name: 'UnknownDIDError',
message: `DID ${bob.did()} has no account`,
did: bob.did(),
})

// fake register alice
service.access.accounts.register(bob.did(), 'did:email:[email protected]', car.cid)

const [r1] = await connection.execute(await add.delegate())
assert.deepEqual(r1, {
with: bob.did(),
link: car.cid,
status: 'upload',
url: 'http://localhost:9090/',
})
})
4 changes: 4 additions & 0 deletions packages/core/src/delegation.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ export class Delegation {
return it(this)
}

delegate() {
return this
}

/**
* @returns {API.DelegationJSON<this>}
*/
Expand Down
19 changes: 19 additions & 0 deletions packages/core/test/delegation.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,3 +249,22 @@ test('toJSON delegation chain', async () => {
},
})
})

test('.delegate() return same value', async () => {
const ucan = await delegate({
issuer: alice,
audience: w3,
capabilities: [
{
with: alice.did(),
can: 'test/echo',
nb: {
message: 'data:1',
},
},
],
expiration: Infinity,
})

assert.equal(ucan.delegate(), ucan)
})
8 changes: 5 additions & 3 deletions packages/interface/src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ export interface Delegation<C extends Capabilities = Capabilities> {
version: UCAN.Version

toJSON(): DelegationJSON<this>
delegate(): Await<Delegation<C>>
}

export type DelegationJSON<T extends Delegation = Delegation> = ToJSON<
Expand Down Expand Up @@ -229,13 +230,14 @@ export interface InvocationOptions<C extends Capability = Capability>
capability: C
}

export interface IssuedInvocation<C extends Capability = Capability>
extends DelegationOptions<[C]> {
readonly issuer: Signer
export interface IssuedInvocation<C extends Capability = Capability> {
readonly issuer: Principal
readonly audience: Principal
readonly capabilities: [C]

readonly proofs: Proof[]

delegate(): Await<Delegation<[C]>>
}

export type ServiceInvocation<
Expand Down
2 changes: 1 addition & 1 deletion packages/transport/src/car.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const encode = async (invocations, options) => {
const roots = []
const blocks = new Map()
for (const invocation of invocations) {
const delegation = await Delegation.delegate(invocation, options)
const delegation = await invocation.delegate()
roots.push(delegation.root)
for (const block of delegation.export()) {
blocks.set(block.cid.toString(), block)
Expand Down
2 changes: 1 addition & 1 deletion packages/transport/src/jwt.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const encode = async batch => {
/** @type {string[]} */
const body = []
for (const invocation of batch) {
const delegation = await Delegation.delegate(invocation)
const delegation = await invocation.delegate()

body.push(`${delegation.cid}`)
for (const proof of iterate(delegation)) {
Expand Down
81 changes: 40 additions & 41 deletions packages/transport/test/car.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { test, assert } from './test.js'
import * as CAR from '../src/car.js'
import * as CBOR from '../src/cbor.js'
import { delegate, Delegation, UCAN, parseLink, isLink } from '@ucanto/core'
import {
delegate,
invoke,
Delegation,
UCAN,
parseLink,
isLink,
} from '@ucanto/core'
import * as UTF8 from '../src/utf8.js'
import { alice, bob, mallory, service } from './fixtures.js'
import { CarReader } from '@ipld/car/reader'
Expand All @@ -15,18 +22,16 @@ test('encode / decode', async () => {
const expiration = 1654298135

const request = await CAR.encode([
{
invoke({
issuer: alice,
audience: bob,
capabilities: [
{
can: 'store/add',
with: alice.did(),
},
],
capability: {
can: 'store/add',
with: alice.did(),
},
expiration,
proofs: [],
},
}),
])

assert.deepEqual(request.headers, {
Expand Down Expand Up @@ -58,17 +63,15 @@ test('encode / decode', async () => {

test('decode requires application/car contet type', async () => {
const { body } = await CAR.encode([
{
invoke({
issuer: alice,
audience: bob,
capabilities: [
{
can: 'store/add',
with: alice.did(),
},
],
capability: {
can: 'store/add',
with: alice.did(),
},
proofs: [],
},
}),
])

try {
Expand All @@ -87,18 +90,16 @@ test('decode requires application/car contet type', async () => {
test('accepts Content-Type as well', async () => {
const expiration = UCAN.now() + 90
const request = await CAR.encode([
{
invoke({
issuer: alice,
audience: bob,
capabilities: [
{
can: 'store/add',
with: alice.did(),
},
],
capability: {
can: 'store/add',
with: alice.did(),
},
proofs: [],
expiration,
},
}),
])

const [invocation] = await CAR.decode({
Expand All @@ -121,6 +122,8 @@ test('accepts Content-Type as well', async () => {
expiration,
})

assert.deepEqual({ ...request }, { ...(await CAR.encode([delegation])) })

assert.deepEqual(invocation.bytes, delegation.bytes)
})

Expand All @@ -139,18 +142,16 @@ test('delegated proofs', async () => {
const expiration = UCAN.now() + 90

const outgoing = await CAR.encode([
{
invoke({
issuer: bob,
audience: service,
capabilities: [
{
can: 'store/add',
with: alice.did(),
},
],
capability: {
can: 'store/add',
with: alice.did(),
},
proofs: [proof],
expiration,
},
}),
])

const reader = await CarReader.fromBytes(outgoing.body)
Expand Down Expand Up @@ -194,18 +195,16 @@ test('omit proof', async () => {
const expiration = UCAN.now() + 90

const outgoing = await CAR.encode([
{
invoke({
issuer: bob,
audience: service,
capabilities: [
{
can: 'store/add',
with: alice.did(),
},
],
capability: {
can: 'store/add',
with: alice.did(),
},
proofs: [proof.cid],
expiration,
},
}),
])

const reader = await CarReader.fromBytes(outgoing.body)
Expand Down
Loading

0 comments on commit 275bc24

Please sign in to comment.