[{"data":1,"prerenderedAt":3267},["ShallowReactive",2],{"navigation_docs_fr":3,"-fr-help-troubleshooting":342,"-fr-help-troubleshooting-surround":3264},[4,45,91,137,195,236,257,291,327],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":44},"Prise en main","i-lucide-rocket","/fr/getting-started","fr/01.getting-started",[10,15,20,24,29,34,39],{"title":11,"path":12,"stem":13,"icon":14},"Qu'est-ce que Qora ?","/fr/getting-started/what-is-qora","fr/01.getting-started/2.what-is-qora","i-lucide-info",{"title":16,"path":17,"stem":18,"icon":19},"Installation","/fr/getting-started/installation","fr/01.getting-started/3.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":6},"Démarrage rapide","/fr/getting-started/quick-start","fr/01.getting-started/4.quick-start",{"title":25,"path":26,"stem":27,"icon":28},"Comparaison","/fr/getting-started/comparison","fr/01.getting-started/5.comparison","i-lucide-scale",{"title":30,"path":31,"stem":32,"icon":33},"Venant de TanStack Query","/fr/getting-started/coming-from-tanstack-query","fr/01.getting-started/6.coming-from-tanstack-query","i-lucide-arrow-left-right",{"title":35,"path":36,"stem":37,"icon":38},"Migrer depuis d'Autres Librairies","/fr/getting-started/migrating-from-other-libraries","fr/01.getting-started/7.migrating-from-other-libraries","i-lucide-arrow-right-left",{"title":40,"path":41,"stem":42,"icon":43},"Assistants IA","/fr/getting-started/ai-assistants","fr/01.getting-started/8.ai-assistants","i-lucide-sparkles",false,{"title":46,"icon":47,"path":48,"stem":49,"children":50,"page":44},"Concepts clés","i-lucide-book-open","/fr/core-concepts","fr/02.core-concepts",[51,56,61,66,71,76,81,86],{"title":52,"path":53,"stem":54,"icon":55},"Requêtes","/fr/core-concepts/queries","fr/02.core-concepts/1.queries","i-lucide-database",{"title":57,"path":58,"stem":59,"icon":60},"Clés de requête","/fr/core-concepts/query-keys","fr/02.core-concepts/2.query-keys","i-lucide-key-round",{"title":62,"path":63,"stem":64,"icon":65},"États des requêtes","/fr/core-concepts/query-states","fr/02.core-concepts/3.query-states","i-lucide-activity",{"title":67,"path":68,"stem":69,"icon":70},"Cache","/fr/core-concepts/caching","fr/02.core-concepts/4.caching","i-lucide-layers-3",{"title":72,"path":73,"stem":74,"icon":75},"Stale-While-Revalidate","/fr/core-concepts/stale-while-revalidate","fr/02.core-concepts/5.stale-while-revalidate","i-lucide-timer-reset",{"title":77,"path":78,"stem":79,"icon":80},"Déduplication","/fr/core-concepts/deduplication","fr/02.core-concepts/6.deduplication","i-lucide-copy-minus",{"title":82,"path":83,"stem":84,"icon":85},"Mutations et invalidation","/fr/core-concepts/mutations","fr/02.core-concepts/7.mutations","i-lucide-pencil-line",{"title":87,"path":88,"stem":89,"icon":90},"Hors-ligne et réseau","/fr/core-concepts/offline","fr/02.core-concepts/8.offline","i-lucide-wifi-off",{"title":92,"icon":93,"path":94,"stem":95,"children":96,"page":44},"Usage avec Flutter","i-lucide-smartphone","/fr/flutter-integration","fr/03.flutter-integration",[97,102,107,112,117,122,127,132],{"title":98,"path":99,"stem":100,"icon":101},"Configuration","/fr/flutter-integration/setup","fr/03.flutter-integration/1.setup","i-lucide-wrench",{"title":103,"path":104,"stem":105,"icon":106},"QoraScope","/fr/flutter-integration/qora-scope","fr/03.flutter-integration/2.qora-scope","i-lucide-share-2",{"title":108,"path":109,"stem":110,"icon":111},"QoraBuilder","/fr/flutter-integration/qora-builder","fr/03.flutter-integration/3.qora-builder","i-lucide-blocks",{"title":113,"path":114,"stem":115,"icon":116},"QoraMutationBuilder","/fr/flutter-integration/qora-mutation-builder","fr/03.flutter-integration/4.qora-mutation-builder","i-lucide-pencil",{"title":118,"path":119,"stem":120,"icon":121},"InfiniteQueryBuilder","/fr/flutter-integration/infinite-query-builder","fr/03.flutter-integration/5.infinite-query-builder","i-lucide-infinity",{"title":123,"path":124,"stem":125,"icon":126},"Hooks (flutter_hooks)","/fr/flutter-integration/hooks","fr/03.flutter-integration/6.hooks","i-lucide-anchor",{"title":128,"path":129,"stem":130,"icon":131},"Widgets de statut réseau","/fr/flutter-integration/network-status","fr/03.flutter-integration/7.network-status","i-lucide-wifi",{"title":133,"path":134,"stem":135,"icon":136},"Bonnes pratiques","/fr/flutter-integration/best-practices","fr/03.flutter-integration/8.best-practices","i-lucide-badge-check",{"title":138,"icon":139,"path":140,"stem":141,"children":142,"page":44},"Guides Pratiques","i-lucide-chef-hat","/fr/recipes","fr/04.recipes",[143,147,152,157,162,166,171,176,181,186,191],{"title":144,"path":145,"stem":146,"icon":85},"Mutations","/fr/recipes/mutations","fr/04.recipes/02.mutations",{"title":148,"path":149,"stem":150,"icon":151},"Mises à jour optimistes","/fr/recipes/optimistic-updates","fr/04.recipes/03.optimistic-updates","i-lucide-zap",{"title":153,"path":154,"stem":155,"icon":156},"Persistance","/fr/recipes/persistence","fr/04.recipes/04.persistence","i-lucide-hard-drive",{"title":158,"path":159,"stem":160,"icon":161},"Réseau adaptatif","/fr/recipes/network-aware","fr/04.recipes/05.network-aware","i-lucide-signal",{"title":163,"path":164,"stem":165,"icon":121},"Requêtes infinies","/fr/recipes/infinite-queries","fr/04.recipes/06.infinite-queries",{"title":167,"path":168,"stem":169,"icon":170},"Requêtes dépendantes","/fr/recipes/dependent-queries","fr/04.recipes/07.dependent-queries","i-lucide-link-2",{"title":172,"path":173,"stem":174,"icon":175},"Annulation","/fr/recipes/cancel-token","fr/04.recipes/08.cancel-token","i-lucide-circle-slash",{"title":177,"path":178,"stem":179,"icon":180},"Hydratation SSR","/fr/recipes/ssr-hydration","fr/04.recipes/09.ssr-hydration","i-lucide-server",{"title":182,"path":183,"stem":184,"icon":185},"Gestion des erreurs","/fr/recipes/error-handling","fr/04.recipes/10.error-handling","i-lucide-shield-alert",{"title":187,"path":188,"stem":189,"icon":190},"Tests","/fr/recipes/testing","fr/04.recipes/11.testing","i-lucide-flask-conical",{"title":192,"path":193,"stem":194},"Prefetch au Niveau des Routes","/fr/recipes/prefetch","fr/04.recipes/12.prefetch",{"title":196,"icon":197,"path":198,"stem":199,"children":200,"page":44},"Référence de l'API","i-lucide-file-code","/fr/api-reference","fr/05.api-reference",[201,206,210,214,219,224,228,232],{"title":202,"path":203,"stem":204,"icon":205},"QoraClient","/fr/api-reference/qora-client","fr/05.api-reference/1.qora-client","i-lucide-cpu",{"title":207,"path":208,"stem":209,"icon":60},"QoraKey","/fr/api-reference/qora-key","fr/05.api-reference/2.qora-key",{"title":211,"path":212,"stem":213,"icon":65},"QoraState","/fr/api-reference/qora-state","fr/05.api-reference/3.qora-state",{"title":215,"path":216,"stem":217,"icon":218},"QoraOptions","/fr/api-reference/qora-options","fr/05.api-reference/4.qora-options","i-lucide-sliders-horizontal",{"title":220,"path":221,"stem":222,"icon":223},"QoraClientConfig","/fr/api-reference/qora-client-config","fr/05.api-reference/5.qora-client-config","i-lucide-settings-2",{"title":225,"path":226,"stem":227,"icon":85},"API Mutation","/fr/api-reference/qora-mutation","fr/05.api-reference/6.qora-mutation",{"title":229,"path":230,"stem":231,"icon":156},"PersistQoraClient","/fr/api-reference/persist-qora-client","fr/05.api-reference/7.persist-qora-client",{"title":233,"path":234,"stem":235,"icon":121},"Requête infinie","/fr/api-reference/infinite-query","fr/05.api-reference/8.infinite-query",{"title":237,"icon":238,"path":239,"stem":240,"children":241,"page":44},"Outils de debug","i-lucide-bug","/fr/devtools","fr/06.devtools",[242,247,252],{"title":243,"path":244,"stem":245,"icon":246},"Vue d'ensemble","/fr/devtools/overview","fr/06.devtools/1.overview","i-lucide-layout-dashboard",{"title":248,"path":249,"stem":250,"icon":251},"Overlay intégré","/fr/devtools/overlay","fr/06.devtools/2.overlay","i-lucide-layers",{"title":253,"path":254,"stem":255,"icon":256},"Sérialisation des données","/fr/devtools/data-display","fr/06.devtools/4.data-display","i-lucide-eye",{"title":258,"icon":259,"path":260,"stem":261,"children":262,"page":44},"Intégrations tierces","i-lucide-puzzle","/fr/third-party","fr/07.third-party",[263,268,272,277,282,286],{"title":264,"path":265,"stem":266,"icon":267},"Avec Provider","/fr/third-party/with-provider","fr/07.third-party/1.with-provider","i-lucide-plug",{"title":269,"path":270,"stem":271,"icon":111},"Avec BLoC","/fr/third-party/with-bloc","fr/07.third-party/2.with-bloc",{"title":273,"path":274,"stem":275,"icon":276},"Avec Riverpod","/fr/third-party/with-riverpod","fr/07.third-party/3.with-riverpod","i-lucide-droplets",{"title":278,"path":279,"stem":280,"icon":281},"Avec RxDart","/fr/third-party/with-rxdart","fr/07.third-party/4.with-rxdart","i-lucide-git-branch",{"title":283,"path":284,"stem":285},"Avec Dio","/fr/third-party/with-dio","fr/07.third-party/5.with-dio",{"title":287,"path":288,"stem":289,"icon":290},"Avec GraphQL","/fr/third-party/with-graphql","fr/07.third-party/6.with-graphql","i-lucide-binary",{"title":292,"icon":190,"path":293,"stem":294,"children":295,"page":44},"Exemples","/fr/examples","fr/08.examples",[296,301,305,310,314,318,322],{"title":297,"path":298,"stem":299,"icon":300},"Étude de cas : Liste et détail utilisateur","/fr/examples/basic-query","fr/08.examples/1.basic-query","i-lucide-play-circle",{"title":302,"path":303,"stem":304,"icon":151},"Étude de cas : Mutations optimistes et rollback","/fr/examples/mutations-optimistic","fr/08.examples/2.mutations-optimistic",{"title":306,"path":307,"stem":308,"icon":309},"Étude de cas : Feed à défilement infini","/fr/examples/infinite-scroll","fr/08.examples/3.infinite-scroll","i-lucide-scroll",{"title":311,"path":312,"stem":313,"icon":90},"Étude de cas : Application Todo offline-first","/fr/examples/offline-first","fr/08.examples/4.offline-first",{"title":315,"path":316,"stem":317,"icon":161},"Étude de cas : Conscience réseau","/fr/examples/network-awareness","fr/08.examples/5.network-awareness",{"title":319,"path":320,"stem":321,"icon":126},"Étude de cas : Intégration des hooks","/fr/examples/hooks-integration","fr/08.examples/6.hooks-integration",{"title":323,"path":324,"stem":325,"icon":326},"Étude de cas : Application Todo complète","/fr/examples/complete-todo-app","fr/08.examples/7.complete-todo-app","i-lucide-check-square",{"title":328,"icon":329,"path":330,"stem":331,"children":332,"page":44},"Aide","i-lucide-life-buoy","/fr/help","fr/09.help",[333,338],{"title":334,"path":335,"stem":336,"icon":337},"FAQ","/fr/help/faq","fr/09.help/1.faq","i-lucide-circle-help",{"title":339,"path":340,"stem":341,"icon":101},"Dépannage","/fr/help/troubleshooting","fr/09.help/2.troubleshooting",{"id":343,"title":339,"body":344,"description":3257,"extension":3258,"links":3259,"meta":3260,"navigation":3261,"path":340,"seo":3262,"stem":341,"__hash__":3263},"docs_fr/fr/09.help/2.troubleshooting.md",{"type":345,"value":346,"toc":3210},"minimark",[347,352,365,440,443,447,452,462,472,657,664,666,673,687,796,798,802,812,1002,1004,1011,1027,1123,1132,1134,1141,1149,1157,1160,1317,1331,1333,1337,1345,1360,1406,1424,1426,1433,1448,1596,1615,1640,1642,1646,1656,1753,1763,1765,1769,1777,1834,1847,1849,1853,1857,1866,2001,2003,2009,2024,2152,2155,2157,2168,2189,2261,2263,2266,2270,2279,2458,2460,2469,2496,2529,2658,2660,2664,2673,2688,2752,2762,2764,2768,2772,2782,2794,2872,2884,2886,2890,2895,2906,2908,2911,2918,2936,3051,3053,3060,3076,3082,3206],[348,349,351],"h2",{"id":350},"activer-le-mode-debug-en-premier","Activer le mode debug en premier",[353,354,355,356,360,361,364],"p",{},"Activer ",[357,358,359],"code",{},"debugMode"," avant toute investigation. Qora journalise les hits de cache, miss de cache, écritures de persistance, sauts d'hydratation et erreurs de sérialiseur avec le préfixe ",[357,362,363],{},"[Qora]",".",[366,367,373],"pre",{"className":368,"code":369,"filename":370,"language":371,"meta":372,"style":372},"language-dart shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","final client = QoraClient( // ou PersistQoraClient\n  config: const QoraClientConfig(debugMode: true),\n);\n","main.dart","dart","",[357,374,375,403,432],{"__ignoreMap":372},[376,377,380,384,388,392,396,399],"span",{"class":378,"line":379},"line",1,[376,381,383],{"class":382},"spNyl","final",[376,385,387],{"class":386},"sTEyZ"," client ",[376,389,391],{"class":390},"sMK4o","=",[376,393,395],{"class":394},"sBMFI"," QoraClient",[376,397,398],{"class":386},"( ",[376,400,402],{"class":401},"sHwdD","// ou PersistQoraClient\n",[376,404,406,409,412,415,418,421,423,426,429],{"class":378,"line":405},2,[376,407,408],{"class":386},"  config",[376,410,411],{"class":390},":",[376,413,414],{"class":382}," const",[376,416,417],{"class":394}," QoraClientConfig",[376,419,420],{"class":386},"(debugMode",[376,422,411],{"class":390},[376,424,425],{"class":390}," true",[376,427,428],{"class":386},")",[376,430,431],{"class":390},",\n",[376,433,435,437],{"class":378,"line":434},3,[376,436,428],{"class":386},[376,438,439],{"class":390},";\n",[441,442],"hr",{},[348,444,446],{"id":445},"persistance-et-hydratation","Persistance et hydratation",[448,449,451],"h3",{"id":450},"les-données-ne-sont-pas-persistées-entre-les-redémarrages","Les données ne sont pas persistées entre les redémarrages",[353,453,454,458,459,461],{},[455,456,457],"strong",{},"Symptôme"," : ",[357,460,229],{}," est configuré, mais l'application démarre toujours avec un état de chargement et sans données en cache.",[353,463,464,467,468,471],{},[455,465,466],{},"Cause"," : Aucun ",[357,469,470],{},"QoraSerializer\u003CT>"," n'est enregistré pour le type récupéré. Qora met les données en cache en mémoire mais ne les persiste pas sur disque.",[366,473,475],{"className":368,"code":474,"filename":370,"language":371,"meta":372,"style":372},"// Enregistrer avant d'appeler hydrate()\nclient.registerSerializer\u003CList\u003CPost>>(\n  QoraSerializer(\n    toJson:   (posts) => posts.map((p) => p.toJson()).toList(),\n    fromJson: (json)  => (json as List).map(Post.fromJson).toList(),\n  ),\n  name: 'List\u003CPost>',\n);\nawait client.hydrate();\n",[357,476,477,482,507,515,563,609,617,631,638],{"__ignoreMap":372},[376,478,479],{"class":378,"line":379},[376,480,481],{"class":401},"// Enregistrer avant d'appeler hydrate()\n",[376,483,484,487,489,493,496,499,501,504],{"class":378,"line":405},[376,485,486],{"class":386},"client",[376,488,364],{"class":390},[376,490,492],{"class":491},"s2Zo4","registerSerializer",[376,494,495],{"class":386},"\u003C",[376,497,498],{"class":394},"List",[376,500,495],{"class":386},[376,502,503],{"class":394},"Post",[376,505,506],{"class":386},">>(\n",[376,508,509,512],{"class":378,"line":434},[376,510,511],{"class":394},"  QoraSerializer",[376,513,514],{"class":386},"(\n",[376,516,518,521,523,526,529,532,534,537,540,542,545,547,550,553,555,558,561],{"class":378,"line":517},4,[376,519,520],{"class":386},"    toJson",[376,522,411],{"class":390},[376,524,525],{"class":386},"   (posts) ",[376,527,528],{"class":390},"=>",[376,530,531],{"class":386}," posts",[376,533,364],{"class":390},[376,535,536],{"class":491},"map",[376,538,539],{"class":386},"((p) ",[376,541,528],{"class":390},[376,543,544],{"class":386}," p",[376,546,364],{"class":390},[376,548,549],{"class":491},"toJson",[376,551,552],{"class":386},"())",[376,554,364],{"class":390},[376,556,557],{"class":491},"toList",[376,559,560],{"class":386},"()",[376,562,431],{"class":390},[376,564,566,569,571,574,576,579,582,585,587,589,591,594,596,598,601,603,605,607],{"class":378,"line":565},5,[376,567,568],{"class":386},"    fromJson",[376,570,411],{"class":390},[376,572,573],{"class":386}," (json)  ",[376,575,528],{"class":390},[376,577,578],{"class":386}," (json ",[376,580,581],{"class":390},"as",[376,583,584],{"class":394}," List",[376,586,428],{"class":386},[376,588,364],{"class":390},[376,590,536],{"class":491},[376,592,593],{"class":386},"(",[376,595,503],{"class":394},[376,597,364],{"class":390},[376,599,600],{"class":386},"fromJson)",[376,602,364],{"class":390},[376,604,557],{"class":491},[376,606,560],{"class":386},[376,608,431],{"class":390},[376,610,612,615],{"class":378,"line":611},6,[376,613,614],{"class":386},"  )",[376,616,431],{"class":390},[376,618,620,623,625,629],{"class":378,"line":619},7,[376,621,622],{"class":386},"  name",[376,624,411],{"class":390},[376,626,628],{"class":627},"sfazB"," 'List\u003CPost>'",[376,630,431],{"class":390},[376,632,634,636],{"class":378,"line":633},8,[376,635,428],{"class":386},[376,637,439],{"class":390},[376,639,641,645,648,650,653,655],{"class":378,"line":640},9,[376,642,644],{"class":643},"s7zQu","await",[376,646,647],{"class":386}," client",[376,649,364],{"class":390},[376,651,652],{"class":491},"hydrate",[376,654,560],{"class":386},[376,656,439],{"class":390},[353,658,659,660,663],{},"Avec ",[357,661,662],{},"debugMode: true",", Qora journalise l'événement de persistance ignoré pour les types non enregistrés.",[441,665],{},[448,667,669,672],{"id":668},"hydrate-sexécute-mais-le-cache-est-toujours-vide",[357,670,671],{},"hydrate()"," s'exécute mais le cache est toujours vide",[353,674,675,458,677,679,680,682,683,686],{},[455,676,466],{},[357,678,492],{}," est appelé après ",[357,681,671],{},". Lors de l'hydratation, Qora résout les sérialiseurs depuis les valeurs ",[357,684,685],{},"typeName"," stockées. Les entrées sans sérialiseur correspondant sont ignorées.",[366,688,690],{"className":368,"code":689,"filename":370,"language":371,"meta":372,"style":372},"// Mauvais ordre\nawait client.hydrate();\nclient.registerSerializer\u003CUser>(...); // trop tard. Les entrées User sont ignorées\n\n// Ordre correct\nclient.registerSerializer\u003CUser>(...);\nawait client.hydrate();\nrunApp(...);\n",[357,691,692,697,711,738,744,749,769,783],{"__ignoreMap":372},[376,693,694],{"class":378,"line":379},[376,695,696],{"class":401},"// Mauvais ordre\n",[376,698,699,701,703,705,707,709],{"class":378,"line":405},[376,700,644],{"class":643},[376,702,647],{"class":386},[376,704,364],{"class":390},[376,706,652],{"class":491},[376,708,560],{"class":386},[376,710,439],{"class":390},[376,712,713,715,717,719,721,724,727,730,732,735],{"class":378,"line":434},[376,714,486],{"class":386},[376,716,364],{"class":390},[376,718,492],{"class":491},[376,720,495],{"class":386},[376,722,723],{"class":394},"User",[376,725,726],{"class":386},">(",[376,728,729],{"class":390},"...",[376,731,428],{"class":386},[376,733,734],{"class":390},";",[376,736,737],{"class":401}," // trop tard. Les entrées User sont ignorées\n",[376,739,740],{"class":378,"line":517},[376,741,743],{"emptyLinePlaceholder":742},true,"\n",[376,745,746],{"class":378,"line":565},[376,747,748],{"class":401},"// Ordre correct\n",[376,750,751,753,755,757,759,761,763,765,767],{"class":378,"line":611},[376,752,486],{"class":386},[376,754,364],{"class":390},[376,756,492],{"class":491},[376,758,495],{"class":386},[376,760,723],{"class":394},[376,762,726],{"class":386},[376,764,729],{"class":390},[376,766,428],{"class":386},[376,768,439],{"class":390},[376,770,771,773,775,777,779,781],{"class":378,"line":619},[376,772,644],{"class":643},[376,774,647],{"class":386},[376,776,364],{"class":390},[376,778,652],{"class":491},[376,780,560],{"class":386},[376,782,439],{"class":390},[376,784,785,788,790,792,794],{"class":378,"line":633},[376,786,787],{"class":491},"runApp",[376,789,593],{"class":386},[376,791,729],{"class":390},[376,793,428],{"class":386},[376,795,439],{"class":390},[441,797],{},[448,799,801],{"id":800},"le-cache-est-chaud-mais-les-widgets-affichent-encore-un-spinner-à-la-première-frame","Le cache est chaud mais les widgets affichent encore un spinner à la première frame",[353,803,804,458,806,808,809,811],{},[455,805,466],{},[357,807,671],{}," n'est pas attendu avant ",[357,810,787],{},". L'arbre de widgets est monté avant la complétion de l'hydratation.",[366,813,815],{"className":368,"code":814,"filename":370,"language":371,"meta":372,"style":372},"// hydrate() se déclenche mais n'est pas attendu\nvoid main() {\n  client.hydrate(); // pas d'await\n  runApp(QoraScope(client: client, child: const MyApp()));\n}\n\n// Attendre avant runApp\nFuture\u003Cvoid> main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n  await storage.init();\n  await client.hydrate();\n  runApp(QoraScope(client: client, child: const MyApp()));\n}\n",[357,816,817,822,833,849,883,888,892,897,921,935,953,968,997],{"__ignoreMap":372},[376,818,819],{"class":378,"line":379},[376,820,821],{"class":401},"// hydrate() se déclenche mais n'est pas attendu\n",[376,823,824,827,830],{"class":378,"line":405},[376,825,826],{"class":382},"void",[376,828,829],{"class":491}," main",[376,831,832],{"class":386},"() {\n",[376,834,835,838,840,842,844,846],{"class":378,"line":434},[376,836,837],{"class":386},"  client",[376,839,364],{"class":390},[376,841,652],{"class":491},[376,843,560],{"class":386},[376,845,734],{"class":390},[376,847,848],{"class":401}," // pas d'await\n",[376,850,851,854,856,858,861,863,865,868,871,873,875,878,881],{"class":378,"line":517},[376,852,853],{"class":491},"  runApp",[376,855,593],{"class":386},[376,857,103],{"class":394},[376,859,860],{"class":386},"(client",[376,862,411],{"class":390},[376,864,647],{"class":386},[376,866,867],{"class":390},",",[376,869,870],{"class":386}," child",[376,872,411],{"class":390},[376,874,414],{"class":382},[376,876,877],{"class":394}," MyApp",[376,879,880],{"class":386},"()))",[376,882,439],{"class":390},[376,884,885],{"class":378,"line":565},[376,886,887],{"class":386},"}\n",[376,889,890],{"class":378,"line":611},[376,891,743],{"emptyLinePlaceholder":742},[376,893,894],{"class":378,"line":619},[376,895,896],{"class":401},"// Attendre avant runApp\n",[376,898,899,902,904,906,909,912,915,918],{"class":378,"line":633},[376,900,901],{"class":394},"Future",[376,903,495],{"class":386},[376,905,826],{"class":382},[376,907,908],{"class":386},"> ",[376,910,911],{"class":491},"main",[376,913,914],{"class":386},"() ",[376,916,917],{"class":643},"async",[376,919,920],{"class":386}," {\n",[376,922,923,926,928,931,933],{"class":378,"line":640},[376,924,925],{"class":394},"  WidgetsFlutterBinding",[376,927,364],{"class":390},[376,929,930],{"class":491},"ensureInitialized",[376,932,560],{"class":386},[376,934,439],{"class":390},[376,936,938,941,944,946,949,951],{"class":378,"line":937},10,[376,939,940],{"class":643},"  await",[376,942,943],{"class":386}," storage",[376,945,364],{"class":390},[376,947,948],{"class":491},"init",[376,950,560],{"class":386},[376,952,439],{"class":390},[376,954,956,958,960,962,964,966],{"class":378,"line":955},11,[376,957,940],{"class":643},[376,959,647],{"class":386},[376,961,364],{"class":390},[376,963,652],{"class":491},[376,965,560],{"class":386},[376,967,439],{"class":390},[376,969,971,973,975,977,979,981,983,985,987,989,991,993,995],{"class":378,"line":970},12,[376,972,853],{"class":491},[376,974,593],{"class":386},[376,976,103],{"class":394},[376,978,860],{"class":386},[376,980,411],{"class":390},[376,982,647],{"class":386},[376,984,867],{"class":390},[376,986,870],{"class":386},[376,988,411],{"class":390},[376,990,414],{"class":382},[376,992,877],{"class":394},[376,994,880],{"class":386},[376,996,439],{"class":390},[376,998,1000],{"class":378,"line":999},13,[376,1001,887],{"class":386},[441,1003],{},[448,1005,1007,1008],{"id":1006},"lhydratation-échoue-après-un-build-flutter-web-ou-obfuscate","L'hydratation échoue après un build Flutter Web ou ",[357,1009,1010],{},"--obfuscate",[353,1012,1013,1015,1016,1019,1020,1022,1023,1026],{},[455,1014,466],{}," : Sans ",[357,1017,1018],{},"name"," explicite, ",[357,1021,492],{}," utilise ",[357,1024,1025],{},"T.toString()"," comme discriminant de type. L'obfuscation change cette valeur. Les entrées persistées d'un mode de build ne correspondent pas aux discriminants d'un autre mode.",[366,1028,1030],{"className":368,"code":1029,"filename":370,"language":371,"meta":372,"style":372},"// Non sûr. Le nom devient 'a' sous obfuscation.\nclient.registerSerializer\u003CUser>(userSerializer);\n\n// Stable dans tous les modes de build\nclient.registerSerializer\u003CUser>(userSerializer, name: 'User');\nclient.registerSerializer\u003CList\u003CPost>>(postListSerializer, name: 'List\u003CPost>');\n",[357,1031,1032,1037,1054,1058,1063,1092],{"__ignoreMap":372},[376,1033,1034],{"class":378,"line":379},[376,1035,1036],{"class":401},"// Non sûr. Le nom devient 'a' sous obfuscation.\n",[376,1038,1039,1041,1043,1045,1047,1049,1052],{"class":378,"line":405},[376,1040,486],{"class":386},[376,1042,364],{"class":390},[376,1044,492],{"class":491},[376,1046,495],{"class":386},[376,1048,723],{"class":394},[376,1050,1051],{"class":386},">(userSerializer)",[376,1053,439],{"class":390},[376,1055,1056],{"class":378,"line":434},[376,1057,743],{"emptyLinePlaceholder":742},[376,1059,1060],{"class":378,"line":517},[376,1061,1062],{"class":401},"// Stable dans tous les modes de build\n",[376,1064,1065,1067,1069,1071,1073,1075,1078,1080,1083,1085,1088,1090],{"class":378,"line":565},[376,1066,486],{"class":386},[376,1068,364],{"class":390},[376,1070,492],{"class":491},[376,1072,495],{"class":386},[376,1074,723],{"class":394},[376,1076,1077],{"class":386},">(userSerializer",[376,1079,867],{"class":390},[376,1081,1082],{"class":386}," name",[376,1084,411],{"class":390},[376,1086,1087],{"class":627}," 'User'",[376,1089,428],{"class":386},[376,1091,439],{"class":390},[376,1093,1094,1096,1098,1100,1102,1104,1106,1108,1111,1113,1115,1117,1119,1121],{"class":378,"line":611},[376,1095,486],{"class":386},[376,1097,364],{"class":390},[376,1099,492],{"class":491},[376,1101,495],{"class":386},[376,1103,498],{"class":394},[376,1105,495],{"class":386},[376,1107,503],{"class":394},[376,1109,1110],{"class":386},">>(postListSerializer",[376,1112,867],{"class":390},[376,1114,1082],{"class":386},[376,1116,411],{"class":390},[376,1118,628],{"class":627},[376,1120,428],{"class":386},[376,1122,439],{"class":390},[353,1124,1125,1126,1128,1129,1131],{},"Le ",[357,1127,1018],{}," du sérialiseur doit rester stable entre les versions de l'app. Un ",[357,1130,1018],{}," modifié invalide les entrées précédemment persistées pour ce type.",[441,1133],{},[448,1135,1137,1140],{"id":1136},"fromjson-plante-au-démarrage-après-un-changement-de-modèle",[357,1138,1139],{},"fromJson"," plante au démarrage après un changement de modèle",[353,1142,1143,1145,1146,1148],{},[455,1144,466],{}," : Un champ requis a été introduit entre les versions de l'app. Le JSON persisté des versions précédentes n'inclut pas le champ, et ",[357,1147,1139],{}," lève une exception.",[353,1150,1151,1153,1154,1156],{},[357,1152,229],{}," attrape les exceptions ",[357,1155,1139],{}," lors de l'hydratation, supprime l'entrée invalide et continue l'exécution. L'entrée est perdue et la prochaine lecture déclenche un fetch réseau.",[353,1158,1159],{},"Implémenter un parsing défensif pour réduire la perte de données :",[366,1161,1164],{"className":368,"code":1162,"filename":1163,"language":371,"meta":372,"style":372},"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    // Ajouté en v2. Valeur par défaut pour les entrées persistées par v1.\n    role: map['role'] as String? ?? 'viewer',\n  );\n}\n","models/user.dart",[357,1165,1166,1186,1219,1228,1251,1273,1278,1307,1313],{"__ignoreMap":372},[376,1167,1168,1171,1174,1176,1178,1180,1183],{"class":378,"line":379},[376,1169,1170],{"class":390},"factory",[376,1172,1173],{"class":394}," User",[376,1175,364],{"class":390},[376,1177,1139],{"class":491},[376,1179,593],{"class":386},[376,1181,1182],{"class":394},"dynamic",[376,1184,1185],{"class":386}," json) {\n",[376,1187,1188,1191,1194,1196,1199,1201,1204,1206,1209,1212,1214,1217],{"class":378,"line":405},[376,1189,1190],{"class":382},"  final",[376,1192,1193],{"class":386}," map ",[376,1195,391],{"class":390},[376,1197,1198],{"class":386}," json ",[376,1200,581],{"class":390},[376,1202,1203],{"class":394}," Map",[376,1205,495],{"class":386},[376,1207,1208],{"class":394},"String",[376,1210,1211],{"class":386},", ",[376,1213,1182],{"class":394},[376,1215,1216],{"class":386},">",[376,1218,439],{"class":390},[376,1220,1221,1224,1226],{"class":378,"line":434},[376,1222,1223],{"class":643},"  return",[376,1225,1173],{"class":394},[376,1227,514],{"class":386},[376,1229,1230,1233,1235,1238,1241,1244,1246,1249],{"class":378,"line":517},[376,1231,1232],{"class":386},"    id",[376,1234,411],{"class":390},[376,1236,1237],{"class":386},"   map[",[376,1239,1240],{"class":627},"'id'",[376,1242,1243],{"class":386},"] ",[376,1245,581],{"class":390},[376,1247,1248],{"class":394}," int",[376,1250,431],{"class":390},[376,1252,1253,1256,1258,1261,1264,1266,1268,1271],{"class":378,"line":565},[376,1254,1255],{"class":386},"    name",[376,1257,411],{"class":390},[376,1259,1260],{"class":386}," map[",[376,1262,1263],{"class":627},"'name'",[376,1265,1243],{"class":386},[376,1267,581],{"class":390},[376,1269,1270],{"class":394}," String",[376,1272,431],{"class":390},[376,1274,1275],{"class":378,"line":611},[376,1276,1277],{"class":401},"    // Ajouté en v2. Valeur par défaut pour les entrées persistées par v1.\n",[376,1279,1280,1283,1285,1287,1290,1292,1294,1296,1299,1302,1305],{"class":378,"line":619},[376,1281,1282],{"class":386},"    role",[376,1284,411],{"class":390},[376,1286,1260],{"class":386},[376,1288,1289],{"class":627},"'role'",[376,1291,1243],{"class":386},[376,1293,581],{"class":390},[376,1295,1270],{"class":394},[376,1297,1298],{"class":390},"?",[376,1300,1301],{"class":390}," ??",[376,1303,1304],{"class":627}," 'viewer'",[376,1306,431],{"class":390},[376,1308,1309,1311],{"class":378,"line":633},[376,1310,614],{"class":386},[376,1312,439],{"class":390},[376,1314,1315],{"class":378,"line":640},[376,1316,887],{"class":386},[353,1318,1319,1320,1322,1323,1326,1327,1330],{},"Pour les changements cassants tels que les changements de type de champ ou la suppression de champ sans valeur par défaut sûre, changer le ",[357,1321,1018],{}," du sérialiseur de ",[357,1324,1325],{},"'User'"," à ",[357,1328,1329],{},"'User_v2'",". Qora ignore les anciennes entrées et réécrit les données fraîches après le prochain fetch réussi.",[441,1332],{},[348,1334,1336],{"id":1335},"état-des-requêtes","État des requêtes",[448,1338,1340,1341,1344],{"id":1339},"la-requête-est-bloquée-dans-initial-et-ne-fetche-jamais","La requête est bloquée dans ",[357,1342,1343],{},"Initial"," et ne fetche jamais",[353,1346,1347,458,1350,1353,1354,1356,1357,1359],{},[455,1348,1349],{},"Cause A",[357,1351,1352],{},"enabled: false"," est configuré sur ",[357,1355,108],{}," ou ",[357,1358,215],{},". Le widget observe l'état mais ne déclenche pas de fetch.",[366,1361,1363],{"className":368,"code":1362,"language":371,"meta":372,"style":372},"// Vérifier cette configuration :\nQoraBuilder\u003CUser>(\n  enabled: someVariable, // false maintient l'état à Initial\n  ...\n)\n",[357,1364,1365,1370,1381,1396,1401],{"__ignoreMap":372},[376,1366,1367],{"class":378,"line":379},[376,1368,1369],{"class":401},"// Vérifier cette configuration :\n",[376,1371,1372,1374,1376,1378],{"class":378,"line":405},[376,1373,108],{"class":394},[376,1375,495],{"class":386},[376,1377,723],{"class":394},[376,1379,1380],{"class":386},">(\n",[376,1382,1383,1386,1388,1391,1393],{"class":378,"line":434},[376,1384,1385],{"class":386},"  enabled",[376,1387,411],{"class":390},[376,1389,1390],{"class":386}," someVariable",[376,1392,867],{"class":390},[376,1394,1395],{"class":401}," // false maintient l'état à Initial\n",[376,1397,1398],{"class":378,"line":517},[376,1399,1400],{"class":390},"  ...\n",[376,1402,1403],{"class":378,"line":565},[376,1404,1405],{"class":386},")\n",[353,1407,1408,458,1411,1414,1415,1417,1418,1420,1421,364],{},[455,1409,1410],{},"Cause B",[357,1412,1413],{},"QoraStateBuilder"," est utilisé à la place de ",[357,1416,108],{},". ",[357,1419,1413],{}," est en observation seule et n'appelle jamais ",[357,1422,1423],{},"fetchQuery",[441,1425],{},[448,1427,1340,1429,1432],{"id":1428},"la-requête-est-bloquée-dans-loading-indéfiniment",[357,1430,1431],{},"Loading"," indéfiniment",[353,1434,1435,458,1437,1440,1441,1417,1444,1447],{},[455,1436,1349],{},[357,1438,1439],{},"dependsOn"," est configuré, et la requête de dépendance n'atteint pas ",[357,1442,1443],{},"Success",[357,1445,1446],{},"watchQuery"," attend la résolution de la dépendance avant d'exécuter le fetch dépendant.",[366,1449,1451],{"className":368,"code":1450,"language":371,"meta":372,"style":372},"// Valider les déclarations de dépendance et de clé.\nclient.watchQuery\u003CProfile>(\n  key: ['profile'],\n  fetcher: () {\n    final auth = client.getQueryData\u003CAuth>(['auth'])!;\n    return api.getProfile(auth.userId);\n  },\n  options: const QoraOptions(dependsOn: ['auth']),\n);\n",[357,1452,1453,1458,1473,1491,1501,1535,1558,1565,1590],{"__ignoreMap":372},[376,1454,1455],{"class":378,"line":379},[376,1456,1457],{"class":401},"// Valider les déclarations de dépendance et de clé.\n",[376,1459,1460,1462,1464,1466,1468,1471],{"class":378,"line":405},[376,1461,486],{"class":386},[376,1463,364],{"class":390},[376,1465,1446],{"class":491},[376,1467,495],{"class":386},[376,1469,1470],{"class":394},"Profile",[376,1472,1380],{"class":386},[376,1474,1475,1478,1480,1483,1486,1489],{"class":378,"line":434},[376,1476,1477],{"class":386},"  key",[376,1479,411],{"class":390},[376,1481,1482],{"class":386}," [",[376,1484,1485],{"class":627},"'profile'",[376,1487,1488],{"class":386},"]",[376,1490,431],{"class":390},[376,1492,1493,1496,1498],{"class":378,"line":517},[376,1494,1495],{"class":386},"  fetcher",[376,1497,411],{"class":390},[376,1499,1500],{"class":386}," () {\n",[376,1502,1503,1506,1509,1511,1513,1515,1518,1520,1523,1526,1529,1532],{"class":378,"line":565},[376,1504,1505],{"class":382},"    final",[376,1507,1508],{"class":386}," auth ",[376,1510,391],{"class":390},[376,1512,647],{"class":386},[376,1514,364],{"class":390},[376,1516,1517],{"class":491},"getQueryData",[376,1519,495],{"class":386},[376,1521,1522],{"class":394},"Auth",[376,1524,1525],{"class":386},">([",[376,1527,1528],{"class":627},"'auth'",[376,1530,1531],{"class":386},"])",[376,1533,1534],{"class":390},"!;\n",[376,1536,1537,1540,1543,1545,1548,1551,1553,1556],{"class":378,"line":611},[376,1538,1539],{"class":643},"    return",[376,1541,1542],{"class":386}," api",[376,1544,364],{"class":390},[376,1546,1547],{"class":491},"getProfile",[376,1549,1550],{"class":386},"(auth",[376,1552,364],{"class":390},[376,1554,1555],{"class":386},"userId)",[376,1557,439],{"class":390},[376,1559,1560,1563],{"class":378,"line":619},[376,1561,1562],{"class":386},"  }",[376,1564,431],{"class":390},[376,1566,1567,1570,1572,1574,1577,1580,1582,1584,1586,1588],{"class":378,"line":633},[376,1568,1569],{"class":386},"  options",[376,1571,411],{"class":390},[376,1573,414],{"class":382},[376,1575,1576],{"class":394}," QoraOptions",[376,1578,1579],{"class":386},"(dependsOn",[376,1581,411],{"class":390},[376,1583,1482],{"class":386},[376,1585,1528],{"class":627},[376,1587,1531],{"class":386},[376,1589,431],{"class":390},[376,1591,1592,1594],{"class":378,"line":640},[376,1593,428],{"class":386},[376,1595,439],{"class":390},[353,1597,1598,458,1600,1602,1603,1417,1605,1607,1608,1611,1612,1614],{},[455,1599,1410],{},[357,1601,1423],{}," est utilisé avec ",[357,1604,1439],{},[357,1606,1423],{}," lève ",[357,1609,1610],{},"StateError"," quand les dépendances ne sont pas résolues. Utiliser ",[357,1613,1446],{}," pour la gestion réactive des dépendances.",[353,1616,1617,458,1620,1623,1624,1627,1628,1631,1632,1635,1636,1639],{},[455,1618,1619],{},"Cause C",[357,1621,1622],{},"NetworkMode.online"," est actif sans ",[357,1625,1626],{},"ConnectivityManager",". Dans cette configuration, les fetches s'exécutent toujours. Avec ",[357,1629,1630],{},"FlutterConnectivityManager"," et sans connectivité, les requêtes transitent vers ",[357,1633,1634],{},"Loading(previousData: null)"," avec ",[357,1637,1638],{},"FetchStatus.paused"," et reprennent automatiquement après la reconnexion.",[441,1641],{},[448,1643,1645],{"id":1644},"la-requête-ne-refetche-pas-quand-lapp-revient-au-premier-plan","La requête ne refetche pas quand l'app revient au premier plan",[353,1647,1648,458,1650,1653,1654,364],{},[455,1649,466],{},[357,1651,1652],{},"FlutterLifecycleManager"," n'est pas fourni à ",[357,1655,103],{},[366,1657,1659],{"className":368,"code":1658,"filename":370,"language":371,"meta":372,"style":372},"// FlutterLifecycleManager manquant\nQoraScope(client: client, child: const MyApp())\n\n// Correct\nQoraScope(\n  client: client,\n  lifecycleManager: FlutterLifecycleManager(qoraClient: client),\n  child: const MyApp(),\n)\n",[357,1660,1661,1666,1689,1693,1698,1704,1714,1734,1749],{"__ignoreMap":372},[376,1662,1663],{"class":378,"line":379},[376,1664,1665],{"class":401},"// FlutterLifecycleManager manquant\n",[376,1667,1668,1670,1672,1674,1676,1678,1680,1682,1684,1686],{"class":378,"line":405},[376,1669,103],{"class":394},[376,1671,860],{"class":386},[376,1673,411],{"class":390},[376,1675,647],{"class":386},[376,1677,867],{"class":390},[376,1679,870],{"class":386},[376,1681,411],{"class":390},[376,1683,414],{"class":382},[376,1685,877],{"class":394},[376,1687,1688],{"class":386},"())\n",[376,1690,1691],{"class":378,"line":434},[376,1692,743],{"emptyLinePlaceholder":742},[376,1694,1695],{"class":378,"line":517},[376,1696,1697],{"class":401},"// Correct\n",[376,1699,1700,1702],{"class":378,"line":565},[376,1701,103],{"class":394},[376,1703,514],{"class":386},[376,1705,1706,1708,1710,1712],{"class":378,"line":611},[376,1707,837],{"class":386},[376,1709,411],{"class":390},[376,1711,647],{"class":386},[376,1713,431],{"class":390},[376,1715,1716,1719,1721,1724,1727,1729,1732],{"class":378,"line":619},[376,1717,1718],{"class":386},"  lifecycleManager",[376,1720,411],{"class":390},[376,1722,1723],{"class":394}," FlutterLifecycleManager",[376,1725,1726],{"class":386},"(qoraClient",[376,1728,411],{"class":390},[376,1730,1731],{"class":386}," client)",[376,1733,431],{"class":390},[376,1735,1736,1739,1741,1743,1745,1747],{"class":378,"line":633},[376,1737,1738],{"class":386},"  child",[376,1740,411],{"class":390},[376,1742,414],{"class":382},[376,1744,877],{"class":394},[376,1746,560],{"class":386},[376,1748,431],{"class":390},[376,1750,1751],{"class":378,"line":640},[376,1752,1405],{"class":386},[353,1754,1755,1756,1759,1760,364],{},"Vérifier également que ",[357,1757,1758],{},"refetchOnWindowFocus: true"," reste activé dans ",[357,1761,1762],{},"QoraClientConfig.defaultOptions",[441,1764],{},[448,1766,1768],{"id":1767},"la-requête-ne-refetche-pas-quand-la-connectivité-est-rétablie","La requête ne refetche pas quand la connectivité est rétablie",[353,1770,1771,458,1773,1653,1775,364],{},[455,1772,466],{},[357,1774,1630],{},[357,1776,103],{},[366,1778,1780],{"className":368,"code":1779,"filename":370,"language":371,"meta":372,"style":372},"// Correct\nQoraScope(\n  client: client,\n  connectivityManager: FlutterConnectivityManager(),\n  child: const MyApp(),\n)\n",[357,1781,1782,1786,1792,1802,1816,1830],{"__ignoreMap":372},[376,1783,1784],{"class":378,"line":379},[376,1785,1697],{"class":401},[376,1787,1788,1790],{"class":378,"line":405},[376,1789,103],{"class":394},[376,1791,514],{"class":386},[376,1793,1794,1796,1798,1800],{"class":378,"line":434},[376,1795,837],{"class":386},[376,1797,411],{"class":390},[376,1799,647],{"class":386},[376,1801,431],{"class":390},[376,1803,1804,1807,1809,1812,1814],{"class":378,"line":517},[376,1805,1806],{"class":386},"  connectivityManager",[376,1808,411],{"class":390},[376,1810,1811],{"class":394}," FlutterConnectivityManager",[376,1813,560],{"class":386},[376,1815,431],{"class":390},[376,1817,1818,1820,1822,1824,1826,1828],{"class":378,"line":565},[376,1819,1738],{"class":386},[376,1821,411],{"class":390},[376,1823,414],{"class":382},[376,1825,877],{"class":394},[376,1827,560],{"class":386},[376,1829,431],{"class":390},[376,1831,1832],{"class":378,"line":611},[376,1833,1405],{"class":386},[353,1835,1836,1838,1839,1842,1843,1846],{},[357,1837,1630],{}," requiert ",[357,1840,1841],{},"connectivity_plus"," dans ",[357,1844,1845],{},"pubspec.yaml",". L'absence de la dépendance cause une erreur d'import à la compilation.",[441,1848],{},[348,1850,1852],{"id":1851},"cache-et-clés","Cache et clés",[448,1854,1856],{"id":1855},"des-widgets-différents-voient-des-données-différentes-pour-la-même-requête","Des widgets différents voient des données différentes pour la \"même\" requête",[353,1858,1859,1861,1862,1865],{},[455,1860,466],{}," : Les clés de requête ne sont pas structurellement équivalentes entre les sites d'appel. Qora utilise l'égalité structurelle profonde (",[357,1863,1864],{},"KeyEquality","). Des types d'exécution différents dans les segments de clé produisent des entrées de cache distinctes.",[366,1867,1869],{"className":368,"code":1868,"language":371,"meta":372,"style":372},"// Types de clé incohérents\nfetchQuery(key: ['users', 42], ...);    // int\nwatchQuery(key: ['users', '42'], ...);  // String. Clé différente.\n\n// Cohérent\nfetchQuery(key: ['users', 42], ...);\nwatchQuery(key: ['users', 42], ...);\n",[357,1870,1871,1876,1910,1940,1944,1949,1975],{"__ignoreMap":372},[376,1872,1873],{"class":378,"line":379},[376,1874,1875],{"class":401},"// Types de clé incohérents\n",[376,1877,1878,1880,1883,1885,1887,1890,1892,1896,1898,1900,1903,1905,1907],{"class":378,"line":405},[376,1879,1423],{"class":491},[376,1881,1882],{"class":386},"(key",[376,1884,411],{"class":390},[376,1886,1482],{"class":386},[376,1888,1889],{"class":627},"'users'",[376,1891,867],{"class":390},[376,1893,1895],{"class":1894},"sbssI"," 42",[376,1897,1488],{"class":386},[376,1899,867],{"class":390},[376,1901,1902],{"class":390}," ...",[376,1904,428],{"class":386},[376,1906,734],{"class":390},[376,1908,1909],{"class":401},"    // int\n",[376,1911,1912,1914,1916,1918,1920,1922,1924,1927,1929,1931,1933,1935,1937],{"class":378,"line":434},[376,1913,1446],{"class":491},[376,1915,1882],{"class":386},[376,1917,411],{"class":390},[376,1919,1482],{"class":386},[376,1921,1889],{"class":627},[376,1923,867],{"class":390},[376,1925,1926],{"class":627}," '42'",[376,1928,1488],{"class":386},[376,1930,867],{"class":390},[376,1932,1902],{"class":390},[376,1934,428],{"class":386},[376,1936,734],{"class":390},[376,1938,1939],{"class":401},"  // String. Clé différente.\n",[376,1941,1942],{"class":378,"line":517},[376,1943,743],{"emptyLinePlaceholder":742},[376,1945,1946],{"class":378,"line":565},[376,1947,1948],{"class":401},"// Cohérent\n",[376,1950,1951,1953,1955,1957,1959,1961,1963,1965,1967,1969,1971,1973],{"class":378,"line":611},[376,1952,1423],{"class":491},[376,1954,1882],{"class":386},[376,1956,411],{"class":390},[376,1958,1482],{"class":386},[376,1960,1889],{"class":627},[376,1962,867],{"class":390},[376,1964,1895],{"class":1894},[376,1966,1488],{"class":386},[376,1968,867],{"class":390},[376,1970,1902],{"class":390},[376,1972,428],{"class":386},[376,1974,439],{"class":390},[376,1976,1977,1979,1981,1983,1985,1987,1989,1991,1993,1995,1997,1999],{"class":378,"line":619},[376,1978,1446],{"class":491},[376,1980,1882],{"class":386},[376,1982,411],{"class":390},[376,1984,1482],{"class":386},[376,1986,1889],{"class":627},[376,1988,867],{"class":390},[376,1990,1895],{"class":1894},[376,1992,1488],{"class":386},[376,1994,867],{"class":390},[376,1996,1902],{"class":390},[376,1998,428],{"class":386},[376,2000,439],{"class":390},[441,2002],{},[448,2004,2006,2008],{"id":2005},"qorabuilder-se-ré-abonne-à-chaque-rebuild-problème-de-performance",[357,2007,108],{}," se ré-abonne à chaque rebuild (problème de performance)",[353,2010,2011,458,2013,2016,2017,1417,2020,2023],{},[455,2012,466],{},[357,2014,2015],{},"queryKey"," est créé inline comme une nouvelle instance de liste non-",[357,2018,2019],{},"const",[357,2021,2022],{},"QoraBuilder.didUpdateWidget"," compare les références, donc chaque rebuild apparaît comme une nouvelle clé et déclenche un ré-abonnement.",[366,2025,2027],{"className":368,"code":2026,"language":371,"meta":372,"style":372},"// Nouvelle instance de List à chaque build\nQoraBuilder\u003CList\u003CPost>>(\n  queryKey: ['posts', page], // nouvelle instance de liste à chaque build\n  ...\n)\n\n// Référence stable. Change uniquement quand page change.\nQoraBuilder\u003CList\u003CPost>>(\n  queryKey: const ['posts'],         // pour les clés statiques\n  // ou\n  queryKey: ['posts', page],         // correct SI page est stable (pas rebuilté à chaque frame)\n  ...\n)\n",[357,2028,2029,2034,2048,2070,2074,2078,2082,2087,2101,2120,2125,2144,2148],{"__ignoreMap":372},[376,2030,2031],{"class":378,"line":379},[376,2032,2033],{"class":401},"// Nouvelle instance de List à chaque build\n",[376,2035,2036,2038,2040,2042,2044,2046],{"class":378,"line":405},[376,2037,108],{"class":394},[376,2039,495],{"class":386},[376,2041,498],{"class":394},[376,2043,495],{"class":386},[376,2045,503],{"class":394},[376,2047,506],{"class":386},[376,2049,2050,2053,2055,2057,2060,2062,2065,2067],{"class":378,"line":434},[376,2051,2052],{"class":386},"  queryKey",[376,2054,411],{"class":390},[376,2056,1482],{"class":386},[376,2058,2059],{"class":627},"'posts'",[376,2061,867],{"class":390},[376,2063,2064],{"class":386}," page]",[376,2066,867],{"class":390},[376,2068,2069],{"class":401}," // nouvelle instance de liste à chaque build\n",[376,2071,2072],{"class":378,"line":517},[376,2073,1400],{"class":390},[376,2075,2076],{"class":378,"line":565},[376,2077,1405],{"class":386},[376,2079,2080],{"class":378,"line":611},[376,2081,743],{"emptyLinePlaceholder":742},[376,2083,2084],{"class":378,"line":619},[376,2085,2086],{"class":401},"// Référence stable. Change uniquement quand page change.\n",[376,2088,2089,2091,2093,2095,2097,2099],{"class":378,"line":633},[376,2090,108],{"class":394},[376,2092,495],{"class":386},[376,2094,498],{"class":394},[376,2096,495],{"class":386},[376,2098,503],{"class":394},[376,2100,506],{"class":386},[376,2102,2103,2105,2107,2109,2111,2113,2115,2117],{"class":378,"line":640},[376,2104,2052],{"class":386},[376,2106,411],{"class":390},[376,2108,414],{"class":382},[376,2110,1482],{"class":386},[376,2112,2059],{"class":627},[376,2114,1488],{"class":386},[376,2116,867],{"class":390},[376,2118,2119],{"class":401},"         // pour les clés statiques\n",[376,2121,2122],{"class":378,"line":937},[376,2123,2124],{"class":401},"  // ou\n",[376,2126,2127,2129,2131,2133,2135,2137,2139,2141],{"class":378,"line":955},[376,2128,2052],{"class":386},[376,2130,411],{"class":390},[376,2132,1482],{"class":386},[376,2134,2059],{"class":627},[376,2136,867],{"class":390},[376,2138,2064],{"class":386},[376,2140,867],{"class":390},[376,2142,2143],{"class":401},"         // correct SI page est stable (pas rebuilté à chaque frame)\n",[376,2145,2146],{"class":378,"line":970},[376,2147,1400],{"class":390},[376,2149,2150],{"class":378,"line":999},[376,2151,1405],{"class":386},[353,2153,2154],{},"Si la clé inclut des variables, mettre à jour ces variables uniquement quand le dataset demandé change.",[441,2156],{},[448,2158,2160,2163,2164,2167],{"id":2159},"dataornull-retourne-null-même-après-un-fetch-réussi",[357,2161,2162],{},"dataOrNull"," retourne ",[357,2165,2166],{},"null"," même après un fetch réussi",[353,2169,2170,2172,2173,2176,2177,2180,2181,2184,2185,2188],{},[455,2171,466],{}," : Le paramètre de type sur ",[357,2174,2175],{},"QoraBuilder\u003CT>"," ne correspond pas au type de données récupéré. Le stream d'état est fortement typé. Un ",[357,2178,2179],{},"Success\u003CUser>"," pour la clé ",[357,2182,2183],{},"['users', 1]"," n'est pas délivré à ",[357,2186,2187],{},"QoraBuilder\u003CProfile>"," sur la même clé.",[366,2190,2192],{"className":368,"code":2191,"language":371,"meta":372,"style":372},"// Incompatibilité de type. L'état est Success\u003CUser> mais le builder attend Profile.\nQoraBuilder\u003CProfile>(queryKey: ['users', userId], ...)\n\n// Correct\nQoraBuilder\u003CUser>(queryKey: ['users', userId], ...)\n",[357,2193,2194,2199,2227,2231,2235],{"__ignoreMap":372},[376,2195,2196],{"class":378,"line":379},[376,2197,2198],{"class":401},"// Incompatibilité de type. L'état est Success\u003CUser> mais le builder attend Profile.\n",[376,2200,2201,2203,2205,2207,2210,2212,2214,2216,2218,2221,2223,2225],{"class":378,"line":405},[376,2202,108],{"class":394},[376,2204,495],{"class":386},[376,2206,1470],{"class":394},[376,2208,2209],{"class":386},">(queryKey",[376,2211,411],{"class":390},[376,2213,1482],{"class":386},[376,2215,1889],{"class":627},[376,2217,867],{"class":390},[376,2219,2220],{"class":386}," userId]",[376,2222,867],{"class":390},[376,2224,1902],{"class":390},[376,2226,1405],{"class":386},[376,2228,2229],{"class":378,"line":434},[376,2230,743],{"emptyLinePlaceholder":742},[376,2232,2233],{"class":378,"line":517},[376,2234,1697],{"class":401},[376,2236,2237,2239,2241,2243,2245,2247,2249,2251,2253,2255,2257,2259],{"class":378,"line":565},[376,2238,108],{"class":394},[376,2240,495],{"class":386},[376,2242,723],{"class":394},[376,2244,2209],{"class":386},[376,2246,411],{"class":390},[376,2248,1482],{"class":386},[376,2250,1889],{"class":627},[376,2252,867],{"class":390},[376,2254,2220],{"class":386},[376,2256,867],{"class":390},[376,2258,1902],{"class":390},[376,2260,1405],{"class":386},[441,2262],{},[348,2264,148],{"id":2265},"mises-à-jour-optimistes",[448,2267,2269],{"id":2268},"le-rollback-ne-fonctionne-pas-et-lui-reste-dans-létat-optimiste-après-léchec","Le rollback ne fonctionne pas et l'UI reste dans l'état optimiste après l'échec",[353,2271,2272,2274,2275,2278],{},[455,2273,466],{}," : Le snapshot a été pris après ",[357,2276,2277],{},"setQueryData"," au lieu d'avant.",[366,2280,2282],{"className":368,"code":2281,"language":371,"meta":372,"style":372},"// Le snapshot est pris après l'écriture optimiste. Il capture le mauvais état.\nclient.setQueryData\u003CUser>(key, optimisticUser);\nfinal snapshot = client.getQueryData\u003CUser>(key); // déjà optimiste : incorrect !\n\n// Toujours prendre le snapshot en premier\nfinal snapshot = client.getQueryData\u003CUser>(key); // T?, null si pas de données précédentes\nclient.setQueryData\u003CUser>(key, optimisticUser);\ntry {\n  await api.updateUser(...);\n} catch (_) {\n  client.restoreQueryData\u003CUser>(key, snapshot); // null → removeQuery ; sinon setQueryData\n}\n",[357,2283,2284,2289,2311,2338,2342,2347,2372,2392,2399,2418,2429,2454],{"__ignoreMap":372},[376,2285,2286],{"class":378,"line":379},[376,2287,2288],{"class":401},"// Le snapshot est pris après l'écriture optimiste. Il capture le mauvais état.\n",[376,2290,2291,2293,2295,2297,2299,2301,2304,2306,2309],{"class":378,"line":405},[376,2292,486],{"class":386},[376,2294,364],{"class":390},[376,2296,2277],{"class":491},[376,2298,495],{"class":386},[376,2300,723],{"class":394},[376,2302,2303],{"class":386},">(key",[376,2305,867],{"class":390},[376,2307,2308],{"class":386}," optimisticUser)",[376,2310,439],{"class":390},[376,2312,2313,2315,2318,2320,2322,2324,2326,2328,2330,2333,2335],{"class":378,"line":434},[376,2314,383],{"class":382},[376,2316,2317],{"class":386}," snapshot ",[376,2319,391],{"class":390},[376,2321,647],{"class":386},[376,2323,364],{"class":390},[376,2325,1517],{"class":491},[376,2327,495],{"class":386},[376,2329,723],{"class":394},[376,2331,2332],{"class":386},">(key)",[376,2334,734],{"class":390},[376,2336,2337],{"class":401}," // déjà optimiste : incorrect !\n",[376,2339,2340],{"class":378,"line":517},[376,2341,743],{"emptyLinePlaceholder":742},[376,2343,2344],{"class":378,"line":565},[376,2345,2346],{"class":401},"// Toujours prendre le snapshot en premier\n",[376,2348,2349,2351,2353,2355,2357,2359,2361,2363,2365,2367,2369],{"class":378,"line":611},[376,2350,383],{"class":382},[376,2352,2317],{"class":386},[376,2354,391],{"class":390},[376,2356,647],{"class":386},[376,2358,364],{"class":390},[376,2360,1517],{"class":491},[376,2362,495],{"class":386},[376,2364,723],{"class":394},[376,2366,2332],{"class":386},[376,2368,734],{"class":390},[376,2370,2371],{"class":401}," // T?, null si pas de données précédentes\n",[376,2373,2374,2376,2378,2380,2382,2384,2386,2388,2390],{"class":378,"line":619},[376,2375,486],{"class":386},[376,2377,364],{"class":390},[376,2379,2277],{"class":491},[376,2381,495],{"class":386},[376,2383,723],{"class":394},[376,2385,2303],{"class":386},[376,2387,867],{"class":390},[376,2389,2308],{"class":386},[376,2391,439],{"class":390},[376,2393,2394,2397],{"class":378,"line":633},[376,2395,2396],{"class":643},"try",[376,2398,920],{"class":386},[376,2400,2401,2403,2405,2407,2410,2412,2414,2416],{"class":378,"line":640},[376,2402,940],{"class":643},[376,2404,1542],{"class":386},[376,2406,364],{"class":390},[376,2408,2409],{"class":491},"updateUser",[376,2411,593],{"class":386},[376,2413,729],{"class":390},[376,2415,428],{"class":386},[376,2417,439],{"class":390},[376,2419,2420,2423,2426],{"class":378,"line":937},[376,2421,2422],{"class":386},"} ",[376,2424,2425],{"class":643},"catch",[376,2427,2428],{"class":386}," (_) {\n",[376,2430,2431,2433,2435,2438,2440,2442,2444,2446,2449,2451],{"class":378,"line":955},[376,2432,837],{"class":386},[376,2434,364],{"class":390},[376,2436,2437],{"class":491},"restoreQueryData",[376,2439,495],{"class":386},[376,2441,723],{"class":394},[376,2443,2303],{"class":386},[376,2445,867],{"class":390},[376,2447,2448],{"class":386}," snapshot)",[376,2450,734],{"class":390},[376,2452,2453],{"class":401}," // null → removeQuery ; sinon setQueryData\n",[376,2455,2456],{"class":378,"line":970},[376,2457,887],{"class":386},[441,2459],{},[448,2461,2463,2464,2466,2467],{"id":2462},"utilisation-de-setquerydata-pour-le-rollback-au-lieu-de-restorequerydata","Utilisation de ",[357,2465,2277],{}," pour le rollback au lieu de ",[357,2468,2437],{},[353,2470,2471,458,2473,2476,2477,2480,2481,2483,2484,2486,2487,2489,2490,2492,2493,2495],{},[455,2472,466],{},[357,2474,2475],{},"setQueryData\u003CT>(key, data)"," requiert un ",[357,2478,2479],{},"T"," non-null. Il produit toujours un état ",[357,2482,1443],{},". Quand l'état pré-mutation ne contenait pas de données (",[357,2485,1343],{},"), il n'y a pas de ",[357,2488,2479],{}," à passer, et appeler ",[357,2491,2277],{}," laisse un état ",[357,2494,1443],{}," incorrect dans le cache.",[353,2497,2498,2501,2502,2505,2506,2509,2510,2513,2514,2516,2517,2520,2521,2509,2523,2525,2526,2528],{},[357,2499,2500],{},"restoreQueryData\u003CT>(key, T? data)"," accepte la valeur ",[357,2503,2504],{},"T?"," retournée par ",[357,2507,2508],{},"getQueryData\u003CT>",". Quand ",[357,2511,2512],{},"data"," est ",[357,2515,2166],{},", il appelle ",[357,2518,2519],{},"removeQuery(key)",", restaurant ",[357,2522,1343],{},[357,2524,2512],{}," est non-null, il appelle ",[357,2527,2475],{},". Cela gère à la fois le cas \"avait des données\" et \"n'avait pas de données\" avec un seul appel.",[366,2530,2532],{"className":368,"code":2531,"language":371,"meta":372,"style":372},"final snapshot = client.getQueryData\u003CUser>(key); // T?, null si l'entrée était vide\n\nclient.setQueryData\u003CUser>(key, optimisticUser);\ntry {\n  await api.updateUser(...);\n} catch (_) {\n  // Erreur de compilation quand snapshot est null ; incorrect quand l'état précédent était Initial.\n  // client.setQueryData\u003CUser>(key, snapshot!);\n\n  // Gère null correctement : supprime l'entrée quand il n'y avait pas de données précédentes.\n  client.restoreQueryData\u003CUser>(key, snapshot);\n}\n",[357,2533,2534,2559,2563,2583,2589,2607,2615,2620,2625,2629,2634,2654],{"__ignoreMap":372},[376,2535,2536,2538,2540,2542,2544,2546,2548,2550,2552,2554,2556],{"class":378,"line":379},[376,2537,383],{"class":382},[376,2539,2317],{"class":386},[376,2541,391],{"class":390},[376,2543,647],{"class":386},[376,2545,364],{"class":390},[376,2547,1517],{"class":491},[376,2549,495],{"class":386},[376,2551,723],{"class":394},[376,2553,2332],{"class":386},[376,2555,734],{"class":390},[376,2557,2558],{"class":401}," // T?, null si l'entrée était vide\n",[376,2560,2561],{"class":378,"line":405},[376,2562,743],{"emptyLinePlaceholder":742},[376,2564,2565,2567,2569,2571,2573,2575,2577,2579,2581],{"class":378,"line":434},[376,2566,486],{"class":386},[376,2568,364],{"class":390},[376,2570,2277],{"class":491},[376,2572,495],{"class":386},[376,2574,723],{"class":394},[376,2576,2303],{"class":386},[376,2578,867],{"class":390},[376,2580,2308],{"class":386},[376,2582,439],{"class":390},[376,2584,2585,2587],{"class":378,"line":517},[376,2586,2396],{"class":643},[376,2588,920],{"class":386},[376,2590,2591,2593,2595,2597,2599,2601,2603,2605],{"class":378,"line":565},[376,2592,940],{"class":643},[376,2594,1542],{"class":386},[376,2596,364],{"class":390},[376,2598,2409],{"class":491},[376,2600,593],{"class":386},[376,2602,729],{"class":390},[376,2604,428],{"class":386},[376,2606,439],{"class":390},[376,2608,2609,2611,2613],{"class":378,"line":611},[376,2610,2422],{"class":386},[376,2612,2425],{"class":643},[376,2614,2428],{"class":386},[376,2616,2617],{"class":378,"line":619},[376,2618,2619],{"class":401},"  // Erreur de compilation quand snapshot est null ; incorrect quand l'état précédent était Initial.\n",[376,2621,2622],{"class":378,"line":633},[376,2623,2624],{"class":401},"  // client.setQueryData\u003CUser>(key, snapshot!);\n",[376,2626,2627],{"class":378,"line":640},[376,2628,743],{"emptyLinePlaceholder":742},[376,2630,2631],{"class":378,"line":937},[376,2632,2633],{"class":401},"  // Gère null correctement : supprime l'entrée quand il n'y avait pas de données précédentes.\n",[376,2635,2636,2638,2640,2642,2644,2646,2648,2650,2652],{"class":378,"line":955},[376,2637,837],{"class":386},[376,2639,364],{"class":390},[376,2641,2437],{"class":491},[376,2643,495],{"class":386},[376,2645,723],{"class":394},[376,2647,2303],{"class":386},[376,2649,867],{"class":390},[376,2651,2448],{"class":386},[376,2653,439],{"class":390},[376,2655,2656],{"class":378,"line":970},[376,2657,887],{"class":386},[441,2659],{},[348,2661,2663],{"id":2662},"intégration-flutter","Intégration Flutter",[448,2665,2667,1607,2670],{"id":2666},"contextqora-lève-fluttererror-qorascope-not-found",[357,2668,2669],{},"context.qora",[357,2671,2672],{},"FlutterError: QoraScope not found",[353,2674,2675,2677,2678,2680,2681,2683,2684,2687],{},[455,2676,466],{}," : Aucun ancêtre ",[357,2679,103],{}," n'existe au-dessus du widget qui appelle ",[357,2682,2669],{}," (ou ",[357,2685,2686],{},"QoraScope.of(context)",").",[366,2689,2691],{"className":368,"code":2690,"filename":370,"language":371,"meta":372,"style":372},"// QoraScope doit être au-dessus de l'arbre de widgets\nrunApp(\n  QoraScope(\n    client: client,\n    child: const MyApp(), // context.qora fonctionne partout à l'intérieur de MyApp\n  ),\n);\n",[357,2692,2693,2698,2704,2711,2722,2740,2746],{"__ignoreMap":372},[376,2694,2695],{"class":378,"line":379},[376,2696,2697],{"class":401},"// QoraScope doit être au-dessus de l'arbre de widgets\n",[376,2699,2700,2702],{"class":378,"line":405},[376,2701,787],{"class":491},[376,2703,514],{"class":386},[376,2705,2706,2709],{"class":378,"line":434},[376,2707,2708],{"class":394},"  QoraScope",[376,2710,514],{"class":386},[376,2712,2713,2716,2718,2720],{"class":378,"line":517},[376,2714,2715],{"class":386},"    client",[376,2717,411],{"class":390},[376,2719,647],{"class":386},[376,2721,431],{"class":390},[376,2723,2724,2727,2729,2731,2733,2735,2737],{"class":378,"line":565},[376,2725,2726],{"class":386},"    child",[376,2728,411],{"class":390},[376,2730,414],{"class":382},[376,2732,877],{"class":394},[376,2734,560],{"class":386},[376,2736,867],{"class":390},[376,2738,2739],{"class":401}," // context.qora fonctionne partout à l'intérieur de MyApp\n",[376,2741,2742,2744],{"class":378,"line":611},[376,2743,614],{"class":386},[376,2745,431],{"class":390},[376,2747,2748,2750],{"class":378,"line":619},[376,2749,428],{"class":386},[376,2751,439],{"class":390},[353,2753,1755,2754,2756,2757,2759,2760,364],{},[357,2755,2669],{}," n'est pas appelé depuis des callbacks exécutés après la destruction du widget. ",[357,2758,2669],{}," doit être résolu à l'intérieur du sous-arbre appartenant à ",[357,2761,103],{},[441,2763],{},[348,2765,2767],{"id":2766},"file-de-mutations-hors-ligne","File de mutations hors ligne",[448,2769,2771],{"id":2770},"les-mutations-ne-sont-pas-rejouées-après-la-reconnexion","Les mutations ne sont pas rejouées après la reconnexion",[353,2773,2774,458,2776,2778,2779,2781],{},[455,2775,1349],{},[357,2777,1630],{}," n'est pas passé à ",[357,2780,103],{},". Qora ne reçoit pas les événements de reconnexion.",[353,2783,2784,458,2786,2789,2790,2793],{},[455,2785,1410],{},[357,2787,2788],{},"offlineQueue: true"," n'est pas défini dans ",[357,2791,2792],{},"MutationOptions",". La mise en file hors ligne est opt-in par mutation.",[366,2795,2797],{"className":368,"code":2796,"language":371,"meta":372,"style":372},"QoraMutationBuilder\u003Cvoid, Todo, void>(\n  mutator: api.createTodo,\n  options: MutationOptions(\n    offlineQueue: true, // requis pour mettre en file quand hors ligne\n  ),\n  ...\n)\n",[357,2798,2799,2818,2834,2845,2858,2864,2868],{"__ignoreMap":372},[376,2800,2801,2803,2805,2807,2809,2812,2814,2816],{"class":378,"line":379},[376,2802,113],{"class":394},[376,2804,495],{"class":386},[376,2806,826],{"class":382},[376,2808,1211],{"class":386},[376,2810,2811],{"class":394},"Todo",[376,2813,1211],{"class":386},[376,2815,826],{"class":382},[376,2817,1380],{"class":386},[376,2819,2820,2823,2825,2827,2829,2832],{"class":378,"line":405},[376,2821,2822],{"class":386},"  mutator",[376,2824,411],{"class":390},[376,2826,1542],{"class":386},[376,2828,364],{"class":390},[376,2830,2831],{"class":386},"createTodo",[376,2833,431],{"class":390},[376,2835,2836,2838,2840,2843],{"class":378,"line":434},[376,2837,1569],{"class":386},[376,2839,411],{"class":390},[376,2841,2842],{"class":394}," MutationOptions",[376,2844,514],{"class":386},[376,2846,2847,2850,2852,2855],{"class":378,"line":517},[376,2848,2849],{"class":386},"    offlineQueue",[376,2851,411],{"class":390},[376,2853,2854],{"class":390}," true,",[376,2856,2857],{"class":401}," // requis pour mettre en file quand hors ligne\n",[376,2859,2860,2862],{"class":378,"line":565},[376,2861,614],{"class":386},[376,2863,431],{"class":390},[376,2865,2866],{"class":378,"line":611},[376,2867,1400],{"class":390},[376,2869,2870],{"class":378,"line":619},[376,2871,1405],{"class":386},[353,2873,2874,2876,2877,1635,2880,2883],{},[455,2875,1619],{}," : la mutation vient de ",[357,2878,2879],{},"useMutation",[357,2881,2882],{},"qora_hooks"," 1.3.1, qui ne branche pas la file hors-ligne. Passez à la 1.3.1 ou plus.",[441,2885],{},[448,2887,2889],{"id":2888},"une-mutation-en-file-a-disparu-après-la-reconnexion","Une mutation en file a disparu après la reconnexion",[353,2891,2892,2894],{},[455,2893,466],{}," : le serveur l'a rejetée pendant le rejeu. Une mutation en file est envoyée une seule fois ; un rejeu en échec n'est pas remis en file, et le rejeu continue avec la suivante.",[353,2896,2897,2898,2901,2902,2905],{},"Résolution : annuler dans ",[357,2899,2900],{},"onError"," (il reçoit le contexte de ",[357,2903,2904],{},"onMutate",", y compris pour les mutations en file) et prévenir l'utilisateur à cet endroit, par exemple avec un snackbar et une action pour réessayer.",[441,2907],{},[348,2909,163],{"id":2910},"requêtes-infinies",[448,2912,2914,2917],{"id":2913},"fetchnextpage-est-appelé-mais-aucune-nouvelle-donnée-ne-se-charge",[357,2915,2916],{},"fetchNextPage()"," est appelé mais aucune nouvelle donnée ne se charge",[353,2919,2920,458,2922,2163,2925,2927,2928,2931,2932,2935],{},[455,2921,466],{},[357,2923,2924],{},"getNextPageParam",[357,2926,2166],{}," sur la dernière page, donc ",[357,2929,2930],{},"hasNextPage"," devient ",[357,2933,2934],{},"false",". Qora ne fetche pas de pages supplémentaires quand la pagination est complète.",[366,2937,2939],{"className":368,"code":2938,"language":371,"meta":372,"style":372},"// Pages entières. Problème courant : retourne null trop tôt.\ngetNextPageParam: (lastPage, allPages) =>\n    lastPage.items.isEmpty ? null : allPages.length + 1,\n// Comportement correct : retourner null uniquement quand le dataset est complet.\n\n// Pagination par curseur. Problème courant : mauvais champ de curseur.\ngetNextPageParam: (lastPage, _) => lastPage.nextCursor,\n// Si nextCursor est \"\" au lieu de null, hasNextPage reste true.\n// Correction : lastPage.nextCursor?.isNotEmpty == true ? lastPage.nextCursor : null\n",[357,2940,2941,2946,2963,3002,3007,3011,3016,3041,3046],{"__ignoreMap":372},[376,2942,2943],{"class":378,"line":379},[376,2944,2945],{"class":401},"// Pages entières. Problème courant : retourne null trop tôt.\n",[376,2947,2948,2950,2952,2955,2957,2960],{"class":378,"line":405},[376,2949,2924],{"class":386},[376,2951,411],{"class":390},[376,2953,2954],{"class":386}," (lastPage",[376,2956,867],{"class":390},[376,2958,2959],{"class":386}," allPages) ",[376,2961,2962],{"class":390},"=>\n",[376,2964,2965,2968,2970,2973,2975,2978,2980,2983,2986,2989,2991,2994,2997,3000],{"class":378,"line":434},[376,2966,2967],{"class":386},"    lastPage",[376,2969,364],{"class":390},[376,2971,2972],{"class":386},"items",[376,2974,364],{"class":390},[376,2976,2977],{"class":386},"isEmpty ",[376,2979,1298],{"class":390},[376,2981,2982],{"class":390}," null",[376,2984,2985],{"class":390}," :",[376,2987,2988],{"class":386}," allPages",[376,2990,364],{"class":390},[376,2992,2993],{"class":386},"length ",[376,2995,2996],{"class":390},"+",[376,2998,2999],{"class":1894}," 1",[376,3001,431],{"class":390},[376,3003,3004],{"class":378,"line":517},[376,3005,3006],{"class":401},"// Comportement correct : retourner null uniquement quand le dataset est complet.\n",[376,3008,3009],{"class":378,"line":565},[376,3010,743],{"emptyLinePlaceholder":742},[376,3012,3013],{"class":378,"line":611},[376,3014,3015],{"class":401},"// Pagination par curseur. Problème courant : mauvais champ de curseur.\n",[376,3017,3018,3020,3022,3024,3026,3029,3031,3034,3036,3039],{"class":378,"line":619},[376,3019,2924],{"class":386},[376,3021,411],{"class":390},[376,3023,2954],{"class":386},[376,3025,867],{"class":390},[376,3027,3028],{"class":386}," _) ",[376,3030,528],{"class":390},[376,3032,3033],{"class":386}," lastPage",[376,3035,364],{"class":390},[376,3037,3038],{"class":386},"nextCursor",[376,3040,431],{"class":390},[376,3042,3043],{"class":378,"line":633},[376,3044,3045],{"class":401},"// Si nextCursor est \"\" au lieu de null, hasNextPage reste true.\n",[376,3047,3048],{"class":378,"line":640},[376,3049,3050],{"class":401},"// Correction : lastPage.nextCursor?.isNotEmpty == true ? lastPage.nextCursor : null\n",[441,3052],{},[448,3054,3056,3057],{"id":3055},"le-feed-affiche-des-éléments-en-double-après-refetch","Le feed affiche des éléments en double après ",[357,3058,3059],{},"refetch()",[353,3061,3062,3064,3065,3068,3069,3072,3073,3075],{},[455,3063,466],{}," : Pagination par numéro de page entier combinée avec des insertions côté serveur. Quand de nouveaux posts sont ajoutés entre ",[357,3066,3067],{},"page=1"," et ",[357,3070,3071],{},"page=2",", re-fetcher ",[357,3074,3067],{}," retourne des éléments différents du premier chargement, causant un chevauchement.",[353,3077,3078,3081],{},[455,3079,3080],{},"Correction"," : Utiliser la pagination par curseur. Les positions de curseur restent stables quand de nouveaux enregistrements sont insérés.",[366,3083,3085],{"className":368,"code":3084,"language":371,"meta":372,"style":372},"// Pages entières. Instable avec les insertions côté serveur.\nInfiniteQueryOptions(\n  initialPageParam: 1,\n  getNextPageParam: (_, pages) => pages.length + 1,\n)\n\n// Pagination par curseur. Stable entre les insertions.\nInfiniteQueryOptions\u003CFeedPage, String?>(\n  initialPageParam: null,\n  getNextPageParam: (last, _) => last.nextCursor,\n)\n",[357,3086,3087,3092,3099,3110,3140,3144,3148,3153,3169,3178,3202],{"__ignoreMap":372},[376,3088,3089],{"class":378,"line":379},[376,3090,3091],{"class":401},"// Pages entières. Instable avec les insertions côté serveur.\n",[376,3093,3094,3097],{"class":378,"line":405},[376,3095,3096],{"class":394},"InfiniteQueryOptions",[376,3098,514],{"class":386},[376,3100,3101,3104,3106,3108],{"class":378,"line":434},[376,3102,3103],{"class":386},"  initialPageParam",[376,3105,411],{"class":390},[376,3107,2999],{"class":1894},[376,3109,431],{"class":390},[376,3111,3112,3115,3117,3120,3122,3125,3127,3130,3132,3134,3136,3138],{"class":378,"line":517},[376,3113,3114],{"class":386},"  getNextPageParam",[376,3116,411],{"class":390},[376,3118,3119],{"class":386}," (_",[376,3121,867],{"class":390},[376,3123,3124],{"class":386}," pages) ",[376,3126,528],{"class":390},[376,3128,3129],{"class":386}," pages",[376,3131,364],{"class":390},[376,3133,2993],{"class":386},[376,3135,2996],{"class":390},[376,3137,2999],{"class":1894},[376,3139,431],{"class":390},[376,3141,3142],{"class":378,"line":565},[376,3143,1405],{"class":386},[376,3145,3146],{"class":378,"line":611},[376,3147,743],{"emptyLinePlaceholder":742},[376,3149,3150],{"class":378,"line":619},[376,3151,3152],{"class":401},"// Pagination par curseur. Stable entre les insertions.\n",[376,3154,3155,3157,3159,3162,3164,3166],{"class":378,"line":633},[376,3156,3096],{"class":394},[376,3158,495],{"class":386},[376,3160,3161],{"class":394},"FeedPage",[376,3163,1211],{"class":386},[376,3165,1208],{"class":394},[376,3167,3168],{"class":386},"?>(\n",[376,3170,3171,3173,3175],{"class":378,"line":640},[376,3172,3103],{"class":386},[376,3174,411],{"class":390},[376,3176,3177],{"class":390}," null,\n",[376,3179,3180,3182,3184,3187,3189,3191,3193,3196,3198,3200],{"class":378,"line":937},[376,3181,3114],{"class":386},[376,3183,411],{"class":390},[376,3185,3186],{"class":386}," (last",[376,3188,867],{"class":390},[376,3190,3028],{"class":386},[376,3192,528],{"class":390},[376,3194,3195],{"class":386}," last",[376,3197,364],{"class":390},[376,3199,3038],{"class":386},[376,3201,431],{"class":390},[376,3203,3204],{"class":378,"line":955},[376,3205,1405],{"class":386},[3207,3208,3209],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .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 .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":372,"searchDepth":405,"depth":405,"links":3211},[3212,3213,3223,3231,3238,3243,3247,3251],{"id":350,"depth":405,"text":351},{"id":445,"depth":405,"text":446,"children":3214},[3215,3216,3218,3219,3221],{"id":450,"depth":434,"text":451},{"id":668,"depth":434,"text":3217},"hydrate() s'exécute mais le cache est toujours vide",{"id":800,"depth":434,"text":801},{"id":1006,"depth":434,"text":3220},"L'hydratation échoue après un build Flutter Web ou --obfuscate",{"id":1136,"depth":434,"text":3222},"fromJson plante au démarrage après un changement de modèle",{"id":1335,"depth":405,"text":1336,"children":3224},[3225,3227,3229,3230],{"id":1339,"depth":434,"text":3226},"La requête est bloquée dans Initial et ne fetche jamais",{"id":1428,"depth":434,"text":3228},"La requête est bloquée dans Loading indéfiniment",{"id":1644,"depth":434,"text":1645},{"id":1767,"depth":434,"text":1768},{"id":1851,"depth":405,"text":1852,"children":3232},[3233,3234,3236],{"id":1855,"depth":434,"text":1856},{"id":2005,"depth":434,"text":3235},"QoraBuilder se ré-abonne à chaque rebuild (problème de performance)",{"id":2159,"depth":434,"text":3237},"dataOrNull retourne null même après un fetch réussi",{"id":2265,"depth":405,"text":148,"children":3239},[3240,3241],{"id":2268,"depth":434,"text":2269},{"id":2462,"depth":434,"text":3242},"Utilisation de setQueryData pour le rollback au lieu de restoreQueryData",{"id":2662,"depth":405,"text":2663,"children":3244},[3245],{"id":2666,"depth":434,"text":3246},"context.qora lève FlutterError: QoraScope not found",{"id":2766,"depth":405,"text":2767,"children":3248},[3249,3250],{"id":2770,"depth":434,"text":2771},{"id":2888,"depth":434,"text":2889},{"id":2910,"depth":405,"text":163,"children":3252},[3253,3255],{"id":2913,"depth":434,"text":3254},"fetchNextPage() est appelé mais aucune nouvelle donnée ne se charge",{"id":3055,"depth":434,"text":3256},"Le feed affiche des éléments en double après refetch()","Diagnostiquer et résoudre les problèmes courants de Qora, notamment les échecs de persistance, les requêtes bloquées, les refetches manquants et les abonnements répétés de widgets.","md",null,{},{"icon":101},{"title":339,"description":3257},"fxa7GdABJKg6I6yQr9x2Vx0krgMhhf05HgdxGizJfa0",[3265,3259],{"title":334,"path":335,"stem":336,"description":3266,"icon":337,"children":-1},"Réponses aux questions fréquentes sur l'API Qora, la sémantique du cache et l'intégration Flutter.",1794040411665]