From 518c09cb869f8c4e6bfb58e61696672cbdf80150 Mon Sep 17 00:00:00 2001 From: dalechyn Date: Wed, 25 Dec 2024 18:13:10 +0200 Subject: [PATCH] nit: userdata --- src/core/Message.ts | 2 +- src/core/UserData.ts | 164 +++++++++++++++++++++++++++++++---- src/core/actions/UserData.ts | 10 +-- 3 files changed, 151 insertions(+), 25 deletions(-) diff --git a/src/core/Message.ts b/src/core/Message.ts index 92d968e..51e1af7 100644 --- a/src/core/Message.ts +++ b/src/core/Message.ts @@ -107,7 +107,7 @@ export function fromProtobuf( /// /// if (message.data.type === MessageProtobuf.MessageType.USER_DATA_ADD) - return { type: 'userDataAdd', data: UserData.fromProtobuf(message) } + return { type: 'userDataAdd', data: UserData.fromMessageProtobuf(message) } if (message.data.type === MessageProtobuf.MessageType.USERNAME_PROOF) return { type: 'usernameProof', diff --git a/src/core/UserData.ts b/src/core/UserData.ts index b238ff3..d8edff7 100644 --- a/src/core/UserData.ts +++ b/src/core/UserData.ts @@ -1,5 +1,9 @@ -import { Hex } from 'ox' +import { toBinary } from '@bufbuild/protobuf' +import { create } from '@bufbuild/protobuf' +import { Hex, type Types } from 'ox' import { BaseError } from 'ox/Errors' +import type { Omit } from 'ox/Internal' +import { FARCASTER_EPOCH_TIMESTAMP } from './Constants.js' import type { GlobalErrorType } from './Error.js' import * as Meta from './Meta.js' import * as MessageProtobuf from './protobufs/message_pb.js' @@ -8,6 +12,8 @@ export type UserData = { meta: Meta.Meta type: 'none' | 'pfp' | 'display' | 'bio' | 'url' | 'username' | 'location' value: string + fid: bigint + timestamp: number } // @TODO: replace by our own BaseError @@ -21,52 +27,172 @@ export class InvalidMessageTypeError extends BaseError { } } +export function fromMessageProtobuf( + message: fromMessageProtobuf.ParametersType, +): fromMessageProtobuf.ReturnType { + const meta = Meta.fromProtobuf(message) + // @TODO: separate error here + if (!message.data) throw new Error('`data` must be defined in Link message.') + if (message.data.body.case !== 'userDataBody') + throw new InvalidMessageTypeError({ hash: meta.hash }) + return fromProtobuf({ + body: message.data.body.value, + meta, + fid: message.data.fid, + timestamp: message.data.timestamp, + }) +} + +export declare namespace fromMessageProtobuf { + type ParametersType = MessageProtobuf.Message + type ReturnType = UserData + type ErrorType = + | InvalidMessageTypeError + | Meta.fromProtobuf.ErrorType + | GlobalErrorType +} + +fromMessageProtobuf.parseError = (error: unknown) => + error as fromMessageProtobuf.ErrorType + export function fromProtobuf( - message: fromProtobuf.ParametersType, + parameters: fromProtobuf.ParametersType, ): fromProtobuf.ReturnType { // @TODO: error here - if (message.data?.body.case !== 'userDataBody') - throw new InvalidMessageTypeError({ - hash: Hex.fromBytes(message.hash), - }) const type = (() => { - if (message.data.body.value.type === MessageProtobuf.UserDataType.PFP) { + if (parameters.body.type === MessageProtobuf.UserDataType.PFP) { return 'pfp' } - if (message.data.body.value.type === MessageProtobuf.UserDataType.BIO) { + if (parameters.body.type === MessageProtobuf.UserDataType.BIO) { return 'bio' } - if (message.data.body.value.type === MessageProtobuf.UserDataType.DISPLAY) { + if (parameters.body.type === MessageProtobuf.UserDataType.DISPLAY) { return 'display' } - if (message.data.body.value.type === MessageProtobuf.UserDataType.URL) { + if (parameters.body.type === MessageProtobuf.UserDataType.URL) { return 'url' } - if ( - message.data.body.value.type === MessageProtobuf.UserDataType.USERNAME - ) { + if (parameters.body.type === MessageProtobuf.UserDataType.USERNAME) { return 'username' } - if ( - message.data.body.value.type === MessageProtobuf.UserDataType.LOCATION - ) { + if (parameters.body.type === MessageProtobuf.UserDataType.LOCATION) { return 'location' } return 'none' })() // @TODO: handle unexpeded type here? return { - meta: Meta.fromProtobuf(message), + meta: parameters.meta, type, - value: message.data.body.value.value, + value: parameters.body.value, + fid: parameters.fid, + timestamp: parameters.timestamp, } } export declare namespace fromProtobuf { - type ParametersType = MessageProtobuf.Message + type ParametersType = { + body: MessageProtobuf.UserDataBody + meta: Meta.Meta + fid: bigint + timestamp: number + } type ReturnType = UserData type ErrorType = InvalidMessageTypeError | GlobalErrorType } fromProtobuf.parseError = (error: unknown) => error as fromProtobuf.ErrorType + +export function toMessageDataProtobuf( + body: toMessageDataProtobuf.ParametersType, +): toMessageDataProtobuf.ReturnType { + return create(MessageProtobuf.MessageDataSchema, { + timestamp: body.timestamp - FARCASTER_EPOCH_TIMESTAMP, + type: MessageProtobuf.MessageType.USER_DATA_ADD, + fid: body.fid, + network: MessageProtobuf.FarcasterNetwork.MAINNET, + body: { + case: 'userDataBody', + value: toProtobuf(body), + }, + }) +} + +export declare namespace toMessageDataProtobuf { + type ParametersType = Omit + type ReturnType = MessageProtobuf.MessageData + + type ErrorType = GlobalErrorType +} + +toMessageDataProtobuf.parseError = (error: unknown) => + error as toMessageDataProtobuf.ErrorType + +export function toHex(body: toHex.ParametersType): toHex.ReturnType { + return Hex.fromBytes( + toBinary(MessageProtobuf.MessageDataSchema, toMessageDataProtobuf(body)), + ) +} + +export declare namespace toHex { + type ParametersType = Omit + type ReturnType = Types.Hex + type ErrorType = GlobalErrorType +} + +toHex.parseError = (error: unknown) => error as toHex.ErrorType + +export function toMessageProtobuf( + parameters: toMessageProtobuf.ParametersType, +): toMessageProtobuf.ReturnType { + return create(MessageProtobuf.MessageSchema, { + ...Meta.toProtobuf( + Meta.create({ + dataBytes: toHex(parameters.data), + privateKey: parameters.privateKey, + }), + ), + data: toMessageDataProtobuf(parameters.data), + }) +} + +export declare namespace toMessageProtobuf { + type ParametersType = { + data: Omit + privateKey: Types.Hex + } + type ReturnType = MessageProtobuf.Message + + // @TODO: errors + type ErrorType = GlobalErrorType +} + +toMessageProtobuf.parseError = (error: unknown) => + error as toMessageProtobuf.ErrorType + +export function toProtobuf( + body: toProtobuf.ParametersType, +): toProtobuf.ReturnType { + return create(MessageProtobuf.UserDataBodySchema, { + type: (() => { + if (body.type === 'username') return MessageProtobuf.UserDataType.USERNAME + if (body.type === 'location') return MessageProtobuf.UserDataType.LOCATION + if (body.type === 'url') return MessageProtobuf.UserDataType.URL + if (body.type === 'bio') return MessageProtobuf.UserDataType.BIO + if (body.type === 'display') return MessageProtobuf.UserDataType.DISPLAY + if (body.type === 'pfp') return MessageProtobuf.UserDataType.PFP + throw new Error('unknown userdatabody type') + })(), + value: body.value, + }) +} + +export declare namespace toProtobuf { + type ParametersType = Omit + type ReturnType = MessageProtobuf.UserDataBody + + type ErrorType = GlobalErrorType +} + +toProtobuf.parseError = (error: unknown) => error as toProtobuf.ErrorType diff --git a/src/core/actions/UserData.ts b/src/core/actions/UserData.ts index 0c41c6e..d22bb2a 100644 --- a/src/core/actions/UserData.ts +++ b/src/core/actions/UserData.ts @@ -21,7 +21,7 @@ export async function get( options?: CallOptions, ): Promise { const message = await client.connectRpcClient.getUserData(parameters, options) - return UserData.fromProtobuf(message) + return UserData.fromMessageProtobuf(message) } get.parseError = (error: unknown) => error as get.ErrorType @@ -35,7 +35,7 @@ export declare namespace getAllUserDataMessagesByFid { nextPageToken: Pagination.NextPageToken } // @TODO: proper error handling - type ErrorType = UserData.fromProtobuf.ErrorType | GlobalErrorType + type ErrorType = UserData.fromMessageProtobuf.ErrorType | GlobalErrorType } export async function getAllUserDataMessagesByFid( client: Client.Client, @@ -50,7 +50,7 @@ export async function getAllUserDataMessagesByFid( options, ) return { - datas: message.messages.map(UserData.fromProtobuf), + datas: message.messages.map(UserData.fromMessageProtobuf), nextPageToken: Pagination.getPageToken(message.nextPageToken), } } @@ -91,7 +91,7 @@ export declare namespace getByFid { datas: UserData.UserData[] nextPageToken: Pagination.NextPageToken } - type ErrorType = UserData.fromProtobuf.ErrorType | GlobalErrorType + type ErrorType = UserData.fromMessageProtobuf.ErrorType | GlobalErrorType } export async function getByFid( client: Client.Client, @@ -106,7 +106,7 @@ export async function getByFid( options, ) return { - datas: message.messages.map(UserData.fromProtobuf), + datas: message.messages.map(UserData.fromMessageProtobuf), nextPageToken: Pagination.getPageToken(message.nextPageToken), } }