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

ayisha-client

v0.5.2

Published

Official JavaScript client for the Ayisha CMS API

Readme

ayisha-client

Official JavaScript client for the Ayisha CMS REST API.

Works in Node.js 18+ and modern browsers (native fetch).

Install

Published on npm: ayisha-client

npm install ayisha-client

Alternatives:

yarn add ayisha-client
pnpm add ayisha-client

Quick start

import { AyishaClient, createMediaField, SCHEMA_ATTRIBUTE_TYPES } from 'ayisha-client';

const ayisha = new AyishaClient({
  baseUrl: 'https://your-cms.example.com',
});
// In browsers, login() persists the JWT to localStorage and restores it on reload.

// 1. Login (required for writes and schema admin)
await ayisha.login('username', 'password');

// 2. List public schema names
const schemaNames = await ayisha.getSchemas();
// [{ name: "product" }, { name: "event" }]

// 3. Read content by schema + name (GET /cms/product/tshirt)
const tshirt = await ayisha.getContent('product', 'tshirt');

// 4. List all products
const { contents } = await ayisha.getContents('product', { page: 1, limit: 20 });

// 5. Create content
await ayisha.createContent('product', {
  name: 'tshirt',
  active: true,
});

// All supported schema attribute types
console.log(SCHEMA_ATTRIBUTE_TYPES.map((t) => t.type));

API naming

The SDK uses a consistent get / create / update / delete pattern:

| Resource | List | Single | Create | Update | Delete | | --- | --- | --- | --- | --- | --- | | Content | getContents(schema, params?) | getContent(schema, nameOrId) | createContent | updateContent | deleteContent | | Schema | getSchemas() / getSchemasAdmin() | getSchema(id) | createSchema | updateSchema | deleteSchema | | User | getUsers(params?) | — | createUser | updateUser | deleteUser |

Pass a schema name (e.g. 'product') for /cms/{schema} routes, or a schema ObjectId for /cms/objects routes — same methods, automatic routing.

Migration from 0.3.x

| Deprecated | Use instead | | --- | --- | | listSchemas() | getSchemas() | | listSchemasAdmin() | getSchemasAdmin() | | listContents(schema, params?) | getContents(schema, params?) | | getContentByName(schema, name) | getContent(schema, name) | | getContentById(schema, id) | getContent(schema, id) | | listContentsByAuthor(...) | getContentsByAuthor(...) | | listObjects(schemaId, params?) | getContents(schemaId, params?) | | getObject(schemaId, id) | getContent(schemaId, id) | | createObject / updateObject / deleteObject | createContent / updateContent / deleteContent | | listUsers() | getUsers() | | listCmsUsers() | getCmsUsers() |

Deprecated aliases remain available and delegate to the new methods.

API routes overview

| Area | Base path | Use case | | --- | --- | --- | | CMS API | /cms/* | All API operations (content, auth, schemas, users, backup, analytics) | | Media files | /api/media/:id | Proxy URLs embedded in JSON responses | | Settings | /cms/settings | Locale and theme |

Auth

| Method | Route | Auth | Description | | --- | --- | --- | --- | | login(username, password) | POST /cms/auth | — | JWT (30d), stored on client and persisted in the browser (localStorage by default). Fails with 403 / AUTH_ACCOUNT_PENDING if the account is inactive. | | loginAdmin(username, password) | POST /cms/auth | — | Same as login() (alias). | | register({ username, password }) | POST /cms/register | — | Creates an inactive user account. No JWT; an administrator must set isActive: true before sign-in. | | registerAdmin({ username, password }) | POST /cms/register | — | First call creates superAdmin (active). Later calls create inactive user accounts (same activation flow as register). | | setToken(token) | — | — | Set or restore JWT (also persists when storage is enabled) | | getToken() | — | — | Current JWT | | logout() | — | — | Clears JWT from memory and storage | | getStore(key) | — | — | Read a persisted app value (browser storage by default) | | setStore(key, value) | — | — | Save a persisted app value (null removes it) | | removeStore(key) | — | — | Remove a persisted app value |

Token persistence (browser)

By default (storage: 'auto'), the client saves the JWT to localStorage after login() and restores it on the next page load:

const ayisha = new AyishaClient({ baseUrl: window.location.origin });
// token restored automatically if the user logged in before

await ayisha.login('username', 'password'); // saved to localStorage

ayisha.logout(); // clears memory + localStorage

Options:

| storage | Behavior | | --- | --- | | 'auto' (default) | localStorage in browsers, disabled in Node.js | | 'local' | Always use localStorage | | 'session' | Use sessionStorage (cleared when the tab closes) | | 'none' | Memory only (previous behavior) | | Custom adapter | { getToken, setToken, removeToken, getStore, setStore, removeStore } |

new AyishaClient({
  baseUrl: 'https://your-cms.example.com',
  storageKey: 'my-app-ayisha-token',
  storePrefix: 'my-app-store:',
});

App store (browser)

Persist your own app data with the same storage backend as the JWT:

ayisha.setStore('cart', [{ id: 'tshirt', qty: 2 }]);
const cart = ayisha.getStore('cart');

ayisha.setStore('theme', 'dark');
ayisha.removeStore('theme');

Values are JSON-serialized. Keys are stored under the prefix ayisha-store: in localStorage by default.

Account activation

Self-registration (register / registerAdmin after bootstrap) returns { pendingActivation: true, code: 'AUTH_REGISTRATION_PENDING' } and does not issue a JWT.

An administrator activates the account with:

await ayisha.loginAdmin('admin', 'password');
await ayisha.updateCmsUser(userId, { isActive: true });
// or updateUser(userId, { isActive: true }) on /cms/users

User records expose isActive (false until activated).

Content

Read

| Method | Route | Returns | | --- | --- | --- | | getContents(schema, params?) | GET /cms/{schema} or GET /cms/objects/{schemaId} | Paginated { contents, totalItems, pageItems, totalPages, currentPage, limit } | | getContent(schema, nameOrId) | GET /cms/{schema}/{segment} or GET /cms/objects/{schemaId}/{id} | Single item (contents[0] on CMS) or null | | getContentsByAuthor(authorId, schema, params?) | GET /cms/{authorId}/{schema} | Paginated wrapper | | iterateContents(schema, params?) | paginated helper | Yields each item |

// List
await ayisha.getContents('product', { page: 1, limit: 20, q: 'cotone' });

// Single by name or ObjectId
const tshirt = await ayisha.getContent('product', 'tshirt');
const byId = await ayisha.getContent('product', '66d4296014cb559e8ba2ce86');

// Admin: same methods with schema ObjectId from getSchemasAdmin()
const { schemas } = await ayisha.getSchemasAdmin();
await ayisha.getContents(schemas[0]._id, { page: 1 });
const obj = await ayisha.getContent(schemas[0]._id, 'OBJECT_ID');

Note: CMS path lookups return the paginated wrapper over HTTP. The SDK unwraps contents[0] for getContent when using schema names.

Write

| Method | Route | Description | | --- | --- | --- | | createContent(schema, data) | POST /cms/{schema} or POST /cms/objects | data.name required | | updateContent(schema, id, data) | PUT /cms/{schema}/{id} or PUT /cms/objects/{schemaId}/{id} | Update by ObjectId | | deleteContent(schema, id) | DELETE /cms/{schema}/{id} or DELETE /cms/objects/{schemaId}/{id} | Delete by ObjectId |

Schema admin

Requires JWT with createSchema, updateSchema, deleteSchema capabilities.

| Method | Route | Description | | --- | --- | --- | | getSchemas() | GET /cms/schemas | Public — [{ name }] only | | getSchemasAdmin(params?) | GET /cms/schemas | Full schemas with attributes | | getSchema(schemaId) | GET /cms/schemas/:id | Single schema | | createSchema({ name, attributes }) | POST /cms/schemas | Create schema | | updateSchema(id, { name, attributes }) | PUT /cms/schemas/:id | Update schema | | deleteSchema(id) | DELETE /cms/schemas/:id | Delete schema and all content |

Schema attribute types

Import SCHEMA_ATTRIBUTE_TYPES and SCHEMA_ATTRIBUTE_EXAMPLE from the package.

| Type | Value in data | Notes | | --- | --- | --- | | text | "hello" | Short string | | longtext | "paragraph..." | Multi-line text | | richtext | "<p>HTML</p>" | HTML | | number | 42 | Number | | boolean, checkbox | true | Filter with ?field=true | | select | "option-a" | Requires options[] on attribute | | multiselect | ["a","b"] | Filter with comma-separated values | | date | "2026-08-07" | ISO date | | datetime-local | "2026-08-07T12:00" | ISO datetime | | time | "12:30" | HH:mm | | email, url, telephone | string | Validated in UI | | password | string | Masked in UI | | color | "#ff0000" | Hex | | currency | "EUR" | ISO 4217 — use options | | rating | 5 | Numeric | | geolocation | "41.90,12.49" | Coordinates | | json | { key: "value" } | JSON object | | array | ["word1","word2"] | Word array | | image, file | { name, media } | Base64 data URL on write | | images, files | [{ name, media }] | Multiple media | | relation | "OBJECT_ID" | relatedCollection = target schema name | | multirelation | ["ID1","ID2"] | Array of ObjectIds | | id | string | Custom id field |

Attribute definition shape:

{
  id: 'uuid',
  type: 'select',
  label: 'category',       // becomes data key and query param
  required: true,
  immutable: false,
  options: ['a', 'b'],     // select, multiselect, currency
  relatedCollection: 'brand', // relation, multirelation
}

Every schema must include a name field (type: 'text', label: 'name', required: true). Ayisha adds it automatically if missing.

import { SCHEMA_ATTRIBUTE_EXAMPLE } from 'ayisha-client';

await ayisha.createSchema(SCHEMA_ATTRIBUTE_EXAMPLE);

Users admin

Requires JWT with user capabilities.

| Method | Route | Capability | | --- | --- | --- | | getUsers(params?) | GET /cms/users | readUser | | createUser(payload) | POST /cms/users | createUser | | updateUser(id, payload) | PUT /cms/users/:id | updateUser | | deleteUser(id) | DELETE /cms/users/:id | deleteUser | | getCmsUsers() | GET /cms/users | JWT | | getCmsUser(id) | GET /cms/users/:id | JWT | | updateCmsUser(id, payload) | PUT /cms/users/:id | JWT |

Profile fields (all optional on create/update): name, surname, email, phone, gender, birthdate, bio, picture (media object).

On create, only username and password are required. Use isActive: false to create a pending account, or activate later with { isActive: true }.

Backup

Server-side async jobs avoid timeouts on large databases. Authenticate first (POST /cms/auth), then use the job endpoints below. See backend/README.md for environment variables and wipe behaviour.

| Method | Route | Description | | --- | --- | --- | | exportBackup({ onProgress }) | POST /cms/backup/export/jobs (+ poll + download) | Server-side async export job | | restoreBackup({ backup }, { onProgress }) | POST /cms/backup/restore/jobs (+ chunks + finalize) | Server-side async restore job | | deleteAllData() | DELETE /cms/backup | Wipe CMS data except current user (schemas, objects, media including GridFS, settings, analytics; cancels backup jobs) |

Media

Media is saved inside content data as { name, media } (base64 data URL). Served at GET /api/media/:id.

| Method | Description | | --- | --- | | createMediaField(file) | Browser File → media object | | fileToDataUrl(file) | Raw data URL | | buildMediaUrl(mediaId) | Public URL | | resolveMediaUrl(mediaField) | From API response field | | getMedia(mediaId) | Download binary (ArrayBuffer) |

Gallery

List all images stored in the CMS (proxy URLs, parent content or user, orphan flag) at GET /cms/gallery.

| Method | Route | Auth | | --- | --- | --- | | getGallery(params?) | GET /cms/gallery | Optional JWT | | iterateGallery(params?) | Async generator over getGallery pages | Optional JWT | | deleteGalleryImage(mediaId) | DELETE /cms/gallery/:mediaId | deleteObject |

User profile pictures appear in the list but cannot be deleted from the gallery endpoint (update the user instead). Deleting a linked CMS image removes the parent content and all its media.

const { images, totalPages } = await ayisha.getGallery({ page: 1, limit: 24, q: 'cover' });

for await (const image of ayisha.iterateGallery({ limit: 50 })) {
  console.log(image.url, image.orphan, image.content?.name);
}

await ayisha.deleteGalleryImage(images[0].id);

Filters and search

await ayisha.getContents('product', {
  name: 'tshirt',
  category: 'abbigliamento',
  active: 'true',
  tags: 'new,sale',       // multiselect
  q: 'cotone',
  page: 1,
  limit: 20,
});

Capabilities

Backoffice users need capabilities on their account:

  • Users: readUser, createUser, updateUser, deleteUser
  • Schemas: readSchema, createSchema, updateSchema, deleteSchema
  • Content: readContent, createContent, updateContent, deleteContent
  • Objects: readObject, createObject, updateObject, deleteObject

Errors

import { AyishaApiError } from 'ayisha-client';

try {
  await ayisha.getContent('product', 'missing');
} catch (error) {
  if (error instanceof AyishaApiError) {
    console.error(error.status, error.message, error.body);
  }
}

Publish (maintainers)

cd packages/ayisha-client
npm run release

Bump "version" in package.json before each publish.

Author

devben — Benito Massidda

License

MIT