[{"data":1,"prerenderedAt":950},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fv1\u002Fclient\u002Fsyncing":121,"\u002Fdocs\u002Fv1\u002Fclient\u002Fsyncing-surround":945},[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":33,"body":123,"description":938,"extension":939,"links":940,"meta":941,"navigation":191,"path":34,"seo":942,"stem":35,"__hash__":944},"docs\u002Fdocs\u002Fv1\u002F2.client\u002F2.syncing.md",{"type":124,"value":125,"toc":928},"minimark",[126,130,133,138,146,265,267,271,278,400,403,448,454,456,460,516,518,522,529,587,594,618,630,632,636,639,715,729,731,735,797,799,803,871,873,877,896,924],[127,128,129],"p",{},"Use Tether to sync offline Laravel client apps on demand, from queue jobs, or on a schedule. Each sync cycle can push local mutations, pull authoritative server snapshots, report conflicts, and keep the local database reconciled.",[131,132],"hr",{},[134,135,137],"h2",{"id":136},"the-tetherclient-facade","The TetherClient facade",[127,139,140,141,145],{},"All sync operations are available on the ",[142,143,144],"code",{},"TetherClient"," facade:",[147,148,153],"pre",{"className":149,"code":150,"language":151,"meta":152,"style":152},"language-php shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","use Tether\\Client\\Facades\\TetherClient;\n\n$result = TetherClient::sync(); \u002F\u002F push, then pull\n$result = TetherClient::push(); \u002F\u002F push only\n$result = TetherClient::pull(); \u002F\u002F pull only\n","php","",[142,154,155,186,193,223,244],{"__ignoreMap":152},[156,157,160,164,168,172,174,176,179,181,183],"span",{"class":158,"line":159},"line",1,[156,161,163],{"class":162},"sbssI","use",[156,165,167],{"class":166},"sTEyZ"," Tether",[156,169,171],{"class":170},"sMK4o","\\",[156,173,23],{"class":166},[156,175,171],{"class":170},[156,177,178],{"class":166},"Facades",[156,180,171],{"class":170},[156,182,144],{"class":166},[156,184,185],{"class":170},";\n",[156,187,189],{"class":158,"line":188},2,[156,190,192],{"emptyLinePlaceholder":191},true,"\n",[156,194,196,199,202,205,209,212,216,219],{"class":158,"line":195},3,[156,197,198],{"class":170},"$",[156,200,201],{"class":166},"result ",[156,203,204],{"class":170},"=",[156,206,208],{"class":207},"sBMFI"," TetherClient",[156,210,211],{"class":170},"::",[156,213,215],{"class":214},"s2Zo4","sync",[156,217,218],{"class":170},"();",[156,220,222],{"class":221},"sHwdD"," \u002F\u002F push, then pull\n",[156,224,226,228,230,232,234,236,239,241],{"class":158,"line":225},4,[156,227,198],{"class":170},[156,229,201],{"class":166},[156,231,204],{"class":170},[156,233,208],{"class":207},[156,235,211],{"class":170},[156,237,238],{"class":214},"push",[156,240,218],{"class":170},[156,242,243],{"class":221}," \u002F\u002F push only\n",[156,245,247,249,251,253,255,257,260,262],{"class":158,"line":246},5,[156,248,198],{"class":170},[156,250,201],{"class":166},[156,252,204],{"class":170},[156,254,208],{"class":207},[156,256,211],{"class":170},[156,258,259],{"class":214},"pull",[156,261,218],{"class":170},[156,263,264],{"class":221}," \u002F\u002F pull only\n",[131,266],{},[134,268,270],{"id":269},"syncresult","SyncResult",[127,272,273,274,277],{},"All three methods return a ",[142,275,276],{},"Tether\\Client\\SyncResult"," object:",[147,279,281],{"className":149,"code":280,"language":151,"meta":152,"style":152},"$result->pushed;     \u002F\u002F int - mutations applied on the server\n$result->pulled;     \u002F\u002F int - snapshots applied locally\n$result->conflicts;  \u002F\u002F int - conflicts returned by the server\n$result->failed;     \u002F\u002F int - rejected mutations\n$result->rejections; \u002F\u002F list\u003CPushRejection>\n$result->pullErrors; \u002F\u002F int - snapshots that failed to apply\n$result->skipped;    \u002F\u002F bool - true if internal Tether lock prevented the cycle (see \"Concurrency protection\" below)\n",[142,282,283,302,318,334,350,366,383],{"__ignoreMap":152},[156,284,285,287,290,293,296,299],{"class":158,"line":159},[156,286,198],{"class":170},[156,288,289],{"class":166},"result",[156,291,292],{"class":170},"->",[156,294,295],{"class":166},"pushed",[156,297,298],{"class":170},";",[156,300,301],{"class":221},"     \u002F\u002F int - mutations applied on the server\n",[156,303,304,306,308,310,313,315],{"class":158,"line":188},[156,305,198],{"class":170},[156,307,289],{"class":166},[156,309,292],{"class":170},[156,311,312],{"class":166},"pulled",[156,314,298],{"class":170},[156,316,317],{"class":221},"     \u002F\u002F int - snapshots applied locally\n",[156,319,320,322,324,326,329,331],{"class":158,"line":195},[156,321,198],{"class":170},[156,323,289],{"class":166},[156,325,292],{"class":170},[156,327,328],{"class":166},"conflicts",[156,330,298],{"class":170},[156,332,333],{"class":221},"  \u002F\u002F int - conflicts returned by the server\n",[156,335,336,338,340,342,345,347],{"class":158,"line":225},[156,337,198],{"class":170},[156,339,289],{"class":166},[156,341,292],{"class":170},[156,343,344],{"class":166},"failed",[156,346,298],{"class":170},[156,348,349],{"class":221},"     \u002F\u002F int - rejected mutations\n",[156,351,352,354,356,358,361,363],{"class":158,"line":246},[156,353,198],{"class":170},[156,355,289],{"class":166},[156,357,292],{"class":170},[156,359,360],{"class":166},"rejections",[156,362,298],{"class":170},[156,364,365],{"class":221}," \u002F\u002F list\u003CPushRejection>\n",[156,367,369,371,373,375,378,380],{"class":158,"line":368},6,[156,370,198],{"class":170},[156,372,289],{"class":166},[156,374,292],{"class":170},[156,376,377],{"class":166},"pullErrors",[156,379,298],{"class":170},[156,381,382],{"class":221}," \u002F\u002F int - snapshots that failed to apply\n",[156,384,386,388,390,392,395,397],{"class":158,"line":385},7,[156,387,198],{"class":170},[156,389,289],{"class":166},[156,391,292],{"class":170},[156,393,394],{"class":166},"skipped",[156,396,298],{"class":170},[156,398,399],{"class":221},"    \u002F\u002F bool - true if internal Tether lock prevented the cycle (see \"Concurrency protection\" below)\n",[127,401,402],{},"Use helpers to inspect structured rejections:",[147,404,406],{"className":149,"code":405,"language":151,"meta":152,"style":152},"$result->rejectionsByReason('validation_failed');\n$result->validationErrors();\n",[142,407,408,434],{"__ignoreMap":152},[156,409,410,412,414,416,419,422,425,429,431],{"class":158,"line":159},[156,411,198],{"class":170},[156,413,289],{"class":166},[156,415,292],{"class":170},[156,417,418],{"class":214},"rejectionsByReason",[156,420,421],{"class":170},"(",[156,423,424],{"class":170},"'",[156,426,428],{"class":427},"sfazB","validation_failed",[156,430,424],{"class":170},[156,432,433],{"class":170},");\n",[156,435,436,438,440,442,445],{"class":158,"line":188},[156,437,198],{"class":170},[156,439,289],{"class":166},[156,441,292],{"class":170},[156,443,444],{"class":214},"validationErrors",[156,446,447],{"class":170},"();\n",[127,449,450,451,453],{},"Transport errors from Laravel's HTTP client calling your server bubble to the caller or queued job handler; they are not stored on ",[142,452,270],{},".",[131,455],{},[134,457,459],{"id":458},"artisan-commands","Artisan commands",[147,461,465],{"className":462,"code":463,"language":464,"meta":152,"style":152},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","php artisan tether:sync   # push then pull\nphp artisan tether:push   # push only\nphp artisan tether:pull   # pull only\nphp artisan tether:status # queue counts and last cursor\n","bash",[142,466,467,480,492,504],{"__ignoreMap":152},[156,468,469,471,474,477],{"class":158,"line":159},[156,470,151],{"class":207},[156,472,473],{"class":427}," artisan",[156,475,476],{"class":427}," tether:sync",[156,478,479],{"class":221},"   # push then pull\n",[156,481,482,484,486,489],{"class":158,"line":188},[156,483,151],{"class":207},[156,485,473],{"class":427},[156,487,488],{"class":427}," tether:push",[156,490,491],{"class":221},"   # push only\n",[156,493,494,496,498,501],{"class":158,"line":195},[156,495,151],{"class":207},[156,497,473],{"class":427},[156,499,500],{"class":427}," tether:pull",[156,502,503],{"class":221},"   # pull only\n",[156,505,506,508,510,513],{"class":158,"line":225},[156,507,151],{"class":207},[156,509,473],{"class":427},[156,511,512],{"class":427}," tether:status",[156,514,515],{"class":221}," # queue counts and last cursor\n",[131,517],{},[134,519,521],{"id":520},"scheduling","Scheduling",[127,523,524,525,528],{},"Schedule automatic sync in ",[142,526,527],{},"routes\u002Fconsole.php"," or your console kernel:",[147,530,532],{"className":149,"code":531,"language":151,"meta":152,"style":152},"use Illuminate\\Support\\Facades\\Schedule;\n\nSchedule::command('tether:sync')->everyFiveMinutes();\n",[142,533,534,557,561],{"__ignoreMap":152},[156,535,536,538,541,543,546,548,550,552,555],{"class":158,"line":159},[156,537,163],{"class":162},[156,539,540],{"class":166}," Illuminate",[156,542,171],{"class":170},[156,544,545],{"class":166},"Support",[156,547,171],{"class":170},[156,549,178],{"class":166},[156,551,171],{"class":170},[156,553,554],{"class":166},"Schedule",[156,556,185],{"class":170},[156,558,559],{"class":158,"line":188},[156,560,192],{"emptyLinePlaceholder":191},[156,562,563,565,567,570,572,574,577,579,582,585],{"class":158,"line":195},[156,564,554],{"class":207},[156,566,211],{"class":170},[156,568,569],{"class":214},"command",[156,571,421],{"class":170},[156,573,424],{"class":170},[156,575,576],{"class":427},"tether:sync",[156,578,424],{"class":170},[156,580,581],{"class":170},")->",[156,583,584],{"class":214},"everyFiveMinutes",[156,586,447],{"class":170},[127,588,589,590,593],{},"For mutation-triggered push, enable ",[142,591,592],{},"auto_sync",":",[147,595,597],{"className":149,"code":596,"language":151,"meta":152,"style":152},"\u002F\u002F config\u002Ftether-client.php\n'auto_sync' => true,\n",[142,598,599,604],{"__ignoreMap":152},[156,600,601],{"class":158,"line":159},[156,602,603],{"class":221},"\u002F\u002F config\u002Ftether-client.php\n",[156,605,606,608,610,612,615],{"class":158,"line":188},[156,607,424],{"class":170},[156,609,592],{"class":427},[156,611,424],{"class":170},[156,613,614],{"class":170}," =>",[156,616,617],{"class":170}," true,\n",[127,619,620,622,623,626,627,629],{},[142,621,592],{}," dispatches ",[142,624,625],{},"PushJob"," after local model writes. ",[142,628,625],{}," is push-only, so inbound snapshots do not cause feedback loops.",[131,631],{},[134,633,635],{"id":634},"queue-jobs","Queue jobs",[127,637,638],{},"Two jobs are available:",[147,640,642],{"className":149,"code":641,"language":151,"meta":152,"style":152},"use Tether\\Client\\Jobs\\PushJob;\nuse Tether\\Client\\Jobs\\PullJob;\n\nPushJob::dispatch(); \u002F\u002F push only\nPullJob::dispatch(); \u002F\u002F pull only\n",[142,643,644,665,686,690,703],{"__ignoreMap":152},[156,645,646,648,650,652,654,656,659,661,663],{"class":158,"line":159},[156,647,163],{"class":162},[156,649,167],{"class":166},[156,651,171],{"class":170},[156,653,23],{"class":166},[156,655,171],{"class":170},[156,657,658],{"class":166},"Jobs",[156,660,171],{"class":170},[156,662,625],{"class":166},[156,664,185],{"class":170},[156,666,667,669,671,673,675,677,679,681,684],{"class":158,"line":188},[156,668,163],{"class":162},[156,670,167],{"class":166},[156,672,171],{"class":170},[156,674,23],{"class":166},[156,676,171],{"class":170},[156,678,658],{"class":166},[156,680,171],{"class":170},[156,682,683],{"class":166},"PullJob",[156,685,185],{"class":170},[156,687,688],{"class":158,"line":195},[156,689,192],{"emptyLinePlaceholder":191},[156,691,692,694,696,699,701],{"class":158,"line":225},[156,693,625],{"class":207},[156,695,211],{"class":170},[156,697,698],{"class":214},"dispatch",[156,700,218],{"class":170},[156,702,243],{"class":221},[156,704,705,707,709,711,713],{"class":158,"line":246},[156,706,683],{"class":207},[156,708,211],{"class":170},[156,710,698],{"class":214},[156,712,218],{"class":170},[156,714,264],{"class":221},[127,716,717,718,721,722,724,725,728],{},"Both jobs use ",[142,719,720],{},"auto_sync_queue"," if set. ",[142,723,625],{}," can be coalesced with ",[142,726,727],{},"auto_sync_throttle",", which uses Laravel's unique job lock to avoid queueing a job for every rapid local write.",[131,730],{},[134,732,734],{"id":733},"how-a-push-cycle-works","How a push cycle works",[736,737,738,753,759,766,779,785,790],"ol",{},[739,740,741,742,745,746,749,750,453],"li",{},"Failed mutations rejected with reason ",[142,743,744],{},"error"," are moved back to ",[142,747,748],{},"pending"," while below ",[142,751,752],{},"max_retry_attempts",[739,754,755,756,453],{},"Pending mutations are loaded and chunked into batches of ",[142,757,758],{},"push_batch_size",[739,760,761,762,765],{},"Each batch is sent to ",[142,763,764],{},"TETHER_SERVER_PUSH_URL"," as JSON.",[739,767,768,769,772,773,776,777,453],{},"The server responds with ",[142,770,771],{},"applied",", ",[142,774,775],{},"rejected",", and ",[142,778,328],{},[739,780,781,782,453],{},"Applied mutations are marked ",[142,783,784],{},"synced",[739,786,787,788,453],{},"Rejected mutations are marked ",[142,789,344],{},[739,791,792,793,796],{},"Conflicted mutations are marked ",[142,794,795],{},"conflict",", and the server state is applied locally.",[131,798],{},[134,800,802],{"id":801},"how-a-pull-cycle-works","How a pull cycle works",[736,804,805,815,826,838,856,861],{},[739,806,807,808,811,812,453],{},"The stored ",[142,809,810],{},"last_sync_cursor"," is read from ",[142,813,814],{},"tether_sync_state",[739,816,817,818,821,822,825],{},"A pull request is sent to ",[142,819,820],{},"TETHER_SERVER_PULL_URL"," with the integer microsecond cursor, or ",[142,823,824],{},"null"," for a full pull.",[739,827,828,829,772,832,776,835,453],{},"The server returns ",[142,830,831],{},"snapshots",[142,833,834],{},"new_sync_cursor",[142,836,837],{},"has_more",[739,839,840,841,844,845,848,849,852,853,453],{},"Each snapshot is applied locally by ",[142,842,843],{},"SnapshotApplicator"," using ",[142,846,847],{},"forceFill()"," and ",[142,850,851],{},"save()"," inside ",[142,854,855],{},"Model::withoutEvents()",[739,857,858,859,453],{},"The cursor is persisted in ",[142,860,814],{},[739,862,863,864,866,867,870],{},"If ",[142,865,837],{}," is ",[142,868,869],{},"true",", the cycle repeats with the new cursor until all pages are consumed.",[131,872],{},[134,874,876],{"id":875},"concurrency-protection","Concurrency protection",[127,878,879,880,884,885,888,889,892,893,453],{},"All three methods use ",[881,882,883],"strong",{},"Laravel's atomic cache lock"," (",[142,886,887],{},"tether_sync_lock",", 60-second TTL) when ",[142,890,891],{},"sync_lock"," is enabled. If the lock is already held, the method returns immediately with ",[142,894,895],{},"skipped = true",[897,898,899],"blockquote",{},[127,900,901,904,905,772,908,772,911,772,914,772,917,920,921,453],{},[881,902,903],{},"Cache driver requirement:"," Atomic locks require one of: ",[142,906,907],{},"memcached",[142,909,910],{},"redis",[142,912,913],{},"dynamodb",[142,915,916],{},"database",[142,918,919],{},"file",", or ",[142,922,923],{},"array",[925,926,927],"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 .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}",{"title":152,"searchDepth":159,"depth":188,"links":929},[930,931,932,933,934,935,936,937],{"id":136,"depth":188,"text":137},{"id":269,"depth":188,"text":270},{"id":458,"depth":188,"text":459},{"id":520,"depth":188,"text":521},{"id":634,"depth":188,"text":635},{"id":733,"depth":188,"text":734},{"id":801,"depth":188,"text":802},{"id":875,"depth":188,"text":876},"Run Laravel Tether sync manually, from queues, or on a schedule, and understand push\u002Fpull results, conflicts, retries, and pull pagination.","md",null,{},{"title":943,"description":938},"Sync Offline Laravel Apps - Push, Pull, Jobs, and Schedules","qDDqpIPTcF5G9PNPWjLBkn1sT8kP9JBrAcOTi0siJCM",[946,948],{"title":29,"path":30,"stem":31,"description":947,"children":-1},"Install tether\u002Fclient, configure a local-first Laravel client app, add Syncable models, and record offline mutations for later sync.",{"title":37,"path":38,"stem":39,"description":949,"children":-1},"Use Laravel events from tether\u002Fclient to react to sync lifecycle changes, push and pull completion, skipped runs, and detected conflicts.",1780481013060]