safe-await-lib
v0.2.2
Published
Safe async/await utility for handling promises without try/catch.
Maintainers
Readme
SAFE-AWAIT-LIB
Safe async/await utility for handling promises without try/catch.
Designed for JavaScript and TypeScript environments.
📌 Why SAFE-AWAIT-LIB?
Traditional async / await requires repetitive try/catch blocks, which:
- clutter business logic
- encourage inconsistent error handling
- hide error intent
SAFE-AWAIT-LIB solves this by enforcing a predictable, explicit error-handling pattern.
Core idea
Async code should never throw — it should return a predictable tuple.
🚀 Features (v0.2.1)
- Safe execution of async functions, promises, or synchronous values
- Always returns a predictable tuple:
[SafeError | null, T | null] - Standardized error normalization
- Fully typed with TypeScript
- Compatible with all JavaScript and TypeScript environments
- Dual output: ESM + CJS
- Tree-shakable
- Built-in utilities:
safe.withTimeout— timeout control for async operationssafe.retry— retry logic for unstable operations
📦 Installation
# npm
npm install safe-await-lib
# yarn
yarn add safe-await-lib
# pnpm
pnpm add safe-await-lib⚡ Basic Usage
import safe from 'safe-await-lib';
async function fetchData() {
return 'Hello World';
}
// Using a function
const [err, data] = await safe(() => fetchData());
if (err) {
console.error(err.message, err.code);
} else {
console.log(data); // "Hello World"
}
// Using a direct promise
const [err2, result] = await safe(Promise.resolve(42));
// Using a synchronous value
const [err3, value] = await safe(10);🛠️ API
safe(input)
safe<T>(input: Promise<T> | T | (() => T | Promise<T>))
→ Promise<[SafeError | null, T | null]>Behavior
- Never throws — always returns
[SafeError | null, T | null] - Normalizes any thrown or rejected value into a
SafeError - Supports promises, synchronous values, or functions returning a value or promise
Return
[null, result]on success[SafeError, null]on failure — useerr.codeto identify the error type
SafeError structure
interface SafeError {
message: string; // Human-readable message
code: string; // Standardized error code
cause?: unknown; // Original error or context
}🌱 Advanced Usage (v0.2.1)
⏱️ Timeout handling — safe.withTimeout
const [err, data] = await safe.withTimeout(fetchData(), 1000);
if (err?.code === 'TIMEOUT_ERROR') {
console.error('Operation timed out');
}Behavior
- Resolves with
[null, result]if completed within the timeout - Resolves with
[SafeError, null]if the operation throws or exceeds the timeout - Never throws — always returns
[SafeError | null, T | null] - Use
err?.code === 'TIMEOUT_ERROR'to detect timeout errors
🔁 Retry logic — safe.retry
const [err, data] = await safe.retry(
() => fetchData(),
{
retries: 3,
delayMs: 500,
onRetry: (error, attempt) => {
console.log(`Retry ${attempt} failed`, error);
}
}
);
if (err) {
console.error(err.code); // RETRY_FAILED
}Behavior
- Tries the operation up to
retriestimes - Optional delay between attempts
- Invokes
onRetryafter each failed attempt - Never throws — always returns
[SafeError | null, T | null] - Returns a
SafeErrorwith codeRETRY_FAILEDif all attempts fail - Use
err?.code === 'RETRY_FAILED'to detect a complete retry failure
✅ Available Today (v0.2.1)
safe()— core safe async executionsafe.withTimeout()— timeout controlsafe.retry()— retry mechanism
More utilities will be added incrementally according to the roadmap.
🧪 Development
# Install dependencies
npm install
# Development build (watch mode)
npm run dev
# Type checking
npm run typecheck
# Run tests
npm test
# Build for production
npm run build📊 Roadmap
| Version | Features | | ------: | ---------------------- | | v0.2.0 | withTimeout, retry ✅ | | v0.3.0 | all, allSettled | | v0.4.0 | withContext | | v0.5.0 | once | | v0.6.0 | strict | | v0.7.0 | map, unwrap | | v0.8.0 | mockSuccess, mockError | | v0.9.0 | debug |
📝 Contributing
Contributions are welcome.
- Fork the repository
- Create a feature branch
- Add tests for your changes
- Ensure
npm testpasses - Submit a pull request
Please respect the existing TypeScript typings and error model.
❓ FAQ
Why return a tuple instead of throwing?
It enforces explicit error handling and removes runtime surprises.
Can I use this in browser, Node.js, or other JS environments?
Yes. SAFE-AWAIT-LIB is runtime-agnostic and fully compatible.
Is this production-ready?
Yes. The core API is stable and versioned.
📖 License
ISC License © Chelohub Inc.
