The @fyit/crouton-devtools package provides a comprehensive Nuxt DevTools integration for visually inspecting, monitoring, and debugging your Crouton collections during development.
Nuxt Crouton DevTools adds a dedicated "Crouton" tab to the Nuxt DevTools panel, providing real-time visibility into your CRUD collections, API endpoints, and database operations.
nuxt dev) and has zero impact on production builds.pnpm add -D @fyit/crouton-devtools
pnpm add -D @fyit/crouton-devtools@0.1.0 --save-exact
Add the module to your nuxt.config.ts:
export default defineNuxtConfig({
modules: [
'@nuxt/devtools', // Required
'@fyit/crouton-devtools' // Add this
],
devtools: {
enabled: true // Ensure DevTools is enabled
}
})
pnpm dev
Open Nuxt DevTools (look for the DevTools icon in the bottom-right corner) and find the Crouton tab.
app.config.croutonCollections and starts tracking operations.The Collection Inspector provides a visual overview of all registered collections in your application.
Each collection card displays:
/api/crouton-collection/tasks)Use the search bar to quickly find collections:
Search: "tasks" → Finds tasks collection
Search: "internal" → Shows all internal collections
Search: "/api/users" → Finds by API path
Click any collection card to view full configuration:
Example Detail View:
{
"key": "tasks",
"name": "tasks",
"layer": "internal",
"apiPath": "/api/crouton-collection/tasks",
"componentName": "CroutonCollectionTasksCreate",
"meta": {
"label": "Tasks",
"description": "Project task management",
"icon": "i-lucide-check-circle"
},
"defaultValues": {
"status": "pending"
},
"columns": ["title", "status", "assignee", "dueDate"]
}
The DevTools integration automatically generates and lists all available CRUD endpoints for each collection.
For each collection, the following endpoints are documented:
| Operation | Method | Path | Description |
|---|---|---|---|
| List/Search | GET | /api/crouton-collection/{name}/search | Paginated search with filters |
| Get Single | GET | /api/crouton-collection/{name}/:id | Retrieve one item by ID |
| Create | POST | /api/crouton-collection/{name} | Create new item |
| Update | PATCH | /api/crouton-collection/{name}/:id | Update existing item |
| Delete | DELETE | /api/crouton-collection/{name}/:id | Delete item by ID |
Each endpoint shows available parameters:
List/Search Parameters:
page (number) - Page number (default: 1)limit (number) - Items per page (default: 10)filter (json) - Filter object (e.g., {"active": true})sort (string) - Sort field (e.g., "createdAt")Get/Update/Delete Parameters:
id (string, required) - Item ID (path parameter)Endpoints are accessible via the DevTools RPC interface:
// Fetch all endpoints
GET /__nuxt_crouton_devtools/api/endpoints
// Response format
{
"success": true,
"data": [
{
"collection": "tasks",
"operation": "list",
"method": "GET",
"path": "/api/crouton-collection/tasks/search",
"params": [...],
"requiresBody": false
},
// ... more endpoints
],
"count": 20 // Total endpoints (5 per collection × 4 collections)
}
The DevTools integration tracks all CRUD operations in real-time using an in-memory operation store.
Every API call to a Crouton collection endpoint is logged with:
{
id: "op_1700000000000_abc123", // Unique operation ID
timestamp: 1700000000000, // Unix timestamp (ms)
collection: "tasks", // Collection name
operation: "create", // Operation type
method: "POST", // HTTP method
path: "/api/crouton-collection/tasks", // Full path
status: 201, // HTTP status code
duration: 45, // Response time (ms)
teamContext: "team_xyz", // Team ID (if applicable)
error: undefined // Error message (if failed)
}
The tracker automatically detects operation types:
/search or base endpointOperations are stored in a circular buffer (max 500 operations) to prevent memory issues during long development sessions.
Retrieve operations with filters:
// Get all operations
GET /__nuxt_crouton_devtools/api/operations
// Filter by collection
GET /__nuxt_crouton_devtools/api/operations?collection=tasks
// Filter by operation type
GET /__nuxt_crouton_devtools/api/operations?operation=create
// Filter by status (success/error)
GET /__nuxt_crouton_devtools/api/operations?status=error
// Filter by timestamp (since)
GET /__nuxt_crouton_devtools/api/operations?since=1700000000000
// Combine filters
GET /__nuxt_crouton_devtools/api/operations?collection=tasks&status=success
Get aggregated statistics:
GET /__nuxt_crouton_devtools/api/operations/stats
// Response
{
"success": true,
"data": {
"total": 127, // Total operations tracked
"byCollection": {
"tasks": 45,
"projects": 38,
"users": 44
},
"byOperation": {
"list": 52,
"get": 31,
"create": 24,
"update": 15,
"delete": 5
},
"successRate": 94, // Percentage
"avgDuration": 38, // Average response time (ms)
"successful": 119, // Success count
"failed": 8 // Failure count
}
}
Clear all tracked operations:
POST /__nuxt_crouton_devtools/api/operations/clear
Test API endpoints directly from DevTools without writing code or using external tools like Postman.
Submit requests to any collection endpoint:
POST /__nuxt_crouton_devtools/api/execute
// Request body
{
"method": "POST",
"path": "/api/crouton-collection/tasks",
"params": {
"title": "Test Task",
"status": "pending"
},
"requestBody": {
"title": "Complete documentation",
"status": "in_progress",
"assignee": "user_123",
"dueDate": "2024-12-01"
},
"headers": {
"Authorization": "Bearer <token>"
}
}
// Response
{
"success": true,
"status": 201,
"data": {
"id": "task_abc123",
"title": "Complete documentation",
"status": "in_progress",
// ... rest of created task
},
"duration": 42 // Response time in ms
}
The execution engine automatically replaces path parameters:
// Request
{
"method": "GET",
"path": "/api/crouton-collection/tasks/:id",
"params": {
"id": "task_abc123"
}
}
// Actual request sent to: /api/crouton-collection/tasks/task_abc123
For GET requests, non-path parameters become query strings:
// Request
{
"method": "GET",
"path": "/api/crouton-collection/tasks/search",
"params": {
"page": 2,
"limit": 20,
"filter": JSON.stringify({ active: true }),
"sort": "-createdAt"
}
}
// Actual request sent to:
// /api/crouton-collection/tasks/search?page=2&limit=20&filter=%7B%22active%22%3Atrue%7D&sort=-createdAt
Failed requests return detailed error information:
{
"success": false,
"status": 404,
"error": "Item not found",
"data": {
"statusCode": 404,
"message": "Task with ID 'invalid_id' not found"
},
"duration": 15
}
Displays a single collection in a card format (internal to DevTools UI).
Props:
interface Props {
collection: CroutonCollection
}
interface CroutonCollection {
key: string
name: string
layer?: string
apiPath?: string
componentName?: string | null
meta?: {
label?: string
description?: string
icon?: string
}
defaultValues?: Record<string, any>
columns?: string[]
schema?: any
}
Events:
@view-details - Emitted when card is clickedFeatures:
Shows full collection configuration in a modal (internal to DevTools UI).
Props:
interface Props {
modelValue?: boolean // Controls visibility
collection?: CroutonCollection | null
}
Events:
@update:modelValue - Two-way binding for visibilityFeatures:
The main index page provides:
The DevTools integration exposes several RPC endpoints for programmatic access.
GET /__nuxt_crouton_devtools/api/collections
Retrieve all registered collections.
Response:
{
success: boolean
data: CroutonCollection[]
count: number
}
GET /__nuxt_crouton_devtools/api/operations
Retrieve tracked operations with optional filters.
Query Parameters:
collection (string) - Filter by collection nameoperation (string) - Filter by operation typestatus (string) - Filter by status ("success" | "error")since (number) - Filter by timestamp (Unix ms)Response:
{
success: boolean
data: Operation[]
count: number
filters: OperationFilters
}
GET /__nuxt_crouton_devtools/api/operations/stats
Get aggregated operation statistics.
Response:
{
success: boolean
data: {
total: number
byCollection: Record<string, number>
byOperation: Record<string, number>
successRate: number
avgDuration: number
successful: number
failed: number
}
}
POST /__nuxt_crouton_devtools/api/operations/clear
Clear all tracked operations.
Response:
{
success: boolean
}
GET /__nuxt_crouton_devtools/api/endpoints
List all available CRUD endpoints.
Response:
{
success: boolean
data: Endpoint[]
count: number
}
interface Endpoint {
collection: string
operation: string
method: string
path: string
params: Parameter[]
requiresBody: boolean
bodyDescription?: string
}
POST /__nuxt_crouton_devtools/api/execute
Execute an API request.
Request Body:
{
method: string // HTTP method
path: string // Endpoint path (with :params)
params?: Record<string, any>
requestBody?: any
headers?: Record<string, string>
}
Response:
{
success: boolean
status: number
data?: any
error?: string
duration: number // ms
}
The DevTools module is organized as follows:
packages/crouton-devtools/
├── src/
│ ├── module.ts # Main Nuxt module
│ ├── runtime/
│ │ ├── client/ # DevTools UI (iframe app)
│ │ │ ├── app.vue # Root component
│ │ │ ├── nuxt.config.ts # Client app config
│ │ │ └── package.json
│ │ ├── pages/
│ │ │ └── data-browser.vue # Data browser page
│ │ ├── server-rpc/ # RPC API handlers
│ │ │ ├── client.ts # Client HTML server
│ │ │ ├── collections.ts # Collections endpoint
│ │ │ ├── endpoints.ts # Endpoints listing
│ │ │ ├── operations.ts # Operations retrieval
│ │ │ ├── operationStats.ts # Statistics
│ │ │ ├── clearOperations.ts # Clear history
│ │ │ ├── executeRequest.ts # Request execution
│ │ │ ├── events.ts # Query persisted events
│ │ │ ├── eventsHealth.ts # Events health stats
│ │ │ ├── systemOperations.ts # System operations
│ │ │ ├── clearSystemOperations.ts # Clear system ops
│ │ │ └── generationHistory.ts # Generation history
│ │ └── server/
│ │ ├── plugins/
│ │ │ └── operationTracker.ts # Nitro plugin (tracks API calls)
│ │ ├── utils/
│ │ │ ├── operationStore.ts # In-memory operation storage
│ │ │ └── systemOperationStore.ts # System operation storage
│ │ └── crouton-hooks.d.ts # Hook type definitions
├── playground/ # Development playground
└── package.json
The module registers itself with Nuxt DevTools:
// src/module.ts
import { addCustomTab } from '@nuxt/devtools-kit'
addCustomTab(() => ({
name: 'crouton',
title: 'Crouton',
icon: 'carbon:data-table',
view: {
type: 'iframe',
src: '/__nuxt_crouton_devtools', // Iframe URL
},
}))
At build time, the module reads collections from app.config.croutonCollections and stores them in Nitro runtime config:
// src/module.ts (build time)
nuxt.options.nitro.runtimeConfig.croutonCollections =
nuxt.options.appConfig?.croutonCollections || {}
At runtime, the RPC handlers access the collections via useAppConfig() (which reflects the build-time data injected above):
// src/runtime/server-rpc/collections.ts
const appConfig = useAppConfig()
const collections = appConfig.croutonCollections || {}
A Nitro plugin intercepts all requests to /api/crouton-collection/* using the onAfterResponse hook:
// src/runtime/server/plugins/operationTracker.ts
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('onAfterResponse', (event) => {
const path = event.path
// Only track Crouton collection API routes
if (!path.startsWith('/api/crouton-collection/')) {
return
}
// Extract metadata and record the operation
const collection = extractCollectionName(path)
const operation = detectOperation(method, path)
operationStore.add({
id: generateId(),
timestamp: Date.now(),
collection,
operation,
method,
path,
status: event.node.res.statusCode,
duration: Date.now() - startTime
})
})
})
Operations are stored in-memory with a circular buffer:
// src/runtime/server/utils/operationStore.ts
class OperationStore {
private operations: Operation[] = []
private readonly maxSize = 500 // Prevent memory issues
add(operation: Operation): void {
this.operations.unshift(operation)
// Maintain circular buffer
if (this.operations.length > this.maxSize) {
this.operations = this.operations.slice(0, this.maxSize)
}
}
}
RPC endpoints handle communication between the DevTools iframe and the Nuxt server:
// DevTools UI fetches data
const response = await $fetch('/__nuxt_crouton_devtools/api/collections')
The module only activates in development:
// src/module.ts
async setup(_options, nuxt) {
// Only enable in development mode
if (nuxt.options.dev === false) {
return
}
// ... rest of setup
}
Production builds completely exclude the DevTools code.
Minimal configuration to get started:
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@nuxt/devtools',
'@fyit/crouton-devtools'
],
devtools: {
enabled: true
}
})
// app.config.ts
export default defineAppConfig({
croutonCollections: {
tasks: {
name: 'tasks',
layer: 'internal',
apiPath: '/api/crouton-collection/tasks',
meta: {
label: 'Tasks',
icon: 'i-lucide-check-circle'
}
}
}
})
pnpm devFrom the DevTools UI (or programmatically):
// Create a task
const response = await $fetch('/__nuxt_crouton_devtools/api/execute', {
method: 'POST',
body: {
method: 'POST',
path: '/api/crouton-collection/tasks',
requestBody: {
title: 'Test task',
status: 'pending'
}
}
})
console.log(response)
// {
// success: true,
// status: 201,
// data: { id: 'task_123', ... },
// duration: 42
// }
// Get failed operations
const errors = await $fetch('/__nuxt_crouton_devtools/api/operations?status=error')
// Get recent task operations
const recentTasks = await $fetch(
'/__nuxt_crouton_devtools/api/operations?collection=tasks&since=' +
(Date.now() - 60000) // Last minute
)
const stats = await $fetch('/__nuxt_crouton_devtools/api/operations/stats')
console.log(`Success rate: ${stats.data.successRate}%`)
console.log(`Average response time: ${stats.data.avgDuration}ms`)
console.log('Operations by collection:', stats.data.byCollection)
Problem: Collection not appearing in DevTools.
Debug Steps:
app.config.croutonCollectionsCommon Issues:
app.config.tsname fieldProblem: API calls failing with 404 or 500 errors.
Debug Steps:
status=errorCommon Issues:
Problem: Slow API responses.
Debug Steps:
avgDuration metricduration valuesCommon Issues:
Problem: Search results not showing expected items.
Debug Steps:
Common Issues:
Keep the DevTools Crouton tab open while developing:
// You'll immediately see:
- Which endpoints are being called
- How long they take
- Which ones fail
- What errors occur
Prevent confusion from old operations:
// Clear history when starting new feature
await $fetch('/__nuxt_crouton_devtools/api/operations/clear', {
method: 'POST'
})
Test endpoints without writing code:
// Instead of creating test files, use DevTools to:
- Test new endpoints
- Validate request/response formats
- Check error handling
- Verify filters and sorting
Monitor operation statistics to catch issues early:
// Check stats periodically
const stats = await $fetch('/__nuxt_crouton_devtools/api/operations/stats')
if (stats.data.successRate < 90) {
console.warn('High error rate detected!')
}
Filter operations by collection when debugging:
// Focus on specific collection
GET /__nuxt_crouton_devtools/api/operations?collection=tasks
Issue: The "Crouton" tab doesn't show up in Nuxt DevTools.
Solutions:
// nuxt.config.ts
export default defineNuxtConfig({
devtools: {
enabled: true // Must be true
}
})
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@nuxt/devtools', // Required
'@fyit/crouton-devtools' // Must be present
]
})
# Stop server (Ctrl+C)
pnpm dev
rm -rf .nuxt
pnpm dev
Issue: DevTools opens but shows "No collections found".
Solutions:
// Ensure collections are defined
export default defineAppConfig({
croutonCollections: {
tasks: { ... } // Must have at least one
}
})
// Each collection needs minimum fields
{
name: 'tasks', // Required
// Other fields optional
}
Issue: Operation tracking shows no data.
Solutions:
// Must start with /api/crouton-collection/
GET /api/crouton-collection/tasks/search ✅
GET /api/custom-tasks ❌
Issue: Testing endpoints via Execute Request returns errors.
Solutions:
// Check endpoints list first
GET /__nuxt_crouton_devtools/api/endpoints
// Must include method and path
{
"method": "GET", // Required
"path": "/api/...", // Required
"params": { ... }, // Optional
"requestBody": { ... } // Optional (for POST/PATCH)
}
{
"success": false,
"status": 404,
"error": "Not found", // Read this message
"data": { ... } // Additional error details
}
Issue: DevTools integration consuming too much memory.
Solutions:
POST /__nuxt_crouton_devtools/api/operations/clear
The operation store uses a circular buffer (max 500 operations) to prevent unbounded memory growth:
// Automatic cleanup
if (operations.length > maxSize) {
operations = operations.slice(0, maxSize)
}
Memory footprint:
Operation tracking has minimal overhead:
Best practice: Clear history periodically during long sessions.
RPC calls are lightweight:
Best practice: Use filtering to reduce response sizes.
The DevTools integration is in Phase 1 (MVP). Future phases will add:
Initial beta release. No migration needed.
When breaking changes occur, this section will provide:
The DevTools integration welcomes contributions!
# Clone repository
git clone https://github.com/pmcp/nuxt-crouton.git
cd nuxt-crouton/packages/crouton-devtools
# Install dependencies
pnpm install
# Start playground
pnpm dev
# Build module
pnpm build
# Run in playground
cd playground
pnpm dev
# Open DevTools and test features
See CONTRIBUTING.md for full guidelines.
No. The DevTools integration only runs in development mode (nuxt dev) and is completely excluded from production builds. It has zero impact on production performance or bundle size.
However, since it's a beta package (v0.x), the API may change between versions. Use with caution.
No. The DevTools integration requires Nuxt 4.0.0 or higher. It uses Nuxt 4-specific APIs and module patterns.
No. The package requires @nuxt/devtools to be installed and enabled. The DevTools integration appears as a custom tab within the Nuxt DevTools panel.
No. The module does not load in production environments. All tracking, monitoring, and debugging features are development-only.
Not currently. The UI is bundled with the package and not customizable. Future versions may support theming or plugins.
In development, the impact is minimal:
Yes! Use the RPC endpoints:
// Fetch operations
const ops = await $fetch('/__nuxt_crouton_devtools/api/operations')
// Get statistics
const stats = await $fetch('/__nuxt_crouton_devtools/api/operations/stats')
Only metadata is stored (no request/response bodies):
Request/response bodies are not stored to minimize memory usage.
Not currently. This is a planned feature for Phase 2. For now, you can fetch operations via the RPC API and save manually:
const ops = await $fetch('/__nuxt_crouton_devtools/api/operations')
console.log(JSON.stringify(ops, null, 2))
If the DevTools integration proves valuable and gains community adoption, it will eventually graduate to v1.0 stable with a stable API and semantic versioning guarantees.
The @fyit/crouton-devtools package provides comprehensive development tooling for Crouton collections:
Next Steps: