> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rocksky.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Clojure

> Idiomatic, pipe-friendly Clojure client for the Rocksky XRPC API.

`app.rocksky/sdk` is an idiomatic Clojure client.

* **Plain maps in, plain maps out** — no records, no protocols.
* **Client-first arg** — every endpoint threads through `->`.
* **No global state** — clients are values you can pass around and reuse.
* **Two real verbs** — `query` (GET) and `procedure` (POST) cover the whole
  XRPC surface; resource namespaces are thin wrappers on top.

## Install

`deps.edn`:

```clojure theme={null}
{:deps {app.rocksky/sdk {:mvn/version "0.2.0-SNAPSHOT"}}}
```

Leiningen / Boot:

```clojure theme={null}
[app.rocksky/sdk "0.2.0-SNAPSHOT"]
```

Or track a specific commit:

```clojure theme={null}
{:deps {app.rocksky/sdk {:git/url   "https://tangled.org/@rocksky.app/rocksky"
                         :git/sha   "..."
                         :deps/root "sdk/clojure"}}}
```

## Quickstart

```clojure theme={null}
(require '[rocksky.core :as rs])

(def client (rs/client))   ;; defaults to https://api.rocksky.app

(rs/get-profile client {:did "did:plc:7vdlgi2bflelz7mmuxoqjfcr"})
;; => {:handle "tsiry-sandratraina.com" :followersCount 42 ...}
```

For authenticated endpoints:

```clojure theme={null}
(def client (rs/client {:token (System/getenv "ROCKSKY_TOKEN")}))

(require '[rocksky.scrobble :as scrobble])
(scrobble/create-scrobble client
                          {:title  "Paranoid Android"
                           :artist "Radiohead"
                           :album  "OK Computer"})
```

## Pipe-friendly composition

```clojure theme={null}
(require '[rocksky.client :as c]
         '[rocksky.actor  :as actor])

(-> (c/client {:base-url "https://api.rocksky.app"})
    (c/with-token (System/getenv "ROCKSKY_TOKEN"))
    (actor/get-profile {:did "did:plc:7vdlgi2bflelz7mmuxoqjfcr"})
    :handle)
;; => "tsiry-sandratraina.com"
```

Reshape responses inline:

```clojure theme={null}
(require '[rocksky.charts :as charts])

(->> (charts/get-top-tracks (c/client) {:limit 5})
     :tracks
     (map :title))
;; => ("Paranoid Android" "Karma Police" ...)
```

## Calling URLs the SDK doesn't wrap

```clojure theme={null}
(c/query     client :app.rocksky.feed.describeFeedGenerator)
(c/procedure client :app.rocksky.shout.createShout {:message "hi"})
```

## Errors

```clojure theme={null}
(try
  (album/get-album client {:uri "at://missing"})
  (catch clojure.lang.ExceptionInfo e
    (let [{:keys [status nsid body]} (ex-data e)]
      (println status nsid body))))
```

## Concurrency

Clients are immutable values — share them across threads:

```clojure theme={null}
(pmap #(actor/get-profile client {:did %}) handles)
```

## Available namespaces

| Namespace             | Wraps                       |
| --------------------- | --------------------------- |
| `rocksky.actor`       | `app.rocksky.actor.*`       |
| `rocksky.album`       | `app.rocksky.album.*`       |
| `rocksky.apikey`      | `app.rocksky.apikey.*`      |
| `rocksky.artist`      | `app.rocksky.artist.*`      |
| `rocksky.charts`      | `app.rocksky.charts.*`      |
| `rocksky.dropbox`     | `app.rocksky.dropbox.*`     |
| `rocksky.feed`        | `app.rocksky.feed.*`        |
| `rocksky.googledrive` | `app.rocksky.googledrive.*` |
| `rocksky.graph`       | `app.rocksky.graph.*`       |
| `rocksky.like`        | `app.rocksky.like.*`        |
| `rocksky.mirror`      | `app.rocksky.mirror.*`      |
| `rocksky.player`      | `app.rocksky.player.*`      |
| `rocksky.playlist`    | `app.rocksky.playlist.*`    |
| `rocksky.scrobble`    | `app.rocksky.scrobble.*`    |
| `rocksky.shout`       | `app.rocksky.shout.*`       |
| `rocksky.song`        | `app.rocksky.song.*`        |
| `rocksky.spotify`     | `app.rocksky.spotify.*`     |
| `rocksky.stats`       | `app.rocksky.stats.*`       |

## Conventions

* **Kebab-case Clojure, camelCase wire.** The SDK translates `:start-date` →
  `startDate`, `:album-art` → `albumArt`, etc. Raw HTTP bodies still use
  camelCase, matching the lexicons.
* **Nil values are dropped.** Pass `:limit nil` and the param won't appear
  on the wire — handy for `cond->` chains.
* **Booleans round-trip.** `:enabled false` is preserved.

## Types

Lexicon-derived schemas (in [malli](https://github.com/metosin/malli) form) are exposed as `rocksky.generated.types/schemas`, a map keyed by `:TypeName` keywords covering every lex `*View*` / `*Record` / `*Input` / `*Output` / `*Params` shape from [the Rocksky lexicons](https://tangled.org/rocksky.app/rocksky/tree/main/apps/api/lexicons). Regenerate with `bun run lexgen:types` at the repo root.

## License

MIT © Tsiry Sandratraina. Source:
[`sdk/clojure`](https://tangled.org/@rocksky.app/rocksky/blob/main/sdk/clojure).
