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

@appport/contract-builder

v1.0.1

Published

Contract builder for creating AppPort application contracts.

Readme

@appport/contract-builder

Contract builder for creating portable AppPort application contracts.

Overview

The contract builder provides tools for defining AppPort application contracts independently of their implementation. Contracts are the canonical machine-readable format that describe what an application can do.

Usage

# Create a new contract
appport contract init

# Inspect a contract
appport contract inspect appport/contract.json

# Validate a contract
appport contract validate appport/contract.json

# Compare two contracts
appport contract diff old.json new.json

# Generate a TypeScript implementation skeleton
appport contract generate --output my-app

Contract Format

A contract is a JSON file describing the application and its capabilities:

{
  "protocol": "appport/1",
  "application": {
    "id": "com.example.myapp",
    "name": "My App",
    "version": "1.0.0",
    "description": "A sample application"
  },
  "capabilities": [
    {
      "name": "documents.list",
      "version": 1,
      "description": "List all documents",
      "purpose": "Retrieve all documents",
      "authority": "documents",
      "input": { "type": "object", "properties": {} },
      "output": {
        "type": "object",
        "properties": {
          "documents": {
            "type": "array",
            "items": { "type": "object" }
          }
        }
      },
      "authorization": ["documents.read"],
      "effects": [
        {
          "type": "read",
          "description": "Reads document data"
        }
      ]
    }
  ],
  "events": []
}

Building Contracts Programmatically

PR15 introduces a contract-native capability builder for fluent contract construction:

import { createContractBuilder, capability } from "@appport/contract-builder";

// Create a contract builder
const contract = createContractBuilder({
  id: "com.example.invoicing",
  name: "Invoicing",
  version: "1.0"
});

// Define and attach capabilities using the builder pattern
const refund = contract
  .capability("invoice.refund", "1")
  .purpose("Refund an invoice")
  .input({
    type: "object",
    properties: {
      invoice_id: { type: "string" },
      reason: { type: "string" }
    },
    required: ["invoice_id", "reason"]
  })
  .output({
    type: "object",
    properties: {
      refund_id: { type: "string" },
      invoice_id: { type: "string" },
      status: { type: "string" }
    },
    required: ["refund_id", "invoice_id", "status"]
  })
  .authority("invoicing")
  .requiresScope("invoice.refund")
  .effect({
    type: "state",
    description: "Invoice becomes refunded"
  })
  .emits("invoice.refunded@1")
  .build();

contract.attach(refund);

// Manage capabilities
contract.getCapability("invoice.refund@1");  // Get by ID (name@version)
contract.listCapabilities();                  // List all attached capabilities
contract.detach("invoice.refund@1");         // Remove a capability

Capability Builder API

  • .purpose(text: string) - Set the semantic purpose of the capability
  • .input(schema: JSONSchema) - Define the input schema
  • .output(schema: JSONSchema) - Define the output schema
  • .authority(auth: string) - Set the domain/authority this capability belongs to
  • .requiresScope(scope: string) - Add an authorization scope requirement
  • .effect(effect: CapabilityEffect) - Add an effect this capability produces
  • .emits(event: string) - Add an event this capability emits
  • .description(text: string) - Set the description
  • .kind(kind: "request" | "stream") - Set the capability kind
  • .build() - Build and return the capability

Contract Builder API (PR15)

  • .capability(name: string, version: string | number) - Create a capability builder
  • .attach(capability: ContractCapability) - Attach a capability to the contract
  • .detach(capabilityId: string) - Remove a capability by ID (name@version format)
  • .getCapability(capabilityId: string) - Retrieve a capability by ID
  • .listCapabilities() - Get all attached capabilities
  • .listProvidedCapabilities() - Alias for listCapabilities

Application Capability Relationships (PR16)

PR16 extends contracts to declare both what an application provides and what it requires from other applications.

Capability Requirements

Applications can declare external dependencies using capability requirements. Requirements support version constraints to enable dynamic composition:

import { createContractBuilder, requirement } from "@appport/contract-builder";

const commerce = createContractBuilder({
  id: "com.example.commerce",
  name: "Commerce",
  version: "1.0"
});

// Add a provided capability
const orderCreate = commerce
  .capability("order.create", 1)
  .purpose("Create an order")
  .input({ type: "object", properties: {} })
  .output({ type: "object", properties: {} })
  .build();

commerce.attach(orderCreate);

// Add requirements from other applications
const invoiceRequirement = commerce
  .requirement("invoice.create", "^1")
  .purpose("Create an invoice for a completed order")
  .from("com.example.invoicing")
  .build();

commerce.addRequirement(invoiceRequirement);

// Manage requirements
commerce.listRequiredCapabilities();       // List all required capabilities
commerce.getRequirement("invoice.create"); // Get by name
commerce.requiresCapability("invoice.create");  // Check if required
commerce.removeRequirement("invoice.create");   // Remove a requirement

Requirement Builder API

  • .purpose(text: string) - Set the purpose of the requirement
  • .from(applicationId: string) - Constrain the provider to a specific application ID
  • .build() - Build and return the requirement

Contract Builder API (PR16 Extensions)

  • .requirement(name: string, versionConstraint: string) - Create a requirement builder
  • .addRequirement(requirement: CapabilityRequirement) - Add a required capability
  • .removeRequirement(name: string) - Remove a requirement by name
  • .getRequirement(name: string) - Retrieve a requirement by name
  • .listRequiredCapabilities() - Get all required capabilities
  • .requiresCapability(name: string) - Check if a capability is required
  • .provides(capabilityId: string) - Check if a capability is provided
  • .hooks(hooks: ContractBuilderHooks) - Register lifecycle hooks

Version Constraints

Requirements support semantic version constraints:

  • ^1 - Compatible with 1.x.x
  • ~1.2 - Compatible with 1.2.x
  • >=1 - Version 1 or higher
  • >1 - Version higher than 1
  • <=2 - Version 2 or lower
  • <2 - Version lower than 2
  • 1 - Exact version 1

Compatibility Checking

Check if a provided capability satisfies a requirement:

import { isCapabilityCompatible, satisfiesVersionConstraint } from "@appport/contract-builder";

// Check version constraint satisfaction
satisfiesVersionConstraint(1, "^1");  // true
satisfiesVersionConstraint(2, "^1");  // false

// Check full compatibility (name and version)
const requirement = { name: "invoice.create", versionConstraint: "^1" };
const capability = { name: "invoice.create", version: 1, input: {}, output: {} };

isCapabilityCompatible(requirement, capability);  // true

Key Distinctions

Provides vs Requires

  • Provides: Capabilities owned by this application (declared via .attach())
  • Requires: Capabilities expected from other applications (declared via .addRequirement())

Discovery vs Compatibility vs Authorization

PR16 establishes three distinct stages:

  1. Discovery - Find available capabilities at runtime
  2. Compatibility - Check version constraints and schema compatibility
  3. Authorization - Verify permission to use the capability

These stages are independent. A capability can be discovered and compatible but still not authorized for use.

No Compile-Time Coupling

Requirements do not include implementation details:

  • No SDK imports
  • No provider URLs
  • No provider code
  • No transport details

The consumer contract describes a requirement. The runtime resolves the provider.

Builder Hooks

Register hooks to be notified of contract authoring events:

const contract = createContractBuilder({...});

contract.hooks({
  onCapabilityAdded(capability) {
    console.log(`Added capability: ${capability.name}`);
  },
  onCapabilityRequired(requirement) {
    console.log(`Added requirement: ${requirement.name}`);
  },
  onCapabilityRequirementRemoved(name) {
    console.log(`Removed requirement: ${name}`);
  }
});

// Hooks are called when capabilities/requirements are added/removed
contract.attach(cap);
contract.addRequirement(req);

Available hooks:

  • onCapabilityAdded(capability) - Called when a capability is attached
  • onCapabilityRemoved(capabilityId) - Called when a capability is detached
  • onCapabilityChanged(old, new) - Called when a capability is modified
  • onCapabilityRequired(requirement) - Called when a requirement is added
  • onCapabilityRequirementRemoved(name) - Called when a requirement is removed
  • onCapabilityRequirementChanged(old, new) - Called when a requirement is modified

Contract Diff with Requirements

The diff function now tracks requirement changes:

import { diffContracts } from "@appport/contract-builder";

const diff = diffContracts(oldContract, newContract);

console.log(diff.capabilities);  // Capability changes
console.log(diff.requirements);  // Requirement changes
console.log(diff.events);        // Event changes
console.log(diff.hasBreakingChanges);  // true if any breaking changes

// Requirement changes include:
// { type: "added", name: "invoice.create", versionConstraint: "^1" }
// { type: "removed", name: "payment.authorize" }
// { type: "modified", name: "invoice.send", versionConstraint: "^2", breaking: true }

Extracting Requirements from Contracts

Extract requirements for analysis:

import { getContractRequirements } from "@appport/contract-builder";

const requirements = getContractRequirements(contract);
// Returns array of requirement objects with full details

API

createContract(application: ContractApplication): Contract

Create a new contract with sensible defaults. (Legacy API)

createContractBuilder(application: ContractApplication): ContractBuilder

Create a new contract builder with the fluent API for constructing contracts programmatically.

capability(name: string, version: string | number): CapabilityBuilder

Create a new capability builder for defining a single capability.

requirement(name: string, versionConstraint: string): RequirementBuilder

Create a new requirement builder for defining a capability requirement.

validateContract(contract: Contract): ValidationResult

Validate a contract. Returns validation issues and overall validity. Validates both provided capabilities and requirements.

diffContracts(from: Contract, to: Contract): ContractDiff

Compare two contracts and produce a diff highlighting changes and breaking changes. Includes capability, event, and requirement changes.

isCapabilityCompatible(requirement: CapabilityRequirement, capability: ContractCapability): boolean

Check if a provided capability can satisfy a requirement by verifying:

  • Name matches
  • Provided version satisfies version constraint
  • Schemas exist

Returns true if compatible, false otherwise. Authorization is NOT checked here.

satisfiesVersionConstraint(providedVersion: number, constraint: string): boolean

Check if a provided version number satisfies a semantic version constraint (e.g., "^1", "~1.2", ">=2").

getContractRequirements(contract: Contract): CapabilityRequirement[]

Extract all required capabilities from a contract, useful for analyzing external dependencies.

contractToManifest(contract: Contract): AppPortManifest

Convert a portable Contract to an AppPortManifest for use with client generation and other tools.

generateTypescriptServer(contract: Contract): GeneratedTypescriptServer

Generate a complete TypeScript implementation skeleton from a contract, including:

  • Configuration
  • Capability definitions
  • Event handlers
  • Server and client setup

Key Design Principles

  1. Contract-Native: The contract is the canonical definition of capabilities and requirements
  2. Fluent API: Build contracts programmatically with a natural, fluent interface
  3. Ownership: Capabilities are explicitly attached to contracts, establishing ownership
  4. Identity: Capabilities and requirements are uniquely identified by name@version
  5. Canonical Format: The contract is the source of truth, not the implementation
  6. Portable: Contracts can move between TypeScript, Python, Rust, etc.
  7. Validation: Strong validation ensures contract correctness
  8. Generation: Contracts can generate implementation skeletons
  9. Diffing: Compare contracts to track changes and breaking changes
  10. Distinct Relationships: Provides (ownership) and requires (participation) are separate concerns
  11. Version Constraints: Requirements use semantic version constraints for dynamic composition
  12. No Compile-Time Coupling: Applications can require capabilities without importing provider code
  13. Discovery ≠ Compatibility ≠ Authorization: Three independent stages in capability resolution
  14. Lifecycle Hooks: Contract authoring events trigger optional hooks for validation and logging