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

@metreeca/blue

v0.9.1

Published

Declarative blueprints for model-driven linked data processing.

Readme

@metreeca/blue

npm

Declarative blueprints for model-driven linked data processing.

@metreeca/blue provides a shape-based schema framework for the linked data model defined by @metreeca/qest.

Shape-based schemas go beyond structural validation, capturing the complete semantics of a resource — structure, constraints, metadata, and relationships — enabling them to act as a single source of truth for automated validation, persistence, API publishing, UI generation, and more:

  • Define Once, Use Everywhere: a single schema drives all automated processes
  • Guaranteed Consistency: schema changes propagate to all dependent processes automatically
  • Less Code to Maintain: declarative definitions replace scattered imperative logic

@metreeca/blue is designed for a broad range of model-driven tasks and ships with a robust and ready-to-use validation engine:

  • No Type Duplication: types and validation rules derived from a single schema
  • One Schema, Every Mode: same schema validates state, updates, projections, and queries
  • Actionable Error Feedback: per-value, per-property traces surface precise violations
  • Custom When Needed: pluggable validators extend built-in constraints

[!NOTE]

@metreeca/blue is part of the @metreeca/qest integrated ecosystem for rapid development of linked data applications.

Installation

npm install @metreeca/blue

[!WARNING]

TypeScript consumers must use "moduleResolution": "nodenext"/"node16"/"bundler" in tsconfig.json. The legacy "node" resolver is not supported.

Usage

[!NOTE]

This section introduces essential concepts; for complete coverage, see the API reference:

| Module | Description | |----------------------------------------------------------------------------------|-------------------------------------------------------------------------| | @metreeca/blue | Linked data validation API | | @metreeca/blue/boolean | Boolean shape model and factories | | @metreeca/blue/number | Numeric shape model and factories | | @metreeca/blue/string | Textual shape model and factories | | @metreeca/blue/local | Language-tagged shape model and factories | | @metreeca/blue/resource | Resource shape model and factories |

Defining Schemas

Schemas describe the expected structure of a resource using shape factories:

import { boolean } from "@metreeca/blue/boolean";
import { local } from "@metreeca/blue/local";
import { number } from "@metreeca/blue/number";
import { id, multiple, optional, reference, required, resource, type, union } from "@metreeca/blue/resource";
import { string, url } from "@metreeca/blue/string";

function Thing() {
	return resource({
		id: id(),
		type: type()
	});
}

function Product() {
	return resource({ extends: Thing }, {
		name: required(local()),
		description: optional(local()),
		price: required(number({ minInclusive: 0 })),
		inStock: required(boolean()),
		tags: multiple(string()),
		rating: optional(Rating),
		vendor: required(reference(Vendor))
	});
}

function Rating() {
	return resource({
		average: required(number({ minInclusive: 0, maxInclusive: 5 })),
		reviews: required(number({ minInclusive: 1 }))
	});
}

function Vendor() {
	return resource({ extends: Thing }, {
		name: required(string()),
		website: required(url()),
		address: optional(union({
			text: string(),
			PostalAddress: reference(PostalAddress),
			VirtualLocation: reference(VirtualLocation)
		}))
	});
}

Shape factories like string(), number(), boolean(), local(), and reference() define the expected value type and optional constraints for each property. Cardinality helpers wrap shape factories to control how many values are expected and to determine the inferred TypeScript type:

| Factory | Cardinality | TypeScript Type | |-----------------|-------------|-----------------------------| | required(s) | 1..1 | V | | optional(s) | 0..1 | undefined \| V | | repeatable(s) | 1..* | readonly [V, ...V[]] | | multiple(s) | 0..* | undefined \| readonly V[] |

Resource properties link to other resources in two ways. A reference() wrapper links to a standalone resource — an independently identified and managed entity like Vendor. A direct shape inclusion defines an embedded resource — a nested object with no independent identity, created and managed together with its parent like Rating.

Properties that accept multiple types are modelled as unions — discriminated variants wrapped in index maps, where each key identifies a type alternative. At runtime, union values are keyed by variant name:

{
  "address": {
    "PostalAddress": {
      "id": "https://data.example.com/addresses/456",
      "streetAddress": "12 Harbour Street",
      "addressLocality": "Copenhagen"
    }
  }
}

Type Inference

Schemas double as TypeScript type definitions. The Infer utility extracts the model type:

import { type Infer } from "@metreeca/blue";

type ProductType = Infer<typeof Product>;

// {
//     id: IRI,
//     type: undefined | IRI,
//     name: Local,
//     description: undefined | Local,
//     price: number,
//     inStock: boolean,
//     tags: undefined | readonly string[],
//     rating: undefined | { average: number, reviews: number },
//     vendor: Reference
// }

No separate interface needed — the schema is the type definition.

Validating Resources

The validate function checks a value against a schema and returns a Relay that dispatches to either a value or trace handler:

const result = validate(data, Product);

result({
	value: product => {
		// product is typed as Infer<typeof Product>
	},
	trace: errors => {
		// errors describes validation violations
	}
});

The same schema validates different kinds of CRUD payloads, each corresponding to a data type defined by @metreeca/qest:

  • "value" — Create/Replace (Resource, default); all constraints enforced, missing and unknown properties rejected
  • "patch" — Partial Update (Patch); null values accepted as deletion markers, missing properties accepted as not modified, custom validators skipped
  • "model" — Retrieve (Model); entry point for retrieval projections, only type compatibility checked, missing properties accepted as not requested
  • "query" — Search (Query); entry point for search queries, extends model validation with operator-prefixed filtering and ordering keys

Models and queries are mutually recursive — a model may contain nested queries and vice versa: "model" and "query" modes provide distinct entry points into a shared recursive validation process, suited to different contexts.

validate(patch, Product, { mode: "patch" }); // partial update
validate(model, Product, { mode: "model" }); // retrieval model
validate(query, Product, { mode: "query" }); // search query

[!WARNING]

In "patch" mode, nested resources are validated as complete states — patch semantics (missing properties accepted, custom validators skipped) apply only at the top level.

[!IMPORTANT]

In "model" and "query" modes, nested resource and reference expansion is controlled by the depth option, which defaults to 0 — rejecting any nested model or query while still accepting IRI references. Set depth to a positive integer to allow that many levels of nesting, or to null for unlimited depth.

validate(model, Product, { mode: "model" });                // depth 0 (default) — flat projections only
validate(model, Product, { mode: "model", depth: 2 });      // up to 2 levels of nesting
validate(model, Product, { mode: "model", depth: null });   // unlimited nesting

SHACL Foundations

SHACL (Shapes Constraint Language) is a W3C standard for describing and validating RDF graphs. It defines shapes — sets of constraints that nodes in a graph must satisfy — covering structure, cardinality, value ranges, and logical combinations.

@metreeca/blue implements a controlled SHACL subset tailored to the JSON-LD profile defined by @metreeca/qest, enabling TypeScript developers to use shape-based validation without mastering SHACL technicalities.

This controlled subset is specified by:

  • cardinality constraints (sh:minCount, sh:maxCount) for specifying how many values a property must or may have

  • value range constraints (sh:minExclusive, sh:maxExclusive, sh:minInclusive, sh:maxInclusive) for numeric value ranges

  • string constraints (sh:minLength, sh:maxLength, sh:pattern, sh:languageIn) for text length, patterns, and language tags

  • value type constraints (sh:class) for declaring the expected type of resource instances; limited to a single class

  • value constraints (sh:in, sh:hasValue) for enumerations and required values

  • logical constraints limited to sh:or as typed unions on properties; sh:not, sh:and, and sh:xone are not supported

  • closed shapes enforced by default on all resource shapes; unknown properties are always rejected

Property pair constraints and property paths are not supported; cross-property logic can be implemented via custom validators.

Support

  • Open an issue to report a problem or to suggest a new feature
  • Start a discussion to ask a how-to question or to share an idea

License

This project is licensed under the Apache 2.0 License – see LICENSE file for details.