Reference/SDK/Collections

SDK · Collections

The records of an app’s collections: which collections the caller may use and what they may do with each, listing with search, filter and sort, reading and writing records and reading their history, following changes live, and the details of the refusals specific to records.

Generated from the SDK’s own source. The SDK Reference is the narrative; this page is every member, in the order the SDK declares them.

CollectionsApi

The records of an app’s collections, reachable as client.collections: the app’s own data model, written by a developer as a schema in the console and read and written here with the caller’s role.

Every call is checked against the caller’s rights on the collection and, for a collection that belongs to robots, against the robots the caller reaches. A collection the caller may not read at all rejects collection_not_found, exactly as one that does not exist; one the caller may read but not write rejects forbidden. The refusals specific to records keep the cloud’s codes, with error.details in the shape each exported schema describes:

  • required_missing (400): requiredMissingDetails — the required fields left empty.
  • reference_invalid (400): referenceInvalidDetails — the reference field and why it was refused.
  • record_changed (409): recordChangedDetails — the revision the record is at now.
  • record_referenced (409): recordReferencedDetails — the collections that still point at the record, with counts.
  • validation_error (400) and plan_limit (409) as elsewhere.
  • rate_limited (429): RateLimitDetails — retry_after_ms, how long to wait before writing again. Surfaced, never retried.

definitions()

ts
definitions(): Promise<CollectionDefinitions>

The collections the caller may read, with their field definitions and what the caller may do with each — what a screen needs to draw a list or a form without hard-coding the schema — and the schema version they belong to. collections is [] for an app that has published none, or whose roles grant this caller none.

The schema can change under a running app; a realtime subscription’s onSchemaPublished says when to read this again, and hands over the version to compare with.

Returns Promise<CollectionDefinitions>.

References: CollectionDefinitions

list()

ts
list(collection: string, options?: CollectionListOptions): Promise<CollectionPage>

One page of a collection’s records, filtered, searched and sorted by the cloud. In a collection that belongs to robots the caller sees only the records of robots they reach.

Rejects invalid_option, before anything is sent, for a filter that is not plain JSON.

Parameter Type Required Description
collection string yes
options CollectionListOptions no

Returns Promise<CollectionPage>.

References: CollectionListOptions, CollectionPage

get()

ts
get(collection: string, id: string, options?: { expand?: string[] }): Promise<CollectionRecord>

One record by id. Rejects not_found when there is no such record or the caller may not see it. expand embeds reference fields, one hop.

Parameter Type Required Description
collection string yes
id string yes
options { expand?: string[] } no

Returns Promise<CollectionRecord>.

References: CollectionRecord

ts
get(collection: string, by: { robot: string }, options?: { expand?: string[] }): Promise<CollectionRecord>

The record of one robot in a one_per_robot collection, which always has exactly one. Rejects robot_not_attached when the robot is not attached to the app or the caller does not reach it, and not_found when the collection holds no record for it. Use it on a one_per_robot collection only: on a per_robot collection, which holds many records per robot, it returns the first of them.

Parameter Type Required Description
collection string yes
by { robot: string } yes
options { expand?: string[] } no

Returns Promise<CollectionRecord>.

References: CollectionRecord

create()

ts
create(collection: string, values: Record<string, unknown>, options?: { robot?: string }): Promise<CollectionRecord>

Creates a record. values holds the fields by key and must set every required one. A collection that belongs to robots takes robot, the id of the robot the record belongs to, which cannot change afterwards. Rejects required_missing, reference_invalid or validation_error for values the schema refuses, and plan_limit when the organization is at its record or storage limit. A one_per_robot collection takes no creates (validation_error): the platform keeps one record for every attached robot already.

Parameter Type Required Description
collection string yes
values Record<string, unknown> yes
options { robot?: string } no

Returns Promise<CollectionRecord>.

References: CollectionRecord

update()

ts
update(collection: string, id: string, values: Record<string, unknown>, options?: { expectedRevision?: number }): Promise<CollectionRecord>

Changes the fields in values and leaves the others alone; a null clears a field. With expectedRevision (the revision you last read) the write is refused with record_changed if the record has moved on, so two editors do not silently overwrite each other.

Parameter Type Required Description
collection string yes
id string yes
values Record<string, unknown> yes
options { expectedRevision?: number } no

Returns Promise<CollectionRecord>.

References: CollectionRecord

delete()

ts
delete(collection: string, id: string): Promise<void>

Deletes a record; its history is kept. Rejects record_referenced while a record of another collection points at it with on_delete: prevent. A one_per_robot collection takes no deletes (validation_error).

Parameter Type Required Description
collection string yes
id string yes

Returns Promise<void>.

history()

ts
history(collection: string, id: string, options?: CollectionHistoryOptions): Promise<CollectionHistoryPage>

A record’s history, newest revision first. Needs the right to update the record.

Parameter Type Required Description
collection string yes
id string yes
options CollectionHistoryOptions no

Returns Promise<CollectionHistoryPage>.

References: CollectionHistoryOptions, CollectionHistoryPage

subscribe()

ts
subscribe(collection: string, options: CollectionSubscribeOptions, onEvent: (event: CollectionEvent) => void): () => void

Follows a collection’s changes live over the client’s realtime channel: onEvent is called for every record that is created, updated, deleted, or comes into or leaves the view of this subscription (see CollectionEvent). options.robot and options.filter narrow it; the caller’s rights are checked on every event, not only when subscribing.

There is no first snapshot, but the cloud confirms the subscription. Once it has accepted and registered it, options.onReady is called, and from then on every change reaches onEvent. To show the records that exist, list in onReady, so that no change can fall between the list and the events; then apply the events to what the list returned. A refusal is answered through options.onError and onReady is not called.

Opens the channel if it is not open, and subscribes again by itself after every reconnect. Changes made while the connection was down are not replayed, but onReady is called again once the cloud has confirmed the subscription on the new connection: the same list in the same place refreshes what the app holds.

Returns the function that ends the subscription. It is safe to call more than once, and after the cloud ended the subscription itself.

Throws invalid_option, before anything is sent, for a filter that is not plain JSON, and for a subscription whose frame, with its filter, is larger than the 16,384 bytes the cloud takes.

Parameter Type Required Description
collection string yes
options CollectionSubscribeOptions yes
onEvent (event: CollectionEvent) => void yes

Returns () => void.

References: CollectionSubscribeOptions, CollectionEvent

CollectionDefinitions

What collections.definitions resolves with: collections, the collections the caller may read (see CollectionDefinition), and version, the schema version they belong to, null while the app has published none. Compare it with the version onSchemaPublished hands over to tell whether what you hold is current.

The wire shape is contracts’ collectionDefinitionsResponse.

The API Schemas page lists its two fields, version and collections.

CollectionDefinition

A collection as the caller may use it, from collections.definitions: key, label, description, binding (global, per_robot or one_per_robot), the display template, every field’s definition under fields, and can, what the caller may do with the records (read, create, and for update and delete 'all', 'own' or false) — the answer to “which buttons do I draw”.

The wire shape is one entry of collections in contracts’ collectionDefinitionsResponse.

The API Schemas page lists its fields as the items of collections.

CollectionField

One field definition, discriminated on type. The schema document lists the options each of the nine field types takes.

CollectionBinding

How a collection relates to robots: global, per_robot or one_per_robot. App Data says what each means.

CollectionRecord

The collection-record wire schema, re-exported so app code and the SDK agree on the shape — see API Schemas for its fields.

One record of a collection: its system fields (id, robot_id, who made it and when, revision), display (the collection’s display template filled in for this record), missing_required (required fields that are empty because the schema changed after the record was written; absent when nothing is missing) and values, the record’s own fields by key. A field without a value is absent from values. With expand, a reference field holds the referenced record in this same shape instead of its id, when the caller may read that collection.

The wire shape is contracts’ collectionRecord; the alias exists so the reference can describe it.

CollectionActor

The collection-actor wire schema, re-exported so app code and the SDK agree on the shape — see API Schemas for its fields.

CollectionListOptions

What collections.list reads. Every field is optional; the wire names are snake_case or encoded (filter is JSON text, sort and expand are comma-separated) and this SDK spells them the way its other options are spelt, leaving out whatever the caller did not set.

Property Type Required Description
search string no Words that must all occur, in any letter case, in at least one searchable field of the record. At most 10 words, separated by whitespace.
filter Record<string, unknown> no A filter: { "<field>": { "<op>": value } }, combined with { and: [...] } and { or: [...] }. The operators are eq, ne, lt, lte, gt, gte, contains, in and empty. A field is a field key, reference.field to go one hop through a reference field, or one of the system fields id, robot_id, created_at, updated_at and created_by. Nested at most 3 levels, 50 conditions in all. A filter the cloud cannot read rejects validation_error naming the part that is wrong. The filter has to be plain JSON; a reactive proxy (Vue, Svelte, MobX) is fine, and a value JSON cannot hold (a BigInt, a function, a number that is not finite, a cycle) rejects invalid_option before anything is sent.
sort string[] no Up to 3 fields to sort by, a leading - for descending, for example ['-created_at']. Ties are broken by id, so a page boundary is exact.
limit number no How many records to return, 1 to 500; absent means 50. Above the cap the cloud refuses with validation_error rather than trimming.
cursor string no The previous page’s nextCursor. Send it back rather than computing one; it stays valid while records are written.
count boolean no true makes the page carry total, the number of records that match.
expand string[] no Reference fields to embed as records instead of ids, one hop. A record is embedded only when the caller may read its collection; otherwise the id stays.
robot string no Only the records of this robot, in a collection that belongs to robots.
deleted boolean no true lists deleted records instead, newest deletion first. Needs the right to create records in the collection.

CollectionPage

One page of collections.list.

Page until nextCursor is null, never until a page looks short. The cloud only knows a page is the last one when there is nothing behind it.

Property Type Required Description
records CollectionRecord[] yes The records of this page, in the requested order.
nextCursor string | null yes Pass it as cursor to read the next page; null on the last page.
total number no The number of records that match the whole query. Present only when the call asked for it with count: true.

References: CollectionRecord

CollectionHistoryOptions

The window of collections.history: both fields optional, newest revisions first.

Property Type Required Description
limit number no How many revisions to return, 1 to 500.
beforeSeq number no The previous page’s nextBeforeSeq: only revisions older than this seq.

CollectionHistoryPage

One page of a record’s history, newest revision first. purged is set when an organization owner removed the older part of the history: it starts with a note saying which revisions went, who removed them and when.

Property Type Required Description
revisions CollectionRevision[] yes The revisions of this page, newest first.
nextBeforeSeq number | null yes Pass it as beforeSeq to read older revisions; null when there are none.
purged { before: string; by: { kind: "fleetless" | "developer" | "server_key" | "app_user"; id: string; label: string }; at: string } | null yes The removal of the older history, or null when none happened. by is the owner who removed it, an actor with a label like a record’s created_by.

References: CollectionRevision

CollectionRevision

The collection-revision wire schema, re-exported so app code and the SDK agree on the shape — see API Schemas for its fields.

One change in the history of a record: seq (the position to page and restore by), the operation (create, update, delete or restore), the actor, reason (schema v5, import, restore v4, or null for an ordinary write), the record’s revision afterwards, changes (each touched field with its old and new value) and, on a delete, the whole record.

The wire shape is contracts’ collectionRevision.

CollectionSubscribeOptions

What collections.subscribe takes besides the collection and the change callback. Every field is optional.

Property Type Required Description
robot string no Only the records of this robot, in a collection that belongs to robots.
filter Record<string, unknown> no Only records matching this filter are delivered. It is the filter of collections.list — the same grammar, at most 3 levels and 50 conditions — and a record that stops matching is announced once as removed. The SDK keeps a copy, so changing the object afterwards changes nothing; a reactive proxy (Vue, Svelte, MobX) is fine. The filter has to be plain JSON: a value JSON cannot hold (a BigInt, a function, a number that is not finite, a cycle) makes subscribe throw invalid_option before anything is sent. The whole subscription frame, filter included, may be at most 16,384 bytes (UTF-8): the cloud closes the connection for a larger one. A filter of a few dozen conditions fits; many long values in in lists may not. subscribe throws invalid_option for a frame over that, before anything is sent, so narrow the filter or follow the collection by robot.

onError()

ts
onError?(error: FleetlessError): void

Optional — a caller need not implement it.

Called when the cloud refuses the subscription (collection_not_found for a collection that does not exist or that the caller may not read, forbidden, robot_not_attached, validation_error for a filter it cannot read, internal_error when it could not check), and when a running one ends: collection_removed after a publish removed the collection, or forbidden / robot_not_attached when a role change or a detached robot no longer allows it. The subscription is over then and delivers nothing more; subscribe again to follow the collection.

Also called, without ending the subscription, when the channel cannot authenticate at all (no_session, for instance) and when the cloud ends the connection because its credential is no longer valid (token_revoked). Nothing reconnects after that, and the subscription stays registered: if the app opens the channel again (by signing in and making a new subscription or command), it is sent again and onReady is called once the cloud has confirmed it.

Parameter Type Required Description
error FleetlessError yes

Returns void.

References: FleetlessError

onReady()

ts
onReady?(): void

Optional — a caller need not implement it.

Called each time the cloud has confirmed the subscription: the first time it is accepted, and again after every reconnect, once the subscription was sent again on the new connection and accepted. From that moment on every change the subscription covers reaches onEvent, so this is the place to read the records that exist: call collections.list here and show its result, then apply the events to it. An event can arrive while the list is still being read, and may or may not be in its result; a record’s revision tells a newer state from an older one, so apply an event only when it is newer than what the list returned for that id.

The same code serves the first load and every later one. The cloud does not replay what changed while the connection was down, so after a reconnect the records the app holds may be stale: read them again here and replace them.

Not called before the cloud has answered, for a subscription it refuses (that is onError), for one that ended (unsubscribe, or onError for an ended one), nor when the app ends the subscription before the answer arrives. A cloud that does not know this answer never calls it.

Returns void.

onSchemaPublished()

ts
onSchemaPublished?(version: number): void

Optional — a caller need not implement it.

Called with the schema version now in force when a developer publishes or restores the app’s collections. Rights, fields and collections may have changed: read collections.definitions again.

Parameter Type Required Description
version number yes

Returns void.

CollectionEvent

One change to a record, as collections.subscribe hands it to its callback.

  • event is created, updated or deleted when the record was written, and removed or entered when it left or came into view of this subscription without being deleted or created: its values stopped or started matching the subscription’s filter, the caller’s role lost or gained the right to read it, or its robot was detached or attached.
  • id is the record’s id.
  • record is the whole record: as it is now for created, updated, entered and removed, and as it was for deleted. It is absent only on a removed event for a record the caller may no longer read, so that its values are not told; the id still is.

The wire frame is contracts’ collectionEvent; the SDK hands over the change itself, without the frame’s type and request_id.

The realtime collection_event frame without its type and request_id, which the SDK keeps to itself; App Data lists the events.

RequiredMissingDetails

The required-missing-details wire schema, re-exported so app code and the SDK agree on the shape — see API Schemas for its fields.

requiredMissingDetails

The details of a 400 required_missing refusal: every required field the write would leave empty.

ts
const requiredMissingDetails: ZodType<RequiredMissingDetails>

References: RequiredMissingDetails

ReferenceInvalidDetails

The reference-invalid-details wire schema, re-exported so app code and the SDK agree on the shape — see API Schemas for its fields.

referenceInvalidDetails

The details of a 400 reference_invalid refusal: which reference field, and why its value was refused.

ts
const referenceInvalidDetails: ZodType<ReferenceInvalidDetails>

References: ReferenceInvalidDetails

RecordChangedDetails

The record-changed-details wire schema, re-exported so app code and the SDK agree on the shape — see API Schemas for its fields.

recordChangedDetails

The details of a 409 record_changed refusal: the revision the record is at now, for the caller to read it again.

ts
const recordChangedDetails: ZodType<RecordChangedDetails>

References: RecordChangedDetails

RecordReferencedDetails

The record-referenced-details wire schema, re-exported so app code and the SDK agree on the shape — see API Schemas for its fields.

recordReferencedDetails

The details of a 409 record_referenced refusal. Counts only: the caller may not be allowed to read the records that point here, so neither their ids nor their values are told. Nor is the key of a collection the caller may not read, for the reason collection_not_found is answered for one: the list names only collections the caller may read, and it is empty when every collection that points here is one they may not.

ts
const recordReferencedDetails: ZodType<RecordReferencedDetails>

References: RecordReferencedDetails