Property Types
xNet provides 16 property types organized into five categories.
Basic types
Section titled “Basic types”A string property with optional length and pattern constraints.
import { text } from '@xnet/data'
title: text({ required: true, maxLength: 500 })draft: falsedescription: text({ placeholder: 'Enter a description...' })slug: text({ pattern: /^[a-z0-9-]+$/ })| Option | Type | Default | Description |
|---|---|---|---|
required | boolean | false | Reject null/undefined values. |
minLength | number | — | Minimum string length. |
maxLength | number | — | Maximum string length. |
pattern | RegExp | — | Regex pattern to match. |
placeholder | string | — | UI hint (not enforced). |
Infers to: string
Coercion: String(value). Returns null for null/undefined.
number
Section titled “number”A numeric property with optional range and integer constraints.
import { number } from '@xnet/data'
priority: number({ min: 1, max: 5 })score: number({ min: 0, integer: true })| Option | Type | Default | Description |
|---|---|---|---|
required | boolean | false | |
min | number | — | Minimum value. |
max | number | — | Maximum value. |
integer | boolean | false | Round to nearest integer. |
Infers to: number
Coercion: Number(value). If integer, applies Math.round(). Returns null for NaN.
checkbox
Section titled “checkbox”A boolean property with an optional default.
import { checkbox } from '@xnet/data'
completed: checkbox({ default: false })isPublic: checkbox({ default: true })| Option | Type | Default | Description |
|---|---|---|---|
required | boolean | false | |
default | boolean | — | Default value for null/undefined. |
Infers to: boolean
Coercion: 'true'/1 to true, 'false'/0 to false, else Boolean(value).
Temporal types
Section titled “Temporal types”A timestamp stored as Unix milliseconds.
import { date } from '@xnet/data'
dueDate: date()scheduledAt: date({ includeTime: true })| Option | Type | Default | Description |
|---|---|---|---|
required | boolean | false | |
includeTime | boolean | false | UI hint for showing time picker. |
Infers to: number (Unix timestamp in ms)
Coercion: Accepts number, Date objects (.getTime()), ISO strings (Date.parse()). Returns null if unparseable.
Validation: Must be between 0 and year 3000 (32503680000000).
dateRange
Section titled “dateRange”A range with a start and optional end date.
import { dateRange } from '@xnet/data'
timeline: dateRange()sprint: dateRange({ includeTime: true })| Option | Type | Default | Description |
|---|---|---|---|
required | boolean | false | |
includeTime | boolean | false | UI hint. |
Infers to: { start: string; end?: string } (ISO 8601 strings)
Coercion: Parses start and end through new Date() and converts to ISO strings.
Selection types
Section titled “Selection types”select
Section titled “select”A single choice from a predefined list.
import { select } from '@xnet/data'
status: select({ options: [ { id: 'todo', name: 'To Do', color: '#6366f1' }, { id: 'doing', name: 'Doing', color: '#f59e0b' }, { id: 'done', name: 'Done', color: '#10b981' } ] as const, default: 'todo'})| Option | Type | Default | Description |
|---|---|---|---|
options | SelectOption[] | — | Available choices. Each has id, name, optional color. |
required | boolean | false | |
default | string | — | Default option ID. |
Infers to: Union of option IDs (e.g., 'todo' | 'doing' | 'done'). Requires as const on the options array.
Coercion: Returns default for null/undefined. Tries case-insensitive name matching as fallback.
multiSelect
Section titled “multiSelect”Multiple choices from a predefined list.
import { multiSelect } from '@xnet/data'
tags: multiSelect({ options: [ { id: 'bug', name: 'Bug', color: '#ef4444' }, { id: 'feature', name: 'Feature', color: '#3b82f6' }, { id: 'docs', name: 'Docs', color: '#8b5cf6' } ] as const})| Option | Type | Default | Description |
|---|---|---|---|
options | SelectOption[] | — | Available choices. |
required | boolean | false | |
default | string[] | — | Default option IDs. |
Infers to: Union of option IDs as array (e.g., ('bug' | 'feature' | 'docs')[])
Coercion: Returns default ?? [] for null/undefined. Coerces single string to [value]. Filters invalid entries.
Reference types
Section titled “Reference types”relation
Section titled “relation”A reference to another node by ID.
import { relation } from '@xnet/data'
project: relation({ target: 'xnet://my-app/Project' })children: relation({ multiple: true })| Option | Type | Default | Description |
|---|---|---|---|
target | SchemaIRI | — | Constrain to a specific schema (optional). |
required | boolean | false | |
multiple | boolean | false | Allow array of references. |
Infers to: string (single) or string[] (multiple)
Coercion: Returns null/[] for null/undefined. Filters empty strings.
See Relations for patterns and temp ID resolution in transactions.
person
Section titled “person”A reference to a user by DID.
import { person } from '@xnet/data'
assignee: person()collaborators: person({ multiple: true })| Option | Type | Default | Description |
|---|---|---|---|
required | boolean | false | |
multiple | boolean | false | Allow array of DIDs. |
Infers to: string (DID) or string[] (multiple DIDs)
Validation: Must match DID pattern: /^did:[a-z]+:[a-zA-Z0-9._:-]+$/
Coercion: Returns null/[] for null/undefined. Filters invalid DIDs.
Rich types
Section titled “Rich types”A validated URL string.
import { url } from '@xnet/data'
website: url()repository: url({ placeholder: 'https://github.com/...' })| Option | Type | Default | Description |
|---|---|---|---|
required | boolean | false | |
placeholder | string | — | UI hint. |
Infers to: string
Validation: Must match /^https?:\/\/.+/i
Coercion: Trims whitespace. Auto-prepends https:// if no protocol present.
A validated email string.
import { email } from '@xnet/data'
contactEmail: email()| Option | Type | Default | Description |
|---|---|---|---|
required | boolean | false | |
placeholder | string | — | UI hint. |
Infers to: string
Validation: Must match /^[^\s@]+@[^\s@]+\.[^\s@]+$/
Coercion: Trims and lowercases.
A validated phone number string.
import { phone } from '@xnet/data'
contactPhone: phone()| Option | Type | Default | Description |
|---|---|---|---|
required | boolean | false | |
placeholder | string | — | UI hint. |
Infers to: string
Validation: Must match /^[+]?[(]?[0-9]{1,4}[)]?[-\s./0-9]*$/ with at least 7 digits.
Coercion: Trims, collapses whitespace. Preserves formatting.
A content-addressed file reference.
import { file } from '@xnet/data'
avatar: file({ accept: ['image/*'], maxSize: 5 * 1024 * 1024 })attachments: file({ multiple: true })| Option | Type | Default | Description |
|---|---|---|---|
required | boolean | false | |
multiple | boolean | false | Allow array of files. |
accept | string[] | — | Allowed MIME types (e.g., ['image/*', 'application/pdf']). |
maxSize | number | — | Maximum file size in bytes. |
Infers to: FileRef or FileRef[]
interface FileRef { cid: string // Content-addressed ID name: string // Original filename mimeType: string // MIME type size: number // File size in bytes}Auto-populated types
Section titled “Auto-populated types”These are read-only fields populated automatically by the system.
created
Section titled “created”Timestamp of when the node was created.
import { created } from '@xnet/data'
createdAt: created()Infers to: number (Unix timestamp in ms)
Behavior: Set to Date.now() at creation time. Read-only afterward.
updated
Section titled “updated”Timestamp of the last modification.
import { updated } from '@xnet/data'
updatedAt: updated()Infers to: number (Unix timestamp in ms)
Behavior: Set to Date.now() on every update. Read-only.
createdBy
Section titled “createdBy”DID of the user who created the node.
import { createdBy } from '@xnet/data'
author: createdBy()Infers to: string (DID)
Behavior: Set to the author’s DID at creation time. Read-only afterward.
Summary table
Section titled “Summary table”| Type | Infers to | Validates | Notable |
|---|---|---|---|
text | string | length, pattern | |
number | number | min, max, integer | |
checkbox | boolean | has default | |
date | number | 0 to year 3000 | stored as ms timestamp |
dateRange | { start, end? } | valid dates | ISO 8601 strings |
select | literal union | option IDs | use as const |
multiSelect | literal union[] | option IDs | use as const |
relation | string | string[] | non-empty | supports temp IDs |
person | string | string[] | DID pattern | did:*:* |
url | string | http(s) | auto-prepends https |
email | string | email pattern | lowercased |
phone | string | phone pattern | 7+ digits |
file | FileRef | FileRef[] | cid, name, mimeType, size | content-addressed |
created | number | auto, read-only | |
updated | number | auto, read-only | |
createdBy | string (DID) | auto, read-only |
Related
Section titled “Related”defineSchema— using these types in a schema- Relations — patterns for linking nodes
- Type Inference — how types flow to hooks