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

@typesugar/contracts

v0.1.0

Published

🧊 Design by Contract macros for typesugar β€” requires/ensures/invariant with configurable stripping and compile-time proofs

Readme

@typesugar/contracts

Design by Contract for TypeScript with compile-time proof elimination.

Overview

@typesugar/contracts provides Eiffel/Dafny-style contracts with a multi-layer proof engine that eliminates runtime checks when conditions can be proven at compile time.

import { requires, ensures, old } from "@typesugar/contracts";
import { Positive } from "@typesugar/type-system";

function withdraw(account: Account, amount: Positive): number {
  requires(account.balance >= amount, "Insufficient funds");
  ensures(account.balance === old(account.balance) - amount);

  account.balance -= amount;
  return account.balance;
}

Installation

npm install @typesugar/contracts
# For refined type integration:
npm install @typesugar/contracts-refined @typesugar/type-system

Features

Core Contracts

| Construct | Description | | --------------------------- | ---------------------------------------------- | | requires(condition, msg?) | Precondition β€” checked at function entry | | ensures(condition, msg?) | Postcondition β€” checked at function exit | | old(expr) | Capture pre-call value (inside ensures) | | @contract | Enable requires:/ensures: labeled blocks | | @invariant(predicate) | Class invariant β€” checked after public methods |

Proof Engine

The prover runs layers in order, stopping at first success:

  1. Constant evaluation β€” Static values, comptime() results
  2. Type deduction β€” Facts from Refined<T, Brand> types
  3. Algebraic rules β€” Pattern matching (a > 0 ∧ b > 0 β†’ a + b > 0)
  4. Linear arithmetic β€” Fourier-Motzkin elimination
  5. Prover plugins β€” External solvers (Z3)

Compile-Time Evaluation

The comptime() macro evaluates expressions at build time:

import { requires, comptime } from "@ttfx/contracts";

// Complex computations at build time
const BUFFER_SIZE = comptime(() => 1024 * 16);  // Becomes: 16384
const FACTORIALS = comptime(() => {
  const result = [1];
  for (let i = 1; i <= 10; i++) result.push(result[i - 1] * i);
  return result;
});  // Becomes: [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]

function allocate(size: number) {
  // Prover can verify this when size is BUFFER_SIZE
  requires(size > 0 && size <= BUFFER_SIZE);
  return new ArrayBuffer(size);
}

comptime() integrates with the prover's constant evaluation layer, enabling complex computations (loops, recursion, array methods) while benefiting from proof elimination.

Coq-Inspired Extensions

Decidability Annotations

Mark predicates with their decidability level to control proof strategy and warnings:

import { decidable, registerDecidability } from "@typesugar/contracts";

// Decorator form
@decidable("compile-time", "constant")
type Literal42 = Refined<number, "Literal42">;

// Programmatic form
registerDecidability({
  brand: "Positive",
  predicate: "$ > 0",
  decidability: "compile-time",
  preferredStrategy: "algebra",
});

| Level | Meaning | | ---------------- | --------------------------------- | | "compile-time" | Always provable at compile time | | "decidable" | Decidable, may need SMT solver | | "runtime" | Must check at runtime | | "undecidable" | Cannot be decided algorithmically |

Decidability Warnings

Configure warnings when proofs fall back to runtime:

// typesugar.config.ts
export default {
  contracts: {
    decidabilityWarnings: {
      warnOnFallback: "warn", // "off" | "warn" | "error"
      warnOnSMT: "info",
      ignoreBrands: ["DynamicCheck"],
    },
  },
};

Subtyping Coercions

Register safe type coercions for automatic widening:

import { registerSubtypingRule, canWiden } from "@typesugar/contracts";

registerSubtypingRule({
  from: "Positive",
  to: "NonNegative",
  proof: "positive_implies_non_negative",
  justification: "x > 0 implies x >= 0",
});

canWiden("Positive", "NonNegative"); // true

Linear Arithmetic Solver

Proves linear inequalities via Fourier-Motzkin elimination:

import { tryLinearArithmetic, trySimpleLinearProof } from "@typesugar/contracts";

// Given: x > 0, y >= 0
// Proves: x + y >= 0
const result = trySimpleLinearProof("x + y >= 0", [
  { variable: "x", predicate: "x > 0" },
  { variable: "y", predicate: "y >= 0" },
]);
// result.proven === true

Supported patterns:

  • Transitivity: x > y ∧ y > z β†’ x > z
  • Sum bounds: x >= a ∧ y >= b β†’ x + y >= a + b
  • Positive implies non-negative: x > 0 β†’ x >= 0
  • Equality bounds: x === c β†’ x >= c ∧ x <= c

Proof Certificates

Generate structured proof traces for debugging:

import {
  createCertificate,
  succeedCertificate,
  formatCertificate,
} from "@typesugar/contracts";

const facts = [{ variable: "x", predicate: "x > 0" }];
let cert = createCertificate("x >= 0", facts);

// Add proof steps...
cert = succeedCertificate(cert, "linear", {
  rule: "positive_implies_nonneg",
  description: "x > 0 implies x >= 0",
});

console.log(formatCertificate(cert));
// Certificate for: x >= 0
// Status: PROVEN (linear)
// Steps:
//   1. [positive_implies_nonneg] x > 0 implies x >= 0

Usage Examples

Inline Style

import { requires, ensures, old } from "@typesugar/contracts";

function deposit(account: Account, amount: Positive): void {
  requires(amount > 0); // PROVEN: Positive type
  ensures(account.balance === old(account.balance) + amount);

  account.balance += amount;
}

Block Style

@contract
function withdraw(account: Account, amount: Positive): Balance {
  requires: {
    account.balance >= amount;
    !account.frozen;
  }
  ensures: (result) => {
    result === old(account.balance) - amount;
  }

  account.balance -= amount;
  return Balance.refine(account.balance);
}

Class Invariants

@invariant((self) => self.balance >= 0, "Balance must be non-negative")
class BankAccount {
  balance = 0;

  deposit(amount: Positive): void {
    this.balance += amount;
  }
}

Custom Algebraic Rules

import { registerAlgebraicRule } from "@typesugar/contracts";

registerAlgebraicRule({
  name: "percentage_bounds",
  description: "Percentage is 0-100",
  match(goal, facts) {
    const m = goal.match(/^(\w+)\s*<=\s*100$/);
    if (!m) return false;
    return facts.some(
      (f) => f.variable === m[1] && f.predicate.includes("Percentage"),
    );
  },
});

Integration with @typesugar/type-system

Import @typesugar/contracts-refined to connect the prover with refined types:

// REQUIRED: Registers all built-in predicates
import "@typesugar/contracts-refined";

import { Positive, Byte, Port } from "@typesugar/type-system";

function processPort(port: Port): void {
  requires(port >= 1); // PROVEN: Port guarantees >= 1
  requires(port <= 65535); // PROVEN: Port guarantees <= 65535
}

Configuration

Via typesugar.config.ts

export default {
  contracts: {
    mode: "full", // "full" | "assertions" | "none"
    proveAtCompileTime: true,
    decidabilityWarnings: {
      warnOnFallback: "warn",
      warnOnSMT: "off",
      ignoreBrands: [],
    },
  },
};

Via Environment Variable

TYPESUGAR_CONTRACTS_MODE=none npm run build  # Production: strip all checks

Mode Reference

| Mode | Preconditions | Postconditions | Invariants | | -------------- | ------------- | -------------- | ---------- | | "full" | Emitted | Emitted | Emitted | | "assertions" | Stripped | Stripped | Emitted | | "none" | Stripped | Stripped | Stripped |

API Reference

Core Functions

  • requires(condition, message?) β€” Precondition check
  • ensures(condition, message?) β€” Postcondition check
  • old(expression) β€” Capture pre-call value
  • comptime(() => expr) β€” Compile-time expression evaluation

Prover API

  • tryProve(ctx, condition, fn) β€” Attempt compile-time proof
  • tryAlgebraicProof(goal, facts) β€” Algebraic pattern matching
  • tryLinearArithmetic(goal, facts) β€” Fourier-Motzkin solver
  • trySimpleLinearProof(goal, facts) β€” Fast linear patterns

Decidability API

  • registerDecidability(info) β€” Register decidability for a brand
  • getDecidability(brand) β€” Get decidability info
  • isCompileTimeDecidable(brand) β€” Check if compile-time provable
  • canProveAtCompileTime(level) β€” Check decidability level
  • emitDecidabilityWarning(info) β€” Emit configured warning

Subtyping API

  • registerSubtypingRule(rule) β€” Register widening rule
  • canWiden(from, to) β€” Check if subtyping exists
  • getSubtypingRule(from, to) β€” Get rule details
  • getWidenTargets(from) β€” Get all widen targets

Certificate API

  • createCertificate(goal, assumptions) β€” Start certificate
  • succeedCertificate(cert, method, step) β€” Mark proven
  • failCertificate(cert, reason) β€” Mark failed
  • addStep(cert, step) β€” Add proof step
  • formatCertificate(cert) β€” Human-readable output

Package Structure

packages/contracts/src/
  index.ts              # Public API
  config.ts             # Configuration + decidability warnings
  macros/
    requires.ts         # requires() expression macro
    ensures.ts          # ensures() expression macro
    old.ts              # old() capture + hoisting
    contract.ts         # @contract attribute macro
    invariant.ts        # @invariant attribute macro
    decidable.ts        # @decidable annotation macro
  prover/
    index.ts            # tryProve() orchestration
    type-facts.ts       # Type fact extraction + subtyping
    algebra.ts          # Algebraic proof rules
    linear.ts           # Fourier-Motzkin solver
    certificate.ts      # Proof certificates
  parser/
    contract-block.ts   # Parse requires:/ensures: blocks
    predicate.ts        # Normalize predicates

See Also

  • @typesugar/contracts-refined β€” Bridges contracts with type-system
  • @typesugar/contracts-z3 β€” Z3 SMT solver plugin
  • @typesugar/type-system β€” Refined types (Positive, Byte, etc.)

License

MIT