Working on the repo
Directorysling_gql/
- .tool-versions flutter 3.47 · nodejs 24 (asdf)
Directorypackages/
Directorysling_gql/ runtime — Accessor, Selection, Cache, SlingClient, QueryBuilder
- …
Directorysling_gql_gen/ generator — introspection JSON → Dart
- …
Directorysling_gql_test/ test helpers — MockGraphQLServer, pumpUntilSettled
- …
Directorysling_gql_hooks/ flutter_hooks adapter — useSlingQuery, useSlingMutation
- …
Directorysling_gql_link/ gql_link adapter — a Link chain as the transport
- …
Directorymock-api/ graphql-yoga server the example and its tests run against
- …
Directoryexample/ Flutter app (iOS + Android + web)
- …
Directorywebsite/ this site (Astro + Starlight)
- …
- AGENTS.md conventions and design decisions, read it first
-
Install the toolchains. Flutter and Node are pinned with asdf; run every command from inside the repo so the pins apply.
Terminal window git clone https://github.com/helloprimary/sling_gql && cd sling_gqlasdf installdart pub global activate melosmelos bootstrap # pub workspace: one `pub get` for all packages -
Start the mock API. Space-themed, ~180 launches, cursor and offset pagination, 400 ms of artificial latency so skeletons are visible.
Terminal window cd mock-api && bun install && bun start# → http://localhost:4000/graphql (GraphiQL) -
Run the tests.
Terminal window melos run test # all the gates belowmelos run test:runtime # runtime, pure Dart + widget testsmelos run test:gen # generatormelos run test:example # e2e; starts the mock API itself if neededmelos run test:example:graphql-http # the same e2e on graphql-http + graphql-ssemelos run test:website # docs buildtest:runtimeincludes a short soak on a large generated schema (packages/sling_gql_sqflite/test/soak_test.dart); the long one isflutter test benchmark/soak_bench_test.dartin that package, by hand.melos run benchruns the read-path and persistence benchmarks five times each and fails when a median regressed by more than 1.5× againstscripts/bench-baseline.json. The metrics are ratios to reference work measured in the same run (jsonDecodeof the same response, plain sqflite inserts and reads), so they hold across machines. After an intended slowdown,melos run bench:updateand commit the baseline.The example test asserts exact request counts after each interaction. It is the one test that catches waterfalls — keep it exact.
-
Run the example.
Terminal window cd example && flutter run -d <ios-simulator-id> # or an Android emulator# or, from the repo root, with the mock API in the page (no server):(cd mock-api && bun run build:browser) && cd example && flutter run -d chromeEvery request is printed to the console and listed in-app (N requests, top right).
-
Change the schema.
mock-api/schema.graphqlis the contract; everything else is derived from it.Terminal window cd mock-api && bun run introspect # → example/graphql/schema.jsoncd .. && melos run generate # example/lib/generated/schema.dart -
Work on the website.
Terminal window cd website && bun install && bun run dev # http://localhost:4321/sling_gql/It deploys to GitHub Pages on every push to
mainthat toucheswebsite/. -
CI and releases. Every push and pull request runs the gates above (
.github/workflows/ci.yml), plus analyze, format, a check that the example’s generated file is up to date, a debug build of the example’s Android app and the benchmarks (melos run bench).Commits follow Conventional Commits scoped by package (
feat(sling_gql): …,fix(sling_gql_gen): …,docs(website): …), because releases are cut by melos from them:Terminal window melos run publish:dry-run # pub.dev validationmelos version # bump + CHANGELOG + commit + `<pkg>-vX.Y.Z` tagsgit push --follow-tags # publish.yml publishes each tagged package to pub.devWhat a release may change is the versioning policy: a breaking change is a major (
!+ aBREAKING CHANGE:footer), deprecations come first and live at least one minor.
Conventions
Section titled “Conventions”- Runtime stays dependency-light:
package:httpandpackage:metaonly. Nogql, noferry, nobuild_runner. - Runtime machinery on public types is
@internal,Accessor’s helpers@protected; building blocks apps never need go topackage:sling_gql/internal.dart. - Every runtime behaviour change ships with a test in
packages/sling_gql/test, usingMockClientfrompackage:http/testing.dartrather than the network. - The hand-written accessor classes at the top of
packages/sling_gql/test/core_test.dartare the contract the generator must produce. Change both together. example/lib/generated/schema.dartis committed and never edited by hand.- In example widgets, read every field you will need at the top of
build(), into locals.