Skip to content

Types exported from frames.js

Example usage

import { Frame } from "frames.js";

Reference

frames.js/types.ts
export type FrameVersion = "vNext" | `${number}-${number}-${number}`;
 
export type ImageAspectRatio = "1.91:1" | "1:1";
 
export type ClientProtocolId = { id: string; version: string };
 
/** A developer friendly representation of a Frame */
export type Frame = {
  /** A valid frame version string. The string must be a release date (e.g. 2020-01-01 ) or vNext. Apps must ignore versions they do not understand. Currently, the only valid version is vNext.  */
  version: FrameVersion;
  /** A 256-byte string which contains a valid URL to send the Signature Packet to. If this prop is not present, apps must POST to the frame URL. */
  postUrl?: string;
  /** A page may contain 0 to 4 buttons. If more than 1 button is present, the idx values must be in sequence starting from 1 (e.g. 1, 2 3). If a broken sequence is present (e.g 1, 2, 4), apps must not render the frame and instead render an OG embed. */
  buttons?: FrameButtonsType;
  /** An image which should have an aspect ratio of 1.91:1 or 1:1 */
  image: string;
  /** Must be either `1.91:1` or `1:1`. Defaults to `1.91:1` */
  imageAspectRatio?: ImageAspectRatio;
  /** An image which should have an aspect ratio of 1.91:1. Fallback for clients that do not support frames. */
  ogImage?: string;
  /** Adding this property enables the text field. The content is a 32-byte label that is shown to the user (e.g. Enter a message). */
  inputText?: string;
  /** Frame servers may set this value and apps must sign and include it in the Frame Signature Packet. May be up to 4kb */
  state?: string;
  /** Open Frames spec: The minimum client protocol version accepted for the given protocol identifier. For example VNext , or 1.5 . At least one $protocol_identifier must be specified. */
  accepts?: ClientProtocolId[];
  title?: string;
};
 
export type ActionButtonType = "post" | "post_redirect" | "link";
 
type FrameOptionalStringKeys =
  | "fc:frame:image:aspect_ratio"
  | "fc:frame:input:text"
  | "fc:frame:state"
  | "fc:frame:post_url"
  | keyof OpenFramesProperties
  | "frames.js:version"
  | "frames.js:debug-info:image";
type FrameOptionalActionButtonTypeKeys =
  `fc:frame:button:${1 | 2 | 3 | 4}:action`;
type FrameOptionalButtonStringKeys =
  | `fc:frame:button:${1 | 2 | 3 | 4}`
  | `fc:frame:button:${1 | 2 | 3 | 4}:target`
  | `fc:frame:button:${1 | 2 | 3 | 4}:post_url`;
type FrameKeys =
  | FrameOptionalStringKeys
  | FrameOptionalActionButtonTypeKeys
  | FrameOptionalButtonStringKeys;
 
type MapFrameOptionalKeyToValueType<K extends FrameKeys> =
  K extends FrameOptionalStringKeys
    ? string | undefined
    : K extends FrameOptionalActionButtonTypeKeys
      ? ActionButtonType | undefined
      : string | undefined;
 
type FrameRequiredProperties = {
  "fc:frame": FrameVersion;
  "fc:frame:image": string;
  "og:image": string;
};
 
export type OpenFramesProperties = {
  "of:version": FrameVersion;
  "of:image": string;
  "of:post_url": string;
  "of:image:aspect_ratio": string;
  "of:input:text": string;
  "of:state": string;
} & {
  [s in `of:accepts:${string}`]: string;
} & {
  [s in `of:button:${1 | 2 | 3 | 4}`]: string;
} & {
  [s in `of:button:${1 | 2 | 3 | 4}:action`]: string;
} & {
  [s in `of:button:${1 | 2 | 3 | 4}:target`]: string;
} & {
  [s in `of:button:${1 | 2 | 3 | 4}:post_url`]: string;
};
 
/** A Frame represented as an object with keys and values corresponding to the Frames spec: https://docs.farcaster.xyz/reference/frames/spec */
export type FrameFlattened = FrameRequiredProperties & {
  [K in
    | FrameOptionalStringKeys
    | FrameOptionalActionButtonTypeKeys
    | FrameOptionalButtonStringKeys]?: MapFrameOptionalKeyToValueType<K>;
};
 
export interface FrameButtonLink {
  action: "link";
  /** required for action type 'link' */
  target: string;
  /** A 256-byte string which is label of the button */
  label: string;
}
 
export interface FrameButtonTx {
  action: "tx";
  target: string;
  post_url?: string;
  /** A 256-byte string which is label of the button */
  label: string;
}
 
export interface FrameButtonMint {
  action: "mint";
  /** The target  property MUST be a valid [CAIP-10](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md) address, plus an optional token_id . */
  target: string;
  /** A 256-byte string which is label of the button */
  label: string;
}
 
export interface FrameButtonPost {
  /** Must be post or post_redirect. Defaults to post if no value was specified.
   * If set to post, app must make the POST request and frame server must respond with a 200 OK, which may contain another frame.
   * If set to post_redirect, app must make the POST request, and the frame server must respond with a 302 OK with a location property set on the header. */
  action: "post" | "post_redirect";
  /**
   * POST the packet to fc:frame:button:$idx:action:target if present
   * POST the packet to fc:frame:post_url if target was not present.
   * POST the packet to fc:frame:button:$idx:post_url if target was not present.
   */
  target?: string;
  post_url?: string;
  /** A 256-byte string which is label of the button */
  label: string;
}
export type FrameButtonPostRedirect = FrameButtonPost;
 
export type FrameButton =
  | FrameButtonPost
  | FrameButtonLink
  | FrameButtonMint
  | FrameButtonTx;
 
/** The permitted types of `buttonIndex` in a Frame POST payload response */
export type ActionIndex = 1 | 2 | 3 | 4;
 
export type FrameButtonsType =
  | []
  | [FrameButton]
  | [FrameButton, FrameButton]
  | [FrameButton, FrameButton, FrameButton]
  | [FrameButton, FrameButton, FrameButton, FrameButton];
 
export type AddressReturnType<
  Options extends { fallbackToCustodyAddress?: boolean } | undefined,
> = Options extends { fallbackToCustodyAddress: true }
  ? `0x${string}`
  : `0x${string}` | null;
 
export type AddressWithType = {
  address: `0x${string}`;
  type: "verified" | "custody";
};
 
export type EthSendTransactionParams = {
  /** JSON ABI. This must include the encoded function type and should include any potential error types. */
  abi: JSON | Abi | [];
  /** transaction to address */
  to: Address;
  /** value of ether to send with the transaction in wei */
  value?: string;
  /** optional transaction call data */
  data?: Hex;
};
 
export type TransactionTargetResponseSendTransaction = {
  /** A [CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md) chain ID to identify the tx network e.g. 'eip155:1' for Ethereum mainnet */
  chainId: string;
  method: "eth_sendTransaction";
  /** Specific parameters for chainId and method */
  params: EthSendTransactionParams;
  /** Return false to omit the [calldata attribution](https://www.notion.so/warpcast/Frame-Transactions-Public-9d9f9f4f527249519a41bd8d16165f73#c1c3182208ce4ae4a7ffa72129b9795a) suffix. If this value is undefined or true, clients will append the attribution suffix. */
  attribution?: boolean;
};
 
export type EthSignTypedDataV4Params = {
  domain: {
    chainId?: number;
    name?: string;
    salt?: Hex;
    verifyingContract?: Address;
    version?: string;
  };
  types: TypedData;
  primaryType: string;
  message: Record<string, unknown>;
};
 
export type TransactionTargetResponseSignTypedDataV4 = {
  /** A [CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md) chain ID to identify the tx network e.g. 'eip155:1' for Ethereum mainnet */
  chainId: string;
  method: "eth_signTypedData_v4";
  /** Specific parameters for chainId and method */
  params: EthSignTypedDataV4Params;
  /** Return false to omit the [calldata attribution](https://www.notion.so/warpcast/Frame-Transactions-Public-9d9f9f4f527249519a41bd8d16165f73#c1c3182208ce4ae4a7ffa72129b9795a) suffix. If this value is undefined or true, clients will append the attribution suffix. */
  attribution?: boolean;
};
 
export type TransactionTargetResponse =
  | TransactionTargetResponseSendTransaction
  | TransactionTargetResponseSignTypedDataV4;
 
export type UserDataReturnType = {
  displayName?: string;
  username?: string;
  bio?: string;
  profileImage?: string;
} | null;
 
export type FrameActionDataParsedAndHubContext = FrameActionDataParsed &
  FrameActionHubContext;
 
/**
 * The body of valid `POST` requests triggered by Frame Buttons in other apps, when formatted as json, conforming to the Frames spec
 */
export type FrameActionPayload = {
  /** once validated, should be the only trusted source for accessing frame data */
  trustedData: { messageBytes: string };
  /**
   * untrustedData can be faked by anyone by hitting your frame with a POST with an arbitrary payload. We recommend only using
   * trustedData to do actions.
   */
  untrustedData: {
    /** the fid of the user who did the message. */
    fid: number;
    /** the url of the original frame, must be under 256 bytes */
    url: string;
    /** the hash of the `Farcaster` `AddFrameActionMessage` */
    messageHash: string;
    /** A Farcaster epoch timestamp (not UNIX timestamp) */
    timestamp: number;
    /** The Farcaster network is on network = 1 */
    network: number;
    /** the button index, starting from 1 that the user pressed to invoke this POST */
    buttonIndex: ActionIndex;
    /** the unique identifiers of the Farcaster cast, via the user who casted's `fid` and the cast `hash`, which is a unique identifier */
    castId: {
      /** the fid of the Farcaster user (unique identifier) that shared the cast that included the frame */
      fid: number;
      /** the hash of the cast (unique identifier) that included the frame */
      hash: string;
    };
    /** text input by the user into any input provided, "" if requested and no input, undefined if input not requested */
    inputText?: string;
    /** Frame servers may set this value and apps must sign and include it in the Frame Signature Packet. May be up to 4kb */
    state?: string;
    /** address of the user's connected wallet, only present in transaction data requests */
    address?: string;
    /** an optional transaction id property. For Ethereum, this must be the transaction hash. For other chains, this is not yet specified.  */
    transactionId?: string;
  };
  /** Open Frames spec: the identifier and version of the client protocol that sent the request e.g. farcaster\@vNext */
  clientProtocol?: string;
};
 
/** Options available in functions that make use of Hub queries */
export type HubHttpUrlOptions = {
  /** Hub HTTP REST API endpoint to use (default: https://hub-api.neynar.com w/ public API key) */
  hubHttpUrl?: string;
  /** Hub HTTP request options (use this for setting API keys) */
  hubRequestOptions?: RequestInit;
};
 
/** Data extracted and parsed from the frame message body */
export type FrameActionDataParsed = {
  buttonIndex: number;
  requesterFid: number;
  castId?: {
    /** the fid of the Farcaster user (unique identifier) that shared the cast that included the frame */
    fid: number;
    /** the hash of the cast (unique identifier) that included the frame */
    hash: `0x${string}`;
  };
  inputText?: string;
  state?: string;
  /**
   * address of the user's connected wallet used to create the transaction, only present in transaction data requests
   */
  address?: `0x${string}`;
  transactionId?: `0x${string}`;
};
 
/** Additional context for a frame message which requires communication with a Hub */
export type FrameActionHubContext = {
  isValid: boolean;
  /** Whether the user that initiated the action (requester) follows the author of the cast */
  requesterFollowsCaster: boolean;
  /** Whether the author of the cast follows the requester */
  casterFollowsRequester: boolean;
  /** Whether the requester has liked the cast that the frame is attached to (false if no cast) */
  likedCast: boolean;
  /** Whether the requester has recasted the cast that the frame is attached to (false if no cast) */
  recastedCast: boolean;
  /** Verified eth addresses of the requester */
  requesterVerifiedAddresses: string[];
  /** Custody address of the requester */
  requesterCustodyAddress: string;
  /** User data of the requester */
  requesterUserData: UserDataReturnType;
};
 
/** Metadata of an action typically triggered on a social post */
export type ActionMetadata = {
  /** The action name. Must be less than 30 characters. */
  name: string;
  /** An [Octicons](https://primer.style/foundations/icons) icon name. */
  icon: string;
  /** A short description up to 80 characters. */
  description: string;
  /** External link to an "about" page for extended description. */
  aboutUrl: string;
  /** The action type. (Same type options as frame buttons). Only post is accepted in V1. */
  action: {
    type: "post";
  };
};