[{"data":1,"prerenderedAt":1543},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fv1\u002Fadvanced\u002Fconflict-resolution":121,"\u002Fdocs\u002Fv1\u002Fadvanced\u002Fconflict-resolution-surround":1538},[4],{"title":5,"path":6,"stem":7,"children":8,"page":44},"Docs","\u002Fdocs","docs",[9],{"title":10,"path":11,"stem":12,"children":13,"page":44},"V1","\u002Fdocs\u002Fv1","docs\u002Fv1",[14,18,22,45,58,80,93,111],{"title":15,"path":16,"stem":17},"Introduction","\u002Fdocs\u002Fv1\u002Fintroduction","docs\u002Fv1\u002F0.introduction",{"title":19,"path":20,"stem":21},"How It Works","\u002Fdocs\u002Fv1\u002Fhow-it-works","docs\u002Fv1\u002F1.how-it-works",{"title":23,"icon":24,"path":25,"stem":26,"children":27,"page":44},"Client","i-lucide-laptop","\u002Fdocs\u002Fv1\u002Fclient","docs\u002Fv1\u002F2.client",[28,32,36,40],{"title":29,"path":30,"stem":31},"Client Setup","\u002Fdocs\u002Fv1\u002Fclient\u002Fsetup","docs\u002Fv1\u002F2.client\u002F1.setup",{"title":33,"path":34,"stem":35},"Syncing","\u002Fdocs\u002Fv1\u002Fclient\u002Fsyncing","docs\u002Fv1\u002F2.client\u002F2.syncing",{"title":37,"path":38,"stem":39},"Events","\u002Fdocs\u002Fv1\u002Fclient\u002Fevents","docs\u002Fv1\u002F2.client\u002F3.events",{"title":41,"path":42,"stem":43},"Configuration","\u002Fdocs\u002Fv1\u002Fclient\u002Fconfiguration","docs\u002Fv1\u002F2.client\u002F4.configuration",false,{"title":46,"icon":47,"path":48,"stem":49,"children":50,"page":44},"Server","i-lucide-server","\u002Fdocs\u002Fv1\u002Fserver","docs\u002Fv1\u002F3.server",[51,55],{"title":52,"path":53,"stem":54},"Server Setup","\u002Fdocs\u002Fv1\u002Fserver\u002Fsetup","docs\u002Fv1\u002F3.server\u002F1.setup",{"title":41,"path":56,"stem":57},"\u002Fdocs\u002Fv1\u002Fserver\u002Fconfiguration","docs\u002Fv1\u002F3.server\u002F2.configuration",{"title":59,"icon":60,"badge":61,"path":62,"stem":63,"children":64,"page":44},"NativePHP","i-lucide-smartphone","Commercial","\u002Fdocs\u002Fv1\u002Fnativephp","docs\u002Fv1\u002F4.nativephp",[65,69,73,76],{"title":66,"path":67,"stem":68},"Overview","\u002Fdocs\u002Fv1\u002Fnativephp\u002Foverview","docs\u002Fv1\u002F4.nativephp\u002F1.overview",{"title":70,"path":71,"stem":72},"Setup","\u002Fdocs\u002Fv1\u002Fnativephp\u002Fsetup","docs\u002Fv1\u002F4.nativephp\u002F2.setup",{"title":41,"path":74,"stem":75},"\u002Fdocs\u002Fv1\u002Fnativephp\u002Fconfiguration","docs\u002Fv1\u002F4.nativephp\u002F3.configuration",{"title":77,"path":78,"stem":79},"Lifecycle & Events","\u002Fdocs\u002Fv1\u002Fnativephp\u002Flifecycle","docs\u002Fv1\u002F4.nativephp\u002F4.lifecycle",{"title":81,"icon":82,"badge":61,"path":83,"stem":84,"children":85,"page":44},"Server Pro","i-lucide-bar-chart-2","\u002Fdocs\u002Fv1\u002Fserver-pro","docs\u002Fv1\u002F5.server-pro",[86,89],{"title":66,"path":87,"stem":88},"\u002Fdocs\u002Fv1\u002Fserver-pro\u002Foverview","docs\u002Fv1\u002F5.server-pro\u002F1.overview",{"title":90,"path":91,"stem":92},"Features","\u002Fdocs\u002Fv1\u002Fserver-pro\u002Ffeatures","docs\u002Fv1\u002F5.server-pro\u002F2.features",{"title":94,"icon":95,"path":96,"stem":97,"children":98,"page":44},"Advanced","i-lucide-settings-2","\u002Fdocs\u002Fv1\u002Fadvanced","docs\u002Fv1\u002F6.advanced",[99,103,107],{"title":100,"path":101,"stem":102},"Service Container","\u002Fdocs\u002Fv1\u002Fadvanced\u002Fservice-container","docs\u002Fv1\u002F6.advanced\u002F0.service-container",{"title":104,"path":105,"stem":106},"Conflict Resolution","\u002Fdocs\u002Fv1\u002Fadvanced\u002Fconflict-resolution","docs\u002Fv1\u002F6.advanced\u002F1.conflict-resolution",{"title":108,"path":109,"stem":110},"Payload Mapping","\u002Fdocs\u002Fv1\u002Fadvanced\u002Fpayload-mapping","docs\u002Fv1\u002F6.advanced\u002F2.payload-mapping",{"title":112,"icon":113,"path":114,"stem":115,"children":116,"page":44},"Examples","i-lucide-book-open","\u002Fdocs\u002Fv1\u002Fexamples","docs\u002Fv1\u002F7.examples",[117],{"title":118,"path":119,"stem":120},"Task Manager","\u002Fdocs\u002Fv1\u002Fexamples\u002Ftask-manager","docs\u002Fv1\u002F7.examples\u002F1.task-manager",{"id":122,"title":104,"body":123,"description":1531,"extension":1532,"links":1533,"meta":1534,"navigation":257,"path":105,"seo":1535,"stem":106,"__hash__":1537},"docs\u002Fdocs\u002Fv1\u002F6.advanced\u002F1.conflict-resolution.md",{"type":124,"value":125,"toc":1515},"minimark",[126,130,133,138,141,166,169,171,175,178,199,201,205,211,301,307,309,313,318,584,588,829,831,834,838,923,926,928,932,1004,1007,1009,1013,1199,1201,1205,1342,1344,1348,1354,1500,1511],[127,128,129],"p",{},"Offline sync conflict resolution matters when more than one client can change the same Laravel record before synchronisation. In Tether, a conflict occurs when a client pushes a non-create mutation for a record that has been modified on the server more recently than the incoming mutation. The server detects this automatically and resolves it with the default server-wins policy or with your custom resolver.",[131,132],"hr",{},[134,135,137],"h2",{"id":136},"how-conflicts-are-detected","How conflicts are detected",[127,139,140],{},"When the server receives a push request, for each non-create mutation it:",[142,143,144,153,163],"ol",{},[145,146,147,148,152],"li",{},"Looks up the existing server record by ",[149,150,151],"code",{},"tether_id",".",[145,154,155,156,159,160,152],{},"Compares the incoming mutation's ",[149,157,158],{},"timestamp"," against the server record's ",[149,161,162],{},"updated_at",[145,164,165],{},"If the mutation is older than the server record, the conflict resolver is called.",[127,167,168],{},"If no conflict is detected, the mutation is applied normally.",[131,170],{},[134,172,174],{"id":173},"default-behaviour-server-wins","Default behaviour - server wins",[127,176,177],{},"Without a custom resolver, the server rejects the incoming mutation and returns the current server state to the client. The client then:",[142,179,180,183,193],{},[145,181,182],{},"Applies the server state locally.",[145,184,185,186,189,190,152],{},"Marks the mutation as ",[149,187,188],{},"conflict"," in ",[149,191,192],{},"tether_mutation_logs",[145,194,195,196,152],{},"Fires ",[149,197,198],{},"TetherConflictDetected",[131,200],{},[134,202,204],{"id":203},"conflictresolution","ConflictResolution",[127,206,207,208,210],{},"Custom resolvers return a ",[149,209,204],{}," instance:",[212,213,218],"pre",{"className":214,"code":215,"language":216,"meta":217,"style":217},"language-php shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","use Tether\\Core\\Conflict\\ConflictResolution;\n\nConflictResolution::apply($payload); \u002F\u002F accept client or merged payload\nConflictResolution::reject();        \u002F\u002F keep server state\n","php","",[149,219,220,252,259,285],{"__ignoreMap":217},[221,222,225,229,233,237,240,242,245,247,249],"span",{"class":223,"line":224},"line",1,[221,226,228],{"class":227},"sbssI","use",[221,230,232],{"class":231},"sTEyZ"," Tether",[221,234,236],{"class":235},"sMK4o","\\",[221,238,239],{"class":231},"Core",[221,241,236],{"class":235},[221,243,244],{"class":231},"Conflict",[221,246,236],{"class":235},[221,248,204],{"class":231},[221,250,251],{"class":235},";\n",[221,253,255],{"class":223,"line":254},2,[221,256,258],{"emptyLinePlaceholder":257},true,"\n",[221,260,262,265,268,272,275,278,281],{"class":223,"line":261},3,[221,263,204],{"class":264},"sBMFI",[221,266,267],{"class":235},"::",[221,269,271],{"class":270},"s2Zo4","apply",[221,273,274],{"class":235},"($",[221,276,277],{"class":231},"payload",[221,279,280],{"class":235},");",[221,282,284],{"class":283},"sHwdD"," \u002F\u002F accept client or merged payload\n",[221,286,288,290,292,295,298],{"class":223,"line":287},4,[221,289,204],{"class":264},[221,291,267],{"class":235},[221,293,294],{"class":270},"reject",[221,296,297],{"class":235},"();",[221,299,300],{"class":283},"        \u002F\u002F keep server state\n",[127,302,303,306],{},[149,304,305],{},"ConflictResolution::apply()"," accepts the payload that will be written to the database.",[131,308],{},[134,310,312],{"id":311},"registering-a-custom-resolver","Registering a custom resolver",[314,315,317],"h3",{"id":316},"on-the-model","On the model",[212,319,321],{"className":214,"code":320,"language":216,"meta":217,"style":217},"use Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Http\\Request;\nuse Tether\\Core\\Conflict\\ConflictResolution;\nuse Tether\\Core\\Mutation\\Mutation;\nuse Tether\\Server\\Traits\\Syncable;\n\nclass Task extends Model\n{\n    use Syncable;\n\n    public static function tetherConflictResolver(\n        Mutation $incoming,\n        Model $serverRecord,\n        Request $request,\n    ): ConflictResolution {\n        return ConflictResolution::apply($incoming->getPayload()); \u002F\u002F client wins\n    }\n}\n",[149,322,323,347,365,385,406,429,434,450,456,467,472,490,505,518,531,543,572,578],{"__ignoreMap":217},[221,324,325,327,330,332,335,337,340,342,345],{"class":223,"line":224},[221,326,228],{"class":227},[221,328,329],{"class":231}," Illuminate",[221,331,236],{"class":235},[221,333,334],{"class":231},"Database",[221,336,236],{"class":235},[221,338,339],{"class":231},"Eloquent",[221,341,236],{"class":235},[221,343,344],{"class":231},"Model",[221,346,251],{"class":235},[221,348,349,351,353,355,358,360,363],{"class":223,"line":254},[221,350,228],{"class":227},[221,352,329],{"class":231},[221,354,236],{"class":235},[221,356,357],{"class":231},"Http",[221,359,236],{"class":235},[221,361,362],{"class":231},"Request",[221,364,251],{"class":235},[221,366,367,369,371,373,375,377,379,381,383],{"class":223,"line":261},[221,368,228],{"class":227},[221,370,232],{"class":231},[221,372,236],{"class":235},[221,374,239],{"class":231},[221,376,236],{"class":235},[221,378,244],{"class":231},[221,380,236],{"class":235},[221,382,204],{"class":231},[221,384,251],{"class":235},[221,386,387,389,391,393,395,397,400,402,404],{"class":223,"line":287},[221,388,228],{"class":227},[221,390,232],{"class":231},[221,392,236],{"class":235},[221,394,239],{"class":231},[221,396,236],{"class":235},[221,398,399],{"class":231},"Mutation",[221,401,236],{"class":235},[221,403,399],{"class":231},[221,405,251],{"class":235},[221,407,409,411,413,415,417,419,422,424,427],{"class":223,"line":408},5,[221,410,228],{"class":227},[221,412,232],{"class":231},[221,414,236],{"class":235},[221,416,46],{"class":231},[221,418,236],{"class":235},[221,420,421],{"class":231},"Traits",[221,423,236],{"class":235},[221,425,426],{"class":231},"Syncable",[221,428,251],{"class":235},[221,430,432],{"class":223,"line":431},6,[221,433,258],{"emptyLinePlaceholder":257},[221,435,437,441,444,447],{"class":223,"line":436},7,[221,438,440],{"class":439},"spNyl","class",[221,442,443],{"class":264}," Task",[221,445,446],{"class":439}," extends",[221,448,449],{"class":264}," Model\n",[221,451,453],{"class":223,"line":452},8,[221,454,455],{"class":235},"{\n",[221,457,459,462,465],{"class":223,"line":458},9,[221,460,461],{"class":227},"    use",[221,463,464],{"class":231}," Syncable",[221,466,251],{"class":235},[221,468,470],{"class":223,"line":469},10,[221,471,258],{"emptyLinePlaceholder":257},[221,473,475,478,481,484,487],{"class":223,"line":474},11,[221,476,477],{"class":439},"    public",[221,479,480],{"class":439}," static",[221,482,483],{"class":439}," function",[221,485,486],{"class":270}," tetherConflictResolver",[221,488,489],{"class":235},"(\n",[221,491,493,496,499,502],{"class":223,"line":492},12,[221,494,495],{"class":264},"        Mutation",[221,497,498],{"class":235}," $",[221,500,501],{"class":231},"incoming",[221,503,504],{"class":235},",\n",[221,506,508,511,513,516],{"class":223,"line":507},13,[221,509,510],{"class":264},"        Model",[221,512,498],{"class":235},[221,514,515],{"class":231},"serverRecord",[221,517,504],{"class":235},[221,519,521,524,526,529],{"class":223,"line":520},14,[221,522,523],{"class":264},"        Request",[221,525,498],{"class":235},[221,527,528],{"class":231},"request",[221,530,504],{"class":235},[221,532,534,537,540],{"class":223,"line":533},15,[221,535,536],{"class":235},"    ):",[221,538,539],{"class":264}," ConflictResolution",[221,541,542],{"class":235}," {\n",[221,544,546,550,552,554,556,558,560,563,566,569],{"class":223,"line":545},16,[221,547,549],{"class":548},"s7zQu","        return",[221,551,539],{"class":264},[221,553,267],{"class":235},[221,555,271],{"class":270},[221,557,274],{"class":235},[221,559,501],{"class":231},[221,561,562],{"class":235},"->",[221,564,565],{"class":270},"getPayload",[221,567,568],{"class":235},"());",[221,570,571],{"class":283}," \u002F\u002F client wins\n",[221,573,575],{"class":223,"line":574},17,[221,576,577],{"class":235},"    }\n",[221,579,581],{"class":223,"line":580},18,[221,582,583],{"class":235},"}\n",[314,585,587],{"id":586},"via-syncregistry","Via SyncRegistry",[212,589,591],{"className":214,"code":590,"language":216,"meta":217,"style":217},"use Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Http\\Request;\nuse Tether\\Core\\Conflict\\ConflictResolution;\nuse Tether\\Core\\Mutation\\Mutation;\nuse Tether\\Server\\SyncRegistry;\n\npublic function boot(): void\n{\n    app(SyncRegistry::class)->register(\n        modelClass: Task::class,\n        conflictResolver: fn (\n            Mutation $incoming,\n            Model $record,\n            Request $request,\n        ) => ConflictResolution::apply($incoming->getPayload()),\n    );\n}\n",[149,592,593,613,629,649,669,686,690,706,710,732,748,761,772,784,795,820,825],{"__ignoreMap":217},[221,594,595,597,599,601,603,605,607,609,611],{"class":223,"line":224},[221,596,228],{"class":227},[221,598,329],{"class":231},[221,600,236],{"class":235},[221,602,334],{"class":231},[221,604,236],{"class":235},[221,606,339],{"class":231},[221,608,236],{"class":235},[221,610,344],{"class":231},[221,612,251],{"class":235},[221,614,615,617,619,621,623,625,627],{"class":223,"line":254},[221,616,228],{"class":227},[221,618,329],{"class":231},[221,620,236],{"class":235},[221,622,357],{"class":231},[221,624,236],{"class":235},[221,626,362],{"class":231},[221,628,251],{"class":235},[221,630,631,633,635,637,639,641,643,645,647],{"class":223,"line":261},[221,632,228],{"class":227},[221,634,232],{"class":231},[221,636,236],{"class":235},[221,638,239],{"class":231},[221,640,236],{"class":235},[221,642,244],{"class":231},[221,644,236],{"class":235},[221,646,204],{"class":231},[221,648,251],{"class":235},[221,650,651,653,655,657,659,661,663,665,667],{"class":223,"line":287},[221,652,228],{"class":227},[221,654,232],{"class":231},[221,656,236],{"class":235},[221,658,239],{"class":231},[221,660,236],{"class":235},[221,662,399],{"class":231},[221,664,236],{"class":235},[221,666,399],{"class":231},[221,668,251],{"class":235},[221,670,671,673,675,677,679,681,684],{"class":223,"line":408},[221,672,228],{"class":227},[221,674,232],{"class":231},[221,676,236],{"class":235},[221,678,46],{"class":231},[221,680,236],{"class":235},[221,682,683],{"class":231},"SyncRegistry",[221,685,251],{"class":235},[221,687,688],{"class":223,"line":431},[221,689,258],{"emptyLinePlaceholder":257},[221,691,692,695,697,700,703],{"class":223,"line":436},[221,693,694],{"class":439},"public",[221,696,483],{"class":439},[221,698,699],{"class":270}," boot",[221,701,702],{"class":235},"():",[221,704,705],{"class":227}," void\n",[221,707,708],{"class":223,"line":452},[221,709,455],{"class":235},[221,711,712,715,718,720,722,724,727,730],{"class":223,"line":458},[221,713,714],{"class":270},"    app",[221,716,717],{"class":235},"(",[221,719,683],{"class":264},[221,721,267],{"class":235},[221,723,440],{"class":227},[221,725,726],{"class":235},")->",[221,728,729],{"class":270},"register",[221,731,489],{"class":235},[221,733,734,737,740,742,744,746],{"class":223,"line":469},[221,735,736],{"class":264},"        modelClass",[221,738,739],{"class":235},":",[221,741,443],{"class":264},[221,743,267],{"class":235},[221,745,440],{"class":227},[221,747,504],{"class":235},[221,749,750,753,755,758],{"class":223,"line":474},[221,751,752],{"class":264},"        conflictResolver",[221,754,739],{"class":235},[221,756,757],{"class":439}," fn",[221,759,760],{"class":235}," (\n",[221,762,763,766,768,770],{"class":223,"line":492},[221,764,765],{"class":264},"            Mutation",[221,767,498],{"class":235},[221,769,501],{"class":231},[221,771,504],{"class":235},[221,773,774,777,779,782],{"class":223,"line":507},[221,775,776],{"class":264},"            Model",[221,778,498],{"class":235},[221,780,781],{"class":231},"record",[221,783,504],{"class":235},[221,785,786,789,791,793],{"class":223,"line":520},[221,787,788],{"class":264},"            Request",[221,790,498],{"class":235},[221,792,528],{"class":231},[221,794,504],{"class":235},[221,796,797,800,803,805,807,809,811,813,815,817],{"class":223,"line":533},[221,798,799],{"class":235},"        )",[221,801,802],{"class":235}," =>",[221,804,539],{"class":264},[221,806,267],{"class":235},[221,808,271],{"class":270},[221,810,274],{"class":235},[221,812,501],{"class":231},[221,814,562],{"class":235},[221,816,565],{"class":270},[221,818,819],{"class":235},"()),\n",[221,821,822],{"class":223,"line":545},[221,823,824],{"class":235},"    );\n",[221,826,827],{"class":223,"line":574},[221,828,583],{"class":235},[131,830],{},[134,832,112],{"id":833},"examples",[314,835,837],{"id":836},"client-always-wins","Client always wins",[212,839,841],{"className":214,"code":840,"language":216,"meta":217,"style":217},"public static function tetherConflictResolver(\n    Mutation $incoming,\n    Model $serverRecord,\n    Request $request,\n): ConflictResolution {\n    return ConflictResolution::apply($incoming->getPayload());\n}\n",[149,842,843,855,866,877,888,897,919],{"__ignoreMap":217},[221,844,845,847,849,851,853],{"class":223,"line":224},[221,846,694],{"class":439},[221,848,480],{"class":439},[221,850,483],{"class":439},[221,852,486],{"class":270},[221,854,489],{"class":235},[221,856,857,860,862,864],{"class":223,"line":254},[221,858,859],{"class":264},"    Mutation",[221,861,498],{"class":235},[221,863,501],{"class":231},[221,865,504],{"class":235},[221,867,868,871,873,875],{"class":223,"line":261},[221,869,870],{"class":264},"    Model",[221,872,498],{"class":235},[221,874,515],{"class":231},[221,876,504],{"class":235},[221,878,879,882,884,886],{"class":223,"line":287},[221,880,881],{"class":264},"    Request",[221,883,498],{"class":235},[221,885,528],{"class":231},[221,887,504],{"class":235},[221,889,890,893,895],{"class":223,"line":408},[221,891,892],{"class":235},"):",[221,894,539],{"class":264},[221,896,542],{"class":235},[221,898,899,902,904,906,908,910,912,914,916],{"class":223,"line":431},[221,900,901],{"class":548},"    return",[221,903,539],{"class":264},[221,905,267],{"class":235},[221,907,271],{"class":270},[221,909,274],{"class":235},[221,911,501],{"class":231},[221,913,562],{"class":235},[221,915,565],{"class":270},[221,917,918],{"class":235},"());\n",[221,920,921],{"class":223,"line":436},[221,922,583],{"class":235},[127,924,925],{},"Use when the client is always authoritative, such as local settings or user preferences.",[131,927],{},[314,929,931],{"id":930},"server-always-wins","Server always wins",[212,933,935],{"className":214,"code":934,"language":216,"meta":217,"style":217},"public static function tetherConflictResolver(\n    Mutation $incoming,\n    Model $serverRecord,\n    Request $request,\n): ConflictResolution {\n    return ConflictResolution::reject();\n}\n",[149,936,937,949,959,969,979,987,1000],{"__ignoreMap":217},[221,938,939,941,943,945,947],{"class":223,"line":224},[221,940,694],{"class":439},[221,942,480],{"class":439},[221,944,483],{"class":439},[221,946,486],{"class":270},[221,948,489],{"class":235},[221,950,951,953,955,957],{"class":223,"line":254},[221,952,859],{"class":264},[221,954,498],{"class":235},[221,956,501],{"class":231},[221,958,504],{"class":235},[221,960,961,963,965,967],{"class":223,"line":261},[221,962,870],{"class":264},[221,964,498],{"class":235},[221,966,515],{"class":231},[221,968,504],{"class":235},[221,970,971,973,975,977],{"class":223,"line":287},[221,972,881],{"class":264},[221,974,498],{"class":235},[221,976,528],{"class":231},[221,978,504],{"class":235},[221,980,981,983,985],{"class":223,"line":408},[221,982,892],{"class":235},[221,984,539],{"class":264},[221,986,542],{"class":235},[221,988,989,991,993,995,997],{"class":223,"line":431},[221,990,901],{"class":548},[221,992,539],{"class":264},[221,994,267],{"class":235},[221,996,294],{"class":270},[221,998,999],{"class":235},"();\n",[221,1001,1002],{"class":223,"line":436},[221,1003,583],{"class":235},[127,1005,1006],{},"This is equivalent to the default behaviour, but makes the decision explicit.",[131,1008],{},[314,1010,1012],{"id":1011},"field-level-merge","Field-level merge",[212,1014,1016],{"className":214,"code":1015,"language":216,"meta":217,"style":217},"public static function tetherConflictResolver(\n    Mutation $incoming,\n    Model $serverRecord,\n    Request $request,\n): ConflictResolution {\n    $incomingPayload = $incoming->getPayload();\n\n    $merged = array_merge(\n        $serverRecord->toArray(),\n        ['status' => $incomingPayload['status'] ?? $serverRecord->status],\n    );\n\n    return ConflictResolution::apply($merged);\n}\n",[149,1017,1018,1030,1040,1050,1060,1068,1089,1093,1107,1122,1169,1173,1177,1195],{"__ignoreMap":217},[221,1019,1020,1022,1024,1026,1028],{"class":223,"line":224},[221,1021,694],{"class":439},[221,1023,480],{"class":439},[221,1025,483],{"class":439},[221,1027,486],{"class":270},[221,1029,489],{"class":235},[221,1031,1032,1034,1036,1038],{"class":223,"line":254},[221,1033,859],{"class":264},[221,1035,498],{"class":235},[221,1037,501],{"class":231},[221,1039,504],{"class":235},[221,1041,1042,1044,1046,1048],{"class":223,"line":261},[221,1043,870],{"class":264},[221,1045,498],{"class":235},[221,1047,515],{"class":231},[221,1049,504],{"class":235},[221,1051,1052,1054,1056,1058],{"class":223,"line":287},[221,1053,881],{"class":264},[221,1055,498],{"class":235},[221,1057,528],{"class":231},[221,1059,504],{"class":235},[221,1061,1062,1064,1066],{"class":223,"line":408},[221,1063,892],{"class":235},[221,1065,539],{"class":264},[221,1067,542],{"class":235},[221,1069,1070,1073,1076,1079,1081,1083,1085,1087],{"class":223,"line":431},[221,1071,1072],{"class":235},"    $",[221,1074,1075],{"class":231},"incomingPayload ",[221,1077,1078],{"class":235},"=",[221,1080,498],{"class":235},[221,1082,501],{"class":231},[221,1084,562],{"class":235},[221,1086,565],{"class":270},[221,1088,999],{"class":235},[221,1090,1091],{"class":223,"line":436},[221,1092,258],{"emptyLinePlaceholder":257},[221,1094,1095,1097,1100,1102,1105],{"class":223,"line":452},[221,1096,1072],{"class":235},[221,1098,1099],{"class":231},"merged ",[221,1101,1078],{"class":235},[221,1103,1104],{"class":270}," array_merge",[221,1106,489],{"class":235},[221,1108,1109,1112,1114,1116,1119],{"class":223,"line":458},[221,1110,1111],{"class":235},"        $",[221,1113,515],{"class":231},[221,1115,562],{"class":235},[221,1117,1118],{"class":270},"toArray",[221,1120,1121],{"class":235},"(),\n",[221,1123,1124,1127,1130,1134,1136,1138,1140,1143,1146,1148,1150,1152,1155,1158,1160,1162,1164,1166],{"class":223,"line":469},[221,1125,1126],{"class":235},"        [",[221,1128,1129],{"class":235},"'",[221,1131,1133],{"class":1132},"sfazB","status",[221,1135,1129],{"class":235},[221,1137,802],{"class":235},[221,1139,498],{"class":235},[221,1141,1142],{"class":231},"incomingPayload",[221,1144,1145],{"class":235},"[",[221,1147,1129],{"class":235},[221,1149,1133],{"class":1132},[221,1151,1129],{"class":235},[221,1153,1154],{"class":235},"]",[221,1156,1157],{"class":235}," ??",[221,1159,498],{"class":235},[221,1161,515],{"class":231},[221,1163,562],{"class":235},[221,1165,1133],{"class":231},[221,1167,1168],{"class":235},"],\n",[221,1170,1171],{"class":223,"line":474},[221,1172,824],{"class":235},[221,1174,1175],{"class":223,"line":492},[221,1176,258],{"emptyLinePlaceholder":257},[221,1178,1179,1181,1183,1185,1187,1189,1192],{"class":223,"line":507},[221,1180,901],{"class":548},[221,1182,539],{"class":264},[221,1184,267],{"class":235},[221,1186,271],{"class":270},[221,1188,274],{"class":235},[221,1190,1191],{"class":231},"merged",[221,1193,1194],{"class":235},");\n",[221,1196,1197],{"class":223,"line":520},[221,1198,583],{"class":235},[131,1200],{},[314,1202,1204],{"id":1203},"per-user-ownership-check","Per-user ownership check",[212,1206,1208],{"className":214,"code":1207,"language":216,"meta":217,"style":217},"public static function tetherConflictResolver(\n    Mutation $incoming,\n    Model $serverRecord,\n    Request $request,\n): ConflictResolution {\n    if ($serverRecord->user_id !== $request->user()->id) {\n        return ConflictResolution::reject();\n    }\n\n    return ConflictResolution::apply($incoming->getPayload());\n}\n",[149,1209,1210,1222,1232,1242,1252,1260,1298,1310,1314,1318,1338],{"__ignoreMap":217},[221,1211,1212,1214,1216,1218,1220],{"class":223,"line":224},[221,1213,694],{"class":439},[221,1215,480],{"class":439},[221,1217,483],{"class":439},[221,1219,486],{"class":270},[221,1221,489],{"class":235},[221,1223,1224,1226,1228,1230],{"class":223,"line":254},[221,1225,859],{"class":264},[221,1227,498],{"class":235},[221,1229,501],{"class":231},[221,1231,504],{"class":235},[221,1233,1234,1236,1238,1240],{"class":223,"line":261},[221,1235,870],{"class":264},[221,1237,498],{"class":235},[221,1239,515],{"class":231},[221,1241,504],{"class":235},[221,1243,1244,1246,1248,1250],{"class":223,"line":287},[221,1245,881],{"class":264},[221,1247,498],{"class":235},[221,1249,528],{"class":231},[221,1251,504],{"class":235},[221,1253,1254,1256,1258],{"class":223,"line":408},[221,1255,892],{"class":235},[221,1257,539],{"class":264},[221,1259,542],{"class":235},[221,1261,1262,1265,1268,1270,1272,1275,1278,1280,1282,1284,1287,1290,1293,1296],{"class":223,"line":431},[221,1263,1264],{"class":548},"    if",[221,1266,1267],{"class":235}," ($",[221,1269,515],{"class":231},[221,1271,562],{"class":235},[221,1273,1274],{"class":231},"user_id ",[221,1276,1277],{"class":235},"!==",[221,1279,498],{"class":235},[221,1281,528],{"class":231},[221,1283,562],{"class":235},[221,1285,1286],{"class":270},"user",[221,1288,1289],{"class":235},"()->",[221,1291,1292],{"class":231},"id",[221,1294,1295],{"class":235},")",[221,1297,542],{"class":235},[221,1299,1300,1302,1304,1306,1308],{"class":223,"line":436},[221,1301,549],{"class":548},[221,1303,539],{"class":264},[221,1305,267],{"class":235},[221,1307,294],{"class":270},[221,1309,999],{"class":235},[221,1311,1312],{"class":223,"line":452},[221,1313,577],{"class":235},[221,1315,1316],{"class":223,"line":458},[221,1317,258],{"emptyLinePlaceholder":257},[221,1319,1320,1322,1324,1326,1328,1330,1332,1334,1336],{"class":223,"line":469},[221,1321,901],{"class":548},[221,1323,539],{"class":264},[221,1325,267],{"class":235},[221,1327,271],{"class":270},[221,1329,274],{"class":235},[221,1331,501],{"class":231},[221,1333,562],{"class":235},[221,1335,565],{"class":270},[221,1337,918],{"class":235},[221,1339,1340],{"class":223,"line":474},[221,1341,583],{"class":235},[131,1343],{},[134,1345,1347],{"id":1346},"what-the-client-receives","What the client receives",[127,1349,1350,1351,739],{},"The push response contains an entry in ",[149,1352,1353],{},"conflicts",[212,1355,1359],{"className":1356,"code":1357,"language":1358,"meta":217,"style":217},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"mutation_id\": \"01HWZMX3KB7T2PA31HV2WDKGF4\",\n  \"reason\": \"conflict\",\n  \"data\": {\n    \"server_state\": { \"title\": \"Server version\", \"status\": \"done\" },\n    \"server_updated_at\": \"2026-05-02T09:00:00+00:00\"\n  }\n}\n","json",[149,1360,1361,1365,1388,1407,1420,1472,1491,1496],{"__ignoreMap":217},[221,1362,1363],{"class":223,"line":224},[221,1364,455],{"class":235},[221,1366,1367,1370,1373,1376,1378,1381,1384,1386],{"class":223,"line":254},[221,1368,1369],{"class":235},"  \"",[221,1371,1372],{"class":439},"mutation_id",[221,1374,1375],{"class":235},"\"",[221,1377,739],{"class":235},[221,1379,1380],{"class":235}," \"",[221,1382,1383],{"class":1132},"01HWZMX3KB7T2PA31HV2WDKGF4",[221,1385,1375],{"class":235},[221,1387,504],{"class":235},[221,1389,1390,1392,1395,1397,1399,1401,1403,1405],{"class":223,"line":261},[221,1391,1369],{"class":235},[221,1393,1394],{"class":439},"reason",[221,1396,1375],{"class":235},[221,1398,739],{"class":235},[221,1400,1380],{"class":235},[221,1402,188],{"class":1132},[221,1404,1375],{"class":235},[221,1406,504],{"class":235},[221,1408,1409,1411,1414,1416,1418],{"class":223,"line":287},[221,1410,1369],{"class":235},[221,1412,1413],{"class":439},"data",[221,1415,1375],{"class":235},[221,1417,739],{"class":235},[221,1419,542],{"class":235},[221,1421,1422,1425,1428,1430,1432,1435,1437,1440,1442,1444,1446,1449,1451,1454,1456,1458,1460,1462,1464,1467,1469],{"class":223,"line":408},[221,1423,1424],{"class":235},"    \"",[221,1426,1427],{"class":264},"server_state",[221,1429,1375],{"class":235},[221,1431,739],{"class":235},[221,1433,1434],{"class":235}," {",[221,1436,1380],{"class":235},[221,1438,1439],{"class":227},"title",[221,1441,1375],{"class":235},[221,1443,739],{"class":235},[221,1445,1380],{"class":235},[221,1447,1448],{"class":1132},"Server version",[221,1450,1375],{"class":235},[221,1452,1453],{"class":235},",",[221,1455,1380],{"class":235},[221,1457,1133],{"class":227},[221,1459,1375],{"class":235},[221,1461,739],{"class":235},[221,1463,1380],{"class":235},[221,1465,1466],{"class":1132},"done",[221,1468,1375],{"class":235},[221,1470,1471],{"class":235}," },\n",[221,1473,1474,1476,1479,1481,1483,1485,1488],{"class":223,"line":431},[221,1475,1424],{"class":235},[221,1477,1478],{"class":264},"server_updated_at",[221,1480,1375],{"class":235},[221,1482,739],{"class":235},[221,1484,1380],{"class":235},[221,1486,1487],{"class":1132},"2026-05-02T09:00:00+00:00",[221,1489,1490],{"class":235},"\"\n",[221,1492,1493],{"class":223,"line":436},[221,1494,1495],{"class":235},"  }\n",[221,1497,1498],{"class":223,"line":452},[221,1499,583],{"class":235},[127,1501,1502,1503,1505,1506,1508,1509,152],{},"The client applies ",[149,1504,1427],{},", marks the mutation as ",[149,1507,188],{},", and fires ",[149,1510,198],{},[1512,1513,1514],"style",{},"html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}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 .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}",{"title":217,"searchDepth":224,"depth":254,"links":1516},[1517,1518,1519,1520,1524,1530],{"id":136,"depth":254,"text":137},{"id":173,"depth":254,"text":174},{"id":203,"depth":254,"text":204},{"id":311,"depth":254,"text":312,"children":1521},[1522,1523],{"id":316,"depth":261,"text":317},{"id":586,"depth":261,"text":587},{"id":833,"depth":254,"text":112,"children":1525},[1526,1527,1528,1529],{"id":836,"depth":261,"text":837},{"id":930,"depth":261,"text":931},{"id":1011,"depth":261,"text":1012},{"id":1203,"depth":261,"text":1204},{"id":1346,"depth":254,"text":1347},"Learn how Laravel Tether detects offline sync conflicts, applies server-wins defaults, returns server state, and supports custom conflict resolvers.","md",null,{},{"title":1536,"description":1531},"Conflict Resolution for Offline-First Laravel Apps","HWiHudb_GPv9HYj-DeB-Bb-U8vqNrGV_4rYF8yDJ4D8",[1539,1541],{"title":100,"path":101,"stem":102,"description":1540,"children":-1},"Inject and extend Tether services through Laravel's container, including sync engines, registries, HTTP clients, snapshot applicators, and queues.",{"title":108,"path":109,"stem":110,"description":1542,"children":-1},"Transform Tether mutation and snapshot payloads between client and server using client mutation mappers, push mappers, and pull snapshot mappers.",1780481015210]