# useDocyrusDataSourceJsonSchema URL: /docs/native/hooks/use-docyrus-data-source-json-schema Generate a JSON Schema (object schema, properties keyed by field slug) from a Docyrus data source field list. ## Installation ```bash pnpm dlx @docyrus/cli add @docyrus/rn-hooks-use-docyrus-data-source-json-schema ``` This 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 beyond React. The only import is the `IFieldType` union from the native form-fields types (type-only). ## 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 property `title` (user-facing label). - `field.type` → the property `type` / `format` (via the built-in field-type map). - `field.description` → the property `description`. 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 ```tsx import { Text } from 'react-native'; import { useDocyrusDataSourceJsonSchema, type DataSourceFieldDescriptor } from '@/hooks/docyrus-native/use-docyrus-data-source-json-schema'; // Module scope keeps the reference stable, so the schema is built once. const fields: DataSourceFieldDescriptor[] = [ { 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 ; } ``` Produces: ```json { "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`: ```tsx const schema = useDocyrusDataSourceJsonSchema(fields, { title: 'Contact', strict: true }); // schema.additionalProperties === false // schema.required === ['full_name', 'email', 'status', 'tags', 'revenue'] ``` ### Marking fields required ```tsx // 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: ```tsx 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 outside React (background tasks, tests, AI tool-definition builders): ```ts import { buildDataSourceJsonSchema } from '@/hooks/docyrus-native/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` | `—` | 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>` | 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-utils` `DataSourceField` metadata). - Resolving enum options or relation targets into concrete schemas — supply those via `overrides` when you need them. - Validation — feed the returned schema to your validator of choice (Ajv, etc.).