Examples
Learn by example! Explore complete working examples that demonstrate temporal-contract in action.
Architecture Overview
Available Examples
Order Processing Example
A complete e-commerce order processing workflow using Result/Future pattern for explicit error handling.
Features:
- Type-safe error handling with
Result<T, E> - Order validation
- Payment processing
- Inventory management
- Email notifications
- Clean Architecture structure
Best for: Understanding temporal-contract with modern, type-safe error handling.
Running the Examples
All examples are located in the samples/ directory of the repository.
Prerequisites
Clone the repository:
bashgit clone https://github.com/btravers/temporal-contract.git cd temporal-contractInstall dependencies:
bashpnpm installBuild the packages:
bashpnpm buildStart Temporal server:
bashtemporal server start-dev
Running an Example
Each example has its own directory with a README:
# Navigate to an example
cd samples/order-processing-worker
# Start the worker
pnpm dev
# In another terminal, run the client
cd samples/order-processing-client
pnpm devExample Structure
Each example follows this structure:
samples/
├── example-contract/ # Shared contract package
│ ├── src/
│ │ └── contract.ts # Contract definition
│ └── package.json
├── example-worker/ # Worker implementation
│ ├── src/
│ │ ├── application/
│ │ │ ├── activities.ts # Activity implementations
│ │ │ ├── workflows.ts # Workflow implementations
│ │ │ └── worker.ts # Worker setup
│ │ ├── domain/ # Business logic / use cases
│ │ └── infrastructure/ # External adapters
│ └── package.json
└── example-client/ # Client application
├── src/
│ └── client.ts # Example client
└── package.jsonCode Snippets
Contract Definition
All examples start with a contract:
import { defineContract } from '@temporal-contract/contract';
import { z } from 'zod';
export const orderContract = defineContract({
taskQueue: 'orders',
activities: {
sendEmail: {
input: z.object({
to: z.string().email(),
subject: z.string(),
body: z.string()
}),
output: z.object({ sent: z.boolean() })
}
},
workflows: {
processOrder: {
input: z.object({
orderId: z.string(),
customerId: z.string(),
items: z.array(z.object({
sku: z.string(),
quantity: z.number().positive()
}))
}),
output: z.object({
success: z.boolean(),
transactionId: z.string().optional()
}),
activities: {
validateInventory: {
input: z.object({ items: z.array(z.any()) }),
output: z.object({ available: z.boolean() })
},
processPayment: {
input: z.object({
customerId: z.string(),
amount: z.number()
}),
output: z.object({
transactionId: z.string(),
success: z.boolean()
})
}
}
}
}
});Activity Implementation
Clean, typed activity implementations with Result/Future pattern:
import { declareActivitiesHandler, ActivityError } from '@temporal-contract/worker/activity';
import { Future, Result } from '@temporal-contract/boxed';
import { orderContract } from '../contracts/order.contract';
import { emailService } from '../infrastructure/email.service';
import { paymentService } from '../infrastructure/payment.service';
export const activities = declareActivitiesHandler({
contract: orderContract,
activities: {
sendEmail: ({ to, subject, body }) => {
return Future.make(async (resolve) => {
try {
await emailService.send({ to, subject, body });
resolve(Result.Ok({ sent: true }));
} catch (error) {
resolve(Result.Error(
new ActivityError('EMAIL_FAILED', 'Failed to send email', error)
));
}
});
},
validateInventory: ({ items }) => {
return Future.make(async (resolve) => {
try {
const available = await inventoryService.checkAvailability(items);
resolve(Result.Ok({ available }));
} catch (error) {
resolve(Result.Error(
new ActivityError('INVENTORY_CHECK_FAILED', 'Failed to check inventory', error)
));
}
});
},
processPayment: ({ customerId, amount }) => {
return Future.make(async (resolve) => {
try {
const result = await paymentService.charge(customerId, amount);
resolve(Result.Ok({
transactionId: result.id,
success: result.status === 'success'
}));
} catch (error) {
resolve(Result.Error(
new ActivityError('PAYMENT_FAILED', 'Failed to process payment', error)
));
}
});
}
}
});Workflow Implementation
Type-safe workflow with full autocomplete:
import { declareWorkflow } from '@temporal-contract/worker/workflow';
import { orderContract } from '../contracts/order.contract';
export const processOrder = declareWorkflow({
workflowName: 'processOrder',
contract: orderContract,
implementation: async (context, { orderId, customerId, items }) => {
// Validate inventory
const inventory = await context.activities.validateInventory({ items });
if (!inventory.available) {
await context.activities.sendEmail({
to: customerId,
subject: 'Order Failed',
body: 'Items not available'
});
return { success: false };
}
// Calculate total
const total = items.reduce((sum, item) => sum + item.quantity * 100, 0);
// Process payment
const payment = await context.activities.processPayment({
customerId,
amount: total
});
if (!payment.success) {
await context.activities.sendEmail({
to: customerId,
subject: 'Payment Failed',
body: 'Unable to process payment'
});
return { success: false };
}
// Send confirmation
await context.activities.sendEmail({
to: customerId,
subject: 'Order Confirmed',
body: `Order ${orderId} confirmed. Transaction: ${payment.transactionId}`
});
return {
success: true,
transactionId: payment.transactionId
};
}
});Learn More
- 📚 Read the Getting Started Guide
- 🔍 Understand Core Concepts
- 📖 Browse the API Reference
Contributing Examples
Have an interesting use case? We welcome example contributions! See our Contributing Guide.