Components
A component packages parts for define({ uses }). The components guide walks through a complete one.
| API | Contract |
|---|---|
component(parts?: ComponentParts): Component | Freezes the parts into a component. Every field is optional and must be an array; unknown fields are rejected. |
ComponentParts | Optional uses (nested components), collections, definitions, tasks, triggers and keys. |
Component | Readonly kind: "component" and each part as a frozen array. |
Usable | What uses accepts: a Component, or an object with a component property, such as an external value. |
A helper that is also a component
import { collection, component, v, type MutationContext } from "@flower-js/sdk";
export function tally(name: string) {
const counts = collection(name, v.int({ min: 0 }));
return {
...component({ collections: [counts] }),
add: (ctx: MutationContext, key: string) => ctx.set(counts, key, (ctx.get(counts, key) ?? 0) + 1),
};
}
// const votes = tally("votes"); define({ uses: [votes], ... }); votes.add(ctx, "yes");definevisits nestedusesfirst and includes each component once, however many times it is reached.- Names are global across components: two different definitions or two tasks with the same name are rejected, and so is one collection declared with different indexes.
- Components never add public methods; spread generated ones, like
jobs.http("jobs"), intohttp.
Tasks
| API | Contract |
|---|---|
task(name, { due, run, onError? }): Task | Background work for the maintenance handler. Names must be unique in the app. |
Task | Readonly kind: "task", name, due, run and optional onError. |
due(ctx: QueryContext): number | null | The earliest time the task has work, or null when idle. Must depend only on data and time, and return a finite number. |
run(ctx: MutationContext): Json | One bounded unit of work, committed on its own. The task stays eligible while due is in the past. |
onError(ctx, failure: TaskFailure): Json | Runs in place of a failed run, against the failed invocation’s snapshot and time; its writes commit instead. Without it, the task backs off. |
TaskFailure | error: Failure, with the real code (yours, COMPUTE_ERROR, EVALUATION_BUDGET…), and failedAt in milliseconds. |
define compiles every task, including those of components and of materialize policies, into one maintenance handler pair, $flower.maintenance and $flower.maintenance.error, named in FlowerModule.maintenance.
- Each run picks the task with the earliest due time and runs it in its own commit. The leader runs maintenance every
FLOWER_MAINTENANCE_INTERVAL_MS(250 ms), in bursts of up toFLOWER_MAINTENANCE_BURST_MS(50 ms) while work remains. - A failure without
onErrordelays only that task: 1 s after the first failure, doubling up to 60 s. The next success clears it. Backoff state lives in the$flower.taskscollection. - A run may be evaluated more than once before it commits. Keep external side effects out of tasks.
Triggers
| API | Contract |
|---|---|
trigger(name, source, run): Trigger | Runs run(ctx, change) inside every mutation that changed a row of source, once per changed key, before the commit. The source collection is declared for you. |
Trigger<T, K> | Readonly kind: "trigger", name, source and run. |
Change<T, K> | key (decoded for typed-key collections), before and after; null means the row didn’t exist. |
- Triggers see and join the mutation’s writes. A row that ends where it started doesn’t fire.
- Writes made by triggers can fire more triggers. After 32 rounds the mutation fails with
TRIGGER_LOOP. - Trigger names must be unique per collection.