Concorde guide — Data flow. Recommended patterns for new Concorde apps (Lit + TypeScript). Under the hood, data lives in a DataProvider store. Doc ID: docs/getting-started/dataFlow. Keywords: Concorde, supersoniks, docs/getting-started/dataFlow, dataFlow, Data flow, guide, DataProvider, get, set, dp, DataProviderKey, sub(key), @subscribe, @state, @ancestorAttribute. URL: https://concorde.supersoniks.org/docs/getting-started/dataFlow.
Data flow
Recommended patterns for new Concorde apps (Lit + TypeScript). Under the hood, data lives in a DataProvider store.
Quick map
| Need | Use |
|---|---|
| Read/write in code | get / set / dp + DataProviderKey (static paths only) |
| Reactive Lit template | sub(key) or @subscribe |
| Read component state from store | @subscribe + DataProviderKey<T, U> + @state |
| Inherit ancestor attributes | @ancestorAttribute |
| Write from component state | @publish |
| React to assignments | @handle |
| HTTP GET | @get + Endpoint, or sonic-list / sonic-queue with fetch |
| HTTP POST (body from store) | @post + Endpoint + body DataProviderKey |
| HTTP PUT / PATCH (body from store) | @put / @patch — same model as @post |
| Forms | formDataProvider + name on fields (no Subscriber on form elements) |
| Derived / aggregate (JSONata) | derive() or sonic-jsonata — Jsonata |
| Offline doc demos | serviceURL="/docs-mock-api" — Local API demos |
Agent skill: concorde (rules/data.md), see AI agents.
DataProviderKey
import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
import { dp, get, set } from "@supersoniks/concorde/utils";
const cartKey = new DataProviderKey<{ items: string[] }>("cart");
set(cartKey, { items: [] });
dp(cartKey.items).set(["a", "b"]);
get(cartKey);
Dynamic paths (users.${userId}) → decorators or sub() — not get("users.${id}") in imperative code. Resolution rules: Dynamic path placeholders.
Decorators
| Decorator | Role |
|---|---|
@subscribe |
Read-only property from store — data configuration (type + key + scope) |
@publish |
Push property writes to store |
@handle |
Method called on assignment |
@ancestorAttribute |
Copy ancestor HTML attribute onto property |
@get |
HTTP GET into ApiResult<T> |
@post |
HTTP POST into ApiResult<T> (body from a publisher) |
@put / @patch |
HTTP PUT / PATCH into ApiResult<T> |
Walkthrough: My first component
HTTP and lists
- @get — single GET on a component
- @post — POST with body read from a
DataProviderKey - @put · @patch — PUT / PATCH (same options as
@post) - List —
fetch+key="data"+/docs-mock-api/api/users - Queue — lazy
offset=$offset&per_page=$limit+ optionaldataFilterProvider(form → query)
Starter kit
npx @supersoniks/create-concorde-ts-starter my-app
Interactive routes mirror these patterns (/concepts/*, /demo/*).
Derived data (derive / sonic-jsonata)
Use when you need client-side aggregations (groupby, top N, chart shapes) from existing DataProviders — without inline app JS in SDUI.
- Primitive:
derive({ inputs, compute, output, variables? })from@supersoniks/concorde/utils(read-only output, debounce, generation, cycle detection,{output}/_state_). - SDUI adapter:
sonic-jsonata(inputProvider→expression→outputProvider, optionalformDataProvider). - vs
sonic-mix: mix composes bidirectionally; jsonata computes unidirectionally.
Legacy integration
| Topic | Page |
|---|---|
data-bind HTML (plain HTML hosts) |
HTML integration — doc demos use Lit in src/docs/example/ |
@onAssign |
@onAssign (prefer @handle) |
sonic-fetch alone |
Fetch |