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

@solaeter/await-to-try

v0.1.0

Published

A Rust-inspired async error handling library with dual-mode distribution

Readme

@solaeter/await-to-try

A Rust-inspired async error handling library with dual-mode distribution

Eliminate try-catch hell and handle async errors elegantly in JavaScript/TypeScript.

Features

  • Try-Catch Hell Elimination - Simplify async error handling with a clean API
  • Dual-Mode Distribution - Use as an NPM library or inject source code via CLI
  • Chainable Enhancements - .toast() for error notifications and .resume() for fallback values
  • Highly Customizable - Inject and modify source code to fit your needs

Installation

Library Mode (NPM)

npm install @solaeter/await-to-try

Source Mode (CLI)

npx solaeter-to

The CLI will guide you through:

  1. Selecting a template
  2. Choosing the destination directory (default: ./src/utils)
  3. Injecting the source code with custom toast logic

Quick Start

Library Mode

import { _to } from '@solaeter/await-to-try';

// Handle a Promise
const { ok, result, error } = await _to(fetch('/api/data'));

if (ok) {
  console.log('Data:', result);
} else {
  console.error('Failed:', error);
}

Source Mode

After running the CLI:

import { _to } from './utils/to';

// Same API as library mode
const { ok, result, error } = await _to(asyncOperation());

API

_to(task)

Wraps a Promise or function execution result in a standardized format.

Parameters:

  • task: Promise<T> | (() => Promise<T>) | (() => T> - The task to handle

Returns: Promise<PromiseProxy<T>> - A promise that resolves to a result object

Result Structure:

{
  ok: boolean;      // true if successful, false if failed
  result?: T;       // the result value (when ok is true)
  error?: unknown;  // the error object (when ok is false)
}

Usage Examples

Basic Usage

// Handle a Promise
const { ok, result, error } = await _to(Promise.resolve(42));
console.log(ok);    // true
console.log(result); // 42

// Handle an async function
const { ok, result, error } = await _to(async () => {
  const res = await db.query('SELECT * FROM users');
  return res;
});

// Handle a sync function
const { ok, result, error } = await _to(() => {
  return JSON.parse(jsonString);
});

Using .toast() for Error Notifications

When an operation fails, .toast() displays an error message:

await _to(asyncOperation)
  .toast('操作失败,请重试');

// Only shows toast when the operation fails

Customizing Toast Logic:

In Source Mode, edit the toast logic in the injected file:

// Example: Using Ant Design
import { message } from 'antd';

// In the toast method:
message.error(message);

// Example: Using Element UI
import { ElMessage } from 'element-plus';

// In the toast method:
ElMessage.error(message);

// Example: Using React Toastify
import { toast } from 'react-toastify';

// In the toast method:
toast.error(message);

Using .resume() for Fallback Values

When an operation fails, .resume() returns a fallback value:

// Simple fallback
const data = await _to(fetchUserData())
  .resume({ id: 0, name: 'Guest' });

// If fetchUserData fails, returns the guest user object

Combining .toast() and .resume()

const items = await _to(fetchItems())
  .toast('列表加载失败,请检查网络')
  .resume([]);

// If fetchItems() fails:
// 1. Shows toast message
// 2. Returns empty array []

Advanced Examples

User Data Fetching

async function getUserProfile(userId: number) {
  const { ok, result: user, error } = await _to(
    fetch(`/api/users/${userId}`).then(res => res.json())
  );

  if (!ok) {
    return null;
  }

  return user;
}

// Or with chaining
const user = await getUserProfile(1)
  .toast('用户数据加载失败')
  .resume(null);

Multiple Async Operations

async function loadDashboard() {
  const [users, posts, comments] = await Promise.all([
    _to(fetchUsers()),
    _to(fetchPosts()),
    _to(fetchComments())
  ]);

  const usersData = users[0].ok ? users[0].result : [];
  const postsData = posts[0].ok ? posts[0].result : [];
  const commentsData = comments[0].ok ? comments[0].result : [];

  return { users: usersData, posts: postsData, comments: commentsData };
}

Error Recovery

async function fetchDataWithRetry(url: string, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const { ok, result, error } = await _to(fetch(url));

    if (ok) {
      return result;
    }

    if (i === maxRetries - 1) {
      await _to(Promise.reject(error))
        .toast(`请求失败,已重试 ${maxRetries} 次`);
    }
  }

  return null;
}

CLI Usage

Interactive Mode

npx solaeter-to

You'll be prompted to:

  1. Choose a template (currently: to.ts)
  2. Specify the output directory (default: ./src/utils)
  3. Confirm the injection

The injected file will have:

  • Your project name
  • Current date
  • Customizable toast logic
  • Full source code access

Customizing Injected Code

After injection, edit src/utils/to.ts to customize:

// Find the toast method in the file
if (prop === 'toast') {
  return (message: string) => {
    if (!target.ok && target.error) {
      // ========================================
      // Toast 逻辑 - 自定义区域
      // ========================================
      // Add your custom toast implementation here
      showToast({ type: 'error', message });
      // ========================================
    }
    return target;
  };
}

Comparison

Traditional Try-Catch

try {
  const response = await fetch('/api/data');
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
  // Fallback handling
}

Using _to

const { ok, result: data } = await _to(
  fetch('/api/data').then(res => res.json())
)
  .toast('数据加载失败')
  .resume(null);

if (data) {
  console.log(data);
}

License

MIT

Author

Solaeter

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.