# Community library

> Browse the Nodaro community library from TypeScript, clone shared characters, locations and objects into your account, favorite them, and report a listing.

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

**`client.community`** reads the community library, the shared collection of characters, locations and objects curated by the Nodaro team. You can browse and search it, read a listing, clone a listing into your own account, favorite it, and report it for moderation. The methods call the [Community REST API](https://nodaro.ai/docs/developers/api/community). See [Community library](https://nodaro.ai/docs/guides/community-library) for the feature and its likeness and consent rules.

The community library exists on multi-user installs: Nodaro Cloud and Business edition. A single-user Community edition install answers every call with `NotFoundError`.

## Methods

| Method | What it does |
| --- | --- |
| [`browse(params?)`](#browseparams) | Browse and search the listings |
| [`get(slug)`](#getslug) | Read one listing |
| [`getFull(slug)`](#getfullslug) | Read one listing with its full public snapshot |
| [`favorites()`](#favorites) | List the listings you favorited |
| [`clone(id, entityType)`](#cloneid-entitytype) | Copy a listing into your account |
| [`favorite(id)`](#favoriteid) | Add or remove a favorite |
| [`report(id, reason)`](#reportid-reason) | Report a listing for moderation |

Publishing is not part of the SDK: the SDK's personal and OAuth tokens cannot publish.

## client.community

A listing is a `CommunityCard`. Its fields use snake_case, as the API sends them. `CommunityEntityType` is `"character"`, `"location"` or `"object"`.

### browse(params?)

Returns a page of public listings and a `nextCursor` (`GET /v1/community/browse`). Pass `nextCursor` back as `cursor` for the next page; it is `null` on the last page.

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

<TypeTable
type={{
entityType: { type: '"character" | "location" | "object"', description: "Only one kind of asset." },
q: { type: 'string', description: "Search the title, description and tags." },
category: { type: 'string', description: "Only one category." },
sort: { type: '"newest" | "popular"', default: '"newest"', description: "The order." },
cursor: { type: 'string', description: "The nextCursor of the previous page." },
limit: { type: 'number', default: '20', description: "The page size, at most 50." },
}}
/>

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

### get(slug)

Reads one listing by its slug (`GET /v1/community/detail/:slug`).

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

<TypeTable
type={{
slug: { type: 'string', required: true, description: "The listing's slug." },
}}
/>

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

Throws `NotFoundError` when the listing does not exist or is no longer active.

### getFull(slug)

Reads one listing with its full public snapshot: its images, voice and text, as a detail page shows them (`GET /v1/community/detail/:slug/full`).

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

<TypeTable
type={{
slug: { type: 'string', required: true, description: "The listing's slug." },
}}
/>

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

### favorites()

Lists the listings you favorited (`GET /v1/community/favorites`).

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

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

### clone(id, entityType)

Copies a listing into your library as an **independent copy** (`POST /v1/community/listings/:id/clone`). Its files are copied into your own storage, so the copy stays when the original changes or is removed. It returns the kind and id of your new asset.

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

<TypeTable
type={{
id: { type: 'string', required: true, description: "The listing id." },
entityType: { type: '"character" | "location" | "object"', required: true, description: "The kind of asset the listing holds." },
}}
/>

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

An OAuth token needs the `assets:write` scope. Throws `StorageExceededError` when your storage is full.

### favorite(id)

Adds a listing to your favorites, or removes it when it is already there (`POST /v1/community/listings/:id/favorite`). It returns the new state.

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

<TypeTable
type={{
id: { type: 'string', required: true, description: "The listing id." },
}}
/>

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

### report(id, reason)

Reports a listing for moderation (`POST /v1/community/listings/:id/report`).

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

<TypeTable
type={{
id: { type: 'string', required: true, description: "The listing id." },
reason: { type: '"real_person_no_consent" | "inappropriate" | "ip_violation" | "other"', required: true, description: "real_person_no_consent: it shows a real person without consent. inappropriate: unsuitable content. ip_violation: it uses someone else's intellectual property. other: any other reason." },
}}
/>

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

## Frequently asked questions

### How do I copy a community character into my account?

Call client.community.clone with the listing id and the entity type, such as character. The copy is yours and does not change when the original does. It counts against your storage.

### Can I publish to the community library with the SDK?

No. Publishing is not part of the SDK. The SDK can browse, read, clone, favorite and report listings.

### Why does client.community answer 404 on my install?

The community library exists on Nodaro Cloud and on Business edition installs. A single-user Community edition install has no community routes and answers 404.

### How do I report a listing that shows a real person without consent?

Call client.community.report with the listing id and the reason real_person_no_consent. The listing goes to moderation.
