Skip to content

Commit

Permalink
feat: sharing spaces
Browse files Browse the repository at this point in the history
  • Loading branch information
fforbeck committed Sep 16, 2024
1 parent b1df89d commit 523c119
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 0 deletions.
34 changes: 34 additions & 0 deletions packages/w3up-client/src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,40 @@ export class Client extends Base {
return space
}

/**
* Share an existing space with another Storacha account.
* Delegates access to the space to the specified email account.
*
* @typedef {object} ShareOptions
* @property {import("./space.js").OwnedSpace} space - The space to share.
* @property {import("./types.js").EmailAddress} delegateEmail - Email of the account to share the space with.
*
* @param {ShareOptions} options
* @returns {Promise<void>} Resolves once the space is successfully shared.
* @throws {Error} - Throws an error if there is an issue delegating access to the space.
*/
async shareSpace(options) {
const { space, delegateEmail } = options

// Create a recovery for the delegate account
const recovery = await space.createRecovery(
Account.fromEmail(delegateEmail)
)

// Delegate space access to the delegate account
const result = await this.capability.access.delegate({
space: space.did(),
delegations: [recovery],
})

if (result.error) {
throw new Error(
`failed to share space with account ${delegateEmail}: ${result.error.message}`,
{ cause: result.error }
)
}
}

/* c8 ignore stop */

/**
Expand Down
80 changes: 80 additions & 0 deletions packages/w3up-client/test/client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,86 @@ export const testClient = {
await assert.rejects(alice.remove(contentCID, { shards: true }))
},
}),

shareSpace: Test.withContext({
'should share the space with another account': async (
assert,
{ client, mail, grantAccess, connect }
) => {
// Step 1: Create a client for Alice and login
const aliceEmail = '[email protected]'
const aliceLogin = client.login(aliceEmail)
const message = await mail.take()
assert.deepEqual(message.to, aliceEmail)
await grantAccess(message)
const aliceAccount = await aliceLogin

// Step 2: Alice creates a space
const space = await client.createSpace('share-space-test', {
account: aliceAccount,
})
assert.ok(space)

// Step 3: Alice shares the space with Bob
const bobEmail = '[email protected]'
await client.shareSpace({ space, delegateEmail: bobEmail })

// Step 4: Bob logs in
const bobClient = await connect()
const bobLogin = bobClient.login(bobEmail)
const bobMessage = await mail.take()
assert.deepEqual(bobMessage.to, bobEmail)
await grantAccess(bobMessage)
const bobAccount = await bobLogin

// Step 5: Bob adds the space to his agent and sets it as current
await bobClient.addSpace(await space.createAuthorization(bobAccount))
await bobClient.setCurrentSpace(space.did())

// Step 6: Bob verifies access to the space
const spaceInfo = await bobClient.capability.space.info(space.did())
assert.ok(spaceInfo)
},

'should fail to share the space if the delegate call returns an error':
async (assert, { client, mail, grantAccess }) => {
// Step 1: Create a client for Alice and login
const aliceEmail = '[email protected]'
const aliceLogin = client.login(aliceEmail)
const message = await mail.take()
assert.deepEqual(message.to, aliceEmail)
await grantAccess(message)
const aliceAccount = await aliceLogin

// Step 2: Alice creates a space
const space = await client.createSpace(
'share-space-delegate-fail-test',
{
account: aliceAccount,
}
)
assert.ok(space)

// Step 3: Mock the delegate call to return an error
const originalDelegate = client.capability.access.delegate
// @ts-ignore
client.capability.access.delegate = async () => {
return { error: { message: 'Delegate failed' } }
}

// Step 4: Attempt to share the space with Bob and expect failure
const bobEmail = '[email protected]'
await assert.rejects(
client.shareSpace({ space, delegateEmail: bobEmail }),
{
message: `failed to share space with account ${bobEmail}: Delegate failed`,
}
)

// Restore the original delegate method
client.capability.access.delegate = originalDelegate
},
}),
}

Test.test({ Client: testClient })

0 comments on commit 523c119

Please sign in to comment.