---
title: "API: Resources and relations"
description: "Public TypeScript declarations verified against the package export entries."
---

> Documentation Index
> Fetch the complete documentation index at: https://pupitre.rikology.com/llms.txt
> Use this file to discover all available pages before exploring further.

# API: Resources and relations

This reference is generated before development, checking and building from declarations reachable through the package's published entry points, following re-exports. Internal source-module exports are omitted. Types shown together share their source module; follow the source link for imports and implementation. Use the guides for examples and runtime behavior.

## src/builder/resource.ts

[Source](https://github.com/rikoriswandha/pupitre/blob/main/packages/pupitre/src/builder/resource.ts)

```ts
export type ModelConstructor = {
    new (...args: never[]): object;
    name: string;
    $columns?: readonly string[];
};

export type ResourceModel = ModelConstructor;

export type ResourceBuilder<M extends ResourceModel> = {
    slug(value: string): ResourceBuilder<M>;
    label(value: string): ResourceBuilder<M>;
    pluralLabel(value: string): ResourceBuilder<M>;
    icon(value: string): ResourceBuilder<M>;
    cluster(value: ClusterBuilder): ResourceBuilder<M>;
    navigation(value: {
        group?: string;
        sort?: number;
        badge?: (ctx: HttpContext) => unknown | Promise<unknown>;
    }): ResourceBuilder<M>;
    recordTitle(value: string): ResourceBuilder<M>;
    globallySearchable(value: readonly (ModelField<M> | `${string}.${string}`)[]): ResourceBuilder<M>;
    globalSearchDetails(value: (record: ModelInstance<M>) => string[]): ResourceBuilder<M>;
    policy(value: PolicyClass | (() => Promise<{
        default: PolicyClass;
    }>)): ResourceBuilder<M>;
    softDeletes(column?: string): ResourceBuilder<M>;
    scope(value: false | ((query: ModelQueryBuilderContract<LucidModel>, ctx: HttpContext) => void)): ResourceBuilder<M>;
    form(callback: (schema: FormSchema<Record<ModelField<M>, unknown>>) => {
        components: ComponentDefinition[];
    } | readonly SchemaComponent[]): ResourceBuilder<M>;
    table(callback: (table: TableSchema) => TableSchema): ResourceBuilder<M>;
    infolist(callback: (schema: FormSchema<Record<string, unknown>>) => {
        components?: ComponentDefinition[];
        entries?: ComponentDefinition[];
    } | readonly SchemaComponent[]): ResourceBuilder<M>;
    actions(value: ResourceActions): ResourceBuilder<M>;
    pages(value: Partial<Record<'list' | 'create' | 'edit' | 'view', PageBuilder>>): ResourceBuilder<M>;
    relations(value: readonly RelationManagerEntry[]): ResourceBuilder<M>;
    nested(value: readonly ResourceBuilder<ResourceModel>[]): ResourceBuilder<M>;
    parent(value: ResourceBuilder<ResourceModel> | ResourceModel, relation: string): ResourceBuilder<M>;
    fill(value: (record: ModelInstance<M>, ctx: HttpContext) => ResourceData | Promise<ResourceData>): ResourceBuilder<M>;
    mutateBeforeCreate(value: NonNullable<ResourceHooks<ModelInstance<M>>['mutateBeforeCreate']>): ResourceBuilder<M>;
    mutateBeforeSave(value: NonNullable<ResourceHooks<ModelInstance<M>>['mutateBeforeSave']>): ResourceBuilder<M>;
    beforeCreate(value: NonNullable<ResourceHooks<ModelInstance<M>>['beforeCreate']>): ResourceBuilder<M>;
    afterCreate(value: NonNullable<ResourceHooks<ModelInstance<M>>['afterCreate']>): ResourceBuilder<M>;
    beforeSave(value: NonNullable<ResourceHooks<ModelInstance<M>>['beforeSave']>): ResourceBuilder<M>;
    afterSave(value: NonNullable<ResourceHooks<ModelInstance<M>>['afterSave']>): ResourceBuilder<M>;
    beforeDelete(value: NonNullable<ResourceHooks<ModelInstance<M>>['beforeDelete']>): ResourceBuilder<M>;
    afterDelete(value: NonNullable<ResourceHooks<ModelInstance<M>>['afterDelete']>): ResourceBuilder<M>;
    create(value: NonNullable<ResourceHandlers<ModelInstance<M>>['create']>): ResourceBuilder<M>;
    update(value: NonNullable<ResourceHandlers<ModelInstance<M>>['update']>): ResourceBuilder<M>;
    toDefinition(): ResourceDefinition<ModelInstance<M>>;
    readonly definition: ResourceDefinition<ModelInstance<M>>;
    toJSON(): string;
};

export function defineResource<M extends ResourceModel>(model: M): ResourceBuilder<M>;
```

## src/builder/relation_manager.ts

[Source](https://github.com/rikoriswandha/pupitre/blob/main/packages/pupitre/src/builder/relation_manager.ts)

```ts
export type RelationManagerBuilder = {
    label(value: string): RelationManagerBuilder;
    icon(value: string): RelationManagerBuilder;
    badge(value: (ctx: HttpContext, record: unknown) => unknown | Promise<unknown>): RelationManagerBuilder;
    readOnly(value?: boolean): RelationManagerBuilder;
    recordTitle(value: string): RelationManagerBuilder;
    form(callback: (schema: FormSchema<Record<string, unknown>>) => {
        components: ComponentDefinition[];
    } | readonly SchemaComponent[]): RelationManagerBuilder;
    table(callback: (table: TableSchema) => TableSchema): RelationManagerBuilder;
    actions(value: ResourceActions): RelationManagerBuilder;
    toDefinition(): RelationManagerDefinition;
    toJSON(): string;
    readonly definition: RelationManagerDefinition;
};

export function defineRelationManager(owner: LucidModel | ResourceLike, relation: string): RelationManagerBuilder;

export function relationGroup(label: string, relations: readonly RelationManagerEntry[]): RelationGroupDefinition;
```

## src/definition/resource.ts

[Source](https://github.com/rikoriswandha/pupitre/blob/main/packages/pupitre/src/definition/resource.ts)

```ts
export type PolicyClass = abstract new (...args: never[]) => object;

export type ResourceData = Record<string, unknown>;

export type ResourceHooks<Model extends object, Trx = TransactionClientContract> = {
    fill?: (record: Model, ctx: HttpContext) => ResourceData | Promise<ResourceData>;
    mutateBeforeCreate?: (data: ResourceData, ctx: HttpContext, trx: Trx) => ResourceData | void | Promise<ResourceData | void>;
    mutateBeforeSave?: (data: ResourceData, record: Model | null, ctx: HttpContext, trx: Trx) => ResourceData | void | Promise<ResourceData | void>;
    beforeCreate?: (data: ResourceData, ctx: HttpContext, trx: Trx) => unknown | Promise<unknown>;
    afterCreate?: (record: Model, ctx: HttpContext, trx: Trx) => unknown | Promise<unknown>;
    beforeSave?: (record: Model | null, data: ResourceData, ctx: HttpContext, trx: Trx) => unknown | Promise<unknown>;
    afterSave?: (record: Model, ctx: HttpContext, trx: Trx) => unknown | Promise<unknown>;
    beforeDelete?: (record: Model, ctx: HttpContext, trx: Trx) => unknown | Promise<unknown>;
    afterDelete?: (record: Model, ctx: HttpContext, trx: Trx) => unknown | Promise<unknown>;
};

export type ResourceHandlers<Model extends object, Trx = TransactionClientContract> = {
    create?: (data: ResourceData, ctx: HttpContext, trx: Trx) => Promise<Model>;
    update?: (record: Model, data: ResourceData, ctx: HttpContext, trx: Trx) => Promise<Model>;
};

export type ResourceDefinition<Model extends object = object> = {
    model: string;
    modelClass?: LucidModel;
    slug: string;
    label: string;
    pluralLabel: string;
    icon?: string;
    cluster?: ClusterDefinition;
    navigation?: {
        group?: string;
        sort?: number;
        badge?: (ctx: HttpContext) => unknown | Promise<unknown>;
    };
    recordTitle?: string;
    globallySearchable?: string[];
    globalSearchDetails?: (record: Model) => string[];
    policy?: PolicyClass | (() => Promise<{
        default: PolicyClass;
    }>);
    scope?: false | ((query: ModelQueryBuilderContract<LucidModel>, ctx: HttpContext) => void);
    form?: ComponentDefinition[];
    table?: TableDefinition;
    softDeletes?: string;
    infolist?: ComponentDefinition[];
    actions?: {
        header: ActionDefinition[];
        row: ActionDefinition[];
        bulk: ActionDefinition[];
    };
    pages: Partial<Record<'list' | 'create' | 'edit' | 'view', PageDefinition>>;
    relations?: RelationManagerEntry[];
    nested?: ResourceDefinition[];
    parent?: {
        resource: string;
        relation: string;
    };
    hooks: ResourceHooks<Model>;
    handlers: ResourceHandlers<Model>;
    toJSON(): string;
};
```

## src/definition/relation_manager.ts

[Source](https://github.com/rikoriswandha/pupitre/blob/main/packages/pupitre/src/definition/relation_manager.ts)

```ts
export type RelationActions = {
    header: ActionDefinition[];
    row: ActionDefinition[];
    bulk: ActionDefinition[];
};

export type RelationManagerDefinition = {
    parentModel: string;
    parentModelClass: LucidModel;
    relation: string;
    label: string;
    icon?: string;
    group?: string;
    badge?: (ctx: HttpContext, record: unknown) => unknown | Promise<unknown>;
    table?: TableDefinition;
    form?: ComponentDefinition[];
    readOnly: boolean;
    recordTitle?: string;
    actions: RelationActions;
};

export type RelationGroupDefinition = {
    kind: 'relationGroup';
    label: string;
    relations: RelationManagerEntry[];
};

export type RelationManagerEntry = RelationManagerDefinition | RelationGroupDefinition | {
    toDefinition(): RelationManagerDefinition;
};
```

## src/definition/page.ts

[Source](https://github.com/rikoriswandha/pupitre/blob/main/packages/pupitre/src/definition/page.ts)

```ts
export type PageKind = 'list' | 'create' | 'edit' | 'view';

export type PageDefinition = {
    kind: PageKind;
    component?: string;
    redirectTo?: 'edit' | 'list' | 'view';
    tabs?: Record<string, {
        label?: string;
        where?: Record<string, unknown> | QueryCallback;
    }>;
    widgets?: WidgetDefinition[];
    footerWidgets?: WidgetDefinition[];
    modals?: boolean;
};
```

Source: https://pupitre.rikology.com/reference/api-resource/index.mdx
