# 커뮤니티 라이브러리

> TypeScript로 Nodaro 커뮤니티 라이브러리를 둘러보고, 공유된 캐릭터, 장소, 오브젝트를 내 계정으로 복제하고, 즐겨찾기에 추가하고, 게시물을 신고합니다.

Source: https://nodaro.ai/ko/docs/developers/sdk/community

<strong>`client.community`</strong>는 커뮤니티 라이브러리를 읽습니다. 커뮤니티 라이브러리는 Nodaro 팀이 선별한 캐릭터, 장소, 오브젝트의 공유 모음입니다. 라이브러리를 둘러보고 검색하고, 게시물을 읽고, 게시물을 내 계정으로 복제하고, 즐겨찾기에 추가하고, 신고해 검토를 요청할 수 있습니다. 이 메서드들은 [커뮤니티 REST API](https://nodaro.ai/docs/developers/api/community)를 호출합니다. 기능 자체와 초상 및 동의 규칙은 [커뮤니티 라이브러리](https://nodaro.ai/docs/guides/community-library)를 참조하세요.

커뮤니티 라이브러리는 다중 사용자 설치인 Nodaro Cloud와 Business 에디션에 있습니다. 단일 사용자용 Community Edition 설치는 모든 호출에 `NotFoundError`로 응답합니다.

## 메서드
| 메서드 | 기능 |
| --- | --- |
| [`browse(params?)`](#browseparams) | 게시물 둘러보기와 검색 |
| [`get(slug)`](#getslug) | 게시물 하나 읽기 |
| [`getFull(slug)`](#getfullslug) | 전체 공개 스냅샷과 함께 게시물 하나 읽기 |
| [`favorites()`](#favorites) | 즐겨찾기에 추가한 게시물 목록 |
| [`clone(id, entityType)`](#cloneid-entitytype) | 게시물을 내 계정으로 복사 |
| [`favorite(id)`](#favoriteid) | 즐겨찾기 추가 또는 제거 |
| [`report(id, reason)`](#reportid-reason) | 게시물을 신고해 검토 요청 |

게시는 SDK에 포함되어 있지 않습니다. SDK의 개인 토큰과 OAuth 토큰으로는 게시할 수 없습니다.

## client.community
게시물은 `CommunityCard`입니다. 필드는 API가 보내는 대로 snake_case를 사용합니다. `CommunityEntityType`은 `"character"`, `"location"`, `"object"` 중 하나입니다.

### browse(params?)
공개 게시물 한 페이지와 `nextCursor`를 반환합니다(`GET /v1/community/browse`). 다음 페이지를 받으려면 `nextCursor`를 `cursor`로 다시 전달하세요. 마지막 페이지에서는 `null`입니다.

```ts
browse(params?: BrowseCommunityParams): Promise<{ data: CommunityCard[]; nextCursor: string | null }>
```

<TypeTable
type={{
entityType: { type: '"character" | "location" | "object"', description: "이 종류의 에셋만 표시합니다." },
q: { type: 'string', description: "제목, 설명, 태그를 검색합니다." },
category: { type: 'string', description: "이 카테고리만 표시합니다." },
sort: { type: '"newest" | "popular"', default: '"newest"', description: "정렬 순서입니다." },
cursor: { type: 'string', description: "이전 페이지의 nextCursor입니다." },
limit: { type: 'number', default: '20', description: "페이지 크기이며, 최대 50입니다." },
}}
/>

```ts
const { data: listings, nextCursor } = await client.community.browse({
entityType: "character",
sort: "popular",
limit: 20,
})
```

### get(slug)
슬러그로 게시물 하나를 읽습니다(`GET /v1/community/detail/:slug`).

```ts
get(slug: string): Promise<{ data: CommunityCard }>
```

<TypeTable
type={{
slug: { type: 'string', required: true, description: "게시물의 슬러그입니다." },
}}
/>

```ts
const { data: listing } = await client.community.get("detective-mara")
```

게시물이 없거나 더 이상 활성 상태가 아니면 `NotFoundError`가 발생합니다.

### getFull(slug)
상세 페이지에 표시되는 것처럼 이미지, 보이스, 텍스트를 포함한 전체 공개 스냅샷과 함께 게시물 하나를 읽습니다(`GET /v1/community/detail/:slug/full`).

```ts
getFull(slug: string): Promise<{ data: CommunityFullDetail }>
```

<TypeTable
type={{
slug: { type: 'string', required: true, description: "게시물의 슬러그입니다." },
}}
/>

```ts
const { data: detail } = await client.community.getFull("detective-mara")
```

### favorites()
내가 즐겨찾기에 추가한 게시물을 나열합니다(`GET /v1/community/favorites`).

```ts
favorites(): Promise<{ data: CommunityCard[] }>
```

```ts
const { data: favorites } = await client.community.favorites()
```

### clone(id, entityType)
게시물을 **독립된 복사본**으로 내 라이브러리에 복사합니다(`POST /v1/community/listings/:id/clone`). 파일이 내 저장 공간으로 복사되므로, 원본이 바뀌거나 삭제되어도 복사본은 남습니다. 새로 만든 내 에셋의 종류와 ID를 반환합니다.

```ts
clone(id: string, entityType: "character" | "location" | "object"): Promise<{ entityType: string; id: string }>
```

<TypeTable
type={{
id: { type: 'string', required: true, description: "게시물 ID입니다." },
entityType: { type: '"character" | "location" | "object"', required: true, description: "게시물에 담긴 에셋의 종류입니다." },
}}
/>

```ts
const { id: characterId } = await client.community.clone(listingId, "character")
const character = await client.characters.get(characterId)
```

OAuth 토큰에는 `assets:write` 스코프가 필요합니다. 저장 공간이 가득 차면 `StorageExceededError`가 발생합니다.

### favorite(id)
게시물을 즐겨찾기에 추가하거나, 이미 추가되어 있으면 제거합니다(`POST /v1/community/listings/:id/favorite`). 바뀐 상태를 반환합니다.

```ts
favorite(id: string): Promise<{ favorited: boolean }>
```

<TypeTable
type={{
id: { type: 'string', required: true, description: "게시물 ID입니다." },
}}
/>

```ts
const { favorited } = await client.community.favorite(listingId)
```

### report(id, reason)
게시물을 신고해 검토를 요청합니다(`POST /v1/community/listings/:id/report`).

```ts
report(id: string, reason: CommunityReportReason): Promise<{ ok: true }>
```

<TypeTable
type={{
id: { type: 'string', required: true, description: "게시물 ID입니다." },
reason: { type: '"real_person_no_consent" | "inappropriate" | "ip_violation" | "other"', required: true, description: "real_person_no_consent: 실존 인물을 동의 없이 보여 줍니다. inappropriate: 부적절한 콘텐츠입니다. ip_violation: 다른 사람의 지식 재산을 사용합니다. other: 그 밖의 사유입니다." },
}}
/>

```ts
await client.community.report(listingId, "real_person_no_consent")
```

## 자주 묻는 질문

### 커뮤니티 캐릭터를 내 계정으로 복사하려면 어떻게 하나요?

게시물 ID와 character 같은 엔티티 유형을 넣어 client.community.clone을 호출하세요. 복사본은 내 것이며, 원본이 바뀌어도 변하지 않습니다. 복사본은 내 저장 공간을 차지합니다.

### SDK로 커뮤니티 라이브러리에 게시할 수 있나요?

아니요. 게시는 SDK에 포함되어 있지 않습니다. SDK로는 게시물을 둘러보고, 읽고, 복제하고, 즐겨찾기에 추가하고, 신고할 수 있습니다.

### 내 설치에서 client.community가 404를 반환하는 이유는 무엇인가요?

커뮤니티 라이브러리는 Nodaro Cloud와 Business 에디션 설치에 있습니다. 단일 사용자용 Community Edition 설치에는 커뮤니티 라우트가 없어서 404를 반환합니다.

### 실존 인물을 동의 없이 보여 주는 게시물은 어떻게 신고하나요?

게시물 ID와 사유 real_person_no_consent를 넣어 client.community.report를 호출하세요. 게시물은 검토 대상으로 넘어갑니다.
