Skip to content

Commit

Permalink
Merge branch 'next' into T-23290/js-action-create-all-the-app-queries
Browse files Browse the repository at this point in the history
  • Loading branch information
juangm committed Dec 19, 2024
2 parents 668ecca + 410656c commit 7d33e8a
Show file tree
Hide file tree
Showing 25 changed files with 900 additions and 268 deletions.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
"lint:fix": "biome check --write",
"new:lib": "NODE_OPTIONS='--import tsx' plop --plopfile=plopfile.ts",
"prepublish": "pnpm run build",
"test:client": "vitest --project @lens-protocol/client",
"test:react": "vitest --project @lens-protocol/react",
"test:storage": "vitest --project @lens-protocol/storage",
"test": "vitest"
"test:client": "vitest --project @lens-protocol/client --no-file-parallelism",
"test:react": "vitest --project @lens-protocol/react --no-file-parallelism",
"test:storage": "vitest --project @lens-protocol/storage --no-file-parallelism",
"test": "vitest --no-file-parallelism"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
Expand Down
1 change: 1 addition & 0 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"@lens-network/sdk": "canary",
"@lens-protocol/metadata": "next",
"ethers": "^6.13.4",
"msw": "^2.7.0",
"tsup": "^8.3.5",
"typescript": "^5.6.3",
"viem": "^2.21.53",
Expand Down
4 changes: 2 additions & 2 deletions packages/client/src/actions/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type {
CreateGroupRequest,
CreateGroupResult,
Group,
GroupMember,
GroupMembersRequest,
GroupRequest,
GroupStatsRequest,
Expand All @@ -24,7 +25,6 @@ import {
} from '@lens-protocol/graphql';
import type { ResultAsync } from '@lens-protocol/types';

import type { Account } from '@lens-protocol/graphql';
import type { AnyClient, SessionClient } from '../clients';
import type { UnauthenticatedError, UnexpectedError } from '../errors';

Expand Down Expand Up @@ -140,7 +140,7 @@ export function fetchGroups(
export function fetchGroupMembers(
client: AnyClient,
request: GroupMembersRequest,
): ResultAsync<Paginated<Account>, UnexpectedError> {
): ResultAsync<Paginated<GroupMember>, UnexpectedError> {
return client.query(GroupMembersQuery, { request });
}

Expand Down
14 changes: 7 additions & 7 deletions packages/client/src/actions/namespace.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import type {
CreateUsernameNamespaceRequest,
CreateUsernameNamespaceResult,
NamespaceRequest,
NamespacesRequest,
Paginated,
UsernameNamespace,
UsernameNamespaceRequest,
} from '@lens-protocol/graphql';
import {
CreateUsernameNamespaceMutation,
NamespaceQuery,
NamespacesQuery,
UsernameNamespaceQuery,
} from '@lens-protocol/graphql';
import type { ResultAsync } from '@lens-protocol/types';

Expand Down Expand Up @@ -38,10 +38,10 @@ export function createUsernameNamespace(
}

/**
* Fetch a UsernameNamespace.
* Fetch a Namespace.
*
* ```ts
* const result = await fetchUsernameNamespace(anyClient, {
* const result = await fetchNamespace(anyClient, {
* namespace: evmAddress('0xe2f2a5C287993345a840db3B0845fbc70f5935a5'),
* });
* ```
Expand All @@ -50,11 +50,11 @@ export function createUsernameNamespace(
* @param request - The query request.
* @returns The UsernameNamespace or `null` if it does not exist.
*/
export function fetchUsernameNamespace(
export function fetchNamespace(
client: AnyClient,
request: UsernameNamespaceRequest,
request: NamespaceRequest,
): ResultAsync<UsernameNamespace | null, UnexpectedError> {
return client.query(UsernameNamespaceQuery, { request });
return client.query(NamespaceQuery, { request });
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/actions/onboarding.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const metadata = account({

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

// Login as onboarding user
Expand Down
29 changes: 28 additions & 1 deletion packages/client/src/actions/posts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
PostReactionsRequest,
PostReferencesRequest,
PostRequest,
PostsRequest,
} from '@lens-protocol/graphql';
import {
PostActionsQuery,
Expand All @@ -19,6 +20,7 @@ import {
PostReactionsQuery,
PostReferencesQuery,
PostTagsQuery,
PostsQuery,
WhoActedOnPostQuery,
WhoReferencedPostQuery,
} from '@lens-protocol/graphql';
Expand All @@ -43,7 +45,7 @@ import type { UnauthenticatedError, UnexpectedError } from '../errors';
*
* ```ts
* const result = await fetchPost(anyClient, {
* post: postId('0x01')
* post: postId('42')
* });
* ```
*
Expand All @@ -58,6 +60,31 @@ export function fetchPost(
return client.query(PostQuery, { request });
}

/**
* Fetch paginated Posts.
*
* Using a {@link SessionClient} will yield {@link Post#operations}
* and {@link Account#operations} specific to the authenticated Account.
*
* ```ts
* const result = await fetchPosts(anyClient, {
* filter: {
* authors: [evmAddress('0xe2f2a5C287993345a840db3B0845fbc70f5935a5')],
* }
* });
* ```
*
* @param client - Any Lens client.
* @param request - The query request.
* @returns The paginated list of Posts.
*/
export function fetchPosts(
client: AnyClient,
request: PostsRequest,
): ResultAsync<Paginated<AnyPost>, UnexpectedError> {
return client.query(PostsQuery, { request });
}

/**
* Fetch available actions for POST.
*
Expand Down
110 changes: 102 additions & 8 deletions packages/client/src/clients.test.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { testnet } from '@lens-protocol/env';
import { url, assertErr, assertOk, evmAddress, signatureFrom } from '@lens-protocol/types';
import { HttpResponse, graphql, passthrough } from 'msw';
import { setupServer } from 'msw/node';

import { privateKeyToAccount } from 'viem/accounts';
import { describe, expect, it } from 'vitest';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';

import { HealthQuery, Role } from '@lens-protocol/graphql';
import { CurrentSessionQuery, HealthQuery, RefreshMutation, Role } from '@lens-protocol/graphql';
import { createGraphQLErrorObject, createPublicClient } from '../testing-utils';
import { currentSession } from './actions';
import { PublicClient } from './clients';
import { UnexpectedError } from './errors';
import { GraphQLErrorCode, UnauthenticatedError, UnexpectedError } from './errors';
import { delay } from './utils';

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

describe(`Given an instance of the ${PublicClient.name}`, () => {
const client = PublicClient.create({
environment: testnet,
origin: 'http://example.com',
});
const client = createPublicClient();

describe('When authenticating via the low-level methods', () => {
it('Then it should authenticate and stay authenticated', async () => {
Expand Down Expand Up @@ -104,4 +104,98 @@ describe(`Given an instance of the ${PublicClient.name}`, () => {
expect(result.error).toBeInstanceOf(UnexpectedError);
});
});

describe('And a SessionClient created from it', () => {
describe('When a request fails with UNAUTHENTICATED extension code', () => {
const server = setupServer(
graphql.query(
CurrentSessionQuery,
(_) =>
HttpResponse.json({
errors: [createGraphQLErrorObject(GraphQLErrorCode.UNAUTHENTICATED)],
}),
{
once: true,
},
),
// Pass through all other operations
graphql.operation(() => passthrough()),
);

beforeAll(() => {
server.listen();
});

afterAll(() => {
server.close();
});

it(
'Then it should silently refresh credentials and retry the request',
{ timeout: 5000 },
async () => {
const authenticated = await client.login({
accountOwner: {
account,
owner,
app,
},
signMessage: (message) => signer.signMessage({ message }),
});
assertOk(authenticated);

// wait 1 second to make sure the new tokens have 'expiry at' different from the previous ones
await delay(1000);

const result = await currentSession(authenticated.value);

assertOk(result);
},
);
});

describe('When a token refresh fails', () => {
const server = setupServer(
graphql.query(CurrentSessionQuery, (_) =>
HttpResponse.json({
errors: [createGraphQLErrorObject(GraphQLErrorCode.UNAUTHENTICATED)],
}),
),
graphql.mutation(RefreshMutation, (_) =>
HttpResponse.json({
errors: [createGraphQLErrorObject(GraphQLErrorCode.BAD_USER_INPUT)],
}),
),
// Pass through all other operations
graphql.operation(() => passthrough()),
);

beforeAll(() => {
server.listen();
});

afterAll(() => {
server.close();
});
it(
`Then it should return a '${UnauthenticatedError.name}' to the original request caller`,
{ timeout: 5000 },
async () => {
const authenticated = await client.login({
accountOwner: {
account,
owner,
app,
},
signMessage: (message) => signer.signMessage({ message }),
});
assertOk(authenticated);

const result = await currentSession(authenticated.value);
assertErr(result);
expect(result.error).toBeInstanceOf(UnauthenticatedError);
},
);
});
});
});
Loading

0 comments on commit 7d33e8a

Please sign in to comment.