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