storacha-network / w3up

⁂ w3up protocol implementation
https://github.com/storacha-network/specs
Other
54 stars 19 forks source link

How to use delegation on the client side? #1514

Closed adamazad closed 2 months ago

adamazad commented 2 months ago

Hi, I'm following the example about using delegation to upload directly to the network. I have a next.js route located at /api/w3up/delegation:

// app/api/w3up/delegation/route.ts

import * as DID from '@ipld/dag-ucan/did';
import { getWeb3StorageClient } from './getWeb3StorageClient';
import { NextResponse } from 'next/server';

export async function GET() {
  const web3StorageClient = await getWeb3StorageClient();
  const did = web3StorageClient.did();

  // Create a delegation for a specific DID
  const audience = DID.parse(did);
  const abilities = ['store/add', 'upload/add'];
  const expiration = Math.floor(Date.now() / 1000) + 60 * 60 * 24; // 24 hours from now
  const delegation = await web3StorageClient.createDelegation(audience, abilities, {
    expiration,
  });

  // Serialize the delegation and send it to the client
  const archive = await delegation.archive();
  const u4 = archive.ok;

  return NextResponse.json({
    delegation: u4?.toString(),
  });
}

on the frontend, I have a hook to create a client:

// api/hooks/useWeb3StorageClient.ts

import * as Delegation from '@ucanto/core/delegation';
import * as Client from '@web3-storage/w3up-client';

import { useEffect, useState } from 'react';

export async function getWeb3StorageClient(): Promise<{
  error: Error | null;
  client: Client.Client | null;
}> {
  try {
    // Fetch the delegation from the backend
    const response = await fetch(`/api/w3up/delegation`);
    const data = await response.arrayBuffer();

    console.log('getDelegationResponse', data);

    const delegationUint8Array = new Uint8Array(data);

    console.log('delegationUint8Array', delegationUint8Array);

    const client = await Client.create();
    // Deserialize the delegation
    const delegation = await Delegation.extract(delegationUint8Array);

    if (!delegation.ok) {
      throw delegation.error as Error;
    }

    // Add proof that this agent has been delegated capabilities on the space
    const space = await client.addSpace(delegation.ok);
    client.setCurrentSpace(space.did());

    return {
      error: null,
      client,
    };
  } catch (error) {
    return {
      error: error as Error,
      client: null,
    };
  }
}

export function useWeb3StorageClient() {
  const [ready, setReady] = useState(false);
  const [client, setClient] = useState<Client.Client | null>(null);
  const [error, setError] = useState<Error | null>(null);

  useEffect(() => {
    if (ready) {
      return;
    }

    getWeb3StorageClient().then(({ error, client }) => {
      if (error) {
        console.error(error);
        setReady(false);
        setClient(null);
        setError(error);
        return;
      }

      setClient(client);
      setReady(true);
      setError(null);
    });
  }, []);

  return { ready, client, error };
}

I get the following error:

image
travis commented 2 months ago

hm, unless I'm reading wrong, I think that in your server code you are returning the delegation inside a json blob but then in the client you are trying to read the json as CBOR - this is, of course, failing.

adamazad commented 2 months ago

Closing this in favor of #1515