Roadmap
Each item below is scoped so it can be built and tested against the bundled
mock API, which already exposes the server side of
phases 2 and 3. The detailed, numbered backlog (including DX and performance findings
from the example app) is TODO.md at the repository root; this page is the summary.
-
Normalized cache — done
Objects with
__typename+idare stored once, referenced from the tree, and scopes are notified per entity field.launch(id:)is served from the entity the list wrote. See Caching. Left for later: type policies (custom merge per field, connection merging) and automaticgc(). -
Mutations — done
client.mutate((m) => m.toggleFavorite(launchId: id)?.favorite)andMutationBuilder<Mutation>, with journaled optimistic writes rolled back on failure. See Mutations. Also done:refetchQueriessugar, typed cache access (client.cacheScope), and list membership after a mutation (cacheScope.list((q) => q.me?.favorites).append/remove,evict) — see Caching. Left for later: connection-aware type policies so paginated/filtered lists update withoutrefetchQueries. -
Subscriptions
The mock API serves
launchStatusChangedandlaunchScheduledover SSE. ASubscriptionBuilder<Subscription>records a selection once, opens the stream, and writes each event into the cache. -
Unions and interfaces (
$on)Generator emits
PetOn get $onwith one getter per possible type; printer emits inline fragments... on Cat { meows }. Add a union to the mock schema first. -
Fine-grained rebuilds — mostly done
Scopes now rebuild on
entity.fieldintersection instead of root aliases. Remaining: list-index granularity for inline lists, and skipping rebuilds when a written value is equal to the cached one inside inline objects. -
Cache expiry and SWR — done
FetchPolicy(cacheFirst/cacheAndNetwork/networkOnly) per widget or client-wide,maxAgestale-while-revalidate on per-field fetch stamps,state.isStale, softstate.revalidate()— see Fetch policies & freshness. Left:WeakReference-held stale entries as an eviction mechanism. -
Developer experience — in progress
Done: real Dart
enums with anunknownvalue (see Code generation), no setters on key fields or connection metadata, andPaginatedQueryBuilder(see Pagination), and a dev-mode waterfall warning (SlingClient.onWaterfall,QueryBuilder.debugLabel) naming the scope and fields that caused a second round trip;Accessor.isFetched+QueryState.isSkeletonfor the three-meanings-of-nullstory;refetchQuerieson mutations;--scalarmapping;MutationBuilderresolving its root fromSlingScope(schema:); thesling_gql_testpackage (MockGraphQLServer,pumpUntilSettled— see Testing). Next: the in-app overlay attributing each request to the widgets that recorded it; apixel-style log line per operation;flutter_hooksadapter (useSlingQuery). -
Transport options — hook done
SlingClient(transport:)is the single interception point (see Transport). Left: agql_linkadapter for auth headers, retries and persisted queries, without changing the runtime’s_postcontract.
Explicitly not planned
Section titled “Explicitly not planned”- SSR hydration. Not applicable.
- Lazy / transaction / paginated query variants.
resolve()plus widget state cover the same ground.