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 examples/ 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 examples/order-processing-worker
# Start the worker
pnpm dev
# In another terminal, run the client
cd examples/order-processing-client
pnpm devExample Structure
Each example follows this structure:
examples/
├── 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.