[{"data":1,"prerenderedAt":2285},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fv1\u002Fadvanced\u002Fservice-container":121,"\u002Fdocs\u002Fv1\u002Fadvanced\u002Fservice-container-surround":2280},[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":100,"body":123,"description":2273,"extension":2274,"links":2275,"meta":2276,"navigation":322,"path":101,"seo":2277,"stem":102,"__hash__":2279},"docs\u002Fdocs\u002Fv1\u002F6.advanced\u002F0.service-container.md",{"type":124,"value":125,"toc":2259},"minimark",[126,130,133,136,141,149,271,276,285,488,497,499,502,510,527,530,590,597,758,761,763,767,776,796,871,877,879,883,888,1077,1087,1094,1096,1100,1108,1263,1270,1272,1276,1281,1360,1364,1373,1758,1768,1770,1774,1784,2123,2126,2128,2132,2135,2224,2227,2255],[127,128,129],"p",{},"Tether registers its offline sync runtime services in Laravel's service container. Most applications only need the model traits, config files, facade, and artisan commands, but the container services are useful when you want to wire the sync engine into your own application services, controllers, auth layer, or diagnostics UI.",[127,131,132],{},"As a rule of thumb, registries and high-level services are the intended extension points. Processors and applicators are lower-level implementation services; use them when building a custom sync surface, and only replace them when you intentionally want to change package behaviour.",[134,135],"hr",{},[137,138,140],"h2",{"id":139},"client-services","Client services",[127,142,143,144,148],{},"These services are registered by ",[145,146,147],"code",{},"tether\u002Fclient",".",[150,151,152,168],"table",{},[153,154,155],"thead",{},[156,157,158,162,165],"tr",{},[159,160,161],"th",{},"Service",[159,163,164],{},"Purpose",[159,166,167],{},"Common use",[169,170,171,199,212,225,242,258],"tbody",{},[156,172,173,179,196],{},[174,175,176],"td",{},[145,177,178],{},"SyncEngine",[174,180,181,182,185,186,185,189,192,193],{},"Runs ",[145,183,184],{},"sync()",", ",[145,187,188],{},"push()",[145,190,191],{},"pull()",", and ",[145,194,195],{},"syncStatus()",[174,197,198],{},"Inject into your own services or controllers",[156,200,201,206,209],{},[174,202,203],{},[145,204,205],{},"SyncHttpClient",[174,207,208],{},"Sends push and pull HTTP requests to the server",[174,210,211],{},"Add auth headers, request signing, or HTTP middleware",[156,213,214,219,222],{},[174,215,216],{},[145,217,218],{},"ClientSyncRegistry",[174,220,221],{},"Registers client-side payload and mutation mappers",[174,223,224],{},"Transform inbound snapshots or outbound mutations",[156,226,227,232,239],{},[174,228,229],{},[145,230,231],{},"ClientIdResolver",[174,233,234,235,238],{},"Resolves the ",[145,236,237],{},"client_id"," sent with every sync request",[174,240,241],{},"Runtime device\u002Fuser identity",[156,243,244,249,255],{},[174,245,246],{},[145,247,248],{},"SyncStateStore",[174,250,251,252],{},"Persists local sync state such as ",[145,253,254],{},"last_sync_cursor",[174,256,257],{},"Status screens and diagnostics",[156,259,260,265,268],{},[174,261,262],{},[145,263,264],{},"PendingSyncQueue",[174,266,267],{},"Reads and updates local mutation log state",[174,269,270],{},"Pending\u002Ffailed\u002Fconflict counters",[272,273,275],"h3",{"id":274},"injecting-the-sync-engine","Injecting the sync engine",[127,277,278,280,281,284],{},[145,279,178],{}," is the service behind the ",[145,282,283],{},"TetherClient"," facade. Inject it when your own application code needs a concrete dependency.",[286,287,292],"pre",{"className":288,"code":289,"language":290,"meta":291,"style":291},"language-php shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","namespace App\\Services;\n\nuse Tether\\Client\\SyncEngine;\nuse Tether\\Client\\SyncResult;\n\nclass ManualSyncService\n{\n    public function __construct(\n        private readonly SyncEngine $sync,\n    ) {}\n\n    public function run(): SyncResult\n    {\n        return $this->sync->sync();\n    }\n}\n","php","",[145,293,294,317,324,344,362,367,377,383,399,420,429,434,450,456,476,482],{"__ignoreMap":291},[295,296,299,303,307,311,314],"span",{"class":297,"line":298},"line",1,[295,300,302],{"class":301},"sbssI","namespace",[295,304,306],{"class":305},"sBMFI"," App",[295,308,310],{"class":309},"sMK4o","\\",[295,312,313],{"class":305},"Services",[295,315,316],{"class":309},";\n",[295,318,320],{"class":297,"line":319},2,[295,321,323],{"emptyLinePlaceholder":322},true,"\n",[295,325,327,330,334,336,338,340,342],{"class":297,"line":326},3,[295,328,329],{"class":301},"use",[295,331,333],{"class":332},"sTEyZ"," Tether",[295,335,310],{"class":309},[295,337,23],{"class":332},[295,339,310],{"class":309},[295,341,178],{"class":332},[295,343,316],{"class":309},[295,345,347,349,351,353,355,357,360],{"class":297,"line":346},4,[295,348,329],{"class":301},[295,350,333],{"class":332},[295,352,310],{"class":309},[295,354,23],{"class":332},[295,356,310],{"class":309},[295,358,359],{"class":332},"SyncResult",[295,361,316],{"class":309},[295,363,365],{"class":297,"line":364},5,[295,366,323],{"emptyLinePlaceholder":322},[295,368,370,374],{"class":297,"line":369},6,[295,371,373],{"class":372},"spNyl","class",[295,375,376],{"class":305}," ManualSyncService\n",[295,378,380],{"class":297,"line":379},7,[295,381,382],{"class":309},"{\n",[295,384,386,389,392,396],{"class":297,"line":385},8,[295,387,388],{"class":372},"    public",[295,390,391],{"class":372}," function",[295,393,395],{"class":394},"s2Zo4"," __construct",[295,397,398],{"class":309},"(\n",[295,400,402,405,408,411,414,417],{"class":297,"line":401},9,[295,403,404],{"class":372},"        private",[295,406,407],{"class":372}," readonly",[295,409,410],{"class":305}," SyncEngine",[295,412,413],{"class":309}," $",[295,415,416],{"class":332},"sync",[295,418,419],{"class":309},",\n",[295,421,423,426],{"class":297,"line":422},10,[295,424,425],{"class":309},"    )",[295,427,428],{"class":309}," {}\n",[295,430,432],{"class":297,"line":431},11,[295,433,323],{"emptyLinePlaceholder":322},[295,435,437,439,441,444,447],{"class":297,"line":436},12,[295,438,388],{"class":372},[295,440,391],{"class":372},[295,442,443],{"class":394}," run",[295,445,446],{"class":309},"():",[295,448,449],{"class":305}," SyncResult\n",[295,451,453],{"class":297,"line":452},13,[295,454,455],{"class":309},"    {\n",[295,457,459,463,466,468,471,473],{"class":297,"line":458},14,[295,460,462],{"class":461},"s7zQu","        return",[295,464,465],{"class":309}," $this->",[295,467,416],{"class":332},[295,469,470],{"class":309},"->",[295,472,416],{"class":394},[295,474,475],{"class":309},"();\n",[295,477,479],{"class":297,"line":478},15,[295,480,481],{"class":309},"    }\n",[295,483,485],{"class":297,"line":484},16,[295,486,487],{"class":309},"}\n",[127,489,490,491,493,494,496],{},"Use ",[145,492,188],{}," when you only want to send local mutations, and ",[145,495,191],{}," when you only want to reconcile from the server.",[134,498],{},[137,500,205],{"id":501},"synchttpclient",[127,503,504,506,507,509],{},[145,505,205],{}," is the client-side HTTP transport used by ",[145,508,178],{},". It is constructed from:",[511,512,513,519,524],"ul",{},[514,515,516],"li",{},[145,517,518],{},"tether-client.server_routes.push",[514,520,521],{},[145,522,523],{},"tether-client.server_routes.pull",[514,525,526],{},"the resolved client ID",[127,528,529],{},"It exposes:",[286,531,533],{"className":288,"code":532,"language":290,"meta":291,"style":291},"$http->push($mutations);      \u002F\u002F returns PushResult\n$http->pull($cursor, $limit); \u002F\u002F returns PullResult\n",[145,534,535,561],{"__ignoreMap":291},[295,536,537,540,543,545,548,551,554,557],{"class":297,"line":298},[295,538,539],{"class":309},"$",[295,541,542],{"class":332},"http",[295,544,470],{"class":309},[295,546,547],{"class":394},"push",[295,549,550],{"class":309},"($",[295,552,553],{"class":332},"mutations",[295,555,556],{"class":309},");",[295,558,560],{"class":559},"sHwdD","      \u002F\u002F returns PushResult\n",[295,562,563,565,567,569,572,574,577,580,582,585,587],{"class":297,"line":319},[295,564,539],{"class":309},[295,566,542],{"class":332},[295,568,470],{"class":309},[295,570,571],{"class":394},"pull",[295,573,550],{"class":309},[295,575,576],{"class":332},"cursor",[295,578,579],{"class":309},",",[295,581,413],{"class":309},[295,583,584],{"class":332},"limit",[295,586,556],{"class":309},[295,588,589],{"class":559}," \u002F\u002F returns PullResult\n",[127,591,592,593,596],{},"Most applications should not call those methods directly. The main developer-facing hook is ",[145,594,595],{},"withMiddleware()",", which applies Guzzle-compatible middleware to every Tether push and pull request.",[286,598,600],{"className":288,"code":599,"language":290,"meta":291,"style":291},"\u002F\u002F AppServiceProvider::boot()\nuse GuzzleHttp\\Middleware;\nuse Tether\\Client\\SyncHttpClient;\n\napp(SyncHttpClient::class)->withMiddleware(\n    Middleware::mapRequest(\n        fn ($request) => $request->withHeader(\n            'Authorization',\n            'Bearer '.config('services.tether.token'),\n        ),\n    ),\n);\n",[145,601,602,607,621,637,641,664,676,704,718,743,748,753],{"__ignoreMap":291},[295,603,604],{"class":297,"line":298},[295,605,606],{"class":559},"\u002F\u002F AppServiceProvider::boot()\n",[295,608,609,611,614,616,619],{"class":297,"line":319},[295,610,329],{"class":301},[295,612,613],{"class":332}," GuzzleHttp",[295,615,310],{"class":309},[295,617,618],{"class":332},"Middleware",[295,620,316],{"class":309},[295,622,623,625,627,629,631,633,635],{"class":297,"line":326},[295,624,329],{"class":301},[295,626,333],{"class":332},[295,628,310],{"class":309},[295,630,23],{"class":332},[295,632,310],{"class":309},[295,634,205],{"class":332},[295,636,316],{"class":309},[295,638,639],{"class":297,"line":346},[295,640,323],{"emptyLinePlaceholder":322},[295,642,643,646,649,651,654,656,659,662],{"class":297,"line":364},[295,644,645],{"class":394},"app",[295,647,648],{"class":309},"(",[295,650,205],{"class":305},[295,652,653],{"class":309},"::",[295,655,373],{"class":301},[295,657,658],{"class":309},")->",[295,660,661],{"class":394},"withMiddleware",[295,663,398],{"class":309},[295,665,666,669,671,674],{"class":297,"line":369},[295,667,668],{"class":305},"    Middleware",[295,670,653],{"class":309},[295,672,673],{"class":394},"mapRequest",[295,675,398],{"class":309},[295,677,678,681,684,687,690,693,695,697,699,702],{"class":297,"line":379},[295,679,680],{"class":372},"        fn",[295,682,683],{"class":309}," ($",[295,685,686],{"class":332},"request",[295,688,689],{"class":309},")",[295,691,692],{"class":309}," =>",[295,694,413],{"class":309},[295,696,686],{"class":332},[295,698,470],{"class":309},[295,700,701],{"class":394},"withHeader",[295,703,398],{"class":309},[295,705,706,709,713,716],{"class":297,"line":385},[295,707,708],{"class":309},"            '",[295,710,712],{"class":711},"sfazB","Authorization",[295,714,715],{"class":309},"'",[295,717,419],{"class":309},[295,719,720,722,725,728,731,733,735,738,740],{"class":297,"line":401},[295,721,708],{"class":309},[295,723,724],{"class":711},"Bearer ",[295,726,727],{"class":309},"'.",[295,729,730],{"class":394},"config",[295,732,648],{"class":309},[295,734,715],{"class":309},[295,736,737],{"class":711},"services.tether.token",[295,739,715],{"class":309},[295,741,742],{"class":309},"),\n",[295,744,745],{"class":297,"line":422},[295,746,747],{"class":309},"        ),\n",[295,749,750],{"class":297,"line":431},[295,751,752],{"class":309},"    ),\n",[295,754,755],{"class":297,"line":436},[295,756,757],{"class":309},");\n",[127,759,760],{},"Use this for bearer tokens, request signing, tenant headers, request logging, or any transport-level concern that should apply to both sync endpoints.",[134,762],{},[137,764,766],{"id":765},"client-identity","Client identity",[127,768,769,770,772,773,775],{},"The ",[145,771,231],{}," decides the ",[145,774,237],{}," included in push and pull requests. Tether resolves it in this order:",[777,778,779,785,790],"ol",{},[514,780,781,782,148],{},"A runtime callable registered with ",[145,783,784],{},"TetherClientServiceProvider::resolveClientIdUsing()",[514,786,787,148],{},[145,788,789],{},"tether-client.client_id",[514,791,792,793,148],{},"An auto-generated ULID persisted in ",[145,794,795],{},"tether_sync_state",[286,797,799],{"className":288,"code":798,"language":290,"meta":291,"style":291},"\u002F\u002F AppServiceProvider::boot()\nuse Tether\\Client\\TetherClientServiceProvider;\n\nTetherClientServiceProvider::resolveClientIdUsing(\n    fn () => 'user-'.auth()->id(),\n);\n",[145,800,801,805,822,826,837,867],{"__ignoreMap":291},[295,802,803],{"class":297,"line":298},[295,804,606],{"class":559},[295,806,807,809,811,813,815,817,820],{"class":297,"line":319},[295,808,329],{"class":301},[295,810,333],{"class":332},[295,812,310],{"class":309},[295,814,23],{"class":332},[295,816,310],{"class":309},[295,818,819],{"class":332},"TetherClientServiceProvider",[295,821,316],{"class":309},[295,823,824],{"class":297,"line":326},[295,825,323],{"emptyLinePlaceholder":322},[295,827,828,830,832,835],{"class":297,"line":346},[295,829,819],{"class":305},[295,831,653],{"class":309},[295,833,834],{"class":394},"resolveClientIdUsing",[295,836,398],{"class":309},[295,838,839,842,845,847,850,853,855,858,861,864],{"class":297,"line":364},[295,840,841],{"class":372},"    fn",[295,843,844],{"class":309}," ()",[295,846,692],{"class":309},[295,848,849],{"class":309}," '",[295,851,852],{"class":711},"user-",[295,854,727],{"class":309},[295,856,857],{"class":394},"auth",[295,859,860],{"class":309},"()->",[295,862,863],{"class":394},"id",[295,865,866],{"class":309},"(),\n",[295,868,869],{"class":297,"line":369},[295,870,757],{"class":309},[127,872,873,874,148],{},"For config-cached applications, prefer an invokable class string in ",[145,875,876],{},"tether-client.client_id_resolver",[134,878],{},[137,880,882],{"id":881},"client-mappers","Client mappers",[127,884,490,885,887],{},[145,886,218],{}," to transform data at the client boundary.",[286,889,891],{"className":288,"code":890,"language":290,"meta":291,"style":291},"\u002F\u002F AppServiceProvider::boot()\nuse App\\Models\\Task;\nuse Tether\\Client\\ClientSyncRegistry;\nuse Tether\\Core\\Mutation\\Mutation;\nuse Tether\\Core\\Sync\\Snapshot;\n\napp(ClientSyncRegistry::class)->register(\n    modelClass: Task::class,\n    payloadMapper: fn (Snapshot $snapshot) => $snapshot,\n    mutationMapper: fn (Mutation $mutation) => $mutation,\n);\n",[145,892,893,897,915,931,953,975,979,998,1015,1045,1073],{"__ignoreMap":291},[295,894,895],{"class":297,"line":298},[295,896,606],{"class":559},[295,898,899,901,903,905,908,910,913],{"class":297,"line":319},[295,900,329],{"class":301},[295,902,306],{"class":332},[295,904,310],{"class":309},[295,906,907],{"class":332},"Models",[295,909,310],{"class":309},[295,911,912],{"class":332},"Task",[295,914,316],{"class":309},[295,916,917,919,921,923,925,927,929],{"class":297,"line":326},[295,918,329],{"class":301},[295,920,333],{"class":332},[295,922,310],{"class":309},[295,924,23],{"class":332},[295,926,310],{"class":309},[295,928,218],{"class":332},[295,930,316],{"class":309},[295,932,933,935,937,939,942,944,947,949,951],{"class":297,"line":346},[295,934,329],{"class":301},[295,936,333],{"class":332},[295,938,310],{"class":309},[295,940,941],{"class":332},"Core",[295,943,310],{"class":309},[295,945,946],{"class":332},"Mutation",[295,948,310],{"class":309},[295,950,946],{"class":332},[295,952,316],{"class":309},[295,954,955,957,959,961,963,965,968,970,973],{"class":297,"line":364},[295,956,329],{"class":301},[295,958,333],{"class":332},[295,960,310],{"class":309},[295,962,941],{"class":332},[295,964,310],{"class":309},[295,966,967],{"class":332},"Sync",[295,969,310],{"class":309},[295,971,972],{"class":332},"Snapshot",[295,974,316],{"class":309},[295,976,977],{"class":297,"line":369},[295,978,323],{"emptyLinePlaceholder":322},[295,980,981,983,985,987,989,991,993,996],{"class":297,"line":379},[295,982,645],{"class":394},[295,984,648],{"class":309},[295,986,218],{"class":305},[295,988,653],{"class":309},[295,990,373],{"class":301},[295,992,658],{"class":309},[295,994,995],{"class":394},"register",[295,997,398],{"class":309},[295,999,1000,1003,1006,1009,1011,1013],{"class":297,"line":385},[295,1001,1002],{"class":305},"    modelClass",[295,1004,1005],{"class":309},":",[295,1007,1008],{"class":305}," Task",[295,1010,653],{"class":309},[295,1012,373],{"class":301},[295,1014,419],{"class":309},[295,1016,1017,1020,1022,1025,1028,1030,1032,1035,1037,1039,1041,1043],{"class":297,"line":401},[295,1018,1019],{"class":305},"    payloadMapper",[295,1021,1005],{"class":309},[295,1023,1024],{"class":372}," fn",[295,1026,1027],{"class":309}," (",[295,1029,972],{"class":305},[295,1031,413],{"class":309},[295,1033,1034],{"class":332},"snapshot",[295,1036,689],{"class":309},[295,1038,692],{"class":309},[295,1040,413],{"class":309},[295,1042,1034],{"class":332},[295,1044,419],{"class":309},[295,1046,1047,1050,1052,1054,1056,1058,1060,1063,1065,1067,1069,1071],{"class":297,"line":422},[295,1048,1049],{"class":305},"    mutationMapper",[295,1051,1005],{"class":309},[295,1053,1024],{"class":372},[295,1055,1027],{"class":309},[295,1057,946],{"class":305},[295,1059,413],{"class":309},[295,1061,1062],{"class":332},"mutation",[295,1064,689],{"class":309},[295,1066,692],{"class":309},[295,1068,413],{"class":309},[295,1070,1062],{"class":332},[295,1072,419],{"class":309},[295,1074,1075],{"class":297,"line":431},[295,1076,757],{"class":309},[127,1078,490,1079,1082,1083,1086],{},[145,1080,1081],{},"payloadMapper"," for inbound pull snapshots before they are written locally. Use ",[145,1084,1085],{},"mutationMapper"," for outbound push mutations before they are sent to the server.",[127,1088,1089,1090,1093],{},"For more examples, see the ",[1091,1092,108],"a",{"href":109}," page.",[134,1095],{},[137,1097,1099],{"id":1098},"status-and-diagnostics","Status and diagnostics",[127,1101,1102,1104,1105,1107],{},[145,1103,248],{}," and ",[145,1106,264],{}," are useful when building a status panel or debug page.",[286,1109,1111],{"className":288,"code":1110,"language":290,"meta":291,"style":291},"use Tether\\Client\\PendingSyncQueue;\nuse Tether\\Client\\SyncStateStore;\n\n$pending = app(PendingSyncQueue::class)->count();\n$failed = app(PendingSyncQueue::class)->failedCount();\n$conflicts = app(PendingSyncQueue::class)->conflictCount();\n$cursor = app(SyncStateStore::class)->get('last_sync_cursor');\n",[145,1112,1113,1129,1145,1149,1177,1203,1229],{"__ignoreMap":291},[295,1114,1115,1117,1119,1121,1123,1125,1127],{"class":297,"line":298},[295,1116,329],{"class":301},[295,1118,333],{"class":332},[295,1120,310],{"class":309},[295,1122,23],{"class":332},[295,1124,310],{"class":309},[295,1126,264],{"class":332},[295,1128,316],{"class":309},[295,1130,1131,1133,1135,1137,1139,1141,1143],{"class":297,"line":319},[295,1132,329],{"class":301},[295,1134,333],{"class":332},[295,1136,310],{"class":309},[295,1138,23],{"class":332},[295,1140,310],{"class":309},[295,1142,248],{"class":332},[295,1144,316],{"class":309},[295,1146,1147],{"class":297,"line":326},[295,1148,323],{"emptyLinePlaceholder":322},[295,1150,1151,1153,1156,1159,1162,1164,1166,1168,1170,1172,1175],{"class":297,"line":346},[295,1152,539],{"class":309},[295,1154,1155],{"class":332},"pending ",[295,1157,1158],{"class":309},"=",[295,1160,1161],{"class":394}," app",[295,1163,648],{"class":309},[295,1165,264],{"class":305},[295,1167,653],{"class":309},[295,1169,373],{"class":301},[295,1171,658],{"class":309},[295,1173,1174],{"class":394},"count",[295,1176,475],{"class":309},[295,1178,1179,1181,1184,1186,1188,1190,1192,1194,1196,1198,1201],{"class":297,"line":364},[295,1180,539],{"class":309},[295,1182,1183],{"class":332},"failed ",[295,1185,1158],{"class":309},[295,1187,1161],{"class":394},[295,1189,648],{"class":309},[295,1191,264],{"class":305},[295,1193,653],{"class":309},[295,1195,373],{"class":301},[295,1197,658],{"class":309},[295,1199,1200],{"class":394},"failedCount",[295,1202,475],{"class":309},[295,1204,1205,1207,1210,1212,1214,1216,1218,1220,1222,1224,1227],{"class":297,"line":369},[295,1206,539],{"class":309},[295,1208,1209],{"class":332},"conflicts ",[295,1211,1158],{"class":309},[295,1213,1161],{"class":394},[295,1215,648],{"class":309},[295,1217,264],{"class":305},[295,1219,653],{"class":309},[295,1221,373],{"class":301},[295,1223,658],{"class":309},[295,1225,1226],{"class":394},"conflictCount",[295,1228,475],{"class":309},[295,1230,1231,1233,1236,1238,1240,1242,1244,1246,1248,1250,1253,1255,1257,1259,1261],{"class":297,"line":379},[295,1232,539],{"class":309},[295,1234,1235],{"class":332},"cursor ",[295,1237,1158],{"class":309},[295,1239,1161],{"class":394},[295,1241,648],{"class":309},[295,1243,248],{"class":305},[295,1245,653],{"class":309},[295,1247,373],{"class":301},[295,1249,658],{"class":309},[295,1251,1252],{"class":394},"get",[295,1254,648],{"class":309},[295,1256,715],{"class":309},[295,1258,254],{"class":711},[295,1260,715],{"class":309},[295,1262,757],{"class":309},[127,1264,1265,1266,1269],{},"For most UI cases, ",[145,1267,1268],{},"SyncEngine::syncStatus()"," is the simpler API because it returns the same information as a single DTO.",[134,1271],{},[137,1273,1275],{"id":1274},"server-services","Server services",[127,1277,143,1278,148],{},[145,1279,1280],{},"tether\u002Fserver",[150,1282,1283,1293],{},[153,1284,1285],{},[156,1286,1287,1289,1291],{},[159,1288,161],{},[159,1290,164],{},[159,1292,167],{},[169,1294,1295,1308,1321,1334,1347],{},[156,1296,1297,1302,1305],{},[174,1298,1299],{},[145,1300,1301],{},"SyncRegistry",[174,1303,1304],{},"Registers syncable server models and callbacks",[174,1306,1307],{},"Main server extension point",[156,1309,1310,1315,1318],{},[174,1311,1312],{},[145,1313,1314],{},"StateSnapshotGenerator",[174,1316,1317],{},"Builds pull snapshots from registered models",[174,1319,1320],{},"Custom pull controllers",[156,1322,1323,1328,1331],{},[174,1324,1325],{},[145,1326,1327],{},"PushSyncProcessor",[174,1329,1330],{},"Applies push requests and records results",[174,1332,1333],{},"Custom push controllers",[156,1335,1336,1341,1344],{},[174,1337,1338],{},[145,1339,1340],{},"ConflictDetector",[174,1342,1343],{},"Evaluates timestamp conflicts and resolvers",[174,1345,1346],{},"Internal unless replacing conflict behaviour",[156,1348,1349,1354,1357],{},[174,1350,1351],{},[145,1352,1353],{},"MutationApplicator",[174,1355,1356],{},"Applies create\u002Fupdate\u002Fdelete mutations to Eloquent",[174,1358,1359],{},"Internal unless replacing mutation application",[272,1361,1363],{"id":1362},"registering-server-models","Registering server models",[127,1365,1366,1368,1369,1372],{},[145,1367,1301],{}," is the primary server-side extension point. Use it when you want explicit registration instead of the server ",[145,1370,1371],{},"Syncable"," trait, or when you want to centralise model sync rules in a service provider.",[286,1374,1376],{"className":288,"code":1375,"language":290,"meta":291,"style":291},"\u002F\u002F AppServiceProvider::boot()\nuse App\\Models\\Task;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Http\\Request;\nuse Tether\\Core\\Conflict\\ConflictResolution;\nuse Tether\\Core\\Mutation\\Mutation;\nuse Tether\\Core\\Sync\\Snapshot;\nuse Tether\\Server\\SyncRegistry;\n\napp(SyncRegistry::class)->register(\n    modelClass: Task::class,\n    scope: fn (Builder $query, string $clientId, Request $request) => $query\n        ->where('user_id', $request->user()->id),\n    pullSnapshotMapper: fn (Snapshot $snapshot, Task $row) => $snapshot,\n    pushMutationMapper: fn (Mutation $mutation, Request $request) => $mutation,\n    conflictResolver: fn (Mutation $mutation, Task $record, Request $request) => ConflictResolution::reject(),\n);\n",[145,1377,1378,1382,1398,1422,1440,1462,1482,1502,1518,1522,1540,1554,1600,1634,1670,1705,1753],{"__ignoreMap":291},[295,1379,1380],{"class":297,"line":298},[295,1381,606],{"class":559},[295,1383,1384,1386,1388,1390,1392,1394,1396],{"class":297,"line":319},[295,1385,329],{"class":301},[295,1387,306],{"class":332},[295,1389,310],{"class":309},[295,1391,907],{"class":332},[295,1393,310],{"class":309},[295,1395,912],{"class":332},[295,1397,316],{"class":309},[295,1399,1400,1402,1405,1407,1410,1412,1415,1417,1420],{"class":297,"line":326},[295,1401,329],{"class":301},[295,1403,1404],{"class":332}," Illuminate",[295,1406,310],{"class":309},[295,1408,1409],{"class":332},"Database",[295,1411,310],{"class":309},[295,1413,1414],{"class":332},"Eloquent",[295,1416,310],{"class":309},[295,1418,1419],{"class":332},"Builder",[295,1421,316],{"class":309},[295,1423,1424,1426,1428,1430,1433,1435,1438],{"class":297,"line":346},[295,1425,329],{"class":301},[295,1427,1404],{"class":332},[295,1429,310],{"class":309},[295,1431,1432],{"class":332},"Http",[295,1434,310],{"class":309},[295,1436,1437],{"class":332},"Request",[295,1439,316],{"class":309},[295,1441,1442,1444,1446,1448,1450,1452,1455,1457,1460],{"class":297,"line":364},[295,1443,329],{"class":301},[295,1445,333],{"class":332},[295,1447,310],{"class":309},[295,1449,941],{"class":332},[295,1451,310],{"class":309},[295,1453,1454],{"class":332},"Conflict",[295,1456,310],{"class":309},[295,1458,1459],{"class":332},"ConflictResolution",[295,1461,316],{"class":309},[295,1463,1464,1466,1468,1470,1472,1474,1476,1478,1480],{"class":297,"line":369},[295,1465,329],{"class":301},[295,1467,333],{"class":332},[295,1469,310],{"class":309},[295,1471,941],{"class":332},[295,1473,310],{"class":309},[295,1475,946],{"class":332},[295,1477,310],{"class":309},[295,1479,946],{"class":332},[295,1481,316],{"class":309},[295,1483,1484,1486,1488,1490,1492,1494,1496,1498,1500],{"class":297,"line":379},[295,1485,329],{"class":301},[295,1487,333],{"class":332},[295,1489,310],{"class":309},[295,1491,941],{"class":332},[295,1493,310],{"class":309},[295,1495,967],{"class":332},[295,1497,310],{"class":309},[295,1499,972],{"class":332},[295,1501,316],{"class":309},[295,1503,1504,1506,1508,1510,1512,1514,1516],{"class":297,"line":385},[295,1505,329],{"class":301},[295,1507,333],{"class":332},[295,1509,310],{"class":309},[295,1511,46],{"class":332},[295,1513,310],{"class":309},[295,1515,1301],{"class":332},[295,1517,316],{"class":309},[295,1519,1520],{"class":297,"line":401},[295,1521,323],{"emptyLinePlaceholder":322},[295,1523,1524,1526,1528,1530,1532,1534,1536,1538],{"class":297,"line":422},[295,1525,645],{"class":394},[295,1527,648],{"class":309},[295,1529,1301],{"class":305},[295,1531,653],{"class":309},[295,1533,373],{"class":301},[295,1535,658],{"class":309},[295,1537,995],{"class":394},[295,1539,398],{"class":309},[295,1541,1542,1544,1546,1548,1550,1552],{"class":297,"line":431},[295,1543,1002],{"class":305},[295,1545,1005],{"class":309},[295,1547,1008],{"class":305},[295,1549,653],{"class":309},[295,1551,373],{"class":301},[295,1553,419],{"class":309},[295,1555,1556,1559,1561,1563,1565,1567,1569,1572,1574,1577,1579,1582,1584,1587,1589,1591,1593,1595,1597],{"class":297,"line":436},[295,1557,1558],{"class":305},"    scope",[295,1560,1005],{"class":309},[295,1562,1024],{"class":372},[295,1564,1027],{"class":309},[295,1566,1419],{"class":305},[295,1568,413],{"class":309},[295,1570,1571],{"class":332},"query",[295,1573,579],{"class":309},[295,1575,1576],{"class":301}," string",[295,1578,413],{"class":309},[295,1580,1581],{"class":332},"clientId",[295,1583,579],{"class":309},[295,1585,1586],{"class":305}," Request",[295,1588,413],{"class":309},[295,1590,686],{"class":332},[295,1592,689],{"class":309},[295,1594,692],{"class":309},[295,1596,413],{"class":309},[295,1598,1599],{"class":332},"query\n",[295,1601,1602,1605,1608,1610,1612,1615,1617,1619,1621,1623,1625,1628,1630,1632],{"class":297,"line":452},[295,1603,1604],{"class":309},"        ->",[295,1606,1607],{"class":394},"where",[295,1609,648],{"class":309},[295,1611,715],{"class":309},[295,1613,1614],{"class":711},"user_id",[295,1616,715],{"class":309},[295,1618,579],{"class":309},[295,1620,413],{"class":309},[295,1622,686],{"class":332},[295,1624,470],{"class":309},[295,1626,1627],{"class":394},"user",[295,1629,860],{"class":309},[295,1631,863],{"class":332},[295,1633,742],{"class":309},[295,1635,1636,1639,1641,1643,1645,1647,1649,1651,1653,1655,1657,1660,1662,1664,1666,1668],{"class":297,"line":458},[295,1637,1638],{"class":305},"    pullSnapshotMapper",[295,1640,1005],{"class":309},[295,1642,1024],{"class":372},[295,1644,1027],{"class":309},[295,1646,972],{"class":305},[295,1648,413],{"class":309},[295,1650,1034],{"class":332},[295,1652,579],{"class":309},[295,1654,1008],{"class":305},[295,1656,413],{"class":309},[295,1658,1659],{"class":332},"row",[295,1661,689],{"class":309},[295,1663,692],{"class":309},[295,1665,413],{"class":309},[295,1667,1034],{"class":332},[295,1669,419],{"class":309},[295,1671,1672,1675,1677,1679,1681,1683,1685,1687,1689,1691,1693,1695,1697,1699,1701,1703],{"class":297,"line":478},[295,1673,1674],{"class":305},"    pushMutationMapper",[295,1676,1005],{"class":309},[295,1678,1024],{"class":372},[295,1680,1027],{"class":309},[295,1682,946],{"class":305},[295,1684,413],{"class":309},[295,1686,1062],{"class":332},[295,1688,579],{"class":309},[295,1690,1586],{"class":305},[295,1692,413],{"class":309},[295,1694,686],{"class":332},[295,1696,689],{"class":309},[295,1698,692],{"class":309},[295,1700,413],{"class":309},[295,1702,1062],{"class":332},[295,1704,419],{"class":309},[295,1706,1707,1710,1712,1714,1716,1718,1720,1722,1724,1726,1728,1731,1733,1735,1737,1739,1741,1743,1746,1748,1751],{"class":297,"line":484},[295,1708,1709],{"class":305},"    conflictResolver",[295,1711,1005],{"class":309},[295,1713,1024],{"class":372},[295,1715,1027],{"class":309},[295,1717,946],{"class":305},[295,1719,413],{"class":309},[295,1721,1062],{"class":332},[295,1723,579],{"class":309},[295,1725,1008],{"class":305},[295,1727,413],{"class":309},[295,1729,1730],{"class":332},"record",[295,1732,579],{"class":309},[295,1734,1586],{"class":305},[295,1736,413],{"class":309},[295,1738,686],{"class":332},[295,1740,689],{"class":309},[295,1742,692],{"class":309},[295,1744,1745],{"class":305}," ConflictResolution",[295,1747,653],{"class":309},[295,1749,1750],{"class":394},"reject",[295,1752,866],{"class":309},[295,1754,1756],{"class":297,"line":1755},17,[295,1757,757],{"class":309},[127,1759,1760,1761,1763,1764,1767],{},"If a model also uses the server ",[145,1762,1371],{}," trait, explicit ",[145,1765,1766],{},"SyncRegistry::register()"," calls take precedence over trait auto-registration.",[134,1769],{},[137,1771,1773],{"id":1772},"custom-sync-controllers","Custom sync controllers",[127,1775,1776,1777,1104,1780,1783],{},"The default server package registers ",[145,1778,1779],{},"POST \u002Ftether\u002Fpush",[145,1781,1782],{},"POST \u002Ftether\u002Fpull",". If you disable route registration, you can build your own controller and inject the same services the package controller uses.",[286,1785,1787],{"className":288,"code":1786,"language":290,"meta":291,"style":291},"namespace App\\Http\\Controllers;\n\nuse Illuminate\\Http\\Request;\nuse Tether\\Core\\Sync\\PullRequest;\nuse Tether\\Core\\Sync\\PushRequest;\nuse Tether\\Server\\PushSyncProcessor;\nuse Tether\\Server\\StateSnapshotGenerator;\n\nclass CustomTetherController\n{\n    public function push(Request $request, PushSyncProcessor $processor)\n    {\n        return response()->json(\n            $processor->process(PushRequest::fromArray($request->all()), $request)->toArray(),\n        );\n    }\n\n    public function pull(Request $request, StateSnapshotGenerator $snapshots)\n    {\n        return response()->json(\n            $snapshots->since(PullRequest::fromArray($request->all()), $request)->toArray(),\n        );\n    }\n}\n",[145,1788,1789,1806,1810,1826,1847,1868,1884,1900,1904,1911,1915,1945,1949,1963,2007,2012,2016,2020,2050,2055,2068,2108,2113,2118],{"__ignoreMap":291},[295,1790,1791,1793,1795,1797,1799,1801,1804],{"class":297,"line":298},[295,1792,302],{"class":301},[295,1794,306],{"class":305},[295,1796,310],{"class":309},[295,1798,1432],{"class":305},[295,1800,310],{"class":309},[295,1802,1803],{"class":305},"Controllers",[295,1805,316],{"class":309},[295,1807,1808],{"class":297,"line":319},[295,1809,323],{"emptyLinePlaceholder":322},[295,1811,1812,1814,1816,1818,1820,1822,1824],{"class":297,"line":326},[295,1813,329],{"class":301},[295,1815,1404],{"class":332},[295,1817,310],{"class":309},[295,1819,1432],{"class":332},[295,1821,310],{"class":309},[295,1823,1437],{"class":332},[295,1825,316],{"class":309},[295,1827,1828,1830,1832,1834,1836,1838,1840,1842,1845],{"class":297,"line":346},[295,1829,329],{"class":301},[295,1831,333],{"class":332},[295,1833,310],{"class":309},[295,1835,941],{"class":332},[295,1837,310],{"class":309},[295,1839,967],{"class":332},[295,1841,310],{"class":309},[295,1843,1844],{"class":332},"PullRequest",[295,1846,316],{"class":309},[295,1848,1849,1851,1853,1855,1857,1859,1861,1863,1866],{"class":297,"line":364},[295,1850,329],{"class":301},[295,1852,333],{"class":332},[295,1854,310],{"class":309},[295,1856,941],{"class":332},[295,1858,310],{"class":309},[295,1860,967],{"class":332},[295,1862,310],{"class":309},[295,1864,1865],{"class":332},"PushRequest",[295,1867,316],{"class":309},[295,1869,1870,1872,1874,1876,1878,1880,1882],{"class":297,"line":369},[295,1871,329],{"class":301},[295,1873,333],{"class":332},[295,1875,310],{"class":309},[295,1877,46],{"class":332},[295,1879,310],{"class":309},[295,1881,1327],{"class":332},[295,1883,316],{"class":309},[295,1885,1886,1888,1890,1892,1894,1896,1898],{"class":297,"line":379},[295,1887,329],{"class":301},[295,1889,333],{"class":332},[295,1891,310],{"class":309},[295,1893,46],{"class":332},[295,1895,310],{"class":309},[295,1897,1314],{"class":332},[295,1899,316],{"class":309},[295,1901,1902],{"class":297,"line":385},[295,1903,323],{"emptyLinePlaceholder":322},[295,1905,1906,1908],{"class":297,"line":401},[295,1907,373],{"class":372},[295,1909,1910],{"class":305}," CustomTetherController\n",[295,1912,1913],{"class":297,"line":422},[295,1914,382],{"class":309},[295,1916,1917,1919,1921,1924,1926,1928,1930,1932,1934,1937,1939,1942],{"class":297,"line":431},[295,1918,388],{"class":372},[295,1920,391],{"class":372},[295,1922,1923],{"class":394}," push",[295,1925,648],{"class":309},[295,1927,1437],{"class":305},[295,1929,413],{"class":309},[295,1931,686],{"class":332},[295,1933,579],{"class":309},[295,1935,1936],{"class":305}," PushSyncProcessor",[295,1938,413],{"class":309},[295,1940,1941],{"class":332},"processor",[295,1943,1944],{"class":309},")\n",[295,1946,1947],{"class":297,"line":436},[295,1948,455],{"class":309},[295,1950,1951,1953,1956,1958,1961],{"class":297,"line":452},[295,1952,462],{"class":461},[295,1954,1955],{"class":394}," response",[295,1957,860],{"class":309},[295,1959,1960],{"class":394},"json",[295,1962,398],{"class":309},[295,1964,1965,1968,1970,1972,1975,1977,1979,1981,1984,1986,1988,1990,1993,1996,1998,2000,2002,2005],{"class":297,"line":458},[295,1966,1967],{"class":309},"            $",[295,1969,1941],{"class":332},[295,1971,470],{"class":309},[295,1973,1974],{"class":394},"process",[295,1976,648],{"class":309},[295,1978,1865],{"class":305},[295,1980,653],{"class":309},[295,1982,1983],{"class":394},"fromArray",[295,1985,550],{"class":309},[295,1987,686],{"class":332},[295,1989,470],{"class":309},[295,1991,1992],{"class":394},"all",[295,1994,1995],{"class":309},"()),",[295,1997,413],{"class":309},[295,1999,686],{"class":332},[295,2001,658],{"class":309},[295,2003,2004],{"class":394},"toArray",[295,2006,866],{"class":309},[295,2008,2009],{"class":297,"line":478},[295,2010,2011],{"class":309},"        );\n",[295,2013,2014],{"class":297,"line":484},[295,2015,481],{"class":309},[295,2017,2018],{"class":297,"line":1755},[295,2019,323],{"emptyLinePlaceholder":322},[295,2021,2023,2025,2027,2030,2032,2034,2036,2038,2040,2043,2045,2048],{"class":297,"line":2022},18,[295,2024,388],{"class":372},[295,2026,391],{"class":372},[295,2028,2029],{"class":394}," pull",[295,2031,648],{"class":309},[295,2033,1437],{"class":305},[295,2035,413],{"class":309},[295,2037,686],{"class":332},[295,2039,579],{"class":309},[295,2041,2042],{"class":305}," StateSnapshotGenerator",[295,2044,413],{"class":309},[295,2046,2047],{"class":332},"snapshots",[295,2049,1944],{"class":309},[295,2051,2053],{"class":297,"line":2052},19,[295,2054,455],{"class":309},[295,2056,2058,2060,2062,2064,2066],{"class":297,"line":2057},20,[295,2059,462],{"class":461},[295,2061,1955],{"class":394},[295,2063,860],{"class":309},[295,2065,1960],{"class":394},[295,2067,398],{"class":309},[295,2069,2071,2073,2075,2077,2080,2082,2084,2086,2088,2090,2092,2094,2096,2098,2100,2102,2104,2106],{"class":297,"line":2070},21,[295,2072,1967],{"class":309},[295,2074,2047],{"class":332},[295,2076,470],{"class":309},[295,2078,2079],{"class":394},"since",[295,2081,648],{"class":309},[295,2083,1844],{"class":305},[295,2085,653],{"class":309},[295,2087,1983],{"class":394},[295,2089,550],{"class":309},[295,2091,686],{"class":332},[295,2093,470],{"class":309},[295,2095,1992],{"class":394},[295,2097,1995],{"class":309},[295,2099,413],{"class":309},[295,2101,686],{"class":332},[295,2103,658],{"class":309},[295,2105,2004],{"class":394},[295,2107,866],{"class":309},[295,2109,2111],{"class":297,"line":2110},22,[295,2112,2011],{"class":309},[295,2114,2116],{"class":297,"line":2115},23,[295,2117,481],{"class":309},[295,2119,2121],{"class":297,"line":2120},24,[295,2122,487],{"class":309},[127,2124,2125],{},"This is useful when you need a different route shape, additional authorization, tenant setup, or custom request logging while keeping Tether's core push and pull behaviour.",[134,2127],{},[137,2129,2131],{"id":2130},"replacing-services","Replacing services",[127,2133,2134],{},"Because Tether uses Laravel's container, you can replace services in your application service provider. Do this sparingly: replacing processors, applicators, or detectors can change sync semantics.",[286,2136,2138],{"className":288,"code":2137,"language":290,"meta":291,"style":291},"\u002F\u002F AppServiceProvider::register()\nuse Tether\\Client\\SyncHttpClient;\n\n$this->app->extend(SyncHttpClient::class, function (SyncHttpClient $client) {\n    \u002F\u002F Prefer withMiddleware() for transport changes.\n    return $client;\n});\n",[145,2139,2140,2145,2161,2165,2203,2208,2219],{"__ignoreMap":291},[295,2141,2142],{"class":297,"line":298},[295,2143,2144],{"class":559},"\u002F\u002F AppServiceProvider::register()\n",[295,2146,2147,2149,2151,2153,2155,2157,2159],{"class":297,"line":319},[295,2148,329],{"class":301},[295,2150,333],{"class":332},[295,2152,310],{"class":309},[295,2154,23],{"class":332},[295,2156,310],{"class":309},[295,2158,205],{"class":332},[295,2160,316],{"class":309},[295,2162,2163],{"class":297,"line":326},[295,2164,323],{"emptyLinePlaceholder":322},[295,2166,2167,2170,2172,2174,2177,2179,2181,2183,2185,2187,2189,2191,2193,2195,2198,2200],{"class":297,"line":346},[295,2168,2169],{"class":309},"$this->",[295,2171,645],{"class":332},[295,2173,470],{"class":309},[295,2175,2176],{"class":394},"extend",[295,2178,648],{"class":309},[295,2180,205],{"class":305},[295,2182,653],{"class":309},[295,2184,373],{"class":301},[295,2186,579],{"class":309},[295,2188,391],{"class":372},[295,2190,1027],{"class":309},[295,2192,205],{"class":305},[295,2194,413],{"class":309},[295,2196,2197],{"class":332},"client",[295,2199,689],{"class":309},[295,2201,2202],{"class":309}," {\n",[295,2204,2205],{"class":297,"line":364},[295,2206,2207],{"class":559},"    \u002F\u002F Prefer withMiddleware() for transport changes.\n",[295,2209,2210,2213,2215,2217],{"class":297,"line":369},[295,2211,2212],{"class":461},"    return",[295,2214,413],{"class":309},[295,2216,2197],{"class":332},[295,2218,316],{"class":309},[295,2220,2221],{"class":297,"line":379},[295,2222,2223],{"class":309},"});\n",[127,2225,2226],{},"Prefer the built-in extension points first:",[511,2228,2229,2235,2242,2247],{},[514,2230,490,2231,2234],{},[145,2232,2233],{},"SyncHttpClient::withMiddleware()"," for transport concerns.",[514,2236,490,2237,1104,2239,2241],{},[145,2238,218],{},[145,2240,1301],{}," for payload transformation.",[514,2243,490,2244,2246],{},[145,2245,1301],{}," conflict resolvers for per-model conflict behaviour.",[514,2248,2249,2250,1104,2252,2254],{},"Use custom controllers with ",[145,2251,1327],{},[145,2253,1314],{}," for route-level changes.",[2256,2257,2258],"style",{},"html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html .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 .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 pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}",{"title":291,"searchDepth":298,"depth":319,"links":2260},[2261,2264,2265,2266,2267,2268,2271,2272],{"id":139,"depth":319,"text":140,"children":2262},[2263],{"id":274,"depth":326,"text":275},{"id":501,"depth":319,"text":205},{"id":765,"depth":319,"text":766},{"id":881,"depth":319,"text":882},{"id":1098,"depth":319,"text":1099},{"id":1274,"depth":319,"text":1275,"children":2269},[2270],{"id":1362,"depth":326,"text":1363},{"id":1772,"depth":319,"text":1773},{"id":2130,"depth":319,"text":2131},"Inject and extend Tether services through Laravel's container, including sync engines, registries, HTTP clients, snapshot applicators, and queues.","md",null,{},{"title":2278,"description":2273},"Laravel Tether Service Container - Extend the Sync Engine","y5RWgfV8htrP9jSHXjVI9tf_KlLABZWcwwgfv-0Wh_w",[2281,2283],{"title":90,"path":91,"stem":92,"description":2282,"children":-1},"Explore tether\u002Fpro-server features: sync observability, mutation inspection, conflict debugging, replay previews, live replay, and health telemetry.",{"title":104,"path":105,"stem":106,"description":2284,"children":-1},"Learn how Laravel Tether detects offline sync conflicts, applies server-wins defaults, returns server state, and supports custom conflict resolvers.",1780481015189]