Core API
safe.allSettled
Runs multiple safe-wrapped async operations in parallel and returns all individual results as named SafeResult entries. Never fails at the group level.
Signature
safe.allSettled<T extends Record<string, Promise<SafeResult<any, any>>>>(
promises: T
): Promise<{ [K in keyof T]: Awaited<T[K]> }>
Accepts an object map of Promise<SafeResult> entries. Always returns an object where each key maps to its individual SafeResult — there is no group-level error wrapper.
Basic usage
const results = await safe.allSettled({
user: safe.async(() => fetchUser(userId)),
posts: safe.async(() => fetchPosts(userId)),
})
if (results.user.ok) {
console.log(results.user.value) // User
}
if (!results.posts.ok) {
console.error(results.posts.error) // Error
}
Mixed success and failure
Unlike safe.all, failures don't affect other results. Each operation is independent.
const results = await safe.allSettled({
config: safe.async(() => loadConfig()),
user: safe.async(() => fetchUser(userId)),
analytics: safe.async(() => trackEvent('page_view')),
})
// analytics failed, but config and user may have succeeded
if (!results.analytics.ok) {
console.warn('Analytics failed:', results.analytics.error)
}
if (results.config.ok) {
applyConfig(results.config.value)
}
Tagged result properties
Each result is a full SafeResult with tagged properties (.ok, .value, .error) and tuple access ([0], [1]):
const results = await safe.allSettled({
val: safe.async(() => Promise.resolve(42)),
})
// Tagged property access
results.val.ok // true
results.val.value // 42
results.val.error // null
// Tuple destructuring
const [value, error] = results.val // [42, null]
With per-operation error mapping
Each operation can use its own parseError, hooks, and configuration:
const results = await safe.allSettled({
user: safe.async(
() => fetchUser(userId),
(e) => ({ code: 'USER_ERROR', message: String(e) })
),
posts: safe.async(
() => fetchPosts(userId),
(e) => ({ code: 'POSTS_ERROR', message: String(e) })
),
})
if (!results.user.ok) {
console.error(results.user.error.code) // 'USER_ERROR'
}
With createSafe
On a createSafe instance, allSettled accepts raw async functions instead of pre-wrapped Promise<SafeResult> entries. The instance applies its own parseError, hooks, retry, and timeout to each function automatically.
const appSafe = createSafe({
parseError: (e) => ({
code: 'ERR',
message: e instanceof Error ? e.message : 'Unknown',
}),
defaultError: { code: 'ERR', message: 'Unknown' },
})
const results = await appSafe.allSettled({
user: () => fetchUser(userId),
posts: () => fetchPosts(userId),
})
if (results.user.ok) {
console.log(results.user.value)
}
if (!results.posts.ok) {
console.error(results.posts.error.code) // typed as { code: string; message: string }
}
Standalone vs createSafe
The standalone safe.allSettled accepts Promise<SafeResult> entries (e.g., safe.async(() => ...)). The createSafe instance allSettled accepts raw async functions and wraps them automatically with the instance's configuration.
Empty input
Passing an empty object returns {}:
const results = await safe.allSettled({})
// results = {}
When to use safe.allSettled vs safe.all
Use safe.allSettled when you want to handle each result independently (e.g., loading optional widgets where some can fail gracefully). Use safe.all when all operations must succeed for the result to be useful.