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

struma

v1.0.0

Published

A schema-driven JSON Database with immutable snapshots capabilities

Downloads

8

Readme

Struma

npm package version number Release & Publish License

A schema-driven JSON Database with immutable snapshots capabilities. Built on top of Immutable, Superstruct and lowdb.

Features

  • Schema Validation: Ensure data integrity with Superstruct schemas
  • Immutable State: Use Immutable to manage state in a predictable way.
  • Flexible Adapter: Compatible with lowdb adapters (filesystem, localStorage, memory, etc), or extend functionality with custom adapters for advanced use cases.
  • Sync/Async Supports: Supports seamlessly both synchronous and asynchronous adapters.
  • Cross-Platform: Works in both Node.js and Browser environments.
  • Snapshot History: Automatically takes snapshots of the state, providing historical views of your data.
  • Explicit Writes: Mutate state without immediate persistence, and write changes explicitly when needed.

Installation

Install the library using npm:

npm install immutable superstruct struma --save

Or with yarn:

yarn add immutable superstruct struma

Usage

1. Define a Schema

Use superstruct to define a schema for your data:

import { number, object, string } from 'superstruct';

const UserSchema = object({
  name: string(),
  age: number(),
  preferences: object({
    theme: string(),
  }),
});

2. Initialize Struma

import { Struma } from 'struma';
import { JSONFile } from 'struma/adapters/node';

const adapter = new JSONFile('db.json');
const db = new Struma(UserSchema, adapter);

3. Update and Save State

import { Map } from 'immutable';

// Update state
const newState = Map({
  name: 'Alice',
  age: 30,
  preferences: Map({
    theme: 'dark',
  }),
});
// Either you can use plain js object too, it will
// auto resolves using `fromJS` method from `immutable`
db.state = newState;

// Save state to write into db.json
await db.write();
// db.json
{
  "name": "Alice",
  "age": 30,
  "preferences": {
    "theme": "dark"
  }
}

4. Read State

console.log((await db.state).toJS()); // { name: 'Alice', age: 30, preferences: { theme: 'dark'} }

5. Access Snapshot History

console.log((await db.snapshots).toJS()); // Array of historical states

API

new Struma(schema, adapter)

Creates a new Struma instance.

  • schema: A superstruct schema for data validation.
  • adapter: An adapter that conforms to the Adapter interface.

db.state

  • Getter: Returns the current state as an immutable object.
  • Setter: Updates the state. Throws an error if the data is invalid.

db.write()

Write the current state to the adapter. Returns a promise that resolves when the write operation is complete.

db.snapshots

Returns a Promise that resolves a list of historical states (snapshots) as an immutable List. Each snapshot is an immutable representation of the state at a specific point in time.

Custom Adapters

You can create your own adapter as long as it conforms to the Adapter interface

import type { Adapter as AsyncAdapter, SyncAdapter } from 'lowdb';

export interface Adapter<T> {
  read: () => ReturnType<AsyncAdapter<T>['read'] | SyncAdapter<T>['read']>;
  write: (data: T) => ReturnType<AsyncAdapter<T>['write'] | SyncAdapter<T>['write']>;
}

[!TIP] For common case, you can go to lowdb Documentation

Examples

Node.js / ES Modules

import { Struma } from 'struma';
import { JSONFile } from 'struma/adapters/node';
import { number, object, string } from 'superstruct';

const UserSchema = object({
  name: string(),
  age: number(),
});

const adapter = new JSONFile<Infer<typeof UserSchema>>('db.json');
const db = new Struma(UserSchema, adapter);

(async () => {
  // Update state
  db.state = { name: 'Alice', age: 25 };

  // Save state
  await db.write();

  // Read state
  console.log((await db.state).toJS()); // { name: 'Alice', age: 25 }

  // Access snapshot history
  console.log((await db.snapshots).toJS()); // [null, { name: 'Alice', age: 25 }]
})();

UMD

As for UMD build, it will exposes Struma class, and Struma.adapters compatible adapters for browser as global.

<script src="https://unpkg.com/immutable"></script>
<script src="https://unpkg.com/superstruct"></script>
<script src="https://unpkg.com/struma"></script>
<script>
  // Define a schema
  const UserSchema = Superstruct.object({
    name: Superstruct.string(),
    age: Superstruct.string(),
  });

  const adapter = new Struma.adapters.LocalStorage('db');
  const db = new Struma(UserSchema, adapter);

  (async () => {
    // Update state
    const newState = { name: 'John', age: '30' };
    db.state = newState;

    // Save state to write into LocalStorage
    await db.write();

    // Read state
    const state = await db.state;
    console.log('Current State:', state.toJS()); // { name: 'John', age: '30' }

    // Access snapshot history
    const snapshots = await db.snapshots;
    console.log('Snapshot History:', snapshots.toJS()); // [null, { name: 'John', age: '30' }]
  })();
</script>

Support

For feedbacks or issues, check out the Issues.