[{"data":1,"prerenderedAt":1484},["ShallowReactive",2],{"navigation_docs_en":3,"-en-help-faq":342,"-en-help-faq-surround":1479},[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":334,"body":344,"description":1472,"extension":1473,"links":1474,"meta":1475,"navigation":1476,"path":335,"seo":1477,"stem":336,"__hash__":1478},"docs_en/en/09.help/1.faq.md",{"type":345,"value":346,"toc":1424},"minimark",[347,352,366,377,390,393,402,416,446,455,457,466,482,527,529,542,548,558,571,574,576,584,589,603,605,613,641,643,647,656,664,677,684,686,693,706,728,730,738,759,761,764,772,784,797,799,803,818,1034,1041,1043,1053,1062,1065,1076,1078,1082,1101,1123,1125,1128,1139,1156,1159,1247,1249,1257,1280,1289,1291,1294,1304,1325,1341,1343,1351,1365,1367,1370,1374,1381,1384,1386,1390,1420],[348,349,351],"h2",{"id":350},"core-api","Core API",[353,354,356,357,361,362,365],"h3",{"id":355},"what-is-the-difference-between-fetchquery-and-watchquery","What is the difference between ",[358,359,360],"code",{},"fetchQuery"," and ",[358,363,364],{},"watchQuery","?",[367,368,369,372,373,376],"p",{},[358,370,371],{},"fetchQuery\u003CT>"," executes a one-time fetch and returns a ",[358,374,375],{},"Future\u003CT>",". It does not subscribe to state changes.",[367,378,379,382,383,386,387,389],{},[358,380,381],{},"watchQuery\u003CT>"," returns a ",[358,384,385],{},"Stream\u003CQoraState\u003CT>>"," that emits on every state transition. It triggers a fetch on the first subscription and handles stale-while-revalidate, deduplication, and lifecycle events automatically. Use ",[358,388,364],{}," whenever a widget needs to reflect live cache state.",[391,392],"hr",{},[353,394,356,396,361,399,365],{"id":395},"what-is-the-difference-between-getquerydata-and-getquerystate",[358,397,398],{},"getQueryData",[358,400,401],{},"getQueryState",[367,403,404,407,408,411,412,415],{},[358,405,406],{},"getQueryData\u003CT>(key)"," returns ",[358,409,410],{},"T?",": the raw data value from the current cache entry, or ",[358,413,414],{},"null"," if no data is available.",[367,417,418,407,421,424,425,428,429,428,432,428,435,438,439,361,442,445],{},[358,419,420],{},"getQueryState\u003CT>(key)",[358,422,423],{},"QoraState\u003CT>",": the full sealed state including the variant (",[358,426,427],{},"Initial",", ",[358,430,431],{},"Loading",[358,433,434],{},"Success",[358,436,437],{},"Failure",") and all associated fields such as ",[358,440,441],{},"updatedAt",[358,443,444],{},"previousData",".",[367,447,448,449,451,452,454],{},"Use ",[358,450,398],{}," when you only need the data value (for example, to snapshot before an optimistic write). Use ",[358,453,401],{}," when you need the full state for display or branching logic.",[391,456],{},[353,458,356,460,361,463,365],{"id":459},"what-is-the-difference-between-restorequerydata-and-setquerydata",[358,461,462],{},"restoreQueryData",[358,464,465],{},"setQueryData",[367,467,468,471,472,475,476,478,479,445],{},[358,469,470],{},"setQueryData\u003CT>(key, T data)"," requires a non-null ",[358,473,474],{},"T",". It always produces a ",[358,477,434],{}," state with ",[358,480,481],{},"updatedAt: DateTime.now()",[367,483,484,487,488,490,491,494,495,497,498,501,502,504,505,507,508,511,512,514,515,517,518,520,521,523,524,526],{},[358,485,486],{},"restoreQueryData\u003CT>(key, T? data)"," accepts ",[358,489,410],{},". When ",[358,492,493],{},"data"," is ",[358,496,414],{},", it calls ",[358,499,500],{},"removeQuery(key)",", which restores ",[358,503,427],{}," state. When ",[358,506,493],{}," is non-null, it calls ",[358,509,510],{},"setQueryData(key, data)",". This makes ",[358,513,462],{}," the correct choice for rollback: the snapshot from ",[358,516,398],{}," may be ",[358,519,414],{}," when there was no prior data, and passing that ",[358,522,414],{}," to ",[358,525,462],{}," removes the optimistic entry cleanly.",[391,528],{},[353,530,356,532,428,535,538,539,365],{"id":531},"what-is-the-difference-between-invalidate-invalidatewhere-and-invalidatequeries",[358,533,534],{},"invalidate",[358,536,537],{},"invalidateWhere",", and ",[358,540,541],{},"invalidateQueries",[367,543,544,547],{},[358,545,546],{},"invalidate(key)"," marks a single specific key as stale.",[367,549,550,553,554,557],{},[358,551,552],{},"invalidateWhere(bool Function(List\u003Cdynamic> key) predicate)"," marks every cached key that satisfies the predicate as stale. Use this to invalidate a family of related keys with one call (for example, all keys starting with ",[358,555,556],{},"'users'",").",[367,559,560,563,564,566,567,570],{},[358,561,562],{},"invalidateQueries({required QueryFilter filter})"," is the typed counterpart to ",[358,565,537],{},", accepting a ",[358,568,569],{},"QueryFilter"," object rather than a raw predicate.",[367,572,573],{},"All three trigger a background refetch for every currently-active subscriber on the affected keys.",[391,575],{},[353,577,356,579,361,582,365],{"id":578},"what-is-the-difference-between-removequery-and-invalidate",[358,580,581],{},"removeQuery",[358,583,534],{},[367,585,586,588],{},[358,587,546],{}," marks the entry as stale and triggers a background refetch for active subscribers. The entry remains in cache.",[367,590,591,593,594,596,597,599,600,445],{},[358,592,500],{}," deletes the entry from cache entirely. Active subscribers transition to ",[358,595,427],{},". On ",[358,598,229],{},", it also deletes the persisted entry from ",[358,601,602],{},"StorageAdapter",[391,604],{},[353,606,608,609,612],{"id":607},"what-is-qorastatus-and-when-should-i-use-it-over-the-sealed-class","What is ",[358,610,611],{},"QoraStatus"," and when should I use it over the sealed class?",[367,614,615,617,618,621,622,625,626,629,630,428,632,428,635,637,638,640],{},[358,616,611],{}," is a plain enum (",[358,619,620],{},"initial | loading | success | error",") accessible via ",[358,623,624],{},"state.status",". It is useful when branching logic does not need access to the state's associated fields (for example, toggling a spinner via ",[358,627,628],{},"state.status.isLoading","). When you need ",[358,631,493],{},[358,633,634],{},"error",[358,636,444],{},", or ",[358,639,441],{},", pattern-match the sealed class directly.",[391,642],{},[348,644,646],{"id":645},"cache-semantics","Cache Semantics",[353,648,356,650,361,653,365],{"id":649},"what-is-the-difference-between-staletime-and-gctime",[358,651,652],{},"staleTime",[358,654,655],{},"gcTime",[367,657,658,660,661,663],{},[358,659,652],{}," controls freshness. Data within the freshness window is served from cache without a network call. After ",[358,662,652],{}," elapses, data is still served from cache, but a background revalidation is triggered simultaneously (stale-while-revalidate).",[367,665,666,668,669,671,672,674,675,445],{},[358,667,655],{}," controls eviction. When the last ",[358,670,364],{}," subscriber cancels, a GC timer is started. If no new subscriber attaches before ",[358,673,655],{}," elapses, the entry is removed from cache. The next access starts from ",[358,676,427],{},[367,678,679,680,683],{},"A common configuration: ",[358,681,682],{},"staleTime \u003C gcTime",". Data goes stale and triggers background revalidation, but the entry survives long enough that navigating back to a screen is instant.",[391,685],{},[353,687,689,690,692],{"id":688},"when-does-a-qorabuilder-refetch-on-mount","When does a ",[358,691,108],{}," refetch on mount?",[367,694,695,696,699,700,702,703,705],{},"By default (",[358,697,698],{},"refetchOnMount: true"," at the ",[358,701,220],{}," level), ",[358,704,364],{}," triggers a fetch on the first subscription regardless of existing cache state.",[367,707,708,709,712,713,715,716,718,719,721,722,724,725,727],{},"When ",[358,710,711],{},"refetchOnMount: false"," (set per-query via ",[358,714,215],{}," or globally via ",[358,717,220],{},"), ",[358,720,364],{}," only fetches when the entry is in ",[358,723,427],{}," state. If any cached state exists, including a stale ",[358,726,434],{},", no fetch is triggered on mount.",[391,729],{},[353,731,733,734,737],{"id":732},"what-happens-when-maxcachesize-is-reached","What happens when ",[358,735,736],{},"maxCacheSize"," is reached?",[367,739,740,741,743,744,748,749,751,752,755,756,758],{},"When the cache reaches ",[358,742,736],{},", Qora evicts the least-recently-used ",[745,746,747],"strong",{},"inactive"," entry (an entry with no active ",[358,750,364],{}," subscribers). Active entries are never evicted by LRU pressure. The ",[358,753,754],{},"onCacheEvict"," callback in ",[358,757,220],{}," is invoked for each evicted entry.",[391,760],{},[348,762,92],{"id":763},"flutter-integration",[353,765,356,767,361,769,365],{"id":766},"what-is-the-difference-between-qorabuilder-and-qorastatebuilder",[358,768,108],{},[358,770,771],{},"QoraStateBuilder",[367,773,774,777,778,780,781,445],{},[358,775,776],{},"QoraBuilder\u003CT>"," calls ",[358,779,364],{}," on mount, which triggers a fetch and subscribes to state changes. It takes a 3-parameter builder: ",[358,782,783],{},"Widget Function(BuildContext, QoraState\u003CT>, FetchStatus)",[367,785,786,777,789,792,793,796],{},[358,787,788],{},"QoraStateBuilder\u003CT>",[358,790,791],{},"watchState"," instead. It observes existing cache state but never triggers a fetch. It takes a 2-parameter builder: ",[358,794,795],{},"Widget Function(BuildContext, QoraState\u003CT>)",". Use it when another widget owns the fetch lifecycle and this widget should only display the result.",[391,798],{},[353,800,802],{"id":801},"how-do-i-get-a-global-loading-indicator","How do I get a global loading indicator?",[367,804,805,806,809,810,813,814,817],{},"With ",[358,807,808],{},"qora_hooks",", use ",[358,811,812],{},"useIsFetching()",". It returns ",[358,815,816],{},"true"," while any query has a request in flight and rebuilds only when the value crosses the zero boundary:",[819,820,826],"pre",{"className":821,"code":822,"filename":823,"language":824,"meta":825,"style":825},"language-dart shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","class AppProgressBar extends HookWidget {\n  const AppProgressBar({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    final isFetching = useIsFetching();\n    return AnimatedOpacity(\n      opacity: isFetching ? 1.0 : 0.0,\n      duration: const Duration(milliseconds: 250),\n      child: const LinearProgressIndicator(minHeight: 2),\n    );\n  }\n}\n","lib/shared/widgets/app_progress_bar.dart","dart","",[358,827,828,851,871,878,884,903,923,936,962,989,1014,1022,1028],{"__ignoreMap":825},[829,830,833,837,841,844,847],"span",{"class":831,"line":832},"line",1,[829,834,836],{"class":835},"sMK4o","class",[829,838,840],{"class":839},"sBMFI"," AppProgressBar",[829,842,843],{"class":835}," extends",[829,845,846],{"class":839}," HookWidget",[829,848,850],{"class":849},"sTEyZ"," {\n",[829,852,854,858,860,863,865,868],{"class":831,"line":853},2,[829,855,857],{"class":856},"spNyl","  const",[829,859,840],{"class":839},[829,861,862],{"class":849},"({super",[829,864,445],{"class":835},[829,866,867],{"class":849},"key})",[829,869,870],{"class":835},";\n",[829,872,874],{"class":831,"line":873},3,[829,875,877],{"emptyLinePlaceholder":876},true,"\n",[829,879,881],{"class":831,"line":880},4,[829,882,883],{"class":856},"  @override\n",[829,885,887,890,894,897,900],{"class":831,"line":886},5,[829,888,889],{"class":839},"  Widget",[829,891,893],{"class":892},"s2Zo4"," build",[829,895,896],{"class":849},"(",[829,898,899],{"class":839},"BuildContext",[829,901,902],{"class":849}," context) {\n",[829,904,906,909,912,915,918,921],{"class":831,"line":905},6,[829,907,908],{"class":856},"    final",[829,910,911],{"class":849}," isFetching ",[829,913,914],{"class":835},"=",[829,916,917],{"class":892}," useIsFetching",[829,919,920],{"class":849},"()",[829,922,870],{"class":835},[829,924,926,930,933],{"class":831,"line":925},7,[829,927,929],{"class":928},"s7zQu","    return",[829,931,932],{"class":839}," AnimatedOpacity",[829,934,935],{"class":849},"(\n",[829,937,939,942,945,947,949,953,956,959],{"class":831,"line":938},8,[829,940,941],{"class":849},"      opacity",[829,943,944],{"class":835},":",[829,946,911],{"class":849},[829,948,365],{"class":835},[829,950,952],{"class":951},"sbssI"," 1.0",[829,954,955],{"class":835}," :",[829,957,958],{"class":951}," 0.0",[829,960,961],{"class":835},",\n",[829,963,965,968,970,973,976,979,981,984,987],{"class":831,"line":964},9,[829,966,967],{"class":849},"      duration",[829,969,944],{"class":835},[829,971,972],{"class":856}," const",[829,974,975],{"class":839}," Duration",[829,977,978],{"class":849},"(milliseconds",[829,980,944],{"class":835},[829,982,983],{"class":951}," 250",[829,985,986],{"class":849},")",[829,988,961],{"class":835},[829,990,992,995,997,999,1002,1005,1007,1010,1012],{"class":831,"line":991},10,[829,993,994],{"class":849},"      child",[829,996,944],{"class":835},[829,998,972],{"class":856},[829,1000,1001],{"class":839}," LinearProgressIndicator",[829,1003,1004],{"class":849},"(minHeight",[829,1006,944],{"class":835},[829,1008,1009],{"class":951}," 2",[829,1011,986],{"class":849},[829,1013,961],{"class":835},[829,1015,1017,1020],{"class":831,"line":1016},11,[829,1018,1019],{"class":849},"    )",[829,1021,870],{"class":835},[829,1023,1025],{"class":831,"line":1024},12,[829,1026,1027],{"class":849},"  }\n",[829,1029,1031],{"class":831,"line":1030},13,[829,1032,1033],{"class":849},"}\n",[367,1035,1036,1037,1040],{},"Without hooks, subscribe to ",[358,1038,1039],{},"client.fetchingCountStream"," directly.",[391,1042],{},[353,1044,1046,1047,361,1050,365],{"id":1045},"do-i-need-flutterlifecyclemanager-and-flutterconnectivitymanager","Do I need ",[358,1048,1049],{},"FlutterLifecycleManager",[358,1051,1052],{},"FlutterConnectivityManager",[367,1054,1055,1056,1058,1059,1061],{},"Both are optional. Without ",[358,1057,1049],{},", queries do not refetch when the app returns to the foreground. Without ",[358,1060,1052],{},", queries do not pause when offline and do not replay on reconnect: all fetches always proceed regardless of connectivity status.",[367,1063,1064],{},"For offline-aware apps, provide both. For apps running in controlled environments (dashboards, internal tools), omitting them is acceptable.",[367,1066,1067,1069,1070,1072,1073,445],{},[358,1068,1052],{}," takes no constructor parameters. ",[358,1071,1049],{}," requires ",[358,1074,1075],{},"qoraClient: client",[391,1077],{},[353,1079,1081],{"id":1080},"can-i-use-qora-without-flutter","Can I use Qora without Flutter?",[367,1083,1084,1085,1088,1089,428,1091,428,1093,428,1095,538,1098,1100],{},"Yes. The ",[358,1086,1087],{},"qora"," package is pure Dart with no Flutter dependency. ",[358,1090,202],{},[358,1092,211],{},[358,1094,215],{},[358,1096,1097],{},"MutationController",[358,1099,229],{}," are all available in non-Flutter environments (Dart CLI, server-side, tests).",[367,1102,1103,1104,1107,1108,428,1110,428,1112,428,1114,428,1116,428,1118,538,1120,445],{},"The ",[358,1105,1106],{},"qora_flutter"," package adds ",[358,1109,103],{},[358,1111,108],{},[358,1113,113],{},[358,1115,118],{},[358,1117,1049],{},[358,1119,1052],{},[358,1121,1122],{},"NetworkStatusIndicator",[391,1124],{},[348,1126,153],{"id":1127},"persistence",[353,1129,1131,1132,1135,1136,365],{"id":1130},"do-i-need-to-call-storageadapterinit-before-hydrate","Do I need to call ",[358,1133,1134],{},"StorageAdapter.init()"," before ",[358,1137,1138],{},"hydrate()",[367,1140,1141,1142,1145,1146,1149,1150,1135,1152,1155],{},"Yes. Call ",[358,1143,1144],{},"await storage.init()"," before calling ",[358,1147,1148],{},"await client.hydrate()",". Calling ",[358,1151,1138],{},[358,1153,1154],{},"init()"," results in undefined behavior for adapters that open file handles or database connections during initialization.",[367,1157,1158],{},"The correct startup sequence:",[819,1160,1163],{"className":821,"code":1161,"filename":1162,"language":824,"meta":825,"style":825},"await storage.init();\nclient.registerSerializer\u003CUser>(userSerializer, name: 'User');\nawait client.hydrate();\nrunApp(...);\n","main.dart",[358,1164,1165,1182,1217,1233],{"__ignoreMap":825},[829,1166,1167,1170,1173,1175,1178,1180],{"class":831,"line":832},[829,1168,1169],{"class":928},"await",[829,1171,1172],{"class":849}," storage",[829,1174,445],{"class":835},[829,1176,1177],{"class":892},"init",[829,1179,920],{"class":849},[829,1181,870],{"class":835},[829,1183,1184,1187,1189,1192,1195,1198,1201,1204,1207,1209,1213,1215],{"class":831,"line":853},[829,1185,1186],{"class":849},"client",[829,1188,445],{"class":835},[829,1190,1191],{"class":892},"registerSerializer",[829,1193,1194],{"class":849},"\u003C",[829,1196,1197],{"class":839},"User",[829,1199,1200],{"class":849},">(userSerializer",[829,1202,1203],{"class":835},",",[829,1205,1206],{"class":849}," name",[829,1208,944],{"class":835},[829,1210,1212],{"class":1211},"sfazB"," 'User'",[829,1214,986],{"class":849},[829,1216,870],{"class":835},[829,1218,1219,1221,1224,1226,1229,1231],{"class":831,"line":873},[829,1220,1169],{"class":928},[829,1222,1223],{"class":849}," client",[829,1225,445],{"class":835},[829,1227,1228],{"class":892},"hydrate",[829,1230,920],{"class":849},[829,1232,870],{"class":835},[829,1234,1235,1238,1240,1243,1245],{"class":831,"line":880},[829,1236,1237],{"class":892},"runApp",[829,1239,896],{"class":849},[829,1241,1242],{"class":835},"...",[829,1244,986],{"class":849},[829,1246,870],{"class":835},[391,1248],{},[353,1250,1252,1253,1256],{"id":1251},"why-is-my-serializer-name-important","Why is my serializer ",[358,1254,1255],{},"name"," important?",[367,1258,1103,1259,1261,1262,1264,1265,1268,1269,1271,1272,1275,1276,1279],{},[358,1260,1255],{}," string is stored alongside each persisted entry as a type discriminator. During ",[358,1263,1138],{},", Qora uses it to find the correct ",[358,1266,1267],{},"fromJson"," converter. If ",[358,1270,1255],{}," is omitted, it defaults to ",[358,1273,1274],{},"T.toString()",", which is mangled by Dart obfuscation (",[358,1277,1278],{},"--obfuscate",") and minification in Flutter Web builds.",[367,1281,1282,1283,1285,1286,1288],{},"Always pass an explicit ",[358,1284,1255],{}," for types that will be persisted in release builds. Keep the ",[358,1287,1255],{}," stable across app versions: changing it invalidates all previously persisted entries for that type.",[391,1290],{},[348,1292,144],{"id":1293},"mutations",[353,1295,1297,1298,1300,1301,365],{"id":1296},"should-i-use-qoramutationbuilder-or-usemutation","Should I use ",[358,1299,113],{}," or ",[358,1302,1303],{},"useMutation",[367,1305,1306,1308,1309,1300,1312,1315,1316,1072,1318,1321,1322,1324],{},[358,1307,113],{}," works in any ",[358,1310,1311],{},"StatelessWidget",[358,1313,1314],{},"StatefulWidget",". ",[358,1317,1303],{},[358,1319,1320],{},"HookWidget",". Both create and dispose a ",[358,1323,1097],{}," tied to the widget lifecycle.",[367,1326,1327,1328,1330,1331,1334,1335,428,1338,1340],{},"On screens that combine a query and a mutation, ",[358,1329,1303],{}," alongside ",[358,1332,1333],{},"useQuery"," avoids nested builder callbacks and reduces indentation depth. On screens with only a mutation or in codebases that do not use ",[358,1336,1337],{},"flutter_hooks",[358,1339,113],{}," is the correct choice.",[391,1342],{},[353,1344,1346,1347,1350],{"id":1345},"when-does-onsuccess-run-for-offline-queued-mutations","When does ",[358,1348,1349],{},"onSuccess"," run for offline-queued mutations?",[367,1352,1353,1355,1356,1359,1360,1300,1362,1364],{},[358,1354,1349],{}," runs only when the mutation completes with a real server response (",[358,1357,1358],{},"isOptimistic: false","). It does not run when an optimistic response is applied locally while offline. This ensures that cache invalidation via ",[358,1361,534],{},[358,1363,465],{}," happens only after the server has confirmed the write.",[391,1366],{},[348,1368,237],{"id":1369},"devtools",[353,1371,1373],{"id":1372},"which-devtools-surface-should-i-use","Which DevTools surface should I use?",[367,1375,1376,1377,1380],{},"The in-app overlay (",[358,1378,1379],{},"qora_devtools_overlay",") is stable and available today. It renders inside the running app, and renders nothing in release builds.",[367,1382,1383],{},"A Flutter DevTools extension is in development and not published. Use the overlay.",[391,1385],{},[353,1387,1389],{"id":1388},"why-is-the-overlay-empty","Why is the overlay empty?",[367,1391,1392,1393,1396,1397,1300,1400,1403,1404,1407,1408,1411,1412,1415,1416,1419],{},"Confirm that the app runs in debug mode (",[358,1394,1395],{},"flutter run",", not ",[358,1398,1399],{},"--release",[358,1401,1402],{},"--profile","): the overlay builds nothing otherwise. Then confirm that the ",[745,1405,1406],{},"same"," ",[358,1409,1410],{},"OverlayTracker"," instance is passed to ",[358,1413,1414],{},"QoraClient(tracker: ...)"," and to ",[358,1417,1418],{},"QoraInspector(tracker: ...)",". A client created without the tracker emits no events.",[1421,1422,1423],"style",{},"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 .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}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}",{"title":825,"searchDepth":853,"depth":853,"links":1425},[1426,1440,1448,1456,1462,1468],{"id":350,"depth":853,"text":351,"children":1427},[1428,1430,1432,1434,1436,1438],{"id":355,"depth":873,"text":1429},"What is the difference between fetchQuery and watchQuery?",{"id":395,"depth":873,"text":1431},"What is the difference between getQueryData and getQueryState?",{"id":459,"depth":873,"text":1433},"What is the difference between restoreQueryData and setQueryData?",{"id":531,"depth":873,"text":1435},"What is the difference between invalidate, invalidateWhere, and invalidateQueries?",{"id":578,"depth":873,"text":1437},"What is the difference between removeQuery and invalidate?",{"id":607,"depth":873,"text":1439},"What is QoraStatus and when should I use it over the sealed class?",{"id":645,"depth":853,"text":646,"children":1441},[1442,1444,1446],{"id":649,"depth":873,"text":1443},"What is the difference between staleTime and gcTime?",{"id":688,"depth":873,"text":1445},"When does a QoraBuilder refetch on mount?",{"id":732,"depth":873,"text":1447},"What happens when maxCacheSize is reached?",{"id":763,"depth":853,"text":92,"children":1449},[1450,1452,1453,1455],{"id":766,"depth":873,"text":1451},"What is the difference between QoraBuilder and QoraStateBuilder?",{"id":801,"depth":873,"text":802},{"id":1045,"depth":873,"text":1454},"Do I need FlutterLifecycleManager and FlutterConnectivityManager?",{"id":1080,"depth":873,"text":1081},{"id":1127,"depth":853,"text":153,"children":1457},[1458,1460],{"id":1130,"depth":873,"text":1459},"Do I need to call StorageAdapter.init() before hydrate()?",{"id":1251,"depth":873,"text":1461},"Why is my serializer name important?",{"id":1293,"depth":853,"text":144,"children":1463},[1464,1466],{"id":1296,"depth":873,"text":1465},"Should I use QoraMutationBuilder or useMutation?",{"id":1345,"depth":873,"text":1467},"When does onSuccess run for offline-queued mutations?",{"id":1369,"depth":853,"text":237,"children":1469},[1470,1471],{"id":1372,"depth":873,"text":1373},{"id":1388,"depth":873,"text":1389},"Answers to common questions about Qora's API, cache semantics, and Flutter integration.","md",null,{},{"icon":337},{"title":334,"description":1472},"6vGqwAEsI1eirPWkNLlFi6Y4Ea0bBHvuGZB38F4eGvw",[1480,1482],{"title":323,"path":324,"stem":325,"description":1481,"icon":326,"children":-1},"A production-grade Flutter app combining every Qora capability: PersistQoraClient, infinite scroll with pagination, optimistic create/toggle/delete, offline mutation queue, and simulated connectivity toggling.",{"title":339,"path":340,"stem":341,"description":1483,"icon":101,"children":-1},"Diagnose and resolve common Qora issues, including persistence failures, blocked queries, missing refetches, and repeated widget subscriptions.",1794040403057]