npm package: @ortha/admin-utils
Description: Shared admin utilities — AJV-based form validation, react-hook-form resolvers, and structured API error-to-form mapping. Used across all admin feature plugins for consistent form handling.
Latest version: 0.0.4

# @ortha/admin-utils

Shared admin utilities — AJV-based form validation, react-hook-form resolvers, and structured API error-to-form mapping. Used across all admin feature plugins for consistent form handling.

## Installation

Internal monorepo dependency — import directly:

```ts
import {
    ajvResolver,
    handleMutationError,
    ajvInstance
} from '@ortha/admin-utils';
```

## Usage

### Form validation with AJV resolver

```ts
import { useForm } from 'react-hook-form';
import { ajvResolver } from '@ortha/admin-utils';

const schema = {
    type: 'object',
    properties: {
        email: { type: 'string', format: 'email' },
        name: { type: 'string', minLength: 1 }
    },
    required: ['email', 'name']
};

const { register, handleSubmit, formState } = useForm({
    resolver: ajvResolver(schema)
});
```

### Handling mutation errors

```ts
import { handleMutationError } from '@ortha/admin-utils';

const mutation = useMutation({
    mutationFn: createUser,
    onError: (error) => {
        handleMutationError(
            error,
            { setError },
            {
                messages: {
                    // Page-specific: {status}.{code}.{path}
                    '409.EMAIL_TAKEN.email': 'This email is already in use',
                    // Shared: {status}.{code}
                    '409.EMAIL_TAKEN': 'Email conflict',
                    // Status fallback
                    '500': 'Something went wrong'
                }
            }
        );
    }
});
```

### URL search string decoding

```ts
import { toReadableSearchString } from '@ortha/admin-utils';

// Decodes %5B / %5D to readable [] in URL params
const readable = toReadableSearchString(searchParams.toString());
```

## API Reference

| Export                       | Kind     | Description                                           |
| ---------------------------- | -------- | ----------------------------------------------------- |
| `ajvInstance`                | instance | Pre-configured AJV instance (with `ajv-formats`)      |
| `ajvResolver()`              | factory  | Creates a `react-hook-form` resolver from JSON Schema |
| `handleMutationError()`      | function | Maps API errors to `react-hook-form` `setError` calls |
| `toReadableSearchString()`   | function | Decodes `%5B`/`%5D` in URL params to readable `[]`    |
| `AjvResolverOptions`         | type     | Options for the AJV resolver factory                  |
| `HandleMutationErrorOptions` | type     | Options for error handler (message maps)              |

## Error Handling — Three-Level Resolution

`handleMutationError()` resolves error messages using a three-level priority system:

1. **Page-specific exact match**: `{status}.{code}.{path}` — field-level error for a specific page
2. **Shared cross-page match**: `{status}.{code}` — generic error for a status+code combo
3. **Status-level fallback**: status code only — catch-all for a given HTTP status

Supports both structured `details[]` arrays (field-level errors) and legacy `errors` objects.

## Internal Structure

```
src/lib/
├── types/index.ts                  # AjvResolverOptions type
├── ajvInstance/index.ts            # Configured AJV instance
├── ajvResolver/index.ts            # react-hook-form resolver factory
├── handleMutationError/index.ts    # API error → form error mapper
└── toReadableSearchString/index.ts # URL bracket decoding utility
```

## Key Patterns

- `ajvResolver()` maps AJV validation errors to `react-hook-form` `FieldErrors`.
- All form validation across admin plugins uses this resolver.
- `handleMutationError()` is called in TanStack Query `onError` callbacks.
- The `ajvInstance` is pre-configured with `ajv-formats` for email, URI, etc.

## Building

```bash
nx build admin-utils
```