@vercel/board 0.16.0 → 0.18.0
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.
- package/README.md +27 -27
- package/dist/{a2-C41hD8SF.mjs → a2-ChRLRupa.mjs} +969 -25
- package/dist/access.d.mts +1 -1
- package/dist/access.mjs +3 -3
- package/dist/{actors-DjMeZpnU.mjs → actors-BOamkEuz.mjs} +3 -73
- package/dist/attempts-CLG840Oj.mjs +20 -0
- package/dist/{auth-COzc09sn.mjs → auth-Drg9FiC2.mjs} +225 -2
- package/dist/backend-B-SJ7p6p.d.mts +680 -0
- package/dist/backend-a2/contract.d.mts +873 -2
- package/dist/backend-a2/contract.mjs +2 -2
- package/dist/backend-a2/scheduler-local.d.mts +1 -1
- package/dist/backend-a2/scheduler-local.mjs +1 -1
- package/dist/backend-a2/scheduler-qstash.d.mts +78 -1
- package/dist/backend-a2/scheduler-qstash.mjs +521 -1
- package/dist/backend-a2/scheduler-vercel.d.mts +37 -1
- package/dist/backend-a2/scheduler-vercel.mjs +203 -1
- package/dist/backend-a2/store-memory.d.mts +2 -2
- package/dist/backend-a2/store-memory.mjs +3 -3
- package/dist/backend-a2/store-postgres.d.mts +1 -1
- package/dist/backend-a2/store-postgres.mjs +2850 -2
- package/dist/backend-a2/store-redis-http.d.mts +1 -1
- package/dist/backend-a2/store-redis-http.mjs +490 -2
- package/dist/backend-a2/store-redis.d.mts +10 -2
- package/dist/backend-a2/store-redis.mjs +51 -2
- package/dist/backend-a2/store-sqlite.d.mts +1 -1
- package/dist/backend-a2/store-sqlite.mjs +3 -3
- package/dist/backend-a2.d.mts +2706 -3
- package/dist/backend-a2.mjs +1 -1
- package/dist/{backend-http-Bid7RIpC.d.mts → backend-http-7cNb8nJI.d.mts} +10 -3
- package/dist/{backend-http-0roEmjl0.mjs → backend-http-CMlL3yq3.mjs} +2 -2
- package/dist/{backend-http-BVRno-ca.mjs → backend-http-Ddzd5kTS.mjs} +32 -3
- package/dist/backend-http.d.mts +1 -1
- package/dist/backend-http.mjs +1 -1
- package/dist/backend-http.node.d.mts +1 -1
- package/dist/backend-http.node.mjs +1 -1
- package/dist/{chat-provider-XCnQlxq6.d.mts → chat-provider-DNJQyajS.d.mts} +16 -4
- package/dist/{chat-provider-jFSeyNmB.mjs → chat-provider-YHy-WbrB.mjs} +15 -9
- package/dist/cli.mjs +30 -10
- package/dist/{client-DGDPaN7U.mjs → client-BA-J7usH.mjs} +10 -2
- package/dist/{conformance-DRR23YNy.mjs → conformance-CT5EeHeC.mjs} +5 -2
- package/dist/conformance.d.mts +1 -1
- package/dist/conformance.mjs +1 -1
- package/dist/{engine-Bir5s8ts.mjs → engine-D0oBUBEK.mjs} +249 -163
- package/dist/events-CewD4kw7.mjs +75 -0
- package/dist/{exports-Dvc1o52I.mjs → exports-CgjfMrQ-.mjs} +35 -32
- package/dist/exports-ZsgjzEnM.d.mts +4 -0
- package/dist/external-BV_cUncs.mjs +151 -0
- package/dist/folds-CRYY14kc.d.mts +534 -0
- package/dist/{reducers-mUPFuFJV.mjs → folds-Dyjput8M.mjs} +6 -73
- package/dist/ids-C6AYo1bu.mjs +31 -0
- package/dist/index.d.mts +4 -4
- package/dist/{index.default-Bkg77Pxn.mjs → index.default-C5Cpz3sa.mjs} +1 -1
- package/dist/index.mjs +5 -5
- package/dist/index.node.d.mts +4 -4
- package/dist/index.node.mjs +3 -3
- package/dist/inspect/app.js +31 -31
- package/dist/inspect/engine.js +5 -5
- package/dist/internal-CvsrprnU-CRY89I-b.mjs +203 -0
- package/dist/{local-Cr_dSjvs.mjs → local-DhkrAqPP.mjs} +1 -1
- package/dist/mentions-CB6ShY4R.mjs +72 -0
- package/dist/{targets-yM5JBUgr.mjs → middleware-CqaCwucP.mjs} +1 -33
- package/dist/platform-B4TnJtWu-CwcTyKg2.mjs +32 -0
- package/dist/{project-CFiArraX.mjs → project-DMDST9kl.mjs} +1 -1
- package/dist/{provider-BGjz-mDa.d.mts → provider-B0b9Qxw4.d.mts} +170 -40
- package/dist/provider-B3DpYSDq.mjs +220 -0
- package/dist/redis-tables-DN9PfIDi.mjs +3897 -0
- package/dist/reducer-CYPHsSmd-BQIfozGi.d.mts +170 -0
- package/dist/reducer-CjmvZSAb-D_OSISmj.mjs +74 -0
- package/dist/{contract-CuJmlrhw.mjs → reducers-BFmIXilu.mjs} +260 -287
- package/dist/retryable-lazy-DZWmHpii-Bye-W8q7.mjs +19 -0
- package/dist/scheduler-task-X1SToDjP-BVoWuInI.mjs +69 -0
- package/dist/{serve-BsOOc-6_.mjs → serve-BGYw0uNL.mjs} +5 -5
- package/dist/{server-jwPY7_wi.mjs → server-DPxBSogx.mjs} +4 -4
- package/dist/server-DtFrWxi3-Boa6gdWO.mjs +3602 -0
- package/dist/server-qgez0Xny-D5mLfqFQ.d.mts +385 -0
- package/dist/{serving-BNbzc96L.mjs → serving-CNkgUPW1.mjs} +1 -1
- package/dist/session-clear-wHd5GCpZ-BnKSxReK.mjs +51 -0
- package/dist/{sql-DbiEnqM0.mjs → sql-U9WTxrwJ.mjs} +2 -2
- package/dist/{sqlite-db-Cbj03vmp.mjs → sqlite-db-Ds4majtT.mjs} +1 -1
- package/dist/store-D0MhBvg6-4Z2L0Kqd.d.mts +530 -0
- package/dist/store-N8PXxDAS-BWBgzBHp.mjs +5 -0
- package/dist/store-codec-DwrWlgQx-CYxGW0aD.mjs +61 -0
- package/dist/store-memory-Bas9Uq5C.mjs +872 -0
- package/dist/store-memory-ZLiZbH3R.mjs +2 -0
- package/dist/store-polling-BZt2Rf3D-BiEM6_HB.mjs +148 -0
- package/dist/store-presence-polling-JuAy2Ck2-CYpuK75X.mjs +109 -0
- package/dist/store-sqlite-BmwL3pUR.mjs +2 -0
- package/dist/store-sqlite-CxxPCcCT.mjs +1053 -0
- package/dist/stream-buffer-DrTyiIuo-BKy-vI14.mjs +53 -0
- package/dist/sync-github.d.mts +24 -17
- package/dist/sync-github.mjs +89 -22
- package/dist/sync-kapso.d.mts +15 -13
- package/dist/sync-kapso.mjs +17 -14
- package/dist/sync-linear.d.mts +219 -0
- package/dist/sync-linear.mjs +311 -0
- package/dist/sync-slack.d.mts +12 -17
- package/dist/sync-slack.mjs +54 -42
- package/dist/sync.chat.d.mts +1 -1
- package/dist/sync.chat.mjs +1 -1
- package/dist/sync.d.mts +3 -3
- package/dist/sync.mjs +5 -4
- package/dist/targets-C-wdR5wP.mjs +33 -0
- package/dist/{tokens-DKLn5P9B.mjs → tokens-DhuzKzAl.mjs} +1 -1
- package/dist/{types-BHCjTZdB.d.mts → types-8yq2VnKI.d.mts} +2 -2
- package/dist/{users-Dls7_ANV.mjs → users-yryHKFMo.mjs} +2 -2
- package/dist/{watch-spec-W0c7ypHJ.mjs → watchers-hash-RLtnSF-t.mjs} +233 -28
- package/docs/01-board/01-mounting.md +1 -1
- package/docs/02-sync/01-overview.md +72 -48
- package/docs/02-sync/02-functions.md +398 -0
- package/docs/02-sync/03-slack.md +30 -25
- package/docs/02-sync/04-github.md +62 -26
- package/docs/02-sync/05-whatsapp.md +23 -19
- package/docs/02-sync/06-providers.md +60 -27
- package/docs/02-sync/07-linear.md +129 -0
- package/docs/03-guides/04-triage.md +1 -1
- package/docs/04-reference/01-cli.md +26 -6
- package/docs/04-reference/02-board.md +18 -5
- package/docs/04-reference/03-http.md +5 -2
- package/docs/04-reference/05-conformance.md +1 -1
- package/docs/index.md +5 -10
- package/package.json +31 -6
- package/dist/a2-D24cvwpN.d.mts +0 -3359
- package/dist/access-CJU2-vaa.mjs +0 -226
- package/dist/attempts-Bxp9KgPf.mjs +0 -919
- package/dist/exports-DLiE7fLY.d.mts +0 -4
- package/dist/provider-CuewcDNZ.mjs +0 -205
- package/dist/redis-tables-B35vv4CZ.mjs +0 -842
- package/dist/reducers-B_vUGQRp.d.mts +0 -1172
- package/dist/watchers-hash-CLjsa6od.mjs +0 -225
- package/docs/02-sync/02-callbacks.md +0 -265
package/dist/inspect/engine.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{C as e,D as t,E as n,
|
|
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=
|
|
3
|
-
`)}function
|
|
4
|
-
`)}`:e,
|
|
5
|
-
`).filter(e=>/^📎 .* didn't come over: /u.test(e)),V=e=>JSON.stringify([e.url,e.message,e.snapshot,e.unavailable]),ce=(e,t)=>e.length===t.length&&e.every((e,n)=>V(e)===V(t[n])),le=/^\s*`?(vb-[a-z0-9]{4}-[a-z0-9]{4})`?\s*$/i,H=6e4,U=new AbortController().signal,ue=e=>{try{return JSON.parse(JSON.stringify(e??null))}catch{return null}},W=e=>typeof e==`string`?f(e):Array.isArray(e)?e.map(W):typeof e==`object`&&e?Object.fromEntries(Object.entries(e).map(([e,t])=>[f(e),W(t)])):e,G=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`},K=e=>e instanceof o&&e.status===404;function q(r){let a=null,s=()=>{if(!a)throw Error(`sync used before board() bound it`);return a},u={self:`sync`,origin:{via:{kind:`engine`}}};function d(e,t,n=U,r=u){let i=s().backend;return i[e].call(i,r,t,n)}let f=e=>{let t=r[e];if(!t)throw _(`no sync entry named ${e}`);return t},m=e=>e.slice(0,e.indexOf(`:`)),h=e=>r[m(e)]!==void 0,v=e=>e.slice(e.indexOf(`:`)+1);async function S(e){try{return await d(`syncThread`,{thread:e})}catch(e){if(K(e))return null;throw e}}async function C(e){try{let{message:t,replies:n}=await d(`message`,{id:e});return[t,...n]}catch(e){if(K(e))return[];throw e}}async function T(e){return(await C(e)).find(t=>t.id===e)??null}async function E(e){return e.length===0?{}:(await d(`syncCopies`,{message:[...new Set(e)]})).copies}let D=(e,t)=>d(`syncFind`,e,t);async function O(){let{actors:e}=await d(`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 k=(e,t)=>Object.entries(e.links).filter(([,e])=>e===t).map(([e])=>e),A=/* @__PURE__ */ new Map,j=e=>{let t=A.get(e);if(t&&(t.complete||Date.now()-t.at<6e4))return t.map;let n=f(e),r=Object.entries(n.mappings),i={complete:!0,at:Date.now(),map:Promise.resolve(/* @__PURE__ */ new Map)};return i.map=Promise.allSettled(r.map(([e])=>n.resolveChannel(e))).then(t=>{let n=/* @__PURE__ */ new Map;return t.forEach((t,a)=>{let[o,s]=r[a];t.status===`fulfilled`?n.set(`${e}:${t.value}`,s):(i.complete=!1,console.warn(`[board] sync ${e}: skipping ${o}: ${t.reason.message}`))}),n}),A.set(e,i),i.map};async function M(e){for(let t of Object.values(r)){let n=await t.findByEmail(e).catch(()=>null);if(n)return{id:n.id,kind:`external`,handle:n.handle,name:n.name,avatar:n.avatar}}return null}async function N(e){let t=[];for(let[n,i]of Object.entries(r))if(i.canStartThreads)for(let[r,i]of await j(n))i.channel===e&&t.push({target:r,kind:`channel`});return t}async function V(e){let t=e.indexOf(`:`);if(t<=0)throw _(`sync targets look like <key>:<channel or thread>, got: ${e}`);let n=e.slice(0,t),r=f(n);try{let i=ie.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 _(`can't sync to ${e}: ${t.message}`)}}async function q(e,t){let{event:n,raw:r,dedupe:i}=oe.parse(W({...t,raw:ue(t.raw)}));for(let t of[n.channel,n.thread,`subthread`in n?n.subthread:null])if(t!==null&&!t.startsWith(`${e}:`))throw _(`provider locations must belong to sync entry ${e}`);((await j(e)).has(n.channel)||await de(n.thread))&&await d(`inboxPush`,{key:e,events:[{id:i,event:n,raw:r}]})}async function de(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 fe(e,t){let n=r[e];if(!n)throw b(`no sync entry named ${e}`);let i;try{i=await n.receive(e,t,t=>q(e,t))}catch(e){return console.error(`[board] intake failed`,e),new Response(`intake failed`,{status:500})}return ne(J([e]).catch(t=>console.error(`[board] couldn't pull ${e}'s inbox:`,G(t)))),i}async function J(e=Object.keys(r)){let t=0,n=Date.now()+24e4;for(let r of e)for(;Date.now()<n;){let{items:e}=await d(`inboxNext`,{key:r,limit:10});if(e.length===0)break;await Promise.all(e.map(e=>pe(r,e))),t+=e.length}return t}async function pe(e,t){let n;try{await ge(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}:`,G(r)),n=G(r)}await d(`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:`,G(e)))}async function me(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:G(e)}));i.push({url:a.url,message:null,snapshot:c.snapshot,unavailable:c.snapshot?null:(c.unavailable??`unknown`).slice(0,300)})}return W(i)}async function he(t,r,i){let a=[],s=[],c=!1;for(let l of r.slice(0,10)){if(c){s.push(z(l));continue}if(l.size!==void 0&&l.size>26214400){s.push(L(l,`over ${w/1024/1024} MB`));continue}let r;try{let e=await t.fetchFile(l);if(e===null){s.push(L(l,`${t.platform} can't hand it over`));continue}r=e}catch(e){if(i<3)throw e;console.warn(`[board] couldn't fetch ${l.name??`a file`} from ${t.platform}:`,G(e)),s.push(L(l,`${t.platform} wouldn't hand it over`));continue}if(r.byteLength>26214400){s.push(L(l,`over ${w/1024/1024} MB`));continue}if(r.byteLength===0){s.push(L(l,`it was empty`));continue}let u=l.name??`${l.type}`;try{a.push((await d(`upload`,{data:r,name:u,type:l.mimeType||n(u)})).attachment)}catch(t){if(t instanceof o&&(t.code===`too_large`||t.code===`no_direct_uploads`)){s.push(L(l,`over ${e/1024/1024} MB`));continue}if(!R(t))throw t;c=!0,s.push(z(l))}}for(let e of r.slice(10))s.push(L(e,`a message carries at most 10`));return{attachments:a,notes:s}}async function ge(e,t,n){let{event:r,raw:i}=t,a=f(e),o=(await j(e)).get(r.channel),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 ve(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:le.exec(r.text)?.[1];if(i&&await ye(e,r,i))return}let u=`author`in r?r.author:{id:`${a.platform}:system`,handle:a.platform,name:a.platform,avatar:null,isBot:!0},d=s().client({author:u,key:e,..._e(e,r)},n.id),p,m=!0,h={id:n.id,key:e,event:r,raw:i,board:d,apply(i,a={}){if(!m)throw _(`the sync callback has finished`);if(p)throw _(`an event can only be imported once per callback`);return p=we(e,t,n,l.parse(i),re.parse(a)).catch(async e=>{if(!(e instanceof y))throw e;let t=(await D({thread:r.thread})).thread;return{root:t===null?null:(await S(t))?.root??null,message:null}}),p},client(e){async function t(t,n,r){if(!m)throw _(`the sync callback has finished`);if(typeof n==`string`)return d.sync(t,n);if(typeof t!=`string`||n!==e)throw _(`sync only accepts the current verified event`);return a.sync(h,t,r)}return{...d,sync:t}}};try{if(o?.run){await o.run(h);return}let e=o?.channel??(c?(await S(c))?.channel:void 0);e&&await a.sync(h,e)}finally{m=!1}}function _e(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 ve(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 S(e);if(!n)return!1;let r=n.targets.filter(e=>n.external[e]===t.thread),a=await C(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 d(`syncRoots`,{by:n.id,since:r-H}),o=await E(a.map(e=>e.id));for(let e of a){let n=await S(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 ye(e,t,n){try{await d(`syncAccount`,{sync:e,account:t.author,code:n,message:x(t.subthread??t.thread,t.message)})}catch(e){if(K(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}:`,G(t))),!0}let be=e=>f(e).users!==null;async function xe(e,t,n){let r=f(e);if(!r.users)throw _(`${e} can't sign people in: link it with a code`);return r.users.authorize(t,n?{callback:n}:{})}async function Se(e,t){let n=f(e);if(!n.users)throw _(`${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 _(`${e} named an account that isn't a ${n.platform} user`);return i}async function Ce(e,t,n){let r=await Se(e,t);return r?(await d(`syncAccount`,{sync:e,account:r,code:n,method:`consent`})).link:null}async function we(e,n,r,i,a){let{event:o,raw:s}=n,l=_e(e,o),p=f(e),m=(await D({thread:o.thread})).thread??void 0,h=m?await S(m):null,g=h?.root,b=e=>c(`board-inbound`,r.id,String(e)),x={key:e,channel:l.via.channel,thread:l.via.thread},C=async e=>{if(!e.dropped)return e.message;for(let t of e.dropped)await l.respond(t);throw new y(e.dropped)},w=async({attachments:t=[],...n})=>{let r=n.channel??h?.channel??i,a=n.re===void 0?{...u,origin:{...u.origin,config:await N(r)}}:u;return{id:await C(await d(`syncImport`,{op:`post`,from:e,source:x,...n,origin:n.origin??null,...t.length?{attachments:t.map(e=>e.id)}:{}},U,a)),re:n.re??null}},E=e=>({root:e.re??e.id,message:e.id}),O=(e={})=>{let t={...e,...a.labels};for(let e of a.unset??[])delete t[e];return t},k=e=>{if(!a.root)return e;let t=a.root(F(structuredClone(e)));if(t&&typeof t==`object`&&`then`in t)throw _(`root overrides must be synchronous`);let n=re.pick({text:!0,labels:!0}).parse(t);return{...e,text:n.text??e.text,labels:{...e.labels,...n.labels}}},A=(t,n,r)=>d(`syncImport`,{op:`labels`,author:t,from:e,origin:{thread:o.thread},set:n,unset:r}),j=async(e,t)=>{if(!a.labels&&!a.unset)return;let n=await T(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 A(e,r,i)};switch(o.kind){case`message`:{let e=(await D({thread:o.subthread??o.thread,message:o.message})).message;if(e!==null)return{root:g??e,message:e};let{attachments:t,notes:n}=o.files?.length?await he(p,o.files,r.attempt):{attachments:[],notes:[]},c=await me(p,o.links??[],h?.channel??i),l={...c.length?{links:c}:{},author:o.author,text:I(B(a.text??o.text,n),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 b(0)},u={...l,...a.noSync?{noSync:!0}:{}};if(g!==void 0)return await j(o.author,g),E(await w({...u,re:g}));let d=await p.fetchRoot(v(o.thread));if(d===null){let e=k({text:o.text,labels:{},author:o.author,raw:s});return E(await w({...l,channel:i,text:I(B(a.text??e.text,n),t.length>0),labels:O(e.labels)}))}let f=k({...d,raw:d.raw??null}),m=await w({author:d.author,channel:i,text:I(f.text),labels:O(f.labels),origin:{channel:o.channel,thread:o.thread,subthread:null,message:`root:${r.id}`,context:null},id:await b(1)});return E(await w({...u,re:m.id}))}case`edited`:case`deleted`:case`reaction`:{let n=(await D({thread:o.subthread??o.thread,message:o.message})).message;if(n===null)return{root:g??null,message:null};let r=`author`in o?o.author:{id:`${p.platform}:system`,handle:p.platform,name:p.platform,avatar:null,isBot:!0},i={thread:o.subthread??o.thread,message:o.message};if(g!==void 0&&await j(r,g),o.kind===`deleted`)await d(`syncImport`,{op:`delete`,author:r,from:e,origin:i});else if(o.kind===`edited`){let t=await T(n),s=I(B(a.text??o.text,t?se(t.text):[]),(t?.attachments.length??0)>0);t&&!o.linksOnly&&t.text!==s&&await C(await d(`syncImport`,{op:`edit`,author:r,from:e,origin:i,text:s,source:x}));let c=t?await me(p,o.links??[],t.channel,t.links):[];t&&!ce(c,t.links)&&await d(`syncImport`,{op:`links`,author:r,from:e,origin:i,links:c})}else{if(p.singleReaction){let a=t(o.emoji);for(let[t,s]of Object.entries((await T(n))?.reactions??{}))s.includes(r.id)&&!(o.added&&t===a)&&await d(`syncImport`,{op:`react`,author:r,from:e,origin:i,emoji:t,remove:!0})}(!p.singleReaction||o.added)&&await d(`syncImport`,{op:`react`,author:r,from:e,origin:i,emoji:o.emoji,remove:!o.added})}return{root:g??null,message:n}}case`lifecycle`:{if(g!==void 0){let e=await T(g),t=e?.origin?.message===`lifecycle:${r.id}`,n=O((t?k({text:o.url?`${o.title}\n${o.url}`:o.title,labels:o.labels,author:o.author,raw:s}):null)?.labels??o.labels),i=e=>o.owns?.some(t=>e.startsWith(t))??!1,c=Object.fromEntries(Object.entries(n).filter(([t,n])=>e?.labels[t]!==n)),l=Object.keys(e?.labels??{}).filter(e=>!(e in n)&&(o.unset.includes(e)||a.unset?.includes(e)||i(e)));return e&&!e.deleted&&(Object.keys(c).length||l.length)&&await A(o.author,c,l),o.reply?E(await w({author:o.author,re:g,text:I(a.text??o.reply),...a.noSync?{noSync:!0}:{},id:await b(1)})):{root:g,message:t?g:null}}if(!o.createRoot)return{root:null,message:null};let e=k({text:o.url?`${o.title}\n${o.url}`:o.title,labels:o.labels,author:o.author,raw:s}),t=await w({author:o.author,channel:i,text:I(o.reply?e.text:a.text??e.text),labels:O(e.labels),origin:{channel:o.channel,thread:o.thread,subthread:null,message:`lifecycle:${r.id}`,context:null},id:await b(0)});return o.reply?E(await w({author:o.author,re:t.id,text:I(a.text??o.reply),...a.noSync?{noSync:!0}:{},id:await b(1)})):E(t)}}}function Te(e,t,n,r=t.text){let i=t.mentions.map(e=>n.byId[e]).filter(e=>e!==void 0);return p(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?Ee(e,a.id,n)??a.name:null})}function Ee(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 k(n,i)){let t=r(e);if(t)return t}return null}async function De(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:`,G(n)),null}}function Oe(e,t,n){let r=f(m(e)),i=Te(r,t,n,P(t.text,t.by.actor));return{markdown:t.attachments.length>0&&!r.uploadsFiles?`${i}\n${Me(t)}`:i}}async function ke(e,t,n,r,i){let a=f(m(e));if(!r.text.trim())return null;let o=await De(a,r,!0);if(!o)return null;try{return await a.postAs(o,v(t),n,Oe(e,r,i))}catch(t){return console.warn(`[board] couldn't post #${r.id} to ${e} as its author; posting as the app:`,G(t)),null}}function Ae(e,t,n,i){let a=i.byId[n.by.actor],o=a?.name??n.by.actor;n.by.profile&&a?.handle.includes(`/`)&&(o=`${a.name} via ${a.handle.split(`/`)[0]}`),n.from&&(o=`${o} (${r[n.from]?.platform??n.by.actor.slice(0,n.by.actor.indexOf(`:`))})`);let s=f(e),c=s.render(F({message:{...structuredClone(n),text:P(n.text,n.by.actor)},author:a?{...a}:null,mentionOf:e=>Ee(s,e,i),label:o,target:t}));if(typeof c!=`string`)throw _(`a provider renderer must return markdown`);let l=Te(s,n,i,c);return n.by.profile&&!n.from?{markdown:l,as:{name:o,avatar:je(n,a,i)}}:{markdown:l}}function je(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 Me=e=>e.attachments.map(t=>`\n📎 ${t.name} (${i(t.size)}, on the board: #${e.id})`).join(``),Y=(e,t,n,r=!1)=>{let i=m(e),{markdown:a,as:o}=Ae(i,e,t,n);return{markdown:t.attachments.length>0&&(r||!f(i).uploadsFiles)?`${a}\n${Me(t)}`:a,...o?{as:o}:{}}};async function Ne(e,t,n,r){let i=e.replyTo===null?void 0:(await E([e.replyTo]))[e.replyTo]?.[t],a=i!==void 0&&i.thread!==n?i.thread:n,o=f(m(t)),s=Y(t,e,r),c,l;if(!s.markdown.trim()&&e.attachments.length&&o.uploadsFiles)try{let n=await Fe(e,t,a);l=n.message,c=n.files}catch(n){if(!o.refusesFiles(n)&&!R(n))throw n;s=Y(t,e,r,!0),l=(await o.post(v(a),`thread`,s)).message,c=null}else{let n=await ke(t,a,`thread`,e,r);if(n){let r={thread:a,message:n.message,asUser:!0};return await X(e,t,r),r}if(!s.markdown.trim())throw _(`a renderer must return text unless the message has media`);l=(await o.post(v(a),`thread`,s)).message}let u={thread:a,message:l,...c===void 0?{}:{files:c}};return await X(e,t,u),u}async function X(e,t,n){await d(`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 Pe(e){return Promise.all(e.attachments.map(async e=>{let{data:t}=await d(`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 Fe(e,t,n){return f(m(t)).uploadFiles(v(n),await Pe(e))}async function Z(e,t,n,r){let i=f(m(t));if(!i.uploadsFiles||e.attachments.length===0||n.files!==void 0)return;let a;try{a=(await Fe(e,t,n.thread)).files}catch(o){if(!i.refusesFiles(o)&&!R(o))throw Object.assign(/* @__PURE__ */ Error(`files: ${G(o)}`),{cause:o,data:{error:`files: ${G(o)}`}});console.warn(`[board] ${t} won't take #${e.id}'s files (${G(o)}); noting them in its text`),a=null,await i.edit(v(n.thread),n.message,Y(t,e,r,!0)).catch(n=>console.warn(`[board] couldn't note #${e.id}'s files on ${t}:`,G(n)))}await d(`syncReceipt`,{kind:`files`,message:e.id,target:t,files:a})}async function Q(e,t){if(t.length!==0){if(e<5||ee(e))throw t[0].error;for(let{id:e,target:n,error:r}of t)console.error(`[board] gave up delivering #${e} to ${n}:`,G(r)),await d(`syncReceipt`,{kind:`failed`,message:e,target:n,error:G(r)})}}async function Ie(e){if(e.re!==null||e.noSync)return;let t=e.origin?e.origin.channel??te(e.origin.thread):null;for(let n of await N(e.channel))n.target!==t&&await d(`syncReceipt`,{kind:`thread`,message:e.id,target:n.target,targetKind:n.kind,cause:`config`})}async function Le(e,t){let{thread:n,target:r}=e.payload;if(!h(r)||(e.payload.kind??(g(r)?`thread`:`channel`))===`thread`)return;let i=await S(n),[a,...o]=i?await C(i.root):[];if(!i||!a||a.id!==i.root||a.deleted)return;let s=await O(),c=await E([a.id,...o.map(e=>e.id)]),l=i.external[r];if(l){let e=c[a.id]?.[r];if(e)try{await Z(a,r,e,s)}catch(e){return Q(t,[{id:a.id,target:r,error:e}])}}else try{let e=f(m(r)),t=Y(r,a,s),n=!t.markdown.trim()&&a.attachments.length>0&&e.uploadsFiles;if(!t.markdown.trim()&&!n)throw _(`a renderer must return text unless the message has media`);let i,o=!1,c=await(async()=>{if(!n){let n=await ke(r,r,`channel`,a,s);return n?(o=!0,n):e.post(v(r),`channel`,t)}try{let n=await e.post(v(r),`channel`,{...t,files:await Pe(a)});return i=n.files??[],n}catch(t){if(!e.refusesFiles(t)&&!R(t))throw t;return i=null,e.post(v(r),`channel`,Y(r,a,s,!0))}})();l=`${m(r)}:${c.thread}`;let u={thread:l,message:c.message,...i===void 0?{}:{files:i},...o?{asUser:!0}:{}};await X(a,r,u),await Z(a,r,u,s)}catch(e){return Q(t,[{id:a.id,target:r,error:e}])}let u=[];for(let e of o)if(!(e.deleted||e.noSync||$(e,r)))try{await Z(e,r,c[e.id]?.[r]??await Ne(e,r,l,s),s)}catch(t){u.push({id:e.id,target:r,error:t})}await Q(t,u)}let $=(e,t)=>e.origin?.thread===t||e.from!==null&&m(t)===e.from;async function Re(e,t){if(!e.message)return;if(e.message.re===null)return Ie(e.message);if(e.payload.noSync)return;let n=await S(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 e of n.targets){let t=n.external[e];if(h(e)&&t&&!$(r,e))try{await Z(r,e,(await E([r.id]))[r.id]?.[e]??await Ne(r,e,t,i),i)}catch(t){a.push({id:r.id,target:e,error:t})}}await Q(t,a)}async function ze(e){let n=(await E([e.payload.id]))[e.payload.id]??{};if(Object.keys(n).length===0)return;let r=e.type===`message.edited`?await T(e.payload.id):e.message;if(e.type===`message.edited`&&(!r||r.deleted))return;let i=await O();for(let[a,o]of Object.entries(n))if(!(!h(a)||e.payload.from!==null&&m(a)===e.payload.from))try{let n=f(m(a)),s=v(o.thread),c=o.asUser&&r&&(e.type===`message.edited`||e.type===`message.deleted`),l=c?await De(n,r,!1):null;if(c&&!l){console.warn(`[board] skipped ${e.type} on ${a}: #${r.id} was posted as its author, and their token is gone`);continue}e.type===`message.edited`&&r?l?await n.editAs(l,s,o.message,Oe(a,r,i)):await n.edit(s,o.message,Y(a,r,i,o.files===null)):e.type===`message.deleted`?(l?await n.deleteAs(l,s,o.message):await n.delete(s,o.message),o.files?.length&&await n.deleteFiles(o.files)):e.type===`reaction.added`?await n.react(s,o.message,t(e.payload.emoji),!0):e.type===`reaction.removed`&&await n.react(s,o.message,t(e.payload.emoji),!1)}catch(t){console.warn(`[board] skipped ${e.type} on ${a}:`,t.message)}}async function Be(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[e,t]of Object.entries(n))if(h(e))try{let n=Y(e,o,a,t.files===null);if(n.markdown===Y(e,s,a,t.files===null).markdown)continue;await f(m(e)).edit(v(t.thread),t.message,n)}catch(t){console.warn(`[board] skipped labels.changed on ${e}:`,G(t))}}async function Ve(e,{attempt:t}){switch(e.type){case`thread.synced`:return Le(e,t);case`message.posted`:return Re(e,t);case`message.edited`:case`message.deleted`:case`reaction.added`:case`reaction.removed`:return ze(e);case`labels.changed`:return Be(e)}}async function He(e,t){let n=e[0]?await S(e[0].thread):null;if(!n)return[];let r=[...new Set(Object.values(n.external))].filter(h);return(await Promise.all(r.map(async n=>{let r=m(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}:`,G(e)),null}}))).filter(e=>e!==null)}async function Ue(e,t){try{return`${e}:${await f(e).resolveChannel(t)}`}catch(e){throw _(`can't resolve inbox channel: ${e.message}`)}}let We=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 Ge(e,t,n){let r=f(e);try{return await r.read(t,{limit:n})}catch(n){throw n instanceof ae?new o(We(n.code),n.code,n.message):_(`can't read ${t} from ${e}: ${G(n)}`,`platform_error`)}}return{entries:r,bind(e){a=e},caller:u,deliver:Ve,receive:ge,pull:J,configTargets:N,normalizeTarget:V,findByEmail:M,handleWebhook:fe,inboxChannel:Ue,signsIn:be,signIn:xe,signedIn:Se,redeemSignIn:Ce,typing:He,readSource:Ge}}export{q 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,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 M(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 N(e,t){let n=t===`github:user:35613825`?k(e):null;return n?`**▲ Vercel**\n${M(n)}`:e}const ne=e=>e>10;function re(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 P=w({root:c(e=>typeof e==`function`).optional(),text:i().optional(),labels:g.optional(),unset:S(v).optional(),noSync:T().optional()}).strict();function F(e){if(e&&typeof e==`object`){for(let t of Object.values(e))F(t);Object.freeze(e)}return e}const ie=w({target:i().min(1),channel:i().min(1),kind:o([`channel`,`thread`])}).strict();var ae=class extends Error{code;constructor(e,t){super(t),this.code=e}};const oe=e=>e instanceof ae&&e.code===`channel_not_found`,se=w({event:b,raw:e(),dedupe:i().min(1)}),I=/* @__PURE__ */ new WeakMap,ce=e=>I.get(e),L=(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},R=(e,t,r=e.name??`a file`)=>`📎 ${r}${e.size===void 0?``:` (${n(e.size)})`} didn't come over: ${t}`,z=e=>e instanceof y&&e.code===`no_files`,B=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})`)},V=(e,t)=>t.length?`${e.trim()?`${e}\n\n`:``}${t.join(`
|
|
4
|
+
`)}`:e,le=e=>e.split(`
|
|
5
|
+
`).filter(e=>/^📎 .* didn't come over: /u.test(e)),H=e=>JSON.stringify([e.url,e.message,e.snapshot,e.unavailable]),ue=(e,t)=>e.length===t.length&&e.every((e,n)=>H(e)===H(t[n])),de=/^\s*`?(vb-[a-z0-9]{4}-[a-z0-9]{4})`?\s*$/i,U=6e4,fe=new AbortController().signal,pe=e=>{try{return JSON.parse(JSON.stringify(e??null))}catch{return null}},W=e=>typeof e==`string`?f(e):Array.isArray(e)?e.map(W):typeof e==`object`&&e?Object.fromEntries(Object.entries(e).map(([e,t])=>[f(e),W(t)])):e,G=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`},K=e=>e instanceof y&&e.status===404;function me(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=fe,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(K(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(K(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=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(!u(t))return v(t);try{let n=f(e).inboxChannel(e,t);return n===null?null:v(n)}catch{return null}}async function M(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 m(`sync targets look like <key>:<channel or thread>, got: ${e}`);let n=e.slice(0,t),r=f(n);try{let i=ie.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 H(e,t){let{event:n,raw:r,dedupe:i}=se.parse(W({...t,raw:pe(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=ce(f(e));(!a||await a(v(n.channel),t=>A(e,t))||await me(n.thread))&&await l(`inboxPush`,{key:e,events:[{id:i,event:n,raw:r}]})}async function me(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 he(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=>H(t,e))}catch(e){return console.error(`[board] intake failed`,e),new Response(`intake failed`,{status:500})}return re(ge([t]).catch(e=>console.error(`[board] couldn't pull ${t}'s inbox:`,G(e)))),i}async function ge(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=>_e(e,t))),n+=t.length}return n}async function _e(e,t){let n;try{await be(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}:`,G(r)),n=G(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:`,G(e)))}async function ve(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:G(e)}));i.push({url:a.url,message:null,snapshot:c.snapshot,unavailable:c.snapshot?null:(c.unavailable??`unknown`).slice(0,300)})}return W(i)}async function ye(e,n,r){let i=[],o=[],s=!1;for(let c of n.slice(0,10)){if(s){o.push(B(c));continue}if(c.size!==void 0&&c.size>26214400){o.push(R(c,`over ${a/1024/1024} MB`));continue}let n;try{let t=await e.fetchFile(c);if(t===null){o.push(R(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}:`,G(t)),o.push(R(c,`${e.platform} wouldn't hand it over`));continue}if(n.byteLength>26214400){o.push(R(c,`over ${a/1024/1024} MB`));continue}if(n.byteLength===0){o.push(R(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(R(c,`over ${C/1024/1024} MB`));continue}if(!z(e))throw e;s=!0,o.push(B(c))}}for(let e of n.slice(10))o.push(R(e,`a message carries at most 10`));return{attachments:i,notes:o}}async function be(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 Ce(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:de.exec(r.text)?.[1];if(i&&await we(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??=F(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,...Se(e,r)},n.id),import(r,i={}){if(!h)throw m(`the sync function has finished`);return d??=xe(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 xe(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 ke(e,t,n,d.parse(o),P.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 Se(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 Ce(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)<U&&!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-U}),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 we(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(K(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}:`,G(t))),!0}let Te=e=>f(e).users!==null;async function Ee(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 De(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 Oe(e,t,n){let r=await De(e,t);return r?(await l(`syncAccount`,{sync:e,account:r,code:n,method:`consent`})).link:null}async function ke(e,t,n,i,a){let{event:o,raw:s}=t,c=Se(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(F(structuredClone(e)));if(t&&typeof t==`object`&&`then`in t)throw m(`root overrides must be synchronous`);let n=P.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 ye(u,o.files,n.attempt):{attachments:[],notes:[]},c=await ve(u,o.links??[],p?.channel??i),l={...c.length?{links:c}:{},author:o.author,text:L(V(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:L(V(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:L(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=L(V(a.text??o.text,r?le(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 ve(u,o.links??[],r.channel,r.links):[];r&&!ue(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=L(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:L(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:L(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:L(a.text??o.reply),...a.noSync?{noSync:!0}:{},id:await g(1)})):S(r)}}}function Ae(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?je(e,a.id,n)??a.name:null})}function je(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:`,G(n)),null}}function Ne(e,t,n){let r=f(p(e)),i=Ae(r,t,n,N(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:`,G(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)))(F({message:{...structuredClone(r),text:N(r.text,r.by.actor)},author:o?{...o}:null,mentionOf:e=>je(c,e,i),label:s,target:n}));if(typeof l!=`string`)throw m(`a provider renderer must return markdown`);let u=Ae(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)&&!z(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)&&!z(s))throw Object.assign(/* @__PURE__ */ Error(`files: ${G(s)}`),{cause:s,data:{error:`files: ${G(s)}`}});console.warn(`[board] ${t} won't take #${e.id}'s files (${G(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}:`,G(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||ne(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}`}:`,G(r)),n!==null&&await l(`syncReceipt`,{kind:`failed`,message:e,target:n,error:G(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:F(structuredClone(t)),message:F(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 I(`${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)&&!z(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||$(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 $=(e,t)=>e.origin?.thread===t||e.from!==null&&p(t)===e.from;async function Ge(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&&!$(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 Ke(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 qe(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}:`,G(e))}}async function Je(e,{attempt:t}){switch(e.type){case`thread.synced`:return Ue(e,t);case`message.posted`:return Ge(e,t);case`message.edited`:case`message.deleted`:case`reaction.added`:case`reaction.removed`:return Ke(e);case`labels.changed`:return qe(e)}}async function Ye(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}:`,G(e)),null}}))).filter(e=>e!==null)}async function Xe(e,t){try{return`${e}:${await f(e).resolveChannel(t)}`}catch(e){throw m(`can't resolve inbox channel: ${e.message}`)}}let Ze=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 ae?new y(Ze(n.code),n.code,n.message):m(`can't read ${t} from ${e}: ${G(n)}`,`platform_error`)}}return{entries:e,bind(e){i=e},caller:c,deliver:Je,receive:be,pull:ge,normalizeTarget:I,findByEmail:M,handleWebhook:he,inboxChannel:Xe,signsIn:Te,signIn:Ee,signedIn:De,redeemSignIn:Oe,typing:Ye,readSource:Qe}}export{me as createSyncEngine};
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
//#region ../../node_modules/.pnpm/experimental-a2@0.22.0_@upstash+qstash@2.12.0_@vercel+queue@0.7.0_ai@7.0.130_zod@4.6.5__52060f00b21aecfab049c27fa3abd2f9/node_modules/experimental-a2/dist/internal-CvsrprnU.js
|
|
2
|
+
/**
|
|
3
|
+
* A null-prototype record for maps keyed by caller-controlled strings
|
|
4
|
+
* (participant ids, presence field names). On a normal object,
|
|
5
|
+
* assigning to '__proto__' rewrites the prototype instead of creating
|
|
6
|
+
* an own property — the prototype-pollution class. Null-prototype
|
|
7
|
+
* objects still satisfy Record types and JSON.stringify cleanly.
|
|
8
|
+
*/
|
|
9
|
+
function nullProtoRecord() {
|
|
10
|
+
return Object.create(null);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Participant ids that collide with Object.prototype plumbing.
|
|
14
|
+
* Null-prototype construction already defuses them, but they are
|
|
15
|
+
* rejected at both seams (`parsePushBody`, `setPresence`) so a hostile
|
|
16
|
+
* id never propagates into userland maps either.
|
|
17
|
+
*/
|
|
18
|
+
const RESERVED_PARTICIPANT_IDS = /* @__PURE__ */ new Set([
|
|
19
|
+
"__proto__",
|
|
20
|
+
"constructor",
|
|
21
|
+
"prototype"
|
|
22
|
+
]);
|
|
23
|
+
const serverInternals = /* @__PURE__ */ new WeakMap();
|
|
24
|
+
/**
|
|
25
|
+
* Consumers A2's own runtimes define: named under `a2.`, with child ids that
|
|
26
|
+
* leave the name out, since their types are disjoint. Defined through
|
|
27
|
+
* `runtimeConsumer` (runtime-consumer.ts), which the server module installs.
|
|
28
|
+
*/
|
|
29
|
+
const runtimeConsumers = /* @__PURE__ */ new WeakSet();
|
|
30
|
+
const runtimeConsumerFactory = {};
|
|
31
|
+
/**
|
|
32
|
+
* Consumer contexts whose previous attempt ended in a failure the consumer
|
|
33
|
+
* threw, as opposed to a claim that lapsed (a crash, a timeout, a frozen
|
|
34
|
+
* process). Only the attempt's own outcome is known, not how far it got.
|
|
35
|
+
*/
|
|
36
|
+
const failedPreviousAttempt = /* @__PURE__ */ new WeakSet();
|
|
37
|
+
const objectLike = (value) => typeof value === "object" && value !== null || typeof value === "function";
|
|
38
|
+
const SCHEDULER_SEND_FAILURE = Symbol.for("experimental-a2.scheduler.send-failure");
|
|
39
|
+
const schedulerSendFailureMarker = (value) => {
|
|
40
|
+
if (!objectLike(value)) return void 0;
|
|
41
|
+
const marker = Reflect.get(value, SCHEDULER_SEND_FAILURE);
|
|
42
|
+
if (!objectLike(marker) || Reflect.get(marker, "version") !== 1 || !Array.isArray(Reflect.get(marker, "pending")) || !Array.isArray(Reflect.get(marker, "active"))) return;
|
|
43
|
+
return marker;
|
|
44
|
+
};
|
|
45
|
+
const schedulerFailureObject = (error) => {
|
|
46
|
+
if (objectLike(error) && (schedulerSendFailureMarker(error) !== void 0 || Object.isExtensible(error))) return error;
|
|
47
|
+
return new Error(String(error), { cause: error });
|
|
48
|
+
};
|
|
49
|
+
const schedulerSendFailureState = (error) => {
|
|
50
|
+
const existing = schedulerSendFailureMarker(error);
|
|
51
|
+
if (existing !== void 0) return existing;
|
|
52
|
+
const marker = {
|
|
53
|
+
version: 1,
|
|
54
|
+
pending: [],
|
|
55
|
+
active: []
|
|
56
|
+
};
|
|
57
|
+
Object.defineProperty(error, SCHEDULER_SEND_FAILURE, {
|
|
58
|
+
value: marker,
|
|
59
|
+
enumerable: false,
|
|
60
|
+
configurable: true,
|
|
61
|
+
writable: false
|
|
62
|
+
});
|
|
63
|
+
return marker;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Classify an adapter error before throwing it. Unclassified adapter failures
|
|
67
|
+
* are retryable because the caller cannot know whether a remote send landed.
|
|
68
|
+
*/
|
|
69
|
+
function classifySchedulerSendFailure(error, disposition) {
|
|
70
|
+
const classified = schedulerFailureObject(error);
|
|
71
|
+
schedulerSendFailureState(classified).pending.push(disposition);
|
|
72
|
+
return classified;
|
|
73
|
+
}
|
|
74
|
+
/** Consume a pending adapter classification and count this rejected send. */
|
|
75
|
+
function markSchedulerSendFailure(error) {
|
|
76
|
+
const marked = schedulerFailureObject(error);
|
|
77
|
+
const marker = schedulerSendFailureState(marked);
|
|
78
|
+
marker.active.push(marker.pending.pop() ?? "retryable");
|
|
79
|
+
return marked;
|
|
80
|
+
}
|
|
81
|
+
const isDrainableServer = (value) => {
|
|
82
|
+
if (value === null || typeof value !== "object") return false;
|
|
83
|
+
const contract = Reflect.get(value, "contract");
|
|
84
|
+
return contract !== null && typeof contract === "object" && typeof Reflect.get(contract, "name") === "string" && typeof Reflect.get(value, "drain") === "function";
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Validate the server list captured by a scheduler route at construction time.
|
|
88
|
+
* The seam stays structural so custom scheduler integrations can supply their
|
|
89
|
+
* own drainable targets.
|
|
90
|
+
*/
|
|
91
|
+
function assertSchedulerTargets(servers) {
|
|
92
|
+
const contracts = /* @__PURE__ */ new Set();
|
|
93
|
+
for (const target of servers) {
|
|
94
|
+
if (!isDrainableServer(target)) throw new TypeError("a2 scheduler: expected a server from createServer()");
|
|
95
|
+
const name = target.contract.name;
|
|
96
|
+
if (contracts.has(name)) throw new TypeError(`a2 scheduler: duplicate server contract '${name}' in one handler`);
|
|
97
|
+
contracts.add(name);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Drain timing knobs. Mutable only as a white-box test seam. Claim
|
|
102
|
+
* heartbeats run on real timers, so tests shrink these to keep suites
|
|
103
|
+
* fast. Production always uses the defaults.
|
|
104
|
+
*/
|
|
105
|
+
const DRAIN_TIMINGS = {
|
|
106
|
+
claimTtlMs: 5e3,
|
|
107
|
+
claimHeartbeatMs: 2e3,
|
|
108
|
+
renewRetryMs: 400,
|
|
109
|
+
watchdogGraceMs: 1e3,
|
|
110
|
+
schedulerArmTimeoutMs: 2e3,
|
|
111
|
+
failureRetryBaseMs: 1e3,
|
|
112
|
+
failureRetryMaxMs: 3e4
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Per server: called when a drain of a session ends with nothing left to run
|
|
116
|
+
* for it in this process, so the layer above can let go of what it kept for
|
|
117
|
+
* that session's next step.
|
|
118
|
+
*/
|
|
119
|
+
const drainSettledHooks = /* @__PURE__ */ new WeakMap();
|
|
120
|
+
/**
|
|
121
|
+
* Stream liveness knobs — the server-side SSE heartbeat and the
|
|
122
|
+
* client-side stall watchdog. Paired by design: the client declares a
|
|
123
|
+
* connection dead after roughly two missed heartbeats. Mutable only as
|
|
124
|
+
* a white-box test seam; production always uses the defaults.
|
|
125
|
+
*/
|
|
126
|
+
/**
|
|
127
|
+
* Poll cadence for the poll-based store streams (sqlite, postgres) —
|
|
128
|
+
* owned, not configurable: adaptive polling removed the operator's
|
|
129
|
+
* reason to tune it (the floor keeps active streams smooth; the
|
|
130
|
+
* ceiling bounds idle cost). Mutable only as a white-box test seam so
|
|
131
|
+
* suites don't wait out real idle gaps.
|
|
132
|
+
*/
|
|
133
|
+
const POLL_TIMINGS = {
|
|
134
|
+
activeFloorMs: 25,
|
|
135
|
+
idleCeilingMs: 2e3
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* Timings for the notify-driven redis live stream. A parked feed re-reads
|
|
139
|
+
* the store every `safetyReadMs` even without a pub/sub wake-up, so a lost
|
|
140
|
+
* notification (subscriber reconnect gap, dropped PUBLISH) costs latency,
|
|
141
|
+
* never an event. Writers publish after their scripts, so wake-ups from
|
|
142
|
+
* concurrent writers can arrive out of order: a feed holds a gap for
|
|
143
|
+
* `reorderMs` before catching up with a read, and a write waits at most
|
|
144
|
+
* `publishMs` for its PUBLISH. Mutable only as a white-box test seam.
|
|
145
|
+
*/
|
|
146
|
+
const NOTIFY_TIMINGS = {
|
|
147
|
+
safetyReadMs: 1e4,
|
|
148
|
+
reorderMs: 50,
|
|
149
|
+
publishMs: 1e3
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Bounds for each server instance's in-memory reducer-state cache. Sizes are
|
|
153
|
+
* encoded JSON lengths, re-measured every `measureEvery` folded events, so
|
|
154
|
+
* the byte budget is approximate. Mutable only as a white-box test seam.
|
|
155
|
+
*/
|
|
156
|
+
const STATE_CACHE = {
|
|
157
|
+
maxEntries: 1e3,
|
|
158
|
+
maxBytes: 33554432,
|
|
159
|
+
snapshotEvery: 128,
|
|
160
|
+
maxTail: 255,
|
|
161
|
+
measureEvery: 16
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* Warm state-read tails for stores that can serve one in a single request:
|
|
165
|
+
* events from `fromIndex` (inclusive) through `throughIndex` or the newest
|
|
166
|
+
* event, or null when that needs more than one request. Like every store
|
|
167
|
+
* read, a tail starts no lower than the latest clear marker. Keyed by the exact
|
|
168
|
+
* store object, so a wrapper built by spreading or proxying a store reads
|
|
169
|
+
* through its own `readHistory` instead.
|
|
170
|
+
*/
|
|
171
|
+
const stateTailReaders = /* @__PURE__ */ new WeakMap();
|
|
172
|
+
const STREAM_TIMINGS = {
|
|
173
|
+
sseHeartbeatMs: 15e3,
|
|
174
|
+
sseDeadlineGraceMs: 1e3,
|
|
175
|
+
stallTimeoutMs: 35e3,
|
|
176
|
+
reconnectBaseMs: 500,
|
|
177
|
+
reconnectMaxMs: 5e3
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* WebSocket down-pump backpressure — `sessionsSocket` parks its pull
|
|
181
|
+
* loop while the socket reports more buffered bytes than the
|
|
182
|
+
* high-water mark and re-checks on the poll cadence, so a slow reader
|
|
183
|
+
* applies backpressure to the store subscription instead of buffering
|
|
184
|
+
* without bound in the socket. Acks and heartbeats stay exempt: they
|
|
185
|
+
* are small and correctness-relevant. Mutable only as a white-box test
|
|
186
|
+
* seam.
|
|
187
|
+
*/
|
|
188
|
+
const SOCKET_TIMINGS = {
|
|
189
|
+
highWaterMarkBytes: 1048576,
|
|
190
|
+
resumePollMs: 25,
|
|
191
|
+
maxInFlightMessages: 32,
|
|
192
|
+
disconnectWaterMarkBytes: 8388608
|
|
193
|
+
};
|
|
194
|
+
/**
|
|
195
|
+
* Presence timings. Owned, not configurable (decision #36's rule).
|
|
196
|
+
* Mutable only as a white-box test seam.
|
|
197
|
+
*/
|
|
198
|
+
const PRESENCE_TIMINGS = {
|
|
199
|
+
sendIntervalMs: 66,
|
|
200
|
+
tombstoneMs: 6e4
|
|
201
|
+
};
|
|
202
|
+
//#endregion
|
|
203
|
+
export { serverInternals as _, RESERVED_PARTICIPANT_IDS as a, STREAM_TIMINGS as c, drainSettledHooks as d, failedPreviousAttempt as f, runtimeConsumers as g, runtimeConsumerFactory as h, PRESENCE_TIMINGS as i, assertSchedulerTargets as l, nullProtoRecord as m, NOTIFY_TIMINGS as n, SOCKET_TIMINGS as o, markSchedulerSendFailure as p, POLL_TIMINGS as r, STATE_CACHE as s, DRAIN_TIMINGS as t, classifySchedulerSendFailure as u, stateTailReaders as v };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as deliverSchedulerClear, r as deliverSchedulerAppend } from "./server-DtFrWxi3-Boa6gdWO.mjs";
|
|
2
2
|
//#region src/scheduler/local.ts
|
|
3
3
|
/** The longest delay a timer takes: past it, `setTimeout` fires at once. */
|
|
4
4
|
const MAX_DELAY = 2 ** 31 - 1;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
//#region src/contract/mentions.ts
|
|
2
|
+
const FENCED_CODE = /```[\s\S]*?```/g;
|
|
3
|
+
const INLINE_CODE = /`[^`\n]*`/g;
|
|
4
|
+
const NAME = "[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?";
|
|
5
|
+
const MENTION = new RegExp(`(?<![\\w@.-])@(${NAME}(?:/${NAME})?)(?!:|[a-z0-9_/-]|\\.(?=[a-z0-9]))`, "gi");
|
|
6
|
+
const EXACT = /(?<![\w@.-])@\[([^\]\s]+)\]/g;
|
|
7
|
+
/** Blanks out code so mentions inside it never count. */
|
|
8
|
+
const proseOnly = (text) => text.replace(FENCED_CODE, (match) => " ".repeat(match.length)).replace(INLINE_CODE, (match) => " ".repeat(match.length));
|
|
9
|
+
/** Mentions in prose order, deduplicated. Handles are lowercased. */
|
|
10
|
+
function extractMentions(text) {
|
|
11
|
+
const prose = proseOnly(text);
|
|
12
|
+
const found = [];
|
|
13
|
+
for (const match of prose.matchAll(EXACT)) {
|
|
14
|
+
const actor = match[1];
|
|
15
|
+
if (actor !== void 0) found.push({
|
|
16
|
+
index: match.index,
|
|
17
|
+
token: {
|
|
18
|
+
kind: "actor",
|
|
19
|
+
actor
|
|
20
|
+
},
|
|
21
|
+
key: `actor:${actor}`
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
for (const match of prose.replace(EXACT, (m) => " ".repeat(m.length)).matchAll(MENTION)) {
|
|
25
|
+
const handle = match[1]?.toLowerCase();
|
|
26
|
+
if (handle !== void 0) found.push({
|
|
27
|
+
index: match.index,
|
|
28
|
+
token: {
|
|
29
|
+
kind: "handle",
|
|
30
|
+
handle
|
|
31
|
+
},
|
|
32
|
+
key: `handle:${handle}`
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
const seen = /* @__PURE__ */ new Set();
|
|
36
|
+
return found.sort((a, b) => a.index - b.index).filter(({ key }) => !seen.has(key) && seen.add(key)).map(({ token }) => token);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Rewrites each mention in prose with `replace`, which also gets the mention as
|
|
40
|
+
* written; one it returns null for stays as written.
|
|
41
|
+
* Code is left alone, as in `extractMentions`.
|
|
42
|
+
*/
|
|
43
|
+
function replaceMentions(text, replace) {
|
|
44
|
+
const prose = proseOnly(text);
|
|
45
|
+
const found = [];
|
|
46
|
+
for (const match of prose.matchAll(EXACT)) found.push({
|
|
47
|
+
index: match.index,
|
|
48
|
+
length: match[0].length,
|
|
49
|
+
token: {
|
|
50
|
+
kind: "actor",
|
|
51
|
+
actor: match[1]
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
for (const match of prose.replace(EXACT, (m) => " ".repeat(m.length)).matchAll(MENTION)) found.push({
|
|
55
|
+
index: match.index,
|
|
56
|
+
length: match[0].length,
|
|
57
|
+
token: {
|
|
58
|
+
kind: "handle",
|
|
59
|
+
handle: match[1].toLowerCase()
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
let out = "";
|
|
63
|
+
let at = 0;
|
|
64
|
+
for (const { index, length, token } of found.sort((a, b) => a.index - b.index)) {
|
|
65
|
+
const written = text.slice(index, index + length);
|
|
66
|
+
out += text.slice(at, index) + (replace(token, written) ?? written);
|
|
67
|
+
at = index + length;
|
|
68
|
+
}
|
|
69
|
+
return out + text.slice(at);
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
export { replaceMentions as n, extractMentions as t };
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { m as MESSAGE_TEXT_MAX, p as Labels } from "./schemas-Be08nyfW.mjs";
|
|
2
2
|
import { t as HttpError } from "./errors-DX3hpwWt.mjs";
|
|
3
|
-
import { o as extractMentions, s as replaceMentions } from "./actors-DjMeZpnU.mjs";
|
|
4
|
-
import { c as isThreadTarget } from "./reducers-mUPFuFJV.mjs";
|
|
5
3
|
import { z } from "zod";
|
|
6
4
|
//#region src/server/middleware.ts
|
|
7
5
|
/** A write the middleware didn't let through: the API answers 422 with what it responded. */
|
|
@@ -61,34 +59,4 @@ async function runMiddleware(middleware, input, commit) {
|
|
|
61
59
|
return committed.value;
|
|
62
60
|
}
|
|
63
61
|
//#endregion
|
|
64
|
-
|
|
65
|
-
/** A target as a post or a receipt names it, resolved: a plain one's kind goes by its shape. */
|
|
66
|
-
const syncTarget = (target) => typeof target === "string" ? {
|
|
67
|
-
target,
|
|
68
|
-
kind: isThreadTarget(target) ? "thread" : "channel"
|
|
69
|
-
} : target;
|
|
70
|
-
/** Whether `text` mentions anyone by email, `@[ada@vercel.com]`, which sync looks up. */
|
|
71
|
-
const mentionsEmails = (text) => extractMentions(text).some((token) => token.kind === "actor" && token.actor.includes("@"));
|
|
72
|
-
/**
|
|
73
|
-
* `@[ada@vercel.com]`: each email `find` knows (a synced platform's user) becomes that user's
|
|
74
|
-
* exact mention, `@[slack:user:U0456]`, so it reads natively there; the rest stay plain text.
|
|
75
|
-
*/
|
|
76
|
-
async function withEmailMentions(text, find) {
|
|
77
|
-
const emails = extractMentions(text).flatMap((token) => token.kind === "actor" && token.actor.includes("@") ? [token.actor] : []);
|
|
78
|
-
if (emails.length === 0) return {
|
|
79
|
-
text,
|
|
80
|
-
found: []
|
|
81
|
-
};
|
|
82
|
-
const byEmail = /* @__PURE__ */ new Map();
|
|
83
|
-
for (const email of emails) byEmail.set(email, await find?.(email).catch(() => null) ?? null);
|
|
84
|
-
return {
|
|
85
|
-
text: replaceMentions(text, (token) => {
|
|
86
|
-
if (token.kind !== "actor" || !byEmail.has(token.actor)) return null;
|
|
87
|
-
const actor = byEmail.get(token.actor);
|
|
88
|
-
return actor ? `@[${actor.id}]` : token.actor;
|
|
89
|
-
}),
|
|
90
|
-
found: [...byEmail.values()].filter((actor) => actor !== null)
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
//#endregion
|
|
94
|
-
export { MIDDLEWARE_ACTOR as a, DroppedError as i, syncTarget as n, runMiddleware as o, withEmailMentions as r, mentionsEmails as t };
|
|
62
|
+
export { MIDDLEWARE_ACTOR as n, runMiddleware as r, DroppedError as t };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region ../../node_modules/.pnpm/experimental-a2@0.22.0_@upstash+qstash@2.12.0_@vercel+queue@0.7.0_ai@7.0.130_zod@4.6.5__52060f00b21aecfab049c27fa3abd2f9/node_modules/experimental-a2/dist/platform-B4TnJtWu.js
|
|
2
|
+
const SYMBOL_FOR_REQ_CONTEXT = Symbol.for("@vercel/request-context");
|
|
3
|
+
function requestContext() {
|
|
4
|
+
try {
|
|
5
|
+
return Reflect.get(globalThis, SYMBOL_FOR_REQ_CONTEXT)?.get?.() ?? {};
|
|
6
|
+
} catch {
|
|
7
|
+
return {};
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/** The current invocation's Vercel deployment identity, when available. */
|
|
11
|
+
function platformVercelOidcToken() {
|
|
12
|
+
try {
|
|
13
|
+
const token = requestContext().headers?.["x-vercel-oidc-token"];
|
|
14
|
+
return typeof token === "string" && token.length > 0 ? token : null;
|
|
15
|
+
} catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function platformWaitUntil(promise) {
|
|
20
|
+
try {
|
|
21
|
+
requestContext().waitUntil?.(promise);
|
|
22
|
+
} catch {}
|
|
23
|
+
}
|
|
24
|
+
/** The invocation's termination time in epoch ms, or null if unknowable. */
|
|
25
|
+
function invocationDeadlineMs() {
|
|
26
|
+
const deadline = requestContext().deadline;
|
|
27
|
+
if (deadline === void 0 || deadline === null) return null;
|
|
28
|
+
const ms = new Date(deadline).getTime();
|
|
29
|
+
return Number.isNaN(ms) ? null : ms;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { platformVercelOidcToken as n, platformWaitUntil as r, invocationDeadlineMs as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as setOwn, t as own } from "./own-OwgPWdmh.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { n as foldMessages, r as foldSync } from "./folds-Dyjput8M.mjs";
|
|
3
3
|
//#region src/store/project.ts
|
|
4
4
|
/** The message an event concerns, if any. */
|
|
5
5
|
function concernedMessageId(event) {
|