UNPKG

trellis

Version:

Agentic State Engine — event-sourced causal graph with branching, decision traces, and realtime sync for AI-native applications

139 lines 6.77 kB
/** * Trellis Schema — typed entity definitions over the ontology. * * `defineType` is the Trellis answer to Jazz's `co.map`: one definition produces * BOTH a runtime {@link SchemaDefinition} (registerable in the kernel via * `createOntology`) AND a static TypeScript type via {@link InferType}. Zod * handles leaf validation + inference; a second options bag handles the graph * semantics Zod can't express — relation cardinality, rollups, formulas, tier. * * This deliberately targets `SchemaDefinition` (the live kernel path consumed by * schema/rollup middleware), not the legacy `OntologySchema` registry — see * {@link TrellisType.toOntologySchema} for the legacy adapter. * * import { defineType, rel } from 'trellis/schema'; * import { z } from 'zod'; * * const NavItem = defineType('NavItem', { * label: z.string(), * icon: z.string().optional(), * order: z.number(), * }, { title: 'label' }); * * const NavSection = defineType('NavSection', { * label: z.string(), * order: z.number(), * collapsed: z.boolean(), * }, { title: 'label', relations: { items: rel(() => NavItem, 'many') } }); * * type Section = InferType<typeof NavSection>; * // { id: string; type: 'NavSection'; label: string; order: number; * // collapsed: boolean; items: Ref<typeof NavItem>[] } * * @module trellis/schema */ import { z } from 'zod'; import type { FieldSyncTier, OntologySchema, OntologyTier, PropertyType, PropertyValueSpecification, SchemaDefinition } from '../core/ontology/types.js'; /** * A reference to another entity. Unresolved it is the target's id (a `string`); * a future `resolve` option swaps it for the loaded {@link InferType} value. */ export type Ref<S extends AnyType = AnyType> = string & { readonly __ref?: S; }; export type RelTarget<S extends AnyType> = (() => S) | string; export interface Relation<S extends AnyType, C extends 'one' | 'many'> { readonly target: RelTarget<S>; readonly cardinality: C; } /** Declare a relation field. Target may be a thunk (define-order safe) or a name. */ export declare function rel<S extends AnyType, C extends 'one' | 'many' = 'one'>(target: RelTarget<S>, cardinality?: C): Relation<S, C>; export type RelationMap = Record<string, Relation<AnyType, 'one' | 'many'>>; export interface ComputedField { readonly spec: Partial<PropertyValueSpecification> & { valueType: PropertyType; }; } export type ComputedMap = Record<string, ComputedField>; /** Declare a rollup over a relation (e.g. count of linked items). */ export declare function rollup(cfg: NonNullable<PropertyValueSpecification['rollup']>): ComputedField; /** Declare a formula field. */ export declare function formula(expr: string): ComputedField; export interface TrellisType<Name extends string, Z extends z.ZodRawShape, R extends RelationMap, C extends ComputedMap> { readonly type: Name; /** Leaf validator (does not include relations/computed). */ readonly zod: z.ZodObject<Z>; readonly relations: R; readonly computed: C; /** Kernel-facing schema, keyed by `@id` = `trellis:<Name>`. */ readonly definition: SchemaDefinition; /** Adapter to the legacy OntologyRegistry (relation resolution only). */ toOntologySchema(): OntologySchema; } export type AnyType = TrellisType<string, z.ZodRawShape, RelationMap, ComputedMap>; type RelValue<X> = X extends Relation<infer S, infer C> ? C extends 'many' ? Ref<S>[] : Ref<S> : never; export type InferType<T> = T extends TrellisType<infer Name, infer Z, infer R, infer C> ? { id: string; type: Name; } & z.infer<z.ZodObject<Z>> & { [K in keyof R]: RelValue<R[K]>; } & { readonly [K in keyof C]: number; } : never; /** Target entity schema of a relation field. */ type RelationTarget<R> = R extends Relation<infer S, 'one' | 'many'> ? S : never; /** * Typed `resolve` spec for {@link InferResolvedType} — mirrors runtime * {@link import('./resolve.js').ResolveSpec} but keyed to declared relations. * * `{ items: true }` — expand `items` to full entities. * `{ items: { section: true } }` — expand `items`, then each item's `section`. */ export type ResolveSpecFor<T extends AnyType> = { [K in keyof T['relations'] & string]?: true | ResolveSpecFor<RelationTarget<T['relations'][K]>>; }; /** Expand one relation key according to a resolve spec entry (`true` or nested). */ type ApplyResolve<Field extends Relation<AnyType, 'one' | 'many'>, Spec> = Field extends Relation<infer S, infer C> ? [Spec] extends [true] ? C extends 'many' ? InferType<S>[] : InferType<S> : Spec extends ResolveSpecFor<S> ? C extends 'many' ? InferResolvedType<S, Spec>[] : InferResolvedType<S, Spec> : RelValue<Field> : never; /** * Like {@link InferType}, but relation keys in `resolve` are expanded entity * shapes instead of `Ref` ids. Nested objects recurse (TRL-4). */ export type InferResolvedType<T extends AnyType, R extends ResolveSpecFor<T>> = T extends TrellisType<infer Name, infer Z, infer Rel, infer C> ? { id: string; type: Name; } & z.infer<z.ZodObject<Z>> & { [K in keyof Rel]: K extends keyof R ? ApplyResolve<Rel[K], R[K]> : RelValue<Rel[K]>; } & { readonly [K in keyof C]: number; } : never; /** * Infer the entity array shape returned by typed live reads (`useEntities`, * `entitiesStore`) from optional read options. */ export type InferEntitiesRead<S extends AnyType, O> = O extends { resolve: infer R; } ? R extends ResolveSpecFor<S> ? InferResolvedType<S, R>[] : InferType<S>[] : InferType<S>[]; /** * Infer the entity shape returned by typed single-entity reads (`useEntity`, * `entityStore`) from optional read options. */ export type InferEntityRead<S extends AnyType, O> = O extends { resolve: infer R; } ? R extends ResolveSpecFor<S> ? InferResolvedType<S, R> | null : InferType<S> | null : InferType<S> | null; export interface DefineTypeOptions<Z extends z.ZodRawShape, R extends RelationMap, C extends ComputedMap> { /** Which leaf key is the entity's `title` property. */ title?: Extract<keyof Z, string>; relations?: R; computed?: C; /** Per-field sync tier (ADR 0018). */ fieldSync?: Partial<Record<Extract<keyof Z, string>, FieldSyncTier>>; /** Defaults to 'user'. Core/system are reserved for shipped schemas. */ tier?: OntologyTier; version?: string; /** Parent type name (`subClassOf`). */ extends?: string; label?: string; } export declare function defineType<Name extends string, Z extends z.ZodRawShape, R extends RelationMap = Record<never, never>, C extends ComputedMap = Record<never, never>>(type: Name, shape: Z, opts?: DefineTypeOptions<Z, R, C>): TrellisType<Name, Z, R, C>; export {}; //# sourceMappingURL=define.d.ts.map