Skip to content

Commit

Permalink
fix: onboarding flow
Browse files Browse the repository at this point in the history
  • Loading branch information
cesarenaldi committed Dec 16, 2024
1 parent 6776f04 commit 34ebf61
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 31 deletions.
10 changes: 10 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@
"enabled": false
}
},
{
"include": ["./packages/**/*.test.ts"],
"linter": {
"rules": {
"style": {
"noNonNullAssertion": "off"
}
}
}
},
{
"include": ["./packages/graphql/*.graphql"],
"formatter": {
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/actions/authentication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export function legacyRolloverRefresh(
* Switch to account managed.
*
* ```ts
* const result = await switchAccount(sessionClient{
* const result = await switchAccount(sessionClient, {
* account: evmAddress('0x90c8c68d0Abfb40D4fCD72316A65e42161520BC3'),
* });
* ```
Expand Down
64 changes: 42 additions & 22 deletions packages/client/src/actions/onboarding.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { account } from '@lens-protocol/metadata';
import { assertOk } from '@lens-protocol/types';
import { describe, it } from 'vitest';
import { assertOk, never } from '@lens-protocol/types';
import { describe, expect, it } from 'vitest';

import { loginAsOnboardingUser, signerWallet } from '../../testing-utils';
import { type Account, Role } from '@lens-protocol/graphql';
import { loginAsOnboardingUser, signer, signerWallet } from '../../testing-utils';
import { handleWith } from '../viem';
import { createAccountWithUsername, fetchAccount } from './account';
import { switchAccount } from './authentication';

const walletClient = signerWallet();
const metadata = account({
Expand All @@ -15,30 +15,50 @@ const metadata = account({

describe('Given an onboarding user', () => {
describe('When switching to the newly created account', () => {
it.skip('Then it should be authenticated', async () => {
it('Then it should be authenticated', { timeout: 60000 }, async () => {
let newAccount: Account | null = null;

// Login as onboarding user
const result = await loginAsOnboardingUser().andThen((sessionClient) =>
// Create an account with username
createAccountWithUsername(sessionClient, {
username: { localName: `testname${Date.now()}` },
metadataUri: `data:application/json,${JSON.stringify(metadata)}`,
})
// Sign if necessary
.andThen(handleWith(walletClient))
const sessionClient = await loginAsOnboardingUser()
.andThen((sessionClient) =>
// Create an account with username
createAccountWithUsername(sessionClient, {
username: { localName: `testname${Date.now()}` },
metadataUri: `data:application/json,${JSON.stringify(metadata)}`,
})
// Sign if necessary
// biome-ignore lint/suspicious/noExplicitAny: temporary
.andThen(handleWith(walletClient) as any)

// Wait for the transaction to be mined
// biome-ignore lint/suspicious/noExplicitAny: temporary
.andThen(sessionClient.waitForTransaction as any)

// Wait for the transaction to be mined
.andThen(sessionClient.waitForTransaction)
// Fetch the account
.andThen((txHash) => fetchAccount(sessionClient, { txHash }))

// Fetch the account
.andThen((txHash) => fetchAccount(sessionClient, { txHash }))
.andTee((account) => {
newAccount = account ?? never('Account not found');
})

// Switch to the newly created account
.andThen((account) => switchAccount(sessionClient, { account: account?.address })),
);
// Switch to the newly created account
.andThen((account) => sessionClient.switchAccount({ account: account?.address })),
)
.match(
(value) => value,
(error) => {
throw error;
},
);

console.log(result);
const user = await sessionClient.getAuthenticatedUser();
assertOk(user);

assertOk(result);
expect(user.value).toMatchObject({
role: Role.AccountOwner,
account: newAccount!.address.toLowerCase(),
owner: signer.toLowerCase(),
});
});
});
});
2 changes: 2 additions & 0 deletions packages/client/src/clients.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ describe(`Given an instance of the ${PublicClient.name}`, () => {
environment: {
backend: url('http://127.0.0.1'),
name: 'broken',
indexingTimeout: 1000,
pollingInterval: 1000,
},
origin: 'http://example.com',
});
Expand Down
30 changes: 29 additions & 1 deletion packages/client/src/clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ import {
} from '@urql/core';
import { type Logger, getLogger } from 'loglevel';

import type { SwitchAccountRequest } from '@lens-protocol/graphql';
import { type AuthenticatedUser, authenticatedUser } from './AuthenticatedUser';
import { transactionStatus } from './actions';
import { switchAccount, transactionStatus } from './actions';
import type { ClientConfig } from './config';
import { type Context, configureContext } from './context';
import {
Expand Down Expand Up @@ -345,6 +346,33 @@ class SessionClient<TContext extends Context = Context> extends AbstractClient<
return true;
}

/**
* Switch authenticated account to a new account.
*
* You MUST be authenticated as Onboarding User, Account Owner, or Account Manager to be able to switch.
* The signer associated with the current session MUST be the owner or a manager of the account.
*
* @returns The updated SessionClient if the switch was successful.
*/
switchAccount(
request: SwitchAccountRequest,
): ResultAsync<
SessionClient<TContext>,
AuthenticationError | UnauthenticatedError | UnexpectedError
> {
return switchAccount(this, request)
.andThen((result) => {
if (result.__typename === 'ForbiddenError') {
return AuthenticationError.from(result.reason).asResultAsync();
}
return okAsync(result);
})
.map(async (tokens) => {
await this.credentials.set(tokens);
return this;
});
}

/**
* Execute a GraphQL query operation.
*
Expand Down
13 changes: 7 additions & 6 deletions packages/client/testing-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import { http, type Account, type Transport, type WalletClient, createWalletClie
import { privateKeyToAccount } from 'viem/accounts';
import { PublicClient, testnet } from './src';

const signer = privateKeyToAccount(import.meta.env.PRIVATE_KEY);
const owner = evmAddress(signer.address);
const pk = privateKeyToAccount(import.meta.env.PRIVATE_KEY);
const account = evmAddress(import.meta.env.TEST_ACCOUNT);
const app = evmAddress(import.meta.env.TEST_APP);

export const signer = evmAddress(pk.address);

export function loginAsAccountOwner() {
const client = PublicClient.create({
environment: testnet,
Expand All @@ -18,10 +19,10 @@ export function loginAsAccountOwner() {
return client.login({
accountOwner: {
account,
owner,
owner: signer,
app,
},
signMessage: (message) => signer.signMessage({ message }),
signMessage: (message) => pk.signMessage({ message }),
});
}

Expand All @@ -33,10 +34,10 @@ export function loginAsOnboardingUser() {

return client.login({
onboardingUser: {
wallet: owner,
wallet: signer,
app,
},
signMessage: (message) => signer.signMessage({ message }),
signMessage: (message) => pk.signMessage({ message }),
});
}

Expand Down
2 changes: 1 addition & 1 deletion packages/env/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,6 @@ export const staging: EnvironmentConfig = {
export const local: EnvironmentConfig = {
name: 'local',
backend: url('http://localhost:3000/graphql'),
indexingTimeout: 5000,
indexingTimeout: 60000,
pollingInterval: 500,
};

0 comments on commit 34ebf61

Please sign in to comment.