Documentation Index
Fetch the complete documentation index at: https://docs.wyrly.dev/llms.txt
Use this file to discover all available pages before exploring further.
This guide shows the smallest useful Wyrly setup: a typed port, a concrete implementation, a use
case, and a request-like scope.
Create a token
Use tokens to keep interface-based dependencies type-safe at runtime.
import { createContainer, Injectable, token } from "@wyrly/core";
interface User {
id: string;
}
interface UserRepository {
findById(id: string): Promise<User | null>;
}
const UserRepositoryToken = token<UserRepository>("UserRepository");
Define a use case
@Injectable declares dependencies explicitly. Wyrly does not read constructor parameter types at
runtime.
@Injectable({
deps: [UserRepositoryToken],
lifetime: "scoped",
})
class GetUserUseCase {
constructor(private readonly users: UserRepository) {}
execute(id: string) {
return this.users.findById(id);
}
}
Register providers
Register concrete implementations at the composition root.
class InMemoryUserRepository implements UserRepository {
async findById(id: string): Promise<User | null> {
return { id };
}
}
const container = createContainer();
container.register(UserRepositoryToken, {
useClass: InMemoryUserRepository,
lifetime: "scoped",
});
container.register(GetUserUseCase);
Resolve from a scope
Create a scope for request-level work and dispose it when the request finishes.
const scope = container.createScope();
try {
const usecase = scope.resolve(GetUserUseCase);
const user = await usecase.execute("user-1");
console.log(user);
} finally {
await scope.dispose();
}
Validate the graph
Run validation in tests or CI to catch missing providers and lifetime problems early.
const result = container.validate();
if (!result.ok) {
throw new Error(result.issues.map((issue) => issue.message).join("\n"));
}
Next steps