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 🙏

© 2025 – Pkg Stats / Ryan Hefner

atpi

v1.0.7

Published

Resolve AT Protocol URLs to JSON data

Readme

atpi

Resolve AT Protocol URLs to JSON data with ease. This package provides both a CLI tool and a programmatic API for resolving at:// URLs.

Features

  • Local Resolution: Connect directly to PDS servers (default)
  • Remote Resolution: Use the atpi.at service
  • Automatic Fallback: Falls back to remote if local fails
  • Smart Caching: Caches DID and handle resolutions
  • Multiple Modes: Choose between local, remote, or auto mode
  • Tab Completion: Smart shell completion for AT Protocol URLs

Installation

Global Install (for CLI usage)

npm install -g atpi

# Optional: Enable tab completion
atpi --install-completion

Local Install (for programmatic usage)

npm install atpi

Quick Start

After installation, you can immediately use atpi:

# Resolve an AT Protocol URL
atpi at://did:plc:7gm5ejhut7kia2kzglqfew5b/app.bsky.feed.post/3lszcx7zf622q

# With tab completion enabled, press TAB to see available collections
atpi at://did:plc:7gm5ejhut7kia2kzglqfew5b/<TAB>

CLI Usage

Once installed globally, you can use the atpi command directly from your terminal:

# Basic usage (pretty printed by default)
atpi at://did:plc:7gm5ejhut7kia2kzglqfew5b/app.bsky.feed.post/3lszcx7zf622q

# Compact JSON output
atpi at://did:plc:7gm5ejhut7kia2kzglqfew5b/app.bsky.feed.post/3lszcx7zf622q --compact

# Save to file
atpi at://did:plc:7gm5ejhut7kia2kzglqfew5b/app.bsky.feed.post/3lszcx7zf622q > post.json

# Process with jq
atpi at://did:plc:7gm5ejhut7kia2kzglqfew5b/app.bsky.feed.post/3lszcx7zf622q | jq '.value.text'

# Multiple URLs
atpi at://did:plc:7gm5ejhut7kia2kzglqfew5b at://did:plc:7gm5ejhut7kia2kzglqfew5b/app.bsky.actor.profile/self

# Local resolution (default - connects directly to PDS)
atpi at://did:plc:7gm5ejhut7kia2kzglqfew5b/app.bsky.feed.post/3lszcx7zf622q --local

# Remote resolution (uses atpi.at service)
atpi at://did:plc:7gm5ejhut7kia2kzglqfew5b/app.bsky.feed.post/3lszcx7zf622q --remote

# Custom timeout (in milliseconds)
atpi at://did:plc:7gm5ejhut7kia2kzglqfew5b/app.bsky.feed.post/3lszcx7zf622q --timeout 10000

Programmatic Usage

JavaScript

const atpi = require('atpi');

// Using async/await
async function getPost() {
  try {
    const data = await atpi.resolve('at://did:plc:7gm5ejhut7kia2kzglqfew5b/app.bsky.feed.post/3lszcx7zf622q');
    console.log(data);
  } catch (error) {
    console.error('Failed to resolve:', error.message);
  }
}

// Using promises
atpi.resolve('at://did:plc:7gm5ejhut7kia2kzglqfew5b/app.bsky.feed.post/3lszcx7zf622q')
  .then(data => console.log(data))
  .catch(error => console.error(error));

TypeScript

import atpi, { ATProtocolData, ATProtocolError } from 'atpi';

async function getPost(): Promise<void> {
  try {
    const data: ATProtocolData = await atpi.resolve('at://did:plc:7gm5ejhut7kia2kzglqfew5b/app.bsky.feed.post/3lszcx7zf622q');
    console.log(data);
  } catch (error) {
    if (error instanceof ATProtocolError) {
      console.error(`AT Protocol Error: ${error.message}`);
      if (error.statusCode) {
        console.error(`Status Code: ${error.statusCode}`);
      }
    }
  }
}

Advanced Options

// Resolution modes
const options = {
  mode: 'local',          // 'local' | 'remote' | 'auto' (default: 'local')
  timeout: 60000,         // Request timeout in ms (default: 30000)
  fallbackToRemote: true, // Fall back to remote if local fails (default: true)
  baseUrl: 'https://custom.resolver/' // Custom remote resolver URL
};

const data = await atpi.resolve('at://...', options);

// Force remote resolution
const remoteData = await atpi.resolve('at://...', { mode: 'remote' });

// Use local with no fallback
const localData = await atpi.resolve('at://...', { 
  mode: 'local', 
  fallbackToRemote: false 
});

API Reference

atpi.resolve(url, options?)

Resolves an AT Protocol URL to JSON data.

  • url (string): The AT Protocol URL to resolve (must start with at://)
  • options (object, optional):
    • mode (string): Resolution mode - 'local', 'remote', or 'auto' (default: 'local')
    • timeout (number): Request timeout in milliseconds (default: 30000)
    • fallbackToRemote (boolean): Fall back to remote if local fails (default: true)
    • baseUrl (string): Custom remote resolver base URL (default: 'https://atpi.')
  • Returns: Promise - The resolved JSON data
  • Throws: ATProtocolError - If the URL is invalid or resolution fails

Error Handling

The package exports an ATProtocolError class for specific error handling:

import { ATProtocolError } from 'atpi';

try {
  const data = await atpi.resolve('at://...');
} catch (error) {
  if (error instanceof ATProtocolError) {
    console.error('AT Protocol specific error:', error.message);
    console.error('Status code:', error.statusCode);
  } else {
    console.error('Unexpected error:', error);
  }
}

How It Works

Local Resolution (Default)

The package connects directly to AT Protocol Personal Data Servers (PDS) to resolve URLs:

  1. Parse AT URI: Extract identifier (DID/handle), collection, and record key
  2. Resolve Handle: If needed, resolve handle to DID using known PDS endpoints
  3. Resolve DID: Get the PDS endpoint URL from the DID document
  4. Fetch Data: Request data directly from the PDS using XRPC endpoints
  5. Cache Results: Cache DID and handle resolutions for better performance

Remote Resolution

When using remote mode, the package transforms AT Protocol URLs to HTTP URLs by prepending a resolver service URL (by default https://atpi.). For example:

  • at://did:plc:7gm5ejhut7kia2kzglqfew5b/app.bsky.feed.post/3lszcx7zf622q becomes https://atpi.at://did:plc:7gm5ejhut7kia2kzglqfew5b/app.bsky.feed.post/3lszcx7zf622q

Resolution Modes

  • Local: Direct PDS connection (faster, no external dependencies)
  • Remote: Via atpi.at service (simpler, works behind restrictive firewalls)
  • Auto: Try local first, fall back to remote if needed

Tab Completion

The package includes smart tab completion that fetches real collections from AT Protocol!

Easy Installation

After installing atpi globally, run:

atpi --install-completion

This will automatically set up tab completion for zsh.

How It Works

  • Smart completions: Fetches actual collections from AT Protocol for any DID
  • Local caching: Collections are cached for 24 hours for fast performance
  • Partial matching: Type partial collection names and tab to complete
  • Offline support: Uses cached data when internet is unavailable

Examples

# Complete a DID's collections (fetches real collections!)
atpi at://did:plc:7gm5ejhut7kia2kzglqfew5b/<TAB>
# Shows: app.bsky.actor.profile app.bsky.feed.post app.bsky.graph.follow ...

# Partial collection name completion
atpi at://did:plc:7gm5ejhut7kia2kzglqfew5b/app.bsky.graph.<TAB>
# Shows: app.bsky.graph.block app.bsky.graph.follow app.bsky.graph.list ...

# Command options
atpi --<TAB>
# Shows: --help --compact --install-completion

Manual Installation

If automatic installation doesn't work, you can manually add completion:

For zsh:

# Add the completion directory to fpath
echo "fpath=($(npm root -g)/atpi/completions \$fpath)" >> ~/.zshrc
echo "autoload -Uz compinit && compinit" >> ~/.zshrc
source ~/.zshrc

License

MIT