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

pocket-cms

v1.0.14

Published

A pocket sized CMS as an express middleware

Downloads

19

Readme

Pocket CMS

A pocket sized CMS written for Node and Express.

Designed as a non-intrusive middleware. Pocket offers :

  • Automatic API generation
  • Schema validation (pocket schema)
  • User and session management
  • Admin panel
  • Multi-db support (Currently Mongo and Nedb)
  • File uploads
  • Server stats

Features planned:

  • Logs
  • API Keys
  • Plugin support

Table of Contents generated with DocToc

Getting started

Firstly, install pocket-cms as a dependency of your project.

npm install --save pocket-cms

In your Node project, hook pocket to your express server :

var express = require("express");
var Pocket = require("pocket-cms");

var app = express();
var cms = new Pocket();

app.use(cms.middleware());

app.listen(3000, () => { console.log('Server running'); })

Done ! A pocket cms is now running in your server.

Configuration

Pocket takes an optional configuration object during construction.

e.g

new Pocket({
    datastore: {
        adapter: 'mongo',
        options: {
            dbName: 'pocket_dev',
            url: 'localhost:27017'
        }
    }
})

The following options are available:

| Key | Description | Type | Default value | | ------------- | ------------- | ------------- | ------------- | | session | Authentication configuration ||| | session.secret | JWT secret | String | random | | session.expiresIn | Session expiry time in seconds | Number | 60 days | | datastore | Database configuration ||| | datastore.adapter | Available options : mongo, disk | String | disk | | datastore.options | Datastore specific options | Object | | | filestore | File upload configuration ||| | filestore.adapter | Available options: disk | String | disk | | filestore.options | Filestore specific options | Object | |

Datastores

Currently the following stores are available :

Mongo

The mongodb adapter requires the following options :

| Key | Description | Type | | ------------- | ------------- | ------------- | | dbName | Name of the mongo database | String | | url | Database url (e.g user:password@localhost:27017) | String |

Disk

The disk adapter supports the following options :

| Key | Description | Type | Defaults | | ------------- | ------------- | ------------- | ------------- | | dataFolder | Folder in which the data will be stored | String | ${POCKET_HOME}/${ENV}_db |

Filestores

Currently Pocket only supports files saved on disk. S3 support is on the roadmap

Disk

| Key | Description | Type | Defaults | | ------------- | ------------- | ------------- | ------------- | | uploadFolder | Folder in which the files will be stored | String | ${POCKET_HOME}/${ENV}_db/uploads |

Using the CMS

Resources

Pocket uses the generic term Resource to define a data type within the CMS. Each resource has :

  • A schema
    • Enables validation of posted data
    • Allows the admin panel to generate a form to edit the records
  • An automatically generated rest endpoint

Resources are created using the following CMS api :

let cms = new Pocket();

cms.resource('cars', schema);

Resources are retrieved using the following CMS api :

const cars = cms.resource('cars');

await cars.find({});

Methods

Creating a record

await resource.create(payload, opts = {}) will create a record matching the payload parameter. Options :

  • skipValidation allows the record to be created without being validated against its schema. Use with care
  • userId will set the _createdBy property of a record
Updating a record

await resource.mergeOne(id, payload, opts = {}) will update the record specified by id by overriding the properties set in payload. Options :

  • skipValidation allows the record to be created without being validated against its schema. Use with care
Updating multiple records

await resource.update(query, operations, options = {}) will update records specified by query with the operations formatted in a mongo like syntax. Options :

  • multi will enable the update to run on multiple records. Defaults to true.
Reading a single record

await resource.get(id) will return the record specified by id

Reading multiple records

await resource.find(query = {}, opts = {}) will return records that match the query argument. Options :

  • pageSize and page will allow to retrieve paginated records
Removing a record

await resource.removeOne(id) will delete the record specified by id

Removing multiple records

await resource.remove(query, opts = {}) will remove all elements that match the query argument. Options :

  • multi will allow multiple records to be removed if set to true. Otherwise only one of them will be deleted
Attaching a file to a record

await resource.attach(recordId, fileName, file) will save the file specified by the file argument in the file store, add add it to the record's _attachments list. file can either be a String pointing to the file on disk or a Stream

Deleting an attachment

await resource.deleteAttachment(recordId, attachmentId) will delete the file from the file store and remove the attachment from its record

Reading an attachment

await resource.readAttachment(attachmentId) will return a node stream of the file

Schema

Pocket exposes a Schema class which can be used to create a resource's schema. More details can be found on the Pocket Schema repo.

e.g

const Pocket = require('pocket-cms');
const { Schema } = Pocket;

const carSchema = new Schema({
    additionalProperties: false,
    fields: {
        name: {
	    type: 'string',
	    index: {
		unique: true
	    }
	}
	brand: {
	    type: 'text',
	    maxLength: 64
	},
	noOfWheels: {
	    type: 'number',
	    required: true,
	},
	color: {
	    type: 'select',
	    options: ['red', 'yellow', 'magenta']
	},
	tags: {
	    type: 'array',
	    items: { type: 'string' }
	}
    }
});

The following types are available :

  • any

  • array|list - options:

    • items? A field definition of the expected array items
  • checkbox|boolean

  • date - options:

    • format? The expected date format (defaults to YYYY-MM-DD)
  • datetime

  • email - options:

    • match? A regular expression to match the email against
  • map - options:

    • items? A field definition of the expected map items
  • multiselect - options:

    • options List or options to select from. An async function can also be passed
  • number - options:

    • min? Minimum allowed value
    • max? Maximum allowed value
  • object|json - options:

    • schema? Schema used to validate the object against
  • password - options:

    • minLength? The minimum length of the password
  • select|enum - options:

    • options List or options to select from. An async function can also be passed
  • text|string - options:

    • minLength? The minimum length of the string
    • maxLength? The maximum length of the string
    • match? A regular expression to match the string against
  • time

  • timestamp

CMS properties

When records are created/updated the CMS automatically adds and keeps track of a number or private properties which cannot be updated manually. All those private properties start by underscore _.

Currently those are:

  • _id
  • _createdAt
  • _updatedAt
  • _createdBy
  • _attachments the list of attachments

Indexes

To mark a field as a database index, its schema field supports the index parameter. Which can either be :

  • A true|false value
  • An object with the following properties :
    • unique true|false

Example :

const Pocket = require('pocket-cms');
const { Schema } = Pocket;

const person = new Schema({
    fields: {
        name: {
            type: 'string',
	    index: {
	        unique: true
	}
    }
});

Hooks

Pre and Post hooks can be added to a schema which allow adding extra functionality and ACL to the CMS.

Available api :

  • schema.before(action, method)
  • schema.after(action, method)

Available methods

  • create
  • remove
  • update
  • save
  • validate
  • read

Example usage

const Pocket = require('pocket-cms');
const { Schema } = Pocket;

const postSchema = new Schema({
    fields: {
        message: {
	    type: 'string',
	}
    }
})
.before('save', async ({ record }, ctx) => {
    const { user } = ctx;

    if (await userCheck(user, record) === false) {
        throw 'User should not save this record';
    }
});

const cms = new Pocket();

pocket.resource('posts', postSchema);

Users

The Pocket CMS class exposes a user manager that can be used to create/remove and authenticate users.

e.g

const Pocket = require('pocket-cms');

const cms = new Pocket();

// Creating a user
await pocket.users.create('username', 'password', [ 'users' ]);

// Authenticating a user
const user = await pocket.users.auth('username', 'password');

// Extracting a user from the JWT auth token
const user = await pocket.users.fromJWT(token)

The underlying resource is named _users

Groups

By default the following groups are created :

  • admins
  • users

Groups can be added by using the underlying resource _groups

REST API

For each resource created, a generic rest api is automatically created for it.

Here's a rundown of the different endpoints

Authentication

  • POST /users/signup to create a user. The following JSON body is expected

    • username
    • password
    • groups (defaults to ['users'])
  • POST /users/login to log in a user.
    Important: This endpoint will return a Java Web Token, which should be included into following requests -> Authorization: Bearer <token>. The following JSON body is expected

    • username
    • password
  • POST /users/logout to logout out. NOTE: As authentication is done via JWT, this endpoint doesn't actually do anything. It exists as a placeholder for future additions (hooks/logs/etc)

  • GET /users/status to retrieve the user and status of an existing JWT Token

Resource management

  • GET /rest/{resource} lists records for the given resource. Available options :

    • pageSize - The number of records to return per page
    • page - The page to return
  • GET /rest/{resource}/{id} returns a single record specified by id

  • POST /rest/{resource} creates a record of the resource type

  • PUT /rest/{resource}/{id} updates the record specified by id of the resource type

  • DELETE /rest/{resource}/{id} deletes the record specified by id`

  • POST /rest/{resource}/{id}/attachments uploads a file and a attach it to the record specified by id

  • GET /rest/{resource}/{id}/attachments/{attachmentId} downloads the attachment of a record

  • DELETE /rest/{resource}/{id}/attachments/{attachmentId} deletes the attachment of a record

The resource key of the endpoints listed above can all be prefixed with a user id to filter on records createdBy that user.

e.g

GET /rest/users/:userId/{resource}/{id} will return only records created by the user specified by userId

ACL

There are multiple rules and ways to control the access of resources by users.

We either allow or deny actions on certain resources. The following actions exist:

  • read
  • create
  • update
  • remove
Admins

Users from the admins group are whitelisted and have permission to make any change to any resources.

Private CMS resources (prefixed with _) cannot be modified by any other group. Currently those are :

  • _users
  • _groups
Schema access configuration

A entire resource can be configured to only be accessible to a certain set of groups.

That is done on the schema level with the following 2 methods :

  • schema.allow(group, actions[])
  • deny(group, actions[])

Note: A wildcard * can be used as a group name to represent all of them

Example :

const Pocket = require('pocket-cms');
const { Schema } = Pocket;

const postSchema = new Schema({
    fields: {
        message: {
        type: 'string'
        }
    }
})
.allow('users', [ 'read' ])
.allow('moderators', [ 'read', 'create', 'update', 'delete' ])
Group access configuration

A group can be given access to a resource through its permissions field.

e.g


pocket.resource('_groups').create({
    name: 'moderators',
    permissions: {
        '*': ['read'],
        'posts': ['read', 'create', 'update', 'delete' ]
    }
});