npm package: @rationalbloks/frontblok-crud
Description: Universal CRUD API layer for RationalBloks frontends
Author: RationalBloks
Latest version: 0.1.2

# @rationalbloks/frontblok-crud

**Universal CRUD API Layer for RationalBloks Frontends**

A generic API layer that works with any entity schema — define your types once, get full CRUD operations everywhere.

---

## 📦 Installation

```bash
npm install @rationalbloks/frontblok-crud
```

Requires peer dependencies:
```bash
npm install react @rationalbloks/frontblok-auth
```

---

## 🚀 Quick Start

### 1. Initialize API (once at app startup)

```typescript
// main.tsx or App.tsx
import { initApi } from '@rationalbloks/frontblok-crud';

initApi(import.meta.env.VITE_DATABASE_API_URL);
```

### 2. Use Hooks in Components

```typescript
// TaskList.tsx
import { useEntityList, useMutation } from '@rationalbloks/frontblok-crud';
import type { Task } from './entities'; // Generated file

function TaskList() {
  const { items, loading, error, refetch } = useEntityList<Task>('tasks');
  const { mutate } = useMutation<Task>('tasks');

  const handleDelete = async (id: string) => {
    await mutate.remove(id);
    refetch();
  };

  if (loading) return <CircularProgress />;
  if (error) return <Alert severity="error">{error.message}</Alert>;

  return (
    <ul>
      {items.map(task => (
        <li key={task.id}>
          {task.title}
          <button onClick={() => handleDelete(task.id)}>Delete</button>
        </li>
      ))}
    </ul>
  );
}
```

### 3. Use Direct API Access

```typescript
import { getApi } from '@rationalbloks/frontblok-crud';
import type { Task } from './entities';

// Get all tasks
const tasks = await getApi().getAll<Task>('tasks');

// Get single task
const task = await getApi().getOne<Task>('tasks', 'uuid-here');

// Create task
const newTask = await getApi().create<Task>('tasks', { title: 'New Task' });

// Update task
const updated = await getApi().update<Task>('tasks', 'uuid-here', { status: 'done' });

// Delete task
await getApi().remove('tasks', 'uuid-here');
```

---

## 📚 API Reference

### Initialization

| Function | Description |
|----------|-------------|
| `initApi(baseUrl, getToken?)` | Initialize the global API instance |
| `getApi()` | Get the global API instance (throws if not initialized) |
| `isApiInitialized()` | Check if API has been initialized |
| `resetApi()` | Reset the API instance (for testing) |

### Hooks

| Hook | Description |
|------|-------------|
| `useEntityList<T>(entityName, options?)` | Fetch list of entities |
| `useEntity<T>(entityName, id?)` | Fetch single entity by ID |
| `useMutation<T>(entityName)` | Create, update, delete entities |
| `useEntityForm<T>(entityName, id?)` | Combined entity + mutation for forms |

### Generator (MCP use only)

| Function | Description |
|----------|-------------|
| `generateEntitiesTs(schema)` | Generate complete entities.ts from schema |
| `validateSchema(schema)` | Validate schema before generation |

---

## 📁 Generated entities.ts Example

Given this schema:
```json
{
  "tasks": {
    "title": { "type": "string", "max_length": 200, "required": true },
    "status": { "type": "string", "max_length": 50, "enum": ["pending", "done"] },
    "due_date": { "type": "date" }
  }
}
```

The generator creates:
```typescript
// entities.ts - Generated by RationalBloks MCP
// DO NOT EDIT MANUALLY

import type { BaseEntity, CreateInput, UpdateInput, EntityRegistry } from '@rationalbloks/frontblok-crud';

// ----------------------------------------------------------------------------
// Task
// ----------------------------------------------------------------------------

export interface Task extends BaseEntity {
  title: string;
  status?: 'pending' | 'done';
  due_date?: string;
}

export type CreateTaskInput = CreateInput<Task>;
export type UpdateTaskInput = UpdateInput<Task>;

// ============================================================================
// ENTITY REGISTRY
// ============================================================================

export const entities = {
  tasks: {
    singular: 'task',
    plural: 'tasks',
    fields: {
      title: { type: 'string', required: true, max_length: 200 },
      status: { type: 'string', enum: ['pending', 'done'] },
      due_date: { type: 'date' }
    },
  },
} as const satisfies EntityRegistry;

export type Entities = typeof entities;
export type EntityName = keyof Entities;
```

---

## 🏗️ Architecture

### Files in this package:

| File | Purpose |
|------|---------|
| `api.ts` | Universal CRUD API client |
| `hooks.ts` | React hooks for data fetching |
| `types.ts` | TypeScript type definitions |
| `utils.ts` | Helper functions |
| `generator.ts` | Generates entities.ts from schema |

---

## 🔗 Integration with frontblok-auth

This package builds on top of `@rationalbloks/frontblok-auth`:

- **frontblok-auth** handles authentication, tokens, and HTTP requests
- **frontblok-crud** adds CRUD operations on top of that HTTP layer
- **entities.ts** in your project defines your data types and entity registry

---

## 📝 License

MIT © RationalBloks Team