Configure and query
Each entry in collections becomes typed getRecord and listRecords methods. Declare only the fields and relationships your app needs:
// contrail.config.ts
export default {
namespace: "com.example",
collections: {
event: {
collection: "community.lexicon.calendar.event",
queryable: {
mode: {},
startsAt: { type: "range" },
},
searchable: ["name", "description"],
relations: {
rsvps: {
collection: "rsvp",
groupBy: "status",
groups: {
going: "community.lexicon.calendar.rsvp#going",
},
},
},
},
rsvp: {
collection: "community.lexicon.calendar.rsvp",
queryable: {
status: {},
"subject.uri": {},
},
references: {
event: { collection: "event", field: "subject.uri" },
},
},
},
};
This produces the following client parameters:
| Config | Query parameter |
|---|---|
mode: {} | mode |
startsAt: { type: "range" } | startsAtMin, startsAtMax |
searchable | search |
relations.rsvps | rsvpsCountMin, hydrateRsvps |
groups.going | rsvpsGoingCountMin |
references.event | hydrateEvent |
Dotted fields become camel case: subject.uri becomes subjectUri. Every list method also supports actor (a DID or handle), sort, order, limit, cursor, and profiles.
Query from the client
After changing the config, re-run contrail connect in your app. The generated Atcute client now knows the new parameters and response types:
const response = await contrail.get("com.example.event.listRecords", {
params: {
mode: "in-person",
startsAtMin: new Date().toISOString(),
rsvpsGoingCountMin: 5,
sort: "startsAt",
order: "asc",
hydrateRsvps: 3,
profiles: true,
limit: 20,
},
});
if (!response.ok) throw new Error(`Contrail returned ${response.status}`);
const { records, profiles, cursor } = response.data;
Every record has uri, cid, and its original record body in value. Hydrated relations and references are added to that record; requested profiles are returned once in the top-level profiles array.
Pass the returned opaque cursor into the same query to get the next page. limit defaults to 50 and may be 1–200.
Full-text search works with D1 and PostgreSQL. The zero-config local SQLite AppView does not provide full-text search.