useDocyrusDataSourceJsonSchema
Generate a JSON Schema (object schema, properties keyed by field slug) from a Docyrus data source field list.
Installation
pnpm dlx @docyrus/cli add @docyrus/hooks-use-docyrus-data-source-json-schemaThis hook is distributed as source. It is fully standalone — it ships its own JsonSchema type and a Docyrus field-type → JSON Schema mapping, so it has no runtime dependency on the JSON Schema Designer or the form-fields system.
Overview
useDocyrusDataSourceJsonSchema turns an array of Docyrus field descriptors into a standard object JSON Schema (Draft 2020-12 / Draft-07 compatible). Each field becomes one property:
field.slug→ the property key (machine name).field.name→ the propertytitle(user-facing label).field.type→ the propertytype/format(via the built-in field-type map).field.description→ the propertydescription.
Use it to drive AI Structured Outputs / tool definitions, runtime validation (Ajv, Zod-from-JSON-Schema, etc.), form generation, or any flow that needs a machine-readable contract for a data source.
The hook is a pure, memoized transform — no state, no effects, no fetching.
Usage
'use client';
import { useDocyrusDataSourceJsonSchema } from '@/hooks/use-docyrus-data-source-json-schema';
const fields = [
{ slug: 'full_name', name: 'Full Name', type: 'field-text', description: 'Contact full name' },
{ slug: 'email', name: 'Email', type: 'field-email' },
{ slug: 'status', name: 'Status', type: 'field-status', description: 'Pipeline stage' },
{ slug: 'tags', name: 'Tags', type: 'field-tagSelect' },
{ slug: 'revenue', name: 'Annual Revenue', type: 'field-money' },
];
export function ContactSchema() {
const schema = useDocyrusDataSourceJsonSchema(fields, {
title: 'Contact',
description: 'A CRM contact record',
});
return <pre>{JSON.stringify(schema, null, 2)}</pre>;
}Produces:
{
"type": "object",
"properties": {
"full_name": { "type": "string", "title": "Full Name", "description": "Contact full name" },
"email": { "type": "string", "format": "email", "title": "Email" },
"status": { "type": "string", "title": "Status", "description": "Pipeline stage" },
"tags": { "type": "array", "items": { "type": "string" }, "title": "Tags" },
"revenue": { "type": "number", "title": "Annual Revenue" }
},
"additionalProperties": true,
"title": "Contact",
"description": "A CRM contact record"
}OpenAI Structured Outputs (strict mode)
Set strict: true to constrain the output to OpenAI Structured Outputs rules — additionalProperties: false plus every field slug listed in required:
const schema = useDocyrusDataSourceJsonSchema(fields, { title: 'Contact', strict: true });
// schema.additionalProperties === false
// schema.required === ['full_name', 'email', 'status', 'tags', 'revenue']Marking fields required
// every field required
useDocyrusDataSourceJsonSchema(fields, { required: true });
// only specific slugs required
useDocyrusDataSourceJsonSchema(fields, { required: ['full_name', 'email'] });Refining individual fields with overrides
The built-in mapping uses pragmatic defaults (single-choice / reference fields → string, multi-choice → array of string, structured fields → open object). When a field needs a tighter shape, deep-merge an override keyed by slug:
const schema = useDocyrusDataSourceJsonSchema(fields, {
overrides: {
// narrow an enum/status field to a fixed set of option ids
status: { enum: ['lead', 'qualified', 'won', 'lost'] },
// describe the shape of a relation reference
owner: { type: 'object', properties: { id: { type: 'string' }, name: { type: 'string' } } },
},
});Overrides are deep-merged onto the generated property (override wins; nested objects merge recursively), so title/description derived from the field metadata are preserved unless you replace them explicitly.
Outside React
Both buildDataSourceJsonSchema and fieldToJsonSchema are pure and can be called from server components, API routes, or AI tool-definition builders:
import { buildDataSourceJsonSchema } from '@/hooks/use-docyrus-data-source-json-schema';
const schema = buildDataSourceJsonSchema(fields, { strict: true });API Reference
useDocyrusDataSourceJsonSchema(fields, options?)
| Parameter | Type | Description |
|---|---|---|
fields | DataSourceFieldDescriptor[] | Field list. Each entry: { slug, name, type, description? }. |
options | UseDocyrusDataSourceJsonSchemaOptions | Generation options (see below). |
Returns a memoized JsonSchema object. Memoization keys on fields and each option — pass a stable fields reference to avoid rebuilding on every render.
DataSourceFieldDescriptor
| Field | Type | Description |
|---|---|---|
slug | string | Machine name → JSON Schema property key. Fields without a slug are skipped. |
name | string | User-facing label → property title. |
type | IFieldType | Docyrus field type (e.g. field-text, field-email, field-status). Drives type / format. |
description | string | null | Optional → property description. |
UseDocyrusDataSourceJsonSchemaOptions
| Option | Type | Default | Description |
|---|---|---|---|
title | string | — | title for the root object schema. |
description | string | — | description for the root object schema. |
required | boolean | string[] | — | true → all slugs required; string[] → listed slugs required; omitted → no required array. |
strict | boolean | false | OpenAI Structured Outputs mode: forces additionalProperties: false + all slugs required. Overrides required and additionalProperties. |
additionalProperties | boolean | true | Root-level additionalProperties. Ignored when strict. |
includeTitles | boolean | true | Emit each property's title from field.name. |
includeDescriptions | boolean | true | Emit each property's description from field.description. |
includeDialect | boolean | false | Include the $schema dialect keyword on the root. |
dialect | string | DEFAULT_JSON_SCHEMA_DIALECT | Dialect URI used when includeDialect is set. |
overrides | Record<string, JsonSchema> | — | Per-slug schema overrides, deep-merged onto the generated property. |
Exports
| Export | Type | Purpose |
|---|---|---|
useDocyrusDataSourceJsonSchema | (fields, options?) => JsonSchema | React hook (memoized). |
buildDataSourceJsonSchema | (fields, options?) => JsonSchema | Pure builder — usable outside React. |
fieldToJsonSchema | (field, options?) => JsonSchema | Pure single-field → property converter. |
FIELD_TYPE_SCHEMA_MAP | Partial<Record<IFieldType, JsonSchema>> | Field type → base schema fragment map. |
DEFAULT_JSON_SCHEMA_DIALECT | string | Default dialect (https://json-schema.org/draft/2020-12/schema). |
JsonSchema | interface | Self-contained JSON Schema type returned by the hook. |
DataSourceFieldDescriptor | interface | Field descriptor input type. |
UseDocyrusDataSourceJsonSchemaOptions | interface | Options type. |
Field type mapping
The defaults below are intentionally pragmatic. Refine any field with overrides.
| JSON Schema output | Docyrus field types |
|---|---|
string | field-text, field-textarea, field-password, field-phone, field-color, field-icon, field-currency, field-display, field-htmlEditor, field-emailEditor, field-codeEditor, field-markdown, field-formula, field-code, field-identity, field-handlebars, field-fileStorageFolder, field-systemEnum |
string + format | field-email (email), field-url (uri), field-date (date), field-dateTime (date-time), field-time (time) |
number | field-number, field-money, field-percent, field-duration, field-rating |
integer | field-autonumber |
boolean | field-checkbox, field-switch, field-todo |
string (id of choice / reference) | field-enum, field-select, field-radioGroup, field-status, field-approvalStatus, field-userSelect, field-relation, field-locationSelect, field-button |
array of string | field-multiSelect, field-tagSelect, field-userMultiSelect, field-list, field-systemTextArray, field-systemUuidArray |
array of object | field-taskList, field-schemaRepeater |
open object | field-json, field-jsonSchema, field-jsonata, field-adaptiveCard, field-schema, field-dynamic, field-inlineData, field-inlineForm, field-conversationChannel, field-queryBuilder, field-systemBuffer, field-systemVector |
stored-file object | field-file, field-image, field-avatar |
date-range object ({ from, to }) | field-dateRange |
string (fallback) | any unmapped / unknown type |
How It Works
The hook reads FIELD_TYPE_SCHEMA_MAP for each field's base fragment, layers on title / description from the field metadata, deep-merges any per-slug overrides, and assembles the property bag under a root object schema. strict and required only affect the root additionalProperties / required keywords — they never mutate individual property shapes. The whole transform is pure and memoized against fields + options.
Out of scope
- Fetching the field list — pass the data source's fields in yourself (e.g. from
@docyrus/app-utilsDataSourceFieldmetadata). - Resolving enum options or relation targets into concrete schemas — supply those via
overrideswhen you need them. - Validation — feed the returned schema to your validator of choice (Ajv, etc.).
useDocyrusDataImportWizard
One-call wiring of a Docyrus data source to the DataImportWizard — handles upload, analyse, mapping, preview, and import in a single guided flow.
useDocyrusDataTable
One-call wiring of a Docyrus data source to a fully configured DataTable + toolbar (DataGridViewSelect, search, filters, group, sort) — including row fetching with view-derived query parameters and an optional side-panel filter rail.