@vercel/board 0.26.0 → 0.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/{a2-Qzj0kCWU.mjs → a2-C4A4vr0M.mjs} +4 -4
  2. package/dist/{attempts-CLG840Oj.mjs → attempts-HXcskN1w.mjs} +1 -11
  3. package/dist/backend-a2.mjs +1 -1
  4. package/dist/{backend-http-BB0Gld6Q.mjs → backend-http-3IxGe13a.mjs} +18 -4
  5. package/dist/{backend-http-F0W6e36G.mjs → backend-http-CQWTNzym.mjs} +1 -1
  6. package/dist/backend-http.mjs +1 -1
  7. package/dist/backend-http.node.mjs +1 -1
  8. package/dist/{backend-vercel-DUWIcFi9.mjs → backend-vercel-BPyPi8Cv.mjs} +8 -3
  9. package/dist/{backend-vercel-CtB46vMQ.mjs → backend-vercel-l5465vyw.mjs} +3 -3
  10. package/dist/backend-vercel.mjs +1 -1
  11. package/dist/backend-vercel.node.mjs +1 -1
  12. package/dist/cli-embedded.mjs +1 -1
  13. package/dist/cli.mjs +2 -2
  14. package/dist/{engine-ROa7-IQY.mjs → engine-Bfe6pcXb.mjs} +2 -2
  15. package/dist/{exports-NFjBgIT2.mjs → exports-B-AeCbYw.mjs} +2 -2
  16. package/dist/{index.default-Boe7x-mK.mjs → index.default-CfAjbQrU.mjs} +1 -1
  17. package/dist/index.mjs +3 -3
  18. package/dist/index.node.mjs +1 -1
  19. package/dist/inspect/app.js +29 -29
  20. package/dist/inspect/engine.js +5 -5
  21. package/dist/{main-BuahKR16.mjs → main-DGyQ4gje.mjs} +9 -4
  22. package/dist/{serve-BbHEQk_Y.mjs → serve-BDLJebk7.mjs} +2 -2
  23. package/dist/{server-Bphio_82.mjs → server-BSXTDTOp.mjs} +3 -3
  24. package/dist/{ids-C6AYo1bu.mjs → wait-until-Dw4XrIDQ.mjs} +12 -1
  25. package/dist/{watchers-hash-BfDPW95j.mjs → watchers-hash-BTF_bMIN.mjs} +1 -1
  26. package/docs/01-board/06-watchers.md +4 -2
  27. package/docs/04-reference/01-cli.md +2 -1
  28. package/docs/04-reference/03-http.md +1 -1
  29. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
- import{C as e,D as t,E as n,O as r,S as i,T as a,_ as o,a as s,b as c,c as l,d as u,f as d,g as f,h as p,i as m,l as h,m as g,n as _,o as ee,p as v,r as y,s as b,t as te,u as x,v as S,w as C,x as w,y as T}from"./app.js";const E=/^\[vc\]: #\S*\r?\n/,D=/\[([^\]]+)\]\((https?:\/\/[^)\s]+)\)/g,O=/!\[([^\]]+)\]\(https:\/\/vercel\.com\/static\/status\/[^)]+\)\s*(?:\[[^\]]*\]\((https?:\/\/[^)\s]+)\))?/;function k(e){if(!E.test(e))return null;let t=e.search(/<details><summary>\d+ Skipped Deployments?<\/summary>/),n=[],r=0;for(let i of e.split(/\r?\n/)){let a=r;if(r=e.indexOf(`
2
- `,r)+1||e.length,!i.startsWith(`|`)||/^\|\s*(Project|Name)\s*\|/.test(i)||/^\|\s*:?-/.test(i))continue;let o=i.split(`|`).slice(1,-1).map(e=>e.trim());if(o.length<2)continue;let s=O.exec(o[1]);if(!s)continue;let c=[...o[0].matchAll(D)].at(-1),l=c?.[1]??o[0].replace(/<[^>]*>/g,``).trim();if(!l)continue;let u=o[2]?[...o[2].matchAll(D)].find(e=>/preview/i.test(e[1])):void 0,d=o[3]?.match(/<relative-time[^>]*>([^<]+)<\/relative-time>/)?.[1]?.trim()??(o[3]?.replace(/<[^>]*>/g,``).trim()||null);n.push({project:l,projectUrl:c?.[2]??null,status:s[1].trim(),deploymentUrl:s[2]??null,previewUrl:u?.[2]??null,updated:d,skipped:t!==-1&&a>t})}return n.length>0?n:null}const A={ready:`✅`,building:`⏳`,queued:`⏳`,initializing:`⏳`,error:`❌`,failed:`❌`,canceled:`⚪`,ignored:`⚪`},j=(e,t)=>t?`[${e}](${t})`:e;function ne(e){return e.map(e=>`- ${[`${A[e.status.toLowerCase()]??`▲`} **${j(e.project,e.projectUrl)}**`,`${j(e.status,e.deploymentUrl)}${e.skipped?` (skipped)`:``}`,...e.previewUrl?[j(`Preview`,e.previewUrl)]:[],...e.updated?[e.updated]:[]].join(` · `)}`).join(`
3
- `)}function re(e,t){let n=t===`github:user:35613825`?k(e):null;return n?`**▲ Vercel**\n${ne(n)}`:e}const ie=e=>e>10;function ae(e){try{Reflect.get(globalThis,Symbol.for(`@vercel/request-context`))?.get?.()?.waitUntil?.(e)}catch{}}w({id:i().min(1),platform:i().min(1),key:i().min(1),...l.shape,raw:e()});const M=w({root:c(e=>typeof e==`function`).optional(),text:i().optional(),labels:g.optional(),unset:S(v).optional(),noSync:T().optional()}).strict();function N(e){if(e&&typeof e==`object`){for(let t of Object.values(e))N(t);Object.freeze(e)}return e}const oe=w({target:i().min(1),channel:i().min(1),kind:o([`channel`,`thread`])}).strict();var P=class extends Error{code;constructor(e,t){super(t),this.code=e}};const se=e=>e instanceof P&&e.code===`channel_not_found`,ce=w({event:b,raw:e(),dedupe:i().min(1)}),F=/* @__PURE__ */ new WeakMap,le=e=>F.get(e),I=(e,t=!1)=>{let n=f(e),r=n.trim()===``?t?``:`(no text)`:n;return r.length>1e4?`${r.slice(0,p-1).toWellFormed()}…`:r},L=(e,t,r=e.name??`a file`)=>`📎 ${r}${e.size===void 0?``:` (${n(e.size)})`} didn't come over: ${t}`,R=e=>e instanceof y&&e.code===`no_files`,ue=e=>{let t=e.name??`a file`;if(!e.url||!/^https?:\/\//.test(e.url))return L(e,`this board keeps no files`);let n=t.replace(/[[\]\\]/g,e=>`\\${e}`),r=e.url.replace(/[ ()]/g,e=>`%${e.charCodeAt(0).toString(16).toUpperCase()}`);return L(e,`this board keeps no files`,`[${n}](${r})`)},z=(e,t)=>t.length?`${e.trim()?`${e}\n\n`:``}${t.join(`
4
- `)}`:e,de=e=>e.split(`
5
- `).filter(e=>/^📎 .* didn't come over: /u.test(e)),B=e=>JSON.stringify([e.url,e.message,e.snapshot,e.unavailable]),fe=(e,t)=>e.length===t.length&&e.every((e,n)=>B(e)===B(t[n])),pe=/^\s*`?(vb-[a-z0-9]{4}-[a-z0-9]{4})`?\s*$/i,V=6e4,me=new AbortController().signal,he=e=>{try{return JSON.parse(JSON.stringify(e??null))}catch{return null}},H=e=>typeof e==`string`?f(e):Array.isArray(e)?e.map(H):typeof e==`object`&&e?Object.fromEntries(Object.entries(e).map(([e,t])=>[f(e),H(t)])):e,U=e=>{let t=e?.data?.error,n=typeof t==`string`?t:e instanceof Error?e.message:String(e);return f(n.slice(0,500))||`unknown error`},W=e=>e instanceof y&&e.status===404;function G(e){let i=null,o=()=>{if(!i)throw Error(`sync used before board() bound it`);return i},c={self:`sync`,origin:{via:{kind:`engine`}}};function l(e,t,n=me,r=c){let i=o().backend;return i[e].call(i,r,t,n)}let f=t=>{let n=e[t];if(!n)throw m(`no sync entry named ${t}`);return n},p=e=>e.slice(0,e.indexOf(`:`)),g=t=>e[p(t)]!==void 0,v=e=>e.slice(e.indexOf(`:`)+1);async function b(e){try{return await l(`syncThread`,{thread:e})}catch(e){if(W(e))return null;throw e}}async function S(e){try{let{message:t,replies:n}=await l(`message`,{id:e});return[t,...n]}catch(e){if(W(e))return[];throw e}}async function w(e){return(await S(e)).find(t=>t.id===e)??null}async function T(e){return e.length===0?{}:(await l(`syncCopies`,{message:[...new Set(e)]})).copies}let E=(e,t)=>l(`syncFind`,e,t);async function D(){let{actors:e}=await l(`actors`,{}),t={byId:{},links:{}};for(let{person:n,...r}of e)t.byId[r.id]={id:r.id,kind:r.kind,handle:r.handle,name:r.name,avatar:r.avatar},n&&(t.links[r.id]=n.id);return t}let O=(e,t)=>Object.entries(e.links).filter(([,e])=>e===t).map(([e])=>e),k=/* @__PURE__ */ new Map;function A(e,t){let n=`${e}:${t}`,r=k.get(n);if(r&&(!r.failed||Date.now()-r.at<6e4))return r.id;let i={id:f(e).resolveChannel(t),failed:!1,at:Date.now()};return i.id.catch(r=>{i.failed=!0;let a=se(r);!a&&k.get(n)===i&&k.delete(n),console.warn(`[board] sync ${e}: ${a?`skipping`:`couldn't resolve`} ${t}: ${r.message}`)}),k.set(n,i),i.id}function j(e,t){if(!u(t))return v(t);try{let n=f(e).inboxChannel(e,t);return n===null?null:v(n)}catch{return null}}async function ne(t){for(let n of Object.values(e)){let e=await n.findByEmail(t).catch(()=>null);if(e)return{id:e.id,kind:`external`,handle:e.handle,name:e.name,avatar:e.avatar}}return null}async function F(e){let t=e.indexOf(`:`);if(t<=0)throw m(`sync targets look like <key>:<channel or thread>, got: ${e}`);let n=e.slice(0,t),r=f(n);try{let i=oe.parse(await r.resolveTarget(e.slice(t+1)));if(i.kind===`channel`&&!r.canStartThreads)throw Error(`${r.platform} cannot start threads; use an existing thread`);return{target:`${n}:${i.target}`,kind:i.kind}}catch(t){throw m(`can't sync to ${e}: ${t.message}`)}}async function B(e,t){let{event:n,raw:r,dedupe:i}=ce.parse(H({...t,raw:he(t.raw)}));for(let t of[n.channel,n.thread,`subthread`in n?n.subthread:null])if(t!==null&&!t.startsWith(`${e}:`))throw m(`provider locations must belong to sync entry ${e}`);let a=le(f(e));(!a||await a(v(n.channel),t=>A(e,t))||await G(n.thread))&&await l(`inboxPush`,{key:e,events:[{id:i,event:n,raw:r}]})}async function G(e){try{return(await E({thread:e},AbortSignal.timeout(2e3))).thread!==null}catch(e){let t=e?.name;if(t===`TimeoutError`||t===`AbortError`)return!0;throw e}}async function ge(t,n){let r=e[t];if(!r)throw s(`no sync entry named ${t}`);let i;try{i=await r.receive(t,n,e=>B(t,e))}catch(e){return console.error(`[board] intake failed`,e),new Response(`intake failed`,{status:500})}return ae(_e([t]).catch(e=>console.error(`[board] couldn't pull ${t}'s inbox:`,U(e)))),i}async function _e(t=Object.keys(e)){let n=0,r=Date.now()+24e4;for(let e of t)for(;Date.now()<r;){let{items:t}=await l(`inboxNext`,{key:e,limit:10});if(t.length===0)break;await Promise.all(t.map(t=>ve(e,t))),n+=t.length}return n}async function ve(e,t){let n;try{await xe(e,{event:t.event,raw:t.raw},{id:t.id,attempt:t.attempt+1})}catch(r){console.error(`[board] sync ${e} couldn't import ${t.id}:`,U(r)),n=U(r)}await l(`inboxAck`,{key:e,id:t.id,lease:t.lease,...n===void 0?{}:{error:n}}).catch(e=>console.error(`[board] couldn't ack an inbox event:`,U(e)))}async function ye(e,t,n,r=[]){if(t.length===0)return[];let i=[];for(let a of t){if(i.some(e=>e.url===a.url))continue;let t=(await E({thread:a.thread,message:a.message})).message,o=t===null?null:await w(t);if(o&&!o.deleted&&o.channel===n){i.push({url:a.url,message:o.id,unavailable:null,snapshot:{author:o.author?.name??o.by.actor,text:o.text,createdAt:o.createdAt,files:o.attachments.map(e=>({name:e.name,url:null}))}});continue}if(a.snapshot){i.push({url:a.url,message:null,snapshot:a.snapshot,unavailable:null});continue}let s=r.find(e=>e.url===a.url&&e.snapshot&&e.message===null);if(s){i.push(s);continue}let c=await e.fetchLink(a).catch(e=>({snapshot:null,unavailable:U(e)}));i.push({url:a.url,message:null,snapshot:c.snapshot,unavailable:c.snapshot?null:(c.unavailable??`unknown`).slice(0,300)})}return H(i)}async function be(e,n,r){let i=[],o=[],s=!1;for(let c of n.slice(0,10)){if(s){o.push(ue(c));continue}if(c.size!==void 0&&c.size>26214400){o.push(L(c,`over ${a/1024/1024} MB`));continue}let n;try{let t=await e.fetchFile(c);if(t===null){o.push(L(c,`${e.platform} can't hand it over`));continue}n=t}catch(t){if(r<3)throw t;console.warn(`[board] couldn't fetch ${c.name??`a file`} from ${e.platform}:`,U(t)),o.push(L(c,`${e.platform} wouldn't hand it over`));continue}if(n.byteLength>26214400){o.push(L(c,`over ${a/1024/1024} MB`));continue}if(n.byteLength===0){o.push(L(c,`it was empty`));continue}let u=c.name??`${c.type}`;try{i.push((await l(`upload`,{data:n,name:u,type:c.mimeType||t(u)})).attachment)}catch(e){if(e instanceof y&&(e.code===`too_large`||e.code===`no_direct_uploads`)){o.push(L(c,`over ${C/1024/1024} MB`));continue}if(!R(e))throw e;s=!0,o.push(ue(c))}}for(let e of n.slice(10))o.push(L(e,`a message carries at most 10`));return{attachments:i,notes:o}}async function xe(e,t,n){let{event:r,raw:i}=t,a=f(e),s=(await E({thread:r.thread})).thread??void 0;if(r.kind===`message`){let t=(await E({thread:r.subthread??r.thread,message:r.message})).message;if(t!==null){let e=(await w(t))?.origin;if(!e||e.message!==r.message||(e.subthread??e.thread)!==(r.subthread??r.thread))return}else if(a.users&&n.attempt<6&&await we(s,r))throw Error(`holding ${r.message} until ${r.author.id}'s board message there has its receipt`);let i=r.author.isBot?void 0:pe.exec(r.text)?.[1];if(i&&await Te(e,r,i))return}let c=`author`in r?r.author:{id:`${a.platform}:system`,handle:a.platform,name:a.platform,avatar:null,isBot:!0},l,u=()=>l??=N(a.event({id:n.id,key:e,event:r,raw:i})),d,p,h=!0,g={direction:`in`,key:e,channel:v(r.channel),get event(){return u()},board:o().client({author:c,key:e,...Ce(e,r)},n.id),import(r,i={}){if(!h)throw m(`the sync function has finished`);return d??=Se(e,t,n,s,r,i),d},permalink(){let e=p??a.permalink(u());return p=e,e.catch(()=>{p===e&&(p=void 0)}),e},resolve:t=>A(e,t)};try{await a.sync(g),await d}finally{h=!1}}async function Se(e,t,n,r,i,a){let o=i??(r?(await b(r))?.channel:void 0);if(o===void 0)return{root:null,message:null};try{return await Ae(e,t,n,d.parse(o),M.parse(a))}catch(e){if(!(e instanceof te))throw e;let n=(await E({thread:t.event.thread})).thread;return{root:n===null?null:(await b(n))?.root??null,message:null}}}function Ce(e,t){let n=f(e),r=(`subthread`in t?t.subthread:null)??t.thread;return{via:{kind:`sync`,key:e,platform:n.platform,channel:t.channel,thread:r},respond:async e=>{await n.post(v(r),`thread`,{markdown:e})}}}async function we(e,t){let n=(await E({account:t.author.id})).person;if(!n||n.method!==`consent`)return!1;let r=Date.now(),i=(e,t,i)=>e.by.principal===n.id&&e.by.profile===null&&e.from===null&&!e.deleted&&!e.noSync&&r-Date.parse(e.createdAt)<V&&!i[t]&&!e.undelivered[t];if(e!==void 0){let n=await b(e);if(!n)return!1;let r=n.targets.filter(e=>n.external[e]===t.thread),a=await S(n.root),o=await T(a.map(e=>e.id));return a.some(e=>r.some(t=>i(e,t,o[e.id]??{})))}let{roots:a}=await l(`syncRoots`,{by:n.id,since:r-V}),o=await T(a.map(e=>e.id));for(let e of a){let n=await b(e.thread);if(n?.targets.includes(t.channel)&&!n.external[t.channel]&&i(e,t.channel,o[e.id]??{}))return!0}return!1}async function Te(e,t,n){try{await l(`syncAccount`,{sync:e,account:t.author,code:n,message:x(t.subthread??t.thread,t.message)})}catch(e){if(W(e))return!1;throw e}return await f(e).react(v(t.subthread??t.thread),t.message,`check`,!0).catch(t=>console.warn(`[board] couldn't confirm a linking code on ${e}:`,U(t))),!0}let Ee=e=>f(e).users!==null;async function De(e,t,n){let r=f(e);if(!r.users)throw m(`${e} can't sign people in: link it with a code`);return r.users.authorize(t,n?{callback:n}:{})}async function Oe(e,t){let n=f(e);if(!n.users)throw m(`${e} can't sign people in: link it with a code`);let r=await n.users.token(t);if(!r)return null;let i=await n.whoAmI(r);if(!i.id.startsWith(`${n.platform}:user:`))throw m(`${e} named an account that isn't a ${n.platform} user`);return i}async function ke(e,t,n){let r=await Oe(e,t);return r?(await l(`syncAccount`,{sync:e,account:r,code:n,method:`consent`})).link:null}async function Ae(e,t,n,i,a){let{event:o,raw:s}=t,c=Ce(e,o),u=f(e),d=(await E({thread:o.thread})).thread??void 0,p=d?await b(d):null,h=p?.root,g=e=>ee(`board-inbound`,n.id,String(e)),_={key:e,channel:c.via.channel,thread:c.via.thread},y=async e=>{if(!e.dropped)return e.message;for(let t of e.dropped)await c.respond(t);throw new te(e.dropped)},x=async({attachments:t=[],...n})=>({id:await y(await l(`syncImport`,{op:`post`,from:e,source:_,...n,origin:n.origin??null,...t.length?{attachments:t.map(e=>e.id)}:{}})),re:n.re??null}),S=e=>({root:e.re??e.id,message:e.id}),C=(e={})=>{let t={...e,...a.labels};for(let e of a.unset??[])delete t[e];return t},T=e=>{if(!a.root)return e;let t=a.root(N(structuredClone(e)));if(t&&typeof t==`object`&&`then`in t)throw m(`root overrides must be synchronous`);let n=M.pick({text:!0,labels:!0}).parse(t);return{...e,text:n.text??e.text,labels:{...e.labels,...n.labels}}},D=(t,n,r)=>l(`syncImport`,{op:`labels`,author:t,from:e,origin:{thread:o.thread},set:n,unset:r}),O=async(e,t)=>{if(!a.labels&&!a.unset)return;let n=await w(t),r=Object.fromEntries(Object.entries(a.labels??{}).filter(([e,t])=>n?.labels[e]!==t)),i=(a.unset??[]).filter(e=>n?.labels[e]!==void 0);(Object.keys(r).length||i.length)&&await D(e,r,i)};switch(o.kind){case`message`:{let e=(await E({thread:o.subthread??o.thread,message:o.message})).message;if(e!==null)return{root:h??e,message:e};let{attachments:t,notes:r}=o.files?.length?await be(u,o.files,n.attempt):{attachments:[],notes:[]},c=await ye(u,o.links??[],p?.channel??i),l={...c.length?{links:c}:{},author:o.author,text:I(z(a.text??o.text,r),t.length>0),...t.length?{attachments:t}:{},origin:{channel:o.channel,thread:o.thread,subthread:o.subthread,message:o.message,context:o.context},id:await g(0)},d={...l,...a.noSync?{noSync:!0}:{}};if(h!==void 0)return await O(o.author,h),S(await x({...d,re:h}));let f=await u.fetchRoot(v(o.thread));if(f===null){let e=T({text:o.text,labels:{},author:o.author,raw:s});return S(await x({...l,channel:i,text:I(z(a.text??e.text,r),t.length>0),labels:C(e.labels)}))}let m=T({...f,raw:f.raw??null}),_=await x({author:f.author,channel:i,text:I(m.text),labels:C(m.labels),origin:{channel:o.channel,thread:o.thread,subthread:null,message:`root:${n.id}`,context:null},id:await g(1)});return S(await x({...d,re:_.id}))}case`edited`:case`deleted`:case`reaction`:{let t=(await E({thread:o.subthread??o.thread,message:o.message})).message;if(t===null)return{root:h??null,message:null};let n=`author`in o?o.author:{id:`${u.platform}:system`,handle:u.platform,name:u.platform,avatar:null,isBot:!0},i={thread:o.subthread??o.thread,message:o.message};if(h!==void 0&&await O(n,h),o.kind===`deleted`)await l(`syncImport`,{op:`delete`,author:n,from:e,origin:i});else if(o.kind===`edited`){let r=await w(t),s=I(z(a.text??o.text,r?de(r.text):[]),(r?.attachments.length??0)>0);r&&!o.linksOnly&&r.text!==s&&await y(await l(`syncImport`,{op:`edit`,author:n,from:e,origin:i,text:s,source:_}));let c=r?await ye(u,o.links??[],r.channel,r.links):[];r&&!fe(c,r.links)&&await l(`syncImport`,{op:`links`,author:n,from:e,origin:i,links:c})}else{if(u.singleReaction){let a=r(o.emoji);for(let[r,s]of Object.entries((await w(t))?.reactions??{}))s.includes(n.id)&&!(o.added&&r===a)&&await l(`syncImport`,{op:`react`,author:n,from:e,origin:i,emoji:r,remove:!0})}(!u.singleReaction||o.added)&&await l(`syncImport`,{op:`react`,author:n,from:e,origin:i,emoji:o.emoji,remove:!o.added})}return{root:h??null,message:t}}case`lifecycle`:{if(h!==void 0){let t=await w(h),r=t?.origin?.message===`lifecycle:${n.id}`,i=C((r?T({text:o.url?`${o.title}\n${o.url}`:o.title,labels:o.labels,author:o.author,raw:s}):null)?.labels??o.labels),c=e=>o.owns?.some(t=>e.startsWith(t))??!1,u=Object.fromEntries(Object.entries(i).filter(([e,n])=>t?.labels[e]!==n)),d=Object.keys(t?.labels??{}).filter(e=>!(e in i)&&(o.unset.includes(e)||a.unset?.includes(e)||c(e)));if(t&&!t.deleted&&(Object.keys(u).length||d.length)&&await D(o.author,u,d),o.retitled&&t&&!t.deleted&&t.from===e&&t.origin?.thread===o.thread){let n=I(a.text??T({text:o.url?`${o.title}\n${o.url}`:o.title,labels:t.labels,author:o.author,raw:s}).text);t.text!==n&&await y(await l(`syncImport`,{op:`edit`,author:o.author,from:e,origin:{thread:t.origin.thread,message:t.origin.message},text:n}))}return o.reply?S(await x({author:o.author,re:h,text:I(a.text??o.reply),...a.noSync?{noSync:!0}:{},id:await g(1)})):{root:h,message:r?h:null}}if(!o.createRoot)return{root:null,message:null};let t=T({text:o.url?`${o.title}\n${o.url}`:o.title,labels:o.labels,author:o.author,raw:s}),r=await x({author:o.author,channel:i,text:I(o.reply?t.text:a.text??t.text),labels:C(t.labels),origin:{channel:o.channel,thread:o.thread,subthread:null,message:`lifecycle:${n.id}`,context:null},id:await g(0)});return o.reply?S(await x({author:o.author,re:r.id,text:I(a.text??o.reply),...a.noSync?{noSync:!0}:{},id:await g(1)})):S(r)}}}function je(e,t,n,r=t.text){let i=t.mentions.map(e=>n.byId[e]).filter(e=>e!==void 0);return _(r,(t,r)=>{let a=t.kind===`actor`?i.find(e=>e.id===t.actor):i.find(e=>e.handle.toLowerCase()===t.handle);return a?K(e,a.id,n)??a.name:null})}function K(e,t,n){let r=t=>{let r=n.byId[t];return r?e.mention(r):null},i=n.links[t]??t,a=r(t)??(i===t?null:r(i));if(a)return a;for(let e of O(n,i)){let t=r(e);if(t)return t}return null}async function Me(e,t,n){if(!e.users||t.from!==null||t.by.profile!==null||!t.by.principal.startsWith(`vercel:user:`))return null;if(n){let{accounts:n}=await E({person:t.by.principal});if(!n.some(t=>t.method===`consent`&&t.id.startsWith(`${e.platform}:user:`)))return null}try{return await e.users.token(t.by.principal)}catch(n){return console.warn(`[board] no ${e.platform} token for ${t.by.principal}; posting #${t.id} as the app:`,U(n)),null}}function Ne(e,t,n){let r=f(p(e)),i=je(r,t,n,re(t.text,t.by.actor));return{markdown:t.attachments.length>0&&!r.uploadsFiles?`${i}\n${Le(t)}`:i}}async function Pe(e,t,n,r,i){let a=f(p(e));if(!r.text.trim())return null;let o=await Me(a,r,!0);if(!o)return null;try{return await a.postAs(o,v(t),n,Ne(e,r,i))}catch(t){return console.warn(`[board] couldn't post #${r.id} to ${e} as its author; posting as the app:`,U(t)),null}}function Fe(t,n,r,i,a){let o=i.byId[r.by.actor],s=o?.name??r.by.actor;r.by.profile&&o?.handle.includes(`/`)&&(s=`${o.name} via ${o.handle.split(`/`)[0]}`),r.from&&(s=`${s} (${e[r.from]?.platform??r.by.actor.slice(0,r.by.actor.indexOf(`:`))})`);let c=f(t),l=(a??(e=>c.render(e)))(N({message:{...structuredClone(r),text:re(r.text,r.by.actor)},author:o?{...o}:null,mentionOf:e=>K(c,e,i),label:s,target:n}));if(typeof l!=`string`)throw m(`a provider renderer must return markdown`);let u=je(c,r,i,l);return r.by.profile&&!r.from?{markdown:u,as:{name:s,avatar:Ie(r,o,i)}}:{markdown:u}}function Ie(e,t,n){let r=e=>!e||/\/avatars\/[a-z0-9-]+$/.test(e),i=t?.avatar??null;if(!r(i))return i;let a=n.byId[e.by.principal]?.avatar;if(!r(a))return a;let o=t?.handle.split(`/`)[0]??``;return!e.by.principal.startsWith(`vercel:user:`)||!o||/^user-/.test(o)?i:`https://vercel.com/api/www/avatar?u=${encodeURIComponent(o)}&s=64&format=png`}let Le=e=>e.attachments.map(t=>`\n📎 ${t.name} (${n(t.size)}, on the board: #${e.id})`).join(``),q=(e,t,n,r=!1,i)=>{let a=p(e),{markdown:o,as:s}=Fe(a,e,t,n,i);return{markdown:t.attachments.length>0&&(r||!f(a).uploadsFiles)?`${o}\n${Le(t)}`:o,...s?{as:s}:{}}};async function Re(e,t,n,r,i){let a=e.replyTo===null?void 0:(await T([e.replyTo]))[e.replyTo]?.[t],o=a!==void 0&&a.thread!==n?a.thread:n,s=f(p(t)),c=q(t,e,r,!1,i),l,u;if(!c.markdown.trim()&&e.attachments.length&&s.uploadsFiles)try{let n=await Be(e,t,o);u=n.message,l=n.files}catch(n){if(!s.refusesFiles(n)&&!R(n))throw n;c=q(t,e,r,!0,i),u=(await s.post(v(o),`thread`,c)).message,l=null}else{let n=await Pe(t,o,`thread`,e,r);if(n){let r={thread:o,message:n.message,asUser:!0};return await J(e,t,r),r}if(!c.markdown.trim())throw m(`a renderer must return text unless the message has media`);u=(await s.post(v(o),`thread`,c)).message}let d={thread:o,message:u,...l===void 0?{}:{files:l}};return await J(e,t,d),d}async function J(e,t,n){await l(`syncReceipt`,{kind:`message`,message:e.id,target:t,external:{thread:n.thread,message:n.message,...n.asUser?{asUser:!0}:{}},...n.files===void 0?{}:{files:n.files}})}async function ze(e){return Promise.all(e.attachments.map(async e=>{let{data:t}=await l(`attachment`,{id:e.id});return{data:t instanceof Uint8Array?t:new Uint8Array(await new Response(t).arrayBuffer()),filename:e.name,mimeType:e.type}}))}async function Be(e,t,n){return f(p(t)).uploadFiles(v(n),await ze(e))}async function Y(e,t,n,r,i){let a=f(p(t));if(!a.uploadsFiles||e.attachments.length===0||n.files!==void 0)return;let o;try{o=(await Be(e,t,n.thread)).files}catch(s){if(!a.refusesFiles(s)&&!R(s))throw Object.assign(/* @__PURE__ */ Error(`files: ${U(s)}`),{cause:s,data:{error:`files: ${U(s)}`}});console.warn(`[board] ${t} won't take #${e.id}'s files (${U(s)}); noting them in its text`),o=null,await a.edit(v(n.thread),n.message,q(t,e,r,!0,i)).catch(n=>console.warn(`[board] couldn't note #${e.id}'s files on ${t}:`,U(n)))}await l(`syncReceipt`,{kind:`files`,message:e.id,target:t,files:o})}let X=(e,t,n,r)=>{e.some(e=>e.error===r)||e.push({id:t,target:n,error:r})};async function Z(e,t){if(t.length!==0){if(e<5||ie(e))throw t[0].error;for(let{id:e,target:n,error:r}of t)console.error(`[board] gave up ${n===null?`syncing #${e}`:`delivering #${e} to ${n}`}:`,U(r)),n!==null&&await l(`syncReceipt`,{kind:`failed`,message:e,target:n,error:U(r)})}}async function Q(e,t,n,r,i){let a,o=!0,s=()=>m(`the sync function has finished`),c={direction:`out`,key:e,channel:r===null?null:j(e,r),event:N(structuredClone(t)),message:N(structuredClone(n)),target:r,deliver(e={}){if(!o)throw s();return a??=r===null?Promise.resolve():i(e.render),a},start(t){if(!o)throw s();return Ve(e,n,t)},resolve:t=>A(e,t)};try{await f(e).sync(c),await a}finally{o=!1}}async function Ve(e,t,n){let{target:r,kind:i}=await F(`${e}:${n}`),a=t.re===null?t:await w(t.re);!a||a.deleted||a.noSync||r!==(a.origin?a.origin.channel??h(a.origin.thread):null)&&await l(`syncReceipt`,{kind:`thread`,message:a.id,target:r,targetKind:i,cause:`config`})}async function He(t,n){let r=Object.keys(e).filter(t=>e[t].canStartThreads);if(t.payload.noSync||r.length===0)return;let i=await w(t.message.id);if(!i||i.deleted)return;let a=[];for(let e of r)try{await Q(e,t,i,null,async()=>{})}catch(e){X(a,i.id,null,e)}await Z(n,a)}async function Ue(e,t){let{thread:n,target:r}=e.payload;if(!g(r)||(e.payload.kind??(u(r)?`thread`:`channel`))===`thread`)return;let i=await b(n),[a,...o]=i?await S(i.root):[];if(!i||!a||a.id!==i.root||a.deleted)return;let s=[];try{await Q(p(r),e,a,r,e=>We(i,a,o,r,s,e))}catch(e){X(s,a.id,r,e)}await Z(t,s)}async function We(e,t,n,r,i,a){let o=await D(),s=await T([t.id,...n.map(e=>e.id)]),c=e=>(i.push({id:t.id,target:r,error:e}),e),l=e.external[r];if(l){let e=s[t.id]?.[r];if(e)try{await Y(t,r,e,o,a)}catch(e){throw c(e)}}else try{let e=f(p(r)),n=q(r,t,o,!1,a),i=!n.markdown.trim()&&t.attachments.length>0&&e.uploadsFiles;if(!n.markdown.trim()&&!i)throw m(`a renderer must return text unless the message has media`);let s,c=!1,u=await(async()=>{if(!i){let i=await Pe(r,r,`channel`,t,o);return i?(c=!0,i):e.post(v(r),`channel`,n)}try{let i=await e.post(v(r),`channel`,{...n,files:await ze(t)});return s=i.files??[],i}catch(n){if(!e.refusesFiles(n)&&!R(n))throw n;return s=null,e.post(v(r),`channel`,q(r,t,o,!0,a))}})();l=`${p(r)}:${u.thread}`;let d={thread:l,message:u.message,...s===void 0?{}:{files:s},...c?{asUser:!0}:{}};await J(t,r,d),await Y(t,r,d,o,a)}catch(e){throw c(e)}let u=[];for(let e of n)if(!(e.deleted||e.noSync||Ge(e,r)))try{await Y(e,r,s[e.id]?.[r]??await Re(e,r,l,o,a),o,a)}catch(t){u.push({id:e.id,target:r,error:t})}if(i.push(...u),u.length)throw u[0].error}let Ge=(e,t)=>e.origin?.thread===t||e.from!==null&&p(t)===e.from;async function Ke(e,t){if(!e.message)return;if(e.message.re===null)return He(e,t);if(e.payload.noSync)return;let n=await b(e.payload.thread);if(!n||n.targets.length===0)return;let r=await w(e.message.id);if(!r||r.deleted)return;let i=await D(),a=[];for(let t of n.targets){let o=n.external[t];if(g(t)&&o&&!Ge(r,t))try{await Q(p(t),e,r,t,async e=>{let n=(await T([r.id]))[r.id]?.[t]??await Re(r,t,o,i,e);await Y(r,t,n,i,e)})}catch(e){X(a,r.id,t,e)}}await Z(t,a)}async function qe(e){let t=(await T([e.payload.id]))[e.payload.id]??{};if(Object.keys(t).length===0)return;let n=e.type===`message.edited`?await w(e.payload.id):e.message??await w(e.payload.id);if(!n||e.type===`message.edited`&&n.deleted)return;let i=await D();for(let[a,o]of Object.entries(t))if(!(!g(a)||e.payload.from!==null&&p(a)===e.payload.from))try{await Q(p(a),e,n,a,async t=>{let s=f(p(a)),c=v(o.thread),l=o.asUser&&(e.type===`message.edited`||e.type===`message.deleted`),u=l?await Me(s,n,!1):null;if(l&&!u){console.warn(`[board] skipped ${e.type} on ${a}: #${n.id} was posted as its author, and their token is gone`);return}e.type===`message.edited`?u?await s.editAs(u,c,o.message,Ne(a,n,i)):await s.edit(c,o.message,q(a,n,i,o.files===null,t)):e.type===`message.deleted`?(u?await s.deleteAs(u,c,o.message):await s.delete(c,o.message),o.files?.length&&await s.deleteFiles(o.files)):e.type===`reaction.added`?await s.react(c,o.message,r(e.payload.emoji),!0):await s.react(c,o.message,r(e.payload.emoji),!1)})}catch(t){console.warn(`[board] skipped ${e.type} on ${a}:`,t.message)}}async function Je(e){let{id:t}=e.payload,n=(await T([t]))[t]??{},r=e.message;if(!r||Object.keys(n).length===0)return;let i=await w(t);if(!i||i.deleted)return;let a=await D(),o={...i,labels:r.labels},s={...i,labels:e.before?.labels??{}};for(let[t,r]of Object.entries(n))if(g(t))try{await Q(p(t),e,o,t,async e=>{let n=q(t,o,a,r.files===null,e);n.markdown!==q(t,s,a,r.files===null,e).markdown&&await f(p(t)).edit(v(r.thread),r.message,n)})}catch(e){console.warn(`[board] skipped labels.changed on ${t}:`,U(e))}}async function Ye(e,{attempt:t}){switch(e.type){case`thread.synced`:return Ue(e,t);case`message.posted`:return Ke(e,t);case`message.edited`:case`message.deleted`:case`reaction.added`:case`reaction.removed`:return qe(e);case`labels.changed`:return Je(e)}}async function Xe(e,t){let n=e[0]?await b(e[0].thread):null;if(!n)return[];let r=[...new Set(Object.values(n.external))].filter(g);return(await Promise.all(r.map(async n=>{let r=p(n);try{let i=f(r),a=null;for(let t=e.length-1;t>=0&&a===null;t--){let r=e[t];!r.deleted&&r.origin?.thread===n&&(a=r.origin.message)}return await i.startTyping(v(n),a,t),n}catch(e){return console.warn(`[board] skipped typing on ${n}:`,U(e)),null}}))).filter(e=>e!==null)}async function Ze(e,t){try{return`${e}:${await f(e).resolveChannel(t)}`}catch(e){throw m(`can't resolve inbox channel: ${e.message}`)}}let $=e=>e===`unsupported`||e===`invalid_target`?400:e===`channel_not_found`?404:e===`ratelimited`?429:[`no_client`,`list_failed`,`internal_error`,`fatal_error`,`service_unavailable`,`request_timeout`].includes(e)?502:403;async function Qe(e,t,n){let r=f(e);try{return await r.read(t,{limit:n})}catch(n){throw n instanceof P?new y($(n.code),n.code,n.message):m(`can't read ${t} from ${e}: ${U(n)}`,`platform_error`)}}async function $e(e,t){let n=f(e);try{return await n.join(t)}catch(n){throw n instanceof P?new y($(n.code),n.code,n.message):m(`can't join ${t} on ${e}: ${U(n)}`,`platform_error`)}}return{entries:e,bind(e){i=e},caller:c,deliver:Ye,receive:xe,pull:_e,normalizeTarget:F,findByEmail:ne,handleWebhook:ge,inboxChannel:Ze,signsIn:Ee,signIn:De,signedIn:Oe,redeemSignIn:ke,typing:Xe,readSource:Qe,joinSource:$e}}export{G as createSyncEngine};
1
+ import{C as e,D as t,E as n,O as r,S as i,T as a,_ as o,a as s,b as c,c as l,d as u,f as d,g as f,h as p,i as m,k as h,l as g,m as _,n as v,o as y,p as b,r as x,s as ee,t as te,u as S,v as C,w,x as T,y as E}from"./app.js";const D=/^\[vc\]: #\S*\r?\n/,O=/\[([^\]]+)\]\((https?:\/\/[^)\s]+)\)/g,ne=/!\[([^\]]+)\]\(https:\/\/vercel\.com\/static\/status\/[^)]+\)\s*(?:\[[^\]]*\]\((https?:\/\/[^)\s]+)\))?/;function k(e){if(!D.test(e))return null;let t=e.search(/<details><summary>\d+ Skipped Deployments?<\/summary>/),n=[],r=0;for(let i of e.split(/\r?\n/)){let a=r;if(r=e.indexOf(`
2
+ `,r)+1||e.length,!i.startsWith(`|`)||/^\|\s*(Project|Name)\s*\|/.test(i)||/^\|\s*:?-/.test(i))continue;let o=i.split(`|`).slice(1,-1).map(e=>e.trim());if(o.length<2)continue;let s=ne.exec(o[1]);if(!s)continue;let c=[...o[0].matchAll(O)].at(-1),l=c?.[1]??o[0].replace(/<[^>]*>/g,``).trim();if(!l)continue;let u=o[2]?[...o[2].matchAll(O)].find(e=>/preview/i.test(e[1])):void 0,d=o[3]?.match(/<relative-time[^>]*>([^<]+)<\/relative-time>/)?.[1]?.trim()??(o[3]?.replace(/<[^>]*>/g,``).trim()||null);n.push({project:l,projectUrl:c?.[2]??null,status:s[1].trim(),deploymentUrl:s[2]??null,previewUrl:u?.[2]??null,updated:d,skipped:t!==-1&&a>t})}return n.length>0?n:null}const A={ready:`✅`,building:`⏳`,queued:`⏳`,initializing:`⏳`,error:`❌`,failed:`❌`,canceled:`⚪`,ignored:`⚪`},j=(e,t)=>t?`[${e}](${t})`:e;function re(e){return e.map(e=>`- ${[`${A[e.status.toLowerCase()]??`▲`} **${j(e.project,e.projectUrl)}**`,`${j(e.status,e.deploymentUrl)}${e.skipped?` (skipped)`:``}`,...e.previewUrl?[j(`Preview`,e.previewUrl)]:[],...e.updated?[e.updated]:[]].join(` · `)}`).join(`
3
+ `)}function M(e,t){let n=t===`github:user:35613825`?k(e):null;return n?`**▲ Vercel**\n${re(n)}`:e}const ie=e=>e>10;i({id:e().min(1),platform:e().min(1),key:e().min(1),...g.shape,raw:w()});const N=i({root:T(e=>typeof e==`function`).optional(),text:e().optional(),labels:p.optional(),unset:E(_).optional(),noSync:c().optional()}).strict();function P(e){if(e&&typeof e==`object`){for(let t of Object.values(e))P(t);Object.freeze(e)}return e}const ae=i({target:e().min(1),channel:e().min(1),kind:C([`channel`,`thread`])}).strict();var F=class extends Error{code;constructor(e,t){super(t),this.code=e}};const oe=e=>e instanceof F&&e.code===`channel_not_found`,se=i({event:l,raw:w(),dedupe:e().min(1)}),I=/* @__PURE__ */ new WeakMap,ce=e=>I.get(e),L=(e,t=!1)=>{let n=o(e),r=n.trim()===``?t?``:`(no text)`:n;return r.length>1e4?`${r.slice(0,f-1).toWellFormed()}…`:r},R=(e,n,r=e.name??`a file`)=>`📎 ${r}${e.size===void 0?``:` (${t(e.size)})`} didn't come over: ${n}`,z=e=>e instanceof m&&e.code===`no_files`,le=e=>{let t=e.name??`a file`;if(!e.url||!/^https?:\/\//.test(e.url))return R(e,`this board keeps no files`);let n=t.replace(/[[\]\\]/g,e=>`\\${e}`),r=e.url.replace(/[ ()]/g,e=>`%${e.charCodeAt(0).toString(16).toUpperCase()}`);return R(e,`this board keeps no files`,`[${n}](${r})`)},B=(e,t)=>t.length?`${e.trim()?`${e}\n\n`:``}${t.join(`
4
+ `)}`:e,ue=e=>e.split(`
5
+ `).filter(e=>/^📎 .* didn't come over: /u.test(e)),V=e=>JSON.stringify([e.url,e.message,e.snapshot,e.unavailable]),de=(e,t)=>e.length===t.length&&e.every((e,n)=>V(e)===V(t[n])),fe=/^\s*`?(vb-[a-z0-9]{4}-[a-z0-9]{4})`?\s*$/i,H=6e4,pe=new AbortController().signal,me=e=>{try{return JSON.parse(JSON.stringify(e??null))}catch{return null}},U=e=>typeof e==`string`?o(e):Array.isArray(e)?e.map(U):typeof e==`object`&&e?Object.fromEntries(Object.entries(e).map(([e,t])=>[o(e),U(t)])):e,W=e=>{let t=e?.data?.error,n=typeof t==`string`?t:e instanceof Error?e.message:String(e);return o(n.slice(0,500))||`unknown error`},G=e=>e instanceof m&&e.status===404;function he(e){let i=null,o=()=>{if(!i)throw Error(`sync used before board() bound it`);return i},c={self:`sync`,origin:{via:{kind:`engine`}}};function l(e,t,n=pe,r=c){let i=o().backend;return i[e].call(i,r,t,n)}let f=t=>{let n=e[t];if(!n)throw s(`no sync entry named ${t}`);return n},p=e=>e.slice(0,e.indexOf(`:`)),g=t=>e[p(t)]!==void 0,_=e=>e.slice(e.indexOf(`:`)+1);async function C(e){try{return await l(`syncThread`,{thread:e})}catch(e){if(G(e))return null;throw e}}async function w(e){try{let{message:t,replies:n}=await l(`message`,{id:e});return[t,...n]}catch(e){if(G(e))return[];throw e}}async function T(e){return(await w(e)).find(t=>t.id===e)??null}async function E(e){return e.length===0?{}:(await l(`syncCopies`,{message:[...new Set(e)]})).copies}let D=(e,t)=>l(`syncFind`,e,t);async function O(){let{actors:e}=await l(`actors`,{}),t={byId:{},links:{}};for(let{person:n,...r}of e)t.byId[r.id]={id:r.id,kind:r.kind,handle:r.handle,name:r.name,avatar:r.avatar},n&&(t.links[r.id]=n.id);return t}let ne=(e,t)=>Object.entries(e.links).filter(([,e])=>e===t).map(([e])=>e),k=/* @__PURE__ */ new Map;function A(e,t){let n=`${e}:${t}`,r=k.get(n);if(r&&(!r.failed||Date.now()-r.at<6e4))return r.id;let i={id:f(e).resolveChannel(t),failed:!1,at:Date.now()};return i.id.catch(r=>{i.failed=!0;let a=oe(r);!a&&k.get(n)===i&&k.delete(n),console.warn(`[board] sync ${e}: ${a?`skipping`:`couldn't resolve`} ${t}: ${r.message}`)}),k.set(n,i),i.id}function j(e,t){if(!d(t))return _(t);try{let n=f(e).inboxChannel(e,t);return n===null?null:_(n)}catch{return null}}async function re(t){for(let n of Object.values(e)){let e=await n.findByEmail(t).catch(()=>null);if(e)return{id:e.id,kind:`external`,handle:e.handle,name:e.name,avatar:e.avatar}}return null}async function I(e){let t=e.indexOf(`:`);if(t<=0)throw s(`sync targets look like <key>:<channel or thread>, got: ${e}`);let n=e.slice(0,t),r=f(n);try{let i=ae.parse(await r.resolveTarget(e.slice(t+1)));if(i.kind===`channel`&&!r.canStartThreads)throw Error(`${r.platform} cannot start threads; use an existing thread`);return{target:`${n}:${i.target}`,kind:i.kind}}catch(t){throw s(`can't sync to ${e}: ${t.message}`)}}async function V(e,t){let{event:n,raw:r,dedupe:i}=se.parse(U({...t,raw:me(t.raw)}));for(let t of[n.channel,n.thread,`subthread`in n?n.subthread:null])if(t!==null&&!t.startsWith(`${e}:`))throw s(`provider locations must belong to sync entry ${e}`);let a=ce(f(e));(!a||await a(_(n.channel),t=>A(e,t))||await he(n.thread))&&await l(`inboxPush`,{key:e,events:[{id:i,event:n,raw:r}]})}async function he(e){try{return(await D({thread:e},AbortSignal.timeout(2e3))).thread!==null}catch(e){let t=e?.name;if(t===`TimeoutError`||t===`AbortError`)return!0;throw e}}async function ge(t,n){let r=e[t];if(!r)throw y(`no sync entry named ${t}`);let i;try{i=await r.receive(t,n,e=>V(t,e))}catch(e){return console.error(`[board] intake failed`,e),new Response(`intake failed`,{status:500})}let a=_e([t]).catch(e=>console.error(`[board] couldn't pull ${t}'s inbox:`,W(e)));return x(a),i}async function _e(t=Object.keys(e)){let n=0,r=Date.now()+24e4;for(let e of t)for(;Date.now()<r;){let{items:t}=await l(`inboxNext`,{key:e,limit:10});if(t.length===0)break;await Promise.all(t.map(t=>ve(e,t))),n+=t.length}return n}async function ve(e,t){let n;try{await xe(e,{event:t.event,raw:t.raw},{id:t.id,attempt:t.attempt+1})}catch(r){console.error(`[board] sync ${e} couldn't import ${t.id}:`,W(r)),n=W(r)}await l(`inboxAck`,{key:e,id:t.id,lease:t.lease,...n===void 0?{}:{error:n}}).catch(e=>console.error(`[board] couldn't ack an inbox event:`,W(e)))}async function ye(e,t,n,r=[]){if(t.length===0)return[];let i=[];for(let a of t){if(i.some(e=>e.url===a.url))continue;let t=(await D({thread:a.thread,message:a.message})).message,o=t===null?null:await T(t);if(o&&!o.deleted&&o.channel===n){i.push({url:a.url,message:o.id,unavailable:null,snapshot:{author:o.author?.name??o.by.actor,text:o.text,createdAt:o.createdAt,files:o.attachments.map(e=>({name:e.name,url:null}))}});continue}if(a.snapshot){i.push({url:a.url,message:null,snapshot:a.snapshot,unavailable:null});continue}let s=r.find(e=>e.url===a.url&&e.snapshot&&e.message===null);if(s){i.push(s);continue}let c=await e.fetchLink(a).catch(e=>({snapshot:null,unavailable:W(e)}));i.push({url:a.url,message:null,snapshot:c.snapshot,unavailable:c.snapshot?null:(c.unavailable??`unknown`).slice(0,300)})}return U(i)}async function be(e,t,i){let o=[],s=[],c=!1;for(let u of t.slice(0,10)){if(c){s.push(le(u));continue}if(u.size!==void 0&&u.size>26214400){s.push(R(u,`over ${n/1024/1024} MB`));continue}let t;try{let n=await e.fetchFile(u);if(n===null){s.push(R(u,`${e.platform} can't hand it over`));continue}t=n}catch(t){if(i<3)throw t;console.warn(`[board] couldn't fetch ${u.name??`a file`} from ${e.platform}:`,W(t)),s.push(R(u,`${e.platform} wouldn't hand it over`));continue}if(t.byteLength>26214400){s.push(R(u,`over ${n/1024/1024} MB`));continue}if(t.byteLength===0){s.push(R(u,`it was empty`));continue}let d=u.name??`${u.type}`;try{o.push((await l(`upload`,{data:t,name:d,type:u.mimeType||r(d)})).attachment)}catch(e){if(e instanceof m&&(e.code===`too_large`||e.code===`no_direct_uploads`)){s.push(R(u,`over ${a/1024/1024} MB`));continue}if(!z(e))throw e;c=!0,s.push(le(u))}}for(let e of t.slice(10))s.push(R(e,`a message carries at most 10`));return{attachments:o,notes:s}}async function xe(e,t,n){let{event:r,raw:i}=t,a=f(e),c=(await D({thread:r.thread})).thread??void 0;if(r.kind===`message`){let t=(await D({thread:r.subthread??r.thread,message:r.message})).message;if(t!==null){let e=(await T(t))?.origin;if(!e||e.message!==r.message||(e.subthread??e.thread)!==(r.subthread??r.thread))return}else if(a.users&&n.attempt<6&&await we(c,r))throw Error(`holding ${r.message} until ${r.author.id}'s board message there has its receipt`);let i=r.author.isBot?void 0:fe.exec(r.text)?.[1];if(i&&await Te(e,r,i))return}let l=`author`in r?r.author:{id:`${a.platform}:system`,handle:a.platform,name:a.platform,avatar:null,isBot:!0},u,d=()=>u??=P(a.event({id:n.id,key:e,event:r,raw:i})),p,m,h=!0,g={direction:`in`,key:e,channel:_(r.channel),get event(){return d()},board:o().client({author:l,key:e,...Ce(e,r)},n.id),import(r,i={}){if(!h)throw s(`the sync function has finished`);return p??=Se(e,t,n,c,r,i),p},permalink(){let e=m??a.permalink(d());return m=e,e.catch(()=>{m===e&&(m=void 0)}),e},resolve:t=>A(e,t)};try{await a.sync(g),await p}finally{h=!1}}async function Se(e,t,n,r,i,a){let o=i??(r?(await C(r))?.channel:void 0);if(o===void 0)return{root:null,message:null};try{return await Ae(e,t,n,b.parse(o),N.parse(a))}catch(e){if(!(e instanceof te))throw e;let n=(await D({thread:t.event.thread})).thread;return{root:n===null?null:(await C(n))?.root??null,message:null}}}function Ce(e,t){let n=f(e),r=(`subthread`in t?t.subthread:null)??t.thread;return{via:{kind:`sync`,key:e,platform:n.platform,channel:t.channel,thread:r},respond:async e=>{await n.post(_(r),`thread`,{markdown:e})}}}async function we(e,t){let n=(await D({account:t.author.id})).person;if(!n||n.method!==`consent`)return!1;let r=Date.now(),i=(e,t,i)=>e.by.principal===n.id&&e.by.profile===null&&e.from===null&&!e.deleted&&!e.noSync&&r-Date.parse(e.createdAt)<H&&!i[t]&&!e.undelivered[t];if(e!==void 0){let n=await C(e);if(!n)return!1;let r=n.targets.filter(e=>n.external[e]===t.thread),a=await w(n.root),o=await E(a.map(e=>e.id));return a.some(e=>r.some(t=>i(e,t,o[e.id]??{})))}let{roots:a}=await l(`syncRoots`,{by:n.id,since:r-H}),o=await E(a.map(e=>e.id));for(let e of a){let n=await C(e.thread);if(n?.targets.includes(t.channel)&&!n.external[t.channel]&&i(e,t.channel,o[e.id]??{}))return!0}return!1}async function Te(e,t,n){try{await l(`syncAccount`,{sync:e,account:t.author,code:n,message:u(t.subthread??t.thread,t.message)})}catch(e){if(G(e))return!1;throw e}return await f(e).react(_(t.subthread??t.thread),t.message,`check`,!0).catch(t=>console.warn(`[board] couldn't confirm a linking code on ${e}:`,W(t))),!0}let Ee=e=>f(e).users!==null;async function De(e,t,n){let r=f(e);if(!r.users)throw s(`${e} can't sign people in: link it with a code`);return r.users.authorize(t,n?{callback:n}:{})}async function Oe(e,t){let n=f(e);if(!n.users)throw s(`${e} can't sign people in: link it with a code`);let r=await n.users.token(t);if(!r)return null;let i=await n.whoAmI(r);if(!i.id.startsWith(`${n.platform}:user:`))throw s(`${e} named an account that isn't a ${n.platform} user`);return i}async function ke(e,t,n){let r=await Oe(e,t);return r?(await l(`syncAccount`,{sync:e,account:r,code:n,method:`consent`})).link:null}async function Ae(e,t,n,r,i){let{event:a,raw:o}=t,c=Ce(e,a),u=f(e),d=(await D({thread:a.thread})).thread??void 0,p=d?await C(d):null,m=p?.root,g=e=>ee(`board-inbound`,n.id,String(e)),v={key:e,channel:c.via.channel,thread:c.via.thread},y=async e=>{if(!e.dropped)return e.message;for(let t of e.dropped)await c.respond(t);throw new te(e.dropped)},b=async({attachments:t=[],...n})=>({id:await y(await l(`syncImport`,{op:`post`,from:e,source:v,...n,origin:n.origin??null,...t.length?{attachments:t.map(e=>e.id)}:{}})),re:n.re??null}),x=e=>({root:e.re??e.id,message:e.id}),S=(e={})=>{let t={...e,...i.labels};for(let e of i.unset??[])delete t[e];return t},w=e=>{if(!i.root)return e;let t=i.root(P(structuredClone(e)));if(t&&typeof t==`object`&&`then`in t)throw s(`root overrides must be synchronous`);let n=N.pick({text:!0,labels:!0}).parse(t);return{...e,text:n.text??e.text,labels:{...e.labels,...n.labels}}},E=(t,n,r)=>l(`syncImport`,{op:`labels`,author:t,from:e,origin:{thread:a.thread},set:n,unset:r}),O=async(e,t)=>{if(!i.labels&&!i.unset)return;let n=await T(t),r=Object.fromEntries(Object.entries(i.labels??{}).filter(([e,t])=>n?.labels[e]!==t)),a=(i.unset??[]).filter(e=>n?.labels[e]!==void 0);(Object.keys(r).length||a.length)&&await E(e,r,a)};switch(a.kind){case`message`:{let e=(await D({thread:a.subthread??a.thread,message:a.message})).message;if(e!==null)return{root:m??e,message:e};let{attachments:t,notes:s}=a.files?.length?await be(u,a.files,n.attempt):{attachments:[],notes:[]},c=await ye(u,a.links??[],p?.channel??r),l={...c.length?{links:c}:{},author:a.author,text:L(B(i.text??a.text,s),t.length>0),...t.length?{attachments:t}:{},origin:{channel:a.channel,thread:a.thread,subthread:a.subthread,message:a.message,context:a.context},id:await g(0)},d={...l,...i.noSync?{noSync:!0}:{}};if(m!==void 0)return await O(a.author,m),x(await b({...d,re:m}));let f=await u.fetchRoot(_(a.thread));if(f===null){let e=w({text:a.text,labels:{},author:a.author,raw:o});return x(await b({...l,channel:r,text:L(B(i.text??e.text,s),t.length>0),labels:S(e.labels)}))}let h=w({...f,raw:f.raw??null}),v=await b({author:f.author,channel:r,text:L(h.text),labels:S(h.labels),origin:{channel:a.channel,thread:a.thread,subthread:null,message:`root:${n.id}`,context:null},id:await g(1)});return x(await b({...d,re:v.id}))}case`edited`:case`deleted`:case`reaction`:{let t=(await D({thread:a.subthread??a.thread,message:a.message})).message;if(t===null)return{root:m??null,message:null};let n=`author`in a?a.author:{id:`${u.platform}:system`,handle:u.platform,name:u.platform,avatar:null,isBot:!0},r={thread:a.subthread??a.thread,message:a.message};if(m!==void 0&&await O(n,m),a.kind===`deleted`)await l(`syncImport`,{op:`delete`,author:n,from:e,origin:r});else if(a.kind===`edited`){let o=await T(t),s=L(B(i.text??a.text,o?ue(o.text):[]),(o?.attachments.length??0)>0);o&&!a.linksOnly&&o.text!==s&&await y(await l(`syncImport`,{op:`edit`,author:n,from:e,origin:r,text:s,source:v}));let c=o?await ye(u,a.links??[],o.channel,o.links):[];o&&!de(c,o.links)&&await l(`syncImport`,{op:`links`,author:n,from:e,origin:r,links:c})}else{if(u.singleReaction){let i=h(a.emoji);for(let[o,s]of Object.entries((await T(t))?.reactions??{}))s.includes(n.id)&&!(a.added&&o===i)&&await l(`syncImport`,{op:`react`,author:n,from:e,origin:r,emoji:o,remove:!0})}(!u.singleReaction||a.added)&&await l(`syncImport`,{op:`react`,author:n,from:e,origin:r,emoji:a.emoji,remove:!a.added})}return{root:m??null,message:t}}case`lifecycle`:{if(m!==void 0){let t=await T(m),r=t?.origin?.message===`lifecycle:${n.id}`,s=S((r?w({text:a.url?`${a.title}\n${a.url}`:a.title,labels:a.labels,author:a.author,raw:o}):null)?.labels??a.labels),c=e=>a.owns?.some(t=>e.startsWith(t))??!1,u=Object.fromEntries(Object.entries(s).filter(([e,n])=>t?.labels[e]!==n)),d=Object.keys(t?.labels??{}).filter(e=>!(e in s)&&(a.unset.includes(e)||i.unset?.includes(e)||c(e)));if(t&&!t.deleted&&(Object.keys(u).length||d.length)&&await E(a.author,u,d),a.retitled&&t&&!t.deleted&&t.from===e&&t.origin?.thread===a.thread){let n=L(i.text??w({text:a.url?`${a.title}\n${a.url}`:a.title,labels:t.labels,author:a.author,raw:o}).text);t.text!==n&&await y(await l(`syncImport`,{op:`edit`,author:a.author,from:e,origin:{thread:t.origin.thread,message:t.origin.message},text:n}))}return a.reply?x(await b({author:a.author,re:m,text:L(i.text??a.reply),...i.noSync?{noSync:!0}:{},id:await g(1)})):{root:m,message:r?m:null}}if(!a.createRoot)return{root:null,message:null};let t=w({text:a.url?`${a.title}\n${a.url}`:a.title,labels:a.labels,author:a.author,raw:o}),s=await b({author:a.author,channel:r,text:L(a.reply?t.text:i.text??t.text),labels:S(t.labels),origin:{channel:a.channel,thread:a.thread,subthread:null,message:`lifecycle:${n.id}`,context:null},id:await g(0)});return a.reply?x(await b({author:a.author,re:s.id,text:L(i.text??a.reply),...i.noSync?{noSync:!0}:{},id:await g(1)})):x(s)}}}function je(e,t,n,r=t.text){let i=t.mentions.map(e=>n.byId[e]).filter(e=>e!==void 0);return v(r,(t,r)=>{let a=t.kind===`actor`?i.find(e=>e.id===t.actor):i.find(e=>e.handle.toLowerCase()===t.handle);return a?K(e,a.id,n)??a.name:null})}function K(e,t,n){let r=t=>{let r=n.byId[t];return r?e.mention(r):null},i=n.links[t]??t,a=r(t)??(i===t?null:r(i));if(a)return a;for(let e of ne(n,i)){let t=r(e);if(t)return t}return null}async function Me(e,t,n){if(!e.users||t.from!==null||t.by.profile!==null||!t.by.principal.startsWith(`vercel:user:`))return null;if(n){let{accounts:n}=await D({person:t.by.principal});if(!n.some(t=>t.method===`consent`&&t.id.startsWith(`${e.platform}:user:`)))return null}try{return await e.users.token(t.by.principal)}catch(n){return console.warn(`[board] no ${e.platform} token for ${t.by.principal}; posting #${t.id} as the app:`,W(n)),null}}function Ne(e,t,n){let r=f(p(e)),i=je(r,t,n,M(t.text,t.by.actor));return{markdown:t.attachments.length>0&&!r.uploadsFiles?`${i}\n${Le(t)}`:i}}async function Pe(e,t,n,r,i){let a=f(p(e));if(!r.text.trim())return null;let o=await Me(a,r,!0);if(!o)return null;try{return await a.postAs(o,_(t),n,Ne(e,r,i))}catch(t){return console.warn(`[board] couldn't post #${r.id} to ${e} as its author; posting as the app:`,W(t)),null}}function Fe(t,n,r,i,a){let o=i.byId[r.by.actor],c=o?.name??r.by.actor;r.by.profile&&o?.handle.includes(`/`)&&(c=`${o.name} via ${o.handle.split(`/`)[0]}`),r.from&&(c=`${c} (${e[r.from]?.platform??r.by.actor.slice(0,r.by.actor.indexOf(`:`))})`);let l=f(t),u=(a??(e=>l.render(e)))(P({message:{...structuredClone(r),text:M(r.text,r.by.actor)},author:o?{...o}:null,mentionOf:e=>K(l,e,i),label:c,target:n}));if(typeof u!=`string`)throw s(`a provider renderer must return markdown`);let d=je(l,r,i,u);return r.by.profile&&!r.from?{markdown:d,as:{name:c,avatar:Ie(r,o,i)}}:{markdown:d}}function Ie(e,t,n){let r=e=>!e||/\/avatars\/[a-z0-9-]+$/.test(e),i=t?.avatar??null;if(!r(i))return i;let a=n.byId[e.by.principal]?.avatar;if(!r(a))return a;let o=t?.handle.split(`/`)[0]??``;return!e.by.principal.startsWith(`vercel:user:`)||!o||/^user-/.test(o)?i:`https://vercel.com/api/www/avatar?u=${encodeURIComponent(o)}&s=64&format=png`}let Le=e=>e.attachments.map(n=>`\n📎 ${n.name} (${t(n.size)}, on the board: #${e.id})`).join(``),q=(e,t,n,r=!1,i)=>{let a=p(e),{markdown:o,as:s}=Fe(a,e,t,n,i);return{markdown:t.attachments.length>0&&(r||!f(a).uploadsFiles)?`${o}\n${Le(t)}`:o,...s?{as:s}:{}}};async function Re(e,t,n,r,i){let a=e.replyTo===null?void 0:(await E([e.replyTo]))[e.replyTo]?.[t],o=a!==void 0&&a.thread!==n?a.thread:n,c=f(p(t)),l=q(t,e,r,!1,i),u,d;if(!l.markdown.trim()&&e.attachments.length&&c.uploadsFiles)try{let n=await Be(e,t,o);d=n.message,u=n.files}catch(n){if(!c.refusesFiles(n)&&!z(n))throw n;l=q(t,e,r,!0,i),d=(await c.post(_(o),`thread`,l)).message,u=null}else{let n=await Pe(t,o,`thread`,e,r);if(n){let r={thread:o,message:n.message,asUser:!0};return await J(e,t,r),r}if(!l.markdown.trim())throw s(`a renderer must return text unless the message has media`);d=(await c.post(_(o),`thread`,l)).message}let m={thread:o,message:d,...u===void 0?{}:{files:u}};return await J(e,t,m),m}async function J(e,t,n){await l(`syncReceipt`,{kind:`message`,message:e.id,target:t,external:{thread:n.thread,message:n.message,...n.asUser?{asUser:!0}:{}},...n.files===void 0?{}:{files:n.files}})}async function ze(e){return Promise.all(e.attachments.map(async e=>{let{data:t}=await l(`attachment`,{id:e.id});return{data:t instanceof Uint8Array?t:new Uint8Array(await new Response(t).arrayBuffer()),filename:e.name,mimeType:e.type}}))}async function Be(e,t,n){return f(p(t)).uploadFiles(_(n),await ze(e))}async function Y(e,t,n,r,i){let a=f(p(t));if(!a.uploadsFiles||e.attachments.length===0||n.files!==void 0)return;let o;try{o=(await Be(e,t,n.thread)).files}catch(s){if(!a.refusesFiles(s)&&!z(s))throw Object.assign(/* @__PURE__ */ Error(`files: ${W(s)}`),{cause:s,data:{error:`files: ${W(s)}`}});console.warn(`[board] ${t} won't take #${e.id}'s files (${W(s)}); noting them in its text`),o=null,await a.edit(_(n.thread),n.message,q(t,e,r,!0,i)).catch(n=>console.warn(`[board] couldn't note #${e.id}'s files on ${t}:`,W(n)))}await l(`syncReceipt`,{kind:`files`,message:e.id,target:t,files:o})}let X=(e,t,n,r)=>{e.some(e=>e.error===r)||e.push({id:t,target:n,error:r})};async function Z(e,t){if(t.length!==0){if(e<5||ie(e))throw t[0].error;for(let{id:e,target:n,error:r}of t)console.error(`[board] gave up ${n===null?`syncing #${e}`:`delivering #${e} to ${n}`}:`,W(r)),n!==null&&await l(`syncReceipt`,{kind:`failed`,message:e,target:n,error:W(r)})}}async function Q(e,t,n,r,i){let a,o=!0,c=()=>s(`the sync function has finished`),l={direction:`out`,key:e,channel:r===null?null:j(e,r),event:P(structuredClone(t)),message:P(structuredClone(n)),target:r,deliver(e={}){if(!o)throw c();return a??=r===null?Promise.resolve():i(e.render),a},start(t){if(!o)throw c();return Ve(e,n,t)},resolve:t=>A(e,t)};try{await f(e).sync(l),await a}finally{o=!1}}async function Ve(e,t,n){let{target:r,kind:i}=await I(`${e}:${n}`),a=t.re===null?t:await T(t.re);!a||a.deleted||a.noSync||r!==(a.origin?a.origin.channel??S(a.origin.thread):null)&&await l(`syncReceipt`,{kind:`thread`,message:a.id,target:r,targetKind:i,cause:`config`})}async function He(t,n){let r=Object.keys(e).filter(t=>e[t].canStartThreads);if(t.payload.noSync||r.length===0)return;let i=await T(t.message.id);if(!i||i.deleted)return;let a=[];for(let e of r)try{await Q(e,t,i,null,async()=>{})}catch(e){X(a,i.id,null,e)}await Z(n,a)}async function Ue(e,t){let{thread:n,target:r}=e.payload;if(!g(r)||(e.payload.kind??(d(r)?`thread`:`channel`))===`thread`)return;let i=await C(n),[a,...o]=i?await w(i.root):[];if(!i||!a||a.id!==i.root||a.deleted)return;let s=[];try{await Q(p(r),e,a,r,e=>We(i,a,o,r,s,e))}catch(e){X(s,a.id,r,e)}await Z(t,s)}async function We(e,t,n,r,i,a){let o=await O(),c=await E([t.id,...n.map(e=>e.id)]),l=e=>(i.push({id:t.id,target:r,error:e}),e),u=e.external[r];if(u){let e=c[t.id]?.[r];if(e)try{await Y(t,r,e,o,a)}catch(e){throw l(e)}}else try{let e=f(p(r)),n=q(r,t,o,!1,a),i=!n.markdown.trim()&&t.attachments.length>0&&e.uploadsFiles;if(!n.markdown.trim()&&!i)throw s(`a renderer must return text unless the message has media`);let c,l=!1,d=await(async()=>{if(!i){let i=await Pe(r,r,`channel`,t,o);return i?(l=!0,i):e.post(_(r),`channel`,n)}try{let i=await e.post(_(r),`channel`,{...n,files:await ze(t)});return c=i.files??[],i}catch(n){if(!e.refusesFiles(n)&&!z(n))throw n;return c=null,e.post(_(r),`channel`,q(r,t,o,!0,a))}})();u=`${p(r)}:${d.thread}`;let m={thread:u,message:d.message,...c===void 0?{}:{files:c},...l?{asUser:!0}:{}};await J(t,r,m),await Y(t,r,m,o,a)}catch(e){throw l(e)}let d=[];for(let e of n)if(!(e.deleted||e.noSync||Ge(e,r)))try{await Y(e,r,c[e.id]?.[r]??await Re(e,r,u,o,a),o,a)}catch(t){d.push({id:e.id,target:r,error:t})}if(i.push(...d),d.length)throw d[0].error}let Ge=(e,t)=>e.origin?.thread===t||e.from!==null&&p(t)===e.from;async function Ke(e,t){if(!e.message)return;if(e.message.re===null)return He(e,t);if(e.payload.noSync)return;let n=await C(e.payload.thread);if(!n||n.targets.length===0)return;let r=await T(e.message.id);if(!r||r.deleted)return;let i=await O(),a=[];for(let t of n.targets){let o=n.external[t];if(g(t)&&o&&!Ge(r,t))try{await Q(p(t),e,r,t,async e=>{let n=(await E([r.id]))[r.id]?.[t]??await Re(r,t,o,i,e);await Y(r,t,n,i,e)})}catch(e){X(a,r.id,t,e)}}await Z(t,a)}async function qe(e){let t=(await E([e.payload.id]))[e.payload.id]??{};if(Object.keys(t).length===0)return;let n=e.type===`message.edited`?await T(e.payload.id):e.message??await T(e.payload.id);if(!n||e.type===`message.edited`&&n.deleted)return;let r=await O();for(let[i,a]of Object.entries(t))if(!(!g(i)||e.payload.from!==null&&p(i)===e.payload.from))try{await Q(p(i),e,n,i,async t=>{let o=f(p(i)),s=_(a.thread),c=a.asUser&&(e.type===`message.edited`||e.type===`message.deleted`),l=c?await Me(o,n,!1):null;if(c&&!l){console.warn(`[board] skipped ${e.type} on ${i}: #${n.id} was posted as its author, and their token is gone`);return}e.type===`message.edited`?l?await o.editAs(l,s,a.message,Ne(i,n,r)):await o.edit(s,a.message,q(i,n,r,a.files===null,t)):e.type===`message.deleted`?(l?await o.deleteAs(l,s,a.message):await o.delete(s,a.message),a.files?.length&&await o.deleteFiles(a.files)):e.type===`reaction.added`?await o.react(s,a.message,h(e.payload.emoji),!0):await o.react(s,a.message,h(e.payload.emoji),!1)})}catch(t){console.warn(`[board] skipped ${e.type} on ${i}:`,t.message)}}async function Je(e){let{id:t}=e.payload,n=(await E([t]))[t]??{},r=e.message;if(!r||Object.keys(n).length===0)return;let i=await T(t);if(!i||i.deleted)return;let a=await O(),o={...i,labels:r.labels},s={...i,labels:e.before?.labels??{}};for(let[t,r]of Object.entries(n))if(g(t))try{await Q(p(t),e,o,t,async e=>{let n=q(t,o,a,r.files===null,e);n.markdown!==q(t,s,a,r.files===null,e).markdown&&await f(p(t)).edit(_(r.thread),r.message,n)})}catch(e){console.warn(`[board] skipped labels.changed on ${t}:`,W(e))}}async function Ye(e,{attempt:t}){switch(e.type){case`thread.synced`:return Ue(e,t);case`message.posted`:return Ke(e,t);case`message.edited`:case`message.deleted`:case`reaction.added`:case`reaction.removed`:return qe(e);case`labels.changed`:return Je(e)}}async function Xe(e,t){let n=e[0]?await C(e[0].thread):null;if(!n)return[];let r=[...new Set(Object.values(n.external))].filter(g);return(await Promise.all(r.map(async n=>{let r=p(n);try{let i=f(r),a=null;for(let t=e.length-1;t>=0&&a===null;t--){let r=e[t];!r.deleted&&r.origin?.thread===n&&(a=r.origin.message)}return await i.startTyping(_(n),a,t),n}catch(e){return console.warn(`[board] skipped typing on ${n}:`,W(e)),null}}))).filter(e=>e!==null)}async function Ze(e,t){try{return`${e}:${await f(e).resolveChannel(t)}`}catch(e){throw s(`can't resolve inbox channel: ${e.message}`)}}let $=e=>e===`unsupported`||e===`invalid_target`?400:e===`channel_not_found`?404:e===`ratelimited`?429:[`no_client`,`list_failed`,`internal_error`,`fatal_error`,`service_unavailable`,`request_timeout`].includes(e)?502:403;async function Qe(e,t,n){let r=f(e);try{return await r.read(t,{limit:n})}catch(n){throw n instanceof F?new m($(n.code),n.code,n.message):s(`can't read ${t} from ${e}: ${W(n)}`,`platform_error`)}}async function $e(e,t){let n=f(e);try{return await n.join(t)}catch(n){throw n instanceof F?new m($(n.code),n.code,n.message):s(`can't join ${t} on ${e}: ${W(n)}`,`platform_error`)}}return{entries:e,bind(e){i=e},caller:c,deliver:Ye,receive:xe,pull:_e,normalizeTarget:I,findByEmail:re,handleWebhook:ge,inboxChannel:Ze,signsIn:Ee,signIn:De,signedIn:Oe,redeemSignIn:ke,typing:Xe,readSource:Qe,joinSource:$e}}export{he as createSyncEngine};
@@ -1,14 +1,14 @@
1
1
  import { i as fileSize, n as DIRECT_UPLOAD_BYTES_MAX } from "./files-SniSmeEr.mjs";
2
2
  import { a as AttachmentId } from "./schemas-Be08nyfW.mjs";
3
- import { d as VERSION, i as withMentions } from "./watchers-hash-BfDPW95j.mjs";
3
+ import { d as VERSION, i as withMentions } from "./watchers-hash-BTF_bMIN.mjs";
4
4
  import { n as displayEmoji, r as normalizeEmoji } from "./emoji-CTLpvH-A.mjs";
5
5
  import { t as BoardError } from "./client-D0Px7KzF.mjs";
6
6
  import { i as groups, n as filters$1, o as options, r as globalOptions, s as usage$1, t as commands } from "./commands-nEG47RM_.mjs";
7
7
  import { i as handLogin, l as vercelProjectFile, n as connect, t as boardUrl } from "./node-Ybi9E6bO.mjs";
8
- import { t as http } from "./backend-http-F0W6e36G.mjs";
9
- import { t as board } from "./server-Bphio_82.mjs";
8
+ import { t as http } from "./backend-http-CQWTNzym.mjs";
9
+ import { t as board } from "./server-BSXTDTOp.mjs";
10
10
  import { t as conformance } from "./conformance-DlnfuzEB.mjs";
11
- import { n as handTeam, r as vercel, t as credentialSource } from "./backend-vercel-DUWIcFi9.mjs";
11
+ import { n as handTeam, r as vercel, t as credentialSource } from "./backend-vercel-BPyPi8Cv.mjs";
12
12
  import { t as displayText } from "./bots-CGkO76qH.mjs";
13
13
  import { spawn } from "node:child_process";
14
14
  import { readFile, stat, writeFile } from "node:fs/promises";
@@ -1073,6 +1073,11 @@ function failureOf(error) {
1073
1073
  ...own("limit", "payload_too_large"),
1074
1074
  message: `Can't ${doing()}. ${sentence(message)}`
1075
1075
  };
1076
+ case "no_team": return {
1077
+ ...own("platform", "api_error"),
1078
+ message: "Couldn't tell which team's board to use.",
1079
+ details: [message]
1080
+ };
1076
1081
  case "upload_failed": return {
1077
1082
  ...own("platform", "upload_failed"),
1078
1083
  message: `Failed to ${doing()}.`,
@@ -1,8 +1,8 @@
1
1
  import { t as BoardError } from "./client-D0Px7KzF.mjs";
2
2
  import { a as localTokenFile } from "./node-Ybi9E6bO.mjs";
3
- import { t as board } from "./server-Bphio_82.mjs";
3
+ import { t as board } from "./server-BSXTDTOp.mjs";
4
4
  import { t as oidcTokens } from "./tokens-BuCU-61R.mjs";
5
- import { n as fsBlob, t as a2 } from "./a2-Qzj0kCWU.mjs";
5
+ import { n as fsBlob, t as a2 } from "./a2-C4A4vr0M.mjs";
6
6
  import { t as localScheduler } from "./local-DhkrAqPP.mjs";
7
7
  import { mkdir, rm, writeFile } from "node:fs/promises";
8
8
  import { userInfo } from "node:os";
@@ -1,5 +1,5 @@
1
- import { t as createBoard } from "./exports-NFjBgIT2.mjs";
2
- import { t as http } from "./backend-http-F0W6e36G.mjs";
1
+ import { t as createBoard } from "./exports-B-AeCbYw.mjs";
2
+ import { t as http } from "./backend-http-CQWTNzym.mjs";
3
3
  //#region src/server/index.ts
4
4
  /**
5
5
  * The handle on a board. With a `backend`, the board lives there: `a2()` keeps it in this
@@ -9,7 +9,7 @@ import { t as http } from "./backend-http-F0W6e36G.mjs";
9
9
  function board(options = {}) {
10
10
  return createBoard(options, {
11
11
  http: () => http(),
12
- sync: () => import("./engine-ROa7-IQY.mjs"),
12
+ sync: () => import("./engine-Bfe6pcXb.mjs"),
13
13
  serving: () => import("./serving-CvOWEym2.mjs")
14
14
  });
15
15
  }
@@ -28,4 +28,15 @@ const keyId = async (principal, derived) => `key:${principal}:${(await sha256(`b
28
28
  */
29
29
  const isKeyIdOf = (id, principal) => id.startsWith(`key:${principal}:`) && /^[0-9a-f]{32}$/.test(id.slice(`key:${principal}:`.length));
30
30
  //#endregion
31
- export { sha256 as a, keyId as i, derivedId as n, isKeyIdOf as r, DERIVED_ID as t };
31
+ //#region src/server/wait-until.ts
32
+ /**
33
+ * Keeps `task` running after the response, where the platform offers it: Vercel's request context, as A2
34
+ * reads it too. Elsewhere it runs on in the process.
35
+ */
36
+ function waitUntil(task) {
37
+ try {
38
+ Reflect.get(globalThis, Symbol.for("@vercel/request-context"))?.get?.()?.waitUntil?.(task);
39
+ } catch {}
40
+ }
41
+ //#endregion
42
+ export { keyId as a, isKeyIdOf as i, DERIVED_ID as n, sha256 as o, derivedId as r, waitUntil as t };
@@ -662,7 +662,7 @@ const routes = {
662
662
  const SYNC = "@sync";
663
663
  //#endregion
664
664
  //#region src/version.ts
665
- const VERSION = "0.26.0";
665
+ const VERSION = "0.26.1";
666
666
  //#endregion
667
667
  //#region src/server/routing.ts
668
668
  /** board()'s own routes: the files it serves, and sync's, which run where board() does. */
@@ -209,8 +209,10 @@ export const GET = team.fetch, POST = team.fetch
209
209
  from.
210
210
  - **A match wakes it with nothing in the wake-up:** a `POST <url>/wake` with
211
211
  no event. It then pulls what matched with its own credentials, runs it, and
212
- acks it, until nothing's left, so a burst of matches wakes it once. A
213
- forged wake-up costs it one pull that finds nothing.
212
+ acks it, until nothing's left, so a burst of matches wakes it once. It
213
+ answers when that's done, or after 2 seconds while it keeps going, so
214
+ whoever woke it never waits on slow watchers. A forged wake-up costs it one
215
+ pull that finds nothing.
214
216
  - **A wake-up that doesn't get there is tried again** a minute or so on. While
215
217
  they keep failing, the wait doubles, up to an hour, and the other board logs
216
218
  the first failure and the start of the back-off. It starts over when this
@@ -49,7 +49,8 @@ const code = await createApp({
49
49
  onWarning: (warning) => console.error(warning.message),
50
50
  // Your Vercel login, and the team whose board to use when --scope names none, as this CLI
51
51
  // resolves its own: asked for only when a request needs them. Help, a typo, or misuse never asks.
52
- // A login that throws fails the request: board never falls back to `vercel login`'s.
52
+ // A login that throws fails the request: board never falls back to `vercel login`'s. A team
53
+ // that throws fails it too, with what it threw as the failure's details.
53
54
  login: async () => process.env.VERCEL_AUTH_TOKEN!,
54
55
  team: async () => process.env.VERCEL_ORG_ID ?? null,
55
56
  }).run(process.argv.slice(3))
@@ -122,7 +122,7 @@ a refused write it can read answers 403. `GET /me` returns the caller's
122
122
  | GET | `/watchers` | `{ watchers }`: the caller's registration, or every one for `manage` in every channel |
123
123
  | GET | `/watchers/matches` | `{ matches }`: the caller's matches it can run now, one thread at a time and in order, each `{ id, watcher, thread, lease, attempt, event }` and leased to it for 5 minutes. Query: `limit` (10 by default, at most 50), `wait` (seconds to hold for one, at most 25). 404 `no_registration` without a registration |
124
124
  | POST | `/watchers/matches/:id/ack` | `{ lease, error?, skip? }`: done, an error to try again after a wait (after 5 tries it's `watch.failed`), or `skip` to drop it. 404 `no_match`, 409 `stale_lease` for a lease that ran out |
125
- | POST | `/wake` | On a board on `http()` (no token): it has matches to pull. Answers `{ ran }` |
125
+ | POST | `/wake` | On a board on `http()` (no token): it has matches to pull. Answers `{ ran }` once they've run, or 202 after 2 seconds while they keep running |
126
126
  | GET | `/inbox/:key` | `{ events }`: raw platform events for a sync entry, newest first. Query: `channel`, `limit` (50 by default, at most 500). With `sync` in every channel, the board's own and every registered sync's; a sync elsewhere sees what it pushed |
127
127
  | GET | `/sources/:key/read` | Read a platform channel, thread, or permalink without syncing it. Query: `target`, `limit` (50 by default, at most 200). The board reads it with entry `key`'s app, through the sync it runs, and needs `manage` in every channel; a board that runs no entry `key` answers 404 `not_synced_here` |
128
128
  | POST | `/sources/:key/join` | Add entry `key`'s app to a public channel so `/sources/:key/read` can read it. Body: `{ target }`, a channel (`#name`, an ID) or a link into it. Answers `{ channel, name, joined }`, `joined: false` when the app was already in. Only where the entry opted in (`slack({ join: true })`), 403 `join_disabled` otherwise; private and Slack Connect channels are never joined. Needs `manage` in every channel; a board that runs no entry `key` answers 404 `not_synced_here` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/board",
3
- "version": "0.26.0",
3
+ "version": "0.26.1",
4
4
  "description": "A message board you mount in one route: one durable log, verified authors, live tail, and two-way sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",