bhofstaetter

payload repository

by bhofstaetter
Testing & developer experience
v3
>=3
MIT

Overview

Summary generated from the README

Provides base classes that wrap Payload's Local API in a repository pattern for collections and globals. You extend them to hold domain-specific operations with type safety from your generated Config types. Optional transformers modify data, where clauses and options before they reach Payload. It is a library used in server code rather than a config plugin and supports Payload 3 and later.

Features

  • CollectionOperations base class for collection-specific operations
  • GlobalOperations base class for globals
  • Typed fields, select and return values from the generated Config type
  • Transformers that modify data, where and options per operation
  • mergeTransformers to chain transformers from layered repositories
  • Async transformer support across all repository operations

Use cases

  • Encapsulate data access logic for a collection in a reusable class instead of scattered Local API calls
  • Automatically inject a tenant ID into queries and writes for tenant-scoped data
  • Apply a default locale to every find call through a shared transformer

From the author

Opinionated repository and operations object wrapper around Payload's Local API.

Installation

npm i payload-repository

0

Stars

0

Forks

0

Open Issues

7 months ago

Last Updated

0

Weekly Downloads

v1.1.4

npm Version

39.2 KB

Unpacked Size

0

Dependencies

GitHub stars

Trends appear after 7 days of data. Daily snapshots have not started yet.

npm weekly downloads

Trends appear after 7 days of data. Daily snapshots have not started yet.

Each point is npm's rolling 7-day download count.

Health Score

43/100Fair

Composite score based on GitHub activity, stars, npm downloads, publish recency, dependency count, and package size.

Badge for your README

Payload Directory health badge
Markdown
[![Payload Directory](https://payloaddirectory.dev/badge/1169584752-root.svg)](https://payloaddirectory.dev/plugins/1169584752-root)
HTML
<a href="https://payloaddirectory.dev/plugins/1169584752-root"><img src="https://payloaddirectory.dev/badge/1169584752-root.svg" alt="Payload Directory"></a>
Updated Mar 15, 2026Created Feb 28, 2026Published Jun 29, 2026

README

Payload Repository and Operations

Opinionated repository and operations object wrapper around Payload's Local API.

Installation

npm install payload-repository

Usage

Pass your generated Payload Config type as the first type argument to get full type safety on fields, select, and return types.

CollectionOperations

Extend CollectionOperations to encapsulate domain-specific operations logic for a collection:

import type {BasePayload} from 'payload';
import type {Config} from '@/payload-types';
import {CollectionOperations} from 'payload-repository';

class PostsOperations extends CollectionOperations<Config, 'posts'> {
    constructor(payload: BasePayload) {
        super(payload, 'posts');
    }

    create(title: string) {
        return this.repository.create({title});
    }

    findAll() {
        return this.repository.find({});
    }

    findById(id: number) {
        return this.repository.findById(id);
    }

    findPublished() {
        return this.repository.find({status: {equals: 'published'}});
    }

    publish(id: number) {
        return this.repository.updateById(id, {status: 'published'});
    }

    deleteById(id: number) {
        return this.repository.deleteById(id);
    }
}

// Usage
const postsOperations = new PostsOperations(payload);

const post = await postsOperations.create('Hello World');
const published = await postsOperations.findPublished();
await postsOperations.publish(post.id);

GlobalOperations

Extend GlobalOperations to encapsulate domain-specific operations logic for a global:

import type {BasePayload} from 'payload';
import type {Config} from '@/payload-types';
import {GlobalOperations} from 'payload-repository';

class SettingsOperations extends GlobalOperations<Config, 'settings'> {
    constructor(payload: BasePayload) {
        super(payload, 'settings');
    }

    get() {
        return this.repository.find();
    }

    setSiteTitle(title: string) {
        return this.repository.update({siteTitle: title});
    }
}

// Usage
const settingsOperations = new SettingsOperations(payload);

const settings = await settingsOperations.get();
await settingsOperations.setSiteTitle('My Site');

Transformers

Transformers are optional middleware functions that intercept and modify arguments before they reach the Payload API. They can transform data, where clauses, and options on a per-operation basis.

Pass transformers as the third argument to CollectionOperations or GlobalOperations:

import type {BasePayload} from 'payload';
import type {Config} from '@/payload-types';
import {CollectionOperations} from 'payload-repository';
import type {CollectionTransformers} from 'payload-repository/internal/types';

const tenantTransformers = (tenantId: number): CollectionTransformers<Config, 'posts'> => ({
    create: {
        data: data => ({...data, tenant: tenantId}),
    },
    find: {
        where: where => ({...where, tenant: {equals: tenantId}}),
    },
    update: {
        data: data => ({...data, tenant: tenantId}),
        where: where => ({...where, tenant: {equals: tenantId}}),
    },
    delete: {
        where: where => ({...where, tenant: {equals: tenantId}}),
    },
});

class PostsOperations extends CollectionOperations<Config, 'posts'> {
    constructor(payload: BasePayload, tenantId: number) {
        super(payload, 'posts', tenantTransformers(tenantId));
    }

    create(title: string) {
        return this.repository.create({title});
    }

    findAll() {
        return this.repository.find({});
    }
}

// Usage
const tenantPosts = new PostsOperations(payload, 42);

// tenant is automatically injected into the data
await tenantPosts.create('Hello World');

// tenant where clause is automatically applied
const posts = await tenantPosts.findAll();

Transformers support async functions and are available for all repository operations.

Merging Transformers

When building layered repositories where each layer contributes its own transformers, use mergeTransformers to combine them. Overlapping transformers on the same operation and argument are chained sequentially:

import type {BasePayload} from 'payload';
import type {Config} from '@/payload-types';
import {CollectionOperations, mergeTransformers} from 'payload-repository';
import type {CollectionTransformers} from 'payload-repository/internal/types';

const tenantTransformers = (tenantId: number): CollectionTransformers<Config, 'posts'> => ({
    find: {
        where: where => ({...where, tenant: {equals: tenantId}}),
    },
});

const localeTransformers = (locale: string): CollectionTransformers<Config, 'posts'> => ({
    find: {
        options: options => ({...options, locale}),
    },
});

class PostsOperations extends CollectionOperations<Config, 'posts'> {
    constructor(payload: BasePayload, tenantId: number, locale: string) {
        super(payload, 'posts', mergeTransformers(
            tenantTransformers(tenantId),
            localeTransformers(locale),
        ));
    }

    findAll() {
        return this.repository.find({});
    }
}

mergeTransformers works with both CollectionTransformers and GlobalTransformers. When multiple transformer objects define the same leaf (e.g. both define find.where), they are chained in order — the second transformer receives the output of the first.

License

MIT

Todo

  • Github Actions

Similar plugins