import * as Effect from 'effect/Effect'; import * as Option from 'effect/Option'; import type { ForeignKey } from '@dxos/echo-protocol'; import { EntityId, type URI } from '@dxos/keys'; import type * as Database from './Database'; import * as Entity from './Entity'; import * as Err from './Err'; import * as internal from './internal'; import * as Ref from './Ref'; import type * as Tag from './Tag'; import * as Type from './Type'; /** * Base type for all ECHO objects. */ interface BaseObj extends internal.AnyEntity, Entity.OfKind { } /** * Object type with specific properties. */ export type OfShape = BaseObj & Props; /** * Object with no known properties beyond id and kind. * Use this when the object's schema/properties are not known. * For objects with arbitrary properties, use `Obj.AnyProps`. * * NOTE: This is a TypeScript type only, not a schema. * To validate that a value is an ECHO object, use `Schema.is(Type.Obj)`. */ export interface Unknown extends BaseObj { } /** * Runtime Effect schema for any ECHO object. * Use for validation, parsing, or as a reference target for collections. * * NOTE: `Schema.is(Type.Obj)` does STRUCTURAL validation only (checks for `id` field). * Use `Obj.isObject()` 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.Obj)(unknownValue)) { ... } * * // ECHO instance type guard (checks KindId brand) * if (Obj.isObject(unknownValue)) { ... } * * // Reference to any object type * const Collection = Schema.Struct({ * objects: Schema.Array(Ref.Ref(Obj.Unknown)), * }).pipe(Type.makeObject(DXN.make('com.example.type.collection', '0.1.0'))); * ``` */ export declare const Unknown: internal.UnknownTypeSchema; /** * Object with arbitrary properties. * * NOTE: Due to how TypeScript works, this type is not assignable to a specific schema type. * In that case, use `Obj.instanceOf` to check if an object is of a specific type. * * Prefer using `Obj.Unknown` when you don't need to access arbitrary properties. */ export interface Any extends BaseObj, internal.AnyProperties { } /** * Base type for snapshot objects (has SnapshotKindId instead of KindId). */ interface BaseSnapshot extends internal.AnyEntity { readonly [Entity.SnapshotKindId]: typeof Entity.Kind.Object; readonly id: EntityId; } /** * Immutable snapshot of an ECHO object. * Branded with SnapshotKindId (not KindId). * Property values are frozen at the time the snapshot was created. * Returned by getSnapshot() and hooks like useObject(). * * Snapshots are structurally identical to reactive objects but have a different brand, * making them distinguishable at the TypeScript level. Neither is assignable to the other. */ export type Snapshot = Omit & BaseSnapshot; /** * JSON-encoded properties for objects. */ export interface BaseObjJson { id: string; } /** * Props type for object creation with a given type. Accepts a `Type.AnyObj` * entity and derives the instance shape via `Type.InstanceType`. Relation-kind * entities are rejected at the type level — use `Relation.MakeProps` for those. * * When the schema is the unconstrained `Type.AnyObj` (`Obj` — e.g. a * dynamic type from `schemaRegistry.register`), the instance shape is not * statically known, so data props widen to `Record` and the * caller can pass arbitrary fields without a cast. */ export type MakeProps = { id?: EntityId; [Parent]?: Unknown; } & ([keyof Entity.Properties>] extends [never] ? Record : Entity.Properties>); /** * Creates a new echo object of the given schema or `Type.Type`. * * @param typeOrSchema - A static object schema (`Type.makeObject(...)`) or a * `Type.Type` entity (e.g. one returned by `db.addType(schemaEntity)`). * @param props - Object properties. * * Meta can be passed as a symbol in `props`. * * Example: * ```ts * const obj = Obj.make(Person, { [Obj.Meta]: { keys: [...] }, name: 'John' }); * ``` * * Note: Only accepts object schemas / object-kind types, not relation schemas. * Use `Relation.make` for relations. */ export declare function make(type: T, props: NoInfer>): OfShape>; /** * Determine if object is an ECHO object. */ export declare const isObject: (obj: unknown) => obj is Unknown; export declare const isSnapshot: (obj: unknown) => obj is Snapshot; /** * Subscribe to object updates. * The callback is called synchronously when the object is modified. * Only accepts reactive objects (not snapshots). * @returns Unsubscribe function. */ export declare const subscribe: (obj: Unknown, callback: () => void) => (() => void); /** * Returns an immutable snapshot of an object. * The snapshot is branded with SnapshotKindId instead of KindId, * making it distinguishable from the reactive object at the type level. */ export declare const getSnapshot: (obj: T) => Snapshot; /** * Returns the reactive version of an object from the database, given its snapshot. * Inverse of `Obj.getSnapshot`. * * Uses `Obj.getDatabase` internally to get the database from the snapshot, * then resolves the reactive object by ID. * * @param snapshot - A snapshot of the object (from `Obj.getSnapshot`). * @returns Effect that succeeds with the reactive object, or fails with `GetReactiveError`. * @example * ```ts * const snapshot = Obj.getSnapshot(obj); * const reactive = Obj.getReactive(snapshot).pipe( * Effect.runSync * ); * ``` */ export declare const getReactive: (snapshot: Snapshot) => Effect.Effect; /** * Like `Obj.getReactive` but returns `Option.none()` instead of failing when the object * cannot be resolved (no database, object not found). * * @param snapshot - A snapshot of the object (from `Obj.getSnapshot`). * @returns Effect that succeeds with `Option.some(reactive)` or `Option.none()`. */ export declare const getReactiveOption: (snapshot: Snapshot) => Effect.Effect, never>; /** * Synchronous version of `Obj.getReactive`. Returns the reactive object or throws * `GetReactiveError` when the object cannot be resolved (no database, object not found). * * @param snapshot - A snapshot of the object (from `Obj.getSnapshot`). * @returns The reactive object. * @throws {Err.GetReactiveError} When the object cannot be resolved. */ export declare const getReactiveOrThrow: (snapshot: Snapshot) => T; export type CloneOptions = { /** * Retain the original object's ID. * @default false */ retainId?: boolean; /** * Recursively clone referenced objects. * @default false */ deep?: boolean; }; /** * Clones an object or relation. * This does not clone referenced objects, only the properties in the object. * @returns A new object with the same schema and properties. */ export declare const clone: (obj: T, opts?: CloneOptions) => T; /** * Makes all properties mutable recursively. * Used to provide a mutable view of an object within `Obj.update`. */ export type Mutable = internal.Mutable; /** * Perform mutations on an echo object within a controlled context. * * All mutations within the callback are batched and trigger a single notification * when the callback completes. Direct mutations outside of `Obj.update` will throw * an error for echo objects. * * This function also works with nested objects within echo objects (e.g., Template structs) * that are reactive at runtime. * * @param obj - The echo object to mutate. Use `Relation.update` for relations. * @param callback - The callback that performs mutations on the object. * * @example * ```ts * const person = Obj.make(Person, { name: 'John', age: 25 }); * * // Mutate within Obj.update * Obj.update(person, (obj) => { * obj.name = 'Jane'; * obj.age = 30; * }); * // ONE notification fires here * * // Direct mutation throws * person.name = 'Bob'; // Error: Cannot modify outside Obj.update() * ``` * * Note: Only accepts objects. Use `Relation.update` for relations. */ export declare const update: (obj: T, callback: internal.ChangeCallback) => void; /** * Get a deeply nested property from an object. * * Similar to lodash.get and getDeep from @dxos/util. * This is the complementary function to setValue. * Accepts both reactive objects and snapshots. * * @param obj - The ECHO object to get the property from. * @param path - Path to the property (array of keys). * @returns The value at the path, or undefined if not found. * * @example * ```ts * const person = Obj.make(Person, { * name: 'John', * addresses: [{ street: '123 Main St' }] * }); * * Obj.getValue(person, ['addresses', 0, 'street']); // '123 Main St' * Obj.getValue(person, ['addresses', 1, 'street']); // undefined * ``` */ export declare const getValue: (obj: Unknown | Snapshot, path: readonly (string | number)[]) => any; /** * Set a deeply nested property on an object, using the object's schema to determine * whether to initialize nested data as an empty object or array. * * Similar to lodash.set and setDeep from @dxos/util, but schema-aware. * Must be called within an `Obj.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. * * @param obj - The mutable ECHO object to set the property on. * @param path - Path to the property (array of keys). * @param value - Value to set. * @returns The value that was set. * * @example * ```ts * const person = Obj.make(Person, { name: 'John' }); * // Person schema has: addresses: Schema.Array(Address) * Obj.update(person, (obj) => { * Obj.setValue(obj, ['addresses', 0, 'street'], '123 Main St'); * }); * // Creates: person.addresses = [{ street: '123 Main St' }] * ``` */ export declare const setValue: (obj: Mutable, path: readonly (string | number)[], value: any) => void; export declare const ID: import("@dxos/keys").EntityIdClass; export type ID = EntityId; /** * Test if an object is an instance of a given object type. * * @example * ```ts * const john = Obj.make(Person, { name: 'John' }); * const isPerson = Obj.instanceOf(Person); * if (isPerson(john)) { * // john is Person * } * ``` * * Only accepts `Type.AnyObj` — use `Relation.instanceOf` for relations and * `Type.isType(value)` to test for `Type.Type` meta-schema entities. */ export declare const instanceOf: { (type: T, _hint?: never, ..._error: ['ERROR: Obj.instanceOf does not accept Type.Type; use Type.isType(value) instead']): never; (type: R, _hint?: never, ..._error: ['ERROR: Obj.instanceOf does not accept relation types; use Relation.instanceOf instead']): never; (schema: S): (value: unknown) => value is Type.InstanceType; (schema: S, value: unknown): value is Type.InstanceType; }; /** * Test if a snapshot is an instance of a schema. * Mirrors `instanceOf` but only accepts values branded with SnapshotKindId. * Use when the value is known to be a snapshot (e.g. from `getSnapshot` or `useObject`). * * @example * ```ts * const snapshot = Obj.getSnapshot(person); * if (Obj.snapshotOf(Person, snapshot)) { * // snapshot is Obj.Snapshot * } * ``` */ export declare const snapshotOf: { (schema: S): (value: unknown) => value is Snapshot>; (schema: S, value: unknown): value is Snapshot>; }; export type { GetURIOptions } from './internal'; /** * Get the URI of the object. * Accepts both reactive objects and snapshots. * * @param options.prefer - Controls the URI form (see {@link GetURIOptions}). */ export declare const getURI: (entity: Unknown | Snapshot, options?: internal.GetURIOptions) => URI.URI; /** * @returns The DXN of the object's type. * @example dxn:com.example.type.person:1.0.0 * @throws If the object is missing its type (corrupted object). */ export declare const getTypeURI: (obj: Unknown | Snapshot) => URI.URI; /** * Get the type entity (`Type.AnyObj`) the object was created from. * * Returns `undefined` when the object's type isn't registered in this runtime * (e.g. a freshly deserialized snapshot whose type entity hasn't been wired * up yet, or an object loaded from storage before its schema is known). To * get the Effect Schema from the returned entity, use `Type.getSchema(...)`. */ export declare const getType: (obj: Unknown | Snapshot) => Type.AnyObj | undefined; /** * @returns The typename of the object's type. * Accepts both reactive objects and snapshots. * @example `com.example.type.person` */ export declare const getTypename: (entity: Unknown | Snapshot) => string | undefined; /** * Get the database the object belongs to. * Accepts both reactive objects and snapshots. * * @idiom org.dxos.echo.objGetDatabase * applies: Reaching an object's database — to query, add, or remove — when the surrounding Space is not otherwise needed * instead-of: `getSpace(obj)?.db` (resolving the whole Space just to read its `.db`) * uses: {@link getDatabase} */ export declare const getDatabase: (entity: Entity.Unknown | Entity.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. * Prevents mutation at all nesting levels (e.g., `meta.keys.push()` is a TypeScript error). */ export type ReadonlyMeta = internal.ReadonlyMeta; /** * Mutable meta type returned by `Obj.getMeta` inside an `Obj.update` callback. */ export type Meta = internal.Meta; /** * Get the metadata for an object. * Returns mutable meta when passed a mutable object (inside `Obj.update` callback). * Returns read-only meta when passed a regular object or snapshot. * * @example * ```ts * // Read-only access outside change callback * const meta = Obj.getMeta(person); // ReadonlyMeta * * // Mutable access inside change callback * Obj.update(person, (obj) => { * const meta = Obj.getMeta(obj); // EntityMeta (mutable) * meta.tags.push(Ref.make(tag)); // tags are refs to Tag objects * }); * ``` */ export declare function getMeta(entity: Mutable): Meta; export declare function getMeta(entity: Unknown | Snapshot): ReadonlyMeta; /** * @returns Foreign keys for the object from the specified source. * Accepts both reactive objects and snapshots. */ export declare const getKeys: { (entity: Unknown | Snapshot, source: string): ForeignKey[]; (source: string): (entity: Unknown | Snapshot) => ForeignKey[]; }; /** * Delete all keys from the object for the specified source. * Must be called within an `Obj.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 object. * Must be called within an `Obj.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 object. * Must be called within an `Obj.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 object is deleted. * Accepts both reactive objects and snapshots. */ export declare const isDeleted: (entity: Unknown | Snapshot) => boolean; /** * Get the label of the object. * Accepts both reactive objects and snapshots. * * @param options.fallback `'typename'` returns the object'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 object. * Must be called within an `Obj.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 object. * Accepts both reactive objects and snapshots. */ export declare const getDescription: (entity: Unknown | Snapshot) => string | undefined; /** * Get the icon annotation for the object (or any entity), resolved via its type-level * `IconAnnotation`. Accepts both reactive entities and snapshots, and either Objects or * Relations — the underlying schema-based lookup works for both. * * Returns the full `{ icon, hue }` annotation; callers wanting just the icon name typically * write `Obj.getIcon(obj)?.icon ?? 'ph--cube--regular'`. */ export declare const getIcon: (entity: Entity.Unknown | Entity.Snapshot) => internal.IconAnnotation | undefined; /** * Set the description of the object. * Must be called within an `Obj.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; /** * Symbol to set parent when creating objects with `Obj.make`. * @example * ```ts * Obj.make(TestSchema.Person, { * [Obj.Parent]: parentObject, * name: 'John', * }) * ``` */ export declare const Parent: unique symbol; /** * Get the parent of an object. * The parent is always loaded together with the object. * Only objects are allowed to have a parent * @returns The parent object, or undefined if the object has no parent. */ export declare const getParent: (entity: Unknown | Snapshot) => Unknown | undefined; /** * Sets the parent of an object. * If a parent (or any transitive parent) is deleted, the object will be deleted. * Only objects are allowed to have a parent. */ export declare const setParent: (entity: Unknown, parent: Any | undefined) => Unknown & internal.InternalObjectProps; interface UpdateFromOptions { exclude?: (keyof T)[]; include?: (keyof T)[]; } /** * For each key present on `source` (except `id`), assigns `target[key]` when the current value differs. * References are compared by target DXN; other values use Effect `Equal.equals` inside a structural region, * with recursive comparison for arrays and plain object-shaped property bags (excluding `id`). * * Must be called within an `Obj.update` callback. * * @returns Whether any property was updated. */ export declare const updateFrom: (target: Mutable, source: T, options?: UpdateFromOptions) => boolean; /** * JSON representation of an object. */ export type JSON = internal.ObjectJSON; /** * Converts object to its JSON representation. * Accepts both reactive objects and snapshots. * * The same algorithm is used when calling the standard `JSON.stringify(obj)` function. */ export declare const toJSON: (entity: Unknown | Snapshot) => JSON; /** * Creates an object from its json representation, performing schema validation. * References and schemas will be resolvable if the `refResolver` is provided. * * The function must be async to support resolving the schema as well as the relation endpoints. * * @param options.refResolver - Resolver for references. Produces hydrated references that can be resolved. * @param options.uri - Override object URI. Changes the result of `Obj.getURI`. * @param options.database - Database to associate with the object. */ export declare const fromJSON: (json: unknown, options?: { refResolver?: Ref.Resolver; uri?: URI.URI; database?: Database.Database; parent?: Unknown; }) => Promise; /** * Comparator function type for sorting objects. * Accepts both reactive objects 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 type VersionCompareResult = internal.VersionCompareResult; /** * Represent object version. * May be backed by Automerge. * Objects with no history are not versioned. */ export type Version = internal.EntityVersion; export declare const isVersion: (entity: unknown) => entity is internal.EntityVersion; export declare const versionValid: (ver: internal.EntityVersion) => boolean; export declare const compareVersions: (version1: internal.EntityVersion, version2: internal.EntityVersion) => internal.VersionCompareResult; export declare const encodeVersion: (ver: internal.EntityVersion) => string; export declare const decodeVersion: (ver: string) => internal.EntityVersion; /** * Returns the version of the object. * Accepts both reactive objects and snapshots. */ export declare const version: (entity: Unknown | Snapshot) => Version; export declare const atom: { (obj: T): import("@effect-atom/atom/Atom").Atom>; (ref: Ref.Ref): import("@effect-atom/atom/Atom").Atom | undefined>; }; export declare const atomReactive: { (obj: T): import("@effect-atom/atom/Atom").Atom; (ref: Ref.Ref): import("@effect-atom/atom/Atom").Atom; }; export declare const atomProperty: (obj: T, key: K) => import("@effect-atom/atom/Atom").Atom; //# sourceMappingURL=Obj.d.ts.map