@temporal-contract/boxed
v0.0.7
Published
Custom Future and Result implementation for Temporal workflows
Maintainers
Readme
@temporal-contract/boxed
Custom Future and Result implementation for Temporal workflows, providing type-safe error handling and async operations compatible with Temporal's deterministic execution model.
Why This Package?
The @swan-io/boxed library doesn't work properly with Temporal workflows due to Temporal's deterministic execution requirements. This package provides a Temporal-compatible implementation of the Result/Future patterns with an identical API surface.
Installation
pnpm add @temporal-contract/boxedBasic Usage
Result Pattern
The Result type provides explicit error handling without exceptions:
import { Result } from '@temporal-contract/boxed';
// Create results
const success = Result.Ok(42);
const failure = Result.Error("Something went wrong");
// Pattern matching
const value = success.match({
Ok: (value) => value * 2,
Error: (error) => 0,
});
// Transformations
const doubled = success.map(x => x * 2);
const recovered = failure.mapError(e => `Error: ${e}`);Future Pattern
The Future type wraps Promises with Result-based error handling:
import { Future, Result } from '@temporal-contract/boxed';
// Create futures
const future = Future.value(42);
const fromPromise = Future.fromPromise(fetch('/api/data'));
// Transform values
const doubled = future.map(x => x * 2);
const chained = future.flatMap(x => Future.value(x * 2));
// Work with Results in Futures
const result = await Future.fromPromise(asyncOperation());
result.match({
Ok: (value) => console.log('Success:', value),
Error: (error) => console.error('Failed:', error),
});Usage in Temporal Workflows
Activities
Activities return Future<Result<T, ActivityError>> for explicit error handling:
import { Future, Result } from '@temporal-contract/boxed';
import { declareActivitiesHandler } from '@temporal-contract/worker/activity';
export const activities = declareActivitiesHandler(contract, {
processPayment: async (args) => {
return Future.fromPromise(paymentService.charge(args))
.mapError(error => new ActivityError('PAYMENT_FAILED', error.message));
},
});Workflows
import { Result } from '@temporal-contract/boxed';
export const workflow = declareWorkflow(contract, (ctx) => ({
async execute(input) {
const payment = await ctx.activities.processPayment(input);
if (payment.isError()) {
return Result.Error({
type: 'PAYMENT_FAILED',
error: payment.error
});
}
return Result.Ok({ success: true });
},
}));Interoperability with @swan-io/boxed
This package provides bi-directional interoperability with @swan-io/boxed for smooth migration and compatibility.
Default Compatibility (Recommended)
Our Result and Future types implement the same interface as @swan-io/boxed, making them compatible by default:
import { Result, Future } from '@temporal-contract/boxed';
// Your types are already compatible with @swan-io/boxed consumers
const result = Result.Ok(42);
const future = Future.value(42);
// These work with any library expecting @swan-io/boxed types
function processSwanResult(r: SwanResult<number, string>) {
return r.match({
Ok: (v) => v * 2,
Error: () => 0,
});
}
processSwanResult(result); // ✅ Works directlyExplicit Converters
For cases where you need explicit conversion, use the interop module:
import { Result, Future } from '@temporal-contract/boxed';
import {
fromSwanResult,
toSwanResult,
fromSwanFuture,
toSwanFuture,
fromSwanFutureResult,
toSwanFutureResult,
} from '@temporal-contract/boxed/interop';
// Convert from @swan-io/boxed to @temporal-contract/boxed
const swanResult = externalLibrary.getSomething();
const temporalResult = fromSwanResult(swanResult);
// Convert from @temporal-contract/boxed to @swan-io/boxed
const temporalResult = Result.Ok(42);
const swanCompatible = toSwanResult(temporalResult);
externalLibrary.processSomething(swanCompatible);Interop API Reference
Result Converters:
fromSwanResult<T, E>(swanResult)- Convert @swan-io/boxed Result to @temporal-contract/boxed ResulttoSwanResult<T, E>(temporalResult)- Convert @temporal-contract/boxed Result to @swan-io/boxed compatible Result
Future Converters:
fromSwanFuture<T>(swanFuture)- Convert @swan-io/boxed Future to @temporal-contract/boxed FuturetoSwanFuture<T>(temporalFuture)- Convert @temporal-contract/boxed Future to @swan-io/boxed compatible Future
Future Converters:
fromSwanFutureResult<T, E>(swanFutureResult)- Convert @swan-io/boxed Future to @temporal-contract/boxed FuturetoSwanFutureResult<T, E>(temporalFutureResult)- Convert @temporal-contract/boxed Future to @swan-io/boxed compatible Future
Note:
@swan-io/boxedis an optional peer dependency and only needed if you're explicitly converting between implementations.
API Reference
Result<T, E>
Result.Ok<T>(value: T)- Create a successful resultResult.Error<E>(error: E)- Create an error resultisOk()- Check if result is OkisError()- Check if result is Errormatch<R>(pattern)- Pattern match on resultmap<U>(fn)- Transform Ok valuemapError<F>(fn)- Transform Error valueflatMap<U>(fn)- Chain resultsgetOr(defaultValue)- Get value or defaulttoOption()- Convert to Option type
Future<T>
Future.value<T>(value)- Create resolved futureFuture.fromPromise<T>(promise)- Create future from promise (returnsFuture<Result<T, Error>>)Future.make<T>(executor)- Create future from executor functionFuture.reject<T>(error)- Create rejected futureFuture.all(futures)- Combine multiple futuresFuture.race(futures)- Race multiple futuresmap<U>(fn)- Transform future valueflatMap<U>(fn)- Chain futuresmapOk<U>(fn)- Transform Ok value in FuturemapError<F>(fn)- Transform Error value in Futuretap(fn)- Execute side effecttapOk(fn)- Execute side effect on OktapError(fn)- Execute side effect on Error
TypeScript Support
This package is written in TypeScript and provides full type safety:
// Type inference works automatically
const result = Result.Ok(42); // Result<number, never>
const error = Result.Error("failed"); // Result<never, string>
// Generic types can be specified explicitly
const typed: Result<number, string> = Result.Ok(42);Testing
cd packages/boxed
pnpm testAll tests verify:
- Result operations and transformations
- Future operations and async behavior
- Interoperability with @swan-io/boxed
- Type safety and compatibility
Documentation
📖 Read the full documentation →
License
MIT
