[{"data":1,"prerenderedAt":2505},["ShallowReactive",2],{"navigation_docs_en":3,"-en-examples-basic-query":342,"-en-examples-basic-query-surround":2500},[4,45,91,137,195,236,257,291,327],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":44},"Getting Started","i-lucide-rocket","/en/getting-started","en/01.getting-started",[10,15,20,24,29,34,39],{"title":11,"path":12,"stem":13,"icon":14},"What is Qora?","/en/getting-started/what-is-qora","en/01.getting-started/2.what-is-qora","i-lucide-info",{"title":16,"path":17,"stem":18,"icon":19},"Installation","/en/getting-started/installation","en/01.getting-started/3.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":6},"Quick Start","/en/getting-started/quick-start","en/01.getting-started/4.quick-start",{"title":25,"path":26,"stem":27,"icon":28},"Comparison","/en/getting-started/comparison","en/01.getting-started/5.comparison","i-lucide-scale",{"title":30,"path":31,"stem":32,"icon":33},"Coming from TanStack Query","/en/getting-started/coming-from-tanstack-query","en/01.getting-started/6.coming-from-tanstack-query","i-lucide-arrow-left-right",{"title":35,"path":36,"stem":37,"icon":38},"Migrating from Other Libraries","/en/getting-started/migrating-from-other-libraries","en/01.getting-started/7.migrating-from-other-libraries","i-lucide-arrow-right-left",{"title":40,"path":41,"stem":42,"icon":43},"AI Assistants","/en/getting-started/ai-assistants","en/01.getting-started/8.ai-assistants","i-lucide-sparkles",false,{"title":46,"icon":47,"path":48,"stem":49,"children":50,"page":44},"Core Concepts","i-lucide-book-open","/en/core-concepts","en/02.core-concepts",[51,56,61,66,71,76,81,86],{"title":52,"path":53,"stem":54,"icon":55},"Queries","/en/core-concepts/queries","en/02.core-concepts/1.queries","i-lucide-database",{"title":57,"path":58,"stem":59,"icon":60},"Query Keys","/en/core-concepts/query-keys","en/02.core-concepts/2.query-keys","i-lucide-key-round",{"title":62,"path":63,"stem":64,"icon":65},"Query States","/en/core-concepts/query-states","en/02.core-concepts/3.query-states","i-lucide-activity",{"title":67,"path":68,"stem":69,"icon":70},"Caching","/en/core-concepts/caching","en/02.core-concepts/4.caching","i-lucide-layers-3",{"title":72,"path":73,"stem":74,"icon":75},"Stale-While-Revalidate","/en/core-concepts/stale-while-revalidate","en/02.core-concepts/5.stale-while-revalidate","i-lucide-timer-reset",{"title":77,"path":78,"stem":79,"icon":80},"Deduplication","/en/core-concepts/deduplication","en/02.core-concepts/6.deduplication","i-lucide-copy-minus",{"title":82,"path":83,"stem":84,"icon":85},"Mutations & Invalidation","/en/core-concepts/mutations","en/02.core-concepts/7.mutations","i-lucide-pencil-line",{"title":87,"path":88,"stem":89,"icon":90},"Offline & Network","/en/core-concepts/offline","en/02.core-concepts/8.offline","i-lucide-wifi-off",{"title":92,"icon":93,"path":94,"stem":95,"children":96,"page":44},"Flutter Integration","i-lucide-smartphone","/en/flutter-integration","en/03.flutter-integration",[97,102,107,112,117,122,127,132],{"title":98,"path":99,"stem":100,"icon":101},"Setup","/en/flutter-integration/setup","en/03.flutter-integration/1.setup","i-lucide-wrench",{"title":103,"path":104,"stem":105,"icon":106},"QoraScope","/en/flutter-integration/qora-scope","en/03.flutter-integration/2.qora-scope","i-lucide-share-2",{"title":108,"path":109,"stem":110,"icon":111},"QoraBuilder","/en/flutter-integration/qora-builder","en/03.flutter-integration/3.qora-builder","i-lucide-blocks",{"title":113,"path":114,"stem":115,"icon":116},"QoraMutationBuilder","/en/flutter-integration/qora-mutation-builder","en/03.flutter-integration/4.qora-mutation-builder","i-lucide-pencil",{"title":118,"path":119,"stem":120,"icon":121},"InfiniteQueryBuilder","/en/flutter-integration/infinite-query-builder","en/03.flutter-integration/5.infinite-query-builder","i-lucide-infinity",{"title":123,"path":124,"stem":125,"icon":126},"Hooks (flutter_hooks)","/en/flutter-integration/hooks","en/03.flutter-integration/6.hooks","i-lucide-anchor",{"title":128,"path":129,"stem":130,"icon":131},"Network Status Widgets","/en/flutter-integration/network-status","en/03.flutter-integration/7.network-status","i-lucide-wifi",{"title":133,"path":134,"stem":135,"icon":136},"Best Practices","/en/flutter-integration/best-practices","en/03.flutter-integration/8.best-practices","i-lucide-badge-check",{"title":138,"icon":139,"path":140,"stem":141,"children":142,"page":44},"Recipes","i-lucide-chef-hat","/en/recipes","en/04.recipes",[143,147,152,157,162,166,171,176,181,186,191],{"title":144,"path":145,"stem":146,"icon":85},"Mutations","/en/recipes/mutations","en/04.recipes/02.mutations",{"title":148,"path":149,"stem":150,"icon":151},"Optimistic Updates","/en/recipes/optimistic-updates","en/04.recipes/03.optimistic-updates","i-lucide-zap",{"title":153,"path":154,"stem":155,"icon":156},"Persistence","/en/recipes/persistence","en/04.recipes/04.persistence","i-lucide-hard-drive",{"title":158,"path":159,"stem":160,"icon":161},"Network Aware","/en/recipes/network-aware","en/04.recipes/05.network-aware","i-lucide-signal",{"title":163,"path":164,"stem":165,"icon":121},"Infinite Queries","/en/recipes/infinite-queries","en/04.recipes/06.infinite-queries",{"title":167,"path":168,"stem":169,"icon":170},"Dependent Queries","/en/recipes/dependent-queries","en/04.recipes/07.dependent-queries","i-lucide-link-2",{"title":172,"path":173,"stem":174,"icon":175},"Cancellation","/en/recipes/cancel-token","en/04.recipes/08.cancel-token","i-lucide-circle-slash",{"title":177,"path":178,"stem":179,"icon":180},"SSR Hydration","/en/recipes/ssr-hydration","en/04.recipes/09.ssr-hydration","i-lucide-server",{"title":182,"path":183,"stem":184,"icon":185},"Error Handling","/en/recipes/error-handling","en/04.recipes/10.error-handling","i-lucide-shield-alert",{"title":187,"path":188,"stem":189,"icon":190},"Testing","/en/recipes/testing","en/04.recipes/11.testing","i-lucide-flask-conical",{"title":192,"path":193,"stem":194},"Route-Level Prefetching","/en/recipes/prefetch","en/04.recipes/12.prefetch",{"title":196,"icon":197,"path":198,"stem":199,"children":200,"page":44},"API Reference","i-lucide-file-code","/en/api-reference","en/05.api-reference",[201,206,210,214,219,224,228,232],{"title":202,"path":203,"stem":204,"icon":205},"QoraClient","/en/api-reference/qora-client","en/05.api-reference/1.qora-client","i-lucide-cpu",{"title":207,"path":208,"stem":209,"icon":60},"QoraKey","/en/api-reference/qora-key","en/05.api-reference/2.qora-key",{"title":211,"path":212,"stem":213,"icon":65},"QoraState","/en/api-reference/qora-state","en/05.api-reference/3.qora-state",{"title":215,"path":216,"stem":217,"icon":218},"QoraOptions","/en/api-reference/qora-options","en/05.api-reference/4.qora-options","i-lucide-sliders-horizontal",{"title":220,"path":221,"stem":222,"icon":223},"QoraClientConfig","/en/api-reference/qora-client-config","en/05.api-reference/5.qora-client-config","i-lucide-settings-2",{"title":225,"path":226,"stem":227,"icon":85},"Mutation API","/en/api-reference/qora-mutation","en/05.api-reference/6.qora-mutation",{"title":229,"path":230,"stem":231,"icon":156},"PersistQoraClient","/en/api-reference/persist-qora-client","en/05.api-reference/7.persist-qora-client",{"title":233,"path":234,"stem":235,"icon":121},"Infinite Query","/en/api-reference/infinite-query","en/05.api-reference/8.infinite-query",{"title":237,"icon":238,"path":239,"stem":240,"children":241,"page":44},"DevTools","i-lucide-bug","/en/devtools","en/06.devtools",[242,247,252],{"title":243,"path":244,"stem":245,"icon":246},"Overview","/en/devtools/overview","en/06.devtools/1.overview","i-lucide-layout-dashboard",{"title":248,"path":249,"stem":250,"icon":251},"In-App Overlay","/en/devtools/overlay","en/06.devtools/2.overlay","i-lucide-layers",{"title":253,"path":254,"stem":255,"icon":256},"Data Serialization","/en/devtools/data-display","en/06.devtools/4.data-display","i-lucide-eye",{"title":258,"icon":259,"path":260,"stem":261,"children":262,"page":44},"Third Party","i-lucide-puzzle","/en/third-party","en/07.third-party",[263,268,272,277,282,286],{"title":264,"path":265,"stem":266,"icon":267},"With Provider","/en/third-party/with-provider","en/07.third-party/1.with-provider","i-lucide-plug",{"title":269,"path":270,"stem":271,"icon":111},"With BLoC","/en/third-party/with-bloc","en/07.third-party/2.with-bloc",{"title":273,"path":274,"stem":275,"icon":276},"With Riverpod","/en/third-party/with-riverpod","en/07.third-party/3.with-riverpod","i-lucide-droplets",{"title":278,"path":279,"stem":280,"icon":281},"With RxDart","/en/third-party/with-rxdart","en/07.third-party/4.with-rxdart","i-lucide-git-branch",{"title":283,"path":284,"stem":285},"With Dio","/en/third-party/with-dio","en/07.third-party/5.with-dio",{"title":287,"path":288,"stem":289,"icon":290},"With GraphQL","/en/third-party/with-graphql","en/07.third-party/6.with-graphql","i-lucide-binary",{"title":292,"icon":190,"path":293,"stem":294,"children":295,"page":44},"Examples","/en/examples","en/08.examples",[296,301,305,310,314,318,322],{"title":297,"path":298,"stem":299,"icon":300},"Case Study: User List & Detail","/en/examples/basic-query","en/08.examples/1.basic-query","i-lucide-play-circle",{"title":302,"path":303,"stem":304,"icon":151},"Case Study: Optimistic Mutations & Rollback","/en/examples/mutations-optimistic","en/08.examples/2.mutations-optimistic",{"title":306,"path":307,"stem":308,"icon":309},"Case Study: Infinite Scroll Feed","/en/examples/infinite-scroll","en/08.examples/3.infinite-scroll","i-lucide-scroll",{"title":311,"path":312,"stem":313,"icon":90},"Case Study: Offline-First Todo App","/en/examples/offline-first","en/08.examples/4.offline-first",{"title":315,"path":316,"stem":317,"icon":161},"Case Study: Network Awareness","/en/examples/network-awareness","en/08.examples/5.network-awareness",{"title":319,"path":320,"stem":321,"icon":126},"Case Study: Hooks Integration","/en/examples/hooks-integration","en/08.examples/6.hooks-integration",{"title":323,"path":324,"stem":325,"icon":326},"Case Study: Complete Todo App","/en/examples/complete-todo-app","en/08.examples/7.complete-todo-app","i-lucide-check-square",{"title":328,"icon":329,"path":330,"stem":331,"children":332,"page":44},"Help","i-lucide-life-buoy","/en/help","en/09.help",[333,338],{"title":334,"path":335,"stem":336,"icon":337},"FAQ","/en/help/faq","en/09.help/1.faq","i-lucide-circle-help",{"title":339,"path":340,"stem":341,"icon":101},"Troubleshooting","/en/help/troubleshooting","en/09.help/2.troubleshooting",{"id":343,"title":297,"body":344,"description":2491,"extension":2492,"links":2493,"meta":2494,"navigation":2495,"path":298,"seo":2496,"stem":299,"__hash__":2499},"docs_en/en/08.examples/1.basic-query.md",{"type":345,"value":346,"toc":2476},"minimark",[347,352,369,375,378,382,473,475,479,486,496,524,774,784,786,790,795,805,842,865,1802,1829,1835,1845,1887,1897,1905,1928,2359,2372,2374,2378,2381,2417,2419,2423,2429,2438,2440,2444,2472],[348,349,351],"h2",{"id":350},"objective","Objective",[353,354,355,359,360,364,365,368],"p",{},[356,357,358],"strong",{},"Context",": Every network-backed screen needs to manage the same five concerns: loading state, error state, cached data, background refresh, and connectivity. With raw ",[361,362,363],"code",{},"FutureBuilder"," or manual ",[361,366,367],{},"setState",", each screen re-implements this logic independently. The code is verbose, inconsistent, and fragile under navigation.",[353,370,371,372,374],{},"This example shows how ",[361,373,108],{}," consolidates these concerns into a single declarative builder. Qora SWR caching allows users to reopen a visited screen without an additional network request.",[376,377],"hr",{},[348,379,381],{"id":380},"key-features-demonstrated","Key Features Demonstrated",[383,384,385,404,412,417,434,443,452,461],"ul",{},[386,387,388,393,394,396,397,400,401],"li",{},[356,389,390,392],{},[361,391,103],{}," setup",": ",[361,395,202],{}," injected at the root with ",[361,398,399],{},"FlutterLifecycleManager"," and ",[361,402,403],{},"FlutterConnectivityManager",[386,405,406,411],{},[356,407,408],{},[361,409,410],{},"QoraBuilder\u003CT>",": fetches on mount, subscribes to state changes, disposes cleanly",[386,413,414,416],{},[356,415,72],{},": cached data shown instantly on re-navigation; background refetch only when stale",[386,418,419,425,426,429,430,433],{},[356,420,421,424],{},[361,422,423],{},"FetchStatus"," as a second UI axis",": distinguishes active fetch (",[361,427,428],{},"fetching","), offline pause (",[361,431,432],{},"paused","), and idle without any custom boolean flags",[386,435,436,442],{},[356,437,438,441],{},[361,439,440],{},"previousData"," graceful degradation",": stale data stays visible during background refresh and on soft errors",[386,444,445,393,448,451],{},[356,446,447],{},"Per-item query keys",[361,449,450],{},"['users', userId]"," gives each user a separate, independent cache entry",[386,453,454,460],{},[356,455,456,459],{},[361,457,458],{},"invalidateWhere"," predicate",": one call invalidates both the list and all open detail screens simultaneously",[386,462,463,393,466,469,470,472],{},[356,464,465],{},"Pull-to-refresh",[361,467,468],{},"RefreshIndicator"," wired to ",[361,471,458],{},", no manual state required",[376,474],{},[348,476,478],{"id":477},"architecture-highlights","Architecture Highlights",[353,480,481,482,485],{},"Widgets never own data: they declare ",[356,483,484],{},"what they want"," and Qora decides whether to fetch, serve from cache, or wait for connectivity:",[487,488,494],"pre",{"className":489,"code":491,"language":492,"meta":493},[490],"language-text","ex_01_basic_query/lib/\n├── main.dart                    ← QoraClient + QoraScope at root\n├── models/\n│   └── user.dart                ← pure data class, no Qora dependency\n├── services/\n│   └── fake_api.dart            ← async functions (2 s simulated latency + ~30 % failure mode)\n└── screens/\n    ├── user_list_screen.dart    ← QoraBuilder\u003CList\u003CUser>>, key: ['users']\n    └── user_detail_screen.dart  ← QoraBuilder\u003CUser>, key: ['users', userId]\n","text","",[361,495,491],{"__ignoreMap":493},[353,497,498,500,501,504,505,508,509,512,513,516,517,516,520,523],{},[361,499,202],{}," is configured once at the root. Screens access it via ",[361,502,503],{},"context.qora",": the ",[361,506,507],{},"BuildContextExtension"," shortcut to ",[361,510,511],{},"QoraScope.of(context)",". No ",[361,514,515],{},"Provider",", no ",[361,518,519],{},"ref",[361,521,522],{},"context.read",":",[487,525,530],{"className":526,"code":527,"filename":528,"language":529,"meta":493,"style":493},"language-dart shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","final client = QoraClient(\n  config: const QoraClientConfig(\n    defaultOptions: QoraOptions(\n      staleTime: Duration(minutes: 5),\n      gcTime: Duration(minutes: 10),\n    ),\n    debugMode: kDebugMode,\n  ),\n);\n\nrunApp(\n  QoraScope(\n    client: client,\n    lifecycleManager: FlutterLifecycleManager(qoraClient: client),\n    connectivityManager: FlutterConnectivityManager(),\n    child: const MyApp(),\n  ),\n);\n","lib/main.dart","dart",[361,531,532,556,572,585,611,632,640,653,661,669,676,685,693,706,727,743,760,767],{"__ignoreMap":493},[533,534,537,541,545,549,553],"span",{"class":535,"line":536},"line",1,[533,538,540],{"class":539},"spNyl","final",[533,542,544],{"class":543},"sTEyZ"," client ",[533,546,548],{"class":547},"sMK4o","=",[533,550,552],{"class":551},"sBMFI"," QoraClient",[533,554,555],{"class":543},"(\n",[533,557,559,562,564,567,570],{"class":535,"line":558},2,[533,560,561],{"class":543},"  config",[533,563,523],{"class":547},[533,565,566],{"class":539}," const",[533,568,569],{"class":551}," QoraClientConfig",[533,571,555],{"class":543},[533,573,575,578,580,583],{"class":535,"line":574},3,[533,576,577],{"class":543},"    defaultOptions",[533,579,523],{"class":547},[533,581,582],{"class":551}," QoraOptions",[533,584,555],{"class":543},[533,586,588,591,593,596,599,601,605,608],{"class":535,"line":587},4,[533,589,590],{"class":543},"      staleTime",[533,592,523],{"class":547},[533,594,595],{"class":551}," Duration",[533,597,598],{"class":543},"(minutes",[533,600,523],{"class":547},[533,602,604],{"class":603},"sbssI"," 5",[533,606,607],{"class":543},")",[533,609,610],{"class":547},",\n",[533,612,614,617,619,621,623,625,628,630],{"class":535,"line":613},5,[533,615,616],{"class":543},"      gcTime",[533,618,523],{"class":547},[533,620,595],{"class":551},[533,622,598],{"class":543},[533,624,523],{"class":547},[533,626,627],{"class":603}," 10",[533,629,607],{"class":543},[533,631,610],{"class":547},[533,633,635,638],{"class":535,"line":634},6,[533,636,637],{"class":543},"    )",[533,639,610],{"class":547},[533,641,643,646,648,651],{"class":535,"line":642},7,[533,644,645],{"class":543},"    debugMode",[533,647,523],{"class":547},[533,649,650],{"class":543}," kDebugMode",[533,652,610],{"class":547},[533,654,656,659],{"class":535,"line":655},8,[533,657,658],{"class":543},"  )",[533,660,610],{"class":547},[533,662,664,666],{"class":535,"line":663},9,[533,665,607],{"class":543},[533,667,668],{"class":547},";\n",[533,670,672],{"class":535,"line":671},10,[533,673,675],{"emptyLinePlaceholder":674},true,"\n",[533,677,679,683],{"class":535,"line":678},11,[533,680,682],{"class":681},"s2Zo4","runApp",[533,684,555],{"class":543},[533,686,688,691],{"class":535,"line":687},12,[533,689,690],{"class":551},"  QoraScope",[533,692,555],{"class":543},[533,694,696,699,701,704],{"class":535,"line":695},13,[533,697,698],{"class":543},"    client",[533,700,523],{"class":547},[533,702,703],{"class":543}," client",[533,705,610],{"class":547},[533,707,709,712,714,717,720,722,725],{"class":535,"line":708},14,[533,710,711],{"class":543},"    lifecycleManager",[533,713,523],{"class":547},[533,715,716],{"class":551}," FlutterLifecycleManager",[533,718,719],{"class":543},"(qoraClient",[533,721,523],{"class":547},[533,723,724],{"class":543}," client)",[533,726,610],{"class":547},[533,728,730,733,735,738,741],{"class":535,"line":729},15,[533,731,732],{"class":543},"    connectivityManager",[533,734,523],{"class":547},[533,736,737],{"class":551}," FlutterConnectivityManager",[533,739,740],{"class":543},"()",[533,742,610],{"class":547},[533,744,746,749,751,753,756,758],{"class":535,"line":745},16,[533,747,748],{"class":543},"    child",[533,750,523],{"class":547},[533,752,566],{"class":539},[533,754,755],{"class":551}," MyApp",[533,757,740],{"class":543},[533,759,610],{"class":547},[533,761,763,765],{"class":535,"line":762},17,[533,764,658],{"class":543},[533,766,610],{"class":547},[533,768,770,772],{"class":535,"line":769},18,[533,771,607],{"class":543},[533,773,668],{"class":547},[353,775,776,779,780,783],{},[361,777,778],{},"staleTime: 5 minutes"," means: if you navigate to a screen visited less than 5 minutes ago, ",[356,781,782],{},"no network call fires",": the cache serves data on the first frame. After 5 minutes, the cached data is shown immediately while Qora revalidates in the background.",[376,785],{},[348,787,789],{"id":788},"implementation-details","Implementation Details",[791,792,794],"h3",{"id":793},"the-two-dimensional-state-matrix","The two-dimensional state matrix",[353,796,797,798,801,802,523],{},"Most state management solutions give you one axis: ",[361,799,800],{},"loading / data / error",". Qora gives you ",[356,803,804],{},"two",[383,806,807,828],{},[386,808,809,393,812,393,815,818,819,818,822,818,825],{},[361,810,811],{},"QoraState\u003CT>",[356,813,814],{},"what you have",[361,816,817],{},"Initial",", ",[361,820,821],{},"Loading",[361,823,824],{},"Success",[361,826,827],{},"Failure",[386,829,830,393,832,393,835,818,837,818,839],{},[361,831,423],{},[356,833,834],{},"what Qora is doing right now",[361,836,428],{},[361,838,432],{},[361,840,841],{},"idle",[353,843,844,845,847,848,850,851,853,854,857,858,861,862,523],{},"These two axes are independent. A widget can be in ",[361,846,824],{}," state (data is visible) while ",[361,849,423],{}," is ",[361,852,428],{}," (SWR background refresh running): the user sees their data and a subtle \"Updating…\" banner, but no spinner, no blank screen. The ",[361,855,856],{},"UserListScreen"," renders all meaningful combinations without a single ",[361,859,860],{},"bool _isLoading"," or ",[361,863,864],{},"bool _isOffline",[487,866,869],{"className":526,"code":867,"filename":868,"language":529,"meta":493,"style":493},"QoraBuilder\u003CList\u003CUser>>(\n  queryKey: const ['users'],\n  fetcher: FakeApi.getUsers,\n  options: const QoraOptions(\n    staleTime: Duration(minutes: 5),\n    gcTime: Duration(minutes: 10),\n  ),\n  builder: (context, state, fetchStatus) {\n\n    // ── Axis 2: FetchStatus → top status banner ────────────────────────\n    final banner = switch (fetchStatus) {\n      FetchStatus.fetching => const _StatusBanner(\n          icon: Icons.sync,\n          label: 'Updating…',\n          color: Colors.blue,\n        ),\n      FetchStatus.paused => const _StatusBanner(\n          icon: Icons.wifi_off,\n          label: 'Offline: showing cached data',\n          color: Colors.orange,\n        ),\n      FetchStatus.idle => const SizedBox.shrink(),\n    };\n\n    // ── Axis 1: QoraState → main content ──────────────────────────────\n    return switch (state) {\n\n      // First load with no cache, or offline with no cache at all\n      Initial() || Loading(previousData: null) =>\n          const Center(child: CircularProgressIndicator()),\n\n      // Hard error: nothing to show\n      Failure(:final error, previousData: null) => _ErrorScreen(\n          error: error,\n          onRetry: () => context.qora.invalidateWhere(\n            (key) => key.firstOrNull == 'users',\n          ),\n        ),\n\n      // Data available in ALL remaining cases:\n      //   Success        → fresh data\n      //   Loading(data)  → stale data, SWR running\n      //   Failure(data)  → refresh failed, stale data still shown\n      _ => Column(\n          children: [\n            banner,\n            if (state is Failure\u003CList\u003CUser>>)\n              _ErrorBanner(error: state.error), // soft error: list still visible\n            Expanded(\n              child: RefreshIndicator(\n                onRefresh: () async {\n                  context.qora.invalidateWhere(\n                    (key) => key.firstOrNull == 'users',\n                  );\n                  await Future\u003Cvoid>.delayed(const Duration(milliseconds: 300));\n                },\n                child: ListView.builder(\n                  itemCount: state.dataOrNull?.length ?? 0,\n                  itemBuilder: (_, i) => _UserTile(user: state.dataOrNull![i]),\n                ),\n              ),\n            ),\n          ],\n        ),\n    };\n  },\n)\n","lib/screens/user_list_screen.dart",[361,870,871,889,910,928,941,960,979,985,1006,1010,1016,1033,1053,1070,1082,1099,1106,1123,1138,1150,1166,1173,1199,1207,1212,1218,1229,1234,1240,1269,1291,1296,1302,1336,1348,1375,1399,1407,1414,1419,1425,1431,1437,1443,1456,1467,1475,1501,1524,1532,1545,1561,1577,1597,1605,1647,1655,1673,1702,1742,1750,1758,1766,1774,1781,1788,1796],{"__ignoreMap":493},[533,872,873,875,878,881,883,886],{"class":535,"line":536},[533,874,108],{"class":551},[533,876,877],{"class":543},"\u003C",[533,879,880],{"class":551},"List",[533,882,877],{"class":543},[533,884,885],{"class":551},"User",[533,887,888],{"class":543},">>(\n",[533,890,891,894,896,898,901,905,908],{"class":535,"line":558},[533,892,893],{"class":543},"  queryKey",[533,895,523],{"class":547},[533,897,566],{"class":539},[533,899,900],{"class":543}," [",[533,902,904],{"class":903},"sfazB","'users'",[533,906,907],{"class":543},"]",[533,909,610],{"class":547},[533,911,912,915,917,920,923,926],{"class":535,"line":574},[533,913,914],{"class":543},"  fetcher",[533,916,523],{"class":547},[533,918,919],{"class":551}," FakeApi",[533,921,922],{"class":547},".",[533,924,925],{"class":543},"getUsers",[533,927,610],{"class":547},[533,929,930,933,935,937,939],{"class":535,"line":587},[533,931,932],{"class":543},"  options",[533,934,523],{"class":547},[533,936,566],{"class":539},[533,938,582],{"class":551},[533,940,555],{"class":543},[533,942,943,946,948,950,952,954,956,958],{"class":535,"line":613},[533,944,945],{"class":543},"    staleTime",[533,947,523],{"class":547},[533,949,595],{"class":551},[533,951,598],{"class":543},[533,953,523],{"class":547},[533,955,604],{"class":603},[533,957,607],{"class":543},[533,959,610],{"class":547},[533,961,962,965,967,969,971,973,975,977],{"class":535,"line":634},[533,963,964],{"class":543},"    gcTime",[533,966,523],{"class":547},[533,968,595],{"class":551},[533,970,598],{"class":543},[533,972,523],{"class":547},[533,974,627],{"class":603},[533,976,607],{"class":543},[533,978,610],{"class":547},[533,980,981,983],{"class":535,"line":642},[533,982,658],{"class":543},[533,984,610],{"class":547},[533,986,987,990,992,995,998,1001,1003],{"class":535,"line":655},[533,988,989],{"class":543},"  builder",[533,991,523],{"class":547},[533,993,994],{"class":543}," (context",[533,996,997],{"class":547},",",[533,999,1000],{"class":543}," state",[533,1002,997],{"class":547},[533,1004,1005],{"class":543}," fetchStatus) {\n",[533,1007,1008],{"class":535,"line":663},[533,1009,675],{"emptyLinePlaceholder":674},[533,1011,1012],{"class":535,"line":671},[533,1013,1015],{"class":1014},"sHwdD","    // ── Axis 2: FetchStatus → top status banner ────────────────────────\n",[533,1017,1018,1021,1024,1026,1030],{"class":535,"line":678},[533,1019,1020],{"class":539},"    final",[533,1022,1023],{"class":543}," banner ",[533,1025,548],{"class":547},[533,1027,1029],{"class":1028},"s7zQu"," switch",[533,1031,1032],{"class":543}," (fetchStatus) {\n",[533,1034,1035,1038,1040,1043,1046,1048,1051],{"class":535,"line":687},[533,1036,1037],{"class":551},"      FetchStatus",[533,1039,922],{"class":547},[533,1041,1042],{"class":543},"fetching ",[533,1044,1045],{"class":547},"=>",[533,1047,566],{"class":539},[533,1049,1050],{"class":551}," _StatusBanner",[533,1052,555],{"class":543},[533,1054,1055,1058,1060,1063,1065,1068],{"class":535,"line":695},[533,1056,1057],{"class":543},"          icon",[533,1059,523],{"class":547},[533,1061,1062],{"class":551}," Icons",[533,1064,922],{"class":547},[533,1066,1067],{"class":1028},"sync",[533,1069,610],{"class":547},[533,1071,1072,1075,1077,1080],{"class":535,"line":708},[533,1073,1074],{"class":543},"          label",[533,1076,523],{"class":547},[533,1078,1079],{"class":903}," 'Updating…'",[533,1081,610],{"class":547},[533,1083,1084,1087,1089,1092,1094,1097],{"class":535,"line":729},[533,1085,1086],{"class":543},"          color",[533,1088,523],{"class":547},[533,1090,1091],{"class":551}," Colors",[533,1093,922],{"class":547},[533,1095,1096],{"class":543},"blue",[533,1098,610],{"class":547},[533,1100,1101,1104],{"class":535,"line":745},[533,1102,1103],{"class":543},"        )",[533,1105,610],{"class":547},[533,1107,1108,1110,1112,1115,1117,1119,1121],{"class":535,"line":762},[533,1109,1037],{"class":551},[533,1111,922],{"class":547},[533,1113,1114],{"class":543},"paused ",[533,1116,1045],{"class":547},[533,1118,566],{"class":539},[533,1120,1050],{"class":551},[533,1122,555],{"class":543},[533,1124,1125,1127,1129,1131,1133,1136],{"class":535,"line":769},[533,1126,1057],{"class":543},[533,1128,523],{"class":547},[533,1130,1062],{"class":551},[533,1132,922],{"class":547},[533,1134,1135],{"class":543},"wifi_off",[533,1137,610],{"class":547},[533,1139,1141,1143,1145,1148],{"class":535,"line":1140},19,[533,1142,1074],{"class":543},[533,1144,523],{"class":547},[533,1146,1147],{"class":903}," 'Offline: showing cached data'",[533,1149,610],{"class":547},[533,1151,1153,1155,1157,1159,1161,1164],{"class":535,"line":1152},20,[533,1154,1086],{"class":543},[533,1156,523],{"class":547},[533,1158,1091],{"class":551},[533,1160,922],{"class":547},[533,1162,1163],{"class":543},"orange",[533,1165,610],{"class":547},[533,1167,1169,1171],{"class":535,"line":1168},21,[533,1170,1103],{"class":543},[533,1172,610],{"class":547},[533,1174,1176,1178,1180,1183,1185,1187,1190,1192,1195,1197],{"class":535,"line":1175},22,[533,1177,1037],{"class":551},[533,1179,922],{"class":547},[533,1181,1182],{"class":543},"idle ",[533,1184,1045],{"class":547},[533,1186,566],{"class":539},[533,1188,1189],{"class":551}," SizedBox",[533,1191,922],{"class":547},[533,1193,1194],{"class":681},"shrink",[533,1196,740],{"class":543},[533,1198,610],{"class":547},[533,1200,1202,1205],{"class":535,"line":1201},23,[533,1203,1204],{"class":543},"    }",[533,1206,668],{"class":547},[533,1208,1210],{"class":535,"line":1209},24,[533,1211,675],{"emptyLinePlaceholder":674},[533,1213,1215],{"class":535,"line":1214},25,[533,1216,1217],{"class":1014},"    // ── Axis 1: QoraState → main content ──────────────────────────────\n",[533,1219,1221,1224,1226],{"class":535,"line":1220},26,[533,1222,1223],{"class":1028},"    return",[533,1225,1029],{"class":1028},[533,1227,1228],{"class":543}," (state) {\n",[533,1230,1232],{"class":535,"line":1231},27,[533,1233,675],{"emptyLinePlaceholder":674},[533,1235,1237],{"class":535,"line":1236},28,[533,1238,1239],{"class":1014},"      // First load with no cache, or offline with no cache at all\n",[533,1241,1243,1246,1249,1252,1255,1258,1260,1263,1266],{"class":535,"line":1242},29,[533,1244,1245],{"class":551},"      Initial",[533,1247,1248],{"class":543},"() ",[533,1250,1251],{"class":547},"||",[533,1253,1254],{"class":551}," Loading",[533,1256,1257],{"class":543},"(previousData",[533,1259,523],{"class":547},[533,1261,1262],{"class":547}," null",[533,1264,1265],{"class":543},") ",[533,1267,1268],{"class":547},"=>\n",[533,1270,1272,1275,1278,1281,1283,1286,1289],{"class":535,"line":1271},30,[533,1273,1274],{"class":539},"          const",[533,1276,1277],{"class":551}," Center",[533,1279,1280],{"class":543},"(child",[533,1282,523],{"class":547},[533,1284,1285],{"class":551}," CircularProgressIndicator",[533,1287,1288],{"class":543},"())",[533,1290,610],{"class":547},[533,1292,1294],{"class":535,"line":1293},31,[533,1295,675],{"emptyLinePlaceholder":674},[533,1297,1299],{"class":535,"line":1298},32,[533,1300,1301],{"class":1014},"      // Hard error: nothing to show\n",[533,1303,1305,1308,1311,1313,1315,1318,1320,1323,1325,1327,1329,1331,1334],{"class":535,"line":1304},33,[533,1306,1307],{"class":551},"      Failure",[533,1309,1310],{"class":543},"(",[533,1312,523],{"class":547},[533,1314,540],{"class":539},[533,1316,1317],{"class":543}," error",[533,1319,997],{"class":547},[533,1321,1322],{"class":543}," previousData",[533,1324,523],{"class":547},[533,1326,1262],{"class":547},[533,1328,1265],{"class":543},[533,1330,1045],{"class":547},[533,1332,1333],{"class":551}," _ErrorScreen",[533,1335,555],{"class":543},[533,1337,1339,1342,1344,1346],{"class":535,"line":1338},34,[533,1340,1341],{"class":543},"          error",[533,1343,523],{"class":547},[533,1345,1317],{"class":543},[533,1347,610],{"class":547},[533,1349,1351,1354,1356,1359,1361,1364,1366,1369,1371,1373],{"class":535,"line":1350},35,[533,1352,1353],{"class":543},"          onRetry",[533,1355,523],{"class":547},[533,1357,1358],{"class":543}," () ",[533,1360,1045],{"class":547},[533,1362,1363],{"class":543}," context",[533,1365,922],{"class":547},[533,1367,1368],{"class":543},"qora",[533,1370,922],{"class":547},[533,1372,458],{"class":681},[533,1374,555],{"class":543},[533,1376,1378,1381,1383,1386,1388,1391,1394,1397],{"class":535,"line":1377},36,[533,1379,1380],{"class":543},"            (key) ",[533,1382,1045],{"class":547},[533,1384,1385],{"class":543}," key",[533,1387,922],{"class":547},[533,1389,1390],{"class":543},"firstOrNull ",[533,1392,1393],{"class":547},"==",[533,1395,1396],{"class":903}," 'users'",[533,1398,610],{"class":547},[533,1400,1402,1405],{"class":535,"line":1401},37,[533,1403,1404],{"class":543},"          )",[533,1406,610],{"class":547},[533,1408,1410,1412],{"class":535,"line":1409},38,[533,1411,1103],{"class":543},[533,1413,610],{"class":547},[533,1415,1417],{"class":535,"line":1416},39,[533,1418,675],{"emptyLinePlaceholder":674},[533,1420,1422],{"class":535,"line":1421},40,[533,1423,1424],{"class":1014},"      // Data available in ALL remaining cases:\n",[533,1426,1428],{"class":535,"line":1427},41,[533,1429,1430],{"class":1014},"      //   Success        → fresh data\n",[533,1432,1434],{"class":535,"line":1433},42,[533,1435,1436],{"class":1014},"      //   Loading(data)  → stale data, SWR running\n",[533,1438,1440],{"class":535,"line":1439},43,[533,1441,1442],{"class":1014},"      //   Failure(data)  → refresh failed, stale data still shown\n",[533,1444,1446,1449,1451,1454],{"class":535,"line":1445},44,[533,1447,1448],{"class":543},"      _ ",[533,1450,1045],{"class":547},[533,1452,1453],{"class":551}," Column",[533,1455,555],{"class":543},[533,1457,1459,1462,1464],{"class":535,"line":1458},45,[533,1460,1461],{"class":543},"          children",[533,1463,523],{"class":547},[533,1465,1466],{"class":543}," [\n",[533,1468,1470,1473],{"class":535,"line":1469},46,[533,1471,1472],{"class":543},"            banner",[533,1474,610],{"class":547},[533,1476,1478,1481,1484,1487,1490,1492,1494,1496,1498],{"class":535,"line":1477},47,[533,1479,1480],{"class":1028},"            if",[533,1482,1483],{"class":543}," (state ",[533,1485,1486],{"class":547},"is",[533,1488,1489],{"class":551}," Failure",[533,1491,877],{"class":543},[533,1493,880],{"class":551},[533,1495,877],{"class":543},[533,1497,885],{"class":551},[533,1499,1500],{"class":543},">>)\n",[533,1502,1504,1507,1510,1512,1514,1516,1519,1521],{"class":535,"line":1503},48,[533,1505,1506],{"class":551},"              _ErrorBanner",[533,1508,1509],{"class":543},"(error",[533,1511,523],{"class":547},[533,1513,1000],{"class":543},[533,1515,922],{"class":547},[533,1517,1518],{"class":543},"error)",[533,1520,997],{"class":547},[533,1522,1523],{"class":1014}," // soft error: list still visible\n",[533,1525,1527,1530],{"class":535,"line":1526},49,[533,1528,1529],{"class":551},"            Expanded",[533,1531,555],{"class":543},[533,1533,1535,1538,1540,1543],{"class":535,"line":1534},50,[533,1536,1537],{"class":543},"              child",[533,1539,523],{"class":547},[533,1541,1542],{"class":551}," RefreshIndicator",[533,1544,555],{"class":543},[533,1546,1548,1551,1553,1555,1558],{"class":535,"line":1547},51,[533,1549,1550],{"class":543},"                onRefresh",[533,1552,523],{"class":547},[533,1554,1358],{"class":543},[533,1556,1557],{"class":1028},"async",[533,1559,1560],{"class":543}," {\n",[533,1562,1564,1567,1569,1571,1573,1575],{"class":535,"line":1563},52,[533,1565,1566],{"class":543},"                  context",[533,1568,922],{"class":547},[533,1570,1368],{"class":543},[533,1572,922],{"class":547},[533,1574,458],{"class":681},[533,1576,555],{"class":543},[533,1578,1580,1583,1585,1587,1589,1591,1593,1595],{"class":535,"line":1579},53,[533,1581,1582],{"class":543},"                    (key) ",[533,1584,1045],{"class":547},[533,1586,1385],{"class":543},[533,1588,922],{"class":547},[533,1590,1390],{"class":543},[533,1592,1393],{"class":547},[533,1594,1396],{"class":903},[533,1596,610],{"class":547},[533,1598,1600,1603],{"class":535,"line":1599},54,[533,1601,1602],{"class":543},"                  )",[533,1604,668],{"class":547},[533,1606,1608,1611,1614,1616,1619,1622,1624,1627,1629,1632,1634,1637,1639,1642,1645],{"class":535,"line":1607},55,[533,1609,1610],{"class":1028},"                  await",[533,1612,1613],{"class":551}," Future",[533,1615,877],{"class":543},[533,1617,1618],{"class":539},"void",[533,1620,1621],{"class":543},">",[533,1623,922],{"class":547},[533,1625,1626],{"class":681},"delayed",[533,1628,1310],{"class":543},[533,1630,1631],{"class":539},"const",[533,1633,595],{"class":551},[533,1635,1636],{"class":543},"(milliseconds",[533,1638,523],{"class":547},[533,1640,1641],{"class":603}," 300",[533,1643,1644],{"class":543},"))",[533,1646,668],{"class":547},[533,1648,1650,1653],{"class":535,"line":1649},56,[533,1651,1652],{"class":543},"                }",[533,1654,610],{"class":547},[533,1656,1658,1661,1663,1666,1668,1671],{"class":535,"line":1657},57,[533,1659,1660],{"class":543},"                child",[533,1662,523],{"class":547},[533,1664,1665],{"class":551}," ListView",[533,1667,922],{"class":547},[533,1669,1670],{"class":681},"builder",[533,1672,555],{"class":543},[533,1674,1676,1679,1681,1683,1685,1688,1691,1694,1697,1700],{"class":535,"line":1675},58,[533,1677,1678],{"class":543},"                  itemCount",[533,1680,523],{"class":547},[533,1682,1000],{"class":543},[533,1684,922],{"class":547},[533,1686,1687],{"class":543},"dataOrNull",[533,1689,1690],{"class":547},"?.",[533,1692,1693],{"class":543},"length ",[533,1695,1696],{"class":547},"??",[533,1698,1699],{"class":603}," 0",[533,1701,610],{"class":547},[533,1703,1705,1708,1710,1713,1715,1718,1720,1723,1726,1728,1730,1732,1734,1737,1740],{"class":535,"line":1704},59,[533,1706,1707],{"class":543},"                  itemBuilder",[533,1709,523],{"class":547},[533,1711,1712],{"class":543}," (_",[533,1714,997],{"class":547},[533,1716,1717],{"class":543}," i) ",[533,1719,1045],{"class":547},[533,1721,1722],{"class":551}," _UserTile",[533,1724,1725],{"class":543},"(user",[533,1727,523],{"class":547},[533,1729,1000],{"class":543},[533,1731,922],{"class":547},[533,1733,1687],{"class":543},[533,1735,1736],{"class":547},"!",[533,1738,1739],{"class":543},"[i])",[533,1741,610],{"class":547},[533,1743,1745,1748],{"class":535,"line":1744},60,[533,1746,1747],{"class":543},"                )",[533,1749,610],{"class":547},[533,1751,1753,1756],{"class":535,"line":1752},61,[533,1754,1755],{"class":543},"              )",[533,1757,610],{"class":547},[533,1759,1761,1764],{"class":535,"line":1760},62,[533,1762,1763],{"class":543},"            )",[533,1765,610],{"class":547},[533,1767,1769,1772],{"class":535,"line":1768},63,[533,1770,1771],{"class":543},"          ]",[533,1773,610],{"class":547},[533,1775,1777,1779],{"class":535,"line":1776},64,[533,1778,1103],{"class":543},[533,1780,610],{"class":547},[533,1782,1784,1786],{"class":535,"line":1783},65,[533,1785,1204],{"class":543},[533,1787,668],{"class":547},[533,1789,1791,1794],{"class":535,"line":1790},66,[533,1792,1793],{"class":543},"  }",[533,1795,610],{"class":547},[533,1797,1799],{"class":535,"line":1798},67,[533,1800,1801],{"class":543},")\n",[353,1803,1804,1805,1808,1809,1811,1812,1818,1819,1821,1822,1824,1825,1828],{},"The pattern ",[361,1806,1807],{},"Loading(previousData: null)"," is a Dart 3 destructure on the sealed class: it matches ",[361,1810,821],{}," ",[356,1813,1814,1815,1817],{},"only when ",[361,1816,440],{}," is null",", i.e. the very first load with no cache. Any subsequent ",[361,1820,821],{}," state (SWR background refresh) carries ",[361,1823,440],{}," and falls through to the ",[361,1826,1827],{},"_"," arm, keeping the list visible. This is why users never see an empty screen or a full-page spinner on re-navigation.",[791,1830,1832,1834],{"id":1831},"invalidatewhere-one-call-every-related-key",[361,1833,458],{},": one call, every related key",[353,1836,1837,1838,1841,1842,1844],{},"After pull-to-refresh, both ",[361,1839,1840],{},"['users']"," (the list) and every ",[361,1843,450],{}," (open detail screens) need fresh data. A predicate covers them all:",[487,1846,1848],{"className":526,"code":1847,"filename":868,"language":529,"meta":493,"style":493},"context.qora.invalidateWhere((key) => key.firstOrNull == 'users');\n// Invalidates: ['users'], ['users', '1'], ['users', '2'], …\n",[361,1849,1850,1882],{"__ignoreMap":493},[533,1851,1852,1855,1857,1859,1861,1863,1866,1868,1870,1872,1874,1876,1878,1880],{"class":535,"line":536},[533,1853,1854],{"class":543},"context",[533,1856,922],{"class":547},[533,1858,1368],{"class":543},[533,1860,922],{"class":547},[533,1862,458],{"class":681},[533,1864,1865],{"class":543},"((key) ",[533,1867,1045],{"class":547},[533,1869,1385],{"class":543},[533,1871,922],{"class":547},[533,1873,1390],{"class":543},[533,1875,1393],{"class":547},[533,1877,1396],{"class":903},[533,1879,607],{"class":543},[533,1881,668],{"class":547},[533,1883,1884],{"class":535,"line":558},[533,1885,1886],{"class":1014},"// Invalidates: ['users'], ['users', '1'], ['users', '2'], …\n",[353,1888,1889,1890,1892,1893,1896],{},"Every active ",[361,1891,108],{}," subscribed to a matching key transitions to ",[361,1894,1895],{},"Loading(previousData: data)"," and re-fetches. Existing data stays visible: no blank screens anywhere in the navigation stack.",[791,1898,1900,1901,1904],{"id":1899},"per-item-cache-and-updatedat-on-the-detail-screen","Per-item cache and ",[361,1902,1903],{},"updatedAt"," on the detail screen",[353,1906,1907,1908,1911,1912,393,1915,1917,1918,504,1921,1924,1925,523],{},"Each ",[361,1909,1910],{},"UserDetailScreen"," uses a ",[356,1913,1914],{},"parameterised key",[361,1916,450],{},". This gives every user their own independent cache entry. The screen also reads ",[361,1919,1920],{},"state.updatedAt",[361,1922,1923],{},"DateTime"," of the last successful fetch: to show a live \"last fetched X minutes ago\" timestamp, making the SWR behaviour ",[356,1926,1927],{},"visible to the user",[487,1929,1932],{"className":526,"code":1930,"filename":1931,"language":529,"meta":493,"style":493},"QoraBuilder\u003CUser>(\n  queryKey: ['users', userId],       // e.g. ['users', '1']\n  fetcher: () => FakeApi.getUser(userId),\n  options: const QoraOptions(staleTime: Duration(minutes: 5)),\n  builder: (context, state, fetchStatus) {\n    return switch (state) {\n      Initial() || Loading(previousData: null) =>\n          const Center(child: CircularProgressIndicator()),\n      Failure(:final error, previousData: null) => _ErrorScreen(error),\n      _ => Column(\n          children: [\n            if (fetchStatus == FetchStatus.paused)\n              const _Banner(label: 'Offline: showing cached data'),\n            if (state is Failure\u003CUser>)\n              _Banner(label: 'Refresh failed: ${state.error}'),\n            if (fetchStatus == FetchStatus.fetching)\n              const LinearProgressIndicator(minHeight: 2),\n            Expanded(\n              child: _UserDetailView(\n                user: state.dataOrNull!,\n                updatedAt: state.updatedAt, // ← timestamp from Success state\n                isStale: state is! Success\u003CUser>,\n              ),\n            ),\n          ],\n        ),\n    };\n  },\n)\n","lib/screens/user_detail_screen.dart",[361,1933,1934,1945,1965,1987,2014,2030,2038,2058,2074,2105,2115,2123,2140,2159,2176,2210,2225,2244,2250,2261,2277,2295,2319,2325,2331,2337,2343,2349,2355],{"__ignoreMap":493},[533,1935,1936,1938,1940,1942],{"class":535,"line":536},[533,1937,108],{"class":551},[533,1939,877],{"class":543},[533,1941,885],{"class":551},[533,1943,1944],{"class":543},">(\n",[533,1946,1947,1949,1951,1953,1955,1957,1960,1962],{"class":535,"line":558},[533,1948,893],{"class":543},[533,1950,523],{"class":547},[533,1952,900],{"class":543},[533,1954,904],{"class":903},[533,1956,997],{"class":547},[533,1958,1959],{"class":543}," userId]",[533,1961,997],{"class":547},[533,1963,1964],{"class":1014},"       // e.g. ['users', '1']\n",[533,1966,1967,1969,1971,1973,1975,1977,1979,1982,1985],{"class":535,"line":574},[533,1968,914],{"class":543},[533,1970,523],{"class":547},[533,1972,1358],{"class":543},[533,1974,1045],{"class":547},[533,1976,919],{"class":551},[533,1978,922],{"class":547},[533,1980,1981],{"class":681},"getUser",[533,1983,1984],{"class":543},"(userId)",[533,1986,610],{"class":547},[533,1988,1989,1991,1993,1995,1997,2000,2002,2004,2006,2008,2010,2012],{"class":535,"line":587},[533,1990,932],{"class":543},[533,1992,523],{"class":547},[533,1994,566],{"class":539},[533,1996,582],{"class":551},[533,1998,1999],{"class":543},"(staleTime",[533,2001,523],{"class":547},[533,2003,595],{"class":551},[533,2005,598],{"class":543},[533,2007,523],{"class":547},[533,2009,604],{"class":603},[533,2011,1644],{"class":543},[533,2013,610],{"class":547},[533,2015,2016,2018,2020,2022,2024,2026,2028],{"class":535,"line":613},[533,2017,989],{"class":543},[533,2019,523],{"class":547},[533,2021,994],{"class":543},[533,2023,997],{"class":547},[533,2025,1000],{"class":543},[533,2027,997],{"class":547},[533,2029,1005],{"class":543},[533,2031,2032,2034,2036],{"class":535,"line":634},[533,2033,1223],{"class":1028},[533,2035,1029],{"class":1028},[533,2037,1228],{"class":543},[533,2039,2040,2042,2044,2046,2048,2050,2052,2054,2056],{"class":535,"line":642},[533,2041,1245],{"class":551},[533,2043,1248],{"class":543},[533,2045,1251],{"class":547},[533,2047,1254],{"class":551},[533,2049,1257],{"class":543},[533,2051,523],{"class":547},[533,2053,1262],{"class":547},[533,2055,1265],{"class":543},[533,2057,1268],{"class":547},[533,2059,2060,2062,2064,2066,2068,2070,2072],{"class":535,"line":655},[533,2061,1274],{"class":539},[533,2063,1277],{"class":551},[533,2065,1280],{"class":543},[533,2067,523],{"class":547},[533,2069,1285],{"class":551},[533,2071,1288],{"class":543},[533,2073,610],{"class":547},[533,2075,2076,2078,2080,2082,2084,2086,2088,2090,2092,2094,2096,2098,2100,2103],{"class":535,"line":663},[533,2077,1307],{"class":551},[533,2079,1310],{"class":543},[533,2081,523],{"class":547},[533,2083,540],{"class":539},[533,2085,1317],{"class":543},[533,2087,997],{"class":547},[533,2089,1322],{"class":543},[533,2091,523],{"class":547},[533,2093,1262],{"class":547},[533,2095,1265],{"class":543},[533,2097,1045],{"class":547},[533,2099,1333],{"class":551},[533,2101,2102],{"class":543},"(error)",[533,2104,610],{"class":547},[533,2106,2107,2109,2111,2113],{"class":535,"line":671},[533,2108,1448],{"class":543},[533,2110,1045],{"class":547},[533,2112,1453],{"class":551},[533,2114,555],{"class":543},[533,2116,2117,2119,2121],{"class":535,"line":678},[533,2118,1461],{"class":543},[533,2120,523],{"class":547},[533,2122,1466],{"class":543},[533,2124,2125,2127,2130,2132,2135,2137],{"class":535,"line":687},[533,2126,1480],{"class":1028},[533,2128,2129],{"class":543}," (fetchStatus ",[533,2131,1393],{"class":547},[533,2133,2134],{"class":551}," FetchStatus",[533,2136,922],{"class":547},[533,2138,2139],{"class":543},"paused)\n",[533,2141,2142,2145,2148,2151,2153,2155,2157],{"class":535,"line":695},[533,2143,2144],{"class":539},"              const",[533,2146,2147],{"class":551}," _Banner",[533,2149,2150],{"class":543},"(label",[533,2152,523],{"class":547},[533,2154,1147],{"class":903},[533,2156,607],{"class":543},[533,2158,610],{"class":547},[533,2160,2161,2163,2165,2167,2169,2171,2173],{"class":535,"line":708},[533,2162,1480],{"class":1028},[533,2164,1483],{"class":543},[533,2166,1486],{"class":547},[533,2168,1489],{"class":551},[533,2170,877],{"class":543},[533,2172,885],{"class":551},[533,2174,2175],{"class":543},">)\n",[533,2177,2178,2181,2183,2185,2188,2191,2195,2197,2200,2203,2206,2208],{"class":535,"line":729},[533,2179,2180],{"class":551},"              _Banner",[533,2182,2150],{"class":543},[533,2184,523],{"class":547},[533,2186,2187],{"class":903}," 'Refresh failed: ",[533,2189,2190],{"class":543},"${",[533,2192,2194],{"class":2193},"sHdIc","state",[533,2196,922],{"class":543},[533,2198,2199],{"class":2193},"error",[533,2201,2202],{"class":543},"}",[533,2204,2205],{"class":903},"'",[533,2207,607],{"class":543},[533,2209,610],{"class":547},[533,2211,2212,2214,2216,2218,2220,2222],{"class":535,"line":745},[533,2213,1480],{"class":1028},[533,2215,2129],{"class":543},[533,2217,1393],{"class":547},[533,2219,2134],{"class":551},[533,2221,922],{"class":547},[533,2223,2224],{"class":543},"fetching)\n",[533,2226,2227,2229,2232,2235,2237,2240,2242],{"class":535,"line":762},[533,2228,2144],{"class":539},[533,2230,2231],{"class":551}," LinearProgressIndicator",[533,2233,2234],{"class":543},"(minHeight",[533,2236,523],{"class":547},[533,2238,2239],{"class":603}," 2",[533,2241,607],{"class":543},[533,2243,610],{"class":547},[533,2245,2246,2248],{"class":535,"line":769},[533,2247,1529],{"class":551},[533,2249,555],{"class":543},[533,2251,2252,2254,2256,2259],{"class":535,"line":1140},[533,2253,1537],{"class":543},[533,2255,523],{"class":547},[533,2257,2258],{"class":551}," _UserDetailView",[533,2260,555],{"class":543},[533,2262,2263,2266,2268,2270,2272,2274],{"class":535,"line":1152},[533,2264,2265],{"class":543},"                user",[533,2267,523],{"class":547},[533,2269,1000],{"class":543},[533,2271,922],{"class":547},[533,2273,1687],{"class":543},[533,2275,2276],{"class":547},"!,\n",[533,2278,2279,2282,2284,2286,2288,2290,2292],{"class":535,"line":1168},[533,2280,2281],{"class":543},"                updatedAt",[533,2283,523],{"class":547},[533,2285,1000],{"class":543},[533,2287,922],{"class":547},[533,2289,1903],{"class":543},[533,2291,997],{"class":547},[533,2293,2294],{"class":1014}," // ← timestamp from Success state\n",[533,2296,2297,2300,2302,2305,2308,2311,2313,2315,2317],{"class":535,"line":1175},[533,2298,2299],{"class":543},"                isStale",[533,2301,523],{"class":547},[533,2303,2304],{"class":543}," state ",[533,2306,2307],{"class":547},"is!",[533,2309,2310],{"class":551}," Success",[533,2312,877],{"class":543},[533,2314,885],{"class":551},[533,2316,1621],{"class":543},[533,2318,610],{"class":547},[533,2320,2321,2323],{"class":535,"line":1201},[533,2322,1755],{"class":543},[533,2324,610],{"class":547},[533,2326,2327,2329],{"class":535,"line":1209},[533,2328,1763],{"class":543},[533,2330,610],{"class":547},[533,2332,2333,2335],{"class":535,"line":1214},[533,2334,1771],{"class":543},[533,2336,610],{"class":547},[533,2338,2339,2341],{"class":535,"line":1220},[533,2340,1103],{"class":543},[533,2342,610],{"class":547},[533,2344,2345,2347],{"class":535,"line":1231},[533,2346,1204],{"class":543},[533,2348,668],{"class":547},[533,2350,2351,2353],{"class":535,"line":1236},[533,2352,1793],{"class":543},[533,2354,610],{"class":547},[533,2356,2357],{"class":535,"line":1242},[533,2358,1801],{"class":543},[353,2360,2361,2362,818,2365,2367,2368,2371],{},"Navigate to a user, go back, reopen: data appears on the ",[356,2363,2364],{},"first frame",[361,2366,1903],{}," shows the original fetch time, and a 2 px ",[361,2369,2370],{},"LinearProgressIndicator"," fires only if the data was stale. The network call happens silently in the background.",[376,2373],{},[348,2375,2377],{"id":2376},"validation-steps","Validation Steps",[353,2379,2380],{},"The example ships with an interactive guide to make the cache behaviour observable:",[2382,2383,2384,2391,2398,2401,2408,2414],"ol",{},[386,2385,2386,2387,2390],{},"Open ",[356,2388,2389],{},"User List"," → wait 2 s for initial load",[386,2392,2393,2394,2397],{},"Go back and reopen → ",[356,2395,2396],{},"instant from cache",", no network call",[386,2399,2400],{},"Pull to refresh → stale list stays visible; blue \"Updating…\" banner appears simultaneously",[386,2402,2403,2404,2407],{},"Open a user → note the ",[356,2405,2406],{},"\"Last fetched\""," timestamp",[386,2409,2410,2411,2413],{},"Go back and reopen within 5 min → ",[356,2412,2396],{},", timestamp unchanged",[386,2415,2416],{},"Toggle airplane mode → orange \"Offline\" banner; list remains fully usable",[376,2418],{},[348,2420,2422],{"id":2421},"source-code","Source Code",[487,2424,2427],{"className":2425,"code":2426,"language":492,"meta":493},[490],"examples/ex_01_basic_query/\n├── lib/\n│   ├── main.dart                    ← QoraClient + QoraScope setup\n│   ├── models/user.dart             ← pure data class\n│   ├── services/fake_api.dart       ← simulated API (2 s delay, ~30 % failure mode)\n│   └── screens/\n│       ├── user_list_screen.dart    ← QoraBuilder + FetchStatus × QoraState matrix\n│       └── user_detail_screen.dart  ← per-item key, updatedAt, previousData\n└── pubspec.yaml\n",[361,2428,2426],{"__ignoreMap":493},[353,2430,2431],{},[2432,2433,2437],"a",{"href":2434,"rel":2435},"https://github.com/meragix/qora/tree/main/examples/ex_01_basic_query",[2436],"nofollow","View full source code",[376,2439],{},[348,2441,2443],{"id":2442},"related","Related",[383,2445,2446,2452,2458,2464],{},[386,2447,2448,2451],{},[2432,2449,21],{"href":2450},"../getting-started/quick-start",": step-by-step conceptual walkthrough of the same feature",[386,2453,2454,2457],{},[2432,2455,108],{"href":2456},"../flutter-integration/qora-builder",": full widget API",[386,2459,2460,2463],{},[2432,2461,72],{"href":2462},"../core-concepts/stale-while-revalidate",": how the cache freshness model works",[386,2465,2466,393,2469,2471],{},[2432,2467,62],{"href":2468},"../core-concepts/query-states",[361,2470,211],{}," sealed class reference",[2473,2474,2475],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}",{"title":493,"searchDepth":558,"depth":558,"links":2477},[2478,2479,2480,2481,2488,2489,2490],{"id":350,"depth":558,"text":351},{"id":380,"depth":558,"text":381},{"id":477,"depth":558,"text":478},{"id":788,"depth":558,"text":789,"children":2482},[2483,2484,2486],{"id":793,"depth":574,"text":794},{"id":1831,"depth":574,"text":2485},"invalidateWhere: one call, every related key",{"id":1899,"depth":574,"text":2487},"Per-item cache and updatedAt on the detail screen",{"id":2376,"depth":558,"text":2377},{"id":2421,"depth":558,"text":2422},{"id":2442,"depth":558,"text":2443},"A complete list-and-detail feature: SWR caching, FetchStatus two-axis state, per-item query keys, pull-to-refresh, and graceful degradation. Zero boilerplate state management.","md",null,{},{"icon":300},{"title":2497,"description":2498},"Case Study: User List & Detail - Qora","Production-grade list and detail screens with QoraBuilder. Covers SWR caching, FetchStatus, previousData graceful degradation, per-item keys, and invalidateWhere.","fyoasNCGLpxh_3ke7ni2Gs3d7pWijvTF7VhxDhdtph0",[2501,2503],{"title":287,"path":288,"stem":289,"description":2502,"icon":290,"children":-1},"Wrap graphql or ferry GraphQL clients in Qora fetchers for seamless query management with stale-while-revalidate, cache invalidation, and pagination.",{"title":302,"path":303,"stem":304,"description":2504,"icon":151,"children":-1},"A complete optimistic update implementation: setQueryData for immediate UI feedback, restoreQueryData for automatic rollback on failure, and invalidateWhere for server reconciliation.",1794040402809]