Repo
Repos (repositories) handle data access and external adapters. They’re the only layer that should communicate with databases, APIs, or other external services.
Example
Section titled “Example”class PostRepo extends Vla.Repo { db = this.inject(Database)
// Memoized queries findById = this.memo((id: string) => { return this.db.posts.find({ id }) })
findByAuthor = this.memo((authorId: string) => { return this.db.posts.findMany({ authorId }) })
// Write operations (not memoized) async create(data: PostData) { const post = await this.db.posts.create({ data })
// Prime the cache this.findById.prime(post.id).value(post)
return post }
async update(id: string, data: Partial<PostData>) { const post = await this.db.posts.update({ where: { id }, data })
// Bust the cache this.findById.bust(id)
return post }}When to Use
Section titled “When to Use”- Database queries
- External API calls
- File system access
Reference
Section titled “Reference”invoke - Shared within a request.
Properties
Section titled “Properties”static readonly scope = 'invoke'Methods
Section titled “Methods”Repos inherit both inject() and memo() methods.
memo()
Section titled “memo()”memo<Args extends unknown[], R>( fn: (...args: Args) => R): Memoized<Args, R>Creates a memoized method that caches results per request.
class UserRepo extends Vla.Repo { db = this.inject(Database)
findById = this.memo((id: string) => { return this.db.users.find({ id }) })}
// Multiple calls with same ID = only one database queryawait repo.findById('1') // Executes queryawait repo.findById('1') // Returns cached resultSee Memoization guide for details.
Characteristics
Section titled “Characteristics”- Scope:
invoke(shared within a request) - Purpose: Data access, external API calls
- Can inject: Resources, Contexts
- Best practices: Memoize reads, not writes; no business logic