Api Reference

Types & Configuration

Complete TypeScript reference for all interfaces, types, and configuration options in Nuxt Crouton

Nuxt Crouton provides comprehensive TypeScript types for type-safe collection management, UI configuration, and data operations. This reference documents all core types, interfaces, and configuration patterns.

Core Configuration Types

CollectionConfig

The master configuration interface for registering collections in app.config.ts.

interface CollectionConfig {
  // Basic Collection Info
  name?: string
  layer?: string
  componentName?: string
  apiPath?: string

  // Pagination Settings
  defaultPagination?: {
    currentPage: number
    pageSize: number
    sortBy: string
    sortDirection: 'asc' | 'desc'
  }

  // Relationship Declarations
  references?: Record<string, string>

  // Custom Component Mapping
  dependentFieldComponents?: Record<string, string>

  // Extensible for custom properties
  [key: string]: any
}

Property Details

PropertyTypeDescription
namestringCollection name (usually auto-set by generator)
layerstringNuxt layer this collection belongs to
componentNamestringName of the form component (e.g., 'ShopProductsForm')
apiPathstringAPI endpoint path (defaults to collection name)
defaultPaginationobjectDefault pagination settings for this collection
referencesRecord<string, string>Field-to-collection mappings for automatic cache refresh
dependentFieldComponentsRecord<string, string>Custom component mappings for dependent fields

Basic Usage

// app.config.ts
export default defineAppConfig({
  croutonCollections: {
    shopProducts: {
      name: 'shopProducts',
      layer: 'shop',
      componentName: 'ShopProductsForm',
      apiPath: 'products',
      defaultPagination: {
        currentPage: 1,
        pageSize: 25,
        sortBy: 'name',
        sortDirection: 'asc'
      }
    }
  }
})

With References (Cache Invalidation)

When a collection has fields that reference other collections, declare them using references. This enables automatic cache refresh when related items are updated.

// app.config.ts
export default defineAppConfig({
  croutonCollections: {
    bookingsEvents: {
      name: 'bookingsEvents',
      layer: 'bookings',
      componentName: 'BookingsEventsForm',
      references: {
        location: 'bookingsLocations',  // 'location' field references 'bookingsLocations'
        host: 'users',                   // 'host' field references 'users'
        category: 'bookingsCategories'   // 'category' field references 'bookingsCategories'
      }
    }
  }
})

How references work:

  1. When you update an event with { location: 'location-123' }
  2. Crouton invalidates cache for both:
    • collection:bookingsEvents:* (the event collection)
    • collection:bookingsLocations:* (the referenced location collection)
  3. Any UI displaying locations automatically refreshes to show updated data
  4. This keeps CardMini displays in sync across the application

With Custom Dependent Fields

For complex field relationships, map field names to custom components:

// app.config.ts
export default defineAppConfig({
  croutonCollections: {
    bookingsEvents: {
      name: 'bookingsEvents',
      layer: 'bookings',
      componentName: 'BookingsEventsForm',
      dependentFieldComponents: {
        slots: 'SlotSelect',           // Use SlotSelect component for 'slots' field
        recurringPattern: 'RecurringPatternEditor'  // Custom editor for recurring events
      }
    }
  }
})

The FormDependentFieldLoader component uses this mapping to dynamically load the correct component for each field.

Custom Properties

You can extend CollectionConfig with any custom properties your application needs:

export default defineAppConfig({
  croutonCollections: {
    shopProducts: {
      name: 'shopProducts',
      layer: 'shop',
      componentName: 'ShopProductsForm',

      // Custom properties
      features: {
        enableInventoryTracking: true,
        enableVariants: true
      },
      permissions: {
        create: 'product:create',
        update: 'product:update',
        delete: 'product:delete'
      },
      metadata: {
        icon: 'i-lucide-package',
        displayName: 'Products',
        singularName: 'Product'
      }
    }
  }
})

Access custom properties via useCollections():

const collections = useCollections()
const config = collections.getConfig('shopProducts')

if (config?.features?.enableInventoryTracking) {
  // Show inventory fields
}

ExternalCollectionConfig

Configuration for external collections (e.g., users from auth system, third-party APIs).

interface ExternalCollectionConfig {
  name: string
  schema: z.ZodSchema
  apiPath?: string
  fetchStrategy?: 'query' | 'restful'
  readonly?: boolean
  meta?: {
    label?: string
    description?: string
  }
  proxy?: {
    enabled: boolean
    sourceEndpoint: string
    transform: (item: any) => { id: string; title: string; [key: string]: any }
  }
}

Property Details

PropertyTypeDefaultDescription
namestringrequiredCollection name (must match app.config.ts key)
schemaz.ZodSchemarequiredZod schema for validation and types
apiPathstringnameAPI endpoint path
fetchStrategy'query' | 'restful''query'Fetch method: ?ids= vs /{id}
readonlybooleantrueHide edit/delete buttons in CardMini
metaobject{}Display metadata
proxyobjectundefinedProxy configuration for external endpoints

Basic External Collection

// composables/useExternalCollections.ts
import { defineExternalCollection } from '@friendlyinternet/nuxt-crouton'
import { z } from 'zod'

const userSchema = z.object({
  id: z.string(),
  title: z.string(),     // Required for CroutonReferenceSelect display
  email: z.string().optional(),
  avatarUrl: z.string().optional()
})

export const usersConfig = defineExternalCollection({
  name: 'users',
  schema: userSchema,
  apiPath: 'users',
  readonly: true,        // Users managed by auth system
  meta: {
    label: 'Team Members',
    description: 'Users from the authentication system'
  }
})
// app.config.ts
import { usersConfig } from '~/composables/useExternalCollections'

export default defineAppConfig({
  croutonCollections: {
    users: usersConfig,
    // ... other collections
  }
})

With Proxy Transform

Proxy external endpoints and transform data to Crouton format:

import { defineExternalCollection } from '@friendlyinternet/nuxt-crouton'
import { z } from 'zod'

const memberSchema = z.object({
  id: z.string(),
  title: z.string(),
  role: z.string(),
  joinedAt: z.string()
})

export const membersConfig = defineExternalCollection({
  name: 'members',
  schema: memberSchema,
  proxy: {
    enabled: true,
    sourceEndpoint: 'members',  // → /api/teams/[id]/members
    transform: (item) => ({
      id: item.userId,
      title: `${item.firstName} ${item.lastName}`,  // Transform to required 'title' field
      role: item.memberRole,
      joinedAt: item.createdAt
    })
  }
})

How proxy works:

  1. CroutonReferenceSelect fetches from /api/teams/[teamId]/members
  2. Raw data from external system is transformed using the transform function
  3. Transformed data has id and title fields (required by Crouton)
  4. Data displays correctly in CroutonItemCardMini and CroutonReferenceSelect

RESTful Fetch Strategy

For APIs using /resource/{id} pattern instead of /resource?ids=:

export const customersConfig = defineExternalCollection({
  name: 'customers',
  schema: customerSchema,
  fetchStrategy: 'restful',  // Use /{id} instead of ?ids=
  apiPath: 'customers'
})

This changes how single items are fetched:

  • 'query' (default): GET /api/teams/[id]/customers?ids=customer-123
  • 'restful': GET /api/teams/[id]/customers/customer-123

Layout System Types

LayoutType

Basic layout modes for displaying collections.

type LayoutType = 'table' | 'list' | 'grid' | 'cards' | 'tree'
LayoutDescriptionUse Case
tableTraditional data tableDesktop, detailed data with many columns
listCompact list viewMobile, simple data, quick scanning
gridGrid of cards (2-3 columns)Mobile/tablet, visual content
cardsLarge card tiles (1-2 columns)Desktop, rich content with images
treeHierarchical tree viewParent-child relationships, nested data

ResponsiveLayout

Responsive layout configuration with breakpoint support.

interface ResponsiveLayout {
  base: LayoutType
  sm?: LayoutType   // 640px+
  md?: LayoutType   // 768px+
  lg?: LayoutType   // 1024px+
  xl?: LayoutType   // 1280px+
  '2xl'?: LayoutType // 1536px+
}

Basic Responsive Layout

<script setup lang="ts">
const layout = {
  base: 'list',   // Mobile: list
  md: 'grid',     // Tablet: grid
  lg: 'table'     // Desktop: table
}
</script>

<template>
  <CroutonCollection
    :layout="layout"
    :rows="products"
    :columns="columns"
    collection="shopProducts"
  />
</template>

Using Layout Presets

// Built-in presets
const layoutPresets = {
  'responsive': { base: 'list', md: 'grid', lg: 'table' },
  'mobile-friendly': { base: 'list', lg: 'table' },
  'compact': { base: 'list', xl: 'table' }
}
<template>
  <!-- Use preset by name -->
  <CroutonCollection
    layout="responsive"
    :rows="products"
    :columns="columns"
    collection="shopProducts"
  />
</template>

Complex Responsive Example

<script setup lang="ts">
import type { ResponsiveLayout } from '@friendlyinternet/nuxt-crouton'

// Fine-tuned for different screen sizes
const layout: ResponsiveLayout = {
  base: 'list',      // Phone (< 640px)
  sm: 'list',        // Large phone (640px+)
  md: 'grid',        // Tablet (768px+)
  lg: 'grid',        // Small laptop (1024px+)
  xl: 'table',       // Desktop (1280px+)
  '2xl': 'table'     // Large desktop (1536px+)
}
</script>

<template>
  <CroutonCollection
    :layout="layout"
    :rows="products"
    :columns="columns"
    collection="shopProducts"
  />
</template>

Table and Column Types

TableColumn

Column definition for table layouts.

interface TableColumn {
  id?: string
  accessorKey?: string
  header: string | ((props: any) => any)
  cell?: (props: any) => any
  sortable?: boolean
  enableSorting?: boolean
  enableHiding?: boolean
}

Property Details

PropertyTypeDefaultDescription
idstringaccessorKeyUnique column identifier
accessorKeystring-Object property to access (dot notation supported)
headerstring | functionrequiredColumn header text or render function
cellfunction-Custom cell renderer (receives { row, value })
sortablebooleanfalseEnable sorting for this column
enableSortingbooleansortableTanStack Table sorting flag
enableHidingbooleantrueAllow hiding this column

Basic Columns

const columns: TableColumn[] = [
  {
    accessorKey: 'name',
    header: 'Product Name',
    sortable: true
  },
  {
    accessorKey: 'price',
    header: 'Price',
    sortable: true
  },
  {
    accessorKey: 'inStock',
    header: 'In Stock'
  }
]

Custom Cell Renderers

import type { TableColumn } from '@friendlyinternet/nuxt-crouton'

const columns: TableColumn[] = [
  {
    accessorKey: 'price',
    header: 'Price',
    cell: ({ value }) => `$${value.toFixed(2)}`
  },
  {
    accessorKey: 'status',
    header: 'Status',
    cell: ({ row }) => {
      const status = row.original.status
      const color = status === 'active' ? 'green' : 'gray'
      return h('span', { class: `text-${color}-600` }, status)
    }
  }
]

Nested Data Access

const columns: TableColumn[] = [
  {
    accessorKey: 'user.name',    // Dot notation for nested properties
    header: 'User Name'
  },
  {
    accessorKey: 'location.city',
    header: 'City'
  }
]

Custom Header Renderers

const columns: TableColumn[] = [
  {
    accessorKey: 'price',
    header: () => h('div', [
      h('span', 'Price '),
      h('span', { class: 'text-xs text-gray-500' }, '(USD)')
    ])
  }
]

CollectionProps

Props interface for CroutonCollection component.

interface CollectionProps {
  // Layout Configuration
  layout?: LayoutType | ResponsiveLayout | keyof typeof layoutPresets
  card?: 'Card' | 'CardMini' | 'CardSmall' | 'CardTree' | string  // Card variant

  // Data (Required)
  rows: any[]
  columns: TableColumn[]
  collection: string

  // Pagination
  serverPagination?: boolean
  paginationData?: PaginationData | null
  refreshFn?: () => Promise<void> | null

  // UI Options
  create?: boolean
  hideDefaultColumns?: {
    createdAt?: boolean
    updatedAt?: boolean
    createdBy?: boolean
    updatedBy?: boolean
    actions?: boolean
  }
}

The card prop allows specifying which card variant to use:

  • card="CardSmall" resolves to {Collection}CardSmall (e.g., BookingsCardSmall)
  • card="CardTree" resolves to {Collection}CardTree
  • No card prop uses {Collection}Card with the layout prop passed to it

Complete Example

Query Examples: For complete useCollectionQuery patterns, see Querying Data.
<script setup lang="ts">
import type { CollectionProps, TableColumn } from '@friendlyinternet/nuxt-crouton'

// See /fundamentals/querying for query patterns
const { items, pending, refresh } = await useCollectionQuery('shopProducts')

const columns: TableColumn[] = [
  { accessorKey: 'name', header: 'Name', sortable: true },
  { accessorKey: 'price', header: 'Price', sortable: true }
]

const paginationData = computed(() => ({
  currentPage: page.value,
  pageSize: 25,
  totalItems: totalItems.value
}))
</script>

<template>
  <CroutonCollection
    layout="responsive"
    :rows="items"
    :columns="columns"
    collection="shopProducts"
    :server-pagination="true"
    :pagination-data="paginationData"
    :refresh-fn="refresh"
    create
    :hide-default-columns="{
      createdBy: true,
      updatedBy: true
    }"
  />
</template>

Pagination Types

PaginationData

Pagination metadata for server-side pagination.

interface PaginationData {
  currentPage: number
  pageSize: number
  totalItems: number
  totalPages?: number
  sortBy?: string
  sortDirection?: 'asc' | 'desc'
}

Property Details

PropertyTypeRequiredDescription
currentPagenumberYesCurrent page number (1-indexed)
pageSizenumberYesItems per page
totalItemsnumberYesTotal number of items across all pages
totalPagesnumberNoTotal pages (auto-calculated if omitted)
sortBystringNoCurrent sort column
sortDirection'asc' | 'desc'NoCurrent sort direction

Pagination Usage

Pagination Examples: For complete pagination and sorting patterns with useCollectionQuery, see Querying Data.
<script setup lang="ts">
// See /fundamentals/querying for query patterns
const { items, data } = await useCollectionQuery('shopProducts')

const paginationData = computed(() => ({
  currentPage: page.value,
  pageSize: 25,
  totalItems: data.value?.pagination?.totalItems || 0
}))
</script>

<template>
  <CroutonCollection
    :rows="items"
    :columns="columns"
    collection="shopProducts"
    :server-pagination="true"
    :pagination-data="paginationData"
  />
</template>

Server Response Format

Your API should return data in this format:

// GET /api/teams/[id]/products?page=1&pageSize=25
{
  items: [
    { id: '1', name: 'Product 1', price: 29.99 },
    // ... more items
  ],
  pagination: {
    currentPage: 1,
    pageSize: 25,
    totalItems: 156,
    totalPages: 7,
    sortBy: 'name',
    sortDirection: 'asc'
  }
}

PaginationState (Internal)

Internal pagination state (used within composables).

interface PaginationState {
  currentPage: number
  pageSize: number
  sortBy: string
  sortDirection: 'asc' | 'desc'
  totalItems?: number
  totalPages?: number
}

Used internally by useCrouton() to manage pagination across multiple collections.

Composable Return Types

CollectionQueryReturn

Return type of useCollectionQuery().

interface CollectionQueryReturn<T = any> {
  items: ComputedRef<T[]>
  data: Ref<any>
  refresh: () => Promise<void>
  pending: Ref<boolean>
  error: Ref<any>
}

Usage with Types

import type { ShopProduct } from '~/layers/shop/types/products'

const {
  items,      // ComputedRef<ShopProduct[]>
  pending,    // Ref<boolean>
  error,      // Ref<any>
  refresh     // () => Promise<void>
} = await useCollectionQuery<ShopProduct>('shopProducts')

CollectionQueryOptions

Options for useCollectionQuery().

interface CollectionQueryOptions {
  query?: ComputedRef<Record<string, any>> | Ref<Record<string, any>>
  watch?: boolean
}

Property Details

PropertyTypeDefaultDescription
queryComputedRef | Ref{}Reactive query parameters
watchbooleantrueAuto-refetch when query changes

Basic Query Options

const page = ref(1)
const search = ref('')

const { items } = await useCollectionQuery('shopProducts', {
  query: computed(() => ({
    page: page.value,
    search: search.value
  })),
  watch: true  // Auto-refetch when page or search changes
})

CollectionMutation

Return type of useCollectionMutation().

interface CollectionMutation {
  create: (data: any) => Promise<any>
  update: (id: string, data: any) => Promise<any>
  deleteItems: (ids: string[]) => Promise<void>
}

Usage

See Mutation Composables API for usage examples.

Component Prop Types

CardProps

Props for custom card components.

interface CardProps {
  item: any
  layout: 'list' | 'grid' | 'cards' | 'tree'
  collection: string
  pending?: boolean
  error?: any
}

Custom Card Component

<script setup lang="ts">
import type { CardProps } from '@friendlyinternet/nuxt-crouton'

const props = defineProps<CardProps>()
</script>

<template>
  <div :class="layout === 'list' ? 'py-2' : 'p-4 border rounded'">
    <h3>{{ item.name }}</h3>
    <p v-if="layout !== 'list'">{{ item.description }}</p>
  </div>
</template>

TableSearchProps

Props for CroutonTableSearch component.

interface TableSearchProps {
  modelValue: string
  placeholder?: string
  debounceMs?: number
}

TablePaginationProps

Props for CroutonTablePagination component.

interface TablePaginationProps {
  page: number
  pageCount: number
  totalItems: number
  loading?: boolean
  pageSizes?: number[]
}

TableActionsProps

Props for CroutonTableActions component.

interface TableActionsProps {
  selectedRows: any[]
  collection: string
  table?: any
  onDelete?: (ids: string[]) => void
  onColumnVisibilityChange?: (column: string, visible: boolean) => void
}

Hook System Types

crouton:mutation Hook

Nuxt hook emitted after successful mutations. Use for event tracking, analytics, or custom cache invalidation.

// Hook payload type
interface CroutonMutationPayload {
  operation: 'create' | 'update' | 'delete'
  collection: string
  itemId?: string
  data?: any
  result?: any
}

Registering Hook Listeners

// plugins/crouton-events.ts
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hooks.hook('crouton:mutation', async (payload) => {
    const { operation, collection, itemId, data, result } = payload

    // Track analytics
    if (operation === 'create') {
      console.log(`Created ${collection} item:`, itemId)
      await $fetch('/api/analytics/track', {
        method: 'POST',
        body: {
          event: `${collection}_created`,
          properties: { itemId }
        }
      })
    }

    // Custom cache invalidation
    if (collection === 'shopProducts' && operation === 'update') {
      // Invalidate related caches
      await clearNuxtData('product-analytics')
      await clearNuxtData('trending-products')
    }
  })
})

Hook Payload Examples

Create operation:

{
  operation: 'create',
  collection: 'shopProducts',
  itemId: 'product-123',
  data: {
    name: 'New Product',
    price: 49.99
  },
  result: {
    id: 'product-123',
    name: 'New Product',
    price: 49.99,
    createdAt: '2025-01-15T10:30:00Z'
  }
}

Update operation:

{
  operation: 'update',
  collection: 'shopProducts',
  itemId: 'product-123',
  data: {
    price: 39.99
  },
  result: {
    id: 'product-123',
    name: 'New Product',
    price: 39.99,
    updatedAt: '2025-01-15T11:00:00Z'
  }
}

Delete operation:

{
  operation: 'delete',
  collection: 'shopProducts',
  itemId: undefined,  // Not available for bulk delete
  data: {
    ids: ['product-123', 'product-456']
  },
  result: undefined
}

Use Cases for Hooks

1. Event Tracking / Analytics

nuxtApp.hooks.hook('crouton:mutation', async ({ operation, collection, itemId }) => {
  await $fetch('/api/analytics/events', {
    method: 'POST',
    body: {
      event: `${collection}.${operation}`,
      userId: user.value?.id,
      timestamp: new Date().toISOString(),
      metadata: { itemId }
    }
  })
})

2. Audit Logging

nuxtApp.hooks.hook('crouton:mutation', async (payload) => {
  await $fetch('/api/audit-log', {
    method: 'POST',
    body: {
      action: payload.operation,
      resource: payload.collection,
      resourceId: payload.itemId,
      changes: payload.data,
      performedBy: user.value?.id,
      timestamp: new Date()
    }
  })
})

3. Custom Cache Invalidation

nuxtApp.hooks.hook('crouton:mutation', async ({ collection, operation }) => {
  // When products change, refresh dashboard stats
  if (collection === 'shopProducts') {
    await clearNuxtData('dashboard-stats')
    await clearNuxtData('inventory-summary')
  }

  // When orders change, refresh customer data
  if (collection === 'shopOrders') {
    await clearNuxtData('customer-orders')
    await clearNuxtData('revenue-stats')
  }
})

4. Webhook Notifications

nuxtApp.hooks.hook('crouton:mutation', async (payload) => {
  // Notify external systems of changes
  if (payload.operation === 'create' && payload.collection === 'shopOrders') {
    await $fetch('/api/webhooks/order-created', {
      method: 'POST',
      body: {
        orderId: payload.itemId,
        order: payload.result
      }
    })
  }
})

5. Real-time Updates (WebSocket)

nuxtApp.hooks.hook('crouton:mutation', async (payload) => {
  // Broadcast changes to connected clients
  websocket.broadcast({
    type: 'collection:mutation',
    collection: payload.collection,
    operation: payload.operation,
    itemId: payload.itemId
  })
})

State Management Types

CroutonState (Internal)

Internal state for modal/form management (used by useCrouton()).

interface CroutonState {
  id: string
  action: CroutonAction
  collection: string | null
  activeItem: any
  items: any[]
  loading: LoadingState
  isOpen: boolean
  containerType: 'slideover' | 'modal' | 'dialog'
}

type CroutonAction = 'create' | 'update' | 'delete' | 'view' | null

type LoadingState =
  | 'notLoading'
  | 'create_send' | 'update_send' | 'delete_send' | 'view_send'
  | 'create_open' | 'update_open' | 'delete_open' | 'view_open'

Utility Types

ProxyConfig (Internal)

Configuration for proxying external collections.

interface ProxyConfig {
  enabled: boolean
  sourceEndpoint: string
  transform: (item: any) => { id: string; title: string; [key: string]: any }
}

ConfigsMap (Internal)

Type for collection configuration registry.

type ConfigsMap = {
  [K in CollectionName]?: CollectionConfig
}

Type Guards and Helpers

Checking Collection Config

const collections = useCollections()
const config = collections.getConfig('shopProducts')

if (!config) {
  throw new Error('Collection not found')
}

// Access config properties
const apiPath = config.apiPath || 'products'
const references = config.references || {}

Type-Safe Query Building

import type { PaginationData } from '@friendlyinternet/nuxt-crouton'

function buildPaginationData(
  page: number,
  pageSize: number,
  total: number
): PaginationData {
  return {
    currentPage: page,
    pageSize,
    totalItems: total,
    totalPages: Math.ceil(total / pageSize)
  }
}

Type-Safe Column Definitions

import type { TableColumn } from '@friendlyinternet/nuxt-crouton'
import type { ShopProduct } from '~/layers/shop/types/products'

function defineProductColumns(): TableColumn[] {
  return [
    {
      accessorKey: 'name',
      header: 'Product Name',
      sortable: true
    },
    {
      accessorKey: 'price',
      header: 'Price',
      cell: ({ row }: { row: { original: ShopProduct } }) =>
        `$${row.original.price.toFixed(2)}`
    }
  ]
}

Common Patterns

Pattern 1: Type-Safe Collection Setup

// 1. Define your data type
import type { ShopProduct } from '~/layers/shop/types/products'

// 2. Register collection config
// app.config.ts
export default defineAppConfig({
  croutonCollections: {
    shopProducts: {
      name: 'shopProducts',
      layer: 'shop',
      componentName: 'ShopProductsForm'
    }
  }
})

// 3. Use with type parameter
const { items, pending } = await useCollectionQuery<ShopProduct>('shopProducts')
// items is ComputedRef<ShopProduct[]>

Pattern 2: External Collection with Transform

// 1. Define external collection
import { defineExternalCollection } from '@friendlyinternet/nuxt-crouton'

export const membersConfig = defineExternalCollection({
  name: 'members',
  schema: z.object({
    id: z.string(),
    title: z.string()
  }),
  proxy: {
    enabled: true,
    sourceEndpoint: 'members',
    transform: (item) => ({
      id: item.userId,
      title: `${item.firstName} ${item.lastName}`
    })
  }
})

// 2. Register in app.config.ts
export default defineAppConfig({
  croutonCollections: {
    members: membersConfig
  }
})

// 3. Use in components
const { items } = await useCollectionQuery('members')

Pattern 3: Responsive Layout with Type Safety

import type { ResponsiveLayout, TableColumn } from '@friendlyinternet/nuxt-crouton'

const layout: ResponsiveLayout = {
  base: 'list',
  md: 'grid',
  lg: 'table'
}

const columns: TableColumn[] = [
  { accessorKey: 'name', header: 'Name' }
]

Pattern 4: Server Pagination with Types

import type { PaginationData } from '@friendlyinternet/nuxt-crouton'

const page = ref(1)

const { items, data } = await useCollectionQuery('shopProducts', {
  query: computed(() => ({ page: page.value }))
})

const paginationData = computed<PaginationData>(() => ({
  currentPage: page.value,
  pageSize: 25,
  totalItems: data.value?.pagination?.totalItems || 0
}))

Pattern 5: Hook Integration

// Plugin for mutation tracking
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hooks.hook('crouton:mutation', async (payload) => {
    // Type-safe payload access
    const { operation, collection, itemId, data, result } = payload

    console.log(`[${operation}] ${collection}:`, itemId)
  })
})

TypeScript Configuration

{
  "extends": "./.nuxt/tsconfig.json",
  "compilerOptions": {
    "strict": true,
    "types": ["@nuxt/types", "@friendlyinternet/nuxt-crouton"]
  }
}

Module Augmentation

Extend Crouton types for your app:

// types/crouton.d.ts
declare module '@friendlyinternet/nuxt-crouton' {
  interface CollectionConfig {
    // Add custom properties
    permissions?: {
      create?: string
      update?: string
      delete?: string
    }
    metadata?: {
      icon?: string
      displayName?: string
    }
  }
}

Type Checking

Always run type checking after making changes:

# Type check your application
npx nuxt typecheck

# Watch mode for development
npx nuxt typecheck --watch