ucanto icon indicating copy to clipboard operation
ucanto copied to clipboard

ucanto server onInvocationHandled callback

Open vasco-santos opened this issue 3 years ago • 4 comments

We are implementing store/* + upload/* in https://github.com/web3-storage/upload-api/ and we want to perform asynchronous post processing on ucan invocations handled by the upload-api service.

We currently need to decode the CBOR in the end of the invocation handling to properly add it to our processing system.

const bytes = Buffer.from(request.body, 'base64')
const car = await CAR.codec.decode(bytes)
const root = car.roots[0].cid.toString()
const cbor = CBOR.codec.decode(car.roots[0].bytes)

Having ucanto-server to support something like onInvocationHandled callback in Server.create or emitting an Event would be great to pass the handled CBOR invocation. Thoughts about this @Gozala ?

vasco-santos avatar Dec 08 '22 16:12 vasco-santos

provide(capability, handler) used in servers is a decorator that simply does the validation, you could simply decorate it with another function that does something with the the passed invocation + context

https://github.com/web3-storage/ucanto/blob/e97bd8e15d5e42a3e9be2ce949acdd18de543dc1/packages/server/src/handler.js#L17-L35

It is also worth pointing out that Invocation passed is just a delegation with single capability

https://github.com/web3-storage/ucanto/blob/e97bd8e15d5e42a3e9be2ce949acdd18de543dc1/packages/interface/src/lib.ts#L174-L175

Which in turn has both cid bytes and data fields that correspond to the cid, block bytes and decoded block cbor (assuming it was in CBOR, it could be JWT as well).

https://github.com/web3-storage/ucanto/blob/e97bd8e15d5e42a3e9be2ce949acdd18de543dc1/packages/interface/src/lib.ts#L126-L144

So you should be able to store invocation block either in the handler or use a decorator to do it before or after handler runs. Unfortunately we do not retain the CAR CID we received the invocation from, perhaps we could add it as metadata to invocation / delegation if it's needed.

Gozala avatar Dec 10 '22 22:12 Gozala

Also please note that assumption here is incorrect

const bytes = Buffer.from(request.body, 'base64')
const car = await CAR.codec.decode(bytes)
const root = car.roots[0].cid.toString()
const cbor = CBOR.codec.decode(car.roots[0].bytes)

Above seems to assume there will be a single invocation in the CAR, but in practice it could be multiple each corresponding to won root.

I also don't think body should be base64 encoded string (unless it's some other AWS quirk)

Gozala avatar Dec 10 '22 22:12 Gozala

@vasco-santos from our conversation I was under impression that ideally we'd just add toJSON method to delegation so you could get a JSON corresponding to the invocation block. delegation.bytes already give you block bytes and delegation.cid give you the CID of the invocation.

Would that be sufficient or do we need more than that ?

Gozala avatar Dec 10 '22 22:12 Gozala

My initial goal was to make it in a way that all handlers could benefit from this out of the box. However, we are now seeing a use case that makes us need to rethink this. So, adding a wrapper on the handler will actually need to be the way to go.

I also don't think body should be base64 encoded string (unless it's some other AWS quirk)

Yeah, is AWS quirk.

Above seems to assume there will be a single invocation in the CAR,

Oh yes, this is good to know!

@vasco-santos from our conversation I was under impression that ideally we'd just add toJSON method to delegation so you could get a JSON corresponding to the invocation block. delegation.bytes already give you block bytes and delegation.cid give you the CID of the invocation. Would that be sufficient or do we need more than that ?

I think this is enough, but I still want to make sure if we want the actual CAR cid. I will sync with Oli on this too before

vasco-santos avatar Dec 12 '22 13:12 vasco-santos