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

@nan0web/co

v2.0.0

Published

Communication starts here with a simple Message.

Readme

@nan0web/co

Communication starts here with a simple Message.

Description

The @nan0web/co package provides a minimal yet powerful foundation for message‑based communication systems and contact handling.

Core classes:

  • Message — a base class for representing generic messages with timestamps.
  • Chat — represents chat messages and chains.
  • Contact — parses and represents contact information with specific URI schemes.
  • Language — handles localisation data including name, icon, code and locale.
  • I18nMessage — extends Message with translation support.
  • InputMessage / OutputMessage — UI‑oriented message adapters.
  • App — minimal event‑driven application core.

Use @nan0web/ui-cli for CLI‑specific commands (e.g. parsing process.argv to Messages).

These classes are perfect for building parsers, communication protocols, message validation layers, and contact or language data management.

Installation

How to install with npm?

npm install @nan0web/co

How to install with pnpm?

pnpm add @nan0web/co

How to install with yarn?

yarn add @nan0web/co

Usage

Basic Message

Messages contain body and time when they were created.

How to create a Message instance from string?

import { Message } from '@nan0web/co'
const msg = Message.from("Hello world")
console.info(String(msg)) // 2023-04-01T10:00:00 Hello world

Messages can be restored from old timestamp.

How to create a Message instance from object?

import { Message } from '@nan0web/co'
const msg = Message.from({ body: "Hello 2000", time: new Date("2000-01-01") })
console.info(String(msg)) // 2000-01-01T00:00:00.000Z Hello 2000

Chat Messages

Chat creates a message chain with authors.

How to create a message chain with authors in a chat?

const alice = Contact.from("[email protected]")
const bob = Contact.from("+1234567890")
const chat = new Chat({
	author: alice,
	body: "Hi Bob!",
	next: new Chat({
		author: bob,
		body: "Hello Alice!",
	}),
})
console.info(String(chat))
// 2025-11-12T11:02:37.033Z mailto:[email protected]
// Hi Bob!
// ---
// 2025-11-12T11:02:37.033Z tel:+1234567890
// Hello Alice!

Contact Handling

Contact handles different URIs and string inputs properly.

How to create contact with different URIs and string inputs properly?

// Create direct instances
const email = new Contact({ type: Contact.EMAIL, value: "[email protected]" })
const phone = Contact.from("+123456") // Auto-detected as telephone
const address = Contact.parse("123 Main St")  // Auto-detected as address
// Parse types
console.info(email.toString()) // "mailto:[email protected]"
console.info(phone.toString()) // "tel:+123456"
console.info(address.toString()) // "address:123 Main St"
// Auto-detect from strings
const website = Contact.parse("https://example.com") // Auto-detected as URL
console.info(website) // "https://example.com"

Language Handling

Language handles ISO codes and string conversion.

How to create a Language instance?

const lang = new Language({
	name: "English",
	icon: "🇬🇧",
	code: "en",
	locale: "en-US",
})
console.info(String(lang)) // ← English 🇬🇧

InputMessage & OutputMessage usage

How to use InputMessage and OutputMessage?

import { InputMessage, OutputMessage } from "@nan0web/co"
const inMsg = new InputMessage({ value: "user input", options: ["yes", "no"] })
const outMsg = new OutputMessage({ content: ["Result:", "Success"], type: OutputMessage.TYPES.SUCCESS })
console.info(inMsg.toString()) // ← TIMESTAMP user input
console.info(outMsg.content) // ← ["Result:", "Success"]

App core example

How to use the App core class?

import { App } from "@nan0web/co"
const app = new App()
const im = new app.InputMessage({ value: "ping" })
const gen = app.run(im)
const { value, done } = await gen.next()
const { done: done2 } = await gen.next()
console.info(value) // ← OutputMessage { body: ["Run"], ... }
console.info(done) // ← false
console.info(done2) // ← true

Message body parsing with static meta configuration

The Message.parseBody method can transform raw input objects into a well‑defined body using a static schema. Below is a concise example that mirrors the test suite’s ParseBody definition.

The test ensures the parsing behaves exactly as described.

How to parse a message body using Message.parseBody()?

import { Message } from "@nan0web/co"
const Body = {
	// Show help flag (alias: h)
	help: { alias: "h", defaultValue: false },
	// Output format (alias: fmt)
	format: { alias: "fmt", defaultValue: "txt", options: ["txt", "md", "html"] },
	// Verbose flag (no alias)
	verbose: { defaultValue: false }
}
const raw = { h: true, fmt: "md", verbose: 1 }
const parsed = Message.parseBody(raw, Body)
console.info(parsed)
// { help: true, format: "md", verbose: true }

Message validation schema

Message now supports a static Body schema that can describe:

  • Aliases – alternative short keys.
  • Default values – applied when a field is missing.
  • Required flags – enforce presence.
  • Pattern matching – regular‑expression validation.
  • Enumerated options – restrict values to a set.
  • Custom validation functions – arbitrary checks returning true or an error string.

Validation is performed by msg.validate() returning a Map<string, string> of errors, while msg.getErrors() provides the legacy Record<string, string[]> format.

This enables powerful, declarative validation directly on message instances and increasing quality of IDE autocomplete feature.

How to validate a message using a custom schema?

class MyBody {
	/** @type {string} */
	name
	static name = {
		alias: "n",
		required: true,
		pattern: /^[a-z]+$/
	}
	/** @type {string} */
	title
	static title = {
		pattern: /^.{3,}$/,
		defaultValue: ""
	}
	/** @type {string} */
	mode
	static mode = {
		options: ["auto", "manual"],
		defaultValue: "auto"
	}
	/** @type {string} */
	custom
	static custom = {
		validate: v => v.length > 5 ? true : "Too short"
	}
	constructor(input = {}) {
		const {
			name,
			title = MyBody.title.defaultValue,
			mode = MyBody.mode.defaultValue,
			custom,
		} = Message.parseBody(input, MyBody)
		this.name = String(name)
		this.title = String(title)
		this.mode = String(mode)
		this.custom = String(custom)
	}
}
class MyMessage extends Message {
	static Body = MyBody
	/** @type {MyBody} */
	body
	constructor(input = {}) {
		super(input)
		this.body = new MyBody(input.body ?? {})
	}
}
const msg = new MyMessage({
	body: { name: "JohnDoe", title: "Hello", custom: "abc" }
})
// setting the incorrect enumeration value
msg.body.mode = "invalid"
const errors = msg.validate()
console.info(errors)
// Map (3) {
//   'custom' => 'Too short',
//   'mode' => 'Enumeration must have one value',
//   'name' => 'Does not match pattern /^[a-z]+$/',
// }

API

Message

  • Properties

    • body – the actual content of the message.
    • time – timestamp of creation.
  • Methods

    • toObject() – returns { body, time }.
    • toString() – formats timestamp and body as a string.
    • static from(input) – instantiates from string or object.
    • validate() – checks body against a static Body schema, returns Map<string, string>.
    • getErrors() – legacy error map, returns Record<string, string[]>.

Chat

Extends Message.

  • Properties

    • author – the contact object representing the message sender.
    • next – the next chat message in the chain (nullable).
  • Methods

    • get size – returns the chain length.
    • get recent – returns the last chat message.
    • toString() – formats the entire chat chain.
    • static from(input) – builds a chat chain from array‑like input.

Contact

  • Static URI prefixes

    • Contact.ADDRESS"address:"
    • Contact.EMAIL"mailto:"
    • Contact.TELEPHONE"tel:"
    • Contact.URL"//"
    • Social links: FACEBOOK, INSTAGRAM, LINKEDIN, SIGNAL, SKYPE, TELEGRAM, VIBER, WHATSAPP, X
  • Methods

    • toString() – converts to a URI string.
    • static parse(string) – detects a URI scheme or uses heuristics to deduce the type.
    • static from(input) – returns a Contact instance if one already exists or creates a new one.

Language

  • Properties

    • name – language name in its native form.
    • icon – flag emoji.
    • code – ISO 639‑1 language code.
    • locale – specific locale identifier.
  • Methods

    • toString() – combines name and icon.
    • static from(input) – creates or returns a Language instance.

All exported classes should pass basic test to ensure API examples work

Playground

How to run playground script?

# Clone the repository and run the CLI playground
git clone https://github.com/nan0web/co.git
cd co
npm install
npm run play

Contributing

How to contribute? - check here

License

How to license? - ISC LICENSE file.