[{"data":1,"prerenderedAt":603},["ShallowReactive",2],{"navigation_docs":3,"-applications-coordinator":72,"-applications-coordinator-surround":598},[4,20,41],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":6},"Overview",false,"\u002Fgetting-started","1.getting-started",[10,15],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F2.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Adding Documentation","\u002Fgetting-started\u002Fadding-documentation","1.getting-started\u002F3.adding-documentation","i-lucide-file-plus",{"title":21,"icon":22,"path":23,"stem":24,"children":25,"page":6},"Applications","i-lucide-layout-grid","\u002Fapplications","2.applications",[26,31,36],{"title":27,"path":28,"stem":29,"icon":30},"Web","\u002Fapplications\u002Fweb","2.applications\u002F1.web","i-lucide-globe-code",{"title":32,"path":33,"stem":34,"icon":35},"Coordinator","\u002Fapplications\u002Fcoordinator","2.applications\u002F2.coordinator","i-lucide-clock",{"title":37,"path":38,"stem":39,"icon":40},"Profile Chrome Extension","\u002Fapplications\u002Fprofile-recorder","2.applications\u002F3.profile-recorder","i-lucide-mouse-pointer-click",{"title":42,"icon":43,"path":44,"stem":45,"children":46,"page":6},"Packages","i-lucide-package","\u002Fpackages","3.packages",[47,52,57,62,67],{"title":48,"path":49,"stem":50,"icon":51},"Profile Runner","\u002Fpackages\u002Fprofile-runner","3.packages\u002F1.profile-runner","i-lucide-scan-search",{"title":53,"path":54,"stem":55,"icon":56},"Schema","\u002Fpackages\u002Fschema","3.packages\u002F2.schema","i-lucide-file-json",{"title":58,"path":59,"stem":60,"icon":61},"UI","\u002Fpackages\u002Fui","3.packages\u002F2.ui","i-lucide-layout-dashboard",{"title":63,"path":64,"stem":65,"icon":66},"Coordinator SDK","\u002Fpackages\u002Fcoordinator-sdk","3.packages\u002F3.coordinator-sdk","i-lucide-plug-zap",{"title":68,"path":69,"stem":70,"icon":71},"Client","\u002Fpackages\u002Fclient","3.packages\u002F4.client","i-lucide-plug",{"id":73,"title":32,"body":74,"description":591,"extension":592,"links":593,"meta":594,"navigation":595,"path":33,"seo":596,"stem":34,"__hash__":597},"docs\u002F2.applications\u002F2.coordinator.md",{"type":75,"value":76,"toc":586},"minimark",[77,89,100,105,112,116,123,272,314,318,327,573,582],[78,79,80,84,85,88],"p",{},[81,82,83],"code",{},"@scrape-admin\u002Fcoordinator"," is a lightweight, multi-tenant service for scheduling webhook callbacks on a cron\nexpression and retrying them reliably, rather than relying on each client (such as ",[86,87,27],"a",{"href":28},") to\nimplement its own scheduling and retry logic.",[78,90,91,92,95,96,99],{},"It integrates with Scrape Admin's web app: a collection entry's ",[81,93,94],{},"destinations"," can be scheduled with the coordinator so\nthe entry is refreshed on its ",[81,97,98],{},"cronExpression",", with the coordinator calling back into the web app (or any other\nclient) to run the actual work.",[101,102,104],"h2",{"id":103},"authentication","Authentication",[78,106,107,108,111],{},"Every request must send an ",[81,109,110],{},"x-tenant-id"," header identifying the caller. All scheduled webhooks and runs are scoped to\nthat tenant — a tenant can only read or modify its own data.",[101,113,115],{"id":114},"api","API",[78,117,118,119,122],{},"All endpoints are under ",[81,120,121],{},"\u002Fapi\u002Fv1\u002Fwebhooks\u002Fscheduled",":",[124,125,126,142],"table",{},[127,128,129],"thead",{},[130,131,132,136,139],"tr",{},[133,134,135],"th",{},"Method",[133,137,138],{},"Path",[133,140,141],{},"Description",[143,144,145,161,175,189,203,217,231,244,258],"tbody",{},[130,146,147,153,158],{},[148,149,150],"td",{},[81,151,152],{},"GET",[148,154,155],{},[81,156,157],{},"\u002F",[148,159,160],{},"List scheduled webhooks for the tenant.",[130,162,163,168,172],{},[148,164,165],{},[81,166,167],{},"POST",[148,169,170],{},[81,171,157],{},[148,173,174],{},"Create a scheduled webhook.",[130,176,177,181,186],{},[148,178,179],{},[81,180,152],{},[148,182,183],{},[81,184,185],{},"\u002F:id",[148,187,188],{},"Get a scheduled webhook.",[130,190,191,196,200],{},[148,192,193],{},[81,194,195],{},"PATCH",[148,197,198],{},[81,199,185],{},[148,201,202],{},"Update a scheduled webhook (reschedules it).",[130,204,205,210,214],{},[148,206,207],{},[81,208,209],{},"DELETE",[148,211,212],{},[81,213,185],{},[148,215,216],{},"Mark a scheduled webhook for deletion.",[130,218,219,223,228],{},[148,220,221],{},[81,222,152],{},[148,224,225],{},[81,226,227],{},"\u002F:id\u002Fruns",[148,229,230],{},"List runs for a scheduled webhook.",[130,232,233,237,241],{},[148,234,235],{},[81,236,167],{},[148,238,239],{},[81,240,227],{},[148,242,243],{},"Manually trigger a run, outside its cron schedule.",[130,245,246,250,255],{},[148,247,248],{},[81,249,152],{},[148,251,252],{},[81,253,254],{},"\u002F:id\u002Fruns\u002F:runId",[148,256,257],{},"Get a single run.",[130,259,260,264,269],{},[148,261,262],{},[81,263,167],{},[148,265,266],{},[81,267,268],{},"\u002Frebuild",[148,270,271],{},"Rebuild all of the tenant's schedules (for example, after a deploy).",[78,273,274,275,277,278,280,281,284,285,288,289,291,292,295,296,299,300,299,303,299,306,309,310,313],{},"A scheduled webhook has one or more ",[81,276,94],{}," (see ",[86,279,53],{"href":54},"'s ",[81,282,283],{},"zWebhookDestination","), an\noptional ",[81,286,287],{},"payload",", and a ",[81,290,98],{},". Each run creates one attempt per destination and retries failed attempts\nup to ",[81,293,294],{},"maxAttempts"," times with the statuses ",[81,297,298],{},"pending",", ",[81,301,302],{},"running",[81,304,305],{},"retrying",[81,307,308],{},"completed",", and ",[81,311,312],{},"failed",".",[101,315,317],{"id":316},"typed-client","Typed client",[78,319,320,323,324,326],{},[81,321,322],{},"@scrape-admin\u002Fcoordinator-sdk"," wraps the API in a typed client for use from other apps — see\n",[86,325,63],{"href":64}," for the full usage guide:",[328,329,334],"pre",{"className":330,"code":331,"language":332,"meta":333,"style":333},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { createCoordinatorClient } from '@scrape-admin\u002Fcoordinator-sdk'\n\nconst coordinator = createCoordinatorClient({\n  baseUrl: 'http:\u002F\u002Flocalhost:3001',\n  tenantId: 'my-tenant',\n})\n\nconst webhook = await coordinator.scheduledWebhooks.create({\n  destinations: [{ url: 'https:\u002F\u002Fexample.com\u002Fhooks\u002Fscrape-complete' }],\n  cronExpression: '*\u002F5 * * * *',\n})\n\nawait coordinator.scheduledWebhooks.runs(webhook.id).trigger()\n","ts","",[81,335,336,368,375,397,417,434,443,448,478,511,528,535,540],{"__ignoreMap":333},[337,338,341,345,349,353,356,359,362,365],"span",{"class":339,"line":340},"line",1,[337,342,344],{"class":343},"s7zQu","import",[337,346,348],{"class":347},"sMK4o"," {",[337,350,352],{"class":351},"sTEyZ"," createCoordinatorClient",[337,354,355],{"class":347}," }",[337,357,358],{"class":343}," from",[337,360,361],{"class":347}," '",[337,363,322],{"class":364},"sfazB",[337,366,367],{"class":347},"'\n",[337,369,371],{"class":339,"line":370},2,[337,372,374],{"emptyLinePlaceholder":373},true,"\n",[337,376,378,382,385,388,391,394],{"class":339,"line":377},3,[337,379,381],{"class":380},"spNyl","const",[337,383,384],{"class":351}," coordinator ",[337,386,387],{"class":347},"=",[337,389,352],{"class":390},"s2Zo4",[337,392,393],{"class":351},"(",[337,395,396],{"class":347},"{\n",[337,398,400,404,406,408,411,414],{"class":339,"line":399},4,[337,401,403],{"class":402},"swJcz","  baseUrl",[337,405,122],{"class":347},[337,407,361],{"class":347},[337,409,410],{"class":364},"http:\u002F\u002Flocalhost:3001",[337,412,413],{"class":347},"'",[337,415,416],{"class":347},",\n",[337,418,420,423,425,427,430,432],{"class":339,"line":419},5,[337,421,422],{"class":402},"  tenantId",[337,424,122],{"class":347},[337,426,361],{"class":347},[337,428,429],{"class":364},"my-tenant",[337,431,413],{"class":347},[337,433,416],{"class":347},[337,435,437,440],{"class":339,"line":436},6,[337,438,439],{"class":347},"}",[337,441,442],{"class":351},")\n",[337,444,446],{"class":339,"line":445},7,[337,447,374],{"emptyLinePlaceholder":373},[337,449,451,453,456,458,461,464,466,469,471,474,476],{"class":339,"line":450},8,[337,452,381],{"class":380},[337,454,455],{"class":351}," webhook ",[337,457,387],{"class":347},[337,459,460],{"class":343}," await",[337,462,463],{"class":351}," coordinator",[337,465,313],{"class":347},[337,467,468],{"class":351},"scheduledWebhooks",[337,470,313],{"class":347},[337,472,473],{"class":390},"create",[337,475,393],{"class":351},[337,477,396],{"class":347},[337,479,481,484,486,489,492,495,497,499,502,504,506,509],{"class":339,"line":480},9,[337,482,483],{"class":402},"  destinations",[337,485,122],{"class":347},[337,487,488],{"class":351}," [",[337,490,491],{"class":347},"{",[337,493,494],{"class":402}," url",[337,496,122],{"class":347},[337,498,361],{"class":347},[337,500,501],{"class":364},"https:\u002F\u002Fexample.com\u002Fhooks\u002Fscrape-complete",[337,503,413],{"class":347},[337,505,355],{"class":347},[337,507,508],{"class":351},"]",[337,510,416],{"class":347},[337,512,514,517,519,521,524,526],{"class":339,"line":513},10,[337,515,516],{"class":402},"  cronExpression",[337,518,122],{"class":347},[337,520,361],{"class":347},[337,522,523],{"class":364},"*\u002F5 * * * *",[337,525,413],{"class":347},[337,527,416],{"class":347},[337,529,531,533],{"class":339,"line":530},11,[337,532,439],{"class":347},[337,534,442],{"class":351},[337,536,538],{"class":339,"line":537},12,[337,539,374],{"emptyLinePlaceholder":373},[337,541,543,546,548,550,552,554,557,560,562,565,567,570],{"class":339,"line":542},13,[337,544,545],{"class":343},"await",[337,547,463],{"class":351},[337,549,313],{"class":347},[337,551,468],{"class":351},[337,553,313],{"class":347},[337,555,556],{"class":390},"runs",[337,558,559],{"class":351},"(webhook",[337,561,313],{"class":347},[337,563,564],{"class":351},"id)",[337,566,313],{"class":347},[337,568,569],{"class":390},"trigger",[337,571,572],{"class":351},"()\n",[78,574,575,576,313],{},"For running the app locally or with Docker, see the\n",[86,577,581],{"href":578,"rel":579},"https:\u002F\u002Fgithub.com\u002Fhareland\u002Fscrape-admin-standalone\u002Fblob\u002Fmain\u002Fapps\u002Fcoordinator\u002FREADME.md",[580],"nofollow","coordinator README",[583,584,585],"style",{},"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 .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 .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}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);}",{"title":333,"searchDepth":370,"depth":370,"links":587},[588,589,590],{"id":103,"depth":370,"text":104},{"id":114,"depth":370,"text":115},{"id":316,"depth":370,"text":317},"Schedules and coordinates reliable webhook callbacks.","md",null,{},{"icon":35},{"title":32,"description":591},"kKJTUPI7ppFoRipIV9ZTWUUikKOwNPkKe-f10i0Ei_0",[599,601],{"title":27,"path":28,"stem":29,"description":600,"icon":30,"children":-1},"The web application for managing scraping tasks, profiles, and results.",{"title":37,"path":38,"stem":39,"description":602,"icon":40,"children":-1},"Profile Recorder is a Chrome extension for recording scraping profiles. It allows you to interact with a web page and capture the elements, actions, and transformations needed to extract data.",1790949708940]