Skip to content

Feed

import { Feed } from '@dxos/echo';

A feed is an append-only log of objects, such as the messages of a chat or the events of a sync. The feed itself is an ECHO object of type org.dxos.type.feed, stored in the space like any other. Its items are stored in blocks, apart from the space’s documents. Feeds explains the model of branches and walks.

Add the feed object to the database first. db.appendToFeed then writes items in one batch.

import {
import Feed
Feed
,
import Obj
Obj
} from '@dxos/echo';
const
const feed: Feed.Feed
feed
=
const db: Database.Database
db
.
Database.add<Feed.Feed>(obj: Feed.Feed, opts?: Database.AddOptions): Feed.Feed

Adds an object or relation to the database.

Only Object and Relation entities are accepted. To persist a Type definition use

addType

— passing a Type entity is rejected at compile time (and at runtime).

Pass { to: feed } to append to a feed instead (synchronous; confirm with

flush

).

@performance ― Synchronous; O(n) in object size to write it into a new linked document (or the root), persisted in the background.

add
(
import Feed
Feed
.
const make: (props?: Obj.MakeProps<typeof Feed.Feed>) => Feed.Feed

Creates a new feed object.

@example

const feed = Feed.make({ name: 'notifications', kind: 'org.dxos.plugin.notifications.v1' });

@performance ― O(1); allocates an in-memory feed object.

make
({
name?: string | undefined
name
: 'Chat' }));
await
const db: Database.Database
db
.
Database.appendToFeed(feed: Feed.Feed, entities: Unknown[], opts?: Database.WriteOptions): Promise<void>

Appends entities to a feed.

The feed must already be stored in the database (added via

add

); its underlying queue is addressed by the feed object's URI.

@performance ― Async; O(n) in entities encoded and appended to the feed in one batch.

appendToFeed
(
const feed: Feed.Feed
feed
, [
import Obj
Obj
.
function make<typeof Message>(type: typeof Message, props: NoInfer<Obj.MakeProps<typeof Message>>, options?: Obj.MakeOptions): Obj.OfShape<Message & OfKind<EntityKind.Object>>

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.

@param ―

options - See MakeOptions.

Meta can be passed as a symbol in props.

Example:

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.

@performance ― O(n) in props size; validates props against the schema and allocates a reactive proxy, with no database I/O.

make
(
class Message
Message
, {
text: string
text
: 'Hello' }),
import Obj
Obj
.
function make<typeof Message>(type: typeof Message, props: NoInfer<Obj.MakeProps<typeof Message>>, options?: Obj.MakeOptions): Obj.OfShape<Message & OfKind<EntityKind.Object>>

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.

@param ―

options - See MakeOptions.

Meta can be passed as a symbol in props.

Example:

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.

@performance ― O(n) in props size; validates props against the schema and allocates a reactive proxy, with no database I/O.

make
(
class Message
Message
, {
text: string
text
: 'Hi back' }),
]);

A walk reads items in the order they were appended. It is a query with a Scope.feed source and an Order.natural order. To read a page at a time, pass limit, then select with Filter.feedCursor from the cursor of the last item to get the page after it. Any filter works over a feed’s items, as over a space, and from(feed) reads every item without walking a path.

import {
import Feed
Feed
,
import Filter
Filter
,
import Order
Order
,
import Query
Query
,
import Scope
Scope
} from '@dxos/echo';
const
const uri: string
uri
=
import Feed
Feed
.
const getFeedUri: (feed: Feed.Feed) => EID | undefined

Returns the feed object's EID when the feed is stored in a space.

Private-ish and on track to be removed — prefer resolving feed scopes via higher-level APIs (e.g. Feed.query) rather than threading the raw queue URI. Used internally by the feed service layer.

@performance ― O(1) URI parse.

getFeedUri
(
const feed: Feed.Feed
feed
)!.
String.toString(): string

Returns a string representation of a string.

toString
();
// Every message on the main path, oldest first.
const
const messages: (Message & OfKind<EntityKind.Object>)[]
messages
= await
const db: Database.Database
db
.
Database.query: Database.QueryFn
<Query.Query<Message & OfKind<EntityKind.Object>>>(query: Query.Query<Message & OfKind<EntityKind.Object>>) => QueryResult<Message & OfKind<EntityKind.Object>> (+1 overload)
query
(
import Query
Query
.
const select: <Filter.Filter<Message & OfKind<EntityKind.Object>>>(filter: Filter.Filter<Message & OfKind<EntityKind.Object>>) => Query.Query<Message & OfKind<EntityKind.Object>>

Select objects based on a filter.

@param ― filter - Filter to select the objects.

@returns ― Query for the selected objects.

@performance ― O(1); wraps the current AST in a new immutable node without executing anything.

select
(
import Filter
Filter
.
const type: <typeof Message>(type: typeof Message, props?: Filter.Props<Message & OfKind<EntityKind.Object>> | undefined) => Filter.Filter<Message & OfKind<EntityKind.Object>> (+4 overloads)
type
(
class Message
Message
))
.
Query<Message & OfKind<EntityKind.Object>>.from(...scopes: Scope[]): Query.Query<Message & OfKind<EntityKind.Object>> (+6 overloads)

Query from one or more raw scopes.

Use the

Scope

constructors rather than raw tagged objects:

Query.select(Filter.type(Type.Type)).from(Scope.space(), Scope.registry());

@performance ― O(k) in the number of scopes; builds the AST without executing anything.

from
(
import Scope
Scope
.
const feed: (feedUri: string, options?: Scope.FeedScopeOptions) => FeedScope

Scope targeting a specific feed (by its underlying queue EID).

To read only what follows a cursor, select with

Filter.feedCursor

— the bound is part of the query, not of the scope.

@example

db.query(Query.select(Filter.feedCursor(cursor)).from(Scope.feed(feedUri)));
db.query(Query.select(Filter.everything()).from(Scope.feed(feedUri, { branches: [null] })));
// Walk the root branch and then the branch, 50 items at a time.
db.query(
Query.select(Filter.feedCursor({ begin: cursor, positions: 'local' }))
.from(Scope.feed(feedUri, { walk: { branch } }))
.orderBy(Order.natural('asc'))
.limit(50),
);

@performance ― O(1); builds a scope node.

feed
(
const uri: string
uri
, {
walk?: {
branch?: Feed.BranchId | null | "all";
forks?: boolean;
} | undefined

Reads the feed as a walk along the path from the root branch to branch, in local order; select with

Filter.feedCursor

to start after a local cursor and order with Order.natural for the direction. 'all' walks every branch in local order. forks also gives the base item of each branch that forks at a block the walk gives.

walk
: {} }))
.
Query<Message & OfKind<EntityKind.Object>>.orderBy(order_0: Order.Order<Message & OfKind<EntityKind.Object>>, ...order: Order.Order<Message & OfKind<EntityKind.Object>>[]): Query.Query<Message & OfKind<EntityKind.Object>>

Order the query results. Orders are specified in priority order. The first order will be applied first, etc.

Order.property orders by the current result shape's fields, so it works both before and after an

aggregate

: before, by member (row) properties; after, by the flat record's fields (any group or aggregate field — e.g. Order.property('lastMessageAt') reorders the groups by that aggregate).

@param ― order - Order to sort the results.

@returns ― Query for the ordered results.

@performance ― O(k) in the number of orders; builds the AST without executing anything.

orderBy
(
import Order
Order
.
const natural: (direction?: OrderDirection) => Order.Order<any>

Order by the database's default order. For non-feed sources this is by id; for feed sources this is insertion order, so desc reads newest-first. Defaults to asc.

@performance ― O(1); builds an order AST node without sorting anything.

natural
('asc')),
)
.
QueryResult<Message & OfKind<EntityKind.Object>>.run(opts?: RunOptions): Promise<(Message & OfKind<EntityKind.Object>)[]>

Returns all known results.

@performance ― Async; executes the full query (index plus working set) on every call, not cached; O(n) in the data the executor examines, not in the result count.

run
();
// The next page: resume after the last item read.
const
const cursor: (string & Brand<"@dxos/echo/Feed/LocalCursor">) | undefined
cursor
=
import Feed
Feed
.
const getLocalCursor: (item: Unknown | Snapshot) => Feed.LocalCursor | undefined

The cursor a walk resumes after this item; undefined on an item the store has not echoed yet.

@performance ― O(k) in the item foreign-key count.

getLocalCursor
(
const messages: (Message & OfKind<EntityKind.Object>)[]
messages
[
const messages: (Message & OfKind<EntityKind.Object>)[]
messages
.
Array<Message & OfKind<EntityKind.Object>>.length: number

Gets or sets the length of the array. This is a number one higher than the highest index in the array.

length
- 1]);
const
const next: any[]
next
= await
const db: Database.Database
db
.
Database.query: Database.QueryFn
<Query.Query<any>>(query: Query.Query<any>) => QueryResult<any> (+1 overload)
query
(
import Query
Query
.
const select: <Filter.Filter<any>>(filter: Filter.Filter<any>) => Query.Query<any>

Select objects based on a filter.

@param ― filter - Filter to select the objects.

@returns ― Query for the selected objects.

@performance ― O(1); wraps the current AST in a new immutable node without executing anything.

select
(
import Filter
Filter
.
const and: <[Filter.Filter<Message & OfKind<EntityKind.Object>>, Filter.Any]>(filters_0: Filter.Filter<Message & OfKind<EntityKind.Object>>, filters_1: Filter.Any) => Filter.Filter<any>

Combine filters with a logical AND.

@performance ― O(k) in the number of filters; builds the AST without matching anything.

and
(
import Filter
Filter
.
const type: <typeof Message>(type: typeof Message, props?: Filter.Props<Message & OfKind<EntityKind.Object>> | undefined) => Filter.Filter<Message & OfKind<EntityKind.Object>> (+4 overloads)
type
(
class Message
Message
),
import Filter
Filter
.
const feedCursor: (range?: Filter.FeedCursorRange) => Filter.Any

Filter feed items to a cursor range — see Feed.getCursor for reading a cursor off an item, and Feed.START for the sentinel that bounds nothing.

The range is pushed into the index scan, so a reader that keeps a cursor pays for what is new rather than for the whole feed. Combine with limit() for a bounded page. Results come back in append order and cover positioned items only — an item a peer wrote but the position authority has not yet acknowledged has no place in that order, and Feed.START selects the same set from the beginning rather than everything. Only meaningful against a feed scope — an automerge object carries no position, so a query that also selects a space's documents is rejected.

@example

// The next 10 items after the last one this reader consumed.
db.query(Query.select(Filter.feedCursor({ begin: cursor })).limit(10).from(feed));
// Everything between two known items, excluding both.
db.query(Query.select(Filter.feedCursor({ begin: first, end: last })).from(feed));

@performance ― O(1); builds a filter AST node without matching anything.

feedCursor
({
begin?: (string & Brand<"@dxos/echo/Feed/LocalCursor">) | (string & Brand<"@dxos/echo/Feed/Cursor">) | undefined

Read after this cursor. Defaults to the start of the feed (

Feed.START

).

begin
:
const cursor: (string & Brand<"@dxos/echo/Feed/LocalCursor">) | undefined
cursor
,
positions?: "local" | "edge" | undefined

The order the cursors are positions in: edge, the position the authority assigned (

Feed.getCursor

), or local, a walk's local cursor (

Feed.getLocalCursor

). Defaults to local in a walk scope and edge elsewhere.

positions
: 'local' }),
),
)
.
Query<any>.from(...scopes: Scope[]): Query.Query<any> (+6 overloads)

Query from one or more raw scopes.

Use the

Scope

constructors rather than raw tagged objects:

Query.select(Filter.type(Type.Type)).from(Scope.space(), Scope.registry());

@performance ― O(k) in the number of scopes; builds the AST without executing anything.

from
(
import Scope
Scope
.
const feed: (feedUri: string, options?: Scope.FeedScopeOptions) => FeedScope

Scope targeting a specific feed (by its underlying queue EID).

To read only what follows a cursor, select with

Filter.feedCursor

— the bound is part of the query, not of the scope.

@example

db.query(Query.select(Filter.feedCursor(cursor)).from(Scope.feed(feedUri)));
db.query(Query.select(Filter.everything()).from(Scope.feed(feedUri, { branches: [null] })));
// Walk the root branch and then the branch, 50 items at a time.
db.query(
Query.select(Filter.feedCursor({ begin: cursor, positions: 'local' }))
.from(Scope.feed(feedUri, { walk: { branch } }))
.orderBy(Order.natural('asc'))
.limit(50),
);

@performance ― O(1); builds a scope node.

feed
(
const uri: string
uri
, {
walk?: {
branch?: Feed.BranchId | null | "all";
forks?: boolean;
} | undefined

Reads the feed as a walk along the path from the root branch to branch, in local order; select with

Filter.feedCursor

to start after a local cursor and order with Order.natural for the direction. 'all' walks every branch in local order. forks also gives the base item of each branch that forks at a block the walk gives.

walk
: {} }))
.
Query<any>.orderBy(order_0: Order.Order<any>, ...order: Order.Order<any>[]): Query.Query<any>

Order the query results. Orders are specified in priority order. The first order will be applied first, etc.

Order.property orders by the current result shape's fields, so it works both before and after an

aggregate

: before, by member (row) properties; after, by the flat record's fields (any group or aggregate field — e.g. Order.property('lastMessageAt') reorders the groups by that aggregate).

@param ― order - Order to sort the results.

@returns ― Query for the ordered results.

@performance ― O(k) in the number of orders; builds the AST without executing anything.

orderBy
(
import Order
Order
.
const natural: (direction?: OrderDirection) => Order.Order<any>

Order by the database's default order. For non-feed sources this is by id; for feed sources this is insertion order, so desc reads newest-first. Defaults to asc.

@performance ― O(1); builds an order AST node without sorting anything.

natural
('asc'))
.
Query<any>.limit(limit: number): Query.Query<any>

Limit the number of results.

@param ― limit - Maximum number of results to return.

@returns ― Query for the limited results.

@performance ― O(1); wraps the current AST in a new immutable node without executing anything.

limit
(50),
)
.
QueryResult<any>.run(opts?: RunOptions): Promise<any[]>

Returns all known results.

@performance ― Async; executes the full query (index plus working set) on every call, not cached; O(n) in the data the executor examines, not in the result count.

run
();
// Any filter works, as in a database query.
const
const greetings: (Message & OfKind<EntityKind.Object>)[]
greetings
= await
const db: Database.Database
db
.
Database.query: Database.QueryFn
<Query.Query<Message & OfKind<EntityKind.Object>>>(query: Query.Query<Message & OfKind<EntityKind.Object>>) => QueryResult<Message & OfKind<EntityKind.Object>> (+1 overload)
query
(
import Query
Query
.
const select: <Filter.Filter<Message & OfKind<EntityKind.Object>>>(filter: Filter.Filter<Message & OfKind<EntityKind.Object>>) => Query.Query<Message & OfKind<EntityKind.Object>>

Select objects based on a filter.

@param ― filter - Filter to select the objects.

@returns ― Query for the selected objects.

@performance ― O(1); wraps the current AST in a new immutable node without executing anything.

select
(
import Filter
Filter
.
const type: <typeof Message>(type: typeof Message, props?: Filter.Props<Message & OfKind<EntityKind.Object>> | undefined) => Filter.Filter<Message & OfKind<EntityKind.Object>> (+4 overloads)
type
(
class Message
Message
, {
text?: string | Filter.Filter<string> | undefined
text
: 'Hello' })).
Query<Message & OfKind<EntityKind.Object>>.from(feeds: Feed.Feed | Feed.Feed[]): Query.Query<Message & OfKind<EntityKind.Object>> (+6 overloads)

Query from selected feeds only.

Example:

Query.select(Filter.type(Person)).from(feed);

@performance ― O(k) in the number of sources; builds the AST without executing anything.

from
(
const feed: Feed.Feed
feed
))
.
QueryResult<Message & OfKind<EntityKind.Object>>.run(opts?: RunOptions): Promise<(Message & OfKind<EntityKind.Object>)[]>

Returns all known results.

@performance ― Async; executes the full query (index plus working set) on every call, not cached; O(n) in the data the executor examines, not in the result count.

run
();

Both options are fields of the feed object, so they replicate and merge like any other field.

org.dxos.echo#F-7.1
  • indexing: { enabled: false } turns indexing of the feed’s items off completely. There is no partial mode. org.dxos.echo#F-7.2
  • retention drops items past maxLength items or older than maxAge milliseconds. With both set, an item goes when it breaks either limit. org.dxos.echo#F-7.3

A write returns once the change is applied locally. It does not wait for the feed store to trim anything.

import {
import Obj
Obj
} from '@dxos/echo';
import Obj
Obj
.
const update: <Feed.Feed>(obj: Feed.Feed, callback: ChangeCallback<Feed.Feed>) => Feed.Feed

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

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.

@performance ― Synchronous; costs the mutations made in the callback plus one batched notification and an O(owning fields) parent pass.

update
(
const feed: Feed.Feed
feed
, (
feed: {
name?: string | undefined | undefined;
kind?: string | undefined | undefined;
namespace?: "data" | "trace" | undefined | undefined;
rewindFrom?: string | undefined | undefined;
indexing?: {
enabled: boolean;
mode?: "all" | "main" | undefined | undefined;
} | undefined;
retention?: {
maxLength?: number | undefined | undefined;
maxAge?: number | undefined | undefined;
} | undefined;
id: EntityId;
"~@dxos/echo/Kind": EntityKind.Object;
}
feed
) => {
feed: {
name?: string | undefined | undefined;
kind?: string | undefined | undefined;
namespace?: "data" | "trace" | undefined | undefined;
rewindFrom?: string | undefined | undefined;
indexing?: {
enabled: boolean;
mode?: "all" | "main" | undefined | undefined;
} | undefined;
retention?: {
maxLength?: number | undefined | undefined;
maxAge?: number | undefined | undefined;
} | undefined;
id: EntityId;
"~@dxos/echo/Kind": EntityKind.Object;
}
feed
.
indexing?: {
enabled: boolean;
mode?: "all" | "main" | undefined | undefined;
} | undefined
indexing
= {
enabled: boolean
enabled
: false };
feed: {
name?: string | undefined | undefined;
kind?: string | undefined | undefined;
namespace?: "data" | "trace" | undefined | undefined;
rewindFrom?: string | undefined | undefined;
indexing?: {
enabled: boolean;
mode?: "all" | "main" | undefined | undefined;
} | undefined;
retention?: {
maxLength?: number | undefined | undefined;
maxAge?: number | undefined | undefined;
} | undefined;
id: EntityId;
"~@dxos/echo/Kind": EntityKind.Object;
}
feed
.
retention?: {
maxLength?: number | undefined | undefined;
maxAge?: number | undefined | undefined;
} | undefined
retention
= {
maxLength?: number | undefined
maxLength
: 1_000,
maxAge?: number | undefined
maxAge
: 30 * 24 * 60 * 60 * 1000 };
});

A fork starts a branch at an existing item, for example an alternate reply in a conversation. db.forkFeed returns the branch id. Walk with { branch } to read the path from the start of the feed to the end of that branch.

import {
import Filter
Filter
,
import Obj
Obj
,
import Order
Order
,
import Query
Query
,
import Scope
Scope
} from '@dxos/echo';
const
const branch: string & Brand<"@dxos/echo/Feed/BranchId">
branch
= await
const db: Database.Database
db
.
Database.forkFeed(feed: Feed.Feed, base: Unknown, opts: {
at: Unknown | Snapshot | Feed.BlockId;
}): Promise<Feed.BranchId>

Appends base as the base block of a new branch of the feed, with the fork point at (an item, at the block it was read from, or a block id) as its predecessor. Resolves to the id of the new branch, the block id of the base, once the base is written.

@performance ― Async; one append of one entity.

forkFeed
(
const feed: Feed.Feed
feed
,
import Obj
Obj
.
function make<typeof Message>(type: typeof Message, props: NoInfer<Obj.MakeProps<typeof Message>>, options?: Obj.MakeOptions): Obj.OfShape<Message & OfKind<EntityKind.Object>>

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.

@param ―

options - See MakeOptions.

Meta can be passed as a symbol in props.

Example:

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.

@performance ― O(n) in props size; validates props against the schema and allocates a reactive proxy, with no database I/O.

make
(
class Message
Message
, {
text: string
text
: 'An alternate reply' }),
{
at: string | Unknown | Snapshot
at
:
const messages: (Message & OfKind<EntityKind.Object>)[]
messages
[0] },
);
const
const alternate: (Message & OfKind<EntityKind.Object>)[]
alternate
= await
const db: Database.Database
db
.
Database.query: Database.QueryFn
<Query.Query<Message & OfKind<EntityKind.Object>>>(query: Query.Query<Message & OfKind<EntityKind.Object>>) => QueryResult<Message & OfKind<EntityKind.Object>> (+1 overload)
query
(
import Query
Query
.
const select: <Filter.Filter<Message & OfKind<EntityKind.Object>>>(filter: Filter.Filter<Message & OfKind<EntityKind.Object>>) => Query.Query<Message & OfKind<EntityKind.Object>>

Select objects based on a filter.

@param ― filter - Filter to select the objects.

@returns ― Query for the selected objects.

@performance ― O(1); wraps the current AST in a new immutable node without executing anything.

select
(
import Filter
Filter
.
const type: <typeof Message>(type: typeof Message, props?: Filter.Props<Message & OfKind<EntityKind.Object>> | undefined) => Filter.Filter<Message & OfKind<EntityKind.Object>> (+4 overloads)
type
(
class Message
Message
))
.
Query<Message & OfKind<EntityKind.Object>>.from(...scopes: Scope[]): Query.Query<Message & OfKind<EntityKind.Object>> (+6 overloads)

Query from one or more raw scopes.

Use the

Scope

constructors rather than raw tagged objects:

Query.select(Filter.type(Type.Type)).from(Scope.space(), Scope.registry());

@performance ― O(k) in the number of scopes; builds the AST without executing anything.

from
(
import Scope
Scope
.
const feed: (feedUri: string, options?: Scope.FeedScopeOptions) => FeedScope

Scope targeting a specific feed (by its underlying queue EID).

To read only what follows a cursor, select with

Filter.feedCursor

— the bound is part of the query, not of the scope.

@example

db.query(Query.select(Filter.feedCursor(cursor)).from(Scope.feed(feedUri)));
db.query(Query.select(Filter.everything()).from(Scope.feed(feedUri, { branches: [null] })));
// Walk the root branch and then the branch, 50 items at a time.
db.query(
Query.select(Filter.feedCursor({ begin: cursor, positions: 'local' }))
.from(Scope.feed(feedUri, { walk: { branch } }))
.orderBy(Order.natural('asc'))
.limit(50),
);

@performance ― O(1); builds a scope node.

feed
(
const uri: string
uri
, {
walk?: {
branch?: Feed.BranchId | null | "all";
forks?: boolean;
} | undefined

Reads the feed as a walk along the path from the root branch to branch, in local order; select with

Filter.feedCursor

to start after a local cursor and order with Order.natural for the direction. 'all' walks every branch in local order. forks also gives the base item of each branch that forks at a block the walk gives.

walk
: {
branch?: (string & Brand<"@dxos/echo/Feed/BranchId">) | "all" | null | undefined
branch
} }))
.
Query<Message & OfKind<EntityKind.Object>>.orderBy(order_0: Order.Order<Message & OfKind<EntityKind.Object>>, ...order: Order.Order<Message & OfKind<EntityKind.Object>>[]): Query.Query<Message & OfKind<EntityKind.Object>>

Order the query results. Orders are specified in priority order. The first order will be applied first, etc.

Order.property orders by the current result shape's fields, so it works both before and after an

aggregate

: before, by member (row) properties; after, by the flat record's fields (any group or aggregate field — e.g. Order.property('lastMessageAt') reorders the groups by that aggregate).

@param ― order - Order to sort the results.

@returns ― Query for the ordered results.

@performance ― O(k) in the number of orders; builds the AST without executing anything.

orderBy
(
import Order
Order
.
const natural: (direction?: OrderDirection) => Order.Order<any>

Order by the database's default order. For non-feed sources this is by id; for feed sources this is insertion order, so desc reads newest-first. Defaults to asc.

@performance ― O(1); builds an order AST node without sorting anything.

natural
('asc')),
)
.
QueryResult<Message & OfKind<EntityKind.Object>>.run(opts?: RunOptions): Promise<(Message & OfKind<EntityKind.Object>)[]>

Returns all known results.

@performance ― Async; executes the full query (index plus working set) on every call, not cached; O(n) in the data the executor examines, not in the result count.

run
();

db.deleteFromFeed removes items you hold. db.removeFeedItemsByIds removes items by id.

await
const db: Database.Database
db
.
Database.deleteFromFeed(feed: Feed.Feed, entities: Unknown[]): Promise<void>

Removes entities from a feed.

@performance ― Async; O(n) in entities, deleted by id in one batch.

deleteFromFeed
(
const feed: Feed.Feed
feed
, [
const messages: (Message & OfKind<EntityKind.Object>)[]
messages
[1]]);
Member Summary
Feed The feed object type
make Create a feed object
getFeedUri The URI a Scope.feed source takes
getLocalCursor The cursor to resume a walk after an item
getBranch isFork The branch an item is on, and whether it starts one
db.appendToFeed db.deleteFromFeed Write and delete items
db.forkFeed Start a branch
db.syncFeed db.getFeedSyncState Replicate a feed and read its progress

The full list is in the API reference.

  • Feeds for branches, walks and cursors.
  • Filter for the filters a walk takes.