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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@klaudhaus/superstate

v0.4.1

Published

Extensible state specification and management

Downloads

16

Readme

SuperState

Supercharging the state of model-driven development

About

Objective

The aim of SuperState is to build upon the basic concepts of a data model by providing further information about the types and fields in the model and a way of managing and processing that information in a running system. This promotes modelling business logic close to the type system rather than being scattered throughout application code, and facilitates generic implementations of user interface elements, integration services etc. The objective is to support and extend the TypeScript and GraphQL type systems, but the approach could also be applied to other languages.

Open Source License

SuperState is published under a permissive open source license (MIT) and may be embedded, extended or forked for any purpose. Community input is welcome but there are no implied warranties or service level agreements for things such as feature requests or issue resolution. If you are interested in using SuperState in mission critical environments, Klaudhaus offers support, training and development services, please get in touch at https://klaudhaus.com.

Why SuperState?

The SuperState project aims to formalise a set of reusable patterns for extending data type schemas with additional capabilities around things such as validation rules, presentation information, integration status and so on. Such concerns are recurrent across diverse information systems, and having a standard approach for encoding them close to the data model definition provides a number of benefits.

Firstly, the rules are more implementation-independent, decoupled from choices about specific application and distribution technologies (e.g. web vs native, React vs Vue, etc.) allowing easier reuse in different contexts.

Secondly, with agreement about generic standards, greater reusability can be built into things such as visual components and integration services such that they can auto-adapt across new systems and data types.

Thirdly, the knowledge that is embodied within such generically represented business rules can be validated, preserved and evolved to support the broader organisational mission over time. It becomes a quantifiable and accountable asset to the company, representing a growing and protected body of learning about the model and processes upon which business value is based.

Policy Modules

SuperState extends the standard type system by adding criteria defined in Policies. These define the content of typed Specifications and extended state Properties. This standardised pattern for state management supports pluggable implementations for functionality.

For an example of a policy module, see @klaudhaus/sup-validation. For a simple example of an application that uses the SuperState with this validation policy module, see @klaudhaus/superstate-sample.

Concepts

SuperState extends a standard type system in accordance with policies provided by pluggable modules, which cover the types of Specifications, the extended state's Properties and, potentially, the available processes (state transitions).

As a conceptual example, take a system which declares a basic Contact type with name, phone, email and age fields. On its own, the standard type system can manage the declaration of objects of this type, and check field access to make sure they are valid. SuperState might be set up with a policy that states "each field can have a label which is a string, and a validation rule that matches its datatype". There would be a SuperState Specification for the Contact type which would add the labels and validation rules to the individual fields, and a Properties definition describing the related runtime state of any individual field, such as whether it is valid and an error message if it is not. The module that provides the validation-related policy elements can also provide validation processes that can be triggered for any field in the model - because they all conform to the same Specifications and have common Properties. By extending this pattern across all data types we end up with a well-structured definition of the fundamentals of an information system.

Types

SuperState builds on the well-established principles of a type system. The following examples will use these TypeScript types:

type Contact = {
	name: string
	age: number
	member: boolean
	address: Address
	phone: string
	email: string
}

type Address = {
	street: string
	suburb: string
	state: AuState
	postcode: string
}

export enum AuState { NSW, SA, QLD, VIC, WA, NT, ACT, TAS }

SuperState refers to the data members of types as "fields", so Contact has an age field, for example, as well as an address field of type Address.

Policies

A Policy defines the additional information that can be added to the data model. It would normally be made up of modular components such as Validation policy and Presentation policy. Due to the lack of higher-kinded types in TypeScript, these are not declared as separate policy types, but each declare their own properties within a standard namespace called Policy, with interfaces Specification and Properties. The Policy namespace is defined in such a way that these properties may be generic in the type of any individual field and/or in type of the parent object in which a field exists. In this way, it's possible to have something like, say, a validation function and have field-level type checking when that policy setting is applied in a specification.

Specification Policy

The specification policy defines the additional information that can be added to the data model. The SuperState package includes some default policy examples such as Validation, which defines a structure for specifying data validation constraints, and Presentation, which includes basics such as field labels. The PresentationPolicy looks like this:

export type PresentationPolicy = {
  label: string
  inputType?: "text" | "email"
}

Policies can be generically typed so that the extra information is assured to match the type of its associated field. For example the ValidationPolicy defines a validator property to be a function that validates the field's data type.

export type ValidationPolicy<T> = {
  validator?: Validator<T>
}

A system can define it's own policies, and can combine them to make an overall policy such as the following:

export type SystemPolicy<T> = PresentationPolicy & ValidationPolicy<T>

Specifications

Specifications are the definition of what the policy settings are for individual fields within the data model. A general specification type is defined from the system policy as follows:

export type SystemSpec<T> = FieldSpec<SystemPolicy<T>, T>

Using this type, specifications can be defined for the system in question.

And the following

A TypeSpec can be defined which encapsulates validation information as follows:

const contactSpec = TypeSpec<Contact> {
  name: {
    label: "Name",
    inputType
  }
}

State

The runtime structure of a SuperState of Contact with the Policy settings described above can be obtained by passing an instance of Contact along with its TypeSpec:

import { superstate } from "superstate"

const contact = {
  name: "Tim",
  phone: "",
  email: "",
  age: 10
}
const contactState = superstate(contactSpec, contact)

contact.name // [object]
contact.name.value // "Tim" - each field's superstate has a value
contact.name.valid // true - 
contact.name.errorMessage

Validation Policy

Validators and Constraints

The included ValidationPolicy provides a way of specifying rules about what values a field can have. These rules are provided in the form of a Validator<V> where V is the type of data to be validated. These are often created using the Constraint pattern - a Constraint<C, V> is a function that takes a configuration of type C and returns a validator for type V. So, for example, to validate teh minimum length of strings, use minLength which is of type Constraint<number, string> - it is configured with a number (the minimum length to check for) and is applied to values of type string.

Systems can provide their own Constraints to define new kinds of validation rule.

Where a validation applies to multiple