import type { ForeignKey } from '@dxos/echo-protocol'; import { EID, type EntityId, type URI } from '@dxos/keys'; import type * as Database from './Database'; import * as Entity from './Entity'; import * as internal from './internal'; import * as Obj from './Obj'; import type * as Ref from './Ref'; import type * as Tag from './Tag'; import * as Type from './Type'; export type Endpoints = { [Source]: Source; [Target]: Target; }; /** * Base type for all ECHO relations. * @private */ interface BaseRelation extends internal.AnyEntity, Endpoints, Entity.OfKind { } /** * Relation with no known properties beyond id, kind, source, and target. * Use this when the relation's schema/properties are not known. * * NOTE: This is a TypeScript type only, not a schema. * To validate that a value is an ECHO relation, use `Relation.isRelation`. */ export interface Unknown extends BaseRelation { } /** * Runtime Effect schema for any ECHO relation. * Use for validation, parsing, or as a reference target for collections. * A relation has `id`, source, and target fields plus any additional properties. * * NOTE: `Schema.is(Type.Relation)` does STRUCTURAL validation only (checks for `id` field). * Use `Relation.isRelation()` for proper ECHO instance type guards that check the KindId brand. * * @example * ```ts * // Structural type guard (accepts any object with id field) * if (Schema.is(Type.Relation)(unknownValue)) { ... } * * // ECHO instance type guard (checks KindId brand) * if (Relation.isRelation(unknownValue)) { ... } * ``` */ export declare const Unknown: internal.UnknownTypeSchema; /** * Relation type with specific source and target types. */ export type OfShape = BaseRelation & Props; /** * Base type for snapshot relations (has SnapshotKindId instead of KindId). */ interface BaseRelationSnapshot extends internal.AnyEntity, Endpoints { readonly [Entity.SnapshotKindId]: internal.EntityKind.Relation; readonly id: EntityId; } /** * JSON-encoded properties for relations. */ export interface BaseRelationJson { id: string; [internal.ATTR_RELATION_SOURCE]: string; [internal.ATTR_RELATION_TARGET]: string; } /** * Immutable snapshot of an ECHO relation. * Branded with SnapshotKindId (not KindId). * Property values are frozen at the time the snapshot was created. * Returned by getSnapshot() and hooks. */ export type Snapshot = Omit & BaseRelationSnapshot; export declare const Source: unique symbol; export type Source = typeof Source; export declare const Target: unique symbol; export type Target = typeof Target; /** * Get relation source type. */ export type SourceOf = A extends Endpoints ? S : never; /** * Get relation target type. */ export type TargetOf = A extends Endpoints ? T : never; /** * Internal props type for relation instance creation. */ type MakePropsInternal> = { id?: EntityId; [Source]: T[Source]; [Target]: T[Target]; } & Entity.Properties; /** * Props type for relation creation with a given schema. Accepts a `Type.AnyRelation` * entity (created with `Type.makeRelation`) and derives the props shape via * `Type.InstanceType`. Object-kind entities are rejected at the type level — * use `Obj.MakeProps` for those. */ export type MakeProps = MakePropsInternal>; /** * Creates new relation. * @param schema - Relation schema. * @param props - Relation properties. Endpoints are passed as [Relation.Source] and [Relation.Target] keys. * @param meta - Relation metadata. (deprecated; use [Obj.Meta] instead) * @returns */ export declare const make: (type: T, props: NoInfer>) => Type.InstanceType & Entity.OfKind; /** * Test if a value is an instance of a given relation type. * * Mirrors `Obj.instanceOf` but only accepts `Type.AnyRelation` — use * `Obj.instanceOf` for objects and `Type.isType` for `Type.Type` entities. * * @example * ```ts * const isEmployedBy = Relation.instanceOf(EmployedBy); * if (isEmployedBy(relation)) { * // relation is EmployedBy * } * ``` */ export declare const instanceOf: { (schema: S): (value: unknown) => value is Type.InstanceType; (schema: S, value: unknown): value is Type.InstanceType; }; /** * Type guard for relations. * Returns true for both reactive relations and relation snapshots. */ export declare const isRelation: (value: unknown) => value is Unknown; export declare const isSnapshot: (value: unknown) => value is Snapshot; /** * @returns Relation source URI. * Accepts both reactive relations and snapshots. * @throws If the object is not a relation. */ export declare const getSourceURI: (value: Unknown | Snapshot) => EID.EID; /** * @returns Relation target URI. * Accepts both reactive relations and snapshots. * @throws If the object is not a relation. */ export declare const getTargetURI: (value: Unknown | Snapshot) => EID.EID; /** * @returns Relation source. * Accepts both reactive relations and snapshots. * @throws If the object is not a relation. */ export declare const getSource: (relation: T) => SourceOf; /** * @returns Relation target. * Accepts both reactive relations and snapshots. * @throws If the object is not a relation. */ export declare const getTarget: (relation: T) => TargetOf; /** * Makes all properties mutable recursively. * Used to provide a mutable view of a relation within `Relation.update`. */ export type Mutable = internal.Mutable; /** * Perform mutations on an echo relation within a controlled context. * * All mutations within the callback are batched and trigger a single notification * when the callback completes. Direct mutations outside of `Relation.update` will throw * an error for echo relations. * * @param relation - The echo relation to mutate. Use `Obj.update` for objects. * @param callback - The callback that performs mutations on the relation. * * @example * ```ts * const worksFor = Relation.make(EmployedBy, { * [Relation.Source]: person, * [Relation.Target]: company, * role: 'Engineer', * }); * * // Mutate within Relation.update * Relation.update(worksFor, (obj) => { * obj.role = 'Senior Engineer'; * }); * ``` * * Note: Only accepts relations. Use `Obj.update` for objects. */ export declare const update: (relation: T, callback: internal.ChangeCallback) => void; /** * Returns an immutable snapshot of a relation. * The snapshot is branded with SnapshotKindId instead of KindId, * making it distinguishable from the reactive relation at the type level. */ export declare const getSnapshot: (rel: T) => Snapshot; /** * Subscribe to relation updates. * The callback is called synchronously when the relation is modified. * Only accepts reactive relations (not snapshots). * @returns Unsubscribe function. */ export declare const subscribe: (rel: Unknown, callback: () => void) => (() => void); /** * Get a deeply nested property from a relation. * Accepts both reactive relations and snapshots. */ export declare const getValue: (rel: Unknown | Snapshot, path: readonly (string | number)[]) => any; /** * Set a deeply nested property on a relation. * Must be called within a `Relation.update` callback. * * NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable` * parameters, so there is no compile-time error. Enforcement is runtime-only. */ export declare const setValue: (rel: Mutable, path: readonly (string | number)[], value: any) => void; /** * Get the canonical URI of the relation. Returns `URI.URI` — today always an EID, * but future entity kinds may surface other URI schemes; narrow with `EID.parse(uri)` * or `DXN.tryMake(uri)` at the point of use. Accepts both reactive relations and snapshots. * * @param options.prefer - Controls the URI form (see {@link internal.GetURIOptions}). */ export declare const getURI: (entity: Unknown | Snapshot, options?: internal.GetURIOptions) => URI.URI; /** * @returns The DXN of the relation's type. */ export declare const getTypeURI: (obj: internal.AnyProperties) => URI.URI | undefined; /** * Get the type entity (`Type.AnyRelation`) the relation was created from. * * Returns `undefined` when the relation's type isn't registered in this * runtime (e.g. a freshly deserialized snapshot whose type entity hasn't been * wired up yet, or a relation loaded from storage before its schema is known). * To get the Effect Schema from the returned entity, use `Type.getSchema(...)`. */ export declare const getType: (relation: Unknown | Snapshot) => Type.AnyRelation | undefined; /** * @returns The typename of the relation's type. * Accepts both reactive relations and snapshots. */ export declare const getTypename: (entity: Unknown | Snapshot) => string | undefined; /** * Get the database the relation belongs to. * Accepts both reactive relations and snapshots. */ export declare const getDatabase: (entity: Unknown | Snapshot) => Database.Database | undefined; /** * Property that accesses metadata for an entity. * * Alias for `Entity.Meta`. */ export declare const Meta: symbol; /** * Deeply read-only version of EntityMeta. */ export type ReadonlyMeta = internal.ReadonlyMeta; /** * Mutable meta type returned by `Relation.getMeta` inside a `Relation.update` callback. */ export type Meta = internal.Meta; /** * Get the metadata for a relation. * Returns mutable meta when passed a mutable relation (inside `Relation.update` callback). * Returns read-only meta when passed a regular relation or snapshot. */ export declare function getMeta(entity: Mutable): Meta; export declare function getMeta(entity: Unknown | Snapshot): ReadonlyMeta; /** * @returns Foreign keys for the relation from the specified source. * Accepts both reactive relations and snapshots. */ export declare const getKeys: (entity: Unknown | Snapshot, source: string) => ForeignKey[]; /** * Delete all keys from the relation for the specified source. * Must be called within a `Relation.update` callback. * * NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable` * parameters, so there is no compile-time error. Enforcement is runtime-only. */ export declare const deleteKeys: (entity: Mutable, source: string) => void; /** * Add a tag to the relation. * Must be called within a `Relation.update` callback. * * NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable` * parameters, so there is no compile-time error. Enforcement is runtime-only. */ export declare const addTag: (entity: Mutable, tag: Ref.Ref) => void; /** * Remove a tag from the relation. * Must be called within a `Relation.update` callback. * * NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable` * parameters, so there is no compile-time error. Enforcement is runtime-only. */ export declare const removeTag: (entity: Mutable, tag: Ref.Ref) => void; /** * Check if the relation is deleted. * Accepts both reactive relations and snapshots. */ export declare const isDeleted: (entity: Unknown | Snapshot) => boolean; /** * Get the label of the relation. * Accepts both reactive relations and snapshots. * * @param options.fallback `'typename'` returns the relation's typename when no * label is set (e.g. `org.dxos.type.table`). */ export declare const getLabel: (entity: Unknown | Snapshot, options?: internal.GetLabelOptions) => string | undefined; /** * Set the label of the relation. * Must be called within a `Relation.update` callback. * * NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable` * parameters, so there is no compile-time error. Enforcement is runtime-only. */ export declare const setLabel: (entity: Mutable, label: string) => void; /** * Get the description of the relation. * Accepts both reactive relations and snapshots. */ export declare const getDescription: (entity: Unknown | Snapshot) => string | undefined; /** * Set the description of the relation. * Must be called within a `Relation.update` callback. * * NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable` * parameters, so there is no compile-time error. Enforcement is runtime-only. */ export declare const setDescription: (entity: Mutable, description: string) => void; /** * JSON representation of a relation. */ export type JSON = internal.ObjectJSON; /** * Converts relation to its JSON representation. * Accepts both reactive relations and snapshots. */ export declare const toJSON: (entity: Unknown | Snapshot) => JSON; /** * Comparator function type for sorting relations. * Accepts both reactive relations and snapshots. */ export type Comparator = internal.Comparator; export declare const sortByLabel: Comparator; export declare const sortByTypename: Comparator; export declare const sort: (...comparators: Comparator[]) => Comparator; export declare const VersionTypeId: "~@dxos/echo/VersionTypeId"; export declare const isVersion: (entity: unknown) => entity is internal.EntityVersion; /** * Represent relation version. */ export type Version = internal.EntityVersion; /** * Returns the version of the relation. * Accepts both reactive relations and snapshots. */ export declare const version: (entity: Unknown | Snapshot) => Version; export declare const atom: (relation: T) => import("@effect-atom/atom/Atom").Atom>; export {}; //# sourceMappingURL=Relation.d.ts.map