npm package: @naridon/cms
Description: Client SDK for consuming Naridon CMS content from any JavaScript/TypeScript app
Latest version: 0.2.0

# @naridon/cms

Client SDK for consuming Naridon CMS content from any JavaScript/TypeScript application. Zero dependencies -- uses native `fetch`.

## Installation

```bash
npm install @naridon/cms
# or
pnpm add @naridon/cms
# or
yarn add @naridon/cms
```

## Quick Start

```typescript
import { createCmsClient } from "@naridon/cms";

const cms = createCmsClient({
  siteSlug: "my-store",
  baseUrl: "https://app.naridon.com",
});

// List published pages
const pages = await cms.pages.list({ type: "blog_post", sort: "-publishedAt", limit: 10 });

// Get a single page by slug
const page = await cms.pages.getBySlug("about-us");

// List content entries
const entries = await cms.entries.list("blog-posts", { sort: "-createdAt" });

// Get a single content entry
const entry = await cms.entries.getBySlug("blog-posts", "my-first-post");

// Blog (convenience endpoint for blog_post pages)
const blog = await cms.blog.list({ page: 1, limit: 10 });
const post = await cms.blog.getBySlug("hello-world");

// Site info
const site = await cms.site.get();

// Media
const media = await cms.media.list();
```

## API Reference

### `createCmsClient(options)`

Creates a new CMS client instance.

| Option     | Type     | Required | Description                                        |
| ---------- | -------- | -------- | -------------------------------------------------- |
| `siteSlug` | `string` | Yes      | Site slug / domain identifier used in API paths     |
| `baseUrl`  | `string` | Yes      | Base URL for the Naridon API                        |
| `fetch`    | `fetch`  | No       | Custom fetch implementation (defaults to global)    |
| `headers`  | `object` | No       | Default headers sent with every request             |

### Pages

```typescript
// List pages with filters
cms.pages.list({ type, locale, sort, fields, limit, offset })

// Get single page (supports preview)
cms.pages.getBySlug("slug", { locale, preview: true, token: "..." })
```

### Content Entries

```typescript
// List entries for a content type
cms.entries.list("type-slug", { locale, sort, limit, offset })

// Get single entry (supports preview)
cms.entries.getBySlug("type-slug", "entry-slug", { preview: true, token: "..." })
```

### Blog

```typescript
// List blog posts (paginated)
cms.blog.list({ page: 1, limit: 10 })

// Get single blog post
cms.blog.getBySlug("post-slug")
```

### Site

```typescript
// Get site info
cms.site.get()
```

### Media

```typescript
// List media files
cms.media.list({ folderId, mimeType, page, perPage })
```

### Draft Preview

Preview unpublished content using preview tokens:

```typescript
// Via page/entry endpoints
const draft = await cms.pages.getBySlug("draft-page", {
  preview: true,
  token: "preview-token-here",
});

// Via standalone preview endpoint
const content = await cms.preview("preview-token-here");
```

## Static Export

Export all published content as a single JSON object for static site generation:

```typescript
// Basic export (pages, site, media)
const data = await cms.export();
// { site, pages, entries: {}, media, exportedAt }

// Export with specific content types
const data = await cms.exportWithEntries(["blog-posts", "team-members", "faqs"]);
// { site, pages, entries: { "blog-posts": [...], "team-members": [...], "faqs": [...] }, media, exportedAt }
```

### Usage with Next.js (SSG)

```typescript
// lib/cms.ts
import { createCmsClient } from "@naridon/cms";

export const cms = createCmsClient({
  siteSlug: process.env.CMS_SITE_SLUG!,
  baseUrl: process.env.CMS_BASE_URL!,
});

// app/blog/page.tsx
export default async function BlogPage() {
  const blog = await cms.blog.list({ limit: 20 });
  return <BlogList posts={blog.posts} />;
}

// app/[slug]/page.tsx
export async function generateStaticParams() {
  const pages = await cms.pages.list({ limit: 100 });
  return pages.map((p) => ({ slug: p.slug }));
}
```

### Usage with Astro

```typescript
// src/lib/cms.ts
import { createCmsClient } from "@naridon/cms";

export const cms = createCmsClient({
  siteSlug: import.meta.env.CMS_SITE_SLUG,
  baseUrl: import.meta.env.CMS_BASE_URL,
});

// src/pages/blog/[slug].astro
const posts = await cms.blog.list({ limit: 100 });
export function getStaticPaths() {
  return posts.posts.map((p) => ({ params: { slug: p.slug } }));
}
```

## Error Handling

```typescript
import { CmsNotFoundError, CmsPreviewError, CmsError } from "@naridon/cms";

try {
  const page = await cms.pages.getBySlug("nonexistent");
} catch (err) {
  if (err instanceof CmsNotFoundError) {
    // 404 - page not found
  } else if (err instanceof CmsPreviewError) {
    // 401/403 - invalid preview token
  } else if (err instanceof CmsError) {
    // Other HTTP error
    console.error(err.status, err.message);
  }
}
```

## TypeScript Types

All types are exported for use in your application:

```typescript
import type {
  CmsPage,
  CmsPageListItem,
  CmsPageMeta,
  CmsContentEntry,
  CmsContentEntryDetail,
  CmsContentType,
  CmsSite,
  CmsMedia,
  CmsBlogResponse,
  CmsStaticData,
} from "@naridon/cms";
```

## Requirements

- Node.js >= 18 (native `fetch` required)
- Or any environment with a global `fetch` (browsers, Deno, Bun, Cloudflare Workers)

## License

MIT