Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add refreshmetadata and refreshmetadatastatus #1089

Open
wants to merge 17 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions packages/client/src/actions/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import type { UnauthenticatedError, UnexpectedError } from '../errors';
* ```ts
* const result = await configurePostAction(sessionClient, {
* post: postId('1234…'),
* feed: evmAddress('0x1234…'),
* params: {
* simpleCollect: {
* amount: {
Expand Down Expand Up @@ -66,8 +65,7 @@ export function configurePostAction(
* ```ts
* const result = await enablePostAction(sessionClient, {
* post: postId('1234…'),
* feed: evmAddress('0x1234…'),
* action: 'SIMPLE_COLLECT'
* action: { simpleCollect: true }
* });
* ```
*
Expand All @@ -88,8 +86,7 @@ export function enablePostAction(
* ```ts
* const result = await disablePostAction(sessionClient, {
* post: postId('1234…'),
* feed: evmAddress('0x1234…'),
* action: 'SIMPLE_COLLECT'
* action: { simpleCollect: true }
* });
* ```
*
Expand All @@ -110,11 +107,9 @@ export function disablePostAction(
* ```ts
* const result = await executePostAction(sessionClient, {
* post: postId('1234…'),
* feed: evmAddress('0x1234…'),
* params: {
* action: {
* simpleCollect: {
* value: '100',
* currency: evmAddress('0x5678…')
* selected: true,
* }
* }
* });
Expand Down Expand Up @@ -161,10 +156,17 @@ export function configureAccountAction(

/**
* Enable account action.
* The tipping action is not possible to modify.
*
* ```ts
* const result = await enableAccountAction(sessionClient, {
* action: 'TIPPING'
* unknown: {
* params: [{
* key: 'usd',
* value: '100'
* }],
* address: evmAddress('0x1234…'),
* }
* });
* ```
*
Expand All @@ -181,10 +183,13 @@ export function enableAccountAction(

/**
* Disable account action.
* Not possible to disable the tipping action.
*
* ```ts
* const result = await disableAccountAction(sessionClient, {
* action: 'TIPPING'
* unknown: {
* address: evmAddress('0x1234…'),
* }
* });
* ```
*
Expand Down
3 changes: 2 additions & 1 deletion packages/client/src/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ export * from './follow';
export * from './graph';
export * from './group';
export * from './health';
export * from './namespace';
export * from './metadata';
export * from './ml';
export * from './namespace';
export * from './notifications';
export * from './post';
export * from './posts';
Expand Down
48 changes: 48 additions & 0 deletions packages/client/src/actions/metadata.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { type PostId, assertOk, invariant } from '@lens-protocol/types';
import { beforeAll, describe, expect, it } from 'vitest';

import {
createPublicClient,
loginAsAccountOwner,
postOnlyTextMetadata,
wallet,
} from '../test-utils';
import { handleOperationWith } from '../viem';
import { refreshMetadata, waitForMetadata } from './metadata';
import { post } from './post';
import { fetchPost } from './posts';

describe('Given user creates a post', () => {
let postId: PostId;

beforeAll(async () => {
// Create a post with metadata
const resources = await postOnlyTextMetadata();
const result = await loginAsAccountOwner().andThen((sessionClient) =>
post(sessionClient, {
contentUri: resources.uri,
})
.andThen(handleOperationWith(wallet))
.andThen(sessionClient.waitForTransaction)
.andThen((tx) => fetchPost(sessionClient, { txHash: tx })),
);
assertOk(result);

Check failure on line 29 in packages/client/src/actions/metadata.test.ts

View workflow job for this annotation

GitHub Actions / Verify / Test

src/actions/metadata.test.ts > Given user creates a post

InvariantError: Expected result to be Ok: [GraphQL] Server error - PgError error deserializing column 1: cannot convert between the Rust type `u32` and the Postgres type `numeric` ❯ Module.l ../types/src/helpers/assertions.ts:31:11 ❯ src/actions/metadata.test.ts:29:5
invariant(result.value, 'Expected post to be defined and created');
postId = result.value.id;
});

describe('When user modifies metadata in the used URL and call refreshMetadata', () => {
it('Then post metadata content should be updated', async () => {
// TODO: add possibility to change metadata in the same URL and refresh later
// That feature will be available soon in the storage nodes
const client = createPublicClient();
const newMetadata = await refreshMetadata(client, { entity: { post: postId } });

assertOk(newMetadata);
invariant(newMetadata.value, 'Expected to be defined');
const result = await waitForMetadata(client, newMetadata.value.id);
assertOk(result);
expect(result.value).toEqual(newMetadata.value.id);
});
});
});
97 changes: 97 additions & 0 deletions packages/client/src/actions/metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import type {
RefreshMetadataRequest,
RefreshMetadataResult,
RefreshMetadataStatusRequest,
RefreshMetadataStatusResult,
} from '@lens-protocol/graphql';
import {
IndexingStatus,
RefreshMetadataMutation,
RefreshMetadataStatusQuery,
} from '@lens-protocol/graphql';
import { ResultAsync, type UUID } from '@lens-protocol/types';

import type { AnyClient } from '../clients';
import { MetadataIndexingError, type UnauthenticatedError, UnexpectedError } from '../errors';
import { delay } from '../utils';

/**
* Fetch the indexing status of metadata.
*
* ```ts
* const result = await refreshMetadataStatus(anyClient, {
* id: uuid("a0a88a62-377f-46eb-a1ec-ca6597aef164")
* });
* ```
*
* @param client - Any Lens client.
* @param request - The query request.
* @returns The indexing status of the metadata.
*/
export function refreshMetadataStatus(
client: AnyClient,
request: RefreshMetadataStatusRequest,
): ResultAsync<RefreshMetadataStatusResult, UnexpectedError> {
return client.query(RefreshMetadataStatusQuery, { request });
}

/**
* Refresh the metadata for a given entity.
*
* ```ts
* const result = await refreshMetadata(anyClient, {
* entity: {
* post: postId('42'),
* },
* });
* ```
*
* @param client - Any Lens client.
* @param request - The mutation request.
* @returns - UUID to track the metadata refresh.
*/
export function refreshMetadata(
client: AnyClient,
request: RefreshMetadataRequest,
): ResultAsync<RefreshMetadataResult, UnauthenticatedError | UnexpectedError> {
return client.mutation(RefreshMetadataMutation, { request });
}

/**
* Given a metadata id, wait for the metadata to be either confirmed or rejected by the Lens API.
*
* @param client - Any Lens client.
* @param id - The metadata id to wait for.
* @returns The metadata id if the metadata was confirmed or an error if the transaction was rejected.
*/
export function waitForMetadata(
client: AnyClient,
id: UUID,
): ResultAsync<UUID, MetadataIndexingError | UnexpectedError> {
return ResultAsync.fromPromise(pollMetadataStatus(client, id), (err) => {
if (err instanceof MetadataIndexingError || err instanceof UnexpectedError) {
return err;
}
return UnexpectedError.from(err);
});
}

async function pollMetadataStatus(client: AnyClient, id: UUID): Promise<UUID> {
const startedAt = Date.now();
while (Date.now() - startedAt < client.context.environment.indexingTimeout) {
const result = await refreshMetadataStatus(client, { id });
if (result.isErr()) {
throw UnexpectedError.from(result.error);
}
switch (result.value.status) {
case IndexingStatus.Finished:
return result.value.id;
case IndexingStatus.Failed:
throw MetadataIndexingError.from(result.value.reason);
case IndexingStatus.Pending:
await delay(client.context.environment.pollingInterval);
break;
}
}
throw MetadataIndexingError.from(`Timeout waiting for metadata ${id}`);
}
6 changes: 3 additions & 3 deletions packages/client/src/clients.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { AuthenticateMutation, ChallengeMutation, RefreshMutation } from '@lens-protocol/graphql';
import type {
AuthenticationChallenge,
ChallengeRequest,
SignedAuthChallenge,
StandardData,
SwitchAccountRequest,
} from '@lens-protocol/graphql';
import { AuthenticateMutation, ChallengeMutation, RefreshMutation } from '@lens-protocol/graphql';
import type { Credentials, IStorage } from '@lens-protocol/storage';
import { createCredentialsStorage } from '@lens-protocol/storage';
import {
Expand All @@ -25,10 +26,9 @@ import {
createClient,
fetchExchange,
} from '@urql/core';
import { type AuthConfig, authExchange } from '@urql/exchange-auth';
import { type Logger, getLogger } from 'loglevel';

import type { SwitchAccountRequest } from '@lens-protocol/graphql';
import { type AuthConfig, authExchange } from '@urql/exchange-auth';
import { type AuthenticatedUser, authenticatedUser } from './AuthenticatedUser';
import { revokeAuthentication, switchAccount, transactionStatus } from './actions';
import type { ClientConfig } from './config';
Expand Down
7 changes: 7 additions & 0 deletions packages/client/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ export class TransactionIndexingError extends ResultAwareError {
name = 'TransactionIndexingError' as const;
}

/**
* Error indicating metadata failed to index.
*/
export class MetadataIndexingError extends ResultAwareError {
name = 'MetadataIndexingError' as const;
}

/**
* Error indicating an operation was not executed due to a validation error.
* See the `cause` property for more information.
Expand Down
18 changes: 16 additions & 2 deletions packages/client/src/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import { StorageClient } from '@lens-chain/storage-client';
import { chains } from '@lens-network/sdk/viem';
import { evmAddress } from '@lens-protocol/types';
import { http, type Account, type Transport, type WalletClient, createWalletClient } from 'viem';
import type { Account, Transport, WalletClient } from 'viem';
import { http, createWalletClient } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';

import { ContentWarning, type TextOnlyOptions, textOnly } from '@lens-protocol/metadata';
import { GraphQLErrorCode, PublicClient, staging } from '.';

const pk = privateKeyToAccount(import.meta.env.PRIVATE_KEY);
Expand All @@ -29,7 +31,6 @@ export function createPublicClient() {

export function loginAsAccountOwner() {
const client = createPublicClient();

return client.login({
accountOwner: {
account,
Expand Down Expand Up @@ -72,4 +73,17 @@ export function createGraphQLErrorObject(code: GraphQLErrorCode) {
};
}

export function postOnlyTextMetadata(customMetadata?: TextOnlyOptions) {
const metadata =
customMetadata !== undefined
? customMetadata
: {
content: 'This is a post for testing purposes',
tags: ['test', 'lens', 'sdk'],
contentWarning: ContentWarning.SENSITIVE,
locale: 'en-US',
};

return storageClient.uploadAsJson(textOnly(metadata));
}
export const storageClient = StorageClient.create();
Loading
Loading