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

@resourcexjs/registry

v2.5.5

Published

ResourceX Registry - Resource storage and retrieval

Readme

@resourcexjs/registry

Registry layer for ResourceX. Provides business logic for RXR (ResourceX Resource) operations on top of the storage layer.

Installation

bun add @resourcexjs/registry

Overview

The @resourcexjs/registry package provides:

  • Three registry types for different use cases
  • Access chain for read-through cache pattern
  • Middleware for cross-cutting concerns
  • Discovery for well-known registry endpoints

All registries implement a common Registry interface and use @resourcexjs/storage for persistence.

Registry Types

LocalRegistry

For local/owned resources without a registry domain in the path.

import { LocalRegistry } from "@resourcexjs/registry";
import { FileSystemStorage } from "@resourcexjs/storage";

const storage = new FileSystemStorage("~/.resourcex/local");
const registry = new LocalRegistry(storage);

// Storage structure: {name}/{tag}/manifest.json + archive.tar.gz
await registry.put(rxr);
const resource = await registry.get(rxl);

Use cases:

  • Client local storage (~/.resourcex/local/)
  • Server authoritative storage (./data/)

MirrorRegistry

For cached/mirrored remote resources. Includes registry domain in the path.

import { MirrorRegistry } from "@resourcexjs/registry";
import { FileSystemStorage } from "@resourcexjs/storage";

const storage = new FileSystemStorage("~/.resourcex/cache");
const registry = new MirrorRegistry(storage);

// Storage structure: {registry}/{name}/{tag}/manifest.json + archive.tar.gz
await registry.put(rxr);
const resource = await registry.get(rxl);

// Cache-specific: clear cached resources
await registry.clear(); // Clear all
await registry.clear("deepractice.ai"); // Clear specific registry

Use cases:

  • Caching remote resources locally
  • Offline access to previously fetched resources

LinkedRegistry

For development symlinks. Changes in the source directory are reflected immediately.

import { LinkedRegistry } from "@resourcexjs/registry";

const registry = new LinkedRegistry("~/.resourcex/linked");

// Create symlink to development directory
const rxl = await registry.link("./my-prompt");

// Get resource (reads from symlink target)
const resource = await registry.get(rxl);

// Remove symlink
await registry.unlink(rxl);

Use cases:

  • Live development without re-adding resources
  • Testing local changes before publishing

Registry Interface

All registries implement:

interface Registry {
  get(rxl: RXL): Promise<RXR>;
  put(rxr: RXR): Promise<void>;
  has(rxl: RXL): Promise<boolean>;
  remove(rxl: RXL): Promise<void>;
  list(options?: SearchOptions): Promise<RXL[]>;
}

interface SearchOptions {
  query?: string; // Filter by name/path substring
  limit?: number; // Max results
  offset?: number; // Skip first N (pagination)
}

Access Chain

The access chain implements a read-through cache pattern for unified resource access.

RegistryAccessChain

Iterates through accessors in order. First accessor that can handle returns the result.

import {
  RegistryAccessChain,
  LinkedAccessor,
  LocalAccessor,
  CacheAccessor,
  RemoteAccessor,
  LocalRegistry,
  MirrorRegistry,
  LinkedRegistry,
} from "@resourcexjs/registry";
import { FileSystemStorage } from "@resourcexjs/storage";

// Create registries
const linkedRegistry = new LinkedRegistry("~/.resourcex/linked");
const localRegistry = new LocalRegistry(new FileSystemStorage("~/.resourcex/local"));
const cacheRegistry = new MirrorRegistry(new FileSystemStorage("~/.resourcex/cache"));

// Create accessor chain
const chain = new RegistryAccessChain(
  [
    new LinkedAccessor(linkedRegistry), // 1. Dev symlinks (highest priority)
    new LocalAccessor(localRegistry), // 2. Local resources (no domain)
    new CacheAccessor(cacheRegistry), // 3. Cached remote resources
    new RemoteAccessor(fetcher, cacheRegistry), // 4. Fetch + auto-cache
  ],
  { memCache: true } // Optional in-memory cache
);

// Get resource (tries each accessor in order)
const rxr = await chain.get(rxl);

// Check existence
const exists = await chain.has(rxl);

// Cache management
chain.invalidate(rxl); // Remove specific resource from memory cache
chain.clearCache(); // Clear entire memory cache

Accessor Types

| Accessor | Handles | Description | | ---------------- | -------------------------- | ------------------------------ | | LinkedAccessor | All (if linked) | Dev symlinks, highest priority | | LocalAccessor | Resources without registry | Local storage | | CacheAccessor | Resources with registry | Cached remote resources | | RemoteAccessor | Resources with registry | Fetch + auto-cache |

RemoteFetcher Interface

RemoteAccessor requires a fetcher implementation:

interface RemoteFetcher {
  fetch(rxl: RXL): Promise<RXR>;
}

// Example implementation
const fetcher: RemoteFetcher = {
  async fetch(rxl) {
    const url = `https://${rxl.registry}/api/v1/resources/${rxl.name}/${rxl.tag}`;
    const response = await fetch(url);
    // ... parse response to RXR
    return rxr;
  },
};

Middleware

RegistryMiddleware

Base class for creating custom middleware. Delegates all operations to the inner registry.

import { RegistryMiddleware } from "@resourcexjs/registry";
import type { RXL, RXR } from "@resourcexjs/core";

class LoggingMiddleware extends RegistryMiddleware {
  async get(rxl: RXL): Promise<RXR> {
    console.log("Getting:", rxl);
    const rxr = await this.inner.get(rxl);
    console.log("Got:", rxr.manifest.name);
    return rxr;
  }
}

const logged = new LoggingMiddleware(registry);

DomainValidation

Built-in middleware that validates resource registry matches a trusted registry.

import { withDomainValidation } from "@resourcexjs/registry";

const validated = withDomainValidation(registry, "deepractice.ai");

// Throws RegistryError if resource.manifest.registry !== "deepractice.ai"
await validated.get(rxl);

Use cases:

  • Server-side validation to prevent registry impersonation
  • Ensuring resources are from trusted sources

Discovery

Discover registry endpoints via well-known URL.

import { discoverRegistry } from "@resourcexjs/registry";

const result = await discoverRegistry("deepractice.ai");
// {
//   domain: "deepractice.ai",
//   registries: ["https://registry.deepractice.ai/api/v1"]
// }

Well-known format (https://{domain}/.well-known/resourcex):

{
  "version": "1.0",
  "registries": ["https://registry.example.com/api/v1"]
}

Storage Structure

~/.resourcex/
├── local/                          # LocalRegistry - local resources
│   └── {path/}{name}/
│       └── {tag}/
│           ├── manifest.json
│           └── archive.tar.gz
│
├── cache/                          # MirrorRegistry - cached remote
│   └── {registry}/
│       └── {path/}{name}/
│           └── {tag}/
│               ├── manifest.json
│               └── archive.tar.gz
│
└── linked/                         # LinkedRegistry - dev symlinks
    └── {registry}/
        └── {path/}{name}/
            └── {tag} -> /path/to/dev/folder

Error Handling

import { RegistryError } from "@resourcexjs/registry";

try {
  await registry.get(rxl);
} catch (error) {
  if (error instanceof RegistryError) {
    console.error("Registry error:", error.message);
  }
}

Common errors:

  • Resource not found: {locator}
  • Resource not found in cache: {locator}
  • Linked resource not found: {locator}
  • LinkedRegistry does not support put(). Use link() instead.
  • Well-known discovery failed for {domain}: {status}
  • Untrusted registry: resource claims "{claimed}" but registry only trusts "{trusted}"

API Reference

Registries

LocalRegistry

new LocalRegistry(storage: Storage)

Registry for local resources without registry domain.

MirrorRegistry

new MirrorRegistry(storage: Storage)

Registry for cached remote resources with registry domain.

Additional methods:

  • clear(registry?: string): Promise<void> - Clear cached resources

LinkedRegistry

new LinkedRegistry(basePath: string)

Registry for development symlinks.

Additional methods:

  • link(devPath: string): Promise<RXL> - Create symlink to development directory
  • unlink(rxl: RXL): Promise<void> - Remove symlink (alias for remove)

Access Chain

RegistryAccessChain

new RegistryAccessChain(accessors: RegistryAccessor[], options?: { memCache?: boolean })

Methods:

  • get(rxl: RXL): Promise<RXR> - Get resource through chain
  • has(rxl: RXL): Promise<boolean> - Check existence
  • clearCache(): void - Clear memory cache
  • invalidate(rxl: RXL): void - Remove specific resource from memory cache

RegistryAccessor

interface RegistryAccessor {
  readonly name: string;
  canHandle(rxl: RXL): Promise<boolean>;
  get(rxl: RXL): Promise<RXR>;
}

Middleware

RegistryMiddleware

abstract class RegistryMiddleware implements Registry {
  constructor(protected readonly inner: Registry)
}

DomainValidation

new DomainValidation(inner: Registry, trustedRegistry: string)

Middleware class that validates resource registry matches the trusted registry.

withDomainValidation

withDomainValidation(registry: Registry, trustedRegistry: string): Registry

Factory function to create DomainValidation middleware.

Discovery

discoverRegistry

discoverRegistry(domain: string): Promise<DiscoveryResult>

Types:

interface DiscoveryResult {
  domain: string;
  registries: string[];
}

interface WellKnownResponse {
  version?: string;
  registries: string[];
}

Error

RegistryError

class RegistryError extends ResourceXError {
  constructor(message: string, options?: ErrorOptions);
}

License

Apache-2.0