npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nexera/management

v0.1.0

Published

Nexera CMS Management SDK — full CRUD for entries, content models, assets, and more

Readme

@nexera/management

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

Installation

npm install @nexera/management

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

Quick Start

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

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.

// 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:

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:

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

Content Models

// 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:

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

// 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).

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.

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.

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

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

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

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

License

MIT