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

@empyria/common

v0.3.18

Published

Shared backend goodies for Empyria

Readme

@empyria/common

Shared backend services for higher-level components in Empyria, a nanoservice framework built primarily on Bun: environment variable schemas, error definitions, Codogram (SMS/TOTP-style challenge codes), and Ata (JSON schema building blocks and validation).

Requirements

  • Bun >=1.4.0 or Node.js >=26
  • Plain ESM, no build step, no TypeScript

Both requirements come from @empyria/classification, which this package depends on and which uses the native Temporal global for all date/time handling.

Install

bun add @empyria/common

Usage

import { createEnv, BaseErrors, generateCodogram, validate, string } from '@empyria/common'

const envSchema = createEnv({ API_KEY: string() })

throw new BaseErrors.EntityInvalid({ type: 'User', id: 42 })

const pin = generateCodogram('PIN')

Everything is re-exported from the package root via index.js. Individual modules under lib/ can also be imported directly if you only need one:

import { defineSchema } from '@empyria/common/lib/Ata.js'

Modules

| Module | Purpose | | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | index.js | Package entry point; re-exports every module below plus Moleculer meta helpers (moleculerMeta, moleculerEmpyriaMeta) and workflow ID helpers (workflowName, workflowId, identifyWorkflow). | | lib/Errors.js | EmpyriaError, the ErrorCreator factory, and BaseErrors — Empyria's catalog of pre-built, templated errors. | | lib/Env.js | createEnv — builds a service's environment-variable JSON schema from Empyria-wide defaults; pass { closed: true } to reject undeclared vars and bind { coerceTypes, removeAdditional } to the schema. | | lib/Ata.js | JSON schema building blocks (string, number, integer, bool, enumType, constant, nullable, array, discriminated, email, isoDateTime, ...) and validation — throwing (defineSchema, createValidator, validate), transform-intent aliases (parse, createParser), or non-throwing/structured (createChecker, checkSchema, now returning the parsed data) — built on ata-validator. See Schema builders and Validation options below. | | lib/Codogram.js | generateCodogram — one-time challenge codes (PIN, alphanumeric, alphabetic) for SMS/TOTP-style verification flows. | | lib/Defaulter.js | defaultsFromSchema — builds a fully-populated default object for a JSON schema. |

Every exported function is documented with JSDoc directly in its source file — hovering a function in VSCode or Zed shows its parameters and return type without any extra tooling, since both editors read JSDoc from plain .js files automatically.

Tests live under test/, one file per module, separate from the lib/ sources.

Validation options

createValidator / validate / parse / createChecker / checkSchema forward ata-validator's options to the underlying Validator. Options are resolved in three layers, last wins:

  1. library defaults — setAtaDefaults({ ... }), called once at startup for a deployment-wide policy; getAtaDefaults() reads it back, setAtaDefaults() clears it.
  2. schema-bound — defineSchema(map, { validation: { ... } }) stores options on a non-enumerable key, so a schema carries its own parsing policy (schemaOptions(schema) reads it). The schema still serialises and compares as plain JSON Schema.
  3. per-call — the options argument to any of the functions above.

formats is merged one level deep, with EMPYRIA_FORMATS always underneath.

| Option | What it does (Empyria relevance) | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | | coerceTypes | "4040" → 4040 before validation. The reason env.js files work — every process.env value is a string. | | useDefaults | Fill missing props from their schema default. On by default; every string()/number()/bool()/enumType() emits one. | | removeAdditional | Strip keys not covered by the schema. Only visible with additionalProperties: false (i.e. defineSchema({ strict: true })). | | assertFormat | Whether a format mismatch is a hard error. On by default. | | abortEarly | Stop at the first error, skip enrichment. For hot verdict-only paths (pair with createChecker, not the throwing path). | | richErrors | Keep ATA#### codes / doc URLs / hints that renderPretty & co. consume. On by default; leave it on. | | verbose | Add parentSchema to each error (ajv's verbose). | | formats | Custom format checkers. EMPYRIA_FORMATS (empyria-email, empyria-password, empyria-ipv4, empyria-ipv6) is folded in automatically. |

Return value / mutation. createValidator & validate return ata-validator's result.data — the same object as the input unless coerceTypes / removeAdditional / useDefaults applied. Those passes also mutate the input object in place, so hand them a copy when the caller must keep its input pristine (as the env.js files do with { ...process.env }). parse / createParser are behavioural aliases for call sites whose intent is to transform rather than merely assert. createChecker / checkSchema now also return data (the parsed value on success, undefined on failure).

Schema builders

Each returns a plain JSON Schema fragment; compose them in defineSchema(map, opts).

| Builder | Produces | | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | bool(default?) | { type: 'boolean' } | | string(default?, minLength \| { minLength, maxLength, pattern, format, description }) | { type: 'string', … } | | number(default?, { min, max, exclusiveMin, exclusiveMax, multipleOf, description }) | { type: 'number', … } | | integer(default?, …) | { type: 'integer', … } — use for ports/counts; rejects 3.5 | | enumType(list, default?, { type, description }) | { enum, type? } | | constant(value, { description }) | { const: value } | | nullable(schema) | type: [t, 'null'], or { anyOf: [schema, { type: 'null' }] } | | array(items?, { minItems, maxItems, uniqueItems, default, description }) | { type: 'array', … } | | email() / password() / ip4() / ip6() | { type: 'string', format: 'empyria-*' } (see EMPYRIA_FORMATS) | | isoDateTime() / isoDate() / isoTime() / duration() / uri() / uuid() | { type: 'string', format: … } (ata built-in formats) | | logLevel() / nodeEnv() / tmpFile() / logFile() | domain presets | | discriminated(prop, { value: schema, … }, { description }) | JSON Schema v1 propertyDependencies — an object whose shape depends on prop's value |

Dialect

defineSchema(map, { dialect: 'v1' \| '2020-12' \| 'draft-07' \| <uri> }) stamps $schema (ata-validator reads it to pick the dialect). setDefaultDialect('v1') / getDefaultDialect() set a process-wide default a per-call dialect overrides. v1 differs from 2020-12 only in $dynamicRef scoping and unlocks propertyDependencies; discriminated() works on any dialect (ata supports the keyword as an extension) but dialect: 'v1' makes it spec-legitimate.

defineSchema(map, { strict: 'unevaluated' }) sets unevaluatedProperties: false while leaving additionalProperties open — the composable form of strict, for schemas meant to be allOf-combined.

Scripts

bun run format       # check formatting (oxfmt)
bun run format:fix   # apply formatting
bun run lint         # lint (oxlint)
bun run lint:fix     # lint and fix
bun run test         # run tests with coverage

License

MIT © Imre Fazekas