npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@croco/repository-core

v0.0.2

Published

TypeScript-safe repository pattern interfaces for Croco Framework.

Readme

@croco/repository-core

TypeScript-safe repository pattern interfaces for Croco Framework.

Overview

This package provides type-safe repository interfaces for data access layers. It follows the Repository pattern from Domain-Driven Design (DDD), separating data access logic from business logic.

Installation

pnpm add @croco/repository-core

Core Interfaces

Repository<T, ID>

Unified repository interface combining read and write operations.

import type { Repository } from "@croco/repository-core";

interface User {
  id: string;
  name: string;
  email: string;
}

class UserRepository implements Repository<User, string> {
  // Read operations
  async findById(id: string): Promise<User | null> {
    // Fetch from database
  }

  async findByIds(ids: readonly string[]): Promise<ReadonlyArray<User>> {
    // Batch fetch
  }

  // Write operations
  async save(entity: User): Promise<User> {
    // Insert or update
  }

  async deleteById(id: string): Promise<void> {
    // Delete from database
  }
}

ReadRepository<T, ID>

Read-only operations for querying entities.

import type { ReadRepository } from "@croco/repository-core";

class UserQueryService implements ReadRepository<User, string> {
  async findById(id: string): Promise<User | null> {
    /* ... */
  }
  async findByIds(ids: readonly string[]): Promise<ReadonlyArray<User>> {
    /* ... */
  }
}

WriteRepository<T, ID>

Write-only operations for persisting entities.

import type { WriteRepository } from "@croco/repository-core";

class UserCommandService implements WriteRepository<User, string> {
  async save(entity: User): Promise<User> {
    /* ... */
  }
  async deleteById(id: string): Promise<void> {
    /* ... */
  }
}

Batch Loading

The @BatchLoad decorator automatically batches multiple findById calls into a single findByIds call, preventing N+1 queries.

import { BatchLoad } from "@croco/repository-core";
import { BATCH_LOADER_FACTORY_TOKEN, IBatchLoaderFactory } from "@croco/repository-core";
import { Container } from "@croco/framework-context";

// 1. Register the batch loader factory
Container.set(BATCH_LOADER_FACTORY_TOKEN, myBatchLoaderFactory);

// 2. Apply the decorator to repository methods
class UserRepository {
  @BatchLoad({ by: "id" })
  async findById(id: string): Promise<User | null> {
    // Single record fetch
  }

  async findByIds(ids: readonly string[]): Promise<ReadonlyArray<User>> {
    // Batch fetch - called automatically when multiple findByIds are triggered
  }
}

// 3. Usage - automatically batched
const user1 = await userRepository.findById("1");
const user2 = await userRepository.findById("2");
const user3 = await userRepository.findById("1"); // Cached, no query

// Result: Only 1 batch query for ['1', '2'] instead of 3 separate queries

Batch Load Options

interface BatchLoadOptions {
  /**
   * The field name to use as the key for mapping results.
   * Required to ensure the order of results matches the order of keys.
   */
  by: string;

  /**
   * The name of the DataLoader.
   * Defaults to `${ClassName}:${methodName}` if not provided.
   */
  name?: string;
}

Type Safety

All interfaces are fully typed with generics:

  • T: The entity type (e.g., User, Order)
  • ID: The ID type (e.g., string, number, or custom ID class)
// String IDs (common)
class UserRepository implements Repository<User, string> {}

// Number IDs
class PostRepository implements Repository<Post, number> {}

// Custom ID class
class UserId {
  constructor(public value: string) {}
}
class TenantRepository implements Repository<Tenant, UserId> {}

Immutability

Repository methods return immutable types:

  • findByIds returns ReadonlyArray<T> (not T[])
  • This prevents accidental mutation of cached entities

Dependency Injection

Use with Croco's DI container:

import { Component } from "@croco/framework-context";
import type { Repository } from "@croco/repository-core";

@Component()
class OrderService {
  constructor(private readonly orderRepository: Repository<Order, string>) {}

  async getOrder(id: string): Promise<Order | null> {
    return this.orderRepository.findById(id);
  }
}

Architecture Notes

Interface Layer

This package is an interface layer only. It does NOT contain:

  • Database-specific implementations (Drizzle, Prisma, TypeORM)
  • ORM-specific types or imports
  • Concrete data access logic

Implementation Pattern

Implementations should be in separate packages:

  • @croco/repository-drizzle - Drizzle ORM implementation
  • @croco/repository-prisma - Prisma implementation
  • @croco/repository-typeorm - TypeORM implementation

Example implementation structure:

// packages/repository-drizzle/src/AbstractDrizzleRepository.ts
import type { Repository } from "@croco/repository-core";

export abstract class AbstractDrizzleRepository<T, ID> implements Repository<T, ID> {
  // Drizzle-specific implementation
}

Testing

# Run tests
pnpm test --filter=@croco/repository-core

# Run with coverage
pnpm test --filter=@croco/repository-core --coverage

License

MIT