bitpro가 원문에서 글자만 모은 내용이에요. 표·그림·수식은 빠지거나 깨질 수 있어요. 전체 17쪽 중 6쪽
col/towns/blob/main/packages/react-sdk/src/useMyMember.ts)
## Parameters
### streamId
* **Type:** `string`
The id of the stream to set the ENS address of.
### config
* **Type:** `ActionConfig<Myself["setEnsAddress"]>`
* **Optional**
Configuration options for the action.
## Return Type
The `setEnsAddress` action and its loading state.
```ts theme={null}
{
data: void | undefined;
error: Error | undefined;
isPending: boolean;
isSuccess: boolean;
isError: boolean;
setEnsAddress: (ensAddress: `0x${string}`) => Promise<void>;
}
```
# useSetNft
Source: https://docs.towns.com/build/react-sdk/api/useSetNft
Hook to set the NFT of the current user in a stream. You should be validating if the NFT belongs to the user before setting it.
## Imports
```ts theme={null}
import { useSetNft } from '@towns-protocol/react-sdk'
```
## Definition
```ts theme={null}
function useSetNft(
streamId: string,
config?: ActionConfig<Myself["setNft"]>,
): {
data: void | undefined;
error: Error | undefined;
isPending: boolean;
isSuccess: boolean;
isError: boolean;
setNft: (nft: NftModel) => Promise<void>;
}
```
**Source:** [useSetNft](https://github.com/towns-protocol/towns/blob/main/packages/react-sdk/src/useMyMember.ts)
## Parameters
### streamId
* **Type:** `string`
The id of the stream to set the NFT of.
### config
* **Type:** `ActionConfig<Myself["setNft"]>`
* **Optional**
Configuration options for the action.
## Return Type
The `setNft` action and its loading state.
```ts theme={null}
{
data: void | undefined;
error: Error | undefined;
isPending: boolean;
isSuccess: boolean;
isError: boolean;
setNft: (nft: NftModel) => Promise<void>;
}
```
# useSetUsername
Source: https://docs.towns.com/build/react-sdk/api/useSetUsername
Hook to set the username of the current user in a stream.
## Imports
```ts theme={null}
import { useSetUsername } from '@towns-protocol/react-sdk'
```
## Definition
```ts theme={null}
function useSetUsername(
streamId: string,
config?: ActionConfig<Myself["setUsername"]>,
): {
data: void | undefined;
error: Error | undefined;
isPending: boolean;
isSuccess: boolean;
isError: boolean;
setUsername: (username: string) => Promise<void>;
}
```
**Source:** [useSetUsername](https://github.com/towns-protocol/towns/blob/main/packages/react-sdk/src/useMyMember.ts)
## Parameters
### streamId
* **Type:** `string`
The id of the stream to set the username of.
### config
* **Type:** `ActionConfig<Myself["setUsername"]>`
* **Optional**
Configuration options for the action.
## Return Type
The `setUsername` action and its loading state.
```ts theme={null}
{
data: void | undefined;
error: Error | undefined;
isPending: boolean;
isSuccess: boolean;
isError: boolean;
setUsername: (username: string) => Promise<void>;
}
```
# useSpace
Source: https://docs.towns.com/build/react-sdk/api/useSpace
Hook to get data about a space. You can use this hook to get space metadata and ids of channels in the space.
## Imports
```ts theme={null}
import { useSpace } from '@towns-protocol/react-sdk'
```
## Examples
You can use this hook to display the data about a space:
```tsx theme={null}
import { useSpace } from '@towns-protocol/react-sdk'
const Space = ({ spaceId }: { spaceId: string }) => {
const { data: space } = useSpace(spaceId)
return <div>{space.metadata?.name || 'Unnamed Space'}</div>
}
```
## Definition
```ts theme={null}
function useSpace(
spaceId: string,
config?: ObservableConfig.FromObservable<Space>,
): ObservableValue<SpaceModel>
```
**Source:** [useSpace](https://github.com/towns-protocol/towns/blob/main/packages/react-sdk/src/useSpace.ts)
## Parameters
### spaceId
* **Type:** `string`
The id of the space to get data about.
### config
* **Type:** `ObservableConfig.FromObservable<Space>`
* **Optional**
Configuration options for the observable.
## Return Type
The SpaceModel data.
```ts theme={null}
ObservableValue<SpaceModel>
```
# useSyncAgent
Source: https://docs.towns.com/build/react-sdk/api/useSyncAgent
Hook to get the sync agent from the TownsSyncProvider.
You can use it to interact with the sync agent for more advanced usage.
Throws an error if no sync agent is set in the TownsSyncProvider.
## Imports
```ts theme={null}
import { useSyncAgent } from '@towns-protocol/react-sdk'
```
## Definition
```ts theme={null}
function useSyncAgent(): SyncAgent
```
**Source:** [useSyncAgent](https://github.com/towns-protocol/towns/blob/main/packages/react-sdk/src/useSyncAgent.tsx)
## Return Type
The sync agent in use, set in TownsSyncProvider.
```ts theme={null}
SyncAgent
```
# useThreads
Source: https://docs.towns.com/build/react-sdk/api/useThreads
Hook to get the threads from a stream.
## Imports
```ts theme={null}
import { useThreads } from '@towns-protocol/react-sdk'
```
## Definition
```ts theme={null}
function useThreads(
streamId: string,
config?: ObservableConfig.FromObservable<TimelinesMap>,
): ObservableValue<TimelinesMap>
```
**Source:** [useThreads](https://github.com/towns-protocol/towns/blob/main/packages/react-sdk/src/useThreads.ts)
## Parameters
### streamId
* **Type:** `string`
The id of the stream to get the threads from.
### config
* **Type:** `ObservableConfig.FromObservable<TimelinesMap>`
* **Optional**
Configuration options for the observable.
## Return Type
The threads of the stream as a map from the message eventId to a thread.
```ts theme={null}
ObservableValue<TimelinesMap>
```
# useTimeline
Source: https://docs.towns.com/build/react-sdk/api/useTimeline
Hook to get the timeline events from a stream.
You can use the `useTimeline` hook to get the timeline events from a channel stream, dm stream or group dm stream
## Imports
```ts theme={null}
import { useTimeline } from '@towns-protocol/react-sdk'
```
## Examples
```ts theme={null}
import { useTimeline } from '@towns-protocol/react-sdk'
import { RiverTimelineEvent } from '@towns-protocol/sdk'
const { data: events } = useTimeline(streamId)
// You can filter the events by their kind
const messages = events.filter((event) => event.content?.kind === RiverTimelineEvent.ChannelMessage)
```
## Definition
```ts theme={null}
function useTimeline(
streamId: string,
config?: ObservableConfig.FromObservable<TimelineEvent[]>,
): ObservableValue<TimelineEvent[]>
```
**Source:** [useTimeline](https://github.com/towns-protocol/towns/blob/main/packages/react-sdk/src/useTimeline.ts)
## Parameters
### streamId
* **Type:** `string`
The id of the stream to get the timeline events from.
### config
* **Type:** `ObservableConfig.FromObservable<TimelineEvent[]>`
* **Optional**
Configuration options for the observable.
## Return Type
The timeline events of the stream as an observable.
```ts theme={null}
ObservableValue<TimelineEvent[]>
```
# useTowns
Source: https://docs.towns.com/build/react-sdk/api/useTowns
Hook to get an observable from the sync agent.
An alternative of our premade hooks, allowing the creation of custom abstractions.
## Imports
```ts theme={null}
import { useTowns } from '@towns-protocol/react-sdk'
```
## Definition
```ts theme={null}
function useTowns<T>(
selector: (sync: SyncSelector) => Observable<T>,
config?: ObservableConfig.FromData<T>,
): ObservableValue<T extends PersistedModel<infer UnwrappedData> ? UnwrappedData : T>
```
**Source:** [useTowns](https://github.com/towns-protocol/towns/blob/main/packages/react-sdk/src/useTowns.ts)
## Parameters
### selector
* **Type:** `(sync: SyncSelector) => Observable<T>`
A selector function to get a observable from the sync agent.
### config
* **Type:** `ObservableConfig.FromData<T>`
* **Optional**
Configuration options for the observable.
#### config.fireImmediately
* **Type:** `boolean`
* **Optional**
Trigger the update immediately, without waiting for the first update.
#### config.onError
* **Type:** `(error: Error) => void`
* **Optional**
Callback function to be called when an error occurs.
#### config.onUpdate
* **Type:** `(data: Data) => void`
* **Optional**
Callback function to be called when the data is updated.
## Return Type
The data from the selected observable.
```ts theme={null}
ObservableValue<T extends PersistedModel<infer UnwrappedData> ? UnwrappedData : T>
```
# useTownsAuthStatus
Source: https://docs.towns.com/build/react-sdk/api/useTownsAuthStatus
Hook to get the auth status of the user connection with the Towns network.
## Imports
```ts theme={null}
import { useTownsAuthStatus } from '@towns-protocol/react-sdk'
```
## Definition
```ts theme={null}
function useTownsAuthStatus(
config?: ObservableConfig.FromObservable<AuthStatus>,
): {
status: AuthStatus;
isInitializing: boolean;
isEvaluatingCredentials: boolean;
isCredentialed: boolean;
isConnectingToTowns: boolean;
isConnectedToTowns: boolean;
isDisconnected: boolean;
isError: boolean;
}
```
**Source:** [useTownsAuthStatus](https://github.com/towns-protocol/towns/blob/main/packages/react-sdk/src/useTownsAuthStatus.ts)
## Parameters
### config
* **Type:** `ObservableConfig.FromObservable<AuthStatus>`
* **Optional**
Configuration options for the observable.
## Return Type
An object containing the current AuthStatus status and boolean flags for each possible status.
```ts theme={null}
{
status: AuthStatus;
isInitializing: boolean;
isEvaluatingCredentials: boolean;
isCredentialed: boolean;
isConnectingToTowns: boolean;
isConnectedToTowns: boolean;
isDisconnected: boolean;
isError: boolean;
}
```
# useUserDms
Source: https://docs.towns.com/build/react-sdk/api/useUserDms
Hook to get the direct messages of the current user.
## Imports
```ts theme={null}
import { useUserDms } from '@towns-protocol/react-sdk'
```
## Examples
You can combine this hook with the `useDm`, `useMemberList` and `useMember` hooks to get all direct messages of the current user and render them, showing the name of the other user in the dm:
```tsx theme={null}
import { useDm, useMyMember, useMemberList, useMember } from '@towns-protocol/react-sdk'
const AllDms = () => {
const { streamIds } = useUserDms()
return <>{streamIds.map((streamId) => <Dm key={streamId} streamId={streamId} />)}</>
}
const Dm = ({ streamId }: { streamId: string }) => {
const { data: dm } = useDm(streamId)
const { userId: myUserId } = useMyMember(streamId)
const { data: members } = useMemberList(streamId)
const { userId, username, displayName } = useMember({
streamId,
// We find the other user in the dm by checking the userIds in the member list
// and defaulting to the current user if we don't find one, since a user is able to send a dm to themselves
userId: members.userIds.find((userId) => userId !== sync.userId) || sync.userId,
})
return <span>{userId === myUserId ? 'You' : displayName || username || userId}</span>
}
```
## Definition
```ts theme={null}
function useUserDms(
config?: ObservableConfig.FromObservable<Dms>,
): {
error: Error | undefined;
status: "loading" | "loaded" | "error";
isLoading: boolean;
isError: boolean;
isLoaded: boolean;
streamIds: string[];
}
```
**Source:** [useUserDms](https://github.com/towns-protocol/towns/blob/main/packages/react-sdk/src/useUserDms.ts)
## Parameters
### config
* **Type:** `ObservableConfig.FromObservable<Dms>`
* **Optional**
Configuration options for the observable.
## Return Type
The list of all direct messages stream ids of the current user.
```ts theme={null}
{
error: Error | undefined;
status: "loading" | "loaded" | "error";
isLoading: boolean;
isError: boolean;
isLoaded: boolean;
streamIds: string[];
}
```
# useUserGdms
Source: https://docs.towns.com/build/react-sdk/api/useUserGdms
Hook to get the group dm streams of the current user.
## Imports
```ts theme={null}
import { useUserGdms } from '@towns-protocol/react-sdk'
```
## Examples
You can combine this hook with the `useGdm` hook to get all group dm streams of the current user and render them:
```tsx theme={null}
import { useUserGdms, useGdm } from '@towns-protocol/react-sdk'
const AllGdms = () => {
const { streamIds } = useUserGdms()
return <>{streamIds.map((streamId) => <Gdm key={streamId} streamId={streamId} />)}</>
}
const Gdm = ({ streamId }: { streamId: string }) => {
const { data: gdm } = useGdm(streamId)
return <div>{gdm.metadata?.name || 'Unnamed Gdm'}</div>
}
```
## Definition
```ts theme={null}
function useUserGdms(
config?: ObservableConfig.FromObservable<Gdms>,
): {
error: Error | undefined;
status: "loading" | "loaded" | "error";
isLoading: boolean;
isError: boolean;
isLoaded: boolean;
streamIds: string[];
}
```
**Source:** [useUserGdms](https://github.com/towns-protocol/towns/blob/main/packages/react-sdk/src/useUserGdms.ts)
## Parameters
### config
* **Type:** `ObservableConfig.FromObservable<Gdms>`
* **Optional**
Configuration options for the observable.
## Return Type
The list of all group dm stream ids of the current user.
```ts theme={null}
{
error: Error | undefined;
status: "loading" | "loaded" | "error";
isLoading: boolean;
isError: boolean;
isLoaded: boolean;
streamIds: string[];
}
```
# useUserSpaces
Source: https://docs.towns.com/build/react-sdk/api/useUserSpaces
Hook to get the spaces of the current user.
## Imports
```ts theme={null}
import { useUserSpaces } from '@towns-protocol/react-sdk'
```
## Examples
You can combine this hook with the `useSpace` hook to get all spaces of the current user and render them:
```tsx theme={null}
import { useUserSpaces, useSpace } from '@towns-protocol/react-sdk'
const AllSpaces = () => {
const { spaceIds } = useUserSpaces()
return <>{spaceIds.map((spaceId) => <Space key={spaceId} spaceId={spaceId} />)}</>
}
const Space = ({ spaceId }: { spaceId: string }) => {
const { data: space } = useSpace(spaceId)
return <div>{space.metadata?.name || 'Unnamed Space'}</div>
}
```
## Definition
```ts theme={null}
function useUserSpaces(
config?: ObservableConfig.FromObservable<Spaces>,
): {
error: Error | undefined;
status: "loading" | "loaded" | "error";
isLoading: boolean;
isError: boolean;
isLoaded: boolean;
spaceIds: string[];
}
```
**Source:** [useUserSpaces](https://github.com/towns-protocol/towns/blob/main/packages/react-sdk/src/useUserSpaces.ts)
## Parameters
### config
* **Type:** `ObservableConfig.FromObservable<Spaces>`
* **Optional**
Configuration options for the observable.
## Return Type
The list of all space ids of the current user.
```ts theme={null}
{
error: Error | undefined;
status: "loading" | "loaded" | "error";
isLoading: boolean;
isError: boolean;
isLoaded: boolean;
spaceIds: string[];
}
```
# Changelog
Source: https://docs.towns.com/build/react-sdk/changelog
# Getting Started
Source: https://docs.towns.com/build/react-sdk/getting-started
This guide will help you get started with Towns Protocol React SDK. You'll learn how to:
1. [Install the React SDK](#installation)
2. [Set up the necessary providers](#setting-up-providers)
3. [Connect to Towns](#connecting-to-towns-protocol)
4. [Create a space](#creating-a-space)
5. [Send your first message](#sending-your-first-message)
## Installation
You can start a new Towns project in two ways:
### Using create-towns-protocol-app (Recommended)
The easiest way to get started is using `create-towns-protocol-app` and follow the instructions in the terminal. This will set up a new React project with all the necessary dependencies and configurations.
```bash theme={null}
# bun
bun create towns-protocol-app my-app
# npm
npm create towns-protocol-app my-app
# yarn
yarn create towns-protocol-app my-app
# pnpm
pnpm create towns-protocol-app my-app
```
By default, this will create a new app using the Towns Playground template - a full-featured example application that demonstrates Towns's Protocol capabilities.
### Manual Installation
If you prefer to add the React SDK to an existing project, install the required dependencies:
```bash theme={null}
bun add @towns-protocol/react-sdk @towns-protocol/sdk vite-plugin-node-polyfills
```
Then, add the `vite-plugin-node-polyfills` to your `vite.config.ts`:
```ts vite.config.ts {1,9} theme={null}
import { nodePolyfills } from 'vite-plugin-node-polyfills'
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
// ...rest of your config
plugins: [
// ...rest of your plugins
nodePolyfills(),
react(),
],
})
```
## Setting Up Providers
Towns requires a few providers to be set up at the root of your application:
1. `WagmiProvider` - For Web3 wallet connection (recommended)
2. `TownsSyncProvider` - For interacting with Towns Protocol
Here's how to set them up:
```tsx App.tsx theme={null}
import { TownsSyncProvider } from "@towns-protocol/react-sdk";
import { base, baseSepolia } from 'viem/chains'
import { WagmiConfig, createConfig } from "wagmi";
import { createPublicClient, http } from 'viem'
// Configure Wagmi
export const wagmiConfig = createConfig({
autoConnect: true,
publicClient: createPublicClient({
chain: [base, baseSepolia],
transport: http()
}),
})
function App() {
return (
<WagmiConfig config={wagmiConfig}>
<TownsSyncProvider>
{/* Your app content */}
</TownsSyncProvider>
</WagmiConfig>
);
}
```
If you need any assistance with setting up Wagmi, check out the [Wagmi Getting Started Guide](https://wagmi.sh/react/getting-started).
## Connecting to Towns Protocol
You can connect to Towns using either a Web3 wallet (recommended) or a bearer token.
You can use the following networks:
* `omega` - The Towns mainnet, uses Base as the EVM chain
* `gamma` - The Towns testnet, uses Base Sepolia as the EVM chain
We recommend using `gamma` as a starting point.
<Note>
You can use other gamma clients like [Towns (gamma)](https://app.gamma.towns.com) or the [Towns Playground](https://river-sample-app.vercel.app) to help you inspect messages on the `gamma` network.
</Note>
### Using a Web3 Wallet
```tsx theme={null}
import { useAgentConnection } from "@towns-protocol/react-sdk";
import { townsEnv } from "@towns-protocol/sdk";
import { getEthersSigner } from "./utils/viem-to-ethers";
import { wagmiConfig } from "./config/wagmi";
const townsConfig = townsEnv().makeTownsConfig("gamma");
function ConnectButton() {
const { connect, isAgentConnecting, isAgentConnected } = useAgentConnection();
return (
<button
onClick={async () => {
const signer = await getEthersSigner(wagmiConfig);
connect(signer, { townsConfig });
}}
>
{isAgentConnecting ? "Connecting..." : "Connect"}
{isAgentConnected && "Connected ✅"}
</button>
);
}
```
<Note>
You'll need to use `getEthersSigner` to get the signer from viem wallet client.
Towns SDK uses ethers under the hood, so you'll need to convert the viem wallet client to an ethers signer.
You can get the `getEthersSigner` function from [Wagmi docs](https://wagmi.sh/core/guides/ethers#usage-1).
</Note>
### Using a Bearer Token
You can connect to Towns using a pre-existing identity.
This allows you to read and send messages, but you won't be able to create spaces or channels (on-chain actions).
<Note>
If you have a Towns account, you can get your bearer token from there. Type `/bearer-token` in any conversation to get your token.
</Note>
```tsx theme={null}
import { useAgentConnection } from "@towns-protocol/react-sdk";
import { townsEnv } from "@towns-protocol/sdk";
const townsConfig = townsEnv().makeTownsConfig("gamma");
function ConnectButton() {
const { connectUsingBearerToken, isAgentConnecting, isAgentConnected } = useAgentConnection();
const [bearerToken, setBearerToken] = useState('');
return (
<div>
<input
value={bearerToken}
onChange={(e) => setBearerToken(e.target.value)}
placeholder="Enter bearer token"
/>
<button
onClick={() => connectUsingBearerToken(bearerToken, { townsConfig })}
>
{isAgentConnecting ? "Connecting..." : "Connect"}
{isAgentConnected && "Connected ✅"}
</button>
</div>
);
}
```
## 프로젝트로 돌아가기