defineSchema
Quick example
Section titled “Quick example”import { defineSchema, text, select, checkbox, relation } from '@xnet/data'
export const TaskSchema = defineSchema({ name: 'Task', namespace: 'xnet://my-app/', properties: { title: text({ required: true, maxLength: 500 }), status: select({ options: [ { id: 'todo', name: 'To Do', color: '#6366f1' }, { id: 'doing', name: 'Doing', color: '#f59e0b' }, { id: 'done', name: 'Done', color: '#10b981' } ] as const }), completed: checkbox({ default: false }), project: relation({ target: 'xnet://my-app/Project' }) }})Signature
Section titled “Signature”function defineSchema<P extends Record<string, PropertyBuilder>>( options: DefineSchemaOptions<P>): DefinedSchema<P>Options
Section titled “Options”| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Schema name (e.g., 'Task'). Used in the schema IRI. |
namespace | `xnet://${string}/` | Yes | Namespace for grouping. Must end with /. |
properties | Record<string, PropertyBuilder> | Yes | Property definitions using builder functions. |
extends | DefinedSchema | No | Parent schema to inherit properties from. |
document | 'yjs' | 'automerge' | No | CRDT document type. Required for useNode rich text. |
Schema IRI
Section titled “Schema IRI”The schema’s unique identifier is ${namespace}${name}:
defineSchema({ name: 'Task', namespace: 'xnet://my-app/' })// Schema IRI: 'xnet://my-app/Task'Each property also gets an IRI: ${schemaId}#${propertyName}:
xnet://my-app/Task#titlexnet://my-app/Task#statusReturn value: DefinedSchema
Section titled “Return value: DefinedSchema”| Field/Method | Type | Description |
|---|---|---|
schema | Schema | The JSON-LD compatible schema object. |
validate(node) | (unknown) => ValidationResult | Validate a node against this schema. |
create(props, options) | (props, options) => Node | Create a new node (used internally). |
is(node) | (node) => boolean | Type guard — check if a node matches this schema. |
_schemaId | string | The computed schema IRI. |
_properties | P | Property builders (for type inference). |
ValidationResult
Section titled “ValidationResult”interface ValidationResult { valid: boolean errors: ValidationError[] // { path, message, value? }}Validation checks:
- Required system fields (
id,schemaId,createdAt,createdBy) schemaIdmatches the schemacreatedBystarts withdid:key:- Each property’s constraints (required, min/max, pattern, etc.)
Adding rich text support
Section titled “Adding rich text support”Add document: 'yjs' to enable collaborative editing via useNode:
export const PageSchema = defineSchema({ name: 'Page', namespace: 'xnet://my-app/', properties: { title: text({ required: true }), icon: text() }, document: 'yjs'})When document: 'yjs' is set, useNode creates a Y.Doc for the node and manages P2P sync for its content.
Schema inheritance
Section titled “Schema inheritance”Use extends to inherit properties from a parent schema:
const BaseSchema = defineSchema({ name: 'Base', namespace: 'xnet://my-app/', properties: { title: text({ required: true }), tags: multiSelect({ options: ['draft', 'published'] as const }) }})
const ArticleSchema = defineSchema({ name: 'Article', namespace: 'xnet://my-app/', extends: BaseSchema, properties: { body: text(), publishedAt: date() }})// ArticleSchema has: title, tags, body, publishedAtCoercion
Section titled “Coercion”When you create or update a node, property values are coerced through the property builder:
text()— callsString(value), trims whitespacenumber()— callsNumber(value), appliesMath.round()ifintegerselect()— validates against option IDs, tries case-insensitive name matching as fallbackdate()— acceptsnumber,Date, or ISO string; normalizes to timestampemail()— trims and lowercasesurl()— auto-prependshttps://if no protocol
This means your data is always normalized regardless of what the user types.
Dev-time warnings
Section titled “Dev-time warnings”In development, defineSchema warns if:
- A
text()property has a name that looks like a reference (e.g.,targetId,parentId), suggesting you userelation()instead
Related
Section titled “Related”- Property Types — all 16 property builders
- Relations — linking nodes together
- Type Inference — how TypeScript types flow