[{"data":1,"prerenderedAt":4583},["ShallowReactive",2],{"navigation_docs_en":3,"-en-recipes-persistence":342,"-en-recipes-persistence-surround":4578},[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":153,"body":344,"description":4571,"extension":4572,"links":4573,"meta":4574,"navigation":4575,"path":154,"seo":4576,"stem":155,"__hash__":4577},"docs_en/en/04.recipes/04.persistence.md",{"type":345,"value":346,"toc":4537},"minimark",[347,354,362,418,421,425,435,615,635,637,641,655,1007,1010,1019,1021,1025,1036,1167,1179,1395,1405,1407,1411,1415,1421,1443,1446,1448,1452,1474,1489,1491,1495,1513,1533,1553,1555,1559,1563,1568,1625,1648,1650,1654,1665,1724,1726,1730,1737,1799,1803,1811,1830,1836,1988,2007,2009,2013,2094,2102,2104,2108,2131,2141,2239,2251,2253,2256,2265,2267,2271,2277,2390,2392,2400,2407,2415,2640,2838,2841,2872,2874,2878,2884,3062,3106,3109,3111,3119,3128,3259,3297,3300,3332,3334,3338,3395,3397,3401,3408,3465,3471,3473,3477,3987,4380,4387,4389,4393,4396,4505,4507,4511,4533],[348,349,350,353],"p",{},[351,352,153],"strong",{}," stores successful query results in a storage backend (Hive, Isar, SharedPreferences, and others) and restores them on application startup. The in-memory cache is hydrated before the first network request, including offline sessions.",[348,355,356,357,361],{},"This is built on three components in the ",[358,359,360],"code",{},"qora"," package:",[363,364,365,378],"table",{},[366,367,368],"thead",{},[369,370,371,375],"tr",{},[372,373,374],"th",{},"Class",[372,376,377],{},"Role",[379,380,381,392,406],"tbody",{},[369,382,383,389],{},[384,385,386],"td",{},[358,387,388],{},"StorageAdapter",[384,390,391],{},"Raw key/value contract for a storage backend",[369,393,394,399],{},[384,395,396],{},[358,397,398],{},"QoraSerializer\u003CT>",[384,400,401,402,405],{},"Converts ",[358,403,404],{},"T"," ↔ JSON for a specific type",[369,407,408,412],{},[384,409,410],{},[358,411,229],{},[384,413,414,415,417],{},"Drop-in ",[358,416,202],{}," replacement that wires everything together",[419,420],"hr",{},[422,423,98],"h2",{"id":424},"setup",[426,427,429,430,432,433],"h3",{"id":428},"_1-replace-qoraclient-with-persistqoraclient","1. Replace ",[358,431,202],{}," with ",[358,434,229],{},[436,437,443],"pre",{"className":438,"code":439,"filename":440,"language":441,"meta":442,"style":442},"language-dart shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import 'package:qora/qora.dart';\n\nfinal client = PersistQoraClient(\n  storage: InMemoryStorageAdapter(), // swap for a real adapter (see below)\n  persistDuration: const Duration(days: 7),\n  config: const QoraClientConfig(\n    defaultOptions: QoraOptions(staleTime: Duration(minutes: 5)),\n    debugMode: true, // prints [PersistQora] logs\n  ),\n);\n","main.dart","dart","",[358,444,445,462,469,490,512,540,555,586,600,608],{"__ignoreMap":442},[446,447,450,454,458],"span",{"class":448,"line":449},"line",1,[446,451,453],{"class":452},"sbssI","import",[446,455,457],{"class":456},"sfazB"," 'package:qora/qora.dart'",[446,459,461],{"class":460},"sMK4o",";\n",[446,463,465],{"class":448,"line":464},2,[446,466,468],{"emptyLinePlaceholder":467},true,"\n",[446,470,472,476,480,483,487],{"class":448,"line":471},3,[446,473,475],{"class":474},"spNyl","final",[446,477,479],{"class":478},"sTEyZ"," client ",[446,481,482],{"class":460},"=",[446,484,486],{"class":485},"sBMFI"," PersistQoraClient",[446,488,489],{"class":478},"(\n",[446,491,493,496,499,502,505,508],{"class":448,"line":492},4,[446,494,495],{"class":478},"  storage",[446,497,498],{"class":460},":",[446,500,501],{"class":485}," InMemoryStorageAdapter",[446,503,504],{"class":478},"()",[446,506,507],{"class":460},",",[446,509,511],{"class":510},"sHwdD"," // swap for a real adapter (see below)\n",[446,513,515,518,520,523,526,529,531,534,537],{"class":448,"line":514},5,[446,516,517],{"class":478},"  persistDuration",[446,519,498],{"class":460},[446,521,522],{"class":474}," const",[446,524,525],{"class":485}," Duration",[446,527,528],{"class":478},"(days",[446,530,498],{"class":460},[446,532,533],{"class":452}," 7",[446,535,536],{"class":478},")",[446,538,539],{"class":460},",\n",[446,541,543,546,548,550,553],{"class":448,"line":542},6,[446,544,545],{"class":478},"  config",[446,547,498],{"class":460},[446,549,522],{"class":474},[446,551,552],{"class":485}," QoraClientConfig",[446,554,489],{"class":478},[446,556,558,561,563,566,569,571,573,576,578,581,584],{"class":448,"line":557},7,[446,559,560],{"class":478},"    defaultOptions",[446,562,498],{"class":460},[446,564,565],{"class":485}," QoraOptions",[446,567,568],{"class":478},"(staleTime",[446,570,498],{"class":460},[446,572,525],{"class":485},[446,574,575],{"class":478},"(minutes",[446,577,498],{"class":460},[446,579,580],{"class":452}," 5",[446,582,583],{"class":478},"))",[446,585,539],{"class":460},[446,587,589,592,594,597],{"class":448,"line":588},8,[446,590,591],{"class":478},"    debugMode",[446,593,498],{"class":460},[446,595,596],{"class":460}," true,",[446,598,599],{"class":510}," // prints [PersistQora] logs\n",[446,601,603,606],{"class":448,"line":602},9,[446,604,605],{"class":478},"  )",[446,607,539],{"class":460},[446,609,611,613],{"class":448,"line":610},10,[446,612,536],{"class":478},[446,614,461],{"class":460},[348,616,617,619,620,622,623,626,627,630,631,634],{},[358,618,229],{}," extends ",[358,621,202],{},". Existing APIs such as ",[358,624,625],{},"fetchQuery",", ",[358,628,629],{},"watchQuery",", and ",[358,632,633],{},"invalidate"," remain unchanged.",[419,636],{},[426,638,640],{"id":639},"_2-register-serializers","2. Register serializers",[348,642,643,644,646,647,650,651,654],{},"Register a ",[358,645,398],{}," for every type you want to persist. Do this ",[351,648,649],{},"before"," calling ",[358,652,653],{},"hydrate",".",[436,656,658],{"className":438,"code":657,"filename":440,"language":441,"meta":442,"style":442},"// Single object\nclient.registerSerializer\u003CUser>(\n  QoraSerializer(\n    toJson: (user) => user.toJson(),\n    fromJson: User.fromJson,\n  ),\n  name: 'User', // explicit name: see Obfuscation section below\n);\n\n// Collection\nclient.registerSerializer\u003CList\u003CPost>>(\n  QoraSerializer(\n    toJson: (posts) => posts.map((p) => p.toJson()).toList(),\n    fromJson: (json)  => (json as List).map((e) => Post.fromJson(e)).toList(),\n  ),\n  name: 'List\u003CPost>',\n);\n\n// Primitive: no conversion needed\nclient.registerSerializer\u003Cint>(\n  QoraSerializer(toJson: (n) => n, fromJson: (json) => json as int),\n  name: 'int',\n);\n",[358,659,660,665,685,692,717,734,740,755,761,765,770,792,799,843,893,900,912,919,924,930,946,988,1000],{"__ignoreMap":442},[446,661,662],{"class":448,"line":449},[446,663,664],{"class":510},"// Single object\n",[446,666,667,670,672,676,679,682],{"class":448,"line":464},[446,668,669],{"class":478},"client",[446,671,654],{"class":460},[446,673,675],{"class":674},"s2Zo4","registerSerializer",[446,677,678],{"class":478},"\u003C",[446,680,681],{"class":485},"User",[446,683,684],{"class":478},">(\n",[446,686,687,690],{"class":448,"line":471},[446,688,689],{"class":485},"  QoraSerializer",[446,691,489],{"class":478},[446,693,694,697,699,702,705,708,710,713,715],{"class":448,"line":492},[446,695,696],{"class":478},"    toJson",[446,698,498],{"class":460},[446,700,701],{"class":478}," (user) ",[446,703,704],{"class":460},"=>",[446,706,707],{"class":478}," user",[446,709,654],{"class":460},[446,711,712],{"class":674},"toJson",[446,714,504],{"class":478},[446,716,539],{"class":460},[446,718,719,722,724,727,729,732],{"class":448,"line":514},[446,720,721],{"class":478},"    fromJson",[446,723,498],{"class":460},[446,725,726],{"class":485}," User",[446,728,654],{"class":460},[446,730,731],{"class":478},"fromJson",[446,733,539],{"class":460},[446,735,736,738],{"class":448,"line":542},[446,737,605],{"class":478},[446,739,539],{"class":460},[446,741,742,745,747,750,752],{"class":448,"line":557},[446,743,744],{"class":478},"  name",[446,746,498],{"class":460},[446,748,749],{"class":456}," 'User'",[446,751,507],{"class":460},[446,753,754],{"class":510}," // explicit name: see Obfuscation section below\n",[446,756,757,759],{"class":448,"line":588},[446,758,536],{"class":478},[446,760,461],{"class":460},[446,762,763],{"class":448,"line":602},[446,764,468],{"emptyLinePlaceholder":467},[446,766,767],{"class":448,"line":610},[446,768,769],{"class":510},"// Collection\n",[446,771,773,775,777,779,781,784,786,789],{"class":448,"line":772},11,[446,774,669],{"class":478},[446,776,654],{"class":460},[446,778,675],{"class":674},[446,780,678],{"class":478},[446,782,783],{"class":485},"List",[446,785,678],{"class":478},[446,787,788],{"class":485},"Post",[446,790,791],{"class":478},">>(\n",[446,793,795,797],{"class":448,"line":794},12,[446,796,689],{"class":485},[446,798,489],{"class":478},[446,800,802,804,806,809,811,814,816,819,822,824,827,829,831,834,836,839,841],{"class":448,"line":801},13,[446,803,696],{"class":478},[446,805,498],{"class":460},[446,807,808],{"class":478}," (posts) ",[446,810,704],{"class":460},[446,812,813],{"class":478}," posts",[446,815,654],{"class":460},[446,817,818],{"class":674},"map",[446,820,821],{"class":478},"((p) ",[446,823,704],{"class":460},[446,825,826],{"class":478}," p",[446,828,654],{"class":460},[446,830,712],{"class":674},[446,832,833],{"class":478},"())",[446,835,654],{"class":460},[446,837,838],{"class":674},"toList",[446,840,504],{"class":478},[446,842,539],{"class":460},[446,844,846,848,850,853,855,858,861,864,866,868,870,873,875,878,880,882,885,887,889,891],{"class":448,"line":845},14,[446,847,721],{"class":478},[446,849,498],{"class":460},[446,851,852],{"class":478}," (json)  ",[446,854,704],{"class":460},[446,856,857],{"class":478}," (json ",[446,859,860],{"class":460},"as",[446,862,863],{"class":485}," List",[446,865,536],{"class":478},[446,867,654],{"class":460},[446,869,818],{"class":674},[446,871,872],{"class":478},"((e) ",[446,874,704],{"class":460},[446,876,877],{"class":485}," Post",[446,879,654],{"class":460},[446,881,731],{"class":674},[446,883,884],{"class":478},"(e))",[446,886,654],{"class":460},[446,888,838],{"class":674},[446,890,504],{"class":478},[446,892,539],{"class":460},[446,894,896,898],{"class":448,"line":895},15,[446,897,605],{"class":478},[446,899,539],{"class":460},[446,901,903,905,907,910],{"class":448,"line":902},16,[446,904,744],{"class":478},[446,906,498],{"class":460},[446,908,909],{"class":456}," 'List\u003CPost>'",[446,911,539],{"class":460},[446,913,915,917],{"class":448,"line":914},17,[446,916,536],{"class":478},[446,918,461],{"class":460},[446,920,922],{"class":448,"line":921},18,[446,923,468],{"emptyLinePlaceholder":467},[446,925,927],{"class":448,"line":926},19,[446,928,929],{"class":510},"// Primitive: no conversion needed\n",[446,931,933,935,937,939,941,944],{"class":448,"line":932},20,[446,934,669],{"class":478},[446,936,654],{"class":460},[446,938,675],{"class":674},[446,940,678],{"class":478},[446,942,943],{"class":485},"int",[446,945,684],{"class":478},[446,947,949,951,954,956,959,961,964,966,969,971,974,976,979,981,984,986],{"class":448,"line":948},21,[446,950,689],{"class":485},[446,952,953],{"class":478},"(toJson",[446,955,498],{"class":460},[446,957,958],{"class":478}," (n) ",[446,960,704],{"class":460},[446,962,963],{"class":478}," n",[446,965,507],{"class":460},[446,967,968],{"class":478}," fromJson",[446,970,498],{"class":460},[446,972,973],{"class":478}," (json) ",[446,975,704],{"class":460},[446,977,978],{"class":478}," json ",[446,980,860],{"class":460},[446,982,983],{"class":485}," int",[446,985,536],{"class":478},[446,987,539],{"class":460},[446,989,991,993,995,998],{"class":448,"line":990},22,[446,992,744],{"class":478},[446,994,498],{"class":460},[446,996,997],{"class":456}," 'int'",[446,999,539],{"class":460},[446,1001,1003,1005],{"class":448,"line":1002},23,[446,1004,536],{"class":478},[446,1006,461],{"class":460},[348,1008,1009],{},"Types without a registered serializer are fetched and cached in memory normally. They are not persisted to disk.",[348,1011,1012,1013,1018],{},"For projects with many models, see ",[1014,1015,1017],"a",{"href":1016},"#organising-serializers-at-scale","Organising Serializers at Scale"," below.",[419,1020],{},[426,1022,1024],{"id":1023},"_3-initialise-storage-then-hydrate","3. Initialise storage, then hydrate",[348,1026,1027,1028,1031,1032,1035],{},"Awaiting ",[358,1029,1030],{},"hydrate()"," before ",[358,1033,1034],{},"runApp"," guarantees a warm cache on the first frame:",[436,1037,1039],{"className":438,"code":1038,"filename":440,"language":441,"meta":442,"style":442},"Future\u003Cvoid> main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n\n  await storage.init();         // open the database / file\n  await client.hydrate();       // warm cache from disk\n\n  runApp(QoraScope(client: client, child: const MyApp()));\n}\n",[358,1040,1041,1067,1081,1085,1106,1124,1128,1162],{"__ignoreMap":442},[446,1042,1043,1046,1048,1051,1054,1057,1060,1064],{"class":448,"line":449},[446,1044,1045],{"class":485},"Future",[446,1047,678],{"class":478},[446,1049,1050],{"class":474},"void",[446,1052,1053],{"class":478},"> ",[446,1055,1056],{"class":674},"main",[446,1058,1059],{"class":478},"() ",[446,1061,1063],{"class":1062},"s7zQu","async",[446,1065,1066],{"class":478}," {\n",[446,1068,1069,1072,1074,1077,1079],{"class":448,"line":464},[446,1070,1071],{"class":485},"  WidgetsFlutterBinding",[446,1073,654],{"class":460},[446,1075,1076],{"class":674},"ensureInitialized",[446,1078,504],{"class":478},[446,1080,461],{"class":460},[446,1082,1083],{"class":448,"line":471},[446,1084,468],{"emptyLinePlaceholder":467},[446,1086,1087,1090,1093,1095,1098,1100,1103],{"class":448,"line":492},[446,1088,1089],{"class":1062},"  await",[446,1091,1092],{"class":478}," storage",[446,1094,654],{"class":460},[446,1096,1097],{"class":674},"init",[446,1099,504],{"class":478},[446,1101,1102],{"class":460},";",[446,1104,1105],{"class":510},"         // open the database / file\n",[446,1107,1108,1110,1113,1115,1117,1119,1121],{"class":448,"line":514},[446,1109,1089],{"class":1062},[446,1111,1112],{"class":478}," client",[446,1114,654],{"class":460},[446,1116,653],{"class":674},[446,1118,504],{"class":478},[446,1120,1102],{"class":460},[446,1122,1123],{"class":510},"       // warm cache from disk\n",[446,1125,1126],{"class":448,"line":542},[446,1127,468],{"emptyLinePlaceholder":467},[446,1129,1130,1133,1136,1138,1141,1143,1145,1147,1150,1152,1154,1157,1160],{"class":448,"line":557},[446,1131,1132],{"class":674},"  runApp",[446,1134,1135],{"class":478},"(",[446,1137,103],{"class":485},[446,1139,1140],{"class":478},"(client",[446,1142,498],{"class":460},[446,1144,1112],{"class":478},[446,1146,507],{"class":460},[446,1148,1149],{"class":478}," child",[446,1151,498],{"class":460},[446,1153,522],{"class":474},[446,1155,1156],{"class":485}," MyApp",[446,1158,1159],{"class":478},"()))",[446,1161,461],{"class":460},[446,1163,1164],{"class":448,"line":588},[446,1165,1166],{"class":478},"}\n",[348,1168,1169,1170,1172,1173,1176,1177,498],{},"If ",[358,1171,1030],{}," is measurably slow (large number of stored entries: verify with profiling before optimising), show a ",[351,1174,1175],{},"splash screen"," while the future runs rather than blocking ",[358,1178,1034],{},[436,1180,1182],{"className":438,"code":1181,"filename":440,"language":441,"meta":442,"style":442},"void main() {\n  WidgetsFlutterBinding.ensureInitialized();\n\n  runApp(\n    QoraScope(\n      client: client,\n      child: FutureBuilder\u003Cvoid>(\n        future: storage.init().then((_) => client.hydrate()),\n        builder: (context, snapshot) {\n          if (snapshot.connectionState != ConnectionState.done) {\n            return const MaterialApp(home: SplashScreen());\n          }\n          return const MyApp();\n        },\n      ),\n    ),\n  );\n}\n",[358,1183,1184,1194,1206,1210,1216,1223,1234,1250,1285,1300,1324,1346,1351,1364,1371,1378,1385,1391],{"__ignoreMap":442},[446,1185,1186,1188,1191],{"class":448,"line":449},[446,1187,1050],{"class":474},[446,1189,1190],{"class":674}," main",[446,1192,1193],{"class":478},"() {\n",[446,1195,1196,1198,1200,1202,1204],{"class":448,"line":464},[446,1197,1071],{"class":485},[446,1199,654],{"class":460},[446,1201,1076],{"class":674},[446,1203,504],{"class":478},[446,1205,461],{"class":460},[446,1207,1208],{"class":448,"line":471},[446,1209,468],{"emptyLinePlaceholder":467},[446,1211,1212,1214],{"class":448,"line":492},[446,1213,1132],{"class":674},[446,1215,489],{"class":478},[446,1217,1218,1221],{"class":448,"line":514},[446,1219,1220],{"class":485},"    QoraScope",[446,1222,489],{"class":478},[446,1224,1225,1228,1230,1232],{"class":448,"line":542},[446,1226,1227],{"class":478},"      client",[446,1229,498],{"class":460},[446,1231,1112],{"class":478},[446,1233,539],{"class":460},[446,1235,1236,1239,1241,1244,1246,1248],{"class":448,"line":557},[446,1237,1238],{"class":478},"      child",[446,1240,498],{"class":460},[446,1242,1243],{"class":485}," FutureBuilder",[446,1245,678],{"class":478},[446,1247,1050],{"class":474},[446,1249,684],{"class":478},[446,1251,1252,1255,1257,1259,1261,1263,1265,1267,1270,1273,1275,1277,1279,1281,1283],{"class":448,"line":588},[446,1253,1254],{"class":478},"        future",[446,1256,498],{"class":460},[446,1258,1092],{"class":478},[446,1260,654],{"class":460},[446,1262,1097],{"class":674},[446,1264,504],{"class":478},[446,1266,654],{"class":460},[446,1268,1269],{"class":674},"then",[446,1271,1272],{"class":478},"((_) ",[446,1274,704],{"class":460},[446,1276,1112],{"class":478},[446,1278,654],{"class":460},[446,1280,653],{"class":674},[446,1282,833],{"class":478},[446,1284,539],{"class":460},[446,1286,1287,1290,1292,1295,1297],{"class":448,"line":602},[446,1288,1289],{"class":478},"        builder",[446,1291,498],{"class":460},[446,1293,1294],{"class":478}," (context",[446,1296,507],{"class":460},[446,1298,1299],{"class":478}," snapshot) {\n",[446,1301,1302,1305,1308,1310,1313,1316,1319,1321],{"class":448,"line":610},[446,1303,1304],{"class":1062},"          if",[446,1306,1307],{"class":478}," (snapshot",[446,1309,654],{"class":460},[446,1311,1312],{"class":478},"connectionState ",[446,1314,1315],{"class":460},"!=",[446,1317,1318],{"class":485}," ConnectionState",[446,1320,654],{"class":460},[446,1322,1323],{"class":478},"done) {\n",[446,1325,1326,1329,1331,1334,1337,1339,1342,1344],{"class":448,"line":772},[446,1327,1328],{"class":1062},"            return",[446,1330,522],{"class":474},[446,1332,1333],{"class":485}," MaterialApp",[446,1335,1336],{"class":478},"(home",[446,1338,498],{"class":460},[446,1340,1341],{"class":485}," SplashScreen",[446,1343,833],{"class":478},[446,1345,461],{"class":460},[446,1347,1348],{"class":448,"line":794},[446,1349,1350],{"class":478},"          }\n",[446,1352,1353,1356,1358,1360,1362],{"class":448,"line":801},[446,1354,1355],{"class":1062},"          return",[446,1357,522],{"class":474},[446,1359,1156],{"class":485},[446,1361,504],{"class":478},[446,1363,461],{"class":460},[446,1365,1366,1369],{"class":448,"line":845},[446,1367,1368],{"class":478},"        }",[446,1370,539],{"class":460},[446,1372,1373,1376],{"class":448,"line":895},[446,1374,1375],{"class":478},"      )",[446,1377,539],{"class":460},[446,1379,1380,1383],{"class":448,"line":902},[446,1381,1382],{"class":478},"    )",[446,1384,539],{"class":460},[446,1386,1387,1389],{"class":448,"line":914},[446,1388,605],{"class":478},[446,1390,461],{"class":460},[446,1392,1393],{"class":448,"line":921},[446,1394,1166],{"class":478},[348,1396,1397,1398,1400,1401,1404],{},"In practice, ",[358,1399,1030],{}," reads a handful of JSON strings from local storage. For most apps the ",[358,1402,1403],{},"before runApp"," pattern is simpler and fast enough.",[419,1406],{},[422,1408,1410],{"id":1409},"how-it-works","How It Works",[426,1412,1414],{"id":1413},"auto-persist-write-through","Auto-persist (write-through)",[348,1416,1417,1418,1420],{},"After every successful fetch: whether triggered directly or by SWR background revalidation: the result is written to ",[358,1419,388],{}," as a JSON envelope containing:",[1422,1423,1424,1428,1434,1440],"ul",{},[1425,1426,1427],"li",{},"the serialised data",[1425,1429,1430,1431,536],{},"a type discriminator (",[358,1432,1433],{},"typeName",[1425,1435,1436,1437,536],{},"the timestamp (",[358,1438,1439],{},"persistedAt",[1425,1441,1442],{},"the TTL in milliseconds",[348,1444,1445],{},"No extra code needed. As long as the type has a registered serializer, it is persisted automatically.",[419,1447],{},[426,1449,1451],{"id":1450},"lazy-typed-hydration","Lazy typed hydration",[348,1453,1454,1456,1457,1460,1461,626,1464,626,1467,1470,1471,654],{},[358,1455,1030],{}," deserialises stored entries but does ",[351,1458,1459],{},"not"," inject them into the cache immediately. Instead, it queues them in an internal map. On the first call to ",[358,1462,1463],{},"fetchQuery\u003CT>",[358,1465,1466],{},"watchQuery\u003CT>",[358,1468,1469],{},"getQueryData\u003CT>",", etc., the queued entry is consumed and injected as a correctly-typed ",[358,1472,1473],{},"CacheEntry\u003CT>",[348,1475,1476,1477,1480,1481,1484,1485,1488],{},"This avoids a Dart runtime cast failure: ",[358,1478,1479],{},"CacheEntry\u003Cdynamic> as CacheEntry\u003CUser>"," throws, but ",[358,1482,1483],{},"CacheEntry\u003CUser>"," created by ",[358,1486,1487],{},"hydrateQuery\u003CUser>"," does not.",[419,1490],{},[426,1492,1494],{"id":1493},"swr-and-freshness","SWR and freshness",[348,1496,1497,1498,1501,1502,1504,1505,1508,1509,1512],{},"The restored ",[358,1499,1500],{},"Success"," state carries the original ",[358,1503,1439],{}," as its ",[358,1506,1507],{},"updatedAt"," timestamp. This means ",[358,1510,1511],{},"staleTime"," works exactly as in-memory:",[1422,1514,1515,1524],{},[1425,1516,1517,1519,1520,1523],{},[358,1518,1439],{}," is recent → entry is ",[351,1521,1522],{},"fresh"," → no network call on mount",[1425,1525,1526,1528,1529,1532],{},[358,1527,1439],{}," is old → entry is ",[351,1530,1531],{},"stale"," → widget shows cached data immediately, then revalidates in background (SWR)",[436,1534,1536],{"className":438,"code":1535,"filename":440,"language":441,"meta":442,"style":442},"// staleTime: 5 minutes\n// If the last fetch was 3 minutes ago → still fresh → no spinner on restart\n// If the last fetch was 8 minutes ago → show cached data + background refetch\n",[358,1537,1538,1543,1548],{"__ignoreMap":442},[446,1539,1540],{"class":448,"line":449},[446,1541,1542],{"class":510},"// staleTime: 5 minutes\n",[446,1544,1545],{"class":448,"line":464},[446,1546,1547],{"class":510},"// If the last fetch was 3 minutes ago → still fresh → no spinner on restart\n",[446,1549,1550],{"class":448,"line":471},[446,1551,1552],{"class":510},"// If the last fetch was 8 minutes ago → show cached data + background refetch\n",[419,1554],{},[422,1556,1558],{"id":1557},"ttl-time-to-live","TTL (Time To Live)",[426,1560,1562],{"id":1561},"global-ttl","Global TTL",[348,1564,1565,1566,498],{},"Set once on ",[358,1567,229],{},[436,1569,1571],{"className":438,"code":1570,"filename":440,"language":441,"meta":442,"style":442},"final client = PersistQoraClient(\n  storage: adapter,\n  persistDuration: const Duration(days: 7), // default\n);\n",[358,1572,1573,1585,1596,1619],{"__ignoreMap":442},[446,1574,1575,1577,1579,1581,1583],{"class":448,"line":449},[446,1576,475],{"class":474},[446,1578,479],{"class":478},[446,1580,482],{"class":460},[446,1582,486],{"class":485},[446,1584,489],{"class":478},[446,1586,1587,1589,1591,1594],{"class":448,"line":464},[446,1588,495],{"class":478},[446,1590,498],{"class":460},[446,1592,1593],{"class":478}," adapter",[446,1595,539],{"class":460},[446,1597,1598,1600,1602,1604,1606,1608,1610,1612,1614,1616],{"class":448,"line":471},[446,1599,517],{"class":478},[446,1601,498],{"class":460},[446,1603,522],{"class":474},[446,1605,525],{"class":485},[446,1607,528],{"class":478},[446,1609,498],{"class":460},[446,1611,533],{"class":452},[446,1613,536],{"class":478},[446,1615,507],{"class":460},[446,1617,1618],{"class":510}," // default\n",[446,1620,1621,1623],{"class":448,"line":492},[446,1622,536],{"class":478},[446,1624,461],{"class":460},[348,1626,1627,1628,1631,1632,1635,1636,1639,1640,1643,1644,1647],{},"By default, entries expire after 7 days (",[358,1629,1630],{},"persistDuration: Duration(days: 7)",").\nPass ",[358,1633,1634],{},"null"," to persist indefinitely (until ",[358,1637,1638],{},"removeQuery"," or ",[358,1641,1642],{},"evictFromStorage"," is called explicitly).\nPass ",[358,1645,1646],{},"Duration.zero"," to disable persistence (entries expire immediately).",[419,1649],{},[426,1651,1653],{"id":1652},"per-query-ttl-override","Per-query TTL override",[348,1655,1656,1657,1660,1661,1664],{},"Pass ",[358,1658,1659],{},"ttl:"," when calling ",[358,1662,1663],{},"persistQuery"," manually:",[436,1666,1668],{"className":438,"code":1667,"filename":440,"language":441,"meta":442,"style":442},"// Force-persist the current cached value with a custom TTL\nawait client.persistQuery\u003CUser>(['users', userId], ttl: const Duration(hours: 1));\n",[358,1669,1670,1675],{"__ignoreMap":442},[446,1671,1672],{"class":448,"line":449},[446,1673,1674],{"class":510},"// Force-persist the current cached value with a custom TTL\n",[446,1676,1677,1680,1682,1684,1686,1688,1690,1693,1696,1698,1701,1703,1706,1708,1710,1712,1715,1717,1720,1722],{"class":448,"line":464},[446,1678,1679],{"class":1062},"await",[446,1681,1112],{"class":478},[446,1683,654],{"class":460},[446,1685,1663],{"class":674},[446,1687,678],{"class":478},[446,1689,681],{"class":485},[446,1691,1692],{"class":478},">([",[446,1694,1695],{"class":456},"'users'",[446,1697,507],{"class":460},[446,1699,1700],{"class":478}," userId]",[446,1702,507],{"class":460},[446,1704,1705],{"class":478}," ttl",[446,1707,498],{"class":460},[446,1709,522],{"class":474},[446,1711,525],{"class":485},[446,1713,1714],{"class":478},"(hours",[446,1716,498],{"class":460},[446,1718,1719],{"class":452}," 1",[446,1721,583],{"class":478},[446,1723,461],{"class":460},[419,1725],{},[426,1727,1729],{"id":1728},"what-happens-to-expired-entries-on-hydrate","What happens to expired entries on hydrate?",[348,1731,1732,1733,1736],{},"Expired entries are ",[351,1734,1735],{},"deleted from storage and skipped",": they are never injected into the cache. The next successful fetch will write a fresh entry.",[436,1738,1742],{"className":1739,"code":1740,"language":1741,"meta":442,"style":442},"language-mermaid shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","graph TD\n    A[hydrate: read all keys from storage]\n    A --> B{Expired?}\n    B -- yes --> C[Delete from storage]\n    B -- no --> D{Serializer found?}\n    D -- no --> E[Warn + skip]\n    D -- yes --> F{fromJson OK?}\n    F -- no --> G[Delete + warn]\n    F -- yes --> H[Queue in _pendingHydration]\n    H --> I[First fetchQuery / watchQuery call]\n    I --> J[hydrateQuery typed injection into cache]\n","mermaid",[358,1743,1744,1749,1754,1759,1764,1769,1774,1779,1784,1789,1794],{"__ignoreMap":442},[446,1745,1746],{"class":448,"line":449},[446,1747,1748],{"class":478},"graph TD\n",[446,1750,1751],{"class":448,"line":464},[446,1752,1753],{"class":478},"    A[hydrate: read all keys from storage]\n",[446,1755,1756],{"class":448,"line":471},[446,1757,1758],{"class":478},"    A --> B{Expired?}\n",[446,1760,1761],{"class":448,"line":492},[446,1762,1763],{"class":478},"    B -- yes --> C[Delete from storage]\n",[446,1765,1766],{"class":448,"line":514},[446,1767,1768],{"class":478},"    B -- no --> D{Serializer found?}\n",[446,1770,1771],{"class":448,"line":542},[446,1772,1773],{"class":478},"    D -- no --> E[Warn + skip]\n",[446,1775,1776],{"class":448,"line":557},[446,1777,1778],{"class":478},"    D -- yes --> F{fromJson OK?}\n",[446,1780,1781],{"class":448,"line":588},[446,1782,1783],{"class":478},"    F -- no --> G[Delete + warn]\n",[446,1785,1786],{"class":448,"line":602},[446,1787,1788],{"class":478},"    F -- yes --> H[Queue in _pendingHydration]\n",[446,1790,1791],{"class":448,"line":610},[446,1792,1793],{"class":478},"    H --> I[First fetchQuery / watchQuery call]\n",[446,1795,1796],{"class":448,"line":772},[446,1797,1798],{"class":478},"    I --> J[hydrateQuery typed injection into cache]\n",[426,1800,1802],{"id":1801},"model-versioning-and-migrations","Model versioning and migrations",[348,1804,1805,1806,1808,1809,654],{},"If your model schema changes between app releases: a required field added to ",[358,1807,681],{},", a field renamed, a type changed: persisted entries written by the old version may fail to deserialise with the new ",[358,1810,731],{},[348,1812,1813,1815,1816,1818,1819,1821,1822,1825,1826,1829],{},[358,1814,229],{}," intercepts every ",[358,1817,731],{}," exception during ",[358,1820,653],{},", logs a warning (when ",[358,1823,1824],{},"debugMode"," is ",[358,1827,1828],{},"true","), deletes the corrupt entry from storage, and moves on. The app never crashes because of a stale schema on disk.",[348,1831,1832,1833,1835],{},"Your responsibility is to write a defensive ",[358,1834,731],{}," that handles both old and new shapes:",[436,1837,1840],{"className":438,"code":1838,"filename":1839,"language":441,"meta":442,"style":442},"factory User.fromJson(dynamic json) {\n  final map = json as Map\u003CString, dynamic>;\n  return User(\n    id: map['id'] as int,\n    name: map['name'] as String,\n    // Added in v2: default to empty string for entries persisted by v1\n    avatarUrl: map['avatarUrl'] as String? ?? '',\n  );\n}\n","models/user.dart",[358,1841,1842,1861,1892,1901,1923,1944,1949,1978,1984],{"__ignoreMap":442},[446,1843,1844,1847,1849,1851,1853,1855,1858],{"class":448,"line":449},[446,1845,1846],{"class":460},"factory",[446,1848,726],{"class":485},[446,1850,654],{"class":460},[446,1852,731],{"class":674},[446,1854,1135],{"class":478},[446,1856,1857],{"class":485},"dynamic",[446,1859,1860],{"class":478}," json) {\n",[446,1862,1863,1866,1869,1871,1873,1875,1878,1880,1883,1885,1887,1890],{"class":448,"line":464},[446,1864,1865],{"class":474},"  final",[446,1867,1868],{"class":478}," map ",[446,1870,482],{"class":460},[446,1872,978],{"class":478},[446,1874,860],{"class":460},[446,1876,1877],{"class":485}," Map",[446,1879,678],{"class":478},[446,1881,1882],{"class":485},"String",[446,1884,626],{"class":478},[446,1886,1857],{"class":485},[446,1888,1889],{"class":478},">",[446,1891,461],{"class":460},[446,1893,1894,1897,1899],{"class":448,"line":471},[446,1895,1896],{"class":1062},"  return",[446,1898,726],{"class":485},[446,1900,489],{"class":478},[446,1902,1903,1906,1908,1911,1914,1917,1919,1921],{"class":448,"line":492},[446,1904,1905],{"class":478},"    id",[446,1907,498],{"class":460},[446,1909,1910],{"class":478}," map[",[446,1912,1913],{"class":456},"'id'",[446,1915,1916],{"class":478},"] ",[446,1918,860],{"class":460},[446,1920,983],{"class":485},[446,1922,539],{"class":460},[446,1924,1925,1928,1930,1932,1935,1937,1939,1942],{"class":448,"line":514},[446,1926,1927],{"class":478},"    name",[446,1929,498],{"class":460},[446,1931,1910],{"class":478},[446,1933,1934],{"class":456},"'name'",[446,1936,1916],{"class":478},[446,1938,860],{"class":460},[446,1940,1941],{"class":485}," String",[446,1943,539],{"class":460},[446,1945,1946],{"class":448,"line":542},[446,1947,1948],{"class":510},"    // Added in v2: default to empty string for entries persisted by v1\n",[446,1950,1951,1954,1956,1958,1961,1963,1965,1967,1970,1973,1976],{"class":448,"line":557},[446,1952,1953],{"class":478},"    avatarUrl",[446,1955,498],{"class":460},[446,1957,1910],{"class":478},[446,1959,1960],{"class":456},"'avatarUrl'",[446,1962,1916],{"class":478},[446,1964,860],{"class":460},[446,1966,1941],{"class":485},[446,1968,1969],{"class":460},"?",[446,1971,1972],{"class":460}," ??",[446,1974,1975],{"class":456}," ''",[446,1977,539],{"class":460},[446,1979,1980,1982],{"class":448,"line":588},[446,1981,605],{"class":478},[446,1983,461],{"class":460},[446,1985,1986],{"class":448,"line":602},[446,1987,1166],{"class":478},[348,1989,1990,1991,1994,1995,1998,1999,2002,2003,2006],{},"For ",[351,1992,1993],{},"breaking changes"," (field removal, type change with no safe default), bump the serializer ",[358,1996,1997],{},"name",": e.g. ",[358,2000,2001],{},"'User'"," → ",[358,2004,2005],{},"'User_v2'",". Old entries are silently skipped on hydration (no serializer registered for the old name), the user gets a fresh network fetch on that run, and future writes use the new schema. Old entries are eventually purged by TTL expiry.",[419,2008],{},[422,2010,2012],{"id":2011},"storage-eviction-semantics","Storage Eviction Semantics",[363,2014,2015,2028],{},[366,2016,2017],{},[369,2018,2019,2022,2025],{},[372,2020,2021],{},"Operation",[372,2023,2024],{},"In-memory cache",[372,2026,2027],{},"Storage",[379,2029,2030,2045,2058,2072,2083],{},[369,2031,2032,2037,2040],{},[384,2033,2034],{},[358,2035,2036],{},"invalidate(key)",[384,2038,2039],{},"Marks stale, triggers refetch",[384,2041,2042],{},[351,2043,2044],{},"Untouched",[369,2046,2047,2052,2055],{},[384,2048,2049],{},[358,2050,2051],{},"removeQuery(key)",[384,2053,2054],{},"Removed",[384,2056,2057],{},"Deleted",[369,2059,2060,2065,2068],{},[384,2061,2062],{},[358,2063,2064],{},"clearCache()",[384,2066,2067],{},"Cleared",[384,2069,2070],{},[351,2071,2044],{},[369,2073,2074,2079,2081],{},[384,2075,2076],{},[358,2077,2078],{},"clearStorage()",[384,2080,2044],{},[384,2082,2067],{},[369,2084,2085,2090,2092],{},[384,2086,2087],{},[358,2088,2089],{},"clear()",[384,2091,2067],{},[384,2093,2067],{},[348,2095,2096,2098,2099,2101],{},[358,2097,633],{}," intentionally does ",[351,2100,1459],{}," delete from storage. The intent is to refetch, not purge. The next successful fetch will overwrite the stored entry with fresh data.",[419,2103],{},[422,2105,2107],{"id":2106},"obfuscation-and-flutter-web","Obfuscation and Flutter Web",[348,2109,2110,2111,2114,2115,2118,2119,626,2121,2124,2125,2127,2128,2130],{},"On Flutter Web or when Dart's ",[358,2112,2113],{},"--obfuscate"," flag is active, ",[358,2116,2117],{},"T.toString()"," is replaced by a short minified identifier (",[358,2120,1014],{},[358,2122,2123],{},"b",", …). If ",[358,2126,675],{}," is called without an explicit ",[358,2129,1997],{},", the type discriminator written to disk becomes unreadable on the next cold start.",[348,2132,2133,2140],{},[351,2134,2135,2136,2139],{},"Always pass ",[358,2137,2138],{},"name:"," explicitly"," when targeting these configurations:",[436,2142,2144],{"className":438,"code":2143,"filename":440,"language":441,"meta":442,"style":442},"// Good: Stable: name is hardcoded, never changes\nclient.registerSerializer\u003CUser>(userSerializer, name: 'User');\nclient.registerSerializer\u003CList\u003CPost>>(postListSerializer, name: 'List\u003CPost>');\n\n// Unsafe on Flutter Web / --obfuscate\nclient.registerSerializer\u003CUser>(userSerializer); // name defaults to User.toString()\n",[358,2145,2146,2151,2179,2210,2214,2219],{"__ignoreMap":442},[446,2147,2148],{"class":448,"line":449},[446,2149,2150],{"class":510},"// Good: Stable: name is hardcoded, never changes\n",[446,2152,2153,2155,2157,2159,2161,2163,2166,2168,2171,2173,2175,2177],{"class":448,"line":464},[446,2154,669],{"class":478},[446,2156,654],{"class":460},[446,2158,675],{"class":674},[446,2160,678],{"class":478},[446,2162,681],{"class":485},[446,2164,2165],{"class":478},">(userSerializer",[446,2167,507],{"class":460},[446,2169,2170],{"class":478}," name",[446,2172,498],{"class":460},[446,2174,749],{"class":456},[446,2176,536],{"class":478},[446,2178,461],{"class":460},[446,2180,2181,2183,2185,2187,2189,2191,2193,2195,2198,2200,2202,2204,2206,2208],{"class":448,"line":471},[446,2182,669],{"class":478},[446,2184,654],{"class":460},[446,2186,675],{"class":674},[446,2188,678],{"class":478},[446,2190,783],{"class":485},[446,2192,678],{"class":478},[446,2194,788],{"class":485},[446,2196,2197],{"class":478},">>(postListSerializer",[446,2199,507],{"class":460},[446,2201,2170],{"class":478},[446,2203,498],{"class":460},[446,2205,909],{"class":456},[446,2207,536],{"class":478},[446,2209,461],{"class":460},[446,2211,2212],{"class":448,"line":492},[446,2213,468],{"emptyLinePlaceholder":467},[446,2215,2216],{"class":448,"line":514},[446,2217,2218],{"class":510},"// Unsafe on Flutter Web / --obfuscate\n",[446,2220,2221,2223,2225,2227,2229,2231,2234,2236],{"class":448,"line":542},[446,2222,669],{"class":478},[446,2224,654],{"class":460},[446,2226,675],{"class":674},[446,2228,678],{"class":478},[446,2230,681],{"class":485},[446,2232,2233],{"class":478},">(userSerializer)",[446,2235,1102],{"class":460},[446,2237,2238],{"class":510}," // name defaults to User.toString()\n",[348,2240,2241,2242,2244,2245,2248,2249,654],{},"The ",[358,2243,1997],{}," must remain ",[351,2246,2247],{},"stable across app versions",". Changing it will cause all previously persisted entries for that type to be silently skipped on the next ",[358,2250,653],{},[419,2252],{},[422,2254,1017],{"id":2255},"organising-serializers-at-scale",[348,2257,2258,2259,2261,2262,2264],{},"For small projects (\u003C 10 models), inline ",[358,2260,675],{}," calls in ",[358,2263,440],{}," are fine. As your app grows, the registrations need structure.",[419,2266],{},[426,2268,2270],{"id":2269},"the-problem-with-inline-registration","The problem with inline registration",[348,2272,2273,2274,2276],{},"With 20+ models, ",[358,2275,440],{}," becomes a maintenance burden:",[436,2278,2280],{"className":438,"code":2279,"filename":440,"language":441,"meta":442,"style":442},"// Bad: Unmanageable at scale\nclient.registerSerializer\u003CUser>(...);\nclient.registerSerializer\u003CPost>(...);\nclient.registerSerializer\u003CComment>(...);\nclient.registerSerializer\u003CProduct>(...);\n// 20 more lines...\nawait client.hydrate();\n",[358,2281,2282,2287,2309,2329,2350,2371,2376],{"__ignoreMap":442},[446,2283,2284],{"class":448,"line":449},[446,2285,2286],{"class":510},"// Bad: Unmanageable at scale\n",[446,2288,2289,2291,2293,2295,2297,2299,2302,2305,2307],{"class":448,"line":464},[446,2290,669],{"class":478},[446,2292,654],{"class":460},[446,2294,675],{"class":674},[446,2296,678],{"class":478},[446,2298,681],{"class":485},[446,2300,2301],{"class":478},">(",[446,2303,2304],{"class":460},"...",[446,2306,536],{"class":478},[446,2308,461],{"class":460},[446,2310,2311,2313,2315,2317,2319,2321,2323,2325,2327],{"class":448,"line":471},[446,2312,669],{"class":478},[446,2314,654],{"class":460},[446,2316,675],{"class":674},[446,2318,678],{"class":478},[446,2320,788],{"class":485},[446,2322,2301],{"class":478},[446,2324,2304],{"class":460},[446,2326,536],{"class":478},[446,2328,461],{"class":460},[446,2330,2331,2333,2335,2337,2339,2342,2344,2346,2348],{"class":448,"line":492},[446,2332,669],{"class":478},[446,2334,654],{"class":460},[446,2336,675],{"class":674},[446,2338,678],{"class":478},[446,2340,2341],{"class":485},"Comment",[446,2343,2301],{"class":478},[446,2345,2304],{"class":460},[446,2347,536],{"class":478},[446,2349,461],{"class":460},[446,2351,2352,2354,2356,2358,2360,2363,2365,2367,2369],{"class":448,"line":514},[446,2353,669],{"class":478},[446,2355,654],{"class":460},[446,2357,675],{"class":674},[446,2359,678],{"class":478},[446,2361,2362],{"class":485},"Product",[446,2364,2301],{"class":478},[446,2366,2304],{"class":460},[446,2368,536],{"class":478},[446,2370,461],{"class":460},[446,2372,2373],{"class":448,"line":542},[446,2374,2375],{"class":510},"// 20 more lines...\n",[446,2377,2378,2380,2382,2384,2386,2388],{"class":448,"line":557},[446,2379,1679],{"class":1062},[446,2381,1112],{"class":478},[446,2383,654],{"class":460},[446,2385,653],{"class":674},[446,2387,504],{"class":478},[446,2389,461],{"class":460},[419,2391],{},[426,2393,2395,2396,2399],{"id":2394},"recommended-satellite-_serializerdart-files","Recommended: satellite ",[358,2397,2398],{},"_serializer.dart"," files",[348,2401,2402,2403,2406],{},"Keep your model ",[351,2404,2405],{},"pure"," (no Qora dependency) and place its serializer in a dedicated satellite file next to it:",[436,2408,2413],{"className":2409,"code":2411,"language":2412,"meta":442},[2410],"language-text","features/\n  user/\n    models/\n      user.dart             ← pure data class, no Qora import\n      user_serializer.dart  ← QoraSerializer lives here\n  post/\n    models/\n      post.dart\n      post_serializer.dart\n","text",[358,2414,2411],{"__ignoreMap":442},[436,2416,2419],{"className":438,"code":2417,"filename":2418,"language":441,"meta":442,"style":442},"// No Qora import: model is fully portable\nclass User {\n  final int id;\n  final String name;\n\n  const User({required this.id, required this.name});\n\n  factory User.fromJson(dynamic json) {\n    final map = json as Map\u003CString, dynamic>;\n    return User(id: map['id'] as int, name: map['name'] as String);\n  }\n\n  Map\u003CString, dynamic> toJson() => {'id': id, 'name': name};\n}\n","features/user/models/user.dart",[358,2420,2421,2426,2435,2446,2456,2460,2495,2499,2516,2543,2585,2590,2594,2636],{"__ignoreMap":442},[446,2422,2423],{"class":448,"line":449},[446,2424,2425],{"class":510},"// No Qora import: model is fully portable\n",[446,2427,2428,2431,2433],{"class":448,"line":464},[446,2429,2430],{"class":460},"class",[446,2432,726],{"class":485},[446,2434,1066],{"class":478},[446,2436,2437,2439,2441,2444],{"class":448,"line":471},[446,2438,1865],{"class":474},[446,2440,983],{"class":485},[446,2442,2443],{"class":478}," id",[446,2445,461],{"class":460},[446,2447,2448,2450,2452,2454],{"class":448,"line":492},[446,2449,1865],{"class":474},[446,2451,1941],{"class":485},[446,2453,2170],{"class":478},[446,2455,461],{"class":460},[446,2457,2458],{"class":448,"line":514},[446,2459,468],{"emptyLinePlaceholder":467},[446,2461,2462,2465,2467,2470,2473,2476,2478,2481,2483,2486,2488,2490,2493],{"class":448,"line":542},[446,2463,2464],{"class":474},"  const",[446,2466,726],{"class":485},[446,2468,2469],{"class":478},"({",[446,2471,2472],{"class":474},"required",[446,2474,2475],{"class":478}," this",[446,2477,654],{"class":460},[446,2479,2480],{"class":478},"id",[446,2482,507],{"class":460},[446,2484,2485],{"class":474}," required",[446,2487,2475],{"class":478},[446,2489,654],{"class":460},[446,2491,2492],{"class":478},"name})",[446,2494,461],{"class":460},[446,2496,2497],{"class":448,"line":557},[446,2498,468],{"emptyLinePlaceholder":467},[446,2500,2501,2504,2506,2508,2510,2512,2514],{"class":448,"line":588},[446,2502,2503],{"class":460},"  factory",[446,2505,726],{"class":485},[446,2507,654],{"class":460},[446,2509,731],{"class":674},[446,2511,1135],{"class":478},[446,2513,1857],{"class":485},[446,2515,1860],{"class":478},[446,2517,2518,2521,2523,2525,2527,2529,2531,2533,2535,2537,2539,2541],{"class":448,"line":602},[446,2519,2520],{"class":474},"    final",[446,2522,1868],{"class":478},[446,2524,482],{"class":460},[446,2526,978],{"class":478},[446,2528,860],{"class":460},[446,2530,1877],{"class":485},[446,2532,678],{"class":478},[446,2534,1882],{"class":485},[446,2536,626],{"class":478},[446,2538,1857],{"class":485},[446,2540,1889],{"class":478},[446,2542,461],{"class":460},[446,2544,2545,2548,2550,2553,2555,2557,2559,2561,2563,2565,2567,2569,2571,2573,2575,2577,2579,2581,2583],{"class":448,"line":610},[446,2546,2547],{"class":1062},"    return",[446,2549,726],{"class":485},[446,2551,2552],{"class":478},"(id",[446,2554,498],{"class":460},[446,2556,1910],{"class":478},[446,2558,1913],{"class":456},[446,2560,1916],{"class":478},[446,2562,860],{"class":460},[446,2564,983],{"class":485},[446,2566,507],{"class":460},[446,2568,2170],{"class":478},[446,2570,498],{"class":460},[446,2572,1910],{"class":478},[446,2574,1934],{"class":456},[446,2576,1916],{"class":478},[446,2578,860],{"class":460},[446,2580,1941],{"class":485},[446,2582,536],{"class":478},[446,2584,461],{"class":460},[446,2586,2587],{"class":448,"line":772},[446,2588,2589],{"class":478},"  }\n",[446,2591,2592],{"class":448,"line":794},[446,2593,468],{"emptyLinePlaceholder":467},[446,2595,2596,2599,2601,2603,2605,2607,2609,2611,2613,2615,2618,2620,2622,2624,2626,2629,2631,2634],{"class":448,"line":801},[446,2597,2598],{"class":485},"  Map",[446,2600,678],{"class":478},[446,2602,1882],{"class":485},[446,2604,626],{"class":478},[446,2606,1857],{"class":485},[446,2608,1053],{"class":478},[446,2610,712],{"class":674},[446,2612,1059],{"class":478},[446,2614,704],{"class":460},[446,2616,2617],{"class":478}," {",[446,2619,1913],{"class":456},[446,2621,498],{"class":460},[446,2623,2443],{"class":478},[446,2625,507],{"class":460},[446,2627,2628],{"class":456}," 'name'",[446,2630,498],{"class":460},[446,2632,2633],{"class":478}," name}",[446,2635,461],{"class":460},[446,2637,2638],{"class":448,"line":845},[446,2639,1166],{"class":478},[436,2641,2644],{"className":438,"code":2642,"filename":2643,"language":441,"meta":442,"style":442},"import 'package:qora/qora.dart';\nimport 'user.dart';\n\nfinal userSerializer = QoraSerializer\u003CUser>(\n  toJson:   (u) => u.toJson(),\n  fromJson: User.fromJson,\n);\n\nfinal userListSerializer = QoraSerializer\u003CList\u003CUser>>(\n  toJson:   (list) => list.map((u) => u.toJson()).toList(),\n  fromJson: (json) => (json as List).map(User.fromJson).toList(),\n);\n","features/user/models/user_serializer.dart",[358,2645,2646,2654,2663,2667,2685,2708,2723,2729,2733,2754,2793,2832],{"__ignoreMap":442},[446,2647,2648,2650,2652],{"class":448,"line":449},[446,2649,453],{"class":452},[446,2651,457],{"class":456},[446,2653,461],{"class":460},[446,2655,2656,2658,2661],{"class":448,"line":464},[446,2657,453],{"class":452},[446,2659,2660],{"class":456}," 'user.dart'",[446,2662,461],{"class":460},[446,2664,2665],{"class":448,"line":471},[446,2666,468],{"emptyLinePlaceholder":467},[446,2668,2669,2671,2674,2676,2679,2681,2683],{"class":448,"line":492},[446,2670,475],{"class":474},[446,2672,2673],{"class":478}," userSerializer ",[446,2675,482],{"class":460},[446,2677,2678],{"class":485}," QoraSerializer",[446,2680,678],{"class":478},[446,2682,681],{"class":485},[446,2684,684],{"class":478},[446,2686,2687,2690,2692,2695,2697,2700,2702,2704,2706],{"class":448,"line":514},[446,2688,2689],{"class":478},"  toJson",[446,2691,498],{"class":460},[446,2693,2694],{"class":478},"   (u) ",[446,2696,704],{"class":460},[446,2698,2699],{"class":478}," u",[446,2701,654],{"class":460},[446,2703,712],{"class":674},[446,2705,504],{"class":478},[446,2707,539],{"class":460},[446,2709,2710,2713,2715,2717,2719,2721],{"class":448,"line":542},[446,2711,2712],{"class":478},"  fromJson",[446,2714,498],{"class":460},[446,2716,726],{"class":485},[446,2718,654],{"class":460},[446,2720,731],{"class":478},[446,2722,539],{"class":460},[446,2724,2725,2727],{"class":448,"line":557},[446,2726,536],{"class":478},[446,2728,461],{"class":460},[446,2730,2731],{"class":448,"line":588},[446,2732,468],{"emptyLinePlaceholder":467},[446,2734,2735,2737,2740,2742,2744,2746,2748,2750,2752],{"class":448,"line":602},[446,2736,475],{"class":474},[446,2738,2739],{"class":478}," userListSerializer ",[446,2741,482],{"class":460},[446,2743,2678],{"class":485},[446,2745,678],{"class":478},[446,2747,783],{"class":485},[446,2749,678],{"class":478},[446,2751,681],{"class":485},[446,2753,791],{"class":478},[446,2755,2756,2758,2760,2763,2765,2768,2770,2772,2775,2777,2779,2781,2783,2785,2787,2789,2791],{"class":448,"line":610},[446,2757,2689],{"class":478},[446,2759,498],{"class":460},[446,2761,2762],{"class":478},"   (list) ",[446,2764,704],{"class":460},[446,2766,2767],{"class":478}," list",[446,2769,654],{"class":460},[446,2771,818],{"class":674},[446,2773,2774],{"class":478},"((u) ",[446,2776,704],{"class":460},[446,2778,2699],{"class":478},[446,2780,654],{"class":460},[446,2782,712],{"class":674},[446,2784,833],{"class":478},[446,2786,654],{"class":460},[446,2788,838],{"class":674},[446,2790,504],{"class":478},[446,2792,539],{"class":460},[446,2794,2795,2797,2799,2801,2803,2805,2807,2809,2811,2813,2815,2817,2819,2821,2824,2826,2828,2830],{"class":448,"line":772},[446,2796,2712],{"class":478},[446,2798,498],{"class":460},[446,2800,973],{"class":478},[446,2802,704],{"class":460},[446,2804,857],{"class":478},[446,2806,860],{"class":460},[446,2808,863],{"class":485},[446,2810,536],{"class":478},[446,2812,654],{"class":460},[446,2814,818],{"class":674},[446,2816,1135],{"class":478},[446,2818,681],{"class":485},[446,2820,654],{"class":460},[446,2822,2823],{"class":478},"fromJson)",[446,2825,654],{"class":460},[446,2827,838],{"class":674},[446,2829,504],{"class":478},[446,2831,539],{"class":460},[446,2833,2834,2836],{"class":448,"line":794},[446,2835,536],{"class":478},[446,2837,461],{"class":460},[348,2839,2840],{},"This pattern has three benefits:",[1422,2842,2843,2849,2859],{},[1425,2844,2845,2848],{},[351,2846,2847],{},"Model stays portable",": reusable with a Dart backend, other packages, or a different cache engine without dragging a Qora dependency",[1425,2850,2851,2854,2855,2858],{},[351,2852,2853],{},"Tree-shaking",": if ",[358,2856,2857],{},"user_serializer.dart"," is never imported, it is not compiled",[1425,2860,2861,2864,2865,626,2868,2871],{},[351,2862,2863],{},"Multi-format friendly",": you can add ",[358,2866,2867],{},"user_firestore.dart",[358,2869,2870],{},"user_supabase.dart"," etc. without touching the model",[419,2873],{},[426,2875,2877],{"id":2876},"central-registration-function","Central registration function",[348,2879,2880,2881,2883],{},"Collect all satellite serializers in one file: ",[358,2882,440],{}," calls a single function:",[436,2885,2888],{"className":438,"code":2886,"filename":2887,"language":441,"meta":442,"style":442},"import 'package:qora/qora.dart';\nimport '../../features/user/models/user_serializer.dart';\nimport '../../features/post/models/post_serializer.dart';\nimport '../../features/product/models/product_serializer.dart';\n\nvoid registerAllSerializers(PersistQoraClient client) {\n  client.registerSerializer\u003CUser>(userSerializer, name: 'User');\n  client.registerSerializer\u003CList\u003CUser>>(userListSerializer, name: 'List\u003CUser>');\n  client.registerSerializer\u003CPost>(postSerializer, name: 'Post');\n  client.registerSerializer\u003CProduct>(productSerializer, name: 'Product');\n}\n","lib/core/persistence/serializers.dart",[358,2889,2890,2898,2907,2916,2925,2929,2943,2970,3002,3030,3058],{"__ignoreMap":442},[446,2891,2892,2894,2896],{"class":448,"line":449},[446,2893,453],{"class":452},[446,2895,457],{"class":456},[446,2897,461],{"class":460},[446,2899,2900,2902,2905],{"class":448,"line":464},[446,2901,453],{"class":452},[446,2903,2904],{"class":456}," '../../features/user/models/user_serializer.dart'",[446,2906,461],{"class":460},[446,2908,2909,2911,2914],{"class":448,"line":471},[446,2910,453],{"class":452},[446,2912,2913],{"class":456}," '../../features/post/models/post_serializer.dart'",[446,2915,461],{"class":460},[446,2917,2918,2920,2923],{"class":448,"line":492},[446,2919,453],{"class":452},[446,2921,2922],{"class":456}," '../../features/product/models/product_serializer.dart'",[446,2924,461],{"class":460},[446,2926,2927],{"class":448,"line":514},[446,2928,468],{"emptyLinePlaceholder":467},[446,2930,2931,2933,2936,2938,2940],{"class":448,"line":542},[446,2932,1050],{"class":474},[446,2934,2935],{"class":674}," registerAllSerializers",[446,2937,1135],{"class":478},[446,2939,229],{"class":485},[446,2941,2942],{"class":478}," client) {\n",[446,2944,2945,2948,2950,2952,2954,2956,2958,2960,2962,2964,2966,2968],{"class":448,"line":557},[446,2946,2947],{"class":478},"  client",[446,2949,654],{"class":460},[446,2951,675],{"class":674},[446,2953,678],{"class":478},[446,2955,681],{"class":485},[446,2957,2165],{"class":478},[446,2959,507],{"class":460},[446,2961,2170],{"class":478},[446,2963,498],{"class":460},[446,2965,749],{"class":456},[446,2967,536],{"class":478},[446,2969,461],{"class":460},[446,2971,2972,2974,2976,2978,2980,2982,2984,2986,2989,2991,2993,2995,2998,3000],{"class":448,"line":588},[446,2973,2947],{"class":478},[446,2975,654],{"class":460},[446,2977,675],{"class":674},[446,2979,678],{"class":478},[446,2981,783],{"class":485},[446,2983,678],{"class":478},[446,2985,681],{"class":485},[446,2987,2988],{"class":478},">>(userListSerializer",[446,2990,507],{"class":460},[446,2992,2170],{"class":478},[446,2994,498],{"class":460},[446,2996,2997],{"class":456}," 'List\u003CUser>'",[446,2999,536],{"class":478},[446,3001,461],{"class":460},[446,3003,3004,3006,3008,3010,3012,3014,3017,3019,3021,3023,3026,3028],{"class":448,"line":602},[446,3005,2947],{"class":478},[446,3007,654],{"class":460},[446,3009,675],{"class":674},[446,3011,678],{"class":478},[446,3013,788],{"class":485},[446,3015,3016],{"class":478},">(postSerializer",[446,3018,507],{"class":460},[446,3020,2170],{"class":478},[446,3022,498],{"class":460},[446,3024,3025],{"class":456}," 'Post'",[446,3027,536],{"class":478},[446,3029,461],{"class":460},[446,3031,3032,3034,3036,3038,3040,3042,3045,3047,3049,3051,3054,3056],{"class":448,"line":610},[446,3033,2947],{"class":478},[446,3035,654],{"class":460},[446,3037,675],{"class":674},[446,3039,678],{"class":478},[446,3041,2362],{"class":485},[446,3043,3044],{"class":478},">(productSerializer",[446,3046,507],{"class":460},[446,3048,2170],{"class":478},[446,3050,498],{"class":460},[446,3052,3053],{"class":456}," 'Product'",[446,3055,536],{"class":478},[446,3057,461],{"class":460},[446,3059,3060],{"class":448,"line":772},[446,3061,1166],{"class":478},[436,3063,3065],{"className":438,"code":3064,"filename":440,"language":441,"meta":442,"style":442},"registerAllSerializers(client); // ← single call, regardless of model count\nawait client.hydrate();\nrunApp(...);\n",[358,3066,3067,3080,3094],{"__ignoreMap":442},[446,3068,3069,3072,3075,3077],{"class":448,"line":449},[446,3070,3071],{"class":674},"registerAllSerializers",[446,3073,3074],{"class":478},"(client)",[446,3076,1102],{"class":460},[446,3078,3079],{"class":510}," // ← single call, regardless of model count\n",[446,3081,3082,3084,3086,3088,3090,3092],{"class":448,"line":464},[446,3083,1679],{"class":1062},[446,3085,1112],{"class":478},[446,3087,654],{"class":460},[446,3089,653],{"class":674},[446,3091,504],{"class":478},[446,3093,461],{"class":460},[446,3095,3096,3098,3100,3102,3104],{"class":448,"line":471},[446,3097,1034],{"class":674},[446,3099,1135],{"class":478},[446,3101,2304],{"class":460},[446,3103,536],{"class":478},[446,3105,461],{"class":460},[348,3107,3108],{},"This file also becomes the authoritative list of every type that gets persisted: useful for auditing and migrations.",[419,3110],{},[426,3112,3114,3115,3118],{"id":3113},"alternative-static-const-on-the-model-class","Alternative: ",[358,3116,3117],{},"static const"," on the model class",[348,3120,3121,3122,3124,3125,3127],{},"If your model lives entirely within the Flutter app and ",[358,3123,360],{}," is a core dependency with no plans to share the model elsewhere, a ",[358,3126,3117],{}," serializer on the class itself is acceptable and offers the best autocompletion:",[436,3129,3131],{"className":438,"code":3130,"filename":2418,"language":441,"meta":442,"style":442},"import 'package:qora/qora.dart';\n\nclass User {\n  // ...\n\n  static const serializer = QoraSerializer\u003CUser>(\n    toJson:   _encode,\n    fromJson: User.fromJson,\n  );\n\n  static Map\u003CString, dynamic> _encode(User u) => u.toJson();\n}\n",[358,3132,3133,3141,3145,3153,3158,3162,3182,3193,3207,3213,3217,3255],{"__ignoreMap":442},[446,3134,3135,3137,3139],{"class":448,"line":449},[446,3136,453],{"class":452},[446,3138,457],{"class":456},[446,3140,461],{"class":460},[446,3142,3143],{"class":448,"line":464},[446,3144,468],{"emptyLinePlaceholder":467},[446,3146,3147,3149,3151],{"class":448,"line":471},[446,3148,2430],{"class":460},[446,3150,726],{"class":485},[446,3152,1066],{"class":478},[446,3154,3155],{"class":448,"line":492},[446,3156,3157],{"class":510},"  // ...\n",[446,3159,3160],{"class":448,"line":514},[446,3161,468],{"emptyLinePlaceholder":467},[446,3163,3164,3167,3169,3172,3174,3176,3178,3180],{"class":448,"line":542},[446,3165,3166],{"class":474},"  static",[446,3168,522],{"class":474},[446,3170,3171],{"class":478}," serializer ",[446,3173,482],{"class":460},[446,3175,2678],{"class":485},[446,3177,678],{"class":478},[446,3179,681],{"class":485},[446,3181,684],{"class":478},[446,3183,3184,3186,3188,3191],{"class":448,"line":557},[446,3185,696],{"class":478},[446,3187,498],{"class":460},[446,3189,3190],{"class":478},"   _encode",[446,3192,539],{"class":460},[446,3194,3195,3197,3199,3201,3203,3205],{"class":448,"line":588},[446,3196,721],{"class":478},[446,3198,498],{"class":460},[446,3200,726],{"class":485},[446,3202,654],{"class":460},[446,3204,731],{"class":478},[446,3206,539],{"class":460},[446,3208,3209,3211],{"class":448,"line":602},[446,3210,605],{"class":478},[446,3212,461],{"class":460},[446,3214,3215],{"class":448,"line":610},[446,3216,468],{"emptyLinePlaceholder":467},[446,3218,3219,3221,3223,3225,3227,3229,3231,3233,3236,3238,3240,3243,3245,3247,3249,3251,3253],{"class":448,"line":772},[446,3220,3166],{"class":474},[446,3222,1877],{"class":485},[446,3224,678],{"class":478},[446,3226,1882],{"class":485},[446,3228,626],{"class":478},[446,3230,1857],{"class":485},[446,3232,1053],{"class":478},[446,3234,3235],{"class":674},"_encode",[446,3237,1135],{"class":478},[446,3239,681],{"class":485},[446,3241,3242],{"class":478}," u) ",[446,3244,704],{"class":460},[446,3246,2699],{"class":478},[446,3248,654],{"class":460},[446,3250,712],{"class":674},[446,3252,504],{"class":478},[446,3254,461],{"class":460},[446,3256,3257],{"class":448,"line":794},[446,3258,1166],{"class":478},[436,3260,3262],{"className":438,"code":3261,"filename":2887,"language":441,"meta":442,"style":442},"client.registerSerializer\u003CUser>(User.serializer, name: 'User');\n",[358,3263,3264],{"__ignoreMap":442},[446,3265,3266,3268,3270,3272,3274,3276,3278,3280,3282,3285,3287,3289,3291,3293,3295],{"class":448,"line":449},[446,3267,669],{"class":478},[446,3269,654],{"class":460},[446,3271,675],{"class":674},[446,3273,678],{"class":478},[446,3275,681],{"class":485},[446,3277,2301],{"class":478},[446,3279,681],{"class":485},[446,3281,654],{"class":460},[446,3283,3284],{"class":478},"serializer",[446,3286,507],{"class":460},[446,3288,2170],{"class":478},[446,3290,498],{"class":460},[446,3292,749],{"class":456},[446,3294,536],{"class":478},[446,3296,461],{"class":460},[348,3298,3299],{},"This approach is simpler but couples the model to Qora. Avoid it if the model is shared across packages or with a backend.",[3301,3302,3303],"blockquote",{},[348,3304,3305,3308,3309,3311,3312,3315,3316,3320,3321,3324,3325,3328,3329,3331],{},[351,3306,3307],{},"Note on Dart extensions:"," ",[358,3310,3117],{}," members defined inside a Dart ",[358,3313,3314],{},"extension"," block are accessed via the ",[3317,3318,3319],"em",{},"extension name"," (",[358,3322,3323],{},"UserQoraExt.serializer","), not via the class (",[358,3326,3327],{},"User.serializer","). If you want ",[358,3330,3327],{}," syntax, the static must be on the class itself, not on an extension.",[419,3333],{},[426,3335,3337],{"id":3336},"decision-guide","Decision guide",[363,3339,3340,3350],{},[366,3341,3342],{},[369,3343,3344,3347],{},[372,3345,3346],{},"Context",[372,3348,3349],{},"Pattern",[379,3351,3352,3362,3372,3385],{},[369,3353,3354,3357],{},[384,3355,3356],{},"\u003C 10 models, small app",[384,3358,3359,3360],{},"Inline in ",[358,3361,440],{},[369,3363,3364,3367],{},[384,3365,3366],{},"Model shared with backend or other packages",[384,3368,3369,3371],{},[358,3370,2398],{}," satellite (mandatory)",[369,3373,3374,3377],{},[384,3375,3376],{},"Feature-first architecture, 15+ models",[384,3378,3379,3381,3382],{},[358,3380,2398],{}," + ",[358,3383,3384],{},"registerAllSerializers()",[369,3386,3387,3390],{},[384,3388,3389],{},"Model is Flutter-only, DX is top priority",[384,3391,3392,3394],{},[358,3393,3117],{}," on the class",[419,3396],{},[422,3398,3400],{"id":3399},"storage-adapters","Storage Adapters",[348,3402,3403,3404,3407],{},"The built-in ",[358,3405,3406],{},"InMemoryStorageAdapter"," is useful for tests. For real apps, use one of the external adapter packages:",[363,3409,3410,3420],{},[366,3411,3412],{},[369,3413,3414,3417],{},[372,3415,3416],{},"Package",[372,3418,3419],{},"Backend",[379,3421,3422,3435,3445,3455],{},[369,3423,3424,3429],{},[384,3425,3426],{},[358,3427,3428],{},"qora_storage_shared_prefs",[384,3430,3431,3434],{},[358,3432,3433],{},"SharedPreferences",": simple, no extra setup",[369,3436,3437,3442],{},[384,3438,3439],{},[358,3440,3441],{},"qora_storage_hive",[384,3443,3444],{},"Hive: fast, no native dependencies",[369,3446,3447,3452],{},[384,3448,3449],{},[358,3450,3451],{},"qora_storage_isar",[384,3453,3454],{},"Isar: reactive, efficient binary format",[369,3456,3457,3462],{},[384,3458,3459],{},[358,3460,3461],{},"qora_storage_drift",[384,3463,3464],{},"Drift / SQLite: relational, great for complex queries",[348,3466,3467,3468,3470],{},"All adapters implement the same ",[358,3469,388],{}," interface: switching backends requires changing one line.",[419,3472],{},[422,3474,3476],{"id":3475},"full-flutter-example","Full Flutter Example",[436,3478,3480],{"className":438,"code":3479,"filename":440,"language":441,"meta":442,"style":442},"import 'package:flutter/material.dart';\nimport 'package:qora_flutter/qora_flutter.dart';\nimport 'package:qora/qora.dart';\n\nFuture\u003Cvoid> main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n\n  final storage = InMemoryStorageAdapter(); // replace with HiveStorageAdapter()\n  await storage.init();\n\n  final client = PersistQoraClient(\n    storage: storage,\n    persistDuration: const Duration(days: 7),\n    config: const QoraClientConfig(\n      defaultOptions: QoraOptions(staleTime: Duration(minutes: 5)),\n    ),\n  );\n\n  client.registerSerializer\u003CUser>(\n    QoraSerializer(toJson: (u) => u.toJson(), fromJson: User.fromJson),\n    name: 'User',\n  );\n  client.registerSerializer\u003CList\u003CPost>>(\n    QoraSerializer(\n      toJson:   (posts) => posts.map((p) => p.toJson()).toList(),\n      fromJson: (json)  => (json as List).map((e) => Post.fromJson(e)).toList(),\n    ),\n    name: 'List\u003CPost>',\n  );\n\n  await client.hydrate(); // warm cache from disk\n\n  runApp(\n    QoraScope(\n      client: client,\n      lifecycleManager: FlutterLifecycleManager(qoraClient: client),\n      child: const MyApp(),\n    ),\n  );\n}\n",[358,3481,3482,3491,3500,3508,3512,3530,3542,3546,3564,3578,3582,3594,3605,3626,3639,3664,3670,3676,3680,3694,3730,3740,3746,3764,3771,3810,3854,3861,3872,3879,3884,3902,3907,3914,3921,3932,3953,3968,3975,3982],{"__ignoreMap":442},[446,3483,3484,3486,3489],{"class":448,"line":449},[446,3485,453],{"class":452},[446,3487,3488],{"class":456}," 'package:flutter/material.dart'",[446,3490,461],{"class":460},[446,3492,3493,3495,3498],{"class":448,"line":464},[446,3494,453],{"class":452},[446,3496,3497],{"class":456}," 'package:qora_flutter/qora_flutter.dart'",[446,3499,461],{"class":460},[446,3501,3502,3504,3506],{"class":448,"line":471},[446,3503,453],{"class":452},[446,3505,457],{"class":456},[446,3507,461],{"class":460},[446,3509,3510],{"class":448,"line":492},[446,3511,468],{"emptyLinePlaceholder":467},[446,3513,3514,3516,3518,3520,3522,3524,3526,3528],{"class":448,"line":514},[446,3515,1045],{"class":485},[446,3517,678],{"class":478},[446,3519,1050],{"class":474},[446,3521,1053],{"class":478},[446,3523,1056],{"class":674},[446,3525,1059],{"class":478},[446,3527,1063],{"class":1062},[446,3529,1066],{"class":478},[446,3531,3532,3534,3536,3538,3540],{"class":448,"line":542},[446,3533,1071],{"class":485},[446,3535,654],{"class":460},[446,3537,1076],{"class":674},[446,3539,504],{"class":478},[446,3541,461],{"class":460},[446,3543,3544],{"class":448,"line":557},[446,3545,468],{"emptyLinePlaceholder":467},[446,3547,3548,3550,3553,3555,3557,3559,3561],{"class":448,"line":588},[446,3549,1865],{"class":474},[446,3551,3552],{"class":478}," storage ",[446,3554,482],{"class":460},[446,3556,501],{"class":485},[446,3558,504],{"class":478},[446,3560,1102],{"class":460},[446,3562,3563],{"class":510}," // replace with HiveStorageAdapter()\n",[446,3565,3566,3568,3570,3572,3574,3576],{"class":448,"line":602},[446,3567,1089],{"class":1062},[446,3569,1092],{"class":478},[446,3571,654],{"class":460},[446,3573,1097],{"class":674},[446,3575,504],{"class":478},[446,3577,461],{"class":460},[446,3579,3580],{"class":448,"line":610},[446,3581,468],{"emptyLinePlaceholder":467},[446,3583,3584,3586,3588,3590,3592],{"class":448,"line":772},[446,3585,1865],{"class":474},[446,3587,479],{"class":478},[446,3589,482],{"class":460},[446,3591,486],{"class":485},[446,3593,489],{"class":478},[446,3595,3596,3599,3601,3603],{"class":448,"line":794},[446,3597,3598],{"class":478},"    storage",[446,3600,498],{"class":460},[446,3602,1092],{"class":478},[446,3604,539],{"class":460},[446,3606,3607,3610,3612,3614,3616,3618,3620,3622,3624],{"class":448,"line":801},[446,3608,3609],{"class":478},"    persistDuration",[446,3611,498],{"class":460},[446,3613,522],{"class":474},[446,3615,525],{"class":485},[446,3617,528],{"class":478},[446,3619,498],{"class":460},[446,3621,533],{"class":452},[446,3623,536],{"class":478},[446,3625,539],{"class":460},[446,3627,3628,3631,3633,3635,3637],{"class":448,"line":845},[446,3629,3630],{"class":478},"    config",[446,3632,498],{"class":460},[446,3634,522],{"class":474},[446,3636,552],{"class":485},[446,3638,489],{"class":478},[446,3640,3641,3644,3646,3648,3650,3652,3654,3656,3658,3660,3662],{"class":448,"line":895},[446,3642,3643],{"class":478},"      defaultOptions",[446,3645,498],{"class":460},[446,3647,565],{"class":485},[446,3649,568],{"class":478},[446,3651,498],{"class":460},[446,3653,525],{"class":485},[446,3655,575],{"class":478},[446,3657,498],{"class":460},[446,3659,580],{"class":452},[446,3661,583],{"class":478},[446,3663,539],{"class":460},[446,3665,3666,3668],{"class":448,"line":902},[446,3667,1382],{"class":478},[446,3669,539],{"class":460},[446,3671,3672,3674],{"class":448,"line":914},[446,3673,605],{"class":478},[446,3675,461],{"class":460},[446,3677,3678],{"class":448,"line":921},[446,3679,468],{"emptyLinePlaceholder":467},[446,3681,3682,3684,3686,3688,3690,3692],{"class":448,"line":926},[446,3683,2947],{"class":478},[446,3685,654],{"class":460},[446,3687,675],{"class":674},[446,3689,678],{"class":478},[446,3691,681],{"class":485},[446,3693,684],{"class":478},[446,3695,3696,3699,3701,3703,3706,3708,3710,3712,3714,3716,3718,3720,3722,3724,3726,3728],{"class":448,"line":932},[446,3697,3698],{"class":485},"    QoraSerializer",[446,3700,953],{"class":478},[446,3702,498],{"class":460},[446,3704,3705],{"class":478}," (u) ",[446,3707,704],{"class":460},[446,3709,2699],{"class":478},[446,3711,654],{"class":460},[446,3713,712],{"class":674},[446,3715,504],{"class":478},[446,3717,507],{"class":460},[446,3719,968],{"class":478},[446,3721,498],{"class":460},[446,3723,726],{"class":485},[446,3725,654],{"class":460},[446,3727,2823],{"class":478},[446,3729,539],{"class":460},[446,3731,3732,3734,3736,3738],{"class":448,"line":948},[446,3733,1927],{"class":478},[446,3735,498],{"class":460},[446,3737,749],{"class":456},[446,3739,539],{"class":460},[446,3741,3742,3744],{"class":448,"line":990},[446,3743,605],{"class":478},[446,3745,461],{"class":460},[446,3747,3748,3750,3752,3754,3756,3758,3760,3762],{"class":448,"line":1002},[446,3749,2947],{"class":478},[446,3751,654],{"class":460},[446,3753,675],{"class":674},[446,3755,678],{"class":478},[446,3757,783],{"class":485},[446,3759,678],{"class":478},[446,3761,788],{"class":485},[446,3763,791],{"class":478},[446,3765,3767,3769],{"class":448,"line":3766},24,[446,3768,3698],{"class":485},[446,3770,489],{"class":478},[446,3772,3774,3777,3779,3782,3784,3786,3788,3790,3792,3794,3796,3798,3800,3802,3804,3806,3808],{"class":448,"line":3773},25,[446,3775,3776],{"class":478},"      toJson",[446,3778,498],{"class":460},[446,3780,3781],{"class":478},"   (posts) ",[446,3783,704],{"class":460},[446,3785,813],{"class":478},[446,3787,654],{"class":460},[446,3789,818],{"class":674},[446,3791,821],{"class":478},[446,3793,704],{"class":460},[446,3795,826],{"class":478},[446,3797,654],{"class":460},[446,3799,712],{"class":674},[446,3801,833],{"class":478},[446,3803,654],{"class":460},[446,3805,838],{"class":674},[446,3807,504],{"class":478},[446,3809,539],{"class":460},[446,3811,3813,3816,3818,3820,3822,3824,3826,3828,3830,3832,3834,3836,3838,3840,3842,3844,3846,3848,3850,3852],{"class":448,"line":3812},26,[446,3814,3815],{"class":478},"      fromJson",[446,3817,498],{"class":460},[446,3819,852],{"class":478},[446,3821,704],{"class":460},[446,3823,857],{"class":478},[446,3825,860],{"class":460},[446,3827,863],{"class":485},[446,3829,536],{"class":478},[446,3831,654],{"class":460},[446,3833,818],{"class":674},[446,3835,872],{"class":478},[446,3837,704],{"class":460},[446,3839,877],{"class":485},[446,3841,654],{"class":460},[446,3843,731],{"class":674},[446,3845,884],{"class":478},[446,3847,654],{"class":460},[446,3849,838],{"class":674},[446,3851,504],{"class":478},[446,3853,539],{"class":460},[446,3855,3857,3859],{"class":448,"line":3856},27,[446,3858,1382],{"class":478},[446,3860,539],{"class":460},[446,3862,3864,3866,3868,3870],{"class":448,"line":3863},28,[446,3865,1927],{"class":478},[446,3867,498],{"class":460},[446,3869,909],{"class":456},[446,3871,539],{"class":460},[446,3873,3875,3877],{"class":448,"line":3874},29,[446,3876,605],{"class":478},[446,3878,461],{"class":460},[446,3880,3882],{"class":448,"line":3881},30,[446,3883,468],{"emptyLinePlaceholder":467},[446,3885,3887,3889,3891,3893,3895,3897,3899],{"class":448,"line":3886},31,[446,3888,1089],{"class":1062},[446,3890,1112],{"class":478},[446,3892,654],{"class":460},[446,3894,653],{"class":674},[446,3896,504],{"class":478},[446,3898,1102],{"class":460},[446,3900,3901],{"class":510}," // warm cache from disk\n",[446,3903,3905],{"class":448,"line":3904},32,[446,3906,468],{"emptyLinePlaceholder":467},[446,3908,3910,3912],{"class":448,"line":3909},33,[446,3911,1132],{"class":674},[446,3913,489],{"class":478},[446,3915,3917,3919],{"class":448,"line":3916},34,[446,3918,1220],{"class":485},[446,3920,489],{"class":478},[446,3922,3924,3926,3928,3930],{"class":448,"line":3923},35,[446,3925,1227],{"class":478},[446,3927,498],{"class":460},[446,3929,1112],{"class":478},[446,3931,539],{"class":460},[446,3933,3935,3938,3940,3943,3946,3948,3951],{"class":448,"line":3934},36,[446,3936,3937],{"class":478},"      lifecycleManager",[446,3939,498],{"class":460},[446,3941,3942],{"class":485}," FlutterLifecycleManager",[446,3944,3945],{"class":478},"(qoraClient",[446,3947,498],{"class":460},[446,3949,3950],{"class":478}," client)",[446,3952,539],{"class":460},[446,3954,3956,3958,3960,3962,3964,3966],{"class":448,"line":3955},37,[446,3957,1238],{"class":478},[446,3959,498],{"class":460},[446,3961,522],{"class":474},[446,3963,1156],{"class":485},[446,3965,504],{"class":478},[446,3967,539],{"class":460},[446,3969,3971,3973],{"class":448,"line":3970},38,[446,3972,1382],{"class":478},[446,3974,539],{"class":460},[446,3976,3978,3980],{"class":448,"line":3977},39,[446,3979,605],{"class":478},[446,3981,461],{"class":460},[446,3983,3985],{"class":448,"line":3984},40,[446,3986,1166],{"class":478},[436,3988,3991],{"className":438,"code":3989,"filename":3990,"language":441,"meta":442,"style":442},"class PostsScreen extends StatelessWidget {\n  const PostsScreen({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return QoraBuilder\u003CList\u003CPost>>(\n      queryKey: ['posts'],\n      fetcher: PostApi.fetchAll,\n      // If hydrated data exists: shown instantly, no spinner.\n      // If stale: shown immediately while refetching in background.\n      builder: (context, state, fetchStatus) => switch (state) {\n        Initial() => const SizedBox.shrink(),\n        Loading(previousData: null) => const CircularProgressIndicator(),\n        Loading(:final previousData?) => PostList(previousData),\n        Success(:final data) => PostList(data),\n        Failure(:final error, previousData: null) => ErrorView('$error'),\n        Failure(:final error, :final previousData?) => Column(children: [\n            PostList(previousData),\n            ErrorBanner('Refresh failed: $error'),\n          ]),\n      },\n    );\n  }\n}\n","screens/posts_screen.dart",[358,3992,3993,4008,4024,4028,4033,4049,4066,4084,4101,4106,4111,4138,4161,4188,4215,4238,4285,4323,4332,4352,4359,4366,4372,4376],{"__ignoreMap":442},[446,3994,3995,3997,4000,4003,4006],{"class":448,"line":449},[446,3996,2430],{"class":460},[446,3998,3999],{"class":485}," PostsScreen",[446,4001,4002],{"class":460}," extends",[446,4004,4005],{"class":485}," StatelessWidget",[446,4007,1066],{"class":478},[446,4009,4010,4012,4014,4017,4019,4022],{"class":448,"line":464},[446,4011,2464],{"class":474},[446,4013,3999],{"class":485},[446,4015,4016],{"class":478},"({super",[446,4018,654],{"class":460},[446,4020,4021],{"class":478},"key})",[446,4023,461],{"class":460},[446,4025,4026],{"class":448,"line":471},[446,4027,468],{"emptyLinePlaceholder":467},[446,4029,4030],{"class":448,"line":492},[446,4031,4032],{"class":474},"  @override\n",[446,4034,4035,4038,4041,4043,4046],{"class":448,"line":514},[446,4036,4037],{"class":485},"  Widget",[446,4039,4040],{"class":674}," build",[446,4042,1135],{"class":478},[446,4044,4045],{"class":485},"BuildContext",[446,4047,4048],{"class":478}," context) {\n",[446,4050,4051,4053,4056,4058,4060,4062,4064],{"class":448,"line":542},[446,4052,2547],{"class":1062},[446,4054,4055],{"class":485}," QoraBuilder",[446,4057,678],{"class":478},[446,4059,783],{"class":485},[446,4061,678],{"class":478},[446,4063,788],{"class":485},[446,4065,791],{"class":478},[446,4067,4068,4071,4073,4076,4079,4082],{"class":448,"line":557},[446,4069,4070],{"class":478},"      queryKey",[446,4072,498],{"class":460},[446,4074,4075],{"class":478}," [",[446,4077,4078],{"class":456},"'posts'",[446,4080,4081],{"class":478},"]",[446,4083,539],{"class":460},[446,4085,4086,4089,4091,4094,4096,4099],{"class":448,"line":588},[446,4087,4088],{"class":478},"      fetcher",[446,4090,498],{"class":460},[446,4092,4093],{"class":485}," PostApi",[446,4095,654],{"class":460},[446,4097,4098],{"class":478},"fetchAll",[446,4100,539],{"class":460},[446,4102,4103],{"class":448,"line":602},[446,4104,4105],{"class":510},"      // If hydrated data exists: shown instantly, no spinner.\n",[446,4107,4108],{"class":448,"line":610},[446,4109,4110],{"class":510},"      // If stale: shown immediately while refetching in background.\n",[446,4112,4113,4116,4118,4120,4122,4125,4127,4130,4132,4135],{"class":448,"line":772},[446,4114,4115],{"class":478},"      builder",[446,4117,498],{"class":460},[446,4119,1294],{"class":478},[446,4121,507],{"class":460},[446,4123,4124],{"class":478}," state",[446,4126,507],{"class":460},[446,4128,4129],{"class":478}," fetchStatus) ",[446,4131,704],{"class":460},[446,4133,4134],{"class":1062}," switch",[446,4136,4137],{"class":478}," (state) {\n",[446,4139,4140,4143,4145,4147,4149,4152,4154,4157,4159],{"class":448,"line":794},[446,4141,4142],{"class":485},"        Initial",[446,4144,1059],{"class":478},[446,4146,704],{"class":460},[446,4148,522],{"class":474},[446,4150,4151],{"class":485}," SizedBox",[446,4153,654],{"class":460},[446,4155,4156],{"class":674},"shrink",[446,4158,504],{"class":478},[446,4160,539],{"class":460},[446,4162,4163,4166,4169,4171,4174,4177,4179,4181,4184,4186],{"class":448,"line":801},[446,4164,4165],{"class":485},"        Loading",[446,4167,4168],{"class":478},"(previousData",[446,4170,498],{"class":460},[446,4172,4173],{"class":460}," null",[446,4175,4176],{"class":478},") ",[446,4178,704],{"class":460},[446,4180,522],{"class":474},[446,4182,4183],{"class":485}," CircularProgressIndicator",[446,4185,504],{"class":478},[446,4187,539],{"class":460},[446,4189,4190,4192,4194,4196,4198,4201,4203,4205,4207,4210,4213],{"class":448,"line":845},[446,4191,4165],{"class":485},[446,4193,1135],{"class":478},[446,4195,498],{"class":460},[446,4197,475],{"class":474},[446,4199,4200],{"class":478}," previousData",[446,4202,1969],{"class":460},[446,4204,4176],{"class":478},[446,4206,704],{"class":460},[446,4208,4209],{"class":485}," PostList",[446,4211,4212],{"class":478},"(previousData)",[446,4214,539],{"class":460},[446,4216,4217,4220,4222,4224,4226,4229,4231,4233,4236],{"class":448,"line":895},[446,4218,4219],{"class":485},"        Success",[446,4221,1135],{"class":478},[446,4223,498],{"class":460},[446,4225,475],{"class":474},[446,4227,4228],{"class":478}," data) ",[446,4230,704],{"class":460},[446,4232,4209],{"class":485},[446,4234,4235],{"class":478},"(data)",[446,4237,539],{"class":460},[446,4239,4240,4243,4245,4247,4249,4252,4254,4256,4258,4260,4262,4264,4267,4269,4272,4275,4279,4281,4283],{"class":448,"line":902},[446,4241,4242],{"class":485},"        Failure",[446,4244,1135],{"class":478},[446,4246,498],{"class":460},[446,4248,475],{"class":474},[446,4250,4251],{"class":478}," error",[446,4253,507],{"class":460},[446,4255,4200],{"class":478},[446,4257,498],{"class":460},[446,4259,4173],{"class":460},[446,4261,4176],{"class":478},[446,4263,704],{"class":460},[446,4265,4266],{"class":485}," ErrorView",[446,4268,1135],{"class":478},[446,4270,4271],{"class":456},"'",[446,4273,4274],{"class":478},"$",[446,4276,4278],{"class":4277},"sHdIc","error",[446,4280,4271],{"class":456},[446,4282,536],{"class":478},[446,4284,539],{"class":460},[446,4286,4287,4289,4291,4293,4295,4297,4299,4302,4304,4306,4308,4310,4312,4315,4318,4320],{"class":448,"line":914},[446,4288,4242],{"class":485},[446,4290,1135],{"class":478},[446,4292,498],{"class":460},[446,4294,475],{"class":474},[446,4296,4251],{"class":478},[446,4298,507],{"class":460},[446,4300,4301],{"class":460}," :",[446,4303,475],{"class":474},[446,4305,4200],{"class":478},[446,4307,1969],{"class":460},[446,4309,4176],{"class":478},[446,4311,704],{"class":460},[446,4313,4314],{"class":485}," Column",[446,4316,4317],{"class":478},"(children",[446,4319,498],{"class":460},[446,4321,4322],{"class":478}," [\n",[446,4324,4325,4328,4330],{"class":448,"line":921},[446,4326,4327],{"class":485},"            PostList",[446,4329,4212],{"class":478},[446,4331,539],{"class":460},[446,4333,4334,4337,4339,4342,4344,4346,4348,4350],{"class":448,"line":926},[446,4335,4336],{"class":485},"            ErrorBanner",[446,4338,1135],{"class":478},[446,4340,4341],{"class":456},"'Refresh failed: ",[446,4343,4274],{"class":478},[446,4345,4278],{"class":4277},[446,4347,4271],{"class":456},[446,4349,536],{"class":478},[446,4351,539],{"class":460},[446,4353,4354,4357],{"class":448,"line":932},[446,4355,4356],{"class":478},"          ])",[446,4358,539],{"class":460},[446,4360,4361,4364],{"class":448,"line":948},[446,4362,4363],{"class":478},"      }",[446,4365,539],{"class":460},[446,4367,4368,4370],{"class":448,"line":990},[446,4369,1382],{"class":478},[446,4371,461],{"class":460},[446,4373,4374],{"class":448,"line":1002},[446,4375,2589],{"class":478},[446,4377,4378],{"class":448,"line":3766},[446,4379,1166],{"class":478},[348,4381,4382,4383,4386],{},"On the first launch, ",[358,4384,4385],{},"PostsScreen"," shows a spinner and fetches from the network. On every subsequent launch, the posts list appears instantly from disk while Qora revalidates in the background if the data is stale.",[419,4388],{},[422,4390,4392],{"id":4391},"logout-account-switch","Logout / Account Switch",[348,4394,4395],{},"When the user logs out, you can choose to clear memory only (keeping storage for next session) or clear both:",[436,4397,4400],{"className":438,"code":4398,"filename":4399,"language":441,"meta":442,"style":442},"Future\u003Cvoid> logout() async {\n  await api.logout();\n\n  // Wipes cache + storage atomically (complete reset)\n  client.clear(); \n\n  // Or, wipe memory only but keep persisted queries for next session\n  // client.clearCache();\n\n  Navigator.pushReplacementNamed(context, '/login');\n}\n","auth_service.dart",[358,4401,4402,4421,4436,4440,4445,4461,4465,4470,4475,4479,4501],{"__ignoreMap":442},[446,4403,4404,4406,4408,4410,4412,4415,4417,4419],{"class":448,"line":449},[446,4405,1045],{"class":485},[446,4407,678],{"class":478},[446,4409,1050],{"class":474},[446,4411,1053],{"class":478},[446,4413,4414],{"class":674},"logout",[446,4416,1059],{"class":478},[446,4418,1063],{"class":1062},[446,4420,1066],{"class":478},[446,4422,4423,4425,4428,4430,4432,4434],{"class":448,"line":464},[446,4424,1089],{"class":1062},[446,4426,4427],{"class":478}," api",[446,4429,654],{"class":460},[446,4431,4414],{"class":674},[446,4433,504],{"class":478},[446,4435,461],{"class":460},[446,4437,4438],{"class":448,"line":471},[446,4439,468],{"emptyLinePlaceholder":467},[446,4441,4442],{"class":448,"line":492},[446,4443,4444],{"class":510},"  // Wipes cache + storage atomically (complete reset)\n",[446,4446,4447,4449,4451,4454,4456,4458],{"class":448,"line":514},[446,4448,2947],{"class":478},[446,4450,654],{"class":460},[446,4452,4453],{"class":674},"clear",[446,4455,504],{"class":478},[446,4457,1102],{"class":460},[446,4459,4460],{"class":478}," \n",[446,4462,4463],{"class":448,"line":542},[446,4464,468],{"emptyLinePlaceholder":467},[446,4466,4467],{"class":448,"line":557},[446,4468,4469],{"class":510},"  // Or, wipe memory only but keep persisted queries for next session\n",[446,4471,4472],{"class":448,"line":588},[446,4473,4474],{"class":510},"  // client.clearCache();\n",[446,4476,4477],{"class":448,"line":602},[446,4478,468],{"emptyLinePlaceholder":467},[446,4480,4481,4484,4486,4489,4492,4494,4497,4499],{"class":448,"line":610},[446,4482,4483],{"class":485},"  Navigator",[446,4485,654],{"class":460},[446,4487,4488],{"class":674},"pushReplacementNamed",[446,4490,4491],{"class":478},"(context",[446,4493,507],{"class":460},[446,4495,4496],{"class":456}," '/login'",[446,4498,536],{"class":478},[446,4500,461],{"class":460},[446,4502,4503],{"class":448,"line":772},[446,4504,1166],{"class":478},[419,4506],{},[422,4508,4510],{"id":4509},"next-steps","Next Steps",[1422,4512,4513,4520,4526],{},[1425,4514,4515,4519],{},[1014,4516,4518],{"href":4517},"../api-reference/persist-qora-client","PersistQoraClient API",": full method reference",[1425,4521,4522,4525],{},[1014,4523,148],{"href":4524},"./optimistic-updates",": combine persistence with optimistic UI",[1425,4527,4528,4532],{},[1014,4529,4531],{"href":4530},"../api-reference/qora-client","QoraClient API",": base client reference",[4534,4535,4536],"style",{},"html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}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 .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}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 .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 .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 .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":442,"searchDepth":464,"depth":464,"links":4538},[4539,4545,4550,4556,4557,4558,4567,4568,4569,4570],{"id":424,"depth":464,"text":98,"children":4540},[4541,4543,4544],{"id":428,"depth":471,"text":4542},"1. Replace QoraClient with PersistQoraClient",{"id":639,"depth":471,"text":640},{"id":1023,"depth":471,"text":1024},{"id":1409,"depth":464,"text":1410,"children":4546},[4547,4548,4549],{"id":1413,"depth":471,"text":1414},{"id":1450,"depth":471,"text":1451},{"id":1493,"depth":471,"text":1494},{"id":1557,"depth":464,"text":1558,"children":4551},[4552,4553,4554,4555],{"id":1561,"depth":471,"text":1562},{"id":1652,"depth":471,"text":1653},{"id":1728,"depth":471,"text":1729},{"id":1801,"depth":471,"text":1802},{"id":2011,"depth":464,"text":2012},{"id":2106,"depth":464,"text":2107},{"id":2255,"depth":464,"text":1017,"children":4559},[4560,4561,4563,4564,4566],{"id":2269,"depth":471,"text":2270},{"id":2394,"depth":471,"text":4562},"Recommended: satellite _serializer.dart files",{"id":2876,"depth":471,"text":2877},{"id":3113,"depth":471,"text":4565},"Alternative: static const on the model class",{"id":3336,"depth":471,"text":3337},{"id":3399,"depth":464,"text":3400},{"id":3475,"depth":464,"text":3476},{"id":4391,"depth":464,"text":4392},{"id":4509,"depth":464,"text":4510},"Persist query results to disk and restore them on startup: giving your app an instant data layer that works fully offline.","md",null,{},{"icon":156},{"title":153,"description":4571},"limWK3YIVEBkCl7zPBZrKALwr7hE3HpMHZRDporS49c",[4579,4581],{"title":148,"path":149,"stem":150,"description":4580,"icon":151,"children":-1},"Update the UI instantly while mutations are in flight, and roll back safely on failure: with no extra libraries.",{"title":158,"path":159,"stem":160,"description":4582,"icon":161,"children":-1},"Handle offline mode, paused queries, offline mutation queuing, and reconnect replay with Qora's network-aware layer.",1794040393901]