@roboto-studio/utils
v0.1.0
Published
Utility functions for Roboto applications
Downloads
322
Maintainers
Readme
@roboto/utils
A comprehensive collection of utility functions for Roboto applications. Built with TypeScript and designed for reliability, performance, and developer experience.
Installation
npm install @roboto/utils
# or
pnpm add @roboto/utils
# or
yarn add @roboto/utilsFeatures
- 🔄 Retry Logic: Robust retry mechanism with exponential backoff
- 🛡️ Safe Operations: Try-catch utilities that never throw
- ⚡ Batch Processing: Efficient concurrent processing with rate limiting
- 🔗 URL Slugification: Convert strings to URL-safe slugs
- 📝 TypeScript First: Full type safety and IntelliSense support
- 🧪 Well Tested: Comprehensive test coverage (>80%)
- 🚀 Zero Dependencies: Lightweight and fast
Quick Start
import {
retryPromise,
tryCatch,
processBatch,
slugify
} from '@roboto/utils'
// Retry failed API calls
const data = await retryPromise(() => fetch('/api/data'))
// Safe JSON parsing
const result = tryCatch(() => JSON.parse(jsonString))
// Process items in batches
const results = await processBatch(urls, async (url) => fetch(url))
// Create URL-safe slugs
const slug = slugify('My Blog Post Title') // 'my-blog-post-title'API Reference
Retry Operations
retryPromise<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>
Retries a promise-returning function with exponential backoff.
import { retryPromise } from '@roboto/utils'
// Basic usage
const result = await retryPromise(() => fetch('/api/data'))
// With custom options
const result = await retryPromise(
() => apiCall(),
{
maxAttempts: 5,
initialDelay: 2000,
maxDelay: 30000,
backoffMultiplier: 2,
shouldRetry: (error) => error.status >= 500,
onRetry: (error, attempt) => console.log(`Retry ${attempt}:`, error)
}
)Options:
maxAttempts(default: 3): Maximum number of retry attemptsinitialDelay(default: 1000): Initial delay between retries in millisecondsmaxDelay(default: 30000): Maximum delay between retries in millisecondsbackoffMultiplier(default: 2): Multiplier for exponential backoffshouldRetry: Function to determine if an error should trigger a retryonRetry: Callback function called before each retry attempt
Error Handling:
- Throws
RetryExhaustedErrorwhen all attempts are exhausted - Automatically retries network errors and 5xx HTTP status codes
- Preserves original error information
Safe Operations
tryCatch<T>(fn: () => T): TryCatchResult<T>
Safely executes a synchronous function and returns a result object instead of throwing.
import { tryCatch, isSuccess, unwrap } from '@roboto/utils'
// Basic usage
const result = tryCatch(() => JSON.parse(jsonString))
if (result.success) {
console.log('Parsed data:', result.data)
} else {
console.error('Parse error:', result.error.message)
}
// Using type guards
if (isSuccess(result)) {
// TypeScript knows result.data is available
console.log(result.data)
}
// Unwrap with default value
const data = unwrapOr(result, {})tryCatchAsync<T>(fn: () => Promise<T>): Promise<TryCatchResult<T>>
Safely executes an asynchronous function.
import { tryCatchAsync } from '@roboto/utils'
const result = await tryCatchAsync(() =>
fetch('/api/data').then(res => res.json())
)
if (result.success) {
console.log('API data:', result.data)
} else {
console.error('API error:', result.error)
}Utility Functions:
isSuccess(result): Type guard for successful resultsisError(result): Type guard for error resultsunwrap(result): Returns data or throws errorunwrapOr(result, defaultValue): Returns data or default valueunwrapOrElse(result, defaultFn): Returns data or computed default value
Batch Processing
processBatch<T, R>(items: T[], processor: (item: T, index: number) => Promise<R>, options?: BatchProcessOptions<T>): Promise<BatchResult<T>[]>
Processes an array of items in batches with controlled concurrency.
import { processBatch, getSuccessfulResults, getBatchStats } from '@roboto/utils'
// Basic usage
const results = await processBatch(
urls,
async (url) => fetch(url).then(res => res.json())
)
// With custom options
const results = await processBatch(
items,
async (item, index) => processItem(item),
{
concurrency: 3,
batchDelay: 1000,
onItemError: (error, item, index) => {
console.error(`Item ${index} failed:`, error)
},
onBatchComplete: (results, batchIndex) => {
console.log(`Batch ${batchIndex} completed`)
}
}
)
// Process results
const successful = getSuccessfulResults(results)
const failed = getFailedResults(results)
const stats = getBatchStats(results)
console.log(`Success rate: ${stats.successRate}%`)Options:
concurrency(default: 5): Maximum number of items to process concurrentlybatchDelay(default: 0): Delay between batches in millisecondsonItemError: Function to handle individual item processing errorsonBatchComplete: Function called when a batch completes
Utility Functions:
getSuccessfulResults(results): Filter successful resultsgetFailedResults(results): Filter failed resultsgetBatchStats(results): Get processing statistics
Slugification
slugify(input: string, options?: SlugifyOptions): string
Converts a string into a URL-safe slug.
import { slugify, createUniqueSlug, isValidSlug } from '@roboto/utils'
// Basic usage
slugify('Hello World!') // 'hello-world'
slugify('My Blog Post Title') // 'my-blog-post-title'
// With custom options
slugify('My Blog Post', {
separator: '_',
maxLength: 20,
lowercase: false
}) // 'My_Blog_Post'
// Handle accented characters
slugify('Café & Restaurant') // 'cafe-and-restaurant'
// Custom replacements
slugify('Price: $99.99', {
replacements: { '$': 'USD-' }
}) // 'price-usd-99-dot-99'createUniqueSlug(input: string, existingSlugs: string[], options?: SlugifyOptions): string
Creates a unique slug by appending a number if the slug already exists.
const existingSlugs = ['my-post', 'my-post-1', 'my-post-2']
const uniqueSlug = createUniqueSlug('My Post', existingSlugs)
console.log(uniqueSlug) // 'my-post-3'isValidSlug(slug: string, options?: SlugifyOptions): boolean
Validates if a string is a valid slug according to the given options.
isValidSlug('hello-world') // true
isValidSlug('Hello World!') // false
isValidSlug('hello_world', { separator: '_' }) // trueOptions:
separator(default: '-'): Character to use as separatorlowercase(default: true): Whether to convert to lowercaseremoveSpecialChars(default: true): Whether to remove special charactersmaxLength(default: 100): Maximum length of the resulting slugreplacements: Custom character replacements
Error Handling
All utilities follow consistent error handling patterns:
- Never throw unexpected errors - Use result objects or explicit error types
- Preserve error information - Original errors are always accessible
- Provide helpful error messages - Clear indication of what went wrong
- Type-safe error handling - Full TypeScript support for error cases
Performance Considerations
- Batch Processing: Automatically manages concurrency to prevent overwhelming systems
- Memory Efficient: Processes items in chunks to handle large datasets
- Zero Dependencies: No external dependencies for minimal bundle size
- Tree Shakeable: Import only what you need
Examples
Real-world API Client
import { retryPromise, tryCatch, processBatch } from '@roboto/utils'
class ApiClient {
async fetchUser(id: string) {
return retryPromise(
() => fetch(`/api/users/${id}`).then(res => res.json()),
{
maxAttempts: 3,
shouldRetry: (error) => error.status >= 500
}
)
}
async fetchMultipleUsers(ids: string[]) {
const results = await processBatch(
ids,
(id) => this.fetchUser(id),
{ concurrency: 5 }
)
return {
users: getSuccessfulResults(results).map(r => r.data),
errors: getFailedResults(results),
stats: getBatchStats(results)
}
}
parseConfig(configString: string) {
const result = tryCatch(() => JSON.parse(configString))
return unwrapOr(result, { default: 'config' })
}
}Content Management System
import { slugify, createUniqueSlug } from '@roboto/utils'
class ContentManager {
private existingSlugs: string[] = []
createPost(title: string, content: string) {
const slug = createUniqueSlug(title, this.existingSlugs)
this.existingSlugs.push(slug)
return {
slug,
title,
content,
url: `/posts/${slug}`
}
}
validateSlug(slug: string): boolean {
return isValidSlug(slug) && !this.existingSlugs.includes(slug)
}
}Development
# Install dependencies
pnpm install
# Run tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Build the package
pnpm build
# Generate coverage report
pnpm test:coverageContributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Write tests for your changes
- Ensure all tests pass (
pnpm test) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT © Roboto Team
Changelog
See CHANGELOG.md for details about changes in each version.
