npm package: @nexera/management
Description: Nexera CMS Management SDK — full CRUD for entries, content models, assets, and more
Latest version: 0.1.0

# @nexera/management

Nexera CMS Management SDK — full CRUD for entries, content models, assets, environments, locales, and branches.

## Installation

```bash
npm install @nexera/management
```

**Requirements:** Node.js 18+ (uses the global `fetch` API). Works in browsers, edge runtimes, and Node.js.

## Quick Start

```ts
import { createManagementClient } from '@nexera/management';

const mgmt = createManagementClient({
  baseUrl: 'https://api.yourcms.com',
  stackId: 'your-stack-uuid',
  tenantId: 'your-tenant-uuid',
  branchId: 'your-branch-uuid',
  apiKey: 'cms_mgmt_abc123...', // or use `token` for JWT
});

// Create and publish an entry
const entry = await mgmt.entries.create('content-model-id', {
  data: { title: 'Hello World', body: 'My first post' },
  locale: 'en',
});
await mgmt.entries.publish('content-model-id', entry.id);
```

## Configuration

```ts
createManagementClient({
  baseUrl: string;           // BFF API base URL
  stackId: string;           // Stack UUID
  tenantId: string;          // Tenant UUID
  branchId: string;          // Branch UUID
  token?: string;            // JWT token (mutually exclusive with apiKey)
  apiKey?: string;           // API key (mutually exclusive with token)
  defaultLocale?: string;    // Default locale for entry operations
  fetch?: typeof fetch;      // Custom fetch
  fetchOptions?: RequestInit; // Default fetch options
})
```

> Either `token` or `apiKey` must be provided.

## Entries

Full CRUD with publish workflow and version management.

```ts
// List
const entries = await mgmt.entries.list('model-id', {
  page: 1, limit: 20, locale: 'en', status: 'published',
});

// Get
const entry = await mgmt.entries.get('model-id', 'entry-id');

// Create
const newEntry = await mgmt.entries.create('model-id', {
  data: { title: 'New Post', body: 'Content here' },
  locale: 'en',
});

// Update
await mgmt.entries.update('model-id', 'entry-id', {
  data: { title: 'Updated Title' },
});

// Delete
await mgmt.entries.delete('model-id', 'entry-id');
```

**Publishing:**

```ts
await mgmt.entries.publish('model-id', 'entry-id');
await mgmt.entries.unpublish('model-id', 'entry-id');
await mgmt.entries.schedule('model-id', 'entry-id', {
  publishAt: '2026-04-01T09:00:00Z',
  unpublishAt: '2026-05-01T09:00:00Z',
});
```

**Version history:**

```ts
const versions = await mgmt.entries.listVersions('model-id', 'entry-id');
await mgmt.entries.restoreVersion('model-id', 'entry-id', 'version-id');
```

## Content Models

```ts
// List all
const models = await mgmt.contentModels.list();

// Get
const model = await mgmt.contentModels.get('model-id');

// Create
const newModel = await mgmt.contentModels.create({
  name: 'Blog Post',
  key: 'blog-post',
  description: 'Blog articles',
});

// Update
await mgmt.contentModels.update('model-id', { description: 'Updated' });

// Delete
await mgmt.contentModels.delete('model-id');
```

**Field management:**

```ts
import { FieldType } from '@nexera/management';

const fields = await mgmt.contentModels.listFields('model-id');

await mgmt.contentModels.addField('model-id', {
  key: 'author',
  name: 'Author',
  type: FieldType.SingleLineText,
  required: true,
});

await mgmt.contentModels.updateField('model-id', 'field-id', {
  required: false,
});
```

## Assets

```ts
// List
const assets = await mgmt.assets.list({ page: 1, limit: 20 });

// Search
const results = await mgmt.assets.search('hero image');

// Upload (Node.js)
import fs from 'node:fs';
const file = new Blob([fs.readFileSync('./photo.jpg')], { type: 'image/jpeg' });
const uploaded = await mgmt.assets.upload(file, { description: 'Team photo' });

// Upload (Browser)
const inputFile = document.querySelector('input[type="file"]').files[0];
const uploaded = await mgmt.assets.upload(inputFile);

// Update metadata
await mgmt.assets.update('asset-id', { title: 'New title' });

// Delete
await mgmt.assets.delete('asset-id');
```

## Environments

Tenant-scoped (not branch-scoped).

```ts
const environments = await mgmt.environments.list();
await mgmt.environments.create({ name: 'staging' });
await mgmt.environments.update('env-id', { name: 'production' });
await mgmt.environments.delete('env-id');
```

## Locales

Branch-scoped.

```ts
const locales = await mgmt.locales.list();
await mgmt.locales.create({ code: 'fr', name: 'French' });
await mgmt.locales.update('locale-id', { isDefault: true });
await mgmt.locales.delete('locale-id');
```

## Branches

Tenant-scoped.

```ts
const branches = await mgmt.branches.list();
await mgmt.branches.create({ name: 'feature/redesign' });
await mgmt.branches.update('branch-id', { name: 'feature/v2' });
await mgmt.branches.delete('branch-id');
```

## Error Handling

```ts
import {
  CmsError,
  CmsAuthenticationError,
  CmsNotFoundError,
  CmsRateLimitError,
} from '@nexera/management';

try {
  await mgmt.entries.get('model-id', 'entry-id');
} catch (error) {
  if (error instanceof CmsNotFoundError) {
    console.log(`${error.resourceType} not found: ${error.resourceId}`);
  } else if (error instanceof CmsAuthenticationError) {
    console.log('Check your API key or JWT token');
  } else if (error instanceof CmsRateLimitError) {
    console.log(`Retry after ${error.retryAfterMs}ms`);
  } else if (error instanceof CmsError) {
    console.log(`HTTP ${error.statusCode}:`, error.responseBody);
  }
}
```

## Enums

```ts
import { EntryState, ContentModelType, FieldType } from '@nexera/management';

EntryState.Draft        // 0
EntryState.Published    // 3

ContentModelType.Standard      // 0
ContentModelType.PageTemplate  // 1
ContentModelType.Component     // 2

FieldType.SingleLineText  // 0
FieldType.Reference       // 11
FieldType.ModularBlock    // 7
```

## Node.js Script Example

```ts
import { createManagementClient } from '@nexera/management';

const mgmt = createManagementClient({
  baseUrl: process.env.API_URL!,
  stackId: process.env.STACK_ID!,
  tenantId: process.env.TENANT_ID!,
  branchId: process.env.BRANCH_ID!,
  apiKey: process.env.MANAGEMENT_API_KEY!,
});

// Bulk publish all draft entries
const drafts = await mgmt.entries.list('blog-model-id', { status: 'draft' });
for (const entry of drafts.items) {
  await mgmt.entries.publish('blog-model-id', entry.id);
  console.log(`Published: ${entry.id}`);
}
```

## Related

- **[@nexera/delivery](https://www.npmjs.com/package/@nexera/delivery)** — Read published content and query via GraphQL.

## License

MIT