npm package: @naranja-labs/the-orange-cms-sdk
Description: SDK for The Orange CMS — fetch and render CMS-managed text content
Latest version: 0.2.3

# @naranja-labs/the-orange-cms-sdk

SDK for [The Orange CMS](https://github.com/NaranjaLabs/the-orange-cms) — fetch and render CMS-managed text content in your website.

## Install

```bash
bun add @naranja-labs/the-orange-cms-sdk
# or
npm install @naranja-labs/the-orange-cms-sdk
```

## Quick Start

### 1. Create a CMS client

```typescript
import { createCMSClient } from "@naranja-labs/the-orange-cms-sdk";

const cms = createCMSClient({
  baseUrl: "https://your-cms.example.com",
  siteSlug: "my-site",
  apiKey: "your-site-api-key",
});
```

### 2. Fetch page content

```typescript
const page = await cms.getPage("homepage");
// { site: "my-site", page: "homepage", sections: { "hero/title": "Welcome", ... } }

const title = await cms.getSection("homepage", "hero/title");
// "Welcome"
```

### 3. Render with React

```tsx
import { Content } from "@naranja-labs/the-orange-cms-sdk/react";

// You control the HTML structure — the CMS provides the text
<h1><Content content={page} section="hero/title" /></h1>
<p><Content content={page} section="hero/subtitle" /></p>
<a href="/signup"><Content content={page} section="hero/cta" /></a>
```

The `<Content>` component renders a `<span>` with the section text. Wrap it in your own elements to control structure.

## API Reference

### `createCMSClient(config)`

Creates a CMS client instance.

```typescript
interface CMSClientConfig {
  baseUrl: string;   // CMS API URL
  siteSlug: string;  // Your site's slug
  apiKey: string;    // Site API key from the CMS admin
}
```

Returns an object with:

- **`getPage(page: string)`** — Fetches all sections for a page. Returns `{ site, page, sections }`.
- **`getSection(page: string, path: string)`** — Fetches a single section's text. Throws if the section doesn't exist.

### `<Content>` Component

```tsx
import { Content } from "@naranja-labs/the-orange-cms-sdk/react";
```

| Prop | Type | Description |
|------|------|-------------|
| `content` | `CMSPageContent` | Page data from `getPage()` |
| `section` | `string` | Section path (e.g. `"hero/title"`) |
| `className` | `string?` | Optional CSS class for the wrapper `<span>` |

Returns `null` if the section doesn't exist. Renders a `<span>` with a `data-cms-section` attribute for preview integration.

**HTML sanitization:** Content with inline HTML (`<strong>`, `<em>`, `<a>`, `<b>`, `<i>`, `<br>`) is sanitized with an allowlist before rendering. Dangerous elements (`<script>`, event handlers, `javascript:` URIs) are stripped.

### `initPreview(options?)`

```typescript
import { initPreview } from "@naranja-labs/the-orange-cms-sdk/preview";
```

Enables bidirectional sync between the CMS editor and your site when loaded in the preview iframe. Auto-activates inside iframes, or call manually:

```typescript
initPreview({ parentOrigin: "https://your-cms.example.com" });
```

| Option | Type | Description |
|--------|------|-------------|
| `parentOrigin` | `string?` | CMS editor origin for secure `postMessage`. Falls back to `document.referrer`. |

## Content Model

The CMS stores page content as delimited text files:

```markdown
<!-- @hero/title -->
Welcome to Our Site

<!-- @hero/subtitle -->
The <strong>best</strong> platform for your needs

<!-- @hero/cta -->
Get Started Today
```

- Section paths use `/` as separator (e.g. `hero/title`, `features/card-1`)
- Content is plain text or inline HTML (`<strong>`, `<em>`, `<a>`)
- Developers control HTML structure; the CMS manages text

## Requirements

- **React** 19+ (optional — only needed for `@naranja-labs/the-orange-cms-sdk/react`)
- Works in any JavaScript runtime (Node.js, Bun, Deno, browsers)

## License

MIT